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:
commit
e9829b9745
41 changed files with 911 additions and 660 deletions
|
@ -154,8 +154,9 @@
|
|||
!Finclude/net/cfg80211.h cfg80211_scan_request
|
||||
!Finclude/net/cfg80211.h cfg80211_scan_done
|
||||
!Finclude/net/cfg80211.h cfg80211_bss
|
||||
!Finclude/net/cfg80211.h cfg80211_inform_bss_width_frame
|
||||
!Finclude/net/cfg80211.h cfg80211_inform_bss_width
|
||||
!Finclude/net/cfg80211.h cfg80211_inform_bss
|
||||
!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_find_ie
|
||||
!Finclude/net/cfg80211.h ieee80211_bss_get_ie
|
||||
|
|
|
@ -3312,7 +3312,7 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
|
|||
}
|
||||
|
||||
/* 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,
|
||||
interval, interval,
|
||||
|
|
|
@ -630,6 +630,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
|
|||
kfree(mvm->d3_resume_sram);
|
||||
if (mvm->nd_config) {
|
||||
kfree(mvm->nd_config->match_sets);
|
||||
kfree(mvm->nd_config->scan_plans);
|
||||
kfree(mvm->nd_config);
|
||||
mvm->nd_config = NULL;
|
||||
}
|
||||
|
|
|
@ -1271,12 +1271,12 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
|
|||
|
||||
params.type = iwl_mvm_get_scan_type(mvm, vif, ¶ms);
|
||||
|
||||
if (req->interval > U16_MAX) {
|
||||
if (req->scan_plans[0].interval > U16_MAX) {
|
||||
IWL_DEBUG_SCAN(mvm,
|
||||
"interval value is > 16-bits, set to max possible\n");
|
||||
params.interval = U16_MAX;
|
||||
} 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
|
||||
|
|
|
@ -266,7 +266,7 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
|
|||
if (beacon_diff > beacon_int)
|
||||
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,
|
||||
&rt2x00dev->autowakeup_work,
|
||||
autowake_timeout - 15);
|
||||
|
|
|
@ -350,7 +350,8 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
|
|||
cfg->bss_type = SCAN_BSS_TYPE_ANY;
|
||||
/* currently NL80211 supports only a single interval */
|
||||
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;
|
||||
ret = wlcore_scan_sched_scan_ssid_list(wl, wlvif, req);
|
||||
|
|
|
@ -228,13 +228,15 @@ int wl18xx_scan_sched_scan_config(struct wl1271 *wl,
|
|||
wl18xx_adjust_channels(cmd, cmd_channels);
|
||||
|
||||
if (c->num_short_intervals && c->long_interval &&
|
||||
c->long_interval > req->interval) {
|
||||
cmd->short_cycles_msec = cpu_to_le16(req->interval);
|
||||
c->long_interval > req->scan_plans[0].interval * MSEC_PER_SEC) {
|
||||
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->short_cycles_count = c->num_short_intervals;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
wl1271_debug(DEBUG_SCAN, "short_interval: %d, long_interval: %d, num_short: %d",
|
||||
|
|
|
@ -1932,6 +1932,8 @@ enum ieee80211_category {
|
|||
WLAN_CATEGORY_HT = 7,
|
||||
WLAN_CATEGORY_SA_QUERY = 8,
|
||||
WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9,
|
||||
WLAN_CATEGORY_WNM = 10,
|
||||
WLAN_CATEGORY_WNM_UNPROTECTED = 11,
|
||||
WLAN_CATEGORY_TDLS = 12,
|
||||
WLAN_CATEGORY_MESH_ACTION = 13,
|
||||
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;
|
||||
return *category != WLAN_CATEGORY_PUBLIC &&
|
||||
*category != WLAN_CATEGORY_HT &&
|
||||
*category != WLAN_CATEGORY_WNM_UNPROTECTED &&
|
||||
*category != WLAN_CATEGORY_SELF_PROTECTED &&
|
||||
*category != WLAN_CATEGORY_UNPROT_DMG &&
|
||||
*category != WLAN_CATEGORY_VHT &&
|
||||
*category != WLAN_CATEGORY_VENDOR_SPECIFIC;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*
|
||||
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2015 Intel Deutschland GmbH
|
||||
*
|
||||
* 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
|
||||
|
@ -1500,6 +1501,20 @@ struct cfg80211_match_set {
|
|||
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
|
||||
*
|
||||
|
@ -1507,7 +1522,6 @@ struct cfg80211_match_set {
|
|||
* @n_ssids: number of SSIDs
|
||||
* @n_channels: total number of channels to scan
|
||||
* @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_len: length of ie in octets
|
||||
* @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
|
||||
* are 0 in the mask should be randomised, bits that are 1 should
|
||||
* 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
|
||||
* @owner_nlportid: netlink portid of owner (if this should is a request
|
||||
* owned by a particular socket)
|
||||
|
@ -1539,7 +1556,6 @@ struct cfg80211_sched_scan_request {
|
|||
int n_ssids;
|
||||
u32 n_channels;
|
||||
enum nl80211_bss_scan_width scan_width;
|
||||
u32 interval;
|
||||
const u8 *ie;
|
||||
size_t ie_len;
|
||||
u32 flags;
|
||||
|
@ -1547,6 +1563,8 @@ struct cfg80211_sched_scan_request {
|
|||
int n_match_sets;
|
||||
s32 min_rssi_thold;
|
||||
u32 delay;
|
||||
struct cfg80211_sched_scan_plan *scan_plans;
|
||||
int n_scan_plans;
|
||||
|
||||
u8 mac_addr[ETH_ALEN] __aligned(2);
|
||||
u8 mac_addr_mask[ETH_ALEN] __aligned(2);
|
||||
|
@ -1575,6 +1593,26 @@ enum cfg80211_signal_type {
|
|||
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
|
||||
* @tsf: TSF contained in the frame that carried these IEs
|
||||
|
@ -3056,6 +3094,12 @@ struct wiphy_vendor_command {
|
|||
* include fixed IEs like supported rates
|
||||
* @max_sched_scan_ie_len: same as max_scan_ie_len, but for scheduled
|
||||
* 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
|
||||
* @fw_version: firmware version for ethtool reporting
|
||||
* @hw_version: hardware version for ethtool reporting
|
||||
|
@ -3163,6 +3207,9 @@ struct wiphy {
|
|||
u8 max_match_sets;
|
||||
u16 max_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;
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @rx_channel: The channel the frame was received on
|
||||
* @scan_width: width of the control channel
|
||||
* @data: the BSS metadata
|
||||
* @mgmt: the management frame (probe response or beacon)
|
||||
* @len: length of the management frame
|
||||
* @signal: the signal strength, type depends on the wiphy's signal_type
|
||||
* @gfp: context flags
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
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,
|
||||
struct ieee80211_channel *rx_channel,
|
||||
enum nl80211_bss_scan_width scan_width,
|
||||
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
|
||||
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,
|
||||
s32 signal, gfp_t gfp)
|
||||
{
|
||||
return cfg80211_inform_bss_width_frame(wiphy, rx_channel,
|
||||
NL80211_BSS_CHAN_WIDTH_20,
|
||||
mgmt, len, signal, gfp);
|
||||
struct cfg80211_inform_bss data = {
|
||||
.chan = rx_channel,
|
||||
.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
|
||||
* @rx_channel: The channel the frame was received on
|
||||
* @scan_width: width of the control channel
|
||||
* @data: the BSS metadata
|
||||
* @ftype: frame type (if known)
|
||||
* @bssid: the BSSID of the BSS
|
||||
* @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
|
||||
* @ie: additional IEs sent by the peer
|
||||
* @ielen: length of the additional IEs
|
||||
* @signal: the signal strength, type depends on the wiphy's signal_type
|
||||
* @gfp: context flags
|
||||
*
|
||||
* This informs cfg80211 that BSS information was found and
|
||||
|
@ -4028,13 +4089,32 @@ enum cfg80211_bss_frame_type {
|
|||
* Or %NULL on error.
|
||||
*/
|
||||
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,
|
||||
struct ieee80211_channel *rx_channel,
|
||||
enum nl80211_bss_scan_width scan_width,
|
||||
enum cfg80211_bss_frame_type ftype,
|
||||
const u8 *bssid, u64 tsf, u16 capability,
|
||||
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
|
||||
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,
|
||||
s32 signal, gfp_t gfp)
|
||||
{
|
||||
return cfg80211_inform_bss_width(wiphy, rx_channel,
|
||||
NL80211_BSS_CHAN_WIDTH_20, ftype,
|
||||
bssid, tsf, capability,
|
||||
beacon_interval, ie, ielen, signal,
|
||||
gfp);
|
||||
struct cfg80211_inform_bss data = {
|
||||
.chan = rx_channel,
|
||||
.scan_width = NL80211_BSS_CHAN_WIDTH_20,
|
||||
.signal = signal,
|
||||
};
|
||||
|
||||
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,
|
||||
|
|
|
@ -1241,11 +1241,6 @@ enum ieee80211_smps_mode {
|
|||
* @flags: configuration flags defined above
|
||||
*
|
||||
* @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
|
||||
* in power saving. Power saving will not be enabled until a beacon
|
||||
* has been received and the DTIM period is known.
|
||||
|
@ -1275,7 +1270,6 @@ enum ieee80211_smps_mode {
|
|||
struct ieee80211_conf {
|
||||
u32 flags;
|
||||
int power_level, dynamic_ps_timeout;
|
||||
int max_sleep_period;
|
||||
|
||||
u16 listen_interval;
|
||||
u8 ps_dtim_period;
|
||||
|
@ -1683,6 +1677,7 @@ struct ieee80211_sta_rates {
|
|||
* @tdls: indicates whether the STA is a TDLS peer
|
||||
* @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.
|
||||
* @mfp: indicates whether the STA uses management frame protection or not.
|
||||
* @txq: per-TID data TX queues (if driver uses the TXQ abstraction)
|
||||
*/
|
||||
struct ieee80211_sta {
|
||||
|
@ -1700,6 +1695,7 @@ struct ieee80211_sta {
|
|||
struct ieee80211_sta_rates __rcu *rates;
|
||||
bool tdls;
|
||||
bool tdls_initiator;
|
||||
bool mfp;
|
||||
|
||||
struct ieee80211_txq *txq[IEEE80211_NUM_TIDS];
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* Copyright 2008, 2009 Luis R. Rodriguez <lrodriguez@atheros.com>
|
||||
* Copyright 2008 Jouni Malinen <jouni.malinen@atheros.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
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -328,7 +329,15 @@
|
|||
* partial scan results may be available
|
||||
*
|
||||
* @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)
|
||||
* are passed, they are used in the probe requests. For
|
||||
* 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
|
||||
* 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
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
|
@ -2130,6 +2152,11 @@ enum nl80211_attrs {
|
|||
|
||||
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 */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
|
@ -3364,6 +3391,9 @@ enum nl80211_bss_scan_width {
|
|||
* (not present if no beacon frame has been received yet)
|
||||
* @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_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_MAX: highest BSS attribute
|
||||
*/
|
||||
|
@ -3383,6 +3413,7 @@ enum nl80211_bss {
|
|||
NL80211_BSS_CHAN_WIDTH,
|
||||
NL80211_BSS_BEACON_TSF,
|
||||
NL80211_BSS_PRESP_DATA,
|
||||
NL80211_BSS_LAST_SEEN_BOOTTIME,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_BSS_AFTER_LAST,
|
||||
|
@ -4589,4 +4620,28 @@ enum nl80211_tdls_peer_capability {
|
|||
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 */
|
||||
|
|
|
@ -27,7 +27,6 @@ mac80211-y := \
|
|||
key.o \
|
||||
util.o \
|
||||
wme.o \
|
||||
event.o \
|
||||
chan.o \
|
||||
trace.o mlme.o \
|
||||
tdls.o \
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include <net/cfg80211.h>
|
||||
#include "ieee80211_i.h"
|
||||
#include "driver-ops.h"
|
||||
#include "cfg.h"
|
||||
#include "rate.h"
|
||||
#include "mesh.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;
|
||||
}
|
||||
|
||||
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,
|
||||
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)) {
|
||||
sta->sta.mfp = !!(set & BIT(NL80211_STA_FLAG_MFP));
|
||||
if (set & BIT(NL80211_STA_FLAG_MFP))
|
||||
set_sta_flag(sta, WLAN_STA_MFP);
|
||||
else
|
||||
|
@ -1427,7 +1388,7 @@ static int ieee80211_change_station(struct wiphy *wiphy,
|
|||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
|
||||
ieee80211_recalc_ps(local, -1);
|
||||
ieee80211_recalc_ps(local);
|
||||
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))
|
||||
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
|
||||
|
||||
ieee80211_recalc_ps(local, -1);
|
||||
ieee80211_recalc_ps(local);
|
||||
ieee80211_recalc_ps_vif(sdata);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -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 */
|
|
@ -50,7 +50,6 @@ static const struct file_operations sta_ ##name## _ops = { \
|
|||
STA_OPS(name)
|
||||
|
||||
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,
|
||||
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(ht_capa);
|
||||
DEBUGFS_ADD(vht_capa);
|
||||
DEBUGFS_ADD(last_ack_signal);
|
||||
|
||||
DEBUGFS_ADD_COUNTER(rx_duplicates, num_duplicates);
|
||||
DEBUGFS_ADD_COUNTER(rx_fragments, rx_fragments);
|
||||
DEBUGFS_ADD_COUNTER(tx_filtered, tx_filtered_count);
|
||||
DEBUGFS_ADD_COUNTER(rx_duplicates, rx_stats.num_duplicates);
|
||||
DEBUGFS_ADD_COUNTER(rx_fragments, rx_stats.fragments);
|
||||
DEBUGFS_ADD_COUNTER(tx_filtered, status_stats.filtered);
|
||||
|
||||
if (sizeof(sta->driver_buffered_tids) == sizeof(u32))
|
||||
debugfs_create_x32("driver_buffered_tids", 0400,
|
||||
|
|
|
@ -40,7 +40,7 @@ static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = {
|
|||
"rx_duplicates", "rx_fragments", "rx_dropped",
|
||||
"tx_packets", "tx_bytes",
|
||||
"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",
|
||||
"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);
|
||||
|
||||
#define ADD_STA_STATS(sta) \
|
||||
do { \
|
||||
data[i++] += sta->rx_packets; \
|
||||
data[i++] += sta->rx_bytes; \
|
||||
data[i++] += sta->num_duplicates; \
|
||||
data[i++] += sta->rx_fragments; \
|
||||
data[i++] += sta->rx_dropped; \
|
||||
\
|
||||
data[i++] += sinfo.tx_packets; \
|
||||
data[i++] += sinfo.tx_bytes; \
|
||||
data[i++] += sta->tx_filtered_count; \
|
||||
data[i++] += sta->tx_retry_failed; \
|
||||
data[i++] += sta->tx_retry_count; \
|
||||
data[i++] += sta->beacon_loss_count; \
|
||||
#define ADD_STA_STATS(sta) \
|
||||
do { \
|
||||
data[i++] += sta->rx_stats.packets; \
|
||||
data[i++] += sta->rx_stats.bytes; \
|
||||
data[i++] += sta->rx_stats.num_duplicates; \
|
||||
data[i++] += sta->rx_stats.fragments; \
|
||||
data[i++] += sta->rx_stats.dropped; \
|
||||
\
|
||||
data[i++] += sinfo.tx_packets; \
|
||||
data[i++] += sinfo.tx_bytes; \
|
||||
data[i++] += sta->status_stats.filtered; \
|
||||
data[i++] += sta->status_stats.retry_failed; \
|
||||
data[i++] += sta->status_stats.retry_count; \
|
||||
} while (0)
|
||||
|
||||
/* For Managed stations, find the single station based on BSSID
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -229,7 +229,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
|||
struct cfg80211_chan_def chandef;
|
||||
struct ieee80211_channel *chan;
|
||||
struct beacon_data *presp;
|
||||
enum nl80211_bss_scan_width scan_width;
|
||||
struct cfg80211_inform_bss bss_meta = {};
|
||||
bool have_higher_than_11mbit;
|
||||
bool radar_required;
|
||||
int err;
|
||||
|
@ -383,10 +383,11 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
|||
mod_timer(&ifibss->timer,
|
||||
round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL));
|
||||
|
||||
scan_width = cfg80211_chandef_to_scan_width(&chandef);
|
||||
bss = cfg80211_inform_bss_width_frame(local->hw.wiphy, chan,
|
||||
scan_width, mgmt,
|
||||
presp->head_len, 0, GFP_KERNEL);
|
||||
bss_meta.chan = chan;
|
||||
bss_meta.scan_width = cfg80211_chandef_to_scan_width(&chandef);
|
||||
bss = cfg80211_inform_bss_frame_data(local->hw.wiphy, &bss_meta, mgmt,
|
||||
presp->head_len, GFP_KERNEL);
|
||||
|
||||
cfg80211_put_bss(local->hw.wiphy, bss);
|
||||
netif_carrier_on(sdata->dev);
|
||||
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;
|
||||
}
|
||||
|
||||
sta->last_rx = jiffies;
|
||||
sta->rx_stats.last_rx = jiffies;
|
||||
|
||||
/* make sure mandatory rates are always added */
|
||||
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) {
|
||||
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)) {
|
||||
active++;
|
||||
break;
|
||||
|
@ -1234,7 +1236,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
|
|||
if (!sta)
|
||||
return;
|
||||
|
||||
sta->last_rx = jiffies;
|
||||
sta->rx_stats.last_rx = jiffies;
|
||||
|
||||
/* make sure mandatory rates are always added */
|
||||
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 sta_info *sta, *tmp;
|
||||
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);
|
||||
|
||||
|
@ -1260,8 +1262,8 @@ static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata)
|
|||
if (sdata != sta->sdata)
|
||||
continue;
|
||||
|
||||
if (time_after(jiffies, sta->last_rx + exp_time) ||
|
||||
(time_after(jiffies, sta->last_rx + exp_rsn_time) &&
|
||||
if (time_after(jiffies, sta->rx_stats.last_rx + exp_time) ||
|
||||
(time_after(jiffies, sta->rx_stats.last_rx + exp_rsn) &&
|
||||
sta->sta_state != IEEE80211_STA_AUTHORIZED)) {
|
||||
sta_dbg(sta->sdata, "expiring inactive %sSTA %pM\n",
|
||||
sta->sta_state != IEEE80211_STA_AUTHORIZED ?
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include "sta_info.h"
|
||||
#include "debug.h"
|
||||
|
||||
extern const struct cfg80211_ops mac80211_config_ops;
|
||||
|
||||
struct ieee80211_local;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Number of times beacon loss was invoked. */
|
||||
unsigned int beacon_loss_count;
|
||||
|
||||
/*
|
||||
* Last Beacon frame signal strength average (ave_beacon_signal / 16)
|
||||
* 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_disable_work;
|
||||
struct timer_list dynamic_ps_timer;
|
||||
struct notifier_block network_latency_notifier;
|
||||
struct notifier_block ifa_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);
|
||||
void ieee80211_send_pspoll(struct ieee80211_local *local,
|
||||
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);
|
||||
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);
|
||||
void ieee80211_sta_work(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 rate, int erp, int short_preamble,
|
||||
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,
|
||||
bool bss_notify);
|
||||
void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
|
||||
|
|
|
@ -709,7 +709,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
|||
if (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 ||
|
||||
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);
|
||||
}
|
||||
|
||||
ieee80211_recalc_ps(local, -1);
|
||||
ieee80211_recalc_ps(local);
|
||||
|
||||
if (cancel_scan)
|
||||
flush_delayed_work(&local->scan_work);
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include <linux/if_arp.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/cfg80211.h>
|
||||
|
@ -32,7 +31,6 @@
|
|||
#include "mesh.h"
|
||||
#include "wep.h"
|
||||
#include "led.h"
|
||||
#include "cfg.h"
|
||||
#include "debugfs.h"
|
||||
|
||||
void ieee80211_configure_filter(struct ieee80211_local *local)
|
||||
|
@ -1083,13 +1081,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
|
||||
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
|
||||
local->ifa_notifier.notifier_call = ieee80211_ifa_changed;
|
||||
result = register_inetaddr_notifier(&local->ifa_notifier);
|
||||
|
@ -1114,10 +1105,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
#endif
|
||||
#if defined(CONFIG_INET) || defined(CONFIG_IPV6)
|
||||
fail_ifa:
|
||||
pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
|
||||
&local->network_latency_notifier);
|
||||
#endif
|
||||
fail_pm_qos:
|
||||
rtnl_lock();
|
||||
rate_control_deinitialize(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->tasklet);
|
||||
|
||||
pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
|
||||
&local->network_latency_notifier);
|
||||
#ifdef CONFIG_INET
|
||||
unregister_inetaddr_notifier(&local->ifa_notifier);
|
||||
#endif
|
||||
|
|
|
@ -329,7 +329,7 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local,
|
|||
if (sta->mesh->fail_avg >= 100)
|
||||
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);
|
||||
if (WARN_ON(!rate))
|
||||
return MAX_METRIC;
|
||||
|
|
|
@ -60,7 +60,9 @@ static bool rssi_threshold_check(struct ieee80211_sub_if_data *sdata,
|
|||
{
|
||||
s32 rssi_threshold = sdata->u.mesh.mshcfg.rssi_threshold;
|
||||
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);
|
||||
|
||||
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 */
|
||||
if (sta->mesh->plink_state == NL80211_PLINK_ESTAB &&
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include <linux/etherdevice.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/slab.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 */
|
||||
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;
|
||||
int count = 0;
|
||||
|
@ -1505,48 +1504,23 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
|
|||
}
|
||||
|
||||
if (count == 1 && ieee80211_powersave_allowed(found)) {
|
||||
u8 dtimper = found->u.mgd.dtim_period;
|
||||
s32 beaconint_us;
|
||||
|
||||
if (latency < 0)
|
||||
latency = pm_qos_request(PM_QOS_NETWORK_LATENCY);
|
||||
|
||||
beaconint_us = ieee80211_tu_to_usec(
|
||||
found->vif.bss_conf.beacon_int);
|
||||
|
||||
timeout = local->dynamic_ps_forced_timeout;
|
||||
if (timeout < 0) {
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
if (timeout < 0)
|
||||
timeout = 100;
|
||||
local->hw.conf.dynamic_ps_timeout = timeout;
|
||||
|
||||
if (beaconint_us > latency) {
|
||||
local->ps_sdata = NULL;
|
||||
} else {
|
||||
int maxslp = 1;
|
||||
u8 dtimper = found->u.mgd.dtim_period;
|
||||
/* If the TIM IE is invalid, pretend the value is 1 */
|
||||
if (!dtimper)
|
||||
dtimper = 1;
|
||||
|
||||
/* If the TIM IE is invalid, pretend the value is 1 */
|
||||
if (!dtimper)
|
||||
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;
|
||||
}
|
||||
local->hw.conf.ps_dtim_period = dtimper;
|
||||
local->ps_sdata = found;
|
||||
} else {
|
||||
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);
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
ieee80211_recalc_ps(local, -1);
|
||||
ieee80211_recalc_ps(local);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
|
||||
ieee80211_recalc_smps(sdata);
|
||||
|
@ -2165,7 +2139,7 @@ static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
|
|||
__ieee80211_stop_poll(sdata);
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
ieee80211_recalc_ps(local, -1);
|
||||
ieee80211_recalc_ps(local);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
|
||||
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;
|
||||
|
||||
mutex_lock(&sdata->local->iflist_mtx);
|
||||
ieee80211_recalc_ps(sdata->local, -1);
|
||||
ieee80211_recalc_ps(sdata->local);
|
||||
mutex_unlock(&sdata->local->iflist_mtx);
|
||||
|
||||
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,
|
||||
u.mgd.beacon_connection_loss_work);
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
struct sta_info *sta;
|
||||
|
||||
if (ifmgd->associated) {
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(sdata, ifmgd->bssid);
|
||||
if (sta)
|
||||
sta->beacon_loss_count++;
|
||||
rcu_read_unlock();
|
||||
}
|
||||
if (ifmgd->associated)
|
||||
ifmgd->beacon_loss_count++;
|
||||
|
||||
if (ifmgd->connection_loss) {
|
||||
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);
|
||||
|
||||
if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED)
|
||||
if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) {
|
||||
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;
|
||||
|
||||
|
@ -3544,7 +3516,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
ifmgd->have_beacon = true;
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
ieee80211_recalc_ps(local, -1);
|
||||
ieee80211_recalc_ps(local);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
|
||||
ieee80211_recalc_ps_vif(sdata);
|
||||
|
@ -4148,21 +4120,6 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
|
|||
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,
|
||||
struct cfg80211_bss *cbss)
|
||||
{
|
||||
|
|
|
@ -75,7 +75,7 @@ void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata,
|
|||
if (!sta)
|
||||
return;
|
||||
|
||||
sta->last_rx = jiffies;
|
||||
sta->rx_stats.last_rx = jiffies;
|
||||
|
||||
/* Add only mandatory rates for now */
|
||||
sband = local->hw.wiphy->bands[band];
|
||||
|
|
|
@ -1113,16 +1113,16 @@ ieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx)
|
|||
is_multicast_ether_addr(hdr->addr1))
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (rx->sta) {
|
||||
if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
|
||||
rx->sta->last_seq_ctrl[rx->seqno_idx] ==
|
||||
hdr->seq_ctrl)) {
|
||||
I802_DEBUG_INC(rx->local->dot11FrameDuplicateCount);
|
||||
rx->sta->num_duplicates++;
|
||||
return RX_DROP_UNUSABLE;
|
||||
} else if (!(status->flag & RX_FLAG_AMSDU_MORE)) {
|
||||
rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl;
|
||||
}
|
||||
if (!rx->sta)
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
|
||||
rx->sta->last_seq_ctrl[rx->seqno_idx] == hdr->seq_ctrl)) {
|
||||
I802_DEBUG_INC(rx->local->dot11FrameDuplicateCount);
|
||||
rx->sta->rx_stats.num_duplicates++;
|
||||
return RX_DROP_UNUSABLE;
|
||||
} else if (!(status->flag & RX_FLAG_AMSDU_MORE)) {
|
||||
rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl;
|
||||
}
|
||||
|
||||
return RX_CONTINUE;
|
||||
|
@ -1396,51 +1396,56 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
|
|||
NL80211_IFTYPE_ADHOC);
|
||||
if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid) &&
|
||||
test_sta_flag(sta, WLAN_STA_AUTHORIZED)) {
|
||||
sta->last_rx = jiffies;
|
||||
sta->rx_stats.last_rx = jiffies;
|
||||
if (ieee80211_is_data(hdr->frame_control) &&
|
||||
!is_multicast_ether_addr(hdr->addr1)) {
|
||||
sta->last_rx_rate_idx = status->rate_idx;
|
||||
sta->last_rx_rate_flag = status->flag;
|
||||
sta->last_rx_rate_vht_flag = status->vht_flag;
|
||||
sta->last_rx_rate_vht_nss = status->vht_nss;
|
||||
sta->rx_stats.last_rate_idx =
|
||||
status->rate_idx;
|
||||
sta->rx_stats.last_rate_flag =
|
||||
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) {
|
||||
sta->last_rx = jiffies;
|
||||
sta->rx_stats.last_rx = jiffies;
|
||||
} else if (!is_multicast_ether_addr(hdr->addr1)) {
|
||||
/*
|
||||
* Mesh beacons will update last_rx when if they are found to
|
||||
* match the current local configuration when processed.
|
||||
*/
|
||||
sta->last_rx = jiffies;
|
||||
sta->rx_stats.last_rx = jiffies;
|
||||
if (ieee80211_is_data(hdr->frame_control)) {
|
||||
sta->last_rx_rate_idx = status->rate_idx;
|
||||
sta->last_rx_rate_flag = status->flag;
|
||||
sta->last_rx_rate_vht_flag = status->vht_flag;
|
||||
sta->last_rx_rate_vht_nss = status->vht_nss;
|
||||
sta->rx_stats.last_rate_idx = status->rate_idx;
|
||||
sta->rx_stats.last_rate_flag = status->flag;
|
||||
sta->rx_stats.last_rate_vht_flag = status->vht_flag;
|
||||
sta->rx_stats.last_rate_vht_nss = status->vht_nss;
|
||||
}
|
||||
}
|
||||
|
||||
if (rx->sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
ieee80211_sta_rx_notify(rx->sdata, hdr);
|
||||
|
||||
sta->rx_fragments++;
|
||||
sta->rx_bytes += rx->skb->len;
|
||||
sta->rx_stats.fragments++;
|
||||
sta->rx_stats.bytes += rx->skb->len;
|
||||
if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
|
||||
sta->last_signal = status->signal;
|
||||
ewma_signal_add(&sta->avg_signal, -status->signal);
|
||||
sta->rx_stats.last_signal = status->signal;
|
||||
ewma_signal_add(&sta->rx_stats.avg_signal, -status->signal);
|
||||
}
|
||||
|
||||
if (status->chains) {
|
||||
sta->chains = status->chains;
|
||||
sta->rx_stats.chains = status->chains;
|
||||
for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) {
|
||||
int signal = status->chain_signal[i];
|
||||
|
||||
if (!(status->chains & BIT(i)))
|
||||
continue;
|
||||
|
||||
sta->chain_signal_last[i] = signal;
|
||||
ewma_signal_add(&sta->chain_signal_avg[i], -signal);
|
||||
sta->rx_stats.chain_signal_last[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
|
||||
* counting this as a dropped packed.
|
||||
*/
|
||||
sta->rx_packets++;
|
||||
sta->rx_stats.packets++;
|
||||
dev_kfree_skb(rx->skb);
|
||||
return RX_QUEUED;
|
||||
}
|
||||
|
@ -1922,7 +1927,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
|
|||
ieee80211_led_rx(rx->local);
|
||||
out_no_led:
|
||||
if (rx->sta)
|
||||
rx->sta->rx_packets++;
|
||||
rx->sta->rx_stats.packets++;
|
||||
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
|
||||
* 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);
|
||||
schedule_work(&local->tdls_chsw_work);
|
||||
if (rx->sta)
|
||||
rx->sta->rx_packets++;
|
||||
rx->sta->rx_stats.packets++;
|
||||
|
||||
return RX_QUEUED;
|
||||
}
|
||||
|
@ -2875,7 +2880,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
|||
|
||||
handled:
|
||||
if (rx->sta)
|
||||
rx->sta->rx_packets++;
|
||||
rx->sta->rx_stats.packets++;
|
||||
dev_kfree_skb(rx->skb);
|
||||
return RX_QUEUED;
|
||||
|
||||
|
@ -2884,7 +2889,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
|||
skb_queue_tail(&sdata->skb_queue, rx->skb);
|
||||
ieee80211_queue_work(&local->hw, &sdata->work);
|
||||
if (rx->sta)
|
||||
rx->sta->rx_packets++;
|
||||
rx->sta->rx_stats.packets++;
|
||||
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,
|
||||
rx->skb->data, rx->skb->len, 0)) {
|
||||
if (rx->sta)
|
||||
rx->sta->rx_packets++;
|
||||
rx->sta->rx_stats.packets++;
|
||||
dev_kfree_skb(rx->skb);
|
||||
return RX_QUEUED;
|
||||
}
|
||||
|
@ -3030,7 +3035,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
|
|||
skb_queue_tail(&sdata->skb_queue, rx->skb);
|
||||
ieee80211_queue_work(&rx->local->hw, &sdata->work);
|
||||
if (rx->sta)
|
||||
rx->sta->rx_packets++;
|
||||
rx->sta->rx_stats.packets++;
|
||||
|
||||
return RX_QUEUED;
|
||||
}
|
||||
|
@ -3112,7 +3117,7 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx,
|
|||
case RX_DROP_MONITOR:
|
||||
I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop);
|
||||
if (rx->sta)
|
||||
rx->sta->rx_dropped++;
|
||||
rx->sta->rx_stats.dropped++;
|
||||
/* fall through */
|
||||
case RX_CONTINUE: {
|
||||
struct ieee80211_rate *rate = NULL;
|
||||
|
@ -3132,7 +3137,7 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx,
|
|||
case RX_DROP_UNUSABLE:
|
||||
I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop);
|
||||
if (rx->sta)
|
||||
rx->sta->rx_dropped++;
|
||||
rx->sta->rx_stats.dropped++;
|
||||
dev_kfree_skb(rx->skb);
|
||||
break;
|
||||
case RX_QUEUED:
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include <linux/if_arp.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <net/sch_generic.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
|
@ -67,24 +66,23 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
|
|||
struct cfg80211_bss *cbss;
|
||||
struct ieee80211_bss *bss;
|
||||
int clen, srlen;
|
||||
enum nl80211_bss_scan_width scan_width;
|
||||
s32 signal = 0;
|
||||
struct cfg80211_inform_bss bss_meta = {};
|
||||
bool signal_valid;
|
||||
|
||||
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))
|
||||
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)
|
||||
scan_width = NL80211_BSS_CHAN_WIDTH_5;
|
||||
bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_5;
|
||||
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,
|
||||
scan_width, mgmt, len, signal,
|
||||
GFP_ATOMIC);
|
||||
bss_meta.chan = channel;
|
||||
cbss = cfg80211_inform_bss_frame_data(local->hw.wiphy, &bss_meta,
|
||||
mgmt, len, GFP_ATOMIC);
|
||||
if (!cbss)
|
||||
return NULL;
|
||||
/* In case the signal is invalid update the status */
|
||||
|
|
|
@ -331,7 +331,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
|||
memcpy(sta->sta.addr, addr, ETH_ALEN);
|
||||
sta->local = local;
|
||||
sta->sdata = sdata;
|
||||
sta->last_rx = jiffies;
|
||||
sta->rx_stats.last_rx = jiffies;
|
||||
|
||||
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->last_connected = ktime_get_seconds();
|
||||
ewma_signal_init(&sta->avg_signal);
|
||||
for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++)
|
||||
ewma_signal_init(&sta->chain_signal_avg[i]);
|
||||
ewma_signal_init(&sta->rx_stats.avg_signal);
|
||||
for (i = 0; i < ARRAY_SIZE(sta->rx_stats.chain_signal_avg); i++)
|
||||
ewma_signal_init(&sta->rx_stats.chain_signal_avg[i]);
|
||||
|
||||
if (local->ops->wake_tx_queue) {
|
||||
void *txq_data;
|
||||
|
@ -1066,7 +1066,7 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
|
|||
if (sdata != sta->sdata)
|
||||
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->sta.addr);
|
||||
|
||||
|
@ -1806,6 +1806,45 @@ u8 sta_info_tx_streams(struct sta_info *sta)
|
|||
>> 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)
|
||||
{
|
||||
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_BSS_PARAM) |
|
||||
BIT(NL80211_STA_INFO_CONNECTED_TIME) |
|
||||
BIT(NL80211_STA_INFO_RX_DROP_MISC) |
|
||||
BIT(NL80211_STA_INFO_BEACON_LOSS);
|
||||
BIT(NL80211_STA_INFO_RX_DROP_MISC);
|
||||
|
||||
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->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) |
|
||||
BIT(NL80211_STA_INFO_TX_BYTES)))) {
|
||||
sinfo->tx_bytes = 0;
|
||||
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);
|
||||
}
|
||||
|
||||
if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_PACKETS))) {
|
||||
sinfo->tx_packets = 0;
|
||||
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);
|
||||
}
|
||||
|
||||
if (!(sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES64) |
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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->rx_dropped_misc = sta->rx_dropped;
|
||||
sinfo->beacon_loss_count = sta->beacon_loss_count;
|
||||
sinfo->rx_dropped_misc = sta->rx_stats.dropped;
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
!(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) ||
|
||||
ieee80211_hw_check(&sta->local->hw, SIGNAL_UNSPEC)) {
|
||||
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);
|
||||
}
|
||||
|
||||
if (!(sinfo->filled & BIT(NL80211_STA_INFO_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);
|
||||
}
|
||||
}
|
||||
|
||||
if (sta->chains &&
|
||||
if (sta->rx_stats.chains &&
|
||||
!(sinfo->filled & (BIT(NL80211_STA_INFO_CHAIN_SIGNAL) |
|
||||
BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)))) {
|
||||
sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL) |
|
||||
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++) {
|
||||
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] =
|
||||
(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))) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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))) {
|
||||
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))) {
|
||||
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 &
|
||||
|
@ -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)) {
|
||||
tidstats->filled |=
|
||||
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 &
|
||||
|
@ -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)) {
|
||||
tidstats->filled |=
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -344,12 +344,6 @@ DECLARE_EWMA(signal, 1024, 8)
|
|||
* @rate_ctrl_lock: spinlock used to protect rate control data
|
||||
* (data inside the algorithm, so serializes calls there)
|
||||
* @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
|
||||
* in the header file.
|
||||
* @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
|
||||
* @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
|
||||
* @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
|
||||
* @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
|
||||
* 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
|
||||
* @ampdu_mlme: A-MPDU state machine state
|
||||
* @timer_to_tid: identity mapping to ID timers
|
||||
|
@ -388,32 +368,22 @@ DECLARE_EWMA(signal, 1024, 8)
|
|||
* @debugfs: debug filesystem info
|
||||
* @dead: set to true when sta is unlinked
|
||||
* @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_state: duplicates information about station state (for debug)
|
||||
* @beacon_loss_count: number of times beacon loss has triggered
|
||||
* @rcu_head: RCU head used for freeing this station struct
|
||||
* @cur_max_bandwidth: maximum bandwidth to use for TX to the station,
|
||||
* 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
|
||||
* AP only.
|
||||
* @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)
|
||||
* @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
|
||||
* @tdls_chandef: a TDLS peer can have a wider chandef that is compatible to
|
||||
* the BSS one.
|
||||
* @tx_stats: TX statistics
|
||||
* @rx_stats: RX statistics
|
||||
* @status_stats: TX status statistics
|
||||
*/
|
||||
struct sta_info {
|
||||
/* General information, mostly static */
|
||||
|
@ -457,42 +427,49 @@ struct sta_info {
|
|||
unsigned long driver_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;
|
||||
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;
|
||||
s8 chain_signal_last[IEEE80211_MAX_CHAINS];
|
||||
struct ewma_signal chain_signal_avg[IEEE80211_MAX_CHAINS];
|
||||
/* Updated from RX path only, no locking requirements */
|
||||
struct {
|
||||
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 */
|
||||
__le16 last_seq_ctrl[IEEE80211_NUM_TIDS + 1];
|
||||
|
||||
/* Updated from TX status path only, no locking requirements */
|
||||
unsigned long tx_filtered_count;
|
||||
unsigned long tx_retry_failed, tx_retry_count;
|
||||
struct {
|
||||
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 */
|
||||
u64 tx_packets[IEEE80211_NUM_ACS];
|
||||
u64 tx_bytes[IEEE80211_NUM_ACS];
|
||||
struct ieee80211_tx_rate last_tx_rate;
|
||||
int last_rx_rate_idx;
|
||||
u32 last_rx_rate_flag;
|
||||
u32 last_rx_rate_vht_flag;
|
||||
u8 last_rx_rate_vht_nss;
|
||||
struct {
|
||||
u64 packets[IEEE80211_NUM_ACS];
|
||||
u64 bytes[IEEE80211_NUM_ACS];
|
||||
struct ieee80211_tx_rate last_rate;
|
||||
u64 msdu[IEEE80211_NUM_TIDS + 1];
|
||||
} tx_stats;
|
||||
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.
|
||||
|
@ -509,15 +486,9 @@ struct sta_info {
|
|||
|
||||
enum ieee80211_sta_rx_bandwidth cur_max_bandwidth;
|
||||
|
||||
unsigned int lost_packets;
|
||||
unsigned int beacon_loss_count;
|
||||
|
||||
enum ieee80211_smps_mode known_smps_mode;
|
||||
const struct ieee80211_cipher_scheme *cipher_scheme;
|
||||
|
||||
/* TDLS timeout data */
|
||||
unsigned long last_tdls_pkt_time;
|
||||
|
||||
u8 reserved_tid;
|
||||
|
||||
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,
|
||||
const struct ieee80211_tx_rate *rate,
|
||||
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 ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
|
||||
|
|
|
@ -67,7 +67,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
|
|||
IEEE80211_TX_INTFL_RETRANSMISSION;
|
||||
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
|
||||
|
@ -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;
|
||||
|
||||
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)) {
|
||||
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))
|
||||
return;
|
||||
|
||||
sta->lost_packets++;
|
||||
if (!sta->sta.tdls && sta->lost_packets < STA_LOST_PKT_THRESHOLD)
|
||||
sta->status_stats.lost_packets++;
|
||||
if (!sta->sta.tdls &&
|
||||
sta->status_stats.lost_packets < STA_LOST_PKT_THRESHOLD)
|
||||
return;
|
||||
|
||||
/*
|
||||
|
@ -568,14 +569,15 @@ static void ieee80211_lost_packet(struct sta_info *sta,
|
|||
* mechanism.
|
||||
*/
|
||||
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,
|
||||
sta->last_tdls_pkt_time + STA_LOST_TDLS_PKT_TIME)))
|
||||
sta->status_stats.last_tdls_pkt_time +
|
||||
STA_LOST_TDLS_PKT_TIME)))
|
||||
return;
|
||||
|
||||
cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr,
|
||||
sta->lost_packets, GFP_ATOMIC);
|
||||
sta->lost_packets = 0;
|
||||
sta->status_stats.lost_packets, GFP_ATOMIC);
|
||||
sta->status_stats.lost_packets = 0;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (!acked)
|
||||
sta->tx_retry_failed++;
|
||||
sta->tx_retry_count += retry_count;
|
||||
sta->status_stats.retry_failed++;
|
||||
sta->status_stats.retry_count += retry_count;
|
||||
|
||||
if (acked) {
|
||||
sta->last_rx = jiffies;
|
||||
sta->rx_stats.last_rx = jiffies;
|
||||
|
||||
if (sta->lost_packets)
|
||||
sta->lost_packets = 0;
|
||||
if (sta->status_stats.lost_packets)
|
||||
sta->status_stats.lost_packets = 0;
|
||||
|
||||
/* Track when last TDLS packet was ACKed */
|
||||
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 {
|
||||
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) &&
|
||||
(ieee80211_is_data(hdr->frame_control)) &&
|
||||
(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) &&
|
||||
(ieee80211_is_data_qos(fc))) {
|
||||
|
@ -830,13 +833,15 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
return;
|
||||
} else {
|
||||
if (!acked)
|
||||
sta->tx_retry_failed++;
|
||||
sta->tx_retry_count += retry_count;
|
||||
sta->status_stats.retry_failed++;
|
||||
sta->status_stats.retry_count += retry_count;
|
||||
|
||||
if (ieee80211_is_data_present(fc)) {
|
||||
if (!acked)
|
||||
sta->tx_msdu_failed[tid]++;
|
||||
sta->tx_msdu_retries[tid] += retry_count;
|
||||
sta->status_stats.msdu_failed[tid]++;
|
||||
|
||||
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 (info->flags & IEEE80211_TX_STAT_ACK) {
|
||||
if (sta->lost_packets)
|
||||
sta->lost_packets = 0;
|
||||
if (sta->status_stats.lost_packets)
|
||||
sta->status_stats.lost_packets = 0;
|
||||
|
||||
/* Track when last TDLS packet was ACKed */
|
||||
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 {
|
||||
ieee80211_lost_packet(sta, info);
|
||||
}
|
||||
}
|
||||
|
||||
if (acked)
|
||||
sta->last_ack_signal = info->status.ack_signal;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
|
|
@ -325,7 +325,6 @@ TRACE_EVENT(drv_config,
|
|||
__field(u32, flags)
|
||||
__field(int, power_level)
|
||||
__field(int, dynamic_ps_timeout)
|
||||
__field(int, max_sleep_period)
|
||||
__field(u16, listen_interval)
|
||||
__field(u8, long_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->power_level = local->hw.conf.power_level;
|
||||
__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->long_frame_max_tx_count =
|
||||
local->hw.conf.long_frame_max_tx_count;
|
||||
|
|
|
@ -757,9 +757,9 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
|
|||
if (txrc.reported_rate.idx < 0) {
|
||||
txrc.reported_rate = tx->rate;
|
||||
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)
|
||||
tx->sta->last_tx_rate = txrc.reported_rate;
|
||||
tx->sta->tx_stats.last_rate = txrc.reported_rate;
|
||||
|
||||
if (ratetbl)
|
||||
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);
|
||||
tx->sdata->sequence_number += 0x10;
|
||||
if (tx->sta)
|
||||
tx->sta->tx_msdu[IEEE80211_NUM_TIDS]++;
|
||||
tx->sta->tx_stats.msdu[IEEE80211_NUM_TIDS]++;
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
|
@ -840,7 +840,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
|
|||
|
||||
qc = ieee80211_get_qos_ctl(hdr);
|
||||
tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
|
||||
tx->sta->tx_msdu[tid]++;
|
||||
tx->sta->tx_stats.msdu[tid]++;
|
||||
|
||||
if (!tx->sta->sta.txq[0])
|
||||
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) {
|
||||
ac = skb_get_queue_mapping(skb);
|
||||
tx->sta->tx_bytes[ac] += skb->len;
|
||||
tx->sta->tx_stats.bytes[ac] += skb->len;
|
||||
}
|
||||
if (ac >= 0)
|
||||
tx->sta->tx_packets[ac]++;
|
||||
tx->sta->tx_stats.packets[ac]++;
|
||||
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
@ -2779,10 +2779,10 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
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);
|
||||
else
|
||||
sta->tx_msdu[tid]++;
|
||||
sta->tx_stats.msdu[tid]++;
|
||||
|
||||
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
|
||||
* has to consider fragmentation, so is more complex)
|
||||
*/
|
||||
sta->tx_bytes[skb_get_queue_mapping(skb)] += skb->len;
|
||||
sta->tx_packets[skb_get_queue_mapping(skb)]++;
|
||||
sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len;
|
||||
sta->tx_stats.packets[skb_get_queue_mapping(skb)]++;
|
||||
|
||||
if (fast_tx->pn_offs) {
|
||||
u64 pn;
|
||||
|
|
|
@ -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
|
||||
|
@ -2042,9 +2042,13 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
|||
if (sched_scan_sdata && sched_scan_req)
|
||||
/*
|
||||
* 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_stopped = true;
|
||||
mutex_unlock(&local->mtx);
|
||||
|
@ -3301,9 +3305,11 @@ void ieee80211_init_tx_queue(struct ieee80211_sub_if_data *sdata,
|
|||
if (sta) {
|
||||
txqi->txq.sta = &sta->sta;
|
||||
sta->sta.txq[tid] = &txqi->txq;
|
||||
txqi->txq.tid = tid;
|
||||
txqi->txq.ac = ieee802_1d_to_ac[tid & 7];
|
||||
} else {
|
||||
sdata->vif.txq = &txqi->txq;
|
||||
txqi->txq.tid = 0;
|
||||
txqi->txq.ac = IEEE80211_AC_BE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -174,9 +174,12 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
|
|||
* a driver that supports HW encryption. Send up the key idx only if
|
||||
* the key is set.
|
||||
*/
|
||||
mac80211_ev_michael_mic_failure(rx->sdata,
|
||||
rx->key ? rx->key->conf.keyidx : -1,
|
||||
(void *) skb->data, NULL, GFP_ATOMIC);
|
||||
cfg80211_michael_mic_failure(rx->sdata->dev, hdr->addr2,
|
||||
is_multicast_ether_addr(hdr->addr1) ?
|
||||
NL80211_KEYTYPE_GROUP :
|
||||
NL80211_KEYTYPE_PAIRWISE,
|
||||
rx->key ? rx->key->conf.keyidx : -1,
|
||||
NULL, GFP_ATOMIC);
|
||||
return RX_DROP_UNUSABLE;
|
||||
}
|
||||
|
||||
|
|
|
@ -174,6 +174,16 @@ config CFG80211_INTERNAL_REGDB
|
|||
|
||||
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
|
||||
bool "cfg80211 wireless extensions compatibility" if !CFG80211_WEXT_EXPORT
|
||||
depends on CFG80211
|
||||
|
|
|
@ -461,6 +461,9 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
|
|||
|
||||
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;
|
||||
}
|
||||
EXPORT_SYMBOL(wiphy_new_nm);
|
||||
|
@ -636,7 +639,7 @@ int wiphy_register(struct wiphy *wiphy)
|
|||
if (WARN_ON(!sband->n_channels))
|
||||
return -EINVAL;
|
||||
/*
|
||||
* on 60gHz band, there are no legacy rates, so
|
||||
* on 60GHz band, there are no legacy rates, so
|
||||
* n_bitrates is 0
|
||||
*/
|
||||
if (WARN_ON(band != IEEE80211_BAND_60GHZ &&
|
||||
|
|
|
@ -137,6 +137,7 @@ struct cfg80211_internal_bss {
|
|||
struct list_head list;
|
||||
struct list_head hidden_list;
|
||||
struct rb_node rbn;
|
||||
u64 ts_boottime;
|
||||
unsigned long ts;
|
||||
unsigned long refcount;
|
||||
atomic_t hold;
|
||||
|
|
|
@ -479,6 +479,12 @@ nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
|
|||
[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,
|
||||
struct netlink_callback *cb,
|
||||
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,
|
||||
rdev->wiphy.max_sched_scan_ie_len) ||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 = ®_rule->freq_range;
|
||||
struct ieee80211_power_rule *power_rule = ®_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)
|
||||
{
|
||||
char *data = NULL;
|
||||
|
@ -5613,6 +5575,57 @@ static int nl80211_get_reg_dump(struct sk_buff *skb,
|
|||
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 = ®_rule->freq_range;
|
||||
struct ieee80211_power_rule *power_rule = ®_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)
|
||||
{
|
||||
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);
|
||||
return r;
|
||||
}
|
||||
#endif /* CONFIG_CFG80211_CRDA_SUPPORT */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 *
|
||||
nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct nlattr **attrs)
|
||||
{
|
||||
struct cfg80211_sched_scan_request *request;
|
||||
struct nlattr *attr;
|
||||
int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i;
|
||||
u32 interval;
|
||||
int err, tmp, n_ssids = 0, n_match_sets = 0, n_channels, i, n_plans = 0;
|
||||
enum ieee80211_band band;
|
||||
size_t ie_len;
|
||||
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]))
|
||||
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]) {
|
||||
n_channels = validate_scan_freqs(
|
||||
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)
|
||||
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)
|
||||
+ sizeof(*request->ssids) * n_ssids
|
||||
+ sizeof(*request->match_sets) * n_match_sets
|
||||
+ sizeof(*request->scan_plans) * n_plans
|
||||
+ sizeof(*request->channels) * n_channels
|
||||
+ ie_len, GFP_KERNEL);
|
||||
if (!request)
|
||||
|
@ -6090,6 +6211,18 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
}
|
||||
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;
|
||||
if (attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
|
||||
/* 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 =
|
||||
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;
|
||||
|
||||
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)))
|
||||
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) {
|
||||
case CFG80211_SIGNAL_TYPE_MBM:
|
||||
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,
|
||||
struct cfg80211_sched_scan_request *req)
|
||||
{
|
||||
struct nlattr *nd, *freqs, *matches, *match;
|
||||
struct nlattr *nd, *freqs, *matches, *match, *scan_plans, *scan_plan;
|
||||
int i;
|
||||
|
||||
if (!req)
|
||||
|
@ -8855,7 +8996,9 @@ static int nl80211_send_wowlan_nd(struct sk_buff *msg,
|
|||
if (!nd)
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
|
@ -10737,6 +10897,7 @@ static const struct genl_ops nl80211_ops[] = {
|
|||
.internal_flags = NL80211_FLAG_NEED_RTNL,
|
||||
/* can be retrieved by unprivileged users */
|
||||
},
|
||||
#ifdef CONFIG_CFG80211_CRDA_SUPPORT
|
||||
{
|
||||
.cmd = NL80211_CMD_SET_REG,
|
||||
.doit = nl80211_set_reg,
|
||||
|
@ -10744,6 +10905,7 @@ static const struct genl_ops nl80211_ops[] = {
|
|||
.flags = GENL_ADMIN_PERM,
|
||||
.internal_flags = NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.cmd = NL80211_CMD_REQ_SET_REG,
|
||||
.doit = nl80211_req_set_reg,
|
||||
|
|
|
@ -135,10 +135,7 @@ static spinlock_t reg_indoor_lock;
|
|||
/* Used to track the userspace process controlling the indoor setting */
|
||||
static u32 reg_is_indoor_portid;
|
||||
|
||||
/* Max number of consecutive attempts to communicate with CRDA */
|
||||
#define REG_MAX_CRDA_TIMEOUTS 10
|
||||
|
||||
static u32 reg_crda_timeouts;
|
||||
static void restore_regulatory_settings(bool reset_user);
|
||||
|
||||
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 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 */
|
||||
static const struct ieee80211_regdomain world_regdom = {
|
||||
.n_reg_rules = 8,
|
||||
|
@ -262,7 +256,7 @@ static const struct ieee80211_regdomain world_regdom = {
|
|||
REG_RULE(5745-10, 5825+10, 80, 6, 20,
|
||||
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),
|
||||
}
|
||||
};
|
||||
|
@ -279,6 +273,9 @@ MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
|
|||
|
||||
static void reg_free_request(struct regulatory_request *request)
|
||||
{
|
||||
if (request == &core_request_world)
|
||||
return;
|
||||
|
||||
if (request != get_last_request())
|
||||
kfree(request);
|
||||
}
|
||||
|
@ -453,68 +450,70 @@ reg_copy_regd(const struct ieee80211_regdomain *src_regd)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_CFG80211_INTERNAL_REGDB
|
||||
struct reg_regdb_search_request {
|
||||
char alpha2[2];
|
||||
struct reg_regdb_apply_request {
|
||||
struct list_head list;
|
||||
const struct ieee80211_regdomain *regdom;
|
||||
};
|
||||
|
||||
static LIST_HEAD(reg_regdb_search_list);
|
||||
static DEFINE_MUTEX(reg_regdb_search_mutex);
|
||||
static LIST_HEAD(reg_regdb_apply_list);
|
||||
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;
|
||||
const struct ieee80211_regdomain *curdom, *regdom = NULL;
|
||||
int i;
|
||||
struct reg_regdb_apply_request *request;
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
mutex_lock(®_regdb_search_mutex);
|
||||
while (!list_empty(®_regdb_search_list)) {
|
||||
request = list_first_entry(®_regdb_search_list,
|
||||
struct reg_regdb_search_request,
|
||||
mutex_lock(®_regdb_apply_mutex);
|
||||
while (!list_empty(®_regdb_apply_list)) {
|
||||
request = list_first_entry(®_regdb_apply_list,
|
||||
struct reg_regdb_apply_request,
|
||||
list);
|
||||
list_del(&request->list);
|
||||
|
||||
for (i = 0; i < reg_regdb_size; i++) {
|
||||
curdom = reg_regdb[i];
|
||||
|
||||
if (alpha2_equal(request->alpha2, curdom->alpha2)) {
|
||||
regdom = reg_copy_regd(curdom);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
set_regdom(request->regdom, REGD_SOURCE_INTERNAL_DB);
|
||||
kfree(request);
|
||||
}
|
||||
mutex_unlock(®_regdb_search_mutex);
|
||||
|
||||
if (!IS_ERR_OR_NULL(regdom))
|
||||
set_regdom(regdom, REGD_SOURCE_INTERNAL_DB);
|
||||
mutex_unlock(®_regdb_apply_mutex);
|
||||
|
||||
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)
|
||||
return;
|
||||
for (i = 0; i < reg_regdb_size; i++) {
|
||||
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)
|
||||
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(®_regdb_search_mutex);
|
||||
list_add_tail(&request->list, ®_regdb_search_list);
|
||||
mutex_unlock(®_regdb_search_mutex);
|
||||
mutex_lock(®_regdb_apply_mutex);
|
||||
list_add_tail(&request->list, ®_regdb_apply_list);
|
||||
mutex_unlock(®_regdb_apply_mutex);
|
||||
|
||||
schedule_work(®_regdb_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Feel free to add any other sanity checks here */
|
||||
|
@ -525,9 +524,45 @@ static void reg_regdb_size_check(void)
|
|||
}
|
||||
#else
|
||||
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 */
|
||||
|
||||
#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
|
||||
* basis in userspace.
|
||||
|
@ -536,13 +571,11 @@ static int call_crda(const char *alpha2)
|
|||
{
|
||||
char country[12];
|
||||
char *env[] = { country, NULL };
|
||||
int ret;
|
||||
|
||||
snprintf(country, sizeof(country), "COUNTRY=%c%c",
|
||||
alpha2[0], alpha2[1]);
|
||||
|
||||
/* query internal regulatory database (if it exists) */
|
||||
reg_regdb_query(alpha2);
|
||||
|
||||
if (reg_crda_timeouts > REG_MAX_CRDA_TIMEOUTS) {
|
||||
pr_debug("Exceeded CRDA call max attempts. Not calling CRDA\n");
|
||||
return -EINVAL;
|
||||
|
@ -554,18 +587,34 @@ static int call_crda(const char *alpha2)
|
|||
else
|
||||
pr_debug("Calling CRDA to update world regulatory domain\n");
|
||||
|
||||
return kobject_uevent_env(®_pdev->dev.kobj, KOBJ_CHANGE, env);
|
||||
}
|
||||
|
||||
static enum reg_request_treatment
|
||||
reg_call_crda(struct regulatory_request *request)
|
||||
{
|
||||
if (call_crda(request->alpha2))
|
||||
return REG_REQ_IGNORE;
|
||||
ret = kobject_uevent_env(®_pdev->dev.kobj, KOBJ_CHANGE, env);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
queue_delayed_work(system_power_efficient_wq,
|
||||
®_timeout, msecs_to_jiffies(3142));
|
||||
return REG_REQ_OK;
|
||||
&crda_timeout, msecs_to_jiffies(3142));
|
||||
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)
|
||||
|
@ -1081,11 +1130,11 @@ const char *reg_initiator_name(enum nl80211_reg_initiator initiator)
|
|||
}
|
||||
EXPORT_SYMBOL(reg_initiator_name);
|
||||
|
||||
#ifdef CONFIG_CFG80211_REG_DEBUG
|
||||
static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd,
|
||||
struct ieee80211_channel *chan,
|
||||
const struct ieee80211_reg_rule *reg_rule)
|
||||
{
|
||||
#ifdef CONFIG_CFG80211_REG_DEBUG
|
||||
const struct ieee80211_power_rule *power_rule;
|
||||
const struct ieee80211_freq_range *freq_range;
|
||||
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)
|
||||
snprintf(max_antenna_gain, sizeof(max_antenna_gain), "N/A");
|
||||
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);
|
||||
|
||||
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",
|
||||
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,
|
||||
bw, max_antenna_gain,
|
||||
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
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
#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;
|
||||
}
|
||||
|
@ -1846,7 +1889,7 @@ static void reg_set_request_processed(void)
|
|||
need_more_processing = true;
|
||||
spin_unlock(®_requests_lock);
|
||||
|
||||
cancel_delayed_work(®_timeout);
|
||||
cancel_crda_timeout();
|
||||
|
||||
if (need_more_processing)
|
||||
schedule_work(®_work);
|
||||
|
@ -1858,19 +1901,18 @@ static void reg_set_request_processed(void)
|
|||
*
|
||||
* The wireless subsystem can use this function to process
|
||||
* a regulatory request issued by the regulatory core.
|
||||
*
|
||||
* Returns one of the different reg request treatment values.
|
||||
*/
|
||||
static enum reg_request_treatment
|
||||
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;
|
||||
core_request->processed = false;
|
||||
|
||||
reg_update_last_request(core_request);
|
||||
|
||||
return reg_call_crda(core_request);
|
||||
return REG_REQ_IGNORE;
|
||||
}
|
||||
|
||||
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
|
||||
* a regulatory request initiated by userspace.
|
||||
*
|
||||
* Returns one of the different reg request treatment values.
|
||||
*/
|
||||
static enum reg_request_treatment
|
||||
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);
|
||||
if (treatment == REG_REQ_IGNORE ||
|
||||
treatment == REG_REQ_ALREADY_SET) {
|
||||
reg_free_request(user_request);
|
||||
return treatment;
|
||||
}
|
||||
treatment == REG_REQ_ALREADY_SET)
|
||||
return REG_REQ_IGNORE;
|
||||
|
||||
user_request->intersect = treatment == REG_REQ_INTERSECT;
|
||||
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];
|
||||
user_alpha2[1] = user_request->alpha2[1];
|
||||
|
||||
return reg_call_crda(user_request);
|
||||
return REG_REQ_IGNORE;
|
||||
}
|
||||
|
||||
static enum reg_request_treatment
|
||||
|
@ -1986,16 +2026,12 @@ reg_process_hint_driver(struct wiphy *wiphy,
|
|||
case REG_REQ_OK:
|
||||
break;
|
||||
case REG_REQ_IGNORE:
|
||||
reg_free_request(driver_request);
|
||||
return treatment;
|
||||
return REG_REQ_IGNORE;
|
||||
case REG_REQ_INTERSECT:
|
||||
/* fall through */
|
||||
case REG_REQ_ALREADY_SET:
|
||||
regd = reg_copy_regd(get_cfg80211_regdom());
|
||||
if (IS_ERR(regd)) {
|
||||
reg_free_request(driver_request);
|
||||
if (IS_ERR(regd))
|
||||
return REG_REQ_IGNORE;
|
||||
}
|
||||
|
||||
tmp = get_wiphy_regdom(wiphy);
|
||||
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->processed = false;
|
||||
|
||||
reg_update_last_request(driver_request);
|
||||
|
||||
/*
|
||||
* Since CRDA will not be called in this case as we already
|
||||
* 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) {
|
||||
nl80211_send_reg_change_event(driver_request);
|
||||
reg_update_last_request(driver_request);
|
||||
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
|
||||
|
@ -2085,12 +2125,11 @@ reg_process_hint_country_ie(struct wiphy *wiphy,
|
|||
case REG_REQ_OK:
|
||||
break;
|
||||
case REG_REQ_IGNORE:
|
||||
/* fall through */
|
||||
return REG_REQ_IGNORE;
|
||||
case REG_REQ_ALREADY_SET:
|
||||
reg_free_request(country_ie_request);
|
||||
return treatment;
|
||||
return REG_REQ_ALREADY_SET;
|
||||
case REG_REQ_INTERSECT:
|
||||
reg_free_request(country_ie_request);
|
||||
/*
|
||||
* This doesn't happen yet, not sure we
|
||||
* 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->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 */
|
||||
|
@ -2118,11 +2160,11 @@ static void reg_process_hint(struct regulatory_request *reg_request)
|
|||
|
||||
switch (reg_request->initiator) {
|
||||
case NL80211_REGDOM_SET_BY_CORE:
|
||||
reg_process_hint_core(reg_request);
|
||||
return;
|
||||
treatment = reg_process_hint_core(reg_request);
|
||||
break;
|
||||
case NL80211_REGDOM_SET_BY_USER:
|
||||
reg_process_hint_user(reg_request);
|
||||
return;
|
||||
treatment = reg_process_hint_user(reg_request);
|
||||
break;
|
||||
case NL80211_REGDOM_SET_BY_DRIVER:
|
||||
if (!wiphy)
|
||||
goto out_free;
|
||||
|
@ -2138,6 +2180,12 @@ static void reg_process_hint(struct regulatory_request *reg_request)
|
|||
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.
|
||||
* 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;
|
||||
|
||||
/* Allow calling CRDA again */
|
||||
reg_crda_timeouts = 0;
|
||||
reset_crda_timeouts();
|
||||
|
||||
queue_regulatory_request(request);
|
||||
|
||||
|
@ -2417,7 +2465,7 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
|
|||
request->initiator = NL80211_REGDOM_SET_BY_DRIVER;
|
||||
|
||||
/* Allow calling CRDA again */
|
||||
reg_crda_timeouts = 0;
|
||||
reset_crda_timeouts();
|
||||
|
||||
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;
|
||||
|
||||
/* Allow calling CRDA again */
|
||||
reg_crda_timeouts = 0;
|
||||
reset_crda_timeouts();
|
||||
|
||||
queue_regulatory_request(request);
|
||||
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);
|
||||
if (!request_wiphy) {
|
||||
queue_delayed_work(system_power_efficient_wq,
|
||||
®_timeout, 0);
|
||||
if (!request_wiphy)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!driver_request->intersect) {
|
||||
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);
|
||||
if (!request_wiphy) {
|
||||
queue_delayed_work(system_power_efficient_wq,
|
||||
®_timeout, 0);
|
||||
if (!request_wiphy)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (country_ie_request->intersect)
|
||||
return -EINVAL;
|
||||
|
@ -2966,7 +3008,7 @@ int set_regdom(const struct ieee80211_regdomain *rd,
|
|||
}
|
||||
|
||||
if (regd_src == REGD_SOURCE_CRDA)
|
||||
reg_crda_timeouts = 0;
|
||||
reset_crda_timeouts();
|
||||
|
||||
lr = get_last_request();
|
||||
|
||||
|
@ -3123,15 +3165,6 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy)
|
|||
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
|
||||
* UNII band definitions
|
||||
|
@ -3217,7 +3250,7 @@ void regulatory_exit(void)
|
|||
struct reg_beacon *reg_beacon, *btmp;
|
||||
|
||||
cancel_work_sync(®_work);
|
||||
cancel_delayed_work_sync(®_timeout);
|
||||
cancel_crda_timeout_sync();
|
||||
cancel_delayed_work_sync(®_check_chans);
|
||||
|
||||
/* Lock to suppress warnings */
|
||||
|
|
|
@ -266,8 +266,7 @@ void __cfg80211_sched_scan_results(struct work_struct *wk)
|
|||
spin_lock_bh(&rdev->bss_lock);
|
||||
__cfg80211_bss_expire(rdev, request->scan_start);
|
||||
spin_unlock_bh(&rdev->bss_lock);
|
||||
request->scan_start =
|
||||
jiffies + msecs_to_jiffies(request->interval);
|
||||
request->scan_start = jiffies;
|
||||
}
|
||||
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.capability = tmp->pub.capability;
|
||||
found->ts = tmp->ts;
|
||||
found->ts_boottime = tmp->ts_boottime;
|
||||
} else {
|
||||
struct cfg80211_internal_bss *new;
|
||||
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. */
|
||||
struct cfg80211_bss*
|
||||
cfg80211_inform_bss_width(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *rx_channel,
|
||||
enum nl80211_bss_scan_width scan_width,
|
||||
enum cfg80211_bss_frame_type ftype,
|
||||
const u8 *bssid, u64 tsf, u16 capability,
|
||||
u16 beacon_interval, const u8 *ie, size_t ielen,
|
||||
s32 signal, gfp_t gfp)
|
||||
struct cfg80211_bss *
|
||||
cfg80211_inform_bss_data(struct wiphy *wiphy,
|
||||
struct cfg80211_inform_bss *data,
|
||||
enum cfg80211_bss_frame_type ftype,
|
||||
const u8 *bssid, u64 tsf, u16 capability,
|
||||
u16 beacon_interval, const u8 *ie, size_t ielen,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct cfg80211_bss_ies *ies;
|
||||
struct ieee80211_channel *channel;
|
||||
|
@ -957,19 +956,21 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
|
|||
return NULL;
|
||||
|
||||
if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
|
||||
(signal < 0 || signal > 100)))
|
||||
(data->signal < 0 || data->signal > 100)))
|
||||
return NULL;
|
||||
|
||||
channel = cfg80211_get_bss_channel(wiphy, ie, ielen, rx_channel);
|
||||
channel = cfg80211_get_bss_channel(wiphy, ie, ielen, data->chan);
|
||||
if (!channel)
|
||||
return NULL;
|
||||
|
||||
memcpy(tmp.pub.bssid, bssid, ETH_ALEN);
|
||||
tmp.pub.channel = channel;
|
||||
tmp.pub.scan_width = scan_width;
|
||||
tmp.pub.signal = signal;
|
||||
tmp.pub.scan_width = data->scan_width;
|
||||
tmp.pub.signal = data->signal;
|
||||
tmp.pub.beacon_interval = beacon_interval;
|
||||
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
|
||||
* 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);
|
||||
|
||||
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;
|
||||
res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid);
|
||||
if (!res)
|
||||
|
@ -1019,15 +1020,15 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
|
|||
/* cfg80211_bss_update gives us a referenced result */
|
||||
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 *
|
||||
cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *rx_channel,
|
||||
enum nl80211_bss_scan_width scan_width,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
s32 signal, gfp_t gfp)
|
||||
cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
|
||||
struct cfg80211_inform_bss *data,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
gfp_t gfp)
|
||||
|
||||
{
|
||||
struct cfg80211_internal_bss tmp = {}, *res;
|
||||
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) !=
|
||||
offsetof(struct ieee80211_mgmt, u.beacon.variable));
|
||||
|
||||
trace_cfg80211_inform_bss_width_frame(wiphy, rx_channel, scan_width, mgmt,
|
||||
len, signal);
|
||||
trace_cfg80211_inform_bss_frame(wiphy, data, mgmt, len);
|
||||
|
||||
if (WARN_ON(!mgmt))
|
||||
return NULL;
|
||||
|
@ -1050,14 +1050,14 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
|
|||
return NULL;
|
||||
|
||||
if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
|
||||
(signal < 0 || signal > 100)))
|
||||
(data->signal < 0 || data->signal > 100)))
|
||||
return NULL;
|
||||
|
||||
if (WARN_ON(len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable)))
|
||||
return NULL;
|
||||
|
||||
channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable,
|
||||
ielen, rx_channel);
|
||||
ielen, data->chan);
|
||||
if (!channel)
|
||||
return NULL;
|
||||
|
||||
|
@ -1077,12 +1077,13 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
|
|||
|
||||
memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN);
|
||||
tmp.pub.channel = channel;
|
||||
tmp.pub.scan_width = scan_width;
|
||||
tmp.pub.signal = signal;
|
||||
tmp.pub.scan_width = data->scan_width;
|
||||
tmp.pub.signal = data->signal;
|
||||
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.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;
|
||||
res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid);
|
||||
if (!res)
|
||||
|
@ -1102,7 +1103,7 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
|
|||
/* cfg80211_bss_update gives us a referenced result */
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -2670,30 +2670,30 @@ TRACE_EVENT(cfg80211_get_bss,
|
|||
__entry->privacy)
|
||||
);
|
||||
|
||||
TRACE_EVENT(cfg80211_inform_bss_width_frame,
|
||||
TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel,
|
||||
enum nl80211_bss_scan_width scan_width,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
s32 signal),
|
||||
TP_ARGS(wiphy, channel, scan_width, mgmt, len, signal),
|
||||
TRACE_EVENT(cfg80211_inform_bss_frame,
|
||||
TP_PROTO(struct wiphy *wiphy, struct cfg80211_inform_bss *data,
|
||||
struct ieee80211_mgmt *mgmt, size_t len),
|
||||
TP_ARGS(wiphy, data, mgmt, len),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
CHAN_ENTRY
|
||||
__field(enum nl80211_bss_scan_width, scan_width)
|
||||
__dynamic_array(u8, mgmt, len)
|
||||
__field(s32, signal)
|
||||
__field(u64, ts_boottime)
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
CHAN_ASSIGN(channel);
|
||||
__entry->scan_width = scan_width;
|
||||
CHAN_ASSIGN(data->chan);
|
||||
__entry->scan_width = data->scan_width;
|
||||
if (mgmt)
|
||||
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,
|
||||
__entry->signal)
|
||||
__entry->signal, (unsigned long long)__entry->ts_boottime)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(cfg80211_bss_evt,
|
||||
|
|
Loading…
Reference in a new issue