]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
EHT: Use HE operating channel width in MCS length calculation
authorAloka Dixit <quic_alokad@quicinc.com>
Thu, 15 Dec 2022 00:11:41 +0000 (16:11 -0800)
committerJouni Malinen <j@w1.fi>
Thu, 15 Dec 2022 16:41:31 +0000 (18:41 +0200)
Channel width in HE Capabilities element added to management frames is
calculated in hostapd_eid_he_capab() by intersecting the driver
capabilities and the operating channel width. Kernel uses this value
from the Beacon frames to verify EHT capabilities length. However, EHT
MCS length calculation uses only the driver capabilities which results
in EHT AP bring up failure in some cases dues to different lengths.

Modify the EHT code to use the HE operating channel width as well to
determine matching length for the information.

Signed-off-by: Aloka Dixit <quic_alokad@quicinc.com>
src/ap/ieee802_11_eht.c

index ec36a9e7ad3240297c80f040eeadc9121e9725f7..238da2ca8bd238cf1da08046ec172b3ce3440c78 100644 (file)
@@ -42,11 +42,29 @@ static u16 ieee80211_eht_ppet_size(u16 ppe_thres_hdr, const u8 *phy_cap_info)
 
 
 static u8 ieee80211_eht_mcs_set_size(enum hostapd_hw_mode mode, u8 opclass,
-                                    const u8 *he_phy_cap,
+                                    u8 he_oper_chwidth, const u8 *he_phy_cap,
                                     const u8 *eht_phy_cap)
 {
        u8 sz = EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS;
        bool band24, band5, band6;
+       u8 he_phy_cap_chwidth = ~HE_PHYCAP_CHANNEL_WIDTH_MASK;
+
+       switch (he_oper_chwidth) {
+       case CONF_OPER_CHWIDTH_80P80MHZ:
+               he_phy_cap_chwidth |=
+                       HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G;
+               /* fall through */
+       case CONF_OPER_CHWIDTH_160MHZ:
+               he_phy_cap_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
+               /* fall through */
+       case CONF_OPER_CHWIDTH_80MHZ:
+       case CONF_OPER_CHWIDTH_USE_HT:
+               he_phy_cap_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
+                       HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
+               break;
+       }
+
+       he_phy_cap_chwidth &= he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX];
 
        band24 = mode == HOSTAPD_MODE_IEEE80211B ||
                mode == HOSTAPD_MODE_IEEE80211G ||
@@ -56,19 +74,18 @@ static u8 ieee80211_eht_mcs_set_size(enum hostapd_hw_mode mode, u8 opclass,
        band6 = is_6ghz_op_class(opclass);
 
        if (band24 &&
-           (he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
-            HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G) == 0)
+           (he_phy_cap_chwidth & HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G) == 0)
                return EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY;
 
        if (band5 &&
-           (he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+           (he_phy_cap_chwidth &
             (HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
              HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
              HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) == 0)
                return EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY;
 
        if (band5 &&
-           (he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+           (he_phy_cap_chwidth &
             (HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
              HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)))
            sz += EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS;
@@ -98,6 +115,7 @@ size_t hostapd_eid_eht_capab_len(struct hostapd_data *hapd,
                return 0;
 
        len += ieee80211_eht_mcs_set_size(mode->mode, hapd->iconf->op_class,
+                                         hapd->iconf->he_oper_chwidth,
                                          mode->he_capab[opmode].phy_cap,
                                          eht_cap->phy_cap);
        len += ieee80211_eht_ppet_size(WPA_GET_LE16(&eht_cap->ppet[0]),
@@ -152,6 +170,7 @@ u8 * hostapd_eid_eht_capab(struct hostapd_data *hapd, u8 *eid,
 
        mcs_nss_len = ieee80211_eht_mcs_set_size(mode->mode,
                                                 hapd->iconf->op_class,
+                                                hapd->iconf->he_oper_chwidth,
                                                 mode->he_capab[opmode].phy_cap,
                                                 eht_cap->phy_cap);
        if (mcs_nss_len) {
@@ -275,6 +294,7 @@ static bool check_valid_eht_mcs(struct hostapd_data *hapd,
        sta_mcs = capab->optional;
 
        if (ieee80211_eht_mcs_set_size(mode->mode, hapd->iconf->op_class,
+                                      hapd->iconf->he_oper_chwidth,
                                       mode->he_capab[opmode].phy_cap,
                                       mode->eht_capab[opmode].phy_cap) ==
            EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY)
@@ -300,7 +320,7 @@ static bool check_valid_eht_mcs(struct hostapd_data *hapd,
 
 
 static bool ieee80211_invalid_eht_cap_size(enum hostapd_hw_mode mode,
-                                          u8 opclass,
+                                          u8 opclass, u8 he_oper_chwidth,
                                           const u8 *he_cap, const u8 *eht_cap,
                                           size_t len)
 {
@@ -317,8 +337,8 @@ static bool ieee80211_invalid_eht_cap_size(enum hostapd_hw_mode mode,
        if (len < cap_len)
                return true;
 
-       cap_len += ieee80211_eht_mcs_set_size(mode, opclass, he_phy_cap,
-                                             cap->phy_cap);
+       cap_len += ieee80211_eht_mcs_set_size(mode, opclass, he_oper_chwidth,
+                                             he_phy_cap, cap->phy_cap);
        if (len < cap_len)
                return true;
 
@@ -342,6 +362,7 @@ u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta,
            !he_capab || he_capab_len < IEEE80211_HE_CAPAB_MIN_LEN ||
            !eht_capab ||
            ieee80211_invalid_eht_cap_size(mode, hapd->iconf->op_class,
+                                          hapd->iconf->he_oper_chwidth,
                                           he_capab, eht_capab,
                                           eht_capab_len) ||
            !check_valid_eht_mcs(hapd, eht_capab, opmode)) {