This time, we have some pretty impactful work. Among
the changes: * changes to make PTK rekeying work better, or actually better/safely if drivers get updated * VHT extended NSS support - some APs had capabilities that didn't fit into the VHT (11ac) spec, so the spec was updated and we follow that now * some TXQ and A-MSDU building work - will allow iwlwifi to use this soon * more HE work, including aligning to 802.11ax Draft 3.0 * L-SIG and 0-length-PSDU support in radiotap -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEH1e1rEeCd0AIMq6MB8qZga/fl8QFAluPm+MACgkQB8qZga/f l8T5QA/6A7zWg81fz1c4UDMtA9fNbv/IeGnqQocDRVHpSCV7PwwhwzzoRI5mRaqE vnP4JzD8Yt1VcYmE76K3WSoQ2UAxm/02sKah+o9CrTk7ar4hqvJkRC9/aBZPp75f Pf8T7WL0Mlem9JimBKr3VIj6Rcom49o2JdWy+3v0guoxNFGwA7xpo5OHoTSHGgfi Ziome5WZu1eL9uAi79TAbkYe6ru6f7J7rx+jjtHVvnDN/5ky+G2LtDTClS0juhJt Jvw3+4V76WmYahYme6yEs6yiiYTFA1I7fUOjuW8/oLW29fjuQu6//K/ZHYU5Vdw1 4ujpbKW1jv+ncpKnIKYJ598JGBURRu6Mc8WOOljJt5wvxkgZGqCjs+APdzf/YQ1B XrGQ9gr9HSYoQ5Gu/9vlPHH/KrXG8GvPW+4bHlkwrcd1IVrDcBDfRr/o8nAMo8j+ WOIf6Ck8zqdzyf2rfHa4D1WGC+c4hJnKgn6OpSvcuOJhghLvFeVmIJk4CSTAI+Ds 0BKKH4VHJDdibE7wslTb4coRU8wxcem6Pm9IhtqeKKYVgDfxjfG+sJjQnRICbRL6 SWfwtGUodA1hdp/3uzlV0X/W9flw5vJCcMFzg2W5qxBoCD7K1yz3LcQM1AkYyQr+ GuubYUyoQIEBn7z9GCsQplUpdrpAsvCpJQ17oka/gQt4wo/L5o0= =HYA6 -----END PGP SIGNATURE----- Merge tag 'mac80211-next-for-davem-2018-09-05' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next Johannes Berg says: ==================== This time, we have some pretty impactful work. Among the changes: * changes to make PTK rekeying work better, or actually better/safely if drivers get updated * VHT extended NSS support - some APs had capabilities that didn't fit into the VHT (11ac) spec, so the spec was updated and we follow that now * some TXQ and A-MSDU building work - will allow iwlwifi to use this soon * more HE work, including aligning to 802.11ax Draft 3.0 * L-SIG and 0-length-PSDU support in radiotap ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
579d03fecb
|
@ -476,30 +476,40 @@ static struct ieee80211_sband_iftype_data iwl_he_capa = {
|
|||
.has_he = true,
|
||||
.he_cap_elem = {
|
||||
.mac_cap_info[0] =
|
||||
IEEE80211_HE_MAC_CAP0_HTC_HE,
|
||||
IEEE80211_HE_MAC_CAP0_HTC_HE |
|
||||
IEEE80211_HE_MAC_CAP0_TWT_REQ,
|
||||
.mac_cap_info[1] =
|
||||
IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US |
|
||||
IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_8,
|
||||
IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8,
|
||||
.mac_cap_info[2] =
|
||||
IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP |
|
||||
IEEE80211_HE_MAC_CAP2_MU_CASCADING |
|
||||
IEEE80211_HE_MAC_CAP2_ACK_EN,
|
||||
.mac_cap_info[3] =
|
||||
IEEE80211_HE_MAC_CAP3_GRP_ADDR_MULTI_STA_BA_DL_MU |
|
||||
IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_2,
|
||||
.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU,
|
||||
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
|
||||
IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2,
|
||||
.mac_cap_info[4] =
|
||||
IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU |
|
||||
IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39,
|
||||
.mac_cap_info[5] =
|
||||
IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B40 |
|
||||
IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B41 |
|
||||
IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU,
|
||||
.phy_cap_info[0] =
|
||||
IEEE80211_HE_PHY_CAP0_DUAL_BAND |
|
||||
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,
|
||||
.phy_cap_info[1] =
|
||||
IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK |
|
||||
IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
|
||||
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD |
|
||||
IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_MAX_NSTS,
|
||||
IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS,
|
||||
.phy_cap_info[2] =
|
||||
IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
|
||||
IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
|
||||
IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ,
|
||||
IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ |
|
||||
IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO |
|
||||
IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO,
|
||||
.phy_cap_info[3] =
|
||||
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_BPSK |
|
||||
IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 |
|
||||
|
@ -511,18 +521,31 @@ static struct ieee80211_sband_iftype_data iwl_he_capa = {
|
|||
IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8,
|
||||
.phy_cap_info[5] =
|
||||
IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 |
|
||||
IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2,
|
||||
IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2 |
|
||||
IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK |
|
||||
IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK,
|
||||
.phy_cap_info[6] =
|
||||
IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU |
|
||||
IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU |
|
||||
IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB |
|
||||
IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB |
|
||||
IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB |
|
||||
IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO |
|
||||
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT,
|
||||
.phy_cap_info[7] =
|
||||
IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR |
|
||||
IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI |
|
||||
IEEE80211_HE_PHY_CAP7_MAX_NC_7,
|
||||
IEEE80211_HE_PHY_CAP7_MAX_NC_1,
|
||||
.phy_cap_info[8] =
|
||||
IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI |
|
||||
IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G |
|
||||
IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU |
|
||||
IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU,
|
||||
IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU |
|
||||
IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_160_OR_80P80_MHZ,
|
||||
.phy_cap_info[9] =
|
||||
IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK |
|
||||
IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB |
|
||||
IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB,
|
||||
},
|
||||
/*
|
||||
* Set default Tx/Rx HE MCS NSS Support field. Indicate support
|
||||
|
@ -559,9 +582,11 @@ static void iwl_init_he_hw_capab(struct ieee80211_supported_band *sband,
|
|||
/* If not 2x2, we need to indicate 1x1 in the Midamble RX Max NSTS */
|
||||
if ((tx_chains & rx_chains) != ANT_AB) {
|
||||
iwl_he_capa.he_cap.he_cap_elem.phy_cap_info[1] &=
|
||||
~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_MAX_NSTS;
|
||||
~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS;
|
||||
iwl_he_capa.he_cap.he_cap_elem.phy_cap_info[2] &=
|
||||
~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_MAX_NSTS;
|
||||
~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS;
|
||||
iwl_he_capa.he_cap.he_cap_elem.phy_cap_info[7] &=
|
||||
~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1978,10 +1978,6 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm,
|
|||
sta_ctxt_cmd.htc_flags |=
|
||||
cpu_to_le32(IWL_HE_HTC_LINK_ADAP_BOTH);
|
||||
}
|
||||
if (sta->he_cap.he_cap_elem.mac_cap_info[2] &
|
||||
IEEE80211_HE_MAC_CAP2_UL_MU_RESP_SCHED)
|
||||
sta_ctxt_cmd.htc_flags |=
|
||||
cpu_to_le32(IWL_HE_HTC_UL_MU_RESP_SCHED);
|
||||
if (sta->he_cap.he_cap_elem.mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_BSR)
|
||||
sta_ctxt_cmd.htc_flags |= cpu_to_le32(IWL_HE_HTC_BSR_SUPP);
|
||||
if (sta->he_cap.he_cap_elem.mac_cap_info[3] &
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2011, Javier Lopez <jlopex@gmail.com>
|
||||
* Copyright (c) 2016 - 2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -2529,23 +2530,20 @@ static const struct ieee80211_sband_iftype_data he_capa_2ghz = {
|
|||
IEEE80211_HE_MAC_CAP0_HTC_HE,
|
||||
.mac_cap_info[1] =
|
||||
IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US |
|
||||
IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_8,
|
||||
IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8,
|
||||
.mac_cap_info[2] =
|
||||
IEEE80211_HE_MAC_CAP2_BSR |
|
||||
IEEE80211_HE_MAC_CAP2_MU_CASCADING |
|
||||
IEEE80211_HE_MAC_CAP2_ACK_EN,
|
||||
.mac_cap_info[3] =
|
||||
IEEE80211_HE_MAC_CAP3_GRP_ADDR_MULTI_STA_BA_DL_MU |
|
||||
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
|
||||
IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_2,
|
||||
IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2,
|
||||
.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU,
|
||||
.phy_cap_info[0] =
|
||||
IEEE80211_HE_PHY_CAP0_DUAL_BAND,
|
||||
.phy_cap_info[1] =
|
||||
IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK |
|
||||
IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
|
||||
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD |
|
||||
IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_MAX_NSTS,
|
||||
IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS,
|
||||
.phy_cap_info[2] =
|
||||
IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
|
||||
IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
|
||||
|
@ -2579,18 +2577,16 @@ static const struct ieee80211_sband_iftype_data he_capa_5ghz = {
|
|||
IEEE80211_HE_MAC_CAP0_HTC_HE,
|
||||
.mac_cap_info[1] =
|
||||
IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US |
|
||||
IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_8,
|
||||
IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8,
|
||||
.mac_cap_info[2] =
|
||||
IEEE80211_HE_MAC_CAP2_BSR |
|
||||
IEEE80211_HE_MAC_CAP2_MU_CASCADING |
|
||||
IEEE80211_HE_MAC_CAP2_ACK_EN,
|
||||
.mac_cap_info[3] =
|
||||
IEEE80211_HE_MAC_CAP3_GRP_ADDR_MULTI_STA_BA_DL_MU |
|
||||
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
|
||||
IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_2,
|
||||
IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2,
|
||||
.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU,
|
||||
.phy_cap_info[0] =
|
||||
IEEE80211_HE_PHY_CAP0_DUAL_BAND |
|
||||
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,
|
||||
|
@ -2598,7 +2594,7 @@ static const struct ieee80211_sband_iftype_data he_capa_5ghz = {
|
|||
IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK |
|
||||
IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
|
||||
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD |
|
||||
IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_MAX_NSTS,
|
||||
IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS,
|
||||
.phy_cap_info[2] =
|
||||
IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
|
||||
IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
|
||||
|
|
|
@ -1460,13 +1460,16 @@ struct ieee80211_ht_operation {
|
|||
* STA can receive. Rate expressed in units of 1 Mbps.
|
||||
* If this field is 0 this value should not be used to
|
||||
* consider the highest RX data rate supported.
|
||||
* The top 3 bits of this field are reserved.
|
||||
* The top 3 bits of this field indicate the Maximum NSTS,total
|
||||
* (a beamformee capability.)
|
||||
* @tx_mcs_map: TX MCS map 2 bits for each stream, total 8 streams
|
||||
* @tx_highest: Indicates highest long GI VHT PPDU data rate
|
||||
* STA can transmit. Rate expressed in units of 1 Mbps.
|
||||
* If this field is 0 this value should not be used to
|
||||
* consider the highest TX data rate supported.
|
||||
* The top 3 bits of this field are reserved.
|
||||
* The top 2 bits of this field are reserved, the
|
||||
* 3rd bit from the top indiciates VHT Extended NSS BW
|
||||
* Capability.
|
||||
*/
|
||||
struct ieee80211_vht_mcs_info {
|
||||
__le16 rx_mcs_map;
|
||||
|
@ -1475,6 +1478,13 @@ struct ieee80211_vht_mcs_info {
|
|||
__le16 tx_highest;
|
||||
} __packed;
|
||||
|
||||
/* for rx_highest */
|
||||
#define IEEE80211_VHT_MAX_NSTS_TOTAL_SHIFT 13
|
||||
#define IEEE80211_VHT_MAX_NSTS_TOTAL_MASK (7 << IEEE80211_VHT_MAX_NSTS_TOTAL_SHIFT)
|
||||
|
||||
/* for tx_highest */
|
||||
#define IEEE80211_VHT_EXT_NSS_BW_CAPABLE (1 << 13)
|
||||
|
||||
/**
|
||||
* enum ieee80211_vht_mcs_support - VHT MCS support definitions
|
||||
* @IEEE80211_VHT_MCS_SUPPORT_0_7: MCSes 0-7 are supported for the
|
||||
|
@ -1545,11 +1555,11 @@ struct ieee80211_vht_operation {
|
|||
* 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
|
||||
* described in P802.11ax_D3.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];
|
||||
u8 mac_cap_info[6];
|
||||
u8 phy_cap_info[11];
|
||||
} __packed;
|
||||
|
||||
#define IEEE80211_TX_RX_MCS_NSS_DESC_MAX_LEN 5
|
||||
|
@ -1650,6 +1660,7 @@ struct ieee80211_mu_edca_param_set {
|
|||
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ 0x00000004
|
||||
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ 0x00000008
|
||||
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK 0x0000000C
|
||||
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_SHIFT 2
|
||||
#define IEEE80211_VHT_CAP_RXLDPC 0x00000010
|
||||
#define IEEE80211_VHT_CAP_SHORT_GI_80 0x00000020
|
||||
#define IEEE80211_VHT_CAP_SHORT_GI_160 0x00000040
|
||||
|
@ -1678,6 +1689,26 @@ struct ieee80211_mu_edca_param_set {
|
|||
#define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB 0x0c000000
|
||||
#define IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN 0x10000000
|
||||
#define IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN 0x20000000
|
||||
#define IEEE80211_VHT_CAP_EXT_NSS_BW_SHIFT 30
|
||||
#define IEEE80211_VHT_CAP_EXT_NSS_BW_MASK 0xc0000000
|
||||
|
||||
/**
|
||||
* ieee80211_get_vht_max_nss - return max NSS for a given bandwidth/MCS
|
||||
* @cap: VHT capabilities of the peer
|
||||
* @bw: bandwidth to use
|
||||
* @mcs: MCS index to use
|
||||
* @ext_nss_bw_capable: indicates whether or not the local transmitter
|
||||
* (rate scaling algorithm) can deal with the new logic
|
||||
* (dot11VHTExtendedNSSBWCapable)
|
||||
*
|
||||
* Due to the VHT Extended NSS Bandwidth Support, the maximum NSS can
|
||||
* vary for a given BW/MCS. This function parses the data.
|
||||
*
|
||||
* Note: This function is exported by cfg80211.
|
||||
*/
|
||||
int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
|
||||
enum ieee80211_vht_chanwidth bw,
|
||||
int mcs, bool ext_nss_bw_capable);
|
||||
|
||||
/* 802.11ax HE MAC capabilities */
|
||||
#define IEEE80211_HE_MAC_CAP0_HTC_HE 0x01
|
||||
|
@ -1707,15 +1738,15 @@ struct ieee80211_mu_edca_param_set {
|
|||
#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
|
||||
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_1 0x00
|
||||
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_2 0x10
|
||||
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_3 0x20
|
||||
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_4 0x30
|
||||
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_5 0x40
|
||||
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_6 0x50
|
||||
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_7 0x60
|
||||
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8 0x70
|
||||
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_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
|
||||
|
@ -1729,14 +1760,13 @@ struct ieee80211_mu_edca_param_set {
|
|||
|
||||
#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_TRS 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
|
||||
|
||||
|
@ -1744,25 +1774,34 @@ struct ieee80211_mu_edca_param_set {
|
|||
* 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_MAX_AMPDU_LEN_EXP_USE_VHT 0x00
|
||||
#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_1 0x08
|
||||
#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2 0x10
|
||||
#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_RESERVED 0x18
|
||||
#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK 0x18
|
||||
#define IEEE80211_HE_MAC_CAP3_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_SRP_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
|
||||
/* Multi TID agg TX is split between byte #4 and #5
|
||||
* The value is a combination of B39,B40,B41
|
||||
*/
|
||||
#define IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39 0x80
|
||||
|
||||
#define IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B40 0x01
|
||||
#define IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B41 0x02
|
||||
#define IEEE80211_HE_MAC_CAP5_SUBCHAN_SELECVITE_TRANSMISSION 0x04
|
||||
#define IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU 0x08
|
||||
#define IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX 0x10
|
||||
|
||||
/* 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
|
||||
|
@ -1779,10 +1818,10 @@ struct ieee80211_mu_edca_param_set {
|
|||
#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
|
||||
/* Midamble RX/TX Max NSTS is split between byte #2 and byte #3 */
|
||||
#define IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS 0x80
|
||||
|
||||
#define IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_MAX_NSTS 0x01
|
||||
#define IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_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
|
||||
|
@ -1883,7 +1922,19 @@ struct ieee80211_mu_edca_param_set {
|
|||
#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
|
||||
#define IEEE80211_HE_PHY_CAP8_MIDAMBLE_RX_TX_2X_AND_1XLTF 0x20
|
||||
#define IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_20MHZ 0x00
|
||||
#define IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_40MHZ 0x40
|
||||
#define IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_80MHZ 0x80
|
||||
#define IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_160_OR_80P80_MHZ 0xc0
|
||||
#define IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_MASK 0xc0
|
||||
|
||||
#define IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM 0x01
|
||||
#define IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK 0x02
|
||||
#define IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU 0x04
|
||||
#define IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU 0x08
|
||||
#define IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB 0x10
|
||||
#define IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB 0x20
|
||||
|
||||
/* 802.11ax HE TX/RX MCS NSS Support */
|
||||
#define IEEE80211_TX_RX_MCS_NSS_SUPP_HIGHEST_MCS_POS (3)
|
||||
|
@ -1963,8 +2014,8 @@ ieee80211_he_ppe_size(u8 ppe_thres_hdr, const u8 *phy_cap_info)
|
|||
#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_PARTIAL_BSS_COLOR 0x00100000
|
||||
#define IEEE80211_HE_OPERATION_VHT_OPER_INFO 0x00200000
|
||||
#define IEEE80211_HE_OPERATION_MULTI_BSSID_AP 0x10000000
|
||||
#define IEEE80211_HE_OPERATION_TX_BSSID_INDICATOR 0x20000000
|
||||
#define IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED 0x40000000
|
||||
|
|
|
@ -849,6 +849,7 @@ struct cfg80211_bitrate_mask {
|
|||
* @beacon_rate: bitrate to be used for beacons
|
||||
* @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)
|
||||
* @ht_required: stations must support HT
|
||||
* @vht_required: stations must support VHT
|
||||
*/
|
||||
|
@ -874,6 +875,7 @@ struct cfg80211_ap_settings {
|
|||
|
||||
const struct ieee80211_ht_cap *ht_cap;
|
||||
const struct ieee80211_vht_cap *vht_cap;
|
||||
const struct ieee80211_he_cap_elem *he_cap;
|
||||
bool ht_required, vht_required;
|
||||
};
|
||||
|
||||
|
|
|
@ -75,6 +75,8 @@ enum ieee80211_radiotap_presence {
|
|||
IEEE80211_RADIOTAP_TIMESTAMP = 22,
|
||||
IEEE80211_RADIOTAP_HE = 23,
|
||||
IEEE80211_RADIOTAP_HE_MU = 24,
|
||||
IEEE80211_RADIOTAP_ZERO_LEN_PSDU = 26,
|
||||
IEEE80211_RADIOTAP_LSIG = 27,
|
||||
|
||||
/* valid in every it_present bitmap, even vendor namespaces */
|
||||
IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29,
|
||||
|
@ -325,6 +327,25 @@ enum ieee80211_radiotap_he_mu_bits {
|
|||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_CH2_CTR_26T_RU = 0x0800,
|
||||
};
|
||||
|
||||
enum ieee80211_radiotap_lsig_data1 {
|
||||
IEEE80211_RADIOTAP_LSIG_DATA1_RATE_KNOWN = 0x0001,
|
||||
IEEE80211_RADIOTAP_LSIG_DATA1_LENGTH_KNOWN = 0x0002,
|
||||
};
|
||||
|
||||
enum ieee80211_radiotap_lsig_data2 {
|
||||
IEEE80211_RADIOTAP_LSIG_DATA2_RATE = 0x000f,
|
||||
IEEE80211_RADIOTAP_LSIG_DATA2_LENGTH = 0xfff0,
|
||||
};
|
||||
|
||||
struct ieee80211_radiotap_lsig {
|
||||
__le16 data1, data2;
|
||||
};
|
||||
|
||||
enum ieee80211_radiotap_zero_len_psdu_type {
|
||||
IEEE80211_RADIOTAP_ZERO_LEN_PSDU_SOUNDING = 0,
|
||||
IEEE80211_RADIOTAP_ZERO_LEN_PSDU_VENDOR = 0xff,
|
||||
};
|
||||
|
||||
/**
|
||||
* ieee80211_get_radiotap_len - get radiotap header length
|
||||
*/
|
||||
|
|
|
@ -101,8 +101,9 @@
|
|||
* Drivers indicate that they use this model by implementing the .wake_tx_queue
|
||||
* driver operation.
|
||||
*
|
||||
* Intermediate queues (struct ieee80211_txq) are kept per-sta per-tid, with a
|
||||
* single per-vif queue for multicast data frames.
|
||||
* Intermediate queues (struct ieee80211_txq) are kept per-sta per-tid, with
|
||||
* another per-sta for non-data/non-mgmt and bufferable management frames, and
|
||||
* a single per-vif queue for multicast data frames.
|
||||
*
|
||||
* The driver is expected to initialize its private per-queue data for stations
|
||||
* and interfaces in the .add_interface and .sta_add ops.
|
||||
|
@ -1140,6 +1141,11 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
|
|||
* from the RX info data, so leave those zeroed when building this data)
|
||||
* @RX_FLAG_RADIOTAP_HE_MU: HE MU radiotap data is present
|
||||
* (&struct ieee80211_radiotap_he_mu)
|
||||
* @RX_FLAG_RADIOTAP_LSIG: L-SIG radiotap data is present
|
||||
* @RX_FLAG_NO_PSDU: use the frame only for radiotap reporting, with
|
||||
* the "0-length PSDU" field included there. The value for it is
|
||||
* in &struct ieee80211_rx_status. Note that if this value isn't
|
||||
* known the frame shouldn't be reported.
|
||||
*/
|
||||
enum mac80211_rx_flags {
|
||||
RX_FLAG_MMIC_ERROR = BIT(0),
|
||||
|
@ -1170,6 +1176,8 @@ enum mac80211_rx_flags {
|
|||
RX_FLAG_AMPDU_EOF_BIT_KNOWN = BIT(25),
|
||||
RX_FLAG_RADIOTAP_HE = BIT(26),
|
||||
RX_FLAG_RADIOTAP_HE_MU = BIT(27),
|
||||
RX_FLAG_RADIOTAP_LSIG = BIT(28),
|
||||
RX_FLAG_NO_PSDU = BIT(29),
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1242,6 +1250,7 @@ enum mac80211_rx_encoding {
|
|||
* @ampdu_reference: A-MPDU reference number, must be a different value for
|
||||
* each A-MPDU but the same for each subframe within one A-MPDU
|
||||
* @ampdu_delimiter_crc: A-MPDU delimiter CRC
|
||||
* @zero_length_psdu_type: radiotap type of the 0-length PSDU
|
||||
*/
|
||||
struct ieee80211_rx_status {
|
||||
u64 mactime;
|
||||
|
@ -1262,6 +1271,7 @@ struct ieee80211_rx_status {
|
|||
u8 chains;
|
||||
s8 chain_signal[IEEE80211_MAX_CHAINS];
|
||||
u8 ampdu_delimiter_crc;
|
||||
u8 zero_length_psdu_type;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1843,7 +1853,9 @@ struct ieee80211_sta_rates {
|
|||
* unlimited.
|
||||
* @support_p2p_ps: indicates whether the STA supports P2P PS mechanism or not.
|
||||
* @max_rc_amsdu_len: Maximum A-MSDU size in bytes recommended by rate control.
|
||||
* @txq: per-TID data TX queues (if driver uses the TXQ abstraction)
|
||||
* @max_tid_amsdu_len: Maximum A-MSDU size in bytes for this TID
|
||||
* @txq: per-TID data TX queues (if driver uses the TXQ abstraction); note that
|
||||
* the last entry (%IEEE80211_NUM_TIDS) is used for non-data frames
|
||||
*/
|
||||
struct ieee80211_sta {
|
||||
u32 supp_rates[NUM_NL80211_BANDS];
|
||||
|
@ -1883,8 +1895,9 @@ struct ieee80211_sta {
|
|||
u16 max_amsdu_len;
|
||||
bool support_p2p_ps;
|
||||
u16 max_rc_amsdu_len;
|
||||
u16 max_tid_amsdu_len[IEEE80211_NUM_TIDS];
|
||||
|
||||
struct ieee80211_txq *txq[IEEE80211_NUM_TIDS];
|
||||
struct ieee80211_txq *txq[IEEE80211_NUM_TIDS + 1];
|
||||
|
||||
/* must be last */
|
||||
u8 drv_priv[0] __aligned(sizeof(void *));
|
||||
|
@ -1918,7 +1931,8 @@ struct ieee80211_tx_control {
|
|||
*
|
||||
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
|
||||
* @sta: station table entry, %NULL for per-vif queue
|
||||
* @tid: the TID for this queue (unused for per-vif queue)
|
||||
* @tid: the TID for this queue (unused for per-vif queue),
|
||||
* %IEEE80211_NUM_TIDS for non-data (if enabled)
|
||||
* @ac: the AC for this queue
|
||||
* @drv_priv: driver private area, sized by hw->txq_data_size
|
||||
*
|
||||
|
@ -2131,6 +2145,19 @@ struct ieee80211_txq {
|
|||
* @IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP: The driver (or firmware) doesn't
|
||||
* support QoS NDP for AP probing - that's most likely a driver bug.
|
||||
*
|
||||
* @IEEE80211_HW_BUFF_MMPDU_TXQ: use the TXQ for bufferable MMPDUs, this of
|
||||
* course requires the driver to use TXQs to start with.
|
||||
*
|
||||
* @IEEE80211_HW_SUPPORTS_VHT_EXT_NSS_BW: (Hardware) rate control supports VHT
|
||||
* extended NSS BW (dot11VHTExtendedNSSBWCapable). This flag will be set if
|
||||
* the selected rate control algorithm sets %RATE_CTRL_CAPA_VHT_EXT_NSS_BW
|
||||
* but if the rate control is built-in then it must be set by the driver.
|
||||
* See also the documentation for that flag.
|
||||
*
|
||||
* @IEEE80211_HW_STA_MMPDU_TXQ: use the extra non-TID per-station TXQ for all
|
||||
* MMPDUs on station interfaces. This of course requires the driver to use
|
||||
* TXQs to start with.
|
||||
*
|
||||
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
|
||||
*/
|
||||
enum ieee80211_hw_flags {
|
||||
|
@ -2176,6 +2203,9 @@ enum ieee80211_hw_flags {
|
|||
IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA,
|
||||
IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP,
|
||||
IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP,
|
||||
IEEE80211_HW_BUFF_MMPDU_TXQ,
|
||||
IEEE80211_HW_SUPPORTS_VHT_EXT_NSS_BW,
|
||||
IEEE80211_HW_STA_MMPDU_TXQ,
|
||||
|
||||
/* keep last, obviously */
|
||||
NUM_IEEE80211_HW_FLAGS
|
||||
|
@ -2294,6 +2324,10 @@ enum ieee80211_hw_flags {
|
|||
* supported by HW.
|
||||
* @max_nan_de_entries: maximum number of NAN DE functions supported by the
|
||||
* device.
|
||||
*
|
||||
* @tx_sk_pacing_shift: Pacing shift to set on TCP sockets when frames from
|
||||
* them are encountered. The default should typically not be changed,
|
||||
* unless the driver has good reasons for needing more buffers.
|
||||
*/
|
||||
struct ieee80211_hw {
|
||||
struct ieee80211_conf conf;
|
||||
|
@ -2329,6 +2363,7 @@ struct ieee80211_hw {
|
|||
u8 n_cipher_schemes;
|
||||
const struct ieee80211_cipher_scheme *cipher_schemes;
|
||||
u8 max_nan_de_entries;
|
||||
u8 tx_sk_pacing_shift;
|
||||
};
|
||||
|
||||
static inline bool _ieee80211_hw_check(struct ieee80211_hw *hw,
|
||||
|
@ -2510,6 +2545,19 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
|
|||
* The set_default_unicast_key() call updates the default WEP key index
|
||||
* configured to the hardware for WEP encryption type. This is required
|
||||
* for devices that support offload of data packets (e.g. ARP responses).
|
||||
*
|
||||
* Mac80211 drivers should set the @NL80211_EXT_FEATURE_CAN_REPLACE_PTK0 flag
|
||||
* when they are able to replace in-use PTK keys according to to following
|
||||
* requirements:
|
||||
* 1) They do not hand over frames decrypted with the old key to
|
||||
mac80211 once the call to set_key() with command %DISABLE_KEY has been
|
||||
completed when also setting @IEEE80211_KEY_FLAG_GENERATE_IV for any key,
|
||||
2) either drop or continue to use the old key for any outgoing frames queued
|
||||
at the time of the key deletion (including re-transmits),
|
||||
3) never send out a frame queued prior to the set_key() %SET_KEY command
|
||||
encrypted with the new key and
|
||||
4) never send out a frame unencrypted when it should be encrypted.
|
||||
Mac80211 will not queue any new frames for a deleted key to the driver.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -3546,6 +3594,10 @@ enum ieee80211_reconfig_type {
|
|||
* @del_nan_func: Remove a NAN function. The driver must call
|
||||
* ieee80211_nan_func_terminated() with
|
||||
* NL80211_NAN_FUNC_TERM_REASON_USER_REQUEST reason code upon removal.
|
||||
* @can_aggregate_in_amsdu: Called in order to determine if HW supports
|
||||
* aggregating two specific frames in the same A-MSDU. The relation
|
||||
* between the skbs should be symmetric and transitive. Note that while
|
||||
* skb is always a real frame, head may or may not be an A-MSDU.
|
||||
*/
|
||||
struct ieee80211_ops {
|
||||
void (*tx)(struct ieee80211_hw *hw,
|
||||
|
@ -3828,6 +3880,9 @@ struct ieee80211_ops {
|
|||
void (*del_nan_func)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
u8 instance_id);
|
||||
bool (*can_aggregate_in_amsdu)(struct ieee80211_hw *hw,
|
||||
struct sk_buff *head,
|
||||
struct sk_buff *skb);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -5648,7 +5703,22 @@ struct ieee80211_tx_rate_control {
|
|||
bool bss;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum rate_control_capabilities - rate control capabilities
|
||||
*/
|
||||
enum rate_control_capabilities {
|
||||
/**
|
||||
* @RATE_CTRL_CAPA_VHT_EXT_NSS_BW:
|
||||
* Support for extended NSS BW support (dot11VHTExtendedNSSCapable)
|
||||
* Note that this is only looked at if the minimum number of chains
|
||||
* that the AP uses is < the number of TX chains the hardware has,
|
||||
* otherwise the NSS difference doesn't bother us.
|
||||
*/
|
||||
RATE_CTRL_CAPA_VHT_EXT_NSS_BW = BIT(0),
|
||||
};
|
||||
|
||||
struct rate_control_ops {
|
||||
unsigned long capa;
|
||||
const char *name;
|
||||
void *(*alloc)(struct ieee80211_hw *hw, struct dentry *debugfsdir);
|
||||
void (*free)(void *priv);
|
||||
|
|
|
@ -5226,6 +5226,11 @@ enum nl80211_feature_flags {
|
|||
* except for supported rates from the probe request content if requested
|
||||
* by the %NL80211_SCAN_FLAG_MIN_PREQ_CONTENT flag.
|
||||
*
|
||||
* @NL80211_EXT_FEATURE_CAN_REPLACE_PTK0: Driver/device confirm that they are
|
||||
* able to rekey an in-use key correctly. Userspace must not rekey PTK keys
|
||||
* if this flag is not set. Ignoring this can leak clear text packets and/or
|
||||
* freeze the connection.
|
||||
*
|
||||
* @NUM_NL80211_EXT_FEATURES: number of extended features.
|
||||
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
|
||||
*/
|
||||
|
@ -5263,6 +5268,7 @@ enum nl80211_ext_feature_index {
|
|||
NL80211_EXT_FEATURE_TXQS,
|
||||
NL80211_EXT_FEATURE_SCAN_RANDOM_SN,
|
||||
NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT,
|
||||
NL80211_EXT_FEATURE_CAN_REPLACE_PTK0,
|
||||
|
||||
/* add new features before the definition below */
|
||||
NUM_NL80211_EXT_FEATURES,
|
||||
|
|
|
@ -158,12 +158,10 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (type == NL80211_IFTYPE_AP_VLAN &&
|
||||
params && params->use_4addr == 0) {
|
||||
if (type == NL80211_IFTYPE_AP_VLAN && params->use_4addr == 0) {
|
||||
RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
|
||||
ieee80211_check_fast_rx_iface(sdata);
|
||||
} else if (type == NL80211_IFTYPE_STATION &&
|
||||
params && params->use_4addr >= 0) {
|
||||
} else if (type == NL80211_IFTYPE_STATION && params->use_4addr >= 0) {
|
||||
sdata->u.mgd.use_4addr = params->use_4addr;
|
||||
}
|
||||
|
||||
|
@ -911,6 +909,9 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
|||
|
||||
sdata->vif.bss_conf.beacon_int = params->beacon_interval;
|
||||
|
||||
if (params->he_cap)
|
||||
sdata->vif.bss_conf.he_support = true;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
err = ieee80211_vif_use_channel(sdata, ¶ms->chandef,
|
||||
IEEE80211_CHANCTX_SHARED);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* GPLv2
|
||||
*
|
||||
|
@ -214,6 +215,9 @@ static const char *hw_flag_names[] = {
|
|||
FLAG(SUPPORTS_TDLS_BUFFER_STA),
|
||||
FLAG(DEAUTH_NEED_MGD_TX_PREP),
|
||||
FLAG(DOESNT_SUPPORT_QOS_NDP),
|
||||
FLAG(BUFF_MMPDU_TXQ),
|
||||
FLAG(SUPPORTS_VHT_EXT_NSS_BW),
|
||||
FLAG(STA_MMPDU_TXQ),
|
||||
#undef FLAG
|
||||
};
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2016 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -140,7 +141,7 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf,
|
|||
{
|
||||
struct sta_info *sta = file->private_data;
|
||||
struct ieee80211_local *local = sta->local;
|
||||
size_t bufsz = AQM_TXQ_ENTRY_LEN*(IEEE80211_NUM_TIDS+1);
|
||||
size_t bufsz = AQM_TXQ_ENTRY_LEN * (IEEE80211_NUM_TIDS + 2);
|
||||
char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
|
||||
struct txq_info *txqi;
|
||||
ssize_t rv;
|
||||
|
@ -162,7 +163,9 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf,
|
|||
bufsz+buf-p,
|
||||
"tid ac backlog-bytes backlog-packets new-flows drops marks overlimit collisions tx-bytes tx-packets flags\n");
|
||||
|
||||
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
|
||||
if (!sta->sta.txq[i])
|
||||
continue;
|
||||
txqi = to_txq_info(sta->sta.txq[i]);
|
||||
p += scnprintf(p, bufsz+buf-p,
|
||||
"%d %d %u %u %u %u %u %u %u %u %u 0x%lx(%s%s%s)\n",
|
||||
|
@ -487,12 +490,368 @@ static ssize_t sta_vht_capa_read(struct file *file, char __user *userbuf,
|
|||
p += scnprintf(p, sizeof(buf)+buf-p,
|
||||
"MCS TX highest: %d Mbps\n",
|
||||
le16_to_cpu(vhtc->vht_mcs.tx_highest));
|
||||
#undef PFLAG
|
||||
}
|
||||
|
||||
return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
|
||||
}
|
||||
STA_OPS(vht_capa);
|
||||
|
||||
static ssize_t sta_he_capa_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
char *buf, *p;
|
||||
size_t buf_sz = PAGE_SIZE;
|
||||
struct sta_info *sta = file->private_data;
|
||||
struct ieee80211_sta_he_cap *hec = &sta->sta.he_cap;
|
||||
struct ieee80211_he_mcs_nss_supp *nss = &hec->he_mcs_nss_supp;
|
||||
u8 ppe_size;
|
||||
u8 *cap;
|
||||
int i;
|
||||
ssize_t ret;
|
||||
|
||||
buf = kmalloc(buf_sz, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
p = buf;
|
||||
|
||||
p += scnprintf(p, buf_sz + buf - p, "HE %ssupported\n",
|
||||
hec->has_he ? "" : "not ");
|
||||
if (!hec->has_he)
|
||||
goto out;
|
||||
|
||||
cap = hec->he_cap_elem.mac_cap_info;
|
||||
p += scnprintf(p, buf_sz + buf - p,
|
||||
"MAC-CAP: %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x\n",
|
||||
cap[0], cap[1], cap[2], cap[3], cap[4], cap[5]);
|
||||
|
||||
#define PRINT(fmt, ...) \
|
||||
p += scnprintf(p, buf_sz + buf - p, "\t\t" fmt "\n", \
|
||||
##__VA_ARGS__)
|
||||
|
||||
#define PFLAG(t, n, a, b) \
|
||||
do { \
|
||||
if (cap[n] & IEEE80211_HE_##t##_CAP##n##_##a) \
|
||||
PRINT("%s", b); \
|
||||
} while (0)
|
||||
|
||||
#define PFLAG_RANGE(t, i, n, s, m, off, fmt) \
|
||||
do { \
|
||||
u8 msk = IEEE80211_HE_##t##_CAP##i##_##n##_MASK; \
|
||||
u8 idx = ((cap[i] & msk) >> (ffs(msk) - 1)) + off; \
|
||||
PRINT(fmt, (s << idx) + (m * idx)); \
|
||||
} while (0)
|
||||
|
||||
#define PFLAG_RANGE_DEFAULT(t, i, n, s, m, off, fmt, a, b) \
|
||||
do { \
|
||||
if (cap[i] == IEEE80211_HE_##t ##_CAP##i##_##n##_##a) { \
|
||||
PRINT("%s", b); \
|
||||
break; \
|
||||
} \
|
||||
PFLAG_RANGE(t, i, n, s, m, off, fmt); \
|
||||
} while (0)
|
||||
|
||||
PFLAG(MAC, 0, HTC_HE, "HTC-HE");
|
||||
PFLAG(MAC, 0, TWT_REQ, "TWT-REQ");
|
||||
PFLAG(MAC, 0, TWT_RES, "TWT-RES");
|
||||
PFLAG_RANGE_DEFAULT(MAC, 0, DYNAMIC_FRAG, 0, 1, 0,
|
||||
"DYNAMIC-FRAG-LEVEL-%d", NOT_SUPP, "NOT-SUPP");
|
||||
PFLAG_RANGE_DEFAULT(MAC, 0, MAX_NUM_FRAG_MSDU, 1, 0, 0,
|
||||
"MAX-NUM-FRAG-MSDU-%d", UNLIMITED, "UNLIMITED");
|
||||
|
||||
PFLAG_RANGE_DEFAULT(MAC, 1, MIN_FRAG_SIZE, 128, 0, -1,
|
||||
"MIN-FRAG-SIZE-%d", UNLIMITED, "UNLIMITED");
|
||||
PFLAG_RANGE_DEFAULT(MAC, 1, TF_MAC_PAD_DUR, 0, 8, 0,
|
||||
"TF-MAC-PAD-DUR-%dUS", MASK, "UNKNOWN");
|
||||
PFLAG_RANGE(MAC, 1, MULTI_TID_AGG_RX_QOS, 0, 1, 1,
|
||||
"MULTI-TID-AGG-RX-QOS-%d");
|
||||
|
||||
if (cap[0] & IEEE80211_HE_MAC_CAP0_HTC_HE) {
|
||||
switch (((cap[2] << 1) | (cap[1] >> 7)) & 0x3) {
|
||||
case 0:
|
||||
PRINT("LINK-ADAPTATION-NO-FEEDBACK");
|
||||
break;
|
||||
case 1:
|
||||
PRINT("LINK-ADAPTATION-RESERVED");
|
||||
break;
|
||||
case 2:
|
||||
PRINT("LINK-ADAPTATION-UNSOLICITED-FEEDBACK");
|
||||
break;
|
||||
case 3:
|
||||
PRINT("LINK-ADAPTATION-BOTH");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PFLAG(MAC, 2, ALL_ACK, "ALL-ACK");
|
||||
PFLAG(MAC, 2, TRS, "TRS");
|
||||
PFLAG(MAC, 2, BSR, "BSR");
|
||||
PFLAG(MAC, 2, BCAST_TWT, "BCAST-TWT");
|
||||
PFLAG(MAC, 2, 32BIT_BA_BITMAP, "32BIT-BA-BITMAP");
|
||||
PFLAG(MAC, 2, MU_CASCADING, "MU-CASCADING");
|
||||
PFLAG(MAC, 2, ACK_EN, "ACK-EN");
|
||||
|
||||
PFLAG(MAC, 3, OMI_CONTROL, "OMI-CONTROL");
|
||||
PFLAG(MAC, 3, OFDMA_RA, "OFDMA-RA");
|
||||
|
||||
switch (cap[3] & IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK) {
|
||||
case IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_USE_VHT:
|
||||
PRINT("MAX-AMPDU-LEN-EXP-USE-VHT");
|
||||
break;
|
||||
case IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_1:
|
||||
PRINT("MAX-AMPDU-LEN-EXP-VHT-1");
|
||||
break;
|
||||
case IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2:
|
||||
PRINT("MAX-AMPDU-LEN-EXP-VHT-2");
|
||||
break;
|
||||
case IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_RESERVED:
|
||||
PRINT("MAX-AMPDU-LEN-EXP-RESERVED");
|
||||
break;
|
||||
}
|
||||
|
||||
PFLAG(MAC, 3, AMSDU_FRAG, "AMSDU-FRAG");
|
||||
PFLAG(MAC, 3, FLEX_TWT_SCHED, "FLEX-TWT-SCHED");
|
||||
PFLAG(MAC, 3, RX_CTRL_FRAME_TO_MULTIBSS, "RX-CTRL-FRAME-TO-MULTIBSS");
|
||||
|
||||
PFLAG(MAC, 4, BSRP_BQRP_A_MPDU_AGG, "BSRP-BQRP-A-MPDU-AGG");
|
||||
PFLAG(MAC, 4, QTP, "QTP");
|
||||
PFLAG(MAC, 4, BQR, "BQR");
|
||||
PFLAG(MAC, 4, SRP_RESP, "SRP-RESP");
|
||||
PFLAG(MAC, 4, NDP_FB_REP, "NDP-FB-REP");
|
||||
PFLAG(MAC, 4, OPS, "OPS");
|
||||
PFLAG(MAC, 4, AMDSU_IN_AMPDU, "AMSDU-IN-AMPDU");
|
||||
|
||||
PRINT("MULTI-TID-AGG-TX-QOS-%d", ((cap[5] << 1) | (cap[4] >> 7)) & 0x7);
|
||||
|
||||
PFLAG(MAC, 5, SUBCHAN_SELECVITE_TRANSMISSION,
|
||||
"SUBCHAN-SELECVITE-TRANSMISSION");
|
||||
PFLAG(MAC, 5, UL_2x996_TONE_RU, "UL-2x996-TONE-RU");
|
||||
PFLAG(MAC, 5, OM_CTRL_UL_MU_DATA_DIS_RX, "OM-CTRL-UL-MU-DATA-DIS-RX");
|
||||
|
||||
cap = hec->he_cap_elem.phy_cap_info;
|
||||
p += scnprintf(p, buf_sz + buf - p,
|
||||
"PHY CAP: %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x\n",
|
||||
cap[0], cap[1], cap[2], cap[3], cap[4], cap[5], cap[6],
|
||||
cap[7], cap[8], cap[9], cap[10]);
|
||||
|
||||
PFLAG(PHY, 0, CHANNEL_WIDTH_SET_40MHZ_IN_2G,
|
||||
"CHANNEL-WIDTH-SET-40MHZ-IN-2G");
|
||||
PFLAG(PHY, 0, CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G,
|
||||
"CHANNEL-WIDTH-SET-40MHZ-80MHZ-IN-5G");
|
||||
PFLAG(PHY, 0, CHANNEL_WIDTH_SET_160MHZ_IN_5G,
|
||||
"CHANNEL-WIDTH-SET-160MHZ-IN-5G");
|
||||
PFLAG(PHY, 0, CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G,
|
||||
"CHANNEL-WIDTH-SET-80PLUS80-MHZ-IN-5G");
|
||||
PFLAG(PHY, 0, CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G,
|
||||
"CHANNEL-WIDTH-SET-RU-MAPPING-IN-2G");
|
||||
PFLAG(PHY, 0, CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G,
|
||||
"CHANNEL-WIDTH-SET-RU-MAPPING-IN-5G");
|
||||
|
||||
switch (cap[1] & IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK) {
|
||||
case IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_80MHZ_ONLY_SECOND_20MHZ:
|
||||
PRINT("PREAMBLE-PUNC-RX-80MHZ-ONLY-SECOND-20MHZ");
|
||||
break;
|
||||
case IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_80MHZ_ONLY_SECOND_40MHZ:
|
||||
PRINT("PREAMBLE-PUNC-RX-80MHZ-ONLY-SECOND-40MHZ");
|
||||
break;
|
||||
case IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_160MHZ_ONLY_SECOND_20MHZ:
|
||||
PRINT("PREAMBLE-PUNC-RX-160MHZ-ONLY-SECOND-20MHZ");
|
||||
break;
|
||||
case IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_160MHZ_ONLY_SECOND_40MHZ:
|
||||
PRINT("PREAMBLE-PUNC-RX-160MHZ-ONLY-SECOND-40MHZ");
|
||||
break;
|
||||
}
|
||||
|
||||
PFLAG(PHY, 1, DEVICE_CLASS_A,
|
||||
"IEEE80211-HE-PHY-CAP1-DEVICE-CLASS-A");
|
||||
PFLAG(PHY, 1, LDPC_CODING_IN_PAYLOAD,
|
||||
"LDPC-CODING-IN-PAYLOAD");
|
||||
PFLAG(PHY, 1, HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US,
|
||||
"HY-CAP1-HE-LTF-AND-GI-FOR-HE-PPDUS-0-8US");
|
||||
PRINT("MIDAMBLE-RX-MAX-NSTS-%d", ((cap[2] << 1) | (cap[1] >> 7)) & 0x3);
|
||||
|
||||
PFLAG(PHY, 2, NDP_4x_LTF_AND_3_2US, "NDP-4X-LTF-AND-3-2US");
|
||||
PFLAG(PHY, 2, STBC_TX_UNDER_80MHZ, "STBC-TX-UNDER-80MHZ");
|
||||
PFLAG(PHY, 2, STBC_RX_UNDER_80MHZ, "STBC-RX-UNDER-80MHZ");
|
||||
PFLAG(PHY, 2, DOPPLER_TX, "DOPPLER-TX");
|
||||
PFLAG(PHY, 2, DOPPLER_RX, "DOPPLER-RX");
|
||||
PFLAG(PHY, 2, UL_MU_FULL_MU_MIMO, "UL-MU-FULL-MU-MIMO");
|
||||
PFLAG(PHY, 2, UL_MU_PARTIAL_MU_MIMO, "UL-MU-PARTIAL-MU-MIMO");
|
||||
|
||||
switch (cap[3] & IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK) {
|
||||
case IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM:
|
||||
PRINT("DCM-MAX-CONST-TX-NO-DCM");
|
||||
break;
|
||||
case IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_BPSK:
|
||||
PRINT("DCM-MAX-CONST-TX-BPSK");
|
||||
break;
|
||||
case IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK:
|
||||
PRINT("DCM-MAX-CONST-TX-QPSK");
|
||||
break;
|
||||
case IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_16_QAM:
|
||||
PRINT("DCM-MAX-CONST-TX-16-QAM");
|
||||
break;
|
||||
}
|
||||
|
||||
PFLAG(PHY, 3, DCM_MAX_TX_NSS_1, "DCM-MAX-TX-NSS-1");
|
||||
PFLAG(PHY, 3, DCM_MAX_TX_NSS_2, "DCM-MAX-TX-NSS-2");
|
||||
|
||||
switch (cap[3] & IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK) {
|
||||
case IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_NO_DCM:
|
||||
PRINT("DCM-MAX-CONST-RX-NO-DCM");
|
||||
break;
|
||||
case IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_BPSK:
|
||||
PRINT("DCM-MAX-CONST-RX-BPSK");
|
||||
break;
|
||||
case IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK:
|
||||
PRINT("DCM-MAX-CONST-RX-QPSK");
|
||||
break;
|
||||
case IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM:
|
||||
PRINT("DCM-MAX-CONST-RX-16-QAM");
|
||||
break;
|
||||
}
|
||||
|
||||
PFLAG(PHY, 3, DCM_MAX_RX_NSS_1, "DCM-MAX-RX-NSS-1");
|
||||
PFLAG(PHY, 3, DCM_MAX_RX_NSS_2, "DCM-MAX-RX-NSS-2");
|
||||
PFLAG(PHY, 3, RX_HE_MU_PPDU_FROM_NON_AP_STA,
|
||||
"RX-HE-MU-PPDU-FROM-NON-AP-STA");
|
||||
PFLAG(PHY, 3, SU_BEAMFORMER, "SU-BEAMFORMER");
|
||||
|
||||
PFLAG(PHY, 4, SU_BEAMFORMEE, "SU-BEAMFORMEE");
|
||||
PFLAG(PHY, 4, MU_BEAMFORMER, "MU-BEAMFORMER");
|
||||
|
||||
PFLAG_RANGE(PHY, 4, BEAMFORMEE_MAX_STS_UNDER_80MHZ, 0, 1, 4,
|
||||
"BEAMFORMEE-MAX-STS-UNDER-%d");
|
||||
PFLAG_RANGE(PHY, 4, BEAMFORMEE_MAX_STS_ABOVE_80MHZ, 0, 1, 4,
|
||||
"BEAMFORMEE-MAX-STS-ABOVE-%d");
|
||||
|
||||
PFLAG_RANGE(PHY, 5, BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ, 0, 1, 1,
|
||||
"NUM-SND-DIM-UNDER-80MHZ-%d");
|
||||
PFLAG_RANGE(PHY, 5, BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ, 0, 1, 1,
|
||||
"NUM-SND-DIM-ABOVE-80MHZ-%d");
|
||||
PFLAG(PHY, 5, NG16_SU_FEEDBACK, "NG16-SU-FEEDBACK");
|
||||
PFLAG(PHY, 5, NG16_MU_FEEDBACK, "NG16-MU-FEEDBACK");
|
||||
|
||||
PFLAG(PHY, 6, CODEBOOK_SIZE_42_SU, "CODEBOOK-SIZE-42-SU");
|
||||
PFLAG(PHY, 6, CODEBOOK_SIZE_75_MU, "CODEBOOK-SIZE-75-MU");
|
||||
PFLAG(PHY, 6, TRIG_SU_BEAMFORMER_FB, "TRIG-SU-BEAMFORMER-FB");
|
||||
PFLAG(PHY, 6, TRIG_MU_BEAMFORMER_FB, "TRIG-MU-BEAMFORMER-FB");
|
||||
PFLAG(PHY, 6, TRIG_CQI_FB, "TRIG-CQI-FB");
|
||||
PFLAG(PHY, 6, PARTIAL_BW_EXT_RANGE, "PARTIAL-BW-EXT-RANGE");
|
||||
PFLAG(PHY, 6, PARTIAL_BANDWIDTH_DL_MUMIMO,
|
||||
"PARTIAL-BANDWIDTH-DL-MUMIMO");
|
||||
PFLAG(PHY, 6, PPE_THRESHOLD_PRESENT, "PPE-THRESHOLD-PRESENT");
|
||||
|
||||
PFLAG(PHY, 7, SRP_BASED_SR, "SRP-BASED-SR");
|
||||
PFLAG(PHY, 7, POWER_BOOST_FACTOR_AR, "POWER-BOOST-FACTOR-AR");
|
||||
PFLAG(PHY, 7, HE_SU_MU_PPDU_4XLTF_AND_08_US_GI,
|
||||
"HE-SU-MU-PPDU-4XLTF-AND-08-US-GI");
|
||||
PFLAG_RANGE(PHY, 7, MAX_NC, 0, 1, 1, "MAX-NC-%d");
|
||||
PFLAG(PHY, 7, STBC_TX_ABOVE_80MHZ, "STBC-TX-ABOVE-80MHZ");
|
||||
PFLAG(PHY, 7, STBC_RX_ABOVE_80MHZ, "STBC-RX-ABOVE-80MHZ");
|
||||
|
||||
PFLAG(PHY, 8, HE_ER_SU_PPDU_4XLTF_AND_08_US_GI,
|
||||
"HE-ER-SU-PPDU-4XLTF-AND-08-US-GI");
|
||||
PFLAG(PHY, 8, 20MHZ_IN_40MHZ_HE_PPDU_IN_2G,
|
||||
"20MHZ-IN-40MHZ-HE-PPDU-IN-2G");
|
||||
PFLAG(PHY, 8, 20MHZ_IN_160MHZ_HE_PPDU, "20MHZ-IN-160MHZ-HE-PPDU");
|
||||
PFLAG(PHY, 8, 80MHZ_IN_160MHZ_HE_PPDU, "80MHZ-IN-160MHZ-HE-PPDU");
|
||||
PFLAG(PHY, 8, HE_ER_SU_1XLTF_AND_08_US_GI,
|
||||
"HE-ER-SU-1XLTF-AND-08-US-GI");
|
||||
PFLAG(PHY, 8, MIDAMBLE_RX_TX_2X_AND_1XLTF,
|
||||
"MIDAMBLE-RX-TX-2X-AND-1XLTF");
|
||||
|
||||
switch (cap[8] & IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_MASK) {
|
||||
case IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_20MHZ:
|
||||
PRINT("DDCM-MAX-BW-20MHZ");
|
||||
break;
|
||||
case IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_40MHZ:
|
||||
PRINT("DCM-MAX-BW-40MHZ");
|
||||
break;
|
||||
case IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_80MHZ:
|
||||
PRINT("DCM-MAX-BW-80MHZ");
|
||||
break;
|
||||
case IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_160_OR_80P80_MHZ:
|
||||
PRINT("DCM-MAX-BW-160-OR-80P80-MHZ");
|
||||
break;
|
||||
}
|
||||
|
||||
PFLAG(PHY, 9, LONGER_THAN_16_SIGB_OFDM_SYM,
|
||||
"LONGER-THAN-16-SIGB-OFDM-SYM");
|
||||
PFLAG(PHY, 9, NON_TRIGGERED_CQI_FEEDBACK,
|
||||
"NON-TRIGGERED-CQI-FEEDBACK");
|
||||
PFLAG(PHY, 9, TX_1024_QAM_LESS_THAN_242_TONE_RU,
|
||||
"TX-1024-QAM-LESS-THAN-242-TONE-RU");
|
||||
PFLAG(PHY, 9, RX_1024_QAM_LESS_THAN_242_TONE_RU,
|
||||
"RX-1024-QAM-LESS-THAN-242-TONE-RU");
|
||||
PFLAG(PHY, 9, RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB,
|
||||
"RX-FULL-BW-SU-USING-MU-WITH-COMP-SIGB");
|
||||
PFLAG(PHY, 9, RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB,
|
||||
"RX-FULL-BW-SU-USING-MU-WITH-NON-COMP-SIGB");
|
||||
|
||||
#undef PFLAG_RANGE_DEFAULT
|
||||
#undef PFLAG_RANGE
|
||||
#undef PFLAG
|
||||
|
||||
#define PRINT_NSS_SUPP(f, n) \
|
||||
do { \
|
||||
int i; \
|
||||
u16 v = le16_to_cpu(nss->f); \
|
||||
p += scnprintf(p, buf_sz + buf - p, n ": %#.4x\n", v); \
|
||||
for (i = 0; i < 8; i += 2) { \
|
||||
switch ((v >> i) & 0x3) { \
|
||||
case 0: \
|
||||
PRINT(n "-%d-SUPPORT-0-7", i / 2); \
|
||||
break; \
|
||||
case 1: \
|
||||
PRINT(n "-%d-SUPPORT-0-9", i / 2); \
|
||||
break; \
|
||||
case 2: \
|
||||
PRINT(n "-%d-SUPPORT-0-11", i / 2); \
|
||||
break; \
|
||||
case 3: \
|
||||
PRINT(n "-%d-NOT-SUPPORTED", i / 2); \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
PRINT_NSS_SUPP(rx_mcs_80, "RX-MCS-80");
|
||||
PRINT_NSS_SUPP(tx_mcs_80, "TX-MCS-80");
|
||||
|
||||
if (cap[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) {
|
||||
PRINT_NSS_SUPP(rx_mcs_160, "RX-MCS-160");
|
||||
PRINT_NSS_SUPP(tx_mcs_160, "TX-MCS-160");
|
||||
}
|
||||
|
||||
if (cap[0] &
|
||||
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) {
|
||||
PRINT_NSS_SUPP(rx_mcs_80p80, "RX-MCS-80P80");
|
||||
PRINT_NSS_SUPP(tx_mcs_80p80, "TX-MCS-80P80");
|
||||
}
|
||||
|
||||
#undef PRINT_NSS_SUPP
|
||||
#undef PRINT
|
||||
|
||||
if (!(cap[6] & IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT))
|
||||
goto out;
|
||||
|
||||
p += scnprintf(p, buf_sz + buf - p, "PPE-THRESHOLDS: %#.2x",
|
||||
hec->ppe_thres[0]);
|
||||
|
||||
ppe_size = ieee80211_he_ppe_size(hec->ppe_thres[0], cap);
|
||||
for (i = 1; i < ppe_size; i++) {
|
||||
p += scnprintf(p, buf_sz + buf - p, " %#.2x",
|
||||
hec->ppe_thres[i]);
|
||||
}
|
||||
p += scnprintf(p, buf_sz + buf - p, "\n");
|
||||
|
||||
out:
|
||||
ret = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
STA_OPS(he_capa);
|
||||
|
||||
#define DEBUGFS_ADD(name) \
|
||||
debugfs_create_file(#name, 0400, \
|
||||
|
@ -538,6 +897,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
|
|||
DEBUGFS_ADD(agg_status);
|
||||
DEBUGFS_ADD(ht_capa);
|
||||
DEBUGFS_ADD(vht_capa);
|
||||
DEBUGFS_ADD(he_capa);
|
||||
|
||||
DEBUGFS_ADD_COUNTER(rx_duplicates, rx_stats.num_duplicates);
|
||||
DEBUGFS_ADD_COUNTER(rx_fragments, rx_stats.fragments);
|
||||
|
|
|
@ -1173,6 +1173,16 @@ static inline void drv_wake_tx_queue(struct ieee80211_local *local,
|
|||
local->ops->wake_tx_queue(&local->hw, &txq->txq);
|
||||
}
|
||||
|
||||
static inline int drv_can_aggregate_in_amsdu(struct ieee80211_local *local,
|
||||
struct sk_buff *head,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
if (!local->ops->can_aggregate_in_amsdu)
|
||||
return true;
|
||||
|
||||
return local->ops->can_aggregate_in_amsdu(&local->hw, head, skb);
|
||||
}
|
||||
|
||||
static inline int drv_start_nan(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_nan_conf *conf)
|
||||
|
|
|
@ -1070,7 +1070,9 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_vht_cap cap_ie;
|
||||
struct ieee80211_sta_vht_cap cap = sta->sta.vht_cap;
|
||||
|
||||
ieee80211_chandef_vht_oper(elems->vht_operation,
|
||||
ieee80211_chandef_vht_oper(&local->hw,
|
||||
elems->vht_operation,
|
||||
elems->ht_operation,
|
||||
&chandef);
|
||||
memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie));
|
||||
ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
|
||||
|
|
|
@ -1199,6 +1199,9 @@ struct ieee80211_local {
|
|||
/* number of RX chains the hardware has */
|
||||
u8 rx_chains;
|
||||
|
||||
/* bitmap of which sbands were copied */
|
||||
u8 sband_allocated;
|
||||
|
||||
int tx_headroom; /* required headroom for hardware/radiotap */
|
||||
|
||||
/* Tasklet and skb queue to process calls from IRQ mode. All frames
|
||||
|
@ -2109,7 +2112,9 @@ u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo);
|
|||
/* channel management */
|
||||
bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
|
||||
struct cfg80211_chan_def *chandef);
|
||||
bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper,
|
||||
bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw,
|
||||
const struct ieee80211_vht_operation *oper,
|
||||
const struct ieee80211_ht_operation *htop,
|
||||
struct cfg80211_chan_def *chandef);
|
||||
u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c);
|
||||
|
||||
|
|
|
@ -248,6 +248,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
|
|||
(key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
|
||||
increment_tailroom_need_count(sdata);
|
||||
|
||||
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
|
||||
ret = drv_set_key(key->local, DISABLE_KEY, sdata,
|
||||
sta ? &sta->sta : NULL, &key->conf);
|
||||
|
||||
|
@ -256,8 +257,65 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
|
|||
"failed to remove key (%d, %pM) from hardware (%d)\n",
|
||||
key->conf.keyidx,
|
||||
sta ? sta->sta.addr : bcast_addr, ret);
|
||||
}
|
||||
|
||||
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
|
||||
static int ieee80211_hw_key_replace(struct ieee80211_key *old_key,
|
||||
struct ieee80211_key *new_key,
|
||||
bool ptk0rekey)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_local *local;
|
||||
struct sta_info *sta;
|
||||
int ret;
|
||||
|
||||
/* Aggregation sessions are OK when running on SW crypto.
|
||||
* A broken remote STA may cause issues not observed with HW
|
||||
* crypto, though.
|
||||
*/
|
||||
if (!(old_key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
|
||||
return 0;
|
||||
|
||||
assert_key_lock(old_key->local);
|
||||
sta = old_key->sta;
|
||||
|
||||
/* PTK only using key ID 0 needs special handling on rekey */
|
||||
if (new_key && sta && ptk0rekey) {
|
||||
local = old_key->local;
|
||||
sdata = old_key->sdata;
|
||||
|
||||
/* Stop TX till we are on the new key */
|
||||
old_key->flags |= KEY_FLAG_TAINTED;
|
||||
ieee80211_clear_fast_xmit(sta);
|
||||
|
||||
/* Aggregation sessions during rekey are complicated due to the
|
||||
* reorder buffer and retransmits. Side step that by blocking
|
||||
* aggregation during rekey and tear down running sessions.
|
||||
*/
|
||||
if (ieee80211_hw_check(&local->hw, AMPDU_AGGREGATION)) {
|
||||
set_sta_flag(sta, WLAN_STA_BLOCK_BA);
|
||||
ieee80211_sta_tear_down_BA_sessions(sta,
|
||||
AGG_STOP_LOCAL_REQUEST);
|
||||
}
|
||||
|
||||
if (!wiphy_ext_feature_isset(local->hw.wiphy,
|
||||
NL80211_EXT_FEATURE_CAN_REPLACE_PTK0)) {
|
||||
pr_warn_ratelimited("Rekeying PTK for STA %pM but driver can't safely do that.",
|
||||
sta->sta.addr);
|
||||
/* Flushing the driver queues *may* help prevent
|
||||
* the clear text leaks and freezes.
|
||||
*/
|
||||
ieee80211_flush_queues(local, sdata, false);
|
||||
}
|
||||
}
|
||||
|
||||
ieee80211_key_disable_hw_accel(old_key);
|
||||
|
||||
if (new_key)
|
||||
ret = ieee80211_key_enable_hw_accel(new_key);
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
|
||||
|
@ -316,38 +374,57 @@ void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
|
||||
static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
|
||||
static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta,
|
||||
bool pairwise,
|
||||
struct ieee80211_key *old,
|
||||
struct ieee80211_key *new)
|
||||
{
|
||||
int idx;
|
||||
int ret;
|
||||
bool defunikey, defmultikey, defmgmtkey;
|
||||
|
||||
/* caller must provide at least one old/new */
|
||||
if (WARN_ON(!new && !old))
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (new)
|
||||
list_add_tail_rcu(&new->list, &sdata->key_list);
|
||||
|
||||
WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);
|
||||
|
||||
if (old)
|
||||
if (old) {
|
||||
idx = old->conf.keyidx;
|
||||
else
|
||||
/* TODO: proper implement and test "Extended Key ID for
|
||||
* Individually Addressed Frames" from IEEE 802.11-2016.
|
||||
* Till then always assume only key ID 0 is used for
|
||||
* pairwise keys.*/
|
||||
ret = ieee80211_hw_key_replace(old, new, pairwise);
|
||||
} else {
|
||||
/* new must be provided in case old is not */
|
||||
idx = new->conf.keyidx;
|
||||
if (!new->local->wowlan)
|
||||
ret = ieee80211_key_enable_hw_accel(new);
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (sta) {
|
||||
if (pairwise) {
|
||||
rcu_assign_pointer(sta->ptk[idx], new);
|
||||
sta->ptk_idx = idx;
|
||||
ieee80211_check_fast_xmit(sta);
|
||||
if (new) {
|
||||
clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
|
||||
ieee80211_check_fast_xmit(sta);
|
||||
}
|
||||
} else {
|
||||
rcu_assign_pointer(sta->gtk[idx], new);
|
||||
}
|
||||
ieee80211_check_fast_rx(sta);
|
||||
if (new)
|
||||
ieee80211_check_fast_rx(sta);
|
||||
} else {
|
||||
defunikey = old &&
|
||||
old == key_mtx_dereference(sdata->local,
|
||||
|
@ -380,6 +457,8 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
if (old)
|
||||
list_del_rcu(&old->list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ieee80211_key *
|
||||
|
@ -575,9 +654,6 @@ static void ieee80211_key_free_common(struct ieee80211_key *key)
|
|||
static void __ieee80211_key_destroy(struct ieee80211_key *key,
|
||||
bool delay_tailroom)
|
||||
{
|
||||
if (key->local)
|
||||
ieee80211_key_disable_hw_accel(key);
|
||||
|
||||
if (key->local) {
|
||||
struct ieee80211_sub_if_data *sdata = key->sdata;
|
||||
|
||||
|
@ -654,7 +730,6 @@ int ieee80211_key_link(struct ieee80211_key *key,
|
|||
struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_key *old_key;
|
||||
int idx = key->conf.keyidx;
|
||||
bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE;
|
||||
|
@ -691,17 +766,13 @@ int ieee80211_key_link(struct ieee80211_key *key,
|
|||
|
||||
increment_tailroom_need_count(sdata);
|
||||
|
||||
ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
|
||||
ieee80211_key_destroy(old_key, delay_tailroom);
|
||||
ret = ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
|
||||
|
||||
ieee80211_debugfs_key_add(key);
|
||||
|
||||
if (!local->wowlan) {
|
||||
ret = ieee80211_key_enable_hw_accel(key);
|
||||
if (ret)
|
||||
ieee80211_key_free(key, delay_tailroom);
|
||||
if (!ret) {
|
||||
ieee80211_debugfs_key_add(key);
|
||||
ieee80211_key_destroy(old_key, delay_tailroom);
|
||||
} else {
|
||||
ret = 0;
|
||||
ieee80211_key_free(key, delay_tailroom);
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -610,6 +611,18 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
|
|||
local->ops = ops;
|
||||
local->use_chanctx = use_chanctx;
|
||||
|
||||
/*
|
||||
* We need a bit of data queued to build aggregates properly, so
|
||||
* instruct the TCP stack to allow more than a single ms of data
|
||||
* to be queued in the stack. The value is a bit-shift of 1
|
||||
* second, so 8 is ~4ms of queued data. Only affects local TCP
|
||||
* sockets.
|
||||
* This is the default, anyhow - drivers may need to override it
|
||||
* for local reasons (longer buffers, longer completion time, or
|
||||
* similar).
|
||||
*/
|
||||
local->hw.tx_sk_pacing_shift = 8;
|
||||
|
||||
/* set up some defaults */
|
||||
local->hw.queues = 1;
|
||||
local->hw.max_rates = 1;
|
||||
|
@ -1158,6 +1171,51 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
goto fail_rate;
|
||||
}
|
||||
|
||||
if (local->rate_ctrl) {
|
||||
clear_bit(IEEE80211_HW_SUPPORTS_VHT_EXT_NSS_BW, hw->flags);
|
||||
if (local->rate_ctrl->ops->capa & RATE_CTRL_CAPA_VHT_EXT_NSS_BW)
|
||||
ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the VHT capabilities don't have IEEE80211_VHT_EXT_NSS_BW_CAPABLE,
|
||||
* or have it when we don't, copy the sband structure and set/clear it.
|
||||
* This is necessary because rate scaling algorithms could be switched
|
||||
* and have different support values.
|
||||
* Print a message so that in the common case the reallocation can be
|
||||
* avoided.
|
||||
*/
|
||||
BUILD_BUG_ON(NUM_NL80211_BANDS > 8 * sizeof(local->sband_allocated));
|
||||
for (band = 0; band < NUM_NL80211_BANDS; band++) {
|
||||
struct ieee80211_supported_band *sband;
|
||||
bool local_cap, ie_cap;
|
||||
|
||||
local_cap = ieee80211_hw_check(hw, SUPPORTS_VHT_EXT_NSS_BW);
|
||||
|
||||
sband = local->hw.wiphy->bands[band];
|
||||
if (!sband || !sband->vht_cap.vht_supported)
|
||||
continue;
|
||||
|
||||
ie_cap = !!(sband->vht_cap.vht_mcs.tx_highest &
|
||||
cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE));
|
||||
|
||||
if (local_cap == ie_cap)
|
||||
continue;
|
||||
|
||||
sband = kmemdup(sband, sizeof(*sband), GFP_KERNEL);
|
||||
if (!sband)
|
||||
goto fail_rate;
|
||||
|
||||
wiphy_dbg(hw->wiphy, "copying sband (band %d) due to VHT EXT NSS BW flag\n",
|
||||
band);
|
||||
|
||||
sband->vht_cap.vht_mcs.tx_highest ^=
|
||||
cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE);
|
||||
|
||||
local->hw.wiphy->bands[band] = sband;
|
||||
local->sband_allocated |= BIT(band);
|
||||
}
|
||||
|
||||
/* add one default STA interface if supported */
|
||||
if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION) &&
|
||||
!ieee80211_hw_check(hw, NO_AUTO_VIF)) {
|
||||
|
@ -1276,6 +1334,7 @@ static int ieee80211_free_ack_frame(int id, void *p, void *data)
|
|||
void ieee80211_free_hw(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
enum nl80211_band band;
|
||||
|
||||
mutex_destroy(&local->iflist_mtx);
|
||||
mutex_destroy(&local->mtx);
|
||||
|
@ -1291,6 +1350,12 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
|
|||
|
||||
ieee80211_free_led_names(local);
|
||||
|
||||
for (band = 0; band < NUM_NL80211_BANDS; band++) {
|
||||
if (!(local->sband_allocated & BIT(band)))
|
||||
continue;
|
||||
kfree(local->hw.wiphy->bands[band]);
|
||||
}
|
||||
|
||||
wiphy_free(local->hw.wiphy);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_free_hw);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2009 open80211s Ltd.
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* Authors: Luis Carlos Cobo <luisca@cozybit.com>
|
||||
* Javier Cardona <javier@cozybit.com>
|
||||
*
|
||||
|
@ -98,7 +99,9 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
|
|||
cfg80211_chandef_create(&sta_chan_def, sdata->vif.bss_conf.chandef.chan,
|
||||
NL80211_CHAN_NO_HT);
|
||||
ieee80211_chandef_ht_oper(ie->ht_operation, &sta_chan_def);
|
||||
ieee80211_chandef_vht_oper(ie->vht_operation, &sta_chan_def);
|
||||
ieee80211_chandef_vht_oper(&sdata->local->hw,
|
||||
ie->vht_operation, ie->ht_operation,
|
||||
&sta_chan_def);
|
||||
|
||||
if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef,
|
||||
&sta_chan_def))
|
||||
|
|
|
@ -220,7 +220,8 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
|
|||
memcpy(&he_oper_vht_cap, he_oper->optional, 3);
|
||||
he_oper_vht_cap.basic_mcs_set = cpu_to_le16(0);
|
||||
|
||||
if (!ieee80211_chandef_vht_oper(&he_oper_vht_cap,
|
||||
if (!ieee80211_chandef_vht_oper(&sdata->local->hw,
|
||||
&he_oper_vht_cap, ht_oper,
|
||||
&vht_chandef)) {
|
||||
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE))
|
||||
sdata_info(sdata,
|
||||
|
@ -228,7 +229,8 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
|
|||
ret = IEEE80211_STA_DISABLE_HE;
|
||||
goto out;
|
||||
}
|
||||
} else if (!ieee80211_chandef_vht_oper(vht_oper, &vht_chandef)) {
|
||||
} else if (!ieee80211_chandef_vht_oper(&sdata->local->hw, vht_oper,
|
||||
ht_oper, &vht_chandef)) {
|
||||
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
|
||||
sdata_info(sdata,
|
||||
"AP VHT information is invalid, disable VHT\n");
|
||||
|
@ -3237,19 +3239,16 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
if (bss_conf->he_support) {
|
||||
u32 he_oper_params =
|
||||
le32_to_cpu(elems.he_operation->he_oper_params);
|
||||
bss_conf->bss_color =
|
||||
le32_get_bits(elems.he_operation->he_oper_params,
|
||||
IEEE80211_HE_OPERATION_BSS_COLOR_MASK);
|
||||
|
||||
bss_conf->bss_color = he_oper_params &
|
||||
IEEE80211_HE_OPERATION_BSS_COLOR_MASK;
|
||||
bss_conf->htc_trig_based_pkt_ext =
|
||||
(he_oper_params &
|
||||
IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK) <<
|
||||
IEEE80211_HE_OPERATION_DFLT_PE_DURATION_OFFSET;
|
||||
le32_get_bits(elems.he_operation->he_oper_params,
|
||||
IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK);
|
||||
bss_conf->frame_time_rts_th =
|
||||
(he_oper_params &
|
||||
IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK) <<
|
||||
IEEE80211_HE_OPERATION_RTS_THRESHOLD_OFFSET;
|
||||
le32_get_bits(elems.he_operation->he_oper_params,
|
||||
IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK);
|
||||
|
||||
bss_conf->multi_sta_back_32bit =
|
||||
sta->sta.he_cap.he_cap_elem.mac_cap_info[2] &
|
||||
|
|
|
@ -115,7 +115,8 @@ static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len,
|
|||
|
||||
if (status->flag & (RX_FLAG_FAILED_FCS_CRC |
|
||||
RX_FLAG_FAILED_PLCP_CRC |
|
||||
RX_FLAG_ONLY_MONITOR))
|
||||
RX_FLAG_ONLY_MONITOR |
|
||||
RX_FLAG_NO_PSDU))
|
||||
return true;
|
||||
|
||||
if (unlikely(skb->len < 16 + present_fcs_len + rtap_space))
|
||||
|
@ -189,6 +190,15 @@ ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local,
|
|||
BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he_mu) != 12);
|
||||
}
|
||||
|
||||
if (status->flag & RX_FLAG_NO_PSDU)
|
||||
len += 1;
|
||||
|
||||
if (status->flag & RX_FLAG_RADIOTAP_LSIG) {
|
||||
len = ALIGN(len, 2);
|
||||
len += 4;
|
||||
BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_lsig) != 4);
|
||||
}
|
||||
|
||||
if (status->chains) {
|
||||
/* antenna and antenna signal fields */
|
||||
len += 2 * hweight8(status->chains);
|
||||
|
@ -279,6 +289,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
|
|||
struct ieee80211_vendor_radiotap rtap = {};
|
||||
struct ieee80211_radiotap_he he = {};
|
||||
struct ieee80211_radiotap_he_mu he_mu = {};
|
||||
struct ieee80211_radiotap_lsig lsig = {};
|
||||
|
||||
if (status->flag & RX_FLAG_RADIOTAP_HE) {
|
||||
he = *(struct ieee80211_radiotap_he *)skb->data;
|
||||
|
@ -291,6 +302,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
|
|||
skb_pull(skb, sizeof(he_mu));
|
||||
}
|
||||
|
||||
if (status->flag & RX_FLAG_RADIOTAP_LSIG) {
|
||||
lsig = *(struct ieee80211_radiotap_lsig *)skb->data;
|
||||
skb_pull(skb, sizeof(lsig));
|
||||
}
|
||||
|
||||
if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) {
|
||||
rtap = *(struct ieee80211_vendor_radiotap *)skb->data;
|
||||
/* rtap.len and rtap.pad are undone immediately */
|
||||
|
@ -549,7 +565,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
|
|||
|
||||
if (status->encoding == RX_ENC_HE &&
|
||||
status->flag & RX_FLAG_RADIOTAP_HE) {
|
||||
#define HE_PREP(f, val) cpu_to_le16(FIELD_PREP(IEEE80211_RADIOTAP_HE_##f, val))
|
||||
#define HE_PREP(f, val) le16_encode_bits(val, IEEE80211_RADIOTAP_HE_##f)
|
||||
|
||||
if (status->enc_flags & RX_ENC_FLAG_STBC_MASK) {
|
||||
he.data6 |= HE_PREP(DATA6_NSTS,
|
||||
|
@ -630,6 +646,21 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
|
|||
pos += sizeof(he_mu);
|
||||
}
|
||||
|
||||
if (status->flag & RX_FLAG_NO_PSDU) {
|
||||
rthdr->it_present |=
|
||||
cpu_to_le32(1 << IEEE80211_RADIOTAP_ZERO_LEN_PSDU);
|
||||
*pos++ = status->zero_length_psdu_type;
|
||||
}
|
||||
|
||||
if (status->flag & RX_FLAG_RADIOTAP_LSIG) {
|
||||
/* ensure 2 byte alignment */
|
||||
while ((pos - (u8 *)rthdr) & 1)
|
||||
pos++;
|
||||
rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_LSIG);
|
||||
memcpy(pos, &lsig, sizeof(lsig));
|
||||
pos += sizeof(lsig);
|
||||
}
|
||||
|
||||
for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) {
|
||||
*pos++ = status->chain_signal[chain];
|
||||
*pos++ = chain;
|
||||
|
@ -1505,7 +1536,7 @@ static void sta_ps_start(struct sta_info *sta)
|
|||
if (!sta->sta.txq[0])
|
||||
return;
|
||||
|
||||
for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
|
||||
for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) {
|
||||
if (txq_has_queue(sta->sta.txq[tid]))
|
||||
set_bit(tid, &sta->txq_buffered_tids);
|
||||
else
|
||||
|
|
|
@ -144,6 +144,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
|
|||
wide_bw_chansw_ie->new_center_freq_seg1,
|
||||
/* .basic_mcs_set doesn't matter */
|
||||
};
|
||||
struct ieee80211_ht_operation ht_oper = {};
|
||||
|
||||
/* default, for the case of IEEE80211_VHT_CHANWIDTH_USE_HT,
|
||||
* to the previously parsed chandef
|
||||
|
@ -151,7 +152,9 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
|
|||
new_vht_chandef = csa_ie->chandef;
|
||||
|
||||
/* ignore if parsing fails */
|
||||
if (!ieee80211_chandef_vht_oper(&vht_oper, &new_vht_chandef))
|
||||
if (!ieee80211_chandef_vht_oper(&sdata->local->hw,
|
||||
&vht_oper, &ht_oper,
|
||||
&new_vht_chandef))
|
||||
new_vht_chandef.chan = NULL;
|
||||
|
||||
if (sta_flags & IEEE80211_STA_DISABLE_80P80MHZ &&
|
||||
|
|
|
@ -113,7 +113,12 @@ static void __cleanup_single_sta(struct sta_info *sta)
|
|||
|
||||
if (sta->sta.txq[0]) {
|
||||
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
|
||||
struct txq_info *txqi = to_txq_info(sta->sta.txq[i]);
|
||||
struct txq_info *txqi;
|
||||
|
||||
if (!sta->sta.txq[i])
|
||||
continue;
|
||||
|
||||
txqi = to_txq_info(sta->sta.txq[i]);
|
||||
|
||||
spin_lock_bh(&fq->lock);
|
||||
ieee80211_txq_purge(local, txqi);
|
||||
|
@ -374,6 +379,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
|||
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
|
||||
struct txq_info *txq = txq_data + i * size;
|
||||
|
||||
/* might not do anything for the bufferable MMPDU TXQ */
|
||||
ieee80211_txq_init(sdata, sta, txq, i);
|
||||
}
|
||||
}
|
||||
|
@ -1239,13 +1245,11 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
|
|||
if (!ieee80211_hw_check(&local->hw, AP_LINK_PS))
|
||||
drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
|
||||
|
||||
if (sta->sta.txq[0]) {
|
||||
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
|
||||
if (!txq_has_queue(sta->sta.txq[i]))
|
||||
continue;
|
||||
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
|
||||
if (!sta->sta.txq[i] || !txq_has_queue(sta->sta.txq[i]))
|
||||
continue;
|
||||
|
||||
drv_wake_tx_queue(local, to_txq_info(sta->sta.txq[i]));
|
||||
}
|
||||
drv_wake_tx_queue(local, to_txq_info(sta->sta.txq[i]));
|
||||
}
|
||||
|
||||
skb_queue_head_init(&pending);
|
||||
|
@ -1683,7 +1687,8 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
|
|||
return;
|
||||
|
||||
for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
|
||||
if (!(driver_release_tids & BIT(tid)) ||
|
||||
if (!sta->sta.txq[tid] ||
|
||||
!(driver_release_tids & BIT(tid)) ||
|
||||
txq_has_queue(sta->sta.txq[tid]))
|
||||
continue;
|
||||
|
||||
|
|
|
@ -1249,10 +1249,18 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
|
|||
(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
|
||||
return NULL;
|
||||
|
||||
if (!ieee80211_is_data_present(hdr->frame_control))
|
||||
return NULL;
|
||||
|
||||
if (sta) {
|
||||
if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) {
|
||||
if ((!ieee80211_is_mgmt(hdr->frame_control) ||
|
||||
ieee80211_is_bufferable_mmpdu(hdr->frame_control) ||
|
||||
vif->type == NL80211_IFTYPE_STATION) &&
|
||||
sta && sta->uploaded) {
|
||||
/*
|
||||
* This will be NULL if the driver didn't set the
|
||||
* opt-in hardware flag.
|
||||
*/
|
||||
txq = sta->sta.txq[IEEE80211_NUM_TIDS];
|
||||
}
|
||||
} else if (sta) {
|
||||
u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
|
||||
|
||||
if (!sta->uploaded)
|
||||
|
@ -1440,16 +1448,33 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
txqi->txq.vif = &sdata->vif;
|
||||
|
||||
if (sta) {
|
||||
txqi->txq.sta = &sta->sta;
|
||||
sta->sta.txq[tid] = &txqi->txq;
|
||||
txqi->txq.tid = tid;
|
||||
txqi->txq.ac = ieee80211_ac_from_tid(tid);
|
||||
} else {
|
||||
if (!sta) {
|
||||
sdata->vif.txq = &txqi->txq;
|
||||
txqi->txq.tid = 0;
|
||||
txqi->txq.ac = IEEE80211_AC_BE;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (tid == IEEE80211_NUM_TIDS) {
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
/* Drivers need to opt in to the management MPDU TXQ */
|
||||
if (!ieee80211_hw_check(&sdata->local->hw,
|
||||
STA_MMPDU_TXQ))
|
||||
return;
|
||||
} else if (!ieee80211_hw_check(&sdata->local->hw,
|
||||
BUFF_MMPDU_TXQ)) {
|
||||
/* Drivers need to opt in to the bufferable MMPDU TXQ */
|
||||
return;
|
||||
}
|
||||
txqi->txq.ac = IEEE80211_AC_VO;
|
||||
} else {
|
||||
txqi->txq.ac = ieee80211_ac_from_tid(tid);
|
||||
}
|
||||
|
||||
txqi->txq.sta = &sta->sta;
|
||||
txqi->txq.tid = tid;
|
||||
sta->sta.txq[tid] = &txqi->txq;
|
||||
}
|
||||
|
||||
void ieee80211_txq_purge(struct ieee80211_local *local,
|
||||
|
@ -2951,6 +2976,10 @@ void ieee80211_check_fast_xmit(struct sta_info *sta)
|
|||
if (!(build.key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
|
||||
goto out;
|
||||
|
||||
/* Key is being removed */
|
||||
if (build.key->flags & KEY_FLAG_TAINTED)
|
||||
goto out;
|
||||
|
||||
switch (build.key->conf.cipher) {
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
case WLAN_CIPHER_SUITE_CCMP_256:
|
||||
|
@ -3196,6 +3225,10 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata,
|
|||
max_amsdu_len = min_t(int, max_amsdu_len,
|
||||
sta->sta.max_rc_amsdu_len);
|
||||
|
||||
if (sta->sta.max_tid_amsdu_len[tid])
|
||||
max_amsdu_len = min_t(int, max_amsdu_len,
|
||||
sta->sta.max_tid_amsdu_len[tid]);
|
||||
|
||||
spin_lock_bh(&fq->lock);
|
||||
|
||||
/* TODO: Ideally aggregation should be done on dequeue to remain
|
||||
|
@ -3228,6 +3261,9 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata,
|
|||
if (max_frags && nfrags > max_frags)
|
||||
goto out;
|
||||
|
||||
if (!drv_can_aggregate_in_amsdu(local, head, skb))
|
||||
goto out;
|
||||
|
||||
if (!ieee80211_amsdu_prepare_head(sdata, fast_tx, head))
|
||||
goto out;
|
||||
|
||||
|
@ -3608,13 +3644,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
if (!IS_ERR_OR_NULL(sta)) {
|
||||
struct ieee80211_fast_tx *fast_tx;
|
||||
|
||||
/* We need a bit of data queued to build aggregates properly, so
|
||||
* instruct the TCP stack to allow more than a single ms of data
|
||||
* to be queued in the stack. The value is a bit-shift of 1
|
||||
* second, so 8 is ~4ms of queued data. Only affects local TCP
|
||||
* sockets.
|
||||
*/
|
||||
sk_pacing_shift_update(skb->sk, 8);
|
||||
sk_pacing_shift_update(skb->sk, sdata->local->hw.tx_sk_pacing_shift);
|
||||
|
||||
fast_tx = rcu_dereference(sta->fast_tx);
|
||||
|
||||
|
|
|
@ -2757,49 +2757,65 @@ bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper,
|
||||
bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw,
|
||||
const struct ieee80211_vht_operation *oper,
|
||||
const struct ieee80211_ht_operation *htop,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct cfg80211_chan_def new = *chandef;
|
||||
int cf1, cf2;
|
||||
int cf0, cf1;
|
||||
int ccfs0, ccfs1, ccfs2;
|
||||
int ccf0, ccf1;
|
||||
|
||||
if (!oper)
|
||||
if (!oper || !htop)
|
||||
return false;
|
||||
|
||||
cf1 = ieee80211_channel_to_frequency(oper->center_freq_seg0_idx,
|
||||
chandef->chan->band);
|
||||
cf2 = ieee80211_channel_to_frequency(oper->center_freq_seg1_idx,
|
||||
chandef->chan->band);
|
||||
ccfs0 = oper->center_freq_seg0_idx;
|
||||
ccfs1 = oper->center_freq_seg1_idx;
|
||||
ccfs2 = (le16_to_cpu(htop->operation_mode) &
|
||||
IEEE80211_HT_OP_MODE_CCFS2_MASK)
|
||||
>> IEEE80211_HT_OP_MODE_CCFS2_SHIFT;
|
||||
|
||||
/* when parsing (and we know how to) CCFS1 and CCFS2 are equivalent */
|
||||
ccf0 = ccfs0;
|
||||
ccf1 = ccfs1;
|
||||
if (!ccfs1 && ieee80211_hw_check(hw, SUPPORTS_VHT_EXT_NSS_BW))
|
||||
ccf1 = ccfs2;
|
||||
|
||||
cf0 = ieee80211_channel_to_frequency(ccf0, chandef->chan->band);
|
||||
cf1 = ieee80211_channel_to_frequency(ccf1, chandef->chan->band);
|
||||
|
||||
switch (oper->chan_width) {
|
||||
case IEEE80211_VHT_CHANWIDTH_USE_HT:
|
||||
/* just use HT information directly */
|
||||
break;
|
||||
case IEEE80211_VHT_CHANWIDTH_80MHZ:
|
||||
new.width = NL80211_CHAN_WIDTH_80;
|
||||
new.center_freq1 = cf1;
|
||||
new.center_freq1 = cf0;
|
||||
/* If needed, adjust based on the newer interop workaround. */
|
||||
if (oper->center_freq_seg1_idx) {
|
||||
if (ccf1) {
|
||||
unsigned int diff;
|
||||
|
||||
diff = abs(oper->center_freq_seg1_idx -
|
||||
oper->center_freq_seg0_idx);
|
||||
diff = abs(ccf1 - ccf0);
|
||||
if (diff == 8) {
|
||||
new.width = NL80211_CHAN_WIDTH_160;
|
||||
new.center_freq1 = cf2;
|
||||
new.center_freq1 = cf1;
|
||||
} else if (diff > 8) {
|
||||
new.width = NL80211_CHAN_WIDTH_80P80;
|
||||
new.center_freq2 = cf2;
|
||||
new.center_freq2 = cf1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IEEE80211_VHT_CHANWIDTH_160MHZ:
|
||||
/* deprecated encoding */
|
||||
new.width = NL80211_CHAN_WIDTH_160;
|
||||
new.center_freq1 = cf1;
|
||||
new.center_freq1 = cf0;
|
||||
break;
|
||||
case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
|
||||
/* deprecated encoding */
|
||||
new.width = NL80211_CHAN_WIDTH_80P80;
|
||||
new.center_freq1 = cf1;
|
||||
new.center_freq2 = cf2;
|
||||
new.center_freq1 = cf0;
|
||||
new.center_freq2 = cf1;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
* Portions of this file
|
||||
* Copyright(c) 2015 - 2016 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -231,6 +232,13 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
|
|||
memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs,
|
||||
sizeof(struct ieee80211_vht_mcs_info));
|
||||
|
||||
/* copy EXT_NSS_BW Support value or remove the capability */
|
||||
if (ieee80211_hw_check(&sdata->local->hw, SUPPORTS_VHT_EXT_NSS_BW))
|
||||
vht_cap->cap |= (cap_info & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK);
|
||||
else
|
||||
vht_cap->vht_mcs.tx_highest &=
|
||||
~cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE);
|
||||
|
||||
/* but also restrict MCSes */
|
||||
for (i = 0; i < 8; i++) {
|
||||
u16 own_rx, own_tx, peer_rx, peer_tx;
|
||||
|
@ -294,6 +302,18 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
|
|||
break;
|
||||
default:
|
||||
sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80;
|
||||
|
||||
if (!(vht_cap->vht_mcs.tx_highest &
|
||||
cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE)))
|
||||
break;
|
||||
|
||||
/*
|
||||
* If this is non-zero, then it does support 160 MHz after all,
|
||||
* in one form or the other. We don't distinguish here (or even
|
||||
* above) between 160 and 80+80 yet.
|
||||
*/
|
||||
if (cap_info & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK)
|
||||
sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160;
|
||||
}
|
||||
|
||||
sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta);
|
||||
|
|
|
@ -4095,6 +4095,9 @@ static void nl80211_calculate_ap_params(struct cfg80211_ap_settings *params)
|
|||
cap = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, ies, ies_len);
|
||||
if (cap && cap[1] >= sizeof(*params->vht_cap))
|
||||
params->vht_cap = (void *)(cap + 2);
|
||||
cap = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, ies, ies_len);
|
||||
if (cap && cap[1] >= sizeof(*params->he_cap) + 1)
|
||||
params->he_cap = (void *)(cap + 3);
|
||||
}
|
||||
|
||||
static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
|
||||
|
|
|
@ -847,22 +847,36 @@ static bool valid_regdb(const u8 *data, unsigned int size)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void set_wmm_rule(struct ieee80211_reg_rule *rrule,
|
||||
struct fwdb_wmm_rule *wmm)
|
||||
static void set_wmm_rule(const struct fwdb_header *db,
|
||||
const struct fwdb_country *country,
|
||||
const struct fwdb_rule *rule,
|
||||
struct ieee80211_reg_rule *rrule)
|
||||
{
|
||||
struct ieee80211_wmm_rule *rule = &rrule->wmm_rule;
|
||||
unsigned int i;
|
||||
struct ieee80211_wmm_rule *wmm_rule = &rrule->wmm_rule;
|
||||
struct fwdb_wmm_rule *wmm;
|
||||
unsigned int i, wmm_ptr;
|
||||
|
||||
wmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2;
|
||||
wmm = (void *)((u8 *)db + wmm_ptr);
|
||||
|
||||
if (!valid_wmm(wmm)) {
|
||||
pr_err("Invalid regulatory WMM rule %u-%u in domain %c%c\n",
|
||||
be32_to_cpu(rule->start), be32_to_cpu(rule->end),
|
||||
country->alpha2[0], country->alpha2[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
|
||||
rule->client[i].cw_min =
|
||||
wmm_rule->client[i].cw_min =
|
||||
ecw2cw((wmm->client[i].ecw & 0xf0) >> 4);
|
||||
rule->client[i].cw_max = ecw2cw(wmm->client[i].ecw & 0x0f);
|
||||
rule->client[i].aifsn = wmm->client[i].aifsn;
|
||||
rule->client[i].cot = 1000 * be16_to_cpu(wmm->client[i].cot);
|
||||
rule->ap[i].cw_min = ecw2cw((wmm->ap[i].ecw & 0xf0) >> 4);
|
||||
rule->ap[i].cw_max = ecw2cw(wmm->ap[i].ecw & 0x0f);
|
||||
rule->ap[i].aifsn = wmm->ap[i].aifsn;
|
||||
rule->ap[i].cot = 1000 * be16_to_cpu(wmm->ap[i].cot);
|
||||
wmm_rule->client[i].cw_max = ecw2cw(wmm->client[i].ecw & 0x0f);
|
||||
wmm_rule->client[i].aifsn = wmm->client[i].aifsn;
|
||||
wmm_rule->client[i].cot =
|
||||
1000 * be16_to_cpu(wmm->client[i].cot);
|
||||
wmm_rule->ap[i].cw_min = ecw2cw((wmm->ap[i].ecw & 0xf0) >> 4);
|
||||
wmm_rule->ap[i].cw_max = ecw2cw(wmm->ap[i].ecw & 0x0f);
|
||||
wmm_rule->ap[i].aifsn = wmm->ap[i].aifsn;
|
||||
wmm_rule->ap[i].cot = 1000 * be16_to_cpu(wmm->ap[i].cot);
|
||||
}
|
||||
|
||||
rrule->has_wmm = true;
|
||||
|
@ -870,7 +884,7 @@ static void set_wmm_rule(struct ieee80211_reg_rule *rrule,
|
|||
|
||||
static int __regdb_query_wmm(const struct fwdb_header *db,
|
||||
const struct fwdb_country *country, int freq,
|
||||
struct ieee80211_reg_rule *rule)
|
||||
struct ieee80211_reg_rule *rrule)
|
||||
{
|
||||
unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
|
||||
struct fwdb_collection *coll = (void *)((u8 *)db + ptr);
|
||||
|
@ -879,18 +893,14 @@ static int __regdb_query_wmm(const struct fwdb_header *db,
|
|||
for (i = 0; i < coll->n_rules; i++) {
|
||||
__be16 *rules_ptr = (void *)((u8 *)coll + ALIGN(coll->len, 2));
|
||||
unsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
|
||||
struct fwdb_rule *rrule = (void *)((u8 *)db + rule_ptr);
|
||||
struct fwdb_wmm_rule *wmm;
|
||||
unsigned int wmm_ptr;
|
||||
struct fwdb_rule *rule = (void *)((u8 *)db + rule_ptr);
|
||||
|
||||
if (rrule->len < offsetofend(struct fwdb_rule, wmm_ptr))
|
||||
if (rule->len < offsetofend(struct fwdb_rule, wmm_ptr))
|
||||
continue;
|
||||
|
||||
if (freq >= KHZ_TO_MHZ(be32_to_cpu(rrule->start)) &&
|
||||
freq <= KHZ_TO_MHZ(be32_to_cpu(rrule->end))) {
|
||||
wmm_ptr = be16_to_cpu(rrule->wmm_ptr) << 2;
|
||||
wmm = (void *)((u8 *)db + wmm_ptr);
|
||||
set_wmm_rule(rule, wmm);
|
||||
if (freq >= KHZ_TO_MHZ(be32_to_cpu(rule->start)) &&
|
||||
freq <= KHZ_TO_MHZ(be32_to_cpu(rule->end))) {
|
||||
set_wmm_rule(db, country, rule, rrule);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -972,12 +982,8 @@ static int regdb_query_country(const struct fwdb_header *db,
|
|||
if (rule->len >= offsetofend(struct fwdb_rule, cac_timeout))
|
||||
rrule->dfs_cac_ms =
|
||||
1000 * be16_to_cpu(rule->cac_timeout);
|
||||
if (rule->len >= offsetofend(struct fwdb_rule, wmm_ptr)) {
|
||||
u32 wmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2;
|
||||
struct fwdb_wmm_rule *wmm = (void *)((u8 *)db + wmm_ptr);
|
||||
|
||||
set_wmm_rule(rrule, wmm);
|
||||
}
|
||||
if (rule->len >= offsetofend(struct fwdb_rule, wmm_ptr))
|
||||
set_wmm_rule(db, country, rule, rrule);
|
||||
}
|
||||
|
||||
return reg_schedule_apply(regdom);
|
||||
|
|
|
@ -5,17 +5,20 @@
|
|||
* Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*/
|
||||
#include <linux/export.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ieee80211.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/dsfield.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/mpls.h>
|
||||
#include <linux/gcd.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include "core.h"
|
||||
#include "rdev-ops.h"
|
||||
|
||||
|
@ -1938,3 +1941,109 @@ void cfg80211_send_layer2_update(struct net_device *dev, const u8 *addr)
|
|||
netif_rx_ni(skb);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_send_layer2_update);
|
||||
|
||||
int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
|
||||
enum ieee80211_vht_chanwidth bw,
|
||||
int mcs, bool ext_nss_bw_capable)
|
||||
{
|
||||
u16 map = le16_to_cpu(cap->supp_mcs.rx_mcs_map);
|
||||
int max_vht_nss = 0;
|
||||
int ext_nss_bw;
|
||||
int supp_width;
|
||||
int i, mcs_encoding;
|
||||
|
||||
if (map == 0xffff)
|
||||
return 0;
|
||||
|
||||
if (WARN_ON(mcs > 9))
|
||||
return 0;
|
||||
if (mcs <= 7)
|
||||
mcs_encoding = 0;
|
||||
else if (mcs == 8)
|
||||
mcs_encoding = 1;
|
||||
else
|
||||
mcs_encoding = 2;
|
||||
|
||||
/* find max_vht_nss for the given MCS */
|
||||
for (i = 7; i >= 0; i--) {
|
||||
int supp = (map >> (2 * i)) & 3;
|
||||
|
||||
if (supp == 3)
|
||||
continue;
|
||||
|
||||
if (supp >= mcs_encoding) {
|
||||
max_vht_nss = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(cap->supp_mcs.tx_mcs_map &
|
||||
cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE)))
|
||||
return max_vht_nss;
|
||||
|
||||
ext_nss_bw = le32_get_bits(cap->vht_cap_info,
|
||||
IEEE80211_VHT_CAP_EXT_NSS_BW_MASK);
|
||||
supp_width = le32_get_bits(cap->vht_cap_info,
|
||||
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK);
|
||||
|
||||
/* if not capable, treat ext_nss_bw as 0 */
|
||||
if (!ext_nss_bw_capable)
|
||||
ext_nss_bw = 0;
|
||||
|
||||
/* This is invalid */
|
||||
if (supp_width == 3)
|
||||
return 0;
|
||||
|
||||
/* This is an invalid combination so pretend nothing is supported */
|
||||
if (supp_width == 2 && (ext_nss_bw == 1 || ext_nss_bw == 2))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Cover all the special cases according to IEEE 802.11-2016
|
||||
* Table 9-250. All other cases are either factor of 1 or not
|
||||
* valid/supported.
|
||||
*/
|
||||
switch (bw) {
|
||||
case IEEE80211_VHT_CHANWIDTH_USE_HT:
|
||||
case IEEE80211_VHT_CHANWIDTH_80MHZ:
|
||||
if ((supp_width == 1 || supp_width == 2) &&
|
||||
ext_nss_bw == 3)
|
||||
return 2 * max_vht_nss;
|
||||
break;
|
||||
case IEEE80211_VHT_CHANWIDTH_160MHZ:
|
||||
if (supp_width == 0 &&
|
||||
(ext_nss_bw == 1 || ext_nss_bw == 2))
|
||||
return DIV_ROUND_UP(max_vht_nss, 2);
|
||||
if (supp_width == 0 &&
|
||||
ext_nss_bw == 3)
|
||||
return DIV_ROUND_UP(3 * max_vht_nss, 4);
|
||||
if (supp_width == 1 &&
|
||||
ext_nss_bw == 3)
|
||||
return 2 * max_vht_nss;
|
||||
break;
|
||||
case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
|
||||
if (supp_width == 0 &&
|
||||
(ext_nss_bw == 1 || ext_nss_bw == 2))
|
||||
return 0; /* not possible */
|
||||
if (supp_width == 0 &&
|
||||
ext_nss_bw == 2)
|
||||
return DIV_ROUND_UP(max_vht_nss, 2);
|
||||
if (supp_width == 0 &&
|
||||
ext_nss_bw == 3)
|
||||
return DIV_ROUND_UP(3 * max_vht_nss, 4);
|
||||
if (supp_width == 1 &&
|
||||
ext_nss_bw == 0)
|
||||
return 0; /* not possible */
|
||||
if (supp_width == 1 &&
|
||||
ext_nss_bw == 1)
|
||||
return DIV_ROUND_UP(max_vht_nss, 2);
|
||||
if (supp_width == 1 &&
|
||||
ext_nss_bw == 2)
|
||||
return DIV_ROUND_UP(3 * max_vht_nss, 4);
|
||||
break;
|
||||
}
|
||||
|
||||
/* not covered or invalid combination received */
|
||||
return max_vht_nss;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_get_vht_max_nss);
|
||||
|
|
Loading…
Reference in New Issue