aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorSam Leffler <sleffler@chromium.org>2012-10-12 00:03:34 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-10-18 03:01:52 -0400
commit15d6030b4bec618742b8b9ccae9209c8f9e4a916 (patch)
tree97856b3f62e268880659757a85df59151958044d /net
parentb292219fa5061e2657ecf518b48426913d0ddae6 (diff)
cfg80211: add support for flushing old scan results
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 result (e.g. on resume). For normal scan, flushing only happens on successful completion of a scan; i.e. it does not happen if the scan is aborted. For scheduled scan, previous scan results are flushed everytime when we get new scan results. This feature is enabled by default. Drivers can disable it by unsetting the NL80211_FEATURE_SCAN_FLUSH flag. Signed-off-by: Sam Leffler <sleffler@chromium.org> Tested-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Bing Zhao <bzhao@marvell.com> [invert polarity of feature flag to account for old kernels] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r--net/wireless/core.c2
-rw-r--r--net/wireless/nl80211.c14
-rw-r--r--net/wireless/scan.c66
-rw-r--r--net/wireless/sme.c1
4 files changed, 59 insertions, 24 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 443d4d7deea2..48c2ea4712e9 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -370,6 +370,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
370 rdev->wiphy.rts_threshold = (u32) -1; 370 rdev->wiphy.rts_threshold = (u32) -1;
371 rdev->wiphy.coverage_class = 0; 371 rdev->wiphy.coverage_class = 0;
372 372
373 rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH;
374
373 return &rdev->wiphy; 375 return &rdev->wiphy;
374} 376}
375EXPORT_SYMBOL(wiphy_new); 377EXPORT_SYMBOL(wiphy_new);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index aee252d65b8f..9e5a7206b0b4 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4371,8 +4371,10 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
4371 if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) { 4371 if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
4372 request->flags = nla_get_u32( 4372 request->flags = nla_get_u32(
4373 info->attrs[NL80211_ATTR_SCAN_FLAGS]); 4373 info->attrs[NL80211_ATTR_SCAN_FLAGS]);
4374 if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && 4374 if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
4375 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { 4375 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
4376 ((request->flags & NL80211_SCAN_FLAG_FLUSH) &&
4377 !(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) {
4376 err = -EOPNOTSUPP; 4378 err = -EOPNOTSUPP;
4377 goto out_free; 4379 goto out_free;
4378 } 4380 }
@@ -4383,6 +4385,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
4383 4385
4384 request->wdev = wdev; 4386 request->wdev = wdev;
4385 request->wiphy = &rdev->wiphy; 4387 request->wiphy = &rdev->wiphy;
4388 request->scan_start = jiffies;
4386 4389
4387 rdev->scan_req = request; 4390 rdev->scan_req = request;
4388 err = rdev->ops->scan(&rdev->wiphy, request); 4391 err = rdev->ops->scan(&rdev->wiphy, request);
@@ -4612,8 +4615,10 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
4612 if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) { 4615 if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
4613 request->flags = nla_get_u32( 4616 request->flags = nla_get_u32(
4614 info->attrs[NL80211_ATTR_SCAN_FLAGS]); 4617 info->attrs[NL80211_ATTR_SCAN_FLAGS]);
4615 if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && 4618 if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
4616 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { 4619 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
4620 ((request->flags & NL80211_SCAN_FLAG_FLUSH) &&
4621 !(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) {
4617 err = -EOPNOTSUPP; 4622 err = -EOPNOTSUPP;
4618 goto out_free; 4623 goto out_free;
4619 } 4624 }
@@ -4622,6 +4627,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
4622 request->dev = dev; 4627 request->dev = dev;
4623 request->wiphy = &rdev->wiphy; 4628 request->wiphy = &rdev->wiphy;
4624 request->interval = interval; 4629 request->interval = interval;
4630 request->scan_start = jiffies;
4625 4631
4626 err = rdev->ops->sched_scan_start(&rdev->wiphy, dev, request); 4632 err = rdev->ops->sched_scan_start(&rdev->wiphy, dev, request);
4627 if (!err) { 4633 if (!err) {
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 20050965abca..a8d5a9a07e49 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -47,6 +47,27 @@ static void __cfg80211_unlink_bss(struct cfg80211_registered_device *dev,
47 kref_put(&bss->ref, bss_release); 47 kref_put(&bss->ref, bss_release);
48} 48}
49 49
50/* must hold dev->bss_lock! */
51static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev,
52 unsigned long expire_time)
53{
54 struct cfg80211_internal_bss *bss, *tmp;
55 bool expired = false;
56
57 list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
58 if (atomic_read(&bss->hold))
59 continue;
60 if (!time_after(expire_time, bss->ts))
61 continue;
62
63 __cfg80211_unlink_bss(dev, bss);
64 expired = true;
65 }
66
67 if (expired)
68 dev->bss_generation++;
69}
70
50void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) 71void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
51{ 72{
52 struct cfg80211_scan_request *request; 73 struct cfg80211_scan_request *request;
@@ -72,10 +93,17 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
72 if (wdev->netdev) 93 if (wdev->netdev)
73 cfg80211_sme_scan_done(wdev->netdev); 94 cfg80211_sme_scan_done(wdev->netdev);
74 95
75 if (request->aborted) 96 if (request->aborted) {
76 nl80211_send_scan_aborted(rdev, wdev); 97 nl80211_send_scan_aborted(rdev, wdev);
77 else 98 } else {
99 if (request->flags & NL80211_SCAN_FLAG_FLUSH) {
100 /* flush entries from previous scans */
101 spin_lock_bh(&rdev->bss_lock);
102 __cfg80211_bss_expire(rdev, request->scan_start);
103 spin_unlock_bh(&rdev->bss_lock);
104 }
78 nl80211_send_scan_done(rdev, wdev); 105 nl80211_send_scan_done(rdev, wdev);
106 }
79 107
80#ifdef CONFIG_CFG80211_WEXT 108#ifdef CONFIG_CFG80211_WEXT
81 if (wdev->netdev && !request->aborted) { 109 if (wdev->netdev && !request->aborted) {
@@ -126,16 +154,27 @@ EXPORT_SYMBOL(cfg80211_scan_done);
126void __cfg80211_sched_scan_results(struct work_struct *wk) 154void __cfg80211_sched_scan_results(struct work_struct *wk)
127{ 155{
128 struct cfg80211_registered_device *rdev; 156 struct cfg80211_registered_device *rdev;
157 struct cfg80211_sched_scan_request *request;
129 158
130 rdev = container_of(wk, struct cfg80211_registered_device, 159 rdev = container_of(wk, struct cfg80211_registered_device,
131 sched_scan_results_wk); 160 sched_scan_results_wk);
132 161
162 request = rdev->sched_scan_req;
163
133 mutex_lock(&rdev->sched_scan_mtx); 164 mutex_lock(&rdev->sched_scan_mtx);
134 165
135 /* we don't have sched_scan_req anymore if the scan is stopping */ 166 /* we don't have sched_scan_req anymore if the scan is stopping */
136 if (rdev->sched_scan_req) 167 if (request) {
137 nl80211_send_sched_scan_results(rdev, 168 if (request->flags & NL80211_SCAN_FLAG_FLUSH) {
138 rdev->sched_scan_req->dev); 169 /* flush entries from previous scans */
170 spin_lock_bh(&rdev->bss_lock);
171 __cfg80211_bss_expire(rdev, request->scan_start);
172 spin_unlock_bh(&rdev->bss_lock);
173 request->scan_start =
174 jiffies + msecs_to_jiffies(request->interval);
175 }
176 nl80211_send_sched_scan_results(rdev, request->dev);
177 }
139 178
140 mutex_unlock(&rdev->sched_scan_mtx); 179 mutex_unlock(&rdev->sched_scan_mtx);
141} 180}
@@ -197,23 +236,9 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev,
197 } 236 }
198} 237}
199 238
200/* must hold dev->bss_lock! */
201void cfg80211_bss_expire(struct cfg80211_registered_device *dev) 239void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
202{ 240{
203 struct cfg80211_internal_bss *bss, *tmp; 241 __cfg80211_bss_expire(dev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE);
204 bool expired = false;
205
206 list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
207 if (atomic_read(&bss->hold))
208 continue;
209 if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
210 continue;
211 __cfg80211_unlink_bss(dev, bss);
212 expired = true;
213 }
214
215 if (expired)
216 dev->bss_generation++;
217} 242}
218 243
219const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len) 244const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len)
@@ -962,6 +987,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
962 creq->ssids = (void *)&creq->channels[n_channels]; 987 creq->ssids = (void *)&creq->channels[n_channels];
963 creq->n_channels = n_channels; 988 creq->n_channels = n_channels;
964 creq->n_ssids = 1; 989 creq->n_ssids = 1;
990 creq->scan_start = jiffies;
965 991
966 /* translate "Scan on frequencies" request */ 992 /* translate "Scan on frequencies" request */
967 i = 0; 993 i = 0;
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 055d59643616..07d717eb9e2a 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -138,6 +138,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
138 138
139 request->wdev = wdev; 139 request->wdev = wdev;
140 request->wiphy = &rdev->wiphy; 140 request->wiphy = &rdev->wiphy;
141 request->scan_start = jiffies;
141 142
142 rdev->scan_req = request; 143 rdev->scan_req = request;
143 144