aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/scan.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/scan.c')
-rw-r--r--net/wireless/scan.c138
1 files changed, 89 insertions, 49 deletions
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 9730c9862bdc..7f97a087f452 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -17,9 +17,58 @@
17#include "core.h" 17#include "core.h"
18#include "nl80211.h" 18#include "nl80211.h"
19#include "wext-compat.h" 19#include "wext-compat.h"
20#include "rdev-ops.h"
20 21
21#define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ) 22#define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ)
22 23
24static void bss_release(struct kref *ref)
25{
26 struct cfg80211_internal_bss *bss;
27
28 bss = container_of(ref, struct cfg80211_internal_bss, ref);
29 if (bss->pub.free_priv)
30 bss->pub.free_priv(&bss->pub);
31
32 if (bss->beacon_ies_allocated)
33 kfree(bss->pub.beacon_ies);
34 if (bss->proberesp_ies_allocated)
35 kfree(bss->pub.proberesp_ies);
36
37 BUG_ON(atomic_read(&bss->hold));
38
39 kfree(bss);
40}
41
42/* must hold dev->bss_lock! */
43static void __cfg80211_unlink_bss(struct cfg80211_registered_device *dev,
44 struct cfg80211_internal_bss *bss)
45{
46 list_del_init(&bss->list);
47 rb_erase(&bss->rbn, &dev->bss_tree);
48 kref_put(&bss->ref, bss_release);
49}
50
51/* must hold dev->bss_lock! */
52static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev,
53 unsigned long expire_time)
54{
55 struct cfg80211_internal_bss *bss, *tmp;
56 bool expired = false;
57
58 list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
59 if (atomic_read(&bss->hold))
60 continue;
61 if (!time_after(expire_time, bss->ts))
62 continue;
63
64 __cfg80211_unlink_bss(dev, bss);
65 expired = true;
66 }
67
68 if (expired)
69 dev->bss_generation++;
70}
71
23void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) 72void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
24{ 73{
25 struct cfg80211_scan_request *request; 74 struct cfg80211_scan_request *request;
@@ -45,10 +94,17 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
45 if (wdev->netdev) 94 if (wdev->netdev)
46 cfg80211_sme_scan_done(wdev->netdev); 95 cfg80211_sme_scan_done(wdev->netdev);
47 96
48 if (request->aborted) 97 if (request->aborted) {
49 nl80211_send_scan_aborted(rdev, wdev); 98 nl80211_send_scan_aborted(rdev, wdev);
50 else 99 } else {
100 if (request->flags & NL80211_SCAN_FLAG_FLUSH) {
101 /* flush entries from previous scans */
102 spin_lock_bh(&rdev->bss_lock);
103 __cfg80211_bss_expire(rdev, request->scan_start);
104 spin_unlock_bh(&rdev->bss_lock);
105 }
51 nl80211_send_scan_done(rdev, wdev); 106 nl80211_send_scan_done(rdev, wdev);
107 }
52 108
53#ifdef CONFIG_CFG80211_WEXT 109#ifdef CONFIG_CFG80211_WEXT
54 if (wdev->netdev && !request->aborted) { 110 if (wdev->netdev && !request->aborted) {
@@ -89,6 +145,7 @@ void __cfg80211_scan_done(struct work_struct *wk)
89 145
90void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) 146void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
91{ 147{
148 trace_cfg80211_scan_done(request, aborted);
92 WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); 149 WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
93 150
94 request->aborted = aborted; 151 request->aborted = aborted;
@@ -99,22 +156,34 @@ EXPORT_SYMBOL(cfg80211_scan_done);
99void __cfg80211_sched_scan_results(struct work_struct *wk) 156void __cfg80211_sched_scan_results(struct work_struct *wk)
100{ 157{
101 struct cfg80211_registered_device *rdev; 158 struct cfg80211_registered_device *rdev;
159 struct cfg80211_sched_scan_request *request;
102 160
103 rdev = container_of(wk, struct cfg80211_registered_device, 161 rdev = container_of(wk, struct cfg80211_registered_device,
104 sched_scan_results_wk); 162 sched_scan_results_wk);
105 163
164 request = rdev->sched_scan_req;
165
106 mutex_lock(&rdev->sched_scan_mtx); 166 mutex_lock(&rdev->sched_scan_mtx);
107 167
108 /* we don't have sched_scan_req anymore if the scan is stopping */ 168 /* we don't have sched_scan_req anymore if the scan is stopping */
109 if (rdev->sched_scan_req) 169 if (request) {
110 nl80211_send_sched_scan_results(rdev, 170 if (request->flags & NL80211_SCAN_FLAG_FLUSH) {
111 rdev->sched_scan_req->dev); 171 /* flush entries from previous scans */
172 spin_lock_bh(&rdev->bss_lock);
173 __cfg80211_bss_expire(rdev, request->scan_start);
174 spin_unlock_bh(&rdev->bss_lock);
175 request->scan_start =
176 jiffies + msecs_to_jiffies(request->interval);
177 }
178 nl80211_send_sched_scan_results(rdev, request->dev);
179 }
112 180
113 mutex_unlock(&rdev->sched_scan_mtx); 181 mutex_unlock(&rdev->sched_scan_mtx);
114} 182}
115 183
116void cfg80211_sched_scan_results(struct wiphy *wiphy) 184void cfg80211_sched_scan_results(struct wiphy *wiphy)
117{ 185{
186 trace_cfg80211_sched_scan_results(wiphy);
118 /* ignore if we're not scanning */ 187 /* ignore if we're not scanning */
119 if (wiphy_to_dev(wiphy)->sched_scan_req) 188 if (wiphy_to_dev(wiphy)->sched_scan_req)
120 queue_work(cfg80211_wq, 189 queue_work(cfg80211_wq,
@@ -126,6 +195,8 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy)
126{ 195{
127 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 196 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
128 197
198 trace_cfg80211_sched_scan_stopped(wiphy);
199
129 mutex_lock(&rdev->sched_scan_mtx); 200 mutex_lock(&rdev->sched_scan_mtx);
130 __cfg80211_stop_sched_scan(rdev, true); 201 __cfg80211_stop_sched_scan(rdev, true);
131 mutex_unlock(&rdev->sched_scan_mtx); 202 mutex_unlock(&rdev->sched_scan_mtx);
@@ -145,7 +216,7 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
145 dev = rdev->sched_scan_req->dev; 216 dev = rdev->sched_scan_req->dev;
146 217
147 if (!driver_initiated) { 218 if (!driver_initiated) {
148 int err = rdev->ops->sched_scan_stop(&rdev->wiphy, dev); 219 int err = rdev_sched_scan_stop(rdev, dev);
149 if (err) 220 if (err)
150 return err; 221 return err;
151 } 222 }
@@ -158,24 +229,6 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
158 return 0; 229 return 0;
159} 230}
160 231
161static void bss_release(struct kref *ref)
162{
163 struct cfg80211_internal_bss *bss;
164
165 bss = container_of(ref, struct cfg80211_internal_bss, ref);
166 if (bss->pub.free_priv)
167 bss->pub.free_priv(&bss->pub);
168
169 if (bss->beacon_ies_allocated)
170 kfree(bss->pub.beacon_ies);
171 if (bss->proberesp_ies_allocated)
172 kfree(bss->pub.proberesp_ies);
173
174 BUG_ON(atomic_read(&bss->hold));
175
176 kfree(bss);
177}
178
179/* must hold dev->bss_lock! */ 232/* must hold dev->bss_lock! */
180void cfg80211_bss_age(struct cfg80211_registered_device *dev, 233void cfg80211_bss_age(struct cfg80211_registered_device *dev,
181 unsigned long age_secs) 234 unsigned long age_secs)
@@ -188,32 +241,9 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev,
188 } 241 }
189} 242}
190 243
191/* must hold dev->bss_lock! */
192static void __cfg80211_unlink_bss(struct cfg80211_registered_device *dev,
193 struct cfg80211_internal_bss *bss)
194{
195 list_del_init(&bss->list);
196 rb_erase(&bss->rbn, &dev->bss_tree);
197 kref_put(&bss->ref, bss_release);
198}
199
200/* must hold dev->bss_lock! */
201void cfg80211_bss_expire(struct cfg80211_registered_device *dev) 244void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
202{ 245{
203 struct cfg80211_internal_bss *bss, *tmp; 246 __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} 247}
218 248
219const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len) 249const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len)
@@ -459,6 +489,9 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
459 struct cfg80211_internal_bss *bss, *res = NULL; 489 struct cfg80211_internal_bss *bss, *res = NULL;
460 unsigned long now = jiffies; 490 unsigned long now = jiffies;
461 491
492 trace_cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, capa_mask,
493 capa_val);
494
462 spin_lock_bh(&dev->bss_lock); 495 spin_lock_bh(&dev->bss_lock);
463 496
464 list_for_each_entry(bss, &dev->bss_list, list) { 497 list_for_each_entry(bss, &dev->bss_list, list) {
@@ -480,6 +513,7 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
480 spin_unlock_bh(&dev->bss_lock); 513 spin_unlock_bh(&dev->bss_lock);
481 if (!res) 514 if (!res)
482 return NULL; 515 return NULL;
516 trace_cfg80211_return_bss(&res->pub);
483 return &res->pub; 517 return &res->pub;
484} 518}
485EXPORT_SYMBOL(cfg80211_get_bss); 519EXPORT_SYMBOL(cfg80211_get_bss);
@@ -792,6 +826,7 @@ cfg80211_inform_bss(struct wiphy *wiphy,
792 if (res->pub.capability & WLAN_CAPABILITY_ESS) 826 if (res->pub.capability & WLAN_CAPABILITY_ESS)
793 regulatory_hint_found_beacon(wiphy, channel, gfp); 827 regulatory_hint_found_beacon(wiphy, channel, gfp);
794 828
829 trace_cfg80211_return_bss(&res->pub);
795 /* cfg80211_bss_update gives us a referenced result */ 830 /* cfg80211_bss_update gives us a referenced result */
796 return &res->pub; 831 return &res->pub;
797} 832}
@@ -804,10 +839,13 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
804 s32 signal, gfp_t gfp) 839 s32 signal, gfp_t gfp)
805{ 840{
806 struct cfg80211_internal_bss *res; 841 struct cfg80211_internal_bss *res;
842
807 size_t ielen = len - offsetof(struct ieee80211_mgmt, 843 size_t ielen = len - offsetof(struct ieee80211_mgmt,
808 u.probe_resp.variable); 844 u.probe_resp.variable);
809 size_t privsz; 845 size_t privsz;
810 846
847 trace_cfg80211_inform_bss_frame(wiphy, channel, mgmt, len, signal);
848
811 if (WARN_ON(!mgmt)) 849 if (WARN_ON(!mgmt))
812 return NULL; 850 return NULL;
813 851
@@ -861,6 +899,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
861 if (res->pub.capability & WLAN_CAPABILITY_ESS) 899 if (res->pub.capability & WLAN_CAPABILITY_ESS)
862 regulatory_hint_found_beacon(wiphy, channel, gfp); 900 regulatory_hint_found_beacon(wiphy, channel, gfp);
863 901
902 trace_cfg80211_return_bss(&res->pub);
864 /* cfg80211_bss_update gives us a referenced result */ 903 /* cfg80211_bss_update gives us a referenced result */
865 return &res->pub; 904 return &res->pub;
866} 905}
@@ -962,6 +1001,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
962 creq->ssids = (void *)&creq->channels[n_channels]; 1001 creq->ssids = (void *)&creq->channels[n_channels];
963 creq->n_channels = n_channels; 1002 creq->n_channels = n_channels;
964 creq->n_ssids = 1; 1003 creq->n_ssids = 1;
1004 creq->scan_start = jiffies;
965 1005
966 /* translate "Scan on frequencies" request */ 1006 /* translate "Scan on frequencies" request */
967 i = 0; 1007 i = 0;
@@ -1026,7 +1066,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
1026 creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1; 1066 creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1;
1027 1067
1028 rdev->scan_req = creq; 1068 rdev->scan_req = creq;
1029 err = rdev->ops->scan(wiphy, creq); 1069 err = rdev_scan(rdev, creq);
1030 if (err) { 1070 if (err) {
1031 rdev->scan_req = NULL; 1071 rdev->scan_req = NULL;
1032 /* creq will be freed below */ 1072 /* creq will be freed below */