From a6d1b4c46c202d1cbf1360a6d7be32bca1c00c40 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Tue, 19 Apr 2022 11:04:12 -0700 Subject: [PATCH] EHT: Process (Re)Association Request frame capabilities 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 Signed-off-by: Pradeep Kumar Chitrapu --- src/ap/ieee802_11.c | 11 ++++ src/ap/ieee802_11.h | 4 ++ src/ap/ieee802_11_eht.c | 120 ++++++++++++++++++++++++++++++++++++++++ src/ap/sta_info.c | 1 + src/ap/sta_info.h | 3 + 5 files changed, 139 insertions(+) diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index d4f49330c..f477a0234 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -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) { diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h index 79c76284c..141915cda 100644 --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -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 */ diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c index fe22d4981..c9040c7b0 100644 --- a/src/ap/ieee802_11_eht.c +++ b/src/ap/ieee802_11_eht.c @@ -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; +} diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index c397e60dd..44fac5099 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -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); diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index 27e72f9a0..af8f171b2 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -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 */