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>
This commit is contained in:
parent
6bd5f5208f
commit
15db0b7fd8
|
@ -497,30 +497,8 @@ static int ieee80211_stop(struct net_device *dev)
|
|||
}
|
||||
/* fall through */
|
||||
default:
|
||||
if (local->scan_sdata == sdata) {
|
||||
if (!local->ops->hw_scan)
|
||||
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);
|
||||
}
|
||||
if (local->scan_sdata == sdata)
|
||||
ieee80211_scan_cancel(local);
|
||||
|
||||
/*
|
||||
* Disable beaconing for AP and mesh, IBSS can't
|
||||
|
|
|
@ -280,6 +280,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
|
|||
if (local->scan_req != local->int_scan_req)
|
||||
cfg80211_scan_done(local->scan_req, aborted);
|
||||
local->scan_req = NULL;
|
||||
local->scan_sdata = NULL;
|
||||
|
||||
was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
|
||||
local->scanning = 0;
|
||||
|
@ -660,6 +661,7 @@ void ieee80211_scan_work(struct work_struct *work)
|
|||
int rc;
|
||||
|
||||
local->scan_req = NULL;
|
||||
local->scan_sdata = NULL;
|
||||
|
||||
rc = __ieee80211_start_scan(sdata, req);
|
||||
mutex_unlock(&local->scan_mtx);
|
||||
|
@ -742,7 +744,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
void ieee80211_scan_cancel(struct ieee80211_local *local)
|
||||
{
|
||||
bool swscan;
|
||||
bool abortscan;
|
||||
|
||||
cancel_delayed_work_sync(&local->scan_work);
|
||||
|
||||
|
@ -751,9 +753,10 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
|
|||
* queued -- mostly at suspend under RTNL.
|
||||
*/
|
||||
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);
|
||||
|
||||
if (swscan)
|
||||
if (abortscan)
|
||||
ieee80211_scan_completed(&local->hw, true);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue