diff options
Diffstat (limited to 'package/mac80211')
-rw-r--r-- | package/mac80211/patches/721-mac80211-fix-scan-race.patch | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/package/mac80211/patches/721-mac80211-fix-scan-race.patch b/package/mac80211/patches/721-mac80211-fix-scan-race.patch new file mode 100644 index 0000000000..efc01b1761 --- /dev/null +++ b/package/mac80211/patches/721-mac80211-fix-scan-race.patch @@ -0,0 +1,141 @@ +Index: compat-wireless-2011-02-25/net/mac80211/scan.c +=================================================================== +--- compat-wireless-2011-02-25.orig/net/mac80211/scan.c 2011-03-07 14:43:55.695666042 +0100 ++++ compat-wireless-2011-02-25/net/mac80211/scan.c 2011-03-07 14:43:57.594439631 +0100 +@@ -258,10 +258,12 @@ static bool ieee80211_prep_hw_scan(struc + return true; + } + +-static bool __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, ++static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, + bool was_hw_scan) + { + struct ieee80211_local *local = hw_to_local(hw); ++ bool on_oper_chan; ++ bool enable_beacons = false; + + lockdep_assert_held(&local->mtx); + +@@ -275,12 +277,12 @@ static bool __ieee80211_scan_completed(s + aborted = true; + + if (WARN_ON(!local->scan_req)) +- return false; ++ return; + + if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { + int rc = drv_hw_scan(local, local->scan_sdata, local->hw_scan_req); + if (rc == 0) +- return false; ++ return; + } + + kfree(local->hw_scan_req); +@@ -294,26 +296,13 @@ static bool __ieee80211_scan_completed(s + local->scanning = 0; + local->scan_channel = NULL; + +- return true; +-} +- +-static void __ieee80211_scan_completed_finish(struct ieee80211_hw *hw, +- bool was_hw_scan) +-{ +- struct ieee80211_local *local = hw_to_local(hw); +- bool on_oper_chan; +- bool enable_beacons = false; +- +- mutex_lock(&local->mtx); + on_oper_chan = ieee80211_cfg_on_oper_channel(local); + + WARN_ON(local->scanning & (SCAN_SW_SCANNING | SCAN_HW_SCANNING)); + +- if (was_hw_scan || !on_oper_chan) { +- if (WARN_ON(local->scan_channel)) +- local->scan_channel = NULL; ++ if (was_hw_scan || !on_oper_chan) + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); +- } else ++ else + /* Set power back to normal operating levels. */ + ieee80211_hw_config(local, 0); + +@@ -331,7 +320,6 @@ static void __ieee80211_scan_completed_f + } + + ieee80211_recalc_idle(local); +- mutex_unlock(&local->mtx); + + ieee80211_mlme_notify_scan_completed(local); + ieee80211_ibss_notify_scan_completed(local); +@@ -686,12 +674,14 @@ void ieee80211_scan_work(struct work_str + { + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, scan_work.work); +- struct ieee80211_sub_if_data *sdata = local->scan_sdata; ++ struct ieee80211_sub_if_data *sdata; + unsigned long next_delay = 0; +- bool aborted, hw_scan, finish; ++ bool aborted, hw_scan; + + mutex_lock(&local->mtx); + ++ sdata = local->scan_sdata; ++ + if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) { + aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning); + goto out_complete; +@@ -755,17 +745,11 @@ void ieee80211_scan_work(struct work_str + } while (next_delay == 0); + + ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay); +- mutex_unlock(&local->mtx); +- return; ++ goto out; + + out_complete: + hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); +- finish = __ieee80211_scan_completed(&local->hw, aborted, hw_scan); +- mutex_unlock(&local->mtx); +- if (finish) +- __ieee80211_scan_completed_finish(&local->hw, hw_scan); +- return; +- ++ __ieee80211_scan_completed(&local->hw, aborted, hw_scan); + out: + mutex_unlock(&local->mtx); + } +@@ -835,7 +819,6 @@ int ieee80211_request_internal_scan(stru + void ieee80211_scan_cancel(struct ieee80211_local *local) + { + bool abortscan; +- bool finish = false; + + /* + * We are only canceling software scan, or deferred scan that was not +@@ -855,14 +838,17 @@ void ieee80211_scan_cancel(struct ieee80 + + mutex_lock(&local->mtx); + abortscan = local->scan_req && !test_bit(SCAN_HW_SCANNING, &local->scanning); +- if (abortscan) +- finish = __ieee80211_scan_completed(&local->hw, true, false); +- mutex_unlock(&local->mtx); +- + if (abortscan) { +- /* The scan is canceled, but stop work from being pending */ +- cancel_delayed_work_sync(&local->scan_work); ++ /* ++ * The scan is canceled, but stop work from being pending. ++ * ++ * If the work is currently running, it must be blocked on ++ * the mutex, but we'll set scan_sdata = NULL and it'll ++ * simply exit once it acquires the mutex. ++ */ ++ cancel_delayed_work(&local->scan_work); ++ /* and clean up */ ++ __ieee80211_scan_completed(&local->hw, true, false); + } +- if (finish) +- __ieee80211_scan_completed_finish(&local->hw, false); ++ mutex_unlock(&local->mtx); + } |