diff options
author | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2013-09-16 04:12:07 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-11-12 22:05:30 -0500 |
commit | 715a606d73f63e94259e6251565e6e12e3271d0f (patch) | |
tree | 2d8dd2d9ff41caf6aa7820b60605bc3aa592baec /net | |
parent | 5be794dc4bb66266acc91eb589ace48e82a6c77e (diff) |
mac80211: correctly close cancelled scans
commit a754055a1296fcbe6f32de3a5eaca6efb2fd1865 upstream.
__ieee80211_scan_completed is called from a worker. This
means that the following flow is possible.
* driver calls ieee80211_scan_completed
* mac80211 cancels the scan (that is already complete)
* __ieee80211_scan_completed runs
When scan_work will finally run, it will see that the scan
hasn't been aborted and might even trigger another scan on
another band. This leads to a situation where cfg80211's
scan is not done and no further scan can be issued.
Fix this by setting a new flag when a HW scan is being
cancelled so that no other scan will be triggered.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
-rw-r--r-- | net/mac80211/scan.c | 19 |
2 files changed, 22 insertions, 0 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9ca8e3278cc0..92ef04c72c51 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -842,6 +842,8 @@ struct tpt_led_trigger { | |||
842 | * that the scan completed. | 842 | * that the scan completed. |
843 | * @SCAN_ABORTED: Set for our scan work function when the driver reported | 843 | * @SCAN_ABORTED: Set for our scan work function when the driver reported |
844 | * a scan complete for an aborted scan. | 844 | * a scan complete for an aborted scan. |
845 | * @SCAN_HW_CANCELLED: Set for our scan work function when the scan is being | ||
846 | * cancelled. | ||
845 | */ | 847 | */ |
846 | enum { | 848 | enum { |
847 | SCAN_SW_SCANNING, | 849 | SCAN_SW_SCANNING, |
@@ -849,6 +851,7 @@ enum { | |||
849 | SCAN_ONCHANNEL_SCANNING, | 851 | SCAN_ONCHANNEL_SCANNING, |
850 | SCAN_COMPLETED, | 852 | SCAN_COMPLETED, |
851 | SCAN_ABORTED, | 853 | SCAN_ABORTED, |
854 | SCAN_HW_CANCELLED, | ||
852 | }; | 855 | }; |
853 | 856 | ||
854 | /** | 857 | /** |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 99b103921a4b..eb03337b6545 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -202,6 +202,9 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | |||
202 | enum ieee80211_band band; | 202 | enum ieee80211_band band; |
203 | int i, ielen, n_chans; | 203 | int i, ielen, n_chans; |
204 | 204 | ||
205 | if (test_bit(SCAN_HW_CANCELLED, &local->scanning)) | ||
206 | return false; | ||
207 | |||
205 | do { | 208 | do { |
206 | if (local->hw_scan_band == IEEE80211_NUM_BANDS) | 209 | if (local->hw_scan_band == IEEE80211_NUM_BANDS) |
207 | return false; | 210 | return false; |
@@ -878,7 +881,23 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) | |||
878 | if (!local->scan_req) | 881 | if (!local->scan_req) |
879 | goto out; | 882 | goto out; |
880 | 883 | ||
884 | /* | ||
885 | * We have a scan running and the driver already reported completion, | ||
886 | * but the worker hasn't run yet or is stuck on the mutex - mark it as | ||
887 | * cancelled. | ||
888 | */ | ||
889 | if (test_bit(SCAN_HW_SCANNING, &local->scanning) && | ||
890 | test_bit(SCAN_COMPLETED, &local->scanning)) { | ||
891 | set_bit(SCAN_HW_CANCELLED, &local->scanning); | ||
892 | goto out; | ||
893 | } | ||
894 | |||
881 | if (test_bit(SCAN_HW_SCANNING, &local->scanning)) { | 895 | if (test_bit(SCAN_HW_SCANNING, &local->scanning)) { |
896 | /* | ||
897 | * Make sure that __ieee80211_scan_completed doesn't trigger a | ||
898 | * scan on another band. | ||
899 | */ | ||
900 | set_bit(SCAN_HW_CANCELLED, &local->scanning); | ||
882 | if (local->ops->cancel_hw_scan) | 901 | if (local->ops->cancel_hw_scan) |
883 | drv_cancel_hw_scan(local, | 902 | drv_cancel_hw_scan(local, |
884 | rcu_dereference_protected(local->scan_sdata, | 903 | rcu_dereference_protected(local->scan_sdata, |