From 93f0490e5deb9445737cabf0e436f3288a4042b7 Mon Sep 17 00:00:00 2001 From: Tamizh chelvam Date: Wed, 7 Oct 2015 10:40:04 +0530 Subject: Revert "mac80211: remove exposing 'mfp' to drivers" This reverts commit 5c48f1201744233d4f235c7dd916d5196ed20716. Some device drivers (ath10k) offload part of aggregation including AddBA/DelBA negotiations to firmware. In such scenario, the PMF configuration of the station needs to be provided to driver to enable encryption of AddBA/DelBA action frames. Signed-off-by: Tamizh chelvam Signed-off-by: Johannes Berg --- include/net/mac80211.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 4ec6fedeb220..1bb2a2b4e187 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1683,6 +1683,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 +1701,7 @@ struct ieee80211_sta { struct ieee80211_sta_rates __rcu *rates; bool tdls; bool tdls_initiator; + bool mfp; struct ieee80211_txq *txq[IEEE80211_NUM_TIDS]; -- cgit v1.2.3 From 6e19bc4b7091ffd26586100eee78232b44427ec7 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Wed, 7 Oct 2015 11:32:53 +0200 Subject: nl80211: allow BSS data to include CLOCK_BOOTTIME timestamp For location and connectivity services, userspace would often like to know the time when the BSS was last seen. The current "last seen" value is calculated in a way that makes it less useful, especially if the system suspended in the meantime. Add the ability for the driver to report a real CLOCK_BOOTTIME stamp that can then be reported to userspace (if present). Drivers wishing to use this must be converted to the new API to call cfg80211_inform_bss_data() or cfg80211_inform_bss_frame_data(). They need to ensure the reported value is accurate enough even when the frame might have been buffered in the device (e.g. firmware.) Signed-off-by: Dmitry Shmidt [modified to use struct, inlines] Signed-off-by: Johannes Berg --- Documentation/DocBook/80211.tmpl | 5 ++- include/net/cfg80211.h | 95 ++++++++++++++++++++++++++++++++-------- include/uapi/linux/nl80211.h | 4 ++ net/wireless/core.h | 1 + net/wireless/nl80211.c | 5 +++ net/wireless/scan.c | 58 ++++++++++++------------ net/wireless/trace.h | 22 +++++----- 7 files changed, 130 insertions(+), 60 deletions(-) (limited to 'include') diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl index aac9357d4866..f9b9ad7894f5 100644 --- a/Documentation/DocBook/80211.tmpl +++ b/Documentation/DocBook/80211.tmpl @@ -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 diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 90332a1838cc..7f1e9ee844e2 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1575,6 +1575,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 @@ -3958,14 +3978,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 +3992,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 +4019,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 +4042,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 +4053,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 +4062,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 +4097,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, diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index c0ab6b0a3919..5dadb844fe18 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -3364,6 +3364,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 +3386,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, diff --git a/net/wireless/core.h b/net/wireless/core.h index b9d5bc8c148d..a618b4b86fa4 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -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; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index f05ba8b7af61..fb0712b3d9cb 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -6605,6 +6605,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)) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 3a50aa2553bf..3feaa03aa046 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -839,6 +839,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 +939,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 +957,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 +1001,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 +1021,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 +1042,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 +1051,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 +1078,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 +1104,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) { diff --git a/net/wireless/trace.h b/net/wireless/trace.h index a808279a432a..0c392d36781b 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -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, -- cgit v1.2.3 From a4288289f585d42a19145f266e214acb165fe9b3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 7 Oct 2015 15:48:25 +0200 Subject: wireless: update robust action frame list Unprotected DMG and VHT action frames are not protected, reflect that in the list. Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index dcfb2f43d316..0109f3847e9a 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -2397,6 +2397,8 @@ static inline bool _ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr) return *category != WLAN_CATEGORY_PUBLIC && *category != WLAN_CATEGORY_HT && *category != WLAN_CATEGORY_SELF_PROTECTED && + *category != WLAN_CATEGORY_UNPROT_DMG && + *category != WLAN_CATEGORY_VHT && *category != WLAN_CATEGORY_VENDOR_SPECIFIC; } -- cgit v1.2.3 From af61426187cd854bffe013ca8547bd8fa3c4dfbf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 7 Oct 2015 15:48:26 +0200 Subject: wireless: add WNM action frame categories Add the WNM and unprotected WNM categories and mark the latter as not robust. Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 0109f3847e9a..452c0b0d2f32 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -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,6 +2398,7 @@ 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 && -- cgit v1.2.3 From 3b06d277957c7af705a9c0cdda4b371759efb717 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Mon, 12 Oct 2015 09:51:34 +0300 Subject: cfg80211: Add multiple scan plans for scheduled scan Add the option to configure multiple 'scan plans' for scheduled scan. Each 'scan plan' defines the number of scan cycles and the interval between scans. The scan plans are executed in the order they were configured. The last scan plan will always run infinitely and thus defines only the interval between scans. The maximum number of scan plans supported by the device and the maximum number of iterations in a single scan plan are advertised to userspace so it can configure the scan plans appropriately. When scheduled scan results are received there is no way to know which scan plan is being currently executed, so there is no way to know when the next scan iteration will start. This is not a problem, however. The scan start timestamp is only used for flushing old scan results, and there is no difference between flushing all results received until the end of the previous iteration or the start of the current one, since no results will be received in between. Signed-off-by: Avraham Stern Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 2 +- drivers/net/wireless/iwlwifi/mvm/ops.c | 1 + drivers/net/wireless/iwlwifi/mvm/scan.c | 4 +- drivers/net/wireless/ti/wl12xx/scan.c | 3 +- drivers/net/wireless/ti/wl18xx/scan.c | 8 +- include/net/cfg80211.h | 31 ++++- include/uapi/linux/nl80211.h | 53 ++++++++- net/wireless/core.c | 3 + net/wireless/nl80211.c | 179 ++++++++++++++++++++++++++--- net/wireless/scan.c | 3 +- 10 files changed, 262 insertions(+), 25 deletions(-) (limited to 'include') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index a511ef3614b9..3fda750db2a9 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -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, diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 064c100e45fe..f0728b784edb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -629,6 +629,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; } diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 4a1f9af63bf0..cee4f267ca66 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -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 diff --git a/drivers/net/wireless/ti/wl12xx/scan.c b/drivers/net/wireless/ti/wl12xx/scan.c index 7c355fff2c5e..ebed13af9852 100644 --- a/drivers/net/wireless/ti/wl12xx/scan.c +++ b/drivers/net/wireless/ti/wl12xx/scan.c @@ -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); diff --git a/drivers/net/wireless/ti/wl18xx/scan.c b/drivers/net/wireless/ti/wl18xx/scan.c index c938c494c785..bc15aa2c3efa 100644 --- a/drivers/net/wireless/ti/wl18xx/scan.c +++ b/drivers/net/wireless/ti/wl18xx/scan.c @@ -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", diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 7f1e9ee844e2..48155be5db7f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5,6 +5,7 @@ * * Copyright 2006-2010 Johannes Berg * 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); @@ -3076,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 @@ -3183,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; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 5dadb844fe18..1f0b4cf5dd03 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -10,6 +10,7 @@ * Copyright 2008, 2009 Luis R. Rodriguez * Copyright 2008 Jouni Malinen * Copyright 2008 Colin McCabe + * 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, @@ -4593,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 */ diff --git a/net/wireless/core.c b/net/wireless/core.c index f223026ddb03..a83037da21b6 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -461,6 +461,9 @@ use_default_name: 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); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index fb0712b3d9cb..28c29e7da749 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -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) && @@ -5974,14 +5986,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 +6088,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 +6151,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 +6209,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 +6383,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; @@ -8850,7 +8984,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) @@ -8860,7 +8994,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)) @@ -8887,6 +9023,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; diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 3feaa03aa046..14d5369eb778 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -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); } -- cgit v1.2.3 From 4a733ef1bea705cdc69d936b95fedab4b47fbd40 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Oct 2015 18:02:43 +0200 Subject: mac80211: remove PM-QoS listener As this API has never really seen any use and most drivers don't ever use the value derived from it, remove it. Change the only driver using it (rt2x00) to simply use the DTIM period instead of the "max sleep" time. Signed-off-by: Johannes Berg --- drivers/net/wireless/rt2x00/rt2x00config.c | 2 +- include/net/mac80211.h | 6 --- net/mac80211/cfg.c | 4 +- net/mac80211/ieee80211_i.h | 5 +-- net/mac80211/iface.c | 4 +- net/mac80211/main.c | 13 ------ net/mac80211/mlme.c | 69 ++++++------------------------ net/mac80211/scan.c | 1 - net/mac80211/trace.h | 2 - net/mac80211/util.c | 2 +- 10 files changed, 21 insertions(+), 87 deletions(-) (limited to 'include') diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 48a2cad29477..7e8bb1198ae9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -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); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 1bb2a2b4e187..4b9dd070aeb9 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -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; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 63d03dad654c..276b57243298 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1428,7 +1428,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); } @@ -2463,7 +2463,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; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f9605f13def9..99735408e99d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1305,7 +1305,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 +1490,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, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 42d7f0f65bd6..f848c75518a2 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -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); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 9b813a2f3a75..e2514fadc3d7 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -1083,13 +1082,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 +1106,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 +1132,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 diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 9c450ffdabe8..6158db06a5b5 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -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; - 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; - } + /* If the TIM IE is invalid, pretend the value is 1 */ + if (!dtimper) + dtimper = 1; + + 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; @@ -3548,7 +3522,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); @@ -4152,21 +4126,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) { diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index a368a1d6caff..b64fd2b2d95a 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 314e3bd7fbdb..5cf8f4ea077f 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -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; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 8f0fa357a5a7..8274c86296f9 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -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 -- cgit v1.2.3