Here's another set of patches for the current cycle:

* I merged net-next back to avoid a conflict with the
  * cfg80211 scheduled scan API extensions
  * preparations for better scan result timestamping
  * regulatory cleanups
  * mac80211 statistics cleanups
  * a few other small cleanups and fixes
 -----BEGIN PGP SIGNATURE-----
 
 iQIcBAABCAAGBQJWJ6lbAAoJEDBSmw7B7bqraasP/Ryaa7zL10E+dOQtqBQHQeMe
 olbrCUtTYltr4nnuESzh5WPeIVZBQ0DIduoLLF0IDSPVwE/NrbpFUVIMHvJvr+s7
 rE9k8RB4P7BMTjf+mkDX1Od9kCKGkt4ezcyt/oNIsqM12SN9JQ99itwz6Mp94xCs
 XKsiXJRh9f/8Qwd/74qQq1Va3UfGAVuKO8WpUe/A7TYTla8ZY20pv1D8kQKQzrFg
 DwsMirjmHcUpobSjnPAAmZevRxdk6o0E+P7DYG172H2Tm8/EIMR/gYMnQeYW6HkA
 lfMMDfAGmNvyRm8v1iuBLodREP4kn4VbhMSZDtH7D6FYfmJh5fSeG09bSe51G5Xh
 zv/B8A1cCbWFqtQHp3wI6ml8VDyAhDc2Hvqb75KRn6FplIkEiszVP0y3cNHWiJVt
 Ix6Sysoa6kQDXEgR50APeLJ3VI+/mhXmvIila4jP9PKhO14SDHrCoRQO62Z0COJ7
 2E5Ir2KE8T+O9mSeuB7m8xD/t60HDd3q3tLZmH0Ps6xfxKf9y2hdZacbX4Hi5Mqk
 2XxXZYnhAXUqZmZhmG3ajnEiB4UGMt21R7dIqNTaQ9chOGBkHqIZxPm82XtNb13h
 yHILavGpUDT0z6OB2z8fxUcj4a4SrrK+aiIGh4iFpDR0Nu0IyZ5cPHXY2FfvJWmD
 ZO74RMEpBodYR8BsV4yP
 =uZ5N
 -----END PGP SIGNATURE-----

Merge tag 'mac80211-next-for-davem-2015-10-21' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next

Johannes Berg says:

====================
Here's another set of patches for the current cycle:
 * I merged net-next back to avoid a conflict with the
 * cfg80211 scheduled scan API extensions
 * preparations for better scan result timestamping
 * regulatory cleanups
 * mac80211 statistics cleanups
 * a few other small cleanups and fixes
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2015-10-22 07:28:41 -07:00
commit e9829b9745
41 changed files with 911 additions and 660 deletions

View File

@ -154,8 +154,9 @@
!Finclude/net/cfg80211.h cfg80211_scan_request !Finclude/net/cfg80211.h cfg80211_scan_request
!Finclude/net/cfg80211.h cfg80211_scan_done !Finclude/net/cfg80211.h cfg80211_scan_done
!Finclude/net/cfg80211.h cfg80211_bss !Finclude/net/cfg80211.h cfg80211_bss
!Finclude/net/cfg80211.h cfg80211_inform_bss_width_frame !Finclude/net/cfg80211.h cfg80211_inform_bss
!Finclude/net/cfg80211.h cfg80211_inform_bss_width !Finclude/net/cfg80211.h cfg80211_inform_bss_frame_data
!Finclude/net/cfg80211.h cfg80211_inform_bss_data
!Finclude/net/cfg80211.h cfg80211_unlink_bss !Finclude/net/cfg80211.h cfg80211_unlink_bss
!Finclude/net/cfg80211.h cfg80211_find_ie !Finclude/net/cfg80211.h cfg80211_find_ie
!Finclude/net/cfg80211.h ieee80211_bss_get_ie !Finclude/net/cfg80211.h ieee80211_bss_get_ie

View File

@ -3312,7 +3312,7 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
} }
/* fw uses seconds, also make sure that it's >0 */ /* fw uses seconds, also make sure that it's >0 */
interval = max_t(u16, 1, request->interval / 1000); interval = max_t(u16, 1, request->scan_plans[0].interval);
ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
interval, interval, interval, interval,

View File

@ -630,6 +630,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
kfree(mvm->d3_resume_sram); kfree(mvm->d3_resume_sram);
if (mvm->nd_config) { if (mvm->nd_config) {
kfree(mvm->nd_config->match_sets); kfree(mvm->nd_config->match_sets);
kfree(mvm->nd_config->scan_plans);
kfree(mvm->nd_config); kfree(mvm->nd_config);
mvm->nd_config = NULL; mvm->nd_config = NULL;
} }

View File

@ -1271,12 +1271,12 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
params.type = iwl_mvm_get_scan_type(mvm, vif, &params); params.type = iwl_mvm_get_scan_type(mvm, vif, &params);
if (req->interval > U16_MAX) { if (req->scan_plans[0].interval > U16_MAX) {
IWL_DEBUG_SCAN(mvm, IWL_DEBUG_SCAN(mvm,
"interval value is > 16-bits, set to max possible\n"); "interval value is > 16-bits, set to max possible\n");
params.interval = U16_MAX; params.interval = U16_MAX;
} else { } else {
params.interval = req->interval / MSEC_PER_SEC; params.interval = req->scan_plans[0].interval;
} }
/* In theory, LMAC scans can handle a 32-bit delay, but since /* In theory, LMAC scans can handle a 32-bit delay, but since

View File

@ -266,7 +266,7 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
if (beacon_diff > beacon_int) if (beacon_diff > beacon_int)
beacon_diff = 0; beacon_diff = 0;
autowake_timeout = (conf->max_sleep_period * beacon_int) - beacon_diff; autowake_timeout = (conf->ps_dtim_period * beacon_int) - beacon_diff;
queue_delayed_work(rt2x00dev->workqueue, queue_delayed_work(rt2x00dev->workqueue,
&rt2x00dev->autowakeup_work, &rt2x00dev->autowakeup_work,
autowake_timeout - 15); autowake_timeout - 15);

View File

@ -350,7 +350,8 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
cfg->bss_type = SCAN_BSS_TYPE_ANY; cfg->bss_type = SCAN_BSS_TYPE_ANY;
/* currently NL80211 supports only a single interval */ /* currently NL80211 supports only a single interval */
for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++) for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++)
cfg->intervals[i] = cpu_to_le32(req->interval); cfg->intervals[i] = cpu_to_le32(req->scan_plans[0].interval *
MSEC_PER_SEC);
cfg->ssid_len = 0; cfg->ssid_len = 0;
ret = wlcore_scan_sched_scan_ssid_list(wl, wlvif, req); ret = wlcore_scan_sched_scan_ssid_list(wl, wlvif, req);

View File

@ -228,13 +228,15 @@ int wl18xx_scan_sched_scan_config(struct wl1271 *wl,
wl18xx_adjust_channels(cmd, cmd_channels); wl18xx_adjust_channels(cmd, cmd_channels);
if (c->num_short_intervals && c->long_interval && if (c->num_short_intervals && c->long_interval &&
c->long_interval > req->interval) { c->long_interval > req->scan_plans[0].interval * MSEC_PER_SEC) {
cmd->short_cycles_msec = cpu_to_le16(req->interval); cmd->short_cycles_msec =
cpu_to_le16(req->scan_plans[0].interval * MSEC_PER_SEC);
cmd->long_cycles_msec = cpu_to_le16(c->long_interval); cmd->long_cycles_msec = cpu_to_le16(c->long_interval);
cmd->short_cycles_count = c->num_short_intervals; cmd->short_cycles_count = c->num_short_intervals;
} else { } else {
cmd->short_cycles_msec = 0; cmd->short_cycles_msec = 0;
cmd->long_cycles_msec = cpu_to_le16(req->interval); cmd->long_cycles_msec =
cpu_to_le16(req->scan_plans[0].interval * MSEC_PER_SEC);
cmd->short_cycles_count = 0; cmd->short_cycles_count = 0;
} }
wl1271_debug(DEBUG_SCAN, "short_interval: %d, long_interval: %d, num_short: %d", wl1271_debug(DEBUG_SCAN, "short_interval: %d, long_interval: %d, num_short: %d",

View File

@ -1932,6 +1932,8 @@ enum ieee80211_category {
WLAN_CATEGORY_HT = 7, WLAN_CATEGORY_HT = 7,
WLAN_CATEGORY_SA_QUERY = 8, WLAN_CATEGORY_SA_QUERY = 8,
WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9, WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9,
WLAN_CATEGORY_WNM = 10,
WLAN_CATEGORY_WNM_UNPROTECTED = 11,
WLAN_CATEGORY_TDLS = 12, WLAN_CATEGORY_TDLS = 12,
WLAN_CATEGORY_MESH_ACTION = 13, WLAN_CATEGORY_MESH_ACTION = 13,
WLAN_CATEGORY_MULTIHOP_ACTION = 14, WLAN_CATEGORY_MULTIHOP_ACTION = 14,
@ -2396,7 +2398,10 @@ static inline bool _ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)
category = ((u8 *) hdr) + 24; category = ((u8 *) hdr) + 24;
return *category != WLAN_CATEGORY_PUBLIC && return *category != WLAN_CATEGORY_PUBLIC &&
*category != WLAN_CATEGORY_HT && *category != WLAN_CATEGORY_HT &&
*category != WLAN_CATEGORY_WNM_UNPROTECTED &&
*category != WLAN_CATEGORY_SELF_PROTECTED && *category != WLAN_CATEGORY_SELF_PROTECTED &&
*category != WLAN_CATEGORY_UNPROT_DMG &&
*category != WLAN_CATEGORY_VHT &&
*category != WLAN_CATEGORY_VENDOR_SPECIFIC; *category != WLAN_CATEGORY_VENDOR_SPECIFIC;
} }

View File

@ -5,6 +5,7 @@
* *
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright 2015 Intel Deutschland GmbH
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
@ -1500,6 +1501,20 @@ struct cfg80211_match_set {
s32 rssi_thold; s32 rssi_thold;
}; };
/**
* struct cfg80211_sched_scan_plan - scan plan for scheduled scan
*
* @interval: interval between scheduled scan iterations. In seconds.
* @iterations: number of scan iterations in this scan plan. Zero means
* infinite loop.
* The last scan plan will always have this parameter set to zero,
* all other scan plans will have a finite number of iterations.
*/
struct cfg80211_sched_scan_plan {
u32 interval;
u32 iterations;
};
/** /**
* struct cfg80211_sched_scan_request - scheduled scan request description * struct cfg80211_sched_scan_request - scheduled scan request description
* *
@ -1507,7 +1522,6 @@ struct cfg80211_match_set {
* @n_ssids: number of SSIDs * @n_ssids: number of SSIDs
* @n_channels: total number of channels to scan * @n_channels: total number of channels to scan
* @scan_width: channel width for scanning * @scan_width: channel width for scanning
* @interval: interval between each scheduled scan cycle
* @ie: optional information element(s) to add into Probe Request or %NULL * @ie: optional information element(s) to add into Probe Request or %NULL
* @ie_len: length of ie in octets * @ie_len: length of ie in octets
* @flags: bit field of flags controlling operation * @flags: bit field of flags controlling operation
@ -1526,6 +1540,9 @@ struct cfg80211_match_set {
* @mac_addr_mask: MAC address mask used with randomisation, bits that * @mac_addr_mask: MAC address mask used with randomisation, bits that
* are 0 in the mask should be randomised, bits that are 1 should * are 0 in the mask should be randomised, bits that are 1 should
* be taken from the @mac_addr * be taken from the @mac_addr
* @scan_plans: scan plans to be executed in this scheduled scan. Lowest
* index must be executed first.
* @n_scan_plans: number of scan plans, at least 1.
* @rcu_head: RCU callback used to free the struct * @rcu_head: RCU callback used to free the struct
* @owner_nlportid: netlink portid of owner (if this should is a request * @owner_nlportid: netlink portid of owner (if this should is a request
* owned by a particular socket) * owned by a particular socket)
@ -1539,7 +1556,6 @@ struct cfg80211_sched_scan_request {
int n_ssids; int n_ssids;
u32 n_channels; u32 n_channels;
enum nl80211_bss_scan_width scan_width; enum nl80211_bss_scan_width scan_width;
u32 interval;
const u8 *ie; const u8 *ie;
size_t ie_len; size_t ie_len;
u32 flags; u32 flags;
@ -1547,6 +1563,8 @@ struct cfg80211_sched_scan_request {
int n_match_sets; int n_match_sets;
s32 min_rssi_thold; s32 min_rssi_thold;
u32 delay; u32 delay;
struct cfg80211_sched_scan_plan *scan_plans;
int n_scan_plans;
u8 mac_addr[ETH_ALEN] __aligned(2); u8 mac_addr[ETH_ALEN] __aligned(2);
u8 mac_addr_mask[ETH_ALEN] __aligned(2); u8 mac_addr_mask[ETH_ALEN] __aligned(2);
@ -1575,6 +1593,26 @@ enum cfg80211_signal_type {
CFG80211_SIGNAL_TYPE_UNSPEC, CFG80211_SIGNAL_TYPE_UNSPEC,
}; };
/**
* struct cfg80211_inform_bss - BSS inform data
* @chan: channel the frame was received on
* @scan_width: scan width that was used
* @signal: signal strength value, according to the wiphy's
* signal type
* @boottime_ns: timestamp (CLOCK_BOOTTIME) when the information was
* received; should match the time when the frame was actually
* received by the device (not just by the host, in case it was
* buffered on the device) and be accurate to about 10ms.
* If the frame isn't buffered, just passing the return value of
* ktime_get_boot_ns() is likely appropriate.
*/
struct cfg80211_inform_bss {
struct ieee80211_channel *chan;
enum nl80211_bss_scan_width scan_width;
s32 signal;
u64 boottime_ns;
};
/** /**
* struct cfg80211_bss_ie_data - BSS entry IE data * struct cfg80211_bss_ie_data - BSS entry IE data
* @tsf: TSF contained in the frame that carried these IEs * @tsf: TSF contained in the frame that carried these IEs
@ -3056,6 +3094,12 @@ struct wiphy_vendor_command {
* include fixed IEs like supported rates * include fixed IEs like supported rates
* @max_sched_scan_ie_len: same as max_scan_ie_len, but for scheduled * @max_sched_scan_ie_len: same as max_scan_ie_len, but for scheduled
* scans * scans
* @max_sched_scan_plans: maximum number of scan plans (scan interval and number
* of iterations) for scheduled scan supported by the device.
* @max_sched_scan_plan_interval: maximum interval (in seconds) for a
* single scan plan supported by the device.
* @max_sched_scan_plan_iterations: maximum number of iterations for a single
* scan plan supported by the device.
* @coverage_class: current coverage class * @coverage_class: current coverage class
* @fw_version: firmware version for ethtool reporting * @fw_version: firmware version for ethtool reporting
* @hw_version: hardware version for ethtool reporting * @hw_version: hardware version for ethtool reporting
@ -3163,6 +3207,9 @@ struct wiphy {
u8 max_match_sets; u8 max_match_sets;
u16 max_scan_ie_len; u16 max_scan_ie_len;
u16 max_sched_scan_ie_len; u16 max_sched_scan_ie_len;
u32 max_sched_scan_plans;
u32 max_sched_scan_plan_interval;
u32 max_sched_scan_plan_iterations;
int n_cipher_suites; int n_cipher_suites;
const u32 *cipher_suites; const u32 *cipher_suites;
@ -3958,14 +4005,11 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy);
void cfg80211_sched_scan_stopped_rtnl(struct wiphy *wiphy); void cfg80211_sched_scan_stopped_rtnl(struct wiphy *wiphy);
/** /**
* cfg80211_inform_bss_width_frame - inform cfg80211 of a received BSS frame * cfg80211_inform_bss_frame_data - inform cfg80211 of a received BSS frame
*
* @wiphy: the wiphy reporting the BSS * @wiphy: the wiphy reporting the BSS
* @rx_channel: The channel the frame was received on * @data: the BSS metadata
* @scan_width: width of the control channel
* @mgmt: the management frame (probe response or beacon) * @mgmt: the management frame (probe response or beacon)
* @len: length of the management frame * @len: length of the management frame
* @signal: the signal strength, type depends on the wiphy's signal_type
* @gfp: context flags * @gfp: context flags
* *
* This informs cfg80211 that BSS information was found and * This informs cfg80211 that BSS information was found and
@ -3975,11 +4019,26 @@ void cfg80211_sched_scan_stopped_rtnl(struct wiphy *wiphy);
* Or %NULL on error. * Or %NULL on error.
*/ */
struct cfg80211_bss * __must_check struct cfg80211_bss * __must_check
cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
struct cfg80211_inform_bss *data,
struct ieee80211_mgmt *mgmt, size_t len,
gfp_t gfp);
static inline struct cfg80211_bss * __must_check
cfg80211_inform_bss_width_frame(struct wiphy *wiphy, cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
struct ieee80211_channel *rx_channel, struct ieee80211_channel *rx_channel,
enum nl80211_bss_scan_width scan_width, enum nl80211_bss_scan_width scan_width,
struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_mgmt *mgmt, size_t len,
s32 signal, gfp_t gfp); s32 signal, gfp_t gfp)
{
struct cfg80211_inform_bss data = {
.chan = rx_channel,
.scan_width = scan_width,
.signal = signal,
};
return cfg80211_inform_bss_frame_data(wiphy, &data, mgmt, len, gfp);
}
static inline struct cfg80211_bss * __must_check static inline struct cfg80211_bss * __must_check
cfg80211_inform_bss_frame(struct wiphy *wiphy, cfg80211_inform_bss_frame(struct wiphy *wiphy,
@ -3987,9 +4046,13 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_mgmt *mgmt, size_t len,
s32 signal, gfp_t gfp) s32 signal, gfp_t gfp)
{ {
return cfg80211_inform_bss_width_frame(wiphy, rx_channel, struct cfg80211_inform_bss data = {
NL80211_BSS_CHAN_WIDTH_20, .chan = rx_channel,
mgmt, len, signal, gfp); .scan_width = NL80211_BSS_CHAN_WIDTH_20,
.signal = signal,
};
return cfg80211_inform_bss_frame_data(wiphy, &data, mgmt, len, gfp);
} }
/** /**
@ -4006,11 +4069,10 @@ enum cfg80211_bss_frame_type {
}; };
/** /**
* cfg80211_inform_bss_width - inform cfg80211 of a new BSS * cfg80211_inform_bss_data - inform cfg80211 of a new BSS
* *
* @wiphy: the wiphy reporting the BSS * @wiphy: the wiphy reporting the BSS
* @rx_channel: The channel the frame was received on * @data: the BSS metadata
* @scan_width: width of the control channel
* @ftype: frame type (if known) * @ftype: frame type (if known)
* @bssid: the BSSID of the BSS * @bssid: the BSSID of the BSS
* @tsf: the TSF sent by the peer in the beacon/probe response (or 0) * @tsf: the TSF sent by the peer in the beacon/probe response (or 0)
@ -4018,7 +4080,6 @@ enum cfg80211_bss_frame_type {
* @beacon_interval: the beacon interval announced by the peer * @beacon_interval: the beacon interval announced by the peer
* @ie: additional IEs sent by the peer * @ie: additional IEs sent by the peer
* @ielen: length of the additional IEs * @ielen: length of the additional IEs
* @signal: the signal strength, type depends on the wiphy's signal_type
* @gfp: context flags * @gfp: context flags
* *
* This informs cfg80211 that BSS information was found and * This informs cfg80211 that BSS information was found and
@ -4028,13 +4089,32 @@ enum cfg80211_bss_frame_type {
* Or %NULL on error. * Or %NULL on error.
*/ */
struct cfg80211_bss * __must_check struct cfg80211_bss * __must_check
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 inline struct cfg80211_bss * __must_check
cfg80211_inform_bss_width(struct wiphy *wiphy, cfg80211_inform_bss_width(struct wiphy *wiphy,
struct ieee80211_channel *rx_channel, struct ieee80211_channel *rx_channel,
enum nl80211_bss_scan_width scan_width, enum nl80211_bss_scan_width scan_width,
enum cfg80211_bss_frame_type ftype, enum cfg80211_bss_frame_type ftype,
const u8 *bssid, u64 tsf, u16 capability, const u8 *bssid, u64 tsf, u16 capability,
u16 beacon_interval, const u8 *ie, size_t ielen, u16 beacon_interval, const u8 *ie, size_t ielen,
s32 signal, gfp_t gfp); s32 signal, gfp_t gfp)
{
struct cfg80211_inform_bss data = {
.chan = rx_channel,
.scan_width = scan_width,
.signal = signal,
};
return cfg80211_inform_bss_data(wiphy, &data, ftype, bssid, tsf,
capability, beacon_interval, ie, ielen,
gfp);
}
static inline struct cfg80211_bss * __must_check static inline struct cfg80211_bss * __must_check
cfg80211_inform_bss(struct wiphy *wiphy, cfg80211_inform_bss(struct wiphy *wiphy,
@ -4044,11 +4124,15 @@ cfg80211_inform_bss(struct wiphy *wiphy,
u16 beacon_interval, const u8 *ie, size_t ielen, u16 beacon_interval, const u8 *ie, size_t ielen,
s32 signal, gfp_t gfp) s32 signal, gfp_t gfp)
{ {
return cfg80211_inform_bss_width(wiphy, rx_channel, struct cfg80211_inform_bss data = {
NL80211_BSS_CHAN_WIDTH_20, ftype, .chan = rx_channel,
bssid, tsf, capability, .scan_width = NL80211_BSS_CHAN_WIDTH_20,
beacon_interval, ie, ielen, signal, .signal = signal,
gfp); };
return cfg80211_inform_bss_data(wiphy, &data, ftype, bssid, tsf,
capability, beacon_interval, ie, ielen,
gfp);
} }
struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,

View File

@ -1241,11 +1241,6 @@ enum ieee80211_smps_mode {
* @flags: configuration flags defined above * @flags: configuration flags defined above
* *
* @listen_interval: listen interval in units of beacon interval * @listen_interval: listen interval in units of beacon interval
* @max_sleep_period: the maximum number of beacon intervals to sleep for
* before checking the beacon for a TIM bit (managed mode only); this
* value will be only achievable between DTIM frames, the hardware
* needs to check for the multicast traffic bit in DTIM beacons.
* This variable is valid only when the CONF_PS flag is set.
* @ps_dtim_period: The DTIM period of the AP we're connected to, for use * @ps_dtim_period: The DTIM period of the AP we're connected to, for use
* in power saving. Power saving will not be enabled until a beacon * in power saving. Power saving will not be enabled until a beacon
* has been received and the DTIM period is known. * has been received and the DTIM period is known.
@ -1275,7 +1270,6 @@ enum ieee80211_smps_mode {
struct ieee80211_conf { struct ieee80211_conf {
u32 flags; u32 flags;
int power_level, dynamic_ps_timeout; int power_level, dynamic_ps_timeout;
int max_sleep_period;
u16 listen_interval; u16 listen_interval;
u8 ps_dtim_period; u8 ps_dtim_period;
@ -1683,6 +1677,7 @@ struct ieee80211_sta_rates {
* @tdls: indicates whether the STA is a TDLS peer * @tdls: indicates whether the STA is a TDLS peer
* @tdls_initiator: indicates the STA is an initiator of the TDLS link. Only * @tdls_initiator: indicates the STA is an initiator of the TDLS link. Only
* valid if the STA is a TDLS peer in the first place. * valid if the STA is a TDLS peer in the first place.
* @mfp: indicates whether the STA uses management frame protection or not.
* @txq: per-TID data TX queues (if driver uses the TXQ abstraction) * @txq: per-TID data TX queues (if driver uses the TXQ abstraction)
*/ */
struct ieee80211_sta { struct ieee80211_sta {
@ -1700,6 +1695,7 @@ struct ieee80211_sta {
struct ieee80211_sta_rates __rcu *rates; struct ieee80211_sta_rates __rcu *rates;
bool tdls; bool tdls;
bool tdls_initiator; bool tdls_initiator;
bool mfp;
struct ieee80211_txq *txq[IEEE80211_NUM_TIDS]; struct ieee80211_txq *txq[IEEE80211_NUM_TIDS];

View File

@ -10,6 +10,7 @@
* Copyright 2008, 2009 Luis R. Rodriguez <lrodriguez@atheros.com> * Copyright 2008, 2009 Luis R. Rodriguez <lrodriguez@atheros.com>
* Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com> * Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
* Copyright 2008 Colin McCabe <colin@cozybit.com> * Copyright 2008 Colin McCabe <colin@cozybit.com>
* Copyright 2015 Intel Deutschland GmbH
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -328,7 +329,15 @@
* partial scan results may be available * partial scan results may be available
* *
* @NL80211_CMD_START_SCHED_SCAN: start a scheduled scan at certain * @NL80211_CMD_START_SCHED_SCAN: start a scheduled scan at certain
* intervals, as specified by %NL80211_ATTR_SCHED_SCAN_INTERVAL. * intervals and certain number of cycles, as specified by
* %NL80211_ATTR_SCHED_SCAN_PLANS. If %NL80211_ATTR_SCHED_SCAN_PLANS is
* not specified and only %NL80211_ATTR_SCHED_SCAN_INTERVAL is specified,
* scheduled scan will run in an infinite loop with the specified interval.
* These attributes are mutually exculsive,
* i.e. NL80211_ATTR_SCHED_SCAN_INTERVAL must not be passed if
* NL80211_ATTR_SCHED_SCAN_PLANS is defined.
* If for some reason scheduled scan is aborted by the driver, all scan
* plans are canceled (including scan plans that did not start yet).
* Like with normal scans, if SSIDs (%NL80211_ATTR_SCAN_SSIDS) * Like with normal scans, if SSIDs (%NL80211_ATTR_SCAN_SSIDS)
* are passed, they are used in the probe requests. For * are passed, they are used in the probe requests. For
* broadcast, a broadcast SSID must be passed (ie. an empty * broadcast, a broadcast SSID must be passed (ie. an empty
@ -1761,6 +1770,19 @@ enum nl80211_commands {
* @NL80211_ATTR_REG_INDOOR: flag attribute, if set indicates that the device * @NL80211_ATTR_REG_INDOOR: flag attribute, if set indicates that the device
* is operating in an indoor environment. * is operating in an indoor environment.
* *
* @NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS: maximum number of scan plans for
* scheduled scan supported by the device (u32), a wiphy attribute.
* @NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL: maximum interval (in seconds) for
* a scan plan (u32), a wiphy attribute.
* @NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS: maximum number of iterations in
* a scan plan (u32), a wiphy attribute.
* @NL80211_ATTR_SCHED_SCAN_PLANS: a list of scan plans for scheduled scan.
* Each scan plan defines the number of scan iterations and the interval
* between scans. The last scan plan will always run infinitely,
* thus it must not specify the number of iterations, only the interval
* between scans. The scan plans are executed sequentially.
* Each scan plan is a nested attribute of &enum nl80211_sched_scan_plan.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined * @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use * @__NL80211_ATTR_AFTER_LAST: internal use
@ -2130,6 +2152,11 @@ enum nl80211_attrs {
NL80211_ATTR_REG_INDOOR, NL80211_ATTR_REG_INDOOR,
NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS,
NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL,
NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
NL80211_ATTR_SCHED_SCAN_PLANS,
/* add attributes here, update the policy in nl80211.c */ /* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST, __NL80211_ATTR_AFTER_LAST,
@ -3364,6 +3391,9 @@ enum nl80211_bss_scan_width {
* (not present if no beacon frame has been received yet) * (not present if no beacon frame has been received yet)
* @NL80211_BSS_PRESP_DATA: the data in @NL80211_BSS_INFORMATION_ELEMENTS and * @NL80211_BSS_PRESP_DATA: the data in @NL80211_BSS_INFORMATION_ELEMENTS and
* @NL80211_BSS_TSF is known to be from a probe response (flag attribute) * @NL80211_BSS_TSF is known to be from a probe response (flag attribute)
* @NL80211_BSS_LAST_SEEN_BOOTTIME: CLOCK_BOOTTIME timestamp when this entry
* was last updated by a received frame. The value is expected to be
* accurate to about 10ms. (u64, nanoseconds)
* @__NL80211_BSS_AFTER_LAST: internal * @__NL80211_BSS_AFTER_LAST: internal
* @NL80211_BSS_MAX: highest BSS attribute * @NL80211_BSS_MAX: highest BSS attribute
*/ */
@ -3383,6 +3413,7 @@ enum nl80211_bss {
NL80211_BSS_CHAN_WIDTH, NL80211_BSS_CHAN_WIDTH,
NL80211_BSS_BEACON_TSF, NL80211_BSS_BEACON_TSF,
NL80211_BSS_PRESP_DATA, NL80211_BSS_PRESP_DATA,
NL80211_BSS_LAST_SEEN_BOOTTIME,
/* keep last */ /* keep last */
__NL80211_BSS_AFTER_LAST, __NL80211_BSS_AFTER_LAST,
@ -4589,4 +4620,28 @@ enum nl80211_tdls_peer_capability {
NL80211_TDLS_PEER_WMM = 1<<2, NL80211_TDLS_PEER_WMM = 1<<2,
}; };
/**
* enum nl80211_sched_scan_plan - scanning plan for scheduled scan
* @__NL80211_SCHED_SCAN_PLAN_INVALID: attribute number 0 is reserved
* @NL80211_SCHED_SCAN_PLAN_INTERVAL: interval between scan iterations. In
* seconds (u32).
* @NL80211_SCHED_SCAN_PLAN_ITERATIONS: number of scan iterations in this
* scan plan (u32). The last scan plan must not specify this attribute
* because it will run infinitely. A value of zero is invalid as it will
* make the scan plan meaningless.
* @NL80211_SCHED_SCAN_PLAN_MAX: highest scheduled scan plan attribute number
* currently defined
* @__NL80211_SCHED_SCAN_PLAN_AFTER_LAST: internal use
*/
enum nl80211_sched_scan_plan {
__NL80211_SCHED_SCAN_PLAN_INVALID,
NL80211_SCHED_SCAN_PLAN_INTERVAL,
NL80211_SCHED_SCAN_PLAN_ITERATIONS,
/* keep last */
__NL80211_SCHED_SCAN_PLAN_AFTER_LAST,
NL80211_SCHED_SCAN_PLAN_MAX =
__NL80211_SCHED_SCAN_PLAN_AFTER_LAST - 1
};
#endif /* __LINUX_NL80211_H */ #endif /* __LINUX_NL80211_H */

View File

@ -27,7 +27,6 @@ mac80211-y := \
key.o \ key.o \
util.o \ util.o \
wme.o \ wme.o \
event.o \
chan.o \ chan.o \
trace.o mlme.o \ trace.o mlme.o \
tdls.o \ tdls.o \

View File

@ -17,7 +17,6 @@
#include <net/cfg80211.h> #include <net/cfg80211.h>
#include "ieee80211_i.h" #include "ieee80211_i.h"
#include "driver-ops.h" #include "driver-ops.h"
#include "cfg.h"
#include "rate.h" #include "rate.h"
#include "mesh.h" #include "mesh.h"
#include "wme.h" #include "wme.h"
@ -469,45 +468,6 @@ void sta_set_rate_info_tx(struct sta_info *sta,
rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI; rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
} }
void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo)
{
rinfo->flags = 0;
if (sta->last_rx_rate_flag & RX_FLAG_HT) {
rinfo->flags |= RATE_INFO_FLAGS_MCS;
rinfo->mcs = sta->last_rx_rate_idx;
} else if (sta->last_rx_rate_flag & RX_FLAG_VHT) {
rinfo->flags |= RATE_INFO_FLAGS_VHT_MCS;
rinfo->nss = sta->last_rx_rate_vht_nss;
rinfo->mcs = sta->last_rx_rate_idx;
} else {
struct ieee80211_supported_band *sband;
int shift = ieee80211_vif_get_shift(&sta->sdata->vif);
u16 brate;
sband = sta->local->hw.wiphy->bands[
ieee80211_get_sdata_band(sta->sdata)];
brate = sband->bitrates[sta->last_rx_rate_idx].bitrate;
rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift);
}
if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI)
rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
if (sta->last_rx_rate_flag & RX_FLAG_5MHZ)
rinfo->bw = RATE_INFO_BW_5;
else if (sta->last_rx_rate_flag & RX_FLAG_10MHZ)
rinfo->bw = RATE_INFO_BW_10;
else if (sta->last_rx_rate_flag & RX_FLAG_40MHZ)
rinfo->bw = RATE_INFO_BW_40;
else if (sta->last_rx_rate_vht_flag & RX_VHT_FLAG_80MHZ)
rinfo->bw = RATE_INFO_BW_80;
else if (sta->last_rx_rate_vht_flag & RX_VHT_FLAG_160MHZ)
rinfo->bw = RATE_INFO_BW_160;
else
rinfo->bw = RATE_INFO_BW_20;
}
static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
int idx, u8 *mac, struct station_info *sinfo) int idx, u8 *mac, struct station_info *sinfo)
{ {
@ -1138,6 +1098,7 @@ static int sta_apply_parameters(struct ieee80211_local *local,
} }
if (mask & BIT(NL80211_STA_FLAG_MFP)) { if (mask & BIT(NL80211_STA_FLAG_MFP)) {
sta->sta.mfp = !!(set & BIT(NL80211_STA_FLAG_MFP));
if (set & BIT(NL80211_STA_FLAG_MFP)) if (set & BIT(NL80211_STA_FLAG_MFP))
set_sta_flag(sta, WLAN_STA_MFP); set_sta_flag(sta, WLAN_STA_MFP);
else else
@ -1427,7 +1388,7 @@ static int ieee80211_change_station(struct wiphy *wiphy,
if (sdata->vif.type == NL80211_IFTYPE_STATION && if (sdata->vif.type == NL80211_IFTYPE_STATION &&
params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) { params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
ieee80211_recalc_ps(local, -1); ieee80211_recalc_ps(local);
ieee80211_recalc_ps_vif(sdata); ieee80211_recalc_ps_vif(sdata);
} }
@ -2462,7 +2423,7 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
if (ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS)) if (ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS))
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
ieee80211_recalc_ps(local, -1); ieee80211_recalc_ps(local);
ieee80211_recalc_ps_vif(sdata); ieee80211_recalc_ps_vif(sdata);
return 0; return 0;

View File

@ -1,9 +0,0 @@
/*
* mac80211 configuration hooks for cfg80211
*/
#ifndef __CFG_H
#define __CFG_H
extern const struct cfg80211_ops mac80211_config_ops;
#endif /* __CFG_H */

View File

@ -50,7 +50,6 @@ static const struct file_operations sta_ ##name## _ops = { \
STA_OPS(name) STA_OPS(name)
STA_FILE(aid, sta.aid, D); STA_FILE(aid, sta.aid, D);
STA_FILE(last_ack_signal, last_ack_signal, D);
static ssize_t sta_flags_read(struct file *file, char __user *userbuf, static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
@ -366,11 +365,10 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
DEBUGFS_ADD(agg_status); DEBUGFS_ADD(agg_status);
DEBUGFS_ADD(ht_capa); DEBUGFS_ADD(ht_capa);
DEBUGFS_ADD(vht_capa); DEBUGFS_ADD(vht_capa);
DEBUGFS_ADD(last_ack_signal);
DEBUGFS_ADD_COUNTER(rx_duplicates, num_duplicates); DEBUGFS_ADD_COUNTER(rx_duplicates, rx_stats.num_duplicates);
DEBUGFS_ADD_COUNTER(rx_fragments, rx_fragments); DEBUGFS_ADD_COUNTER(rx_fragments, rx_stats.fragments);
DEBUGFS_ADD_COUNTER(tx_filtered, tx_filtered_count); DEBUGFS_ADD_COUNTER(tx_filtered, status_stats.filtered);
if (sizeof(sta->driver_buffered_tids) == sizeof(u32)) if (sizeof(sta->driver_buffered_tids) == sizeof(u32))
debugfs_create_x32("driver_buffered_tids", 0400, debugfs_create_x32("driver_buffered_tids", 0400,

View File

@ -40,7 +40,7 @@ static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = {
"rx_duplicates", "rx_fragments", "rx_dropped", "rx_duplicates", "rx_fragments", "rx_dropped",
"tx_packets", "tx_bytes", "tx_packets", "tx_bytes",
"tx_filtered", "tx_retry_failed", "tx_retries", "tx_filtered", "tx_retry_failed", "tx_retries",
"beacon_loss", "sta_state", "txrate", "rxrate", "signal", "sta_state", "txrate", "rxrate", "signal",
"channel", "noise", "ch_time", "ch_time_busy", "channel", "noise", "ch_time", "ch_time_busy",
"ch_time_ext_busy", "ch_time_rx", "ch_time_tx" "ch_time_ext_busy", "ch_time_rx", "ch_time_tx"
}; };
@ -77,20 +77,19 @@ static void ieee80211_get_stats(struct net_device *dev,
memset(data, 0, sizeof(u64) * STA_STATS_LEN); memset(data, 0, sizeof(u64) * STA_STATS_LEN);
#define ADD_STA_STATS(sta) \ #define ADD_STA_STATS(sta) \
do { \ do { \
data[i++] += sta->rx_packets; \ data[i++] += sta->rx_stats.packets; \
data[i++] += sta->rx_bytes; \ data[i++] += sta->rx_stats.bytes; \
data[i++] += sta->num_duplicates; \ data[i++] += sta->rx_stats.num_duplicates; \
data[i++] += sta->rx_fragments; \ data[i++] += sta->rx_stats.fragments; \
data[i++] += sta->rx_dropped; \ data[i++] += sta->rx_stats.dropped; \
\ \
data[i++] += sinfo.tx_packets; \ data[i++] += sinfo.tx_packets; \
data[i++] += sinfo.tx_bytes; \ data[i++] += sinfo.tx_bytes; \
data[i++] += sta->tx_filtered_count; \ data[i++] += sta->status_stats.filtered; \
data[i++] += sta->tx_retry_failed; \ data[i++] += sta->status_stats.retry_failed; \
data[i++] += sta->tx_retry_count; \ data[i++] += sta->status_stats.retry_count; \
data[i++] += sta->beacon_loss_count; \
} while (0) } while (0)
/* For Managed stations, find the single station based on BSSID /* For Managed stations, find the single station based on BSSID

View File

@ -1,27 +0,0 @@
/*
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
*
* 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
* published by the Free Software Foundation.
*
* mac80211 - events
*/
#include <net/cfg80211.h>
#include "ieee80211_i.h"
/*
* Indicate a failed Michael MIC to userspace. If the caller knows the TSC of
* the frame that generated the MIC failure (i.e., if it was provided by the
* driver or is still in the frame), it should provide that information.
*/
void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx,
struct ieee80211_hdr *hdr, const u8 *tsc,
gfp_t gfp)
{
cfg80211_michael_mic_failure(sdata->dev, hdr->addr2,
(hdr->addr1[0] & 0x01) ?
NL80211_KEYTYPE_GROUP :
NL80211_KEYTYPE_PAIRWISE,
keyidx, tsc, gfp);
}

View File

@ -229,7 +229,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
struct cfg80211_chan_def chandef; struct cfg80211_chan_def chandef;
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
struct beacon_data *presp; struct beacon_data *presp;
enum nl80211_bss_scan_width scan_width; struct cfg80211_inform_bss bss_meta = {};
bool have_higher_than_11mbit; bool have_higher_than_11mbit;
bool radar_required; bool radar_required;
int err; int err;
@ -383,10 +383,11 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
mod_timer(&ifibss->timer, mod_timer(&ifibss->timer,
round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL));
scan_width = cfg80211_chandef_to_scan_width(&chandef); bss_meta.chan = chan;
bss = cfg80211_inform_bss_width_frame(local->hw.wiphy, chan, bss_meta.scan_width = cfg80211_chandef_to_scan_width(&chandef);
scan_width, mgmt, bss = cfg80211_inform_bss_frame_data(local->hw.wiphy, &bss_meta, mgmt,
presp->head_len, 0, GFP_KERNEL); presp->head_len, GFP_KERNEL);
cfg80211_put_bss(local->hw.wiphy, bss); cfg80211_put_bss(local->hw.wiphy, bss);
netif_carrier_on(sdata->dev); netif_carrier_on(sdata->dev);
cfg80211_ibss_joined(sdata->dev, ifibss->bssid, chan, GFP_KERNEL); cfg80211_ibss_joined(sdata->dev, ifibss->bssid, chan, GFP_KERNEL);
@ -646,7 +647,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid,
return NULL; return NULL;
} }
sta->last_rx = jiffies; sta->rx_stats.last_rx = jiffies;
/* make sure mandatory rates are always added */ /* make sure mandatory rates are always added */
sband = local->hw.wiphy->bands[band]; sband = local->hw.wiphy->bands[band];
@ -668,7 +669,8 @@ static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
list_for_each_entry_rcu(sta, &local->sta_list, list) { list_for_each_entry_rcu(sta, &local->sta_list, list) {
if (sta->sdata == sdata && if (sta->sdata == sdata &&
time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, time_after(sta->rx_stats.last_rx +
IEEE80211_IBSS_MERGE_INTERVAL,
jiffies)) { jiffies)) {
active++; active++;
break; break;
@ -1234,7 +1236,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
if (!sta) if (!sta)
return; return;
sta->last_rx = jiffies; sta->rx_stats.last_rx = jiffies;
/* make sure mandatory rates are always added */ /* make sure mandatory rates are always added */
sband = local->hw.wiphy->bands[band]; sband = local->hw.wiphy->bands[band];
@ -1252,7 +1254,7 @@ static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata)
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct sta_info *sta, *tmp; struct sta_info *sta, *tmp;
unsigned long exp_time = IEEE80211_IBSS_INACTIVITY_LIMIT; unsigned long exp_time = IEEE80211_IBSS_INACTIVITY_LIMIT;
unsigned long exp_rsn_time = IEEE80211_IBSS_RSN_INACTIVITY_LIMIT; unsigned long exp_rsn = IEEE80211_IBSS_RSN_INACTIVITY_LIMIT;
mutex_lock(&local->sta_mtx); mutex_lock(&local->sta_mtx);
@ -1260,8 +1262,8 @@ static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata)
if (sdata != sta->sdata) if (sdata != sta->sdata)
continue; continue;
if (time_after(jiffies, sta->last_rx + exp_time) || if (time_after(jiffies, sta->rx_stats.last_rx + exp_time) ||
(time_after(jiffies, sta->last_rx + exp_rsn_time) && (time_after(jiffies, sta->rx_stats.last_rx + exp_rsn) &&
sta->sta_state != IEEE80211_STA_AUTHORIZED)) { sta->sta_state != IEEE80211_STA_AUTHORIZED)) {
sta_dbg(sta->sdata, "expiring inactive %sSTA %pM\n", sta_dbg(sta->sdata, "expiring inactive %sSTA %pM\n",
sta->sta_state != IEEE80211_STA_AUTHORIZED ? sta->sta_state != IEEE80211_STA_AUTHORIZED ?

View File

@ -34,6 +34,8 @@
#include "sta_info.h" #include "sta_info.h"
#include "debug.h" #include "debug.h"
extern const struct cfg80211_ops mac80211_config_ops;
struct ieee80211_local; struct ieee80211_local;
/* Maximum number of broadcast/multicast frames to buffer when some of the /* Maximum number of broadcast/multicast frames to buffer when some of the
@ -501,6 +503,9 @@ struct ieee80211_if_managed {
*/ */
unsigned int count_beacon_signal; unsigned int count_beacon_signal;
/* Number of times beacon loss was invoked. */
unsigned int beacon_loss_count;
/* /*
* Last Beacon frame signal strength average (ave_beacon_signal / 16) * Last Beacon frame signal strength average (ave_beacon_signal / 16)
* that triggered a cqm event. 0 indicates that no event has been * that triggered a cqm event. 0 indicates that no event has been
@ -1305,7 +1310,6 @@ struct ieee80211_local {
struct work_struct dynamic_ps_enable_work; struct work_struct dynamic_ps_enable_work;
struct work_struct dynamic_ps_disable_work; struct work_struct dynamic_ps_disable_work;
struct timer_list dynamic_ps_timer; struct timer_list dynamic_ps_timer;
struct notifier_block network_latency_notifier;
struct notifier_block ifa_notifier; struct notifier_block ifa_notifier;
struct notifier_block ifa6_notifier; struct notifier_block ifa6_notifier;
@ -1491,10 +1495,8 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
struct cfg80211_disassoc_request *req); struct cfg80211_disassoc_request *req);
void ieee80211_send_pspoll(struct ieee80211_local *local, void ieee80211_send_pspoll(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata); struct ieee80211_sub_if_data *sdata);
void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency); void ieee80211_recalc_ps(struct ieee80211_local *local);
void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata); void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata);
int ieee80211_max_network_latency(struct notifier_block *nb,
unsigned long data, void *dummy);
int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata); int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata);
void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata); void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata);
void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
@ -1766,9 +1768,6 @@ extern const void *const mac80211_wiphy_privid; /* for wiphy privid */
int ieee80211_frame_duration(enum ieee80211_band band, size_t len, int ieee80211_frame_duration(enum ieee80211_band band, size_t len,
int rate, int erp, int short_preamble, int rate, int erp, int short_preamble,
int shift); int shift);
void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx,
struct ieee80211_hdr *hdr, const u8 *tsc,
gfp_t gfp);
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
bool bss_notify); bool bss_notify);
void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,

View File

@ -709,7 +709,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
if (hw_reconf_flags) if (hw_reconf_flags)
ieee80211_hw_config(local, hw_reconf_flags); ieee80211_hw_config(local, hw_reconf_flags);
ieee80211_recalc_ps(local, -1); ieee80211_recalc_ps(local);
if (sdata->vif.type == NL80211_IFTYPE_MONITOR || if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
@ -1016,7 +1016,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
drv_remove_interface(local, sdata); drv_remove_interface(local, sdata);
} }
ieee80211_recalc_ps(local, -1); ieee80211_recalc_ps(local);
if (cancel_scan) if (cancel_scan)
flush_delayed_work(&local->scan_work); flush_delayed_work(&local->scan_work);

View File

@ -20,7 +20,6 @@
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/bitmap.h> #include <linux/bitmap.h>
#include <linux/pm_qos.h>
#include <linux/inetdevice.h> #include <linux/inetdevice.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <net/cfg80211.h> #include <net/cfg80211.h>
@ -32,7 +31,6 @@
#include "mesh.h" #include "mesh.h"
#include "wep.h" #include "wep.h"
#include "led.h" #include "led.h"
#include "cfg.h"
#include "debugfs.h" #include "debugfs.h"
void ieee80211_configure_filter(struct ieee80211_local *local) void ieee80211_configure_filter(struct ieee80211_local *local)
@ -1083,13 +1081,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
rtnl_unlock(); rtnl_unlock();
local->network_latency_notifier.notifier_call =
ieee80211_max_network_latency;
result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY,
&local->network_latency_notifier);
if (result)
goto fail_pm_qos;
#ifdef CONFIG_INET #ifdef CONFIG_INET
local->ifa_notifier.notifier_call = ieee80211_ifa_changed; local->ifa_notifier.notifier_call = ieee80211_ifa_changed;
result = register_inetaddr_notifier(&local->ifa_notifier); result = register_inetaddr_notifier(&local->ifa_notifier);
@ -1114,10 +1105,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
#endif #endif
#if defined(CONFIG_INET) || defined(CONFIG_IPV6) #if defined(CONFIG_INET) || defined(CONFIG_IPV6)
fail_ifa: fail_ifa:
pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
&local->network_latency_notifier);
#endif #endif
fail_pm_qos:
rtnl_lock(); rtnl_lock();
rate_control_deinitialize(local); rate_control_deinitialize(local);
ieee80211_remove_interfaces(local); ieee80211_remove_interfaces(local);
@ -1143,8 +1131,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
tasklet_kill(&local->tx_pending_tasklet); tasklet_kill(&local->tx_pending_tasklet);
tasklet_kill(&local->tasklet); tasklet_kill(&local->tasklet);
pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
&local->network_latency_notifier);
#ifdef CONFIG_INET #ifdef CONFIG_INET
unregister_inetaddr_notifier(&local->ifa_notifier); unregister_inetaddr_notifier(&local->ifa_notifier);
#endif #endif

View File

@ -329,7 +329,7 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local,
if (sta->mesh->fail_avg >= 100) if (sta->mesh->fail_avg >= 100)
return MAX_METRIC; return MAX_METRIC;
sta_set_rate_info_tx(sta, &sta->last_tx_rate, &rinfo); sta_set_rate_info_tx(sta, &sta->tx_stats.last_rate, &rinfo);
rate = cfg80211_calculate_bitrate(&rinfo); rate = cfg80211_calculate_bitrate(&rinfo);
if (WARN_ON(!rate)) if (WARN_ON(!rate))
return MAX_METRIC; return MAX_METRIC;

View File

@ -60,7 +60,9 @@ static bool rssi_threshold_check(struct ieee80211_sub_if_data *sdata,
{ {
s32 rssi_threshold = sdata->u.mesh.mshcfg.rssi_threshold; s32 rssi_threshold = sdata->u.mesh.mshcfg.rssi_threshold;
return rssi_threshold == 0 || return rssi_threshold == 0 ||
(sta && (s8) -ewma_signal_read(&sta->avg_signal) > rssi_threshold); (sta &&
(s8)-ewma_signal_read(&sta->rx_stats.avg_signal) >
rssi_threshold);
} }
/** /**
@ -390,7 +392,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
rates = ieee80211_sta_get_rates(sdata, elems, band, &basic_rates); rates = ieee80211_sta_get_rates(sdata, elems, band, &basic_rates);
spin_lock_bh(&sta->mesh->plink_lock); spin_lock_bh(&sta->mesh->plink_lock);
sta->last_rx = jiffies; sta->rx_stats.last_rx = jiffies;
/* rates and capabilities don't change during peering */ /* rates and capabilities don't change during peering */
if (sta->mesh->plink_state == NL80211_PLINK_ESTAB && if (sta->mesh->plink_state == NL80211_PLINK_ESTAB &&

View File

@ -20,7 +20,6 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/pm_qos.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/export.h> #include <linux/export.h>
@ -1476,7 +1475,7 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata)
} }
/* need to hold RTNL or interface lock */ /* need to hold RTNL or interface lock */
void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) void ieee80211_recalc_ps(struct ieee80211_local *local)
{ {
struct ieee80211_sub_if_data *sdata, *found = NULL; struct ieee80211_sub_if_data *sdata, *found = NULL;
int count = 0; int count = 0;
@ -1505,48 +1504,23 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
} }
if (count == 1 && ieee80211_powersave_allowed(found)) { if (count == 1 && ieee80211_powersave_allowed(found)) {
u8 dtimper = found->u.mgd.dtim_period;
s32 beaconint_us; s32 beaconint_us;
if (latency < 0)
latency = pm_qos_request(PM_QOS_NETWORK_LATENCY);
beaconint_us = ieee80211_tu_to_usec( beaconint_us = ieee80211_tu_to_usec(
found->vif.bss_conf.beacon_int); found->vif.bss_conf.beacon_int);
timeout = local->dynamic_ps_forced_timeout; timeout = local->dynamic_ps_forced_timeout;
if (timeout < 0) { if (timeout < 0)
/* timeout = 100;
* Go to full PSM if the user configures a very low
* latency requirement.
* The 2000 second value is there for compatibility
* until the PM_QOS_NETWORK_LATENCY is configured
* with real values.
*/
if (latency > (1900 * USEC_PER_MSEC) &&
latency != (2000 * USEC_PER_SEC))
timeout = 0;
else
timeout = 100;
}
local->hw.conf.dynamic_ps_timeout = timeout; local->hw.conf.dynamic_ps_timeout = timeout;
if (beaconint_us > latency) { /* If the TIM IE is invalid, pretend the value is 1 */
local->ps_sdata = NULL; if (!dtimper)
} else { dtimper = 1;
int maxslp = 1;
u8 dtimper = found->u.mgd.dtim_period;
/* If the TIM IE is invalid, pretend the value is 1 */ local->hw.conf.ps_dtim_period = dtimper;
if (!dtimper) local->ps_sdata = found;
dtimper = 1;
else if (dtimper > 1)
maxslp = min_t(int, dtimper,
latency / beaconint_us);
local->hw.conf.max_sleep_period = maxslp;
local->hw.conf.ps_dtim_period = dtimper;
local->ps_sdata = found;
}
} else { } else {
local->ps_sdata = NULL; local->ps_sdata = NULL;
} }
@ -1997,7 +1971,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
ieee80211_bss_info_change_notify(sdata, bss_info_changed); ieee80211_bss_info_change_notify(sdata, bss_info_changed);
mutex_lock(&local->iflist_mtx); mutex_lock(&local->iflist_mtx);
ieee80211_recalc_ps(local, -1); ieee80211_recalc_ps(local);
mutex_unlock(&local->iflist_mtx); mutex_unlock(&local->iflist_mtx);
ieee80211_recalc_smps(sdata); ieee80211_recalc_smps(sdata);
@ -2165,7 +2139,7 @@ static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
__ieee80211_stop_poll(sdata); __ieee80211_stop_poll(sdata);
mutex_lock(&local->iflist_mtx); mutex_lock(&local->iflist_mtx);
ieee80211_recalc_ps(local, -1); ieee80211_recalc_ps(local);
mutex_unlock(&local->iflist_mtx); mutex_unlock(&local->iflist_mtx);
if (ieee80211_hw_check(&sdata->local->hw, CONNECTION_MONITOR)) if (ieee80211_hw_check(&sdata->local->hw, CONNECTION_MONITOR))
@ -2341,7 +2315,7 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
goto out; goto out;
mutex_lock(&sdata->local->iflist_mtx); mutex_lock(&sdata->local->iflist_mtx);
ieee80211_recalc_ps(sdata->local, -1); ieee80211_recalc_ps(sdata->local);
mutex_unlock(&sdata->local->iflist_mtx); mutex_unlock(&sdata->local->iflist_mtx);
ifmgd->probe_send_count = 0; ifmgd->probe_send_count = 0;
@ -2446,15 +2420,9 @@ static void ieee80211_beacon_connection_loss_work(struct work_struct *work)
container_of(work, struct ieee80211_sub_if_data, container_of(work, struct ieee80211_sub_if_data,
u.mgd.beacon_connection_loss_work); u.mgd.beacon_connection_loss_work);
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct sta_info *sta;
if (ifmgd->associated) { if (ifmgd->associated)
rcu_read_lock(); ifmgd->beacon_loss_count++;
sta = sta_info_get(sdata, ifmgd->bssid);
if (sta)
sta->beacon_loss_count++;
rcu_read_unlock();
}
if (ifmgd->connection_loss) { if (ifmgd->connection_loss) {
sdata_info(sdata, "Connection to AP %pM lost\n", sdata_info(sdata, "Connection to AP %pM lost\n",
@ -3044,8 +3012,12 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
rate_control_rate_init(sta); rate_control_rate_init(sta);
if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) {
set_sta_flag(sta, WLAN_STA_MFP); set_sta_flag(sta, WLAN_STA_MFP);
sta->sta.mfp = true;
} else {
sta->sta.mfp = false;
}
sta->sta.wme = elems.wmm_param && local->hw.queues >= IEEE80211_NUM_ACS; sta->sta.wme = elems.wmm_param && local->hw.queues >= IEEE80211_NUM_ACS;
@ -3544,7 +3516,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
ifmgd->have_beacon = true; ifmgd->have_beacon = true;
mutex_lock(&local->iflist_mtx); mutex_lock(&local->iflist_mtx);
ieee80211_recalc_ps(local, -1); ieee80211_recalc_ps(local);
mutex_unlock(&local->iflist_mtx); mutex_unlock(&local->iflist_mtx);
ieee80211_recalc_ps_vif(sdata); ieee80211_recalc_ps_vif(sdata);
@ -4148,21 +4120,6 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
rcu_read_unlock(); rcu_read_unlock();
} }
int ieee80211_max_network_latency(struct notifier_block *nb,
unsigned long data, void *dummy)
{
s32 latency_usec = (s32) data;
struct ieee80211_local *local =
container_of(nb, struct ieee80211_local,
network_latency_notifier);
mutex_lock(&local->iflist_mtx);
ieee80211_recalc_ps(local, latency_usec);
mutex_unlock(&local->iflist_mtx);
return NOTIFY_OK;
}
static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata, static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata,
struct cfg80211_bss *cbss) struct cfg80211_bss *cbss)
{ {

View File

@ -75,7 +75,7 @@ void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata,
if (!sta) if (!sta)
return; return;
sta->last_rx = jiffies; sta->rx_stats.last_rx = jiffies;
/* Add only mandatory rates for now */ /* Add only mandatory rates for now */
sband = local->hw.wiphy->bands[band]; sband = local->hw.wiphy->bands[band];

View File

@ -1113,16 +1113,16 @@ ieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx)
is_multicast_ether_addr(hdr->addr1)) is_multicast_ether_addr(hdr->addr1))
return RX_CONTINUE; return RX_CONTINUE;
if (rx->sta) { if (!rx->sta)
if (unlikely(ieee80211_has_retry(hdr->frame_control) && return RX_CONTINUE;
rx->sta->last_seq_ctrl[rx->seqno_idx] ==
hdr->seq_ctrl)) { if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
I802_DEBUG_INC(rx->local->dot11FrameDuplicateCount); rx->sta->last_seq_ctrl[rx->seqno_idx] == hdr->seq_ctrl)) {
rx->sta->num_duplicates++; I802_DEBUG_INC(rx->local->dot11FrameDuplicateCount);
return RX_DROP_UNUSABLE; rx->sta->rx_stats.num_duplicates++;
} else if (!(status->flag & RX_FLAG_AMSDU_MORE)) { return RX_DROP_UNUSABLE;
rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl; } else if (!(status->flag & RX_FLAG_AMSDU_MORE)) {
} rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl;
} }
return RX_CONTINUE; return RX_CONTINUE;
@ -1396,51 +1396,56 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
NL80211_IFTYPE_ADHOC); NL80211_IFTYPE_ADHOC);
if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid) && if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid) &&
test_sta_flag(sta, WLAN_STA_AUTHORIZED)) { test_sta_flag(sta, WLAN_STA_AUTHORIZED)) {
sta->last_rx = jiffies; sta->rx_stats.last_rx = jiffies;
if (ieee80211_is_data(hdr->frame_control) && if (ieee80211_is_data(hdr->frame_control) &&
!is_multicast_ether_addr(hdr->addr1)) { !is_multicast_ether_addr(hdr->addr1)) {
sta->last_rx_rate_idx = status->rate_idx; sta->rx_stats.last_rate_idx =
sta->last_rx_rate_flag = status->flag; status->rate_idx;
sta->last_rx_rate_vht_flag = status->vht_flag; sta->rx_stats.last_rate_flag =
sta->last_rx_rate_vht_nss = status->vht_nss; status->flag;
sta->rx_stats.last_rate_vht_flag =
status->vht_flag;
sta->rx_stats.last_rate_vht_nss =
status->vht_nss;
} }
} }
} else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) { } else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) {
sta->last_rx = jiffies; sta->rx_stats.last_rx = jiffies;
} else if (!is_multicast_ether_addr(hdr->addr1)) { } else if (!is_multicast_ether_addr(hdr->addr1)) {
/* /*
* Mesh beacons will update last_rx when if they are found to * Mesh beacons will update last_rx when if they are found to
* match the current local configuration when processed. * match the current local configuration when processed.
*/ */
sta->last_rx = jiffies; sta->rx_stats.last_rx = jiffies;
if (ieee80211_is_data(hdr->frame_control)) { if (ieee80211_is_data(hdr->frame_control)) {
sta->last_rx_rate_idx = status->rate_idx; sta->rx_stats.last_rate_idx = status->rate_idx;
sta->last_rx_rate_flag = status->flag; sta->rx_stats.last_rate_flag = status->flag;
sta->last_rx_rate_vht_flag = status->vht_flag; sta->rx_stats.last_rate_vht_flag = status->vht_flag;
sta->last_rx_rate_vht_nss = status->vht_nss; sta->rx_stats.last_rate_vht_nss = status->vht_nss;
} }
} }
if (rx->sdata->vif.type == NL80211_IFTYPE_STATION) if (rx->sdata->vif.type == NL80211_IFTYPE_STATION)
ieee80211_sta_rx_notify(rx->sdata, hdr); ieee80211_sta_rx_notify(rx->sdata, hdr);
sta->rx_fragments++; sta->rx_stats.fragments++;
sta->rx_bytes += rx->skb->len; sta->rx_stats.bytes += rx->skb->len;
if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) { if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
sta->last_signal = status->signal; sta->rx_stats.last_signal = status->signal;
ewma_signal_add(&sta->avg_signal, -status->signal); ewma_signal_add(&sta->rx_stats.avg_signal, -status->signal);
} }
if (status->chains) { if (status->chains) {
sta->chains = status->chains; sta->rx_stats.chains = status->chains;
for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) { for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) {
int signal = status->chain_signal[i]; int signal = status->chain_signal[i];
if (!(status->chains & BIT(i))) if (!(status->chains & BIT(i)))
continue; continue;
sta->chain_signal_last[i] = signal; sta->rx_stats.chain_signal_last[i] = signal;
ewma_signal_add(&sta->chain_signal_avg[i], -signal); ewma_signal_add(&sta->rx_stats.chain_signal_avg[i],
-signal);
} }
} }
@ -1500,7 +1505,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
* Update counter and free packet here to avoid * Update counter and free packet here to avoid
* counting this as a dropped packed. * counting this as a dropped packed.
*/ */
sta->rx_packets++; sta->rx_stats.packets++;
dev_kfree_skb(rx->skb); dev_kfree_skb(rx->skb);
return RX_QUEUED; return RX_QUEUED;
} }
@ -1922,7 +1927,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
ieee80211_led_rx(rx->local); ieee80211_led_rx(rx->local);
out_no_led: out_no_led:
if (rx->sta) if (rx->sta)
rx->sta->rx_packets++; rx->sta->rx_stats.packets++;
return RX_CONTINUE; return RX_CONTINUE;
} }
@ -2376,7 +2381,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
* for non-QoS-data frames. Here we know it's a data * for non-QoS-data frames. Here we know it's a data
* frame, so count MSDUs. * frame, so count MSDUs.
*/ */
rx->sta->rx_msdu[rx->seqno_idx]++; rx->sta->rx_stats.msdu[rx->seqno_idx]++;
} }
/* /*
@ -2413,7 +2418,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
skb_queue_tail(&local->skb_queue_tdls_chsw, rx->skb); skb_queue_tail(&local->skb_queue_tdls_chsw, rx->skb);
schedule_work(&local->tdls_chsw_work); schedule_work(&local->tdls_chsw_work);
if (rx->sta) if (rx->sta)
rx->sta->rx_packets++; rx->sta->rx_stats.packets++;
return RX_QUEUED; return RX_QUEUED;
} }
@ -2875,7 +2880,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
handled: handled:
if (rx->sta) if (rx->sta)
rx->sta->rx_packets++; rx->sta->rx_stats.packets++;
dev_kfree_skb(rx->skb); dev_kfree_skb(rx->skb);
return RX_QUEUED; return RX_QUEUED;
@ -2884,7 +2889,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
skb_queue_tail(&sdata->skb_queue, rx->skb); skb_queue_tail(&sdata->skb_queue, rx->skb);
ieee80211_queue_work(&local->hw, &sdata->work); ieee80211_queue_work(&local->hw, &sdata->work);
if (rx->sta) if (rx->sta)
rx->sta->rx_packets++; rx->sta->rx_stats.packets++;
return RX_QUEUED; return RX_QUEUED;
} }
@ -2911,7 +2916,7 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
if (cfg80211_rx_mgmt(&rx->sdata->wdev, status->freq, sig, if (cfg80211_rx_mgmt(&rx->sdata->wdev, status->freq, sig,
rx->skb->data, rx->skb->len, 0)) { rx->skb->data, rx->skb->len, 0)) {
if (rx->sta) if (rx->sta)
rx->sta->rx_packets++; rx->sta->rx_stats.packets++;
dev_kfree_skb(rx->skb); dev_kfree_skb(rx->skb);
return RX_QUEUED; return RX_QUEUED;
} }
@ -3030,7 +3035,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
skb_queue_tail(&sdata->skb_queue, rx->skb); skb_queue_tail(&sdata->skb_queue, rx->skb);
ieee80211_queue_work(&rx->local->hw, &sdata->work); ieee80211_queue_work(&rx->local->hw, &sdata->work);
if (rx->sta) if (rx->sta)
rx->sta->rx_packets++; rx->sta->rx_stats.packets++;
return RX_QUEUED; return RX_QUEUED;
} }
@ -3112,7 +3117,7 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx,
case RX_DROP_MONITOR: case RX_DROP_MONITOR:
I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop); I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop);
if (rx->sta) if (rx->sta)
rx->sta->rx_dropped++; rx->sta->rx_stats.dropped++;
/* fall through */ /* fall through */
case RX_CONTINUE: { case RX_CONTINUE: {
struct ieee80211_rate *rate = NULL; struct ieee80211_rate *rate = NULL;
@ -3132,7 +3137,7 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx,
case RX_DROP_UNUSABLE: case RX_DROP_UNUSABLE:
I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop); I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop);
if (rx->sta) if (rx->sta)
rx->sta->rx_dropped++; rx->sta->rx_stats.dropped++;
dev_kfree_skb(rx->skb); dev_kfree_skb(rx->skb);
break; break;
case RX_QUEUED: case RX_QUEUED:

View File

@ -16,7 +16,6 @@
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/pm_qos.h>
#include <net/sch_generic.h> #include <net/sch_generic.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/export.h> #include <linux/export.h>
@ -67,24 +66,23 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
struct cfg80211_bss *cbss; struct cfg80211_bss *cbss;
struct ieee80211_bss *bss; struct ieee80211_bss *bss;
int clen, srlen; int clen, srlen;
enum nl80211_bss_scan_width scan_width; struct cfg80211_inform_bss bss_meta = {};
s32 signal = 0;
bool signal_valid; bool signal_valid;
if (ieee80211_hw_check(&local->hw, SIGNAL_DBM)) if (ieee80211_hw_check(&local->hw, SIGNAL_DBM))
signal = rx_status->signal * 100; bss_meta.signal = rx_status->signal * 100;
else if (ieee80211_hw_check(&local->hw, SIGNAL_UNSPEC)) else if (ieee80211_hw_check(&local->hw, SIGNAL_UNSPEC))
signal = (rx_status->signal * 100) / local->hw.max_signal; bss_meta.signal = (rx_status->signal * 100) / local->hw.max_signal;
scan_width = NL80211_BSS_CHAN_WIDTH_20; bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_20;
if (rx_status->flag & RX_FLAG_5MHZ) if (rx_status->flag & RX_FLAG_5MHZ)
scan_width = NL80211_BSS_CHAN_WIDTH_5; bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_5;
if (rx_status->flag & RX_FLAG_10MHZ) if (rx_status->flag & RX_FLAG_10MHZ)
scan_width = NL80211_BSS_CHAN_WIDTH_10; bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_10;
cbss = cfg80211_inform_bss_width_frame(local->hw.wiphy, channel, bss_meta.chan = channel;
scan_width, mgmt, len, signal, cbss = cfg80211_inform_bss_frame_data(local->hw.wiphy, &bss_meta,
GFP_ATOMIC); mgmt, len, GFP_ATOMIC);
if (!cbss) if (!cbss)
return NULL; return NULL;
/* In case the signal is invalid update the status */ /* In case the signal is invalid update the status */

View File

@ -331,7 +331,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
memcpy(sta->sta.addr, addr, ETH_ALEN); memcpy(sta->sta.addr, addr, ETH_ALEN);
sta->local = local; sta->local = local;
sta->sdata = sdata; sta->sdata = sdata;
sta->last_rx = jiffies; sta->rx_stats.last_rx = jiffies;
sta->sta_state = IEEE80211_STA_NONE; sta->sta_state = IEEE80211_STA_NONE;
@ -339,9 +339,9 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
sta->reserved_tid = IEEE80211_TID_UNRESERVED; sta->reserved_tid = IEEE80211_TID_UNRESERVED;
sta->last_connected = ktime_get_seconds(); sta->last_connected = ktime_get_seconds();
ewma_signal_init(&sta->avg_signal); ewma_signal_init(&sta->rx_stats.avg_signal);
for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++) for (i = 0; i < ARRAY_SIZE(sta->rx_stats.chain_signal_avg); i++)
ewma_signal_init(&sta->chain_signal_avg[i]); ewma_signal_init(&sta->rx_stats.chain_signal_avg[i]);
if (local->ops->wake_tx_queue) { if (local->ops->wake_tx_queue) {
void *txq_data; void *txq_data;
@ -1066,7 +1066,7 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
if (sdata != sta->sdata) if (sdata != sta->sdata)
continue; continue;
if (time_after(jiffies, sta->last_rx + exp_time)) { if (time_after(jiffies, sta->rx_stats.last_rx + exp_time)) {
sta_dbg(sta->sdata, "expiring inactive STA %pM\n", sta_dbg(sta->sdata, "expiring inactive STA %pM\n",
sta->sta.addr); sta->sta.addr);
@ -1806,6 +1806,45 @@ u8 sta_info_tx_streams(struct sta_info *sta)
>> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1; >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1;
} }
static void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo)
{
rinfo->flags = 0;
if (sta->rx_stats.last_rate_flag & RX_FLAG_HT) {
rinfo->flags |= RATE_INFO_FLAGS_MCS;
rinfo->mcs = sta->rx_stats.last_rate_idx;
} else if (sta->rx_stats.last_rate_flag & RX_FLAG_VHT) {
rinfo->flags |= RATE_INFO_FLAGS_VHT_MCS;
rinfo->nss = sta->rx_stats.last_rate_vht_nss;
rinfo->mcs = sta->rx_stats.last_rate_idx;
} else {
struct ieee80211_supported_band *sband;
int shift = ieee80211_vif_get_shift(&sta->sdata->vif);
u16 brate;
sband = sta->local->hw.wiphy->bands[
ieee80211_get_sdata_band(sta->sdata)];
brate = sband->bitrates[sta->rx_stats.last_rate_idx].bitrate;
rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift);
}
if (sta->rx_stats.last_rate_flag & RX_FLAG_SHORT_GI)
rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
if (sta->rx_stats.last_rate_flag & RX_FLAG_5MHZ)
rinfo->bw = RATE_INFO_BW_5;
else if (sta->rx_stats.last_rate_flag & RX_FLAG_10MHZ)
rinfo->bw = RATE_INFO_BW_10;
else if (sta->rx_stats.last_rate_flag & RX_FLAG_40MHZ)
rinfo->bw = RATE_INFO_BW_40;
else if (sta->rx_stats.last_rate_vht_flag & RX_VHT_FLAG_80MHZ)
rinfo->bw = RATE_INFO_BW_80;
else if (sta->rx_stats.last_rate_vht_flag & RX_VHT_FLAG_160MHZ)
rinfo->bw = RATE_INFO_BW_160;
else
rinfo->bw = RATE_INFO_BW_20;
}
void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
{ {
struct ieee80211_sub_if_data *sdata = sta->sdata; struct ieee80211_sub_if_data *sdata = sta->sdata;
@ -1832,50 +1871,54 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
BIT(NL80211_STA_INFO_STA_FLAGS) | BIT(NL80211_STA_INFO_STA_FLAGS) |
BIT(NL80211_STA_INFO_BSS_PARAM) | BIT(NL80211_STA_INFO_BSS_PARAM) |
BIT(NL80211_STA_INFO_CONNECTED_TIME) | BIT(NL80211_STA_INFO_CONNECTED_TIME) |
BIT(NL80211_STA_INFO_RX_DROP_MISC) | BIT(NL80211_STA_INFO_RX_DROP_MISC);
BIT(NL80211_STA_INFO_BEACON_LOSS);
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
sinfo->beacon_loss_count = sdata->u.mgd.beacon_loss_count;
sinfo->filled |= BIT(NL80211_STA_INFO_BEACON_LOSS);
}
sinfo->connected_time = ktime_get_seconds() - sta->last_connected; sinfo->connected_time = ktime_get_seconds() - sta->last_connected;
sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); sinfo->inactive_time =
jiffies_to_msecs(jiffies - sta->rx_stats.last_rx);
if (!(sinfo->filled & (BIT(NL80211_STA_INFO_TX_BYTES64) | if (!(sinfo->filled & (BIT(NL80211_STA_INFO_TX_BYTES64) |
BIT(NL80211_STA_INFO_TX_BYTES)))) { BIT(NL80211_STA_INFO_TX_BYTES)))) {
sinfo->tx_bytes = 0; sinfo->tx_bytes = 0;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
sinfo->tx_bytes += sta->tx_bytes[ac]; sinfo->tx_bytes += sta->tx_stats.bytes[ac];
sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES64); sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES64);
} }
if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_PACKETS))) { if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_PACKETS))) {
sinfo->tx_packets = 0; sinfo->tx_packets = 0;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
sinfo->tx_packets += sta->tx_packets[ac]; sinfo->tx_packets += sta->tx_stats.packets[ac];
sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS); sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
} }
if (!(sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES64) | if (!(sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES64) |
BIT(NL80211_STA_INFO_RX_BYTES)))) { BIT(NL80211_STA_INFO_RX_BYTES)))) {
sinfo->rx_bytes = sta->rx_bytes; sinfo->rx_bytes = sta->rx_stats.bytes;
sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64); sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64);
} }
if (!(sinfo->filled & BIT(NL80211_STA_INFO_RX_PACKETS))) { if (!(sinfo->filled & BIT(NL80211_STA_INFO_RX_PACKETS))) {
sinfo->rx_packets = sta->rx_packets; sinfo->rx_packets = sta->rx_stats.packets;
sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS); sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
} }
if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_RETRIES))) { if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_RETRIES))) {
sinfo->tx_retries = sta->tx_retry_count; sinfo->tx_retries = sta->status_stats.retry_count;
sinfo->filled |= BIT(NL80211_STA_INFO_TX_RETRIES); sinfo->filled |= BIT(NL80211_STA_INFO_TX_RETRIES);
} }
if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_FAILED))) { if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_FAILED))) {
sinfo->tx_failed = sta->tx_retry_failed; sinfo->tx_failed = sta->status_stats.retry_failed;
sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED); sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
} }
sinfo->rx_dropped_misc = sta->rx_dropped; sinfo->rx_dropped_misc = sta->rx_stats.dropped;
sinfo->beacon_loss_count = sta->beacon_loss_count;
if (sdata->vif.type == NL80211_IFTYPE_STATION && if (sdata->vif.type == NL80211_IFTYPE_STATION &&
!(sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER)) { !(sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER)) {
@ -1887,33 +1930,35 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
if (ieee80211_hw_check(&sta->local->hw, SIGNAL_DBM) || if (ieee80211_hw_check(&sta->local->hw, SIGNAL_DBM) ||
ieee80211_hw_check(&sta->local->hw, SIGNAL_UNSPEC)) { ieee80211_hw_check(&sta->local->hw, SIGNAL_UNSPEC)) {
if (!(sinfo->filled & BIT(NL80211_STA_INFO_SIGNAL))) { if (!(sinfo->filled & BIT(NL80211_STA_INFO_SIGNAL))) {
sinfo->signal = (s8)sta->last_signal; sinfo->signal = (s8)sta->rx_stats.last_signal;
sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
} }
if (!(sinfo->filled & BIT(NL80211_STA_INFO_SIGNAL_AVG))) { if (!(sinfo->filled & BIT(NL80211_STA_INFO_SIGNAL_AVG))) {
sinfo->signal_avg = sinfo->signal_avg =
(s8) -ewma_signal_read(&sta->avg_signal); -ewma_signal_read(&sta->rx_stats.avg_signal);
sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG); sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG);
} }
} }
if (sta->chains && if (sta->rx_stats.chains &&
!(sinfo->filled & (BIT(NL80211_STA_INFO_CHAIN_SIGNAL) | !(sinfo->filled & (BIT(NL80211_STA_INFO_CHAIN_SIGNAL) |
BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)))) { BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)))) {
sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL) | sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL) |
BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG); BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG);
sinfo->chains = sta->chains; sinfo->chains = sta->rx_stats.chains;
for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) { for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) {
sinfo->chain_signal[i] = sta->chain_signal_last[i]; sinfo->chain_signal[i] =
sta->rx_stats.chain_signal_last[i];
sinfo->chain_signal_avg[i] = sinfo->chain_signal_avg[i] =
(s8) -ewma_signal_read(&sta->chain_signal_avg[i]); -ewma_signal_read(&sta->rx_stats.chain_signal_avg[i]);
} }
} }
if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE))) { if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE))) {
sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); sta_set_rate_info_tx(sta, &sta->tx_stats.last_rate,
&sinfo->txrate);
sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
} }
@ -1928,12 +1973,12 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
if (!(tidstats->filled & BIT(NL80211_TID_STATS_RX_MSDU))) { if (!(tidstats->filled & BIT(NL80211_TID_STATS_RX_MSDU))) {
tidstats->filled |= BIT(NL80211_TID_STATS_RX_MSDU); tidstats->filled |= BIT(NL80211_TID_STATS_RX_MSDU);
tidstats->rx_msdu = sta->rx_msdu[i]; tidstats->rx_msdu = sta->rx_stats.msdu[i];
} }
if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU))) { if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU))) {
tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU); tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU);
tidstats->tx_msdu = sta->tx_msdu[i]; tidstats->tx_msdu = sta->tx_stats.msdu[i];
} }
if (!(tidstats->filled & if (!(tidstats->filled &
@ -1941,7 +1986,8 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) { ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
tidstats->filled |= tidstats->filled |=
BIT(NL80211_TID_STATS_TX_MSDU_RETRIES); BIT(NL80211_TID_STATS_TX_MSDU_RETRIES);
tidstats->tx_msdu_retries = sta->tx_msdu_retries[i]; tidstats->tx_msdu_retries =
sta->status_stats.msdu_retries[i];
} }
if (!(tidstats->filled & if (!(tidstats->filled &
@ -1949,7 +1995,8 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) { ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
tidstats->filled |= tidstats->filled |=
BIT(NL80211_TID_STATS_TX_MSDU_FAILED); BIT(NL80211_TID_STATS_TX_MSDU_FAILED);
tidstats->tx_msdu_failed = sta->tx_msdu_failed[i]; tidstats->tx_msdu_failed =
sta->status_stats.msdu_failed[i];
} }
} }

View File

@ -344,12 +344,6 @@ DECLARE_EWMA(signal, 1024, 8)
* @rate_ctrl_lock: spinlock used to protect rate control data * @rate_ctrl_lock: spinlock used to protect rate control data
* (data inside the algorithm, so serializes calls there) * (data inside the algorithm, so serializes calls there)
* @rate_ctrl_priv: rate control private per-STA pointer * @rate_ctrl_priv: rate control private per-STA pointer
* @last_tx_rate: rate used for last transmit, to report to userspace as
* "the" transmit rate
* @last_rx_rate_idx: rx status rate index of the last data packet
* @last_rx_rate_flag: rx status flag of the last data packet
* @last_rx_rate_vht_flag: rx status vht flag of the last data packet
* @last_rx_rate_vht_nss: rx status nss of last data packet
* @lock: used for locking all fields that require locking, see comments * @lock: used for locking all fields that require locking, see comments
* in the header file. * in the header file.
* @drv_deliver_wk: used for delivering frames after driver PS unblocking * @drv_deliver_wk: used for delivering frames after driver PS unblocking
@ -364,23 +358,9 @@ DECLARE_EWMA(signal, 1024, 8)
* the station when it leaves powersave or polls for frames * the station when it leaves powersave or polls for frames
* @driver_buffered_tids: bitmap of TIDs the driver has data buffered on * @driver_buffered_tids: bitmap of TIDs the driver has data buffered on
* @txq_buffered_tids: bitmap of TIDs that mac80211 has txq data buffered on * @txq_buffered_tids: bitmap of TIDs that mac80211 has txq data buffered on
* @rx_packets: Number of MSDUs received from this STA
* @rx_bytes: Number of bytes received from this STA
* @last_rx: time (in jiffies) when last frame was received from this STA
* @last_connected: time (in seconds) when a station got connected * @last_connected: time (in seconds) when a station got connected
* @num_duplicates: number of duplicate frames received from this STA
* @rx_fragments: number of received MPDUs
* @rx_dropped: number of dropped MPDUs from this STA
* @last_signal: signal of last received frame from this STA
* @avg_signal: moving average of signal of received frames from this STA
* @last_ack_signal: signal of last received Ack frame from this STA
* @last_seq_ctrl: last received seq/frag number from this STA (per TID * @last_seq_ctrl: last received seq/frag number from this STA (per TID
* plus one for non-QoS frames) * plus one for non-QoS frames)
* @tx_filtered_count: number of frames the hardware filtered for this STA
* @tx_retry_failed: number of frames that failed retry
* @tx_retry_count: total number of retries for frames to this STA
* @tx_packets: number of RX/TX MSDUs
* @tx_bytes: number of bytes transmitted to this STA
* @tid_seq: per-TID sequence numbers for sending to this STA * @tid_seq: per-TID sequence numbers for sending to this STA
* @ampdu_mlme: A-MPDU state machine state * @ampdu_mlme: A-MPDU state machine state
* @timer_to_tid: identity mapping to ID timers * @timer_to_tid: identity mapping to ID timers
@ -388,32 +368,22 @@ DECLARE_EWMA(signal, 1024, 8)
* @debugfs: debug filesystem info * @debugfs: debug filesystem info
* @dead: set to true when sta is unlinked * @dead: set to true when sta is unlinked
* @uploaded: set to true when sta is uploaded to the driver * @uploaded: set to true when sta is uploaded to the driver
* @lost_packets: number of consecutive lost packets
* @sta: station information we share with the driver * @sta: station information we share with the driver
* @sta_state: duplicates information about station state (for debug) * @sta_state: duplicates information about station state (for debug)
* @beacon_loss_count: number of times beacon loss has triggered * @beacon_loss_count: number of times beacon loss has triggered
* @rcu_head: RCU head used for freeing this station struct * @rcu_head: RCU head used for freeing this station struct
* @cur_max_bandwidth: maximum bandwidth to use for TX to the station, * @cur_max_bandwidth: maximum bandwidth to use for TX to the station,
* taken from HT/VHT capabilities or VHT operating mode notification * taken from HT/VHT capabilities or VHT operating mode notification
* @chains: chains ever used for RX from this station
* @chain_signal_last: last signal (per chain)
* @chain_signal_avg: signal average (per chain)
* @known_smps_mode: the smps_mode the client thinks we are in. Relevant for * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for
* AP only. * AP only.
* @cipher_scheme: optional cipher scheme for this station * @cipher_scheme: optional cipher scheme for this station
* @last_tdls_pkt_time: holds the time in jiffies of last TDLS pkt ACKed
* @reserved_tid: reserved TID (if any, otherwise IEEE80211_TID_UNRESERVED) * @reserved_tid: reserved TID (if any, otherwise IEEE80211_TID_UNRESERVED)
* @tx_msdu: MSDUs transmitted to this station, using IEEE80211_NUM_TID
* entry for non-QoS frames
* @tx_msdu_retries: MSDU retries for transmissions to to this station,
* using IEEE80211_NUM_TID entry for non-QoS frames
* @tx_msdu_failed: MSDU failures for transmissions to to this station,
* using IEEE80211_NUM_TID entry for non-QoS frames
* @rx_msdu: MSDUs received from this station, using IEEE80211_NUM_TID
* entry for non-QoS frames
* @fast_tx: TX fastpath information * @fast_tx: TX fastpath information
* @tdls_chandef: a TDLS peer can have a wider chandef that is compatible to * @tdls_chandef: a TDLS peer can have a wider chandef that is compatible to
* the BSS one. * the BSS one.
* @tx_stats: TX statistics
* @rx_stats: RX statistics
* @status_stats: TX status statistics
*/ */
struct sta_info { struct sta_info {
/* General information, mostly static */ /* General information, mostly static */
@ -457,42 +427,49 @@ struct sta_info {
unsigned long driver_buffered_tids; unsigned long driver_buffered_tids;
unsigned long txq_buffered_tids; unsigned long txq_buffered_tids;
/* Updated from RX path only, no locking requirements */
unsigned long rx_packets;
u64 rx_bytes;
unsigned long last_rx;
long last_connected; long last_connected;
unsigned long num_duplicates;
unsigned long rx_fragments;
unsigned long rx_dropped;
int last_signal;
struct ewma_signal avg_signal;
int last_ack_signal;
u8 chains; /* Updated from RX path only, no locking requirements */
s8 chain_signal_last[IEEE80211_MAX_CHAINS]; struct {
struct ewma_signal chain_signal_avg[IEEE80211_MAX_CHAINS]; unsigned long packets;
u64 bytes;
unsigned long last_rx;
unsigned long num_duplicates;
unsigned long fragments;
unsigned long dropped;
int last_signal;
struct ewma_signal avg_signal;
u8 chains;
s8 chain_signal_last[IEEE80211_MAX_CHAINS];
struct ewma_signal chain_signal_avg[IEEE80211_MAX_CHAINS];
int last_rate_idx;
u32 last_rate_flag;
u32 last_rate_vht_flag;
u8 last_rate_vht_nss;
u64 msdu[IEEE80211_NUM_TIDS + 1];
} rx_stats;
/* Plus 1 for non-QoS frames */ /* Plus 1 for non-QoS frames */
__le16 last_seq_ctrl[IEEE80211_NUM_TIDS + 1]; __le16 last_seq_ctrl[IEEE80211_NUM_TIDS + 1];
/* Updated from TX status path only, no locking requirements */ /* Updated from TX status path only, no locking requirements */
unsigned long tx_filtered_count; struct {
unsigned long tx_retry_failed, tx_retry_count; unsigned long filtered;
unsigned long retry_failed, retry_count;
unsigned int lost_packets;
unsigned long last_tdls_pkt_time;
u64 msdu_retries[IEEE80211_NUM_TIDS + 1];
u64 msdu_failed[IEEE80211_NUM_TIDS + 1];
} status_stats;
/* Updated from TX path only, no locking requirements */ /* Updated from TX path only, no locking requirements */
u64 tx_packets[IEEE80211_NUM_ACS]; struct {
u64 tx_bytes[IEEE80211_NUM_ACS]; u64 packets[IEEE80211_NUM_ACS];
struct ieee80211_tx_rate last_tx_rate; u64 bytes[IEEE80211_NUM_ACS];
int last_rx_rate_idx; struct ieee80211_tx_rate last_rate;
u32 last_rx_rate_flag; u64 msdu[IEEE80211_NUM_TIDS + 1];
u32 last_rx_rate_vht_flag; } tx_stats;
u8 last_rx_rate_vht_nss;
u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
u64 tx_msdu[IEEE80211_NUM_TIDS + 1];
u64 tx_msdu_retries[IEEE80211_NUM_TIDS + 1];
u64 tx_msdu_failed[IEEE80211_NUM_TIDS + 1];
u64 rx_msdu[IEEE80211_NUM_TIDS + 1];
/* /*
* Aggregation information, locked with lock. * Aggregation information, locked with lock.
@ -509,15 +486,9 @@ struct sta_info {
enum ieee80211_sta_rx_bandwidth cur_max_bandwidth; enum ieee80211_sta_rx_bandwidth cur_max_bandwidth;
unsigned int lost_packets;
unsigned int beacon_loss_count;
enum ieee80211_smps_mode known_smps_mode; enum ieee80211_smps_mode known_smps_mode;
const struct ieee80211_cipher_scheme *cipher_scheme; const struct ieee80211_cipher_scheme *cipher_scheme;
/* TDLS timeout data */
unsigned long last_tdls_pkt_time;
u8 reserved_tid; u8 reserved_tid;
struct cfg80211_chan_def tdls_chandef; struct cfg80211_chan_def tdls_chandef;
@ -688,8 +659,6 @@ static inline int sta_info_flush(struct ieee80211_sub_if_data *sdata)
void sta_set_rate_info_tx(struct sta_info *sta, void sta_set_rate_info_tx(struct sta_info *sta,
const struct ieee80211_tx_rate *rate, const struct ieee80211_tx_rate *rate,
struct rate_info *rinfo); struct rate_info *rinfo);
void sta_set_rate_info_rx(struct sta_info *sta,
struct rate_info *rinfo);
void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo); void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo);
void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,

View File

@ -67,7 +67,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
IEEE80211_TX_INTFL_RETRANSMISSION; IEEE80211_TX_INTFL_RETRANSMISSION;
info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS; info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
sta->tx_filtered_count++; sta->status_stats.filtered++;
/* /*
* Clear more-data bit on filtered frames, it might be set * Clear more-data bit on filtered frames, it might be set
@ -183,7 +183,7 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
struct ieee80211_sub_if_data *sdata = sta->sdata; struct ieee80211_sub_if_data *sdata = sta->sdata;
if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
sta->last_rx = jiffies; sta->rx_stats.last_rx = jiffies;
if (ieee80211_is_data_qos(mgmt->frame_control)) { if (ieee80211_is_data_qos(mgmt->frame_control)) {
struct ieee80211_hdr *hdr = (void *) skb->data; struct ieee80211_hdr *hdr = (void *) skb->data;
@ -557,8 +557,9 @@ static void ieee80211_lost_packet(struct sta_info *sta,
!(info->flags & IEEE80211_TX_STAT_AMPDU)) !(info->flags & IEEE80211_TX_STAT_AMPDU))
return; return;
sta->lost_packets++; sta->status_stats.lost_packets++;
if (!sta->sta.tdls && sta->lost_packets < STA_LOST_PKT_THRESHOLD) if (!sta->sta.tdls &&
sta->status_stats.lost_packets < STA_LOST_PKT_THRESHOLD)
return; return;
/* /*
@ -568,14 +569,15 @@ static void ieee80211_lost_packet(struct sta_info *sta,
* mechanism. * mechanism.
*/ */
if (sta->sta.tdls && if (sta->sta.tdls &&
(sta->lost_packets < STA_LOST_TDLS_PKT_THRESHOLD || (sta->status_stats.lost_packets < STA_LOST_TDLS_PKT_THRESHOLD ||
time_before(jiffies, time_before(jiffies,
sta->last_tdls_pkt_time + STA_LOST_TDLS_PKT_TIME))) sta->status_stats.last_tdls_pkt_time +
STA_LOST_TDLS_PKT_TIME)))
return; return;
cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr, cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr,
sta->lost_packets, GFP_ATOMIC); sta->status_stats.lost_packets, GFP_ATOMIC);
sta->lost_packets = 0; sta->status_stats.lost_packets = 0;
} }
static int ieee80211_tx_get_rates(struct ieee80211_hw *hw, static int ieee80211_tx_get_rates(struct ieee80211_hw *hw,
@ -636,18 +638,18 @@ void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
sta = container_of(pubsta, struct sta_info, sta); sta = container_of(pubsta, struct sta_info, sta);
if (!acked) if (!acked)
sta->tx_retry_failed++; sta->status_stats.retry_failed++;
sta->tx_retry_count += retry_count; sta->status_stats.retry_count += retry_count;
if (acked) { if (acked) {
sta->last_rx = jiffies; sta->rx_stats.last_rx = jiffies;
if (sta->lost_packets) if (sta->status_stats.lost_packets)
sta->lost_packets = 0; sta->status_stats.lost_packets = 0;
/* Track when last TDLS packet was ACKed */ /* Track when last TDLS packet was ACKed */
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
sta->last_tdls_pkt_time = jiffies; sta->status_stats.last_tdls_pkt_time = jiffies;
} else { } else {
ieee80211_lost_packet(sta, info); ieee80211_lost_packet(sta, info);
} }
@ -784,7 +786,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL) && if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL) &&
(ieee80211_is_data(hdr->frame_control)) && (ieee80211_is_data(hdr->frame_control)) &&
(rates_idx != -1)) (rates_idx != -1))
sta->last_tx_rate = info->status.rates[rates_idx]; sta->tx_stats.last_rate =
info->status.rates[rates_idx];
if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
(ieee80211_is_data_qos(fc))) { (ieee80211_is_data_qos(fc))) {
@ -830,13 +833,15 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
return; return;
} else { } else {
if (!acked) if (!acked)
sta->tx_retry_failed++; sta->status_stats.retry_failed++;
sta->tx_retry_count += retry_count; sta->status_stats.retry_count += retry_count;
if (ieee80211_is_data_present(fc)) { if (ieee80211_is_data_present(fc)) {
if (!acked) if (!acked)
sta->tx_msdu_failed[tid]++; sta->status_stats.msdu_failed[tid]++;
sta->tx_msdu_retries[tid] += retry_count;
sta->status_stats.msdu_retries[tid] +=
retry_count;
} }
} }
@ -854,19 +859,17 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) { if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
if (info->flags & IEEE80211_TX_STAT_ACK) { if (info->flags & IEEE80211_TX_STAT_ACK) {
if (sta->lost_packets) if (sta->status_stats.lost_packets)
sta->lost_packets = 0; sta->status_stats.lost_packets = 0;
/* Track when last TDLS packet was ACKed */ /* Track when last TDLS packet was ACKed */
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
sta->last_tdls_pkt_time = jiffies; sta->status_stats.last_tdls_pkt_time =
jiffies;
} else { } else {
ieee80211_lost_packet(sta, info); ieee80211_lost_packet(sta, info);
} }
} }
if (acked)
sta->last_ack_signal = info->status.ack_signal;
} }
rcu_read_unlock(); rcu_read_unlock();

View File

@ -325,7 +325,6 @@ TRACE_EVENT(drv_config,
__field(u32, flags) __field(u32, flags)
__field(int, power_level) __field(int, power_level)
__field(int, dynamic_ps_timeout) __field(int, dynamic_ps_timeout)
__field(int, max_sleep_period)
__field(u16, listen_interval) __field(u16, listen_interval)
__field(u8, long_frame_max_tx_count) __field(u8, long_frame_max_tx_count)
__field(u8, short_frame_max_tx_count) __field(u8, short_frame_max_tx_count)
@ -339,7 +338,6 @@ TRACE_EVENT(drv_config,
__entry->flags = local->hw.conf.flags; __entry->flags = local->hw.conf.flags;
__entry->power_level = local->hw.conf.power_level; __entry->power_level = local->hw.conf.power_level;
__entry->dynamic_ps_timeout = local->hw.conf.dynamic_ps_timeout; __entry->dynamic_ps_timeout = local->hw.conf.dynamic_ps_timeout;
__entry->max_sleep_period = local->hw.conf.max_sleep_period;
__entry->listen_interval = local->hw.conf.listen_interval; __entry->listen_interval = local->hw.conf.listen_interval;
__entry->long_frame_max_tx_count = __entry->long_frame_max_tx_count =
local->hw.conf.long_frame_max_tx_count; local->hw.conf.long_frame_max_tx_count;

View File

@ -757,9 +757,9 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
if (txrc.reported_rate.idx < 0) { if (txrc.reported_rate.idx < 0) {
txrc.reported_rate = tx->rate; txrc.reported_rate = tx->rate;
if (tx->sta && ieee80211_is_data(hdr->frame_control)) if (tx->sta && ieee80211_is_data(hdr->frame_control))
tx->sta->last_tx_rate = txrc.reported_rate; tx->sta->tx_stats.last_rate = txrc.reported_rate;
} else if (tx->sta) } else if (tx->sta)
tx->sta->last_tx_rate = txrc.reported_rate; tx->sta->tx_stats.last_rate = txrc.reported_rate;
if (ratetbl) if (ratetbl)
return TX_CONTINUE; return TX_CONTINUE;
@ -824,7 +824,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number); hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number);
tx->sdata->sequence_number += 0x10; tx->sdata->sequence_number += 0x10;
if (tx->sta) if (tx->sta)
tx->sta->tx_msdu[IEEE80211_NUM_TIDS]++; tx->sta->tx_stats.msdu[IEEE80211_NUM_TIDS]++;
return TX_CONTINUE; return TX_CONTINUE;
} }
@ -840,7 +840,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
qc = ieee80211_get_qos_ctl(hdr); qc = ieee80211_get_qos_ctl(hdr);
tid = *qc & IEEE80211_QOS_CTL_TID_MASK; tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
tx->sta->tx_msdu[tid]++; tx->sta->tx_stats.msdu[tid]++;
if (!tx->sta->sta.txq[0]) if (!tx->sta->sta.txq[0])
hdr->seq_ctrl = ieee80211_tx_next_seq(tx->sta, tid); hdr->seq_ctrl = ieee80211_tx_next_seq(tx->sta, tid);
@ -994,10 +994,10 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
skb_queue_walk(&tx->skbs, skb) { skb_queue_walk(&tx->skbs, skb) {
ac = skb_get_queue_mapping(skb); ac = skb_get_queue_mapping(skb);
tx->sta->tx_bytes[ac] += skb->len; tx->sta->tx_stats.bytes[ac] += skb->len;
} }
if (ac >= 0) if (ac >= 0)
tx->sta->tx_packets[ac]++; tx->sta->tx_stats.packets[ac]++;
return TX_CONTINUE; return TX_CONTINUE;
} }
@ -2779,10 +2779,10 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
} }
if (skb_shinfo(skb)->gso_size) if (skb_shinfo(skb)->gso_size)
sta->tx_msdu[tid] += sta->tx_stats.msdu[tid] +=
DIV_ROUND_UP(skb->len, skb_shinfo(skb)->gso_size); DIV_ROUND_UP(skb->len, skb_shinfo(skb)->gso_size);
else else
sta->tx_msdu[tid]++; sta->tx_stats.msdu[tid]++;
info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)]; info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
@ -2813,8 +2813,8 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
/* statistics normally done by ieee80211_tx_h_stats (but that /* statistics normally done by ieee80211_tx_h_stats (but that
* has to consider fragmentation, so is more complex) * has to consider fragmentation, so is more complex)
*/ */
sta->tx_bytes[skb_get_queue_mapping(skb)] += skb->len; sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len;
sta->tx_packets[skb_get_queue_mapping(skb)]++; sta->tx_stats.packets[skb_get_queue_mapping(skb)]++;
if (fast_tx->pn_offs) { if (fast_tx->pn_offs) {
u64 pn; u64 pn;

View File

@ -1951,7 +1951,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
} }
} }
ieee80211_recalc_ps(local, -1); ieee80211_recalc_ps(local);
/* /*
* The sta might be in psm against the ap (e.g. because * The sta might be in psm against the ap (e.g. because
@ -2042,9 +2042,13 @@ int ieee80211_reconfig(struct ieee80211_local *local)
if (sched_scan_sdata && sched_scan_req) if (sched_scan_sdata && sched_scan_req)
/* /*
* Sched scan stopped, but we don't want to report it. Instead, * Sched scan stopped, but we don't want to report it. Instead,
* we're trying to reschedule. * we're trying to reschedule. However, if more than one scan
* plan was set, we cannot reschedule since we don't know which
* scan plan was currently running (and some scan plans may have
* already finished).
*/ */
if (__ieee80211_request_sched_scan_start(sched_scan_sdata, if (sched_scan_req->n_scan_plans > 1 ||
__ieee80211_request_sched_scan_start(sched_scan_sdata,
sched_scan_req)) sched_scan_req))
sched_scan_stopped = true; sched_scan_stopped = true;
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
@ -3301,9 +3305,11 @@ void ieee80211_init_tx_queue(struct ieee80211_sub_if_data *sdata,
if (sta) { if (sta) {
txqi->txq.sta = &sta->sta; txqi->txq.sta = &sta->sta;
sta->sta.txq[tid] = &txqi->txq; sta->sta.txq[tid] = &txqi->txq;
txqi->txq.tid = tid;
txqi->txq.ac = ieee802_1d_to_ac[tid & 7]; txqi->txq.ac = ieee802_1d_to_ac[tid & 7];
} else { } else {
sdata->vif.txq = &txqi->txq; sdata->vif.txq = &txqi->txq;
txqi->txq.tid = 0;
txqi->txq.ac = IEEE80211_AC_BE; txqi->txq.ac = IEEE80211_AC_BE;
} }
} }

View File

@ -174,9 +174,12 @@ mic_fail_no_key:
* a driver that supports HW encryption. Send up the key idx only if * a driver that supports HW encryption. Send up the key idx only if
* the key is set. * the key is set.
*/ */
mac80211_ev_michael_mic_failure(rx->sdata, cfg80211_michael_mic_failure(rx->sdata->dev, hdr->addr2,
rx->key ? rx->key->conf.keyidx : -1, is_multicast_ether_addr(hdr->addr1) ?
(void *) skb->data, NULL, GFP_ATOMIC); NL80211_KEYTYPE_GROUP :
NL80211_KEYTYPE_PAIRWISE,
rx->key ? rx->key->conf.keyidx : -1,
NULL, GFP_ATOMIC);
return RX_DROP_UNUSABLE; return RX_DROP_UNUSABLE;
} }

View File

@ -174,6 +174,16 @@ config CFG80211_INTERNAL_REGDB
Most distributions have a CRDA package. So if unsure, say N. Most distributions have a CRDA package. So if unsure, say N.
config CFG80211_CRDA_SUPPORT
bool "support CRDA" if CFG80211_INTERNAL_REGDB
default y
depends on CFG80211
help
You should enable this option unless you know for sure you have no
need for it, for example when using internal regdb (above.)
If unsure, say Y.
config CFG80211_WEXT config CFG80211_WEXT
bool "cfg80211 wireless extensions compatibility" if !CFG80211_WEXT_EXPORT bool "cfg80211 wireless extensions compatibility" if !CFG80211_WEXT_EXPORT
depends on CFG80211 depends on CFG80211

View File

@ -461,6 +461,9 @@ use_default_name:
rdev->wiphy.max_num_csa_counters = 1; rdev->wiphy.max_num_csa_counters = 1;
rdev->wiphy.max_sched_scan_plans = 1;
rdev->wiphy.max_sched_scan_plan_interval = U32_MAX;
return &rdev->wiphy; return &rdev->wiphy;
} }
EXPORT_SYMBOL(wiphy_new_nm); EXPORT_SYMBOL(wiphy_new_nm);
@ -636,7 +639,7 @@ int wiphy_register(struct wiphy *wiphy)
if (WARN_ON(!sband->n_channels)) if (WARN_ON(!sband->n_channels))
return -EINVAL; return -EINVAL;
/* /*
* on 60gHz band, there are no legacy rates, so * on 60GHz band, there are no legacy rates, so
* n_bitrates is 0 * n_bitrates is 0
*/ */
if (WARN_ON(band != IEEE80211_BAND_60GHZ && if (WARN_ON(band != IEEE80211_BAND_60GHZ &&

View File

@ -137,6 +137,7 @@ struct cfg80211_internal_bss {
struct list_head list; struct list_head list;
struct list_head hidden_list; struct list_head hidden_list;
struct rb_node rbn; struct rb_node rbn;
u64 ts_boottime;
unsigned long ts; unsigned long ts;
unsigned long refcount; unsigned long refcount;
atomic_t hold; atomic_t hold;

View File

@ -479,6 +479,12 @@ nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 }, [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
}; };
static const struct nla_policy
nl80211_plan_policy[NL80211_SCHED_SCAN_PLAN_MAX + 1] = {
[NL80211_SCHED_SCAN_PLAN_INTERVAL] = { .type = NLA_U32 },
[NL80211_SCHED_SCAN_PLAN_ITERATIONS] = { .type = NLA_U32 },
};
static int nl80211_prepare_wdev_dump(struct sk_buff *skb, static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
struct netlink_callback *cb, struct netlink_callback *cb,
struct cfg80211_registered_device **rdev, struct cfg80211_registered_device **rdev,
@ -1304,7 +1310,13 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN, nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
rdev->wiphy.max_sched_scan_ie_len) || rdev->wiphy.max_sched_scan_ie_len) ||
nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS, nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS,
rdev->wiphy.max_match_sets)) rdev->wiphy.max_match_sets) ||
nla_put_u32(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS,
rdev->wiphy.max_sched_scan_plans) ||
nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL,
rdev->wiphy.max_sched_scan_plan_interval) ||
nla_put_u32(msg, NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
rdev->wiphy.max_sched_scan_plan_iterations))
goto nla_put_failure; goto nla_put_failure;
if ((rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) && if ((rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) &&
@ -4932,56 +4944,6 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
return err; return err;
} }
static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
[NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
[NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
[NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
[NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
[NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
[NL80211_ATTR_DFS_CAC_TIME] = { .type = NLA_U32 },
};
static int parse_reg_rule(struct nlattr *tb[],
struct ieee80211_reg_rule *reg_rule)
{
struct ieee80211_freq_range *freq_range = &reg_rule->freq_range;
struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;
if (!tb[NL80211_ATTR_REG_RULE_FLAGS])
return -EINVAL;
if (!tb[NL80211_ATTR_FREQ_RANGE_START])
return -EINVAL;
if (!tb[NL80211_ATTR_FREQ_RANGE_END])
return -EINVAL;
if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
return -EINVAL;
if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
return -EINVAL;
reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
freq_range->start_freq_khz =
nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
freq_range->end_freq_khz =
nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
freq_range->max_bandwidth_khz =
nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
power_rule->max_eirp =
nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);
if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN])
power_rule->max_antenna_gain =
nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);
if (tb[NL80211_ATTR_DFS_CAC_TIME])
reg_rule->dfs_cac_ms =
nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]);
return 0;
}
static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
{ {
char *data = NULL; char *data = NULL;
@ -5613,6 +5575,57 @@ out_err:
return err; return err;
} }
#ifdef CONFIG_CFG80211_CRDA_SUPPORT
static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
[NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
[NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
[NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
[NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
[NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
[NL80211_ATTR_DFS_CAC_TIME] = { .type = NLA_U32 },
};
static int parse_reg_rule(struct nlattr *tb[],
struct ieee80211_reg_rule *reg_rule)
{
struct ieee80211_freq_range *freq_range = &reg_rule->freq_range;
struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;
if (!tb[NL80211_ATTR_REG_RULE_FLAGS])
return -EINVAL;
if (!tb[NL80211_ATTR_FREQ_RANGE_START])
return -EINVAL;
if (!tb[NL80211_ATTR_FREQ_RANGE_END])
return -EINVAL;
if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
return -EINVAL;
if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
return -EINVAL;
reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
freq_range->start_freq_khz =
nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
freq_range->end_freq_khz =
nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
freq_range->max_bandwidth_khz =
nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
power_rule->max_eirp =
nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);
if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN])
power_rule->max_antenna_gain =
nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);
if (tb[NL80211_ATTR_DFS_CAC_TIME])
reg_rule->dfs_cac_ms =
nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]);
return 0;
}
static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
{ {
struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1]; struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
@ -5689,6 +5702,7 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
kfree(rd); kfree(rd);
return r; return r;
} }
#endif /* CONFIG_CFG80211_CRDA_SUPPORT */
static int validate_scan_freqs(struct nlattr *freqs) static int validate_scan_freqs(struct nlattr *freqs)
{ {
@ -5974,14 +5988,100 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
return err; return err;
} }
static int
nl80211_parse_sched_scan_plans(struct wiphy *wiphy, int n_plans,
struct cfg80211_sched_scan_request *request,
struct nlattr **attrs)
{
int tmp, err, i = 0;
struct nlattr *attr;
if (!attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
u32 interval;
/*
* If scan plans are not specified,
* %NL80211_ATTR_SCHED_SCAN_INTERVAL must be specified. In this
* case one scan plan will be set with the specified scan
* interval and infinite number of iterations.
*/
if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
return -EINVAL;
interval = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]);
if (!interval)
return -EINVAL;
request->scan_plans[0].interval =
DIV_ROUND_UP(interval, MSEC_PER_SEC);
if (!request->scan_plans[0].interval)
return -EINVAL;
if (request->scan_plans[0].interval >
wiphy->max_sched_scan_plan_interval)
request->scan_plans[0].interval =
wiphy->max_sched_scan_plan_interval;
return 0;
}
nla_for_each_nested(attr, attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp) {
struct nlattr *plan[NL80211_SCHED_SCAN_PLAN_MAX + 1];
if (WARN_ON(i >= n_plans))
return -EINVAL;
err = nla_parse(plan, NL80211_SCHED_SCAN_PLAN_MAX,
nla_data(attr), nla_len(attr),
nl80211_plan_policy);
if (err)
return err;
if (!plan[NL80211_SCHED_SCAN_PLAN_INTERVAL])
return -EINVAL;
request->scan_plans[i].interval =
nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_INTERVAL]);
if (!request->scan_plans[i].interval ||
request->scan_plans[i].interval >
wiphy->max_sched_scan_plan_interval)
return -EINVAL;
if (plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]) {
request->scan_plans[i].iterations =
nla_get_u32(plan[NL80211_SCHED_SCAN_PLAN_ITERATIONS]);
if (!request->scan_plans[i].iterations ||
(request->scan_plans[i].iterations >
wiphy->max_sched_scan_plan_iterations))
return -EINVAL;
} else if (i < n_plans - 1) {
/*
* All scan plans but the last one must specify
* a finite number of iterations
*/
return -EINVAL;
}
i++;
}
/*
* The last scan plan must not specify the number of
* iterations, it is supposed to run infinitely
*/
if (request->scan_plans[n_plans - 1].iterations)
return -EINVAL;
return 0;
}
static struct cfg80211_sched_scan_request * static struct cfg80211_sched_scan_request *
nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev, nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
struct nlattr **attrs) struct nlattr **attrs)
{ {
struct cfg80211_sched_scan_request *request; struct cfg80211_sched_scan_request *request;
struct nlattr *attr; struct nlattr *attr;
int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i; int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i, n_plans = 0;
u32 interval;
enum ieee80211_band band; enum ieee80211_band band;
size_t ie_len; size_t ie_len;
struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1]; struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
@ -5990,13 +6090,6 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
if (!is_valid_ie_attr(attrs[NL80211_ATTR_IE])) if (!is_valid_ie_attr(attrs[NL80211_ATTR_IE]))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
return ERR_PTR(-EINVAL);
interval = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]);
if (interval == 0)
return ERR_PTR(-EINVAL);
if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
n_channels = validate_scan_freqs( n_channels = validate_scan_freqs(
attrs[NL80211_ATTR_SCAN_FREQUENCIES]); attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
@ -6060,9 +6153,37 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
if (ie_len > wiphy->max_sched_scan_ie_len) if (ie_len > wiphy->max_sched_scan_ie_len)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
if (attrs[NL80211_ATTR_SCHED_SCAN_PLANS]) {
/*
* NL80211_ATTR_SCHED_SCAN_INTERVAL must not be specified since
* each scan plan already specifies its own interval
*/
if (attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
return ERR_PTR(-EINVAL);
nla_for_each_nested(attr,
attrs[NL80211_ATTR_SCHED_SCAN_PLANS], tmp)
n_plans++;
} else {
/*
* The scan interval attribute is kept for backward
* compatibility. If no scan plans are specified and sched scan
* interval is specified, one scan plan will be set with this
* scan interval and infinite number of iterations.
*/
if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
return ERR_PTR(-EINVAL);
n_plans = 1;
}
if (!n_plans || n_plans > wiphy->max_sched_scan_plans)
return ERR_PTR(-EINVAL);
request = kzalloc(sizeof(*request) request = kzalloc(sizeof(*request)
+ sizeof(*request->ssids) * n_ssids + sizeof(*request->ssids) * n_ssids
+ sizeof(*request->match_sets) * n_match_sets + sizeof(*request->match_sets) * n_match_sets
+ sizeof(*request->scan_plans) * n_plans
+ sizeof(*request->channels) * n_channels + sizeof(*request->channels) * n_channels
+ ie_len, GFP_KERNEL); + ie_len, GFP_KERNEL);
if (!request) if (!request)
@ -6090,6 +6211,18 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
} }
request->n_match_sets = n_match_sets; request->n_match_sets = n_match_sets;
if (n_match_sets)
request->scan_plans = (void *)(request->match_sets +
n_match_sets);
else if (request->ie)
request->scan_plans = (void *)(request->ie + ie_len);
else if (n_ssids)
request->scan_plans = (void *)(request->ssids + n_ssids);
else
request->scan_plans = (void *)(request->channels + n_channels);
request->n_scan_plans = n_plans;
i = 0; i = 0;
if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
/* user specified, bail out if channel not found */ /* user specified, bail out if channel not found */
@ -6252,7 +6385,10 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
request->delay = request->delay =
nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_DELAY]); nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_DELAY]);
request->interval = interval; err = nl80211_parse_sched_scan_plans(wiphy, n_plans, request, attrs);
if (err)
goto out_free;
request->scan_start = jiffies; request->scan_start = jiffies;
return request; return request;
@ -6605,6 +6741,11 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
jiffies_to_msecs(jiffies - intbss->ts))) jiffies_to_msecs(jiffies - intbss->ts)))
goto nla_put_failure; goto nla_put_failure;
if (intbss->ts_boottime &&
nla_put_u64(msg, NL80211_BSS_LAST_SEEN_BOOTTIME,
intbss->ts_boottime))
goto nla_put_failure;
switch (rdev->wiphy.signal_type) { switch (rdev->wiphy.signal_type) {
case CFG80211_SIGNAL_TYPE_MBM: case CFG80211_SIGNAL_TYPE_MBM:
if (nla_put_u32(msg, NL80211_BSS_SIGNAL_MBM, res->signal)) if (nla_put_u32(msg, NL80211_BSS_SIGNAL_MBM, res->signal))
@ -8845,7 +8986,7 @@ static int nl80211_send_wowlan_tcp(struct sk_buff *msg,
static int nl80211_send_wowlan_nd(struct sk_buff *msg, static int nl80211_send_wowlan_nd(struct sk_buff *msg,
struct cfg80211_sched_scan_request *req) struct cfg80211_sched_scan_request *req)
{ {
struct nlattr *nd, *freqs, *matches, *match; struct nlattr *nd, *freqs, *matches, *match, *scan_plans, *scan_plan;
int i; int i;
if (!req) if (!req)
@ -8855,7 +8996,9 @@ static int nl80211_send_wowlan_nd(struct sk_buff *msg,
if (!nd) if (!nd)
return -ENOBUFS; return -ENOBUFS;
if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, req->interval)) if (req->n_scan_plans == 1 &&
nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL,
req->scan_plans[0].interval * 1000))
return -ENOBUFS; return -ENOBUFS;
if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay)) if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay))
@ -8882,6 +9025,23 @@ static int nl80211_send_wowlan_nd(struct sk_buff *msg,
nla_nest_end(msg, matches); nla_nest_end(msg, matches);
} }
scan_plans = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_PLANS);
if (!scan_plans)
return -ENOBUFS;
for (i = 0; i < req->n_scan_plans; i++) {
scan_plan = nla_nest_start(msg, i + 1);
if (!scan_plan ||
nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_INTERVAL,
req->scan_plans[i].interval) ||
(req->scan_plans[i].iterations &&
nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_ITERATIONS,
req->scan_plans[i].iterations)))
return -ENOBUFS;
nla_nest_end(msg, scan_plan);
}
nla_nest_end(msg, scan_plans);
nla_nest_end(msg, nd); nla_nest_end(msg, nd);
return 0; return 0;
@ -10737,6 +10897,7 @@ static const struct genl_ops nl80211_ops[] = {
.internal_flags = NL80211_FLAG_NEED_RTNL, .internal_flags = NL80211_FLAG_NEED_RTNL,
/* can be retrieved by unprivileged users */ /* can be retrieved by unprivileged users */
}, },
#ifdef CONFIG_CFG80211_CRDA_SUPPORT
{ {
.cmd = NL80211_CMD_SET_REG, .cmd = NL80211_CMD_SET_REG,
.doit = nl80211_set_reg, .doit = nl80211_set_reg,
@ -10744,6 +10905,7 @@ static const struct genl_ops nl80211_ops[] = {
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_RTNL, .internal_flags = NL80211_FLAG_NEED_RTNL,
}, },
#endif
{ {
.cmd = NL80211_CMD_REQ_SET_REG, .cmd = NL80211_CMD_REQ_SET_REG,
.doit = nl80211_req_set_reg, .doit = nl80211_req_set_reg,

View File

@ -135,10 +135,7 @@ static spinlock_t reg_indoor_lock;
/* Used to track the userspace process controlling the indoor setting */ /* Used to track the userspace process controlling the indoor setting */
static u32 reg_is_indoor_portid; static u32 reg_is_indoor_portid;
/* Max number of consecutive attempts to communicate with CRDA */ static void restore_regulatory_settings(bool reset_user);
#define REG_MAX_CRDA_TIMEOUTS 10
static u32 reg_crda_timeouts;
static const struct ieee80211_regdomain *get_cfg80211_regdom(void) static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
{ {
@ -226,9 +223,6 @@ static DECLARE_DELAYED_WORK(reg_check_chans, reg_check_chans_work);
static void reg_todo(struct work_struct *work); static void reg_todo(struct work_struct *work);
static DECLARE_WORK(reg_work, reg_todo); static DECLARE_WORK(reg_work, reg_todo);
static void reg_timeout_work(struct work_struct *work);
static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work);
/* We keep a static world regulatory domain in case of the absence of CRDA */ /* We keep a static world regulatory domain in case of the absence of CRDA */
static const struct ieee80211_regdomain world_regdom = { static const struct ieee80211_regdomain world_regdom = {
.n_reg_rules = 8, .n_reg_rules = 8,
@ -262,7 +256,7 @@ static const struct ieee80211_regdomain world_regdom = {
REG_RULE(5745-10, 5825+10, 80, 6, 20, REG_RULE(5745-10, 5825+10, 80, 6, 20,
NL80211_RRF_NO_IR), NL80211_RRF_NO_IR),
/* IEEE 802.11ad (60gHz), channels 1..3 */ /* IEEE 802.11ad (60GHz), channels 1..3 */
REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0), REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0),
} }
}; };
@ -279,6 +273,9 @@ MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
static void reg_free_request(struct regulatory_request *request) static void reg_free_request(struct regulatory_request *request)
{ {
if (request == &core_request_world)
return;
if (request != get_last_request()) if (request != get_last_request())
kfree(request); kfree(request);
} }
@ -453,68 +450,70 @@ reg_copy_regd(const struct ieee80211_regdomain *src_regd)
} }
#ifdef CONFIG_CFG80211_INTERNAL_REGDB #ifdef CONFIG_CFG80211_INTERNAL_REGDB
struct reg_regdb_search_request { struct reg_regdb_apply_request {
char alpha2[2];
struct list_head list; struct list_head list;
const struct ieee80211_regdomain *regdom;
}; };
static LIST_HEAD(reg_regdb_search_list); static LIST_HEAD(reg_regdb_apply_list);
static DEFINE_MUTEX(reg_regdb_search_mutex); static DEFINE_MUTEX(reg_regdb_apply_mutex);
static void reg_regdb_search(struct work_struct *work) static void reg_regdb_apply(struct work_struct *work)
{ {
struct reg_regdb_search_request *request; struct reg_regdb_apply_request *request;
const struct ieee80211_regdomain *curdom, *regdom = NULL;
int i;
rtnl_lock(); rtnl_lock();
mutex_lock(&reg_regdb_search_mutex); mutex_lock(&reg_regdb_apply_mutex);
while (!list_empty(&reg_regdb_search_list)) { while (!list_empty(&reg_regdb_apply_list)) {
request = list_first_entry(&reg_regdb_search_list, request = list_first_entry(&reg_regdb_apply_list,
struct reg_regdb_search_request, struct reg_regdb_apply_request,
list); list);
list_del(&request->list); list_del(&request->list);
for (i = 0; i < reg_regdb_size; i++) { set_regdom(request->regdom, REGD_SOURCE_INTERNAL_DB);
curdom = reg_regdb[i];
if (alpha2_equal(request->alpha2, curdom->alpha2)) {
regdom = reg_copy_regd(curdom);
break;
}
}
kfree(request); kfree(request);
} }
mutex_unlock(&reg_regdb_search_mutex); mutex_unlock(&reg_regdb_apply_mutex);
if (!IS_ERR_OR_NULL(regdom))
set_regdom(regdom, REGD_SOURCE_INTERNAL_DB);
rtnl_unlock(); rtnl_unlock();
} }
static DECLARE_WORK(reg_regdb_work, reg_regdb_search); static DECLARE_WORK(reg_regdb_work, reg_regdb_apply);
static void reg_regdb_query(const char *alpha2) static int reg_query_builtin(const char *alpha2)
{ {
struct reg_regdb_search_request *request; const struct ieee80211_regdomain *regdom = NULL;
struct reg_regdb_apply_request *request;
unsigned int i;
if (!alpha2) for (i = 0; i < reg_regdb_size; i++) {
return; if (alpha2_equal(alpha2, reg_regdb[i]->alpha2)) {
regdom = reg_regdb[i];
break;
}
}
request = kzalloc(sizeof(struct reg_regdb_search_request), GFP_KERNEL); if (!regdom)
return -ENODATA;
request = kzalloc(sizeof(struct reg_regdb_apply_request), GFP_KERNEL);
if (!request) if (!request)
return; return -ENOMEM;
memcpy(request->alpha2, alpha2, 2); request->regdom = reg_copy_regd(regdom);
if (IS_ERR_OR_NULL(request->regdom)) {
kfree(request);
return -ENOMEM;
}
mutex_lock(&reg_regdb_search_mutex); mutex_lock(&reg_regdb_apply_mutex);
list_add_tail(&request->list, &reg_regdb_search_list); list_add_tail(&request->list, &reg_regdb_apply_list);
mutex_unlock(&reg_regdb_search_mutex); mutex_unlock(&reg_regdb_apply_mutex);
schedule_work(&reg_regdb_work); schedule_work(&reg_regdb_work);
return 0;
} }
/* Feel free to add any other sanity checks here */ /* Feel free to add any other sanity checks here */
@ -525,9 +524,45 @@ static void reg_regdb_size_check(void)
} }
#else #else
static inline void reg_regdb_size_check(void) {} static inline void reg_regdb_size_check(void) {}
static inline void reg_regdb_query(const char *alpha2) {} static inline int reg_query_builtin(const char *alpha2)
{
return -ENODATA;
}
#endif /* CONFIG_CFG80211_INTERNAL_REGDB */ #endif /* CONFIG_CFG80211_INTERNAL_REGDB */
#ifdef CONFIG_CFG80211_CRDA_SUPPORT
/* Max number of consecutive attempts to communicate with CRDA */
#define REG_MAX_CRDA_TIMEOUTS 10
static u32 reg_crda_timeouts;
static void crda_timeout_work(struct work_struct *work);
static DECLARE_DELAYED_WORK(crda_timeout, crda_timeout_work);
static void crda_timeout_work(struct work_struct *work)
{
REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n");
rtnl_lock();
reg_crda_timeouts++;
restore_regulatory_settings(true);
rtnl_unlock();
}
static void cancel_crda_timeout(void)
{
cancel_delayed_work(&crda_timeout);
}
static void cancel_crda_timeout_sync(void)
{
cancel_delayed_work_sync(&crda_timeout);
}
static void reset_crda_timeouts(void)
{
reg_crda_timeouts = 0;
}
/* /*
* This lets us keep regulatory code which is updated on a regulatory * This lets us keep regulatory code which is updated on a regulatory
* basis in userspace. * basis in userspace.
@ -536,13 +571,11 @@ static int call_crda(const char *alpha2)
{ {
char country[12]; char country[12];
char *env[] = { country, NULL }; char *env[] = { country, NULL };
int ret;
snprintf(country, sizeof(country), "COUNTRY=%c%c", snprintf(country, sizeof(country), "COUNTRY=%c%c",
alpha2[0], alpha2[1]); alpha2[0], alpha2[1]);
/* query internal regulatory database (if it exists) */
reg_regdb_query(alpha2);
if (reg_crda_timeouts > REG_MAX_CRDA_TIMEOUTS) { if (reg_crda_timeouts > REG_MAX_CRDA_TIMEOUTS) {
pr_debug("Exceeded CRDA call max attempts. Not calling CRDA\n"); pr_debug("Exceeded CRDA call max attempts. Not calling CRDA\n");
return -EINVAL; return -EINVAL;
@ -554,18 +587,34 @@ static int call_crda(const char *alpha2)
else else
pr_debug("Calling CRDA to update world regulatory domain\n"); pr_debug("Calling CRDA to update world regulatory domain\n");
return kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, env); ret = kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, env);
} if (ret)
return ret;
static enum reg_request_treatment
reg_call_crda(struct regulatory_request *request)
{
if (call_crda(request->alpha2))
return REG_REQ_IGNORE;
queue_delayed_work(system_power_efficient_wq, queue_delayed_work(system_power_efficient_wq,
&reg_timeout, msecs_to_jiffies(3142)); &crda_timeout, msecs_to_jiffies(3142));
return REG_REQ_OK; return 0;
}
#else
static inline void cancel_crda_timeout(void) {}
static inline void cancel_crda_timeout_sync(void) {}
static inline void reset_crda_timeouts(void) {}
static inline int call_crda(const char *alpha2)
{
return -ENODATA;
}
#endif /* CONFIG_CFG80211_CRDA_SUPPORT */
static bool reg_query_database(struct regulatory_request *request)
{
/* query internal regulatory database (if it exists) */
if (reg_query_builtin(request->alpha2) == 0)
return true;
if (call_crda(request->alpha2) == 0)
return true;
return false;
} }
bool reg_is_valid_request(const char *alpha2) bool reg_is_valid_request(const char *alpha2)
@ -1081,11 +1130,11 @@ const char *reg_initiator_name(enum nl80211_reg_initiator initiator)
} }
EXPORT_SYMBOL(reg_initiator_name); EXPORT_SYMBOL(reg_initiator_name);
#ifdef CONFIG_CFG80211_REG_DEBUG
static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd, static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
const struct ieee80211_reg_rule *reg_rule) const struct ieee80211_reg_rule *reg_rule)
{ {
#ifdef CONFIG_CFG80211_REG_DEBUG
const struct ieee80211_power_rule *power_rule; const struct ieee80211_power_rule *power_rule;
const struct ieee80211_freq_range *freq_range; const struct ieee80211_freq_range *freq_range;
char max_antenna_gain[32], bw[32]; char max_antenna_gain[32], bw[32];
@ -1096,7 +1145,7 @@ static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd,
if (!power_rule->max_antenna_gain) if (!power_rule->max_antenna_gain)
snprintf(max_antenna_gain, sizeof(max_antenna_gain), "N/A"); snprintf(max_antenna_gain, sizeof(max_antenna_gain), "N/A");
else else
snprintf(max_antenna_gain, sizeof(max_antenna_gain), "%d", snprintf(max_antenna_gain, sizeof(max_antenna_gain), "%d mBi",
power_rule->max_antenna_gain); power_rule->max_antenna_gain);
if (reg_rule->flags & NL80211_RRF_AUTO_BW) if (reg_rule->flags & NL80211_RRF_AUTO_BW)
@ -1110,19 +1159,12 @@ static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd,
REG_DBG_PRINT("Updating information on frequency %d MHz with regulatory rule:\n", REG_DBG_PRINT("Updating information on frequency %d MHz with regulatory rule:\n",
chan->center_freq); chan->center_freq);
REG_DBG_PRINT("%d KHz - %d KHz @ %s), (%s mBi, %d mBm)\n", REG_DBG_PRINT("(%d KHz - %d KHz @ %s), (%s, %d mBm)\n",
freq_range->start_freq_khz, freq_range->end_freq_khz, freq_range->start_freq_khz, freq_range->end_freq_khz,
bw, max_antenna_gain, bw, max_antenna_gain,
power_rule->max_eirp); power_rule->max_eirp);
}
#else
static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd,
struct ieee80211_channel *chan,
const struct ieee80211_reg_rule *reg_rule)
{
return;
}
#endif #endif
}
/* /*
* Note that right now we assume the desired channel bandwidth * Note that right now we assume the desired channel bandwidth
@ -1311,7 +1353,8 @@ static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy)
return !(wiphy->features & NL80211_FEATURE_CELL_BASE_REG_HINTS); return !(wiphy->features & NL80211_FEATURE_CELL_BASE_REG_HINTS);
} }
#else #else
static int reg_ignore_cell_hint(struct regulatory_request *pending_request) static enum reg_request_treatment
reg_ignore_cell_hint(struct regulatory_request *pending_request)
{ {
return REG_REQ_IGNORE; return REG_REQ_IGNORE;
} }
@ -1846,7 +1889,7 @@ static void reg_set_request_processed(void)
need_more_processing = true; need_more_processing = true;
spin_unlock(&reg_requests_lock); spin_unlock(&reg_requests_lock);
cancel_delayed_work(&reg_timeout); cancel_crda_timeout();
if (need_more_processing) if (need_more_processing)
schedule_work(&reg_work); schedule_work(&reg_work);
@ -1858,19 +1901,18 @@ static void reg_set_request_processed(void)
* *
* The wireless subsystem can use this function to process * The wireless subsystem can use this function to process
* a regulatory request issued by the regulatory core. * a regulatory request issued by the regulatory core.
*
* Returns one of the different reg request treatment values.
*/ */
static enum reg_request_treatment static enum reg_request_treatment
reg_process_hint_core(struct regulatory_request *core_request) reg_process_hint_core(struct regulatory_request *core_request)
{ {
if (reg_query_database(core_request)) {
core_request->intersect = false;
core_request->processed = false;
reg_update_last_request(core_request);
return REG_REQ_OK;
}
core_request->intersect = false; return REG_REQ_IGNORE;
core_request->processed = false;
reg_update_last_request(core_request);
return reg_call_crda(core_request);
} }
static enum reg_request_treatment static enum reg_request_treatment
@ -1915,8 +1957,6 @@ __reg_process_hint_user(struct regulatory_request *user_request)
* *
* The wireless subsystem can use this function to process * The wireless subsystem can use this function to process
* a regulatory request initiated by userspace. * a regulatory request initiated by userspace.
*
* Returns one of the different reg request treatment values.
*/ */
static enum reg_request_treatment static enum reg_request_treatment
reg_process_hint_user(struct regulatory_request *user_request) reg_process_hint_user(struct regulatory_request *user_request)
@ -1925,20 +1965,20 @@ reg_process_hint_user(struct regulatory_request *user_request)
treatment = __reg_process_hint_user(user_request); treatment = __reg_process_hint_user(user_request);
if (treatment == REG_REQ_IGNORE || if (treatment == REG_REQ_IGNORE ||
treatment == REG_REQ_ALREADY_SET) { treatment == REG_REQ_ALREADY_SET)
reg_free_request(user_request); return REG_REQ_IGNORE;
return treatment;
}
user_request->intersect = treatment == REG_REQ_INTERSECT; user_request->intersect = treatment == REG_REQ_INTERSECT;
user_request->processed = false; user_request->processed = false;
reg_update_last_request(user_request); if (reg_query_database(user_request)) {
reg_update_last_request(user_request);
user_alpha2[0] = user_request->alpha2[0];
user_alpha2[1] = user_request->alpha2[1];
return REG_REQ_OK;
}
user_alpha2[0] = user_request->alpha2[0]; return REG_REQ_IGNORE;
user_alpha2[1] = user_request->alpha2[1];
return reg_call_crda(user_request);
} }
static enum reg_request_treatment static enum reg_request_treatment
@ -1986,16 +2026,12 @@ reg_process_hint_driver(struct wiphy *wiphy,
case REG_REQ_OK: case REG_REQ_OK:
break; break;
case REG_REQ_IGNORE: case REG_REQ_IGNORE:
reg_free_request(driver_request); return REG_REQ_IGNORE;
return treatment;
case REG_REQ_INTERSECT: case REG_REQ_INTERSECT:
/* fall through */
case REG_REQ_ALREADY_SET: case REG_REQ_ALREADY_SET:
regd = reg_copy_regd(get_cfg80211_regdom()); regd = reg_copy_regd(get_cfg80211_regdom());
if (IS_ERR(regd)) { if (IS_ERR(regd))
reg_free_request(driver_request);
return REG_REQ_IGNORE; return REG_REQ_IGNORE;
}
tmp = get_wiphy_regdom(wiphy); tmp = get_wiphy_regdom(wiphy);
rcu_assign_pointer(wiphy->regd, regd); rcu_assign_pointer(wiphy->regd, regd);
@ -2006,8 +2042,6 @@ reg_process_hint_driver(struct wiphy *wiphy,
driver_request->intersect = treatment == REG_REQ_INTERSECT; driver_request->intersect = treatment == REG_REQ_INTERSECT;
driver_request->processed = false; driver_request->processed = false;
reg_update_last_request(driver_request);
/* /*
* Since CRDA will not be called in this case as we already * Since CRDA will not be called in this case as we already
* have applied the requested regulatory domain before we just * have applied the requested regulatory domain before we just
@ -2015,11 +2049,17 @@ reg_process_hint_driver(struct wiphy *wiphy,
*/ */
if (treatment == REG_REQ_ALREADY_SET) { if (treatment == REG_REQ_ALREADY_SET) {
nl80211_send_reg_change_event(driver_request); nl80211_send_reg_change_event(driver_request);
reg_update_last_request(driver_request);
reg_set_request_processed(); reg_set_request_processed();
return treatment; return REG_REQ_ALREADY_SET;
} }
return reg_call_crda(driver_request); if (reg_query_database(driver_request)) {
reg_update_last_request(driver_request);
return REG_REQ_OK;
}
return REG_REQ_IGNORE;
} }
static enum reg_request_treatment static enum reg_request_treatment
@ -2085,12 +2125,11 @@ reg_process_hint_country_ie(struct wiphy *wiphy,
case REG_REQ_OK: case REG_REQ_OK:
break; break;
case REG_REQ_IGNORE: case REG_REQ_IGNORE:
/* fall through */ return REG_REQ_IGNORE;
case REG_REQ_ALREADY_SET: case REG_REQ_ALREADY_SET:
reg_free_request(country_ie_request); reg_free_request(country_ie_request);
return treatment; return REG_REQ_ALREADY_SET;
case REG_REQ_INTERSECT: case REG_REQ_INTERSECT:
reg_free_request(country_ie_request);
/* /*
* This doesn't happen yet, not sure we * This doesn't happen yet, not sure we
* ever want to support it for this case. * ever want to support it for this case.
@ -2102,9 +2141,12 @@ reg_process_hint_country_ie(struct wiphy *wiphy,
country_ie_request->intersect = false; country_ie_request->intersect = false;
country_ie_request->processed = false; country_ie_request->processed = false;
reg_update_last_request(country_ie_request); if (reg_query_database(country_ie_request)) {
reg_update_last_request(country_ie_request);
return REG_REQ_OK;
}
return reg_call_crda(country_ie_request); return REG_REQ_IGNORE;
} }
/* This processes *all* regulatory hints */ /* This processes *all* regulatory hints */
@ -2118,11 +2160,11 @@ static void reg_process_hint(struct regulatory_request *reg_request)
switch (reg_request->initiator) { switch (reg_request->initiator) {
case NL80211_REGDOM_SET_BY_CORE: case NL80211_REGDOM_SET_BY_CORE:
reg_process_hint_core(reg_request); treatment = reg_process_hint_core(reg_request);
return; break;
case NL80211_REGDOM_SET_BY_USER: case NL80211_REGDOM_SET_BY_USER:
reg_process_hint_user(reg_request); treatment = reg_process_hint_user(reg_request);
return; break;
case NL80211_REGDOM_SET_BY_DRIVER: case NL80211_REGDOM_SET_BY_DRIVER:
if (!wiphy) if (!wiphy)
goto out_free; goto out_free;
@ -2138,6 +2180,12 @@ static void reg_process_hint(struct regulatory_request *reg_request)
goto out_free; goto out_free;
} }
if (treatment == REG_REQ_IGNORE)
goto out_free;
WARN(treatment != REG_REQ_OK && treatment != REG_REQ_ALREADY_SET,
"unexpected treatment value %d\n", treatment);
/* This is required so that the orig_* parameters are saved. /* This is required so that the orig_* parameters are saved.
* NOTE: treatment must be set for any case that reaches here! * NOTE: treatment must be set for any case that reaches here!
*/ */
@ -2345,7 +2393,7 @@ int regulatory_hint_user(const char *alpha2,
request->user_reg_hint_type = user_reg_hint_type; request->user_reg_hint_type = user_reg_hint_type;
/* Allow calling CRDA again */ /* Allow calling CRDA again */
reg_crda_timeouts = 0; reset_crda_timeouts();
queue_regulatory_request(request); queue_regulatory_request(request);
@ -2417,7 +2465,7 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
request->initiator = NL80211_REGDOM_SET_BY_DRIVER; request->initiator = NL80211_REGDOM_SET_BY_DRIVER;
/* Allow calling CRDA again */ /* Allow calling CRDA again */
reg_crda_timeouts = 0; reset_crda_timeouts();
queue_regulatory_request(request); queue_regulatory_request(request);
@ -2473,7 +2521,7 @@ void regulatory_hint_country_ie(struct wiphy *wiphy, enum ieee80211_band band,
request->country_ie_env = env; request->country_ie_env = env;
/* Allow calling CRDA again */ /* Allow calling CRDA again */
reg_crda_timeouts = 0; reset_crda_timeouts();
queue_regulatory_request(request); queue_regulatory_request(request);
request = NULL; request = NULL;
@ -2874,11 +2922,8 @@ static int reg_set_rd_driver(const struct ieee80211_regdomain *rd,
} }
request_wiphy = wiphy_idx_to_wiphy(driver_request->wiphy_idx); request_wiphy = wiphy_idx_to_wiphy(driver_request->wiphy_idx);
if (!request_wiphy) { if (!request_wiphy)
queue_delayed_work(system_power_efficient_wq,
&reg_timeout, 0);
return -ENODEV; return -ENODEV;
}
if (!driver_request->intersect) { if (!driver_request->intersect) {
if (request_wiphy->regd) if (request_wiphy->regd)
@ -2935,11 +2980,8 @@ static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd,
} }
request_wiphy = wiphy_idx_to_wiphy(country_ie_request->wiphy_idx); request_wiphy = wiphy_idx_to_wiphy(country_ie_request->wiphy_idx);
if (!request_wiphy) { if (!request_wiphy)
queue_delayed_work(system_power_efficient_wq,
&reg_timeout, 0);
return -ENODEV; return -ENODEV;
}
if (country_ie_request->intersect) if (country_ie_request->intersect)
return -EINVAL; return -EINVAL;
@ -2966,7 +3008,7 @@ int set_regdom(const struct ieee80211_regdomain *rd,
} }
if (regd_src == REGD_SOURCE_CRDA) if (regd_src == REGD_SOURCE_CRDA)
reg_crda_timeouts = 0; reset_crda_timeouts();
lr = get_last_request(); lr = get_last_request();
@ -3123,15 +3165,6 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy)
lr->country_ie_env = ENVIRON_ANY; lr->country_ie_env = ENVIRON_ANY;
} }
static void reg_timeout_work(struct work_struct *work)
{
REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n");
rtnl_lock();
reg_crda_timeouts++;
restore_regulatory_settings(true);
rtnl_unlock();
}
/* /*
* See http://www.fcc.gov/document/5-ghz-unlicensed-spectrum-unii, for * See http://www.fcc.gov/document/5-ghz-unlicensed-spectrum-unii, for
* UNII band definitions * UNII band definitions
@ -3217,7 +3250,7 @@ void regulatory_exit(void)
struct reg_beacon *reg_beacon, *btmp; struct reg_beacon *reg_beacon, *btmp;
cancel_work_sync(&reg_work); cancel_work_sync(&reg_work);
cancel_delayed_work_sync(&reg_timeout); cancel_crda_timeout_sync();
cancel_delayed_work_sync(&reg_check_chans); cancel_delayed_work_sync(&reg_check_chans);
/* Lock to suppress warnings */ /* Lock to suppress warnings */

View File

@ -266,8 +266,7 @@ void __cfg80211_sched_scan_results(struct work_struct *wk)
spin_lock_bh(&rdev->bss_lock); spin_lock_bh(&rdev->bss_lock);
__cfg80211_bss_expire(rdev, request->scan_start); __cfg80211_bss_expire(rdev, request->scan_start);
spin_unlock_bh(&rdev->bss_lock); spin_unlock_bh(&rdev->bss_lock);
request->scan_start = request->scan_start = jiffies;
jiffies + msecs_to_jiffies(request->interval);
} }
nl80211_send_sched_scan_results(rdev, request->dev); nl80211_send_sched_scan_results(rdev, request->dev);
} }
@ -839,6 +838,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
found->pub.signal = tmp->pub.signal; found->pub.signal = tmp->pub.signal;
found->pub.capability = tmp->pub.capability; found->pub.capability = tmp->pub.capability;
found->ts = tmp->ts; found->ts = tmp->ts;
found->ts_boottime = tmp->ts_boottime;
} else { } else {
struct cfg80211_internal_bss *new; struct cfg80211_internal_bss *new;
struct cfg80211_internal_bss *hidden; struct cfg80211_internal_bss *hidden;
@ -938,14 +938,13 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
} }
/* Returned bss is reference counted and must be cleaned up appropriately. */ /* Returned bss is reference counted and must be cleaned up appropriately. */
struct cfg80211_bss* struct cfg80211_bss *
cfg80211_inform_bss_width(struct wiphy *wiphy, cfg80211_inform_bss_data(struct wiphy *wiphy,
struct ieee80211_channel *rx_channel, struct cfg80211_inform_bss *data,
enum nl80211_bss_scan_width scan_width, enum cfg80211_bss_frame_type ftype,
enum cfg80211_bss_frame_type ftype, const u8 *bssid, u64 tsf, u16 capability,
const u8 *bssid, u64 tsf, u16 capability, u16 beacon_interval, const u8 *ie, size_t ielen,
u16 beacon_interval, const u8 *ie, size_t ielen, gfp_t gfp)
s32 signal, gfp_t gfp)
{ {
struct cfg80211_bss_ies *ies; struct cfg80211_bss_ies *ies;
struct ieee80211_channel *channel; struct ieee80211_channel *channel;
@ -957,19 +956,21 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
return NULL; return NULL;
if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC && if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
(signal < 0 || signal > 100))) (data->signal < 0 || data->signal > 100)))
return NULL; return NULL;
channel = cfg80211_get_bss_channel(wiphy, ie, ielen, rx_channel); channel = cfg80211_get_bss_channel(wiphy, ie, ielen, data->chan);
if (!channel) if (!channel)
return NULL; return NULL;
memcpy(tmp.pub.bssid, bssid, ETH_ALEN); memcpy(tmp.pub.bssid, bssid, ETH_ALEN);
tmp.pub.channel = channel; tmp.pub.channel = channel;
tmp.pub.scan_width = scan_width; tmp.pub.scan_width = data->scan_width;
tmp.pub.signal = signal; tmp.pub.signal = data->signal;
tmp.pub.beacon_interval = beacon_interval; tmp.pub.beacon_interval = beacon_interval;
tmp.pub.capability = capability; tmp.pub.capability = capability;
tmp.ts_boottime = data->boottime_ns;
/* /*
* If we do not know here whether the IEs are from a Beacon or Probe * If we do not know here whether the IEs are from a Beacon or Probe
* Response frame, we need to pick one of the options and only use it * Response frame, we need to pick one of the options and only use it
@ -999,7 +1000,7 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
} }
rcu_assign_pointer(tmp.pub.ies, ies); rcu_assign_pointer(tmp.pub.ies, ies);
signal_valid = abs(rx_channel->center_freq - channel->center_freq) <= signal_valid = abs(data->chan->center_freq - channel->center_freq) <=
wiphy->max_adj_channel_rssi_comp; wiphy->max_adj_channel_rssi_comp;
res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid); res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid);
if (!res) if (!res)
@ -1019,15 +1020,15 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
/* cfg80211_bss_update gives us a referenced result */ /* cfg80211_bss_update gives us a referenced result */
return &res->pub; return &res->pub;
} }
EXPORT_SYMBOL(cfg80211_inform_bss_width); EXPORT_SYMBOL(cfg80211_inform_bss_data);
/* Returned bss is reference counted and must be cleaned up appropriately. */ /* cfg80211_inform_bss_width_frame helper */
struct cfg80211_bss * struct cfg80211_bss *
cfg80211_inform_bss_width_frame(struct wiphy *wiphy, cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
struct ieee80211_channel *rx_channel, struct cfg80211_inform_bss *data,
enum nl80211_bss_scan_width scan_width, struct ieee80211_mgmt *mgmt, size_t len,
struct ieee80211_mgmt *mgmt, size_t len, gfp_t gfp)
s32 signal, gfp_t gfp)
{ {
struct cfg80211_internal_bss tmp = {}, *res; struct cfg80211_internal_bss tmp = {}, *res;
struct cfg80211_bss_ies *ies; struct cfg80211_bss_ies *ies;
@ -1040,8 +1041,7 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) != BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=
offsetof(struct ieee80211_mgmt, u.beacon.variable)); offsetof(struct ieee80211_mgmt, u.beacon.variable));
trace_cfg80211_inform_bss_width_frame(wiphy, rx_channel, scan_width, mgmt, trace_cfg80211_inform_bss_frame(wiphy, data, mgmt, len);
len, signal);
if (WARN_ON(!mgmt)) if (WARN_ON(!mgmt))
return NULL; return NULL;
@ -1050,14 +1050,14 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
return NULL; return NULL;
if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC && if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
(signal < 0 || signal > 100))) (data->signal < 0 || data->signal > 100)))
return NULL; return NULL;
if (WARN_ON(len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable))) if (WARN_ON(len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable)))
return NULL; return NULL;
channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable, channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable,
ielen, rx_channel); ielen, data->chan);
if (!channel) if (!channel)
return NULL; return NULL;
@ -1077,12 +1077,13 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN); memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN);
tmp.pub.channel = channel; tmp.pub.channel = channel;
tmp.pub.scan_width = scan_width; tmp.pub.scan_width = data->scan_width;
tmp.pub.signal = signal; tmp.pub.signal = data->signal;
tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
tmp.ts_boottime = data->boottime_ns;
signal_valid = abs(rx_channel->center_freq - channel->center_freq) <= signal_valid = abs(data->chan->center_freq - channel->center_freq) <=
wiphy->max_adj_channel_rssi_comp; wiphy->max_adj_channel_rssi_comp;
res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid); res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid);
if (!res) if (!res)
@ -1102,7 +1103,7 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
/* cfg80211_bss_update gives us a referenced result */ /* cfg80211_bss_update gives us a referenced result */
return &res->pub; return &res->pub;
} }
EXPORT_SYMBOL(cfg80211_inform_bss_width_frame); EXPORT_SYMBOL(cfg80211_inform_bss_frame_data);
void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
{ {

View File

@ -2670,30 +2670,30 @@ TRACE_EVENT(cfg80211_get_bss,
__entry->privacy) __entry->privacy)
); );
TRACE_EVENT(cfg80211_inform_bss_width_frame, TRACE_EVENT(cfg80211_inform_bss_frame,
TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel, TP_PROTO(struct wiphy *wiphy, struct cfg80211_inform_bss *data,
enum nl80211_bss_scan_width scan_width, struct ieee80211_mgmt *mgmt, size_t len),
struct ieee80211_mgmt *mgmt, size_t len, TP_ARGS(wiphy, data, mgmt, len),
s32 signal),
TP_ARGS(wiphy, channel, scan_width, mgmt, len, signal),
TP_STRUCT__entry( TP_STRUCT__entry(
WIPHY_ENTRY WIPHY_ENTRY
CHAN_ENTRY CHAN_ENTRY
__field(enum nl80211_bss_scan_width, scan_width) __field(enum nl80211_bss_scan_width, scan_width)
__dynamic_array(u8, mgmt, len) __dynamic_array(u8, mgmt, len)
__field(s32, signal) __field(s32, signal)
__field(u64, ts_boottime)
), ),
TP_fast_assign( TP_fast_assign(
WIPHY_ASSIGN; WIPHY_ASSIGN;
CHAN_ASSIGN(channel); CHAN_ASSIGN(data->chan);
__entry->scan_width = scan_width; __entry->scan_width = data->scan_width;
if (mgmt) if (mgmt)
memcpy(__get_dynamic_array(mgmt), mgmt, len); memcpy(__get_dynamic_array(mgmt), mgmt, len);
__entry->signal = signal; __entry->signal = data->signal;
__entry->ts_boottime = data->boottime_ns;
), ),
TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT "(scan_width: %d) signal: %d", TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT "(scan_width: %d) signal: %d, tsb:%llu",
WIPHY_PR_ARG, CHAN_PR_ARG, __entry->scan_width, WIPHY_PR_ARG, CHAN_PR_ARG, __entry->scan_width,
__entry->signal) __entry->signal, (unsigned long long)__entry->ts_boottime)
); );
DECLARE_EVENT_CLASS(cfg80211_bss_evt, DECLARE_EVENT_CLASS(cfg80211_bss_evt,