diff options
Diffstat (limited to 'net/mac80211/scan.c')
-rw-r--r-- | net/mac80211/scan.c | 154 |
1 files changed, 86 insertions, 68 deletions
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 5171a9581631..fb274db77e3c 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -249,12 +249,12 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | |||
249 | return true; | 249 | return true; |
250 | } | 250 | } |
251 | 251 | ||
252 | static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | 252 | static bool __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, |
253 | bool was_hw_scan) | ||
253 | { | 254 | { |
254 | struct ieee80211_local *local = hw_to_local(hw); | 255 | struct ieee80211_local *local = hw_to_local(hw); |
255 | bool was_hw_scan; | ||
256 | 256 | ||
257 | mutex_lock(&local->mtx); | 257 | lockdep_assert_held(&local->mtx); |
258 | 258 | ||
259 | /* | 259 | /* |
260 | * It's ok to abort a not-yet-running scan (that | 260 | * It's ok to abort a not-yet-running scan (that |
@@ -265,17 +265,13 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
265 | if (WARN_ON(!local->scanning && !aborted)) | 265 | if (WARN_ON(!local->scanning && !aborted)) |
266 | aborted = true; | 266 | aborted = true; |
267 | 267 | ||
268 | if (WARN_ON(!local->scan_req)) { | 268 | if (WARN_ON(!local->scan_req)) |
269 | mutex_unlock(&local->mtx); | 269 | return false; |
270 | return; | ||
271 | } | ||
272 | 270 | ||
273 | was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); | ||
274 | if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { | 271 | if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { |
275 | ieee80211_queue_delayed_work(&local->hw, | 272 | int rc = drv_hw_scan(local, local->scan_sdata, local->hw_scan_req); |
276 | &local->scan_work, 0); | 273 | if (rc == 0) |
277 | mutex_unlock(&local->mtx); | 274 | return false; |
278 | return; | ||
279 | } | 275 | } |
280 | 276 | ||
281 | kfree(local->hw_scan_req); | 277 | kfree(local->hw_scan_req); |
@@ -289,23 +285,25 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
289 | local->scanning = 0; | 285 | local->scanning = 0; |
290 | local->scan_channel = NULL; | 286 | local->scan_channel = NULL; |
291 | 287 | ||
292 | /* we only have to protect scan_req and hw/sw scan */ | 288 | return true; |
293 | mutex_unlock(&local->mtx); | 289 | } |
294 | |||
295 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
296 | if (was_hw_scan) | ||
297 | goto done; | ||
298 | |||
299 | ieee80211_configure_filter(local); | ||
300 | 290 | ||
301 | drv_sw_scan_complete(local); | 291 | static void __ieee80211_scan_completed_finish(struct ieee80211_hw *hw, |
292 | bool was_hw_scan) | ||
293 | { | ||
294 | struct ieee80211_local *local = hw_to_local(hw); | ||
302 | 295 | ||
303 | ieee80211_offchannel_return(local, true); | 296 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); |
297 | if (!was_hw_scan) { | ||
298 | ieee80211_configure_filter(local); | ||
299 | drv_sw_scan_complete(local); | ||
300 | ieee80211_offchannel_return(local, true); | ||
301 | } | ||
304 | 302 | ||
305 | done: | ||
306 | mutex_lock(&local->mtx); | 303 | mutex_lock(&local->mtx); |
307 | ieee80211_recalc_idle(local); | 304 | ieee80211_recalc_idle(local); |
308 | mutex_unlock(&local->mtx); | 305 | mutex_unlock(&local->mtx); |
306 | |||
309 | ieee80211_mlme_notify_scan_completed(local); | 307 | ieee80211_mlme_notify_scan_completed(local); |
310 | ieee80211_ibss_notify_scan_completed(local); | 308 | ieee80211_ibss_notify_scan_completed(local); |
311 | ieee80211_mesh_notify_scan_completed(local); | 309 | ieee80211_mesh_notify_scan_completed(local); |
@@ -366,6 +364,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
366 | struct ieee80211_local *local = sdata->local; | 364 | struct ieee80211_local *local = sdata->local; |
367 | int rc; | 365 | int rc; |
368 | 366 | ||
367 | lockdep_assert_held(&local->mtx); | ||
368 | |||
369 | if (local->scan_req) | 369 | if (local->scan_req) |
370 | return -EBUSY; | 370 | return -EBUSY; |
371 | 371 | ||
@@ -447,8 +447,8 @@ ieee80211_scan_get_channel_time(struct ieee80211_channel *chan) | |||
447 | return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME; | 447 | return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME; |
448 | } | 448 | } |
449 | 449 | ||
450 | static int ieee80211_scan_state_decision(struct ieee80211_local *local, | 450 | static void ieee80211_scan_state_decision(struct ieee80211_local *local, |
451 | unsigned long *next_delay) | 451 | unsigned long *next_delay) |
452 | { | 452 | { |
453 | bool associated = false; | 453 | bool associated = false; |
454 | bool tx_empty = true; | 454 | bool tx_empty = true; |
@@ -458,12 +458,6 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
458 | struct ieee80211_sub_if_data *sdata; | 458 | struct ieee80211_sub_if_data *sdata; |
459 | struct ieee80211_channel *next_chan; | 459 | struct ieee80211_channel *next_chan; |
460 | 460 | ||
461 | /* if no more bands/channels left, complete scan and advance to the idle state */ | ||
462 | if (local->scan_channel_idx >= local->scan_req->n_channels) { | ||
463 | __ieee80211_scan_completed(&local->hw, false); | ||
464 | return 1; | ||
465 | } | ||
466 | |||
467 | /* | 461 | /* |
468 | * check if at least one STA interface is associated, | 462 | * check if at least one STA interface is associated, |
469 | * check if at least one STA interface has pending tx frames | 463 | * check if at least one STA interface has pending tx frames |
@@ -535,7 +529,6 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
535 | } | 529 | } |
536 | 530 | ||
537 | *next_delay = 0; | 531 | *next_delay = 0; |
538 | return 0; | ||
539 | } | 532 | } |
540 | 533 | ||
541 | static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local, | 534 | static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local, |
@@ -651,28 +644,17 @@ void ieee80211_scan_work(struct work_struct *work) | |||
651 | container_of(work, struct ieee80211_local, scan_work.work); | 644 | container_of(work, struct ieee80211_local, scan_work.work); |
652 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | 645 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; |
653 | unsigned long next_delay = 0; | 646 | unsigned long next_delay = 0; |
647 | bool aborted, hw_scan, finish; | ||
654 | 648 | ||
655 | if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) { | 649 | mutex_lock(&local->mtx); |
656 | bool aborted; | ||
657 | 650 | ||
651 | if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) { | ||
658 | aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning); | 652 | aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning); |
659 | __ieee80211_scan_completed(&local->hw, aborted); | 653 | goto out_complete; |
660 | return; | ||
661 | } | ||
662 | |||
663 | mutex_lock(&local->mtx); | ||
664 | if (!sdata || !local->scan_req) { | ||
665 | mutex_unlock(&local->mtx); | ||
666 | return; | ||
667 | } | 654 | } |
668 | 655 | ||
669 | if (local->hw_scan_req) { | 656 | if (!sdata || !local->scan_req) |
670 | int rc = drv_hw_scan(local, sdata, local->hw_scan_req); | 657 | goto out; |
671 | mutex_unlock(&local->mtx); | ||
672 | if (rc) | ||
673 | __ieee80211_scan_completed(&local->hw, true); | ||
674 | return; | ||
675 | } | ||
676 | 658 | ||
677 | if (local->scan_req && !local->scanning) { | 659 | if (local->scan_req && !local->scanning) { |
678 | struct cfg80211_scan_request *req = local->scan_req; | 660 | struct cfg80211_scan_request *req = local->scan_req; |
@@ -682,21 +664,21 @@ void ieee80211_scan_work(struct work_struct *work) | |||
682 | local->scan_sdata = NULL; | 664 | local->scan_sdata = NULL; |
683 | 665 | ||
684 | rc = __ieee80211_start_scan(sdata, req); | 666 | rc = __ieee80211_start_scan(sdata, req); |
685 | mutex_unlock(&local->mtx); | 667 | if (rc) { |
686 | 668 | /* need to complete scan in cfg80211 */ | |
687 | if (rc) | 669 | local->scan_req = req; |
688 | __ieee80211_scan_completed(&local->hw, true); | 670 | aborted = true; |
689 | return; | 671 | goto out_complete; |
672 | } else | ||
673 | goto out; | ||
690 | } | 674 | } |
691 | 675 | ||
692 | mutex_unlock(&local->mtx); | ||
693 | |||
694 | /* | 676 | /* |
695 | * Avoid re-scheduling when the sdata is going away. | 677 | * Avoid re-scheduling when the sdata is going away. |
696 | */ | 678 | */ |
697 | if (!ieee80211_sdata_running(sdata)) { | 679 | if (!ieee80211_sdata_running(sdata)) { |
698 | __ieee80211_scan_completed(&local->hw, true); | 680 | aborted = true; |
699 | return; | 681 | goto out_complete; |
700 | } | 682 | } |
701 | 683 | ||
702 | /* | 684 | /* |
@@ -706,8 +688,12 @@ void ieee80211_scan_work(struct work_struct *work) | |||
706 | do { | 688 | do { |
707 | switch (local->next_scan_state) { | 689 | switch (local->next_scan_state) { |
708 | case SCAN_DECISION: | 690 | case SCAN_DECISION: |
709 | if (ieee80211_scan_state_decision(local, &next_delay)) | 691 | /* if no more bands/channels left, complete scan */ |
710 | return; | 692 | if (local->scan_channel_idx >= local->scan_req->n_channels) { |
693 | aborted = false; | ||
694 | goto out_complete; | ||
695 | } | ||
696 | ieee80211_scan_state_decision(local, &next_delay); | ||
711 | break; | 697 | break; |
712 | case SCAN_SET_CHANNEL: | 698 | case SCAN_SET_CHANNEL: |
713 | ieee80211_scan_state_set_channel(local, &next_delay); | 699 | ieee80211_scan_state_set_channel(local, &next_delay); |
@@ -725,6 +711,19 @@ void ieee80211_scan_work(struct work_struct *work) | |||
725 | } while (next_delay == 0); | 711 | } while (next_delay == 0); |
726 | 712 | ||
727 | ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay); | 713 | ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay); |
714 | mutex_unlock(&local->mtx); | ||
715 | return; | ||
716 | |||
717 | out_complete: | ||
718 | hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); | ||
719 | finish = __ieee80211_scan_completed(&local->hw, aborted, hw_scan); | ||
720 | mutex_unlock(&local->mtx); | ||
721 | if (finish) | ||
722 | __ieee80211_scan_completed_finish(&local->hw, hw_scan); | ||
723 | return; | ||
724 | |||
725 | out: | ||
726 | mutex_unlock(&local->mtx); | ||
728 | } | 727 | } |
729 | 728 | ||
730 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | 729 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, |
@@ -786,21 +785,40 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, | |||
786 | return ret; | 785 | return ret; |
787 | } | 786 | } |
788 | 787 | ||
788 | /* | ||
789 | * Only call this function when a scan can't be queued -- under RTNL. | ||
790 | */ | ||
789 | void ieee80211_scan_cancel(struct ieee80211_local *local) | 791 | void ieee80211_scan_cancel(struct ieee80211_local *local) |
790 | { | 792 | { |
791 | bool abortscan; | 793 | bool abortscan; |
792 | 794 | bool finish = false; | |
793 | cancel_delayed_work_sync(&local->scan_work); | ||
794 | 795 | ||
795 | /* | 796 | /* |
796 | * Only call this function when a scan can't be | 797 | * We are only canceling software scan, or deferred scan that was not |
797 | * queued -- mostly at suspend under RTNL. | 798 | * yet really started (see __ieee80211_start_scan ). |
799 | * | ||
800 | * Regarding hardware scan: | ||
801 | * - we can not call __ieee80211_scan_completed() as when | ||
802 | * SCAN_HW_SCANNING bit is set this function change | ||
803 | * local->hw_scan_req to operate on 5G band, what race with | ||
804 | * driver which can use local->hw_scan_req | ||
805 | * | ||
806 | * - we can not cancel scan_work since driver can schedule it | ||
807 | * by ieee80211_scan_completed(..., true) to finish scan | ||
808 | * | ||
809 | * Hence low lever driver is responsible for canceling HW scan. | ||
798 | */ | 810 | */ |
811 | |||
799 | mutex_lock(&local->mtx); | 812 | mutex_lock(&local->mtx); |
800 | abortscan = test_bit(SCAN_SW_SCANNING, &local->scanning) || | 813 | abortscan = local->scan_req && !test_bit(SCAN_HW_SCANNING, &local->scanning); |
801 | (!local->scanning && local->scan_req); | 814 | if (abortscan) |
815 | finish = __ieee80211_scan_completed(&local->hw, true, false); | ||
802 | mutex_unlock(&local->mtx); | 816 | mutex_unlock(&local->mtx); |
803 | 817 | ||
804 | if (abortscan) | 818 | if (abortscan) { |
805 | __ieee80211_scan_completed(&local->hw, true); | 819 | /* The scan is canceled, but stop work from being pending */ |
820 | cancel_delayed_work_sync(&local->scan_work); | ||
821 | } | ||
822 | if (finish) | ||
823 | __ieee80211_scan_completed_finish(&local->hw, false); | ||
806 | } | 824 | } |