HE: Add AP mode MLME/SME handling for HE stations
Process HE information in (Re)Association Request frames and add HE elements into (Re)Association Response frames when HE is enabled in the BSS. Signed-off-by: Shashidhar Lakkavalli <slakkavalli@datto.com> Signed-off-by: John Crispin <john@phrozen.org>
This commit is contained in:
parent
8f5fc369e2
commit
78d35b16de
8 changed files with 149 additions and 1 deletions
|
@ -413,6 +413,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
|
|||
u16 listen_interval,
|
||||
const struct ieee80211_ht_capabilities *ht_capab,
|
||||
const struct ieee80211_vht_capabilities *vht_capab,
|
||||
const struct ieee80211_he_capabilities *he_capab,
|
||||
size_t he_capab_len,
|
||||
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
|
||||
int set)
|
||||
{
|
||||
|
@ -432,6 +434,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
|
|||
params.listen_interval = listen_interval;
|
||||
params.ht_capabilities = ht_capab;
|
||||
params.vht_capabilities = vht_capab;
|
||||
params.he_capab = he_capab;
|
||||
params.he_capab_len = he_capab_len;
|
||||
params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
|
||||
params.vht_opmode = vht_opmode;
|
||||
params.flags = hostapd_sta_flags_to_drv(flags);
|
||||
|
|
|
@ -41,6 +41,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
|
|||
u16 listen_interval,
|
||||
const struct ieee80211_ht_capabilities *ht_capab,
|
||||
const struct ieee80211_vht_capabilities *vht_capab,
|
||||
const struct ieee80211_he_capabilities *he_capab,
|
||||
size_t he_capab_len,
|
||||
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
|
||||
int set);
|
||||
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
|
||||
|
|
|
@ -2325,7 +2325,8 @@ static void handle_auth(struct hostapd_data *hapd,
|
|||
WLAN_STA_AUTHORIZED);
|
||||
|
||||
if (hostapd_sta_add(hapd, sta->addr, 0, 0, NULL, 0, 0,
|
||||
NULL, NULL, sta->flags, 0, 0, 0, 0)) {
|
||||
NULL, NULL, NULL, 0,
|
||||
sta->flags, 0, 0, 0, 0)) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_NOTICE,
|
||||
|
@ -2866,6 +2867,14 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
|||
return resp;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
resp = copy_sta_he_capab(hapd, sta, elems.he_capabilities,
|
||||
elems.he_capabilities_len);
|
||||
if (resp != WLAN_STATUS_SUCCESS)
|
||||
return resp;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
if (elems.p2p) {
|
||||
|
@ -3228,6 +3237,7 @@ static int add_associated_sta(struct hostapd_data *hapd,
|
|||
{
|
||||
struct ieee80211_ht_capabilities ht_cap;
|
||||
struct ieee80211_vht_capabilities vht_cap;
|
||||
struct ieee80211_he_capabilities he_cap;
|
||||
int set = 1;
|
||||
|
||||
/*
|
||||
|
@ -3280,6 +3290,12 @@ static int add_associated_sta(struct hostapd_data *hapd,
|
|||
if (sta->flags & WLAN_STA_VHT)
|
||||
hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (sta->flags & WLAN_STA_HE) {
|
||||
hostapd_get_he_capab(hapd, sta->he_capab, &he_cap,
|
||||
sta->he_capab_len);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
/*
|
||||
* Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
|
||||
|
@ -3291,6 +3307,8 @@ static int add_associated_sta(struct hostapd_data *hapd,
|
|||
sta->listen_interval,
|
||||
sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
|
||||
sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
|
||||
sta->flags & WLAN_STA_HE ? &he_cap : NULL,
|
||||
sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
|
||||
sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
|
||||
sta->vht_opmode, sta->p2p_ie ? 1 : 0,
|
||||
set)) {
|
||||
|
@ -3442,6 +3460,15 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
|
|||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
p = hostapd_eid_he_capab(hapd, p);
|
||||
p = hostapd_eid_he_operation(hapd, p);
|
||||
p = hostapd_eid_spatial_reuse(hapd, p);
|
||||
p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
p = hostapd_eid_ext_capab(hapd, p);
|
||||
p = hostapd_eid_bss_max_idle_period(hapd, p);
|
||||
if (sta && sta->qos_map_enabled)
|
||||
|
|
|
@ -71,6 +71,10 @@ void hostapd_get_ht_capab(struct hostapd_data *hapd,
|
|||
void hostapd_get_vht_capab(struct hostapd_data *hapd,
|
||||
struct ieee80211_vht_capabilities *vht_cap,
|
||||
struct ieee80211_vht_capabilities *neg_vht_cap);
|
||||
void hostapd_get_he_capab(struct hostapd_data *hapd,
|
||||
const struct ieee80211_he_capabilities *he_cap,
|
||||
struct ieee80211_he_capabilities *neg_he_cap,
|
||||
size_t he_capab_len);
|
||||
int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *ht_capab);
|
||||
|
@ -86,6 +90,8 @@ u16 copy_sta_vht_oper(struct hostapd_data *hapd, struct sta_info *sta,
|
|||
const u8 *vht_oper);
|
||||
u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *vht_opmode);
|
||||
u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *he_capab, size_t he_capab_len);
|
||||
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
|
||||
const u8 *buf, size_t len, int ack);
|
||||
void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* hostapd / IEEE 802.11ax HE
|
||||
* Copyright (c) 2016-2017, Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2019 John Crispin <john@phrozen.org>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
|
@ -13,6 +14,7 @@
|
|||
#include "hostapd.h"
|
||||
#include "ap_config.h"
|
||||
#include "beacon.h"
|
||||
#include "sta_info.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "dfs.h"
|
||||
|
||||
|
@ -236,3 +238,104 @@ u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid)
|
|||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
void hostapd_get_he_capab(struct hostapd_data *hapd,
|
||||
const struct ieee80211_he_capabilities *he_cap,
|
||||
struct ieee80211_he_capabilities *neg_he_cap,
|
||||
size_t he_capab_len)
|
||||
{
|
||||
if (!he_cap)
|
||||
return;
|
||||
|
||||
if (he_capab_len > sizeof(*neg_he_cap))
|
||||
he_capab_len = sizeof(*neg_he_cap);
|
||||
/* TODO: mask out unsupported features */
|
||||
|
||||
os_memcpy(neg_he_cap, he_cap, he_capab_len);
|
||||
}
|
||||
|
||||
|
||||
static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab)
|
||||
{
|
||||
u16 sta_rx_mcs_set, ap_tx_mcs_set;
|
||||
u8 mcs_count = 0;
|
||||
const u16 *ap_mcs_set, *sta_mcs_set;
|
||||
int i;
|
||||
|
||||
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 capabilities for STAs for which there is not even a single
|
||||
* allowed MCS in any supported number of streams, i.e., STA is
|
||||
* advertising 3 (not supported) as HE MCS rates for all supported
|
||||
* band/stream cases.
|
||||
*/
|
||||
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 < mcs_count; i++) {
|
||||
int j;
|
||||
|
||||
/* AP Tx MCS map vs. STA Rx MCS map */
|
||||
sta_rx_mcs_set = WPA_GET_LE16((const u8 *) &sta_mcs_set[i * 2]);
|
||||
ap_tx_mcs_set = WPA_GET_LE16((const u8 *)
|
||||
&ap_mcs_set[(i * 2) + 1]);
|
||||
|
||||
for (j = 0; j < HE_NSS_MAX_STREAMS; j++) {
|
||||
if (((ap_tx_mcs_set >> (j * 2)) & 0x3) == 3)
|
||||
continue;
|
||||
|
||||
if (((sta_rx_mcs_set >> (j * 2)) & 0x3) == 3)
|
||||
continue;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"No matching HE MCS found between AP TX and STA RX");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *he_capab, size_t he_capab_len)
|
||||
{
|
||||
if (!he_capab || !hapd->iconf->ieee80211ax ||
|
||||
!check_valid_he_mcs(hapd, he_capab) ||
|
||||
he_capab_len > sizeof(struct ieee80211_he_capabilities)) {
|
||||
sta->flags &= ~WLAN_STA_HE;
|
||||
os_free(sta->he_capab);
|
||||
sta->he_capab = NULL;
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (!sta->he_capab) {
|
||||
sta->he_capab =
|
||||
os_zalloc(sizeof(struct ieee80211_he_capabilities));
|
||||
if (!sta->he_capab)
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
}
|
||||
|
||||
sta->flags |= WLAN_STA_HE;
|
||||
os_memset(sta->he_capab, 0, sizeof(struct ieee80211_he_capabilities));
|
||||
os_memcpy(sta->he_capab, he_capab, he_capab_len);
|
||||
sta->he_capab_len = he_capab_len;
|
||||
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -330,6 +330,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
|||
os_free(sta->ht_capabilities);
|
||||
os_free(sta->vht_capabilities);
|
||||
os_free(sta->vht_operation);
|
||||
os_free(sta->he_capab);
|
||||
hostapd_free_psk_list(sta->psk);
|
||||
os_free(sta->identity);
|
||||
os_free(sta->radius_cui);
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#define WLAN_STA_VENDOR_VHT BIT(21)
|
||||
#define WLAN_STA_PENDING_FILS_ERP BIT(22)
|
||||
#define WLAN_STA_MULTI_AP BIT(23)
|
||||
#define WLAN_STA_HE BIT(24)
|
||||
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
|
||||
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
|
||||
#define WLAN_STA_NONERP BIT(31)
|
||||
|
@ -166,6 +167,8 @@ struct sta_info {
|
|||
struct ieee80211_vht_capabilities *vht_capabilities;
|
||||
struct ieee80211_vht_operation *vht_operation;
|
||||
u8 vht_opmode;
|
||||
struct ieee80211_he_capabilities *he_capab;
|
||||
size_t he_capab_len;
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
int sa_query_count; /* number of pending SA Query requests;
|
||||
|
|
|
@ -1280,6 +1280,8 @@ struct ieee80211_ampe_ie {
|
|||
#define CHANWIDTH_160MHZ 2
|
||||
#define CHANWIDTH_80P80MHZ 3
|
||||
|
||||
#define HE_NSS_MAX_STREAMS 8
|
||||
|
||||
#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
|
||||
* 00:50:F2 */
|
||||
#define WPA_IE_VENDOR_TYPE 0x0050f201
|
||||
|
|
Loading…
Reference in a new issue