Commit 15db0b7f authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

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: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 6bd5f520
...@@ -497,30 +497,8 @@ static int ieee80211_stop(struct net_device *dev) ...@@ -497,30 +497,8 @@ static int ieee80211_stop(struct net_device *dev)
} }
/* fall through */ /* fall through */
default: default:
if (local->scan_sdata == sdata) { if (local->scan_sdata == sdata)
if (!local->ops->hw_scan) ieee80211_scan_cancel(local);
cancel_delayed_work_sync(&local->scan_work);
/*
* The software scan can no longer run now, so we can
* clear out the scan_sdata reference. However, the
* hardware scan may still be running. The complete
* function must be prepared to handle a NULL value.
*/
local->scan_sdata = NULL;
/*
* The memory barrier guarantees that another CPU
* that is hardware-scanning will now see the fact
* that this interface is gone.
*/
smp_mb();
/*
* If software scanning, complete the scan but since
* the scan_sdata is NULL already don't send out a
* scan event to userspace -- the scan is incomplete.
*/
if (test_bit(SCAN_SW_SCANNING, &local->scanning))
ieee80211_scan_completed(&local->hw, true);
}
/* /*
* Disable beaconing for AP and mesh, IBSS can't * Disable beaconing for AP and mesh, IBSS can't
......
...@@ -280,6 +280,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) ...@@ -280,6 +280,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
if (local->scan_req != local->int_scan_req) if (local->scan_req != local->int_scan_req)
cfg80211_scan_done(local->scan_req, aborted); cfg80211_scan_done(local->scan_req, aborted);
local->scan_req = NULL; local->scan_req = NULL;
local->scan_sdata = NULL;
was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
local->scanning = 0; local->scanning = 0;
...@@ -660,6 +661,7 @@ void ieee80211_scan_work(struct work_struct *work) ...@@ -660,6 +661,7 @@ void ieee80211_scan_work(struct work_struct *work)
int rc; int rc;
local->scan_req = NULL; local->scan_req = NULL;
local->scan_sdata = NULL;
rc = __ieee80211_start_scan(sdata, req); rc = __ieee80211_start_scan(sdata, req);
mutex_unlock(&local->scan_mtx); mutex_unlock(&local->scan_mtx);
...@@ -742,7 +744,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, ...@@ -742,7 +744,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
void ieee80211_scan_cancel(struct ieee80211_local *local) void ieee80211_scan_cancel(struct ieee80211_local *local)
{ {
bool swscan; bool abortscan;
cancel_delayed_work_sync(&local->scan_work); cancel_delayed_work_sync(&local->scan_work);
...@@ -751,9 +753,10 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) ...@@ -751,9 +753,10 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
* queued -- mostly at suspend under RTNL. * queued -- mostly at suspend under RTNL.
*/ */
mutex_lock(&local->scan_mtx); mutex_lock(&local->scan_mtx);
swscan = test_bit(SCAN_SW_SCANNING, &local->scanning); abortscan = test_bit(SCAN_SW_SCANNING, &local->scanning) ||
(!local->scanning && local->scan_req);
mutex_unlock(&local->scan_mtx); mutex_unlock(&local->scan_mtx);
if (swscan) if (abortscan)
ieee80211_scan_completed(&local->hw, true); ieee80211_scan_completed(&local->hw, true);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment