[PATCH V4 7/8] HE: various beacon fixes

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

 



The HE Caps beacon has a dynamic size. Mask out the channel width capabilities
that are less than the configured. Only add the MCS/NSS sets for the announced
channel widths and also add the PPET elements.

Signed-off-by: Shashidhar Lakkavalli <slakkavalli@xxxxxxxxx>
Signed-off-by: John Crispin <john@xxxxxxxxxxx>
---
 src/ap/ieee802_11_he.c       | 97 +++++++++++++++++++++++++++++-------
 src/common/ieee802_11_defs.h | 11 +++-
 src/drivers/driver.h         |  2 +-
 3 files changed, 90 insertions(+), 20 deletions(-)

diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index f6a9e9f5d..d54b6c6ad 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -18,17 +18,66 @@
 #include "ieee802_11.h"
 #include "dfs.h"
 
+static inline u8
+ieee80211_he_ppet_size(u8 ppe_thres_hdr, const u8 *phy_cap_info)
+{
+	u8 sz = 0, ru;
+
+	if ((phy_cap_info[HE_PHYCAP_PPE_THRESHOLD_PRESENT_IDX] &
+	     HE_PHYCAP_PPE_THRESHOLD_PRESENT_IDX) == 0)
+		return 0;
+
+	ru = (ppe_thres_hdr >> HE_PPE_THRES_RU_INDEX_BITMASK_SHIFT) & HE_PPE_THRES_RU_INDEX_BITMASK_MASK;
+	while (ru) {
+		if (ru & 0x1)
+			sz++;
+		ru >>= 1;
+	}
+
+	sz *= 1 + (ppe_thres_hdr & HE_PPE_THRES_NSS_MASK);
+	sz = (sz * 6) + 7;
+	if (sz % 8)
+		sz += 8;
+	sz /= 8;
+
+	return sz;
+}
+
 u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid)
 {
-	struct ieee80211_he_capabilities *cap;
+	struct ieee80211_he_capabilities *cap = NULL;
 	struct hostapd_hw_modes *mode = hapd->iface->current_mode;
+	u8 he_oper_chwidth = ~HE_PHYCAP_CHANNEL_WIDTH_MASK;
 	u8 *pos = eid;
+	u8 ie_size = 0, mcs_nss_size = 0, ppet_size = 0;
 
 	if (!mode)
 		return eid;
 
+	ie_size = sizeof(cap->he_mac_capab_info) + sizeof(cap->he_phy_capab_info);
+	ppet_size = ieee80211_he_ppet_size(mode->he_capab.ppet[0], mode->he_capab.phy_cap);
+
+	switch (hapd->iface->conf->he_oper_chwidth) {
+	case CHANWIDTH_80P80MHZ:
+		he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G;
+		mcs_nss_size += 4;
+		/* fall through */
+	case CHANWIDTH_160MHZ:
+		he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
+		mcs_nss_size += 4;
+		/* fall through */
+	case CHANWIDTH_80MHZ:
+	case CHANWIDTH_USE_HT:
+		he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
+				   HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
+		mcs_nss_size += 4;
+		break;
+	}
+
+	ie_size += mcs_nss_size + ppet_size;
+
 	*pos++ = WLAN_EID_EXTENSION;
-	*pos++ = 1 + sizeof(struct ieee80211_he_capabilities);
+	*pos++ = 1 + ie_size;
 	*pos++ = WLAN_EID_EXT_HE_CAPABILITIES;
 
 	cap = (struct ieee80211_he_capabilities *) pos;
@@ -38,8 +87,11 @@ u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid)
 		  HE_MAX_MAC_CAPAB_SIZE);
 	os_memcpy(cap->he_phy_capab_info, mode->he_capab.phy_cap,
 		  HE_MAX_PHY_CAPAB_SIZE);
-	os_memcpy(cap->he_txrx_mcs_support, mode->he_capab.mcs,
-		  HE_MAX_MCS_CAPAB_SIZE);
+	os_memcpy(cap->optional, mode->he_capab.mcs,
+		  mcs_nss_size);
+	if (ppet_size)
+		os_memcpy(&cap->optional[mcs_nss_size], mode->he_capab.ppet,
+			  ppet_size);
 
 	if (hapd->iface->conf->he_phy_capab.he_su_beamformer)
 		cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] |=
@@ -53,7 +105,9 @@ u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid)
 		cap->he_phy_capab_info[HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX] |=
 			HE_PHYCAP_MU_BEAMFORMER_CAPAB;
 
-	pos += sizeof(*cap);
+	cap->he_phy_capab_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &= he_oper_chwidth;
+
+	pos += ie_size;
 
 	return pos;
 }
@@ -204,16 +258,17 @@ void hostapd_get_he_oper(struct hostapd_data *hapd,
 }
 
 
-static int check_valid_he_mcs(struct hostapd_hw_modes *mode,
-			      const u8 *sta_he_capab)
+static int check_valid_he_mcs(struct hostapd_data *hapd, 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;
+	u8 mcs_count = 0;
+	const u16 *ap_mcs_set, *sta_mcs_set;
 	int i;
 
-	if (!mode)
+	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 caps for STAs for which there is not even a single
@@ -221,16 +276,24 @@ static int check_valid_he_mcs(struct hostapd_hw_modes *mode,
 	 * 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;
+	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 < HE_NSS_MAX_BANDS; i++) {
+	for (i = 0; i < mcs_count; 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]);
+		sta_rx_mcs_set = le_to_host16(sta_mcs_set[i * 2]);
+		ap_tx_mcs_set = le_to_host16(ap_mcs_set[(i * 2) + 1]);
 
 		for (j = 0; j < HE_NSS_MAX_STREAMS; j++) {
 			if ((ap_tx_mcs_set & (0x3 << (j * 2))) == 3)
@@ -254,7 +317,7 @@ 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) ||
+	    !check_valid_he_mcs(hapd, he_capab) ||
 	    he_capab_len > sizeof(struct ieee80211_he_capabilities)) {
 		sta->flags &= ~WLAN_STA_HE;
 		os_free(sta->he_capabilities);
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index ed6a9132e..48b7f411d 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -2108,8 +2108,7 @@ enum nr_chan_width {
 struct ieee80211_he_capabilities {
 	u8 he_mac_capab_info[6];
 	u8 he_phy_capab_info[11];
-	u16 he_txrx_mcs_support[6]; /* TODO: 2, 4, or 6 words */
-	u8 he_ppe_threshold[25];
+	u8 optional[];
 } STRUCT_PACKED;
 
 struct ieee80211_he_operation {
@@ -2154,6 +2153,14 @@ struct ieee80211_spatial_reuse {
 #define HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX	4
 #define HE_PHYCAP_MU_BEAMFORMER_CAPAB		((u8) BIT(1))
 
+#define HE_PHYCAP_PPE_THRESHOLD_PRESENT_IDX	6
+#define HE_PHYCAP_PPE_THRESHOLD_PRESENT		((u8) BIT(7))
+
+/* HE PPE Threshold define */
+#define HE_PPE_THRES_RU_INDEX_BITMASK_MASK	0xf
+#define HE_PPE_THRES_RU_INDEX_BITMASK_SHIFT	3
+#define HE_PPE_THRES_NSS_MASK			0x7
+
 /* HE Operation defines */
 /* HE Operation Parameters and BSS Color Information fields */
 #define HE_OPERATION_DFLT_PE_DURATION_MASK	((u32) (BIT(0) | BIT(1) | \
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 20f583900..ac43dcf17 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -180,7 +180,7 @@ struct he_capabilities {
 	u8 phy_cap[HE_MAX_PHY_CAPAB_SIZE];
 	u8 mac_cap[HE_MAX_MAC_CAPAB_SIZE];
 	u8 mcs[HE_MAX_MCS_CAPAB_SIZE];
-	struct he_ppe_threshold ppet;
+	u8 ppet[25];
 };
 
 #define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
-- 
2.20.1


_______________________________________________
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