The HE Caps beacon has a dynamic size. Mask out the channel width capabilities that are less than the configured. Only add the MCS/NSS sets for the announced channel widths and also add the PPET elements. Signed-off-by: Shashidhar Lakkavalli <slakkavalli@xxxxxxxxx> Signed-off-by: John Crispin <john@xxxxxxxxxxx> --- src/ap/ieee802_11_he.c | 97 +++++++++++++++++++++++++++++------- src/common/ieee802_11_defs.h | 11 +++- src/drivers/driver.h | 2 +- 3 files changed, 90 insertions(+), 20 deletions(-) diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c index f6a9e9f5d..d54b6c6ad 100644 --- a/src/ap/ieee802_11_he.c +++ b/src/ap/ieee802_11_he.c @@ -18,17 +18,66 @@ #include "ieee802_11.h" #include "dfs.h" +static inline u8 +ieee80211_he_ppet_size(u8 ppe_thres_hdr, const u8 *phy_cap_info) +{ + u8 sz = 0, ru; + + if ((phy_cap_info[HE_PHYCAP_PPE_THRESHOLD_PRESENT_IDX] & + HE_PHYCAP_PPE_THRESHOLD_PRESENT_IDX) == 0) + return 0; + + ru = (ppe_thres_hdr >> HE_PPE_THRES_RU_INDEX_BITMASK_SHIFT) & HE_PPE_THRES_RU_INDEX_BITMASK_MASK; + while (ru) { + if (ru & 0x1) + sz++; + ru >>= 1; + } + + sz *= 1 + (ppe_thres_hdr & HE_PPE_THRES_NSS_MASK); + sz = (sz * 6) + 7; + if (sz % 8) + sz += 8; + sz /= 8; + + return sz; +} + u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid) { - struct ieee80211_he_capabilities *cap; + struct ieee80211_he_capabilities *cap = NULL; struct hostapd_hw_modes *mode = hapd->iface->current_mode; + u8 he_oper_chwidth = ~HE_PHYCAP_CHANNEL_WIDTH_MASK; u8 *pos = eid; + u8 ie_size = 0, mcs_nss_size = 0, ppet_size = 0; if (!mode) return eid; + ie_size = sizeof(cap->he_mac_capab_info) + sizeof(cap->he_phy_capab_info); + ppet_size = ieee80211_he_ppet_size(mode->he_capab.ppet[0], mode->he_capab.phy_cap); + + switch (hapd->iface->conf->he_oper_chwidth) { + case CHANWIDTH_80P80MHZ: + he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G; + mcs_nss_size += 4; + /* fall through */ + case CHANWIDTH_160MHZ: + he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G; + mcs_nss_size += 4; + /* fall through */ + case CHANWIDTH_80MHZ: + case CHANWIDTH_USE_HT: + he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G | + HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; + mcs_nss_size += 4; + break; + } + + ie_size += mcs_nss_size + ppet_size; + *pos++ = WLAN_EID_EXTENSION; - *pos++ = 1 + sizeof(struct ieee80211_he_capabilities); + *pos++ = 1 + ie_size; *pos++ = WLAN_EID_EXT_HE_CAPABILITIES; cap = (struct ieee80211_he_capabilities *) pos; @@ -38,8 +87,11 @@ u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid) HE_MAX_MAC_CAPAB_SIZE); os_memcpy(cap->he_phy_capab_info, mode->he_capab.phy_cap, HE_MAX_PHY_CAPAB_SIZE); - os_memcpy(cap->he_txrx_mcs_support, mode->he_capab.mcs, - HE_MAX_MCS_CAPAB_SIZE); + os_memcpy(cap->optional, mode->he_capab.mcs, + mcs_nss_size); + if (ppet_size) + os_memcpy(&cap->optional[mcs_nss_size], mode->he_capab.ppet, + ppet_size); if (hapd->iface->conf->he_phy_capab.he_su_beamformer) cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] |= @@ -53,7 +105,9 @@ u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid) cap->he_phy_capab_info[HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX] |= HE_PHYCAP_MU_BEAMFORMER_CAPAB; - pos += sizeof(*cap); + cap->he_phy_capab_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &= he_oper_chwidth; + + pos += ie_size; return pos; } @@ -204,16 +258,17 @@ void hostapd_get_he_oper(struct hostapd_data *hapd, } -static int check_valid_he_mcs(struct hostapd_hw_modes *mode, - const u8 *sta_he_capab) +static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab) { - const struct ieee80211_he_capabilities *he_cap; - struct ieee80211_he_capabilities ap_he_cap; u16 sta_rx_mcs_set, ap_tx_mcs_set; + u8 mcs_count = 0; + const u16 *ap_mcs_set, *sta_mcs_set; int i; - if (!mode) + if (!hapd->iface->current_mode) return 1; + ap_mcs_set = (u16 *)hapd->iface->current_mode->he_capab.mcs; + sta_mcs_set = (u16*)((const struct ieee80211_he_capabilities *) sta_he_capab)->optional; /* * Disable HE caps for STAs for which there is not even a single @@ -221,16 +276,24 @@ static int check_valid_he_mcs(struct hostapd_hw_modes *mode, * advertising 3 (not supported) as HE MCS rates for all supported * band/stream cases. */ - os_memcpy(&ap_he_cap.he_txrx_mcs_support, mode->he_capab.mcs, - HE_MAX_MCS_CAPAB_SIZE); - he_cap = (const struct ieee80211_he_capabilities *) sta_he_capab; + switch (hapd->iface->conf->he_oper_chwidth) { + case CHANWIDTH_80P80MHZ: + mcs_count = 3; + break; + case CHANWIDTH_160MHZ: + mcs_count = 2; + break; + default: + mcs_count = 1; + break; + } - for (i = 0; i < HE_NSS_MAX_BANDS; i++) { + for (i = 0; i < mcs_count; i++) { int j; /* AP Tx MCS map vs. STA Rx MCS map */ - sta_rx_mcs_set = le_to_host16(he_cap->he_txrx_mcs_support[i * 2]); - ap_tx_mcs_set = le_to_host16(ap_he_cap.he_txrx_mcs_support[(i * 2) + 1]); + sta_rx_mcs_set = le_to_host16(sta_mcs_set[i * 2]); + ap_tx_mcs_set = le_to_host16(ap_mcs_set[(i * 2) + 1]); for (j = 0; j < HE_NSS_MAX_STREAMS; j++) { if ((ap_tx_mcs_set & (0x3 << (j * 2))) == 3) @@ -254,7 +317,7 @@ u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta, const u8 *he_capab, int he_capab_len) { if (!he_capab || !hapd->iconf->ieee80211ax || - !check_valid_he_mcs(hapd->iface->current_mode, he_capab) || + !check_valid_he_mcs(hapd, he_capab) || he_capab_len > sizeof(struct ieee80211_he_capabilities)) { sta->flags &= ~WLAN_STA_HE; os_free(sta->he_capabilities); diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index ed6a9132e..48b7f411d 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -2108,8 +2108,7 @@ enum nr_chan_width { struct ieee80211_he_capabilities { u8 he_mac_capab_info[6]; u8 he_phy_capab_info[11]; - u16 he_txrx_mcs_support[6]; /* TODO: 2, 4, or 6 words */ - u8 he_ppe_threshold[25]; + u8 optional[]; } STRUCT_PACKED; struct ieee80211_he_operation { @@ -2154,6 +2153,14 @@ struct ieee80211_spatial_reuse { #define HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX 4 #define HE_PHYCAP_MU_BEAMFORMER_CAPAB ((u8) BIT(1)) +#define HE_PHYCAP_PPE_THRESHOLD_PRESENT_IDX 6 +#define HE_PHYCAP_PPE_THRESHOLD_PRESENT ((u8) BIT(7)) + +/* HE PPE Threshold define */ +#define HE_PPE_THRES_RU_INDEX_BITMASK_MASK 0xf +#define HE_PPE_THRES_RU_INDEX_BITMASK_SHIFT 3 +#define HE_PPE_THRES_NSS_MASK 0x7 + /* HE Operation defines */ /* HE Operation Parameters and BSS Color Information fields */ #define HE_OPERATION_DFLT_PE_DURATION_MASK ((u32) (BIT(0) | BIT(1) | \ diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 20f583900..ac43dcf17 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -180,7 +180,7 @@ struct he_capabilities { u8 phy_cap[HE_MAX_PHY_CAPAB_SIZE]; u8 mac_cap[HE_MAX_MAC_CAPAB_SIZE]; u8 mcs[HE_MAX_MCS_CAPAB_SIZE]; - struct he_ppe_threshold ppet; + u8 ppet[25]; }; #define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0) -- 2.20.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap