[PATCH V2] HE: add mlme handling for HE stations

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds the HE handling to the assoc request parsing and
response generation.

Signed-off-by: Shashidhar Lakkavalli <slakkavalli@xxxxxxxxx>
Signed-off-by: John Crispin <john@xxxxxxxxxxx>

---
Changes in V2
* fix the comment for the basic NSS rates was wrong
* add SPR IE to assoc responses

 src/ap/ap_drv_ops.c            |   6 ++
 src/ap/ap_drv_ops.h            |   4 ++
 src/ap/ieee802_11.c            |  35 ++++++++++-
 src/ap/ieee802_11.h            |  12 ++++
 src/ap/ieee802_11_he.c         | 130 +++++++++++++++++++++++++++++++++++++++++
 src/ap/sta_info.c              |   2 +
 src/ap/sta_info.h              |   5 ++
 src/common/ieee802_11_common.c |   4 ++
 src/common/ieee802_11_common.h |   2 +
 src/common/ieee802_11_defs.h   |   5 +-
 src/drivers/driver.h           |   4 ++
 src/drivers/driver_nl80211.c   |  10 ++++
 12 files changed, 217 insertions(+), 2 deletions(-)

diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 067cf863e..3628f3b22 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, int he_capab_len,
+		    const struct ieee80211_he_operation *he_oper, int he_oper_len,
 		    u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
 		    int set)
 {
@@ -432,6 +434,10 @@ 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_capabilities = he_capab;
+	params.he_capabilities_len = he_capab_len;
+	params.he_operation = he_oper;
+	params.he_operation_len = he_oper_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 de40171e1..db9653868 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -41,6 +41,10 @@ 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,
+		    int he_capab_len,
+		    const struct ieee80211_he_operation *he_oper,
+		    int he_oper_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 56f6363a3..82917ebea 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, NULL, 0,
+				    sta->flags, 0, 0, 0, 0)) {
 			hostapd_logger(hapd, sta->addr,
 				       HOSTAPD_MODULE_IEEE80211,
 				       HOSTAPD_LEVEL_NOTICE,
@@ -2870,6 +2871,17 @@ 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;
+
+		resp = copy_sta_he_oper(hapd, sta, elems.he_operation, elems.he_operation_len);
+		if (resp != WLAN_STATUS_SUCCESS)
+			return resp;
+	}
+#endif /* CONFIG_IEEE80211N */
 
 #ifdef CONFIG_P2P
 	if (elems.p2p) {
@@ -3232,6 +3244,8 @@ 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;
+	struct ieee80211_he_operation he_oper;
 	int set = 1;
 
 	/*
@@ -3284,6 +3298,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_capabilities, &he_cap, sta->he_capabilities_len);
+		hostapd_get_he_oper(hapd, sta->he_operation, &he_oper, sta->he_operation_len);
+	}
+#endif /* CONFIG_IEEE80211AX */
 
 	/*
 	 * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
@@ -3295,6 +3315,10 @@ 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_capabilities_len : 0,
+			    sta->flags & WLAN_STA_HE ? &he_oper : NULL,
+			    sta->flags & WLAN_STA_HE ? sta->he_operation_len : 0,
 			    sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
 			    sta->vht_opmode, sta->p2p_ie ? 1 : 0,
 			    set)) {
@@ -3435,6 +3459,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_he_mu_edca_parameter_set(hapd, p);
+		p = hostapd_eid_spatial_reuse(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 3699246b3..830d0586f 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -71,6 +71,14 @@ 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,
+			  struct ieee80211_he_capabilities *he_cap,
+			  struct ieee80211_he_capabilities *neg_he_cap,
+			  int he_capab_len);
+void hostapd_get_he_oper(struct hostapd_data *hapd,
+			 struct ieee80211_he_operation *he_oper,
+			 struct ieee80211_he_operation *neg_he_oper,
+			 int he_oper_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 +94,10 @@ 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, int he_capab_len);
+u16 copy_sta_he_oper(struct hostapd_data *hapd, struct sta_info *sta,
+		     const u8 *he_oper, int he_oper_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 72d88b0a2..b32e5aa2f 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@xxxxxxxxxxx>
  *
  * 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"
 
@@ -91,6 +93,10 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
 			(hapd->iface->conf->he_op.he_bss_color <<
 			 HE_OPERATION_BSS_COLOR_OFFSET);
 
+	/* Basic NSS rates. Make no special requirements */
+	oper->he_mcs_nss_set[0] = 0xff;
+	oper->he_mcs_nss_set[1] = 0xff;
+
 	/* TODO: conditional MaxBSSID Indicator subfield */
 
 	pos += oper_size;
@@ -170,3 +176,127 @@ u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid)
 
 	return pos;
 }
+
+void hostapd_get_he_capab(struct hostapd_data *hapd,
+			  struct ieee80211_he_capabilities *he_cap,
+			  struct ieee80211_he_capabilities *neg_he_cap,
+			  int he_capab_len)
+{
+	if (he_cap == NULL)
+		return;
+
+	/* TODO: mask out unsupported features */
+
+	os_memcpy(neg_he_cap, he_cap, he_capab_len);
+}
+
+
+void hostapd_get_he_oper(struct hostapd_data *hapd,
+			 struct ieee80211_he_operation *he_oper,
+			 struct ieee80211_he_operation *neg_he_oper,
+			 int he_oper_len)
+{
+	if (he_oper == NULL)
+		return;
+
+	/* TODO: mask out unsupported features */
+
+	os_memcpy(neg_he_oper, he_oper, he_oper_len);
+}
+
+
+static int check_valid_he_mcs(struct hostapd_hw_modes *mode,
+			      const u8 *sta_he_capab)
+{
+	const struct ieee80211_he_capabilities *he_cap;
+	struct ieee80211_he_capabilities ap_he_cap;
+	u16 sta_rx_mcs_set, ap_tx_mcs_set;
+	int i;
+
+	if (!mode)
+		return 1;
+
+	/*
+	 * Disable HE caps 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.
+	 */
+	os_memcpy(&ap_he_cap.he_txrx_mcs_support, mode->he_capab.mcs,
+		 HE_MAX_MCS_CAPAB_SIZE);
+	he_cap = (const struct ieee80211_he_capabilities *) sta_he_capab;
+
+	for (i = 0; i < HE_NSS_MAX_BANDS; i++) {
+		int j;
+
+		/* AP Tx MCS map vs. STA Rx MCS map */
+		sta_rx_mcs_set = le_to_host16(he_cap->he_txrx_mcs_support[i * 2]);
+		ap_tx_mcs_set = le_to_host16(ap_he_cap.he_txrx_mcs_support[(i * 2) + 1]);
+
+		for (j = 0; j < HE_NSS_MAX_STREAMS; j++) {
+			if ((ap_tx_mcs_set & (0x3 << (j * 2))) == 3)
+				continue;
+
+			if ((sta_rx_mcs_set & (0x3 << (j * 2))) == 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, int he_capab_len)
+{
+	if (!he_capab || !hapd->iconf->ieee80211ax ||
+	    !check_valid_he_mcs(hapd->iface->current_mode, he_capab)) {
+		sta->flags &= ~WLAN_STA_HE;
+		os_free(sta->he_capabilities);
+		sta->he_capabilities = NULL;
+		return WLAN_STATUS_SUCCESS;
+	}
+
+	if (sta->he_capabilities == NULL) {
+		sta->he_capabilities =
+			os_zalloc(sizeof(struct ieee80211_he_capabilities));
+		if (sta->he_capabilities == NULL)
+			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	sta->flags |= WLAN_STA_HE;
+	os_memset(sta->he_capabilities, 0, sizeof(struct ieee80211_he_capabilities));
+	os_memcpy(sta->he_capabilities, he_capab, he_capab_len);
+	sta->he_capabilities_len = he_capab_len;
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+u16 copy_sta_he_oper(struct hostapd_data *hapd, struct sta_info *sta,
+		     const u8 *he_oper, int he_oper_len)
+{
+	if (!he_oper) {
+		os_free(sta->he_operation);
+		sta->he_operation = NULL;
+		return WLAN_STATUS_SUCCESS;
+	}
+
+	if (!sta->he_operation) {
+		sta->he_operation =
+			os_zalloc(sizeof(struct ieee80211_he_operation));
+		if (!sta->he_operation)
+			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	os_memset(sta->he_operation, 0, sizeof(struct ieee80211_he_operation));
+	os_memcpy(sta->he_operation, he_oper, he_oper_len);
+	sta->he_operation_len = he_oper_len;
+
+	return WLAN_STATUS_SUCCESS;
+}
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 4f9eae847..6de858449 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -330,6 +330,8 @@ 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_capabilities);
+	os_free(sta->he_operation);
 	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 ece0c60ab..2d28c2589 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,10 @@ struct sta_info {
 	struct ieee80211_vht_capabilities *vht_capabilities;
 	struct ieee80211_vht_operation *vht_operation;
 	u8 vht_opmode;
+	struct ieee80211_he_capabilities *he_capabilities;
+	int he_capabilities_len;
+	struct ieee80211_he_operation *he_operation;
+	int he_operation_len;
 
 #ifdef CONFIG_IEEE80211W
 	int sa_query_count; /* number of pending SA Query requests;
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index c02b99dbc..4de539935 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -274,6 +274,10 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
 		elems->he_capabilities = pos;
 		elems->he_capabilities_len = elen;
 		break;
+	case WLAN_EID_EXT_HE_OPERATION:
+		elems->he_operation = pos;
+		elems->he_operation_len = elen;
+		break;
 	case WLAN_EID_EXT_OCV_OCI:
 		elems->oci = pos;
 		elems->oci_len = elen;
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 930d45420..9b045b41a 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -94,6 +94,7 @@ struct ieee802_11_elems {
 	const u8 *oci;
 	const u8 *multi_ap;
 	const u8 *he_capabilities;
+	const u8 *he_operation;
 
 	u8 ssid_len;
 	u8 supp_rates_len;
@@ -143,6 +144,7 @@ struct ieee802_11_elems {
 	u8 oci_len;
 	u8 multi_ap_len;
 	u8 he_capabilities_len;
+	u8 he_operation_len;
 
 	struct mb_ies_info mb_ies;
 };
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 90615ece6..54bb35520 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -1280,6 +1280,9 @@ struct ieee80211_ampe_ie {
 #define VHT_CHANWIDTH_160MHZ	2
 #define VHT_CHANWIDTH_80P80MHZ	3
 
+#define HE_NSS_MAX_BANDS			    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
@@ -2105,7 +2108,7 @@ enum nr_chan_width {
 struct ieee80211_he_capabilities {
 	u8 he_mac_capab_info[6];
 	u8 he_phy_capab_info[11];
-	u8 he_txrx_mcs_support[12]; /* TODO: 4, 8, or 12 octets */
+	u16 he_txrx_mcs_support[6]; /* TODO: 2, 4, or 6 words */
 	/* PPE Thresholds (optional) */
 } STRUCT_PACKED;
 
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 0acc0958a..376e65c4d 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1788,6 +1788,10 @@ struct hostapd_sta_add_params {
 	const struct ieee80211_vht_capabilities *vht_capabilities;
 	int vht_opmode_enabled;
 	u8 vht_opmode;
+	const struct ieee80211_he_capabilities *he_capabilities;
+	int he_capabilities_len;
+	const struct ieee80211_he_operation *he_operation;
+	int he_operation_len;
 	u32 flags; /* bitmask of WPA_STA_* flags */
 	u32 flags_mask; /* unset bits in flags */
 #ifdef CONFIG_MESH
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 5da8a793b..94c77b470 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -4563,6 +4563,16 @@ static int wpa_driver_nl80211_sta_add(void *priv,
 				goto fail;
 		}
 
+		if (params->he_capabilities) {
+			wpa_hexdump(MSG_DEBUG, "  * he_capabilities",
+				    (u8 *) params->he_capabilities,
+				    params->he_capabilities_len);
+			if (nla_put(msg, NL80211_ATTR_HE_CAPABILITY,
+				    params->he_capabilities_len,
+				    params->he_capabilities))
+				goto fail;
+		}
+
 		if (params->ext_capab) {
 			wpa_hexdump(MSG_DEBUG, "  * ext_capab",
 				    params->ext_capab, params->ext_capab_len);
-- 
2.11.0


_______________________________________________
Hostap mailing list
Hostap@xxxxxxxxxxxxxxxxxxx
http://lists.infradead.org/mailman/listinfo/hostap



[Index of Archives]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux