]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
EHT: Process (Re)Association Request frame capabilities
authorAloka Dixit <quic_alokad@quicinc.com>
Tue, 19 Apr 2022 18:04:12 +0000 (11:04 -0700)
committerJouni Malinen <j@w1.fi>
Fri, 29 Apr 2022 14:28:40 +0000 (17:28 +0300)
Parse EHT capabilities sent by a non-AP STA in (Re)Association Request
frames. Validate the length of the element, matching MCS rates between
AP TX and STA RX. Store the capabilities in the station info structure.

Signed-off-by: Aloka Dixit <quic_alokad@quicinc.com>
Signed-off-by: Pradeep Kumar Chitrapu <quic_pradeepc@quicinc.com>
src/ap/ieee802_11.c
src/ap/ieee802_11.h
src/ap/ieee802_11_eht.c
src/ap/sta_info.c
src/ap/sta_info.h

index d4f49330c7ddf6063a57157ce2c7f9c454497045..f477a0234338ffb32117adfce93df967a2801525 100644 (file)
@@ -4554,6 +4554,17 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
                }
        }
 #endif /* CONFIG_IEEE80211AX */
+#ifdef CONFIG_IEEE80211BE
+       if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
+               resp = copy_sta_eht_capab(hapd, sta, IEEE80211_MODE_AP,
+                                         elems.he_capabilities,
+                                         elems.he_capabilities_len,
+                                         elems.eht_capabilities,
+                                         elems.eht_capabilities_len);
+               if (resp != WLAN_STATUS_SUCCESS)
+                       return resp;
+       }
+#endif /* CONFIG_IEEE80211BE */
 
 #ifdef CONFIG_P2P
        if (elems.p2p) {
index 79c76284c0c3f10fe4a5bf260a698c9d9b61544b..141915cda0a54596561d0e147a20ae2f6ee61d5a 100644 (file)
@@ -206,5 +206,9 @@ size_t hostapd_eid_eht_capab_len(struct hostapd_data *hapd,
 u8 * hostapd_eid_eht_capab(struct hostapd_data *hapd, u8 *eid,
                           enum ieee80211_op_mode opmode);
 u8 * hostapd_eid_eht_operation(struct hostapd_data *hapd, u8 *eid);
+u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+                      enum ieee80211_op_mode opmode,
+                      const u8 *he_capab, size_t he_capab_len,
+                      const u8 *eht_capab, size_t eht_capab_len);
 
 #endif /* IEEE802_11_H */
index fe22d4981d78a14384209d13155f0461ac29965c..c9040c7b0e655b746a0c89d88c255cbc00f1bbfb 100644 (file)
@@ -9,6 +9,7 @@
 #include "utils/includes.h"
 #include "utils/common.h"
 #include "hostapd.h"
+#include "sta_info.h"
 #include "ieee802_11.h"
 
 
@@ -216,3 +217,122 @@ u8 * hostapd_eid_eht_operation(struct hostapd_data *hapd, u8 *eid)
 
        return pos + 4;
 }
+
+
+static bool check_valid_eht_mcs_nss(struct hostapd_data *hapd, const u8 *ap_mcs,
+                                   const u8 *sta_mcs, u8 mcs_count, u8 map_len)
+{
+       unsigned int i, j;
+
+       for (i = 0; i < mcs_count; i++) {
+               ap_mcs += i * 3;
+               sta_mcs += i * 3;
+
+               for (j = 0; j < map_len; j++) {
+                       if (((ap_mcs[j] >> 4) & 0xFF) == 0)
+                               continue;
+
+                       if ((sta_mcs[j] & 0xFF) == 0)
+                               continue;
+
+                       return true;
+               }
+       }
+
+       wpa_printf(MSG_DEBUG,
+                  "No matching EHT MCS found between AP TX and STA RX");
+       return false;
+}
+
+
+static bool check_valid_eht_mcs(struct hostapd_data *hapd,
+                               const u8 *sta_eht_capab,
+                               enum ieee80211_op_mode opmode)
+{
+       struct hostapd_hw_modes *mode;
+       const struct ieee80211_eht_capabilities *capab;
+       const u8 *ap_mcs, *sta_mcs;
+       u8 mcs_count = 1;
+
+       mode = hapd->iface->current_mode;
+       if (!mode)
+               return true;
+
+       ap_mcs = mode->eht_capab[opmode].mcs;
+       capab = (const struct ieee80211_eht_capabilities *) sta_eht_capab;
+       sta_mcs = capab->optional;
+
+       if (ieee80211_eht_mcs_set_size(mode->he_capab[opmode].phy_cap,
+                                      mode->eht_capab[opmode].phy_cap) ==
+           EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY)
+               return check_valid_eht_mcs_nss(
+                       hapd, ap_mcs, sta_mcs, 1,
+                       EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY);
+
+       switch (hapd->iface->conf->eht_oper_chwidth) {
+       /* TODO: CHANWIDTH_320MHZ */
+       case CHANWIDTH_80P80MHZ:
+       case CHANWIDTH_160MHZ:
+               mcs_count = 2;
+               break;
+       }
+
+       return check_valid_eht_mcs_nss(hapd, ap_mcs, sta_mcs, mcs_count,
+                                      EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS);
+}
+
+
+static bool ieee80211_invalid_eht_cap_size(const u8 *he_cap, const u8 *eht_cap,
+                                          size_t len)
+{
+       const struct ieee80211_he_capabilities *he_capab;
+       struct ieee80211_eht_capabilities *cap;
+       const u8 *he_phy_cap;
+       size_t cap_len;
+
+       he_capab = (const struct ieee80211_he_capabilities *) he_cap;
+       he_phy_cap = he_capab->he_phy_capab_info;
+       cap = (struct ieee80211_eht_capabilities *) eht_cap;
+       cap_len = sizeof(*cap);
+       if (len < cap_len)
+               return true;
+
+       cap_len += ieee80211_eht_mcs_set_size(he_phy_cap, cap->phy_cap);
+       if (len < cap_len)
+               return true;
+
+       cap_len += ieee80211_eht_ppet_size(&eht_cap[cap_len], cap->phy_cap);
+
+       return len < cap_len;
+}
+
+
+u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+                      enum ieee80211_op_mode opmode,
+                      const u8 *he_capab, size_t he_capab_len,
+                      const u8 *eht_capab, size_t eht_capab_len)
+{
+       if (!hapd->iconf->ieee80211be || hapd->conf->disable_11be ||
+           !he_capab || he_capab_len < IEEE80211_HE_CAPAB_MIN_LEN ||
+           !eht_capab ||
+           ieee80211_invalid_eht_cap_size(he_capab, eht_capab,
+                                          eht_capab_len) ||
+           !check_valid_eht_mcs(hapd, eht_capab, opmode)) {
+               sta->flags &= ~WLAN_STA_EHT;
+               os_free(sta->eht_capab);
+               sta->eht_capab = NULL;
+               return WLAN_STATUS_SUCCESS;
+       }
+
+       os_free(sta->eht_capab);
+       sta->eht_capab = os_memdup(eht_capab, eht_capab_len);
+       if (!sta->eht_capab) {
+               sta->eht_capab_len = 0;
+               return WLAN_STATUS_UNSPECIFIED_FAILURE;
+       }
+
+       sta->flags |= WLAN_STA_EHT;
+       sta->eht_capab_len = eht_capab_len;
+
+       return WLAN_STATUS_SUCCESS;
+}
index c397e60ddd7ecfc9d3eac754bc9ef5f3bab4c42e..44fac50995f2fa969a461432264dac42ede66010 100644 (file)
@@ -358,6 +358,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
        os_free(sta->vht_operation);
        os_free(sta->he_capab);
        os_free(sta->he_6ghz_capab);
+       os_free(sta->eht_capab);
        hostapd_free_psk_list(sta->psk);
        os_free(sta->identity);
        os_free(sta->radius_cui);
index 27e72f9a0164813c3f3be5c5ffc4bad75d8c2841..af8f171b2b09b08ff6fbd63d5ed9b7680fdfd312 100644 (file)
@@ -42,6 +42,7 @@
 #define WLAN_STA_HE BIT(24)
 #define WLAN_STA_6GHZ BIT(25)
 #define WLAN_STA_PENDING_PASN_FILS_ERP BIT(26)
+#define WLAN_STA_EHT BIT(27)
 #define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
 #define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
 #define WLAN_STA_NONERP BIT(31)
@@ -213,6 +214,8 @@ struct sta_info {
        struct ieee80211_he_capabilities *he_capab;
        size_t he_capab_len;
        struct ieee80211_he_6ghz_band_cap *he_6ghz_capab;
+       struct ieee80211_eht_capabilities *eht_capab;
+       size_t eht_capab_len;
 
        int sa_query_count; /* number of pending SA Query requests;
                             * 0 = no SA Query in progress */