From 11ce7a1bc3e2f5d38e8d34f2f0f031808acc0c2a Mon Sep 17 00:00:00 2001 From: Siva Mullati Date: Mon, 7 Jan 2019 14:56:24 +0530 Subject: [PATCH] HE: Add MU EDCA Parameter Set element (AP) Add support for configuring parameters for the MU EDCA Parameter Set element per IEEE P802.11ax/D3.0. Signed-off-by: Siva Mullati --- hostapd/config_file.c | 92 ++++++++++++++++++++++++++++++++++++ hostapd/hostapd.conf | 24 ++++++++++ src/ap/ap_config.h | 1 + src/ap/beacon.c | 8 +++- src/ap/ieee802_11.h | 1 + src/ap/ieee802_11_he.c | 31 ++++++++++++ src/common/ieee802_11_defs.h | 34 +++++++++++++ 7 files changed, 189 insertions(+), 2 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 10a52fda2..daaa484f2 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -1379,6 +1379,14 @@ static int hostapd_config_vht_capab(struct hostapd_config *conf, #endif /* CONFIG_IEEE80211AC */ +#ifdef CONFIG_IEEE80211AX +static u8 set_he_cap(int val, u8 mask) +{ + return (u8) (mask & (val << ffs(mask))); +} +#endif /* CONFIG_IEEE80211AX */ + + #ifdef CONFIG_INTERWORKING static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos, int line) @@ -3397,6 +3405,90 @@ static int hostapd_config_fill(struct hostapd_config *conf, conf->he_op.he_twt_required = atoi(pos); } else if (os_strcmp(buf, "he_rts_threshold") == 0) { conf->he_op.he_rts_threshold = atoi(pos); + } else if (os_strcmp(buf, "he_mu_edca_qos_info_param_count") == 0) { + conf->he_mu_edca.he_qos_info |= + set_he_cap(atoi(pos), HE_QOS_INFO_EDCA_PARAM_SET_COUNT); + } else if (os_strcmp(buf, "he_mu_edca_qos_info_q_ack") == 0) { + conf->he_mu_edca.he_qos_info |= + set_he_cap(atoi(pos), HE_QOS_INFO_Q_ACK); + } else if (os_strcmp(buf, "he_mu_edca_qos_info_queue_request") == 0) { + conf->he_mu_edca.he_qos_info |= + set_he_cap(atoi(pos), HE_QOS_INFO_QUEUE_REQUEST); + } else if (os_strcmp(buf, "he_mu_edca_qos_info_txop_request") == 0) { + conf->he_mu_edca.he_qos_info |= + set_he_cap(atoi(pos), HE_QOS_INFO_TXOP_REQUEST); + } else if (os_strcmp(buf, "he_mu_edca_ac_be_aifsn") == 0) { + conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ACI_IDX] |= + set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN); + } else if (os_strcmp(buf, "he_mu_edca_ac_be_acm") == 0) { + conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ACI_IDX] |= + set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM); + } else if (os_strcmp(buf, "he_mu_edca_ac_be_aci") == 0) { + conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ACI_IDX] |= + set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI); + } else if (os_strcmp(buf, "he_mu_edca_ac_be_ecwmin") == 0) { + conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ECW_IDX] |= + set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN); + } else if (os_strcmp(buf, "he_mu_edca_ac_be_ecwmax") == 0) { + conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ECW_IDX] |= + set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX); + } else if (os_strcmp(buf, "he_mu_edca_ac_be_timer") == 0) { + conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_TIMER_IDX] = + atoi(pos) & 0xff; + } else if (os_strcmp(buf, "he_mu_edca_ac_bk_aifsn") == 0) { + conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ACI_IDX] |= + set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN); + } else if (os_strcmp(buf, "he_mu_edca_ac_bk_acm") == 0) { + conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ACI_IDX] |= + set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM); + } else if (os_strcmp(buf, "he_mu_edca_ac_bk_aci") == 0) { + conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ACI_IDX] |= + set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI); + } else if (os_strcmp(buf, "he_mu_edca_ac_bk_ecwmin") == 0) { + conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ECW_IDX] |= + set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN); + } else if (os_strcmp(buf, "he_mu_edca_ac_bk_ecwmax") == 0) { + conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ECW_IDX] |= + set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX); + } else if (os_strcmp(buf, "he_mu_edca_ac_bk_timer") == 0) { + conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_TIMER_IDX] = + atoi(pos) & 0xff; + } else if (os_strcmp(buf, "he_mu_edca_ac_vi_aifsn") == 0) { + conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ACI_IDX] |= + set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN); + } else if (os_strcmp(buf, "he_mu_edca_ac_vi_acm") == 0) { + conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ACI_IDX] |= + set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM); + } else if (os_strcmp(buf, "he_mu_edca_ac_vi_aci") == 0) { + conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ACI_IDX] |= + set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI); + } else if (os_strcmp(buf, "he_mu_edca_ac_vi_ecwmin") == 0) { + conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ECW_IDX] |= + set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN); + } else if (os_strcmp(buf, "he_mu_edca_ac_vi_ecwmax") == 0) { + conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ECW_IDX] |= + set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX); + } else if (os_strcmp(buf, "he_mu_edca_ac_vi_timer") == 0) { + conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_TIMER_IDX] = + atoi(pos) & 0xff; + } else if (os_strcmp(buf, "he_mu_edca_ac_vo_aifsn") == 0) { + conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ACI_IDX] |= + set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN); + } else if (os_strcmp(buf, "he_mu_edca_ac_vo_acm") == 0) { + conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ACI_IDX] |= + set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM); + } else if (os_strcmp(buf, "he_mu_edca_ac_vo_aci") == 0) { + conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ACI_IDX] |= + set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI); + } else if (os_strcmp(buf, "he_mu_edca_ac_vo_ecwmin") == 0) { + conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ECW_IDX] |= + set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN); + } else if (os_strcmp(buf, "he_mu_edca_ac_vo_ecwmax") == 0) { + conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ECW_IDX] |= + set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX); + } else if (os_strcmp(buf, "he_mu_edca_ac_vo_timer") == 0) { + conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_TIMER_IDX] = + atoi(pos) & 0xff; #endif /* CONFIG_IEEE80211AX */ } else if (os_strcmp(buf, "max_listen_interval") == 0) { bss->max_listen_interval = atoi(pos); diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 26f9d3467..739d36772 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -801,6 +801,30 @@ wmm_ac_vo_acm=0 # unsigned integer = duration in units of 16 us #he_rts_threshold=0 +#he_mu_edca_qos_info_param_count +#he_mu_edca_qos_info_q_ack +#he_mu_edca_qos_info_queue_request=1 +#he_mu_edca_qos_info_txop_request +#he_mu_edca_ac_be_aifsn=0 +#he_mu_edca_ac_be_ecwmin=15 +#he_mu_edca_ac_be_ecwmax=15 +#he_mu_edca_ac_be_timer=255 +#he_mu_edca_ac_bk_aifsn=0 +#he_mu_edca_ac_bk_aci=1 +#he_mu_edca_ac_bk_ecwmin=15 +#he_mu_edca_ac_bk_ecwmax=15 +#he_mu_edca_ac_bk_timer=255 +#he_mu_edca_ac_vi_ecwmin=15 +#he_mu_edca_ac_vi_ecwmax=15 +#he_mu_edca_ac_vi_aifsn=0 +#he_mu_edca_ac_vi_aci=2 +#he_mu_edca_ac_vi_timer=255 +#he_mu_edca_ac_vo_aifsn=0 +#he_mu_edca_ac_vo_aci=3 +#he_mu_edca_ac_vo_ecwmin=15 +#he_mu_edca_ac_vo_ecwmax=15 +#he_mu_edca_ac_vo_timer=255 + ##### IEEE 802.1X-2004 related configuration ################################## # Require IEEE 802.1X authorization diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index c49e2c1c4..990d0d1b5 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -843,6 +843,7 @@ struct hostapd_config { #ifdef CONFIG_IEEE80211AX struct he_phy_capabilities_info he_phy_capab; struct he_operation he_op; + struct ieee80211_he_mu_edca_parameter_set he_mu_edca; #endif /* CONFIG_IEEE80211AX */ /* VHT enable/disable config from CHAN_SWITCH */ diff --git a/src/ap/beacon.c b/src/ap/beacon.c index 19d0bcd2a..3e62991d0 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -397,7 +397,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, #ifdef CONFIG_IEEE80211AX if (hapd->iconf->ieee80211ax) { buflen += 3 + sizeof(struct ieee80211_he_capabilities) + - 3 + sizeof(struct ieee80211_he_operation); + 3 + sizeof(struct ieee80211_he_operation) + + 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set); } #endif /* CONFIG_IEEE80211AX */ @@ -510,6 +511,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, if (hapd->iconf->ieee80211ax) { pos = hostapd_eid_he_capab(hapd, pos); pos = hostapd_eid_he_operation(hapd, pos); + pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos); } #endif /* CONFIG_IEEE80211AX */ @@ -1085,7 +1087,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, #ifdef CONFIG_IEEE80211AX if (hapd->iconf->ieee80211ax) { tail_len += 3 + sizeof(struct ieee80211_he_capabilities) + - 3 + sizeof(struct ieee80211_he_operation); + 3 + sizeof(struct ieee80211_he_operation) + + 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set); } #endif /* CONFIG_IEEE80211AX */ @@ -1222,6 +1225,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, if (hapd->iconf->ieee80211ax) { tailpos = hostapd_eid_he_capab(hapd, tailpos); tailpos = hostapd_eid_he_operation(hapd, tailpos); + tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos); } #endif /* CONFIG_IEEE80211AX */ diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h index 11747e135..508222673 100644 --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -59,6 +59,7 @@ u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid); u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid); u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid); u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid); +u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid); int hostapd_ht_operation_update(struct hostapd_iface *iface); void ieee802_11_send_sa_query_req(struct hostapd_data *hapd, diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c index 1a8d46972..072135863 100644 --- a/src/ap/ieee802_11_he.c +++ b/src/ap/ieee802_11_he.c @@ -86,3 +86,34 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid) return pos; } + + +u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid) +{ + struct ieee80211_he_mu_edca_parameter_set *edca; + u8 *pos; + size_t i; + + pos = (u8 *) &hapd->iface->conf->he_mu_edca; + for (i = 0; i < sizeof(*edca); i++) { + if (pos[i]) + break; + } + if (i == sizeof(*edca)) + return eid; /* no MU EDCA Parameters configured */ + + pos = eid; + *pos++ = WLAN_EID_EXTENSION; + *pos++ = 1 + sizeof(*edca); + *pos++ = WLAN_EID_EXT_HE_MU_EDCA_PARAMS; + + edca = (struct ieee80211_he_mu_edca_parameter_set *) pos; + os_memcpy(edca, &hapd->iface->conf->he_mu_edca, sizeof(*edca)); + + wpa_hexdump(MSG_DEBUG, "HE: MU EDCA Parameter Set element", + pos, sizeof(*edca)); + + pos += sizeof(*edca); + + return pos; +} diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 178cab041..cc512c6c9 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -467,6 +467,7 @@ #define WLAN_EID_EXT_PASSWORD_IDENTIFIER 33 #define WLAN_EID_EXT_HE_CAPABILITIES 35 #define WLAN_EID_EXT_HE_OPERATION 36 +#define WLAN_EID_EXT_HE_MU_EDCA_PARAMS 38 #define WLAN_EID_EXT_OCV_OCI 54 /* Extended Capabilities field */ @@ -2147,6 +2148,39 @@ struct ieee80211_he_operation { BIT(20) | BIT(21))) #define HE_OPERATION_RTS_THRESHOLD_OFFSET 12 +struct ieee80211_he_mu_edca_parameter_set { + u8 he_qos_info; + u8 he_mu_ac_be_param[3]; + u8 he_mu_ac_bk_param[3]; + u8 he_mu_ac_vi_param[3]; + u8 he_mu_ac_vo_param[3]; +} STRUCT_PACKED; + +/* HE MU AC parameter record field format */ +/* ACI/AIFSN */ +#define HE_MU_AC_PARAM_ACI_IDX 0 +#define HE_MU_AC_PARAM_AIFSN ((u8) (BIT(0) | BIT(1) | BIT(2) | BIT(3))) +#define HE_MU_AC_PARAM_ACM ((u8) BIT(4)) +#define HE_MU_AC_PARAM_ACI ((u8) (BIT(5) | BIT(6))) +/* B7: Reserved */ + +/* ECWmin/ECWmax */ +#define HE_MU_AC_PARAM_ECW_IDX 1 +#define HE_MU_AC_PARAM_ECWMIN ((u8) (BIT(0) | BIT(1) | BIT(2) | BIT(3))) +#define HE_MU_AC_PARAM_ECWMAX ((u8) (BIT(4) | BIT(5) | BIT(6) | BIT(7))) + +/* MU EDCA Timer */ +#define HE_MU_AC_PARAM_TIMER_IDX 2 + +/* HE QoS Info field */ +#define HE_QOS_INFO_EDCA_PARAM_SET_COUNT ((u8) (BIT(0) | BIT(1) | \ + BIT(2) | BIT(3))) +#define HE_QOS_INFO_Q_ACK ((u8) (BIT(4))) +#define HE_QOS_INFO_QUEUE_REQUEST ((u8) (BIT(5))) +#define HE_QOS_INFO_TXOP_REQUEST ((u8) (BIT(6))) +/* B7: Reserved if sent by an AP; More Data Ack if sent by a non-AP STA */ +#define HE_QOS_INFO_MORE_DATA_ACK ((u8) (BIT(7))) + /* DPP Public Action frame identifiers - OUI_WFA */ #define DPP_OUI_TYPE 0x1A