Add an NL80211_SCAN_FLAG_FLUSH flag that causes old bss cache entries to
be flushed on scan completion. This is useful for collecting guaranteed
fresh scan/survey results (e.g. on resume). Flushing only happens on
successful completion of a scan; i.e. it does not happen if the scan
is aborted/canceled.
Change-Id: I7741a30857b1dc425f152d1db83c846f09cf8299
Signed-off-by: Sam Leffler <[email protected]>
---
include/linux/nl80211.h | 2 ++
include/net/cfg80211.h | 4 ++++
net/wireless/nl80211.c | 1 +
net/wireless/scan.c | 24 +++++++++++++++++++++---
net/wireless/sme.c | 1 +
5 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 0b37d1d..4cb7676 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -3057,9 +3057,11 @@ enum nl80211_probe_resp_offload_support_attr {
* requests.
*
* @NL80211_SCAN_FLAG_TX_ABORT: abort scan if tx collides
+ * @NL80211_SCAN_FLAG_FLUSH: flush cache before scanning
*/
enum nl80211_scan_flags {
NL80211_SCAN_FLAG_TX_ABORT = 1<<0,
+ NL80211_SCAN_FLAG_FLUSH = 1<<1,
};
#endif /* __LINUX_NL80211_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index a6a10ff..c5da2bd 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -995,9 +995,11 @@ struct cfg80211_ssid {
* enum cfg80211_scan_flags - scan request control flags
*
* @CFG80211_SCAN__FLAG_TX_ABORT: abort scan on pending transmit
+ * @CFG80211_SCAN__FLAG_FLUSH: flush cache before scanning
*/
enum cfg80211_scan_flags {
CFG80211_SCAN_FLAG_TX_ABORT = NL80211_SCAN_FLAG_TX_ABORT,
+ CFG80211_SCAN_FLAG_FLUSH = NL80211_SCAN_FLAG_FLUSH,
};
/**
@@ -1012,6 +1014,7 @@ enum cfg80211_scan_flags {
* @flags: bit field of flags controlling operation
* @rates: bitmap of rates to advertise for each band
* @wiphy: the wiphy this was for
+ * @scan_start: time (in jiffies) when the scan started
* @wdev: the wireless device to scan for
* @aborted: (internal) scan request was notified as aborted
* @no_cck: used to send probe requests at non CCK rate in 2GHz band
@@ -1030,6 +1033,7 @@ struct cfg80211_scan_request {
/* internal */
struct wiphy *wiphy;
+ unsigned long scan_start;
bool aborted;
bool no_cck;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index cbd2904..5edc7d8 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4347,6 +4347,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
request->wdev = wdev;
request->wiphy = &rdev->wiphy;
+ request->scan_start = jiffies;
rdev->scan_req = request;
err = rdev->ops->scan(&rdev->wiphy, request);
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 9730c98..c3bc184 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -20,6 +20,9 @@
#define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ)
+static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev,
+ int maxage);
+
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
{
struct cfg80211_scan_request *request;
@@ -47,8 +50,16 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
if (request->aborted)
nl80211_send_scan_aborted(rdev, wdev);
- else
+ else {
+ if (request->flags & CFG80211_SCAN_FLAG_FLUSH) {
+ /* flush entries from previous scans */
+ spin_lock_bh(&rdev->bss_lock);
+ __cfg80211_bss_expire(rdev,
+ jiffies - request->scan_start);
+ spin_unlock_bh(&rdev->bss_lock);
+ }
nl80211_send_scan_done(rdev, wdev);
+ }
#ifdef CONFIG_CFG80211_WEXT
if (wdev->netdev && !request->aborted) {
@@ -198,7 +209,8 @@ static void __cfg80211_unlink_bss(struct cfg80211_registered_device *dev,
}
/* must hold dev->bss_lock! */
-void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
+static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev,
+ int maxage)
{
struct cfg80211_internal_bss *bss, *tmp;
bool expired = false;
@@ -206,7 +218,7 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
if (atomic_read(&bss->hold))
continue;
- if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
+ if (!time_after(jiffies, bss->ts + maxage))
continue;
__cfg80211_unlink_bss(dev, bss);
expired = true;
@@ -216,6 +228,11 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
dev->bss_generation++;
}
+void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
+{
+ __cfg80211_bss_expire(dev, IEEE80211_SCAN_RESULT_EXPIRE);
+}
+
const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len)
{
while (len > 2 && ies[0] != eid) {
@@ -962,6 +979,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
creq->ssids = (void *)&creq->channels[n_channels];
creq->n_channels = n_channels;
creq->n_ssids = 1;
+ creq->scan_start = jiffies;
/* translate "Scan on frequencies" request */
i = 0;
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 6f39cb8..dde1d47 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -138,6 +138,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
request->wdev = wdev;
request->wiphy = &rdev->wiphy;
+ request->scan_start = jiffies;
rdev->scan_req = request;
--
1.7.7.3
On Thu, 2012-09-27 at 11:15 +0200, Johannes Berg wrote:
> On Fri, 2012-09-21 at 11:08 -0700, Sam Leffler wrote:
>
> > void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
> > {
> > struct cfg80211_scan_request *request;
> > @@ -47,8 +50,16 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
> >
> > if (request->aborted)
> > nl80211_send_scan_aborted(rdev, wdev);
> > - else
> > + else {
> > + if (request->flags & CFG80211_SCAN_FLAG_FLUSH) {
> > + /* flush entries from previous scans */
> > + spin_lock_bh(&rdev->bss_lock);
> > + __cfg80211_bss_expire(rdev,
> > + jiffies - request->scan_start);
>
> I wonder if we should pass an absolute time instead? jiffies will
> continue to advance while we iterate the list etc., if we pass the
> absolute time in both cases we can avoid this small race condition.
>
> The race really isn't important, but it still seems a bit cleaner to me
> overall.
jiffies are also complicated by suspend/resume. Absolute time would be
better.
Dan
On Fri, 2012-09-21 at 11:08 -0700, Sam Leffler wrote:
> void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
> {
> struct cfg80211_scan_request *request;
> @@ -47,8 +50,16 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
>
> if (request->aborted)
> nl80211_send_scan_aborted(rdev, wdev);
> - else
> + else {
> + if (request->flags & CFG80211_SCAN_FLAG_FLUSH) {
> + /* flush entries from previous scans */
> + spin_lock_bh(&rdev->bss_lock);
> + __cfg80211_bss_expire(rdev,
> + jiffies - request->scan_start);
I wonder if we should pass an absolute time instead? jiffies will
continue to advance while we iterate the list etc., if we pass the
absolute time in both cases we can avoid this small race condition.
The race really isn't important, but it still seems a bit cleaner to me
overall.
johannes