mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-25 10:23:55 +07:00
Merge branch 'cfg80211-mac80211-multi-bssid' into mac80211-next
This finally merges the multi-BSSID code. This is the result of a long collaboration between the team at Qualcomm (Peng and Jouni) and our team at Intel (mostly Sara). Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
commit
db33aa7ea6
@ -2801,6 +2801,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
||||
ieee80211_hw_set(hw, TDLS_WIDER_BW);
|
||||
if (rctbl)
|
||||
ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
|
||||
ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
|
||||
|
||||
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
|
||||
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
|
||||
* Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH
|
||||
* Copyright (c) 2016 - 2017 Intel Deutschland GmbH
|
||||
* Copyright (c) 2018 Intel Corporation
|
||||
* Copyright (c) 2018 - 2019 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@ -2475,6 +2475,7 @@ enum ieee80211_eid_ext {
|
||||
WLAN_EID_EXT_HE_OPERATION = 36,
|
||||
WLAN_EID_EXT_UORA = 37,
|
||||
WLAN_EID_EXT_HE_MU_EDCA = 38,
|
||||
WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION = 55,
|
||||
};
|
||||
|
||||
/* Action category code */
|
||||
@ -2656,6 +2657,11 @@ enum ieee80211_tdls_actioncode {
|
||||
*/
|
||||
#define WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING BIT(2)
|
||||
|
||||
/* Multiple BSSID capability is set in the 6th bit of 3rd byte of the
|
||||
* @WLAN_EID_EXT_CAPABILITY information element
|
||||
*/
|
||||
#define WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT BIT(6)
|
||||
|
||||
/* TDLS capabilities in the the 4th byte of @WLAN_EID_EXT_CAPABILITY */
|
||||
#define WLAN_EXT_CAPA4_TDLS_BUFFER_STA BIT(4)
|
||||
#define WLAN_EXT_CAPA4_TDLS_PEER_PSM BIT(5)
|
||||
@ -2691,6 +2697,9 @@ enum ieee80211_tdls_actioncode {
|
||||
#define WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT BIT(5)
|
||||
#define WLAN_EXT_CAPA10_TWT_RESPONDER_SUPPORT BIT(6)
|
||||
|
||||
/* Defines support for enhanced multi-bssid advertisement*/
|
||||
#define WLAN_EXT_CAPA11_EMA_SUPPORT BIT(1)
|
||||
|
||||
/* TDLS specific payload type in the LLC/SNAP header */
|
||||
#define WLAN_TDLS_SNAP_RFTYPE 0x2
|
||||
|
||||
@ -2882,6 +2891,34 @@ enum ieee80211_sa_query_action {
|
||||
WLAN_ACTION_SA_QUERY_RESPONSE = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ieee80211_bssid_index
|
||||
*
|
||||
* This structure refers to "Multiple BSSID-index element"
|
||||
*
|
||||
* @bssid_index: BSSID index
|
||||
* @dtim_period: optional, overrides transmitted BSS dtim period
|
||||
* @dtim_count: optional, overrides transmitted BSS dtim count
|
||||
*/
|
||||
struct ieee80211_bssid_index {
|
||||
u8 bssid_index;
|
||||
u8 dtim_period;
|
||||
u8 dtim_count;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ieee80211_multiple_bssid_configuration
|
||||
*
|
||||
* This structure refers to "Multiple BSSID Configuration element"
|
||||
*
|
||||
* @bssid_count: total number of active BSSIDs in the set
|
||||
* @profile_periodicity: the least number of beacon frames need to be received
|
||||
* in order to discover all the nontransmitted BSSIDs in the set.
|
||||
*/
|
||||
struct ieee80211_multiple_bssid_configuration {
|
||||
u8 bssid_count;
|
||||
u8 profile_periodicity;
|
||||
};
|
||||
|
||||
#define SUITE(oui, id) (((oui) << 8) | (id))
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2015-2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* Copyright (C) 2018-2019 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@ -2035,9 +2035,15 @@ struct cfg80211_bss_ies {
|
||||
* a BSS that hides the SSID in its beacon, this points to the BSS struct
|
||||
* that holds the beacon data. @beacon_ies is still valid, of course, and
|
||||
* points to the same data as hidden_beacon_bss->beacon_ies in that case.
|
||||
* @transmitted_bss: pointer to the transmitted BSS, if this is a
|
||||
* non-transmitted one (multi-BSSID support)
|
||||
* @nontrans_list: list of non-transmitted BSS, if this is a transmitted one
|
||||
* (multi-BSSID support)
|
||||
* @signal: signal strength value (type depends on the wiphy's signal_type)
|
||||
* @chains: bitmask for filled values in @chain_signal.
|
||||
* @chain_signal: per-chain signal strength of last received BSS in dBm.
|
||||
* @bssid_index: index in the multiple BSS set
|
||||
* @max_bssid_indicator: max number of members in the BSS set
|
||||
* @priv: private area for driver use, has at least wiphy->bss_priv_size bytes
|
||||
*/
|
||||
struct cfg80211_bss {
|
||||
@ -2049,6 +2055,8 @@ struct cfg80211_bss {
|
||||
const struct cfg80211_bss_ies __rcu *proberesp_ies;
|
||||
|
||||
struct cfg80211_bss *hidden_beacon_bss;
|
||||
struct cfg80211_bss *transmitted_bss;
|
||||
struct list_head nontrans_list;
|
||||
|
||||
s32 signal;
|
||||
|
||||
@ -2059,6 +2067,9 @@ struct cfg80211_bss {
|
||||
u8 chains;
|
||||
s8 chain_signal[IEEE80211_MAX_CHAINS];
|
||||
|
||||
u8 bssid_index;
|
||||
u8 max_bssid_indicator;
|
||||
|
||||
u8 priv[0] __aligned(sizeof(void *));
|
||||
};
|
||||
|
||||
@ -4313,6 +4324,11 @@ struct cfg80211_pmsr_capabilities {
|
||||
* @txq_memory_limit: configuration internal TX queue memory limit
|
||||
* @txq_quantum: configuration of internal TX queue scheduler quantum
|
||||
*
|
||||
* @support_mbssid: can HW support association with nontransmitted AP
|
||||
* @support_only_he_mbssid: don't parse MBSSID elements if it is not
|
||||
* HE AP, in order to avoid compatibility issues.
|
||||
* @support_mbssid must be set for this to have any effect.
|
||||
*
|
||||
* @pmsr_capa: peer measurement capabilities
|
||||
*/
|
||||
struct wiphy {
|
||||
@ -4453,6 +4469,9 @@ struct wiphy {
|
||||
u32 txq_memory_limit;
|
||||
u32 txq_quantum;
|
||||
|
||||
u8 support_mbssid:1,
|
||||
support_only_he_mbssid:1;
|
||||
|
||||
const struct cfg80211_pmsr_capabilities *pmsr_capa;
|
||||
|
||||
char priv[0] __aligned(NETDEV_ALIGN);
|
||||
@ -5451,6 +5470,29 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
|
||||
return cfg80211_inform_bss_frame_data(wiphy, &data, mgmt, len, gfp);
|
||||
}
|
||||
|
||||
/**
|
||||
* cfg80211_gen_new_bssid - generate a nontransmitted BSSID for multi-BSSID
|
||||
* @bssid: transmitter BSSID
|
||||
* @max_bssid: max BSSID indicator, taken from Multiple BSSID element
|
||||
* @mbssid_index: BSSID index, taken from Multiple BSSID index element
|
||||
* @new_bssid_addr: address of the resulting BSSID
|
||||
*/
|
||||
static inline void cfg80211_gen_new_bssid(const u8 *bssid, u8 max_bssid,
|
||||
u8 mbssid_index, u8 *new_bssid_addr)
|
||||
{
|
||||
u64 bssid_tmp, new_bssid;
|
||||
u64 lsb_n;
|
||||
|
||||
bssid_tmp = ether_addr_to_u64(bssid);
|
||||
|
||||
lsb_n = bssid_tmp & ((1 << max_bssid) - 1);
|
||||
new_bssid = bssid_tmp;
|
||||
new_bssid &= ~((1 << max_bssid) - 1);
|
||||
new_bssid |= (lsb_n + mbssid_index) % (1 << max_bssid);
|
||||
|
||||
u64_to_ether_addr(new_bssid, new_bssid_addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* enum cfg80211_bss_frame_type - frame type that the BSS data came from
|
||||
* @CFG80211_BSS_FTYPE_UNKNOWN: driver doesn't know whether the data is
|
||||
|
@ -591,6 +591,14 @@ struct ieee80211_ftm_responder_params {
|
||||
* @ftm_responder: whether to enable or disable fine timing measurement FTM
|
||||
* responder functionality.
|
||||
* @ftmr_params: configurable lci/civic parameter when enabling FTM responder.
|
||||
* @nontransmitted: this BSS is a nontransmitted BSS profile
|
||||
* @transmitter_bssid: the address of transmitter AP
|
||||
* @bssid_index: index inside the multiple BSSID set
|
||||
* @bssid_indicator: 2^bssid_indicator is the maximum number of APs in set
|
||||
* @ema_ap: AP supports enhancements of discovery and advertisement of
|
||||
* nontransmitted BSSIDs
|
||||
* @profile_periodicity: the least number of beacon frames need to be received
|
||||
* in order to discover all the nontransmitted BSSIDs in the set.
|
||||
*/
|
||||
struct ieee80211_bss_conf {
|
||||
const u8 *bssid;
|
||||
@ -644,6 +652,13 @@ struct ieee80211_bss_conf {
|
||||
bool protected_keep_alive;
|
||||
bool ftm_responder;
|
||||
struct ieee80211_ftm_responder_params *ftmr_params;
|
||||
/* Multiple BSSID data */
|
||||
bool nontransmitted;
|
||||
u8 transmitter_bssid[ETH_ALEN];
|
||||
u8 bssid_index;
|
||||
u8 bssid_indicator;
|
||||
bool ema_ap;
|
||||
u8 profile_periodicity;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2219,6 +2234,11 @@ struct ieee80211_txq {
|
||||
* @IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN: Driver does not report accurate A-MPDU
|
||||
* length in tx status information
|
||||
*
|
||||
* @IEEE80211_HW_SUPPORTS_MULTI_BSSID: Hardware supports multi BSSID
|
||||
*
|
||||
* @IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID: Hardware supports multi BSSID
|
||||
* only for HE APs. Applies if @IEEE80211_HW_SUPPORTS_MULTI_BSSID is set.
|
||||
*
|
||||
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
|
||||
*/
|
||||
enum ieee80211_hw_flags {
|
||||
@ -2268,6 +2288,8 @@ enum ieee80211_hw_flags {
|
||||
IEEE80211_HW_SUPPORTS_VHT_EXT_NSS_BW,
|
||||
IEEE80211_HW_STA_MMPDU_TXQ,
|
||||
IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN,
|
||||
IEEE80211_HW_SUPPORTS_MULTI_BSSID,
|
||||
IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID,
|
||||
|
||||
/* keep last, obviously */
|
||||
NUM_IEEE80211_HW_FLAGS
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* Copyright (C) 2018 - 2019 Intel Corporation
|
||||
*
|
||||
* GPLv2
|
||||
*
|
||||
@ -219,6 +219,8 @@ static const char *hw_flag_names[] = {
|
||||
FLAG(SUPPORTS_VHT_EXT_NSS_BW),
|
||||
FLAG(STA_MMPDU_TXQ),
|
||||
FLAG(TX_STATUS_NO_AMPDU_LEN),
|
||||
FLAG(SUPPORTS_MULTI_BSSID),
|
||||
FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID),
|
||||
#undef FLAG
|
||||
};
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
* Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2016 Intel Deutschland GmbH
|
||||
* Copyright(c) 2018-2019 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@ -1124,8 +1125,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
ieee80211_update_sta_info(sdata, mgmt, len, rx_status, elems, channel);
|
||||
|
||||
bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
|
||||
channel);
|
||||
bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, channel);
|
||||
if (!bss)
|
||||
return;
|
||||
|
||||
@ -1604,7 +1604,7 @@ void ieee80211_rx_mgmt_probe_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
return;
|
||||
|
||||
ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
|
||||
false, &elems);
|
||||
false, &elems, mgmt->bssid, NULL);
|
||||
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
|
||||
}
|
||||
@ -1654,7 +1654,7 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
ieee802_11_parse_elems(
|
||||
mgmt->u.action.u.chan_switch.variable,
|
||||
ies_len, true, &elems);
|
||||
ies_len, true, &elems, mgmt->bssid, NULL);
|
||||
|
||||
if (elems.parse_error)
|
||||
break;
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* Copyright (C) 2018-2019 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@ -1495,6 +1495,12 @@ struct ieee802_11_elems {
|
||||
const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
|
||||
struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie;
|
||||
const struct ieee80211_bss_max_idle_period_ie *max_idle_period_ie;
|
||||
const struct ieee80211_multiple_bssid_configuration *mbssid_config_ie;
|
||||
const struct ieee80211_bssid_index *bssid_index;
|
||||
const u8 *nontransmitted_bssid_profile;
|
||||
u8 max_bssid_indicator;
|
||||
u8 dtim_count;
|
||||
u8 dtim_period;
|
||||
|
||||
/* length of them, respectively */
|
||||
u8 ext_capab_len;
|
||||
@ -1513,6 +1519,7 @@ struct ieee802_11_elems {
|
||||
u8 prep_len;
|
||||
u8 perr_len;
|
||||
u8 country_elem_len;
|
||||
u8 bssid_index_len;
|
||||
|
||||
/* whether a parse error occurred while retrieving these elements */
|
||||
bool parse_error;
|
||||
@ -1672,7 +1679,6 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
size_t len,
|
||||
struct ieee802_11_elems *elems,
|
||||
struct ieee80211_channel *channel);
|
||||
void ieee80211_rx_bss_put(struct ieee80211_local *local,
|
||||
struct ieee80211_bss *bss);
|
||||
@ -1956,12 +1962,16 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
struct ieee802_11_elems *elems,
|
||||
u64 filter, u32 crc);
|
||||
u64 filter, u32 crc, u8 *transmitter_bssid,
|
||||
u8 *bss_bssid);
|
||||
static inline void ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||
bool action,
|
||||
struct ieee802_11_elems *elems)
|
||||
struct ieee802_11_elems *elems,
|
||||
u8 *transmitter_bssid,
|
||||
u8 *bss_bssid)
|
||||
{
|
||||
ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0);
|
||||
ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0,
|
||||
transmitter_bssid, bss_bssid);
|
||||
}
|
||||
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* Copyright (C) 2018 - 2019 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@ -1112,6 +1112,17 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
if (ieee80211_hw_check(&local->hw, CHANCTX_STA_CSA))
|
||||
local->ext_capa[0] |= WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING;
|
||||
|
||||
/* mac80211 supports multi BSSID, if the driver supports it */
|
||||
if (ieee80211_hw_check(&local->hw, SUPPORTS_MULTI_BSSID)) {
|
||||
local->hw.wiphy->support_mbssid = true;
|
||||
if (ieee80211_hw_check(&local->hw,
|
||||
SUPPORTS_ONLY_HE_MULTI_BSSID))
|
||||
local->hw.wiphy->support_only_he_mbssid = true;
|
||||
else
|
||||
local->ext_capa[2] |=
|
||||
WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT;
|
||||
}
|
||||
|
||||
local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CSA_COUNTERS_NUM;
|
||||
|
||||
result = wiphy_register(local->hw.wiphy);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2009 open80211s Ltd.
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* Copyright (C) 2018 - 2019 Intel Corporation
|
||||
* Authors: Luis Carlos Cobo <luisca@cozybit.com>
|
||||
* Javier Cardona <javier@cozybit.com>
|
||||
*
|
||||
@ -1106,7 +1106,8 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
|
||||
if (baselen > len)
|
||||
return;
|
||||
|
||||
ieee802_11_parse_elems(pos, len - baselen, false, &elems);
|
||||
ieee802_11_parse_elems(pos, len - baselen, false, &elems, mgmt->bssid,
|
||||
NULL);
|
||||
|
||||
if (!elems.mesh_id)
|
||||
return;
|
||||
@ -1170,7 +1171,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
|
||||
return;
|
||||
|
||||
ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
|
||||
false, &elems);
|
||||
false, &elems, mgmt->bssid, NULL);
|
||||
|
||||
/* ignore non-mesh or secure / unsecure mismatch */
|
||||
if ((!elems.mesh_id || !elems.mesh_config) ||
|
||||
@ -1306,7 +1307,8 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
|
||||
pos = mgmt->u.action.u.chan_switch.variable;
|
||||
baselen = offsetof(struct ieee80211_mgmt,
|
||||
u.action.u.chan_switch.variable);
|
||||
ieee802_11_parse_elems(pos, len - baselen, true, &elems);
|
||||
ieee802_11_parse_elems(pos, len - baselen, true, &elems,
|
||||
mgmt->bssid, NULL);
|
||||
|
||||
ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl;
|
||||
if (!--ifmsh->chsw_ttl)
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2009 open80211s Ltd.
|
||||
* Copyright (C) 2019 Intel Corporation
|
||||
* Author: Luis Carlos Cobo <luisca@cozybit.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -926,7 +927,7 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt;
|
||||
ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
|
||||
len - baselen, false, &elems);
|
||||
len - baselen, false, &elems, mgmt->bssid, NULL);
|
||||
|
||||
if (elems.preq) {
|
||||
if (elems.preq_len != 37)
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2009 open80211s Ltd.
|
||||
* Copyright (C) 2019 Intel Corporation
|
||||
* Author: Luis Carlos Cobo <luisca@cozybit.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -1214,6 +1215,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
|
||||
if (baselen > len)
|
||||
return;
|
||||
}
|
||||
ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems);
|
||||
ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems,
|
||||
mgmt->bssid, NULL);
|
||||
mesh_process_plink_frame(sdata, mgmt, &elems, rx_status);
|
||||
}
|
||||
|
@ -813,6 +813,21 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
|
||||
}
|
||||
}
|
||||
|
||||
/* Set MBSSID support for HE AP if needed */
|
||||
if (ieee80211_hw_check(&local->hw, SUPPORTS_ONLY_HE_MULTI_BSSID) &&
|
||||
!(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && assoc_data->ie_len) {
|
||||
struct element *elem;
|
||||
|
||||
/* we know it's writable, cast away the const */
|
||||
elem = (void *)cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY,
|
||||
assoc_data->ie,
|
||||
assoc_data->ie_len);
|
||||
|
||||
/* We can probably assume both always true */
|
||||
if (elem && elem->datalen >= 3)
|
||||
elem->data[2] |= WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT;
|
||||
}
|
||||
|
||||
/* if present, add any custom IEs that go before HT */
|
||||
if (assoc_data->ie_len) {
|
||||
static const u8 before_ht[] = {
|
||||
@ -2762,7 +2777,8 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
|
||||
u32 tx_flags = 0;
|
||||
|
||||
pos = mgmt->u.auth.variable;
|
||||
ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), false, &elems);
|
||||
ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems,
|
||||
mgmt->bssid, auth_data->bss->bssid);
|
||||
if (!elems.challenge)
|
||||
return;
|
||||
auth_data->expected_transaction = 4;
|
||||
@ -3130,7 +3146,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
pos = mgmt->u.assoc_resp.variable;
|
||||
ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), false, &elems);
|
||||
ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems,
|
||||
mgmt->bssid, assoc_data->bss->bssid);
|
||||
|
||||
if (!elems.supp_rates) {
|
||||
sdata_info(sdata, "no SuppRates element in AssocResp\n");
|
||||
@ -3167,7 +3184,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
||||
return false;
|
||||
|
||||
ieee802_11_parse_elems(bss_ies->data, bss_ies->len,
|
||||
false, &bss_elems);
|
||||
false, &bss_elems,
|
||||
mgmt->bssid,
|
||||
assoc_data->bss->bssid);
|
||||
if (assoc_data->wmm &&
|
||||
!elems.wmm_param && bss_elems.wmm_param) {
|
||||
elems.wmm_param = bss_elems.wmm_param;
|
||||
@ -3304,6 +3323,14 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
||||
/* TODO: OPEN: what happens if BSS color disable is set? */
|
||||
}
|
||||
|
||||
if (cbss->transmitted_bss) {
|
||||
bss_conf->nontransmitted = true;
|
||||
ether_addr_copy(bss_conf->transmitter_bssid,
|
||||
cbss->transmitted_bss->bssid);
|
||||
bss_conf->bssid_indicator = cbss->max_bssid_indicator;
|
||||
bss_conf->bssid_index = cbss->bssid_index;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some APs, e.g. Netgear WNDR3700, report invalid HT operation data
|
||||
* in their association response, so ignore that data for our own
|
||||
@ -3464,7 +3491,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
||||
return;
|
||||
|
||||
pos = mgmt->u.assoc_resp.variable;
|
||||
ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), false, &elems);
|
||||
ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems,
|
||||
mgmt->bssid, assoc_data->bss->bssid);
|
||||
|
||||
if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
|
||||
elems.timeout_int &&
|
||||
@ -3521,8 +3549,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
struct ieee802_11_elems *elems)
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_bss *bss;
|
||||
@ -3534,8 +3561,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
if (!channel)
|
||||
return;
|
||||
|
||||
bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
|
||||
channel);
|
||||
bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, channel);
|
||||
if (bss) {
|
||||
sdata->vif.bss_conf.beacon_rate = bss->beacon_rate;
|
||||
ieee80211_rx_bss_put(local, bss);
|
||||
@ -3550,7 +3576,6 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_if_managed *ifmgd;
|
||||
struct ieee80211_rx_status *rx_status = (void *) skb->cb;
|
||||
size_t baselen, len = skb->len;
|
||||
struct ieee802_11_elems elems;
|
||||
|
||||
ifmgd = &sdata->u.mgd;
|
||||
|
||||
@ -3563,10 +3588,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
|
||||
if (baselen > len)
|
||||
return;
|
||||
|
||||
ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
|
||||
false, &elems);
|
||||
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status);
|
||||
|
||||
if (ifmgd->associated &&
|
||||
ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
|
||||
@ -3693,6 +3715,16 @@ static void ieee80211_handle_beacon_sig(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
}
|
||||
|
||||
static bool ieee80211_rx_our_beacon(const u8 *tx_bssid,
|
||||
struct cfg80211_bss *bss)
|
||||
{
|
||||
if (ether_addr_equal(tx_bssid, bss->bssid))
|
||||
return true;
|
||||
if (!bss->transmitted_bss)
|
||||
return false;
|
||||
return ether_addr_equal(tx_bssid, bss->transmitted_bss->bssid);
|
||||
}
|
||||
|
||||
static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
@ -3734,15 +3766,16 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
rcu_read_unlock();
|
||||
|
||||
if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon &&
|
||||
ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) {
|
||||
ieee80211_rx_our_beacon(mgmt->bssid, ifmgd->assoc_data->bss)) {
|
||||
ieee802_11_parse_elems(mgmt->u.beacon.variable,
|
||||
len - baselen, false, &elems);
|
||||
len - baselen, false, &elems,
|
||||
mgmt->bssid,
|
||||
ifmgd->assoc_data->bss->bssid);
|
||||
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
|
||||
if (elems.tim && !elems.parse_error) {
|
||||
const struct ieee80211_tim_ie *tim_ie = elems.tim;
|
||||
ifmgd->dtim_period = tim_ie->dtim_period;
|
||||
}
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status);
|
||||
|
||||
if (elems.dtim_period)
|
||||
ifmgd->dtim_period = elems.dtim_period;
|
||||
ifmgd->have_beacon = true;
|
||||
ifmgd->assoc_data->need_beacon = false;
|
||||
if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) {
|
||||
@ -3750,12 +3783,17 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
le64_to_cpu(mgmt->u.beacon.timestamp);
|
||||
sdata->vif.bss_conf.sync_device_ts =
|
||||
rx_status->device_timestamp;
|
||||
if (elems.tim)
|
||||
sdata->vif.bss_conf.sync_dtim_count =
|
||||
elems.tim->dtim_count;
|
||||
else
|
||||
sdata->vif.bss_conf.sync_dtim_count = 0;
|
||||
sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count;
|
||||
}
|
||||
|
||||
if (elems.mbssid_config_ie)
|
||||
bss_conf->profile_periodicity =
|
||||
elems.mbssid_config_ie->profile_periodicity;
|
||||
|
||||
if (elems.ext_capab_len >= 11 &&
|
||||
(elems.ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT))
|
||||
bss_conf->ema_ap = true;
|
||||
|
||||
/* continue assoc process */
|
||||
ifmgd->assoc_data->timeout = jiffies;
|
||||
ifmgd->assoc_data->timeout_started = true;
|
||||
@ -3764,7 +3802,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
if (!ifmgd->associated ||
|
||||
!ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
|
||||
!ieee80211_rx_our_beacon(mgmt->bssid, ifmgd->associated))
|
||||
return;
|
||||
bssid = ifmgd->associated->bssid;
|
||||
|
||||
@ -3787,7 +3825,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
|
||||
ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable,
|
||||
len - baselen, false, &elems,
|
||||
care_about_ies, ncrc);
|
||||
care_about_ies, ncrc,
|
||||
mgmt->bssid, bssid);
|
||||
|
||||
if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
|
||||
ieee80211_check_tim(elems.tim, elems.tim_len, ifmgd->aid)) {
|
||||
@ -3859,11 +3898,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
le64_to_cpu(mgmt->u.beacon.timestamp);
|
||||
sdata->vif.bss_conf.sync_device_ts =
|
||||
rx_status->device_timestamp;
|
||||
if (elems.tim)
|
||||
sdata->vif.bss_conf.sync_dtim_count =
|
||||
elems.tim->dtim_count;
|
||||
else
|
||||
sdata->vif.bss_conf.sync_dtim_count = 0;
|
||||
sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count;
|
||||
}
|
||||
|
||||
if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
|
||||
@ -3871,7 +3906,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
ifmgd->beacon_crc = ncrc;
|
||||
ifmgd->beacon_crc_valid = true;
|
||||
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status);
|
||||
|
||||
ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
|
||||
rx_status->device_timestamp,
|
||||
@ -3889,10 +3924,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
*/
|
||||
if (!ifmgd->have_beacon) {
|
||||
/* a few bogus AP send dtim_period = 0 or no TIM IE */
|
||||
if (elems.tim)
|
||||
bss_conf->dtim_period = elems.tim->dtim_period ?: 1;
|
||||
else
|
||||
bss_conf->dtim_period = 1;
|
||||
bss_conf->dtim_period = elems.dtim_period ?: 1;
|
||||
|
||||
changed |= BSS_CHANGED_BEACON_INFO;
|
||||
ifmgd->have_beacon = true;
|
||||
@ -3992,9 +4024,10 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
||||
if (ies_len < 0)
|
||||
break;
|
||||
|
||||
/* CSA IE cannot be overridden, no need for BSSID */
|
||||
ieee802_11_parse_elems(
|
||||
mgmt->u.action.u.chan_switch.variable,
|
||||
ies_len, true, &elems);
|
||||
ies_len, true, &elems, mgmt->bssid, NULL);
|
||||
|
||||
if (elems.parse_error)
|
||||
break;
|
||||
@ -4011,9 +4044,13 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
||||
if (ies_len < 0)
|
||||
break;
|
||||
|
||||
/*
|
||||
* extended CSA IE can't be overridden, no need for
|
||||
* BSSID
|
||||
*/
|
||||
ieee802_11_parse_elems(
|
||||
mgmt->u.action.u.ext_chan_switch.variable,
|
||||
ies_len, true, &elems);
|
||||
ies_len, true, &elems, mgmt->bssid, NULL);
|
||||
|
||||
if (elems.parse_error)
|
||||
break;
|
||||
@ -4754,6 +4791,40 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool ieee80211_get_dtim(const struct cfg80211_bss_ies *ies,
|
||||
u8 *dtim_count, u8 *dtim_period)
|
||||
{
|
||||
const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len);
|
||||
const u8 *idx_ie = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX, ies->data,
|
||||
ies->len);
|
||||
const struct ieee80211_tim_ie *tim = NULL;
|
||||
const struct ieee80211_bssid_index *idx;
|
||||
bool valid = tim_ie && tim_ie[1] >= 2;
|
||||
|
||||
if (valid)
|
||||
tim = (void *)(tim_ie + 2);
|
||||
|
||||
if (dtim_count)
|
||||
*dtim_count = valid ? tim->dtim_count : 0;
|
||||
|
||||
if (dtim_period)
|
||||
*dtim_period = valid ? tim->dtim_period : 0;
|
||||
|
||||
/* Check if value is overridden by non-transmitted profile */
|
||||
if (!idx_ie || idx_ie[1] < 3)
|
||||
return valid;
|
||||
|
||||
idx = (void *)(idx_ie + 2);
|
||||
|
||||
if (dtim_count)
|
||||
*dtim_count = idx->dtim_count;
|
||||
|
||||
if (dtim_period)
|
||||
*dtim_period = idx->dtim_period;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_bss *cbss, bool assoc,
|
||||
bool override)
|
||||
@ -4845,17 +4916,13 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
|
||||
rcu_read_lock();
|
||||
ies = rcu_dereference(cbss->beacon_ies);
|
||||
if (ies) {
|
||||
const u8 *tim_ie;
|
||||
|
||||
sdata->vif.bss_conf.sync_tsf = ies->tsf;
|
||||
sdata->vif.bss_conf.sync_device_ts =
|
||||
bss->device_ts_beacon;
|
||||
tim_ie = cfg80211_find_ie(WLAN_EID_TIM,
|
||||
ies->data, ies->len);
|
||||
if (tim_ie && tim_ie[1] >= 2)
|
||||
sdata->vif.bss_conf.sync_dtim_count = tim_ie[2];
|
||||
else
|
||||
sdata->vif.bss_conf.sync_dtim_count = 0;
|
||||
|
||||
ieee80211_get_dtim(ies,
|
||||
&sdata->vif.bss_conf.sync_dtim_count,
|
||||
NULL);
|
||||
} else if (!ieee80211_hw_check(&sdata->local->hw,
|
||||
TIMING_BEACON_ONLY)) {
|
||||
ies = rcu_dereference(cbss->proberesp_ies);
|
||||
@ -5325,17 +5392,12 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
assoc_data->timeout_started = true;
|
||||
assoc_data->need_beacon = true;
|
||||
} else if (beacon_ies) {
|
||||
const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM,
|
||||
beacon_ies->data,
|
||||
beacon_ies->len);
|
||||
const u8 *ie;
|
||||
u8 dtim_count = 0;
|
||||
|
||||
if (tim_ie && tim_ie[1] >= sizeof(struct ieee80211_tim_ie)) {
|
||||
const struct ieee80211_tim_ie *tim;
|
||||
tim = (void *)(tim_ie + 2);
|
||||
ifmgd->dtim_period = tim->dtim_period;
|
||||
dtim_count = tim->dtim_count;
|
||||
}
|
||||
ieee80211_get_dtim(beacon_ies, &dtim_count,
|
||||
&ifmgd->dtim_period);
|
||||
|
||||
ifmgd->have_beacon = true;
|
||||
assoc_data->timeout = jiffies;
|
||||
assoc_data->timeout_started = true;
|
||||
@ -5346,6 +5408,17 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
bss->device_ts_beacon;
|
||||
sdata->vif.bss_conf.sync_dtim_count = dtim_count;
|
||||
}
|
||||
|
||||
ie = cfg80211_find_ext_ie(WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION,
|
||||
beacon_ies->data, beacon_ies->len);
|
||||
if (ie && ie[1] >= 3)
|
||||
sdata->vif.bss_conf.profile_periodicity = ie[4];
|
||||
|
||||
ie = cfg80211_find_ie(WLAN_EID_EXT_CAPABILITY,
|
||||
beacon_ies->data, beacon_ies->len);
|
||||
if (ie && ie[1] >= 11 &&
|
||||
(ie[10] & WLAN_EXT_CAPA11_EMA_SUPPORT))
|
||||
sdata->vif.bss_conf.ema_ap = true;
|
||||
} else {
|
||||
assoc_data->timeout = jiffies;
|
||||
assoc_data->timeout_started = true;
|
||||
|
@ -8,6 +8,7 @@
|
||||
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
||||
* Copyright 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright 2016-2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018-2019 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@ -57,62 +58,14 @@ static bool is_uapsd_supported(struct ieee802_11_elems *elems)
|
||||
return qos_info & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD;
|
||||
}
|
||||
|
||||
struct ieee80211_bss *
|
||||
ieee80211_bss_info_update(struct ieee80211_local *local,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
struct ieee802_11_elems *elems,
|
||||
struct ieee80211_channel *channel)
|
||||
static void
|
||||
ieee80211_update_bss_from_elems(struct ieee80211_local *local,
|
||||
struct ieee80211_bss *bss,
|
||||
struct ieee802_11_elems *elems,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
bool beacon)
|
||||
{
|
||||
bool beacon = ieee80211_is_beacon(mgmt->frame_control);
|
||||
struct cfg80211_bss *cbss;
|
||||
struct ieee80211_bss *bss;
|
||||
int clen, srlen;
|
||||
struct cfg80211_inform_bss bss_meta = {
|
||||
.boottime_ns = rx_status->boottime_ns,
|
||||
};
|
||||
bool signal_valid;
|
||||
struct ieee80211_sub_if_data *scan_sdata;
|
||||
|
||||
if (rx_status->flag & RX_FLAG_NO_SIGNAL_VAL)
|
||||
bss_meta.signal = 0; /* invalid signal indication */
|
||||
else if (ieee80211_hw_check(&local->hw, SIGNAL_DBM))
|
||||
bss_meta.signal = rx_status->signal * 100;
|
||||
else if (ieee80211_hw_check(&local->hw, SIGNAL_UNSPEC))
|
||||
bss_meta.signal = (rx_status->signal * 100) / local->hw.max_signal;
|
||||
|
||||
bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_20;
|
||||
if (rx_status->bw == RATE_INFO_BW_5)
|
||||
bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_5;
|
||||
else if (rx_status->bw == RATE_INFO_BW_10)
|
||||
bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_10;
|
||||
|
||||
bss_meta.chan = channel;
|
||||
|
||||
rcu_read_lock();
|
||||
scan_sdata = rcu_dereference(local->scan_sdata);
|
||||
if (scan_sdata && scan_sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
scan_sdata->vif.bss_conf.assoc &&
|
||||
ieee80211_have_rx_timestamp(rx_status)) {
|
||||
bss_meta.parent_tsf =
|
||||
ieee80211_calculate_rx_timestamp(local, rx_status,
|
||||
len + FCS_LEN, 24);
|
||||
ether_addr_copy(bss_meta.parent_bssid,
|
||||
scan_sdata->vif.bss_conf.bssid);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
cbss = cfg80211_inform_bss_frame_data(local->hw.wiphy, &bss_meta,
|
||||
mgmt, len, GFP_ATOMIC);
|
||||
if (!cbss)
|
||||
return NULL;
|
||||
/* In case the signal is invalid update the status */
|
||||
signal_valid = abs(channel->center_freq - cbss->channel->center_freq)
|
||||
<= local->hw.wiphy->max_adj_channel_rssi_comp;
|
||||
if (!signal_valid)
|
||||
rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
|
||||
|
||||
bss = (void *)cbss->priv;
|
||||
|
||||
if (beacon)
|
||||
bss->device_ts_beacon = rx_status->device_timestamp;
|
||||
@ -182,6 +135,89 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
|
||||
bss->beacon_rate =
|
||||
&sband->bitrates[rx_status->rate_idx];
|
||||
}
|
||||
}
|
||||
|
||||
struct ieee80211_bss *
|
||||
ieee80211_bss_info_update(struct ieee80211_local *local,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
struct ieee80211_channel *channel)
|
||||
{
|
||||
bool beacon = ieee80211_is_beacon(mgmt->frame_control);
|
||||
struct cfg80211_bss *cbss, *non_tx_cbss;
|
||||
struct ieee80211_bss *bss, *non_tx_bss;
|
||||
struct cfg80211_inform_bss bss_meta = {
|
||||
.boottime_ns = rx_status->boottime_ns,
|
||||
};
|
||||
bool signal_valid;
|
||||
struct ieee80211_sub_if_data *scan_sdata;
|
||||
struct ieee802_11_elems elems;
|
||||
size_t baselen;
|
||||
u8 *elements;
|
||||
|
||||
if (rx_status->flag & RX_FLAG_NO_SIGNAL_VAL)
|
||||
bss_meta.signal = 0; /* invalid signal indication */
|
||||
else if (ieee80211_hw_check(&local->hw, SIGNAL_DBM))
|
||||
bss_meta.signal = rx_status->signal * 100;
|
||||
else if (ieee80211_hw_check(&local->hw, SIGNAL_UNSPEC))
|
||||
bss_meta.signal = (rx_status->signal * 100) / local->hw.max_signal;
|
||||
|
||||
bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_20;
|
||||
if (rx_status->bw == RATE_INFO_BW_5)
|
||||
bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_5;
|
||||
else if (rx_status->bw == RATE_INFO_BW_10)
|
||||
bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_10;
|
||||
|
||||
bss_meta.chan = channel;
|
||||
|
||||
rcu_read_lock();
|
||||
scan_sdata = rcu_dereference(local->scan_sdata);
|
||||
if (scan_sdata && scan_sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
scan_sdata->vif.bss_conf.assoc &&
|
||||
ieee80211_have_rx_timestamp(rx_status)) {
|
||||
bss_meta.parent_tsf =
|
||||
ieee80211_calculate_rx_timestamp(local, rx_status,
|
||||
len + FCS_LEN, 24);
|
||||
ether_addr_copy(bss_meta.parent_bssid,
|
||||
scan_sdata->vif.bss_conf.bssid);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
cbss = cfg80211_inform_bss_frame_data(local->hw.wiphy, &bss_meta,
|
||||
mgmt, len, GFP_ATOMIC);
|
||||
if (!cbss)
|
||||
return NULL;
|
||||
|
||||
if (ieee80211_is_probe_resp(mgmt->frame_control)) {
|
||||
elements = mgmt->u.probe_resp.variable;
|
||||
baselen = offsetof(struct ieee80211_mgmt,
|
||||
u.probe_resp.variable);
|
||||
} else {
|
||||
baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
|
||||
elements = mgmt->u.beacon.variable;
|
||||
}
|
||||
|
||||
if (baselen > len)
|
||||
return NULL;
|
||||
|
||||
ieee802_11_parse_elems(elements, len - baselen, false, &elems,
|
||||
mgmt->bssid, cbss->bssid);
|
||||
|
||||
/* In case the signal is invalid update the status */
|
||||
signal_valid = abs(channel->center_freq - cbss->channel->center_freq)
|
||||
<= local->hw.wiphy->max_adj_channel_rssi_comp;
|
||||
if (!signal_valid)
|
||||
rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
|
||||
|
||||
bss = (void *)cbss->priv;
|
||||
ieee80211_update_bss_from_elems(local, bss, &elems, rx_status, beacon);
|
||||
|
||||
list_for_each_entry(non_tx_cbss, &cbss->nontrans_list, nontrans_list) {
|
||||
non_tx_bss = (void *)non_tx_cbss->priv;
|
||||
|
||||
ieee80211_update_bss_from_elems(local, non_tx_bss, &elems,
|
||||
rx_status, beacon);
|
||||
}
|
||||
|
||||
return bss;
|
||||
}
|
||||
@ -206,10 +242,7 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
|
||||
struct ieee80211_sub_if_data *sdata1, *sdata2;
|
||||
struct ieee80211_mgmt *mgmt = (void *)skb->data;
|
||||
struct ieee80211_bss *bss;
|
||||
u8 *elements;
|
||||
struct ieee80211_channel *channel;
|
||||
size_t baselen;
|
||||
struct ieee802_11_elems elems;
|
||||
|
||||
if (skb->len < 24 ||
|
||||
(!ieee80211_is_probe_resp(mgmt->frame_control) &&
|
||||
@ -244,26 +277,15 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
|
||||
!ieee80211_scan_accept_presp(sdata2, sched_scan_req_flags,
|
||||
mgmt->da))
|
||||
return;
|
||||
|
||||
elements = mgmt->u.probe_resp.variable;
|
||||
baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
|
||||
} else {
|
||||
baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
|
||||
elements = mgmt->u.beacon.variable;
|
||||
}
|
||||
|
||||
if (baselen > skb->len)
|
||||
return;
|
||||
|
||||
ieee802_11_parse_elems(elements, skb->len - baselen, false, &elems);
|
||||
|
||||
channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
|
||||
|
||||
if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
|
||||
return;
|
||||
|
||||
bss = ieee80211_bss_info_update(local, rx_status,
|
||||
mgmt, skb->len, &elems,
|
||||
mgmt, skb->len,
|
||||
channel);
|
||||
if (bss)
|
||||
ieee80211_rx_bss_put(local, bss);
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Copyright 2014, Intel Corporation
|
||||
* Copyright 2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2015 - 2016 Intel Deutschland GmbH
|
||||
* Copyright (C) 2019 Intel Corporation
|
||||
*
|
||||
* This file is GPLv2 as found in COPYING.
|
||||
*/
|
||||
@ -1716,7 +1717,8 @@ ieee80211_process_tdls_channel_switch_resp(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
ieee802_11_parse_elems(tf->u.chan_switch_resp.variable,
|
||||
skb->len - baselen, false, &elems);
|
||||
skb->len - baselen, false, &elems,
|
||||
NULL, NULL);
|
||||
if (elems.parse_error) {
|
||||
tdls_dbg(sdata, "Invalid IEs in TDLS channel switch resp\n");
|
||||
ret = -EINVAL;
|
||||
@ -1828,7 +1830,7 @@ ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
ieee802_11_parse_elems(tf->u.chan_switch_req.variable,
|
||||
skb->len - baselen, false, &elems);
|
||||
skb->len - baselen, false, &elems, NULL, NULL);
|
||||
if (elems.parse_error) {
|
||||
tdls_dbg(sdata, "Invalid IEs in TDLS channel switch req\n");
|
||||
return -EINVAL;
|
||||
|
@ -891,19 +891,18 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_queue_delayed_work);
|
||||
|
||||
u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
struct ieee802_11_elems *elems,
|
||||
u64 filter, u32 crc)
|
||||
static u32
|
||||
_ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
struct ieee802_11_elems *elems,
|
||||
u64 filter, u32 crc, u8 *transmitter_bssid,
|
||||
u8 *bss_bssid)
|
||||
{
|
||||
struct element *elem;
|
||||
const struct element *elem, *sub;
|
||||
bool calc_crc = filter != 0;
|
||||
DECLARE_BITMAP(seen_elems, 256);
|
||||
const u8 *ie;
|
||||
|
||||
bitmap_zero(seen_elems, 256);
|
||||
memset(elems, 0, sizeof(*elems));
|
||||
elems->ie_start = start;
|
||||
elems->total_len = len;
|
||||
|
||||
for_each_element(elem, start, len) {
|
||||
bool elem_parse_failed;
|
||||
@ -1209,6 +1208,57 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
if (elen >= sizeof(*elems->max_idle_period_ie))
|
||||
elems->max_idle_period_ie = (void *)pos;
|
||||
break;
|
||||
case WLAN_EID_MULTIPLE_BSSID:
|
||||
if (!bss_bssid || !transmitter_bssid || elen < 4)
|
||||
break;
|
||||
|
||||
elems->max_bssid_indicator = pos[0];
|
||||
|
||||
for_each_element(sub, pos + 1, elen - 1) {
|
||||
u8 sub_len = sub->datalen;
|
||||
u8 new_bssid[ETH_ALEN];
|
||||
const u8 *index;
|
||||
|
||||
/*
|
||||
* we only expect the "non-transmitted BSSID
|
||||
* profile" subelement (subelement id 0)
|
||||
*/
|
||||
if (sub->id != 0 || sub->datalen < 4) {
|
||||
/* not a valid BSS profile */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sub->data[0] != WLAN_EID_NON_TX_BSSID_CAP ||
|
||||
sub->data[1] != 2) {
|
||||
/* The first element of the
|
||||
* Nontransmitted BSSID Profile is not
|
||||
* the Nontransmitted BSSID Capability
|
||||
* element.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
/* found a Nontransmitted BSSID Profile */
|
||||
index = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX,
|
||||
sub->data, sub_len);
|
||||
if (!index || index[1] < 1 || index[2] == 0) {
|
||||
/* Invalid MBSSID Index element */
|
||||
continue;
|
||||
}
|
||||
|
||||
cfg80211_gen_new_bssid(transmitter_bssid,
|
||||
pos[0],
|
||||
index[2],
|
||||
new_bssid);
|
||||
if (ether_addr_equal(new_bssid, bss_bssid)) {
|
||||
elems->nontransmitted_bssid_profile =
|
||||
(void *)sub;
|
||||
elems->bssid_index_len = index[1];
|
||||
elems->bssid_index = (void *)&index[2];
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WLAN_EID_EXTENSION:
|
||||
if (pos[0] == WLAN_EID_EXT_HE_MU_EDCA &&
|
||||
elen >= (sizeof(*elems->mu_edca_param_set) + 1)) {
|
||||
@ -1224,6 +1274,10 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
elems->he_operation = (void *)&pos[1];
|
||||
} else if (pos[0] == WLAN_EID_EXT_UORA && elen >= 1) {
|
||||
elems->uora_element = (void *)&pos[1];
|
||||
} else if (pos[0] ==
|
||||
WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION &&
|
||||
elen == 3) {
|
||||
elems->mbssid_config_ie = (void *)&pos[1];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -1242,6 +1296,48 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
return crc;
|
||||
}
|
||||
|
||||
u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
struct ieee802_11_elems *elems,
|
||||
u64 filter, u32 crc, u8 *transmitter_bssid,
|
||||
u8 *bss_bssid)
|
||||
{
|
||||
memset(elems, 0, sizeof(*elems));
|
||||
elems->ie_start = start;
|
||||
elems->total_len = len;
|
||||
|
||||
crc = _ieee802_11_parse_elems_crc(start, len, action, elems, filter,
|
||||
crc, transmitter_bssid, bss_bssid);
|
||||
|
||||
/* Override with nontransmitted profile, if found */
|
||||
if (transmitter_bssid && elems->nontransmitted_bssid_profile) {
|
||||
const u8 *profile = elems->nontransmitted_bssid_profile;
|
||||
|
||||
_ieee802_11_parse_elems_crc(&profile[2], profile[1],
|
||||
action, elems, 0, 0,
|
||||
transmitter_bssid, bss_bssid);
|
||||
}
|
||||
|
||||
if (elems->tim && !elems->parse_error) {
|
||||
const struct ieee80211_tim_ie *tim_ie = elems->tim;
|
||||
|
||||
elems->dtim_period = tim_ie->dtim_period;
|
||||
elems->dtim_count = tim_ie->dtim_count;
|
||||
}
|
||||
|
||||
/* Override DTIM period and count if needed */
|
||||
if (elems->bssid_index &&
|
||||
elems->bssid_index_len >=
|
||||
offsetofend(struct ieee80211_bssid_index, dtim_period))
|
||||
elems->dtim_period = elems->bssid_index->dtim_period;
|
||||
|
||||
if (elems->bssid_index &&
|
||||
elems->bssid_index_len >=
|
||||
offsetofend(struct ieee80211_bssid_index, dtim_count))
|
||||
elems->dtim_count = elems->bssid_index->dtim_count;
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_tx_queue_params
|
||||
*qparam, int ac)
|
||||
|
@ -3,7 +3,7 @@
|
||||
* Wireless configuration interface internals.
|
||||
*
|
||||
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* Copyright (C) 2018-2019 Intel Corporation
|
||||
*/
|
||||
#ifndef __NET_WIRELESS_CORE_H
|
||||
#define __NET_WIRELESS_CORE_H
|
||||
@ -182,12 +182,23 @@ static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pu
|
||||
static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss)
|
||||
{
|
||||
atomic_inc(&bss->hold);
|
||||
if (bss->pub.transmitted_bss) {
|
||||
bss = container_of(bss->pub.transmitted_bss,
|
||||
struct cfg80211_internal_bss, pub);
|
||||
atomic_inc(&bss->hold);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss)
|
||||
{
|
||||
int r = atomic_dec_return(&bss->hold);
|
||||
WARN_ON(r < 0);
|
||||
if (bss->pub.transmitted_bss) {
|
||||
bss = container_of(bss->pub.transmitted_bss,
|
||||
struct cfg80211_internal_bss, pub);
|
||||
r = atomic_dec_return(&bss->hold);
|
||||
WARN_ON(r < 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2016 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018-2019 Intel Corporation
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
@ -109,6 +110,12 @@ static inline void bss_ref_get(struct cfg80211_registered_device *rdev,
|
||||
pub);
|
||||
bss->refcount++;
|
||||
}
|
||||
if (bss->pub.transmitted_bss) {
|
||||
bss = container_of(bss->pub.transmitted_bss,
|
||||
struct cfg80211_internal_bss,
|
||||
pub);
|
||||
bss->refcount++;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void bss_ref_put(struct cfg80211_registered_device *rdev,
|
||||
@ -125,6 +132,18 @@ static inline void bss_ref_put(struct cfg80211_registered_device *rdev,
|
||||
if (hbss->refcount == 0)
|
||||
bss_free(hbss);
|
||||
}
|
||||
|
||||
if (bss->pub.transmitted_bss) {
|
||||
struct cfg80211_internal_bss *tbss;
|
||||
|
||||
tbss = container_of(bss->pub.transmitted_bss,
|
||||
struct cfg80211_internal_bss,
|
||||
pub);
|
||||
tbss->refcount--;
|
||||
if (tbss->refcount == 0)
|
||||
bss_free(tbss);
|
||||
}
|
||||
|
||||
bss->refcount--;
|
||||
if (bss->refcount == 0)
|
||||
bss_free(bss);
|
||||
@ -150,6 +169,7 @@ static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev,
|
||||
}
|
||||
|
||||
list_del_init(&bss->list);
|
||||
list_del_init(&bss->pub.nontrans_list);
|
||||
rb_erase(&bss->rbn, &rdev->bss_tree);
|
||||
rdev->bss_entries--;
|
||||
WARN_ONCE((rdev->bss_entries == 0) ^ list_empty(&rdev->bss_list),
|
||||
@ -159,6 +179,162 @@ static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev,
|
||||
return true;
|
||||
}
|
||||
|
||||
static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
|
||||
const u8 *subelement, size_t subie_len,
|
||||
u8 *new_ie, gfp_t gfp)
|
||||
{
|
||||
u8 *pos, *tmp;
|
||||
const u8 *tmp_old, *tmp_new;
|
||||
u8 *sub_copy;
|
||||
|
||||
/* copy subelement as we need to change its content to
|
||||
* mark an ie after it is processed.
|
||||
*/
|
||||
sub_copy = kmalloc(subie_len, gfp);
|
||||
if (!sub_copy)
|
||||
return 0;
|
||||
memcpy(sub_copy, subelement, subie_len);
|
||||
|
||||
pos = &new_ie[0];
|
||||
|
||||
/* set new ssid */
|
||||
tmp_new = cfg80211_find_ie(WLAN_EID_SSID, sub_copy, subie_len);
|
||||
if (tmp_new) {
|
||||
memcpy(pos, tmp_new, tmp_new[1] + 2);
|
||||
pos += (tmp_new[1] + 2);
|
||||
}
|
||||
|
||||
/* go through IEs in ie (skip SSID) and subelement,
|
||||
* merge them into new_ie
|
||||
*/
|
||||
tmp_old = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen);
|
||||
tmp_old = (tmp_old) ? tmp_old + tmp_old[1] + 2 : ie;
|
||||
|
||||
while (tmp_old + tmp_old[1] + 2 - ie <= ielen) {
|
||||
if (tmp_old[0] == 0) {
|
||||
tmp_old++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tmp_old[0] == WLAN_EID_EXTENSION)
|
||||
tmp = (u8 *)cfg80211_find_ext_ie(tmp_old[2], sub_copy,
|
||||
subie_len);
|
||||
else
|
||||
tmp = (u8 *)cfg80211_find_ie(tmp_old[0], sub_copy,
|
||||
subie_len);
|
||||
|
||||
if (!tmp) {
|
||||
/* ie in old ie but not in subelement */
|
||||
if (tmp_old[0] != WLAN_EID_MULTIPLE_BSSID) {
|
||||
memcpy(pos, tmp_old, tmp_old[1] + 2);
|
||||
pos += tmp_old[1] + 2;
|
||||
}
|
||||
} else {
|
||||
/* ie in transmitting ie also in subelement,
|
||||
* copy from subelement and flag the ie in subelement
|
||||
* as copied (by setting eid field to WLAN_EID_SSID,
|
||||
* which is skipped anyway).
|
||||
* For vendor ie, compare OUI + type + subType to
|
||||
* determine if they are the same ie.
|
||||
*/
|
||||
if (tmp_old[0] == WLAN_EID_VENDOR_SPECIFIC) {
|
||||
if (!memcmp(tmp_old + 2, tmp + 2, 5)) {
|
||||
/* same vendor ie, copy from
|
||||
* subelement
|
||||
*/
|
||||
memcpy(pos, tmp, tmp[1] + 2);
|
||||
pos += tmp[1] + 2;
|
||||
tmp[0] = WLAN_EID_SSID;
|
||||
} else {
|
||||
memcpy(pos, tmp_old, tmp_old[1] + 2);
|
||||
pos += tmp_old[1] + 2;
|
||||
}
|
||||
} else {
|
||||
/* copy ie from subelement into new ie */
|
||||
memcpy(pos, tmp, tmp[1] + 2);
|
||||
pos += tmp[1] + 2;
|
||||
tmp[0] = WLAN_EID_SSID;
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp_old + tmp_old[1] + 2 - ie == ielen)
|
||||
break;
|
||||
|
||||
tmp_old += tmp_old[1] + 2;
|
||||
}
|
||||
|
||||
/* go through subelement again to check if there is any ie not
|
||||
* copied to new ie, skip ssid, capability, bssid-index ie
|
||||
*/
|
||||
tmp_new = sub_copy;
|
||||
while (tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
|
||||
if (!(tmp_new[0] == WLAN_EID_NON_TX_BSSID_CAP ||
|
||||
tmp_new[0] == WLAN_EID_SSID ||
|
||||
tmp_new[0] == WLAN_EID_MULTI_BSSID_IDX)) {
|
||||
memcpy(pos, tmp_new, tmp_new[1] + 2);
|
||||
pos += tmp_new[1] + 2;
|
||||
}
|
||||
if (tmp_new + tmp_new[1] + 2 - sub_copy == subie_len)
|
||||
break;
|
||||
tmp_new += tmp_new[1] + 2;
|
||||
}
|
||||
|
||||
kfree(sub_copy);
|
||||
return pos - new_ie;
|
||||
}
|
||||
|
||||
static bool is_bss(struct cfg80211_bss *a, const u8 *bssid,
|
||||
const u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
const u8 *ssidie;
|
||||
|
||||
if (bssid && !ether_addr_equal(a->bssid, bssid))
|
||||
return false;
|
||||
|
||||
if (!ssid)
|
||||
return true;
|
||||
|
||||
ies = rcu_access_pointer(a->ies);
|
||||
if (!ies)
|
||||
return false;
|
||||
ssidie = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len);
|
||||
if (!ssidie)
|
||||
return false;
|
||||
if (ssidie[1] != ssid_len)
|
||||
return false;
|
||||
return memcmp(ssidie + 2, ssid, ssid_len) == 0;
|
||||
}
|
||||
|
||||
static int
|
||||
cfg80211_add_nontrans_list(struct cfg80211_bss *trans_bss,
|
||||
struct cfg80211_bss *nontrans_bss)
|
||||
{
|
||||
const u8 *ssid;
|
||||
size_t ssid_len;
|
||||
struct cfg80211_bss *bss = NULL;
|
||||
|
||||
rcu_read_lock();
|
||||
ssid = ieee80211_bss_get_ie(nontrans_bss, WLAN_EID_SSID);
|
||||
if (!ssid) {
|
||||
rcu_read_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
ssid_len = ssid[1];
|
||||
ssid = ssid + 2;
|
||||
rcu_read_unlock();
|
||||
|
||||
/* check if nontrans_bss is in the list */
|
||||
list_for_each_entry(bss, &trans_bss->nontrans_list, nontrans_list) {
|
||||
if (is_bss(bss, nontrans_bss->bssid, ssid, ssid_len))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* add to the list */
|
||||
list_add_tail(&nontrans_bss->nontrans_list, &trans_bss->nontrans_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __cfg80211_bss_expire(struct cfg80211_registered_device *rdev,
|
||||
unsigned long expire_time)
|
||||
{
|
||||
@ -518,29 +694,6 @@ const struct element *cfg80211_find_vendor_elem(unsigned int oui, int oui_type,
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_find_vendor_elem);
|
||||
|
||||
static bool is_bss(struct cfg80211_bss *a, const u8 *bssid,
|
||||
const u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
const u8 *ssidie;
|
||||
|
||||
if (bssid && !ether_addr_equal(a->bssid, bssid))
|
||||
return false;
|
||||
|
||||
if (!ssid)
|
||||
return true;
|
||||
|
||||
ies = rcu_access_pointer(a->ies);
|
||||
if (!ies)
|
||||
return false;
|
||||
ssidie = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len);
|
||||
if (!ssidie)
|
||||
return false;
|
||||
if (ssidie[1] != ssid_len)
|
||||
return false;
|
||||
return memcmp(ssidie + 2, ssid, ssid_len) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* enum bss_compare_mode - BSS compare mode
|
||||
* @BSS_CMP_REGULAR: regular compare mode (for insertion and normal find)
|
||||
@ -875,6 +1028,12 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev,
|
||||
return true;
|
||||
}
|
||||
|
||||
struct cfg80211_non_tx_bss {
|
||||
struct cfg80211_bss *tx_bss;
|
||||
u8 max_bssid_indicator;
|
||||
u8 bssid_index;
|
||||
};
|
||||
|
||||
/* Returned bss is reference counted and must be cleaned up appropriately. */
|
||||
static struct cfg80211_internal_bss *
|
||||
cfg80211_bss_update(struct cfg80211_registered_device *rdev,
|
||||
@ -978,6 +1137,8 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
|
||||
memcpy(found->pub.chain_signal, tmp->pub.chain_signal,
|
||||
IEEE80211_MAX_CHAINS);
|
||||
ether_addr_copy(found->parent_bssid, tmp->parent_bssid);
|
||||
found->pub.max_bssid_indicator = tmp->pub.max_bssid_indicator;
|
||||
found->pub.bssid_index = tmp->pub.bssid_index;
|
||||
} else {
|
||||
struct cfg80211_internal_bss *new;
|
||||
struct cfg80211_internal_bss *hidden;
|
||||
@ -1002,6 +1163,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
|
||||
memcpy(new, tmp, sizeof(*new));
|
||||
new->refcount = 1;
|
||||
INIT_LIST_HEAD(&new->hidden_list);
|
||||
INIT_LIST_HEAD(&new->pub.nontrans_list);
|
||||
|
||||
if (rcu_access_pointer(tmp->pub.proberesp_ies)) {
|
||||
hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN);
|
||||
@ -1035,6 +1197,17 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
|
||||
goto drop;
|
||||
}
|
||||
|
||||
/* This must be before the call to bss_ref_get */
|
||||
if (tmp->pub.transmitted_bss) {
|
||||
struct cfg80211_internal_bss *pbss =
|
||||
container_of(tmp->pub.transmitted_bss,
|
||||
struct cfg80211_internal_bss,
|
||||
pub);
|
||||
|
||||
new->pub.transmitted_bss = tmp->pub.transmitted_bss;
|
||||
bss_ref_get(rdev, pbss);
|
||||
}
|
||||
|
||||
list_add_tail(&new->list, &rdev->bss_list);
|
||||
rdev->bss_entries++;
|
||||
rb_insert_bss(rdev, new);
|
||||
@ -1123,14 +1296,16 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
|
||||
}
|
||||
|
||||
/* Returned bss is reference counted and must be cleaned up appropriately. */
|
||||
struct cfg80211_bss *
|
||||
cfg80211_inform_bss_data(struct wiphy *wiphy,
|
||||
struct cfg80211_inform_bss *data,
|
||||
enum cfg80211_bss_frame_type ftype,
|
||||
const u8 *bssid, u64 tsf, u16 capability,
|
||||
u16 beacon_interval, const u8 *ie, size_t ielen,
|
||||
gfp_t gfp)
|
||||
static struct cfg80211_bss *
|
||||
cfg80211_inform_single_bss_data(struct wiphy *wiphy,
|
||||
struct cfg80211_inform_bss *data,
|
||||
enum cfg80211_bss_frame_type ftype,
|
||||
const u8 *bssid, u64 tsf, u16 capability,
|
||||
u16 beacon_interval, const u8 *ie, size_t ielen,
|
||||
struct cfg80211_non_tx_bss *non_tx_data,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||
struct cfg80211_bss_ies *ies;
|
||||
struct ieee80211_channel *channel;
|
||||
struct cfg80211_internal_bss tmp = {}, *res;
|
||||
@ -1156,6 +1331,11 @@ cfg80211_inform_bss_data(struct wiphy *wiphy,
|
||||
tmp.pub.beacon_interval = beacon_interval;
|
||||
tmp.pub.capability = capability;
|
||||
tmp.ts_boottime = data->boottime_ns;
|
||||
if (non_tx_data) {
|
||||
tmp.pub.transmitted_bss = non_tx_data->tx_bss;
|
||||
tmp.pub.bssid_index = non_tx_data->bssid_index;
|
||||
tmp.pub.max_bssid_indicator = non_tx_data->max_bssid_indicator;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we do not know here whether the IEs are from a Beacon or Probe
|
||||
@ -1202,19 +1382,247 @@ cfg80211_inform_bss_data(struct wiphy *wiphy,
|
||||
regulatory_hint_found_beacon(wiphy, channel, gfp);
|
||||
}
|
||||
|
||||
if (non_tx_data && non_tx_data->tx_bss) {
|
||||
/* this is a nontransmitting bss, we need to add it to
|
||||
* transmitting bss' list if it is not there
|
||||
*/
|
||||
if (cfg80211_add_nontrans_list(non_tx_data->tx_bss,
|
||||
&res->pub)) {
|
||||
if (__cfg80211_unlink_bss(rdev, res))
|
||||
rdev->bss_generation++;
|
||||
}
|
||||
}
|
||||
|
||||
trace_cfg80211_return_bss(&res->pub);
|
||||
/* cfg80211_bss_update gives us a referenced result */
|
||||
return &res->pub;
|
||||
}
|
||||
|
||||
static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
|
||||
struct cfg80211_inform_bss *data,
|
||||
enum cfg80211_bss_frame_type ftype,
|
||||
const u8 *bssid, u64 tsf,
|
||||
u16 beacon_interval, const u8 *ie,
|
||||
size_t ielen,
|
||||
struct cfg80211_non_tx_bss *non_tx_data,
|
||||
gfp_t gfp)
|
||||
{
|
||||
const u8 *mbssid_index_ie;
|
||||
const struct element *elem, *sub;
|
||||
size_t new_ie_len;
|
||||
u8 new_bssid[ETH_ALEN];
|
||||
u8 *new_ie;
|
||||
u16 capability;
|
||||
struct cfg80211_bss *bss;
|
||||
|
||||
if (!non_tx_data)
|
||||
return;
|
||||
if (!cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen))
|
||||
return;
|
||||
if (!wiphy->support_mbssid)
|
||||
return;
|
||||
if (wiphy->support_only_he_mbssid &&
|
||||
!cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, ie, ielen))
|
||||
return;
|
||||
|
||||
new_ie = kmalloc(IEEE80211_MAX_DATA_LEN, gfp);
|
||||
if (!new_ie)
|
||||
return;
|
||||
|
||||
for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, ie, ielen) {
|
||||
if (elem->datalen < 4)
|
||||
continue;
|
||||
for_each_element(sub, elem->data + 1, elem->datalen - 1) {
|
||||
if (sub->id != 0 || sub->datalen < 4) {
|
||||
/* not a valid BSS profile */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sub->data[0] != WLAN_EID_NON_TX_BSSID_CAP ||
|
||||
sub->data[1] != 2) {
|
||||
/* The first element within the Nontransmitted
|
||||
* BSSID Profile is not the Nontransmitted
|
||||
* BSSID Capability element.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
/* found a Nontransmitted BSSID Profile */
|
||||
mbssid_index_ie = cfg80211_find_ie
|
||||
(WLAN_EID_MULTI_BSSID_IDX,
|
||||
sub->data, sub->datalen);
|
||||
if (!mbssid_index_ie || mbssid_index_ie[1] < 1 ||
|
||||
mbssid_index_ie[2] == 0) {
|
||||
/* No valid Multiple BSSID-Index element */
|
||||
continue;
|
||||
}
|
||||
|
||||
non_tx_data->bssid_index = mbssid_index_ie[2];
|
||||
non_tx_data->max_bssid_indicator = elem->data[0];
|
||||
|
||||
cfg80211_gen_new_bssid(bssid,
|
||||
non_tx_data->max_bssid_indicator,
|
||||
non_tx_data->bssid_index,
|
||||
new_bssid);
|
||||
memset(new_ie, 0, IEEE80211_MAX_DATA_LEN);
|
||||
new_ie_len = cfg80211_gen_new_ie(ie, ielen, sub->data,
|
||||
sub->datalen, new_ie,
|
||||
gfp);
|
||||
if (!new_ie_len)
|
||||
continue;
|
||||
|
||||
capability = get_unaligned_le16(sub->data + 2);
|
||||
bss = cfg80211_inform_single_bss_data(wiphy, data,
|
||||
ftype,
|
||||
new_bssid, tsf,
|
||||
capability,
|
||||
beacon_interval,
|
||||
new_ie,
|
||||
new_ie_len,
|
||||
non_tx_data,
|
||||
gfp);
|
||||
if (!bss)
|
||||
break;
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(new_ie);
|
||||
}
|
||||
|
||||
struct cfg80211_bss *
|
||||
cfg80211_inform_bss_data(struct wiphy *wiphy,
|
||||
struct cfg80211_inform_bss *data,
|
||||
enum cfg80211_bss_frame_type ftype,
|
||||
const u8 *bssid, u64 tsf, u16 capability,
|
||||
u16 beacon_interval, const u8 *ie, size_t ielen,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct cfg80211_bss *res;
|
||||
struct cfg80211_non_tx_bss non_tx_data;
|
||||
|
||||
res = cfg80211_inform_single_bss_data(wiphy, data, ftype, bssid, tsf,
|
||||
capability, beacon_interval, ie,
|
||||
ielen, NULL, gfp);
|
||||
non_tx_data.tx_bss = res;
|
||||
cfg80211_parse_mbssid_data(wiphy, data, ftype, bssid, tsf,
|
||||
beacon_interval, ie, ielen, &non_tx_data,
|
||||
gfp);
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_inform_bss_data);
|
||||
|
||||
/* cfg80211_inform_bss_width_frame helper */
|
||||
struct cfg80211_bss *
|
||||
cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
|
||||
struct cfg80211_inform_bss *data,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
gfp_t gfp)
|
||||
static void
|
||||
cfg80211_parse_mbssid_frame_data(struct wiphy *wiphy,
|
||||
struct cfg80211_inform_bss *data,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
struct cfg80211_non_tx_bss *non_tx_data,
|
||||
gfp_t gfp)
|
||||
{
|
||||
enum cfg80211_bss_frame_type ftype;
|
||||
const u8 *ie = mgmt->u.probe_resp.variable;
|
||||
size_t ielen = len - offsetof(struct ieee80211_mgmt,
|
||||
u.probe_resp.variable);
|
||||
|
||||
ftype = ieee80211_is_beacon(mgmt->frame_control) ?
|
||||
CFG80211_BSS_FTYPE_BEACON : CFG80211_BSS_FTYPE_PRESP;
|
||||
|
||||
cfg80211_parse_mbssid_data(wiphy, data, ftype, mgmt->bssid,
|
||||
le64_to_cpu(mgmt->u.probe_resp.timestamp),
|
||||
le16_to_cpu(mgmt->u.probe_resp.beacon_int),
|
||||
ie, ielen, non_tx_data, gfp);
|
||||
}
|
||||
|
||||
static void
|
||||
cfg80211_update_notlisted_nontrans(struct wiphy *wiphy,
|
||||
struct cfg80211_bss *nontrans_bss,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
gfp_t gfp)
|
||||
{
|
||||
u8 *ie, *new_ie, *pos;
|
||||
const u8 *nontrans_ssid, *trans_ssid, *mbssid;
|
||||
size_t ielen = len - offsetof(struct ieee80211_mgmt,
|
||||
u.probe_resp.variable);
|
||||
size_t new_ie_len;
|
||||
struct cfg80211_bss_ies *new_ies;
|
||||
const struct cfg80211_bss_ies *old;
|
||||
u8 cpy_len;
|
||||
|
||||
ie = mgmt->u.probe_resp.variable;
|
||||
|
||||
new_ie_len = ielen;
|
||||
trans_ssid = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen);
|
||||
if (!trans_ssid)
|
||||
return;
|
||||
new_ie_len -= trans_ssid[1];
|
||||
mbssid = cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen);
|
||||
if (!mbssid)
|
||||
return;
|
||||
new_ie_len -= mbssid[1];
|
||||
rcu_read_lock();
|
||||
nontrans_ssid = ieee80211_bss_get_ie(nontrans_bss, WLAN_EID_SSID);
|
||||
if (!nontrans_ssid) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
new_ie_len += nontrans_ssid[1];
|
||||
rcu_read_unlock();
|
||||
|
||||
/* generate new ie for nontrans BSS
|
||||
* 1. replace SSID with nontrans BSS' SSID
|
||||
* 2. skip MBSSID IE
|
||||
*/
|
||||
new_ie = kzalloc(new_ie_len, gfp);
|
||||
if (!new_ie)
|
||||
return;
|
||||
new_ies = kzalloc(sizeof(*new_ies) + new_ie_len, gfp);
|
||||
if (!new_ies)
|
||||
goto out_free;
|
||||
|
||||
pos = new_ie;
|
||||
|
||||
/* copy the nontransmitted SSID */
|
||||
cpy_len = nontrans_ssid[1] + 2;
|
||||
memcpy(pos, nontrans_ssid, cpy_len);
|
||||
pos += cpy_len;
|
||||
/* copy the IEs between SSID and MBSSID */
|
||||
cpy_len = trans_ssid[1] + 2;
|
||||
memcpy(pos, (trans_ssid + cpy_len), (mbssid - (trans_ssid + cpy_len)));
|
||||
pos += (mbssid - (trans_ssid + cpy_len));
|
||||
/* copy the IEs after MBSSID */
|
||||
cpy_len = mbssid[1] + 2;
|
||||
memcpy(pos, mbssid + cpy_len, ((ie + ielen) - (mbssid + cpy_len)));
|
||||
|
||||
/* update ie */
|
||||
new_ies->len = new_ie_len;
|
||||
new_ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
|
||||
new_ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control);
|
||||
memcpy(new_ies->data, new_ie, new_ie_len);
|
||||
if (ieee80211_is_probe_resp(mgmt->frame_control)) {
|
||||
old = rcu_access_pointer(nontrans_bss->proberesp_ies);
|
||||
rcu_assign_pointer(nontrans_bss->proberesp_ies, new_ies);
|
||||
rcu_assign_pointer(nontrans_bss->ies, new_ies);
|
||||
if (old)
|
||||
kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
|
||||
} else {
|
||||
old = rcu_access_pointer(nontrans_bss->beacon_ies);
|
||||
rcu_assign_pointer(nontrans_bss->beacon_ies, new_ies);
|
||||
rcu_assign_pointer(nontrans_bss->ies, new_ies);
|
||||
if (old)
|
||||
kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
|
||||
}
|
||||
|
||||
out_free:
|
||||
kfree(new_ie);
|
||||
}
|
||||
|
||||
/* cfg80211_inform_bss_width_frame helper */
|
||||
static struct cfg80211_bss *
|
||||
cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
|
||||
struct cfg80211_inform_bss *data,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
struct cfg80211_non_tx_bss *non_tx_data,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct cfg80211_internal_bss tmp = {}, *res;
|
||||
struct cfg80211_bss_ies *ies;
|
||||
@ -1272,6 +1680,11 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
|
||||
tmp.pub.chains = data->chains;
|
||||
memcpy(tmp.pub.chain_signal, data->chain_signal, IEEE80211_MAX_CHAINS);
|
||||
ether_addr_copy(tmp.parent_bssid, data->parent_bssid);
|
||||
if (non_tx_data) {
|
||||
tmp.pub.transmitted_bss = non_tx_data->tx_bss;
|
||||
tmp.pub.bssid_index = non_tx_data->bssid_index;
|
||||
tmp.pub.max_bssid_indicator = non_tx_data->max_bssid_indicator;
|
||||
}
|
||||
|
||||
signal_valid = abs(data->chan->center_freq - channel->center_freq) <=
|
||||
wiphy->max_adj_channel_rssi_comp;
|
||||
@ -1293,6 +1706,53 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
|
||||
/* cfg80211_bss_update gives us a referenced result */
|
||||
return &res->pub;
|
||||
}
|
||||
|
||||
struct cfg80211_bss *
|
||||
cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
|
||||
struct cfg80211_inform_bss *data,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct cfg80211_bss *res, *tmp_bss;
|
||||
const u8 *ie = mgmt->u.probe_resp.variable;
|
||||
const struct cfg80211_bss_ies *ies1, *ies2;
|
||||
size_t ielen = len - offsetof(struct ieee80211_mgmt,
|
||||
u.probe_resp.variable);
|
||||
struct cfg80211_non_tx_bss non_tx_data;
|
||||
|
||||
res = cfg80211_inform_single_bss_frame_data(wiphy, data, mgmt,
|
||||
len, NULL, gfp);
|
||||
if (!res || !wiphy->support_mbssid ||
|
||||
!cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen))
|
||||
return res;
|
||||
if (wiphy->support_only_he_mbssid &&
|
||||
!cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, ie, ielen))
|
||||
return res;
|
||||
|
||||
non_tx_data.tx_bss = res;
|
||||
/* process each non-transmitting bss */
|
||||
cfg80211_parse_mbssid_frame_data(wiphy, data, mgmt, len,
|
||||
&non_tx_data, gfp);
|
||||
|
||||
/* check if the res has other nontransmitting bss which is not
|
||||
* in MBSSID IE
|
||||
*/
|
||||
ies1 = rcu_access_pointer(res->ies);
|
||||
|
||||
/* go through nontrans_list, if the timestamp of the BSS is
|
||||
* earlier than the timestamp of the transmitting BSS then
|
||||
* update it
|
||||
*/
|
||||
list_for_each_entry(tmp_bss, &res->nontrans_list,
|
||||
nontrans_list) {
|
||||
ies2 = rcu_access_pointer(tmp_bss->ies);
|
||||
if (ies2->tsf < ies1->tsf)
|
||||
cfg80211_update_notlisted_nontrans(wiphy, tmp_bss,
|
||||
mgmt, len, gfp);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_inform_bss_frame_data);
|
||||
|
||||
void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
|
||||
@ -1330,7 +1790,8 @@ EXPORT_SYMBOL(cfg80211_put_bss);
|
||||
void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||
struct cfg80211_internal_bss *bss;
|
||||
struct cfg80211_internal_bss *bss, *tmp1;
|
||||
struct cfg80211_bss *nontrans_bss, *tmp;
|
||||
|
||||
if (WARN_ON(!pub))
|
||||
return;
|
||||
@ -1338,10 +1799,21 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
|
||||
bss = container_of(pub, struct cfg80211_internal_bss, pub);
|
||||
|
||||
spin_lock_bh(&rdev->bss_lock);
|
||||
if (!list_empty(&bss->list)) {
|
||||
if (__cfg80211_unlink_bss(rdev, bss))
|
||||
if (list_empty(&bss->list))
|
||||
goto out;
|
||||
|
||||
list_for_each_entry_safe(nontrans_bss, tmp,
|
||||
&pub->nontrans_list,
|
||||
nontrans_list) {
|
||||
tmp1 = container_of(nontrans_bss,
|
||||
struct cfg80211_internal_bss, pub);
|
||||
if (__cfg80211_unlink_bss(rdev, tmp1))
|
||||
rdev->bss_generation++;
|
||||
}
|
||||
|
||||
if (__cfg80211_unlink_bss(rdev, bss))
|
||||
rdev->bss_generation++;
|
||||
out:
|
||||
spin_unlock_bh(&rdev->bss_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_unlink_bss);
|
||||
|
Loading…
Reference in New Issue
Block a user