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 <quic_alokad@quicinc.com> Signed-off-by: Pradeep Kumar Chitrapu <quic_pradeepc@quicinc.com>
This commit is contained in:
parent
340c0e2122
commit
a6d1b4c46c
5 changed files with 139 additions and 0 deletions
|
@ -4554,6 +4554,17 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_IEEE80211AX */
|
#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
|
#ifdef CONFIG_P2P
|
||||||
if (elems.p2p) {
|
if (elems.p2p) {
|
||||||
|
|
|
@ -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,
|
u8 * hostapd_eid_eht_capab(struct hostapd_data *hapd, u8 *eid,
|
||||||
enum ieee80211_op_mode opmode);
|
enum ieee80211_op_mode opmode);
|
||||||
u8 * hostapd_eid_eht_operation(struct hostapd_data *hapd, u8 *eid);
|
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 */
|
#endif /* IEEE802_11_H */
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "utils/includes.h"
|
#include "utils/includes.h"
|
||||||
#include "utils/common.h"
|
#include "utils/common.h"
|
||||||
#include "hostapd.h"
|
#include "hostapd.h"
|
||||||
|
#include "sta_info.h"
|
||||||
#include "ieee802_11.h"
|
#include "ieee802_11.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -216,3 +217,122 @@ u8 * hostapd_eid_eht_operation(struct hostapd_data *hapd, u8 *eid)
|
||||||
|
|
||||||
return pos + 4;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -358,6 +358,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||||
os_free(sta->vht_operation);
|
os_free(sta->vht_operation);
|
||||||
os_free(sta->he_capab);
|
os_free(sta->he_capab);
|
||||||
os_free(sta->he_6ghz_capab);
|
os_free(sta->he_6ghz_capab);
|
||||||
|
os_free(sta->eht_capab);
|
||||||
hostapd_free_psk_list(sta->psk);
|
hostapd_free_psk_list(sta->psk);
|
||||||
os_free(sta->identity);
|
os_free(sta->identity);
|
||||||
os_free(sta->radius_cui);
|
os_free(sta->radius_cui);
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#define WLAN_STA_HE BIT(24)
|
#define WLAN_STA_HE BIT(24)
|
||||||
#define WLAN_STA_6GHZ BIT(25)
|
#define WLAN_STA_6GHZ BIT(25)
|
||||||
#define WLAN_STA_PENDING_PASN_FILS_ERP BIT(26)
|
#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_DISASSOC_CB BIT(29)
|
||||||
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
|
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
|
||||||
#define WLAN_STA_NONERP BIT(31)
|
#define WLAN_STA_NONERP BIT(31)
|
||||||
|
@ -213,6 +214,8 @@ struct sta_info {
|
||||||
struct ieee80211_he_capabilities *he_capab;
|
struct ieee80211_he_capabilities *he_capab;
|
||||||
size_t he_capab_len;
|
size_t he_capab_len;
|
||||||
struct ieee80211_he_6ghz_band_cap *he_6ghz_capab;
|
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;
|
int sa_query_count; /* number of pending SA Query requests;
|
||||||
* 0 = no SA Query in progress */
|
* 0 = no SA Query in progress */
|
||||||
|
|
Loading…
Reference in a new issue