Quite a few changes:
* the applicable eth_hw_addr_set() and const hw_addr changes * various code cleanups/refactorings * stack usage reductions across the wireless stack * some unstructured find_ie() -> structured find_element() changes * a few more pieces of multi-BSSID support * some 6 GHz regulatory support * 6 GHz support in hwsim, for testing userspace code * Light Communications (LC, 802.11bb) early band definitions to be able to add a first driver soon -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEH1e1rEeCd0AIMq6MB8qZga/fl8QFAmFxi7MACgkQB8qZga/f l8SGYA/+IRqIfgIcdQW2XkRZanpYHirS4ZELcB7qH2XDAVLALpZx9h9kVhpVrjmh BFYaJz3H5cEfwH6+JSfc7dvYlzUN0oIwzs+s0PpUwK13R/NhqCcP0PSJESBtfk/4 sxerJAHyWNZ2Ji0dq18m17IEU5IC03y8h3xekzeyl5UOmU72sqvqq3ZT8yQ48bu9 K4BbTFv5/cPKS8EAiFDGQbzVYz94zj+6XZH/kiN3vnhtqhI7knbvwF5zAafXdZOF wnCucHbWcyvwxiqIMPZBUy0nP7p2Lrz24MFbDSUK/9umxO7JNyP6A8KOM5/CwsEF u0hcGmW8NSRIkMQZoZi41d0eHZa8iPMv9gRYlSDFvElBR/kPp206zOYgzYj9Fi5g zuAISwhzWT06BsfLvKLLjK/xZmxXybOvkdie/vT0VAWHBrGR8FZV5ovfac/Qb9FJ RwAuyOKpHP1q+Oy+tQdNpnAVx1W0E/VoHXyT0a+G4cXfHG6wZL6zG1F4/kS/g+wC 184MpQwxZkliNhuHbHScIARhCBCGxSNvU9R9Kz3vGGS9l+syT8ecl2IQRgEvU6FY yo6bryWFWXkE7jtjEZWvnqQMOD1EcQeu66Nvg2LS82twcn/lJ/RlkjaXneeNP2wD BZMOk3u0wWgWhm7AcaehT7IuMJi3Q0BYask+ZTA8Uv5eqW7YADg= =ZXrI -----END PGP SIGNATURE----- Merge tag 'mac80211-next-for-net-next-2021-10-21' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next Johannes Berg says: ==================== Quite a few changes: * the applicable eth_hw_addr_set() and const hw_addr changes * various code cleanups/refactorings * stack usage reductions across the wireless stack * some unstructured find_ie() -> structured find_element() changes * a few more pieces of multi-BSSID support * some 6 GHz regulatory support * 6 GHz support in hwsim, for testing userspace code * Light Communications (LC, 802.11bb) early band definitions to be able to add a first driver soon * tag 'mac80211-next-for-net-next-2021-10-21' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next: (35 commits) cfg80211: fix kernel-doc for MBSSID EMA mac80211: Prevent AP probing during suspend nl80211: Add LC placeholder band definition to nl80211_band ... ==================== Link: https://lore.kernel.org/r/20211021154953.134849-1-johannes@sipsolutions.net Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Коммит
24f7cf9b85
|
@ -2802,7 +2802,6 @@ out_err:
|
|||
|
||||
static const struct ieee80211_sband_iftype_data he_capa_2ghz[] = {
|
||||
{
|
||||
/* TODO: should we support other types, e.g., P2P?*/
|
||||
.types_mask = BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_AP),
|
||||
.he_cap = {
|
||||
|
@ -2850,7 +2849,6 @@ static const struct ieee80211_sband_iftype_data he_capa_2ghz[] = {
|
|||
},
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
{
|
||||
/* TODO: should we support other types, e.g., IBSS?*/
|
||||
.types_mask = BIT(NL80211_IFTYPE_MESH_POINT),
|
||||
.he_cap = {
|
||||
.has_he = true,
|
||||
|
@ -2988,6 +2986,122 @@ static const struct ieee80211_sband_iftype_data he_capa_5ghz[] = {
|
|||
#endif
|
||||
};
|
||||
|
||||
static const struct ieee80211_sband_iftype_data he_capa_6ghz[] = {
|
||||
{
|
||||
/* TODO: should we support other types, e.g., P2P?*/
|
||||
.types_mask = BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_AP),
|
||||
.he_6ghz_capa = {
|
||||
.capa = cpu_to_le16(IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START |
|
||||
IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP |
|
||||
IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN |
|
||||
IEEE80211_HE_6GHZ_CAP_SM_PS |
|
||||
IEEE80211_HE_6GHZ_CAP_RD_RESPONDER |
|
||||
IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS |
|
||||
IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS),
|
||||
},
|
||||
.he_cap = {
|
||||
.has_he = true,
|
||||
.he_cap_elem = {
|
||||
.mac_cap_info[0] =
|
||||
IEEE80211_HE_MAC_CAP0_HTC_HE,
|
||||
.mac_cap_info[1] =
|
||||
IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US |
|
||||
IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_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_EXT_3,
|
||||
.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU,
|
||||
.phy_cap_info[0] =
|
||||
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
|
||||
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
|
||||
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G,
|
||||
.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,
|
||||
.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,
|
||||
|
||||
/* Leave all the other PHY capability bytes
|
||||
* unset, as DCM, beam forming, RU and PPE
|
||||
* threshold information are not supported
|
||||
*/
|
||||
},
|
||||
.he_mcs_nss_supp = {
|
||||
.rx_mcs_80 = cpu_to_le16(0xfffa),
|
||||
.tx_mcs_80 = cpu_to_le16(0xfffa),
|
||||
.rx_mcs_160 = cpu_to_le16(0xfffa),
|
||||
.tx_mcs_160 = cpu_to_le16(0xfffa),
|
||||
.rx_mcs_80p80 = cpu_to_le16(0xfffa),
|
||||
.tx_mcs_80p80 = cpu_to_le16(0xfffa),
|
||||
},
|
||||
},
|
||||
},
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
{
|
||||
/* TODO: should we support other types, e.g., IBSS?*/
|
||||
.types_mask = BIT(NL80211_IFTYPE_MESH_POINT),
|
||||
.he_6ghz_capa = {
|
||||
.capa = cpu_to_le16(IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START |
|
||||
IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP |
|
||||
IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN |
|
||||
IEEE80211_HE_6GHZ_CAP_SM_PS |
|
||||
IEEE80211_HE_6GHZ_CAP_RD_RESPONDER |
|
||||
IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS |
|
||||
IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS),
|
||||
},
|
||||
.he_cap = {
|
||||
.has_he = true,
|
||||
.he_cap_elem = {
|
||||
.mac_cap_info[0] =
|
||||
IEEE80211_HE_MAC_CAP0_HTC_HE,
|
||||
.mac_cap_info[1] =
|
||||
IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8,
|
||||
.mac_cap_info[2] =
|
||||
IEEE80211_HE_MAC_CAP2_ACK_EN,
|
||||
.mac_cap_info[3] =
|
||||
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
|
||||
IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3,
|
||||
.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU,
|
||||
.phy_cap_info[0] =
|
||||
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
|
||||
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
|
||||
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G,
|
||||
.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,
|
||||
.phy_cap_info[2] = 0,
|
||||
|
||||
/* Leave all the other PHY capability bytes
|
||||
* unset, as DCM, beam forming, RU and PPE
|
||||
* threshold information are not supported
|
||||
*/
|
||||
},
|
||||
.he_mcs_nss_supp = {
|
||||
.rx_mcs_80 = cpu_to_le16(0xfffa),
|
||||
.tx_mcs_80 = cpu_to_le16(0xfffa),
|
||||
.rx_mcs_160 = cpu_to_le16(0xfffa),
|
||||
.tx_mcs_160 = cpu_to_le16(0xfffa),
|
||||
.rx_mcs_80p80 = cpu_to_le16(0xfffa),
|
||||
.tx_mcs_80p80 = cpu_to_le16(0xfffa),
|
||||
},
|
||||
},
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static void mac80211_hwsim_he_capab(struct ieee80211_supported_band *sband)
|
||||
{
|
||||
u16 n_iftype_data;
|
||||
|
@ -3000,6 +3114,10 @@ static void mac80211_hwsim_he_capab(struct ieee80211_supported_band *sband)
|
|||
n_iftype_data = ARRAY_SIZE(he_capa_5ghz);
|
||||
sband->iftype_data =
|
||||
(struct ieee80211_sband_iftype_data *)he_capa_5ghz;
|
||||
} else if (sband->band == NL80211_BAND_6GHZ) {
|
||||
n_iftype_data = ARRAY_SIZE(he_capa_6ghz);
|
||||
sband->iftype_data =
|
||||
(struct ieee80211_sband_iftype_data *)he_capa_6ghz;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
@ -3290,6 +3408,12 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
|||
sband->vht_cap.vht_mcs.tx_mcs_map =
|
||||
sband->vht_cap.vht_mcs.rx_mcs_map;
|
||||
break;
|
||||
case NL80211_BAND_6GHZ:
|
||||
sband->channels = data->channels_6ghz;
|
||||
sband->n_channels = ARRAY_SIZE(hwsim_channels_6ghz);
|
||||
sband->bitrates = data->rates + 4;
|
||||
sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4;
|
||||
break;
|
||||
case NL80211_BAND_S1GHZ:
|
||||
memcpy(&sband->s1g_cap, &hwsim_s1g_cap,
|
||||
sizeof(sband->s1g_cap));
|
||||
|
@ -3300,19 +3424,21 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
|||
continue;
|
||||
}
|
||||
|
||||
sband->ht_cap.ht_supported = true;
|
||||
sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
|
||||
IEEE80211_HT_CAP_GRN_FLD |
|
||||
IEEE80211_HT_CAP_SGI_20 |
|
||||
IEEE80211_HT_CAP_SGI_40 |
|
||||
IEEE80211_HT_CAP_DSSSCCK40;
|
||||
sband->ht_cap.ampdu_factor = 0x3;
|
||||
sband->ht_cap.ampdu_density = 0x6;
|
||||
memset(&sband->ht_cap.mcs, 0,
|
||||
sizeof(sband->ht_cap.mcs));
|
||||
sband->ht_cap.mcs.rx_mask[0] = 0xff;
|
||||
sband->ht_cap.mcs.rx_mask[1] = 0xff;
|
||||
sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
|
||||
if (band != NL80211_BAND_6GHZ){
|
||||
sband->ht_cap.ht_supported = true;
|
||||
sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
|
||||
IEEE80211_HT_CAP_GRN_FLD |
|
||||
IEEE80211_HT_CAP_SGI_20 |
|
||||
IEEE80211_HT_CAP_SGI_40 |
|
||||
IEEE80211_HT_CAP_DSSSCCK40;
|
||||
sband->ht_cap.ampdu_factor = 0x3;
|
||||
sband->ht_cap.ampdu_density = 0x6;
|
||||
memset(&sband->ht_cap.mcs, 0,
|
||||
sizeof(sband->ht_cap.mcs));
|
||||
sband->ht_cap.mcs.rx_mask[0] = 0xff;
|
||||
sband->ht_cap.mcs.rx_mask[1] = 0xff;
|
||||
sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
|
||||
}
|
||||
|
||||
mac80211_hwsim_he_capab(sband);
|
||||
|
||||
|
@ -3527,13 +3653,16 @@ static const struct net_device_ops hwsim_netdev_ops = {
|
|||
|
||||
static void hwsim_mon_setup(struct net_device *dev)
|
||||
{
|
||||
u8 addr[ETH_ALEN];
|
||||
|
||||
dev->netdev_ops = &hwsim_netdev_ops;
|
||||
dev->needs_free_netdev = true;
|
||||
ether_setup(dev);
|
||||
dev->priv_flags |= IFF_NO_QUEUE;
|
||||
dev->type = ARPHRD_IEEE80211_RADIOTAP;
|
||||
eth_zero_addr(dev->dev_addr);
|
||||
dev->dev_addr[0] = 0x12;
|
||||
eth_zero_addr(addr);
|
||||
addr[0] = 0x12;
|
||||
eth_hw_addr_set(dev, addr);
|
||||
}
|
||||
|
||||
static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(const u8 *addr)
|
||||
|
|
|
@ -1988,6 +1988,44 @@ int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
|
|||
int mcs, bool ext_nss_bw_capable,
|
||||
unsigned int max_vht_nss);
|
||||
|
||||
/**
|
||||
* enum ieee80211_ap_reg_power - regulatory power for a Access Point
|
||||
*
|
||||
* @IEEE80211_REG_UNSET_AP: Access Point has no regulatory power mode
|
||||
* @IEEE80211_REG_LPI: Indoor Access Point
|
||||
* @IEEE80211_REG_SP: Standard power Access Point
|
||||
* @IEEE80211_REG_VLP: Very low power Access Point
|
||||
* @IEEE80211_REG_AP_POWER_AFTER_LAST: internal
|
||||
* @IEEE80211_REG_AP_POWER_MAX: maximum value
|
||||
*/
|
||||
enum ieee80211_ap_reg_power {
|
||||
IEEE80211_REG_UNSET_AP,
|
||||
IEEE80211_REG_LPI_AP,
|
||||
IEEE80211_REG_SP_AP,
|
||||
IEEE80211_REG_VLP_AP,
|
||||
IEEE80211_REG_AP_POWER_AFTER_LAST,
|
||||
IEEE80211_REG_AP_POWER_MAX =
|
||||
IEEE80211_REG_AP_POWER_AFTER_LAST - 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ieee80211_client_reg_power - regulatory power for a client
|
||||
*
|
||||
* @IEEE80211_REG_UNSET_CLIENT: Client has no regulatory power mode
|
||||
* @IEEE80211_REG_DEFAULT_CLIENT: Default Client
|
||||
* @IEEE80211_REG_SUBORDINATE_CLIENT: Subordinate Client
|
||||
* @IEEE80211_REG_CLIENT_POWER_AFTER_LAST: internal
|
||||
* @IEEE80211_REG_CLIENT_POWER_MAX: maximum value
|
||||
*/
|
||||
enum ieee80211_client_reg_power {
|
||||
IEEE80211_REG_UNSET_CLIENT,
|
||||
IEEE80211_REG_DEFAULT_CLIENT,
|
||||
IEEE80211_REG_SUBORDINATE_CLIENT,
|
||||
IEEE80211_REG_CLIENT_POWER_AFTER_LAST,
|
||||
IEEE80211_REG_CLIENT_POWER_MAX =
|
||||
IEEE80211_REG_CLIENT_POWER_AFTER_LAST - 1,
|
||||
};
|
||||
|
||||
/* 802.11ax HE MAC capabilities */
|
||||
#define IEEE80211_HE_MAC_CAP0_HTC_HE 0x01
|
||||
#define IEEE80211_HE_MAC_CAP0_TWT_REQ 0x02
|
||||
|
|
|
@ -739,6 +739,22 @@ struct cfg80211_tid_config {
|
|||
struct cfg80211_tid_cfg tid_conf[];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_fils_aad - FILS AAD data
|
||||
* @macaddr: STA MAC address
|
||||
* @kek: FILS KEK
|
||||
* @kek_len: FILS KEK length
|
||||
* @snonce: STA Nonce
|
||||
* @anonce: AP Nonce
|
||||
*/
|
||||
struct cfg80211_fils_aad {
|
||||
const u8 *macaddr;
|
||||
const u8 *kek;
|
||||
u8 kek_len;
|
||||
const u8 *snonce;
|
||||
const u8 *anonce;
|
||||
};
|
||||
|
||||
/**
|
||||
* cfg80211_get_chandef_type - return old channel type from chandef
|
||||
* @chandef: the channel definition
|
||||
|
@ -1040,6 +1056,36 @@ struct cfg80211_crypto_settings {
|
|||
enum nl80211_sae_pwe_mechanism sae_pwe;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_mbssid_config - AP settings for multi bssid
|
||||
*
|
||||
* @tx_wdev: pointer to the transmitted interface in the MBSSID set
|
||||
* @index: index of this AP in the multi bssid group.
|
||||
* @ema: set to true if the beacons should be sent out in EMA mode.
|
||||
*/
|
||||
struct cfg80211_mbssid_config {
|
||||
struct wireless_dev *tx_wdev;
|
||||
u8 index;
|
||||
bool ema;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_mbssid_elems - Multiple BSSID elements
|
||||
*
|
||||
* @cnt: Number of elements in array %elems.
|
||||
*
|
||||
* @elem: Array of multiple BSSID element(s) to be added into Beacon frames.
|
||||
* @elem.data: Data for multiple BSSID elements.
|
||||
* @elem.len: Length of data.
|
||||
*/
|
||||
struct cfg80211_mbssid_elems {
|
||||
u8 cnt;
|
||||
struct {
|
||||
const u8 *data;
|
||||
size_t len;
|
||||
} elem[];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_beacon_data - beacon data
|
||||
* @head: head portion of beacon (before TIM IE)
|
||||
|
@ -1058,6 +1104,7 @@ struct cfg80211_crypto_settings {
|
|||
* @assocresp_ies_len: length of assocresp_ies in octets
|
||||
* @probe_resp_len: length of probe response template (@probe_resp)
|
||||
* @probe_resp: probe response template (AP mode only)
|
||||
* @mbssid_ies: multiple BSSID elements
|
||||
* @ftm_responder: enable FTM responder functionality; -1 for no change
|
||||
* (which also implies no change in LCI/civic location data)
|
||||
* @lci: Measurement Report element content, starting with Measurement Token
|
||||
|
@ -1075,6 +1122,7 @@ struct cfg80211_beacon_data {
|
|||
const u8 *probe_resp;
|
||||
const u8 *lci;
|
||||
const u8 *civicloc;
|
||||
struct cfg80211_mbssid_elems *mbssid_ies;
|
||||
s8 ftm_responder;
|
||||
|
||||
size_t head_len, tail_len;
|
||||
|
@ -1189,6 +1237,7 @@ enum cfg80211_ap_settings_flags {
|
|||
* @he_oper: HE operation IE (or %NULL if HE isn't enabled)
|
||||
* @fils_discovery: FILS discovery transmission parameters
|
||||
* @unsol_bcast_probe_resp: Unsolicited broadcast probe response parameters
|
||||
* @mbssid_config: AP settings for multiple bssid
|
||||
*/
|
||||
struct cfg80211_ap_settings {
|
||||
struct cfg80211_chan_def chandef;
|
||||
|
@ -1221,6 +1270,7 @@ struct cfg80211_ap_settings {
|
|||
struct cfg80211_he_bss_color he_bss_color;
|
||||
struct cfg80211_fils_discovery fils_discovery;
|
||||
struct cfg80211_unsol_bcast_probe_resp unsol_bcast_probe_resp;
|
||||
struct cfg80211_mbssid_config mbssid_config;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -4018,6 +4068,10 @@ struct mgmt_frame_regs {
|
|||
* @set_sar_specs: Update the SAR (TX power) settings.
|
||||
*
|
||||
* @color_change: Initiate a color change.
|
||||
*
|
||||
* @set_fils_aad: Set FILS AAD data to the AP driver so that the driver can use
|
||||
* those to decrypt (Re)Association Request and encrypt (Re)Association
|
||||
* Response frame.
|
||||
*/
|
||||
struct cfg80211_ops {
|
||||
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
|
||||
|
@ -4348,6 +4402,8 @@ struct cfg80211_ops {
|
|||
int (*color_change)(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_color_change_settings *params);
|
||||
int (*set_fils_aad)(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct cfg80211_fils_aad *fils_aad);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -4981,6 +5037,13 @@ struct wiphy_iftype_akm_suites {
|
|||
* %NL80211_TID_CONFIG_ATTR_RETRY_LONG attributes
|
||||
* @sar_capa: SAR control capabilities
|
||||
* @rfkill: a pointer to the rfkill structure
|
||||
*
|
||||
* @mbssid_max_interfaces: maximum number of interfaces supported by the driver
|
||||
* in a multiple BSSID set. This field must be set to a non-zero value
|
||||
* by the driver to advertise MBSSID support.
|
||||
* @ema_max_profile_periodicity: maximum profile periodicity supported by
|
||||
* the driver. Setting this field to a non-zero value indicates that the
|
||||
* driver supports enhanced multi-BSSID advertisements (EMA AP).
|
||||
*/
|
||||
struct wiphy {
|
||||
struct mutex mtx;
|
||||
|
@ -5125,6 +5188,9 @@ struct wiphy {
|
|||
|
||||
struct rfkill *rfkill;
|
||||
|
||||
u8 mbssid_max_interfaces;
|
||||
u8 ema_max_profile_periodicity;
|
||||
|
||||
char priv[] __aligned(NETDEV_ALIGN);
|
||||
};
|
||||
|
||||
|
@ -5492,7 +5558,7 @@ struct wireless_dev {
|
|||
unsigned long unprot_beacon_reported;
|
||||
};
|
||||
|
||||
static inline u8 *wdev_address(struct wireless_dev *wdev)
|
||||
static inline const u8 *wdev_address(struct wireless_dev *wdev)
|
||||
{
|
||||
if (wdev->netdev)
|
||||
return wdev->netdev->dev_addr;
|
||||
|
@ -6310,6 +6376,17 @@ static inline void cfg80211_gen_new_bssid(const u8 *bssid, u8 max_bssid,
|
|||
u64_to_ether_addr(new_bssid_u64, new_bssid);
|
||||
}
|
||||
|
||||
/**
|
||||
* cfg80211_get_ies_channel_number - returns the channel number from ies
|
||||
* @ie: IEs
|
||||
* @ielen: length of IEs
|
||||
* @band: enum nl80211_band of the channel
|
||||
*
|
||||
* Returns the channel number, or -1 if none could be determined.
|
||||
*/
|
||||
int cfg80211_get_ies_channel_number(const u8 *ie, size_t ielen,
|
||||
enum nl80211_band band);
|
||||
|
||||
/**
|
||||
* cfg80211_is_element_inherited - returns if element ID should be inherited
|
||||
* @element: element to check
|
||||
|
|
|
@ -632,6 +632,10 @@ struct ieee80211_fils_discovery {
|
|||
* @s1g: BSS is S1G BSS (affects Association Request format).
|
||||
* @beacon_tx_rate: The configured beacon transmit rate that needs to be passed
|
||||
* to driver when rate control is offloaded to firmware.
|
||||
* @power_type: power type of BSS for 6 GHz
|
||||
* @tx_pwr_env: transmit power envelope array of BSS.
|
||||
* @tx_pwr_env_num: number of @tx_pwr_env.
|
||||
* @pwr_reduction: power constraint of BSS.
|
||||
*/
|
||||
struct ieee80211_bss_conf {
|
||||
const u8 *bssid;
|
||||
|
@ -702,6 +706,10 @@ struct ieee80211_bss_conf {
|
|||
u32 unsol_bcast_probe_resp_interval;
|
||||
bool s1g;
|
||||
struct cfg80211_bitrate_mask beacon_tx_rate;
|
||||
enum ieee80211_ap_reg_power power_type;
|
||||
struct ieee80211_tx_pwr_env tx_pwr_env[IEEE80211_TPE_MAX_IE_COUNT];
|
||||
u8 tx_pwr_env_num;
|
||||
u8 pwr_reduction;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1715,6 +1723,7 @@ enum ieee80211_offload_flags {
|
|||
* write-protected by sdata_lock and local->mtx so holding either is fine
|
||||
* for read access.
|
||||
* @color_change_color: the bss color that will be used after the change.
|
||||
* @mbssid_tx_vif: Pointer to the transmitting interface if MBSSID is enabled.
|
||||
*/
|
||||
struct ieee80211_vif {
|
||||
enum nl80211_iftype type;
|
||||
|
@ -1746,6 +1755,8 @@ struct ieee80211_vif {
|
|||
bool color_change_active;
|
||||
u8 color_change_color;
|
||||
|
||||
struct ieee80211_vif *mbssid_tx_vif;
|
||||
|
||||
/* must be last */
|
||||
u8 drv_priv[] __aligned(sizeof(void *));
|
||||
};
|
||||
|
|
|
@ -13,6 +13,35 @@
|
|||
* enum iwl_mvm_vendor_cmd - supported vendor commands
|
||||
* @IWL_MVM_VENDOR_CMD_GET_CSME_CONN_INFO: reports CSME connection info.
|
||||
* @IWL_MVM_VENDOR_CMD_HOST_GET_OWNERSHIP: asks for ownership on the device.
|
||||
* This is useful when the CSME firmware owns the device and the kernel
|
||||
* wants to use it. In case the CSME firmware has no connection active the
|
||||
* kernel will manage on its own to get ownership of the device.
|
||||
* When the CSME firmware has an active connection, the user space
|
||||
* involvement is required. The kernel will assert the RFKILL signal with
|
||||
* the "device not owned" reason so that nobody can touch the device. Then
|
||||
* the user space can run the following flow to be able to get connected
|
||||
* to the very same AP the CSME firmware is currently connected to:
|
||||
*
|
||||
* 1) The user space (NetworkManager) boots and sees that the device is
|
||||
* in RFKILL because the host doesn't own the device
|
||||
* 2) The user space asks the kernel what AP the CSME firmware is
|
||||
* connected to (with %IWL_MVM_VENDOR_CMD_GET_CSME_CONN_INFO)
|
||||
* 3) The user space checks if it has a profile that matches the reply
|
||||
* from the CSME firmware
|
||||
* 4) The user space installs a network to the wpa_supplicant with a
|
||||
* specific BSSID and a specific frequency
|
||||
* 5) The user space prevents any type of full scan
|
||||
* 6) The user space asks iwlmei to request ownership on the device (with
|
||||
* this command)
|
||||
* 7) iwlmei requests ownership from the CSME firmware
|
||||
* 8) The CSME firmware grants ownership
|
||||
* 9) iwlmei tells iwlwifi to lift the RFKILL
|
||||
* 10) RFKILL OFF is reported to user space
|
||||
* 11) The host boots the device, loads the firwmare, and connects to a
|
||||
* specific BSSID without scanning including IP as fast as it can
|
||||
* 12) The host reports to the CSME firmware that there is a connection
|
||||
* 13) The TCP connection is preserved and the host has connectivity
|
||||
*
|
||||
* @IWL_MVM_VENDOR_CMD_ROAMING_FORBIDDEN_EVENT: notifies if roaming is allowed.
|
||||
* It contains a &IWL_MVM_VENDOR_ATTR_ROAMING_FORBIDDEN and a
|
||||
* &IWL_MVM_VENDOR_ATTR_VIF_ADDR attributes.
|
||||
|
|
|
@ -300,6 +300,29 @@
|
|||
* the interface goes down.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DOC: FILS shared key crypto offload
|
||||
*
|
||||
* This feature is applicable to drivers running in AP mode.
|
||||
*
|
||||
* FILS shared key crypto offload can be advertised by drivers by setting
|
||||
* @NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD flag. The drivers that support
|
||||
* FILS shared key crypto offload should be able to encrypt and decrypt
|
||||
* association frames for FILS shared key authentication as per IEEE 802.11ai.
|
||||
* With this capability, for FILS key derivation, drivers depend on userspace.
|
||||
*
|
||||
* After FILS key derivation, userspace shares the FILS AAD details with the
|
||||
* driver and the driver stores the same to use in decryption of association
|
||||
* request and in encryption of association response. The below parameters
|
||||
* should be given to the driver in %NL80211_CMD_SET_FILS_AAD.
|
||||
* %NL80211_ATTR_MAC - STA MAC address, used for storing FILS AAD per STA
|
||||
* %NL80211_ATTR_FILS_KEK - Used for encryption or decryption
|
||||
* %NL80211_ATTR_FILS_NONCES - Used for encryption or decryption
|
||||
* (STA Nonce 16 bytes followed by AP Nonce 16 bytes)
|
||||
*
|
||||
* Once the association is done, the driver cleans the FILS AAD data.
|
||||
*/
|
||||
|
||||
/**
|
||||
* enum nl80211_commands - supported nl80211 commands
|
||||
*
|
||||
|
@ -337,7 +360,10 @@
|
|||
* @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes
|
||||
* %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from
|
||||
* userspace to request deletion of a virtual interface, then requires
|
||||
* attribute %NL80211_ATTR_IFINDEX.
|
||||
* attribute %NL80211_ATTR_IFINDEX. If multiple BSSID advertisements are
|
||||
* enabled using %NL80211_ATTR_MBSSID_CONFIG, %NL80211_ATTR_MBSSID_ELEMS,
|
||||
* and if this command is used for the transmitting interface, then all
|
||||
* the non-transmitting interfaces are deleted as well.
|
||||
*
|
||||
* @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
|
||||
* by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
|
||||
|
@ -1200,6 +1226,12 @@
|
|||
* @NL80211_CMD_COLOR_CHANGE_COMPLETED: Notify userland that the color change
|
||||
* has completed
|
||||
*
|
||||
* @NL80211_CMD_SET_FILS_AAD: Set FILS AAD data to the driver using -
|
||||
* &NL80211_ATTR_MAC - for STA MAC address
|
||||
* &NL80211_ATTR_FILS_KEK - for KEK
|
||||
* &NL80211_ATTR_FILS_NONCES - for FILS Nonces
|
||||
* (STA Nonce 16 bytes followed by AP Nonce 16 bytes)
|
||||
*
|
||||
* @NL80211_CMD_MAX: highest used command number
|
||||
* @__NL80211_CMD_AFTER_LAST: internal use
|
||||
*/
|
||||
|
@ -1440,6 +1472,8 @@ enum nl80211_commands {
|
|||
NL80211_CMD_COLOR_CHANGE_ABORTED,
|
||||
NL80211_CMD_COLOR_CHANGE_COMPLETED,
|
||||
|
||||
NL80211_CMD_SET_FILS_AAD,
|
||||
|
||||
/* add new commands above here */
|
||||
|
||||
/* used to define NL80211_CMD_MAX below */
|
||||
|
@ -2593,6 +2627,18 @@ enum nl80211_commands {
|
|||
* @NL80211_ATTR_COLOR_CHANGE_ELEMS: Nested set of attributes containing the IE
|
||||
* information for the time while performing a color switch.
|
||||
*
|
||||
* @NL80211_ATTR_MBSSID_CONFIG: Nested attribute for multiple BSSID
|
||||
* advertisements (MBSSID) parameters in AP mode.
|
||||
* Kernel uses this attribute to indicate the driver's support for MBSSID
|
||||
* and enhanced multi-BSSID advertisements (EMA AP) to the userspace.
|
||||
* Userspace should use this attribute to configure per interface MBSSID
|
||||
* parameters.
|
||||
* See &enum nl80211_mbssid_config_attributes for details.
|
||||
*
|
||||
* @NL80211_ATTR_MBSSID_ELEMS: Nested parameter to pass multiple BSSID elements.
|
||||
* Mandatory parameter for the transmitting interface to enable MBSSID.
|
||||
* Optional for the non-transmitting interfaces.
|
||||
*
|
||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
|
@ -3096,6 +3142,9 @@ enum nl80211_attrs {
|
|||
NL80211_ATTR_COLOR_CHANGE_COLOR,
|
||||
NL80211_ATTR_COLOR_CHANGE_ELEMS,
|
||||
|
||||
NL80211_ATTR_MBSSID_CONFIG,
|
||||
NL80211_ATTR_MBSSID_ELEMS,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
|
@ -4929,6 +4978,7 @@ enum nl80211_txrate_gi {
|
|||
* @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 69.12 GHz)
|
||||
* @NL80211_BAND_6GHZ: around 6 GHz band (5.9 - 7.2 GHz)
|
||||
* @NL80211_BAND_S1GHZ: around 900MHz, supported by S1G PHYs
|
||||
* @NL80211_BAND_LC: light communication band (placeholder)
|
||||
* @NUM_NL80211_BANDS: number of bands, avoid using this in userspace
|
||||
* since newer kernel versions may support more bands
|
||||
*/
|
||||
|
@ -4938,6 +4988,7 @@ enum nl80211_band {
|
|||
NL80211_BAND_60GHZ,
|
||||
NL80211_BAND_6GHZ,
|
||||
NL80211_BAND_S1GHZ,
|
||||
NL80211_BAND_LC,
|
||||
|
||||
NUM_NL80211_BANDS,
|
||||
};
|
||||
|
@ -5995,6 +6046,11 @@ enum nl80211_feature_flags {
|
|||
* @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision
|
||||
* detection and change announcemnts.
|
||||
*
|
||||
* @NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD: Driver running in AP mode supports
|
||||
* FILS encryption and decryption for (Re)Association Request and Response
|
||||
* frames. Userspace has to share FILS AAD details to the driver by using
|
||||
* @NL80211_CMD_SET_FILS_AAD.
|
||||
*
|
||||
* @NUM_NL80211_EXT_FEATURES: number of extended features.
|
||||
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
|
||||
*/
|
||||
|
@ -6060,6 +6116,7 @@ enum nl80211_ext_feature_index {
|
|||
NL80211_EXT_FEATURE_SECURE_RTT,
|
||||
NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE,
|
||||
NL80211_EXT_FEATURE_BSS_COLOR,
|
||||
NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD,
|
||||
|
||||
/* add new features before the definition below */
|
||||
NUM_NL80211_EXT_FEATURES,
|
||||
|
@ -7349,4 +7406,60 @@ enum nl80211_sar_specs_attrs {
|
|||
NL80211_SAR_ATTR_SPECS_MAX = __NL80211_SAR_ATTR_SPECS_LAST - 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_mbssid_config_attributes - multiple BSSID (MBSSID) and enhanced
|
||||
* multi-BSSID advertisements (EMA) in AP mode.
|
||||
* Kernel uses some of these attributes to advertise driver's support for
|
||||
* MBSSID and EMA.
|
||||
* Remaining attributes should be used by the userspace to configure the
|
||||
* features.
|
||||
*
|
||||
* @__NL80211_MBSSID_CONFIG_ATTR_INVALID: Invalid
|
||||
*
|
||||
* @NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES: Used by the kernel to advertise
|
||||
* the maximum number of MBSSID interfaces supported by the driver.
|
||||
* Driver should indicate MBSSID support by setting
|
||||
* wiphy->mbssid_max_interfaces to a value more than or equal to 2.
|
||||
*
|
||||
* @NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY: Used by the kernel
|
||||
* to advertise the maximum profile periodicity supported by the driver
|
||||
* if EMA is enabled. Driver should indicate EMA support to the userspace
|
||||
* by setting wiphy->ema_max_profile_periodicity to
|
||||
* a non-zero value.
|
||||
*
|
||||
* @NL80211_MBSSID_CONFIG_ATTR_INDEX: Mandatory parameter to pass the index of
|
||||
* this BSS (u8) in the multiple BSSID set.
|
||||
* Value must be set to 0 for the transmitting interface and non-zero for
|
||||
* all non-transmitting interfaces. The userspace will be responsible
|
||||
* for using unique indices for the interfaces.
|
||||
* Range: 0 to wiphy->mbssid_max_interfaces-1.
|
||||
*
|
||||
* @NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX: Mandatory parameter for
|
||||
* a non-transmitted profile which provides the interface index (u32) of
|
||||
* the transmitted profile. The value must match one of the interface
|
||||
* indices advertised by the kernel. Optional if the interface being set up
|
||||
* is the transmitting one, however, if provided then the value must match
|
||||
* the interface index of the same.
|
||||
*
|
||||
* @NL80211_MBSSID_CONFIG_ATTR_EMA: Flag used to enable EMA AP feature.
|
||||
* Setting this flag is permitted only if the driver advertises EMA support
|
||||
* by setting wiphy->ema_max_profile_periodicity to non-zero.
|
||||
*
|
||||
* @__NL80211_MBSSID_CONFIG_ATTR_LAST: Internal
|
||||
* @NL80211_MBSSID_CONFIG_ATTR_MAX: highest attribute
|
||||
*/
|
||||
enum nl80211_mbssid_config_attributes {
|
||||
__NL80211_MBSSID_CONFIG_ATTR_INVALID,
|
||||
|
||||
NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES,
|
||||
NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY,
|
||||
NL80211_MBSSID_CONFIG_ATTR_INDEX,
|
||||
NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX,
|
||||
NL80211_MBSSID_CONFIG_ATTR_EMA,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_MBSSID_CONFIG_ATTR_LAST,
|
||||
NL80211_MBSSID_CONFIG_ATTR_MAX = __NL80211_MBSSID_CONFIG_ATTR_LAST - 1,
|
||||
};
|
||||
|
||||
#endif /* __LINUX_NL80211_H */
|
||||
|
|
|
@ -477,7 +477,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
|
|||
size_t len)
|
||||
{
|
||||
u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num;
|
||||
struct ieee802_11_elems elems = { };
|
||||
struct ieee802_11_elems *elems = NULL;
|
||||
u8 dialog_token;
|
||||
int ies_len;
|
||||
|
||||
|
@ -495,16 +495,18 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
|
|||
ies_len = len - offsetof(struct ieee80211_mgmt,
|
||||
u.action.u.addba_req.variable);
|
||||
if (ies_len) {
|
||||
ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable,
|
||||
ies_len, true, &elems, mgmt->bssid, NULL);
|
||||
if (elems.parse_error)
|
||||
return;
|
||||
elems = ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable,
|
||||
ies_len, true, mgmt->bssid, NULL);
|
||||
if (!elems || elems->parse_error)
|
||||
goto free;
|
||||
}
|
||||
|
||||
__ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
|
||||
start_seq_num, ba_policy, tid,
|
||||
buf_size, true, false,
|
||||
elems.addba_ext_ie);
|
||||
elems ? elems->addba_ext_ie : NULL);
|
||||
free:
|
||||
kfree(elems);
|
||||
}
|
||||
|
||||
void ieee80211_manage_rx_ba_offl(struct ieee80211_vif *vif,
|
||||
|
|
|
@ -111,6 +111,36 @@ static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_set_ap_mbssid_options(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_mbssid_config params)
|
||||
{
|
||||
struct ieee80211_sub_if_data *tx_sdata;
|
||||
|
||||
sdata->vif.mbssid_tx_vif = NULL;
|
||||
sdata->vif.bss_conf.bssid_index = 0;
|
||||
sdata->vif.bss_conf.nontransmitted = false;
|
||||
sdata->vif.bss_conf.ema_ap = false;
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_AP || !params.tx_wdev)
|
||||
return -EINVAL;
|
||||
|
||||
tx_sdata = IEEE80211_WDEV_TO_SUB_IF(params.tx_wdev);
|
||||
if (!tx_sdata)
|
||||
return -EINVAL;
|
||||
|
||||
if (tx_sdata == sdata) {
|
||||
sdata->vif.mbssid_tx_vif = &sdata->vif;
|
||||
} else {
|
||||
sdata->vif.mbssid_tx_vif = &tx_sdata->vif;
|
||||
sdata->vif.bss_conf.nontransmitted = true;
|
||||
sdata->vif.bss_conf.bssid_index = params.index;
|
||||
}
|
||||
if (params.ema)
|
||||
sdata->vif.bss_conf.ema_ap = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy,
|
||||
const char *name,
|
||||
unsigned char name_assign_type,
|
||||
|
@ -1105,6 +1135,14 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
|||
changed |= BSS_CHANGED_HE_BSS_COLOR;
|
||||
}
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP &&
|
||||
params->mbssid_config.tx_wdev) {
|
||||
err = ieee80211_set_ap_mbssid_options(sdata,
|
||||
params->mbssid_config);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
err = ieee80211_vif_use_channel(sdata, ¶ms->chandef,
|
||||
IEEE80211_CHANCTX_SHARED);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2016 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 - 2020 Intel Corporation
|
||||
* Copyright (C) 2018 - 2021 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
|
@ -153,20 +153,20 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf,
|
|||
rcu_read_lock();
|
||||
|
||||
p += scnprintf(p,
|
||||
bufsz+buf-p,
|
||||
bufsz + buf - p,
|
||||
"target %uus interval %uus ecn %s\n",
|
||||
codel_time_to_us(sta->cparams.target),
|
||||
codel_time_to_us(sta->cparams.interval),
|
||||
sta->cparams.ecn ? "yes" : "no");
|
||||
p += scnprintf(p,
|
||||
bufsz+buf-p,
|
||||
bufsz + buf - p,
|
||||
"tid ac backlog-bytes backlog-packets new-flows drops marks overlimit collisions tx-bytes tx-packets flags\n");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
|
||||
if (!sta->sta.txq[i])
|
||||
continue;
|
||||
txqi = to_txq_info(sta->sta.txq[i]);
|
||||
p += scnprintf(p, bufsz+buf-p,
|
||||
p += scnprintf(p, bufsz + buf - p,
|
||||
"%d %d %u %u %u %u %u %u %u %u %u 0x%lx(%s%s%s)\n",
|
||||
txqi->txq.tid,
|
||||
txqi->txq.ac,
|
||||
|
@ -314,17 +314,24 @@ STA_OPS_RW(aql);
|
|||
static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
char buf[71 + IEEE80211_NUM_TIDS * 40], *p = buf;
|
||||
char *buf, *p;
|
||||
ssize_t bufsz = 71 + IEEE80211_NUM_TIDS * 40;
|
||||
int i;
|
||||
struct sta_info *sta = file->private_data;
|
||||
struct tid_ampdu_rx *tid_rx;
|
||||
struct tid_ampdu_tx *tid_tx;
|
||||
ssize_t ret;
|
||||
|
||||
buf = kzalloc(bufsz, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
p = buf;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
p += scnprintf(p, sizeof(buf) + buf - p, "next dialog_token: %#02x\n",
|
||||
p += scnprintf(p, bufsz + buf - p, "next dialog_token: %#02x\n",
|
||||
sta->ampdu_mlme.dialog_token_allocator + 1);
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
p += scnprintf(p, bufsz + buf - p,
|
||||
"TID\t\tRX\tDTKN\tSSN\t\tTX\tDTKN\tpending\n");
|
||||
|
||||
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
|
||||
|
@ -334,25 +341,27 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
|
|||
tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[i]);
|
||||
tid_rx_valid = test_bit(i, sta->ampdu_mlme.agg_session_valid);
|
||||
|
||||
p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i);
|
||||
p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x",
|
||||
p += scnprintf(p, bufsz + buf - p, "%02d", i);
|
||||
p += scnprintf(p, bufsz + buf - p, "\t\t%x",
|
||||
tid_rx_valid);
|
||||
p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x",
|
||||
p += scnprintf(p, bufsz + buf - p, "\t%#.2x",
|
||||
tid_rx_valid ?
|
||||
sta->ampdu_mlme.tid_rx_token[i] : 0);
|
||||
p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x",
|
||||
p += scnprintf(p, bufsz + buf - p, "\t%#.3x",
|
||||
tid_rx ? tid_rx->ssn : 0);
|
||||
|
||||
p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", !!tid_tx);
|
||||
p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x",
|
||||
p += scnprintf(p, bufsz + buf - p, "\t\t%x", !!tid_tx);
|
||||
p += scnprintf(p, bufsz + buf - p, "\t%#.2x",
|
||||
tid_tx ? tid_tx->dialog_token : 0);
|
||||
p += scnprintf(p, sizeof(buf) + buf - p, "\t%03d",
|
||||
p += scnprintf(p, bufsz + buf - p, "\t%03d",
|
||||
tid_tx ? skb_queue_len(&tid_tx->pending) : 0);
|
||||
p += scnprintf(p, sizeof(buf) + buf - p, "\n");
|
||||
p += scnprintf(p, bufsz + buf - p, "\n");
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
|
||||
ret = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t sta_agg_status_write(struct file *file, const char __user *userbuf,
|
||||
|
@ -434,15 +443,22 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
|
|||
if (_cond) \
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "\t" _str "\n"); \
|
||||
} while (0)
|
||||
char buf[512], *p = buf;
|
||||
char *buf, *p;
|
||||
int i;
|
||||
ssize_t bufsz = 512;
|
||||
struct sta_info *sta = file->private_data;
|
||||
struct ieee80211_sta_ht_cap *htc = &sta->sta.ht_cap;
|
||||
ssize_t ret;
|
||||
|
||||
p += scnprintf(p, sizeof(buf) + buf - p, "ht %ssupported\n",
|
||||
buf = kzalloc(bufsz, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
p = buf;
|
||||
|
||||
p += scnprintf(p, bufsz + buf - p, "ht %ssupported\n",
|
||||
htc->ht_supported ? "" : "not ");
|
||||
if (htc->ht_supported) {
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.4x\n", htc->cap);
|
||||
p += scnprintf(p, bufsz + buf - p, "cap: %#.4x\n", htc->cap);
|
||||
|
||||
PRINT_HT_CAP((htc->cap & BIT(0)), "RX LDPC");
|
||||
PRINT_HT_CAP((htc->cap & BIT(1)), "HT20/HT40");
|
||||
|
@ -484,81 +500,90 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
|
|||
|
||||
PRINT_HT_CAP((htc->cap & BIT(15)), "L-SIG TXOP protection");
|
||||
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "ampdu factor/density: %d/%d\n",
|
||||
p += scnprintf(p, bufsz + buf - p, "ampdu factor/density: %d/%d\n",
|
||||
htc->ampdu_factor, htc->ampdu_density);
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "MCS mask:");
|
||||
p += scnprintf(p, bufsz + buf - p, "MCS mask:");
|
||||
|
||||
for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, " %.2x",
|
||||
p += scnprintf(p, bufsz + buf - p, " %.2x",
|
||||
htc->mcs.rx_mask[i]);
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "\n");
|
||||
p += scnprintf(p, bufsz + buf - p, "\n");
|
||||
|
||||
/* If not set this is meaningless */
|
||||
if (le16_to_cpu(htc->mcs.rx_highest)) {
|
||||
p += scnprintf(p, sizeof(buf)+buf-p,
|
||||
p += scnprintf(p, bufsz + buf - p,
|
||||
"MCS rx highest: %d Mbps\n",
|
||||
le16_to_cpu(htc->mcs.rx_highest));
|
||||
}
|
||||
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "MCS tx params: %x\n",
|
||||
p += scnprintf(p, bufsz + buf - p, "MCS tx params: %x\n",
|
||||
htc->mcs.tx_params);
|
||||
}
|
||||
|
||||
return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
|
||||
ret = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
STA_OPS(ht_capa);
|
||||
|
||||
static ssize_t sta_vht_capa_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
char buf[512], *p = buf;
|
||||
char *buf, *p;
|
||||
struct sta_info *sta = file->private_data;
|
||||
struct ieee80211_sta_vht_cap *vhtc = &sta->sta.vht_cap;
|
||||
ssize_t ret;
|
||||
ssize_t bufsz = 512;
|
||||
|
||||
p += scnprintf(p, sizeof(buf) + buf - p, "VHT %ssupported\n",
|
||||
buf = kzalloc(bufsz, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
p = buf;
|
||||
|
||||
p += scnprintf(p, bufsz + buf - p, "VHT %ssupported\n",
|
||||
vhtc->vht_supported ? "" : "not ");
|
||||
if (vhtc->vht_supported) {
|
||||
p += scnprintf(p, sizeof(buf) + buf - p, "cap: %#.8x\n",
|
||||
p += scnprintf(p, bufsz + buf - p, "cap: %#.8x\n",
|
||||
vhtc->cap);
|
||||
#define PFLAG(a, b) \
|
||||
do { \
|
||||
if (vhtc->cap & IEEE80211_VHT_CAP_ ## a) \
|
||||
p += scnprintf(p, sizeof(buf) + buf - p, \
|
||||
p += scnprintf(p, bufsz + buf - p, \
|
||||
"\t\t%s\n", b); \
|
||||
} while (0)
|
||||
|
||||
switch (vhtc->cap & 0x3) {
|
||||
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895:
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
p += scnprintf(p, bufsz + buf - p,
|
||||
"\t\tMAX-MPDU-3895\n");
|
||||
break;
|
||||
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991:
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
p += scnprintf(p, bufsz + buf - p,
|
||||
"\t\tMAX-MPDU-7991\n");
|
||||
break;
|
||||
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
p += scnprintf(p, bufsz + buf - p,
|
||||
"\t\tMAX-MPDU-11454\n");
|
||||
break;
|
||||
default:
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
p += scnprintf(p, bufsz + buf - p,
|
||||
"\t\tMAX-MPDU-UNKNOWN\n");
|
||||
}
|
||||
switch (vhtc->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
|
||||
case 0:
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
p += scnprintf(p, bufsz + buf - p,
|
||||
"\t\t80Mhz\n");
|
||||
break;
|
||||
case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
p += scnprintf(p, bufsz + buf - p,
|
||||
"\t\t160Mhz\n");
|
||||
break;
|
||||
case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
p += scnprintf(p, bufsz + buf - p,
|
||||
"\t\t80+80Mhz\n");
|
||||
break;
|
||||
default:
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
p += scnprintf(p, bufsz + buf - p,
|
||||
"\t\tUNKNOWN-MHZ: 0x%x\n",
|
||||
(vhtc->cap >> 2) & 0x3);
|
||||
}
|
||||
|
@ -566,15 +591,15 @@ static ssize_t sta_vht_capa_read(struct file *file, char __user *userbuf,
|
|||
PFLAG(SHORT_GI_80, "SHORT-GI-80");
|
||||
PFLAG(SHORT_GI_160, "SHORT-GI-160");
|
||||
PFLAG(TXSTBC, "TXSTBC");
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
p += scnprintf(p, bufsz + buf - p,
|
||||
"\t\tRXSTBC_%d\n", (vhtc->cap >> 8) & 0x7);
|
||||
PFLAG(SU_BEAMFORMER_CAPABLE, "SU-BEAMFORMER-CAPABLE");
|
||||
PFLAG(SU_BEAMFORMEE_CAPABLE, "SU-BEAMFORMEE-CAPABLE");
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
p += scnprintf(p, bufsz + buf - p,
|
||||
"\t\tBEAMFORMEE-STS: 0x%x\n",
|
||||
(vhtc->cap & IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK) >>
|
||||
IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
p += scnprintf(p, bufsz + buf - p,
|
||||
"\t\tSOUNDING-DIMENSIONS: 0x%x\n",
|
||||
(vhtc->cap & IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK)
|
||||
>> IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT);
|
||||
|
@ -582,34 +607,36 @@ static ssize_t sta_vht_capa_read(struct file *file, char __user *userbuf,
|
|||
PFLAG(MU_BEAMFORMEE_CAPABLE, "MU-BEAMFORMEE-CAPABLE");
|
||||
PFLAG(VHT_TXOP_PS, "TXOP-PS");
|
||||
PFLAG(HTC_VHT, "HTC-VHT");
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
p += scnprintf(p, bufsz + buf - p,
|
||||
"\t\tMPDU-LENGTH-EXPONENT: 0x%x\n",
|
||||
(vhtc->cap & IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >>
|
||||
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
|
||||
PFLAG(VHT_LINK_ADAPTATION_VHT_UNSOL_MFB,
|
||||
"LINK-ADAPTATION-VHT-UNSOL-MFB");
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
p += scnprintf(p, bufsz + buf - p,
|
||||
"\t\tLINK-ADAPTATION-VHT-MRQ-MFB: 0x%x\n",
|
||||
(vhtc->cap & IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB) >> 26);
|
||||
PFLAG(RX_ANTENNA_PATTERN, "RX-ANTENNA-PATTERN");
|
||||
PFLAG(TX_ANTENNA_PATTERN, "TX-ANTENNA-PATTERN");
|
||||
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "RX MCS: %.4x\n",
|
||||
p += scnprintf(p, bufsz + buf - p, "RX MCS: %.4x\n",
|
||||
le16_to_cpu(vhtc->vht_mcs.rx_mcs_map));
|
||||
if (vhtc->vht_mcs.rx_highest)
|
||||
p += scnprintf(p, sizeof(buf)+buf-p,
|
||||
p += scnprintf(p, bufsz + buf - p,
|
||||
"MCS RX highest: %d Mbps\n",
|
||||
le16_to_cpu(vhtc->vht_mcs.rx_highest));
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "TX MCS: %.4x\n",
|
||||
p += scnprintf(p, bufsz + buf - p, "TX MCS: %.4x\n",
|
||||
le16_to_cpu(vhtc->vht_mcs.tx_mcs_map));
|
||||
if (vhtc->vht_mcs.tx_highest)
|
||||
p += scnprintf(p, sizeof(buf)+buf-p,
|
||||
p += scnprintf(p, bufsz + buf - p,
|
||||
"MCS TX highest: %d Mbps\n",
|
||||
le16_to_cpu(vhtc->vht_mcs.tx_highest));
|
||||
#undef PFLAG
|
||||
}
|
||||
|
||||
return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
|
||||
ret = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
STA_OPS(vht_capa);
|
||||
|
||||
|
|
|
@ -219,7 +219,8 @@ int fils_encrypt_assoc_req(struct sk_buff *skb,
|
|||
{
|
||||
struct ieee80211_mgmt *mgmt = (void *)skb->data;
|
||||
u8 *capab, *ies, *encr;
|
||||
const u8 *addr[5 + 1], *session;
|
||||
const u8 *addr[5 + 1];
|
||||
const struct element *session;
|
||||
size_t len[5 + 1];
|
||||
size_t crypt_len;
|
||||
|
||||
|
@ -231,12 +232,12 @@ int fils_encrypt_assoc_req(struct sk_buff *skb,
|
|||
ies = mgmt->u.assoc_req.variable;
|
||||
}
|
||||
|
||||
session = cfg80211_find_ext_ie(WLAN_EID_EXT_FILS_SESSION,
|
||||
ies, skb->data + skb->len - ies);
|
||||
if (!session || session[1] != 1 + 8)
|
||||
session = cfg80211_find_ext_elem(WLAN_EID_EXT_FILS_SESSION,
|
||||
ies, skb->data + skb->len - ies);
|
||||
if (!session || session->datalen != 1 + 8)
|
||||
return -EINVAL;
|
||||
/* encrypt after FILS Session element */
|
||||
encr = (u8 *)session + 2 + 1 + 8;
|
||||
encr = (u8 *)session->data + 1 + 8;
|
||||
|
||||
/* AES-SIV AAD vectors */
|
||||
|
||||
|
@ -270,7 +271,8 @@ int fils_decrypt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
|||
{
|
||||
struct ieee80211_mgmt *mgmt = (void *)frame;
|
||||
u8 *capab, *ies, *encr;
|
||||
const u8 *addr[5 + 1], *session;
|
||||
const u8 *addr[5 + 1];
|
||||
const struct element *session;
|
||||
size_t len[5 + 1];
|
||||
int res;
|
||||
size_t crypt_len;
|
||||
|
@ -280,16 +282,16 @@ int fils_decrypt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
capab = (u8 *)&mgmt->u.assoc_resp.capab_info;
|
||||
ies = mgmt->u.assoc_resp.variable;
|
||||
session = cfg80211_find_ext_ie(WLAN_EID_EXT_FILS_SESSION,
|
||||
ies, frame + *frame_len - ies);
|
||||
if (!session || session[1] != 1 + 8) {
|
||||
session = cfg80211_find_ext_elem(WLAN_EID_EXT_FILS_SESSION,
|
||||
ies, frame + *frame_len - ies);
|
||||
if (!session || session->datalen != 1 + 8) {
|
||||
mlme_dbg(sdata,
|
||||
"No (valid) FILS Session element in (Re)Association Response frame from %pM",
|
||||
mgmt->sa);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* decrypt after FILS Session element */
|
||||
encr = (u8 *)session + 2 + 1 + 8;
|
||||
encr = (u8 *)session->data + 1 + 8;
|
||||
|
||||
/* AES-SIV AAD vectors */
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
* Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2016 Intel Deutschland GmbH
|
||||
* Copyright(c) 2018-2020 Intel Corporation
|
||||
* Copyright(c) 2018-2021 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
@ -1589,7 +1589,7 @@ void ieee80211_rx_mgmt_probe_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_rx_status *rx_status)
|
||||
{
|
||||
size_t baselen;
|
||||
struct ieee802_11_elems elems;
|
||||
struct ieee802_11_elems *elems;
|
||||
|
||||
BUILD_BUG_ON(offsetof(typeof(mgmt->u.probe_resp), variable) !=
|
||||
offsetof(typeof(mgmt->u.beacon), variable));
|
||||
|
@ -1602,10 +1602,14 @@ void ieee80211_rx_mgmt_probe_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
if (baselen > len)
|
||||
return;
|
||||
|
||||
ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
|
||||
false, &elems, mgmt->bssid, NULL);
|
||||
elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
|
||||
len - baselen, false,
|
||||
mgmt->bssid, NULL);
|
||||
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
|
||||
if (elems) {
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, elems);
|
||||
kfree(elems);
|
||||
}
|
||||
}
|
||||
|
||||
void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
||||
|
@ -1614,7 +1618,7 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_rx_status *rx_status;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
u16 fc;
|
||||
struct ieee802_11_elems elems;
|
||||
struct ieee802_11_elems *elems;
|
||||
int ies_len;
|
||||
|
||||
rx_status = IEEE80211_SKB_RXCB(skb);
|
||||
|
@ -1651,15 +1655,16 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
|||
if (ies_len < 0)
|
||||
break;
|
||||
|
||||
ieee802_11_parse_elems(
|
||||
elems = ieee802_11_parse_elems(
|
||||
mgmt->u.action.u.chan_switch.variable,
|
||||
ies_len, true, &elems, mgmt->bssid, NULL);
|
||||
ies_len, true, mgmt->bssid, NULL);
|
||||
|
||||
if (elems.parse_error)
|
||||
break;
|
||||
|
||||
ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len,
|
||||
rx_status, &elems);
|
||||
if (elems && !elems->parse_error)
|
||||
ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt,
|
||||
skb->len,
|
||||
rx_status,
|
||||
elems);
|
||||
kfree(elems);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -631,10 +631,9 @@ struct ieee80211_if_ocb {
|
|||
*/
|
||||
struct ieee802_11_elems;
|
||||
struct ieee80211_mesh_sync_ops {
|
||||
void (*rx_bcn_presp)(struct ieee80211_sub_if_data *sdata,
|
||||
u16 stype,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
struct ieee802_11_elems *elems,
|
||||
void (*rx_bcn_presp)(struct ieee80211_sub_if_data *sdata, u16 stype,
|
||||
struct ieee80211_mgmt *mgmt, unsigned int len,
|
||||
const struct ieee80211_meshconf_ie *mesh_cfg,
|
||||
struct ieee80211_rx_status *rx_status);
|
||||
|
||||
/* should be called with beacon_data under RCU read lock */
|
||||
|
@ -1242,6 +1241,9 @@ struct ieee80211_local {
|
|||
*/
|
||||
bool suspended;
|
||||
|
||||
/* suspending is true during the whole suspend process */
|
||||
bool suspending;
|
||||
|
||||
/*
|
||||
* Resuming is true while suspended, but when we're reprogramming the
|
||||
* hardware -- at that time it's allowed to use ieee80211_queue_work()
|
||||
|
@ -1508,6 +1510,7 @@ struct ieee80211_csa_ie {
|
|||
struct ieee802_11_elems {
|
||||
const u8 *ie_start;
|
||||
size_t total_len;
|
||||
u32 crc;
|
||||
|
||||
/* pointers to IEs */
|
||||
const struct ieee80211_tdls_lnkie *lnk_id;
|
||||
|
@ -1517,7 +1520,6 @@ struct ieee802_11_elems {
|
|||
const u8 *supp_rates;
|
||||
const u8 *ds_params;
|
||||
const struct ieee80211_tim_ie *tim;
|
||||
const u8 *challenge;
|
||||
const u8 *rsn;
|
||||
const u8 *rsnx;
|
||||
const u8 *erp_info;
|
||||
|
@ -1571,7 +1573,6 @@ struct ieee802_11_elems {
|
|||
u8 ssid_len;
|
||||
u8 supp_rates_len;
|
||||
u8 tim_len;
|
||||
u8 challenge_len;
|
||||
u8 rsn_len;
|
||||
u8 rsnx_len;
|
||||
u8 ext_supp_rates_len;
|
||||
|
@ -2194,18 +2195,18 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
|
|||
ieee80211_tx_skb_tid(sdata, skb, 7);
|
||||
}
|
||||
|
||||
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);
|
||||
static inline void ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||
bool action,
|
||||
struct ieee802_11_elems *elems,
|
||||
u8 *transmitter_bssid,
|
||||
u8 *bss_bssid)
|
||||
struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len,
|
||||
bool action,
|
||||
u64 filter, u32 crc,
|
||||
const u8 *transmitter_bssid,
|
||||
const u8 *bss_bssid);
|
||||
static inline struct ieee802_11_elems *
|
||||
ieee802_11_parse_elems(const u8 *start, size_t len, bool action,
|
||||
const u8 *transmitter_bssid,
|
||||
const u8 *bss_bssid)
|
||||
{
|
||||
ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0,
|
||||
transmitter_bssid, bss_bssid);
|
||||
return ieee802_11_parse_elems_crc(start, len, action, 0, 0,
|
||||
transmitter_bssid, bss_bssid);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -632,17 +632,46 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
|
|||
ieee80211_add_virtual_monitor(local);
|
||||
}
|
||||
|
||||
static void ieee80211_stop_mbssid(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_sub_if_data *tx_sdata, *non_tx_sdata, *tmp_sdata;
|
||||
struct ieee80211_vif *tx_vif = sdata->vif.mbssid_tx_vif;
|
||||
|
||||
if (!tx_vif)
|
||||
return;
|
||||
|
||||
tx_sdata = vif_to_sdata(tx_vif);
|
||||
sdata->vif.mbssid_tx_vif = NULL;
|
||||
|
||||
list_for_each_entry_safe(non_tx_sdata, tmp_sdata,
|
||||
&tx_sdata->local->interfaces, list) {
|
||||
if (non_tx_sdata != sdata && non_tx_sdata != tx_sdata &&
|
||||
non_tx_sdata->vif.mbssid_tx_vif == tx_vif &&
|
||||
ieee80211_sdata_running(non_tx_sdata)) {
|
||||
non_tx_sdata->vif.mbssid_tx_vif = NULL;
|
||||
dev_close(non_tx_sdata->wdev.netdev);
|
||||
}
|
||||
}
|
||||
|
||||
if (sdata != tx_sdata && ieee80211_sdata_running(tx_sdata)) {
|
||||
tx_sdata->vif.mbssid_tx_vif = NULL;
|
||||
dev_close(tx_sdata->wdev.netdev);
|
||||
}
|
||||
}
|
||||
|
||||
static int ieee80211_stop(struct net_device *dev)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
/* close all dependent VLAN interfaces before locking wiphy */
|
||||
/* close dependent VLAN and MBSSID interfaces before locking wiphy */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP) {
|
||||
struct ieee80211_sub_if_data *vlan, *tmpsdata;
|
||||
|
||||
list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
|
||||
u.vlan.list)
|
||||
dev_close(vlan->dev);
|
||||
|
||||
ieee80211_stop_mbssid(sdata);
|
||||
}
|
||||
|
||||
wiphy_lock(sdata->local->hw.wiphy);
|
||||
|
@ -1108,9 +1137,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
|||
* this interface, if it has the special null one.
|
||||
*/
|
||||
if (dev && is_zero_ether_addr(dev->dev_addr)) {
|
||||
memcpy(dev->dev_addr,
|
||||
local->hw.wiphy->perm_addr,
|
||||
ETH_ALEN);
|
||||
eth_hw_addr_set(dev, local->hw.wiphy->perm_addr);
|
||||
memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
|
||||
|
||||
if (!is_valid_ether_addr(dev->dev_addr)) {
|
||||
|
@ -1964,9 +1991,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
|||
|
||||
ieee80211_assign_perm_addr(local, ndev->perm_addr, type);
|
||||
if (is_valid_ether_addr(params->macaddr))
|
||||
memcpy(ndev->dev_addr, params->macaddr, ETH_ALEN);
|
||||
eth_hw_addr_set(ndev, params->macaddr);
|
||||
else
|
||||
memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN);
|
||||
eth_hw_addr_set(ndev, ndev->perm_addr);
|
||||
SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
|
||||
|
||||
/* don't use IEEE80211_DEV_TO_SUB_IF -- it checks too much */
|
||||
|
|
|
@ -1246,7 +1246,7 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
|
|||
struct sk_buff *presp;
|
||||
struct beacon_data *bcn;
|
||||
struct ieee80211_mgmt *hdr;
|
||||
struct ieee802_11_elems elems;
|
||||
struct ieee802_11_elems *elems;
|
||||
size_t baselen;
|
||||
u8 *pos;
|
||||
|
||||
|
@ -1255,22 +1255,24 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
|
|||
if (baselen > len)
|
||||
return;
|
||||
|
||||
ieee802_11_parse_elems(pos, len - baselen, false, &elems, mgmt->bssid,
|
||||
NULL);
|
||||
|
||||
if (!elems.mesh_id)
|
||||
elems = ieee802_11_parse_elems(pos, len - baselen, false, mgmt->bssid,
|
||||
NULL);
|
||||
if (!elems)
|
||||
return;
|
||||
|
||||
if (!elems->mesh_id)
|
||||
goto free;
|
||||
|
||||
/* 802.11-2012 10.1.4.3.2 */
|
||||
if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) &&
|
||||
!is_broadcast_ether_addr(mgmt->da)) ||
|
||||
elems.ssid_len != 0)
|
||||
return;
|
||||
elems->ssid_len != 0)
|
||||
goto free;
|
||||
|
||||
if (elems.mesh_id_len != 0 &&
|
||||
(elems.mesh_id_len != ifmsh->mesh_id_len ||
|
||||
memcmp(elems.mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len)))
|
||||
return;
|
||||
if (elems->mesh_id_len != 0 &&
|
||||
(elems->mesh_id_len != ifmsh->mesh_id_len ||
|
||||
memcmp(elems->mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len)))
|
||||
goto free;
|
||||
|
||||
rcu_read_lock();
|
||||
bcn = rcu_dereference(ifmsh->beacon);
|
||||
|
@ -1294,6 +1296,8 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
|
|||
ieee80211_tx_skb(sdata, presp);
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
free:
|
||||
kfree(elems);
|
||||
}
|
||||
|
||||
static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
|
||||
|
@ -1304,7 +1308,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
|
|||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
struct ieee802_11_elems elems;
|
||||
struct ieee802_11_elems *elems;
|
||||
struct ieee80211_channel *channel;
|
||||
size_t baselen;
|
||||
int freq;
|
||||
|
@ -1319,42 +1323,47 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
|
|||
if (baselen > len)
|
||||
return;
|
||||
|
||||
ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
|
||||
false, &elems, mgmt->bssid, NULL);
|
||||
|
||||
/* ignore non-mesh or secure / unsecure mismatch */
|
||||
if ((!elems.mesh_id || !elems.mesh_config) ||
|
||||
(elems.rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) ||
|
||||
(!elems.rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE))
|
||||
elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
|
||||
len - baselen,
|
||||
false, mgmt->bssid, NULL);
|
||||
if (!elems)
|
||||
return;
|
||||
|
||||
if (elems.ds_params)
|
||||
freq = ieee80211_channel_to_frequency(elems.ds_params[0], band);
|
||||
/* ignore non-mesh or secure / unsecure mismatch */
|
||||
if ((!elems->mesh_id || !elems->mesh_config) ||
|
||||
(elems->rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) ||
|
||||
(!elems->rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE))
|
||||
goto free;
|
||||
|
||||
if (elems->ds_params)
|
||||
freq = ieee80211_channel_to_frequency(elems->ds_params[0], band);
|
||||
else
|
||||
freq = rx_status->freq;
|
||||
|
||||
channel = ieee80211_get_channel(local->hw.wiphy, freq);
|
||||
|
||||
if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
|
||||
return;
|
||||
goto free;
|
||||
|
||||
if (mesh_matches_local(sdata, &elems)) {
|
||||
if (mesh_matches_local(sdata, elems)) {
|
||||
mpl_dbg(sdata, "rssi_threshold=%d,rx_status->signal=%d\n",
|
||||
sdata->u.mesh.mshcfg.rssi_threshold, rx_status->signal);
|
||||
if (!sdata->u.mesh.user_mpm ||
|
||||
sdata->u.mesh.mshcfg.rssi_threshold == 0 ||
|
||||
sdata->u.mesh.mshcfg.rssi_threshold < rx_status->signal)
|
||||
mesh_neighbour_update(sdata, mgmt->sa, &elems,
|
||||
mesh_neighbour_update(sdata, mgmt->sa, elems,
|
||||
rx_status);
|
||||
|
||||
if (ifmsh->csa_role != IEEE80211_MESH_CSA_ROLE_INIT &&
|
||||
!sdata->vif.csa_active)
|
||||
ieee80211_mesh_process_chnswitch(sdata, &elems, true);
|
||||
ieee80211_mesh_process_chnswitch(sdata, elems, true);
|
||||
}
|
||||
|
||||
if (ifmsh->sync_ops)
|
||||
ifmsh->sync_ops->rx_bcn_presp(sdata,
|
||||
stype, mgmt, &elems, rx_status);
|
||||
ifmsh->sync_ops->rx_bcn_presp(sdata, stype, mgmt, len,
|
||||
elems->mesh_config, rx_status);
|
||||
free:
|
||||
kfree(elems);
|
||||
}
|
||||
|
||||
int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
|
||||
|
@ -1446,7 +1455,7 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_mgmt *mgmt, size_t len)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
struct ieee802_11_elems elems;
|
||||
struct ieee802_11_elems *elems;
|
||||
u16 pre_value;
|
||||
bool fwd_csa = true;
|
||||
size_t baselen;
|
||||
|
@ -1459,33 +1468,37 @@ 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,
|
||||
mgmt->bssid, NULL);
|
||||
|
||||
if (!mesh_matches_local(sdata, &elems))
|
||||
elems = ieee802_11_parse_elems(pos, len - baselen, true,
|
||||
mgmt->bssid, NULL);
|
||||
if (!elems)
|
||||
return;
|
||||
|
||||
ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl;
|
||||
if (!mesh_matches_local(sdata, elems))
|
||||
goto free;
|
||||
|
||||
ifmsh->chsw_ttl = elems->mesh_chansw_params_ie->mesh_ttl;
|
||||
if (!--ifmsh->chsw_ttl)
|
||||
fwd_csa = false;
|
||||
|
||||
pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value);
|
||||
pre_value = le16_to_cpu(elems->mesh_chansw_params_ie->mesh_pre_value);
|
||||
if (ifmsh->pre_value >= pre_value)
|
||||
return;
|
||||
goto free;
|
||||
|
||||
ifmsh->pre_value = pre_value;
|
||||
|
||||
if (!sdata->vif.csa_active &&
|
||||
!ieee80211_mesh_process_chnswitch(sdata, &elems, false)) {
|
||||
!ieee80211_mesh_process_chnswitch(sdata, elems, false)) {
|
||||
mcsa_dbg(sdata, "Failed to process CSA action frame");
|
||||
return;
|
||||
goto free;
|
||||
}
|
||||
|
||||
/* forward or re-broadcast the CSA frame */
|
||||
if (fwd_csa) {
|
||||
if (mesh_fwd_csa_frame(sdata, mgmt, len, &elems) < 0)
|
||||
if (mesh_fwd_csa_frame(sdata, mgmt, len, elems) < 0)
|
||||
mcsa_dbg(sdata, "Failed to forward the CSA frame");
|
||||
}
|
||||
free:
|
||||
kfree(elems);
|
||||
}
|
||||
|
||||
static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2008, 2009 open80211s Ltd.
|
||||
* Copyright (C) 2019 Intel Corporation
|
||||
* Copyright (C) 2019, 2021 Intel Corporation
|
||||
* Author: Luis Carlos Cobo <luisca@cozybit.com>
|
||||
*/
|
||||
|
||||
|
@ -908,7 +908,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
|
|||
void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt, size_t len)
|
||||
{
|
||||
struct ieee802_11_elems elems;
|
||||
struct ieee802_11_elems *elems;
|
||||
size_t baselen;
|
||||
u32 path_metric;
|
||||
struct sta_info *sta;
|
||||
|
@ -926,37 +926,41 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
|
|||
rcu_read_unlock();
|
||||
|
||||
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, mgmt->bssid, NULL);
|
||||
elems = ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
|
||||
len - baselen, false, mgmt->bssid, NULL);
|
||||
if (!elems)
|
||||
return;
|
||||
|
||||
if (elems.preq) {
|
||||
if (elems.preq_len != 37)
|
||||
if (elems->preq) {
|
||||
if (elems->preq_len != 37)
|
||||
/* Right now we support just 1 destination and no AE */
|
||||
return;
|
||||
path_metric = hwmp_route_info_get(sdata, mgmt, elems.preq,
|
||||
goto free;
|
||||
path_metric = hwmp_route_info_get(sdata, mgmt, elems->preq,
|
||||
MPATH_PREQ);
|
||||
if (path_metric)
|
||||
hwmp_preq_frame_process(sdata, mgmt, elems.preq,
|
||||
hwmp_preq_frame_process(sdata, mgmt, elems->preq,
|
||||
path_metric);
|
||||
}
|
||||
if (elems.prep) {
|
||||
if (elems.prep_len != 31)
|
||||
if (elems->prep) {
|
||||
if (elems->prep_len != 31)
|
||||
/* Right now we support no AE */
|
||||
return;
|
||||
path_metric = hwmp_route_info_get(sdata, mgmt, elems.prep,
|
||||
goto free;
|
||||
path_metric = hwmp_route_info_get(sdata, mgmt, elems->prep,
|
||||
MPATH_PREP);
|
||||
if (path_metric)
|
||||
hwmp_prep_frame_process(sdata, mgmt, elems.prep,
|
||||
hwmp_prep_frame_process(sdata, mgmt, elems->prep,
|
||||
path_metric);
|
||||
}
|
||||
if (elems.perr) {
|
||||
if (elems.perr_len != 15)
|
||||
if (elems->perr) {
|
||||
if (elems->perr_len != 15)
|
||||
/* Right now we support only one destination per PERR */
|
||||
return;
|
||||
hwmp_perr_frame_process(sdata, mgmt, elems.perr);
|
||||
goto free;
|
||||
hwmp_perr_frame_process(sdata, mgmt, elems->perr);
|
||||
}
|
||||
if (elems.rann)
|
||||
hwmp_rann_frame_process(sdata, mgmt, elems.rann);
|
||||
if (elems->rann)
|
||||
hwmp_rann_frame_process(sdata, mgmt, elems->rann);
|
||||
free:
|
||||
kfree(elems);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2008, 2009 open80211s Ltd.
|
||||
* Copyright (C) 2019 Intel Corporation
|
||||
* Copyright (C) 2019, 2021 Intel Corporation
|
||||
* Author: Luis Carlos Cobo <luisca@cozybit.com>
|
||||
*/
|
||||
#include <linux/gfp.h>
|
||||
|
@ -1200,7 +1200,7 @@ void mesh_rx_plink_frame(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 ieee802_11_elems *elems;
|
||||
size_t baselen;
|
||||
u8 *baseaddr;
|
||||
|
||||
|
@ -1228,7 +1228,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
|
|||
if (baselen > len)
|
||||
return;
|
||||
}
|
||||
ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems,
|
||||
mgmt->bssid, NULL);
|
||||
mesh_process_plink_frame(sdata, mgmt, &elems, rx_status);
|
||||
elems = ieee802_11_parse_elems(baseaddr, len - baselen, true,
|
||||
mgmt->bssid, NULL);
|
||||
mesh_process_plink_frame(sdata, mgmt, elems, rx_status);
|
||||
kfree(elems);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* Copyright 2011-2012, Pavel Zubarev <pavel.zubarev@gmail.com>
|
||||
* Copyright 2011-2012, Marco Porsch <marco.porsch@s2005.tu-chemnitz.de>
|
||||
* Copyright 2011-2012, cozybit Inc.
|
||||
* Copyright (C) 2021 Intel Corporation
|
||||
*/
|
||||
|
||||
#include "ieee80211_i.h"
|
||||
|
@ -35,12 +36,12 @@ struct sync_method {
|
|||
/**
|
||||
* mesh_peer_tbtt_adjusting - check if an mp is currently adjusting its TBTT
|
||||
*
|
||||
* @ie: information elements of a management frame from the mesh peer
|
||||
* @cfg: mesh config element from the mesh peer (or %NULL)
|
||||
*/
|
||||
static bool mesh_peer_tbtt_adjusting(struct ieee802_11_elems *ie)
|
||||
static bool mesh_peer_tbtt_adjusting(const struct ieee80211_meshconf_ie *cfg)
|
||||
{
|
||||
return (ie->mesh_config->meshconf_cap &
|
||||
IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING) != 0;
|
||||
return cfg &&
|
||||
(cfg->meshconf_cap & IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING);
|
||||
}
|
||||
|
||||
void mesh_sync_adjust_tsf(struct ieee80211_sub_if_data *sdata)
|
||||
|
@ -76,11 +77,11 @@ void mesh_sync_adjust_tsf(struct ieee80211_sub_if_data *sdata)
|
|||
}
|
||||
}
|
||||
|
||||
static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
|
||||
u16 stype,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
struct ieee802_11_elems *elems,
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
static void
|
||||
mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, u16 stype,
|
||||
struct ieee80211_mgmt *mgmt, unsigned int len,
|
||||
const struct ieee80211_meshconf_ie *mesh_cfg,
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
@ -101,10 +102,7 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
|
|||
*/
|
||||
if (ieee80211_have_rx_timestamp(rx_status))
|
||||
t_r = ieee80211_calculate_rx_timestamp(local, rx_status,
|
||||
24 + 12 +
|
||||
elems->total_len +
|
||||
FCS_LEN,
|
||||
24);
|
||||
len + FCS_LEN, 24);
|
||||
else
|
||||
t_r = drv_get_tsf(local, sdata);
|
||||
|
||||
|
@ -119,7 +117,7 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
|
|||
* dot11MeshNbrOffsetMaxNeighbor non-peer non-MBSS neighbors
|
||||
*/
|
||||
|
||||
if (elems->mesh_config && mesh_peer_tbtt_adjusting(elems)) {
|
||||
if (mesh_peer_tbtt_adjusting(mesh_cfg)) {
|
||||
msync_dbg(sdata, "STA %pM : is adjusting TBTT\n",
|
||||
sta->sta.addr);
|
||||
goto no_sync;
|
||||
|
|
|
@ -1490,6 +1490,7 @@ ieee80211_find_80211h_pwr_constr(struct ieee80211_sub_if_data *sdata,
|
|||
fallthrough;
|
||||
case NL80211_BAND_2GHZ:
|
||||
case NL80211_BAND_60GHZ:
|
||||
case NL80211_BAND_LC:
|
||||
chan_increment = 1;
|
||||
break;
|
||||
case NL80211_BAND_5GHZ:
|
||||
|
@ -2258,6 +2259,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
|||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
|
||||
u32 changed = 0;
|
||||
struct ieee80211_prep_tx_info info = {
|
||||
.subtype = stype,
|
||||
|
@ -2407,6 +2409,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
|||
cancel_delayed_work_sync(&ifmgd->tx_tspec_wk);
|
||||
|
||||
sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
|
||||
|
||||
bss_conf->pwr_reduction = 0;
|
||||
bss_conf->tx_pwr_env_num = 0;
|
||||
memset(bss_conf->tx_pwr_env, 0, sizeof(bss_conf->tx_pwr_env));
|
||||
}
|
||||
|
||||
static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
|
||||
|
@ -2509,7 +2515,7 @@ static void ieee80211_mlme_send_probe_req(struct ieee80211_sub_if_data *sdata,
|
|||
static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
const u8 *ssid;
|
||||
const struct element *ssid;
|
||||
u8 *dst = ifmgd->associated->bssid;
|
||||
u8 unicast_limit = max(1, max_probe_tries - 3);
|
||||
struct sta_info *sta;
|
||||
|
@ -2546,14 +2552,14 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
|
|||
int ssid_len;
|
||||
|
||||
rcu_read_lock();
|
||||
ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
|
||||
ssid = ieee80211_bss_get_elem(ifmgd->associated, WLAN_EID_SSID);
|
||||
if (WARN_ON_ONCE(ssid == NULL))
|
||||
ssid_len = 0;
|
||||
else
|
||||
ssid_len = ssid[1];
|
||||
ssid_len = ssid->datalen;
|
||||
|
||||
ieee80211_mlme_send_probe_req(sdata, sdata->vif.addr, dst,
|
||||
ssid + 2, ssid_len,
|
||||
ssid->data, ssid_len,
|
||||
ifmgd->associated->channel);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
@ -2583,6 +2589,13 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (sdata->local->suspending) {
|
||||
/* reschedule after resume */
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
ieee80211_reset_ap_probe(sdata);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (beacon) {
|
||||
mlme_dbg_ratelimited(sdata,
|
||||
"detected beacon loss from AP (missed %d beacons) - probing\n",
|
||||
|
@ -2629,7 +2642,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
|
|||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
struct cfg80211_bss *cbss;
|
||||
struct sk_buff *skb;
|
||||
const u8 *ssid;
|
||||
const struct element *ssid;
|
||||
int ssid_len;
|
||||
|
||||
if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
|
||||
|
@ -2647,16 +2660,17 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
|
|||
return NULL;
|
||||
|
||||
rcu_read_lock();
|
||||
ssid = ieee80211_bss_get_ie(cbss, WLAN_EID_SSID);
|
||||
if (WARN_ONCE(!ssid || ssid[1] > IEEE80211_MAX_SSID_LEN,
|
||||
"invalid SSID element (len=%d)", ssid ? ssid[1] : -1))
|
||||
ssid = ieee80211_bss_get_elem(cbss, WLAN_EID_SSID);
|
||||
if (WARN_ONCE(!ssid || ssid->datalen > IEEE80211_MAX_SSID_LEN,
|
||||
"invalid SSID element (len=%d)",
|
||||
ssid ? ssid->datalen : -1))
|
||||
ssid_len = 0;
|
||||
else
|
||||
ssid_len = ssid[1];
|
||||
ssid_len = ssid->datalen;
|
||||
|
||||
skb = ieee80211_build_probe_req(sdata, sdata->vif.addr, cbss->bssid,
|
||||
(u32) -1, cbss->channel,
|
||||
ssid + 2, ssid_len,
|
||||
ssid->data, ssid_len,
|
||||
NULL, 0, IEEE80211_PROBE_FLAG_DIRECTED);
|
||||
rcu_read_unlock();
|
||||
|
||||
|
@ -2870,17 +2884,17 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
|
|||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data;
|
||||
const struct element *challenge;
|
||||
u8 *pos;
|
||||
struct ieee802_11_elems elems;
|
||||
u32 tx_flags = 0;
|
||||
struct ieee80211_prep_tx_info info = {
|
||||
.subtype = IEEE80211_STYPE_AUTH,
|
||||
};
|
||||
|
||||
pos = mgmt->u.auth.variable;
|
||||
ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems,
|
||||
mgmt->bssid, auth_data->bss->bssid);
|
||||
if (!elems.challenge)
|
||||
challenge = cfg80211_find_elem(WLAN_EID_CHALLENGE, pos,
|
||||
len - (pos - (u8 *)mgmt));
|
||||
if (!challenge)
|
||||
return;
|
||||
auth_data->expected_transaction = 4;
|
||||
drv_mgd_prepare_tx(sdata->local, sdata, &info);
|
||||
|
@ -2888,7 +2902,8 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
|
|||
tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
|
||||
IEEE80211_TX_INTFL_MLME_CONN_TX;
|
||||
ieee80211_send_auth(sdata, 3, auth_data->algorithm, 0,
|
||||
elems.challenge - 2, elems.challenge_len + 2,
|
||||
(void *)challenge,
|
||||
challenge->datalen + sizeof(*challenge),
|
||||
auth_data->bss->bssid, auth_data->bss->bssid,
|
||||
auth_data->key, auth_data->key_len,
|
||||
auth_data->key_idx, tx_flags);
|
||||
|
@ -3290,8 +3305,11 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
|||
aid = 0; /* TODO */
|
||||
}
|
||||
capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
|
||||
ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, elems,
|
||||
mgmt->bssid, assoc_data->bss->bssid);
|
||||
elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false,
|
||||
mgmt->bssid, assoc_data->bss->bssid);
|
||||
|
||||
if (!elems)
|
||||
return false;
|
||||
|
||||
if (elems->aid_resp)
|
||||
aid = le16_to_cpu(elems->aid_resp->aid);
|
||||
|
@ -3313,7 +3331,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
if (!is_s1g && !elems->supp_rates) {
|
||||
sdata_info(sdata, "no SuppRates element in AssocResp\n");
|
||||
return false;
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sdata->vif.bss_conf.aid = aid;
|
||||
|
@ -3335,7 +3354,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
|||
(!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
|
||||
(!elems->vht_cap_elem || !elems->vht_operation)))) {
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
struct ieee802_11_elems bss_elems;
|
||||
struct ieee802_11_elems *bss_elems;
|
||||
|
||||
rcu_read_lock();
|
||||
ies = rcu_dereference(cbss->ies);
|
||||
|
@ -3343,16 +3362,22 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
|||
bss_ies = kmemdup(ies, sizeof(*ies) + ies->len,
|
||||
GFP_ATOMIC);
|
||||
rcu_read_unlock();
|
||||
if (!bss_ies)
|
||||
return false;
|
||||
if (!bss_ies) {
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bss_elems = ieee802_11_parse_elems(bss_ies->data, bss_ies->len,
|
||||
false, mgmt->bssid,
|
||||
assoc_data->bss->bssid);
|
||||
if (!bss_elems) {
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ieee802_11_parse_elems(bss_ies->data, bss_ies->len,
|
||||
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;
|
||||
!elems->wmm_param && bss_elems->wmm_param) {
|
||||
elems->wmm_param = bss_elems->wmm_param;
|
||||
sdata_info(sdata,
|
||||
"AP bug: WMM param missing from AssocResp\n");
|
||||
}
|
||||
|
@ -3361,30 +3386,32 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
|||
* Also check if we requested HT/VHT, otherwise the AP doesn't
|
||||
* have to include the IEs in the (re)association response.
|
||||
*/
|
||||
if (!elems->ht_cap_elem && bss_elems.ht_cap_elem &&
|
||||
if (!elems->ht_cap_elem && bss_elems->ht_cap_elem &&
|
||||
!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
|
||||
elems->ht_cap_elem = bss_elems.ht_cap_elem;
|
||||
elems->ht_cap_elem = bss_elems->ht_cap_elem;
|
||||
sdata_info(sdata,
|
||||
"AP bug: HT capability missing from AssocResp\n");
|
||||
}
|
||||
if (!elems->ht_operation && bss_elems.ht_operation &&
|
||||
if (!elems->ht_operation && bss_elems->ht_operation &&
|
||||
!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
|
||||
elems->ht_operation = bss_elems.ht_operation;
|
||||
elems->ht_operation = bss_elems->ht_operation;
|
||||
sdata_info(sdata,
|
||||
"AP bug: HT operation missing from AssocResp\n");
|
||||
}
|
||||
if (!elems->vht_cap_elem && bss_elems.vht_cap_elem &&
|
||||
if (!elems->vht_cap_elem && bss_elems->vht_cap_elem &&
|
||||
!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) {
|
||||
elems->vht_cap_elem = bss_elems.vht_cap_elem;
|
||||
elems->vht_cap_elem = bss_elems->vht_cap_elem;
|
||||
sdata_info(sdata,
|
||||
"AP bug: VHT capa missing from AssocResp\n");
|
||||
}
|
||||
if (!elems->vht_operation && bss_elems.vht_operation &&
|
||||
if (!elems->vht_operation && bss_elems->vht_operation &&
|
||||
!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) {
|
||||
elems->vht_operation = bss_elems.vht_operation;
|
||||
elems->vht_operation = bss_elems->vht_operation;
|
||||
sdata_info(sdata,
|
||||
"AP bug: VHT operation missing from AssocResp\n");
|
||||
}
|
||||
|
||||
kfree(bss_elems);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3629,6 +3656,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
ret = true;
|
||||
out:
|
||||
kfree(elems);
|
||||
kfree(bss_ies);
|
||||
return ret;
|
||||
}
|
||||
|
@ -3640,7 +3668,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
|
||||
u16 capab_info, status_code, aid;
|
||||
struct ieee802_11_elems elems;
|
||||
struct ieee802_11_elems *elems;
|
||||
int ac, uapsd_queues = -1;
|
||||
u8 *pos;
|
||||
bool reassoc;
|
||||
|
@ -3697,14 +3725,16 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
|||
fils_decrypt_assoc_resp(sdata, (u8 *)mgmt, &len, assoc_data) < 0)
|
||||
return;
|
||||
|
||||
ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems,
|
||||
mgmt->bssid, assoc_data->bss->bssid);
|
||||
elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false,
|
||||
mgmt->bssid, assoc_data->bss->bssid);
|
||||
if (!elems)
|
||||
goto notify_driver;
|
||||
|
||||
if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
|
||||
elems.timeout_int &&
|
||||
elems.timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) {
|
||||
elems->timeout_int &&
|
||||
elems->timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) {
|
||||
u32 tu, ms;
|
||||
tu = le32_to_cpu(elems.timeout_int->value);
|
||||
tu = le32_to_cpu(elems->timeout_int->value);
|
||||
ms = tu * 1024 / 1000;
|
||||
sdata_info(sdata,
|
||||
"%pM rejected association temporarily; comeback duration %u TU (%u ms)\n",
|
||||
|
@ -3724,7 +3754,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
|||
event.u.mlme.reason = status_code;
|
||||
drv_event_callback(sdata->local, sdata, &event);
|
||||
} else {
|
||||
if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, &elems)) {
|
||||
if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, elems)) {
|
||||
/* oops -- internal error -- send timeout for now */
|
||||
ieee80211_destroy_assoc_data(sdata, false, false);
|
||||
cfg80211_assoc_timeout(sdata->dev, cbss);
|
||||
|
@ -3754,6 +3784,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
|||
ifmgd->assoc_req_ies, ifmgd->assoc_req_ies_len);
|
||||
notify_driver:
|
||||
drv_mgd_complete_tx(sdata->local, sdata, &info);
|
||||
kfree(elems);
|
||||
}
|
||||
|
||||
static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
|
@ -3958,7 +3989,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
|
||||
struct ieee80211_mgmt *mgmt = (void *) hdr;
|
||||
size_t baselen;
|
||||
struct ieee802_11_elems elems;
|
||||
struct ieee802_11_elems *elems;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
struct ieee80211_channel *chan;
|
||||
|
@ -4004,15 +4035,16 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon &&
|
||||
ieee80211_rx_our_beacon(bssid, ifmgd->assoc_data->bss)) {
|
||||
ieee802_11_parse_elems(variable,
|
||||
len - baselen, false, &elems,
|
||||
bssid,
|
||||
ifmgd->assoc_data->bss->bssid);
|
||||
elems = ieee802_11_parse_elems(variable, len - baselen, false,
|
||||
bssid,
|
||||
ifmgd->assoc_data->bss->bssid);
|
||||
if (!elems)
|
||||
return;
|
||||
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status);
|
||||
|
||||
if (elems.dtim_period)
|
||||
ifmgd->dtim_period = elems.dtim_period;
|
||||
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)) {
|
||||
|
@ -4020,17 +4052,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;
|
||||
sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count;
|
||||
sdata->vif.bss_conf.sync_dtim_count = elems->dtim_count;
|
||||
}
|
||||
|
||||
if (elems.mbssid_config_ie)
|
||||
if (elems->mbssid_config_ie)
|
||||
bss_conf->profile_periodicity =
|
||||
elems.mbssid_config_ie->profile_periodicity;
|
||||
elems->mbssid_config_ie->profile_periodicity;
|
||||
else
|
||||
bss_conf->profile_periodicity = 0;
|
||||
|
||||
if (elems.ext_capab_len >= 11 &&
|
||||
(elems.ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT))
|
||||
if (elems->ext_capab_len >= 11 &&
|
||||
(elems->ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT))
|
||||
bss_conf->ema_ap = true;
|
||||
else
|
||||
bss_conf->ema_ap = false;
|
||||
|
@ -4039,6 +4071,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
ifmgd->assoc_data->timeout = jiffies;
|
||||
ifmgd->assoc_data->timeout_started = true;
|
||||
run_again(sdata, ifmgd->assoc_data->timeout);
|
||||
kfree(elems);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4070,13 +4103,15 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
*/
|
||||
if (!ieee80211_is_s1g_beacon(hdr->frame_control))
|
||||
ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
|
||||
ncrc = ieee802_11_parse_elems_crc(variable,
|
||||
len - baselen, false, &elems,
|
||||
care_about_ies, ncrc,
|
||||
mgmt->bssid, bssid);
|
||||
elems = ieee802_11_parse_elems_crc(variable, len - baselen,
|
||||
false, care_about_ies, ncrc,
|
||||
mgmt->bssid, bssid);
|
||||
if (!elems)
|
||||
return;
|
||||
ncrc = elems->crc;
|
||||
|
||||
if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
|
||||
ieee80211_check_tim(elems.tim, elems.tim_len, bss_conf->aid)) {
|
||||
ieee80211_check_tim(elems->tim, elems->tim_len, bss_conf->aid)) {
|
||||
if (local->hw.conf.dynamic_ps_timeout > 0) {
|
||||
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
|
||||
local->hw.conf.flags &= ~IEEE80211_CONF_PS;
|
||||
|
@ -4146,12 +4181,12 @@ 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;
|
||||
sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count;
|
||||
sdata->vif.bss_conf.sync_dtim_count = elems->dtim_count;
|
||||
}
|
||||
|
||||
if ((ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) ||
|
||||
ieee80211_is_s1g_short_beacon(mgmt->frame_control))
|
||||
return;
|
||||
goto free;
|
||||
ifmgd->beacon_crc = ncrc;
|
||||
ifmgd->beacon_crc_valid = true;
|
||||
|
||||
|
@ -4159,12 +4194,12 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
|
||||
rx_status->device_timestamp,
|
||||
&elems, true);
|
||||
elems, true);
|
||||
|
||||
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) &&
|
||||
ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
|
||||
elems.wmm_param_len,
|
||||
elems.mu_edca_param_set))
|
||||
ieee80211_sta_wmm_params(local, sdata, elems->wmm_param,
|
||||
elems->wmm_param_len,
|
||||
elems->mu_edca_param_set))
|
||||
changed |= BSS_CHANGED_QOS;
|
||||
|
||||
/*
|
||||
|
@ -4173,7 +4208,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 */
|
||||
bss_conf->dtim_period = elems.dtim_period ?: 1;
|
||||
bss_conf->dtim_period = elems->dtim_period ?: 1;
|
||||
|
||||
changed |= BSS_CHANGED_BEACON_INFO;
|
||||
ifmgd->have_beacon = true;
|
||||
|
@ -4185,9 +4220,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
ieee80211_recalc_ps_vif(sdata);
|
||||
}
|
||||
|
||||
if (elems.erp_info) {
|
||||
if (elems->erp_info) {
|
||||
erp_valid = true;
|
||||
erp_value = elems.erp_info[0];
|
||||
erp_value = elems->erp_info[0];
|
||||
} else {
|
||||
erp_valid = false;
|
||||
}
|
||||
|
@ -4200,12 +4235,12 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
mutex_lock(&local->sta_mtx);
|
||||
sta = sta_info_get(sdata, bssid);
|
||||
|
||||
changed |= ieee80211_recalc_twt_req(sdata, sta, &elems);
|
||||
changed |= ieee80211_recalc_twt_req(sdata, sta, elems);
|
||||
|
||||
if (ieee80211_config_bw(sdata, sta, elems.ht_cap_elem,
|
||||
elems.vht_cap_elem, elems.ht_operation,
|
||||
elems.vht_operation, elems.he_operation,
|
||||
elems.s1g_oper, bssid, &changed)) {
|
||||
if (ieee80211_config_bw(sdata, sta, elems->ht_cap_elem,
|
||||
elems->vht_cap_elem, elems->ht_operation,
|
||||
elems->vht_operation, elems->he_operation,
|
||||
elems->s1g_oper, bssid, &changed)) {
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
sdata_info(sdata,
|
||||
"failed to follow AP %pM bandwidth change, disconnect\n",
|
||||
|
@ -4217,21 +4252,23 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
sizeof(deauth_buf), true,
|
||||
WLAN_REASON_DEAUTH_LEAVING,
|
||||
false);
|
||||
return;
|
||||
goto free;
|
||||
}
|
||||
|
||||
if (sta && elems.opmode_notif)
|
||||
ieee80211_vht_handle_opmode(sdata, sta, *elems.opmode_notif,
|
||||
if (sta && elems->opmode_notif)
|
||||
ieee80211_vht_handle_opmode(sdata, sta, *elems->opmode_notif,
|
||||
rx_status->band);
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
|
||||
changed |= ieee80211_handle_pwr_constr(sdata, chan, mgmt,
|
||||
elems.country_elem,
|
||||
elems.country_elem_len,
|
||||
elems.pwr_constr_elem,
|
||||
elems.cisco_dtpc_elem);
|
||||
elems->country_elem,
|
||||
elems->country_elem_len,
|
||||
elems->pwr_constr_elem,
|
||||
elems->cisco_dtpc_elem);
|
||||
|
||||
ieee80211_bss_info_change_notify(sdata, changed);
|
||||
free:
|
||||
kfree(elems);
|
||||
}
|
||||
|
||||
void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata,
|
||||
|
@ -4260,7 +4297,6 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_rx_status *rx_status;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
u16 fc;
|
||||
struct ieee802_11_elems elems;
|
||||
int ies_len;
|
||||
|
||||
rx_status = (struct ieee80211_rx_status *) skb->cb;
|
||||
|
@ -4292,6 +4328,8 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
|||
break;
|
||||
case IEEE80211_STYPE_ACTION:
|
||||
if (mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) {
|
||||
struct ieee802_11_elems *elems;
|
||||
|
||||
ies_len = skb->len -
|
||||
offsetof(struct ieee80211_mgmt,
|
||||
u.action.u.chan_switch.variable);
|
||||
|
@ -4300,18 +4338,19 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
|||
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, mgmt->bssid, NULL);
|
||||
elems = ieee802_11_parse_elems(
|
||||
mgmt->u.action.u.chan_switch.variable,
|
||||
ies_len, true, mgmt->bssid, NULL);
|
||||
|
||||
if (elems.parse_error)
|
||||
break;
|
||||
|
||||
ieee80211_sta_process_chanswitch(sdata,
|
||||
rx_status->mactime,
|
||||
rx_status->device_timestamp,
|
||||
&elems, false);
|
||||
if (elems && !elems->parse_error)
|
||||
ieee80211_sta_process_chanswitch(sdata,
|
||||
rx_status->mactime,
|
||||
rx_status->device_timestamp,
|
||||
elems, false);
|
||||
kfree(elems);
|
||||
} else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) {
|
||||
struct ieee802_11_elems *elems;
|
||||
|
||||
ies_len = skb->len -
|
||||
offsetof(struct ieee80211_mgmt,
|
||||
u.action.u.ext_chan_switch.variable);
|
||||
|
@ -4323,21 +4362,22 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
|||
* 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, mgmt->bssid, NULL);
|
||||
elems = ieee802_11_parse_elems(
|
||||
mgmt->u.action.u.ext_chan_switch.variable,
|
||||
ies_len, true, mgmt->bssid, NULL);
|
||||
|
||||
if (elems.parse_error)
|
||||
break;
|
||||
if (elems && !elems->parse_error) {
|
||||
/* for the handling code pretend it was an IE */
|
||||
elems->ext_chansw_ie =
|
||||
&mgmt->u.action.u.ext_chan_switch.data;
|
||||
|
||||
/* for the handling code pretend this was also an IE */
|
||||
elems.ext_chansw_ie =
|
||||
&mgmt->u.action.u.ext_chan_switch.data;
|
||||
ieee80211_sta_process_chanswitch(sdata,
|
||||
rx_status->mactime,
|
||||
rx_status->device_timestamp,
|
||||
elems, false);
|
||||
}
|
||||
|
||||
ieee80211_sta_process_chanswitch(sdata,
|
||||
rx_status->mactime,
|
||||
rx_status->device_timestamp,
|
||||
&elems, false);
|
||||
kfree(elems);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -4972,10 +5012,22 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
|
|||
bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ;
|
||||
bool is_5ghz = cbss->channel->band == NL80211_BAND_5GHZ;
|
||||
struct ieee80211_bss *bss = (void *)cbss->priv;
|
||||
struct ieee802_11_elems *elems;
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
int ret;
|
||||
u32 i;
|
||||
bool have_80mhz;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
ies = rcu_dereference(cbss->ies);
|
||||
elems = ieee802_11_parse_elems(ies->data, ies->len, false,
|
||||
NULL, NULL);
|
||||
if (!elems) {
|
||||
rcu_read_unlock();
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sband = local->hw.wiphy->bands[cbss->channel->band];
|
||||
|
||||
ifmgd->flags &= ~(IEEE80211_STA_DISABLE_40MHZ |
|
||||
|
@ -4998,18 +5050,9 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
|
|||
ieee80211_vif_type_p2p(&sdata->vif)))
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && !is_6ghz) {
|
||||
const u8 *ht_oper_ie, *ht_cap_ie;
|
||||
|
||||
ht_oper_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_OPERATION);
|
||||
if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper))
|
||||
ht_oper = (void *)(ht_oper_ie + 2);
|
||||
|
||||
ht_cap_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_CAPABILITY);
|
||||
if (ht_cap_ie && ht_cap_ie[1] >= sizeof(*ht_cap))
|
||||
ht_cap = (void *)(ht_cap_ie + 2);
|
||||
ht_oper = elems->ht_operation;
|
||||
ht_cap = elems->ht_cap_elem;
|
||||
|
||||
if (!ht_cap) {
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
|
||||
|
@ -5018,12 +5061,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && !is_6ghz) {
|
||||
const u8 *vht_oper_ie, *vht_cap;
|
||||
|
||||
vht_oper_ie = ieee80211_bss_get_ie(cbss,
|
||||
WLAN_EID_VHT_OPERATION);
|
||||
if (vht_oper_ie && vht_oper_ie[1] >= sizeof(*vht_oper))
|
||||
vht_oper = (void *)(vht_oper_ie + 2);
|
||||
vht_oper = elems->vht_operation;
|
||||
if (vht_oper && !ht_oper) {
|
||||
vht_oper = NULL;
|
||||
sdata_info(sdata,
|
||||
|
@ -5033,25 +5071,38 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
|
|||
ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
|
||||
}
|
||||
|
||||
vht_cap = ieee80211_bss_get_ie(cbss, WLAN_EID_VHT_CAPABILITY);
|
||||
if (!vht_cap || vht_cap[1] < sizeof(struct ieee80211_vht_cap)) {
|
||||
if (!elems->vht_cap_elem) {
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
|
||||
vht_oper = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE)) {
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
const u8 *he_oper_ie;
|
||||
he_oper = elems->he_operation;
|
||||
|
||||
ies = rcu_dereference(cbss->ies);
|
||||
he_oper_ie = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_OPERATION,
|
||||
ies->data, ies->len);
|
||||
if (he_oper_ie &&
|
||||
he_oper_ie[1] >= ieee80211_he_oper_size(&he_oper_ie[3]))
|
||||
he_oper = (void *)(he_oper_ie + 3);
|
||||
else
|
||||
he_oper = NULL;
|
||||
if (is_6ghz) {
|
||||
struct ieee80211_bss_conf *bss_conf;
|
||||
u8 i, j = 0;
|
||||
|
||||
bss_conf = &sdata->vif.bss_conf;
|
||||
|
||||
if (elems->pwr_constr_elem)
|
||||
bss_conf->pwr_reduction = *elems->pwr_constr_elem;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(bss_conf->tx_pwr_env) !=
|
||||
ARRAY_SIZE(elems->tx_pwr_env));
|
||||
|
||||
for (i = 0; i < elems->tx_pwr_env_num; i++) {
|
||||
if (elems->tx_pwr_env_len[i] >
|
||||
sizeof(bss_conf->tx_pwr_env[j]))
|
||||
continue;
|
||||
|
||||
bss_conf->tx_pwr_env_num++;
|
||||
memcpy(&bss_conf->tx_pwr_env[j], elems->tx_pwr_env[i],
|
||||
elems->tx_pwr_env_len[i]);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ieee80211_verify_sta_he_mcs_support(sdata, sband, he_oper))
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
|
||||
|
@ -5072,13 +5123,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
|
|||
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
|
||||
|
||||
if (sband->band == NL80211_BAND_S1GHZ) {
|
||||
const u8 *s1g_oper_ie;
|
||||
|
||||
s1g_oper_ie = ieee80211_bss_get_ie(cbss,
|
||||
WLAN_EID_S1G_OPERATION);
|
||||
if (s1g_oper_ie && s1g_oper_ie[1] >= sizeof(*s1g_oper))
|
||||
s1g_oper = (void *)(s1g_oper_ie + 2);
|
||||
else
|
||||
s1g_oper = elems->s1g_oper;
|
||||
if (!s1g_oper)
|
||||
sdata_info(sdata,
|
||||
"AP missing S1G operation element?\n");
|
||||
}
|
||||
|
@ -5094,6 +5140,9 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
|
|||
local->rx_chains);
|
||||
|
||||
rcu_read_unlock();
|
||||
/* the element data was RCU protected so no longer valid anyway */
|
||||
kfree(elems);
|
||||
elems = NULL;
|
||||
|
||||
if (ifmgd->flags & IEEE80211_STA_DISABLE_HE && is_6ghz) {
|
||||
sdata_info(sdata, "Rejecting non-HE 6/7 GHz connection");
|
||||
|
@ -5498,7 +5547,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
|||
const struct cfg80211_bss_ies *beacon_ies;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
|
||||
const u8 *ssidie, *ht_ie, *vht_ie;
|
||||
const struct element *ssid_elem, *ht_elem, *vht_elem;
|
||||
int i, err;
|
||||
bool override = false;
|
||||
|
||||
|
@ -5507,14 +5556,14 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
|||
return -ENOMEM;
|
||||
|
||||
rcu_read_lock();
|
||||
ssidie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
|
||||
if (!ssidie || ssidie[1] > sizeof(assoc_data->ssid)) {
|
||||
ssid_elem = ieee80211_bss_get_elem(req->bss, WLAN_EID_SSID);
|
||||
if (!ssid_elem || ssid_elem->datalen > sizeof(assoc_data->ssid)) {
|
||||
rcu_read_unlock();
|
||||
kfree(assoc_data);
|
||||
return -EINVAL;
|
||||
}
|
||||
memcpy(assoc_data->ssid, ssidie + 2, ssidie[1]);
|
||||
assoc_data->ssid_len = ssidie[1];
|
||||
memcpy(assoc_data->ssid, ssid_elem->data, ssid_elem->datalen);
|
||||
assoc_data->ssid_len = ssid_elem->datalen;
|
||||
memcpy(bss_conf->ssid, assoc_data->ssid, assoc_data->ssid_len);
|
||||
bss_conf->ssid_len = assoc_data->ssid_len;
|
||||
rcu_read_unlock();
|
||||
|
@ -5628,15 +5677,15 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
|||
assoc_data->supp_rates_len = bss->supp_rates_len;
|
||||
|
||||
rcu_read_lock();
|
||||
ht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION);
|
||||
if (ht_ie && ht_ie[1] >= sizeof(struct ieee80211_ht_operation))
|
||||
ht_elem = ieee80211_bss_get_elem(req->bss, WLAN_EID_HT_OPERATION);
|
||||
if (ht_elem && ht_elem->datalen >= sizeof(struct ieee80211_ht_operation))
|
||||
assoc_data->ap_ht_param =
|
||||
((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param;
|
||||
((struct ieee80211_ht_operation *)(ht_elem->data))->ht_param;
|
||||
else if (!is_6ghz)
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
|
||||
vht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_VHT_CAPABILITY);
|
||||
if (vht_ie && vht_ie[1] >= sizeof(struct ieee80211_vht_cap))
|
||||
memcpy(&assoc_data->ap_vht_cap, vht_ie + 2,
|
||||
vht_elem = ieee80211_bss_get_elem(req->bss, WLAN_EID_VHT_CAPABILITY);
|
||||
if (vht_elem && vht_elem->datalen >= sizeof(struct ieee80211_vht_cap))
|
||||
memcpy(&assoc_data->ap_vht_cap, vht_elem->data,
|
||||
sizeof(struct ieee80211_vht_cap));
|
||||
else if (is_5ghz)
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT |
|
||||
|
|
|
@ -27,6 +27,9 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
|||
if (!local->open_count)
|
||||
goto suspend;
|
||||
|
||||
local->suspending = true;
|
||||
mb(); /* make suspending visible before any cancellation */
|
||||
|
||||
ieee80211_scan_cancel(local);
|
||||
|
||||
ieee80211_dfs_cac_cancel(local);
|
||||
|
@ -176,6 +179,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
|||
/* need suspended to be visible before quiescing is false */
|
||||
barrier();
|
||||
local->quiescing = false;
|
||||
local->suspending = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -3216,10 +3216,7 @@ static bool
|
|||
ieee80211_process_rx_twt_action(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)rx->skb->data;
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
||||
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
||||
const struct ieee80211_sta_he_cap *hecap;
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
/* TWT actions are only supported in AP for the moment */
|
||||
if (sdata->vif.type != NL80211_IFTYPE_AP)
|
||||
|
@ -3228,14 +3225,7 @@ ieee80211_process_rx_twt_action(struct ieee80211_rx_data *rx)
|
|||
if (!rx->local->ops->add_twt_setup)
|
||||
return false;
|
||||
|
||||
sband = rx->local->hw.wiphy->bands[status->band];
|
||||
hecap = ieee80211_get_he_iftype_cap(sband,
|
||||
ieee80211_vif_type_p2p(&sdata->vif));
|
||||
if (!hecap)
|
||||
return false;
|
||||
|
||||
if (!(hecap->he_cap_elem.mac_cap_info[0] &
|
||||
IEEE80211_HE_MAC_CAP0_TWT_RES))
|
||||
if (!sdata->vif.bss_conf.twt_responder)
|
||||
return false;
|
||||
|
||||
if (!rx->sta)
|
||||
|
|
|
@ -104,9 +104,11 @@ ieee80211_s1g_rx_twt_setup(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
/* broadcast TWT not supported yet */
|
||||
if (twt->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST) {
|
||||
le16p_replace_bits(&twt_agrt->req_type,
|
||||
TWT_SETUP_CMD_REJECT,
|
||||
IEEE80211_TWT_REQTYPE_SETUP_CMD);
|
||||
twt_agrt->req_type &=
|
||||
~cpu_to_le16(IEEE80211_TWT_REQTYPE_SETUP_CMD);
|
||||
twt_agrt->req_type |=
|
||||
le16_encode_bits(TWT_SETUP_CMD_REJECT,
|
||||
IEEE80211_TWT_REQTYPE_SETUP_CMD);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
||||
* Copyright 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright 2016-2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
* Copyright (C) 2018-2021 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <linux/if_arp.h>
|
||||
|
@ -155,7 +155,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
|
|||
};
|
||||
bool signal_valid;
|
||||
struct ieee80211_sub_if_data *scan_sdata;
|
||||
struct ieee802_11_elems elems;
|
||||
struct ieee802_11_elems *elems;
|
||||
size_t baselen;
|
||||
u8 *elements;
|
||||
|
||||
|
@ -209,8 +209,10 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
|
|||
if (baselen > len)
|
||||
return NULL;
|
||||
|
||||
ieee802_11_parse_elems(elements, len - baselen, false, &elems,
|
||||
mgmt->bssid, cbss->bssid);
|
||||
elems = ieee802_11_parse_elems(elements, len - baselen, false,
|
||||
mgmt->bssid, cbss->bssid);
|
||||
if (!elems)
|
||||
return NULL;
|
||||
|
||||
/* In case the signal is invalid update the status */
|
||||
signal_valid = channel == cbss->channel;
|
||||
|
@ -218,15 +220,17 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
|
|||
rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
|
||||
|
||||
bss = (void *)cbss->priv;
|
||||
ieee80211_update_bss_from_elems(local, bss, &elems, rx_status, beacon);
|
||||
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,
|
||||
ieee80211_update_bss_from_elems(local, non_tx_bss, elems,
|
||||
rx_status, beacon);
|
||||
}
|
||||
|
||||
kfree(elems);
|
||||
|
||||
return bss;
|
||||
}
|
||||
|
||||
|
|
|
@ -444,6 +444,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
switch (i) {
|
||||
case NL80211_BAND_2GHZ:
|
||||
case NL80211_BAND_LC:
|
||||
/*
|
||||
* We use both here, even if we cannot really know for
|
||||
* sure the station will support both, but the only use
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Copyright 2014, Intel Corporation
|
||||
* Copyright 2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2015 - 2016 Intel Deutschland GmbH
|
||||
* Copyright (C) 2019 Intel Corporation
|
||||
* Copyright (C) 2019, 2021 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <linux/ieee80211.h>
|
||||
|
@ -1684,7 +1684,7 @@ ieee80211_process_tdls_channel_switch_resp(struct ieee80211_sub_if_data *sdata,
|
|||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee802_11_elems elems;
|
||||
struct ieee802_11_elems *elems = NULL;
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_tdls_data *tf = (void *)skb->data;
|
||||
bool local_initiator;
|
||||
|
@ -1718,16 +1718,20 @@ ieee80211_process_tdls_channel_switch_resp(struct ieee80211_sub_if_data *sdata,
|
|||
goto call_drv;
|
||||
}
|
||||
|
||||
ieee802_11_parse_elems(tf->u.chan_switch_resp.variable,
|
||||
skb->len - baselen, false, &elems,
|
||||
NULL, NULL);
|
||||
if (elems.parse_error) {
|
||||
elems = ieee802_11_parse_elems(tf->u.chan_switch_resp.variable,
|
||||
skb->len - baselen, false, NULL, NULL);
|
||||
if (!elems) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (elems->parse_error) {
|
||||
tdls_dbg(sdata, "Invalid IEs in TDLS channel switch resp\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!elems.ch_sw_timing || !elems.lnk_id) {
|
||||
if (!elems->ch_sw_timing || !elems->lnk_id) {
|
||||
tdls_dbg(sdata, "TDLS channel switch resp - missing IEs\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
|
@ -1735,15 +1739,15 @@ ieee80211_process_tdls_channel_switch_resp(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
/* validate the initiator is set correctly */
|
||||
local_initiator =
|
||||
!memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN);
|
||||
!memcmp(elems->lnk_id->init_sta, sdata->vif.addr, ETH_ALEN);
|
||||
if (local_initiator == sta->sta.tdls_initiator) {
|
||||
tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time);
|
||||
params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout);
|
||||
params.switch_time = le16_to_cpu(elems->ch_sw_timing->switch_time);
|
||||
params.switch_timeout = le16_to_cpu(elems->ch_sw_timing->switch_timeout);
|
||||
|
||||
params.tmpl_skb =
|
||||
ieee80211_tdls_ch_sw_resp_tmpl_get(sta, ¶ms.ch_sw_tm_ie);
|
||||
|
@ -1763,6 +1767,7 @@ call_drv:
|
|||
out:
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
dev_kfree_skb_any(params.tmpl_skb);
|
||||
kfree(elems);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1771,7 +1776,7 @@ ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata,
|
|||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee802_11_elems elems;
|
||||
struct ieee802_11_elems *elems;
|
||||
struct cfg80211_chan_def chandef;
|
||||
struct ieee80211_channel *chan;
|
||||
enum nl80211_channel_type chan_type;
|
||||
|
@ -1831,22 +1836,27 @@ ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
ieee802_11_parse_elems(tf->u.chan_switch_req.variable,
|
||||
skb->len - baselen, false, &elems, NULL, NULL);
|
||||
if (elems.parse_error) {
|
||||
elems = ieee802_11_parse_elems(tf->u.chan_switch_req.variable,
|
||||
skb->len - baselen, false, NULL, NULL);
|
||||
if (!elems)
|
||||
return -ENOMEM;
|
||||
|
||||
if (elems->parse_error) {
|
||||
tdls_dbg(sdata, "Invalid IEs in TDLS channel switch req\n");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto free;
|
||||
}
|
||||
|
||||
if (!elems.ch_sw_timing || !elems.lnk_id) {
|
||||
if (!elems->ch_sw_timing || !elems->lnk_id) {
|
||||
tdls_dbg(sdata, "TDLS channel switch req - missing IEs\n");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto free;
|
||||
}
|
||||
|
||||
if (!elems.sec_chan_offs) {
|
||||
if (!elems->sec_chan_offs) {
|
||||
chan_type = NL80211_CHAN_HT20;
|
||||
} else {
|
||||
switch (elems.sec_chan_offs->sec_chan_offs) {
|
||||
switch (elems->sec_chan_offs->sec_chan_offs) {
|
||||
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
|
||||
chan_type = NL80211_CHAN_HT40PLUS;
|
||||
break;
|
||||
|
@ -1865,7 +1875,8 @@ ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata,
|
|||
if (!cfg80211_reg_can_beacon_relax(sdata->local->hw.wiphy, &chandef,
|
||||
sdata->wdev.iftype)) {
|
||||
tdls_dbg(sdata, "TDLS chan switch to forbidden channel\n");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto free;
|
||||
}
|
||||
|
||||
mutex_lock(&local->sta_mtx);
|
||||
|
@ -1881,7 +1892,7 @@ ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
/* validate the initiator is set correctly */
|
||||
local_initiator =
|
||||
!memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN);
|
||||
!memcmp(elems->lnk_id->init_sta, sdata->vif.addr, ETH_ALEN);
|
||||
if (local_initiator == sta->sta.tdls_initiator) {
|
||||
tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n");
|
||||
ret = -EINVAL;
|
||||
|
@ -1889,16 +1900,16 @@ ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
/* peer should have known better */
|
||||
if (!sta->sta.ht_cap.ht_supported && elems.sec_chan_offs &&
|
||||
elems.sec_chan_offs->sec_chan_offs) {
|
||||
if (!sta->sta.ht_cap.ht_supported && elems->sec_chan_offs &&
|
||||
elems->sec_chan_offs->sec_chan_offs) {
|
||||
tdls_dbg(sdata, "TDLS chan switch - wide chan unsupported\n");
|
||||
ret = -ENOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
params.chandef = &chandef;
|
||||
params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time);
|
||||
params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout);
|
||||
params.switch_time = le16_to_cpu(elems->ch_sw_timing->switch_time);
|
||||
params.switch_timeout = le16_to_cpu(elems->ch_sw_timing->switch_timeout);
|
||||
|
||||
params.tmpl_skb =
|
||||
ieee80211_tdls_ch_sw_resp_tmpl_get(sta,
|
||||
|
@ -1917,6 +1928,8 @@ ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata,
|
|||
out:
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
dev_kfree_skb_any(params.tmpl_skb);
|
||||
free:
|
||||
kfree(elems);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -146,7 +146,8 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
|
|||
rate = DIV_ROUND_UP(r->bitrate, 1 << shift);
|
||||
|
||||
switch (sband->band) {
|
||||
case NL80211_BAND_2GHZ: {
|
||||
case NL80211_BAND_2GHZ:
|
||||
case NL80211_BAND_LC: {
|
||||
u32 flag;
|
||||
if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
|
||||
flag = IEEE80211_RATE_MANDATORY_G;
|
||||
|
@ -4991,6 +4992,115 @@ static int ieee80211_beacon_protect(struct sk_buff *skb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ieee80211_beacon_get_finish(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_mutable_offsets *offs,
|
||||
struct beacon_data *beacon,
|
||||
struct sk_buff *skb,
|
||||
struct ieee80211_chanctx_conf *chanctx_conf,
|
||||
u16 csa_off_base)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
struct ieee80211_tx_info *info;
|
||||
enum nl80211_band band;
|
||||
struct ieee80211_tx_rate_control txrc;
|
||||
|
||||
/* CSA offsets */
|
||||
if (offs && beacon) {
|
||||
u16 i;
|
||||
|
||||
for (i = 0; i < IEEE80211_MAX_CNTDWN_COUNTERS_NUM; i++) {
|
||||
u16 csa_off = beacon->cntdwn_counter_offsets[i];
|
||||
|
||||
if (!csa_off)
|
||||
continue;
|
||||
|
||||
offs->cntdwn_counter_offs[i] = csa_off_base + csa_off;
|
||||
}
|
||||
}
|
||||
|
||||
band = chanctx_conf->def.chan->band;
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
||||
info->band = band;
|
||||
|
||||
memset(&txrc, 0, sizeof(txrc));
|
||||
txrc.hw = hw;
|
||||
txrc.sband = local->hw.wiphy->bands[band];
|
||||
txrc.bss_conf = &sdata->vif.bss_conf;
|
||||
txrc.skb = skb;
|
||||
txrc.reported_rate.idx = -1;
|
||||
if (sdata->beacon_rate_set && sdata->beacon_rateidx_mask[band])
|
||||
txrc.rate_idx_mask = sdata->beacon_rateidx_mask[band];
|
||||
else
|
||||
txrc.rate_idx_mask = sdata->rc_rateidx_mask[band];
|
||||
txrc.bss = true;
|
||||
rate_control_get_rate(sdata, NULL, &txrc);
|
||||
|
||||
info->control.vif = vif;
|
||||
info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT |
|
||||
IEEE80211_TX_CTL_ASSIGN_SEQ |
|
||||
IEEE80211_TX_CTL_FIRST_FRAGMENT;
|
||||
}
|
||||
|
||||
static struct sk_buff *
|
||||
ieee80211_beacon_get_ap(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_mutable_offsets *offs,
|
||||
bool is_template,
|
||||
struct beacon_data *beacon,
|
||||
struct ieee80211_chanctx_conf *chanctx_conf)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
struct ieee80211_if_ap *ap = &sdata->u.ap;
|
||||
struct sk_buff *skb = NULL;
|
||||
u16 csa_off_base = 0;
|
||||
|
||||
if (beacon->cntdwn_counter_offsets[0]) {
|
||||
if (!is_template)
|
||||
ieee80211_beacon_update_cntdwn(vif);
|
||||
|
||||
ieee80211_set_beacon_cntdwn(sdata, beacon);
|
||||
}
|
||||
|
||||
/* headroom, head length,
|
||||
* tail length and maximum TIM length
|
||||
*/
|
||||
skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
|
||||
beacon->tail_len + 256 +
|
||||
local->hw.extra_beacon_tailroom);
|
||||
if (!skb)
|
||||
return NULL;
|
||||
|
||||
skb_reserve(skb, local->tx_headroom);
|
||||
skb_put_data(skb, beacon->head, beacon->head_len);
|
||||
|
||||
ieee80211_beacon_add_tim(sdata, &ap->ps, skb, is_template);
|
||||
|
||||
if (offs) {
|
||||
offs->tim_offset = beacon->head_len;
|
||||
offs->tim_length = skb->len - beacon->head_len;
|
||||
offs->cntdwn_counter_offs[0] = beacon->cntdwn_counter_offsets[0];
|
||||
|
||||
/* for AP the csa offsets are from tail */
|
||||
csa_off_base = skb->len;
|
||||
}
|
||||
|
||||
if (beacon->tail)
|
||||
skb_put_data(skb, beacon->tail, beacon->tail_len);
|
||||
|
||||
if (ieee80211_beacon_protect(skb, local, sdata) < 0)
|
||||
return NULL;
|
||||
|
||||
ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, chanctx_conf,
|
||||
csa_off_base);
|
||||
return skb;
|
||||
}
|
||||
|
||||
static struct sk_buff *
|
||||
__ieee80211_beacon_get(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
|
@ -5000,12 +5110,8 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
|
|||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct beacon_data *beacon = NULL;
|
||||
struct sk_buff *skb = NULL;
|
||||
struct ieee80211_tx_info *info;
|
||||
struct ieee80211_sub_if_data *sdata = NULL;
|
||||
enum nl80211_band band;
|
||||
struct ieee80211_tx_rate_control txrc;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
int csa_off_base = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
|
@ -5022,48 +5128,11 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
|
|||
struct ieee80211_if_ap *ap = &sdata->u.ap;
|
||||
|
||||
beacon = rcu_dereference(ap->beacon);
|
||||
if (beacon) {
|
||||
if (beacon->cntdwn_counter_offsets[0]) {
|
||||
if (!is_template)
|
||||
ieee80211_beacon_update_cntdwn(vif);
|
||||
|
||||
ieee80211_set_beacon_cntdwn(sdata, beacon);
|
||||
}
|
||||
|
||||
/*
|
||||
* headroom, head length,
|
||||
* tail length and maximum TIM length
|
||||
*/
|
||||
skb = dev_alloc_skb(local->tx_headroom +
|
||||
beacon->head_len +
|
||||
beacon->tail_len + 256 +
|
||||
local->hw.extra_beacon_tailroom);
|
||||
if (!skb)
|
||||
goto out;
|
||||
|
||||
skb_reserve(skb, local->tx_headroom);
|
||||
skb_put_data(skb, beacon->head, beacon->head_len);
|
||||
|
||||
ieee80211_beacon_add_tim(sdata, &ap->ps, skb,
|
||||
is_template);
|
||||
|
||||
if (offs) {
|
||||
offs->tim_offset = beacon->head_len;
|
||||
offs->tim_length = skb->len - beacon->head_len;
|
||||
offs->cntdwn_counter_offs[0] = beacon->cntdwn_counter_offsets[0];
|
||||
|
||||
/* for AP the csa offsets are from tail */
|
||||
csa_off_base = skb->len;
|
||||
}
|
||||
|
||||
if (beacon->tail)
|
||||
skb_put_data(skb, beacon->tail,
|
||||
beacon->tail_len);
|
||||
|
||||
if (ieee80211_beacon_protect(skb, local, sdata) < 0)
|
||||
goto out;
|
||||
} else
|
||||
if (!beacon)
|
||||
goto out;
|
||||
|
||||
skb = ieee80211_beacon_get_ap(hw, vif, offs, is_template,
|
||||
beacon, chanctx_conf);
|
||||
} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
|
||||
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
||||
struct ieee80211_hdr *hdr;
|
||||
|
@ -5089,6 +5158,9 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
|
|||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_BEACON);
|
||||
|
||||
ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb,
|
||||
chanctx_conf, 0);
|
||||
} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
|
||||
|
@ -5128,51 +5200,13 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
|
|||
}
|
||||
|
||||
skb_put_data(skb, beacon->tail, beacon->tail_len);
|
||||
ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb,
|
||||
chanctx_conf, 0);
|
||||
} else {
|
||||
WARN_ON(1);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* CSA offsets */
|
||||
if (offs && beacon) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IEEE80211_MAX_CNTDWN_COUNTERS_NUM; i++) {
|
||||
u16 csa_off = beacon->cntdwn_counter_offsets[i];
|
||||
|
||||
if (!csa_off)
|
||||
continue;
|
||||
|
||||
offs->cntdwn_counter_offs[i] = csa_off_base + csa_off;
|
||||
}
|
||||
}
|
||||
|
||||
band = chanctx_conf->def.chan->band;
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
||||
info->band = band;
|
||||
|
||||
memset(&txrc, 0, sizeof(txrc));
|
||||
txrc.hw = hw;
|
||||
txrc.sband = local->hw.wiphy->bands[band];
|
||||
txrc.bss_conf = &sdata->vif.bss_conf;
|
||||
txrc.skb = skb;
|
||||
txrc.reported_rate.idx = -1;
|
||||
if (sdata->beacon_rate_set && sdata->beacon_rateidx_mask[band])
|
||||
txrc.rate_idx_mask = sdata->beacon_rateidx_mask[band];
|
||||
else
|
||||
txrc.rate_idx_mask = sdata->rc_rateidx_mask[band];
|
||||
txrc.bss = true;
|
||||
rate_control_get_rate(sdata, NULL, &txrc);
|
||||
|
||||
info->control.vif = vif;
|
||||
|
||||
info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT |
|
||||
IEEE80211_TX_CTL_ASSIGN_SEQ |
|
||||
IEEE80211_TX_CTL_FIRST_FRAGMENT;
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
return skb;
|
||||
|
|
|
@ -1112,10 +1112,6 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
|||
} else
|
||||
elem_parse_failed = true;
|
||||
break;
|
||||
case WLAN_EID_CHALLENGE:
|
||||
elems->challenge = pos;
|
||||
elems->challenge_len = elen;
|
||||
break;
|
||||
case WLAN_EID_VENDOR_SPECIFIC:
|
||||
if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
|
||||
pos[2] == 0xf2) {
|
||||
|
@ -1395,8 +1391,8 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
|||
|
||||
static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len,
|
||||
struct ieee802_11_elems *elems,
|
||||
u8 *transmitter_bssid,
|
||||
u8 *bss_bssid,
|
||||
const u8 *transmitter_bssid,
|
||||
const u8 *bss_bssid,
|
||||
u8 *nontransmitted_profile)
|
||||
{
|
||||
const struct element *elem, *sub;
|
||||
|
@ -1461,16 +1457,20 @@ static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len,
|
|||
return found ? profile_len : 0;
|
||||
}
|
||||
|
||||
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)
|
||||
struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len,
|
||||
bool action, u64 filter,
|
||||
u32 crc,
|
||||
const u8 *transmitter_bssid,
|
||||
const u8 *bss_bssid)
|
||||
{
|
||||
struct ieee802_11_elems *elems;
|
||||
const struct element *non_inherit = NULL;
|
||||
u8 *nontransmitted_profile;
|
||||
int nontransmitted_profile_len = 0;
|
||||
|
||||
memset(elems, 0, sizeof(*elems));
|
||||
elems = kzalloc(sizeof(*elems), GFP_ATOMIC);
|
||||
if (!elems)
|
||||
return NULL;
|
||||
elems->ie_start = start;
|
||||
elems->total_len = len;
|
||||
|
||||
|
@ -1516,7 +1516,9 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
|||
|
||||
kfree(nontransmitted_profile);
|
||||
|
||||
return crc;
|
||||
elems->crc = crc;
|
||||
|
||||
return elems;
|
||||
}
|
||||
|
||||
void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata,
|
||||
|
@ -3383,6 +3385,7 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
|
|||
const struct ieee80211_sta_he_cap *he_cap;
|
||||
struct cfg80211_chan_def he_chandef = *chandef;
|
||||
const struct ieee80211_he_6ghz_oper *he_6ghz_oper;
|
||||
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
|
||||
bool support_80_80, support_160;
|
||||
u8 he_phy_cap;
|
||||
u32 freq;
|
||||
|
@ -3426,6 +3429,19 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
|
|||
NL80211_BAND_6GHZ);
|
||||
he_chandef.chan = ieee80211_get_channel(sdata->local->hw.wiphy, freq);
|
||||
|
||||
switch (u8_get_bits(he_6ghz_oper->control,
|
||||
IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO)) {
|
||||
case IEEE80211_6GHZ_CTRL_REG_LPI_AP:
|
||||
bss_conf->power_type = IEEE80211_REG_LPI_AP;
|
||||
break;
|
||||
case IEEE80211_6GHZ_CTRL_REG_SP_AP:
|
||||
bss_conf->power_type = IEEE80211_REG_SP_AP;
|
||||
break;
|
||||
default:
|
||||
bss_conf->power_type = IEEE80211_REG_UNSET_AP;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (u8_get_bits(he_6ghz_oper->control,
|
||||
IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH)) {
|
||||
case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_20MHZ:
|
||||
|
|
|
@ -26,7 +26,7 @@ endif
|
|||
|
||||
$(obj)/shipped-certs.c: $(wildcard $(srctree)/$(src)/certs/*.hex)
|
||||
@$(kecho) " GEN $@"
|
||||
@(echo '#include "reg.h"'; \
|
||||
$(Q)(echo '#include "reg.h"'; \
|
||||
echo 'const u8 shipped_regdb_certs[] = {'; \
|
||||
echo | cat - $^ ; \
|
||||
echo '};'; \
|
||||
|
@ -36,7 +36,7 @@ $(obj)/shipped-certs.c: $(wildcard $(srctree)/$(src)/certs/*.hex)
|
|||
$(obj)/extra-certs.c: $(CONFIG_CFG80211_EXTRA_REGDB_KEYDIR:"%"=%) \
|
||||
$(wildcard $(CONFIG_CFG80211_EXTRA_REGDB_KEYDIR:"%"=%)/*.x509)
|
||||
@$(kecho) " GEN $@"
|
||||
@(set -e; \
|
||||
$(Q)(set -e; \
|
||||
allf=""; \
|
||||
for f in $^ ; do \
|
||||
test -f $$f || continue;\
|
||||
|
|
|
@ -1080,6 +1080,16 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
|
|||
list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
|
||||
cfg80211_put_bss(&rdev->wiphy, &scan->pub);
|
||||
mutex_destroy(&rdev->wiphy.mtx);
|
||||
|
||||
/*
|
||||
* The 'regd' can only be non-NULL if we never finished
|
||||
* initializing the wiphy and thus never went through the
|
||||
* unregister path - e.g. in failure scenarios. Thus, it
|
||||
* cannot have been visible to anyone if non-NULL, so we
|
||||
* can just free it here.
|
||||
*/
|
||||
kfree(rcu_dereference_raw(rdev->wiphy.regd));
|
||||
|
||||
kfree(rdev);
|
||||
}
|
||||
|
||||
|
|
|
@ -437,6 +437,16 @@ sar_policy[NL80211_SAR_ATTR_MAX + 1] = {
|
|||
[NL80211_SAR_ATTR_SPECS] = NLA_POLICY_NESTED_ARRAY(sar_specs_policy),
|
||||
};
|
||||
|
||||
static const struct nla_policy
|
||||
nl80211_mbssid_config_policy[NL80211_MBSSID_CONFIG_ATTR_MAX + 1] = {
|
||||
[NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES] = NLA_POLICY_MIN(NLA_U8, 2),
|
||||
[NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY] =
|
||||
NLA_POLICY_MIN(NLA_U8, 1),
|
||||
[NL80211_MBSSID_CONFIG_ATTR_INDEX] = { .type = NLA_U8 },
|
||||
[NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX] = { .type = NLA_U32 },
|
||||
[NL80211_MBSSID_CONFIG_ATTR_EMA] = { .type = NLA_FLAG },
|
||||
};
|
||||
|
||||
static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
||||
[0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD },
|
||||
[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
|
||||
|
@ -763,6 +773,9 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
|||
[NL80211_ATTR_COLOR_CHANGE_COUNT] = { .type = NLA_U8 },
|
||||
[NL80211_ATTR_COLOR_CHANGE_COLOR] = { .type = NLA_U8 },
|
||||
[NL80211_ATTR_COLOR_CHANGE_ELEMS] = NLA_POLICY_NESTED(nl80211_policy),
|
||||
[NL80211_ATTR_MBSSID_CONFIG] =
|
||||
NLA_POLICY_NESTED(nl80211_mbssid_config_policy),
|
||||
[NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED },
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
|
@ -853,6 +866,7 @@ nl80211_match_band_rssi_policy[NUM_NL80211_BANDS] = {
|
|||
[NL80211_BAND_5GHZ] = { .type = NLA_S32 },
|
||||
[NL80211_BAND_6GHZ] = { .type = NLA_S32 },
|
||||
[NL80211_BAND_60GHZ] = { .type = NLA_S32 },
|
||||
[NL80211_BAND_LC] = { .type = NLA_S32 },
|
||||
};
|
||||
|
||||
static const struct nla_policy
|
||||
|
@ -2207,6 +2221,35 @@ fail:
|
|||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
static int nl80211_put_mbssid_support(struct wiphy *wiphy, struct sk_buff *msg)
|
||||
{
|
||||
struct nlattr *config;
|
||||
|
||||
if (!wiphy->mbssid_max_interfaces)
|
||||
return 0;
|
||||
|
||||
config = nla_nest_start(msg, NL80211_ATTR_MBSSID_CONFIG);
|
||||
if (!config)
|
||||
return -ENOBUFS;
|
||||
|
||||
if (nla_put_u8(msg, NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES,
|
||||
wiphy->mbssid_max_interfaces))
|
||||
goto fail;
|
||||
|
||||
if (wiphy->ema_max_profile_periodicity &&
|
||||
nla_put_u8(msg,
|
||||
NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY,
|
||||
wiphy->ema_max_profile_periodicity))
|
||||
goto fail;
|
||||
|
||||
nla_nest_end(msg, config);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
nla_nest_cancel(msg, config);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
struct nl80211_dump_wiphy_state {
|
||||
s64 filter_wiphy;
|
||||
long start;
|
||||
|
@ -2792,6 +2835,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
|
|||
if (nl80211_put_sar_specs(rdev, msg))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (nl80211_put_mbssid_support(&rdev->wiphy, msg))
|
||||
goto nla_put_failure;
|
||||
|
||||
/* done */
|
||||
state->split_start = 0;
|
||||
break;
|
||||
|
@ -4981,6 +5027,96 @@ static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int nl80211_parse_mbssid_config(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
struct nlattr *attrs,
|
||||
struct cfg80211_mbssid_config *config,
|
||||
u8 num_elems)
|
||||
{
|
||||
struct nlattr *tb[NL80211_MBSSID_CONFIG_ATTR_MAX + 1];
|
||||
|
||||
if (!wiphy->mbssid_max_interfaces)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (nla_parse_nested(tb, NL80211_MBSSID_CONFIG_ATTR_MAX, attrs, NULL,
|
||||
NULL) ||
|
||||
!tb[NL80211_MBSSID_CONFIG_ATTR_INDEX])
|
||||
return -EINVAL;
|
||||
|
||||
config->ema = nla_get_flag(tb[NL80211_MBSSID_CONFIG_ATTR_EMA]);
|
||||
if (config->ema) {
|
||||
if (!wiphy->ema_max_profile_periodicity)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (num_elems > wiphy->ema_max_profile_periodicity)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
config->index = nla_get_u8(tb[NL80211_MBSSID_CONFIG_ATTR_INDEX]);
|
||||
if (config->index >= wiphy->mbssid_max_interfaces ||
|
||||
(!config->index && !num_elems))
|
||||
return -EINVAL;
|
||||
|
||||
if (tb[NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX]) {
|
||||
u32 tx_ifindex =
|
||||
nla_get_u32(tb[NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX]);
|
||||
|
||||
if ((!config->index && tx_ifindex != dev->ifindex) ||
|
||||
(config->index && tx_ifindex == dev->ifindex))
|
||||
return -EINVAL;
|
||||
|
||||
if (tx_ifindex != dev->ifindex) {
|
||||
struct net_device *tx_netdev =
|
||||
dev_get_by_index(wiphy_net(wiphy), tx_ifindex);
|
||||
|
||||
if (!tx_netdev || !tx_netdev->ieee80211_ptr ||
|
||||
tx_netdev->ieee80211_ptr->wiphy != wiphy ||
|
||||
tx_netdev->ieee80211_ptr->iftype !=
|
||||
NL80211_IFTYPE_AP) {
|
||||
dev_put(tx_netdev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
config->tx_wdev = tx_netdev->ieee80211_ptr;
|
||||
} else {
|
||||
config->tx_wdev = dev->ieee80211_ptr;
|
||||
}
|
||||
} else if (!config->index) {
|
||||
config->tx_wdev = dev->ieee80211_ptr;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cfg80211_mbssid_elems *
|
||||
nl80211_parse_mbssid_elems(struct wiphy *wiphy, struct nlattr *attrs)
|
||||
{
|
||||
struct nlattr *nl_elems;
|
||||
struct cfg80211_mbssid_elems *elems;
|
||||
int rem_elems;
|
||||
u8 i = 0, num_elems = 0;
|
||||
|
||||
if (!wiphy->mbssid_max_interfaces)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
nla_for_each_nested(nl_elems, attrs, rem_elems)
|
||||
num_elems++;
|
||||
|
||||
elems = kzalloc(struct_size(elems, elem, num_elems), GFP_KERNEL);
|
||||
if (!elems)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
nla_for_each_nested(nl_elems, attrs, rem_elems) {
|
||||
elems->elem[i].data = nla_data(nl_elems);
|
||||
elems->elem[i].len = nla_len(nl_elems);
|
||||
i++;
|
||||
}
|
||||
elems->cnt = num_elems;
|
||||
return elems;
|
||||
}
|
||||
|
||||
static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev,
|
||||
struct nlattr *attrs[],
|
||||
struct cfg80211_beacon_data *bcn)
|
||||
|
@ -5061,6 +5197,17 @@ static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev,
|
|||
bcn->ftm_responder = -1;
|
||||
}
|
||||
|
||||
if (attrs[NL80211_ATTR_MBSSID_ELEMS]) {
|
||||
struct cfg80211_mbssid_elems *mbssid =
|
||||
nl80211_parse_mbssid_elems(&rdev->wiphy,
|
||||
attrs[NL80211_ATTR_MBSSID_ELEMS]);
|
||||
|
||||
if (IS_ERR(mbssid))
|
||||
return PTR_ERR(mbssid);
|
||||
|
||||
bcn->mbssid_ies = mbssid;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -5192,21 +5339,21 @@ nl80211_parse_unsol_bcast_probe_resp(struct cfg80211_registered_device *rdev,
|
|||
}
|
||||
|
||||
static void nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params,
|
||||
const u8 *rates)
|
||||
const struct element *rates)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!rates)
|
||||
return;
|
||||
|
||||
for (i = 0; i < rates[1]; i++) {
|
||||
if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
|
||||
for (i = 0; i < rates->datalen; i++) {
|
||||
if (rates->data[i] == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
|
||||
params->ht_required = true;
|
||||
if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_VHT_PHY)
|
||||
if (rates->data[i] == BSS_MEMBERSHIP_SELECTOR_VHT_PHY)
|
||||
params->vht_required = true;
|
||||
if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_HE_PHY)
|
||||
if (rates->data[i] == BSS_MEMBERSHIP_SELECTOR_HE_PHY)
|
||||
params->he_required = true;
|
||||
if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_SAE_H2E)
|
||||
if (rates->data[i] == BSS_MEMBERSHIP_SELECTOR_SAE_H2E)
|
||||
params->sae_h2e_required = true;
|
||||
}
|
||||
}
|
||||
|
@ -5221,27 +5368,27 @@ static void nl80211_calculate_ap_params(struct cfg80211_ap_settings *params)
|
|||
const struct cfg80211_beacon_data *bcn = ¶ms->beacon;
|
||||
size_t ies_len = bcn->tail_len;
|
||||
const u8 *ies = bcn->tail;
|
||||
const u8 *rates;
|
||||
const u8 *cap;
|
||||
const struct element *rates;
|
||||
const struct element *cap;
|
||||
|
||||
rates = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies, ies_len);
|
||||
rates = cfg80211_find_elem(WLAN_EID_SUPP_RATES, ies, ies_len);
|
||||
nl80211_check_ap_rate_selectors(params, rates);
|
||||
|
||||
rates = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, ies, ies_len);
|
||||
rates = cfg80211_find_elem(WLAN_EID_EXT_SUPP_RATES, ies, ies_len);
|
||||
nl80211_check_ap_rate_selectors(params, rates);
|
||||
|
||||
cap = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
|
||||
if (cap && cap[1] >= sizeof(*params->ht_cap))
|
||||
params->ht_cap = (void *)(cap + 2);
|
||||
cap = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, ies, ies_len);
|
||||
if (cap && cap[1] >= sizeof(*params->vht_cap))
|
||||
params->vht_cap = (void *)(cap + 2);
|
||||
cap = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, ies, ies_len);
|
||||
if (cap && cap[1] >= sizeof(*params->he_cap) + 1)
|
||||
params->he_cap = (void *)(cap + 3);
|
||||
cap = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_OPERATION, ies, ies_len);
|
||||
if (cap && cap[1] >= sizeof(*params->he_oper) + 1)
|
||||
params->he_oper = (void *)(cap + 3);
|
||||
cap = cfg80211_find_elem(WLAN_EID_HT_CAPABILITY, ies, ies_len);
|
||||
if (cap && cap->datalen >= sizeof(*params->ht_cap))
|
||||
params->ht_cap = (void *)cap->data;
|
||||
cap = cfg80211_find_elem(WLAN_EID_VHT_CAPABILITY, ies, ies_len);
|
||||
if (cap && cap->datalen >= sizeof(*params->vht_cap))
|
||||
params->vht_cap = (void *)cap->data;
|
||||
cap = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_CAPABILITY, ies, ies_len);
|
||||
if (cap && cap->datalen >= sizeof(*params->he_cap) + 1)
|
||||
params->he_cap = (void *)(cap->data + 1);
|
||||
cap = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ies, ies_len);
|
||||
if (cap && cap->datalen >= sizeof(*params->he_oper) + 1)
|
||||
params->he_oper = (void *)(cap->data + 1);
|
||||
}
|
||||
|
||||
static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
|
||||
|
@ -5323,7 +5470,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
|||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
struct net_device *dev = info->user_ptr[1];
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_ap_settings params;
|
||||
struct cfg80211_ap_settings *params;
|
||||
int err;
|
||||
|
||||
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
|
||||
|
@ -5336,27 +5483,29 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
|||
if (wdev->beacon_interval)
|
||||
return -EALREADY;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
/* these are required for START_AP */
|
||||
if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
|
||||
!info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
|
||||
!info->attrs[NL80211_ATTR_BEACON_HEAD])
|
||||
return -EINVAL;
|
||||
|
||||
err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon);
|
||||
if (err)
|
||||
return err;
|
||||
params = kzalloc(sizeof(*params), GFP_KERNEL);
|
||||
if (!params)
|
||||
return -ENOMEM;
|
||||
|
||||
params.beacon_interval =
|
||||
err = nl80211_parse_beacon(rdev, info->attrs, ¶ms->beacon);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
params->beacon_interval =
|
||||
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
|
||||
params.dtim_period =
|
||||
params->dtim_period =
|
||||
nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
|
||||
|
||||
err = cfg80211_validate_beacon_int(rdev, dev->ieee80211_ptr->iftype,
|
||||
params.beacon_interval);
|
||||
params->beacon_interval);
|
||||
if (err)
|
||||
return err;
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* In theory, some of these attributes should be required here
|
||||
|
@ -5366,129 +5515,157 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
|||
* additional information -- drivers must check!
|
||||
*/
|
||||
if (info->attrs[NL80211_ATTR_SSID]) {
|
||||
params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
|
||||
params.ssid_len =
|
||||
params->ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
|
||||
params->ssid_len =
|
||||
nla_len(info->attrs[NL80211_ATTR_SSID]);
|
||||
if (params.ssid_len == 0)
|
||||
return -EINVAL;
|
||||
if (params->ssid_len == 0) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_HIDDEN_SSID])
|
||||
params.hidden_ssid = nla_get_u32(
|
||||
params->hidden_ssid = nla_get_u32(
|
||||
info->attrs[NL80211_ATTR_HIDDEN_SSID]);
|
||||
|
||||
params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
|
||||
params->privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
|
||||
|
||||
if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
|
||||
params.auth_type = nla_get_u32(
|
||||
params->auth_type = nla_get_u32(
|
||||
info->attrs[NL80211_ATTR_AUTH_TYPE]);
|
||||
if (!nl80211_valid_auth_type(rdev, params.auth_type,
|
||||
NL80211_CMD_START_AP))
|
||||
return -EINVAL;
|
||||
if (!nl80211_valid_auth_type(rdev, params->auth_type,
|
||||
NL80211_CMD_START_AP)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
} else
|
||||
params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
|
||||
params->auth_type = NL80211_AUTHTYPE_AUTOMATIC;
|
||||
|
||||
err = nl80211_crypto_settings(rdev, info, ¶ms.crypto,
|
||||
err = nl80211_crypto_settings(rdev, info, ¶ms->crypto,
|
||||
NL80211_MAX_NR_CIPHER_SUITES);
|
||||
if (err)
|
||||
return err;
|
||||
goto out;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]) {
|
||||
if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER))
|
||||
return -EOPNOTSUPP;
|
||||
params.inactivity_timeout = nla_get_u16(
|
||||
if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER)) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
params->inactivity_timeout = nla_get_u16(
|
||||
info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
|
||||
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
|
||||
return -EINVAL;
|
||||
params.p2p_ctwindow =
|
||||
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
params->p2p_ctwindow =
|
||||
nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
|
||||
if (params.p2p_ctwindow != 0 &&
|
||||
!(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
|
||||
return -EINVAL;
|
||||
if (params->p2p_ctwindow != 0 &&
|
||||
!(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
|
||||
u8 tmp;
|
||||
|
||||
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
|
||||
return -EINVAL;
|
||||
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
|
||||
params.p2p_opp_ps = tmp;
|
||||
if (params.p2p_opp_ps != 0 &&
|
||||
!(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
|
||||
return -EINVAL;
|
||||
params->p2p_opp_ps = tmp;
|
||||
if (params->p2p_opp_ps != 0 &&
|
||||
!(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
|
||||
err = nl80211_parse_chandef(rdev, info, ¶ms.chandef);
|
||||
err = nl80211_parse_chandef(rdev, info, ¶ms->chandef);
|
||||
if (err)
|
||||
return err;
|
||||
goto out;
|
||||
} else if (wdev->preset_chandef.chan) {
|
||||
params.chandef = wdev->preset_chandef;
|
||||
} else if (!nl80211_get_ap_channel(rdev, ¶ms))
|
||||
return -EINVAL;
|
||||
params->chandef = wdev->preset_chandef;
|
||||
} else if (!nl80211_get_ap_channel(rdev, params)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, ¶ms.chandef,
|
||||
wdev->iftype))
|
||||
return -EINVAL;
|
||||
if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, ¶ms->chandef,
|
||||
wdev->iftype)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_TX_RATES]) {
|
||||
err = nl80211_parse_tx_bitrate_mask(info, info->attrs,
|
||||
NL80211_ATTR_TX_RATES,
|
||||
¶ms.beacon_rate,
|
||||
¶ms->beacon_rate,
|
||||
dev, false);
|
||||
if (err)
|
||||
return err;
|
||||
goto out;
|
||||
|
||||
err = validate_beacon_tx_rate(rdev, params.chandef.chan->band,
|
||||
¶ms.beacon_rate);
|
||||
err = validate_beacon_tx_rate(rdev, params->chandef.chan->band,
|
||||
¶ms->beacon_rate);
|
||||
if (err)
|
||||
return err;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_SMPS_MODE]) {
|
||||
params.smps_mode =
|
||||
params->smps_mode =
|
||||
nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]);
|
||||
switch (params.smps_mode) {
|
||||
switch (params->smps_mode) {
|
||||
case NL80211_SMPS_OFF:
|
||||
break;
|
||||
case NL80211_SMPS_STATIC:
|
||||
if (!(rdev->wiphy.features &
|
||||
NL80211_FEATURE_STATIC_SMPS))
|
||||
return -EINVAL;
|
||||
NL80211_FEATURE_STATIC_SMPS)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
case NL80211_SMPS_DYNAMIC:
|
||||
if (!(rdev->wiphy.features &
|
||||
NL80211_FEATURE_DYNAMIC_SMPS))
|
||||
return -EINVAL;
|
||||
NL80211_FEATURE_DYNAMIC_SMPS)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
params.smps_mode = NL80211_SMPS_OFF;
|
||||
params->smps_mode = NL80211_SMPS_OFF;
|
||||
}
|
||||
|
||||
params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
|
||||
if (params.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ])
|
||||
return -EOPNOTSUPP;
|
||||
params->pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
|
||||
if (params->pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ]) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
|
||||
params.acl = parse_acl_data(&rdev->wiphy, info);
|
||||
if (IS_ERR(params.acl))
|
||||
return PTR_ERR(params.acl);
|
||||
params->acl = parse_acl_data(&rdev->wiphy, info);
|
||||
if (IS_ERR(params->acl)) {
|
||||
err = PTR_ERR(params->acl);
|
||||
params->acl = NULL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
params.twt_responder =
|
||||
params->twt_responder =
|
||||
nla_get_flag(info->attrs[NL80211_ATTR_TWT_RESPONDER]);
|
||||
|
||||
if (info->attrs[NL80211_ATTR_HE_OBSS_PD]) {
|
||||
err = nl80211_parse_he_obss_pd(
|
||||
info->attrs[NL80211_ATTR_HE_OBSS_PD],
|
||||
¶ms.he_obss_pd);
|
||||
¶ms->he_obss_pd);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
@ -5496,7 +5673,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
|||
if (info->attrs[NL80211_ATTR_HE_BSS_COLOR]) {
|
||||
err = nl80211_parse_he_bss_color(
|
||||
info->attrs[NL80211_ATTR_HE_BSS_COLOR],
|
||||
¶ms.he_bss_color);
|
||||
¶ms->he_bss_color);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
@ -5504,7 +5681,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
|||
if (info->attrs[NL80211_ATTR_FILS_DISCOVERY]) {
|
||||
err = nl80211_parse_fils_discovery(rdev,
|
||||
info->attrs[NL80211_ATTR_FILS_DISCOVERY],
|
||||
¶ms);
|
||||
params);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
@ -5512,24 +5689,35 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
|||
if (info->attrs[NL80211_ATTR_UNSOL_BCAST_PROBE_RESP]) {
|
||||
err = nl80211_parse_unsol_bcast_probe_resp(
|
||||
rdev, info->attrs[NL80211_ATTR_UNSOL_BCAST_PROBE_RESP],
|
||||
¶ms);
|
||||
params);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
nl80211_calculate_ap_params(¶ms);
|
||||
if (info->attrs[NL80211_ATTR_MBSSID_CONFIG]) {
|
||||
err = nl80211_parse_mbssid_config(&rdev->wiphy, dev,
|
||||
info->attrs[NL80211_ATTR_MBSSID_CONFIG],
|
||||
¶ms->mbssid_config,
|
||||
params->beacon.mbssid_ies ?
|
||||
params->beacon.mbssid_ies->cnt :
|
||||
0);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
nl80211_calculate_ap_params(params);
|
||||
|
||||
if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT])
|
||||
params.flags |= AP_SETTINGS_EXTERNAL_AUTH_SUPPORT;
|
||||
params->flags |= AP_SETTINGS_EXTERNAL_AUTH_SUPPORT;
|
||||
|
||||
wdev_lock(wdev);
|
||||
err = rdev_start_ap(rdev, dev, ¶ms);
|
||||
err = rdev_start_ap(rdev, dev, params);
|
||||
if (!err) {
|
||||
wdev->preset_chandef = params.chandef;
|
||||
wdev->beacon_interval = params.beacon_interval;
|
||||
wdev->chandef = params.chandef;
|
||||
wdev->ssid_len = params.ssid_len;
|
||||
memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
|
||||
wdev->preset_chandef = params->chandef;
|
||||
wdev->beacon_interval = params->beacon_interval;
|
||||
wdev->chandef = params->chandef;
|
||||
wdev->ssid_len = params->ssid_len;
|
||||
memcpy(wdev->ssid, params->ssid, wdev->ssid_len);
|
||||
|
||||
if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
|
||||
wdev->conn_owner_nlportid = info->snd_portid;
|
||||
|
@ -5537,7 +5725,13 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
|||
wdev_unlock(wdev);
|
||||
|
||||
out:
|
||||
kfree(params.acl);
|
||||
kfree(params->acl);
|
||||
kfree(params->beacon.mbssid_ies);
|
||||
if (params->mbssid_config.tx_wdev &&
|
||||
params->mbssid_config.tx_wdev->netdev &&
|
||||
params->mbssid_config.tx_wdev->netdev != dev)
|
||||
dev_put(params->mbssid_config.tx_wdev->netdev);
|
||||
kfree(params);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -5562,12 +5756,14 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
err = nl80211_parse_beacon(rdev, info->attrs, ¶ms);
|
||||
if (err)
|
||||
return err;
|
||||
goto out;
|
||||
|
||||
wdev_lock(wdev);
|
||||
err = rdev_change_beacon(rdev, dev, ¶ms);
|
||||
wdev_unlock(wdev);
|
||||
|
||||
out:
|
||||
kfree(params.mbssid_ies);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -9244,12 +9440,14 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon_after);
|
||||
if (err)
|
||||
return err;
|
||||
goto free;
|
||||
|
||||
csa_attrs = kcalloc(NL80211_ATTR_MAX + 1, sizeof(*csa_attrs),
|
||||
GFP_KERNEL);
|
||||
if (!csa_attrs)
|
||||
return -ENOMEM;
|
||||
if (!csa_attrs) {
|
||||
err = -ENOMEM;
|
||||
goto free;
|
||||
}
|
||||
|
||||
err = nla_parse_nested_deprecated(csa_attrs, NL80211_ATTR_MAX,
|
||||
info->attrs[NL80211_ATTR_CSA_IES],
|
||||
|
@ -9367,6 +9565,8 @@ skip_beacons:
|
|||
wdev_unlock(wdev);
|
||||
|
||||
free:
|
||||
kfree(params.beacon_after.mbssid_ies);
|
||||
kfree(params.beacon_csa.mbssid_ies);
|
||||
kfree(csa_attrs);
|
||||
return err;
|
||||
}
|
||||
|
@ -11767,8 +11967,9 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
|
|||
if (n_thresholds) {
|
||||
struct cfg80211_cqm_config *cqm_config;
|
||||
|
||||
cqm_config = kzalloc(sizeof(struct cfg80211_cqm_config) +
|
||||
n_thresholds * sizeof(s32), GFP_KERNEL);
|
||||
cqm_config = kzalloc(struct_size(cqm_config, rssi_thresholds,
|
||||
n_thresholds),
|
||||
GFP_KERNEL);
|
||||
if (!cqm_config) {
|
||||
err = -ENOMEM;
|
||||
goto unlock;
|
||||
|
@ -11777,7 +11978,8 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
|
|||
cqm_config->rssi_hyst = hysteresis;
|
||||
cqm_config->n_rssi_thresholds = n_thresholds;
|
||||
memcpy(cqm_config->rssi_thresholds, thresholds,
|
||||
n_thresholds * sizeof(s32));
|
||||
flex_array_size(cqm_config, rssi_thresholds,
|
||||
n_thresholds));
|
||||
|
||||
wdev->cqm_config = cqm_config;
|
||||
}
|
||||
|
@ -14900,10 +15102,35 @@ static int nl80211_color_change(struct sk_buff *skb, struct genl_info *info)
|
|||
wdev_unlock(wdev);
|
||||
|
||||
out:
|
||||
kfree(params.beacon_next.mbssid_ies);
|
||||
kfree(params.beacon_color_change.mbssid_ies);
|
||||
kfree(tb);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nl80211_set_fils_aad(struct sk_buff *skb,
|
||||
struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
struct net_device *dev = info->user_ptr[1];
|
||||
struct cfg80211_fils_aad fils_aad = {};
|
||||
u8 *nonces;
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_MAC] ||
|
||||
!info->attrs[NL80211_ATTR_FILS_KEK] ||
|
||||
!info->attrs[NL80211_ATTR_FILS_NONCES])
|
||||
return -EINVAL;
|
||||
|
||||
fils_aad.macaddr = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
||||
fils_aad.kek_len = nla_len(info->attrs[NL80211_ATTR_FILS_KEK]);
|
||||
fils_aad.kek = nla_data(info->attrs[NL80211_ATTR_FILS_KEK]);
|
||||
nonces = nla_data(info->attrs[NL80211_ATTR_FILS_NONCES]);
|
||||
fils_aad.snonce = nonces;
|
||||
fils_aad.anonce = nonces + FILS_NONCE_LEN;
|
||||
|
||||
return rdev_set_fils_aad(rdev, dev, &fils_aad);
|
||||
}
|
||||
|
||||
#define NL80211_FLAG_NEED_WIPHY 0x01
|
||||
#define NL80211_FLAG_NEED_NETDEV 0x02
|
||||
#define NL80211_FLAG_NEED_RTNL 0x04
|
||||
|
@ -15081,9 +15308,7 @@ static int nl80211_set_sar_specs(struct sk_buff *skb, struct genl_info *info)
|
|||
if (specs > rdev->wiphy.sar_capa->num_freq_ranges)
|
||||
return -EINVAL;
|
||||
|
||||
sar_spec = kzalloc(sizeof(*sar_spec) +
|
||||
specs * sizeof(struct cfg80211_sar_sub_specs),
|
||||
GFP_KERNEL);
|
||||
sar_spec = kzalloc(struct_size(sar_spec, sub_specs, specs), GFP_KERNEL);
|
||||
if (!sar_spec)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -15907,6 +16132,13 @@ static const struct genl_small_ops nl80211_small_ops[] = {
|
|||
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
||||
NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_SET_FILS_AAD,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.doit = nl80211_set_fils_aad,
|
||||
.flags = GENL_UNS_ADMIN_PERM,
|
||||
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
|
||||
},
|
||||
};
|
||||
|
||||
static struct genl_family nl80211_fam __ro_after_init = {
|
||||
|
|
|
@ -1381,4 +1381,18 @@ static inline int rdev_color_change(struct cfg80211_registered_device *rdev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
rdev_set_fils_aad(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev, struct cfg80211_fils_aad *fils_aad)
|
||||
{
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
trace_rdev_set_fils_aad(&rdev->wiphy, dev, fils_aad);
|
||||
if (rdev->ops->set_fils_aad)
|
||||
ret = rdev->ops->set_fils_aad(&rdev->wiphy, dev, fils_aad);
|
||||
trace_rdev_return_int(&rdev->wiphy, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* __CFG80211_RDEV_OPS */
|
||||
|
|
|
@ -383,7 +383,7 @@ 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;
|
||||
const struct element *ssid_elem;
|
||||
|
||||
if (bssid && !ether_addr_equal(a->bssid, bssid))
|
||||
return false;
|
||||
|
@ -394,12 +394,12 @@ static bool is_bss(struct cfg80211_bss *a, const u8 *bssid,
|
|||
ies = rcu_access_pointer(a->ies);
|
||||
if (!ies)
|
||||
return false;
|
||||
ssidie = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len);
|
||||
if (!ssidie)
|
||||
ssid_elem = cfg80211_find_elem(WLAN_EID_SSID, ies->data, ies->len);
|
||||
if (!ssid_elem)
|
||||
return false;
|
||||
if (ssidie[1] != ssid_len)
|
||||
if (ssid_elem->datalen != ssid_len)
|
||||
return false;
|
||||
return memcmp(ssidie + 2, ssid, ssid_len) == 0;
|
||||
return memcmp(ssid_elem->data, ssid, ssid_len) == 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1791,25 +1791,13 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update RX channel information based on the available frame payload
|
||||
* information. This is mainly for the 2.4 GHz band where frames can be received
|
||||
* from neighboring channels and the Beacon frames use the DSSS Parameter Set
|
||||
* element to indicate the current (transmitting) channel, but this might also
|
||||
* be needed on other bands if RX frequency does not match with the actual
|
||||
* operating channel of a BSS.
|
||||
*/
|
||||
static struct ieee80211_channel *
|
||||
cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
|
||||
struct ieee80211_channel *channel,
|
||||
enum nl80211_bss_scan_width scan_width)
|
||||
int cfg80211_get_ies_channel_number(const u8 *ie, size_t ielen,
|
||||
enum nl80211_band band)
|
||||
{
|
||||
const u8 *tmp;
|
||||
u32 freq;
|
||||
int channel_number = -1;
|
||||
struct ieee80211_channel *alt_channel;
|
||||
|
||||
if (channel->band == NL80211_BAND_S1GHZ) {
|
||||
if (band == NL80211_BAND_S1GHZ) {
|
||||
tmp = cfg80211_find_ie(WLAN_EID_S1G_OPERATION, ie, ielen);
|
||||
if (tmp && tmp[1] >= sizeof(struct ieee80211_s1g_oper_ie)) {
|
||||
struct ieee80211_s1g_oper_ie *s1gop = (void *)(tmp + 2);
|
||||
|
@ -1830,6 +1818,29 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
|
|||
}
|
||||
}
|
||||
|
||||
return channel_number;
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_get_ies_channel_number);
|
||||
|
||||
/*
|
||||
* Update RX channel information based on the available frame payload
|
||||
* information. This is mainly for the 2.4 GHz band where frames can be received
|
||||
* from neighboring channels and the Beacon frames use the DSSS Parameter Set
|
||||
* element to indicate the current (transmitting) channel, but this might also
|
||||
* be needed on other bands if RX frequency does not match with the actual
|
||||
* operating channel of a BSS.
|
||||
*/
|
||||
static struct ieee80211_channel *
|
||||
cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
|
||||
struct ieee80211_channel *channel,
|
||||
enum nl80211_bss_scan_width scan_width)
|
||||
{
|
||||
u32 freq;
|
||||
int channel_number;
|
||||
struct ieee80211_channel *alt_channel;
|
||||
|
||||
channel_number = cfg80211_get_ies_channel_number(ie, ielen, channel->band);
|
||||
|
||||
if (channel_number < 0) {
|
||||
/* No channel information in frame payload */
|
||||
return channel;
|
||||
|
@ -2072,12 +2083,12 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
|
|||
|
||||
if (!non_tx_data)
|
||||
return;
|
||||
if (!cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen))
|
||||
if (!cfg80211_find_elem(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))
|
||||
!cfg80211_find_ext_elem(WLAN_EID_EXT_HE_CAPABILITY, ie, ielen))
|
||||
return;
|
||||
|
||||
new_ie = kmalloc(IEEE80211_MAX_DATA_LEN, gfp);
|
||||
|
@ -2444,10 +2455,10 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
|
|||
res = cfg80211_inform_single_bss_frame_data(wiphy, data, mgmt,
|
||||
len, gfp);
|
||||
if (!res || !wiphy->support_mbssid ||
|
||||
!cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen))
|
||||
!cfg80211_find_elem(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))
|
||||
!cfg80211_find_ext_elem(WLAN_EID_EXT_HE_CAPABILITY, ie, ielen))
|
||||
return res;
|
||||
|
||||
non_tx_data.tx_bss = res;
|
||||
|
|
|
@ -167,6 +167,19 @@
|
|||
__entry->center_freq1, __entry->freq1_offset, \
|
||||
__entry->center_freq2
|
||||
|
||||
#define FILS_AAD_ASSIGN(fa) \
|
||||
do { \
|
||||
if (fa) { \
|
||||
ether_addr_copy(__entry->macaddr, fa->macaddr); \
|
||||
__entry->kek_len = fa->kek_len; \
|
||||
} else { \
|
||||
eth_zero_addr(__entry->macaddr); \
|
||||
__entry->kek_len = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
#define FILS_AAD_PR_FMT \
|
||||
"macaddr: %pM, kek_len: %d"
|
||||
|
||||
#define SINFO_ENTRY __field(int, generation) \
|
||||
__field(u32, connected_time) \
|
||||
__field(u32, inactive_time) \
|
||||
|
@ -2614,6 +2627,24 @@ DEFINE_EVENT(wiphy_wdev_cookie_evt, rdev_abort_pmsr,
|
|||
TP_ARGS(wiphy, wdev, cookie)
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_set_fils_aad,
|
||||
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
|
||||
struct cfg80211_fils_aad *fils_aad),
|
||||
TP_ARGS(wiphy, netdev, fils_aad),
|
||||
TP_STRUCT__entry(WIPHY_ENTRY
|
||||
NETDEV_ENTRY
|
||||
__array(u8, macaddr, ETH_ALEN)
|
||||
__field(u8, kek_len)
|
||||
),
|
||||
TP_fast_assign(WIPHY_ASSIGN;
|
||||
NETDEV_ASSIGN;
|
||||
FILS_AAD_ASSIGN(fils_aad);
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " FILS_AAD_PR_FMT,
|
||||
WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->macaddr,
|
||||
__entry->kek_len)
|
||||
);
|
||||
|
||||
/*************************************************************
|
||||
* cfg80211 exported functions traces *
|
||||
*************************************************************/
|
||||
|
|
|
@ -80,6 +80,7 @@ u32 ieee80211_channel_to_freq_khz(int chan, enum nl80211_band band)
|
|||
return 0; /* not supported */
|
||||
switch (band) {
|
||||
case NL80211_BAND_2GHZ:
|
||||
case NL80211_BAND_LC:
|
||||
if (chan == 14)
|
||||
return MHZ_TO_KHZ(2484);
|
||||
else if (chan < 14)
|
||||
|
@ -209,6 +210,7 @@ static void set_mandatory_flags_band(struct ieee80211_supported_band *sband)
|
|||
WARN_ON(want);
|
||||
break;
|
||||
case NL80211_BAND_2GHZ:
|
||||
case NL80211_BAND_LC:
|
||||
want = 7;
|
||||
for (i = 0; i < sband->n_bitrates; i++) {
|
||||
switch (sband->bitrates[i].bitrate) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче