aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-04-23 10:01:47 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-05-06 15:14:31 -0400
commitf3b85252f081581a8f257545ed748062dce7798b (patch)
tree899a804545850c7e1b1e3eea5c743df2c8cddf3d
parent2d72289095e9621158acf1d59a830cfe920fa93b (diff)
mac80211: fix scan races and rework scanning
There are some places marked /* XXX maybe racy? */ and they really are racy because there's no locking. This patch reworks much of the scan code, and introduces proper locking for the scan request as well as the internal scanning (which is necessary for IBSS/managed modes). Helper functions are added to call the scanning code whenever necessary. The scan deferring is changed to simply queue the scanning work instead of trying to start the scan in place, the scanning work will then take care of the rest. Also, currently when internal scans are requested for an interface that is trying to associate, we reject such scans. This was not intended, the mlme code has provisions to scan twice when it can't find the BSS to associate with right away; this has never worked properly. Fix this by not rejecting internal scan requests for an interface that is associating. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--net/mac80211/ibss.c22
-rw-r--r--net/mac80211/ieee80211_i.h6
-rw-r--r--net/mac80211/main.c2
-rw-r--r--net/mac80211/mlme.c28
-rw-r--r--net/mac80211/scan.c387
5 files changed, 229 insertions, 216 deletions
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 9fe1f937e0b4..25ff583612ef 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -432,15 +432,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
432 printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " 432 printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
433 "IBSS networks with same SSID (merge)\n", sdata->dev->name); 433 "IBSS networks with same SSID (merge)\n", sdata->dev->name);
434 434
435 /* XXX maybe racy? */ 435 ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len);
436 if (sdata->local->scan_req)
437 return;
438
439 memcpy(sdata->local->int_scan_req.ssids[0].ssid,
440 ifibss->ssid, IEEE80211_MAX_SSID_LEN);
441 sdata->local->int_scan_req.ssids[0].ssid_len = ifibss->ssid_len;
442 if (ieee80211_request_scan(sdata, &sdata->local->int_scan_req))
443 ieee80211_scan_failed(sdata->local);
444} 436}
445 437
446static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) 438static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
@@ -553,16 +545,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
553 printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " 545 printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
554 "join\n", sdata->dev->name); 546 "join\n", sdata->dev->name);
555 547
556 /* XXX maybe racy? */ 548 ieee80211_request_internal_scan(sdata, ifibss->ssid,
557 if (local->scan_req) 549 ifibss->ssid_len);
558 return;
559
560 memcpy(local->int_scan_req.ssids[0].ssid,
561 ifibss->ssid, IEEE80211_MAX_SSID_LEN);
562 local->int_scan_req.ssids[0].ssid_len =
563 ifibss->ssid_len;
564 if (ieee80211_request_scan(sdata, &local->int_scan_req))
565 ieee80211_scan_failed(local);
566 } else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) { 550 } else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) {
567 int interval = IEEE80211_SCAN_INTERVAL; 551 int interval = IEEE80211_SCAN_INTERVAL;
568 552
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 1579bc92c88d..e6fd4bcf1c3c 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -659,6 +659,7 @@ struct ieee80211_local {
659 659
660 660
661 /* Scanning and BSS list */ 661 /* Scanning and BSS list */
662 struct mutex scan_mtx;
662 bool sw_scanning, hw_scanning; 663 bool sw_scanning, hw_scanning;
663 struct cfg80211_ssid scan_ssid; 664 struct cfg80211_ssid scan_ssid;
664 struct cfg80211_scan_request int_scan_req; 665 struct cfg80211_scan_request int_scan_req;
@@ -947,6 +948,8 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata);
947 948
948/* scan/BSS handling */ 949/* scan/BSS handling */
949void ieee80211_scan_work(struct work_struct *work); 950void ieee80211_scan_work(struct work_struct *work);
951int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
952 const u8 *ssid, u8 ssid_len);
950int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, 953int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
951 struct cfg80211_scan_request *req); 954 struct cfg80211_scan_request *req);
952int ieee80211_scan_results(struct ieee80211_local *local, 955int ieee80211_scan_results(struct ieee80211_local *local,
@@ -960,9 +963,6 @@ int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata,
960 const char *ie, size_t len); 963 const char *ie, size_t len);
961 964
962void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); 965void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local);
963void ieee80211_scan_failed(struct ieee80211_local *local);
964int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
965 struct cfg80211_scan_request *req);
966struct ieee80211_bss * 966struct ieee80211_bss *
967ieee80211_bss_info_update(struct ieee80211_local *local, 967ieee80211_bss_info_update(struct ieee80211_local *local,
968 struct ieee80211_rx_status *rx_status, 968 struct ieee80211_rx_status *rx_status,
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 5ca62ea15079..e00d124e4ef7 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -783,6 +783,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
783 783
784 INIT_LIST_HEAD(&local->interfaces); 784 INIT_LIST_HEAD(&local->interfaces);
785 mutex_init(&local->iflist_mtx); 785 mutex_init(&local->iflist_mtx);
786 mutex_init(&local->scan_mtx);
786 787
787 spin_lock_init(&local->key_lock); 788 spin_lock_init(&local->key_lock);
788 789
@@ -1126,6 +1127,7 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
1126 struct ieee80211_local *local = hw_to_local(hw); 1127 struct ieee80211_local *local = hw_to_local(hw);
1127 1128
1128 mutex_destroy(&local->iflist_mtx); 1129 mutex_destroy(&local->iflist_mtx);
1130 mutex_destroy(&local->scan_mtx);
1129 1131
1130 wiphy_free(local->hw.wiphy); 1132 wiphy_free(local->hw.wiphy);
1131} 1133}
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index f8925ca7c8f0..a2f5e6223059 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2072,19 +2072,15 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata)
2072 return 0; 2072 return 0;
2073 } else { 2073 } else {
2074 if (ifmgd->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { 2074 if (ifmgd->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) {
2075 u8 ssid_len = 0;
2076
2077 if (!(ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL))
2078 ssid_len = ifmgd->ssid_len;
2079
2075 ifmgd->assoc_scan_tries++; 2080 ifmgd->assoc_scan_tries++;
2076 /* XXX maybe racy? */
2077 if (local->scan_req)
2078 return -1;
2079 memcpy(local->int_scan_req.ssids[0].ssid,
2080 ifmgd->ssid, IEEE80211_MAX_SSID_LEN);
2081 if (ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL)
2082 local->int_scan_req.ssids[0].ssid_len = 0;
2083 else
2084 local->int_scan_req.ssids[0].ssid_len = ifmgd->ssid_len;
2085 2081
2086 if (ieee80211_start_scan(sdata, &local->int_scan_req)) 2082 ieee80211_request_internal_scan(sdata, ifmgd->ssid,
2087 ieee80211_scan_failed(local); 2083 ssid_len);
2088 2084
2089 ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; 2085 ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE;
2090 set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); 2086 set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request);
@@ -2122,14 +2118,8 @@ static void ieee80211_sta_work(struct work_struct *work)
2122 ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE && 2118 ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE &&
2123 ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE && 2119 ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE &&
2124 test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) { 2120 test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) {
2125 /* 2121 queue_delayed_work(local->hw.workqueue, &local->scan_work,
2126 * The call to ieee80211_start_scan can fail but ieee80211_request_scan 2122 round_jiffies_relative(0));
2127 * (which queued ieee80211_sta_work) did not return an error. Thus, call
2128 * ieee80211_scan_failed here if ieee80211_start_scan fails in order to
2129 * notify the scan requester.
2130 */
2131 if (ieee80211_start_scan(sdata, local->scan_req))
2132 ieee80211_scan_failed(local);
2133 return; 2123 return;
2134 } 2124 }
2135 2125
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index f25b07feabf9..086d21645cbc 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -202,18 +202,6 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
202 return RX_QUEUED; 202 return RX_QUEUED;
203} 203}
204 204
205void ieee80211_scan_failed(struct ieee80211_local *local)
206{
207 if (WARN_ON(!local->scan_req))
208 return;
209
210 /* notify cfg80211 about the failed scan */
211 if (local->scan_req != &local->int_scan_req)
212 cfg80211_scan_done(local->scan_req, true);
213
214 local->scan_req = NULL;
215}
216
217/* 205/*
218 * inform AP that we will go to sleep so that it will buffer the frames 206 * inform AP that we will go to sleep so that it will buffer the frames
219 * while we scan 207 * while we scan
@@ -274,29 +262,46 @@ static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata)
274 } 262 }
275} 263}
276 264
265static void ieee80211_restore_scan_ies(struct ieee80211_local *local)
266{
267 kfree(local->scan_req->ie);
268 local->scan_req->ie = local->orig_ies;
269 local->scan_req->ie_len = local->orig_ies_len;
270}
271
277void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) 272void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
278{ 273{
279 struct ieee80211_local *local = hw_to_local(hw); 274 struct ieee80211_local *local = hw_to_local(hw);
280 struct ieee80211_sub_if_data *sdata; 275 struct ieee80211_sub_if_data *sdata;
276 bool was_hw_scan;
281 277
282 if (WARN_ON(!local->hw_scanning && !local->sw_scanning)) 278 mutex_lock(&local->scan_mtx);
283 return;
284 279
285 if (WARN_ON(!local->scan_req)) 280 if (WARN_ON(!local->hw_scanning && !local->sw_scanning)) {
281 mutex_unlock(&local->scan_mtx);
286 return; 282 return;
283 }
287 284
288 if (local->hw_scanning) { 285 if (WARN_ON(!local->scan_req)) {
289 kfree(local->scan_req->ie); 286 mutex_unlock(&local->scan_mtx);
290 local->scan_req->ie = local->orig_ies; 287 return;
291 local->scan_req->ie_len = local->orig_ies_len;
292 } 288 }
293 289
290 if (local->hw_scanning)
291 ieee80211_restore_scan_ies(local);
292
294 if (local->scan_req != &local->int_scan_req) 293 if (local->scan_req != &local->int_scan_req)
295 cfg80211_scan_done(local->scan_req, aborted); 294 cfg80211_scan_done(local->scan_req, aborted);
296 local->scan_req = NULL; 295 local->scan_req = NULL;
297 296
298 if (local->hw_scanning) { 297 was_hw_scan = local->hw_scanning;
299 local->hw_scanning = false; 298 local->hw_scanning = false;
299 local->sw_scanning = false;
300
301 /* we only have to protect scan_req and hw/sw scan */
302 mutex_unlock(&local->scan_mtx);
303
304 if (was_hw_scan) {
300 /* 305 /*
301 * Somebody might have requested channel change during scan 306 * Somebody might have requested channel change during scan
302 * that we won't have acted upon, try now. ieee80211_hw_config 307 * that we won't have acted upon, try now. ieee80211_hw_config
@@ -306,7 +311,6 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
306 goto done; 311 goto done;
307 } 312 }
308 313
309 local->sw_scanning = false;
310 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); 314 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
311 315
312 netif_tx_lock_bh(local->mdev); 316 netif_tx_lock_bh(local->mdev);
@@ -354,6 +358,146 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
354} 358}
355EXPORT_SYMBOL(ieee80211_scan_completed); 359EXPORT_SYMBOL(ieee80211_scan_completed);
356 360
361static int ieee80211_start_sw_scan(struct ieee80211_local *local)
362{
363 struct ieee80211_sub_if_data *sdata;
364
365 /*
366 * Hardware/driver doesn't support hw_scan, so use software
367 * scanning instead. First send a nullfunc frame with power save
368 * bit on so that AP will buffer the frames for us while we are not
369 * listening, then send probe requests to each channel and wait for
370 * the responses. After all channels are scanned, tune back to the
371 * original channel and send a nullfunc frame with power save bit
372 * off to trigger the AP to send us all the buffered frames.
373 *
374 * Note that while local->sw_scanning is true everything else but
375 * nullfunc frames and probe requests will be dropped in
376 * ieee80211_tx_h_check_assoc().
377 */
378 if (local->ops->sw_scan_start)
379 local->ops->sw_scan_start(local_to_hw(local));
380
381 mutex_lock(&local->iflist_mtx);
382 list_for_each_entry(sdata, &local->interfaces, list) {
383 if (!netif_running(sdata->dev))
384 continue;
385
386 /* disable beaconing */
387 if (sdata->vif.type == NL80211_IFTYPE_AP ||
388 sdata->vif.type == NL80211_IFTYPE_ADHOC ||
389 sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
390 ieee80211_if_config(sdata,
391 IEEE80211_IFCC_BEACON_ENABLED);
392
393 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
394 if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
395 netif_tx_stop_all_queues(sdata->dev);
396 ieee80211_scan_ps_enable(sdata);
397 }
398 } else
399 netif_tx_stop_all_queues(sdata->dev);
400 }
401 mutex_unlock(&local->iflist_mtx);
402
403 local->scan_state = SCAN_SET_CHANNEL;
404 local->scan_channel_idx = 0;
405
406 netif_addr_lock_bh(local->mdev);
407 local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
408 local->ops->configure_filter(local_to_hw(local),
409 FIF_BCN_PRBRESP_PROMISC,
410 &local->filter_flags,
411 local->mdev->mc_count,
412 local->mdev->mc_list);
413 netif_addr_unlock_bh(local->mdev);
414
415 /* TODO: start scan as soon as all nullfunc frames are ACKed */
416 queue_delayed_work(local->hw.workqueue, &local->scan_work,
417 IEEE80211_CHANNEL_TIME);
418
419 return 0;
420}
421
422
423static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
424 struct cfg80211_scan_request *req)
425{
426 struct ieee80211_local *local = sdata->local;
427 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
428 int rc;
429
430 if (local->scan_req)
431 return -EBUSY;
432
433 if (local->ops->hw_scan) {
434 u8 *ies;
435 int ielen;
436
437 ies = kmalloc(2 + IEEE80211_MAX_SSID_LEN +
438 local->scan_ies_len + req->ie_len, GFP_KERNEL);
439 if (!ies)
440 return -ENOMEM;
441
442 ielen = ieee80211_build_preq_ies(local, ies,
443 req->ie, req->ie_len);
444 local->orig_ies = req->ie;
445 local->orig_ies_len = req->ie_len;
446 req->ie = ies;
447 req->ie_len = ielen;
448 }
449
450 local->scan_req = req;
451 local->scan_sdata = sdata;
452
453 if (req != &local->int_scan_req &&
454 sdata->vif.type == NL80211_IFTYPE_STATION &&
455 (ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE ||
456 ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE ||
457 ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE)) {
458 /* actually wait for the assoc to finish/time out */
459 set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request);
460 return 0;
461 }
462
463 if (local->ops->hw_scan)
464 local->hw_scanning = true;
465 else
466 local->sw_scanning = true;
467 /*
468 * Kicking off the scan need not be protected,
469 * only the scan variable stuff, since now
470 * local->scan_req is assigned and other callers
471 * will abort their scan attempts.
472 *
473 * This avoids getting a scan_mtx -> iflist_mtx
474 * dependency, so that the scan completed calls
475 * have more locking freedom.
476 */
477 mutex_unlock(&local->scan_mtx);
478
479 if (local->ops->hw_scan)
480 rc = local->ops->hw_scan(local_to_hw(local),
481 local->scan_req);
482 else
483 rc = ieee80211_start_sw_scan(local);
484
485 mutex_lock(&local->scan_mtx);
486
487 if (rc) {
488 if (local->ops->hw_scan) {
489 local->hw_scanning = false;
490 ieee80211_restore_scan_ies(local);
491 } else
492 local->sw_scanning = false;
493
494 local->scan_req = NULL;
495 local->scan_sdata = NULL;
496 }
497
498 return rc;
499}
500
357void ieee80211_scan_work(struct work_struct *work) 501void ieee80211_scan_work(struct work_struct *work)
358{ 502{
359 struct ieee80211_local *local = 503 struct ieee80211_local *local =
@@ -363,17 +507,41 @@ void ieee80211_scan_work(struct work_struct *work)
363 int skip, i; 507 int skip, i;
364 unsigned long next_delay = 0; 508 unsigned long next_delay = 0;
365 509
510 mutex_lock(&local->scan_mtx);
511 if (!sdata || !local->scan_req) {
512 mutex_unlock(&local->scan_mtx);
513 return;
514 }
515
516 if (local->scan_req && !(local->sw_scanning || local->hw_scanning)) {
517 struct cfg80211_scan_request *req = local->scan_req;
518 int rc;
519
520 local->scan_req = NULL;
521
522 rc = __ieee80211_start_scan(sdata, req);
523 mutex_unlock(&local->scan_mtx);
524
525 if (rc)
526 ieee80211_scan_completed(&local->hw, true);
527 return;
528 }
529
530 mutex_unlock(&local->scan_mtx);
531
366 /* 532 /*
367 * Avoid re-scheduling when the sdata is going away. 533 * Avoid re-scheduling when the sdata is going away.
368 */ 534 */
369 if (!netif_running(sdata->dev)) 535 if (!netif_running(sdata->dev)) {
536 ieee80211_scan_completed(&local->hw, true);
370 return; 537 return;
538 }
371 539
372 switch (local->scan_state) { 540 switch (local->scan_state) {
373 case SCAN_SET_CHANNEL: 541 case SCAN_SET_CHANNEL:
374 /* if no more bands/channels left, complete scan */ 542 /* if no more bands/channels left, complete scan */
375 if (local->scan_channel_idx >= local->scan_req->n_channels) { 543 if (local->scan_channel_idx >= local->scan_req->n_channels) {
376 ieee80211_scan_completed(local_to_hw(local), false); 544 ieee80211_scan_completed(&local->hw, false);
377 return; 545 return;
378 } 546 }
379 skip = 0; 547 skip = 0;
@@ -422,166 +590,35 @@ void ieee80211_scan_work(struct work_struct *work)
422 next_delay); 590 next_delay);
423} 591}
424 592
425 593int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
426int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, 594 struct cfg80211_scan_request *req)
427 struct cfg80211_scan_request *req)
428{ 595{
429 struct ieee80211_local *local = scan_sdata->local; 596 int res;
430 struct ieee80211_sub_if_data *sdata;
431
432 if (!req)
433 return -EINVAL;
434
435 if (local->scan_req && local->scan_req != req)
436 return -EBUSY;
437
438 local->scan_req = req;
439
440 /* MLME-SCAN.request (page 118) page 144 (11.1.3.1)
441 * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS
442 * BSSID: MACAddress
443 * SSID
444 * ScanType: ACTIVE, PASSIVE
445 * ProbeDelay: delay (in microseconds) to be used prior to transmitting
446 * a Probe frame during active scanning
447 * ChannelList
448 * MinChannelTime (>= ProbeDelay), in TU
449 * MaxChannelTime: (>= MinChannelTime), in TU
450 */
451
452 /* MLME-SCAN.confirm
453 * BSSDescriptionSet
454 * ResultCode: SUCCESS, INVALID_PARAMETERS
455 */
456
457 if (local->sw_scanning || local->hw_scanning) {
458 if (local->scan_sdata == scan_sdata)
459 return 0;
460 return -EBUSY;
461 }
462
463 if (local->ops->hw_scan) {
464 u8 *ies;
465 int rc, ielen;
466
467 ies = kmalloc(2 + IEEE80211_MAX_SSID_LEN +
468 local->scan_ies_len + req->ie_len, GFP_KERNEL);
469 if (!ies)
470 return -ENOMEM;
471 597
472 ielen = ieee80211_build_preq_ies(local, ies, 598 mutex_lock(&sdata->local->scan_mtx);
473 req->ie, req->ie_len); 599 res = __ieee80211_start_scan(sdata, req);
474 local->orig_ies = req->ie; 600 mutex_unlock(&sdata->local->scan_mtx);
475 local->orig_ies_len = req->ie_len;
476 req->ie = ies;
477 req->ie_len = ielen;
478
479 local->hw_scanning = true;
480 rc = local->ops->hw_scan(local_to_hw(local), req);
481 if (rc) {
482 local->hw_scanning = false;
483 kfree(ies);
484 req->ie_len = local->orig_ies_len;
485 req->ie = local->orig_ies;
486 return rc;
487 }
488 local->scan_sdata = scan_sdata;
489 return 0;
490 }
491 601
492 /* 602 return res;
493 * Hardware/driver doesn't support hw_scan, so use software
494 * scanning instead. First send a nullfunc frame with power save
495 * bit on so that AP will buffer the frames for us while we are not
496 * listening, then send probe requests to each channel and wait for
497 * the responses. After all channels are scanned, tune back to the
498 * original channel and send a nullfunc frame with power save bit
499 * off to trigger the AP to send us all the buffered frames.
500 *
501 * Note that while local->sw_scanning is true everything else but
502 * nullfunc frames and probe requests will be dropped in
503 * ieee80211_tx_h_check_assoc().
504 */
505 local->sw_scanning = true;
506 if (local->ops->sw_scan_start)
507 local->ops->sw_scan_start(local_to_hw(local));
508
509 mutex_lock(&local->iflist_mtx);
510 list_for_each_entry(sdata, &local->interfaces, list) {
511 if (!netif_running(sdata->dev))
512 continue;
513
514 /* disable beaconing */
515 if (sdata->vif.type == NL80211_IFTYPE_AP ||
516 sdata->vif.type == NL80211_IFTYPE_ADHOC ||
517 sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
518 ieee80211_if_config(sdata,
519 IEEE80211_IFCC_BEACON_ENABLED);
520
521 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
522 if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
523 netif_tx_stop_all_queues(sdata->dev);
524 ieee80211_scan_ps_enable(sdata);
525 }
526 } else
527 netif_tx_stop_all_queues(sdata->dev);
528 }
529 mutex_unlock(&local->iflist_mtx);
530
531 local->scan_state = SCAN_SET_CHANNEL;
532 local->scan_channel_idx = 0;
533 local->scan_sdata = scan_sdata;
534 local->scan_req = req;
535
536 netif_addr_lock_bh(local->mdev);
537 local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
538 local->ops->configure_filter(local_to_hw(local),
539 FIF_BCN_PRBRESP_PROMISC,
540 &local->filter_flags,
541 local->mdev->mc_count,
542 local->mdev->mc_list);
543 netif_addr_unlock_bh(local->mdev);
544
545 /* TODO: start scan as soon as all nullfunc frames are ACKed */
546 queue_delayed_work(local->hw.workqueue, &local->scan_work,
547 IEEE80211_CHANNEL_TIME);
548
549 return 0;
550} 603}
551 604
552 605int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
553int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, 606 const u8 *ssid, u8 ssid_len)
554 struct cfg80211_scan_request *req)
555{ 607{
556 struct ieee80211_local *local = sdata->local; 608 struct ieee80211_local *local = sdata->local;
557 struct ieee80211_if_managed *ifmgd; 609 int ret = -EBUSY;
558
559 if (!req)
560 return -EINVAL;
561
562 if (local->scan_req && local->scan_req != req)
563 return -EBUSY;
564
565 local->scan_req = req;
566 610
567 if (sdata->vif.type != NL80211_IFTYPE_STATION) 611 mutex_lock(&local->scan_mtx);
568 return ieee80211_start_scan(sdata, req);
569 612
570 /* 613 /* busy scanning */
571 * STA has a state machine that might need to defer scanning 614 if (local->scan_req)
572 * while it's trying to associate/authenticate, therefore we 615 goto unlock;
573 * queue it up to the state machine in that case.
574 */
575 616
576 if (local->sw_scanning || local->hw_scanning) { 617 memcpy(local->int_scan_req.ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN);
577 if (local->scan_sdata == sdata) 618 local->int_scan_req.ssids[0].ssid_len = ssid_len;
578 return 0;
579 return -EBUSY;
580 }
581
582 ifmgd = &sdata->u.mgd;
583 set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request);
584 queue_work(local->hw.workqueue, &ifmgd->work);
585 619
586 return 0; 620 ret = __ieee80211_start_scan(sdata, &sdata->local->int_scan_req);
621 unlock:
622 mutex_unlock(&local->scan_mtx);
623 return ret;
587} 624}