2021-12-22 09:05:40

by Veerendranath Jakkam

[permalink] [raw]
Subject: [PATCH 0/6] cfg80211/nl80211: add support for EHT

This patch series adds support for EHT and 320 MHz channel width in
cfg80211 and also add userspace API to send rate information out,
conforming with P802.11be_D1.3.

Jia Ding (1):
cfg80211: Add support for EHT 320 MHz channel width

Sriram R (1):
nl80211: add support for 320MHz channel limitation

Veerendranath Jakkam (1):
nl80211: add EHT MCS support

Vikram Kandukuri (3):
ieee80211: add EHT capabilities element definitions
nl80211: add support to advertise driver's EHT capabilities
nl80211: add support to send EHT capabilities from userspace

include/linux/ieee80211.h | 702 +++++++++++++++++++++++++++++++++++++++++++
include/net/cfg80211.h | 79 +++++
include/uapi/linux/nl80211.h | 89 ++++++
net/wireless/chan.c | 91 +++++-
net/wireless/nl80211.c | 67 ++++-
net/wireless/reg.c | 6 +
net/wireless/util.c | 131 ++++++++
7 files changed, 1155 insertions(+), 10 deletions(-)

--
2.7.4



2021-12-22 09:05:42

by Veerendranath Jakkam

[permalink] [raw]
Subject: [PATCH 1/6] ieee80211: add EHT capabilities element definitions

From: Vikram Kandukuri <[email protected]>

Add definitions from P802.11be_D1.3, Section 9.4.2.313 EHT Capabilities
element and related helper functions.

Signed-off-by: Vikram Kandukuri <[email protected]>
Co-authored-by: Aloka Dixit <[email protected]>
Signed-off-by: Aloka Dixit <[email protected]>
Co-authored-by: Veerendranath Jakkam <[email protected]>
Signed-off-by: Veerendranath Jakkam <[email protected]>
---
include/linux/ieee80211.h | 702 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 702 insertions(+)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 559b6c6..5137e7d 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -20,6 +20,7 @@
#include <linux/etherdevice.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
+#include <linux/bitfield.h>

/*
* DS bit usage
@@ -2606,6 +2607,706 @@ ieee80211_he_spr_size(const u8 *he_spr_ie)
#define IEEE80211_MAX_USF FIELD_MAX(LISTEN_INT_USF)
#define IEEE80211_MAX_UI FIELD_MAX(LISTEN_INT_UI)

+/**
+ * struct ieee80211_eht_cap_elem - EHT capabilities element
+ *
+ * @mac_cap_info: EHT MAC Capabilities Information
+ * @phy_cap_info: EHT PHY Capabilities Information
+ *
+ * This structure represents the "EHT capabilities element" fixed fields as
+ * described in P802.11be_D1.3 section 9.4.2.313.2 and 9.4.2.313.3.
+ */
+struct ieee80211_eht_cap_elem {
+ u8 mac_cap_info[2];
+ u8 phy_cap_info[8];
+} __packed;
+
+/* 802.11be EHT MAC capabilities from P802.11be_D1.3, section 9.4.2.313.2 */
+#define IEEE80211_EHT_MAC_CAP0_NSEP_PRIORITY_ACCESS BIT(0)
+#define IEEE80211_EHT_MAC_CAP0_EHT_OM_CONTROL BIT(1)
+#define IEEE80211_EHT_MAC_CAP0_TXOP_SHARING_MODE1 BIT(2)
+#define IEEE80211_EHT_MAC_CAP0_TXOP_SHARING_MODE2 BIT(3)
+#define IEEE80211_EHT_MAC_CAP0_RESTRICTED_TWT BIT(4)
+#define IEEE80211_EHT_MAC_CAP0_SCS_TRAFFIC_DESC BIT(5)
+
+#define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN GENMASK(7, 6)
+
+/**
+ * enum ieee80211_eht_max_mpdu_len - maximum MPDU length that STA is capable of
+ * receiving
+ * @EHT_MAX_MPDU_LEN_3895: maximum 3895 octets supported
+ * @EHT_MAX_MPDU_LEN_7991: maximum 7991 octets supported
+ * @EHT_MAX_MPDU_LEN_11454: maximum 11454 octets supported
+ */
+enum ieee80211_eht_max_mpdu_len {
+ EHT_MAX_MPDU_LEN_3895 = 0,
+ EHT_MAX_MPDU_LEN_7991,
+ EHT_MAX_MPDU_LEN_11454,
+};
+
+/**
+ * ieee80211_eht_set_max_mpdu_len - set maximum MPDU length that STA is capable
+ * of receiving
+ *
+ * @mac_cap_info: EHT MAC capabilities information field data
+ * @max_len: maximum MPDU length supported, see &enum ieee80211_eht_max_mpdu_len
+ *
+ * Set "Maximum MPDU Length" subfield as encoded in "EHT MAC Capabilities
+ * Information" field in EHT Capabilities element
+ */
+static inline void
+ieee80211_eht_set_max_mpdu_len(u8 *mac_cap_info,
+ enum ieee80211_eht_max_mpdu_len max_len)
+{
+ mac_cap_info[0] |= FIELD_PREP(IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN,
+ max_len);
+}
+
+/**
+ * ieee80211_eht_get_max_mpdu_len - get maximum MPDU length that STA is capable
+ * of receiving
+ *
+ * @mac_cap_info: EHT MAC capabilities information field data
+ *
+ * Get "Maximum MPDU Length" subfield value from "EHT MAC Capabilities
+ * Information" field in EHT Capabilities element
+ *
+ * Return: maximum MPDU length supported, see &enum ieee80211_eht_max_mpdu_len
+ */
+static inline enum ieee80211_eht_max_mpdu_len
+ieee80211_eht_get_max_mpdu_len(const u8 *mac_cap_info)
+{
+ return FIELD_GET(IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN, mac_cap_info[0]);
+}
+
+/* 802.11be EHT PHY capabilities from P802.11be_D1.3, section 9.4.2.313.3 */
+#define IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ BIT(1)
+#define IEEE80211_EHT_PHY_CAP0_NON_AP_20MHZ_ONLY_STA_242_RU_SUPPORT BIT(2)
+#define IEEE80211_EHT_PHY_CAP0_NDP_4x_LTF_AND_3_2US BIT(3)
+#define IEEE80211_EHT_PHY_CAP0_PARTIAL_BANDWIDTH_UL_MUMIMO BIT(4)
+#define IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER BIT(5)
+#define IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE BIT(6)
+
+/* Beamformee SS for under 80MHz is split between byte #1 and byte #2 */
+#define IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_MAX_STS_UPTO_80MHZ GENMASK(7, 7)
+#define IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_MAX_STS_UPTO_80MHZ GENMASK(1, 0)
+#define IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_MAX_STS_160MHZ GENMASK(4, 2)
+#define IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_MAX_STS_320MHZ GENMASK(7, 5)
+
+#define IEEE80211_EHT_PHY_CAP2_BEAMFORMER_NUM_SND_DIM_UPTO_80MHZ \
+ GENMASK(2, 0)
+#define IEEE80211_EHT_PHY_CAP2_BEAMFORMER_NUM_SND_DIM_160MHZ GENMASK(5, 3)
+
+/*
+ * Number of sounding dimensions supported for 320MHz is split
+ * between byte #2 and byte #3
+ */
+#define IEEE80211_EHT_PHY_CAP2_BEAMFORMER_NUM_SND_DIM_320MHZ GENMASK(7, 6)
+#define IEEE80211_EHT_PHY_CAP3_BEAMFORMER_NUM_SND_DIM_320MHZ GENMASK(0, 0)
+
+#define IEEE80211_EHT_PHY_CAP3_NG16_SU_FEEDBACK BIT(1)
+#define IEEE80211_EHT_PHY_CAP3_NG16_MU_FEEDBACK BIT(2)
+
+#define IEEE80211_EHT_PHY_CAP3_CODEBOOK_SIZE_42_SU BIT(3)
+#define IEEE80211_EHT_PHY_CAP3_CODEBOOK_SIZE_75_MU BIT(4)
+
+#define IEEE80211_EHT_PHY_CAP3_TRIG_SU_BEAMFORMER_FB BIT(5)
+#define IEEE80211_EHT_PHY_CAP3_TRIG_MU_BEAMFORMER_FB BIT(6)
+#define IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FB BIT(7)
+
+#define IEEE80211_EHT_PHY_CAP4_PARTIAL_BANDWIDTH_DL_MUMIMO BIT(0)
+#define IEEE80211_EHT_PHY_CAP4_PSR_BASED_SR BIT(1)
+#define IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACTOR_AR BIT(2)
+#define IEEE80211_EHT_PHY_CAP4_MU_PPDU_4XLTF_AND_08_US_GI BIT(3)
+
+#define IEEE80211_EHT_PHY_CAP4_MAX_NC GENMASK(7, 4)
+
+#define IEEE80211_EHT_PHY_CAP5_NON_TRIGGERED_CQI_FEEDBACK BIT(0)
+#define IEEE80211_EHT_PHY_CAP5_TX_1024_4096_QAM_LESS_THAN_242_TONE_RU BIT(1)
+#define IEEE80211_EHT_PHY_CAP5_RX_1024_4096_QAM_LESS_THAN_242_TONE_RU BIT(2)
+#define IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT BIT(3)
+
+#define IEEE80211_EHT_PHY_CAP5_NOMINAL_PKT_PADDING GENMASK(5, 4)
+
+/* Maximum Number Of Supported EHT-LTFs is split between byte 5 and byte 6 */
+#define IEEE80211_EHT_PHY_CAP5_MAX_EHT_LTF_SUPP BIT(6)
+#define IEEE80211_EHT_PHY_CAP5_MAX_EHT_LTF_SUPP_SU GENMASK(7, 7)
+#define IEEE80211_EHT_PHY_CAP6_MAX_EHT_LTF_SUPP_SU_RESERVED GENMASK(0, 0)
+#define IEEE80211_EHT_PHY_CAP6_MAX_EHT_LTF_SUPP_MU GENMASK(2, 1)
+
+#define IEEE80211_EHT_PHY_CAP6_MCS15_52_26_TONE_106_26_TONE_SUPP BIT(3)
+#define IEEE80211_EHT_PHY_CAP6_MCS15_484_242_TONE_80MHZ_SUPP BIT(4)
+#define IEEE80211_EHT_PHY_CAP6_MCS15_996_484_TONE_160MHZ_SUPP BIT(5)
+#define IEEE80211_EHT_PHY_CAP6_MCS15_3X996_TONE_320MHZ_SUPP BIT(6)
+#define IEEE80211_EHT_PHY_CAP6_EHT_DUP_SUPP_6GHZ BIT(7)
+
+#define IEEE80211_EHT_PHY_CAP7_20MHZ_STA_NDP_WIDE_BW_SUPP BIT(0)
+#define IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_UNDER_80MHZ BIT(1)
+#define IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ BIT(2)
+#define IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ BIT(3)
+#define IEEE80211_EHT_PHY_CAP7_NON_OFDMA_MU_BEAMFORMER_UNDER_80MHZ BIT(4)
+#define IEEE80211_EHT_PHY_CAP7_NON_OFDMA_MU_BEAMFORMER_160MHZ BIT(5)
+#define IEEE80211_EHT_PHY_CAP7_NON_OFDMA_MU_BEAMFORMER_320MHZ BIT(6)
+#define IEEE80211_EHT_PHY_CAP7_TB_SND_FB_RATE_LIMIT BIT(7)
+
+/**
+ * enum ieee80211_eht_beamformee_max_sts - maximum number of spatial streams
+ * that the STA is capable of receiving in an EHT sounding NDP. Minimal
+ * allowed spatial streams is 4.
+ * @EHT_BEAMFORMEE_MAX_STS_4: 4 spatial streams supported
+ * @EHT_BEAMFORMEE_MAX_STS_5: 5 spatial streams supported
+ * @EHT_BEAMFORMEE_MAX_STS_6: 6 spatial streams supported
+ * @EHT_BEAMFORMEE_MAX_STS_7: 7 spatial streams supported
+ * @EHT_BEAMFORMEE_MAX_STS_8: 8 spatial streams supported
+ */
+enum ieee80211_eht_beamformee_max_sts {
+ EHT_BEAMFORMEE_MAX_STS_4 = 3,
+ EHT_BEAMFORMEE_MAX_STS_5 = 4,
+ EHT_BEAMFORMEE_MAX_STS_6 = 5,
+ EHT_BEAMFORMEE_MAX_STS_7 = 6,
+ EHT_BEAMFORMEE_MAX_STS_8 = 7,
+};
+
+/**
+ * ieee80211_eht_beamformee_set_max_sts_upto_80mhz - set maximum number of
+ * spatial streams that the STA is capable of receiving in an EHT sounding
+ * NDP for bandwidths upto 80 MHz
+ *
+ * @phy_cap_info: EHT PHY capabilities information field data
+ * @max_sts: maximum number of spatial streams supported, see &enum
+ * ieee80211_eht_beamformee_max_sts
+ *
+ * Set "Beamformee SS upto 80 MHz" subfield as encoded in "EHT PHY Capabilities
+ * Information" field in EHT Capabilities element
+ */
+static inline void
+ieee80211_eht_beamformee_set_max_sts_upto_80mhz(
+ u8 *phy_cap_info,
+ enum ieee80211_eht_beamformee_max_sts max_sts)
+{
+ phy_cap_info[0] |=
+ FIELD_PREP(IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_MAX_STS_UPTO_80MHZ,
+ max_sts);
+
+ phy_cap_info[1] |=
+ FIELD_PREP(IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_MAX_STS_UPTO_80MHZ,
+ max_sts >> 1);
+}
+
+/**
+ * ieee80211_eht_beamformee_get_max_sts_upto_80mhz - get maximum number of
+ * spatial streams that the STA is capable of receiving in an EHT sounding
+ * NDP for bandwidths upto 80 MHz
+ *
+ * @phy_cap_info: EHT PHY capabilities information field data
+ *
+ * Get "Beamformee SS upto 80 MHz" subfield value from "EHT PHY Capabilities
+ * Information" field in EHT Capabilities element
+ *
+ * Return: maximum number of spatial streams supported, see &enum
+ * ieee80211_eht_beamformee_max_sts
+ */
+static inline enum ieee80211_eht_beamformee_max_sts
+ieee80211_eht_beamformee_get_max_sts_upto_80mhz(const u8 *phy_cap_info)
+{
+
+ u8 max_sts = FIELD_GET(
+ IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_MAX_STS_UPTO_80MHZ,
+ phy_cap_info[0]);
+
+ max_sts += FIELD_GET(
+ IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_MAX_STS_UPTO_80MHZ,
+ phy_cap_info[1]) << 1;
+
+ return max_sts;
+}
+
+/**
+ * ieee80211_eht_beamformee_set_max_sts_160mhz - set maximum number of spatial
+ * streams that the STA is capable of receiving in an EHT sounding NDP for
+ * bandwidth 160 MHz
+ *
+ * @phy_cap_info: EHT PHY capabilities information field data
+ * @max_sts: maximum number of spatial streams supported, see &enum
+ * ieee80211_eht_beamformee_max_sts
+ *
+ * Set "Beamformee SS for 160 MHz" subfield as encoded in "EHT PHY Capabilities
+ * Information" field in EHT Capabilities element
+ */
+static inline void
+ieee80211_eht_beamformee_set_max_sts_160mhz(
+ u8 *phy_cap_info,
+ enum ieee80211_eht_beamformee_max_sts max_sts)
+{
+ phy_cap_info[1] |=
+ FIELD_PREP(IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_MAX_STS_160MHZ, max_sts);
+}
+
+/**
+ * ieee80211_eht_beamformee_get_max_sts_160mhz - get maximum number of spatial
+ * streams that the STA is capable of receiving in an EHT sounding NDP for
+ * bandwidth 160 MHz
+ *
+ * @phy_cap_info: EHT PHY capabilities information field data
+ *
+ * Get "Beamformee SS for 160 MHz" subfield value from "EHT PHY Capabilities
+ * Information" field in EHT Capabilities element
+ *
+ * Return: maximum number of spatial streams supported, see &enum
+ * ieee80211_eht_beamformee_max_sts
+ */
+static inline enum ieee80211_eht_beamformee_max_sts
+ieee80211_eht_beamformee_get_max_sts_160mhz(const u8 *phy_cap_info)
+{
+
+ return FIELD_GET(IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_MAX_STS_160MHZ,
+ phy_cap_info[1]);
+}
+
+/**
+ * ieee80211_eht_beamformee_set_max_sts_320mhz - set maximum number of spatial
+ * streams that the STA is capable of receiving in an EHT sounding NDP for
+ * bandwidth 320 MHz
+ *
+ * @phy_cap_info: EHT PHY capabilities information field data
+ * @max_sts: maximum number of spatial streams supported, see &enum
+ * ieee80211_eht_beamformee_max_sts
+ *
+ * Set "Beamformee SS for 320 MHz" subfield as encoded in "EHT PHY Capabilities
+ * Information" field in EHT Capabilities element
+ */
+static inline void
+ieee80211_eht_beamformee_set_max_sts_320mhz(
+ u8 *phy_cap_info,
+ enum ieee80211_eht_beamformee_max_sts max_sts)
+{
+ phy_cap_info[1] |=
+ FIELD_PREP(IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_MAX_STS_320MHZ, max_sts);
+}
+
+/**
+ * ieee80211_eht_beamformee_get_max_sts_320mhz - get maximum number of spatial
+ * streams that the STA is capable of receiving in an EHT sounding NDP for
+ * bandwidth 320 MHz
+ *
+ * @phy_cap_info: EHT PHY capabilities information field data
+ *
+ * Get "Beamformee SS for 320 MHz" subfield value from "EHT PHY Capabilities
+ * Information" field in EHT Capabilities element
+ *
+ * Return: maximum number of spatial streams supported, see &enum
+ * ieee80211_eht_beamformee_max_sts
+ */
+static inline enum ieee80211_eht_beamformee_max_sts
+ieee80211_eht_beamformee_get_max_sts_320mhz(const u8 *phy_cap_info)
+{
+
+ return FIELD_GET(IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_MAX_STS_320MHZ,
+ phy_cap_info[1]);
+}
+
+/**
+ * enum ieee80211_eht_beamformer_snd_dim - Beamformer number of supported
+ * sounding dimensions
+ * @EHT_BEAMFORMER_SND_DIM_1: 1 sounding dimension supported
+ * @EHT_BEAMFORMER_SND_DIM_2: 2 sounding dimensions supported
+ * @EHT_BEAMFORMER_SND_DIM_3: 3 sounding dimensions supported
+ * @EHT_BEAMFORMER_SND_DIM_4: 4 sounding dimensions supported
+ * @EHT_BEAMFORMER_SND_DIM_5: 5 sounding dimensions supported
+ * @EHT_BEAMFORMER_SND_DIM_6: 6 sounding dimensions supported
+ * @EHT_BEAMFORMER_SND_DIM_7: 7 sounding dimensions supported
+ * @EHT_BEAMFORMER_SND_DIM_8: 8 sounding dimensions supported
+ */
+enum ieee80211_eht_beamformer_snd_dim {
+ EHT_BEAMFORMER_SND_DIM_1 = 0,
+ EHT_BEAMFORMER_SND_DIM_2,
+ EHT_BEAMFORMER_SND_DIM_3,
+ EHT_BEAMFORMER_SND_DIM_4,
+ EHT_BEAMFORMER_SND_DIM_5,
+ EHT_BEAMFORMER_SND_DIM_6,
+ EHT_BEAMFORMER_SND_DIM_7,
+ EHT_BEAMFORMER_SND_DIM_8,
+};
+
+/**
+ * ieee80211_eht_set_snd_dim_upto_80mhz - set number of sounding dimensions
+ * supported upto 80 MHz
+ *
+ * @phy_cap_info: EHT PHY capabilities information field data
+ * @num_snd_dim: number of sounding dimensions supported, see &enum
+ * ieee80211_eht_beamformer_snd_dim
+ *
+ * Set "Number Of Sounding Dimensions for upto 80 MHz" subfield as encoded in
+ * "EHT PHY Capabilities Information" field in EHT Capabilities element
+ */
+static inline void
+ieee80211_eht_set_snd_dim_upto_80mhz(
+ u8 *phy_cap_info,
+ enum ieee80211_eht_beamformer_snd_dim num_snd_dim)
+{
+ phy_cap_info[2] |=
+ FIELD_PREP(IEEE80211_EHT_PHY_CAP2_BEAMFORMER_NUM_SND_DIM_UPTO_80MHZ,
+ num_snd_dim);
+}
+
+/**
+ * ieee80211_eht_get_snd_dim_upto_80mhz - get number of sounding dimensions
+ * supported upto 80 MHz
+ *
+ * @phy_cap_info: EHT PHY capabilities information field data
+ *
+ * Get "Number Of Sounding Dimensions upto 80 MHz" subfield value from "EHT PHY
+ * Capabilities Information" field in EHT Capabilities element
+ *
+ * Return: number of sounding dimensions supported, see &enum
+ * ieee80211_eht_beamformer_snd_dim
+ */
+static inline enum ieee80211_eht_beamformer_snd_dim
+ieee80211_eht_get_snd_dim_upto_80mhz(const u8 *phy_cap_info)
+{
+ return FIELD_GET(
+ IEEE80211_EHT_PHY_CAP2_BEAMFORMER_NUM_SND_DIM_UPTO_80MHZ,
+ phy_cap_info[2]);
+}
+
+/**
+ * ieee80211_eht_set_snd_dim_160mhz - set number of sounding dimensions
+ * supported upto 160 MHz
+ *
+ * @phy_cap_info: EHT PHY capabilities information field data
+ * @num_snd_dim: number of sounding dimensions supported, see &enum
+ * ieee80211_eht_beamformer_snd_dim
+ *
+ * Set "Number Of Sounding Dimensions for 160 MHz" subfield as encoded in "EHT
+ * PHY Capabilities Information" field in EHT Capabilities element
+ */
+static inline void
+ieee80211_eht_set_snd_dim_160mhz(
+ u8 *phy_cap_info,
+ enum ieee80211_eht_beamformer_snd_dim num_snd_dim)
+{
+ phy_cap_info[2] |=
+ FIELD_PREP(IEEE80211_EHT_PHY_CAP2_BEAMFORMER_NUM_SND_DIM_160MHZ,
+ num_snd_dim);
+}
+
+/**
+ * ieee80211_eht_get_snd_dim_160mhz - get number of sounding dimensions
+ * supported for 160 MHz
+ *
+ * @phy_cap_info: EHT PHY capabilities information field data
+ *
+ * Get "Number Of Sounding Dimensions for 160 MHz" subfield value from "EHT PHY
+ * Capabilities Information" field in EHT Capabilities element
+ *
+ * Return: number of sounding dimensions supported, see &enum
+ * ieee80211_eht_beamformer_snd_dim
+ */
+static inline enum ieee80211_eht_beamformer_snd_dim
+ieee80211_eht_get_snd_dim_160mhz(const u8 *phy_cap_info)
+{
+ return FIELD_GET(
+ IEEE80211_EHT_PHY_CAP2_BEAMFORMER_NUM_SND_DIM_160MHZ,
+ phy_cap_info[2]);
+}
+
+/**
+ * ieee80211_eht_set_snd_dim_320mhz - set number of sounding dimensions
+ * supported for 320 MHz
+ *
+ * @phy_cap_info: EHT PHY capabilities information field data
+ * @num_snd_dim: number of sounding dimensions supported, &enum
+ * ieee80211_eht_beamformer_snd_dim
+ *
+ * Set "Number Of Sounding Dimensions for 320 MHz" subfield as encoded in "EHT
+ * PHY Capabilities Information" field in EHT Capabilities element
+ */
+static inline void
+ieee80211_eht_set_max_snd_dim_320(
+ u8 *phy_cap_info,
+ enum ieee80211_eht_beamformer_snd_dim num_snd_dim)
+{
+ phy_cap_info[2] |=
+ FIELD_PREP(IEEE80211_EHT_PHY_CAP2_BEAMFORMER_NUM_SND_DIM_320MHZ,
+ num_snd_dim);
+
+ phy_cap_info[3] |=
+ FIELD_PREP(IEEE80211_EHT_PHY_CAP3_BEAMFORMER_NUM_SND_DIM_320MHZ,
+ num_snd_dim >> 2);
+}
+
+/**
+ * ieee80211_eht_get_snd_dim_320mhz - get number of sounding dimensions
+ * supported for 320 MHz
+ *
+ * @phy_cap_info: EHT PHY capabilities information field data
+ *
+ * Get "Number Of Sounding Dimensions for 320 MHz" subfield value from "EHT
+ * PHY Capabilities Information" field in EHT Capabilities element
+ *
+ * Return: number of sounding dimensions supported, &enum
+ * ieee80211_eht_beamformer_snd_dim
+ */
+static inline enum ieee80211_eht_beamformer_snd_dim
+ieee80211_eht_get_max_snd_dim_320(const u8 *phy_cap_info)
+{
+ u8 num_snd_dim =
+ FIELD_GET(IEEE80211_EHT_PHY_CAP2_BEAMFORMER_NUM_SND_DIM_320MHZ,
+ phy_cap_info[2]);
+
+ if (FIELD_GET(IEEE80211_EHT_PHY_CAP3_BEAMFORMER_NUM_SND_DIM_320MHZ,
+ phy_cap_info[3]))
+ num_snd_dim += 4;
+
+ return num_snd_dim;
+}
+
+/**
+ * enum ieee80211_eht_max_nc - maximum supported Nc definitions
+ * @EHT_MAX_NC_1: maximum 1 Nc supported
+ * @EHT_MAX_NC_2: maximum 2 Nc supported
+ * @EHT_MAX_NC_3: maximum 3 Nc supported
+ * @EHT_MAX_NC_4: maximum 4 Nc supported
+ * @EHT_MAX_NC_5: maximum 5 Nc supported
+ * @EHT_MAX_NC_6: maximum 6 Nc supported
+ * @EHT_MAX_NC_7: maximum 7 Nc supported
+ * @EHT_MAX_NC_8: maximum 8 Nc supported
+ */
+enum ieee80211_eht_max_nc {
+ EHT_MAX_NC_1 = 0,
+ EHT_MAX_NC_2,
+ EHT_MAX_NC_3,
+ EHT_MAX_NC_4,
+ EHT_MAX_NC_5,
+ EHT_MAX_NC_6,
+ EHT_MAX_NC_7,
+ EHT_MAX_NC_8,
+};
+
+/**
+ * ieee80211_eht_set_max_nc - set maximum supported Nc
+ *
+ * @phy_cap_info: EHT PHY capabilities information field data
+ * @max_nc: Maximum supported Nc, see &enum ieee80211_eht_max_nc
+ *
+ * Set "Max Nc" subfield as encoded in "EHT PHY Capabilities Information" field
+ * in EHT Capabilities element
+ */
+static inline void
+ieee80211_eht_set_max_nc(u8 *phy_cap_info, enum ieee80211_eht_max_nc max_nc)
+{
+ phy_cap_info[4] |= FIELD_PREP(IEEE80211_EHT_PHY_CAP4_MAX_NC, max_nc);
+}
+
+/**
+ * ieee80211_eht_get_max_nc - get maximum supported Nc
+ * @phy_cap_info: EHT PHY capabilities information field data
+ *
+ * Get "Max Nc" subfield value from "EHT PHY Capabilities Information" field
+ * in EHT Capabilities element
+ *
+ * Return: Max supported Nc, see &enum ieee80211_eht_max_nc
+ */
+static inline enum ieee80211_eht_max_nc
+ieee80211_eht_get_max_nc(const u8 *phy_cap_info)
+{
+ return FIELD_GET(IEEE80211_EHT_PHY_CAP4_MAX_NC, phy_cap_info[4]);
+}
+
+/**
+ * enum ieee80211_eht_nominal_pkt_padding - EHT nominal packet padding
+ * definitions
+ * @EHT_NOMINAL_PKT_PADDING_0US - 0 us common nominal packet padding
+ * @EHT_NOMINAL_PKT_PADDING_8US - 8 us common nominal packet padding
+ * @EHT_NOMINAL_PKT_PADDING_16US - 16 us common nominal packet padding
+ * @EHT_NOMINAL_PKT_PADDING_16US_OR_20US - 16 us common nominal packet padding
+ * for all modes with constellation <= 1024, nss <= 8, RU/MRU <= 2x996 and
+ * 20 us for all other modes
+ */
+enum ieee80211_eht_nominal_pkt_padding {
+ EHT_NOMINAL_PKT_PADDING_0US = 0,
+ EHT_NOMINAL_PKT_PADDING_8US,
+ EHT_NOMINAL_PKT_PADDING_16US,
+ EHT_NOMINAL_PKT_PADDING_16US_OR_20US,
+};
+
+/**
+ * ieee80211_eht_set_common_nominal_pkt_padding - set EHT common nominal packet
+ * padding.
+ *
+ * @phy_cap_info: EHT PHY capabilities information field data
+ * @nominal_pkt_pad: common nominal packet padding, see &enum
+ * ieee80211_eht_nominal_pkt_padding
+ *
+ * Set "Common Nominal Packet Padding" subfield as encoded in "EHT PHY
+ * Capabilities Information" field in EHT Capabilities element
+ */
+static inline void
+ieee80211_eht_set_common_nominal_pkt_padding(
+ u8 *phy_cap_info,
+ enum ieee80211_eht_nominal_pkt_padding nominal_pkt_pad)
+{
+ phy_cap_info[5] |=
+ FIELD_PREP(IEEE80211_EHT_PHY_CAP5_NOMINAL_PKT_PADDING, nominal_pkt_pad);
+}
+
+/**
+ * ieee80211_eht_get_common_nominal_pkt_padding - get EHT common nominal packet
+ * padding.
+ *
+ * @phy_cap_info: EHT PHY capabilities information field data
+ *
+ * Set "Common Nominal Packet Padding" subfield value from "EHT PHY Capabilities
+ * Information" field in EHT Capabilities element
+ *
+ * Return: EHT common nominal packet padding capability, see &enum
+ * ieee80211_eht_nominal_pkt_padding
+ */
+static inline enum ieee80211_eht_nominal_pkt_padding
+ieee80211_eht_get_common_nominal_pkt_padding(const u8 *phy_cap_info)
+{
+ return FIELD_GET(IEEE80211_EHT_PHY_CAP5_NOMINAL_PKT_PADDING,
+ phy_cap_info[5]);
+}
+
+/**
+ * enum ieee80211_eht_max_ltf_supp - EHT maximum LTF support definitions
+ * @EHT_MAX_4XLTF_SUPP - Maximum of four EHT-LTFs supported
+ * @EHT_MAX_8XLTF_SUPP - Maximum of eight EHT-LTFs supported
+ */
+enum ieee80211_eht_max_ltf_supp {
+ EHT_MAX_4XLTF_SUPP = 0,
+ EHT_MAX_8XLTF_SUPP,
+};
+
+/**
+ * ieee80211_eht_set_max_eht_ltf_supp - set maximum number of supported EHT-LTFs
+ *
+ * @phy_cap_info: EHT PHY capabilities information field data
+ * @mu: Multiple user configuration
+ * @max_ltf: Maximum number of EHT-LTFs supported, see &enum
+ * ieee80211_eht_max_ltf_supp
+ *
+ * Set "Maximum Number Of Supported EHT-LTFs" subfield as encoded in "EHT PHY
+ * Capabilities Information" field in EHT Capabilities element
+ */
+static inline void
+ieee80211_eht_set_max_eht_ltf_supp(u8 *phy_cap_info, bool mu,
+ enum ieee80211_eht_max_ltf_supp max_ltf)
+{
+
+ if (mu) {
+ phy_cap_info[6] |=
+ FIELD_PREP(IEEE80211_EHT_PHY_CAP6_MAX_EHT_LTF_SUPP_MU, max_ltf);
+ return;
+ }
+
+ phy_cap_info[5] |=
+ FIELD_PREP(IEEE80211_EHT_PHY_CAP5_MAX_EHT_LTF_SUPP_SU, max_ltf);
+}
+
+/**
+ * ieee80211_eht_get_max_eht_ltf_supp - get maximum number of supported EHT-LTFs
+ *
+ * @phy_cap_info: EHT PHY capabilities information field data
+ * @mu: Multiple user configuration
+ *
+ * Get "Maximum Number Of Supported EHT-LTFs" subfield value from "EHT PHY
+ * Capabilities Information" field in EHT Capabilities element
+ *
+ * Return: Maximum number of EHT-LTFs supported, see &enum
+ * ieee80211_eht_max_ltf_supp
+ */
+static inline enum ieee80211_eht_max_ltf_supp
+ieee80211_eht_get_max_eht_ltf_supp(const u8 *phy_cap_info, bool mu)
+{
+ if (mu)
+ return FIELD_GET(IEEE80211_EHT_PHY_CAP6_MAX_EHT_LTF_SUPP_MU,
+ phy_cap_info[6]);
+
+ return FIELD_GET(IEEE80211_EHT_PHY_CAP5_MAX_EHT_LTF_SUPP_SU,
+ phy_cap_info[5]);
+}
+
+/**
+ * ieee80211_eht_mcs_nss_size - Get EHT MCS NSS Support Field size
+ *
+ * @eht_cap: EHT capabilities element
+ * @he_cap: HE capabilities element
+ *
+ * Calculate Tx/Rx EHT MCS NSS Support Field size in EHT capabilities IE
+ *
+ * Return: EHT MCS NSS Support Field size
+ */
+static inline u8
+ieee80211_eht_mcs_nss_size(const struct ieee80211_eht_cap_elem *eht_cap,
+ const struct ieee80211_he_cap_elem *he_cap)
+{
+ if ((he_cap->phy_cap_info[0] &
+ (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)) == 0)
+ return 4;
+
+ if (eht_cap->phy_cap_info[0] & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ)
+ return 9;
+
+ if (he_cap->phy_cap_info[0] &
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
+ return 6;
+
+ return 3;
+}
+
+/* EHT PPE Thresholds from P802.11be_D1.3, section 9.4.2.313.5 */
+#define IEEE80211_EHT_PPE_THRES0_NSS GENMASK(3, 0)
+
+/* RU Index Bitmask is split between byte 0 and byte 1 */
+#define IEEE80211_EHT_PPE_THRES0_RU_INDEX GENMASK(7, 4)
+#define IEEE80211_EHT_PPE_THRES1_RU_INDEX BIT(0)
+
+/* PPE Thresholds Information subfields size in number of bits */
+#define IEEE80211_EHT_PPE_THRES_INFO_HEADER_SIZE 9
+#define IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE 6
+
+/**
+ * ieee80211_eht_ppe_size - Get EHT PPE Thresholds Info Field size
+ *
+ * @ppe_thres_hdr: Header bytes of PPE Thresholds field
+ * @phy_cap_info: EHT PHY capabilities information
+ *
+ * Calculate EHT PPE Thresholds Info Field size in EHT capabilities IE
+ *
+ * Return: EHT PPE Thresholds Info Field size
+ */
+static inline u8
+ieee80211_eht_ppe_size(const u8 *ppe_thres_hdr, const u8 *phy_cap_info)
+{
+ u8 n;
+
+ if ((phy_cap_info[5] &
+ IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT) == 0)
+ return 0;
+
+ n = hweight8(FIELD_GET(IEEE80211_EHT_PPE_THRES0_RU_INDEX,
+ ppe_thres_hdr[0]));
+ n += hweight8(FIELD_GET(IEEE80211_EHT_PPE_THRES1_RU_INDEX,
+ ppe_thres_hdr[1]));
+
+ n *= (1 + FIELD_GET(IEEE80211_EHT_PPE_THRES0_NSS, ppe_thres_hdr[0]));
+
+ /**
+ * Each pair is 6 bits, and we need to add the 9 "header" bits to the
+ * total size.
+ */
+ n = (n * IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE) +
+ IEEE80211_EHT_PPE_THRES_INFO_HEADER_SIZE;
+ n = DIV_ROUND_UP(n, 8);
+
+ return n;
+}
+
/* Authentication algorithms */
#define WLAN_AUTH_OPEN 0
#define WLAN_AUTH_SHARED_KEY 1
@@ -3054,6 +3755,7 @@ enum ieee80211_eid_ext {
WLAN_EID_EXT_SHORT_SSID_LIST = 58,
WLAN_EID_EXT_HE_6GHZ_CAPA = 59,
WLAN_EID_EXT_UL_MU_POWER_CAPA = 60,
+ WLAN_EID_EXT_EHT_CAPABILITY = 108,
};

/* Action category code */
--
2.7.4


2021-12-22 09:05:44

by Veerendranath Jakkam

[permalink] [raw]
Subject: [PATCH 2/6] nl80211: add support to advertise driver's EHT capabilities

From: Vikram Kandukuri <[email protected]>

Add nl80211 support to advertise EHT capabilities to the userspace.

Add new attributes in enum nl80211_band_iftype_attr to indicate EHT MAC
capabilities, PHY capabilities, supported MCC-NSS set and PPE threshold
fields.

Signed-off-by: Vikram Kandukuri <[email protected]>
Co-authored-by: Aloka Dixit <[email protected]>
Signed-off-by: Aloka Dixit <[email protected]>
Co-authored-by: Veerendranath Jakkam <[email protected]>
Signed-off-by: Veerendranath Jakkam <[email protected]>
---
include/net/cfg80211.h | 56 ++++++++++++++++++++++++++++++++++++++++++++
include/uapi/linux/nl80211.h | 12 ++++++++++
net/wireless/nl80211.c | 17 ++++++++++++++
3 files changed, 85 insertions(+)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index d19e48f..df197c6 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -361,6 +361,28 @@ struct ieee80211_sta_he_cap {
};

/**
+ * struct ieee80211_sta_eht_cap - STA's EHT capabilities
+ *
+ * This structure describes parameters needed to describe 802.11be EHT
+ * capabilities for a STA.
+ *
+ * @has_eht: true if EHT data is valid.
+ * @eht_cap_elem: Fixed portion of the EHT capabilities element.
+ * @mcs_nss: The supported NSS/MCS combinations.
+ * @mcs_nss_len: Length of NSS/MCS combinations data.
+ * @ppe_thres: Holds the PPE Thresholds data.
+ * @ppe_thres_len: Length PPE Thresholds data.
+ */
+struct ieee80211_sta_eht_cap {
+ bool has_eht;
+ struct ieee80211_eht_cap_elem eht_cap_elem;
+ u8 *mcs_nss;
+ u8 mcs_nss_len;
+ u8 *ppe_thres;
+ u8 ppe_thres_len;
+};
+
+/**
* struct ieee80211_sband_iftype_data - sband data per interface type
*
* This structure encapsulates sband data that is relevant for the
@@ -374,6 +396,7 @@ struct ieee80211_sta_he_cap {
* @vendor_elems: vendor element(s) to advertise
* @vendor_elems.data: vendor element(s) data
* @vendor_elems.len: vendor element(s) length
+ * @eht_cap: holds the EHT capabilities.
*/
struct ieee80211_sband_iftype_data {
u16 types_mask;
@@ -383,6 +406,7 @@ struct ieee80211_sband_iftype_data {
const u8 *data;
unsigned int len;
} vendor_elems;
+ struct ieee80211_sta_eht_cap eht_cap;
};

/**
@@ -522,6 +546,38 @@ ieee80211_get_sband_iftype_data(const struct ieee80211_supported_band *sband,
}

/**
+ * ieee80211_get_eht_iftype_cap - return EHT capabilities for an sband's iftype
+ * @sband: the sband to search for the iftype on
+ * @iftype: enum nl80211_iftype
+ *
+ * Return: pointer to the struct ieee80211_sta_eht_cap, or NULL is none found
+ */
+static inline const struct ieee80211_sta_eht_cap *
+ieee80211_get_eht_iftype_cap(const struct ieee80211_supported_band *sband,
+ u8 iftype)
+{
+ const struct ieee80211_sband_iftype_data *data =
+ ieee80211_get_sband_iftype_data(sband, iftype);
+
+ if (data && data->eht_cap.has_eht)
+ return &data->eht_cap;
+
+ return NULL;
+}
+
+/**
+ * ieee80211_get_eht_sta_cap - return EHT capabilities for an sband's STA
+ * @sband: the sband to search for the STA on
+ *
+ * Return: pointer to the struct ieee80211_sta_eht_cap, or NULL is none found
+ */
+static inline const struct ieee80211_sta_eht_cap *
+ieee80211_get_eht_sta_cap(const struct ieee80211_supported_band *sband)
+{
+ return ieee80211_get_eht_iftype_cap(sband, NL80211_IFTYPE_STATION);
+}
+
+/**
* ieee80211_get_he_iftype_cap - return HE capabilities for an sband's iftype
* @sband: the sband to search for the iftype on
* @iftype: enum nl80211_iftype
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index f1a9d65..a709f5c 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3766,6 +3766,14 @@ enum nl80211_mpath_info {
* given for all 6 GHz band channels
* @NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS: vendor element capabilities that are
* advertised on this band/for this iftype (binary)
+ * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC: EHT MAC capabilities as in EHT
+ * capabilities IE
+ * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY: EHT PHY capabilities as in EHT
+ * capabilities IE
+ * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET: EHT supported NSS/MCS as in EHT
+ * capabilities IE
+ * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE: EHT PPE thresholds information as
+ * defined in EHT capabilities IE
* @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use
* @NL80211_BAND_IFTYPE_ATTR_MAX: highest band attribute currently defined
*/
@@ -3779,6 +3787,10 @@ enum nl80211_band_iftype_attr {
NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE,
NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA,
NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS,
+ NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC,
+ NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY,
+ NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET,
+ NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE,

/* keep last */
__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 578bff9..0ece4d3 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1729,6 +1729,7 @@ nl80211_send_iftype_data(struct sk_buff *msg,
const struct ieee80211_sband_iftype_data *iftdata)
{
const struct ieee80211_sta_he_cap *he_cap = &iftdata->he_cap;
+ const struct ieee80211_sta_eht_cap *eht_cap = &iftdata->eht_cap;

if (nl80211_put_iftypes(msg, NL80211_BAND_IFTYPE_ATTR_IFTYPES,
iftdata->types_mask))
@@ -1755,6 +1756,22 @@ nl80211_send_iftype_data(struct sk_buff *msg,
&iftdata->he_6ghz_capa))
return -ENOBUFS;

+ if (eht_cap->has_eht) {
+ if (nla_put(msg, NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC,
+ sizeof(eht_cap->eht_cap_elem.mac_cap_info),
+ eht_cap->eht_cap_elem.mac_cap_info) ||
+ nla_put(msg, NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY,
+ sizeof(eht_cap->eht_cap_elem.phy_cap_info),
+ eht_cap->eht_cap_elem.phy_cap_info) ||
+ (eht_cap->mcs_nss_len &&
+ nla_put(msg, NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET,
+ eht_cap->mcs_nss_len, eht_cap->mcs_nss)) ||
+ (eht_cap->ppe_thres_len &&
+ nla_put(msg, NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE,
+ eht_cap->ppe_thres_len, eht_cap->ppe_thres)))
+ return -ENOBUFS;
+ }
+
if (iftdata->vendor_elems.data && iftdata->vendor_elems.len &&
nla_put(msg, NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS,
iftdata->vendor_elems.len, iftdata->vendor_elems.data))
--
2.7.4


2021-12-22 09:05:47

by Veerendranath Jakkam

[permalink] [raw]
Subject: [PATCH 3/6] nl80211: add support to send EHT capabilities from userspace

From: Vikram Kandukuri <[email protected]>

Add support to process EHT capabilities element passed by the userspace
in beacon template and store the pointer in struct cfg80211_ap_settings.

Add new attribute NL80211_ATTR_EHT_CAPABILITY to be used by the
userspace to pass EHT capabilities of a station trying to associate.

Signed-off-by: Vikram Kandukuri <[email protected]>
Co-authored-by: Aloka Dixit <[email protected]>
Signed-off-by: Aloka Dixit <[email protected]>
Co-authored-by: Veerendranath Jakkam <[email protected]>
Signed-off-by: Veerendranath Jakkam <[email protected]>
---
include/net/cfg80211.h | 6 ++++++
include/uapi/linux/nl80211.h | 7 +++++++
net/wireless/nl80211.c | 29 ++++++++++++++++++++++++++---
3 files changed, 39 insertions(+), 3 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index df197c6..ce34dd7 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1271,6 +1271,7 @@ struct cfg80211_unsol_bcast_probe_resp {
* @ht_cap: HT capabilities (or %NULL if HT isn't enabled)
* @vht_cap: VHT capabilities (or %NULL if VHT isn't enabled)
* @he_cap: HE capabilities (or %NULL if HE isn't enabled)
+ * @eht_cap: EHT capabilities (or %NULL if EHT isn't enabled)
* @ht_required: stations must support HT
* @vht_required: stations must support VHT
* @twt_responder: Enable Target Wait Time
@@ -1308,6 +1309,7 @@ struct cfg80211_ap_settings {
const struct ieee80211_vht_cap *vht_cap;
const struct ieee80211_he_cap_elem *he_cap;
const struct ieee80211_he_operation *he_oper;
+ const struct ieee80211_eht_cap_elem *eht_cap;
bool ht_required, vht_required, he_required, sae_h2e_required;
bool twt_responder;
u32 flags;
@@ -1473,6 +1475,8 @@ struct sta_txpwr {
* @airtime_weight: airtime scheduler weight for this station
* @txpwr: transmit power for an associated station
* @he_6ghz_capa: HE 6 GHz Band capabilities of station
+ * @eht_capa: EHT capabilities of station
+ * @eht_capa_len: the length of the EHT capabilities
*/
struct station_parameters {
const u8 *supported_rates;
@@ -1506,6 +1510,8 @@ struct station_parameters {
u16 airtime_weight;
struct sta_txpwr txpwr;
const struct ieee80211_he_6ghz_capa *he_6ghz_capa;
+ const struct ieee80211_eht_cap_elem *eht_capa;
+ u8 eht_capa_len;
};

/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index a709f5c..c221322 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2659,6 +2659,8 @@ enum nl80211_commands {
* enumerated in &enum nl80211_ap_settings_flags. This attribute shall be
* used with %NL80211_CMD_START_AP request.
*
+ * @NL80211_ATTR_EHT_CAPABILITY: EHT Capability information element.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3169,6 +3171,8 @@ enum nl80211_attrs {

NL80211_ATTR_AP_SETTINGS_FLAGS,

+ NL80211_ATTR_EHT_CAPABILITY,
+
/* add attributes here, update the policy in nl80211.c */

__NL80211_ATTR_AFTER_LAST,
@@ -3225,6 +3229,9 @@ enum nl80211_attrs {
#define NL80211_MAX_NR_CIPHER_SUITES 5
#define NL80211_MAX_NR_AKM_SUITES 2

+#define NL80211_EHT_MIN_CAPABILITY_LEN 10
+#define NL80211_EHT_MAX_CAPABILITY_LEN 81
+
#define NL80211_MIN_REMAIN_ON_CHANNEL_TIME 10

/* default RSSI threshold for scan results if none specified. */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 0ece4d3..dba4002 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -778,6 +778,10 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED },
[NL80211_ATTR_RADAR_BACKGROUND] = { .type = NLA_FLAG },
[NL80211_ATTR_AP_SETTINGS_FLAGS] = { .type = NLA_U32 },
+ [NL80211_ATTR_EHT_CAPABILITY] =
+ NLA_POLICY_RANGE(NLA_BINARY,
+ NL80211_EHT_MIN_CAPABILITY_LEN,
+ NL80211_EHT_MAX_CAPABILITY_LEN),
};

/* policy for the key attributes */
@@ -5414,6 +5418,9 @@ static void nl80211_calculate_ap_params(struct cfg80211_ap_settings *params)
cap = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ies, ies_len);
if (cap && cap->datalen >= sizeof(*params->he_oper) + 1)
params->he_oper = (void *)(cap->data + 1);
+ cap = cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_CAPABILITY, ies, ies_len);
+ if (cap && cap->datalen >= sizeof(*params->eht_cap) + 1)
+ params->eht_cap = (void *)(cap->data + 1);
}

static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
@@ -6382,7 +6389,7 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
if (params->supported_rates)
return -EINVAL;
if (params->ext_capab || params->ht_capa || params->vht_capa ||
- params->he_capa)
+ params->he_capa || params->eht_capa)
return -EINVAL;
}

@@ -6567,6 +6574,17 @@ static int nl80211_parse_sta_channel_info(struct genl_info *info,
return 0;
}

+static void nl80211_parse_sta_eht_capa(struct genl_info *info,
+ struct station_parameters *params)
+{
+ if (info->attrs[NL80211_ATTR_EHT_CAPABILITY]) {
+ params->eht_capa =
+ nla_data(info->attrs[NL80211_ATTR_EHT_CAPABILITY]);
+ params->eht_capa_len =
+ nla_len(info->attrs[NL80211_ATTR_EHT_CAPABILITY]);
+ }
+}
+
static int nl80211_set_station_tdls(struct genl_info *info,
struct station_parameters *params)
{
@@ -6587,6 +6605,8 @@ static int nl80211_set_station_tdls(struct genl_info *info,
nla_len(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
}

+ nl80211_parse_sta_eht_capa(info, params);
+
err = nl80211_parse_sta_channel_info(info, params);
if (err)
return err;
@@ -6848,6 +6868,8 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
params.he_6ghz_capa =
nla_data(info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]);

+ nl80211_parse_sta_eht_capa(info, &params);
+
if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
params.opmode_notif_used = true;
params.opmode_notif =
@@ -6891,8 +6913,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
params.ht_capa = NULL;
params.vht_capa = NULL;

- /* HE requires WME */
- if (params.he_capa_len || params.he_6ghz_capa)
+ /* HE and EHT requires WME */
+ if (params.he_capa_len || params.he_6ghz_capa ||
+ params.eht_capa_len)
return -EINVAL;
}

--
2.7.4


2021-12-22 09:05:52

by Veerendranath Jakkam

[permalink] [raw]
Subject: [PATCH 4/6] cfg80211: Add support for EHT 320 MHz channel width

From: Jia Ding <[email protected]>

Add 320 MHz support in the channel def and center frequency validation
with compatible check.

Signed-off-by: Jia Ding <[email protected]>
Co-authored-by: Karthikeyan Periyasamy <[email protected]>
Signed-off-by: Karthikeyan Periyasamy <[email protected]>
Co-authored-by: Muna Sinada <[email protected]>
Signed-off-by: Muna Sinada <[email protected]>
Co-authored-by: Veerendranath Jakkam <[email protected]>
Signed-off-by: Veerendranath Jakkam <[email protected]>
---
include/net/cfg80211.h | 6 +++
include/uapi/linux/nl80211.h | 3 ++
net/wireless/chan.c | 91 ++++++++++++++++++++++++++++++++++++++++----
3 files changed, 93 insertions(+), 7 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ce34dd7..eeb2854 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -110,6 +110,11 @@ struct wiphy;
* @IEEE80211_CHAN_16MHZ: 16 MHz bandwidth is permitted
* on this channel.
*
+ * @IEEE80211_CHAN_NO_320MHZ: If the driver supports 320 MHz on the band,
+ * this flag indicates that a 320 MHz channel cannot use this
+ * channel as the control or any of the secondary channels.
+ * This may be due to the driver or due to regulatory bandwidth
+ * restrictions.
*/
enum ieee80211_channel_flags {
IEEE80211_CHAN_DISABLED = 1<<0,
@@ -131,6 +136,7 @@ enum ieee80211_channel_flags {
IEEE80211_CHAN_4MHZ = 1<<16,
IEEE80211_CHAN_8MHZ = 1<<17,
IEEE80211_CHAN_16MHZ = 1<<18,
+ IEEE80211_CHAN_NO_320MHZ = 1<<19,
};

#define IEEE80211_CHAN_NO_HT40 \
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index c221322..e4ac7ab 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -4691,6 +4691,8 @@ enum nl80211_key_mode {
* @NL80211_CHAN_WIDTH_4: 4 MHz OFDM channel
* @NL80211_CHAN_WIDTH_8: 8 MHz OFDM channel
* @NL80211_CHAN_WIDTH_16: 16 MHz OFDM channel
+ * @NL80211_CHAN_WIDTH_320: 320 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
+ * attribute must be provided as well
*/
enum nl80211_chan_width {
NL80211_CHAN_WIDTH_20_NOHT,
@@ -4706,6 +4708,7 @@ enum nl80211_chan_width {
NL80211_CHAN_WIDTH_4,
NL80211_CHAN_WIDTH_8,
NL80211_CHAN_WIDTH_16,
+ NL80211_CHAN_WIDTH_320,
};

/**
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index eb82205..8b7fb4a 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -181,6 +181,9 @@ static int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width)
case NL80211_CHAN_WIDTH_160:
mhz = 160;
break;
+ case NL80211_CHAN_WIDTH_320:
+ mhz = 320;
+ break;
default:
WARN_ON_ONCE(1);
return -1;
@@ -271,6 +274,17 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
case NL80211_CHAN_WIDTH_16:
/* all checked above */
break;
+ case NL80211_CHAN_WIDTH_320:
+ if (chandef->center_freq1 == control_freq + 150 ||
+ chandef->center_freq1 == control_freq + 130 ||
+ chandef->center_freq1 == control_freq + 110 ||
+ chandef->center_freq1 == control_freq + 90 ||
+ chandef->center_freq1 == control_freq - 90 ||
+ chandef->center_freq1 == control_freq - 110 ||
+ chandef->center_freq1 == control_freq - 130 ||
+ chandef->center_freq1 == control_freq - 150)
+ break;
+ fallthrough;
case NL80211_CHAN_WIDTH_160:
if (chandef->center_freq1 == control_freq + 70 ||
chandef->center_freq1 == control_freq + 50 ||
@@ -307,7 +321,7 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
EXPORT_SYMBOL(cfg80211_chandef_valid);

static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
- u32 *pri40, u32 *pri80)
+ u32 *pri40, u32 *pri80, u32 *pri160)
{
int tmp;

@@ -315,9 +329,11 @@ static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
case NL80211_CHAN_WIDTH_40:
*pri40 = c->center_freq1;
*pri80 = 0;
+ *pri160 = 0;
break;
case NL80211_CHAN_WIDTH_80:
case NL80211_CHAN_WIDTH_80P80:
+ *pri160 = 0;
*pri80 = c->center_freq1;
/* n_P20 */
tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
@@ -327,6 +343,7 @@ static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
*pri40 = c->center_freq1 - 20 + 40 * tmp;
break;
case NL80211_CHAN_WIDTH_160:
+ *pri160 = c->center_freq1;
/* n_P20 */
tmp = (70 + c->chan->center_freq - c->center_freq1)/20;
/* n_P40 */
@@ -337,6 +354,20 @@ static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
tmp /= 2;
*pri80 = c->center_freq1 - 40 + 80 * tmp;
break;
+ case NL80211_CHAN_WIDTH_320:
+ /* n_P20 */
+ tmp = (150 + c->chan->center_freq - c->center_freq1) / 20;
+ /* n_P40 */
+ tmp /= 2;
+ /* freq_P40 */
+ *pri40 = c->center_freq1 - 140 + 40 * tmp;
+ /* n_P80 */
+ tmp /= 2;
+ *pri80 = c->center_freq1 - 120 + 80 * tmp;
+ /* n_P160 */
+ tmp /= 2;
+ *pri160 = c->center_freq1 - 80 + 160 * tmp;
+ break;
default:
WARN_ON_ONCE(1);
}
@@ -346,7 +377,7 @@ const struct cfg80211_chan_def *
cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
const struct cfg80211_chan_def *c2)
{
- u32 c1_pri40, c1_pri80, c2_pri40, c2_pri80;
+ u32 c1_pri40, c1_pri80, c2_pri40, c2_pri80, c1_pri160, c2_pri160;

/* If they are identical, return */
if (cfg80211_chandef_identical(c1, c2))
@@ -381,14 +412,31 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
c2->width == NL80211_CHAN_WIDTH_20)
return c1;

- chandef_primary_freqs(c1, &c1_pri40, &c1_pri80);
- chandef_primary_freqs(c2, &c2_pri40, &c2_pri80);
+ chandef_primary_freqs(c1, &c1_pri40, &c1_pri80, &c1_pri160);
+ chandef_primary_freqs(c2, &c2_pri40, &c2_pri80, &c2_pri160);

if (c1_pri40 != c2_pri40)
return NULL;

- WARN_ON(!c1_pri80 && !c2_pri80);
- if (c1_pri80 && c2_pri80 && c1_pri80 != c2_pri80)
+ if (c1->width == NL80211_CHAN_WIDTH_40)
+ return c2;
+
+ if (c2->width == NL80211_CHAN_WIDTH_40)
+ return c1;
+
+ if (c1_pri80 != c2_pri80)
+ return NULL;
+
+ if (c1->width == NL80211_CHAN_WIDTH_80 &&
+ c2->width > NL80211_CHAN_WIDTH_80)
+ return c2;
+
+ if (c2->width == NL80211_CHAN_WIDTH_80 &&
+ c1->width > NL80211_CHAN_WIDTH_80)
+ return c1;
+
+ WARN_ON(!c1_pri160 && !c2_pri160);
+ if (c1_pri160 && c2_pri160 && c1_pri160 != c2_pri160)
return NULL;

if (c1->width > c2->width)
@@ -960,7 +1008,10 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
struct ieee80211_sta_vht_cap *vht_cap;
struct ieee80211_edmg *edmg_cap;
u32 width, control_freq, cap;
- bool ext_nss_cap, support_80_80 = false;
+ bool ext_nss_cap, support_80_80 = false, support_320 = false;
+ const struct ieee80211_sband_iftype_data *iftd;
+ struct ieee80211_supported_band *sband;
+ int i;

if (WARN_ON(!cfg80211_chandef_valid(chandef)))
return false;
@@ -1062,6 +1113,32 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
(vht_cap->cap & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK)))
return false;
break;
+ case NL80211_CHAN_WIDTH_320:
+ prohibited_flags |= IEEE80211_CHAN_NO_320MHZ;
+ width = 320;
+
+ if (chandef->chan->band != NL80211_BAND_6GHZ)
+ return false;
+
+ sband = wiphy->bands[NL80211_BAND_6GHZ];
+ if (!sband)
+ return false;
+
+ for (i = 0; i < sband->n_iftype_data; i++) {
+ iftd = &sband->iftype_data[i];
+ if (!iftd->eht_cap.has_eht)
+ continue;
+
+ if (iftd->eht_cap.eht_cap_elem.phy_cap_info[0] &
+ IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ) {
+ support_320 = true;
+ break;
+ }
+ }
+
+ if (!support_320)
+ return false;
+ break;
default:
WARN_ON_ONCE(1);
return false;
--
2.7.4


2021-12-22 09:05:53

by Veerendranath Jakkam

[permalink] [raw]
Subject: [PATCH 5/6] nl80211: add support for 320MHz channel limitation

From: Sriram R <[email protected]>

Add support to advertise drivers or regulatory limitations on 320 MHz
channels to userspace.

Signed-off-by: Sriram R <[email protected]>
Co-authored-by: Karthikeyan Periyasamy <[email protected]>
Signed-off-by: Karthikeyan Periyasamy <[email protected]>
Co-authored-by: Veerendranath Jakkam <[email protected]>
Signed-off-by: Veerendranath Jakkam <[email protected]>
---
include/uapi/linux/nl80211.h | 5 +++++
net/wireless/nl80211.c | 3 +++
net/wireless/reg.c | 6 ++++++
3 files changed, 14 insertions(+)

diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index e4ac7ab..b985cb0 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3942,6 +3942,8 @@ enum nl80211_wmm_rule {
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_16MHZ: 16 MHz operation is allowed
* on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_NO_320MHZ: any 320 MHz channel using this channel
+ * as the primary or any of the secondary channels isn't possible
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -3978,6 +3980,7 @@ enum nl80211_frequency_attr {
NL80211_FREQUENCY_ATTR_4MHZ,
NL80211_FREQUENCY_ATTR_8MHZ,
NL80211_FREQUENCY_ATTR_16MHZ,
+ NL80211_FREQUENCY_ATTR_NO_320MHZ,

/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -4176,6 +4179,7 @@ enum nl80211_sched_scan_match_attr {
* @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed
* @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed
* @NL80211_RRF_NO_HE: HE operation not allowed
+ * @NL80211_RRF_NO_320MHZ: 320MHz operation not allowed
*/
enum nl80211_reg_rule_flags {
NL80211_RRF_NO_OFDM = 1<<0,
@@ -4194,6 +4198,7 @@ enum nl80211_reg_rule_flags {
NL80211_RRF_NO_80MHZ = 1<<15,
NL80211_RRF_NO_160MHZ = 1<<16,
NL80211_RRF_NO_HE = 1<<17,
+ NL80211_RRF_NO_320MHZ = 1<<18,
};

#define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index dba4002..f31a464 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1152,6 +1152,9 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy,
if ((chan->flags & IEEE80211_CHAN_16MHZ) &&
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_16MHZ))
goto nla_put_failure;
+ if ((chan->flags & IEEE80211_CHAN_NO_320MHZ) &&
+ nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_320MHZ))
+ goto nla_put_failure;
}

if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index ec25924..c76cd97 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1238,6 +1238,8 @@ unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd,
{
unsigned int bw = reg_get_max_bandwidth_from_range(rd, rule);

+ if (rule->flags & NL80211_RRF_NO_320MHZ)
+ bw = min_t(unsigned int, bw, MHZ_TO_KHZ(160));
if (rule->flags & NL80211_RRF_NO_160MHZ)
bw = min_t(unsigned int, bw, MHZ_TO_KHZ(80));
if (rule->flags & NL80211_RRF_NO_80MHZ)
@@ -1611,6 +1613,8 @@ static u32 map_regdom_flags(u32 rd_flags)
channel_flags |= IEEE80211_CHAN_NO_160MHZ;
if (rd_flags & NL80211_RRF_NO_HE)
channel_flags |= IEEE80211_CHAN_NO_HE;
+ if (rd_flags & NL80211_RRF_NO_320MHZ)
+ channel_flags |= IEEE80211_CHAN_NO_320MHZ;
return channel_flags;
}

@@ -1773,6 +1777,8 @@ static uint32_t reg_rule_to_chan_bw_flags(const struct ieee80211_regdomain *regd
bw_flags |= IEEE80211_CHAN_NO_80MHZ;
if (max_bandwidth_khz < MHZ_TO_KHZ(160))
bw_flags |= IEEE80211_CHAN_NO_160MHZ;
+ if (max_bandwidth_khz < MHZ_TO_KHZ(320))
+ bw_flags |= IEEE80211_CHAN_NO_320MHZ;
}
return bw_flags;
}
--
2.7.4


2021-12-22 09:05:56

by Veerendranath Jakkam

[permalink] [raw]
Subject: [PATCH 6/6] nl80211: add EHT MCS support

Add support for reporting and calculating EHT bitrates.

Signed-off-by: Veerendranath Jakkam <[email protected]>
---
include/net/cfg80211.h | 11 ++++
include/uapi/linux/nl80211.h | 62 ++++++++++++++++++++
net/wireless/nl80211.c | 18 ++++++
net/wireless/util.c | 131 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 222 insertions(+)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index eeb2854..56ead14 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1595,6 +1595,7 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
* @RATE_INFO_FLAGS_HE_MCS: HE MCS information
* @RATE_INFO_FLAGS_EDMG: 60GHz MCS in EDMG mode
* @RATE_INFO_FLAGS_EXTENDED_SC_DMG: 60GHz extended SC MCS
+ * @RATE_INFO_FLAGS_EHT_MCS: EHT MCS information
*/
enum rate_info_flags {
RATE_INFO_FLAGS_MCS = BIT(0),
@@ -1604,6 +1605,7 @@ enum rate_info_flags {
RATE_INFO_FLAGS_HE_MCS = BIT(4),
RATE_INFO_FLAGS_EDMG = BIT(5),
RATE_INFO_FLAGS_EXTENDED_SC_DMG = BIT(6),
+ RATE_INFO_FLAGS_EHT_MCS = BIT(7),
};

/**
@@ -1618,6 +1620,8 @@ enum rate_info_flags {
* @RATE_INFO_BW_80: 80 MHz bandwidth
* @RATE_INFO_BW_160: 160 MHz bandwidth
* @RATE_INFO_BW_HE_RU: bandwidth determined by HE RU allocation
+ * @RATE_INFO_BW_320: 320 MHz bandwidth
+ * @RATE_INFO_BW_EHT_RU: bandwidth determined by EHT RU allocation
*/
enum rate_info_bw {
RATE_INFO_BW_20 = 0,
@@ -1627,6 +1631,8 @@ enum rate_info_bw {
RATE_INFO_BW_80,
RATE_INFO_BW_160,
RATE_INFO_BW_HE_RU,
+ RATE_INFO_BW_320,
+ RATE_INFO_BW_EHT_RU,
};

/**
@@ -1644,6 +1650,9 @@ enum rate_info_bw {
* @he_ru_alloc: HE RU allocation (from &enum nl80211_he_ru_alloc,
* only valid if bw is %RATE_INFO_BW_HE_RU)
* @n_bonded_ch: In case of EDMG the number of bonded channels (1-4)
+ * @eht_gi: EHT guard interval (from &enum nl80211_eht_gi)
+ * @eht_ru_alloc: EHT RU allocation (from &enum nl80211_eht_ru_alloc,
+ * only valid if bw is %RATE_INFO_BW_EHT_RU)
*/
struct rate_info {
u8 flags;
@@ -1655,6 +1664,8 @@ struct rate_info {
u8 he_dcm;
u8 he_ru_alloc;
u8 n_bonded_ch;
+ u8 eht_gi;
+ u8 eht_ru_alloc;
};

/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index b985cb0..76c70fc 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3400,6 +3400,56 @@ enum nl80211_he_ru_alloc {
};

/**
+ * enum nl80211_eht_gi - EHT guard interval
+ * @NL80211_RATE_INFO_EHT_GI_0_8: 0.8 usec
+ * @NL80211_RATE_INFO_EHT_GI_1_6: 1.6 usec
+ * @NL80211_RATE_INFO_EHT_GI_3_2: 3.2 usec
+ */
+enum nl80211_eht_gi {
+ NL80211_RATE_INFO_EHT_GI_0_8,
+ NL80211_RATE_INFO_EHT_GI_1_6,
+ NL80211_RATE_INFO_EHT_GI_3_2,
+};
+
+/**
+ * enum nl80211_eht_ru_alloc - EHT RU allocation values
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_26: 26-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_52: 52-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_52P26: 52+26-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_106: 106-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_106P26: 106+26 tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_242: 242-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_484: 484-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_484P242: 484+242 tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_996: 996-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_996P484: 996+484 tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_996P484P242: 996+484+242 tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_2x996: 2x996-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_2x996P484: 2x996+484 tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_3x996: 3x996-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_3x996P484: 3x996+484 tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_4x996: 4x996-tone RU allocation
+ */
+enum nl80211_eht_ru_alloc {
+ NL80211_RATE_INFO_EHT_RU_ALLOC_26,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_52,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_52P26,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_106,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_106P26,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_242,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_484,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_484P242,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_996,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_996P484,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_996P484P242,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_2x996,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_2x996P484,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_3x996,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_3x996P484,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_4x996,
+};
+
+/**
* enum nl80211_rate_info - bitrate information
*
* These attribute types are used with %NL80211_STA_INFO_TXRATE
@@ -3438,6 +3488,13 @@ enum nl80211_he_ru_alloc {
* @NL80211_RATE_INFO_HE_DCM: HE DCM value (u8, 0/1)
* @NL80211_RATE_INFO_RU_ALLOC: HE RU allocation, if not present then
* non-OFDMA was used (u8, see &enum nl80211_he_ru_alloc)
+ * @NL80211_RATE_INFO_320_MHZ_WIDTH: 320 MHz bitrate
+ * @NL80211_RATE_INFO_EHT_MCS: EHT MCS index (u8, 0-15)
+ * @NL80211_RATE_INFO_EHT_NSS: EHT NSS value (u8, 1-8)
+ * @NL80211_RATE_INFO_EHT_GI: EHT guard interval identifier
+ * (u8, see &enum nl80211_eht_gi)
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC: EHT RU allocation, if not present then
+ * non-OFDMA was used (u8, see &enum nl80211_eht_ru_alloc)
* @__NL80211_RATE_INFO_AFTER_LAST: internal use
*/
enum nl80211_rate_info {
@@ -3459,6 +3516,11 @@ enum nl80211_rate_info {
NL80211_RATE_INFO_HE_GI,
NL80211_RATE_INFO_HE_DCM,
NL80211_RATE_INFO_HE_RU_ALLOC,
+ NL80211_RATE_INFO_320_MHZ_WIDTH,
+ NL80211_RATE_INFO_EHT_MCS,
+ NL80211_RATE_INFO_EHT_NSS,
+ NL80211_RATE_INFO_EHT_GI,
+ NL80211_RATE_INFO_EHT_RU_ALLOC,

/* keep last */
__NL80211_RATE_INFO_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f31a464..10f4fc6 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5946,6 +5946,13 @@ bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, int attr)
case RATE_INFO_BW_HE_RU:
rate_flg = 0;
WARN_ON(!(info->flags & RATE_INFO_FLAGS_HE_MCS));
+ break;
+ case RATE_INFO_BW_320:
+ rate_flg = NL80211_RATE_INFO_320_MHZ_WIDTH;
+ break;
+ case RATE_INFO_BW_EHT_RU:
+ rate_flg = 0;
+ WARN_ON(!(info->flags & RATE_INFO_FLAGS_EHT_MCS));
}

if (rate_flg && nla_put_flag(msg, rate_flg))
@@ -5978,6 +5985,17 @@ bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, int attr)
nla_put_u8(msg, NL80211_RATE_INFO_HE_RU_ALLOC,
info->he_ru_alloc))
return false;
+ } else if (info->flags & RATE_INFO_FLAGS_EHT_MCS) {
+ if (nla_put_u8(msg, NL80211_RATE_INFO_EHT_MCS, info->mcs))
+ return false;
+ if (nla_put_u8(msg, NL80211_RATE_INFO_EHT_NSS, info->nss))
+ return false;
+ if (nla_put_u8(msg, NL80211_RATE_INFO_EHT_GI, info->eht_gi))
+ return false;
+ if (info->bw == RATE_INFO_BW_EHT_RU &&
+ nla_put_u8(msg, NL80211_RATE_INFO_EHT_RU_ALLOC,
+ info->eht_ru_alloc))
+ return false;
}

nla_nest_end(msg, rate);
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 41ea65d..327257c 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1428,6 +1428,135 @@ static u32 cfg80211_calculate_bitrate_he(struct rate_info *rate)
return result / 10000;
}

+static u32 cfg80211_calculate_bitrate_eht(struct rate_info *rate)
+{
+#define SCALE 6144
+ static const u32 mcs_divisors[16] = {
+ 102399, /* 16.666666... */
+ 51201, /* 8.333333... */
+ 34134, /* 5.555555... */
+ 25599, /* 4.166666... */
+ 17067, /* 2.777777... */
+ 12801, /* 2.083333... */
+ 11769, /* 1.851851... */
+ 10239, /* 1.666666... */
+ 8532, /* 1.388888... */
+ 7680, /* 1.250000... */
+ 6828, /* 1.111111... */
+ 6144, /* 1.000000... */
+ 5690, /* 0.926106... */
+ 5120, /* 0.833333... */
+ 409600, /* 66.666666... */
+ 204800, /* 33.333333... */
+ };
+ static const u32 rates_996[3] = { 480388888, 453700000, 408333333 };
+ static const u32 rates_484[3] = { 229411111, 216666666, 195000000 };
+ static const u32 rates_242[3] = { 114711111, 108333333, 97500000 };
+ static const u32 rates_106[3] = { 40000000, 37777777, 34000000 };
+ static const u32 rates_52[3] = { 18820000, 17777777, 16000000 };
+ static const u32 rates_26[3] = { 9411111, 8888888, 8000000 };
+ u64 tmp;
+ u32 result;
+
+ if (WARN_ON_ONCE(rate->mcs > 15))
+ return 0;
+ if (WARN_ON_ONCE(rate->eht_gi > NL80211_RATE_INFO_EHT_GI_3_2))
+ return 0;
+ if (WARN_ON_ONCE(rate->eht_ru_alloc >
+ NL80211_RATE_INFO_EHT_RU_ALLOC_4x996))
+ return 0;
+ if (WARN_ON_ONCE(rate->nss < 1 || rate->nss > 8))
+ return 0;
+
+ /* Bandwidth checks for MCS 14 */
+ if (rate->mcs == 14) {
+ if ((rate->bw != RATE_INFO_BW_EHT_RU &&
+ rate->bw != RATE_INFO_BW_80 &&
+ rate->bw != RATE_INFO_BW_160 &&
+ rate->bw != RATE_INFO_BW_320) ||
+ (rate->bw == RATE_INFO_BW_EHT_RU &&
+ rate->eht_ru_alloc != NL80211_RATE_INFO_EHT_RU_ALLOC_996 &&
+ rate->eht_ru_alloc != NL80211_RATE_INFO_EHT_RU_ALLOC_2x996 &&
+ rate->eht_ru_alloc != NL80211_RATE_INFO_EHT_RU_ALLOC_4x996)) {
+ WARN(1, "invalid EHT BW for MCS 14: bw:%d, ru:%d\n",
+ rate->bw, rate->eht_ru_alloc);
+ return 0;
+ }
+ }
+
+ if (rate->bw == RATE_INFO_BW_320 ||
+ (rate->bw == RATE_INFO_BW_EHT_RU &&
+ rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_4x996))
+ result = 4 * rates_996[rate->eht_gi];
+ else if (rate->bw == RATE_INFO_BW_EHT_RU &&
+ rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_3x996P484)
+ result = 3 * rates_996[rate->eht_gi] + rates_484[rate->eht_gi];
+ else if (rate->bw == RATE_INFO_BW_EHT_RU &&
+ rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_3x996)
+ result = 3 * rates_996[rate->eht_gi];
+ else if (rate->bw == RATE_INFO_BW_EHT_RU &&
+ rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_2x996P484)
+ result = 2 * rates_996[rate->eht_gi] + rates_484[rate->eht_gi];
+ else if (rate->bw == RATE_INFO_BW_160 ||
+ (rate->bw == RATE_INFO_BW_EHT_RU &&
+ rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_2x996))
+ result = 2 * rates_996[rate->eht_gi];
+ else if (rate->bw == RATE_INFO_BW_EHT_RU &&
+ rate->eht_ru_alloc ==
+ NL80211_RATE_INFO_EHT_RU_ALLOC_996P484P242)
+ result = rates_996[rate->eht_gi] + rates_484[rate->eht_gi]
+ + rates_242[rate->eht_gi];
+ else if (rate->bw == RATE_INFO_BW_EHT_RU &&
+ rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_996P484)
+ result = rates_996[rate->eht_gi] + rates_484[rate->eht_gi];
+ else if (rate->bw == RATE_INFO_BW_80 ||
+ (rate->bw == RATE_INFO_BW_EHT_RU &&
+ rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_996))
+ result = rates_996[rate->eht_gi];
+ else if (rate->bw == RATE_INFO_BW_EHT_RU &&
+ rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_484P242)
+ result = rates_484[rate->eht_gi] + rates_242[rate->eht_gi];
+ else if (rate->bw == RATE_INFO_BW_40 ||
+ (rate->bw == RATE_INFO_BW_EHT_RU &&
+ rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_484))
+ result = rates_484[rate->eht_gi];
+ else if (rate->bw == RATE_INFO_BW_20 ||
+ (rate->bw == RATE_INFO_BW_EHT_RU &&
+ rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_242))
+ result = rates_242[rate->eht_gi];
+ else if (rate->bw == RATE_INFO_BW_EHT_RU &&
+ rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_106P26)
+ result = rates_106[rate->eht_gi] + rates_26[rate->eht_gi];
+ else if (rate->bw == RATE_INFO_BW_EHT_RU &&
+ rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_106)
+ result = rates_106[rate->eht_gi];
+ else if (rate->bw == RATE_INFO_BW_EHT_RU &&
+ rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_52P26)
+ result = rates_52[rate->eht_gi] + rates_26[rate->eht_gi];
+ else if (rate->bw == RATE_INFO_BW_EHT_RU &&
+ rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_52)
+ result = rates_52[rate->eht_gi];
+ else if (rate->bw == RATE_INFO_BW_EHT_RU &&
+ rate->eht_ru_alloc == NL80211_RATE_INFO_EHT_RU_ALLOC_26)
+ result = rates_26[rate->eht_gi];
+ else {
+ WARN(1, "invalid EHT MCS: bw:%d, ru:%d\n",
+ rate->bw, rate->eht_ru_alloc);
+ return 0;
+ }
+
+ /* now scale to the appropriate MCS */
+ tmp = result;
+ tmp *= SCALE;
+ do_div(tmp, mcs_divisors[rate->mcs]);
+ result = tmp;
+
+ /* and take NSS */
+ result = (result * rate->nss) / 8;
+
+ return result / 10000;
+}
+
u32 cfg80211_calculate_bitrate(struct rate_info *rate)
{
if (rate->flags & RATE_INFO_FLAGS_MCS)
@@ -1442,6 +1571,8 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate)
return cfg80211_calculate_bitrate_vht(rate);
if (rate->flags & RATE_INFO_FLAGS_HE_MCS)
return cfg80211_calculate_bitrate_he(rate);
+ if (rate->flags & RATE_INFO_FLAGS_EHT_MCS)
+ return cfg80211_calculate_bitrate_eht(rate);

return rate->legacy;
}
--
2.7.4


2022-02-03 14:35:47

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 3/6] nl80211: add support to send EHT capabilities from userspace

On Wed, 2021-12-22 at 14:34 +0530, Veerendranath Jakkam wrote:
>
> +#define NL80211_EHT_MIN_CAPABILITY_LEN 10
> +#define NL80211_EHT_MAX_CAPABILITY_LEN 81
>

How did you get to 81?

I calculate only 51, based on the assumption that we can only have
NSS==8. Even if you think NSS==16 (which I doubt), I get to 80 only?

johannes

2022-02-04 14:48:20

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 3/6] nl80211: add support to send EHT capabilities from userspace

On Fri, 2022-02-04 at 12:42 +0530, Veerendranath Jakkam wrote:
> >
> > I calculate only 51, based on the assumption that we can only have
> > NSS==8. Even if you think NSS==16 (which I doubt), I get to 80 only?
>
> So total max length would be 81 bytes
>

Right. Now I don't know how I got to 80...

Regardless, I don't think NSS>8 is actually valid, the PHY spec always
says it's max of 8, so I think we can safely limit to 51?

johannes

2022-02-04 19:42:16

by Veerendranath Jakkam

[permalink] [raw]
Subject: Re: [PATCH 3/6] nl80211: add support to send EHT capabilities from userspace

On 2/3/22 6:17 PM, Johannes Berg wrote:
> On Wed, 2021-12-22 at 14:34 +0530, Veerendranath Jakkam wrote:
>> +#define NL80211_EHT_MIN_CAPABILITY_LEN 10
>>
> And that's 13, no? You have to support 80 MHz.
>
> johannes

I considered fixed fields lengths only for minimum length.

But I agree that we can include minimum possible length of MCS-NSS Set
field also.


2022-02-04 23:21:02

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 3/6] nl80211: add support to send EHT capabilities from userspace

On Wed, 2021-12-22 at 14:34 +0530, Veerendranath Jakkam wrote:
>
> +#define NL80211_EHT_MIN_CAPABILITY_LEN 10
>

And that's 13, no? You have to support 80 MHz.

johannes

2022-02-05 17:29:55

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 3/6] nl80211: add support to send EHT capabilities from userspace

On Fri, 2022-02-04 at 20:07 +0530, Veerendranath Jakkam wrote:
>
> There are some references for NSS > 8, ex: Table 9-33a, P802.11be_D1.3
> hence I used 81.

Right, the spec confuses me. In a lot of places it reserves enough space
for 8 < NSS <= 16, but then it has e.g. Table 36-40 with 4 bits, but
saying "for up to 8 spatial streams" (MU-MIMO). And even for OFDMA it
states in a lot of places that the maximum is only 8.

> Please let me know if you would like this to be changed to 51
>
Nah, don't worry. I think it probably doesn't even really *matter*, we
can safely leave it at 81 anyway (I had evidently miscalculated as 80
before, so I was confused).

We also already had some patches in this area, and I'm just working on a
combination - e.g. in your first patch I don't like the use of FIELD_GET
so much, preferring uXX_get_bits(), but Ilan already had patches here
that deal with that.

For many of the other patches, Ilan and you arrived at a literally bit-
identical version of things!

So I think I'm going to pick a couple of things from him and a couple of
things from you, and send out a combined series. Perhaps later today, if
I manage to get it done.

Also in your later nl80211 patch I'm thinking we should combine the
HE/EHT GI settings etc., there's no point duplicating all the enums,
though we might want to do some renaming.

Sounds OK?

johannes

2022-02-05 18:49:32

by Veerendranath Jakkam

[permalink] [raw]
Subject: Re: [PATCH 3/6] nl80211: add support to send EHT capabilities from userspace

On 2/3/22 6:15 PM, Johannes Berg wrote:
> On Wed, 2021-12-22 at 14:34 +0530, Veerendranath Jakkam wrote:
>>
>> +#define NL80211_EHT_MIN_CAPABILITY_LEN 10
>> +#define NL80211_EHT_MAX_CAPABILITY_LEN 81
>>
> How did you get to 81?
>
> I calculate only 51, based on the assumption that we can only have
> NSS==8. Even if you think NSS==16 (which I doubt), I get to 80 only?
>
> johannes

I considered max values for NSS and RU Index Bitmask sub-fields in PPE
threshold field.

i.e. NSS=16, RU Index Bitmask = 0x11111 with this max PPE threshold info
sub-field length is 60 bytes


Max PPE thresholds field length = 4 bits (for NSS) + 5 bits (for RU
Index Bitmask) +  480 bits (PPE info) + 7 bits (PPE pad)= 62 bytes

EHT fixed fields length = 10 bytes

Max MCS-NSS Set field length = 9 bytes

So total max length would be 81 bytes

2022-02-07 15:26:16

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 6/6] nl80211: add EHT MCS support

On Wed, 2021-12-22 at 14:34 +0530, Veerendranath Jakkam wrote:
>
> + * @NL80211_RATE_INFO_EHT_NSS: EHT NSS value (u8, 1-8)
>

I'll note you also put 1-8 here ;-)

johannes

2022-02-07 19:25:18

by Veerendranath Jakkam

[permalink] [raw]
Subject: Re: [PATCH 3/6] nl80211: add support to send EHT capabilities from userspace

On 2/4/22 11:15 PM, Johannes Berg wrote:
> On Fri, 2022-02-04 at 23:13 +0530, Veerendranath Jakkam wrote:
>>
>>> Also in your later nl80211 patch I'm thinking we should combine the
>>> HE/EHT GI settings etc., there's no point duplicating all the enums,
>>> though we might want to do some renaming.
> I actually just decided against that ... it gets messy because we still
> need the attributes, and the GI is the only one that's entirely the
> same, so I think probably duplicating that is more understandable (all
> the EHT stuff belongs together)...
>
>> meanwhile I will upload new patch set with the suggested changes in last
>> patch.
> No need. I'm doing rework on this, and we also have mac80211 assoc
> patches, STA capabilities, etc. I'll send it all out soon.
>
> johannes


Thank a lot for your assistance. Looking forward to see your patches.. :)


veeru



2022-02-08 09:06:51

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 3/6] nl80211: add support to send EHT capabilities from userspace

On Fri, 2022-02-04 at 23:13 +0530, Veerendranath Jakkam wrote:
>
>
> > Also in your later nl80211 patch I'm thinking we should combine the
> > HE/EHT GI settings etc., there's no point duplicating all the enums,
> > though we might want to do some renaming.

I actually just decided against that ... it gets messy because we still
need the attributes, and the GI is the only one that's entirely the
same, so I think probably duplicating that is more understandable (all
the EHT stuff belongs together)...

>
> meanwhile I will upload new patch set with the suggested changes in last
> patch.

No need. I'm doing rework on this, and we also have mac80211 assoc
patches, STA capabilities, etc. I'll send it all out soon.

johannes

2022-02-09 11:55:28

by Veerendranath Jakkam

[permalink] [raw]
Subject: Re: [PATCH 3/6] nl80211: add support to send EHT capabilities from userspace

On 2/4/22 1:41 PM, Johannes Berg wrote:
> On Fri, 2022-02-04 at 12:42 +0530, Veerendranath Jakkam wrote:
>>> I calculate only 51, based on the assumption that we can only have
>>> NSS==8. Even if you think NSS==16 (which I doubt), I get to 80 only?
>> So total max length would be 81 bytes
>>
> Right. Now I don't know how I got to 80...
>
> Regardless, I don't think NSS>8 is actually valid, the PHY spec always
> says it's max of 8, so I think we can safely limit to 51?
>
> johannes


There are some references for NSS > 8, ex: Table 9-33a, P802.11be_D1.3
hence I used 81.

Please let me know if you would like this to be changed to 51


2022-02-10 05:39:39

by Aloka Dixit

[permalink] [raw]
Subject: RE: [PATCH 2/6] nl80211: add support to advertise driver's EHT capabilities

Hi Johannes,

Considering that 20MHz-only STA and one that supports other bandwidths will not occur at the same time,
instead of a separate field for struct ieee80211_eht_mcs_nss_supp_20mhz_only inside struct ieee80211_eht_mcs_nss_supp, we can use a byte array as we added in here:
https://patchwork.kernel.org/project/linux-wireless/patch/[email protected]/
Instead of length field with dynamic allocation we can have an array of size 9 bytes.

Anyway most operations still need to differentiate between 20MHz-only and other cases, it will just change how many bytes those operations process (4 vs 3,6,9).

What do you think?

2022-02-10 10:02:54

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 2/6] nl80211: add support to advertise driver's EHT capabilities

On Thu, 2022-02-10 at 05:14 +0000, Aloka Dixit (QUIC) wrote:
> Hi Johannes,
>
> Considering that 20MHz-only STA and one that supports other bandwidths will not occur at the same time,
> instead of a separate field for struct ieee80211_eht_mcs_nss_supp_20mhz_only inside struct ieee80211_eht_mcs_nss_supp, we can use a byte array as we added in here:
> https://patchwork.kernel.org/project/linux-wireless/patch/[email protected]/
> Instead of length field with dynamic allocation we can have an array of size 9 bytes.
>

We did something like that in our patches:

https://patchwork.kernel.org/project/linux-wireless/patch/20220204230119.b0eeb527d761.I2413a37c8f7d2d6d638038a3d95360a3fce0114d@changeid/
https://patchwork.kernel.org/project/linux-wireless/patch/20220204230119.1ee92202ac30.Id30a3ef2844b296efbd5486fe1da9ca36a95c5cf@changeid/

Not overlapping wastes like 4 bytes of memory, I think I can live with
that, vs. the extra complexity? If you overlap you need another bit to
indicate which one you're using ...

johannes

2022-02-10 12:51:32

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 2/6] nl80211: add support to advertise driver's EHT capabilities

On Thu, 2022-02-10 at 09:26 +0100, Johannes Berg wrote:
> >
> > Considering that 20MHz-only STA and one that supports other bandwidths will not occur at the same time,
> > instead of a separate field for struct ieee80211_eht_mcs_nss_supp_20mhz_only inside struct ieee80211_eht_mcs_nss_supp, we can use a byte array as we added in here:
> > https://patchwork.kernel.org/project/linux-wireless/patch/[email protected]/
> > Instead of length field with dynamic allocation we can have an array of size 9 bytes.
> >
>
> We did something like that in our patches:
>
> https://patchwork.kernel.org/project/linux-wireless/patch/20220204230119.b0eeb527d761.I2413a37c8f7d2d6d638038a3d95360a3fce0114d@changeid/
> https://patchwork.kernel.org/project/linux-wireless/patch/20220204230119.1ee92202ac30.Id30a3ef2844b296efbd5486fe1da9ca36a95c5cf@changeid/
>
> Not overlapping wastes like 4 bytes of memory, I think I can live with
> that, vs. the extra complexity? If you overlap you need another bit to
> indicate which one you're using ...
>

OTOH, that means we need to unwrap it in userspace, which is also
strange ... So yeah I'm changing it to a union.

johannes

2022-02-10 16:37:34

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 2/6] nl80211: add support to advertise driver's EHT capabilities

On Thu, 2022-02-10 at 15:57 +0000, Aloka Dixit (QUIC) wrote:
>
>
> My comment was actually about your Patches but realized I hadn't
> subscribed this email with the mailing list so never got emails for
> those.

Oh.

> So replied here (as I am in cc), just pasted wrong link ????

Ah ok :)

>
> But yeah, union would work.

I'll also make all the pieces have the right size in nl80211.

johannes

2022-02-10 23:45:43

by Aloka Dixit

[permalink] [raw]
Subject: RE: [PATCH 2/6] nl80211: add support to advertise driver's EHT capabilities

> We did something like that in our patches:
>
> https://patchwork.kernel.org/project/linux-wireless/patch/20220204230119.b0eeb527d761.I2413a37c8f7d2d6d638038a3d95360a3fce0114d@changeid/
> https://patchwork.kernel.org/project/linux-wireless/patch/20220204230119.1ee92202ac30.Id30a3ef2844b296efbd5486fe1da9ca36a95c5cf@changeid/
>
> Not overlapping wastes like 4 bytes of memory, I think I can live with
> that, vs. the extra complexity? If you overlap you need another bit to
> indicate which one you're using ...
>

OTOH, that means we need to unwrap it in userspace, which is also
strange ... So yeah I'm changing it to a union.

Johannes

My comment was actually about your Patches but realized I hadn't subscribed this email with the mailing list so never got emails for those.
So replied here (as I am in cc), just pasted wrong link ????

But yeah, union would work.
Thanks.