Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+2 −24
Original line number Diff line number Diff line
@@ -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
+6 −3
Original line number Diff line number Diff line
@@ -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);
}