This time we have, of note:
* the massive patch series for multi-BSSID support, I ended up applying that through a side branch to record some details * CSA improvements * HE (802.11ax) updates to Draft 3.3 * strongly typed element iteration/etc. to make such code more readable - this came up in particular in multi-BSSID * rhashtable conversion patches from Herbert Along, as usual, with various fixes and improvements. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEH1e1rEeCd0AIMq6MB8qZga/fl8QFAlxv96gACgkQB8qZga/f l8S/ww/9HpKtn/yH4tInn/KUSfX7yVPC3Fiy6kk09tRa4u9MemWMkU/TXVI6sh+b Rdafn9k0pdEMdOWeHNDJeWJ2EaDv0F6JLAJksx3N+vhkHKOMEPDjWG+WcQHpdmXo vl9Fzm49vXBb8NtzlkcrbNyjjCv1Trge02OlKteSyJ9+lOaWcDOMAZ8W31S1NJuZ ikWtEIQpohtO3+iYGbaYFifvOc5noKRdYF2t94KgMBS8wdPiovgfdtve06aHgI+t lUiiPq0h7B2un36PAeS20bL3/Xd83qiVKuhmPbF5h1azDLGIq4ZThArd8tmZNSRl 5Q+gAutZ/kYsmsulPQSUrxN6lntWNkK6hUV4TXjf1LaSJkj1cGeTKaCS+P6qF7Ye eYTdVVRxPp0GUF9qmrSzZZVLkoko/sqP3w8grr7pSkGEryUGVnL4wBJcRlD+6FcO GMhQRF7fbItMng7Ft5vliOwzxST4anGZv3zztzZR7dwh9bnTrK/EiRoVv3PIDfE6 wBfr/RPihmICG7/ZWFNs5dDqeHDI7g5NUlWL1POQNy83+Drjv3LCNUZDD12ekT0N +0FqAWePXS2Wp9c+p0q+DRjL20aAyG8nVodoRfw2/fzLspveS/djzf0VTaL/KTma WoUPLaBOaKZxOQCHa29V7xe1CrROaJ+OP9/FpUbXGJaO5Sd2bNo= =SM9w -----END PGP SIGNATURE----- Merge tag 'mac80211-next-for-davem-2019-02-22' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next Johannes Berg says: ==================== This time we have, of note: * the massive patch series for multi-BSSID support, I ended up applying that through a side branch to record some details * CSA improvements * HE (802.11ax) updates to Draft 3.3 * strongly typed element iteration/etc. to make such code more readable - this came up in particular in multi-BSSID * rhashtable conversion patches from Herbert Along, as usual, with various fixes and improvements. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Коммит
5328b633c9
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2017 Intel Deutschland GmbH
|
||||
* Copyright(c) 2018 Intel Corporation
|
||||
* Copyright(c) 2018 - 2019 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
|
@ -29,7 +29,7 @@
|
|||
*
|
||||
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2017 Intel Deutschland GmbH
|
||||
* Copyright(c) 2018 Intel Corporation
|
||||
* Copyright(c) 2018 - 2019 Intel Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -433,6 +433,28 @@ struct iwl_he_backoff_conf {
|
|||
__le16 mu_time;
|
||||
} __packed; /* AC_QOS_DOT11AX_API_S */
|
||||
|
||||
/**
|
||||
* enum iwl_he_pkt_ext_constellations - PPE constellation indices
|
||||
* @IWL_HE_PKT_EXT_BPSK: BPSK
|
||||
* @IWL_HE_PKT_EXT_QPSK: QPSK
|
||||
* @IWL_HE_PKT_EXT_16QAM: 16-QAM
|
||||
* @IWL_HE_PKT_EXT_64QAM: 64-QAM
|
||||
* @IWL_HE_PKT_EXT_256QAM: 256-QAM
|
||||
* @IWL_HE_PKT_EXT_1024QAM: 1024-QAM
|
||||
* @IWL_HE_PKT_EXT_RESERVED: reserved value
|
||||
* @IWL_HE_PKT_EXT_NONE: not defined
|
||||
*/
|
||||
enum iwl_he_pkt_ext_constellations {
|
||||
IWL_HE_PKT_EXT_BPSK = 0,
|
||||
IWL_HE_PKT_EXT_QPSK,
|
||||
IWL_HE_PKT_EXT_16QAM,
|
||||
IWL_HE_PKT_EXT_64QAM,
|
||||
IWL_HE_PKT_EXT_256QAM,
|
||||
IWL_HE_PKT_EXT_1024QAM,
|
||||
IWL_HE_PKT_EXT_RESERVED,
|
||||
IWL_HE_PKT_EXT_NONE,
|
||||
};
|
||||
|
||||
#define MAX_HE_SUPP_NSS 2
|
||||
#define MAX_HE_CHANNEL_BW_INDX 4
|
||||
|
||||
|
|
|
@ -479,7 +479,6 @@ static struct ieee80211_sband_iftype_data iwl_he_capa[] = {
|
|||
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_OMI_CONTROL |
|
||||
|
@ -490,7 +489,9 @@ static struct ieee80211_sband_iftype_data iwl_he_capa[] = {
|
|||
.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,
|
||||
IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU |
|
||||
IEEE80211_HE_MAC_CAP5_HE_DYNAMIC_SM_PS |
|
||||
IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX,
|
||||
.phy_cap_info[0] =
|
||||
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
|
||||
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
|
||||
|
@ -498,18 +499,13 @@ static struct ieee80211_sband_iftype_data iwl_he_capa[] = {
|
|||
.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_TX_MAX_NSTS,
|
||||
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD,
|
||||
.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_UL_MU_FULL_MU_MIMO |
|
||||
IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO,
|
||||
IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US,
|
||||
.phy_cap_info[3] =
|
||||
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_BPSK |
|
||||
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM |
|
||||
IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 |
|
||||
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_BPSK |
|
||||
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_NO_DCM |
|
||||
IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1,
|
||||
.phy_cap_info[4] =
|
||||
IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE |
|
||||
|
@ -517,16 +513,8 @@ 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_NG16_SU_FEEDBACK |
|
||||
IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK,
|
||||
IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2,
|
||||
.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 |
|
||||
|
@ -537,11 +525,12 @@ static struct ieee80211_sband_iftype_data iwl_he_capa[] = {
|
|||
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_DCM_MAX_BW_160_OR_80P80_MHZ,
|
||||
IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_2x996,
|
||||
.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,
|
||||
IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB |
|
||||
IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED,
|
||||
},
|
||||
/*
|
||||
* Set default Tx/Rx HE MCS NSS Support field.
|
||||
|
@ -575,28 +564,26 @@ static struct ieee80211_sband_iftype_data iwl_he_capa[] = {
|
|||
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_OMI_CONTROL |
|
||||
IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2,
|
||||
.mac_cap_info[4] =
|
||||
IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU,
|
||||
.mac_cap_info[5] =
|
||||
IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU,
|
||||
.phy_cap_info[0] =
|
||||
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
|
||||
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
|
||||
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G,
|
||||
.phy_cap_info[1] =
|
||||
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD |
|
||||
IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS,
|
||||
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD,
|
||||
.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_NDP_4x_LTF_AND_3_2US,
|
||||
.phy_cap_info[3] =
|
||||
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_BPSK |
|
||||
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM |
|
||||
IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 |
|
||||
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_BPSK |
|
||||
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_NO_DCM |
|
||||
IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1,
|
||||
.phy_cap_info[4] =
|
||||
IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE |
|
||||
|
@ -604,12 +591,8 @@ 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_NG16_SU_FEEDBACK |
|
||||
IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK,
|
||||
IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2,
|
||||
.phy_cap_info[6] =
|
||||
IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU |
|
||||
IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU |
|
||||
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT,
|
||||
.phy_cap_info[7] =
|
||||
IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI |
|
||||
|
@ -619,10 +602,11 @@ static struct ieee80211_sband_iftype_data iwl_he_capa[] = {
|
|||
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_DCM_MAX_BW_160_OR_80P80_MHZ,
|
||||
IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_2x996,
|
||||
.phy_cap_info[9] =
|
||||
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,
|
||||
IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB |
|
||||
IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED,
|
||||
},
|
||||
/*
|
||||
* Set default Tx/Rx HE MCS NSS Support field.
|
||||
|
|
|
@ -2182,6 +2182,46 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm,
|
|||
}
|
||||
|
||||
flags |= STA_CTXT_HE_PACKET_EXT;
|
||||
} else if ((sta->he_cap.he_cap_elem.phy_cap_info[9] &
|
||||
IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_MASK) !=
|
||||
IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED) {
|
||||
int low_th = -1;
|
||||
int high_th = -1;
|
||||
|
||||
/* Take the PPE thresholds from the nominal padding info */
|
||||
switch (sta->he_cap.he_cap_elem.phy_cap_info[9] &
|
||||
IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_MASK) {
|
||||
case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_0US:
|
||||
low_th = IWL_HE_PKT_EXT_NONE;
|
||||
high_th = IWL_HE_PKT_EXT_NONE;
|
||||
break;
|
||||
case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_8US:
|
||||
low_th = IWL_HE_PKT_EXT_BPSK;
|
||||
high_th = IWL_HE_PKT_EXT_NONE;
|
||||
break;
|
||||
case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US:
|
||||
low_th = IWL_HE_PKT_EXT_NONE;
|
||||
high_th = IWL_HE_PKT_EXT_BPSK;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set the PPE thresholds accordingly */
|
||||
if (low_th >= 0 && high_th >= 0) {
|
||||
u8 ***pkt_ext_qam =
|
||||
(void *)sta_ctxt_cmd.pkt_ext.pkt_ext_qam_th;
|
||||
|
||||
for (i = 0; i < MAX_HE_SUPP_NSS; i++) {
|
||||
u8 bw;
|
||||
|
||||
for (bw = 0; bw < MAX_HE_CHANNEL_BW_INDX;
|
||||
bw++) {
|
||||
pkt_ext_qam[i][bw][0] = low_th;
|
||||
pkt_ext_qam[i][bw][1] = high_th;
|
||||
}
|
||||
}
|
||||
|
||||
flags |= STA_CTXT_HE_PACKET_EXT;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
|
|
|
@ -1273,10 +1273,12 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
|
|||
* probably doesn't really matter.
|
||||
*/
|
||||
if (ieee80211_is_beacon(hdr->frame_control) ||
|
||||
ieee80211_is_probe_resp(hdr->frame_control))
|
||||
ieee80211_is_probe_resp(hdr->frame_control)) {
|
||||
rx_status.boottime_ns = ktime_get_boot_ns();
|
||||
now = data->abs_bcn_ts;
|
||||
else
|
||||
} else {
|
||||
now = mac80211_hwsim_get_tsf_raw();
|
||||
}
|
||||
|
||||
/* Copy skb to all enabled radios that are on the current frequency */
|
||||
spin_lock(&hwsim_radio_lock);
|
||||
|
@ -2799,6 +2801,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
|||
ieee80211_hw_set(hw, TDLS_WIDER_BW);
|
||||
if (rctbl)
|
||||
ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
|
||||
ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
|
||||
|
||||
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
|
||||
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
|
||||
|
|
|
@ -360,7 +360,6 @@ static struct wiphy *virt_wifi_make_wiphy(void)
|
|||
wiphy->bands[NL80211_BAND_5GHZ] = &band_5ghz;
|
||||
wiphy->bands[NL80211_BAND_60GHZ] = NULL;
|
||||
|
||||
wiphy->regulatory_flags = REGULATORY_WIPHY_SELF_MANAGED;
|
||||
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
|
||||
|
||||
priv = wiphy_priv(wiphy);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
|
||||
* Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH
|
||||
* Copyright (c) 2016 - 2017 Intel Deutschland GmbH
|
||||
* Copyright (c) 2018 Intel Corporation
|
||||
* Copyright (c) 2018 - 2019 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
|
||||
|
@ -1803,6 +1803,9 @@ int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
|
|||
#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
|
||||
#define IEEE80211_HE_MAC_CAP5_HE_DYNAMIC_SM_PS 0x20
|
||||
#define IEEE80211_HE_MAC_CAP5_PUNCTURED_SOUNDING 0x40
|
||||
#define IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX 0x80
|
||||
|
||||
/* 802.11ax HE PHY capabilities */
|
||||
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G 0x02
|
||||
|
@ -1926,11 +1929,11 @@ int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
|
|||
#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_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_CAP8_DCM_MAX_RU_242 0x00
|
||||
#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484 0x40
|
||||
#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_996 0x80
|
||||
#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_2x996 0xc0
|
||||
#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_MASK 0xc0
|
||||
|
||||
#define IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM 0x01
|
||||
#define IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK 0x02
|
||||
|
@ -1938,6 +1941,11 @@ int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
|
|||
#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
|
||||
#define IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_0US 0x00
|
||||
#define IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_8US 0x40
|
||||
#define IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US 0x80
|
||||
#define IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED 0xc0
|
||||
#define IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_MASK 0xc0
|
||||
|
||||
/* 802.11ax HE TX/RX MCS NSS Support */
|
||||
#define IEEE80211_TX_RX_MCS_NSS_SUPP_HIGHEST_MCS_POS (3)
|
||||
|
@ -2016,7 +2024,7 @@ ieee80211_he_ppe_size(u8 ppe_thres_hdr, const u8 *phy_cap_info)
|
|||
#define IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK 0x00003ff0
|
||||
#define IEEE80211_HE_OPERATION_RTS_THRESHOLD_OFFSET 4
|
||||
#define IEEE80211_HE_OPERATION_VHT_OPER_INFO 0x00004000
|
||||
#define IEEE80211_HE_OPERATION_CO_LOCATED_BSS 0x00008000
|
||||
#define IEEE80211_HE_OPERATION_CO_HOSTED_BSS 0x00008000
|
||||
#define IEEE80211_HE_OPERATION_ER_SU_DISABLE 0x00010000
|
||||
#define IEEE80211_HE_OPERATION_BSS_COLOR_MASK 0x3f000000
|
||||
#define IEEE80211_HE_OPERATION_BSS_COLOR_OFFSET 24
|
||||
|
@ -2046,7 +2054,7 @@ ieee80211_he_oper_size(const u8 *he_oper_ie)
|
|||
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_CO_LOCATED_BSS)
|
||||
if (he_oper_params & IEEE80211_HE_OPERATION_CO_HOSTED_BSS)
|
||||
oper_len++;
|
||||
|
||||
/* Add the first byte (extension ID) to the total length */
|
||||
|
@ -2475,6 +2483,8 @@ enum ieee80211_eid_ext {
|
|||
WLAN_EID_EXT_HE_OPERATION = 36,
|
||||
WLAN_EID_EXT_UORA = 37,
|
||||
WLAN_EID_EXT_HE_MU_EDCA = 38,
|
||||
WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME = 52,
|
||||
WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION = 55,
|
||||
};
|
||||
|
||||
/* Action category code */
|
||||
|
@ -2656,6 +2666,11 @@ enum ieee80211_tdls_actioncode {
|
|||
*/
|
||||
#define WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING BIT(2)
|
||||
|
||||
/* Multiple BSSID capability is set in the 6th bit of 3rd byte of the
|
||||
* @WLAN_EID_EXT_CAPABILITY information element
|
||||
*/
|
||||
#define WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT BIT(6)
|
||||
|
||||
/* TDLS capabilities in the the 4th byte of @WLAN_EID_EXT_CAPABILITY */
|
||||
#define WLAN_EXT_CAPA4_TDLS_BUFFER_STA BIT(4)
|
||||
#define WLAN_EXT_CAPA4_TDLS_PEER_PSM BIT(5)
|
||||
|
@ -2691,6 +2706,9 @@ enum ieee80211_tdls_actioncode {
|
|||
#define WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT BIT(5)
|
||||
#define WLAN_EXT_CAPA10_TWT_RESPONDER_SUPPORT BIT(6)
|
||||
|
||||
/* Defines support for enhanced multi-bssid advertisement*/
|
||||
#define WLAN_EXT_CAPA11_EMA_SUPPORT BIT(1)
|
||||
|
||||
/* TDLS specific payload type in the LLC/SNAP header */
|
||||
#define WLAN_TDLS_SNAP_RFTYPE 0x2
|
||||
|
||||
|
@ -2882,6 +2900,34 @@ enum ieee80211_sa_query_action {
|
|||
WLAN_ACTION_SA_QUERY_RESPONSE = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ieee80211_bssid_index
|
||||
*
|
||||
* This structure refers to "Multiple BSSID-index element"
|
||||
*
|
||||
* @bssid_index: BSSID index
|
||||
* @dtim_period: optional, overrides transmitted BSS dtim period
|
||||
* @dtim_count: optional, overrides transmitted BSS dtim count
|
||||
*/
|
||||
struct ieee80211_bssid_index {
|
||||
u8 bssid_index;
|
||||
u8 dtim_period;
|
||||
u8 dtim_count;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ieee80211_multiple_bssid_configuration
|
||||
*
|
||||
* This structure refers to "Multiple BSSID Configuration element"
|
||||
*
|
||||
* @bssid_count: total number of active BSSIDs in the set
|
||||
* @profile_periodicity: the least number of beacon frames need to be received
|
||||
* in order to discover all the nontransmitted BSSIDs in the set.
|
||||
*/
|
||||
struct ieee80211_multiple_bssid_configuration {
|
||||
u8 bssid_count;
|
||||
u8 profile_periodicity;
|
||||
};
|
||||
|
||||
#define SUITE(oui, id) (((oui) << 8) | (id))
|
||||
|
||||
|
@ -3243,4 +3289,57 @@ static inline bool ieee80211_action_contains_tpc(struct sk_buff *skb)
|
|||
return true;
|
||||
}
|
||||
|
||||
struct element {
|
||||
u8 id;
|
||||
u8 datalen;
|
||||
u8 data[];
|
||||
} __packed;
|
||||
|
||||
/* element iteration helpers */
|
||||
#define for_each_element(_elem, _data, _datalen) \
|
||||
for (_elem = (const struct element *)(_data); \
|
||||
(const u8 *)(_data) + (_datalen) - (const u8 *)_elem >= \
|
||||
(int)sizeof(*_elem) && \
|
||||
(const u8 *)(_data) + (_datalen) - (const u8 *)_elem >= \
|
||||
(int)sizeof(*_elem) + _elem->datalen; \
|
||||
_elem = (const struct element *)(_elem->data + _elem->datalen))
|
||||
|
||||
#define for_each_element_id(element, _id, data, datalen) \
|
||||
for_each_element(element, data, datalen) \
|
||||
if (element->id == (_id))
|
||||
|
||||
#define for_each_element_extid(element, extid, _data, _datalen) \
|
||||
for_each_element(element, _data, _datalen) \
|
||||
if (element->id == WLAN_EID_EXTENSION && \
|
||||
element->datalen > 0 && \
|
||||
element->data[0] == (extid))
|
||||
|
||||
#define for_each_subelement(sub, element) \
|
||||
for_each_element(sub, (element)->data, (element)->datalen)
|
||||
|
||||
#define for_each_subelement_id(sub, id, element) \
|
||||
for_each_element_id(sub, id, (element)->data, (element)->datalen)
|
||||
|
||||
#define for_each_subelement_extid(sub, extid, element) \
|
||||
for_each_element_extid(sub, extid, (element)->data, (element)->datalen)
|
||||
|
||||
/**
|
||||
* for_each_element_completed - determine if element parsing consumed all data
|
||||
* @element: element pointer after for_each_element() or friends
|
||||
* @data: same data pointer as passed to for_each_element() or friends
|
||||
* @datalen: same data length as passed to for_each_element() or friends
|
||||
*
|
||||
* This function returns %true if all the data was parsed or considered
|
||||
* while walking the elements. Only use this if your for_each_element()
|
||||
* loop cannot be broken out of, otherwise it always returns %false.
|
||||
*
|
||||
* If some data was malformed, this returns %false since the last parsed
|
||||
* element will not fill the whole remaining data.
|
||||
*/
|
||||
static inline bool for_each_element_completed(const struct element *element,
|
||||
const void *data, size_t datalen)
|
||||
{
|
||||
return (const u8 *)element == (const u8 *)data + datalen;
|
||||
}
|
||||
|
||||
#endif /* LINUX_IEEE80211_H */
|
||||
|
|
|
@ -1113,14 +1113,6 @@ static inline int rhashtable_replace_fast(
|
|||
return err;
|
||||
}
|
||||
|
||||
/* Obsolete function, do not use in new code. */
|
||||
static inline int rhashtable_walk_init(struct rhashtable *ht,
|
||||
struct rhashtable_iter *iter, gfp_t gfp)
|
||||
{
|
||||
rhashtable_walk_enter(ht, iter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* rhltable_walk_enter - Initialise an iterator
|
||||
* @hlt: Table to walk over
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2015-2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* Copyright (C) 2018-2019 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
|
||||
|
@ -2035,9 +2035,15 @@ struct cfg80211_bss_ies {
|
|||
* a BSS that hides the SSID in its beacon, this points to the BSS struct
|
||||
* that holds the beacon data. @beacon_ies is still valid, of course, and
|
||||
* points to the same data as hidden_beacon_bss->beacon_ies in that case.
|
||||
* @transmitted_bss: pointer to the transmitted BSS, if this is a
|
||||
* non-transmitted one (multi-BSSID support)
|
||||
* @nontrans_list: list of non-transmitted BSS, if this is a transmitted one
|
||||
* (multi-BSSID support)
|
||||
* @signal: signal strength value (type depends on the wiphy's signal_type)
|
||||
* @chains: bitmask for filled values in @chain_signal.
|
||||
* @chain_signal: per-chain signal strength of last received BSS in dBm.
|
||||
* @bssid_index: index in the multiple BSS set
|
||||
* @max_bssid_indicator: max number of members in the BSS set
|
||||
* @priv: private area for driver use, has at least wiphy->bss_priv_size bytes
|
||||
*/
|
||||
struct cfg80211_bss {
|
||||
|
@ -2049,6 +2055,8 @@ struct cfg80211_bss {
|
|||
const struct cfg80211_bss_ies __rcu *proberesp_ies;
|
||||
|
||||
struct cfg80211_bss *hidden_beacon_bss;
|
||||
struct cfg80211_bss *transmitted_bss;
|
||||
struct list_head nontrans_list;
|
||||
|
||||
s32 signal;
|
||||
|
||||
|
@ -2059,19 +2067,36 @@ struct cfg80211_bss {
|
|||
u8 chains;
|
||||
s8 chain_signal[IEEE80211_MAX_CHAINS];
|
||||
|
||||
u8 bssid_index;
|
||||
u8 max_bssid_indicator;
|
||||
|
||||
u8 priv[0] __aligned(sizeof(void *));
|
||||
};
|
||||
|
||||
/**
|
||||
* ieee80211_bss_get_ie - find IE with given ID
|
||||
* ieee80211_bss_get_elem - find element with given ID
|
||||
* @bss: the bss to search
|
||||
* @ie: the IE ID
|
||||
* @id: the element ID
|
||||
*
|
||||
* Note that the return value is an RCU-protected pointer, so
|
||||
* rcu_read_lock() must be held when calling this function.
|
||||
* Return: %NULL if not found.
|
||||
*/
|
||||
const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie);
|
||||
const struct element *ieee80211_bss_get_elem(struct cfg80211_bss *bss, u8 id);
|
||||
|
||||
/**
|
||||
* ieee80211_bss_get_ie - find IE with given ID
|
||||
* @bss: the bss to search
|
||||
* @id: the element ID
|
||||
*
|
||||
* Note that the return value is an RCU-protected pointer, so
|
||||
* rcu_read_lock() must be held when calling this function.
|
||||
* Return: %NULL if not found.
|
||||
*/
|
||||
static inline const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 id)
|
||||
{
|
||||
return (void *)ieee80211_bss_get_elem(bss, id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -4299,6 +4324,11 @@ struct cfg80211_pmsr_capabilities {
|
|||
* @txq_memory_limit: configuration internal TX queue memory limit
|
||||
* @txq_quantum: configuration of internal TX queue scheduler quantum
|
||||
*
|
||||
* @support_mbssid: can HW support association with nontransmitted AP
|
||||
* @support_only_he_mbssid: don't parse MBSSID elements if it is not
|
||||
* HE AP, in order to avoid compatibility issues.
|
||||
* @support_mbssid must be set for this to have any effect.
|
||||
*
|
||||
* @pmsr_capa: peer measurement capabilities
|
||||
*/
|
||||
struct wiphy {
|
||||
|
@ -4439,6 +4469,9 @@ struct wiphy {
|
|||
u32 txq_memory_limit;
|
||||
u32 txq_quantum;
|
||||
|
||||
u8 support_mbssid:1,
|
||||
support_only_he_mbssid:1;
|
||||
|
||||
const struct cfg80211_pmsr_capabilities *pmsr_capa;
|
||||
|
||||
char priv[0] __aligned(NETDEV_ALIGN);
|
||||
|
@ -4999,6 +5032,33 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
|
|||
unsigned int cfg80211_classify8021d(struct sk_buff *skb,
|
||||
struct cfg80211_qos_map *qos_map);
|
||||
|
||||
/**
|
||||
* cfg80211_find_elem_match - match information element and byte array in data
|
||||
*
|
||||
* @eid: element ID
|
||||
* @ies: data consisting of IEs
|
||||
* @len: length of data
|
||||
* @match: byte array to match
|
||||
* @match_len: number of bytes in the match array
|
||||
* @match_offset: offset in the IE data where the byte array should match.
|
||||
* Note the difference to cfg80211_find_ie_match() which considers
|
||||
* the offset to start from the element ID byte, but here we take
|
||||
* the data portion instead.
|
||||
*
|
||||
* Return: %NULL if the element ID could not be found or if
|
||||
* the element is invalid (claims to be longer than the given
|
||||
* data) or if the byte array doesn't match; otherwise return the
|
||||
* requested element struct.
|
||||
*
|
||||
* Note: There are no checks on the element length other than
|
||||
* having to fit into the given data and being large enough for the
|
||||
* byte array to match.
|
||||
*/
|
||||
const struct element *
|
||||
cfg80211_find_elem_match(u8 eid, const u8 *ies, unsigned int len,
|
||||
const u8 *match, unsigned int match_len,
|
||||
unsigned int match_offset);
|
||||
|
||||
/**
|
||||
* cfg80211_find_ie_match - match information element and byte array in data
|
||||
*
|
||||
|
@ -5023,9 +5083,44 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb,
|
|||
* having to fit into the given data and being large enough for the
|
||||
* byte array to match.
|
||||
*/
|
||||
const u8 *cfg80211_find_ie_match(u8 eid, const u8 *ies, int len,
|
||||
const u8 *match, int match_len,
|
||||
int match_offset);
|
||||
static inline const u8 *
|
||||
cfg80211_find_ie_match(u8 eid, const u8 *ies, unsigned int len,
|
||||
const u8 *match, unsigned int match_len,
|
||||
unsigned int match_offset)
|
||||
{
|
||||
/* match_offset can't be smaller than 2, unless match_len is
|
||||
* zero, in which case match_offset must be zero as well.
|
||||
*/
|
||||
if (WARN_ON((match_len && match_offset < 2) ||
|
||||
(!match_len && match_offset)))
|
||||
return NULL;
|
||||
|
||||
return (void *)cfg80211_find_elem_match(eid, ies, len,
|
||||
match, match_len,
|
||||
match_offset ?
|
||||
match_offset - 2 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* cfg80211_find_elem - find information element in data
|
||||
*
|
||||
* @eid: element ID
|
||||
* @ies: data consisting of IEs
|
||||
* @len: length of data
|
||||
*
|
||||
* Return: %NULL if the element ID could not be found or if
|
||||
* the element is invalid (claims to be longer than the given
|
||||
* data) or if the byte array doesn't match; otherwise return the
|
||||
* requested element struct.
|
||||
*
|
||||
* Note: There are no checks on the element length other than
|
||||
* having to fit into the given data.
|
||||
*/
|
||||
static inline const struct element *
|
||||
cfg80211_find_elem(u8 eid, const u8 *ies, int len)
|
||||
{
|
||||
return cfg80211_find_elem_match(eid, ies, len, NULL, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* cfg80211_find_ie - find information element in data
|
||||
|
@ -5047,6 +5142,28 @@ static inline const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len)
|
|||
return cfg80211_find_ie_match(eid, ies, len, NULL, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* cfg80211_find_ext_elem - find information element with EID Extension in data
|
||||
*
|
||||
* @ext_eid: element ID Extension
|
||||
* @ies: data consisting of IEs
|
||||
* @len: length of data
|
||||
*
|
||||
* Return: %NULL if the etended element could not be found or if
|
||||
* the element is invalid (claims to be longer than the given
|
||||
* data) or if the byte array doesn't match; otherwise return the
|
||||
* requested element struct.
|
||||
*
|
||||
* Note: There are no checks on the element length other than
|
||||
* having to fit into the given data.
|
||||
*/
|
||||
static inline const struct element *
|
||||
cfg80211_find_ext_elem(u8 ext_eid, const u8 *ies, int len)
|
||||
{
|
||||
return cfg80211_find_elem_match(WLAN_EID_EXTENSION, ies, len,
|
||||
&ext_eid, 1, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* cfg80211_find_ext_ie - find information element with EID Extension in data
|
||||
*
|
||||
|
@ -5068,6 +5185,25 @@ static inline const u8 *cfg80211_find_ext_ie(u8 ext_eid, const u8 *ies, int len)
|
|||
&ext_eid, 1, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* cfg80211_find_vendor_elem - find vendor specific information element in data
|
||||
*
|
||||
* @oui: vendor OUI
|
||||
* @oui_type: vendor-specific OUI type (must be < 0xff), negative means any
|
||||
* @ies: data consisting of IEs
|
||||
* @len: length of data
|
||||
*
|
||||
* Return: %NULL if the vendor specific element ID could not be found or if the
|
||||
* element is invalid (claims to be longer than the given data); otherwise
|
||||
* return the element structure for the requested element.
|
||||
*
|
||||
* Note: There are no checks on the element length other than having to fit into
|
||||
* the given data.
|
||||
*/
|
||||
const struct element *cfg80211_find_vendor_elem(unsigned int oui, int oui_type,
|
||||
const u8 *ies,
|
||||
unsigned int len);
|
||||
|
||||
/**
|
||||
* cfg80211_find_vendor_ie - find vendor specific information element in data
|
||||
*
|
||||
|
@ -5084,8 +5220,12 @@ static inline const u8 *cfg80211_find_ext_ie(u8 ext_eid, const u8 *ies, int len)
|
|||
* Note: There are no checks on the element length other than having to fit into
|
||||
* the given data.
|
||||
*/
|
||||
const u8 *cfg80211_find_vendor_ie(unsigned int oui, int oui_type,
|
||||
const u8 *ies, int len);
|
||||
static inline const u8 *
|
||||
cfg80211_find_vendor_ie(unsigned int oui, int oui_type,
|
||||
const u8 *ies, unsigned int len)
|
||||
{
|
||||
return (void *)cfg80211_find_vendor_elem(oui, oui_type, ies, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* cfg80211_send_layer2_update - send layer 2 update frame
|
||||
|
@ -5330,6 +5470,27 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
|
|||
return cfg80211_inform_bss_frame_data(wiphy, &data, mgmt, len, gfp);
|
||||
}
|
||||
|
||||
/**
|
||||
* cfg80211_gen_new_bssid - generate a nontransmitted BSSID for multi-BSSID
|
||||
* @bssid: transmitter BSSID
|
||||
* @max_bssid: max BSSID indicator, taken from Multiple BSSID element
|
||||
* @mbssid_index: BSSID index, taken from Multiple BSSID index element
|
||||
* @new_bssid: calculated nontransmitted BSSID
|
||||
*/
|
||||
static inline void cfg80211_gen_new_bssid(const u8 *bssid, u8 max_bssid,
|
||||
u8 mbssid_index, u8 *new_bssid)
|
||||
{
|
||||
u64 bssid_u64 = ether_addr_to_u64(bssid);
|
||||
u64 mask = GENMASK_ULL(max_bssid - 1, 0);
|
||||
u64 new_bssid_u64;
|
||||
|
||||
new_bssid_u64 = bssid_u64 & ~mask;
|
||||
|
||||
new_bssid_u64 |= ((bssid_u64 & mask) + mbssid_index) & mask;
|
||||
|
||||
u64_to_ether_addr(new_bssid_u64, new_bssid);
|
||||
}
|
||||
|
||||
/**
|
||||
* enum cfg80211_bss_frame_type - frame type that the BSS data came from
|
||||
* @CFG80211_BSS_FTYPE_UNKNOWN: driver doesn't know whether the data is
|
||||
|
@ -5515,10 +5676,12 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr);
|
|||
* @dev: network device
|
||||
* @bss: the BSS that association was requested with, ownership of the pointer
|
||||
* moves to cfg80211 in this call
|
||||
* @buf: authentication frame (header + body)
|
||||
* @buf: (Re)Association Response frame (header + body)
|
||||
* @len: length of the frame data
|
||||
* @uapsd_queues: bitmap of queues configured for uapsd. Same format
|
||||
* as the AC bitmap in the QoS info field
|
||||
* @req_ies: information elements from the (Re)Association Request frame
|
||||
* @req_ies_len: length of req_ies data
|
||||
*
|
||||
* After being asked to associate via cfg80211_ops::assoc() the driver must
|
||||
* call either this function or cfg80211_auth_timeout().
|
||||
|
@ -5528,7 +5691,8 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr);
|
|||
void cfg80211_rx_assoc_resp(struct net_device *dev,
|
||||
struct cfg80211_bss *bss,
|
||||
const u8 *buf, size_t len,
|
||||
int uapsd_queues);
|
||||
int uapsd_queues,
|
||||
const u8 *req_ies, size_t req_ies_len);
|
||||
|
||||
/**
|
||||
* cfg80211_assoc_timeout - notification of timed out association
|
||||
|
@ -5690,6 +5854,7 @@ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
|
|||
struct wireless_dev *wdev,
|
||||
enum nl80211_commands cmd,
|
||||
enum nl80211_attrs attr,
|
||||
unsigned int portid,
|
||||
int vendor_event_idx,
|
||||
int approxlen, gfp_t gfp);
|
||||
|
||||
|
@ -5739,6 +5904,15 @@ cfg80211_vendor_cmd_alloc_reply_skb(struct wiphy *wiphy, int approxlen)
|
|||
*/
|
||||
int cfg80211_vendor_cmd_reply(struct sk_buff *skb);
|
||||
|
||||
/**
|
||||
* cfg80211_vendor_cmd_get_sender
|
||||
* @wiphy: the wiphy
|
||||
*
|
||||
* Return the current netlink port ID in a vendor command handler.
|
||||
* Valid to call only there.
|
||||
*/
|
||||
unsigned int cfg80211_vendor_cmd_get_sender(struct wiphy *wiphy);
|
||||
|
||||
/**
|
||||
* cfg80211_vendor_event_alloc - allocate vendor-specific event skb
|
||||
* @wiphy: the wiphy
|
||||
|
@ -5766,7 +5940,42 @@ cfg80211_vendor_event_alloc(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
{
|
||||
return __cfg80211_alloc_event_skb(wiphy, wdev, NL80211_CMD_VENDOR,
|
||||
NL80211_ATTR_VENDOR_DATA,
|
||||
event_idx, approxlen, gfp);
|
||||
0, event_idx, approxlen, gfp);
|
||||
}
|
||||
|
||||
/**
|
||||
* cfg80211_vendor_event_alloc_ucast - alloc unicast vendor-specific event skb
|
||||
* @wiphy: the wiphy
|
||||
* @wdev: the wireless device
|
||||
* @event_idx: index of the vendor event in the wiphy's vendor_events
|
||||
* @portid: port ID of the receiver
|
||||
* @approxlen: an upper bound of the length of the data that will
|
||||
* be put into the skb
|
||||
* @gfp: allocation flags
|
||||
*
|
||||
* This function allocates and pre-fills an skb for an event to send to
|
||||
* a specific (userland) socket. This socket would previously have been
|
||||
* obtained by cfg80211_vendor_cmd_get_sender(), and the caller MUST take
|
||||
* care to register a netlink notifier to see when the socket closes.
|
||||
*
|
||||
* If wdev != NULL, both the ifindex and identifier of the specified
|
||||
* wireless device are added to the event message before the vendor data
|
||||
* attribute.
|
||||
*
|
||||
* When done filling the skb, call cfg80211_vendor_event() with the
|
||||
* skb to send the event.
|
||||
*
|
||||
* Return: An allocated and pre-filled skb. %NULL if any errors happen.
|
||||
*/
|
||||
static inline struct sk_buff *
|
||||
cfg80211_vendor_event_alloc_ucast(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
unsigned int portid, int approxlen,
|
||||
int event_idx, gfp_t gfp)
|
||||
{
|
||||
return __cfg80211_alloc_event_skb(wiphy, wdev, NL80211_CMD_VENDOR,
|
||||
NL80211_ATTR_VENDOR_DATA,
|
||||
portid, event_idx, approxlen, gfp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5866,7 +6075,7 @@ static inline struct sk_buff *
|
|||
cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, int approxlen, gfp_t gfp)
|
||||
{
|
||||
return __cfg80211_alloc_event_skb(wiphy, NULL, NL80211_CMD_TESTMODE,
|
||||
NL80211_ATTR_TESTDATA, -1,
|
||||
NL80211_ATTR_TESTDATA, 0, -1,
|
||||
approxlen, gfp);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Intel Deutschland GmbH
|
||||
* Copyright (c) 2018 Intel Corporation
|
||||
* Copyright (c) 2018-2019 Intel Corporation
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -343,6 +343,7 @@ struct ieee80211_radiotap_lsig {
|
|||
|
||||
enum ieee80211_radiotap_zero_len_psdu_type {
|
||||
IEEE80211_RADIOTAP_ZERO_LEN_PSDU_SOUNDING = 0,
|
||||
IEEE80211_RADIOTAP_ZERO_LEN_PSDU_NOT_CAPTURED = 1,
|
||||
IEEE80211_RADIOTAP_ZERO_LEN_PSDU_VENDOR = 0xff,
|
||||
};
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2015 - 2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* Copyright (C) 2018 - 2019 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
|
||||
|
@ -591,6 +591,14 @@ struct ieee80211_ftm_responder_params {
|
|||
* @ftm_responder: whether to enable or disable fine timing measurement FTM
|
||||
* responder functionality.
|
||||
* @ftmr_params: configurable lci/civic parameter when enabling FTM responder.
|
||||
* @nontransmitted: this BSS is a nontransmitted BSS profile
|
||||
* @transmitter_bssid: the address of transmitter AP
|
||||
* @bssid_index: index inside the multiple BSSID set
|
||||
* @bssid_indicator: 2^bssid_indicator is the maximum number of APs in set
|
||||
* @ema_ap: AP supports enhancements of discovery and advertisement of
|
||||
* nontransmitted BSSIDs
|
||||
* @profile_periodicity: the least number of beacon frames need to be received
|
||||
* in order to discover all the nontransmitted BSSIDs in the set.
|
||||
*/
|
||||
struct ieee80211_bss_conf {
|
||||
const u8 *bssid;
|
||||
|
@ -644,6 +652,13 @@ struct ieee80211_bss_conf {
|
|||
bool protected_keep_alive;
|
||||
bool ftm_responder;
|
||||
struct ieee80211_ftm_responder_params *ftmr_params;
|
||||
/* Multiple BSSID data */
|
||||
bool nontransmitted;
|
||||
u8 transmitter_bssid[ETH_ALEN];
|
||||
u8 bssid_index;
|
||||
u8 bssid_indicator;
|
||||
bool ema_ap;
|
||||
u8 profile_periodicity;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1504,6 +1519,9 @@ struct ieee80211_conf {
|
|||
* scheduled channel switch, as indicated by the AP.
|
||||
* @chandef: the new channel to switch to
|
||||
* @count: the number of TBTT's until the channel switch event
|
||||
* @delay: maximum delay between the time the AP transmitted the last beacon in
|
||||
* current channel and the expected time of the first beacon in the new
|
||||
* channel, expressed in TU.
|
||||
*/
|
||||
struct ieee80211_channel_switch {
|
||||
u64 timestamp;
|
||||
|
@ -1511,6 +1529,7 @@ struct ieee80211_channel_switch {
|
|||
bool block_tx;
|
||||
struct cfg80211_chan_def chandef;
|
||||
u8 count;
|
||||
u32 delay;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -2219,6 +2238,11 @@ struct ieee80211_txq {
|
|||
* @IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN: Driver does not report accurate A-MPDU
|
||||
* length in tx status information
|
||||
*
|
||||
* @IEEE80211_HW_SUPPORTS_MULTI_BSSID: Hardware supports multi BSSID
|
||||
*
|
||||
* @IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID: Hardware supports multi BSSID
|
||||
* only for HE APs. Applies if @IEEE80211_HW_SUPPORTS_MULTI_BSSID is set.
|
||||
*
|
||||
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
|
||||
*/
|
||||
enum ieee80211_hw_flags {
|
||||
|
@ -2268,6 +2292,8 @@ enum ieee80211_hw_flags {
|
|||
IEEE80211_HW_SUPPORTS_VHT_EXT_NSS_BW,
|
||||
IEEE80211_HW_STA_MMPDU_TXQ,
|
||||
IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN,
|
||||
IEEE80211_HW_SUPPORTS_MULTI_BSSID,
|
||||
IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID,
|
||||
|
||||
/* keep last, obviously */
|
||||
NUM_IEEE80211_HW_FLAGS
|
||||
|
@ -3617,7 +3643,12 @@ enum ieee80211_reconfig_type {
|
|||
* @post_channel_switch: This is an optional callback that is called
|
||||
* after a channel switch procedure is completed, allowing the
|
||||
* driver to go back to a normal configuration.
|
||||
*
|
||||
* @abort_channel_switch: This is an optional callback that is called
|
||||
* when channel switch procedure was completed, allowing the
|
||||
* driver to go back to a normal configuration.
|
||||
* @channel_switch_rx_beacon: This is an optional callback that is called
|
||||
* when channel switch procedure is in progress and additional beacon with
|
||||
* CSA IE was received, allowing driver to track changes in count.
|
||||
* @join_ibss: Join an IBSS (on an IBSS interface); this is called after all
|
||||
* information in bss_conf is set up and the beacon can be retrieved. A
|
||||
* channel context is bound before this is called.
|
||||
|
@ -3920,6 +3951,11 @@ struct ieee80211_ops {
|
|||
|
||||
int (*post_channel_switch)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif);
|
||||
void (*abort_channel_switch)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif);
|
||||
void (*channel_switch_rx_beacon)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_channel_switch *ch_switch);
|
||||
|
||||
int (*join_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
|
||||
void (*leave_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
|
||||
|
|
|
@ -682,7 +682,7 @@ EXPORT_SYMBOL_GPL(rhashtable_walk_enter);
|
|||
* rhashtable_walk_exit - Free an iterator
|
||||
* @iter: Hash table Iterator
|
||||
*
|
||||
* This function frees resources allocated by rhashtable_walk_init.
|
||||
* This function frees resources allocated by rhashtable_walk_enter.
|
||||
*/
|
||||
void rhashtable_walk_exit(struct rhashtable_iter *iter)
|
||||
{
|
||||
|
|
|
@ -177,16 +177,11 @@ static int __init test_rht_lookup(struct rhashtable *ht, struct test_obj *array,
|
|||
|
||||
static void test_bucket_stats(struct rhashtable *ht, unsigned int entries)
|
||||
{
|
||||
unsigned int err, total = 0, chain_len = 0;
|
||||
unsigned int total = 0, chain_len = 0;
|
||||
struct rhashtable_iter hti;
|
||||
struct rhash_head *pos;
|
||||
|
||||
err = rhashtable_walk_init(ht, &hti, GFP_KERNEL);
|
||||
if (err) {
|
||||
pr_warn("Test failed: allocation error");
|
||||
return;
|
||||
}
|
||||
|
||||
rhashtable_walk_enter(ht, &hti);
|
||||
rhashtable_walk_start(&hti);
|
||||
|
||||
while ((pos = rhashtable_walk_next(&hti))) {
|
||||
|
|
|
@ -385,10 +385,7 @@ int ila_xlat_nl_cmd_flush(struct sk_buff *skb, struct genl_info *info)
|
|||
spinlock_t *lock;
|
||||
int ret;
|
||||
|
||||
ret = rhashtable_walk_init(&ilan->xlat.rhash_table, &iter, GFP_KERNEL);
|
||||
if (ret)
|
||||
goto done;
|
||||
|
||||
rhashtable_walk_enter(&ilan->xlat.rhash_table, &iter);
|
||||
rhashtable_walk_start(&iter);
|
||||
|
||||
for (;;) {
|
||||
|
@ -509,23 +506,17 @@ int ila_xlat_nl_dump_start(struct netlink_callback *cb)
|
|||
struct net *net = sock_net(cb->skb->sk);
|
||||
struct ila_net *ilan = net_generic(net, ila_net_id);
|
||||
struct ila_dump_iter *iter;
|
||||
int ret;
|
||||
|
||||
iter = kmalloc(sizeof(*iter), GFP_KERNEL);
|
||||
if (!iter)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = rhashtable_walk_init(&ilan->xlat.rhash_table, &iter->rhiter,
|
||||
GFP_KERNEL);
|
||||
if (ret) {
|
||||
kfree(iter);
|
||||
return ret;
|
||||
}
|
||||
rhashtable_walk_enter(&ilan->xlat.rhash_table, &iter->rhiter);
|
||||
|
||||
iter->skip = 0;
|
||||
cb->args[0] = (long)iter;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ila_xlat_nl_dump_done(struct netlink_callback *cb)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* Copyright (C) 2018 - 2019 Intel Corporation
|
||||
*
|
||||
* GPLv2
|
||||
*
|
||||
|
@ -219,6 +219,8 @@ static const char *hw_flag_names[] = {
|
|||
FLAG(SUPPORTS_VHT_EXT_NSS_BW),
|
||||
FLAG(STA_MMPDU_TXQ),
|
||||
FLAG(TX_STATUS_NO_AMPDU_LEN),
|
||||
FLAG(SUPPORTS_MULTI_BSSID),
|
||||
FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID),
|
||||
#undef FLAG
|
||||
};
|
||||
|
||||
|
|
|
@ -4,7 +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
|
||||
* Copyright (C) 2018 - 2019 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
|
||||
|
@ -685,6 +685,9 @@ static ssize_t sta_he_capa_read(struct file *file, char __user *userbuf,
|
|||
"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");
|
||||
PFLAG(MAC, 5, HE_DYNAMIC_SM_PS, "HE-DYNAMIC-SM-PS");
|
||||
PFLAG(MAC, 5, PUNCTURED_SOUNDING, "PUNCTURED-SOUNDING");
|
||||
PFLAG(MAC, 5, HT_VHT_TRIG_FRAME_RX, "HT-VHT-TRIG-FRAME-RX");
|
||||
|
||||
cap = hec->he_cap_elem.phy_cap_info;
|
||||
p += scnprintf(p, buf_sz + buf - p,
|
||||
|
@ -819,18 +822,18 @@ static ssize_t sta_he_capa_read(struct file *file, char __user *userbuf,
|
|||
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");
|
||||
switch (cap[8] & IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_MASK) {
|
||||
case IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_242:
|
||||
PRINT("DCM-MAX-RU-242");
|
||||
break;
|
||||
case IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_40MHZ:
|
||||
PRINT("DCM-MAX-BW-40MHZ");
|
||||
case IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484:
|
||||
PRINT("DCM-MAX-RU-484");
|
||||
break;
|
||||
case IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_80MHZ:
|
||||
PRINT("DCM-MAX-BW-80MHZ");
|
||||
case IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_996:
|
||||
PRINT("DCM-MAX-RU-996");
|
||||
break;
|
||||
case IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_160_OR_80P80_MHZ:
|
||||
PRINT("DCM-MAX-BW-160-OR-80P80-MHZ");
|
||||
case IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_2x996:
|
||||
PRINT("DCM-MAX-RU-2x996");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -847,6 +850,18 @@ static ssize_t sta_he_capa_read(struct file *file, char __user *userbuf,
|
|||
PFLAG(PHY, 9, RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB,
|
||||
"RX-FULL-BW-SU-USING-MU-WITH-NON-COMP-SIGB");
|
||||
|
||||
switch (cap[9] & IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_MASK) {
|
||||
case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_0US:
|
||||
PRINT("NOMINAL-PACKET-PADDING-0US");
|
||||
break;
|
||||
case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_8US:
|
||||
PRINT("NOMINAL-PACKET-PADDING-8US");
|
||||
break;
|
||||
case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US:
|
||||
PRINT("NOMINAL-PACKET-PADDING-16US");
|
||||
break;
|
||||
}
|
||||
|
||||
#undef PFLAG_RANGE_DEFAULT
|
||||
#undef PFLAG_RANGE
|
||||
#undef PFLAG
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/*
|
||||
* Portions of this file
|
||||
* Copyright(c) 2016 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* Copyright (C) 2018 - 2019 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __MAC80211_DRIVER_OPS
|
||||
|
@ -1052,6 +1052,35 @@ drv_post_channel_switch(struct ieee80211_sub_if_data *sdata)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline void
|
||||
drv_abort_channel_switch(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return;
|
||||
|
||||
trace_drv_abort_channel_switch(local, sdata);
|
||||
|
||||
if (local->ops->abort_channel_switch)
|
||||
local->ops->abort_channel_switch(&local->hw, &sdata->vif);
|
||||
}
|
||||
|
||||
static inline void
|
||||
drv_channel_switch_rx_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_channel_switch *ch_switch)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return;
|
||||
|
||||
trace_drv_channel_switch_rx_beacon(local, sdata, ch_switch);
|
||||
if (local->ops->channel_switch_rx_beacon)
|
||||
local->ops->channel_switch_rx_beacon(&local->hw, &sdata->vif,
|
||||
ch_switch);
|
||||
}
|
||||
|
||||
static inline int drv_join_ibss(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
* Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2016 Intel Deutschland GmbH
|
||||
* Copyright(c) 2018-2019 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
|
||||
|
@ -1124,8 +1125,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
ieee80211_update_sta_info(sdata, mgmt, len, rx_status, elems, channel);
|
||||
|
||||
bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
|
||||
channel);
|
||||
bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, channel);
|
||||
if (!bss)
|
||||
return;
|
||||
|
||||
|
@ -1604,7 +1604,7 @@ void ieee80211_rx_mgmt_probe_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
return;
|
||||
|
||||
ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
|
||||
false, &elems);
|
||||
false, &elems, mgmt->bssid, NULL);
|
||||
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
|
||||
}
|
||||
|
@ -1654,7 +1654,7 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
ieee802_11_parse_elems(
|
||||
mgmt->u.action.u.chan_switch.variable,
|
||||
ies_len, true, &elems);
|
||||
ies_len, true, &elems, mgmt->bssid, NULL);
|
||||
|
||||
if (elems.parse_error)
|
||||
break;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* Copyright (C) 2018-2019 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
|
||||
|
@ -556,6 +556,12 @@ struct ieee80211_if_managed {
|
|||
* get stuck in a downgraded situation and flush takes forever.
|
||||
*/
|
||||
struct delayed_work tx_tspec_wk;
|
||||
|
||||
/* Information elements from the last transmitted (Re)Association
|
||||
* Request frame.
|
||||
*/
|
||||
u8 *assoc_req_ies;
|
||||
size_t assoc_req_ies_len;
|
||||
};
|
||||
|
||||
struct ieee80211_if_ibss {
|
||||
|
@ -1447,6 +1453,7 @@ struct ieee80211_csa_ie {
|
|||
u8 ttl;
|
||||
u16 pre_value;
|
||||
u16 reason_code;
|
||||
u32 max_switch_time;
|
||||
};
|
||||
|
||||
/* Parsed Information Elements */
|
||||
|
@ -1487,6 +1494,7 @@ struct ieee802_11_elems {
|
|||
const struct ieee80211_channel_sw_ie *ch_switch_ie;
|
||||
const struct ieee80211_ext_chansw_ie *ext_chansw_ie;
|
||||
const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
|
||||
const u8 *max_channel_switch_time;
|
||||
const u8 *country_elem;
|
||||
const u8 *pwr_constr_elem;
|
||||
const u8 *cisco_dtpc_elem;
|
||||
|
@ -1495,6 +1503,12 @@ struct ieee802_11_elems {
|
|||
const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
|
||||
struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie;
|
||||
const struct ieee80211_bss_max_idle_period_ie *max_idle_period_ie;
|
||||
const struct ieee80211_multiple_bssid_configuration *mbssid_config_ie;
|
||||
const struct ieee80211_bssid_index *bssid_index;
|
||||
const u8 *nontransmitted_bssid_profile;
|
||||
u8 max_bssid_indicator;
|
||||
u8 dtim_count;
|
||||
u8 dtim_period;
|
||||
|
||||
/* length of them, respectively */
|
||||
u8 ext_capab_len;
|
||||
|
@ -1513,6 +1527,7 @@ struct ieee802_11_elems {
|
|||
u8 prep_len;
|
||||
u8 perr_len;
|
||||
u8 country_elem_len;
|
||||
u8 bssid_index_len;
|
||||
|
||||
/* whether a parse error occurred while retrieving these elements */
|
||||
bool parse_error;
|
||||
|
@ -1672,7 +1687,6 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
|
|||
struct ieee80211_rx_status *rx_status,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
size_t len,
|
||||
struct ieee802_11_elems *elems,
|
||||
struct ieee80211_channel *channel);
|
||||
void ieee80211_rx_bss_put(struct ieee80211_local *local,
|
||||
struct ieee80211_bss *bss);
|
||||
|
@ -1956,12 +1970,16 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
struct ieee802_11_elems *elems,
|
||||
u64 filter, u32 crc);
|
||||
u64 filter, u32 crc, u8 *transmitter_bssid,
|
||||
u8 *bss_bssid);
|
||||
static inline void ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||
bool action,
|
||||
struct ieee802_11_elems *elems)
|
||||
struct ieee802_11_elems *elems,
|
||||
u8 *transmitter_bssid,
|
||||
u8 *bss_bssid)
|
||||
{
|
||||
ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0);
|
||||
ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0,
|
||||
transmitter_bssid, bss_bssid);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -4,7 +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
|
||||
* Copyright (C) 2018 - 2019 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
|
||||
|
@ -1112,6 +1112,17 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
if (ieee80211_hw_check(&local->hw, CHANCTX_STA_CSA))
|
||||
local->ext_capa[0] |= WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING;
|
||||
|
||||
/* mac80211 supports multi BSSID, if the driver supports it */
|
||||
if (ieee80211_hw_check(&local->hw, SUPPORTS_MULTI_BSSID)) {
|
||||
local->hw.wiphy->support_mbssid = true;
|
||||
if (ieee80211_hw_check(&local->hw,
|
||||
SUPPORTS_ONLY_HE_MULTI_BSSID))
|
||||
local->hw.wiphy->support_only_he_mbssid = true;
|
||||
else
|
||||
local->ext_capa[2] |=
|
||||
WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT;
|
||||
}
|
||||
|
||||
local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CSA_COUNTERS_NUM;
|
||||
|
||||
result = wiphy_register(local->hw.wiphy);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2009 open80211s Ltd.
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* Copyright (C) 2018 - 2019 Intel Corporation
|
||||
* Authors: Luis Carlos Cobo <luisca@cozybit.com>
|
||||
* Javier Cardona <javier@cozybit.com>
|
||||
*
|
||||
|
@ -1106,7 +1106,8 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
|
|||
if (baselen > len)
|
||||
return;
|
||||
|
||||
ieee802_11_parse_elems(pos, len - baselen, false, &elems);
|
||||
ieee802_11_parse_elems(pos, len - baselen, false, &elems, mgmt->bssid,
|
||||
NULL);
|
||||
|
||||
if (!elems.mesh_id)
|
||||
return;
|
||||
|
@ -1170,7 +1171,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
|
|||
return;
|
||||
|
||||
ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
|
||||
false, &elems);
|
||||
false, &elems, mgmt->bssid, NULL);
|
||||
|
||||
/* ignore non-mesh or secure / unsecure mismatch */
|
||||
if ((!elems.mesh_id || !elems.mesh_config) ||
|
||||
|
@ -1306,7 +1307,8 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
|
|||
pos = mgmt->u.action.u.chan_switch.variable;
|
||||
baselen = offsetof(struct ieee80211_mgmt,
|
||||
u.action.u.chan_switch.variable);
|
||||
ieee802_11_parse_elems(pos, len - baselen, true, &elems);
|
||||
ieee802_11_parse_elems(pos, len - baselen, true, &elems,
|
||||
mgmt->bssid, NULL);
|
||||
|
||||
ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl;
|
||||
if (!--ifmsh->chsw_ttl)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2009 open80211s Ltd.
|
||||
* Copyright (C) 2019 Intel Corporation
|
||||
* Author: Luis Carlos Cobo <luisca@cozybit.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -926,7 +927,7 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt;
|
||||
ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
|
||||
len - baselen, false, &elems);
|
||||
len - baselen, false, &elems, mgmt->bssid, NULL);
|
||||
|
||||
if (elems.preq) {
|
||||
if (elems.preq_len != 37)
|
||||
|
|
|
@ -404,7 +404,6 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,
|
|||
{
|
||||
struct mesh_table *tbl;
|
||||
struct mesh_path *mpath, *new_mpath;
|
||||
int ret;
|
||||
|
||||
if (ether_addr_equal(dst, sdata->vif.addr))
|
||||
/* never add ourselves as neighbours */
|
||||
|
@ -422,25 +421,18 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
tbl = sdata->u.mesh.mesh_paths;
|
||||
spin_lock_bh(&tbl->walk_lock);
|
||||
do {
|
||||
ret = rhashtable_lookup_insert_fast(&tbl->rhead,
|
||||
&new_mpath->rhash,
|
||||
mesh_rht_params);
|
||||
|
||||
if (ret == -EEXIST)
|
||||
mpath = rhashtable_lookup_fast(&tbl->rhead,
|
||||
dst,
|
||||
mesh_rht_params);
|
||||
else if (!ret)
|
||||
hlist_add_head(&new_mpath->walk_list, &tbl->walk_head);
|
||||
} while (unlikely(ret == -EEXIST && !mpath));
|
||||
mpath = rhashtable_lookup_get_insert_fast(&tbl->rhead,
|
||||
&new_mpath->rhash,
|
||||
mesh_rht_params);
|
||||
if (!mpath)
|
||||
hlist_add_head(&new_mpath->walk_list, &tbl->walk_head);
|
||||
spin_unlock_bh(&tbl->walk_lock);
|
||||
|
||||
if (ret) {
|
||||
if (mpath) {
|
||||
kfree(new_mpath);
|
||||
|
||||
if (ret != -EEXIST)
|
||||
return ERR_PTR(ret);
|
||||
if (IS_ERR(mpath))
|
||||
return mpath;
|
||||
|
||||
new_mpath = mpath;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2009 open80211s Ltd.
|
||||
* Copyright (C) 2019 Intel Corporation
|
||||
* Author: Luis Carlos Cobo <luisca@cozybit.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -1214,6 +1215,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
|
|||
if (baselen > len)
|
||||
return;
|
||||
}
|
||||
ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems);
|
||||
ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems,
|
||||
mgmt->bssid, NULL);
|
||||
mesh_process_plink_frame(sdata, mgmt, &elems, rx_status);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2015 - 2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* Copyright (C) 2018 - 2019 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
|
||||
|
@ -644,7 +644,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
|
|||
struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
u8 *pos, qos_info;
|
||||
u8 *pos, qos_info, *ie_start;
|
||||
size_t offset = 0, noffset;
|
||||
int i, count, rates_len, supp_rates_len, shift;
|
||||
u16 capab;
|
||||
|
@ -752,6 +752,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
|
|||
|
||||
/* SSID */
|
||||
pos = skb_put(skb, 2 + assoc_data->ssid_len);
|
||||
ie_start = pos;
|
||||
*pos++ = WLAN_EID_SSID;
|
||||
*pos++ = assoc_data->ssid_len;
|
||||
memcpy(pos, assoc_data->ssid, assoc_data->ssid_len);
|
||||
|
@ -813,6 +814,21 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
|
|||
}
|
||||
}
|
||||
|
||||
/* Set MBSSID support for HE AP if needed */
|
||||
if (ieee80211_hw_check(&local->hw, SUPPORTS_ONLY_HE_MULTI_BSSID) &&
|
||||
!(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && assoc_data->ie_len) {
|
||||
struct element *elem;
|
||||
|
||||
/* we know it's writable, cast away the const */
|
||||
elem = (void *)cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY,
|
||||
assoc_data->ie,
|
||||
assoc_data->ie_len);
|
||||
|
||||
/* We can probably assume both always true */
|
||||
if (elem && elem->datalen >= 3)
|
||||
elem->data[2] |= WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT;
|
||||
}
|
||||
|
||||
/* if present, add any custom IEs that go before HT */
|
||||
if (assoc_data->ie_len) {
|
||||
static const u8 before_ht[] = {
|
||||
|
@ -961,6 +977,11 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
|
|||
return;
|
||||
}
|
||||
|
||||
pos = skb_tail_pointer(skb);
|
||||
kfree(ifmgd->assoc_req_ies);
|
||||
ifmgd->assoc_req_ies = kmemdup(ie_start, pos - ie_start, GFP_ATOMIC);
|
||||
ifmgd->assoc_req_ies_len = pos - ie_start;
|
||||
|
||||
drv_mgd_prepare_tx(local, sdata, 0);
|
||||
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
|
@ -1237,6 +1258,32 @@ static void ieee80211_chswitch_timer(struct timer_list *t)
|
|||
ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.chswitch_work);
|
||||
}
|
||||
|
||||
static void
|
||||
ieee80211_sta_abort_chanswitch(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
if (!local->ops->abort_channel_switch)
|
||||
return;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
|
||||
mutex_lock(&local->chanctx_mtx);
|
||||
ieee80211_vif_unreserve_chanctx(sdata);
|
||||
mutex_unlock(&local->chanctx_mtx);
|
||||
|
||||
if (sdata->csa_block_tx)
|
||||
ieee80211_wake_vif_queues(local, sdata,
|
||||
IEEE80211_QUEUE_STOP_REASON_CSA);
|
||||
|
||||
sdata->csa_block_tx = false;
|
||||
sdata->vif.csa_active = false;
|
||||
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
drv_abort_channel_switch(sdata);
|
||||
}
|
||||
|
||||
static void
|
||||
ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
||||
u64 timestamp, u32 device_timestamp,
|
||||
|
@ -1261,19 +1308,36 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
|||
if (local->scanning)
|
||||
return;
|
||||
|
||||
/* disregard subsequent announcements if we are already processing */
|
||||
if (sdata->vif.csa_active)
|
||||
return;
|
||||
|
||||
current_band = cbss->channel->band;
|
||||
res = ieee80211_parse_ch_switch_ie(sdata, elems, current_band,
|
||||
ifmgd->flags,
|
||||
ifmgd->associated->bssid, &csa_ie);
|
||||
if (res < 0)
|
||||
|
||||
if (!res) {
|
||||
ch_switch.timestamp = timestamp;
|
||||
ch_switch.device_timestamp = device_timestamp;
|
||||
ch_switch.block_tx = beacon ? csa_ie.mode : 0;
|
||||
ch_switch.chandef = csa_ie.chandef;
|
||||
ch_switch.count = csa_ie.count;
|
||||
ch_switch.delay = csa_ie.max_switch_time;
|
||||
}
|
||||
|
||||
if (res < 0) {
|
||||
ieee80211_queue_work(&local->hw,
|
||||
&ifmgd->csa_connection_drop_work);
|
||||
if (res)
|
||||
return;
|
||||
}
|
||||
|
||||
if (beacon && sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) {
|
||||
if (res)
|
||||
ieee80211_sta_abort_chanswitch(sdata);
|
||||
else
|
||||
drv_channel_switch_rx_beacon(sdata, &ch_switch);
|
||||
return;
|
||||
} else if (sdata->vif.csa_active || res) {
|
||||
/* disregard subsequent announcements if already processing */
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cfg80211_chandef_usable(local->hw.wiphy, &csa_ie.chandef,
|
||||
IEEE80211_CHAN_DISABLED)) {
|
||||
|
@ -1289,7 +1353,8 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
if (cfg80211_chandef_identical(&csa_ie.chandef,
|
||||
&sdata->vif.bss_conf.chandef)) {
|
||||
&sdata->vif.bss_conf.chandef) &&
|
||||
(!csa_ie.mode || !beacon)) {
|
||||
if (ifmgd->csa_ignored_same_chan)
|
||||
return;
|
||||
sdata_info(sdata,
|
||||
|
@ -1326,12 +1391,6 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
|||
goto drop_connection;
|
||||
}
|
||||
|
||||
ch_switch.timestamp = timestamp;
|
||||
ch_switch.device_timestamp = device_timestamp;
|
||||
ch_switch.block_tx = csa_ie.mode;
|
||||
ch_switch.chandef = csa_ie.chandef;
|
||||
ch_switch.count = csa_ie.count;
|
||||
|
||||
if (drv_pre_channel_switch(sdata, &ch_switch)) {
|
||||
sdata_info(sdata,
|
||||
"preparing for channel switch failed, disconnecting\n");
|
||||
|
@ -1350,7 +1409,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
sdata->vif.csa_active = true;
|
||||
sdata->csa_chandef = csa_ie.chandef;
|
||||
sdata->csa_block_tx = csa_ie.mode;
|
||||
sdata->csa_block_tx = ch_switch.block_tx;
|
||||
ifmgd->csa_ignored_same_chan = false;
|
||||
|
||||
if (sdata->csa_block_tx)
|
||||
|
@ -1384,7 +1443,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
|||
* reset when the disconnection worker runs.
|
||||
*/
|
||||
sdata->vif.csa_active = true;
|
||||
sdata->csa_block_tx = csa_ie.mode;
|
||||
sdata->csa_block_tx = ch_switch.block_tx;
|
||||
|
||||
ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work);
|
||||
mutex_unlock(&local->chanctx_mtx);
|
||||
|
@ -2762,7 +2821,8 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
|
|||
u32 tx_flags = 0;
|
||||
|
||||
pos = mgmt->u.auth.variable;
|
||||
ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), false, &elems);
|
||||
ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems,
|
||||
mgmt->bssid, auth_data->bss->bssid);
|
||||
if (!elems.challenge)
|
||||
return;
|
||||
auth_data->expected_transaction = 4;
|
||||
|
@ -3130,7 +3190,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
pos = mgmt->u.assoc_resp.variable;
|
||||
ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), false, &elems);
|
||||
ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems,
|
||||
mgmt->bssid, assoc_data->bss->bssid);
|
||||
|
||||
if (!elems.supp_rates) {
|
||||
sdata_info(sdata, "no SuppRates element in AssocResp\n");
|
||||
|
@ -3167,7 +3228,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
|||
return false;
|
||||
|
||||
ieee802_11_parse_elems(bss_ies->data, bss_ies->len,
|
||||
false, &bss_elems);
|
||||
false, &bss_elems,
|
||||
mgmt->bssid,
|
||||
assoc_data->bss->bssid);
|
||||
if (assoc_data->wmm &&
|
||||
!elems.wmm_param && bss_elems.wmm_param) {
|
||||
elems.wmm_param = bss_elems.wmm_param;
|
||||
|
@ -3304,6 +3367,14 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
|||
/* TODO: OPEN: what happens if BSS color disable is set? */
|
||||
}
|
||||
|
||||
if (cbss->transmitted_bss) {
|
||||
bss_conf->nontransmitted = true;
|
||||
ether_addr_copy(bss_conf->transmitter_bssid,
|
||||
cbss->transmitted_bss->bssid);
|
||||
bss_conf->bssid_indicator = cbss->max_bssid_indicator;
|
||||
bss_conf->bssid_index = cbss->bssid_index;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some APs, e.g. Netgear WNDR3700, report invalid HT operation data
|
||||
* in their association response, so ignore that data for our own
|
||||
|
@ -3464,7 +3535,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
|||
return;
|
||||
|
||||
pos = mgmt->u.assoc_resp.variable;
|
||||
ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), false, &elems);
|
||||
ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems,
|
||||
mgmt->bssid, assoc_data->bss->bssid);
|
||||
|
||||
if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
|
||||
elems.timeout_int &&
|
||||
|
@ -3516,13 +3588,13 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
|||
uapsd_queues |= ieee80211_ac_to_qos_mask[ac];
|
||||
}
|
||||
|
||||
cfg80211_rx_assoc_resp(sdata->dev, bss, (u8 *)mgmt, len, uapsd_queues);
|
||||
cfg80211_rx_assoc_resp(sdata->dev, bss, (u8 *)mgmt, len, uapsd_queues,
|
||||
ifmgd->assoc_req_ies, ifmgd->assoc_req_ies_len);
|
||||
}
|
||||
|
||||
static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
struct ieee802_11_elems *elems)
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_bss *bss;
|
||||
|
@ -3534,8 +3606,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
if (!channel)
|
||||
return;
|
||||
|
||||
bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
|
||||
channel);
|
||||
bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, channel);
|
||||
if (bss) {
|
||||
sdata->vif.bss_conf.beacon_rate = bss->beacon_rate;
|
||||
ieee80211_rx_bss_put(local, bss);
|
||||
|
@ -3550,7 +3621,6 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_if_managed *ifmgd;
|
||||
struct ieee80211_rx_status *rx_status = (void *) skb->cb;
|
||||
size_t baselen, len = skb->len;
|
||||
struct ieee802_11_elems elems;
|
||||
|
||||
ifmgd = &sdata->u.mgd;
|
||||
|
||||
|
@ -3563,10 +3633,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
|
|||
if (baselen > len)
|
||||
return;
|
||||
|
||||
ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
|
||||
false, &elems);
|
||||
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status);
|
||||
|
||||
if (ifmgd->associated &&
|
||||
ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
|
||||
|
@ -3693,6 +3760,16 @@ static void ieee80211_handle_beacon_sig(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
}
|
||||
|
||||
static bool ieee80211_rx_our_beacon(const u8 *tx_bssid,
|
||||
struct cfg80211_bss *bss)
|
||||
{
|
||||
if (ether_addr_equal(tx_bssid, bss->bssid))
|
||||
return true;
|
||||
if (!bss->transmitted_bss)
|
||||
return false;
|
||||
return ether_addr_equal(tx_bssid, bss->transmitted_bss->bssid);
|
||||
}
|
||||
|
||||
static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
|
@ -3734,15 +3811,16 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
rcu_read_unlock();
|
||||
|
||||
if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon &&
|
||||
ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) {
|
||||
ieee80211_rx_our_beacon(mgmt->bssid, ifmgd->assoc_data->bss)) {
|
||||
ieee802_11_parse_elems(mgmt->u.beacon.variable,
|
||||
len - baselen, false, &elems);
|
||||
len - baselen, false, &elems,
|
||||
mgmt->bssid,
|
||||
ifmgd->assoc_data->bss->bssid);
|
||||
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
|
||||
if (elems.tim && !elems.parse_error) {
|
||||
const struct ieee80211_tim_ie *tim_ie = elems.tim;
|
||||
ifmgd->dtim_period = tim_ie->dtim_period;
|
||||
}
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status);
|
||||
|
||||
if (elems.dtim_period)
|
||||
ifmgd->dtim_period = elems.dtim_period;
|
||||
ifmgd->have_beacon = true;
|
||||
ifmgd->assoc_data->need_beacon = false;
|
||||
if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) {
|
||||
|
@ -3750,12 +3828,17 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
le64_to_cpu(mgmt->u.beacon.timestamp);
|
||||
sdata->vif.bss_conf.sync_device_ts =
|
||||
rx_status->device_timestamp;
|
||||
if (elems.tim)
|
||||
sdata->vif.bss_conf.sync_dtim_count =
|
||||
elems.tim->dtim_count;
|
||||
else
|
||||
sdata->vif.bss_conf.sync_dtim_count = 0;
|
||||
sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count;
|
||||
}
|
||||
|
||||
if (elems.mbssid_config_ie)
|
||||
bss_conf->profile_periodicity =
|
||||
elems.mbssid_config_ie->profile_periodicity;
|
||||
|
||||
if (elems.ext_capab_len >= 11 &&
|
||||
(elems.ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT))
|
||||
bss_conf->ema_ap = true;
|
||||
|
||||
/* continue assoc process */
|
||||
ifmgd->assoc_data->timeout = jiffies;
|
||||
ifmgd->assoc_data->timeout_started = true;
|
||||
|
@ -3764,7 +3847,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
if (!ifmgd->associated ||
|
||||
!ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
|
||||
!ieee80211_rx_our_beacon(mgmt->bssid, ifmgd->associated))
|
||||
return;
|
||||
bssid = ifmgd->associated->bssid;
|
||||
|
||||
|
@ -3787,7 +3870,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
|
||||
ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable,
|
||||
len - baselen, false, &elems,
|
||||
care_about_ies, ncrc);
|
||||
care_about_ies, ncrc,
|
||||
mgmt->bssid, bssid);
|
||||
|
||||
if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
|
||||
ieee80211_check_tim(elems.tim, elems.tim_len, ifmgd->aid)) {
|
||||
|
@ -3859,11 +3943,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
le64_to_cpu(mgmt->u.beacon.timestamp);
|
||||
sdata->vif.bss_conf.sync_device_ts =
|
||||
rx_status->device_timestamp;
|
||||
if (elems.tim)
|
||||
sdata->vif.bss_conf.sync_dtim_count =
|
||||
elems.tim->dtim_count;
|
||||
else
|
||||
sdata->vif.bss_conf.sync_dtim_count = 0;
|
||||
sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count;
|
||||
}
|
||||
|
||||
if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
|
||||
|
@ -3871,7 +3951,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
ifmgd->beacon_crc = ncrc;
|
||||
ifmgd->beacon_crc_valid = true;
|
||||
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status);
|
||||
|
||||
ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
|
||||
rx_status->device_timestamp,
|
||||
|
@ -3889,10 +3969,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
*/
|
||||
if (!ifmgd->have_beacon) {
|
||||
/* a few bogus AP send dtim_period = 0 or no TIM IE */
|
||||
if (elems.tim)
|
||||
bss_conf->dtim_period = elems.tim->dtim_period ?: 1;
|
||||
else
|
||||
bss_conf->dtim_period = 1;
|
||||
bss_conf->dtim_period = elems.dtim_period ?: 1;
|
||||
|
||||
changed |= BSS_CHANGED_BEACON_INFO;
|
||||
ifmgd->have_beacon = true;
|
||||
|
@ -3992,9 +4069,10 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
|||
if (ies_len < 0)
|
||||
break;
|
||||
|
||||
/* CSA IE cannot be overridden, no need for BSSID */
|
||||
ieee802_11_parse_elems(
|
||||
mgmt->u.action.u.chan_switch.variable,
|
||||
ies_len, true, &elems);
|
||||
ies_len, true, &elems, mgmt->bssid, NULL);
|
||||
|
||||
if (elems.parse_error)
|
||||
break;
|
||||
|
@ -4011,9 +4089,13 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
|||
if (ies_len < 0)
|
||||
break;
|
||||
|
||||
/*
|
||||
* extended CSA IE can't be overridden, no need for
|
||||
* BSSID
|
||||
*/
|
||||
ieee802_11_parse_elems(
|
||||
mgmt->u.action.u.ext_chan_switch.variable,
|
||||
ies_len, true, &elems);
|
||||
ies_len, true, &elems, mgmt->bssid, NULL);
|
||||
|
||||
if (elems.parse_error)
|
||||
break;
|
||||
|
@ -4754,6 +4836,40 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool ieee80211_get_dtim(const struct cfg80211_bss_ies *ies,
|
||||
u8 *dtim_count, u8 *dtim_period)
|
||||
{
|
||||
const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len);
|
||||
const u8 *idx_ie = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX, ies->data,
|
||||
ies->len);
|
||||
const struct ieee80211_tim_ie *tim = NULL;
|
||||
const struct ieee80211_bssid_index *idx;
|
||||
bool valid = tim_ie && tim_ie[1] >= 2;
|
||||
|
||||
if (valid)
|
||||
tim = (void *)(tim_ie + 2);
|
||||
|
||||
if (dtim_count)
|
||||
*dtim_count = valid ? tim->dtim_count : 0;
|
||||
|
||||
if (dtim_period)
|
||||
*dtim_period = valid ? tim->dtim_period : 0;
|
||||
|
||||
/* Check if value is overridden by non-transmitted profile */
|
||||
if (!idx_ie || idx_ie[1] < 3)
|
||||
return valid;
|
||||
|
||||
idx = (void *)(idx_ie + 2);
|
||||
|
||||
if (dtim_count)
|
||||
*dtim_count = idx->dtim_count;
|
||||
|
||||
if (dtim_period)
|
||||
*dtim_period = idx->dtim_period;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_bss *cbss, bool assoc,
|
||||
bool override)
|
||||
|
@ -4845,17 +4961,13 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
|
|||
rcu_read_lock();
|
||||
ies = rcu_dereference(cbss->beacon_ies);
|
||||
if (ies) {
|
||||
const u8 *tim_ie;
|
||||
|
||||
sdata->vif.bss_conf.sync_tsf = ies->tsf;
|
||||
sdata->vif.bss_conf.sync_device_ts =
|
||||
bss->device_ts_beacon;
|
||||
tim_ie = cfg80211_find_ie(WLAN_EID_TIM,
|
||||
ies->data, ies->len);
|
||||
if (tim_ie && tim_ie[1] >= 2)
|
||||
sdata->vif.bss_conf.sync_dtim_count = tim_ie[2];
|
||||
else
|
||||
sdata->vif.bss_conf.sync_dtim_count = 0;
|
||||
|
||||
ieee80211_get_dtim(ies,
|
||||
&sdata->vif.bss_conf.sync_dtim_count,
|
||||
NULL);
|
||||
} else if (!ieee80211_hw_check(&sdata->local->hw,
|
||||
TIMING_BEACON_ONLY)) {
|
||||
ies = rcu_dereference(cbss->proberesp_ies);
|
||||
|
@ -5325,17 +5437,12 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
|||
assoc_data->timeout_started = true;
|
||||
assoc_data->need_beacon = true;
|
||||
} else if (beacon_ies) {
|
||||
const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM,
|
||||
beacon_ies->data,
|
||||
beacon_ies->len);
|
||||
const u8 *ie;
|
||||
u8 dtim_count = 0;
|
||||
|
||||
if (tim_ie && tim_ie[1] >= sizeof(struct ieee80211_tim_ie)) {
|
||||
const struct ieee80211_tim_ie *tim;
|
||||
tim = (void *)(tim_ie + 2);
|
||||
ifmgd->dtim_period = tim->dtim_period;
|
||||
dtim_count = tim->dtim_count;
|
||||
}
|
||||
ieee80211_get_dtim(beacon_ies, &dtim_count,
|
||||
&ifmgd->dtim_period);
|
||||
|
||||
ifmgd->have_beacon = true;
|
||||
assoc_data->timeout = jiffies;
|
||||
assoc_data->timeout_started = true;
|
||||
|
@ -5346,6 +5453,17 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
|||
bss->device_ts_beacon;
|
||||
sdata->vif.bss_conf.sync_dtim_count = dtim_count;
|
||||
}
|
||||
|
||||
ie = cfg80211_find_ext_ie(WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION,
|
||||
beacon_ies->data, beacon_ies->len);
|
||||
if (ie && ie[1] >= 3)
|
||||
sdata->vif.bss_conf.profile_periodicity = ie[4];
|
||||
|
||||
ie = cfg80211_find_ie(WLAN_EID_EXT_CAPABILITY,
|
||||
beacon_ies->data, beacon_ies->len);
|
||||
if (ie && ie[1] >= 11 &&
|
||||
(ie[10] & WLAN_EXT_CAPA11_EMA_SUPPORT))
|
||||
sdata->vif.bss_conf.ema_ap = true;
|
||||
} else {
|
||||
assoc_data->timeout = jiffies;
|
||||
assoc_data->timeout_started = true;
|
||||
|
@ -5503,6 +5621,9 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
|
|||
ifmgd->teardown_skb = NULL;
|
||||
ifmgd->orig_teardown_skb = NULL;
|
||||
}
|
||||
kfree(ifmgd->assoc_req_ies);
|
||||
ifmgd->assoc_req_ies = NULL;
|
||||
ifmgd->assoc_req_ies_len = 0;
|
||||
spin_unlock_bh(&ifmgd->teardown_lock);
|
||||
del_timer_sync(&ifmgd->timer);
|
||||
sdata_unlock(sdata);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* Copyright (C) 2018-2019 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
|
||||
|
@ -208,7 +208,24 @@ ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local,
|
|||
}
|
||||
|
||||
if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) {
|
||||
struct ieee80211_vendor_radiotap *rtap = (void *)skb->data;
|
||||
struct ieee80211_vendor_radiotap *rtap;
|
||||
int vendor_data_offset = 0;
|
||||
|
||||
/*
|
||||
* The position to look at depends on the existence (or non-
|
||||
* existence) of other elements, so take that into account...
|
||||
*/
|
||||
if (status->flag & RX_FLAG_RADIOTAP_HE)
|
||||
vendor_data_offset +=
|
||||
sizeof(struct ieee80211_radiotap_he);
|
||||
if (status->flag & RX_FLAG_RADIOTAP_HE_MU)
|
||||
vendor_data_offset +=
|
||||
sizeof(struct ieee80211_radiotap_he_mu);
|
||||
if (status->flag & RX_FLAG_RADIOTAP_LSIG)
|
||||
vendor_data_offset +=
|
||||
sizeof(struct ieee80211_radiotap_lsig);
|
||||
|
||||
rtap = (void *)&skb->data[vendor_data_offset];
|
||||
|
||||
/* alignment for fixed 6-byte vendor data header */
|
||||
len = ALIGN(len, 2);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
||||
* Copyright 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright 2016-2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018-2019 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
|
||||
|
@ -57,62 +58,14 @@ static bool is_uapsd_supported(struct ieee802_11_elems *elems)
|
|||
return qos_info & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD;
|
||||
}
|
||||
|
||||
struct ieee80211_bss *
|
||||
ieee80211_bss_info_update(struct ieee80211_local *local,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
struct ieee802_11_elems *elems,
|
||||
struct ieee80211_channel *channel)
|
||||
static void
|
||||
ieee80211_update_bss_from_elems(struct ieee80211_local *local,
|
||||
struct ieee80211_bss *bss,
|
||||
struct ieee802_11_elems *elems,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
bool beacon)
|
||||
{
|
||||
bool beacon = ieee80211_is_beacon(mgmt->frame_control);
|
||||
struct cfg80211_bss *cbss;
|
||||
struct ieee80211_bss *bss;
|
||||
int clen, srlen;
|
||||
struct cfg80211_inform_bss bss_meta = {
|
||||
.boottime_ns = rx_status->boottime_ns,
|
||||
};
|
||||
bool signal_valid;
|
||||
struct ieee80211_sub_if_data *scan_sdata;
|
||||
|
||||
if (rx_status->flag & RX_FLAG_NO_SIGNAL_VAL)
|
||||
bss_meta.signal = 0; /* invalid signal indication */
|
||||
else if (ieee80211_hw_check(&local->hw, SIGNAL_DBM))
|
||||
bss_meta.signal = rx_status->signal * 100;
|
||||
else if (ieee80211_hw_check(&local->hw, SIGNAL_UNSPEC))
|
||||
bss_meta.signal = (rx_status->signal * 100) / local->hw.max_signal;
|
||||
|
||||
bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_20;
|
||||
if (rx_status->bw == RATE_INFO_BW_5)
|
||||
bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_5;
|
||||
else if (rx_status->bw == RATE_INFO_BW_10)
|
||||
bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_10;
|
||||
|
||||
bss_meta.chan = channel;
|
||||
|
||||
rcu_read_lock();
|
||||
scan_sdata = rcu_dereference(local->scan_sdata);
|
||||
if (scan_sdata && scan_sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
scan_sdata->vif.bss_conf.assoc &&
|
||||
ieee80211_have_rx_timestamp(rx_status)) {
|
||||
bss_meta.parent_tsf =
|
||||
ieee80211_calculate_rx_timestamp(local, rx_status,
|
||||
len + FCS_LEN, 24);
|
||||
ether_addr_copy(bss_meta.parent_bssid,
|
||||
scan_sdata->vif.bss_conf.bssid);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
cbss = cfg80211_inform_bss_frame_data(local->hw.wiphy, &bss_meta,
|
||||
mgmt, len, GFP_ATOMIC);
|
||||
if (!cbss)
|
||||
return NULL;
|
||||
/* In case the signal is invalid update the status */
|
||||
signal_valid = abs(channel->center_freq - cbss->channel->center_freq)
|
||||
<= local->hw.wiphy->max_adj_channel_rssi_comp;
|
||||
if (!signal_valid)
|
||||
rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
|
||||
|
||||
bss = (void *)cbss->priv;
|
||||
|
||||
if (beacon)
|
||||
bss->device_ts_beacon = rx_status->device_timestamp;
|
||||
|
@ -182,6 +135,89 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
|
|||
bss->beacon_rate =
|
||||
&sband->bitrates[rx_status->rate_idx];
|
||||
}
|
||||
}
|
||||
|
||||
struct ieee80211_bss *
|
||||
ieee80211_bss_info_update(struct ieee80211_local *local,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
struct ieee80211_channel *channel)
|
||||
{
|
||||
bool beacon = ieee80211_is_beacon(mgmt->frame_control);
|
||||
struct cfg80211_bss *cbss, *non_tx_cbss;
|
||||
struct ieee80211_bss *bss, *non_tx_bss;
|
||||
struct cfg80211_inform_bss bss_meta = {
|
||||
.boottime_ns = rx_status->boottime_ns,
|
||||
};
|
||||
bool signal_valid;
|
||||
struct ieee80211_sub_if_data *scan_sdata;
|
||||
struct ieee802_11_elems elems;
|
||||
size_t baselen;
|
||||
u8 *elements;
|
||||
|
||||
if (rx_status->flag & RX_FLAG_NO_SIGNAL_VAL)
|
||||
bss_meta.signal = 0; /* invalid signal indication */
|
||||
else if (ieee80211_hw_check(&local->hw, SIGNAL_DBM))
|
||||
bss_meta.signal = rx_status->signal * 100;
|
||||
else if (ieee80211_hw_check(&local->hw, SIGNAL_UNSPEC))
|
||||
bss_meta.signal = (rx_status->signal * 100) / local->hw.max_signal;
|
||||
|
||||
bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_20;
|
||||
if (rx_status->bw == RATE_INFO_BW_5)
|
||||
bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_5;
|
||||
else if (rx_status->bw == RATE_INFO_BW_10)
|
||||
bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_10;
|
||||
|
||||
bss_meta.chan = channel;
|
||||
|
||||
rcu_read_lock();
|
||||
scan_sdata = rcu_dereference(local->scan_sdata);
|
||||
if (scan_sdata && scan_sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
scan_sdata->vif.bss_conf.assoc &&
|
||||
ieee80211_have_rx_timestamp(rx_status)) {
|
||||
bss_meta.parent_tsf =
|
||||
ieee80211_calculate_rx_timestamp(local, rx_status,
|
||||
len + FCS_LEN, 24);
|
||||
ether_addr_copy(bss_meta.parent_bssid,
|
||||
scan_sdata->vif.bss_conf.bssid);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
cbss = cfg80211_inform_bss_frame_data(local->hw.wiphy, &bss_meta,
|
||||
mgmt, len, GFP_ATOMIC);
|
||||
if (!cbss)
|
||||
return NULL;
|
||||
|
||||
if (ieee80211_is_probe_resp(mgmt->frame_control)) {
|
||||
elements = mgmt->u.probe_resp.variable;
|
||||
baselen = offsetof(struct ieee80211_mgmt,
|
||||
u.probe_resp.variable);
|
||||
} else {
|
||||
baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
|
||||
elements = mgmt->u.beacon.variable;
|
||||
}
|
||||
|
||||
if (baselen > len)
|
||||
return NULL;
|
||||
|
||||
ieee802_11_parse_elems(elements, len - baselen, false, &elems,
|
||||
mgmt->bssid, cbss->bssid);
|
||||
|
||||
/* In case the signal is invalid update the status */
|
||||
signal_valid = abs(channel->center_freq - cbss->channel->center_freq)
|
||||
<= local->hw.wiphy->max_adj_channel_rssi_comp;
|
||||
if (!signal_valid)
|
||||
rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
|
||||
|
||||
bss = (void *)cbss->priv;
|
||||
ieee80211_update_bss_from_elems(local, bss, &elems, rx_status, beacon);
|
||||
|
||||
list_for_each_entry(non_tx_cbss, &cbss->nontrans_list, nontrans_list) {
|
||||
non_tx_bss = (void *)non_tx_cbss->priv;
|
||||
|
||||
ieee80211_update_bss_from_elems(local, non_tx_bss, &elems,
|
||||
rx_status, beacon);
|
||||
}
|
||||
|
||||
return bss;
|
||||
}
|
||||
|
@ -206,10 +242,7 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
|
|||
struct ieee80211_sub_if_data *sdata1, *sdata2;
|
||||
struct ieee80211_mgmt *mgmt = (void *)skb->data;
|
||||
struct ieee80211_bss *bss;
|
||||
u8 *elements;
|
||||
struct ieee80211_channel *channel;
|
||||
size_t baselen;
|
||||
struct ieee802_11_elems elems;
|
||||
|
||||
if (skb->len < 24 ||
|
||||
(!ieee80211_is_probe_resp(mgmt->frame_control) &&
|
||||
|
@ -244,26 +277,15 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
|
|||
!ieee80211_scan_accept_presp(sdata2, sched_scan_req_flags,
|
||||
mgmt->da))
|
||||
return;
|
||||
|
||||
elements = mgmt->u.probe_resp.variable;
|
||||
baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
|
||||
} else {
|
||||
baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
|
||||
elements = mgmt->u.beacon.variable;
|
||||
}
|
||||
|
||||
if (baselen > skb->len)
|
||||
return;
|
||||
|
||||
ieee802_11_parse_elems(elements, skb->len - baselen, false, &elems);
|
||||
|
||||
channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
|
||||
|
||||
if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
|
||||
return;
|
||||
|
||||
bss = ieee80211_bss_info_update(local, rx_status,
|
||||
mgmt, skb->len, &elems,
|
||||
mgmt, skb->len,
|
||||
channel);
|
||||
if (bss)
|
||||
ieee80211_rx_bss_put(local, bss);
|
||||
|
|
|
@ -177,6 +177,12 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
|
|||
csa_ie->chandef = new_vht_chandef;
|
||||
}
|
||||
|
||||
if (elems->max_channel_switch_time)
|
||||
csa_ie->max_switch_time =
|
||||
(elems->max_channel_switch_time[0] << 0) |
|
||||
(elems->max_channel_switch_time[1] << 8) |
|
||||
(elems->max_channel_switch_time[2] << 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* Copyright 2014, Intel Corporation
|
||||
* Copyright 2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2015 - 2016 Intel Deutschland GmbH
|
||||
* Copyright (C) 2019 Intel Corporation
|
||||
*
|
||||
* This file is GPLv2 as found in COPYING.
|
||||
*/
|
||||
|
@ -1716,7 +1717,8 @@ ieee80211_process_tdls_channel_switch_resp(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
ieee802_11_parse_elems(tf->u.chan_switch_resp.variable,
|
||||
skb->len - baselen, false, &elems);
|
||||
skb->len - baselen, false, &elems,
|
||||
NULL, NULL);
|
||||
if (elems.parse_error) {
|
||||
tdls_dbg(sdata, "Invalid IEs in TDLS channel switch resp\n");
|
||||
ret = -EINVAL;
|
||||
|
@ -1828,7 +1830,7 @@ ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
ieee802_11_parse_elems(tf->u.chan_switch_req.variable,
|
||||
skb->len - baselen, false, &elems);
|
||||
skb->len - baselen, false, &elems, NULL, NULL);
|
||||
if (elems.parse_error) {
|
||||
tdls_dbg(sdata, "Invalid IEs in TDLS channel switch req\n");
|
||||
return -EINVAL;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Portions of this file
|
||||
* Copyright(c) 2016 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* Copyright(c) 2016-2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 - 2019 Intel Corporation
|
||||
*/
|
||||
|
||||
#if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ)
|
||||
|
@ -2452,6 +2452,48 @@ DEFINE_EVENT(local_sdata_evt, drv_post_channel_switch,
|
|||
TP_ARGS(local, sdata)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(local_sdata_evt, drv_abort_channel_switch,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata),
|
||||
TP_ARGS(local, sdata)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_channel_switch_rx_beacon,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_channel_switch *ch_switch),
|
||||
|
||||
TP_ARGS(local, sdata, ch_switch),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
VIF_ENTRY
|
||||
CHANDEF_ENTRY
|
||||
__field(u64, timestamp)
|
||||
__field(u32, device_timestamp)
|
||||
__field(bool, block_tx)
|
||||
__field(u8, count)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
CHANDEF_ASSIGN(&ch_switch->chandef)
|
||||
__entry->timestamp = ch_switch->timestamp;
|
||||
__entry->device_timestamp = ch_switch->device_timestamp;
|
||||
__entry->block_tx = ch_switch->block_tx;
|
||||
__entry->count = ch_switch->count;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT VIF_PR_FMT
|
||||
" received a channel switch beacon to "
|
||||
CHANDEF_PR_FMT " count:%d block_tx:%d timestamp:%llu",
|
||||
LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count,
|
||||
__entry->block_tx, __entry->timestamp
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_get_txpower,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
|
|
|
@ -891,33 +891,24 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
|
|||
}
|
||||
EXPORT_SYMBOL(ieee80211_queue_delayed_work);
|
||||
|
||||
u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
struct ieee802_11_elems *elems,
|
||||
u64 filter, u32 crc)
|
||||
static u32
|
||||
_ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
struct ieee802_11_elems *elems,
|
||||
u64 filter, u32 crc, u8 *transmitter_bssid,
|
||||
u8 *bss_bssid)
|
||||
{
|
||||
size_t left = len;
|
||||
const u8 *pos = start;
|
||||
const struct element *elem, *sub;
|
||||
bool calc_crc = filter != 0;
|
||||
DECLARE_BITMAP(seen_elems, 256);
|
||||
const u8 *ie;
|
||||
|
||||
bitmap_zero(seen_elems, 256);
|
||||
memset(elems, 0, sizeof(*elems));
|
||||
elems->ie_start = start;
|
||||
elems->total_len = len;
|
||||
|
||||
while (left >= 2) {
|
||||
u8 id, elen;
|
||||
for_each_element(elem, start, len) {
|
||||
bool elem_parse_failed;
|
||||
|
||||
id = *pos++;
|
||||
elen = *pos++;
|
||||
left -= 2;
|
||||
|
||||
if (elen > left) {
|
||||
elems->parse_error = true;
|
||||
break;
|
||||
}
|
||||
u8 id = elem->id;
|
||||
u8 elen = elem->datalen;
|
||||
const u8 *pos = elem->data;
|
||||
|
||||
switch (id) {
|
||||
case WLAN_EID_SSID:
|
||||
|
@ -960,8 +951,6 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
|||
*/
|
||||
if (test_bit(id, seen_elems)) {
|
||||
elems->parse_error = true;
|
||||
left -= elen;
|
||||
pos += elen;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
@ -1219,6 +1208,57 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
|||
if (elen >= sizeof(*elems->max_idle_period_ie))
|
||||
elems->max_idle_period_ie = (void *)pos;
|
||||
break;
|
||||
case WLAN_EID_MULTIPLE_BSSID:
|
||||
if (!bss_bssid || !transmitter_bssid || elen < 4)
|
||||
break;
|
||||
|
||||
elems->max_bssid_indicator = pos[0];
|
||||
|
||||
for_each_element(sub, pos + 1, elen - 1) {
|
||||
u8 sub_len = sub->datalen;
|
||||
u8 new_bssid[ETH_ALEN];
|
||||
const u8 *index;
|
||||
|
||||
/*
|
||||
* we only expect the "non-transmitted BSSID
|
||||
* profile" subelement (subelement id 0)
|
||||
*/
|
||||
if (sub->id != 0 || sub->datalen < 4) {
|
||||
/* not a valid BSS profile */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sub->data[0] != WLAN_EID_NON_TX_BSSID_CAP ||
|
||||
sub->data[1] != 2) {
|
||||
/* The first element of the
|
||||
* Nontransmitted BSSID Profile is not
|
||||
* the Nontransmitted BSSID Capability
|
||||
* element.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
/* found a Nontransmitted BSSID Profile */
|
||||
index = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX,
|
||||
sub->data, sub_len);
|
||||
if (!index || index[1] < 1 || index[2] == 0) {
|
||||
/* Invalid MBSSID Index element */
|
||||
continue;
|
||||
}
|
||||
|
||||
cfg80211_gen_new_bssid(transmitter_bssid,
|
||||
pos[0],
|
||||
index[2],
|
||||
new_bssid);
|
||||
if (ether_addr_equal(new_bssid, bss_bssid)) {
|
||||
elems->nontransmitted_bssid_profile =
|
||||
(void *)sub;
|
||||
elems->bssid_index_len = index[1];
|
||||
elems->bssid_index = (void *)&index[2];
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WLAN_EID_EXTENSION:
|
||||
if (pos[0] == WLAN_EID_EXT_HE_MU_EDCA &&
|
||||
elen >= (sizeof(*elems->mu_edca_param_set) + 1)) {
|
||||
|
@ -1234,6 +1274,14 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
|||
elems->he_operation = (void *)&pos[1];
|
||||
} else if (pos[0] == WLAN_EID_EXT_UORA && elen >= 1) {
|
||||
elems->uora_element = (void *)&pos[1];
|
||||
} else if (pos[0] ==
|
||||
WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME &&
|
||||
elen == 4) {
|
||||
elems->max_channel_switch_time = pos + 1;
|
||||
} else if (pos[0] ==
|
||||
WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION &&
|
||||
elen == 3) {
|
||||
elems->mbssid_config_ie = (void *)&pos[1];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -1244,17 +1292,56 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
|||
elems->parse_error = true;
|
||||
else
|
||||
__set_bit(id, seen_elems);
|
||||
|
||||
left -= elen;
|
||||
pos += elen;
|
||||
}
|
||||
|
||||
if (left != 0)
|
||||
if (!for_each_element_completed(elem, start, len))
|
||||
elems->parse_error = true;
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
struct ieee802_11_elems *elems,
|
||||
u64 filter, u32 crc, u8 *transmitter_bssid,
|
||||
u8 *bss_bssid)
|
||||
{
|
||||
memset(elems, 0, sizeof(*elems));
|
||||
elems->ie_start = start;
|
||||
elems->total_len = len;
|
||||
|
||||
crc = _ieee802_11_parse_elems_crc(start, len, action, elems, filter,
|
||||
crc, transmitter_bssid, bss_bssid);
|
||||
|
||||
/* Override with nontransmitted profile, if found */
|
||||
if (transmitter_bssid && elems->nontransmitted_bssid_profile) {
|
||||
const u8 *profile = elems->nontransmitted_bssid_profile;
|
||||
|
||||
_ieee802_11_parse_elems_crc(&profile[2], profile[1],
|
||||
action, elems, 0, 0,
|
||||
transmitter_bssid, bss_bssid);
|
||||
}
|
||||
|
||||
if (elems->tim && !elems->parse_error) {
|
||||
const struct ieee80211_tim_ie *tim_ie = elems->tim;
|
||||
|
||||
elems->dtim_period = tim_ie->dtim_period;
|
||||
elems->dtim_count = tim_ie->dtim_count;
|
||||
}
|
||||
|
||||
/* Override DTIM period and count if needed */
|
||||
if (elems->bssid_index &&
|
||||
elems->bssid_index_len >=
|
||||
offsetofend(struct ieee80211_bssid_index, dtim_period))
|
||||
elems->dtim_period = elems->bssid_index->dtim_period;
|
||||
|
||||
if (elems->bssid_index &&
|
||||
elems->bssid_index_len >=
|
||||
offsetofend(struct ieee80211_bssid_index, dtim_count))
|
||||
elems->dtim_count = elems->bssid_index->dtim_count;
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_tx_queue_params
|
||||
*qparam, int ac)
|
||||
|
|
|
@ -2549,15 +2549,7 @@ struct nl_seq_iter {
|
|||
|
||||
static int netlink_walk_start(struct nl_seq_iter *iter)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = rhashtable_walk_init(&nl_table[iter->link].hash, &iter->hti,
|
||||
GFP_KERNEL);
|
||||
if (err) {
|
||||
iter->link = MAX_LINKS;
|
||||
return err;
|
||||
}
|
||||
|
||||
rhashtable_walk_enter(&nl_table[iter->link].hash, &iter->hti);
|
||||
rhashtable_walk_start(&iter->hti);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Wireless configuration interface internals.
|
||||
*
|
||||
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* Copyright (C) 2018-2019 Intel Corporation
|
||||
*/
|
||||
#ifndef __NET_WIRELESS_CORE_H
|
||||
#define __NET_WIRELESS_CORE_H
|
||||
|
@ -182,12 +182,23 @@ static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pu
|
|||
static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss)
|
||||
{
|
||||
atomic_inc(&bss->hold);
|
||||
if (bss->pub.transmitted_bss) {
|
||||
bss = container_of(bss->pub.transmitted_bss,
|
||||
struct cfg80211_internal_bss, pub);
|
||||
atomic_inc(&bss->hold);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss)
|
||||
{
|
||||
int r = atomic_dec_return(&bss->hold);
|
||||
WARN_ON(r < 0);
|
||||
if (bss->pub.transmitted_bss) {
|
||||
bss = container_of(bss->pub.transmitted_bss,
|
||||
struct cfg80211_internal_bss, pub);
|
||||
r = atomic_dec_return(&bss->hold);
|
||||
WARN_ON(r < 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
|
||||
|
||||
void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
|
||||
const u8 *buf, size_t len, int uapsd_queues)
|
||||
const u8 *buf, size_t len, int uapsd_queues,
|
||||
const u8 *req_ies, size_t req_ies_len)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
|
@ -33,6 +34,8 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
|
|||
cr.status = (int)le16_to_cpu(mgmt->u.assoc_resp.status_code);
|
||||
cr.bssid = mgmt->bssid;
|
||||
cr.bss = bss;
|
||||
cr.req_ie = req_ies;
|
||||
cr.req_ie_len = req_ies_len;
|
||||
cr.resp_ie = mgmt->u.assoc_resp.variable;
|
||||
cr.resp_ie_len =
|
||||
len - offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
|
||||
|
@ -52,7 +55,8 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
|
|||
return;
|
||||
}
|
||||
|
||||
nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL, uapsd_queues);
|
||||
nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL, uapsd_queues,
|
||||
req_ies, req_ies_len);
|
||||
/* update current_bss etc., consumes the bss reference */
|
||||
__cfg80211_connect_result(dev, &cr, cr.status == WLAN_STATUS_SUCCESS);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2015-2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* Copyright (C) 2018-2019 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <linux/if.h>
|
||||
|
@ -203,29 +203,17 @@ cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info)
|
|||
static int validate_ie_attr(const struct nlattr *attr,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
const u8 *pos;
|
||||
int len;
|
||||
const u8 *data = nla_data(attr);
|
||||
unsigned int len = nla_len(attr);
|
||||
const struct element *elem;
|
||||
|
||||
pos = nla_data(attr);
|
||||
len = nla_len(attr);
|
||||
|
||||
while (len) {
|
||||
u8 elemlen;
|
||||
|
||||
if (len < 2)
|
||||
goto error;
|
||||
len -= 2;
|
||||
|
||||
elemlen = pos[1];
|
||||
if (elemlen > len)
|
||||
goto error;
|
||||
|
||||
len -= elemlen;
|
||||
pos += 2 + elemlen;
|
||||
for_each_element(elem, data, len) {
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
return 0;
|
||||
error:
|
||||
if (for_each_element_completed(elem, data, len))
|
||||
return 0;
|
||||
|
||||
NL_SET_ERR_MSG_ATTR(extack, attr, "malformed information elements");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -9318,6 +9306,7 @@ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
|
|||
struct wireless_dev *wdev,
|
||||
enum nl80211_commands cmd,
|
||||
enum nl80211_attrs attr,
|
||||
unsigned int portid,
|
||||
int vendor_event_idx,
|
||||
int approxlen, gfp_t gfp)
|
||||
{
|
||||
|
@ -9341,7 +9330,7 @@ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return __cfg80211_alloc_vendor_skb(rdev, wdev, approxlen, 0, 0,
|
||||
return __cfg80211_alloc_vendor_skb(rdev, wdev, approxlen, portid, 0,
|
||||
cmd, attr, info, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
|
||||
|
@ -9350,6 +9339,7 @@ void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
|
|||
{
|
||||
struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
|
||||
void *hdr = ((void **)skb->cb)[1];
|
||||
struct nlmsghdr *nlhdr = nlmsg_hdr(skb);
|
||||
struct nlattr *data = ((void **)skb->cb)[2];
|
||||
enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;
|
||||
|
||||
|
@ -9359,11 +9349,16 @@ void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
|
|||
nla_nest_end(skb, data);
|
||||
genlmsg_end(skb, hdr);
|
||||
|
||||
if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
|
||||
mcgrp = NL80211_MCGRP_VENDOR;
|
||||
if (nlhdr->nlmsg_pid) {
|
||||
genlmsg_unicast(wiphy_net(&rdev->wiphy), skb,
|
||||
nlhdr->nlmsg_pid);
|
||||
} else {
|
||||
if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
|
||||
mcgrp = NL80211_MCGRP_VENDOR;
|
||||
|
||||
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0,
|
||||
mcgrp, gfp);
|
||||
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
|
||||
skb, 0, mcgrp, gfp);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(__cfg80211_send_event_skb);
|
||||
|
||||
|
@ -12748,6 +12743,17 @@ int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply);
|
||||
|
||||
unsigned int cfg80211_vendor_cmd_get_sender(struct wiphy *wiphy)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||
|
||||
if (WARN_ON(!rdev->cur_cmd_info))
|
||||
return 0;
|
||||
|
||||
return rdev->cur_cmd_info->snd_portid;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_get_sender);
|
||||
|
||||
static int nl80211_set_qos_map(struct sk_buff *skb,
|
||||
struct genl_info *info)
|
||||
{
|
||||
|
@ -14503,12 +14509,13 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
|
|||
struct net_device *netdev,
|
||||
const u8 *buf, size_t len,
|
||||
enum nl80211_commands cmd, gfp_t gfp,
|
||||
int uapsd_queues)
|
||||
int uapsd_queues, const u8 *req_ies,
|
||||
size_t req_ies_len)
|
||||
{
|
||||
struct sk_buff *msg;
|
||||
void *hdr;
|
||||
|
||||
msg = nlmsg_new(100 + len, gfp);
|
||||
msg = nlmsg_new(100 + len + req_ies_len, gfp);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
|
@ -14520,7 +14527,9 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
|
|||
|
||||
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
|
||||
nla_put(msg, NL80211_ATTR_FRAME, len, buf))
|
||||
nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
|
||||
(req_ies &&
|
||||
nla_put(msg, NL80211_ATTR_REQ_IE, req_ies_len, req_ies)))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (uapsd_queues >= 0) {
|
||||
|
@ -14551,15 +14560,17 @@ void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
|
|||
size_t len, gfp_t gfp)
|
||||
{
|
||||
nl80211_send_mlme_event(rdev, netdev, buf, len,
|
||||
NL80211_CMD_AUTHENTICATE, gfp, -1);
|
||||
NL80211_CMD_AUTHENTICATE, gfp, -1, NULL, 0);
|
||||
}
|
||||
|
||||
void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *buf,
|
||||
size_t len, gfp_t gfp, int uapsd_queues)
|
||||
size_t len, gfp_t gfp, int uapsd_queues,
|
||||
const u8 *req_ies, size_t req_ies_len)
|
||||
{
|
||||
nl80211_send_mlme_event(rdev, netdev, buf, len,
|
||||
NL80211_CMD_ASSOCIATE, gfp, uapsd_queues);
|
||||
NL80211_CMD_ASSOCIATE, gfp, uapsd_queues,
|
||||
req_ies, req_ies_len);
|
||||
}
|
||||
|
||||
void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
|
||||
|
@ -14567,7 +14578,7 @@ void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
|
|||
size_t len, gfp_t gfp)
|
||||
{
|
||||
nl80211_send_mlme_event(rdev, netdev, buf, len,
|
||||
NL80211_CMD_DEAUTHENTICATE, gfp, -1);
|
||||
NL80211_CMD_DEAUTHENTICATE, gfp, -1, NULL, 0);
|
||||
}
|
||||
|
||||
void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
|
||||
|
@ -14575,7 +14586,7 @@ void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
|
|||
size_t len, gfp_t gfp)
|
||||
{
|
||||
nl80211_send_mlme_event(rdev, netdev, buf, len,
|
||||
NL80211_CMD_DISASSOCIATE, gfp, -1);
|
||||
NL80211_CMD_DISASSOCIATE, gfp, -1, NULL, 0);
|
||||
}
|
||||
|
||||
void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
|
||||
|
@ -14596,7 +14607,8 @@ void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
|
|||
cmd = NL80211_CMD_UNPROT_DISASSOCIATE;
|
||||
|
||||
trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len);
|
||||
nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1);
|
||||
nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1,
|
||||
NULL, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt);
|
||||
|
||||
|
|
|
@ -67,7 +67,8 @@ void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
|
|||
void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev,
|
||||
const u8 *buf, size_t len, gfp_t gfp,
|
||||
int uapsd_queues);
|
||||
int uapsd_queues,
|
||||
const u8 *req_ies, size_t req_ies_len);
|
||||
void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev,
|
||||
const u8 *buf, size_t len, gfp_t gfp);
|
||||
|
|
|
@ -257,7 +257,7 @@ int nl80211_pmsr_start(struct sk_buff *skb, struct genl_info *info)
|
|||
goto out_err;
|
||||
} else {
|
||||
memcpy(req->mac_addr, wdev_address(wdev), ETH_ALEN);
|
||||
memset(req->mac_addr_mask, 0xff, ETH_ALEN);
|
||||
eth_broadcast_addr(req->mac_addr_mask);
|
||||
}
|
||||
|
||||
idx = 0;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Copyright 2008-2011 Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* Copyright (C) 2018 - 2019 Intel Corporation
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -131,7 +131,8 @@ static spinlock_t reg_indoor_lock;
|
|||
/* Used to track the userspace process controlling the indoor setting */
|
||||
static u32 reg_is_indoor_portid;
|
||||
|
||||
static void restore_regulatory_settings(bool reset_user);
|
||||
static void restore_regulatory_settings(bool reset_user, bool cached);
|
||||
static void print_regdomain(const struct ieee80211_regdomain *rd);
|
||||
|
||||
static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
|
||||
{
|
||||
|
@ -263,6 +264,7 @@ static const struct ieee80211_regdomain *cfg80211_world_regdom =
|
|||
|
||||
static char *ieee80211_regdom = "00";
|
||||
static char user_alpha2[2];
|
||||
static const struct ieee80211_regdomain *cfg80211_user_regdom;
|
||||
|
||||
module_param(ieee80211_regdom, charp, 0444);
|
||||
MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
|
||||
|
@ -445,6 +447,15 @@ reg_copy_regd(const struct ieee80211_regdomain *src_regd)
|
|||
return regd;
|
||||
}
|
||||
|
||||
static void cfg80211_save_user_regdom(const struct ieee80211_regdomain *rd)
|
||||
{
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (!IS_ERR(cfg80211_user_regdom))
|
||||
kfree(cfg80211_user_regdom);
|
||||
cfg80211_user_regdom = reg_copy_regd(rd);
|
||||
}
|
||||
|
||||
struct reg_regdb_apply_request {
|
||||
struct list_head list;
|
||||
const struct ieee80211_regdomain *regdom;
|
||||
|
@ -510,7 +521,7 @@ static void crda_timeout_work(struct work_struct *work)
|
|||
pr_debug("Timeout while waiting for CRDA to reply, restoring regulatory settings\n");
|
||||
rtnl_lock();
|
||||
reg_crda_timeouts++;
|
||||
restore_regulatory_settings(true);
|
||||
restore_regulatory_settings(true, false);
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
|
@ -1044,7 +1055,7 @@ static void regdb_fw_cb(const struct firmware *fw, void *context)
|
|||
}
|
||||
|
||||
if (restore)
|
||||
restore_regulatory_settings(true);
|
||||
restore_regulatory_settings(true, false);
|
||||
|
||||
rtnl_unlock();
|
||||
|
||||
|
@ -3117,7 +3128,7 @@ static void restore_custom_reg_settings(struct wiphy *wiphy)
|
|||
* keep their own regulatory domain on wiphy->regd so that does does
|
||||
* not need to be remembered.
|
||||
*/
|
||||
static void restore_regulatory_settings(bool reset_user)
|
||||
static void restore_regulatory_settings(bool reset_user, bool cached)
|
||||
{
|
||||
char alpha2[2];
|
||||
char world_alpha2[2];
|
||||
|
@ -3176,15 +3187,41 @@ static void restore_regulatory_settings(bool reset_user)
|
|||
restore_custom_reg_settings(&rdev->wiphy);
|
||||
}
|
||||
|
||||
regulatory_hint_core(world_alpha2);
|
||||
if (cached && (!is_an_alpha2(alpha2) ||
|
||||
!IS_ERR_OR_NULL(cfg80211_user_regdom))) {
|
||||
reset_regdomains(false, cfg80211_world_regdom);
|
||||
update_all_wiphy_regulatory(NL80211_REGDOM_SET_BY_CORE);
|
||||
print_regdomain(get_cfg80211_regdom());
|
||||
nl80211_send_reg_change_event(&core_request_world);
|
||||
reg_set_request_processed();
|
||||
|
||||
/*
|
||||
* This restores the ieee80211_regdom module parameter
|
||||
* preference or the last user requested regulatory
|
||||
* settings, user regulatory settings takes precedence.
|
||||
*/
|
||||
if (is_an_alpha2(alpha2))
|
||||
regulatory_hint_user(alpha2, NL80211_USER_REG_HINT_USER);
|
||||
if (is_an_alpha2(alpha2) &&
|
||||
!regulatory_hint_user(alpha2, NL80211_USER_REG_HINT_USER)) {
|
||||
struct regulatory_request *ureq;
|
||||
|
||||
spin_lock(®_requests_lock);
|
||||
ureq = list_last_entry(®_requests_list,
|
||||
struct regulatory_request,
|
||||
list);
|
||||
list_del(&ureq->list);
|
||||
spin_unlock(®_requests_lock);
|
||||
|
||||
notify_self_managed_wiphys(ureq);
|
||||
reg_update_last_request(ureq);
|
||||
set_regdom(reg_copy_regd(cfg80211_user_regdom),
|
||||
REGD_SOURCE_CACHED);
|
||||
}
|
||||
} else {
|
||||
regulatory_hint_core(world_alpha2);
|
||||
|
||||
/*
|
||||
* This restores the ieee80211_regdom module parameter
|
||||
* preference or the last user requested regulatory
|
||||
* settings, user regulatory settings takes precedence.
|
||||
*/
|
||||
if (is_an_alpha2(alpha2))
|
||||
regulatory_hint_user(alpha2, NL80211_USER_REG_HINT_USER);
|
||||
}
|
||||
|
||||
spin_lock(®_requests_lock);
|
||||
list_splice_tail_init(&tmp_reg_req_list, ®_requests_list);
|
||||
|
@ -3244,7 +3281,7 @@ void regulatory_hint_disconnect(void)
|
|||
}
|
||||
|
||||
pr_debug("All devices are disconnected, going to restore regulatory settings\n");
|
||||
restore_regulatory_settings(false);
|
||||
restore_regulatory_settings(false, true);
|
||||
}
|
||||
|
||||
static bool freq_is_chan_12_13_14(u32 freq)
|
||||
|
@ -3561,6 +3598,9 @@ int set_regdom(const struct ieee80211_regdomain *rd,
|
|||
bool user_reset = false;
|
||||
int r;
|
||||
|
||||
if (IS_ERR_OR_NULL(rd))
|
||||
return -ENODATA;
|
||||
|
||||
if (!reg_is_valid_request(rd->alpha2)) {
|
||||
kfree(rd);
|
||||
return -EINVAL;
|
||||
|
@ -3577,6 +3617,7 @@ int set_regdom(const struct ieee80211_regdomain *rd,
|
|||
r = reg_set_rd_core(rd);
|
||||
break;
|
||||
case NL80211_REGDOM_SET_BY_USER:
|
||||
cfg80211_save_user_regdom(rd);
|
||||
r = reg_set_rd_user(rd, lr);
|
||||
user_reset = true;
|
||||
break;
|
||||
|
@ -3599,7 +3640,7 @@ int set_regdom(const struct ieee80211_regdomain *rd,
|
|||
break;
|
||||
default:
|
||||
/* Back to world regulatory in case of errors */
|
||||
restore_regulatory_settings(user_reset);
|
||||
restore_regulatory_settings(user_reset, false);
|
||||
}
|
||||
|
||||
kfree(rd);
|
||||
|
@ -3935,6 +3976,8 @@ void regulatory_exit(void)
|
|||
|
||||
if (!IS_ERR_OR_NULL(regdb))
|
||||
kfree(regdb);
|
||||
if (!IS_ERR_OR_NULL(cfg80211_user_regdom))
|
||||
kfree(cfg80211_user_regdom);
|
||||
|
||||
free_regdb_keyring();
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
/*
|
||||
* Copyright 2008-2011 Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
|
||||
* Copyright (C) 2019 Intel Corporation
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -22,6 +23,7 @@
|
|||
enum ieee80211_regd_source {
|
||||
REGD_SOURCE_INTERNAL_DB,
|
||||
REGD_SOURCE_CRDA,
|
||||
REGD_SOURCE_CACHED,
|
||||
};
|
||||
|
||||
extern const struct ieee80211_regdomain __rcu *cfg80211_regdomain;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2016 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018-2019 Intel Corporation
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -109,6 +110,12 @@ static inline void bss_ref_get(struct cfg80211_registered_device *rdev,
|
|||
pub);
|
||||
bss->refcount++;
|
||||
}
|
||||
if (bss->pub.transmitted_bss) {
|
||||
bss = container_of(bss->pub.transmitted_bss,
|
||||
struct cfg80211_internal_bss,
|
||||
pub);
|
||||
bss->refcount++;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void bss_ref_put(struct cfg80211_registered_device *rdev,
|
||||
|
@ -125,6 +132,18 @@ static inline void bss_ref_put(struct cfg80211_registered_device *rdev,
|
|||
if (hbss->refcount == 0)
|
||||
bss_free(hbss);
|
||||
}
|
||||
|
||||
if (bss->pub.transmitted_bss) {
|
||||
struct cfg80211_internal_bss *tbss;
|
||||
|
||||
tbss = container_of(bss->pub.transmitted_bss,
|
||||
struct cfg80211_internal_bss,
|
||||
pub);
|
||||
tbss->refcount--;
|
||||
if (tbss->refcount == 0)
|
||||
bss_free(tbss);
|
||||
}
|
||||
|
||||
bss->refcount--;
|
||||
if (bss->refcount == 0)
|
||||
bss_free(bss);
|
||||
|
@ -150,6 +169,7 @@ static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev,
|
|||
}
|
||||
|
||||
list_del_init(&bss->list);
|
||||
list_del_init(&bss->pub.nontrans_list);
|
||||
rb_erase(&bss->rbn, &rdev->bss_tree);
|
||||
rdev->bss_entries--;
|
||||
WARN_ONCE((rdev->bss_entries == 0) ^ list_empty(&rdev->bss_list),
|
||||
|
@ -159,6 +179,162 @@ static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev,
|
|||
return true;
|
||||
}
|
||||
|
||||
static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
|
||||
const u8 *subelement, size_t subie_len,
|
||||
u8 *new_ie, gfp_t gfp)
|
||||
{
|
||||
u8 *pos, *tmp;
|
||||
const u8 *tmp_old, *tmp_new;
|
||||
u8 *sub_copy;
|
||||
|
||||
/* copy subelement as we need to change its content to
|
||||
* mark an ie after it is processed.
|
||||
*/
|
||||
sub_copy = kmalloc(subie_len, gfp);
|
||||
if (!sub_copy)
|
||||
return 0;
|
||||
memcpy(sub_copy, subelement, subie_len);
|
||||
|
||||
pos = &new_ie[0];
|
||||
|
||||
/* set new ssid */
|
||||
tmp_new = cfg80211_find_ie(WLAN_EID_SSID, sub_copy, subie_len);
|
||||
if (tmp_new) {
|
||||
memcpy(pos, tmp_new, tmp_new[1] + 2);
|
||||
pos += (tmp_new[1] + 2);
|
||||
}
|
||||
|
||||
/* go through IEs in ie (skip SSID) and subelement,
|
||||
* merge them into new_ie
|
||||
*/
|
||||
tmp_old = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen);
|
||||
tmp_old = (tmp_old) ? tmp_old + tmp_old[1] + 2 : ie;
|
||||
|
||||
while (tmp_old + tmp_old[1] + 2 - ie <= ielen) {
|
||||
if (tmp_old[0] == 0) {
|
||||
tmp_old++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tmp_old[0] == WLAN_EID_EXTENSION)
|
||||
tmp = (u8 *)cfg80211_find_ext_ie(tmp_old[2], sub_copy,
|
||||
subie_len);
|
||||
else
|
||||
tmp = (u8 *)cfg80211_find_ie(tmp_old[0], sub_copy,
|
||||
subie_len);
|
||||
|
||||
if (!tmp) {
|
||||
/* ie in old ie but not in subelement */
|
||||
if (tmp_old[0] != WLAN_EID_MULTIPLE_BSSID) {
|
||||
memcpy(pos, tmp_old, tmp_old[1] + 2);
|
||||
pos += tmp_old[1] + 2;
|
||||
}
|
||||
} else {
|
||||
/* ie in transmitting ie also in subelement,
|
||||
* copy from subelement and flag the ie in subelement
|
||||
* as copied (by setting eid field to WLAN_EID_SSID,
|
||||
* which is skipped anyway).
|
||||
* For vendor ie, compare OUI + type + subType to
|
||||
* determine if they are the same ie.
|
||||
*/
|
||||
if (tmp_old[0] == WLAN_EID_VENDOR_SPECIFIC) {
|
||||
if (!memcmp(tmp_old + 2, tmp + 2, 5)) {
|
||||
/* same vendor ie, copy from
|
||||
* subelement
|
||||
*/
|
||||
memcpy(pos, tmp, tmp[1] + 2);
|
||||
pos += tmp[1] + 2;
|
||||
tmp[0] = WLAN_EID_SSID;
|
||||
} else {
|
||||
memcpy(pos, tmp_old, tmp_old[1] + 2);
|
||||
pos += tmp_old[1] + 2;
|
||||
}
|
||||
} else {
|
||||
/* copy ie from subelement into new ie */
|
||||
memcpy(pos, tmp, tmp[1] + 2);
|
||||
pos += tmp[1] + 2;
|
||||
tmp[0] = WLAN_EID_SSID;
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp_old + tmp_old[1] + 2 - ie == ielen)
|
||||
break;
|
||||
|
||||
tmp_old += tmp_old[1] + 2;
|
||||
}
|
||||
|
||||
/* go through subelement again to check if there is any ie not
|
||||
* copied to new ie, skip ssid, capability, bssid-index ie
|
||||
*/
|
||||
tmp_new = sub_copy;
|
||||
while (tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
|
||||
if (!(tmp_new[0] == WLAN_EID_NON_TX_BSSID_CAP ||
|
||||
tmp_new[0] == WLAN_EID_SSID ||
|
||||
tmp_new[0] == WLAN_EID_MULTI_BSSID_IDX)) {
|
||||
memcpy(pos, tmp_new, tmp_new[1] + 2);
|
||||
pos += tmp_new[1] + 2;
|
||||
}
|
||||
if (tmp_new + tmp_new[1] + 2 - sub_copy == subie_len)
|
||||
break;
|
||||
tmp_new += tmp_new[1] + 2;
|
||||
}
|
||||
|
||||
kfree(sub_copy);
|
||||
return pos - new_ie;
|
||||
}
|
||||
|
||||
static bool is_bss(struct cfg80211_bss *a, const u8 *bssid,
|
||||
const u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
const u8 *ssidie;
|
||||
|
||||
if (bssid && !ether_addr_equal(a->bssid, bssid))
|
||||
return false;
|
||||
|
||||
if (!ssid)
|
||||
return true;
|
||||
|
||||
ies = rcu_access_pointer(a->ies);
|
||||
if (!ies)
|
||||
return false;
|
||||
ssidie = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len);
|
||||
if (!ssidie)
|
||||
return false;
|
||||
if (ssidie[1] != ssid_len)
|
||||
return false;
|
||||
return memcmp(ssidie + 2, ssid, ssid_len) == 0;
|
||||
}
|
||||
|
||||
static int
|
||||
cfg80211_add_nontrans_list(struct cfg80211_bss *trans_bss,
|
||||
struct cfg80211_bss *nontrans_bss)
|
||||
{
|
||||
const u8 *ssid;
|
||||
size_t ssid_len;
|
||||
struct cfg80211_bss *bss = NULL;
|
||||
|
||||
rcu_read_lock();
|
||||
ssid = ieee80211_bss_get_ie(nontrans_bss, WLAN_EID_SSID);
|
||||
if (!ssid) {
|
||||
rcu_read_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
ssid_len = ssid[1];
|
||||
ssid = ssid + 2;
|
||||
rcu_read_unlock();
|
||||
|
||||
/* check if nontrans_bss is in the list */
|
||||
list_for_each_entry(bss, &trans_bss->nontrans_list, nontrans_list) {
|
||||
if (is_bss(bss, nontrans_bss->bssid, ssid, ssid_len))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* add to the list */
|
||||
list_add_tail(&nontrans_bss->nontrans_list, &trans_bss->nontrans_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __cfg80211_bss_expire(struct cfg80211_registered_device *rdev,
|
||||
unsigned long expire_time)
|
||||
{
|
||||
|
@ -480,73 +656,43 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *rdev)
|
|||
__cfg80211_bss_expire(rdev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE);
|
||||
}
|
||||
|
||||
const u8 *cfg80211_find_ie_match(u8 eid, const u8 *ies, int len,
|
||||
const u8 *match, int match_len,
|
||||
int match_offset)
|
||||
const struct element *
|
||||
cfg80211_find_elem_match(u8 eid, const u8 *ies, unsigned int len,
|
||||
const u8 *match, unsigned int match_len,
|
||||
unsigned int match_offset)
|
||||
{
|
||||
/* match_offset can't be smaller than 2, unless match_len is
|
||||
* zero, in which case match_offset must be zero as well.
|
||||
*/
|
||||
if (WARN_ON((match_len && match_offset < 2) ||
|
||||
(!match_len && match_offset)))
|
||||
return NULL;
|
||||
const struct element *elem;
|
||||
|
||||
while (len >= 2 && len >= ies[1] + 2) {
|
||||
if ((ies[0] == eid) &&
|
||||
(ies[1] + 2 >= match_offset + match_len) &&
|
||||
!memcmp(ies + match_offset, match, match_len))
|
||||
return ies;
|
||||
|
||||
len -= ies[1] + 2;
|
||||
ies += ies[1] + 2;
|
||||
for_each_element_id(elem, eid, ies, len) {
|
||||
if (elem->datalen >= match_offset + match_len &&
|
||||
!memcmp(elem->data + match_offset, match, match_len))
|
||||
return elem;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_find_ie_match);
|
||||
EXPORT_SYMBOL(cfg80211_find_elem_match);
|
||||
|
||||
const u8 *cfg80211_find_vendor_ie(unsigned int oui, int oui_type,
|
||||
const u8 *ies, int len)
|
||||
const struct element *cfg80211_find_vendor_elem(unsigned int oui, int oui_type,
|
||||
const u8 *ies,
|
||||
unsigned int len)
|
||||
{
|
||||
const u8 *ie;
|
||||
const struct element *elem;
|
||||
u8 match[] = { oui >> 16, oui >> 8, oui, oui_type };
|
||||
int match_len = (oui_type < 0) ? 3 : sizeof(match);
|
||||
|
||||
if (WARN_ON(oui_type > 0xff))
|
||||
return NULL;
|
||||
|
||||
ie = cfg80211_find_ie_match(WLAN_EID_VENDOR_SPECIFIC, ies, len,
|
||||
match, match_len, 2);
|
||||
elem = cfg80211_find_elem_match(WLAN_EID_VENDOR_SPECIFIC, ies, len,
|
||||
match, match_len, 0);
|
||||
|
||||
if (ie && (ie[1] < 4))
|
||||
if (!elem || elem->datalen < 4)
|
||||
return NULL;
|
||||
|
||||
return ie;
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_find_vendor_ie);
|
||||
|
||||
static bool is_bss(struct cfg80211_bss *a, const u8 *bssid,
|
||||
const u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
const u8 *ssidie;
|
||||
|
||||
if (bssid && !ether_addr_equal(a->bssid, bssid))
|
||||
return false;
|
||||
|
||||
if (!ssid)
|
||||
return true;
|
||||
|
||||
ies = rcu_access_pointer(a->ies);
|
||||
if (!ies)
|
||||
return false;
|
||||
ssidie = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len);
|
||||
if (!ssidie)
|
||||
return false;
|
||||
if (ssidie[1] != ssid_len)
|
||||
return false;
|
||||
return memcmp(ssidie + 2, ssid, ssid_len) == 0;
|
||||
return elem;
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_find_vendor_elem);
|
||||
|
||||
/**
|
||||
* enum bss_compare_mode - BSS compare mode
|
||||
|
@ -882,6 +1028,12 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev,
|
|||
return true;
|
||||
}
|
||||
|
||||
struct cfg80211_non_tx_bss {
|
||||
struct cfg80211_bss *tx_bss;
|
||||
u8 max_bssid_indicator;
|
||||
u8 bssid_index;
|
||||
};
|
||||
|
||||
/* Returned bss is reference counted and must be cleaned up appropriately. */
|
||||
static struct cfg80211_internal_bss *
|
||||
cfg80211_bss_update(struct cfg80211_registered_device *rdev,
|
||||
|
@ -985,6 +1137,8 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
|
|||
memcpy(found->pub.chain_signal, tmp->pub.chain_signal,
|
||||
IEEE80211_MAX_CHAINS);
|
||||
ether_addr_copy(found->parent_bssid, tmp->parent_bssid);
|
||||
found->pub.max_bssid_indicator = tmp->pub.max_bssid_indicator;
|
||||
found->pub.bssid_index = tmp->pub.bssid_index;
|
||||
} else {
|
||||
struct cfg80211_internal_bss *new;
|
||||
struct cfg80211_internal_bss *hidden;
|
||||
|
@ -1009,6 +1163,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
|
|||
memcpy(new, tmp, sizeof(*new));
|
||||
new->refcount = 1;
|
||||
INIT_LIST_HEAD(&new->hidden_list);
|
||||
INIT_LIST_HEAD(&new->pub.nontrans_list);
|
||||
|
||||
if (rcu_access_pointer(tmp->pub.proberesp_ies)) {
|
||||
hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN);
|
||||
|
@ -1042,6 +1197,17 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
|
|||
goto drop;
|
||||
}
|
||||
|
||||
/* This must be before the call to bss_ref_get */
|
||||
if (tmp->pub.transmitted_bss) {
|
||||
struct cfg80211_internal_bss *pbss =
|
||||
container_of(tmp->pub.transmitted_bss,
|
||||
struct cfg80211_internal_bss,
|
||||
pub);
|
||||
|
||||
new->pub.transmitted_bss = tmp->pub.transmitted_bss;
|
||||
bss_ref_get(rdev, pbss);
|
||||
}
|
||||
|
||||
list_add_tail(&new->list, &rdev->bss_list);
|
||||
rdev->bss_entries++;
|
||||
rb_insert_bss(rdev, new);
|
||||
|
@ -1130,14 +1296,16 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
|
|||
}
|
||||
|
||||
/* Returned bss is reference counted and must be cleaned up appropriately. */
|
||||
struct cfg80211_bss *
|
||||
cfg80211_inform_bss_data(struct wiphy *wiphy,
|
||||
struct cfg80211_inform_bss *data,
|
||||
enum cfg80211_bss_frame_type ftype,
|
||||
const u8 *bssid, u64 tsf, u16 capability,
|
||||
u16 beacon_interval, const u8 *ie, size_t ielen,
|
||||
gfp_t gfp)
|
||||
static struct cfg80211_bss *
|
||||
cfg80211_inform_single_bss_data(struct wiphy *wiphy,
|
||||
struct cfg80211_inform_bss *data,
|
||||
enum cfg80211_bss_frame_type ftype,
|
||||
const u8 *bssid, u64 tsf, u16 capability,
|
||||
u16 beacon_interval, const u8 *ie, size_t ielen,
|
||||
struct cfg80211_non_tx_bss *non_tx_data,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||
struct cfg80211_bss_ies *ies;
|
||||
struct ieee80211_channel *channel;
|
||||
struct cfg80211_internal_bss tmp = {}, *res;
|
||||
|
@ -1163,6 +1331,11 @@ cfg80211_inform_bss_data(struct wiphy *wiphy,
|
|||
tmp.pub.beacon_interval = beacon_interval;
|
||||
tmp.pub.capability = capability;
|
||||
tmp.ts_boottime = data->boottime_ns;
|
||||
if (non_tx_data) {
|
||||
tmp.pub.transmitted_bss = non_tx_data->tx_bss;
|
||||
tmp.pub.bssid_index = non_tx_data->bssid_index;
|
||||
tmp.pub.max_bssid_indicator = non_tx_data->max_bssid_indicator;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we do not know here whether the IEs are from a Beacon or Probe
|
||||
|
@ -1209,19 +1382,247 @@ cfg80211_inform_bss_data(struct wiphy *wiphy,
|
|||
regulatory_hint_found_beacon(wiphy, channel, gfp);
|
||||
}
|
||||
|
||||
if (non_tx_data && non_tx_data->tx_bss) {
|
||||
/* this is a nontransmitting bss, we need to add it to
|
||||
* transmitting bss' list if it is not there
|
||||
*/
|
||||
if (cfg80211_add_nontrans_list(non_tx_data->tx_bss,
|
||||
&res->pub)) {
|
||||
if (__cfg80211_unlink_bss(rdev, res))
|
||||
rdev->bss_generation++;
|
||||
}
|
||||
}
|
||||
|
||||
trace_cfg80211_return_bss(&res->pub);
|
||||
/* cfg80211_bss_update gives us a referenced result */
|
||||
return &res->pub;
|
||||
}
|
||||
|
||||
static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
|
||||
struct cfg80211_inform_bss *data,
|
||||
enum cfg80211_bss_frame_type ftype,
|
||||
const u8 *bssid, u64 tsf,
|
||||
u16 beacon_interval, const u8 *ie,
|
||||
size_t ielen,
|
||||
struct cfg80211_non_tx_bss *non_tx_data,
|
||||
gfp_t gfp)
|
||||
{
|
||||
const u8 *mbssid_index_ie;
|
||||
const struct element *elem, *sub;
|
||||
size_t new_ie_len;
|
||||
u8 new_bssid[ETH_ALEN];
|
||||
u8 *new_ie;
|
||||
u16 capability;
|
||||
struct cfg80211_bss *bss;
|
||||
|
||||
if (!non_tx_data)
|
||||
return;
|
||||
if (!cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen))
|
||||
return;
|
||||
if (!wiphy->support_mbssid)
|
||||
return;
|
||||
if (wiphy->support_only_he_mbssid &&
|
||||
!cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, ie, ielen))
|
||||
return;
|
||||
|
||||
new_ie = kmalloc(IEEE80211_MAX_DATA_LEN, gfp);
|
||||
if (!new_ie)
|
||||
return;
|
||||
|
||||
for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, ie, ielen) {
|
||||
if (elem->datalen < 4)
|
||||
continue;
|
||||
for_each_element(sub, elem->data + 1, elem->datalen - 1) {
|
||||
if (sub->id != 0 || sub->datalen < 4) {
|
||||
/* not a valid BSS profile */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sub->data[0] != WLAN_EID_NON_TX_BSSID_CAP ||
|
||||
sub->data[1] != 2) {
|
||||
/* The first element within the Nontransmitted
|
||||
* BSSID Profile is not the Nontransmitted
|
||||
* BSSID Capability element.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
/* found a Nontransmitted BSSID Profile */
|
||||
mbssid_index_ie = cfg80211_find_ie
|
||||
(WLAN_EID_MULTI_BSSID_IDX,
|
||||
sub->data, sub->datalen);
|
||||
if (!mbssid_index_ie || mbssid_index_ie[1] < 1 ||
|
||||
mbssid_index_ie[2] == 0) {
|
||||
/* No valid Multiple BSSID-Index element */
|
||||
continue;
|
||||
}
|
||||
|
||||
non_tx_data->bssid_index = mbssid_index_ie[2];
|
||||
non_tx_data->max_bssid_indicator = elem->data[0];
|
||||
|
||||
cfg80211_gen_new_bssid(bssid,
|
||||
non_tx_data->max_bssid_indicator,
|
||||
non_tx_data->bssid_index,
|
||||
new_bssid);
|
||||
memset(new_ie, 0, IEEE80211_MAX_DATA_LEN);
|
||||
new_ie_len = cfg80211_gen_new_ie(ie, ielen, sub->data,
|
||||
sub->datalen, new_ie,
|
||||
gfp);
|
||||
if (!new_ie_len)
|
||||
continue;
|
||||
|
||||
capability = get_unaligned_le16(sub->data + 2);
|
||||
bss = cfg80211_inform_single_bss_data(wiphy, data,
|
||||
ftype,
|
||||
new_bssid, tsf,
|
||||
capability,
|
||||
beacon_interval,
|
||||
new_ie,
|
||||
new_ie_len,
|
||||
non_tx_data,
|
||||
gfp);
|
||||
if (!bss)
|
||||
break;
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(new_ie);
|
||||
}
|
||||
|
||||
struct cfg80211_bss *
|
||||
cfg80211_inform_bss_data(struct wiphy *wiphy,
|
||||
struct cfg80211_inform_bss *data,
|
||||
enum cfg80211_bss_frame_type ftype,
|
||||
const u8 *bssid, u64 tsf, u16 capability,
|
||||
u16 beacon_interval, const u8 *ie, size_t ielen,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct cfg80211_bss *res;
|
||||
struct cfg80211_non_tx_bss non_tx_data;
|
||||
|
||||
res = cfg80211_inform_single_bss_data(wiphy, data, ftype, bssid, tsf,
|
||||
capability, beacon_interval, ie,
|
||||
ielen, NULL, gfp);
|
||||
non_tx_data.tx_bss = res;
|
||||
cfg80211_parse_mbssid_data(wiphy, data, ftype, bssid, tsf,
|
||||
beacon_interval, ie, ielen, &non_tx_data,
|
||||
gfp);
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_inform_bss_data);
|
||||
|
||||
/* cfg80211_inform_bss_width_frame helper */
|
||||
struct cfg80211_bss *
|
||||
cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
|
||||
struct cfg80211_inform_bss *data,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
gfp_t gfp)
|
||||
static void
|
||||
cfg80211_parse_mbssid_frame_data(struct wiphy *wiphy,
|
||||
struct cfg80211_inform_bss *data,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
struct cfg80211_non_tx_bss *non_tx_data,
|
||||
gfp_t gfp)
|
||||
{
|
||||
enum cfg80211_bss_frame_type ftype;
|
||||
const u8 *ie = mgmt->u.probe_resp.variable;
|
||||
size_t ielen = len - offsetof(struct ieee80211_mgmt,
|
||||
u.probe_resp.variable);
|
||||
|
||||
ftype = ieee80211_is_beacon(mgmt->frame_control) ?
|
||||
CFG80211_BSS_FTYPE_BEACON : CFG80211_BSS_FTYPE_PRESP;
|
||||
|
||||
cfg80211_parse_mbssid_data(wiphy, data, ftype, mgmt->bssid,
|
||||
le64_to_cpu(mgmt->u.probe_resp.timestamp),
|
||||
le16_to_cpu(mgmt->u.probe_resp.beacon_int),
|
||||
ie, ielen, non_tx_data, gfp);
|
||||
}
|
||||
|
||||
static void
|
||||
cfg80211_update_notlisted_nontrans(struct wiphy *wiphy,
|
||||
struct cfg80211_bss *nontrans_bss,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
gfp_t gfp)
|
||||
{
|
||||
u8 *ie, *new_ie, *pos;
|
||||
const u8 *nontrans_ssid, *trans_ssid, *mbssid;
|
||||
size_t ielen = len - offsetof(struct ieee80211_mgmt,
|
||||
u.probe_resp.variable);
|
||||
size_t new_ie_len;
|
||||
struct cfg80211_bss_ies *new_ies;
|
||||
const struct cfg80211_bss_ies *old;
|
||||
u8 cpy_len;
|
||||
|
||||
ie = mgmt->u.probe_resp.variable;
|
||||
|
||||
new_ie_len = ielen;
|
||||
trans_ssid = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen);
|
||||
if (!trans_ssid)
|
||||
return;
|
||||
new_ie_len -= trans_ssid[1];
|
||||
mbssid = cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen);
|
||||
if (!mbssid)
|
||||
return;
|
||||
new_ie_len -= mbssid[1];
|
||||
rcu_read_lock();
|
||||
nontrans_ssid = ieee80211_bss_get_ie(nontrans_bss, WLAN_EID_SSID);
|
||||
if (!nontrans_ssid) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
new_ie_len += nontrans_ssid[1];
|
||||
rcu_read_unlock();
|
||||
|
||||
/* generate new ie for nontrans BSS
|
||||
* 1. replace SSID with nontrans BSS' SSID
|
||||
* 2. skip MBSSID IE
|
||||
*/
|
||||
new_ie = kzalloc(new_ie_len, gfp);
|
||||
if (!new_ie)
|
||||
return;
|
||||
new_ies = kzalloc(sizeof(*new_ies) + new_ie_len, gfp);
|
||||
if (!new_ies)
|
||||
goto out_free;
|
||||
|
||||
pos = new_ie;
|
||||
|
||||
/* copy the nontransmitted SSID */
|
||||
cpy_len = nontrans_ssid[1] + 2;
|
||||
memcpy(pos, nontrans_ssid, cpy_len);
|
||||
pos += cpy_len;
|
||||
/* copy the IEs between SSID and MBSSID */
|
||||
cpy_len = trans_ssid[1] + 2;
|
||||
memcpy(pos, (trans_ssid + cpy_len), (mbssid - (trans_ssid + cpy_len)));
|
||||
pos += (mbssid - (trans_ssid + cpy_len));
|
||||
/* copy the IEs after MBSSID */
|
||||
cpy_len = mbssid[1] + 2;
|
||||
memcpy(pos, mbssid + cpy_len, ((ie + ielen) - (mbssid + cpy_len)));
|
||||
|
||||
/* update ie */
|
||||
new_ies->len = new_ie_len;
|
||||
new_ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
|
||||
new_ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control);
|
||||
memcpy(new_ies->data, new_ie, new_ie_len);
|
||||
if (ieee80211_is_probe_resp(mgmt->frame_control)) {
|
||||
old = rcu_access_pointer(nontrans_bss->proberesp_ies);
|
||||
rcu_assign_pointer(nontrans_bss->proberesp_ies, new_ies);
|
||||
rcu_assign_pointer(nontrans_bss->ies, new_ies);
|
||||
if (old)
|
||||
kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
|
||||
} else {
|
||||
old = rcu_access_pointer(nontrans_bss->beacon_ies);
|
||||
rcu_assign_pointer(nontrans_bss->beacon_ies, new_ies);
|
||||
rcu_assign_pointer(nontrans_bss->ies, new_ies);
|
||||
if (old)
|
||||
kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
|
||||
}
|
||||
|
||||
out_free:
|
||||
kfree(new_ie);
|
||||
}
|
||||
|
||||
/* cfg80211_inform_bss_width_frame helper */
|
||||
static struct cfg80211_bss *
|
||||
cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
|
||||
struct cfg80211_inform_bss *data,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
struct cfg80211_non_tx_bss *non_tx_data,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct cfg80211_internal_bss tmp = {}, *res;
|
||||
struct cfg80211_bss_ies *ies;
|
||||
|
@ -1279,6 +1680,11 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
|
|||
tmp.pub.chains = data->chains;
|
||||
memcpy(tmp.pub.chain_signal, data->chain_signal, IEEE80211_MAX_CHAINS);
|
||||
ether_addr_copy(tmp.parent_bssid, data->parent_bssid);
|
||||
if (non_tx_data) {
|
||||
tmp.pub.transmitted_bss = non_tx_data->tx_bss;
|
||||
tmp.pub.bssid_index = non_tx_data->bssid_index;
|
||||
tmp.pub.max_bssid_indicator = non_tx_data->max_bssid_indicator;
|
||||
}
|
||||
|
||||
signal_valid = abs(data->chan->center_freq - channel->center_freq) <=
|
||||
wiphy->max_adj_channel_rssi_comp;
|
||||
|
@ -1300,6 +1706,53 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
|
|||
/* cfg80211_bss_update gives us a referenced result */
|
||||
return &res->pub;
|
||||
}
|
||||
|
||||
struct cfg80211_bss *
|
||||
cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
|
||||
struct cfg80211_inform_bss *data,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct cfg80211_bss *res, *tmp_bss;
|
||||
const u8 *ie = mgmt->u.probe_resp.variable;
|
||||
const struct cfg80211_bss_ies *ies1, *ies2;
|
||||
size_t ielen = len - offsetof(struct ieee80211_mgmt,
|
||||
u.probe_resp.variable);
|
||||
struct cfg80211_non_tx_bss non_tx_data;
|
||||
|
||||
res = cfg80211_inform_single_bss_frame_data(wiphy, data, mgmt,
|
||||
len, NULL, gfp);
|
||||
if (!res || !wiphy->support_mbssid ||
|
||||
!cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen))
|
||||
return res;
|
||||
if (wiphy->support_only_he_mbssid &&
|
||||
!cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, ie, ielen))
|
||||
return res;
|
||||
|
||||
non_tx_data.tx_bss = res;
|
||||
/* process each non-transmitting bss */
|
||||
cfg80211_parse_mbssid_frame_data(wiphy, data, mgmt, len,
|
||||
&non_tx_data, gfp);
|
||||
|
||||
/* check if the res has other nontransmitting bss which is not
|
||||
* in MBSSID IE
|
||||
*/
|
||||
ies1 = rcu_access_pointer(res->ies);
|
||||
|
||||
/* go through nontrans_list, if the timestamp of the BSS is
|
||||
* earlier than the timestamp of the transmitting BSS then
|
||||
* update it
|
||||
*/
|
||||
list_for_each_entry(tmp_bss, &res->nontrans_list,
|
||||
nontrans_list) {
|
||||
ies2 = rcu_access_pointer(tmp_bss->ies);
|
||||
if (ies2->tsf < ies1->tsf)
|
||||
cfg80211_update_notlisted_nontrans(wiphy, tmp_bss,
|
||||
mgmt, len, gfp);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_inform_bss_frame_data);
|
||||
|
||||
void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
|
||||
|
@ -1337,7 +1790,8 @@ EXPORT_SYMBOL(cfg80211_put_bss);
|
|||
void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||
struct cfg80211_internal_bss *bss;
|
||||
struct cfg80211_internal_bss *bss, *tmp1;
|
||||
struct cfg80211_bss *nontrans_bss, *tmp;
|
||||
|
||||
if (WARN_ON(!pub))
|
||||
return;
|
||||
|
@ -1345,10 +1799,21 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
|
|||
bss = container_of(pub, struct cfg80211_internal_bss, pub);
|
||||
|
||||
spin_lock_bh(&rdev->bss_lock);
|
||||
if (!list_empty(&bss->list)) {
|
||||
if (__cfg80211_unlink_bss(rdev, bss))
|
||||
if (list_empty(&bss->list))
|
||||
goto out;
|
||||
|
||||
list_for_each_entry_safe(nontrans_bss, tmp,
|
||||
&pub->nontrans_list,
|
||||
nontrans_list) {
|
||||
tmp1 = container_of(nontrans_bss,
|
||||
struct cfg80211_internal_bss, pub);
|
||||
if (__cfg80211_unlink_bss(rdev, tmp1))
|
||||
rdev->bss_generation++;
|
||||
}
|
||||
|
||||
if (__cfg80211_unlink_bss(rdev, bss))
|
||||
rdev->bss_generation++;
|
||||
out:
|
||||
spin_unlock_bh(&rdev->bss_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_unlink_bss);
|
||||
|
|
|
@ -789,7 +789,7 @@ out:
|
|||
}
|
||||
EXPORT_SYMBOL(cfg80211_classify8021d);
|
||||
|
||||
const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie)
|
||||
const struct element *ieee80211_bss_get_elem(struct cfg80211_bss *bss, u8 id)
|
||||
{
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
|
||||
|
@ -797,9 +797,9 @@ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie)
|
|||
if (!ies)
|
||||
return NULL;
|
||||
|
||||
return cfg80211_find_ie(ie, ies->data, ies->len);
|
||||
return cfg80211_find_elem(id, ies->data, ies->len);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_bss_get_ie);
|
||||
EXPORT_SYMBOL(ieee80211_bss_get_elem);
|
||||
|
||||
void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче