aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/scan.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-07-30 03:13:03 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-07-30 03:13:03 -0400
commitfcb06702f023a0e7b1e6ebf9746f34b610ca0508 (patch)
treedb022324c4978dd9af059be38822d23455a45f55 /net/mac80211/scan.c
parent5e31fc0815a4e2c72b1b495fe7a0d8f9bfb9e4b4 (diff)
parent9dbf5f55f8d35ff9aedc75267f4e4042aaf89755 (diff)
Merge remote-tracking branch 'wireless/master' into mac80211
Diffstat (limited to 'net/mac80211/scan.c')
-rw-r--r--net/mac80211/scan.c123
1 files changed, 65 insertions, 58 deletions
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 7644181cb6b4..df36280ed78f 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -83,13 +83,14 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
83 83
84 cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel, 84 cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel,
85 mgmt, len, signal, GFP_ATOMIC); 85 mgmt, len, signal, GFP_ATOMIC);
86
87 if (!cbss) 86 if (!cbss)
88 return NULL; 87 return NULL;
89 88
90 cbss->free_priv = ieee80211_rx_bss_free; 89 cbss->free_priv = ieee80211_rx_bss_free;
91 bss = (void *)cbss->priv; 90 bss = (void *)cbss->priv;
92 91
92 bss->device_ts = rx_status->device_timestamp;
93
93 if (elems->parse_error) { 94 if (elems->parse_error) {
94 if (beacon) 95 if (beacon)
95 bss->corrupt_data |= IEEE80211_BSS_CORRUPT_BEACON; 96 bss->corrupt_data |= IEEE80211_BSS_CORRUPT_BEACON;
@@ -114,8 +115,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
114 115
115 if (elems->tim && (!elems->parse_error || 116 if (elems->tim && (!elems->parse_error ||
116 !(bss->valid_data & IEEE80211_BSS_VALID_DTIM))) { 117 !(bss->valid_data & IEEE80211_BSS_VALID_DTIM))) {
117 struct ieee80211_tim_ie *tim_ie = 118 struct ieee80211_tim_ie *tim_ie = elems->tim;
118 (struct ieee80211_tim_ie *)elems->tim;
119 bss->dtim_period = tim_ie->dtim_period; 119 bss->dtim_period = tim_ie->dtim_period;
120 if (!elems->parse_error) 120 if (!elems->parse_error)
121 bss->valid_data |= IEEE80211_BSS_VALID_DTIM; 121 bss->valid_data |= IEEE80211_BSS_VALID_DTIM;
@@ -165,52 +165,47 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
165 return bss; 165 return bss;
166} 166}
167 167
168ieee80211_rx_result 168void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
169ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
170{ 169{
171 struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); 170 struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
172 struct ieee80211_mgmt *mgmt; 171 struct ieee80211_sub_if_data *sdata1, *sdata2;
172 struct ieee80211_mgmt *mgmt = (void *)skb->data;
173 struct ieee80211_bss *bss; 173 struct ieee80211_bss *bss;
174 u8 *elements; 174 u8 *elements;
175 struct ieee80211_channel *channel; 175 struct ieee80211_channel *channel;
176 size_t baselen; 176 size_t baselen;
177 int freq; 177 int freq;
178 __le16 fc; 178 bool beacon;
179 bool presp, beacon = false;
180 struct ieee802_11_elems elems; 179 struct ieee802_11_elems elems;
181 180
182 if (skb->len < 2) 181 if (skb->len < 24 ||
183 return RX_DROP_UNUSABLE; 182 (!ieee80211_is_probe_resp(mgmt->frame_control) &&
184 183 !ieee80211_is_beacon(mgmt->frame_control)))
185 mgmt = (struct ieee80211_mgmt *) skb->data; 184 return;
186 fc = mgmt->frame_control;
187 185
188 if (ieee80211_is_ctl(fc)) 186 sdata1 = rcu_dereference(local->scan_sdata);
189 return RX_CONTINUE; 187 sdata2 = rcu_dereference(local->sched_scan_sdata);
190 188
191 if (skb->len < 24) 189 if (likely(!sdata1 && !sdata2))
192 return RX_CONTINUE; 190 return;
193 191
194 presp = ieee80211_is_probe_resp(fc); 192 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
195 if (presp) {
196 /* ignore ProbeResp to foreign address */ 193 /* ignore ProbeResp to foreign address */
197 if (!ether_addr_equal(mgmt->da, sdata->vif.addr)) 194 if ((!sdata1 || !ether_addr_equal(mgmt->da, sdata1->vif.addr)) &&
198 return RX_DROP_MONITOR; 195 (!sdata2 || !ether_addr_equal(mgmt->da, sdata2->vif.addr)))
196 return;
199 197
200 presp = true;
201 elements = mgmt->u.probe_resp.variable; 198 elements = mgmt->u.probe_resp.variable;
202 baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); 199 baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
200 beacon = false;
203 } else { 201 } else {
204 beacon = ieee80211_is_beacon(fc);
205 baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable); 202 baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
206 elements = mgmt->u.beacon.variable; 203 elements = mgmt->u.beacon.variable;
204 beacon = true;
207 } 205 }
208 206
209 if (!presp && !beacon)
210 return RX_CONTINUE;
211
212 if (baselen > skb->len) 207 if (baselen > skb->len)
213 return RX_DROP_MONITOR; 208 return;
214 209
215 ieee802_11_parse_elems(elements, skb->len - baselen, &elems); 210 ieee802_11_parse_elems(elements, skb->len - baselen, &elems);
216 211
@@ -220,22 +215,16 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
220 else 215 else
221 freq = rx_status->freq; 216 freq = rx_status->freq;
222 217
223 channel = ieee80211_get_channel(sdata->local->hw.wiphy, freq); 218 channel = ieee80211_get_channel(local->hw.wiphy, freq);
224 219
225 if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) 220 if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
226 return RX_DROP_MONITOR; 221 return;
227 222
228 bss = ieee80211_bss_info_update(sdata->local, rx_status, 223 bss = ieee80211_bss_info_update(local, rx_status,
229 mgmt, skb->len, &elems, 224 mgmt, skb->len, &elems,
230 channel, beacon); 225 channel, beacon);
231 if (bss) 226 if (bss)
232 ieee80211_rx_bss_put(sdata->local, bss); 227 ieee80211_rx_bss_put(local, bss);
233
234 if (channel == sdata->local->oper_channel)
235 return RX_CONTINUE;
236
237 dev_kfree_skb(skb);
238 return RX_QUEUED;
239} 228}
240 229
241/* return false if no more work */ 230/* return false if no more work */
@@ -293,7 +282,13 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
293 return; 282 return;
294 283
295 if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { 284 if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) {
296 int rc = drv_hw_scan(local, local->scan_sdata, local->hw_scan_req); 285 int rc;
286
287 rc = drv_hw_scan(local,
288 rcu_dereference_protected(local->scan_sdata,
289 lockdep_is_held(&local->mtx)),
290 local->hw_scan_req);
291
297 if (rc == 0) 292 if (rc == 0)
298 return; 293 return;
299 } 294 }
@@ -323,7 +318,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
323 ieee80211_mlme_notify_scan_completed(local); 318 ieee80211_mlme_notify_scan_completed(local);
324 ieee80211_ibss_notify_scan_completed(local); 319 ieee80211_ibss_notify_scan_completed(local);
325 ieee80211_mesh_notify_scan_completed(local); 320 ieee80211_mesh_notify_scan_completed(local);
326 ieee80211_queue_work(&local->hw, &local->work_work); 321 ieee80211_start_next_roc(local);
327} 322}
328 323
329void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) 324void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
@@ -376,7 +371,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
376static bool ieee80211_can_scan(struct ieee80211_local *local, 371static bool ieee80211_can_scan(struct ieee80211_local *local,
377 struct ieee80211_sub_if_data *sdata) 372 struct ieee80211_sub_if_data *sdata)
378{ 373{
379 if (!list_empty(&local->work_list)) 374 if (!list_empty(&local->roc_list))
380 return false; 375 return false;
381 376
382 if (sdata->vif.type == NL80211_IFTYPE_STATION && 377 if (sdata->vif.type == NL80211_IFTYPE_STATION &&
@@ -394,7 +389,10 @@ void ieee80211_run_deferred_scan(struct ieee80211_local *local)
394 if (!local->scan_req || local->scanning) 389 if (!local->scan_req || local->scanning)
395 return; 390 return;
396 391
397 if (!ieee80211_can_scan(local, local->scan_sdata)) 392 if (!ieee80211_can_scan(local,
393 rcu_dereference_protected(
394 local->scan_sdata,
395 lockdep_is_held(&local->mtx))))
398 return; 396 return;
399 397
400 ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 398 ieee80211_queue_delayed_work(&local->hw, &local->scan_work,
@@ -405,9 +403,12 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
405 unsigned long *next_delay) 403 unsigned long *next_delay)
406{ 404{
407 int i; 405 int i;
408 struct ieee80211_sub_if_data *sdata = local->scan_sdata; 406 struct ieee80211_sub_if_data *sdata;
409 enum ieee80211_band band = local->hw.conf.channel->band; 407 enum ieee80211_band band = local->hw.conf.channel->band;
410 408
409 sdata = rcu_dereference_protected(local->scan_sdata,
410 lockdep_is_held(&local->mtx));;
411
411 for (i = 0; i < local->scan_req->n_ssids; i++) 412 for (i = 0; i < local->scan_req->n_ssids; i++)
412 ieee80211_send_probe_req( 413 ieee80211_send_probe_req(
413 sdata, NULL, 414 sdata, NULL,
@@ -439,7 +440,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
439 if (!ieee80211_can_scan(local, sdata)) { 440 if (!ieee80211_can_scan(local, sdata)) {
440 /* wait for the work to finish/time out */ 441 /* wait for the work to finish/time out */
441 local->scan_req = req; 442 local->scan_req = req;
442 local->scan_sdata = sdata; 443 rcu_assign_pointer(local->scan_sdata, sdata);
443 return 0; 444 return 0;
444 } 445 }
445 446
@@ -473,7 +474,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
473 } 474 }
474 475
475 local->scan_req = req; 476 local->scan_req = req;
476 local->scan_sdata = sdata; 477 rcu_assign_pointer(local->scan_sdata, sdata);
477 478
478 if (local->ops->hw_scan) { 479 if (local->ops->hw_scan) {
479 __set_bit(SCAN_HW_SCANNING, &local->scanning); 480 __set_bit(SCAN_HW_SCANNING, &local->scanning);
@@ -533,7 +534,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
533 ieee80211_recalc_idle(local); 534 ieee80211_recalc_idle(local);
534 535
535 local->scan_req = NULL; 536 local->scan_req = NULL;
536 local->scan_sdata = NULL; 537 rcu_assign_pointer(local->scan_sdata, NULL);
537 } 538 }
538 539
539 return rc; 540 return rc;
@@ -720,7 +721,8 @@ void ieee80211_scan_work(struct work_struct *work)
720 721
721 mutex_lock(&local->mtx); 722 mutex_lock(&local->mtx);
722 723
723 sdata = local->scan_sdata; 724 sdata = rcu_dereference_protected(local->scan_sdata,
725 lockdep_is_held(&local->mtx));
724 726
725 /* When scanning on-channel, the first-callback means completed. */ 727 /* When scanning on-channel, the first-callback means completed. */
726 if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) { 728 if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) {
@@ -741,7 +743,7 @@ void ieee80211_scan_work(struct work_struct *work)
741 int rc; 743 int rc;
742 744
743 local->scan_req = NULL; 745 local->scan_req = NULL;
744 local->scan_sdata = NULL; 746 rcu_assign_pointer(local->scan_sdata, NULL);
745 747
746 rc = __ieee80211_start_scan(sdata, req); 748 rc = __ieee80211_start_scan(sdata, req);
747 if (rc) { 749 if (rc) {
@@ -893,7 +895,9 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
893 895
894 if (test_bit(SCAN_HW_SCANNING, &local->scanning)) { 896 if (test_bit(SCAN_HW_SCANNING, &local->scanning)) {
895 if (local->ops->cancel_hw_scan) 897 if (local->ops->cancel_hw_scan)
896 drv_cancel_hw_scan(local, local->scan_sdata); 898 drv_cancel_hw_scan(local,
899 rcu_dereference_protected(local->scan_sdata,
900 lockdep_is_held(&local->mtx)));
897 goto out; 901 goto out;
898 } 902 }
899 903
@@ -915,9 +919,9 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
915 struct ieee80211_local *local = sdata->local; 919 struct ieee80211_local *local = sdata->local;
916 int ret, i; 920 int ret, i;
917 921
918 mutex_lock(&sdata->local->mtx); 922 mutex_lock(&local->mtx);
919 923
920 if (local->sched_scanning) { 924 if (rcu_access_pointer(local->sched_scan_sdata)) {
921 ret = -EBUSY; 925 ret = -EBUSY;
922 goto out; 926 goto out;
923 } 927 }
@@ -928,6 +932,9 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
928 } 932 }
929 933
930 for (i = 0; i < IEEE80211_NUM_BANDS; i++) { 934 for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
935 if (!local->hw.wiphy->bands[i])
936 continue;
937
931 local->sched_scan_ies.ie[i] = kzalloc(2 + 938 local->sched_scan_ies.ie[i] = kzalloc(2 +
932 IEEE80211_MAX_SSID_LEN + 939 IEEE80211_MAX_SSID_LEN +
933 local->scan_ies_len + 940 local->scan_ies_len +
@@ -948,7 +955,7 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
948 ret = drv_sched_scan_start(local, sdata, req, 955 ret = drv_sched_scan_start(local, sdata, req,
949 &local->sched_scan_ies); 956 &local->sched_scan_ies);
950 if (ret == 0) { 957 if (ret == 0) {
951 local->sched_scanning = true; 958 rcu_assign_pointer(local->sched_scan_sdata, sdata);
952 goto out; 959 goto out;
953 } 960 }
954 961
@@ -956,7 +963,7 @@ out_free:
956 while (i > 0) 963 while (i > 0)
957 kfree(local->sched_scan_ies.ie[--i]); 964 kfree(local->sched_scan_ies.ie[--i]);
958out: 965out:
959 mutex_unlock(&sdata->local->mtx); 966 mutex_unlock(&local->mtx);
960 return ret; 967 return ret;
961} 968}
962 969
@@ -965,22 +972,22 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
965 struct ieee80211_local *local = sdata->local; 972 struct ieee80211_local *local = sdata->local;
966 int ret = 0, i; 973 int ret = 0, i;
967 974
968 mutex_lock(&sdata->local->mtx); 975 mutex_lock(&local->mtx);
969 976
970 if (!local->ops->sched_scan_stop) { 977 if (!local->ops->sched_scan_stop) {
971 ret = -ENOTSUPP; 978 ret = -ENOTSUPP;
972 goto out; 979 goto out;
973 } 980 }
974 981
975 if (local->sched_scanning) { 982 if (rcu_access_pointer(local->sched_scan_sdata)) {
976 for (i = 0; i < IEEE80211_NUM_BANDS; i++) 983 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
977 kfree(local->sched_scan_ies.ie[i]); 984 kfree(local->sched_scan_ies.ie[i]);
978 985
979 drv_sched_scan_stop(local, sdata); 986 drv_sched_scan_stop(local, sdata);
980 local->sched_scanning = false; 987 rcu_assign_pointer(local->sched_scan_sdata, NULL);
981 } 988 }
982out: 989out:
983 mutex_unlock(&sdata->local->mtx); 990 mutex_unlock(&local->mtx);
984 991
985 return ret; 992 return ret;
986} 993}
@@ -1004,7 +1011,7 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work)
1004 1011
1005 mutex_lock(&local->mtx); 1012 mutex_lock(&local->mtx);
1006 1013
1007 if (!local->sched_scanning) { 1014 if (!rcu_access_pointer(local->sched_scan_sdata)) {
1008 mutex_unlock(&local->mtx); 1015 mutex_unlock(&local->mtx);
1009 return; 1016 return;
1010 } 1017 }
@@ -1012,7 +1019,7 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work)
1012 for (i = 0; i < IEEE80211_NUM_BANDS; i++) 1019 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
1013 kfree(local->sched_scan_ies.ie[i]); 1020 kfree(local->sched_scan_ies.ie[i]);
1014 1021
1015 local->sched_scanning = false; 1022 rcu_assign_pointer(local->sched_scan_sdata, NULL);
1016 1023
1017 mutex_unlock(&local->mtx); 1024 mutex_unlock(&local->mtx);
1018 1025