aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Crispin <john@phrozen.org>2019-05-20 07:55:05 (GMT)
committerJouni Malinen <j@w1.fi>2019-05-27 13:40:48 (GMT)
commit78d35b16de46dfe4f5ae75f7290dfb224a3fad1f (patch)
treefbdf7a781396bab744509fc2b3dfd6a744cb8f39
parent8f5fc369e2638bc83fcf285fa440b56deaab48b1 (diff)
downloadhostap-78d35b16de46dfe4f5ae75f7290dfb224a3fad1f.zip
hostap-78d35b16de46dfe4f5ae75f7290dfb224a3fad1f.tar.gz
hostap-78d35b16de46dfe4f5ae75f7290dfb224a3fad1f.tar.bz2
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>
-rw-r--r--src/ap/ap_drv_ops.c4
-rw-r--r--src/ap/ap_drv_ops.h2
-rw-r--r--src/ap/ieee802_11.c29
-rw-r--r--src/ap/ieee802_11.h6
-rw-r--r--src/ap/ieee802_11_he.c103
-rw-r--r--src/ap/sta_info.c1
-rw-r--r--src/ap/sta_info.h3
-rw-r--r--src/common/ieee802_11_defs.h2
8 files changed, 149 insertions, 1 deletions
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 9d7759d..8bdacf6 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -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);
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 8758ec1..4357cee 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -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);
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 890da7a..f050336 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -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)
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 3699246..914cd1f 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -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,
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index c22427a..066a032 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -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;
+}
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 4f9eae8..98b609c 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -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);
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index c185d7a..9a081cb 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -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;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index dbe832c..e6ffc10 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -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