Commit c4cbaf79 authored by Luca Coelho's avatar Luca Coelho Committed by Johannes Berg

cfg80211: Add support for HE

Add support for the HE in cfg80211 and also add userspace API to
nl80211 to send rate information out, conforming with P802.11ax_D2.0.
Signed-off-by: default avatarLiad Kaufman <liad.kaufman@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarIlan Peer <ilan.peer@intel.com>
Signed-off-by: default avatarIdo Yariv <idox.yariv@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
parent 446faa15
......@@ -1539,6 +1539,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_D2.0 section 9.4.2.237.2 and 9.4.2.237.3
*/
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_D2.0 section 9.4.2.237.4
*
* @rx_mcs_80: Rx MCS map 2 bits for each stream, total 8 streams, for channel
* widths less than 80MHz.
* @tx_mcs_80: Tx MCS map 2 bits for each stream, total 8 streams, for channel
* widths less than 80MHz.
* @rx_mcs_160: Rx MCS map 2 bits for each stream, total 8 streams, for channel
* width 160MHz.
* @tx_mcs_160: Tx MCS map 2 bits for each stream, total 8 streams, for channel
* width 160MHz.
* @rx_mcs_80p80: Rx MCS map 2 bits for each stream, total 8 streams, for
* channel width 80p80MHz.
* @tx_mcs_80p80: Tx MCS map 2 bits for each stream, total 8 streams, for
* channel width 80p80MHz.
*/
struct ieee80211_he_mcs_nss_supp {
__le16 rx_mcs_80;
__le16 tx_mcs_80;
__le16 rx_mcs_160;
__le16 tx_mcs_160;
__le16 rx_mcs_80p80;
__le16 tx_mcs_80p80;
} __packed;
/**
* struct ieee80211_he_operation - HE capabilities element
*
* This structure is the "HE operation element" fields as
* described in P802.11ax_D2.0 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_D2.0 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_D2.0 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 +1677,328 @@ 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 HE_MAC_CAP1 and
* HE_MAC_CAP2. 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 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_BQRP_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
#define IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU 0x40
/* 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
/* Midamble RX Max NSTS is split between byte #2 and byte #3 */
#define IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_MAX_NSTS 0x80
#define IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_MAX_NSTS 0x01
#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_RX_HE_MU_PPDU_FROM_NON_AP_STA 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
#define IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI 0x10
#define IEEE80211_HE_PHY_CAP8_MIDAMBLE_RX_2X_AND_1XLTF 0x20
/* 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_SUPPORT_2NSS (1)
#define IEEE80211_PPE_THRES_NSS_POS (0)
#define IEEE80211_PPE_THRES_NSS_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_MASK) >>
IEEE80211_PPE_THRES_NSS_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 +2414,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 */
......
......@@ -285,6 +285,41 @@ 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_mask. Each type in the
* @types_mask must be unique across all instances of iftype_data.
*
* @types_mask: interface types mask
* @he_cap: holds the HE capabilities
*/
struct ieee80211_sband_iftype_data {
u16 types_mask;
struct ieee80211_sta_he_cap he_cap;
};
/**
* struct ieee80211_supported_band - frequency band definition
*
......@@ -301,6 +336,11 @@ 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. Note that the bits in
* @types_mask inside this structure cannot overlap (i.e. only
* one occurrence of each type is allowed across all instances of
* iftype_data).
*/
struct ieee80211_supported_band {
struct ieee80211_channel *channels;
......@@ -310,8 +350,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_iftype_data - return sband data for a given iftype
* @sband: the sband to search for the STA on
* @iftype: enum nl80211_iftype
*
* Return: pointer to struct ieee80211_sband_iftype_data, or NULL is none found
*/
static inline const struct ieee80211_sband_iftype_data *
ieee80211_get_sband_iftype_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_mask & 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_iftype_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 +986,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 +1015,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 +1091,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 +1112,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 +1121,7 @@ enum rate_info_bw {
RATE_INFO_BW_40,
RATE_INFO_BW_80,
RATE_INFO_BW_160,
RATE_INFO_BW_HE_RU,
};
/**
......@@ -1035,10 +1130,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 +1145,9 @@ struct rate_info {
u16 legacy;
u8 nss;
u8 bw;
u8 he_gi;
u8 he_dcm;
u8 he_ru_alloc;
};
/**
......
......@@ -2237,6 +2237,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
......@@ -2677,6 +2680,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,
......@@ -2726,7 +2731,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
......@@ -2853,6 +2859,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
*
......@@ -2885,6 +2923,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 {
......@@ -2901,6 +2946,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,
......@@ -3166,6 +3216,38 @@ enum nl80211_mpath_info {
NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1
};
/**
* enum nl80211_band_iftype_attr - Interface type data attributes
*
* @__NL80211_BAND_IFTYPE_ATTR_INVALID: attribute number 0 is reserved
* @NL80211_BAND_IFTYPE_ATTR_IFTYPES: nested attribute containing a flag attribute
* for each interface type that supports the band data
* @NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC: HE MAC capabilities as in HE
* capabilities IE
* @NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY: HE PHY capabilities as in HE
* capabilities IE
* @NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET: HE supported NSS/MCS as in HE
* capabilities IE
* @NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE: HE PPE thresholds information as
* defined in HE capabilities IE
* @NL80211_BAND_IFTYPE_ATTR_MAX: highest band HE capability attribute currently
* defined
* @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use
*/
enum nl80211_band_iftype_attr {
__NL80211_BAND_IFTYPE_ATTR_INVALID,
NL80211_BAND_IFTYPE_ATTR_IFTYPES,
NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC,
NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY,
NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET,
NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE,
/* keep last */
__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST,
NL80211_BAND_IFTYPE_ATTR_MAX = __NL80211_BAND_IFTYPE_ATTR_AFTER_LAST - 1
};
/**
* enum nl80211_band_attr - band attributes
* @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved
......@@ -3181,6 +3263,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_iftype_attr
* @NL80211_BAND_ATTR_MAX: highest band attribute currently defined
* @__NL80211_BAND_ATTR_AFTER_LAST: internal use
*/
......@@ -3196,6 +3280,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,
......
......@@ -3,7 +3,7 @@
*
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright 2015 Intel Deutschland GmbH
* Copyright 2015-2017 Intel Deutschland GmbH
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
......@@ -744,6 +744,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;
......@@ -788,6 +790,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_mask))
return -EINVAL;
if (WARN_ON(types & iftd->types_mask))
return -EINVAL;
/* at least one piece of information must be present */
if (WARN_ON(!iftd->he_cap.has_he))
return -EINVAL;
types |= iftd->types_mask;
}
have_band = true;
}
......
......@@ -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_iftype_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_IFTYPE_ATTR_IFTYPES,
iftdata->types_mask))
return -ENOBUFS;
if (he_cap->has_he) {
if (nla_put(msg, NL80211_BAND_IFTYPE_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_IFTYPE_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_IFTYPE_ATTR_HE_CAP_MCS_SET,
sizeof(he_cap->he_mcs_nss_supp),
&he_cap->he_mcs_nss_supp) ||
nla_put(msg, NL80211_BAND_IFTYPE_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_iftype_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)
......@@ -4472,6 +4528,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))
......@@ -4491,6 +4550,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);
......@@ -4887,7 +4959,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;
}
......@@ -5093,6 +5166,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)
......@@ -5320,6 +5402,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 =
......@@ -5352,6 +5445,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 */
......
......@@ -4,6 +4,7 @@
*
* Copyright 2007-2009 Johannes Berg <johannes@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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment