From: Luca Coelho <luciano.coe...@intel.com>

Add support for the HE in cfg80211 and also add userspace API to
nl80211 to send rate information out, conforming with P802.11ax_D1.4.

Additionally, remove the IEEE80211_MAX_AMPDU_BUF definition from some
realtek drivers in staging because they are now conflicting with the
new definitions and are not used anyway.

Signed-off-by: Liad Kaufman <liad.kauf...@intel.com>
Signed-off-by: Johannes Berg <johannes.b...@intel.com>
Signed-off-by: Ilan Peer <ilan.p...@intel.com>
Signed-off-by: Ido Yariv <idox.ya...@intel.com>
Signed-off-by: Luca Coelho <luciano.coe...@intel.com>
---
 drivers/staging/rtl8188eu/include/wifi.h |   1 -
 drivers/staging/rtl8712/wifi.h           |   1 -
 drivers/staging/rtl8723bs/include/wifi.h |   1 -
 include/linux/ieee80211.h                | 431 ++++++++++++++++++++++-
 include/net/cfg80211.h                   | 102 +++++-
 include/uapi/linux/nl80211.h             |  87 ++++-
 net/wireless/core.c                      |  21 +-
 net/wireless/nl80211.c                   |  99 +++++-
 net/wireless/util.c                      |  82 +++++
 9 files changed, 813 insertions(+), 12 deletions(-)

diff --git a/drivers/staging/rtl8188eu/include/wifi.h 
b/drivers/staging/rtl8188eu/include/wifi.h
index 084a246eec19..6790b7c8cfb1 100644
--- a/drivers/staging/rtl8188eu/include/wifi.h
+++ b/drivers/staging/rtl8188eu/include/wifi.h
@@ -575,7 +575,6 @@ enum ht_cap_ampdu_factor {
  * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2)
  */
 #define IEEE80211_MIN_AMPDU_BUF 0x8
-#define IEEE80211_MAX_AMPDU_BUF 0x40
 
 
 #define OP_MODE_PURE                    0
diff --git a/drivers/staging/rtl8712/wifi.h b/drivers/staging/rtl8712/wifi.h
index 0ed2f44ab4e9..00a4302e9983 100644
--- a/drivers/staging/rtl8712/wifi.h
+++ b/drivers/staging/rtl8712/wifi.h
@@ -574,7 +574,6 @@ struct ieee80211_ht_addt_info {
  * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2)
  */
 #define IEEE80211_MIN_AMPDU_BUF 0x8
-#define IEEE80211_MAX_AMPDU_BUF 0x40
 
 
 /* Spatial Multiplexing Power Save Modes */
diff --git a/drivers/staging/rtl8723bs/include/wifi.h 
b/drivers/staging/rtl8723bs/include/wifi.h
index 530d698f50d9..e6477acfa961 100644
--- a/drivers/staging/rtl8723bs/include/wifi.h
+++ b/drivers/staging/rtl8723bs/include/wifi.h
@@ -807,7 +807,6 @@ enum HT_CAP_AMPDU_FACTOR {
  * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2)
  */
 #define IEEE80211_MIN_AMPDU_BUF 0x8
-#define IEEE80211_MAX_AMPDU_BUF 0x40
 
 
 /* Spatial Multiplexing Power Save Modes */
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 8fe7e4306816..7e1a650be329 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1433,11 +1433,13 @@ struct ieee80211_ht_operation {
 #define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800
 
 /*
- * A-PMDU buffer sizes
- * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2)
+ * A-MPDU buffer sizes
+ * According to HT size varies from 8 to 64 frames
+ * HE adds the ability to have up to 256 frames.
  */
-#define IEEE80211_MIN_AMPDU_BUF 0x8
-#define IEEE80211_MAX_AMPDU_BUF 0x40
+#define IEEE80211_MIN_AMPDU_BUF                0x8
+#define IEEE80211_MAX_AMPDU_BUF_HT     0x40
+#define IEEE80211_MAX_AMPDU_BUF                0x100
 
 
 /* Spatial Multiplexing Power Save Modes (for capability) */
@@ -1539,6 +1541,106 @@ struct ieee80211_vht_operation {
        __le16 basic_mcs_set;
 } __packed;
 
+/**
+ * struct ieee80211_he_cap_elem - HE capabilities element
+ *
+ * This structure is the "HE capabilities element" fixed fields as
+ * described in P802.11ax_D1.4 section 9.4.2.237.1
+ */
+struct ieee80211_he_cap_elem {
+       u8 mac_cap_info[5];
+       u8 phy_cap_info[9];
+} __packed;
+
+#define IEEE80211_TX_RX_MCS_NSS_DESC_MAX_LEN   5
+
+/**
+ * enum ieee80211_he_mcs_support - HE MCS support definitions
+ * @IEEE80211_HE_MCS_SUPPORT_0_7: MCSes 0-7 are supported for the
+ *     number of streams
+ * @IEEE80211_HE_MCS_SUPPORT_0_9: MCSes 0-9 are supported
+ * @IEEE80211_HE_MCS_SUPPORT_0_11: MCSes 0-11 are supported
+ * @IEEE80211_HE_MCS_NOT_SUPPORTED: This number of streams isn't supported
+ *
+ * These definitions are used in each 2-bit subfield of the rx_mcs_*
+ * and tx_mcs_* fields of &struct ieee80211_he_mcs_nss_supp, which are
+ * both split into 8 subfields by number of streams. These values indicate
+ * which MCSes are supported for the number of streams the value appears
+ * for.
+ */
+enum ieee80211_he_mcs_support {
+       IEEE80211_HE_MCS_SUPPORT_0_7    = 0,
+       IEEE80211_HE_MCS_SUPPORT_0_9    = 1,
+       IEEE80211_HE_MCS_SUPPORT_0_11   = 2,
+       IEEE80211_HE_MCS_NOT_SUPPORTED  = 3,
+};
+
+/**
+ * struct ieee80211_he_mcs_nss_supp - HE Tx/Rx HE MCS NSS Support Field
+ *
+ * This structure holds the data required for the Tx/Rx HE MCS NSS Support 
Field
+ * described in P802.11ax_D1.4 section 9.4.2.237.4
+ *
+ * @rx_msc_80: Rx MCS map 2 bits for each stream, total 8 streams, for channel
+ *     widths less than 80MHz.
+ * @tx_msc_80: Tx MCS map 2 bits for each stream, total 8 streams, for channel
+ *     widths less than 80MHz.
+ * @rx_msc_160: Rx MCS map 2 bits for each stream, total 8 streams, for channel
+ *     width 160MHz.
+ * @tx_msc_160: Tx MCS map 2 bits for each stream, total 8 streams, for channel
+ *     width 160MHz.
+ * @rx_msc_80p80: Rx MCS map 2 bits for each stream, total 8 streams, for
+ *     channel width 80p80MHz.
+ * @tx_msc_80p80: Tx MCS map 2 bits for each stream, total 8 streams, for
+ *     channel width 80p80MHz.
+ */
+struct ieee80211_he_mcs_nss_supp {
+       __le16 rx_msc_80;
+       __le16 tx_msc_80;
+       __le16 rx_msc_160;
+       __le16 tx_msc_160;
+       __le16 rx_msc_80p80;
+       __le16 tx_msc_80p80;
+} __packed;
+
+/**
+ * struct ieee80211_he_operation - HE capabilities element
+ *
+ * This structure is the "HE operation element" fields as
+ * described in P802.11ax_D1.4 section 9.4.2.238
+ */
+struct ieee80211_he_operation {
+       __le32 he_oper_params;
+       __le16 he_mcs_nss_set;
+       /* Optional 0,1,3 or 4 bytes: depends on %he_oper_params */
+       u8 optional[0];
+} __packed;
+
+/**
+ * struct ieee80211_he_mu_edca_param_ac_rec - MU AC Parameter Record field
+ *
+ * This structure is the "MU AC Parameter Record" fields as
+ * described in P802.11ax_D1.4 section 9.4.2.240
+ */
+struct ieee80211_he_mu_edca_param_ac_rec {
+       u8 aifsn;
+       u8 ecw_min_max;
+       u8 mu_edca_timer;
+} __packed;
+
+/**
+ * struct ieee80211_mu_edca_param_set - MU EDCA Parameter Set element
+ *
+ * This structure is the "MU EDCA Parameter Set element" fields as
+ * described in P802.11ax_D1.4 section 9.4.2.240
+ */
+struct ieee80211_mu_edca_param_set {
+       u8 mu_qos_info;
+       struct ieee80211_he_mu_edca_param_ac_rec ac_be;
+       struct ieee80211_he_mu_edca_param_ac_rec ac_bk;
+       struct ieee80211_he_mu_edca_param_ac_rec ac_vi;
+       struct ieee80211_he_mu_edca_param_ac_rec ac_vo;
+} __packed;
 
 /* 802.11ac VHT Capabilities */
 #define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895                 0x00000000
@@ -1577,6 +1679,322 @@ struct ieee80211_vht_operation {
 #define IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN                   0x10000000
 #define IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN                   0x20000000
 
+/* 802.11ax HE MAC capabilities */
+#define IEEE80211_HE_MAC_CAP0_HTC_HE                           0x01
+#define IEEE80211_HE_MAC_CAP0_TWT_REQ                          0x02
+#define IEEE80211_HE_MAC_CAP0_TWT_RES                          0x04
+#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_NOT_SUPP            0x00
+#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_LEVEL_1             0x08
+#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_LEVEL_2             0x10
+#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_LEVEL_3             0x18
+#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_MASK                        0x18
+#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_1              0x00
+#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_2              0x20
+#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_4              0x40
+#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_8              0x60
+#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_16             0x80
+#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_32             0xa0
+#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_64             0xc0
+#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_UNLIMITED      0xe0
+#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_MASK           0xe0
+
+#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_UNLIMITED          0x00
+#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_128                        0x01
+#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_256                        0x02
+#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_512                        0x03
+#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_MASK               0x03
+#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_0US               0x00
+#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_8US               0x04
+#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US              0x08
+#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK              0x0c
+#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_1              0x00
+#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_2              0x10
+#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_3              0x20
+#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_4              0x30
+#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_5              0x40
+#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_6              0x50
+#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_7              0x60
+#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_8              0x70
+#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_MASK           0x70
+
+/* Link adaptation is split between byte #2 and byte #3. It should be set only
+ * if IEEE80211_HE_MAC_CAP0_HTC_HE in which case the following values apply:
+ * 0 = No feedback.
+ * 1 = reserved.
+ * 2 = Unsolicited feedback.
+ * 3 = both
+ */
+#define IEEE80211_HE_MAC_CAP1_LINK_ADAPTATION                  0x80
+
+#define IEEE80211_HE_MAC_CAP2_LINK_ADAPTATION                  0x01
+#define IEEE80211_HE_MAC_CAP2_ALL_ACK                          0x02
+#define IEEE80211_HE_MAC_CAP2_UL_MU_RESP_SCHED                 0x04
+#define IEEE80211_HE_MAC_CAP2_BSR                              0x08
+#define IEEE80211_HE_MAC_CAP2_BCAST_TWT                                0x10
+#define IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP                  0x20
+#define IEEE80211_HE_MAC_CAP2_MU_CASCADING                     0x40
+#define IEEE80211_HE_MAC_CAP2_ACK_EN_MULTI_TID_ADD             0x80
+
+#define IEEE80211_HE_MAC_CAP3_GRP_ADDR_MULTI_STA_BA_DL_MU      0x01
+#define IEEE80211_HE_MAC_CAP3_OMI_CONTROL                      0x02
+#define IEEE80211_HE_MAC_CAP3_OFDMA_RA                         0x04
+
+/* The maximum length of an A-MDPU is defined by the combination of the Maximum
+ * A-MDPU Length Exponent field in the HT capabilities, VHT capabilities and 
the
+ * same field in the HE capabilities.
+ */
+#define IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_USE_VHT      0x00
+#define IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_1                0x08
+#define IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_2                0x10
+#define IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_RESERVED     0x18
+#define IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_MASK         0x18
+#define IEEE80211_HE_MAC_CAP3_A_AMSDU_FRAG                     0x20
+#define IEEE80211_HE_MAC_CAP3_FLEX_TWT_SCHED                   0x40
+#define IEEE80211_HE_MAC_CAP3_RX_CTRL_FRAME_TO_MULTIBSS                0x80
+
+#define IEEE80211_HE_MAC_CAP4_BSRP_A_MPDU_AGG                  0x01
+#define IEEE80211_HE_MAC_CAP4_QTP                              0x02
+#define IEEE80211_HE_MAC_CAP4_BQR                              0x04
+#define IEEE80211_HE_MAC_CAP4_SR_RESP                          0x08
+#define IEEE80211_HE_MAC_CAP4_NDP_FB_REP                       0x10
+#define IEEE80211_HE_MAC_CAP4_OPS                              0x20
+
+/* 802.11ax HE PHY capabilities */
+#define IEEE80211_HE_PHY_CAP0_DUAL_BAND                                        
0x01
+#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G            0x02
+#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G      0x04
+#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G           0x08
+#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G     0x10
+#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G       0x20
+#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G       0x40
+#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK                   0xfe
+
+#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_80MHZ_ONLY_SECOND_20MHZ 0x01
+#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_80MHZ_ONLY_SECOND_40MHZ 0x02
+#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_160MHZ_ONLY_SECOND_20MHZ        
0x04
+#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_160MHZ_ONLY_SECOND_40MHZ        
0x08
+#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK                    0x0f
+#define IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A                           0x10
+#define IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD                   0x20
+#define IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US         0x40
+/* Bit 7 of CAP1 is reserved, as well as bit 0 of CAP2 */
+
+#define IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US                     0x02
+#define IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ                      0x04
+#define IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ                      0x08
+#define IEEE80211_HE_PHY_CAP2_DOPPLER_TX                               0x10
+#define IEEE80211_HE_PHY_CAP2_DOPPLER_RX                               0x20
+
+/* Note that the meaning of UL MU below is different between an AP and a non-AP
+ * sta, where in the AP case it indicates support for Rx and in the non-AP sta
+ * case it indicates support for Tx.
+ */
+#define IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO                       0x40
+#define IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO                    0x80
+
+#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM                  0x00
+#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_BPSK                    0x01
+#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK                    0x02
+#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_16_QAM                  0x03
+#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK                    0x03
+#define IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1                         0x00
+#define IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_2                         0x04
+#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_NO_DCM                  0x00
+#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_BPSK                    0x08
+#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK                    0x10
+#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM                  0x18
+#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK                    0x18
+#define IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1                         0x00
+#define IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_2                         0x20
+#define IEEE80211_HE_PHY_CAP3_UL_HE_MU_PPDU                            0x40
+#define IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER                            0x80
+
+#define IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE                            0x01
+#define IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER                            0x02
+
+/* Minimal allowed value of Max STS under 80MHz is 3 */
+#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4         0x0c
+#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_5         0x10
+#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_6         0x14
+#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_7         0x18
+#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8         0x1c
+#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK      0x1c
+
+/* Minimal allowed value of Max STS above 80MHz is 3 */
+#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4         0x60
+#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_5         0x80
+#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_6         0xa0
+#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_7         0xc0
+#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8         0xe0
+#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK      0xe0
+
+#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_1     0x00
+#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2     0x01
+#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_3     0x02
+#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_4     0x03
+#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_5     0x04
+#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_6     0x05
+#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_7     0x06
+#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_8     0x07
+#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK  0x07
+
+#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_1     0x00
+#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2     0x08
+#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_3     0x10
+#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_4     0x18
+#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_5     0x20
+#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_6     0x28
+#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_7     0x30
+#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_8     0x38
+#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK  0x38
+
+#define IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK                         0x40
+#define IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK                         0x80
+
+#define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU                      0x01
+#define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU                      0x02
+#define IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB                    0x04
+#define IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB                    0x08
+#define IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB                              0x10
+#define IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE                     0x20
+#define IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO              0x40
+#define IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT                    0x80
+
+#define IEEE80211_HE_PHY_CAP7_SRP_BASED_SR                             0x01
+#define IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR                    0x02
+#define IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI         0x04
+#define IEEE80211_HE_PHY_CAP7_MAX_NC_1                                 0x08
+#define IEEE80211_HE_PHY_CAP7_MAX_NC_2                                 0x10
+#define IEEE80211_HE_PHY_CAP7_MAX_NC_3                                 0x18
+#define IEEE80211_HE_PHY_CAP7_MAX_NC_4                                 0x20
+#define IEEE80211_HE_PHY_CAP7_MAX_NC_5                                 0x28
+#define IEEE80211_HE_PHY_CAP7_MAX_NC_6                                 0x30
+#define IEEE80211_HE_PHY_CAP7_MAX_NC_7                                 0x38
+#define IEEE80211_HE_PHY_CAP7_MAX_NC_MASK                              0x38
+#define IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ                      0x40
+#define IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ                      0x80
+
+#define IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI         0x01
+#define IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G             0x02
+#define IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU                  0x04
+#define IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU                  0x08
+
+/* 802.11ax HE TX/RX MCS NSS Support  */
+#define IEEE80211_TX_RX_MCS_NSS_SUPP_HIGHEST_MCS_POS                   (3)
+#define IEEE80211_TX_RX_MCS_NSS_SUPP_TX_BITMAP_POS                     (6)
+#define IEEE80211_TX_RX_MCS_NSS_SUPP_RX_BITMAP_POS                     (11)
+#define IEEE80211_TX_RX_MCS_NSS_SUPP_TX_BITMAP_MASK                    0x07c0
+#define IEEE80211_TX_RX_MCS_NSS_SUPP_RX_BITMAP_MASK                    0xf800
+
+/* TX/RX HE MCS Support field Highest MCS subfield encoding */
+enum ieee80211_he_highest_mcs_supported_subfield_enc {
+       HIGHEST_MCS_SUPPORTED_MCS7 = 0,
+       HIGHEST_MCS_SUPPORTED_MCS8,
+       HIGHEST_MCS_SUPPORTED_MCS9,
+       HIGHEST_MCS_SUPPORTED_MCS10,
+       HIGHEST_MCS_SUPPORTED_MCS11,
+};
+
+/* Calculate 802.11ax HE capabilities IE Tx/Rx HE MCS NSS Support Field size */
+static inline u8
+ieee80211_he_mcs_nss_size(const struct ieee80211_he_cap_elem *he_cap)
+{
+       u8 count = 4;
+
+       if (he_cap->phy_cap_info[0] &
+           IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
+               count += 4;
+
+       if (he_cap->phy_cap_info[0] &
+           IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
+               count += 4;
+
+       return count;
+}
+
+/* 802.11ax HE PPE Thresholds */
+#define IEEE80211_PPE_THRES_NSS_M1_SUPPORT_2NSS                        (1)
+#define IEEE80211_PPE_THRES_NSS_M1_POS                         (0)
+#define IEEE80211_PPE_THRES_NSS_M1_MASK                                (7)
+#define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_2x966_AND_966_RU  \
+       (BIT(5) | BIT(6))
+#define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK              0x78
+#define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS               (3)
+#define IEEE80211_PPE_THRES_INFO_PPET_SIZE                     (3)
+
+/*
+ * Calculate 802.11ax HE capabilities IE PPE field size
+ * Input: Header byte of ppe_thres (first byte), and HE capa IE's PHY cap u8*
+ */
+static inline u8
+ieee80211_he_ppe_size(u8 ppe_thres_hdr, const u8 *phy_cap_info)
+{
+       u8 n;
+
+       if ((phy_cap_info[6] &
+            IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) == 0)
+               return 0;
+
+       n = hweight8(ppe_thres_hdr &
+                    IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK);
+       n *= (1 + ((ppe_thres_hdr & IEEE80211_PPE_THRES_NSS_M1_MASK) >>
+                  IEEE80211_PPE_THRES_NSS_M1_POS));
+
+       /*
+        * Each pair is 6 bits, and we need to add the 7 "header" bits to the
+        * total size.
+        */
+       n = (n * IEEE80211_PPE_THRES_INFO_PPET_SIZE * 2) + 7;
+       n = DIV_ROUND_UP(n, 8);
+
+       return n;
+}
+
+/* HE Operation defines */
+#define IEEE80211_HE_OPERATION_BSS_COLOR_MASK                  0x0000003f
+#define IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK           0x000001c0
+#define IEEE80211_HE_OPERATION_DFLT_PE_DURATION_OFFSET         6
+#define IEEE80211_HE_OPERATION_TWT_REQUIRED                    0x00000200
+#define IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK              0x000ffc00
+#define IEEE80211_HE_OPERATION_RTS_THRESHOLD_OFFSET            10
+#define IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR               0x000100000
+#define IEEE80211_HE_OPERATION_VHT_OPER_INFO                   0x000200000
+#define IEEE80211_HE_OPERATION_MULTI_BSSID_AP                  0x10000000
+#define IEEE80211_HE_OPERATION_TX_BSSID_INDICATOR              0x20000000
+#define IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED              0x40000000
+
+/*
+ * ieee80211_he_oper_size - calculate 802.11ax HE Operations IE size
+ * @he_oper_ie: byte data of the He Operations IE, stating from the the byte
+ *     after the ext ID byte. It is assumed that he_oper_ie has at least
+ *     sizeof(struct ieee80211_he_operation) bytes, checked already in
+ *     ieee802_11_parse_elems_crc()
+ * @return the actual size of the IE data (not including header), or 0 on error
+ */
+static inline u8
+ieee80211_he_oper_size(const u8 *he_oper_ie)
+{
+       struct ieee80211_he_operation *he_oper = (void *)he_oper_ie;
+       u8 oper_len = sizeof(struct ieee80211_he_operation);
+       u32 he_oper_params;
+
+       /* Make sure the input is not NULL */
+       if (!he_oper_ie)
+               return 0;
+
+       /* Calc required length */
+       he_oper_params = le32_to_cpu(he_oper->he_oper_params);
+       if (he_oper_params & IEEE80211_HE_OPERATION_VHT_OPER_INFO)
+               oper_len += 3;
+       if (he_oper_params & IEEE80211_HE_OPERATION_MULTI_BSSID_AP)
+               oper_len++;
+
+       /* Add the first byte (extension ID) to the total length */
+       oper_len++;
+
+       return oper_len;
+}
+
 /* Authentication algorithms */
 #define WLAN_AUTH_OPEN 0
 #define WLAN_AUTH_SHARED_KEY 1
@@ -1992,6 +2410,11 @@ enum ieee80211_eid_ext {
        WLAN_EID_EXT_FILS_WRAPPED_DATA = 8,
        WLAN_EID_EXT_FILS_PUBLIC_KEY = 12,
        WLAN_EID_EXT_FILS_NONCE = 13,
+       WLAN_EID_EXT_FUTURE_CHAN_GUIDANCE = 14,
+       WLAN_EID_EXT_HE_CAPABILITY = 35,
+       WLAN_EID_EXT_HE_OPERATION = 36,
+       WLAN_EID_EXT_UORA = 37,
+       WLAN_EID_EXT_HE_MU_EDCA = 38,
 };
 
 /* Action category code */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 8db6071b6063..074c016ed2eb 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -285,6 +285,40 @@ struct ieee80211_sta_vht_cap {
        struct ieee80211_vht_mcs_info vht_mcs;
 };
 
+#define IEEE80211_HE_PPE_THRES_MAX_LEN         25
+
+/**
+ * struct ieee80211_sta_he_cap - STA's HE capabilities
+ *
+ * This structure describes most essential parameters needed
+ * to describe 802.11ax HE capabilities for a STA.
+ *
+ * @has_he: true iff HE data is valid.
+ * @he_cap_elem: Fixed portion of the HE capabilities element.
+ * @he_mcs_nss_supp: The supported NSS/MCS combinations.
+ * @ppe_thres: Holds the PPE Thresholds data.
+ */
+struct ieee80211_sta_he_cap {
+       bool has_he;
+       struct ieee80211_he_cap_elem he_cap_elem;
+       struct ieee80211_he_mcs_nss_supp he_mcs_nss_supp;
+       u8 ppe_thres[IEEE80211_HE_PPE_THRES_MAX_LEN];
+};
+
+/**
+ * struct ieee80211_sband_iftype_data
+ *
+ * This structure encapsulates sband data that is relevant for the interface
+ * types defined in %types
+ *
+ * @types: interface types (bits)
+ * @he_cap: holds the HE capabilities
+ */
+struct ieee80211_sband_iftype_data {
+       u16 types;
+       struct ieee80211_sta_he_cap he_cap;
+};
+
 /**
  * struct ieee80211_supported_band - frequency band definition
  *
@@ -301,6 +335,8 @@ struct ieee80211_sta_vht_cap {
  * @n_bitrates: Number of bitrates in @bitrates
  * @ht_cap: HT capabilities in this band
  * @vht_cap: VHT capabilities in this band
+ * @n_iftype_data: number of iftype data entries
+ * @iftype_data: interface type data entries
  */
 struct ieee80211_supported_band {
        struct ieee80211_channel *channels;
@@ -310,8 +346,55 @@ struct ieee80211_supported_band {
        int n_bitrates;
        struct ieee80211_sta_ht_cap ht_cap;
        struct ieee80211_sta_vht_cap vht_cap;
+       u16 n_iftype_data;
+       const struct ieee80211_sband_iftype_data *iftype_data;
 };
 
+/**
+ * ieee80211_get_sband_ift_data - return sband data for a given iftype
+ * @sband: the sband to search for the STA on
+ * @iftype: enum nl80211_iftype
+ *
+ * Return: pointer to the struct ieee80211_sband_iftype_data, or NULL is none 
found
+ */
+static inline const struct ieee80211_sband_iftype_data *
+ieee80211_get_sband_ift_data(const struct ieee80211_supported_band *sband,
+                            u8 iftype)
+{
+       int i;
+
+       if (WARN_ON(iftype >= NL80211_IFTYPE_MAX))
+               return NULL;
+
+       for (i = 0; i < sband->n_iftype_data; i++)  {
+               const struct ieee80211_sband_iftype_data *data =
+                       &sband->iftype_data[i];
+
+               if (data->types & BIT(iftype))
+                       return data;
+       }
+
+       return NULL;
+}
+
+/**
+ * ieee80211_get_he_sta_cap - return HE capabilities for an sband's STA
+ * @sband: the sband to search for the STA on
+ *
+ * Return: pointer to the struct ieee80211_sta_he_cap, or NULL is none found
+ */
+static inline const struct ieee80211_sta_he_cap *
+ieee80211_get_he_sta_cap(const struct ieee80211_supported_band *sband)
+{
+       const struct ieee80211_sband_iftype_data *data =
+               ieee80211_get_sband_ift_data(sband, NL80211_IFTYPE_STATION);
+
+       if (data && data->he_cap.has_he)
+               return &data->he_cap;
+
+       return NULL;
+}
+
 /**
  * wiphy_read_of_freq_limits - read frequency limits from device tree
  *
@@ -899,6 +982,8 @@ enum station_parameters_apply_mask {
  * @opmode_notif: operating mode field from Operating Mode Notification
  * @opmode_notif_used: information if operating mode field is used
  * @support_p2p_ps: information if station supports P2P PS mechanism
+ * @he_capa: HE capabilities of station
+ * @he_capa_len: the length of the HE capabilities
  */
 struct station_parameters {
        const u8 *supported_rates;
@@ -926,6 +1011,8 @@ struct station_parameters {
        u8 opmode_notif;
        bool opmode_notif_used;
        int support_p2p_ps;
+       const struct ieee80211_he_cap_elem *he_capa;
+       u8 he_capa_len;
 };
 
 /**
@@ -1000,12 +1087,14 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
  * @RATE_INFO_FLAGS_VHT_MCS: mcs field filled with VHT MCS
  * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval
  * @RATE_INFO_FLAGS_60G: 60GHz MCS
+ * @RATE_INFO_FLAGS_HE_MCS: HE MCS information
  */
 enum rate_info_flags {
        RATE_INFO_FLAGS_MCS                     = BIT(0),
        RATE_INFO_FLAGS_VHT_MCS                 = BIT(1),
        RATE_INFO_FLAGS_SHORT_GI                = BIT(2),
        RATE_INFO_FLAGS_60G                     = BIT(3),
+       RATE_INFO_FLAGS_HE_MCS                  = BIT(4),
 };
 
 /**
@@ -1019,6 +1108,7 @@ enum rate_info_flags {
  * @RATE_INFO_BW_40: 40 MHz bandwidth
  * @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
  */
 enum rate_info_bw {
        RATE_INFO_BW_20 = 0,
@@ -1027,6 +1117,7 @@ enum rate_info_bw {
        RATE_INFO_BW_40,
        RATE_INFO_BW_80,
        RATE_INFO_BW_160,
+       RATE_INFO_BW_HE_RU,
 };
 
 /**
@@ -1035,10 +1126,14 @@ enum rate_info_bw {
  * Information about a receiving or transmitting bitrate
  *
  * @flags: bitflag of flags from &enum rate_info_flags
- * @mcs: mcs index if struct describes a 802.11n bitrate
+ * @mcs: mcs index if struct describes an HT/VHT/HE rate
  * @legacy: bitrate in 100kbit/s for 802.11abg
- * @nss: number of streams (VHT only)
+ * @nss: number of streams (VHT & HE only)
  * @bw: bandwidth (from &enum rate_info_bw)
+ * @he_gi: HE guard interval (from &enum nl80211_he_gi)
+ * @he_dcm: HE DCM value
+ * @he_ru_alloc: HE RU allocation (from &enum nl80211_he_ru_alloc,
+ *     only valid if bw is %RATE_INFO_BW_HE_RU)
  */
 struct rate_info {
        u8 flags;
@@ -1046,6 +1141,9 @@ struct rate_info {
        u16 legacy;
        u8 nss;
        u8 bw;
+       u8 he_gi;
+       u8 he_dcm;
+       u8 he_ru_alloc;
 };
 
 /**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 5e67e3444aba..04f2f8c2a4a6 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2235,6 +2235,9 @@ enum nl80211_commands {
  *      enforced.
  * @NL80211_ATTR_TXQ_QUANTUM: TXQ scheduler quantum (bytes). Number of bytes
  *      a flow is assigned on each round of the DRR scheduler.
+ * @NL80211_ATTR_HE_CAPABILITY: HE Capability information element (from
+ *     association request when used with NL80211_CMD_NEW_STATION). Can be set
+ *     only if &NL80211_STA_FLAG_WME is set.
  *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
@@ -2675,6 +2678,8 @@ enum nl80211_attrs {
        NL80211_ATTR_TXQ_MEMORY_LIMIT,
        NL80211_ATTR_TXQ_QUANTUM,
 
+       NL80211_ATTR_HE_CAPABILITY,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -2722,7 +2727,8 @@ enum nl80211_attrs {
 #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY    24
 #define NL80211_HT_CAPABILITY_LEN              26
 #define NL80211_VHT_CAPABILITY_LEN             12
-
+#define NL80211_HE_MIN_CAPABILITY_LEN           16
+#define NL80211_HE_MAX_CAPABILITY_LEN           51
 #define NL80211_MAX_NR_CIPHER_SUITES           5
 #define NL80211_MAX_NR_AKM_SUITES              2
 
@@ -2849,6 +2855,38 @@ struct nl80211_sta_flag_update {
        __u32 set;
 } __attribute__((packed));
 
+/**
+ * enum nl80211_he_gi - HE guard interval
+ * @NL80211_RATE_INFO_HE_GI_0_8: 0.8 usec
+ * @NL80211_RATE_INFO_HE_GI_1_6: 1.6 usec
+ * @NL80211_RATE_INFO_HE_GI_3_2: 3.2 usec
+ */
+enum nl80211_he_gi {
+       NL80211_RATE_INFO_HE_GI_0_8,
+       NL80211_RATE_INFO_HE_GI_1_6,
+       NL80211_RATE_INFO_HE_GI_3_2,
+};
+
+/**
+ * @enum nl80211_he_ru_alloc - HE RU allocation values
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_26: 26-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_52: 52-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_106: 106-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_242: 242-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_484: 484-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_996: 996-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_2x996: 2x996-tone RU allocation
+ */
+enum nl80211_he_ru_alloc {
+       NL80211_RATE_INFO_HE_RU_ALLOC_26,
+       NL80211_RATE_INFO_HE_RU_ALLOC_52,
+       NL80211_RATE_INFO_HE_RU_ALLOC_106,
+       NL80211_RATE_INFO_HE_RU_ALLOC_242,
+       NL80211_RATE_INFO_HE_RU_ALLOC_484,
+       NL80211_RATE_INFO_HE_RU_ALLOC_996,
+       NL80211_RATE_INFO_HE_RU_ALLOC_2x996,
+};
+
 /**
  * enum nl80211_rate_info - bitrate information
  *
@@ -2881,6 +2919,13 @@ struct nl80211_sta_flag_update {
  * @NL80211_RATE_INFO_5_MHZ_WIDTH: 5 MHz width - note that this is
  *     a legacy rate and will be reported as the actual bitrate, i.e.
  *     a quarter of the base (20 MHz) rate
+ * @NL80211_RATE_INFO_HE_MCS: HE MCS index (u8, 0-11)
+ * @NL80211_RATE_INFO_HE_NSS: HE NSS value (u8, 1-8)
+ * @NL80211_RATE_INFO_HE_GI: HE guard interval identifier
+ *     (u8, see &enum nl80211_he_gi)
+ * @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_AFTER_LAST: internal use
  */
 enum nl80211_rate_info {
@@ -2897,6 +2942,11 @@ enum nl80211_rate_info {
        NL80211_RATE_INFO_160_MHZ_WIDTH,
        NL80211_RATE_INFO_10_MHZ_WIDTH,
        NL80211_RATE_INFO_5_MHZ_WIDTH,
+       NL80211_RATE_INFO_HE_MCS,
+       NL80211_RATE_INFO_HE_NSS,
+       NL80211_RATE_INFO_HE_GI,
+       NL80211_RATE_INFO_HE_DCM,
+       NL80211_RATE_INFO_HE_RU_ALLOC,
 
        /* keep last */
        __NL80211_RATE_INFO_AFTER_LAST,
@@ -3162,6 +3212,38 @@ enum nl80211_mpath_info {
        NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1
 };
 
+/**
+ * enum nl80211_band_ift_attr - Interface type data attributes
+ *
+ * @__NL80211_BAND_IFT_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_BAND_IFT_ATTR_IFTYPES: nested attribute containing a flag attribute
+ *     for each interface type that supports the band data
+ * @NL80211_BAND_IFT_ATTR_HE_CAP_MAC: HE MAC capabilities as in HE
+ *     capabilities IE
+ * @NL80211_BAND_IFT_ATTR_HE_CAP_PHY: HE PHY capabilities as in HE
+ *     capabilities IE
+ * @NL80211_BAND_IFT_ATTR_HE_CAP_MCS_SET: HE supported NSS/MCS as in HE
+ *     capabilities IE
+ * @NL80211_BAND_IFT_ATTR_HE_CAP_PPE: HE PPE thresholds information as
+ *     defined in HE capabilities IE
+ * @NL80211_BAND_IFT_ATTR_MAX: highest band HE capability attribute currently
+ *     defined
+ * @__NL80211_BAND_IFT_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_band_ift_attr {
+       __NL80211_BAND_IFT_ATTR_INVALID,
+
+       NL80211_BAND_IFT_ATTR_IFTYPES,
+       NL80211_BAND_IFT_ATTR_HE_CAP_MAC,
+       NL80211_BAND_IFT_ATTR_HE_CAP_PHY,
+       NL80211_BAND_IFT_ATTR_HE_CAP_MCS_SET,
+       NL80211_BAND_IFT_ATTR_HE_CAP_PPE,
+
+       /* keep last */
+       __NL80211_BAND_IFT_ATTR_AFTER_LAST,
+       NL80211_BAND_IFT_ATTR_MAX = __NL80211_BAND_IFT_ATTR_AFTER_LAST - 1
+};
+
 /**
  * enum nl80211_band_attr - band attributes
  * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved
@@ -3177,6 +3259,8 @@ enum nl80211_mpath_info {
  * @NL80211_BAND_ATTR_VHT_MCS_SET: 32-byte attribute containing the MCS set as
  *     defined in 802.11ac
  * @NL80211_BAND_ATTR_VHT_CAPA: VHT capabilities, as in the HT information IE
+ * @NL80211_BAND_ATTR_IFTYPE_DATA: nested array attribute, with each entry 
using
+ *     attributes from &enum nl80211_band_ift_attr
  * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined
  * @__NL80211_BAND_ATTR_AFTER_LAST: internal use
  */
@@ -3192,6 +3276,7 @@ enum nl80211_band_attr {
 
        NL80211_BAND_ATTR_VHT_MCS_SET,
        NL80211_BAND_ATTR_VHT_CAPA,
+       NL80211_BAND_ATTR_IFTYPE_DATA,
 
        /* keep last */
        __NL80211_BAND_ATTR_AFTER_LAST,
diff --git a/net/wireless/core.c b/net/wireless/core.c
index a6f3cac8c640..848d16631643 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -3,7 +3,7 @@
  *
  * Copyright 2006-2010         Johannes Berg <johan...@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
- * Copyright 2015      Intel Deutschland GmbH
+ * Copyright 2015-2018 Intel Deutschland GmbH
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -737,6 +737,8 @@ int wiphy_register(struct wiphy *wiphy)
 
        /* sanity check supported bands/channels */
        for (band = 0; band < NUM_NL80211_BANDS; band++) {
+               u16 types = 0;
+
                sband = wiphy->bands[band];
                if (!sband)
                        continue;
@@ -781,6 +783,23 @@ int wiphy_register(struct wiphy *wiphy)
                        sband->channels[i].band = band;
                }
 
+               for (i = 0; i < sband->n_iftype_data; i++) {
+                       const struct ieee80211_sband_iftype_data *iftd;
+
+                       iftd = &sband->iftype_data[i];
+
+                       if (WARN_ON(!iftd->types))
+                               return -EINVAL;
+                       if (WARN_ON(types & iftd->types))
+                               return -EINVAL;
+
+                       /* at least one piece of information must be present */
+                       if (WARN_ON(!iftd->he_cap.has_he))
+                               return -EINVAL;
+
+                       types |= iftd->types;
+               }
+
                have_band = true;
        }
 
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f7715b85fd2b..661728dbf989 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -428,6 +428,8 @@ static const struct nla_policy 
nl80211_policy[NUM_NL80211_ATTR] = {
        [NL80211_ATTR_TXQ_LIMIT] = { .type = NLA_U32 },
        [NL80211_ATTR_TXQ_MEMORY_LIMIT] = { .type = NLA_U32 },
        [NL80211_ATTR_TXQ_QUANTUM] = { .type = NLA_U32 },
+       [NL80211_ATTR_HE_CAPABILITY] = { .type = NLA_BINARY,
+                                        .len = NL80211_HE_MAX_CAPABILITY_LEN },
 };
 
 /* policy for the key attributes */
@@ -1324,6 +1326,34 @@ static int nl80211_send_coalesce(struct sk_buff *msg,
        return 0;
 }
 
+static int
+nl80211_send_ift_data(struct sk_buff *msg,
+                     const struct ieee80211_sband_iftype_data *iftdata)
+{
+       const struct ieee80211_sta_he_cap *he_cap = &iftdata->he_cap;
+
+       if (nl80211_put_iftypes(msg, NL80211_BAND_IFT_ATTR_IFTYPES,
+                               iftdata->types))
+               return -ENOBUFS;
+
+       if (he_cap->has_he) {
+               if (nla_put(msg, NL80211_BAND_IFT_ATTR_HE_CAP_MAC,
+                           sizeof(he_cap->he_cap_elem.mac_cap_info),
+                           he_cap->he_cap_elem.mac_cap_info) ||
+                   nla_put(msg, NL80211_BAND_IFT_ATTR_HE_CAP_PHY,
+                           sizeof(he_cap->he_cap_elem.phy_cap_info),
+                           he_cap->he_cap_elem.phy_cap_info) ||
+                   nla_put(msg, NL80211_BAND_IFT_ATTR_HE_CAP_MCS_SET,
+                           sizeof(he_cap->he_mcs_nss_supp),
+                           &he_cap->he_mcs_nss_supp) ||
+                   nla_put(msg, NL80211_BAND_IFT_ATTR_HE_CAP_PPE,
+                           sizeof(he_cap->ppe_thres), he_cap->ppe_thres))
+                       return -ENOBUFS;
+       }
+
+       return 0;
+}
+
 static int nl80211_send_band_rateinfo(struct sk_buff *msg,
                                      struct ieee80211_supported_band *sband)
 {
@@ -1353,6 +1383,32 @@ static int nl80211_send_band_rateinfo(struct sk_buff 
*msg,
                         sband->vht_cap.cap)))
                return -ENOBUFS;
 
+       if (sband->n_iftype_data) {
+               struct nlattr *nl_iftype_data =
+                       nla_nest_start(msg, NL80211_BAND_ATTR_IFTYPE_DATA);
+               int err;
+
+               if (!nl_iftype_data)
+                       return -ENOBUFS;
+
+               for (i = 0; i < sband->n_iftype_data; i++) {
+                       struct nlattr *iftdata;
+
+                       iftdata = nla_nest_start(msg, i + 1);
+                       if (!iftdata)
+                               return -ENOBUFS;
+
+                       err = nl80211_send_ift_data(msg,
+                                                   &sband->iftype_data[i]);
+                       if (err)
+                               return err;
+
+                       nla_nest_end(msg, iftdata);
+               }
+
+               nla_nest_end(msg, nl_iftype_data);
+       }
+
        /* add bitrates */
        nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
        if (!nl_rates)
@@ -4471,6 +4527,9 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, 
struct rate_info *info,
        case RATE_INFO_BW_160:
                rate_flg = NL80211_RATE_INFO_160_MHZ_WIDTH;
                break;
+       case RATE_INFO_BW_HE_RU:
+               rate_flg = 0;
+               WARN_ON(!(info->flags & RATE_INFO_FLAGS_HE_MCS));
        }
 
        if (rate_flg && nla_put_flag(msg, rate_flg))
@@ -4490,6 +4549,19 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, 
struct rate_info *info,
                if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
                    nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
                        return false;
+       } else if (info->flags & RATE_INFO_FLAGS_HE_MCS) {
+               if (nla_put_u8(msg, NL80211_RATE_INFO_HE_MCS, info->mcs))
+                       return false;
+               if (nla_put_u8(msg, NL80211_RATE_INFO_HE_NSS, info->nss))
+                       return false;
+               if (nla_put_u8(msg, NL80211_RATE_INFO_HE_GI, info->he_gi))
+                       return false;
+               if (nla_put_u8(msg, NL80211_RATE_INFO_HE_DCM, info->he_dcm))
+                       return false;
+               if (info->bw == RATE_INFO_BW_HE_RU &&
+                   nla_put_u8(msg, NL80211_RATE_INFO_HE_RU_ALLOC,
+                              info->he_ru_alloc))
+                       return false;
        }
 
        nla_nest_end(msg, rate);
@@ -4899,7 +4971,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
                        return -EINVAL;
                if (params->supported_rates)
                        return -EINVAL;
-               if (params->ext_capab || params->ht_capa || params->vht_capa)
+               if (params->ext_capab || params->ht_capa || params->vht_capa ||
+                   params->he_capa)
                        return -EINVAL;
        }
 
@@ -5105,6 +5178,15 @@ static int nl80211_set_station_tdls(struct genl_info 
*info,
        if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
                params->vht_capa =
                        nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
+       if (info->attrs[NL80211_ATTR_HE_CAPABILITY]) {
+               params->he_capa =
+                       nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
+               params->he_capa_len =
+                       nla_len(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
+
+               if (params->he_capa_len < NL80211_HE_MIN_CAPABILITY_LEN)
+                       return -EINVAL;
+       }
 
        err = nl80211_parse_sta_channel_info(info, params);
        if (err)
@@ -5332,6 +5414,17 @@ static int nl80211_new_station(struct sk_buff *skb, 
struct genl_info *info)
                params.vht_capa =
                        nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
 
+       if (info->attrs[NL80211_ATTR_HE_CAPABILITY]) {
+               params.he_capa =
+                       nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
+               params.he_capa_len =
+                       nla_len(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
+
+               /* max len is validated in nla policy */
+               if (params.he_capa_len < NL80211_HE_MIN_CAPABILITY_LEN)
+                       return -EINVAL;
+       }
+
        if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
                params.opmode_notif_used = true;
                params.opmode_notif =
@@ -5364,6 +5457,10 @@ static int nl80211_new_station(struct sk_buff *skb, 
struct genl_info *info)
        if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) {
                params.ht_capa = NULL;
                params.vht_capa = NULL;
+
+               /* HE requires WME */
+               if (params.he_capa_len)
+                       return -EINVAL;
        }
 
        /* When you run into this, adjust the code below for the new flag */
diff --git a/net/wireless/util.c b/net/wireless/util.c
index d112e9a89364..b66a68a41cd6 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -4,6 +4,7 @@
  *
  * Copyright 2007-2009 Johannes Berg <johan...@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
+ * Copyright 2017      Intel Deutschland GmbH
  */
 #include <linux/export.h>
 #include <linux/bitops.h>
@@ -1142,6 +1143,85 @@ static u32 cfg80211_calculate_bitrate_vht(struct 
rate_info *rate)
        return 0;
 }
 
+static u32 cfg80211_calculate_bitrate_he(struct rate_info *rate)
+{
+#define SCALE 2048
+       u16 mcs_divisors[12] = {
+               34133, /* 16.666666... */
+               17067, /*  8.333333... */
+               11378, /*  5.555555... */
+                8533, /*  4.166666... */
+                5689, /*  2.777777... */
+                4267, /*  2.083333... */
+                3923, /*  1.851851... */
+                3413, /*  1.666666... */
+                2844, /*  1.388888... */
+                2560, /*  1.250000... */
+                2276, /*  1.111111... */
+                2048, /*  1.000000... */
+       };
+       u32 rates_160M[3] = { 960777777, 907400000, 816666666 };
+       u32 rates_969[3] =  { 480388888, 453700000, 408333333 };
+       u32 rates_484[3] =  { 229411111, 216666666, 195000000 };
+       u32 rates_242[3] =  { 114711111, 108333333,  97500000 };
+       u32 rates_106[3] =  {  40000000,  37777777,  34000000 };
+       u32 rates_52[3]  =  {  18820000,  17777777,  16000000 };
+       u32 rates_26[3]  =  {   9411111,   8888888,   8000000 };
+       u64 tmp;
+       u32 result;
+
+       if (WARN_ON_ONCE(rate->mcs > 11))
+               return 0;
+
+       if (WARN_ON_ONCE(rate->he_gi > NL80211_RATE_INFO_HE_GI_3_2))
+               return 0;
+       if (WARN_ON_ONCE(rate->he_ru_alloc >
+                        NL80211_RATE_INFO_HE_RU_ALLOC_2x996))
+               return 0;
+       if (WARN_ON_ONCE(rate->nss < 1 || rate->nss > 8))
+               return 0;
+
+       if (rate->bw == RATE_INFO_BW_160)
+               result = rates_160M[rate->he_gi];
+       else if (rate->bw == RATE_INFO_BW_80 ||
+                (rate->bw == RATE_INFO_BW_HE_RU &&
+                 rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_996))
+               result = rates_969[rate->he_gi];
+       else if (rate->bw == RATE_INFO_BW_40 ||
+                (rate->bw == RATE_INFO_BW_HE_RU &&
+                 rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_484))
+               result = rates_484[rate->he_gi];
+       else if (rate->bw == RATE_INFO_BW_20 ||
+                (rate->bw == RATE_INFO_BW_HE_RU &&
+                 rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_242))
+               result = rates_242[rate->he_gi];
+       else if (rate->bw == RATE_INFO_BW_HE_RU &&
+                rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_106)
+               result = rates_106[rate->he_gi];
+       else if (rate->bw == RATE_INFO_BW_HE_RU &&
+                rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_52)
+               result = rates_52[rate->he_gi];
+       else if (rate->bw == RATE_INFO_BW_HE_RU &&
+                rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_26)
+               result = rates_26[rate->he_gi];
+       else if (WARN(1, "invalid HE MCS: bw:%d, ru:%d\n",
+                     rate->bw, rate->he_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, DCM into account */
+       result = (result * rate->nss) / 8;
+       if (rate->he_dcm)
+               result /= 2;
+
+       return result;
+}
+
 u32 cfg80211_calculate_bitrate(struct rate_info *rate)
 {
        if (rate->flags & RATE_INFO_FLAGS_MCS)
@@ -1150,6 +1230,8 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate)
                return cfg80211_calculate_bitrate_60g(rate);
        if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
                return cfg80211_calculate_bitrate_vht(rate);
+       if (rate->flags & RATE_INFO_FLAGS_HE_MCS)
+               return cfg80211_calculate_bitrate_he(rate);
 
        return rate->legacy;
 }
-- 
2.17.0

Reply via email to