diff options
Diffstat (limited to 'net/wireless/scan.c')
-rw-r--r-- | net/wireless/scan.c | 138 |
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 | ||
24 | static 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! */ | ||
43 | static 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! */ | ||
52 | static 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 | |||
23 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) | 72 | void ___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 | ||
90 | void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) | 146 | void 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); | |||
99 | void __cfg80211_sched_scan_results(struct work_struct *wk) | 156 | void __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 | ||
116 | void cfg80211_sched_scan_results(struct wiphy *wiphy) | 184 | void 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 | ||
161 | static 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! */ |
180 | void cfg80211_bss_age(struct cfg80211_registered_device *dev, | 233 | void 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! */ | ||
192 | static 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! */ | ||
201 | void cfg80211_bss_expire(struct cfg80211_registered_device *dev) | 244 | void 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 | ||
219 | const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len) | 249 | const 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 | } |
485 | EXPORT_SYMBOL(cfg80211_get_bss); | 519 | EXPORT_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 */ |