summaryrefslogtreecommitdiffstats
path: root/package/mac80211/patches/721-mac80211-fix-scan-race.patch
blob: efc01b1761cef3711acd07c2a8dd808be50306b5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
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);
 }