aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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}