diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-08-25 10:33:47 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-08-28 14:40:45 -0400 |
commit | 15db0b7fd872b0312033666d3a82e1214a227ec0 (patch) | |
tree | 0c853f69292d085fac68e0cf5098b484fde9d13c | |
parent | 6bd5f5208fac04d00325b458355e4a4abda76595 (diff) |
mac80211: fix scan cancel on ifdown
When an interface is taken down while a scan is
pending -- i.e. a scan request was accepted but
not yet acted upon due to other work being in
progress -- we currently do not properly cancel
that scan and end up getting stuck. Fix this by
doing better checks when an interface is taken
down.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | net/mac80211/iface.c | 26 | ||||
-rw-r--r-- | net/mac80211/scan.c | 9 |
2 files changed, 8 insertions, 27 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index d134bd79972f..f6005adcbf90 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -497,30 +497,8 @@ static int ieee80211_stop(struct net_device *dev) | |||
497 | } | 497 | } |
498 | /* fall through */ | 498 | /* fall through */ |
499 | default: | 499 | default: |
500 | if (local->scan_sdata == sdata) { | 500 | if (local->scan_sdata == sdata) |
501 | if (!local->ops->hw_scan) | 501 | ieee80211_scan_cancel(local); |
502 | cancel_delayed_work_sync(&local->scan_work); | ||
503 | /* | ||
504 | * The software scan can no longer run now, so we can | ||
505 | * clear out the scan_sdata reference. However, the | ||
506 | * hardware scan may still be running. The complete | ||
507 | * function must be prepared to handle a NULL value. | ||
508 | */ | ||
509 | local->scan_sdata = NULL; | ||
510 | /* | ||
511 | * The memory barrier guarantees that another CPU | ||
512 | * that is hardware-scanning will now see the fact | ||
513 | * that this interface is gone. | ||
514 | */ | ||
515 | smp_mb(); | ||
516 | /* | ||
517 | * If software scanning, complete the scan but since | ||
518 | * the scan_sdata is NULL already don't send out a | ||
519 | * scan event to userspace -- the scan is incomplete. | ||
520 | */ | ||
521 | if (test_bit(SCAN_SW_SCANNING, &local->scanning)) | ||
522 | ieee80211_scan_completed(&local->hw, true); | ||
523 | } | ||
524 | 502 | ||
525 | /* | 503 | /* |
526 | * Disable beaconing for AP and mesh, IBSS can't | 504 | * Disable beaconing for AP and mesh, IBSS can't |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 1e04be6b9129..039901109fa1 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -280,6 +280,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
280 | if (local->scan_req != local->int_scan_req) | 280 | if (local->scan_req != local->int_scan_req) |
281 | cfg80211_scan_done(local->scan_req, aborted); | 281 | cfg80211_scan_done(local->scan_req, aborted); |
282 | local->scan_req = NULL; | 282 | local->scan_req = NULL; |
283 | local->scan_sdata = NULL; | ||
283 | 284 | ||
284 | was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); | 285 | was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); |
285 | local->scanning = 0; | 286 | local->scanning = 0; |
@@ -660,6 +661,7 @@ void ieee80211_scan_work(struct work_struct *work) | |||
660 | int rc; | 661 | int rc; |
661 | 662 | ||
662 | local->scan_req = NULL; | 663 | local->scan_req = NULL; |
664 | local->scan_sdata = NULL; | ||
663 | 665 | ||
664 | rc = __ieee80211_start_scan(sdata, req); | 666 | rc = __ieee80211_start_scan(sdata, req); |
665 | mutex_unlock(&local->scan_mtx); | 667 | mutex_unlock(&local->scan_mtx); |
@@ -742,7 +744,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, | |||
742 | 744 | ||
743 | void ieee80211_scan_cancel(struct ieee80211_local *local) | 745 | void ieee80211_scan_cancel(struct ieee80211_local *local) |
744 | { | 746 | { |
745 | bool swscan; | 747 | bool abortscan; |
746 | 748 | ||
747 | cancel_delayed_work_sync(&local->scan_work); | 749 | cancel_delayed_work_sync(&local->scan_work); |
748 | 750 | ||
@@ -751,9 +753,10 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) | |||
751 | * queued -- mostly at suspend under RTNL. | 753 | * queued -- mostly at suspend under RTNL. |
752 | */ | 754 | */ |
753 | mutex_lock(&local->scan_mtx); | 755 | mutex_lock(&local->scan_mtx); |
754 | swscan = test_bit(SCAN_SW_SCANNING, &local->scanning); | 756 | abortscan = test_bit(SCAN_SW_SCANNING, &local->scanning) || |
757 | (!local->scanning && local->scan_req); | ||
755 | mutex_unlock(&local->scan_mtx); | 758 | mutex_unlock(&local->scan_mtx); |
756 | 759 | ||
757 | if (swscan) | 760 | if (abortscan) |
758 | ieee80211_scan_completed(&local->hw, true); | 761 | ieee80211_scan_completed(&local->hw, true); |
759 | } | 762 | } |