diff options
author | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2013-09-16 04:12:07 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-10-09 12:40:07 -0400 |
commit | a754055a1296fcbe6f32de3a5eaca6efb2fd1865 (patch) | |
tree | 6812b556c369c031478a94d6de4b2b6259bd2ca9 /net/mac80211 | |
parent | 22c4ceed0184318ec5a6182c6d75d398452c2e39 (diff) |
mac80211: correctly close cancelled scans
__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.
Cc: stable@vger.kernel.org
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-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 b6186517ec56..611abfcfb5eb 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -893,6 +893,8 @@ struct tpt_led_trigger { | |||
893 | * that the scan completed. | 893 | * that the scan completed. |
894 | * @SCAN_ABORTED: Set for our scan work function when the driver reported | 894 | * @SCAN_ABORTED: Set for our scan work function when the driver reported |
895 | * a scan complete for an aborted scan. | 895 | * a scan complete for an aborted scan. |
896 | * @SCAN_HW_CANCELLED: Set for our scan work function when the scan is being | ||
897 | * cancelled. | ||
896 | */ | 898 | */ |
897 | enum { | 899 | enum { |
898 | SCAN_SW_SCANNING, | 900 | SCAN_SW_SCANNING, |
@@ -900,6 +902,7 @@ enum { | |||
900 | SCAN_ONCHANNEL_SCANNING, | 902 | SCAN_ONCHANNEL_SCANNING, |
901 | SCAN_COMPLETED, | 903 | SCAN_COMPLETED, |
902 | SCAN_ABORTED, | 904 | SCAN_ABORTED, |
905 | SCAN_HW_CANCELLED, | ||
903 | }; | 906 | }; |
904 | 907 | ||
905 | /** | 908 | /** |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 08afe74b98f4..d2d17a449224 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -238,6 +238,9 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | |||
238 | enum ieee80211_band band; | 238 | enum ieee80211_band band; |
239 | int i, ielen, n_chans; | 239 | int i, ielen, n_chans; |
240 | 240 | ||
241 | if (test_bit(SCAN_HW_CANCELLED, &local->scanning)) | ||
242 | return false; | ||
243 | |||
241 | do { | 244 | do { |
242 | if (local->hw_scan_band == IEEE80211_NUM_BANDS) | 245 | if (local->hw_scan_band == IEEE80211_NUM_BANDS) |
243 | return false; | 246 | return false; |
@@ -940,7 +943,23 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) | |||
940 | if (!local->scan_req) | 943 | if (!local->scan_req) |
941 | goto out; | 944 | goto out; |
942 | 945 | ||
946 | /* | ||
947 | * We have a scan running and the driver already reported completion, | ||
948 | * but the worker hasn't run yet or is stuck on the mutex - mark it as | ||
949 | * cancelled. | ||
950 | */ | ||
951 | if (test_bit(SCAN_HW_SCANNING, &local->scanning) && | ||
952 | test_bit(SCAN_COMPLETED, &local->scanning)) { | ||
953 | set_bit(SCAN_HW_CANCELLED, &local->scanning); | ||
954 | goto out; | ||
955 | } | ||
956 | |||
943 | if (test_bit(SCAN_HW_SCANNING, &local->scanning)) { | 957 | if (test_bit(SCAN_HW_SCANNING, &local->scanning)) { |
958 | /* | ||
959 | * Make sure that __ieee80211_scan_completed doesn't trigger a | ||
960 | * scan on another band. | ||
961 | */ | ||
962 | set_bit(SCAN_HW_CANCELLED, &local->scanning); | ||
944 | if (local->ops->cancel_hw_scan) | 963 | if (local->ops->cancel_hw_scan) |
945 | drv_cancel_hw_scan(local, | 964 | drv_cancel_hw_scan(local, |
946 | rcu_dereference_protected(local->scan_sdata, | 965 | rcu_dereference_protected(local->scan_sdata, |