Blame view

net/mac80211/scan.c 38.4 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
0a51b27e9   Johannes Berg   mac80211: start m...
2
  /*
5484e2374   Johannes Berg   mac80211: move BS...
3
4
   * Scanning implementation
   *
0a51b27e9   Johannes Berg   mac80211: start m...
5
6
7
8
9
   * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
   * Copyright 2004, Instant802 Networks, Inc.
   * Copyright 2005, Devicescape Software, Inc.
   * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
   * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
74d803b60   Sara Sharon   mac80211: ignore ...
10
   * Copyright 2013-2015  Intel Mobile Communications GmbH
40b0bd249   Roee Zamir   mac80211: oce: en...
11
   * Copyright 2016-2017  Intel Deutschland GmbH
c8cb5b854   Tova Mussai   nl80211/cfg80211:...
12
   * Copyright (C) 2018-2020 Intel Corporation
0a51b27e9   Johannes Berg   mac80211: start m...
13
   */
0a51b27e9   Johannes Berg   mac80211: start m...
14
  #include <linux/if_arp.h>
888d04dfb   Felix Fietkau   mac80211: use com...
15
  #include <linux/etherdevice.h>
078e1e60d   Johannes Berg   mac80211: Add cap...
16
  #include <linux/rtnetlink.h>
df13cce53   Helmut Schaa   mac80211: Improve...
17
  #include <net/sch_generic.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
18
  #include <linux/slab.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
19
  #include <linux/export.h>
b9771d41a   Johannes Berg   mac80211: support...
20
  #include <linux/random.h>
0a51b27e9   Johannes Berg   mac80211: start m...
21
  #include <net/mac80211.h>
0a51b27e9   Johannes Berg   mac80211: start m...
22
23
  
  #include "ieee80211_i.h"
244879813   Johannes Berg   mac80211: add dri...
24
  #include "driver-ops.h"
5484e2374   Johannes Berg   mac80211: move BS...
25
  #include "mesh.h"
0a51b27e9   Johannes Berg   mac80211: start m...
26
27
28
  
  #define IEEE80211_PROBE_DELAY (HZ / 33)
  #define IEEE80211_CHANNEL_TIME (HZ / 33)
3f892b61a   Stanislaw Gruszka   mac80211: improve...
29
  #define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 9)
0a51b27e9   Johannes Berg   mac80211: start m...
30

5484e2374   Johannes Berg   mac80211: move BS...
31
  void ieee80211_rx_bss_put(struct ieee80211_local *local,
c2b13452b   Johannes Berg   mac80211: clean u...
32
  			  struct ieee80211_bss *bss)
5484e2374   Johannes Berg   mac80211: move BS...
33
  {
0c1ad2cac   Johannes Berg   mac80211: proper ...
34
35
  	if (!bss)
  		return;
5b112d3d0   Johannes Berg   cfg80211: pass wi...
36
37
  	cfg80211_put_bss(local->hw.wiphy,
  			 container_of((void *)bss, struct cfg80211_bss, priv));
5484e2374   Johannes Berg   mac80211: move BS...
38
  }
ab13315af   Kalle Valo   mac80211: add U-A...
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
  static bool is_uapsd_supported(struct ieee802_11_elems *elems)
  {
  	u8 qos_info;
  
  	if (elems->wmm_info && elems->wmm_info_len == 7
  	    && elems->wmm_info[5] == 1)
  		qos_info = elems->wmm_info[6];
  	else if (elems->wmm_param && elems->wmm_param_len == 24
  		 && elems->wmm_param[5] == 1)
  		qos_info = elems->wmm_param[6];
  	else
  		/* no valid wmm information or parameter element found */
  		return false;
  
  	return qos_info & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD;
  }
fcea7db50   Sara Sharon   mac80211: move th...
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
  static void
  ieee80211_update_bss_from_elems(struct ieee80211_local *local,
  				struct ieee80211_bss *bss,
  				struct ieee802_11_elems *elems,
  				struct ieee80211_rx_status *rx_status,
  				bool beacon)
  {
  	int clen, srlen;
  
  	if (beacon)
  		bss->device_ts_beacon = rx_status->device_timestamp;
  	else
  		bss->device_ts_presp = rx_status->device_timestamp;
  
  	if (elems->parse_error) {
  		if (beacon)
  			bss->corrupt_data |= IEEE80211_BSS_CORRUPT_BEACON;
  		else
  			bss->corrupt_data |= IEEE80211_BSS_CORRUPT_PROBE_RESP;
  	} else {
  		if (beacon)
  			bss->corrupt_data &= ~IEEE80211_BSS_CORRUPT_BEACON;
  		else
  			bss->corrupt_data &= ~IEEE80211_BSS_CORRUPT_PROBE_RESP;
  	}
  
  	/* save the ERP value so that it is available at association time */
  	if (elems->erp_info && (!elems->parse_error ||
  				!(bss->valid_data & IEEE80211_BSS_VALID_ERP))) {
  		bss->erp_value = elems->erp_info[0];
  		bss->has_erp_value = true;
  		if (!elems->parse_error)
  			bss->valid_data |= IEEE80211_BSS_VALID_ERP;
  	}
  
  	/* replace old supported rates if we get new values */
  	if (!elems->parse_error ||
  	    !(bss->valid_data & IEEE80211_BSS_VALID_RATES)) {
  		srlen = 0;
  		if (elems->supp_rates) {
  			clen = IEEE80211_MAX_SUPP_RATES;
  			if (clen > elems->supp_rates_len)
  				clen = elems->supp_rates_len;
  			memcpy(bss->supp_rates, elems->supp_rates, clen);
  			srlen += clen;
  		}
  		if (elems->ext_supp_rates) {
  			clen = IEEE80211_MAX_SUPP_RATES - srlen;
  			if (clen > elems->ext_supp_rates_len)
  				clen = elems->ext_supp_rates_len;
  			memcpy(bss->supp_rates + srlen, elems->ext_supp_rates,
  			       clen);
  			srlen += clen;
  		}
  		if (srlen) {
  			bss->supp_rates_len = srlen;
  			if (!elems->parse_error)
  				bss->valid_data |= IEEE80211_BSS_VALID_RATES;
  		}
  	}
  
  	if (!elems->parse_error ||
  	    !(bss->valid_data & IEEE80211_BSS_VALID_WMM)) {
  		bss->wmm_used = elems->wmm_param || elems->wmm_info;
  		bss->uapsd_supported = is_uapsd_supported(elems);
  		if (!elems->parse_error)
  			bss->valid_data |= IEEE80211_BSS_VALID_WMM;
  	}
  
  	if (beacon) {
  		struct ieee80211_supported_band *sband =
  			local->hw.wiphy->bands[rx_status->band];
  		if (!(rx_status->encoding == RX_ENC_HT) &&
  		    !(rx_status->encoding == RX_ENC_VHT))
  			bss->beacon_rate =
  				&sband->bitrates[rx_status->rate_idx];
  	}
2a333a0db   Johannes Berg   mac80211: avoid u...
132
133
134
135
136
137
  
  	if (elems->vht_cap_elem)
  		bss->vht_cap_info =
  			le32_to_cpu(elems->vht_cap_elem->vht_cap_info);
  	else
  		bss->vht_cap_info = 0;
fcea7db50   Sara Sharon   mac80211: move th...
138
  }
c2b13452b   Johannes Berg   mac80211: clean u...
139
  struct ieee80211_bss *
5484e2374   Johannes Berg   mac80211: move BS...
140
141
  ieee80211_bss_info_update(struct ieee80211_local *local,
  			  struct ieee80211_rx_status *rx_status,
d45c41722   Emmanuel Grumbach   mac82011: use fra...
142
  			  struct ieee80211_mgmt *mgmt, size_t len,
d45c41722   Emmanuel Grumbach   mac82011: use fra...
143
  			  struct ieee80211_channel *channel)
5484e2374   Johannes Berg   mac80211: move BS...
144
  {
cd418ba63   Thomas Pedersen   mac80211: convert...
145
146
  	bool beacon = ieee80211_is_beacon(mgmt->frame_control) ||
  		      ieee80211_is_s1g_beacon(mgmt->frame_control);
78ac51f81   Sara Sharon   mac80211: support...
147
148
  	struct cfg80211_bss *cbss, *non_tx_cbss;
  	struct ieee80211_bss *bss, *non_tx_bss;
162dd6a72   Johannes Berg   mac80211: allow d...
149
150
151
  	struct cfg80211_inform_bss bss_meta = {
  		.boottime_ns = rx_status->boottime_ns,
  	};
74d803b60   Sara Sharon   mac80211: ignore ...
152
  	bool signal_valid;
7947d3e07   Avraham Stern   mac80211: Add sup...
153
  	struct ieee80211_sub_if_data *scan_sdata;
4abb52a46   Sara Sharon   mac80211: pass bs...
154
155
156
  	struct ieee802_11_elems elems;
  	size_t baselen;
  	u8 *elements;
2a5193119   Johannes Berg   cfg80211/nl80211:...
157

1ad22fb5b   Tosoni   mac80211: inform ...
158
159
160
  	if (rx_status->flag & RX_FLAG_NO_SIGNAL_VAL)
  		bss_meta.signal = 0; /* invalid signal indication */
  	else if (ieee80211_hw_check(&local->hw, SIGNAL_DBM))
61f6bba00   Johannes Berg   mac80211: use new...
161
  		bss_meta.signal = rx_status->signal * 100;
30686bf7f   Johannes Berg   mac80211: convert...
162
  	else if (ieee80211_hw_check(&local->hw, SIGNAL_UNSPEC))
61f6bba00   Johannes Berg   mac80211: use new...
163
  		bss_meta.signal = (rx_status->signal * 100) / local->hw.max_signal;
2a5193119   Johannes Berg   cfg80211/nl80211:...
164

61f6bba00   Johannes Berg   mac80211: use new...
165
  	bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_20;
da6a4352e   Johannes Berg   mac80211: separat...
166
  	if (rx_status->bw == RATE_INFO_BW_5)
61f6bba00   Johannes Berg   mac80211: use new...
167
  		bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_5;
da6a4352e   Johannes Berg   mac80211: separat...
168
  	else if (rx_status->bw == RATE_INFO_BW_10)
61f6bba00   Johannes Berg   mac80211: use new...
169
  		bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_10;
7ca15a0ae   Simon Wunderlich   mac80211: allow s...
170

61f6bba00   Johannes Berg   mac80211: use new...
171
  	bss_meta.chan = channel;
7947d3e07   Avraham Stern   mac80211: Add sup...
172
173
174
175
176
177
178
179
180
181
182
183
184
  
  	rcu_read_lock();
  	scan_sdata = rcu_dereference(local->scan_sdata);
  	if (scan_sdata && scan_sdata->vif.type == NL80211_IFTYPE_STATION &&
  	    scan_sdata->vif.bss_conf.assoc &&
  	    ieee80211_have_rx_timestamp(rx_status)) {
  		bss_meta.parent_tsf =
  			ieee80211_calculate_rx_timestamp(local, rx_status,
  							 len + FCS_LEN, 24);
  		ether_addr_copy(bss_meta.parent_bssid,
  				scan_sdata->vif.bss_conf.bssid);
  	}
  	rcu_read_unlock();
61f6bba00   Johannes Berg   mac80211: use new...
185
186
  	cbss = cfg80211_inform_bss_frame_data(local->hw.wiphy, &bss_meta,
  					      mgmt, len, GFP_ATOMIC);
0c1ad2cac   Johannes Berg   mac80211: proper ...
187
  	if (!cbss)
00d3f14cf   Johannes Berg   mac80211: use cfg...
188
  		return NULL;
4abb52a46   Sara Sharon   mac80211: pass bs...
189
190
191
192
193
  
  	if (ieee80211_is_probe_resp(mgmt->frame_control)) {
  		elements = mgmt->u.probe_resp.variable;
  		baselen = offsetof(struct ieee80211_mgmt,
  				   u.probe_resp.variable);
cd418ba63   Thomas Pedersen   mac80211: convert...
194
195
196
197
198
  	} else if (ieee80211_is_s1g_beacon(mgmt->frame_control)) {
  		struct ieee80211_ext *ext = (void *) mgmt;
  
  		baselen = offsetof(struct ieee80211_ext, u.s1g_beacon.variable);
  		elements = ext->u.s1g_beacon.variable;
4abb52a46   Sara Sharon   mac80211: pass bs...
199
200
201
202
203
204
205
206
207
208
  	} else {
  		baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
  		elements = mgmt->u.beacon.variable;
  	}
  
  	if (baselen > len)
  		return NULL;
  
  	ieee802_11_parse_elems(elements, len - baselen, false, &elems,
  			       mgmt->bssid, cbss->bssid);
74d803b60   Sara Sharon   mac80211: ignore ...
209
  	/* In case the signal is invalid update the status */
7bb106eb6   Emmanuel Grumbach   cfg80211: remove ...
210
  	signal_valid = channel == cbss->channel;
74d803b60   Sara Sharon   mac80211: ignore ...
211
212
  	if (!signal_valid)
  		rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
00d3f14cf   Johannes Berg   mac80211: use cfg...
213

0c1ad2cac   Johannes Berg   mac80211: proper ...
214
  	bss = (void *)cbss->priv;
fcea7db50   Sara Sharon   mac80211: move th...
215
  	ieee80211_update_bss_from_elems(local, bss, &elems, rx_status, beacon);
817cee767   Alexander Bondar   mac80211: track A...
216

78ac51f81   Sara Sharon   mac80211: support...
217
218
219
220
221
222
  	list_for_each_entry(non_tx_cbss, &cbss->nontrans_list, nontrans_list) {
  		non_tx_bss = (void *)non_tx_cbss->priv;
  
  		ieee80211_update_bss_from_elems(local, non_tx_bss, &elems,
  						rx_status, beacon);
  	}
5484e2374   Johannes Berg   mac80211: move BS...
223
224
  	return bss;
  }
0a51b27e9   Johannes Berg   mac80211: start m...
225

40b0bd249   Roee Zamir   mac80211: oce: en...
226
227
228
229
230
231
232
233
234
235
236
237
238
  static bool ieee80211_scan_accept_presp(struct ieee80211_sub_if_data *sdata,
  					u32 scan_flags, const u8 *da)
  {
  	if (!sdata)
  		return false;
  	/* accept broadcast for OCE */
  	if (scan_flags & NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP &&
  	    is_broadcast_ether_addr(da))
  		return true;
  	if (scan_flags & NL80211_SCAN_FLAG_RANDOM_ADDR)
  		return true;
  	return ether_addr_equal(da, sdata->vif.addr);
  }
d48b29685   Johannes Berg   mac80211: redesig...
239
  void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
98c8fccfa   Johannes Berg   mac80211: refacto...
240
  {
f1d58c252   Johannes Berg   mac80211: push rx...
241
  	struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
d48b29685   Johannes Berg   mac80211: redesig...
242
243
  	struct ieee80211_sub_if_data *sdata1, *sdata2;
  	struct ieee80211_mgmt *mgmt = (void *)skb->data;
c2b13452b   Johannes Berg   mac80211: clean u...
244
  	struct ieee80211_bss *bss;
98c8fccfa   Johannes Berg   mac80211: refacto...
245
  	struct ieee80211_channel *channel;
98c8fccfa   Johannes Berg   mac80211: refacto...
246

cd418ba63   Thomas Pedersen   mac80211: convert...
247
248
249
250
251
252
  	if (ieee80211_is_s1g_beacon(mgmt->frame_control)) {
  		if (skb->len < 15)
  			return;
  	} else if (skb->len < 24 ||
  		 (!ieee80211_is_probe_resp(mgmt->frame_control) &&
  		  !ieee80211_is_beacon(mgmt->frame_control)))
d48b29685   Johannes Berg   mac80211: redesig...
253
  		return;
98c8fccfa   Johannes Berg   mac80211: refacto...
254

d48b29685   Johannes Berg   mac80211: redesig...
255
256
  	sdata1 = rcu_dereference(local->scan_sdata);
  	sdata2 = rcu_dereference(local->sched_scan_sdata);
98c8fccfa   Johannes Berg   mac80211: refacto...
257

d48b29685   Johannes Berg   mac80211: redesig...
258
259
  	if (likely(!sdata1 && !sdata2))
  		return;
98c8fccfa   Johannes Berg   mac80211: refacto...
260

d48b29685   Johannes Berg   mac80211: redesig...
261
  	if (ieee80211_is_probe_resp(mgmt->frame_control)) {
a344d6778   Johannes Berg   mac80211: allow d...
262
263
  		struct cfg80211_scan_request *scan_req;
  		struct cfg80211_sched_scan_request *sched_scan_req;
40b0bd249   Roee Zamir   mac80211: oce: en...
264
  		u32 scan_req_flags = 0, sched_scan_req_flags = 0;
a344d6778   Johannes Berg   mac80211: allow d...
265
266
267
  
  		scan_req = rcu_dereference(local->scan_req);
  		sched_scan_req = rcu_dereference(local->sched_scan_req);
40b0bd249   Roee Zamir   mac80211: oce: en...
268
269
270
271
272
273
274
275
  		if (scan_req)
  			scan_req_flags = scan_req->flags;
  
  		if (sched_scan_req)
  			sched_scan_req_flags = sched_scan_req->flags;
  
  		/* ignore ProbeResp to foreign address or non-bcast (OCE)
  		 * unless scanning with randomised address
a344d6778   Johannes Berg   mac80211: allow d...
276
  		 */
40b0bd249   Roee Zamir   mac80211: oce: en...
277
278
279
280
  		if (!ieee80211_scan_accept_presp(sdata1, scan_req_flags,
  						 mgmt->da) &&
  		    !ieee80211_scan_accept_presp(sdata2, sched_scan_req_flags,
  						 mgmt->da))
d48b29685   Johannes Berg   mac80211: redesig...
281
  			return;
98c8fccfa   Johannes Berg   mac80211: refacto...
282
  	}
3b23c184f   Thomas Pedersen   mac80211: add fre...
283
284
  	channel = ieee80211_get_channel_khz(local->hw.wiphy,
  					ieee80211_rx_status_to_khz(rx_status));
98c8fccfa   Johannes Berg   mac80211: refacto...
285
286
  
  	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
d48b29685   Johannes Berg   mac80211: redesig...
287
  		return;
98c8fccfa   Johannes Berg   mac80211: refacto...
288

d48b29685   Johannes Berg   mac80211: redesig...
289
  	bss = ieee80211_bss_info_update(local, rx_status,
4abb52a46   Sara Sharon   mac80211: pass bs...
290
  					mgmt, skb->len,
d45c41722   Emmanuel Grumbach   mac82011: use fra...
291
  					channel);
d048e503a   Jouni Malinen   mac80211: Fix sca...
292
  	if (bss)
d48b29685   Johannes Berg   mac80211: redesig...
293
  		ieee80211_rx_bss_put(local, bss);
98c8fccfa   Johannes Berg   mac80211: refacto...
294
  }
2103dec14   Simon Wunderlich   mac80211: select ...
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
  static void
  ieee80211_prepare_scan_chandef(struct cfg80211_chan_def *chandef,
  			       enum nl80211_bss_scan_width scan_width)
  {
  	memset(chandef, 0, sizeof(*chandef));
  	switch (scan_width) {
  	case NL80211_BSS_CHAN_WIDTH_5:
  		chandef->width = NL80211_CHAN_WIDTH_5;
  		break;
  	case NL80211_BSS_CHAN_WIDTH_10:
  		chandef->width = NL80211_CHAN_WIDTH_10;
  		break;
  	default:
  		chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
  		break;
  	}
  }
4d36ec582   Johannes Berg   mac80211: split h...
312
  /* return false if no more work */
2ad2274c5   Ilan Peer   mac80211: Add HE ...
313
  static bool ieee80211_prep_hw_scan(struct ieee80211_sub_if_data *sdata)
4d36ec582   Johannes Berg   mac80211: split h...
314
  {
2ad2274c5   Ilan Peer   mac80211: Add HE ...
315
  	struct ieee80211_local *local = sdata->local;
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
316
  	struct cfg80211_scan_request *req;
2103dec14   Simon Wunderlich   mac80211: select ...
317
  	struct cfg80211_chan_def chandef;
c56ef6725   David Spinadel   mac80211: support...
318
  	u8 bands_used = 0;
4d36ec582   Johannes Berg   mac80211: split h...
319
  	int i, ielen, n_chans;
b9771d41a   Johannes Berg   mac80211: support...
320
  	u32 flags = 0;
4d36ec582   Johannes Berg   mac80211: split h...
321

6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
322
323
  	req = rcu_dereference_protected(local->scan_req,
  					lockdep_is_held(&local->mtx));
a754055a1   Emmanuel Grumbach   mac80211: correct...
324
325
  	if (test_bit(SCAN_HW_CANCELLED, &local->scanning))
  		return false;
30686bf7f   Johannes Berg   mac80211: convert...
326
  	if (ieee80211_hw_check(&local->hw, SINGLE_SCAN_ON_ALL_BANDS)) {
4d36ec582   Johannes Berg   mac80211: split h...
327
  		for (i = 0; i < req->n_channels; i++) {
c56ef6725   David Spinadel   mac80211: support...
328
329
330
331
332
333
334
  			local->hw_scan_req->req.channels[i] = req->channels[i];
  			bands_used |= BIT(req->channels[i]->band);
  		}
  
  		n_chans = req->n_channels;
  	} else {
  		do {
57fbcce37   Johannes Berg   cfg80211: remove ...
335
  			if (local->hw_scan_band == NUM_NL80211_BANDS)
c56ef6725   David Spinadel   mac80211: support...
336
337
338
339
340
341
342
343
344
  				return false;
  
  			n_chans = 0;
  
  			for (i = 0; i < req->n_channels; i++) {
  				if (req->channels[i]->band !=
  				    local->hw_scan_band)
  					continue;
  				local->hw_scan_req->req.channels[n_chans] =
4d36ec582   Johannes Berg   mac80211: split h...
345
346
  							req->channels[i];
  				n_chans++;
c56ef6725   David Spinadel   mac80211: support...
347
  				bands_used |= BIT(req->channels[i]->band);
4d36ec582   Johannes Berg   mac80211: split h...
348
  			}
4d36ec582   Johannes Berg   mac80211: split h...
349

c56ef6725   David Spinadel   mac80211: support...
350
351
352
  			local->hw_scan_band++;
  		} while (!n_chans);
  	}
4d36ec582   Johannes Berg   mac80211: split h...
353

c56ef6725   David Spinadel   mac80211: support...
354
  	local->hw_scan_req->req.n_channels = n_chans;
2103dec14   Simon Wunderlich   mac80211: select ...
355
  	ieee80211_prepare_scan_chandef(&chandef, req->scan_width);
4d36ec582   Johannes Berg   mac80211: split h...
356

b9771d41a   Johannes Berg   mac80211: support...
357
358
  	if (req->flags & NL80211_SCAN_FLAG_MIN_PREQ_CONTENT)
  		flags |= IEEE80211_PROBE_FLAG_MIN_CONTENT;
2ad2274c5   Ilan Peer   mac80211: Add HE ...
359
  	ielen = ieee80211_build_preq_ies(sdata,
c56ef6725   David Spinadel   mac80211: support...
360
  					 (u8 *)local->hw_scan_req->req.ie,
c604b9f21   Johannes Berg   mac80211: make ie...
361
  					 local->hw_scan_ies_bufsize,
c56ef6725   David Spinadel   mac80211: support...
362
363
  					 &local->hw_scan_req->ies,
  					 req->ie, req->ie_len,
b9771d41a   Johannes Berg   mac80211: support...
364
365
  					 bands_used, req->rates, &chandef,
  					 flags);
c56ef6725   David Spinadel   mac80211: support...
366
367
  	local->hw_scan_req->req.ie_len = ielen;
  	local->hw_scan_req->req.no_cck = req->no_cck;
a344d6778   Johannes Berg   mac80211: allow d...
368
369
370
  	ether_addr_copy(local->hw_scan_req->req.mac_addr, req->mac_addr);
  	ether_addr_copy(local->hw_scan_req->req.mac_addr_mask,
  			req->mac_addr_mask);
e345f44f2   Jouni Malinen   mac80211: Support...
371
  	ether_addr_copy(local->hw_scan_req->req.bssid, req->bssid);
4d36ec582   Johannes Berg   mac80211: split h...
372
373
374
  
  	return true;
  }
8bd2a2489   Eliad Peller   mac80211: determi...
375
  static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
0a51b27e9   Johannes Berg   mac80211: start m...
376
377
  {
  	struct ieee80211_local *local = hw_to_local(hw);
e9da68dde   Johannes Berg   mac80211: allow h...
378
  	bool hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
a2b70e833   Eliad Peller   mac80211: start_n...
379
  	bool was_scanning = local->scanning;
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
380
  	struct cfg80211_scan_request *scan_req;
a344d6778   Johannes Berg   mac80211: allow d...
381
  	struct ieee80211_sub_if_data *scan_sdata;
4fa11ec72   Sachin Kulkarni   mac80211: Requeue...
382
  	struct ieee80211_sub_if_data *sdata;
0a51b27e9   Johannes Berg   mac80211: start m...
383

e229f844d   Stanislaw Gruszka   mac80211: keep lo...
384
  	lockdep_assert_held(&local->mtx);
5bc75728f   Johannes Berg   mac80211: fix sca...
385

6d3560d4f   Johannes Berg   mac80211: fix sca...
386
387
388
389
390
391
392
393
  	/*
  	 * It's ok to abort a not-yet-running scan (that
  	 * we have one at all will be verified by checking
  	 * local->scan_req next), but not to complete it
  	 * successfully.
  	 */
  	if (WARN_ON(!local->scanning && !aborted))
  		aborted = true;
5bc75728f   Johannes Berg   mac80211: fix sca...
394

e229f844d   Stanislaw Gruszka   mac80211: keep lo...
395
  	if (WARN_ON(!local->scan_req))
d07bfd8b6   Johannes Berg   mac80211: fix sca...
396
  		return;
de95a54b1   Johannes Berg   mac80211: pass al...
397

2ad2274c5   Ilan Peer   mac80211: Add HE ...
398
399
  	scan_sdata = rcu_dereference_protected(local->scan_sdata,
  					       lockdep_is_held(&local->mtx));
c56ef6725   David Spinadel   mac80211: support...
400
  	if (hw_scan && !aborted &&
30686bf7f   Johannes Berg   mac80211: convert...
401
  	    !ieee80211_hw_check(&local->hw, SINGLE_SCAN_ON_ALL_BANDS) &&
2ad2274c5   Ilan Peer   mac80211: Add HE ...
402
  	    ieee80211_prep_hw_scan(scan_sdata)) {
e2fd5dbc1   Johannes Berg   mac80211: make sc...
403
404
405
406
407
408
  		int rc;
  
  		rc = drv_hw_scan(local,
  			rcu_dereference_protected(local->scan_sdata,
  						  lockdep_is_held(&local->mtx)),
  			local->hw_scan_req);
6eb11a9a3   Stanislaw Gruszka   mac80211: do not ...
409
  		if (rc == 0)
d07bfd8b6   Johannes Berg   mac80211: fix sca...
410
  			return;
7947d3e07   Avraham Stern   mac80211: Add sup...
411

7d10f6b17   Johannes Berg   mac80211: report ...
412
413
  		/* HW scan failed and is going to be reported as aborted,
  		 * so clear old scan info.
7947d3e07   Avraham Stern   mac80211: Add sup...
414
415
  		 */
  		memset(&local->scan_info, 0, sizeof(local->scan_info));
7d10f6b17   Johannes Berg   mac80211: report ...
416
  		aborted = true;
4d36ec582   Johannes Berg   mac80211: split h...
417
418
419
420
  	}
  
  	kfree(local->hw_scan_req);
  	local->hw_scan_req = NULL;
f3b85252f   Johannes Berg   mac80211: fix sca...
421

6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
422
423
  	scan_req = rcu_dereference_protected(local->scan_req,
  					     lockdep_is_held(&local->mtx));
1d76250bd   Avraham Stern   nl80211: support ...
424
  	if (scan_req != local->int_scan_req) {
7947d3e07   Avraham Stern   mac80211: Add sup...
425
426
  		local->scan_info.aborted = aborted;
  		cfg80211_scan_done(scan_req, &local->scan_info);
1d76250bd   Avraham Stern   nl80211: support ...
427
  	}
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
428
  	RCU_INIT_POINTER(local->scan_req, NULL);
0c2bef462   Monam Agarwal   mac80211: use RCU...
429
  	RCU_INIT_POINTER(local->scan_sdata, NULL);
2a5193119   Johannes Berg   cfg80211/nl80211:...
430

fbe9c429f   Helmut Schaa   mac80211: Replace...
431
  	local->scanning = 0;
7ca15a0ae   Simon Wunderlich   mac80211: allow s...
432
  	local->scan_chandef.chan = NULL;
f3b85252f   Johannes Berg   mac80211: fix sca...
433

07ef03ee8   Johannes Berg   mac80211: simplif...
434
435
  	/* Set power back to normal operating levels. */
  	ieee80211_hw_config(local, 0);
a0daa0e75   Luis R. Rodriguez   Revert "mac80211:...
436

8bd2a2489   Eliad Peller   mac80211: determi...
437
  	if (!hw_scan) {
e229f844d   Stanislaw Gruszka   mac80211: keep lo...
438
  		ieee80211_configure_filter(local);
a344d6778   Johannes Berg   mac80211: allow d...
439
  		drv_sw_scan_complete(local, scan_sdata);
aacde9ee4   Stanislaw Gruszka   mac80211: synchro...
440
  		ieee80211_offchannel_return(local);
e229f844d   Stanislaw Gruszka   mac80211: keep lo...
441
  	}
0a51b27e9   Johannes Berg   mac80211: start m...
442

5cff20e6c   Johannes Berg   mac80211: tell dr...
443
  	ieee80211_recalc_idle(local);
e229f844d   Stanislaw Gruszka   mac80211: keep lo...
444

0a51b27e9   Johannes Berg   mac80211: start m...
445
  	ieee80211_mlme_notify_scan_completed(local);
469002983   Johannes Berg   mac80211: split I...
446
  	ieee80211_ibss_notify_scan_completed(local);
4fa11ec72   Sachin Kulkarni   mac80211: Requeue...
447
448
449
450
451
452
453
454
455
  
  	/* Requeue all the work that might have been ignored while
  	 * the scan was in progress; if there was none this will
  	 * just be a no-op for the particular interface.
  	 */
  	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
  		if (ieee80211_sdata_running(sdata))
  			ieee80211_queue_work(&sdata->local->hw, &sdata->work);
  	}
a2b70e833   Eliad Peller   mac80211: start_n...
456
457
  	if (was_scanning)
  		ieee80211_start_next_roc(local);
0a51b27e9   Johannes Berg   mac80211: start m...
458
  }
8789d459b   Johannes Berg   mac80211: allow s...
459

7947d3e07   Avraham Stern   mac80211: Add sup...
460
461
  void ieee80211_scan_completed(struct ieee80211_hw *hw,
  			      struct cfg80211_scan_info *info)
8789d459b   Johannes Berg   mac80211: allow s...
462
463
  {
  	struct ieee80211_local *local = hw_to_local(hw);
58bd7f115   Johannes Berg   mac80211: fix sca...
464
  	trace_api_scan_completed(local, info->aborted);
8789d459b   Johannes Berg   mac80211: allow s...
465
466
  
  	set_bit(SCAN_COMPLETED, &local->scanning);
7947d3e07   Avraham Stern   mac80211: Add sup...
467
  	if (info->aborted)
8789d459b   Johannes Berg   mac80211: allow s...
468
  		set_bit(SCAN_ABORTED, &local->scanning);
7947d3e07   Avraham Stern   mac80211: Add sup...
469
470
  
  	memcpy(&local->scan_info, info, sizeof(*info));
8789d459b   Johannes Berg   mac80211: allow s...
471
472
  	ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0);
  }
0a51b27e9   Johannes Berg   mac80211: start m...
473
  EXPORT_SYMBOL(ieee80211_scan_completed);
a344d6778   Johannes Berg   mac80211: allow d...
474
475
  static int ieee80211_start_sw_scan(struct ieee80211_local *local,
  				   struct ieee80211_sub_if_data *sdata)
f3b85252f   Johannes Berg   mac80211: fix sca...
476
  {
fe57d9f5c   Johannes Berg   mac80211: track w...
477
478
479
  	/* Software scan is not supported in multi-channel cases */
  	if (local->use_chanctx)
  		return -EOPNOTSUPP;
f3b85252f   Johannes Berg   mac80211: fix sca...
480
481
482
483
484
485
486
487
488
489
490
491
492
  	/*
  	 * Hardware/driver doesn't support hw_scan, so use software
  	 * scanning instead. First send a nullfunc frame with power save
  	 * bit on so that AP will buffer the frames for us while we are not
  	 * listening, then send probe requests to each channel and wait for
  	 * the responses. After all channels are scanned, tune back to the
  	 * original channel and send a nullfunc frame with power save bit
  	 * off to trigger the AP to send us all the buffered frames.
  	 *
  	 * Note that while local->sw_scanning is true everything else but
  	 * nullfunc frames and probe requests will be dropped in
  	 * ieee80211_tx_h_check_assoc().
  	 */
a344d6778   Johannes Berg   mac80211: allow d...
493
  	drv_sw_scan_start(local, sdata, local->scan_addr);
f3b85252f   Johannes Berg   mac80211: fix sca...
494

de312db34   Rajkumar Manoharan   mac80211: fix ope...
495
  	local->leave_oper_channel_time = jiffies;
977923b00   Helmut Schaa   mac80211: rename ...
496
  	local->next_scan_state = SCAN_DECISION;
f3b85252f   Johannes Berg   mac80211: fix sca...
497
  	local->scan_channel_idx = 0;
aacde9ee4   Stanislaw Gruszka   mac80211: synchro...
498
  	ieee80211_offchannel_stop_vifs(local);
a80f7c0b0   Johannes Berg   mac80211: introdu...
499

9c35d7d23   Seth Forshee   mac80211: Add flu...
500
  	/* ensure nullfunc is transmitted before leaving operating channel */
3b24f4c65   Emmanuel Grumbach   mac80211: let flu...
501
  	ieee80211_flush_queues(local, NULL, false);
9c35d7d23   Seth Forshee   mac80211: Add flu...
502

3ac64beec   Johannes Berg   mac80211: allow c...
503
  	ieee80211_configure_filter(local);
f3b85252f   Johannes Berg   mac80211: fix sca...
504

59bdf3b0f   Ben Greear   mac80211: Ensure ...
505
506
  	/* We need to set power level at maximum rate for scanning. */
  	ieee80211_hw_config(local, 0);
42935ecaf   Luis R. Rodriguez   mac80211: redefin...
507
  	ieee80211_queue_delayed_work(&local->hw,
07ef03ee8   Johannes Berg   mac80211: simplif...
508
  				     &local->scan_work, 0);
f3b85252f   Johannes Berg   mac80211: fix sca...
509
510
511
  
  	return 0;
  }
dc0c18ed2   Aaron Komisar   mac80211: fix sca...
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
  static bool __ieee80211_can_leave_ch(struct ieee80211_sub_if_data *sdata)
  {
  	struct ieee80211_local *local = sdata->local;
  	struct ieee80211_sub_if_data *sdata_iter;
  
  	if (!ieee80211_is_radar_required(local))
  		return true;
  
  	if (!regulatory_pre_cac_allowed(local->hw.wiphy))
  		return false;
  
  	mutex_lock(&local->iflist_mtx);
  	list_for_each_entry(sdata_iter, &local->interfaces, list) {
  		if (sdata_iter->wdev.cac_started) {
  			mutex_unlock(&local->iflist_mtx);
  			return false;
  		}
  	}
  	mutex_unlock(&local->iflist_mtx);
  
  	return true;
  }
133d40f9a   Stanislaw Gruszka   mac80211: do not ...
534
535
536
  static bool ieee80211_can_scan(struct ieee80211_local *local,
  			       struct ieee80211_sub_if_data *sdata)
  {
dc0c18ed2   Aaron Komisar   mac80211: fix sca...
537
  	if (!__ieee80211_can_leave_ch(sdata))
164eb02d0   Simon Wunderlich   mac80211: add rad...
538
  		return false;
2eb278e08   Johannes Berg   mac80211: unify S...
539
  	if (!list_empty(&local->roc_list))
133d40f9a   Stanislaw Gruszka   mac80211: do not ...
540
541
542
  		return false;
  
  	if (sdata->vif.type == NL80211_IFTYPE_STATION &&
392b9ffb0   Stanislaw Gruszka   mac80211: change ...
543
  	    sdata->u.mgd.flags & IEEE80211_STA_CONNECTION_POLL)
133d40f9a   Stanislaw Gruszka   mac80211: do not ...
544
545
546
547
548
549
550
551
552
553
554
  		return false;
  
  	return true;
  }
  
  void ieee80211_run_deferred_scan(struct ieee80211_local *local)
  {
  	lockdep_assert_held(&local->mtx);
  
  	if (!local->scan_req || local->scanning)
  		return;
e2fd5dbc1   Johannes Berg   mac80211: make sc...
555
556
557
558
  	if (!ieee80211_can_scan(local,
  				rcu_dereference_protected(
  					local->scan_sdata,
  					lockdep_is_held(&local->mtx))))
133d40f9a   Stanislaw Gruszka   mac80211: do not ...
559
560
561
562
563
  		return;
  
  	ieee80211_queue_delayed_work(&local->hw, &local->scan_work,
  				     round_jiffies_relative(0));
  }
f3b85252f   Johannes Berg   mac80211: fix sca...
564

45ad68348   Johannes Berg   mac80211: split i...
565
566
567
568
569
570
571
572
573
574
575
576
  static void ieee80211_send_scan_probe_req(struct ieee80211_sub_if_data *sdata,
  					  const u8 *src, const u8 *dst,
  					  const u8 *ssid, size_t ssid_len,
  					  const u8 *ie, size_t ie_len,
  					  u32 ratemask, u32 flags, u32 tx_flags,
  					  struct ieee80211_channel *channel)
  {
  	struct sk_buff *skb;
  
  	skb = ieee80211_build_probe_req(sdata, src, dst, ratemask, channel,
  					ssid, ssid_len,
  					ie, ie_len, flags);
b9771d41a   Johannes Berg   mac80211: support...
577

45ad68348   Johannes Berg   mac80211: split i...
578
  	if (skb) {
b9771d41a   Johannes Berg   mac80211: support...
579
580
  		if (flags & IEEE80211_PROBE_FLAG_RANDOM_SN) {
  			struct ieee80211_hdr *hdr = (void *)skb->data;
2b3dab135   Mathy Vanhoef   mac80211: use sam...
581
  			struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
b9771d41a   Johannes Berg   mac80211: support...
582
  			u16 sn = get_random_u32();
2b3dab135   Mathy Vanhoef   mac80211: use sam...
583
  			info->control.flags |= IEEE80211_TX_CTRL_NO_SEQNO;
b9771d41a   Johannes Berg   mac80211: support...
584
585
586
  			hdr->seq_ctrl =
  				cpu_to_le16(IEEE80211_SN_TO_SEQ(sn));
  		}
45ad68348   Johannes Berg   mac80211: split i...
587
  		IEEE80211_SKB_CB(skb)->flags |= tx_flags;
08aca29aa   Mathy Vanhoef   mac80211: remove ...
588
  		ieee80211_tx_skb_tid_band(sdata, skb, 7, channel->band);
45ad68348   Johannes Berg   mac80211: split i...
589
590
  	}
  }
8a690674e   Ben Greear   mac80211: Support...
591
592
593
594
  static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
  					    unsigned long *next_delay)
  {
  	int i;
e2fd5dbc1   Johannes Berg   mac80211: make sc...
595
  	struct ieee80211_sub_if_data *sdata;
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
596
  	struct cfg80211_scan_request *scan_req;
57fbcce37   Johannes Berg   cfg80211: remove ...
597
  	enum nl80211_band band = local->hw.conf.chandef.chan->band;
b9771d41a   Johannes Berg   mac80211: support...
598
  	u32 flags = 0, tx_flags;
6c17b77b6   Seth Forshee   mac80211: Fix tx ...
599

6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
600
601
  	scan_req = rcu_dereference_protected(local->scan_req,
  					     lockdep_is_held(&local->mtx));
6c17b77b6   Seth Forshee   mac80211: Fix tx ...
602
  	tx_flags = IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
603
  	if (scan_req->no_cck)
6c17b77b6   Seth Forshee   mac80211: Fix tx ...
604
  		tx_flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
b9771d41a   Johannes Berg   mac80211: support...
605
606
607
608
  	if (scan_req->flags & NL80211_SCAN_FLAG_MIN_PREQ_CONTENT)
  		flags |= IEEE80211_PROBE_FLAG_MIN_CONTENT;
  	if (scan_req->flags & NL80211_SCAN_FLAG_RANDOM_SN)
  		flags |= IEEE80211_PROBE_FLAG_RANDOM_SN;
8a690674e   Ben Greear   mac80211: Support...
609

e2fd5dbc1   Johannes Berg   mac80211: make sc...
610
  	sdata = rcu_dereference_protected(local->scan_sdata,
316b6b5df   Peter Senna Tschudin   net/mac80211/scan...
611
  					  lockdep_is_held(&local->mtx));
e2fd5dbc1   Johannes Berg   mac80211: make sc...
612

6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
613
  	for (i = 0; i < scan_req->n_ssids; i++)
45ad68348   Johannes Berg   mac80211: split i...
614
  		ieee80211_send_scan_probe_req(
e345f44f2   Jouni Malinen   mac80211: Support...
615
  			sdata, local->scan_addr, scan_req->bssid,
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
616
617
  			scan_req->ssids[i].ssid, scan_req->ssids[i].ssid_len,
  			scan_req->ie, scan_req->ie_len,
b9771d41a   Johannes Berg   mac80211: support...
618
  			scan_req->rates[band], flags,
45ad68348   Johannes Berg   mac80211: split i...
619
  			tx_flags, local->hw.conf.chandef.chan);
8a690674e   Ben Greear   mac80211: Support...
620
621
622
623
624
625
626
627
  
  	/*
  	 * After sending probe requests, wait for probe responses
  	 * on the channel.
  	 */
  	*next_delay = IEEE80211_CHANNEL_TIME;
  	local->next_scan_state = SCAN_DECISION;
  }
f3b85252f   Johannes Berg   mac80211: fix sca...
628
629
630
631
  static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
  				  struct cfg80211_scan_request *req)
  {
  	struct ieee80211_local *local = sdata->local;
e9da68dde   Johannes Berg   mac80211: allow h...
632
  	bool hw_scan = local->ops->hw_scan;
f3b85252f   Johannes Berg   mac80211: fix sca...
633
  	int rc;
e229f844d   Stanislaw Gruszka   mac80211: keep lo...
634
  	lockdep_assert_held(&local->mtx);
dc0c18ed2   Aaron Komisar   mac80211: fix sca...
635
636
637
638
  	if (local->scan_req)
  		return -EBUSY;
  
  	if (!__ieee80211_can_leave_ch(sdata))
f3b85252f   Johannes Berg   mac80211: fix sca...
639
  		return -EBUSY;
133d40f9a   Stanislaw Gruszka   mac80211: do not ...
640
  	if (!ieee80211_can_scan(local, sdata)) {
6e7e6213e   John W. Linville   Merge branch 'mas...
641
  		/* wait for the work to finish/time out */
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
642
  		rcu_assign_pointer(local->scan_req, req);
e2fd5dbc1   Johannes Berg   mac80211: make sc...
643
  		rcu_assign_pointer(local->scan_sdata, sdata);
c0ce77b83   Johannes Berg   mac80211: fix def...
644
645
  		return 0;
  	}
e9da68dde   Johannes Berg   mac80211: allow h...
646
647
   again:
  	if (hw_scan) {
f3b85252f   Johannes Berg   mac80211: fix sca...
648
  		u8 *ies;
f3b85252f   Johannes Berg   mac80211: fix sca...
649

e4dcbb375   David Spinadel   mac80211: fix IE ...
650
  		local->hw_scan_ies_bufsize = local->scan_ies_len + req->ie_len;
c56ef6725   David Spinadel   mac80211: support...
651

30686bf7f   Johannes Berg   mac80211: convert...
652
  		if (ieee80211_hw_check(&local->hw, SINGLE_SCAN_ON_ALL_BANDS)) {
c56ef6725   David Spinadel   mac80211: support...
653
654
655
656
657
658
659
660
661
662
663
664
  			int i, n_bands = 0;
  			u8 bands_counted = 0;
  
  			for (i = 0; i < req->n_channels; i++) {
  				if (bands_counted & BIT(req->channels[i]->band))
  					continue;
  				bands_counted |= BIT(req->channels[i]->band);
  				n_bands++;
  			}
  
  			local->hw_scan_ies_bufsize *= n_bands;
  		}
4d36ec582   Johannes Berg   mac80211: split h...
665
666
667
  		local->hw_scan_req = kmalloc(
  				sizeof(*local->hw_scan_req) +
  				req->n_channels * sizeof(req->channels[0]) +
c604b9f21   Johannes Berg   mac80211: make ie...
668
  				local->hw_scan_ies_bufsize, GFP_KERNEL);
4d36ec582   Johannes Berg   mac80211: split h...
669
  		if (!local->hw_scan_req)
f3b85252f   Johannes Berg   mac80211: fix sca...
670
  			return -ENOMEM;
c56ef6725   David Spinadel   mac80211: support...
671
672
  		local->hw_scan_req->req.ssids = req->ssids;
  		local->hw_scan_req->req.n_ssids = req->n_ssids;
4d36ec582   Johannes Berg   mac80211: split h...
673
674
675
  		ies = (u8 *)local->hw_scan_req +
  			sizeof(*local->hw_scan_req) +
  			req->n_channels * sizeof(req->channels[0]);
c56ef6725   David Spinadel   mac80211: support...
676
677
  		local->hw_scan_req->req.ie = ies;
  		local->hw_scan_req->req.flags = req->flags;
e345f44f2   Jouni Malinen   mac80211: Support...
678
  		eth_broadcast_addr(local->hw_scan_req->req.bssid);
7947d3e07   Avraham Stern   mac80211: Add sup...
679
680
681
  		local->hw_scan_req->req.duration = req->duration;
  		local->hw_scan_req->req.duration_mandatory =
  			req->duration_mandatory;
4d36ec582   Johannes Berg   mac80211: split h...
682
683
  
  		local->hw_scan_band = 0;
c8cb5b854   Tova Mussai   nl80211/cfg80211:...
684
685
686
687
  		local->hw_scan_req->req.n_6ghz_params = req->n_6ghz_params;
  		local->hw_scan_req->req.scan_6ghz_params =
  			req->scan_6ghz_params;
  		local->hw_scan_req->req.scan_6ghz = req->scan_6ghz;
6e7e6213e   John W. Linville   Merge branch 'mas...
688
689
690
691
692
693
694
695
  
  		/*
  		 * After allocating local->hw_scan_req, we must
  		 * go through until ieee80211_prep_hw_scan(), so
  		 * anything that might be changed here and leave
  		 * this function early must not go after this
  		 * allocation.
  		 */
f3b85252f   Johannes Berg   mac80211: fix sca...
696
  	}
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
697
  	rcu_assign_pointer(local->scan_req, req);
e2fd5dbc1   Johannes Berg   mac80211: make sc...
698
  	rcu_assign_pointer(local->scan_sdata, sdata);
f3b85252f   Johannes Berg   mac80211: fix sca...
699

a344d6778   Johannes Berg   mac80211: allow d...
700
701
702
703
704
705
  	if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)
  		get_random_mask_addr(local->scan_addr,
  				     req->mac_addr,
  				     req->mac_addr_mask);
  	else
  		memcpy(local->scan_addr, sdata->vif.addr, ETH_ALEN);
e9da68dde   Johannes Berg   mac80211: allow h...
706
  	if (hw_scan) {
fbe9c429f   Helmut Schaa   mac80211: Replace...
707
  		__set_bit(SCAN_HW_SCANNING, &local->scanning);
8a690674e   Ben Greear   mac80211: Support...
708
  	} else if ((req->n_channels == 1) &&
675a0b049   Karl Beldan   mac80211: Use a c...
709
  		   (req->channels[0] == local->_oper_chandef.chan)) {
9b8648704   Johannes Berg   mac80211: check o...
710
711
712
  		/*
  		 * If we are scanning only on the operating channel
  		 * then we do not need to stop normal activities
8a690674e   Ben Greear   mac80211: Support...
713
714
715
716
717
718
719
720
721
  		 */
  		unsigned long next_delay;
  
  		__set_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning);
  
  		ieee80211_recalc_idle(local);
  
  		/* Notify driver scan is starting, keep order of operations
  		 * same as normal software scan, in case that matters. */
a344d6778   Johannes Berg   mac80211: allow d...
722
  		drv_sw_scan_start(local, sdata, local->scan_addr);
8a690674e   Ben Greear   mac80211: Support...
723
724
725
726
727
  
  		ieee80211_configure_filter(local); /* accept probe-responses */
  
  		/* We need to ensure power level is at max for scanning. */
  		ieee80211_hw_config(local, 0);
4e39ccac0   Antonio Quartulli   mac80211: do not ...
728
729
  		if ((req->channels[0]->flags & (IEEE80211_CHAN_NO_IR |
  						IEEE80211_CHAN_RADAR)) ||
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
730
  		    !req->n_ssids) {
8a690674e   Ben Greear   mac80211: Support...
731
732
733
734
735
736
737
738
739
740
741
742
  			next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
  		} else {
  			ieee80211_scan_state_send_probe(local, &next_delay);
  			next_delay = IEEE80211_CHANNEL_TIME;
  		}
  
  		/* Now, just wait a bit and we are all done! */
  		ieee80211_queue_delayed_work(&local->hw, &local->scan_work,
  					     next_delay);
  		return 0;
  	} else {
  		/* Do normal software scan */
fbe9c429f   Helmut Schaa   mac80211: Replace...
743
  		__set_bit(SCAN_SW_SCANNING, &local->scanning);
8a690674e   Ben Greear   mac80211: Support...
744
  	}
6e7e6213e   John W. Linville   Merge branch 'mas...
745

5cff20e6c   Johannes Berg   mac80211: tell dr...
746
  	ieee80211_recalc_idle(local);
f3b85252f   Johannes Berg   mac80211: fix sca...
747

e9da68dde   Johannes Berg   mac80211: allow h...
748
  	if (hw_scan) {
2ad2274c5   Ilan Peer   mac80211: Add HE ...
749
  		WARN_ON(!ieee80211_prep_hw_scan(sdata));
a060bbfe4   Johannes Berg   mac80211: give vi...
750
  		rc = drv_hw_scan(local, sdata, local->hw_scan_req);
a344d6778   Johannes Berg   mac80211: allow d...
751
752
753
  	} else {
  		rc = ieee80211_start_sw_scan(local, sdata);
  	}
f3b85252f   Johannes Berg   mac80211: fix sca...
754

f3b85252f   Johannes Berg   mac80211: fix sca...
755
  	if (rc) {
4d36ec582   Johannes Berg   mac80211: split h...
756
757
  		kfree(local->hw_scan_req);
  		local->hw_scan_req = NULL;
fbe9c429f   Helmut Schaa   mac80211: Replace...
758
  		local->scanning = 0;
f3b85252f   Johannes Berg   mac80211: fix sca...
759

5cff20e6c   Johannes Berg   mac80211: tell dr...
760
  		ieee80211_recalc_idle(local);
f3b85252f   Johannes Berg   mac80211: fix sca...
761
  		local->scan_req = NULL;
0c2bef462   Monam Agarwal   mac80211: use RCU...
762
  		RCU_INIT_POINTER(local->scan_sdata, NULL);
f3b85252f   Johannes Berg   mac80211: fix sca...
763
  	}
e9da68dde   Johannes Berg   mac80211: allow h...
764
765
766
767
768
769
770
771
772
773
774
  	if (hw_scan && rc == 1) {
  		/*
  		 * we can't fall back to software for P2P-GO
  		 * as it must update NoA etc.
  		 */
  		if (ieee80211_vif_type_p2p(&sdata->vif) ==
  				NL80211_IFTYPE_P2P_GO)
  			return -EOPNOTSUPP;
  		hw_scan = false;
  		goto again;
  	}
f3b85252f   Johannes Berg   mac80211: fix sca...
775
776
  	return rc;
  }
df13cce53   Helmut Schaa   mac80211: Improve...
777
778
779
780
781
782
783
  static unsigned long
  ieee80211_scan_get_channel_time(struct ieee80211_channel *chan)
  {
  	/*
  	 * TODO: channel switching also consumes quite some time,
  	 * add that delay as well to get a better estimation
  	 */
4e39ccac0   Antonio Quartulli   mac80211: do not ...
784
  	if (chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR))
df13cce53   Helmut Schaa   mac80211: Improve...
785
786
787
  		return IEEE80211_PASSIVE_CHANNEL_TIME;
  	return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME;
  }
e229f844d   Stanislaw Gruszka   mac80211: keep lo...
788
789
  static void ieee80211_scan_state_decision(struct ieee80211_local *local,
  					  unsigned long *next_delay)
7d3be3cc4   Helmut Schaa   mac80211: refacto...
790
  {
142b9f507   Helmut Schaa   mac80211: impleme...
791
  	bool associated = false;
df13cce53   Helmut Schaa   mac80211: Improve...
792
793
  	bool tx_empty = true;
  	bool bad_latency;
142b9f507   Helmut Schaa   mac80211: impleme...
794
  	struct ieee80211_sub_if_data *sdata;
df13cce53   Helmut Schaa   mac80211: Improve...
795
  	struct ieee80211_channel *next_chan;
cd2bb512c   Sam Leffler   mac80211: add sup...
796
  	enum mac80211_scan_state next_scan_state;
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
797
  	struct cfg80211_scan_request *scan_req;
142b9f507   Helmut Schaa   mac80211: impleme...
798

df13cce53   Helmut Schaa   mac80211: Improve...
799
800
801
802
803
  	/*
  	 * check if at least one STA interface is associated,
  	 * check if at least one STA interface has pending tx frames
  	 * and grab the lowest used beacon interval
  	 */
142b9f507   Helmut Schaa   mac80211: impleme...
804
805
  	mutex_lock(&local->iflist_mtx);
  	list_for_each_entry(sdata, &local->interfaces, list) {
9607e6b66   Johannes Berg   mac80211: add iee...
806
  		if (!ieee80211_sdata_running(sdata))
142b9f507   Helmut Schaa   mac80211: impleme...
807
808
809
810
811
  			continue;
  
  		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
  			if (sdata->u.mgd.associated) {
  				associated = true;
df13cce53   Helmut Schaa   mac80211: Improve...
812

df13cce53   Helmut Schaa   mac80211: Improve...
813
814
815
816
  				if (!qdisc_all_tx_empty(sdata->dev)) {
  					tx_empty = false;
  					break;
  				}
142b9f507   Helmut Schaa   mac80211: impleme...
817
818
819
820
  			}
  		}
  	}
  	mutex_unlock(&local->iflist_mtx);
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
821
822
823
824
  	scan_req = rcu_dereference_protected(local->scan_req,
  					     lockdep_is_held(&local->mtx));
  
  	next_chan = scan_req->channels[local->scan_channel_idx];
b23b025fe   Ben Greear   mac80211: Optimiz...
825

a80f7c0b0   Johannes Berg   mac80211: introdu...
826
  	/*
07ef03ee8   Johannes Berg   mac80211: simplif...
827
828
829
830
  	 * we're currently scanning a different channel, let's
  	 * see if we can scan another channel without interfering
  	 * with the current traffic situation.
  	 *
3f892b61a   Stanislaw Gruszka   mac80211: improve...
831
  	 * Keep good latency, do not stay off-channel more than 125 ms.
a80f7c0b0   Johannes Berg   mac80211: introdu...
832
  	 */
a80f7c0b0   Johannes Berg   mac80211: introdu...
833

07ef03ee8   Johannes Berg   mac80211: simplif...
834
  	bad_latency = time_after(jiffies +
3f892b61a   Stanislaw Gruszka   mac80211: improve...
835
836
  				 ieee80211_scan_get_channel_time(next_chan),
  				 local->leave_oper_channel_time + HZ / 8);
142b9f507   Helmut Schaa   mac80211: impleme...
837

cd2bb512c   Sam Leffler   mac80211: add sup...
838
  	if (associated && !tx_empty) {
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
839
  		if (scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY)
cd2bb512c   Sam Leffler   mac80211: add sup...
840
841
842
  			next_scan_state = SCAN_ABORT;
  		else
  			next_scan_state = SCAN_SUSPEND;
3f892b61a   Stanislaw Gruszka   mac80211: improve...
843
  	} else if (associated && bad_latency) {
cd2bb512c   Sam Leffler   mac80211: add sup...
844
845
846
847
848
849
  		next_scan_state = SCAN_SUSPEND;
  	} else {
  		next_scan_state = SCAN_SET_CHANNEL;
  	}
  
  	local->next_scan_state = next_scan_state;
142b9f507   Helmut Schaa   mac80211: impleme...
850

07ef03ee8   Johannes Berg   mac80211: simplif...
851
  	*next_delay = 0;
142b9f507   Helmut Schaa   mac80211: impleme...
852
  }
2fb3f028a   Helmut Schaa   mac80211: introdu...
853
854
855
856
857
  static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
  					     unsigned long *next_delay)
  {
  	int skip;
  	struct ieee80211_channel *chan;
7ca15a0ae   Simon Wunderlich   mac80211: allow s...
858
  	enum nl80211_bss_scan_width oper_scan_width;
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
859
860
861
862
  	struct cfg80211_scan_request *scan_req;
  
  	scan_req = rcu_dereference_protected(local->scan_req,
  					     lockdep_is_held(&local->mtx));
2fb3f028a   Helmut Schaa   mac80211: introdu...
863

7d3be3cc4   Helmut Schaa   mac80211: refacto...
864
  	skip = 0;
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
865
  	chan = scan_req->channels[local->scan_channel_idx];
7d3be3cc4   Helmut Schaa   mac80211: refacto...
866

7ca15a0ae   Simon Wunderlich   mac80211: allow s...
867
868
  	local->scan_chandef.chan = chan;
  	local->scan_chandef.center_freq1 = chan->center_freq;
b6011960f   Thomas Pedersen   mac80211: handle ...
869
  	local->scan_chandef.freq1_offset = chan->freq_offset;
7ca15a0ae   Simon Wunderlich   mac80211: allow s...
870
  	local->scan_chandef.center_freq2 = 0;
75b159353   Thomas Pedersen   mac80211: s1g: ch...
871
872
873
874
875
876
877
878
879
880
  
  	/* For scanning on the S1G band, ignore scan_width (which is constant
  	 * across all channels) for now since channel width is specific to each
  	 * channel. Detect the required channel width here and likely revisit
  	 * later. Maybe scan_width could be used to build the channel scan list?
  	 */
  	if (chan->band == NL80211_BAND_S1GHZ) {
  		local->scan_chandef.width = ieee80211_s1g_channel_width(chan);
  		goto set_channel;
  	}
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
881
  	switch (scan_req->scan_width) {
7ca15a0ae   Simon Wunderlich   mac80211: allow s...
882
883
884
885
886
887
  	case NL80211_BSS_CHAN_WIDTH_5:
  		local->scan_chandef.width = NL80211_CHAN_WIDTH_5;
  		break;
  	case NL80211_BSS_CHAN_WIDTH_10:
  		local->scan_chandef.width = NL80211_CHAN_WIDTH_10;
  		break;
df78a0c0b   Thomas Pedersen   nl80211: S1G band...
888
  	default:
7ca15a0ae   Simon Wunderlich   mac80211: allow s...
889
890
891
892
893
894
895
  	case NL80211_BSS_CHAN_WIDTH_20:
  		/* If scanning on oper channel, use whatever channel-type
  		 * is currently in use.
  		 */
  		oper_scan_width = cfg80211_chandef_to_scan_width(
  					&local->_oper_chandef);
  		if (chan == local->_oper_chandef.chan &&
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
896
  		    oper_scan_width == scan_req->scan_width)
7ca15a0ae   Simon Wunderlich   mac80211: allow s...
897
898
899
900
  			local->scan_chandef = local->_oper_chandef;
  		else
  			local->scan_chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
  		break;
75b159353   Thomas Pedersen   mac80211: s1g: ch...
901
902
903
904
905
  	case NL80211_BSS_CHAN_WIDTH_1:
  	case NL80211_BSS_CHAN_WIDTH_2:
  		/* shouldn't get here, S1G handled above */
  		WARN_ON(1);
  		break;
7ca15a0ae   Simon Wunderlich   mac80211: allow s...
906
  	}
b23b025fe   Ben Greear   mac80211: Optimiz...
907

75b159353   Thomas Pedersen   mac80211: s1g: ch...
908
  set_channel:
07ef03ee8   Johannes Berg   mac80211: simplif...
909
910
  	if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL))
  		skip = 1;
7d3be3cc4   Helmut Schaa   mac80211: refacto...
911

7d3be3cc4   Helmut Schaa   mac80211: refacto...
912
913
  	/* advance state machine to next channel/band */
  	local->scan_channel_idx++;
0ee9c13c7   Helmut Schaa   mac80211: fix an ...
914
915
916
  	if (skip) {
  		/* if we skip this channel return to the decision state */
  		local->next_scan_state = SCAN_DECISION;
2fb3f028a   Helmut Schaa   mac80211: introdu...
917
  		return;
0ee9c13c7   Helmut Schaa   mac80211: fix an ...
918
  	}
7d3be3cc4   Helmut Schaa   mac80211: refacto...
919
920
921
922
923
924
925
926
927
928
929
  
  	/*
  	 * Probe delay is used to update the NAV, cf. 11.1.3.2.2
  	 * (which unfortunately doesn't say _why_ step a) is done,
  	 * but it waits for the probe delay or until a frame is
  	 * received - and the received frame would update the NAV).
  	 * For now, we do not support waiting until a frame is
  	 * received.
  	 *
  	 * In any case, it is not necessary for a passive scan.
  	 */
4e39ccac0   Antonio Quartulli   mac80211: do not ...
930
931
  	if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) ||
  	    !scan_req->n_ssids) {
7d3be3cc4   Helmut Schaa   mac80211: refacto...
932
  		*next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
977923b00   Helmut Schaa   mac80211: rename ...
933
  		local->next_scan_state = SCAN_DECISION;
2fb3f028a   Helmut Schaa   mac80211: introdu...
934
  		return;
7d3be3cc4   Helmut Schaa   mac80211: refacto...
935
  	}
2fb3f028a   Helmut Schaa   mac80211: introdu...
936
  	/* active scan, send probes */
7d3be3cc4   Helmut Schaa   mac80211: refacto...
937
  	*next_delay = IEEE80211_PROBE_DELAY;
977923b00   Helmut Schaa   mac80211: rename ...
938
  	local->next_scan_state = SCAN_SEND_PROBE;
7d3be3cc4   Helmut Schaa   mac80211: refacto...
939
  }
07ef03ee8   Johannes Berg   mac80211: simplif...
940
941
942
943
  static void ieee80211_scan_state_suspend(struct ieee80211_local *local,
  					 unsigned long *next_delay)
  {
  	/* switch back to the operating channel */
7ca15a0ae   Simon Wunderlich   mac80211: allow s...
944
  	local->scan_chandef.chan = NULL;
07ef03ee8   Johannes Berg   mac80211: simplif...
945
  	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
aacde9ee4   Stanislaw Gruszka   mac80211: synchro...
946
947
  	/* disable PS */
  	ieee80211_offchannel_return(local);
07ef03ee8   Johannes Berg   mac80211: simplif...
948
949
950
951
952
953
954
955
956
  
  	*next_delay = HZ / 5;
  	/* afterwards, resume scan & go to next channel */
  	local->next_scan_state = SCAN_RESUME;
  }
  
  static void ieee80211_scan_state_resume(struct ieee80211_local *local,
  					unsigned long *next_delay)
  {
aacde9ee4   Stanislaw Gruszka   mac80211: synchro...
957
  	ieee80211_offchannel_stop_vifs(local);
07ef03ee8   Johannes Berg   mac80211: simplif...
958
959
  
  	if (local->ops->flush) {
3b24f4c65   Emmanuel Grumbach   mac80211: let flu...
960
  		ieee80211_flush_queues(local, NULL, false);
07ef03ee8   Johannes Berg   mac80211: simplif...
961
962
963
964
965
966
967
968
  		*next_delay = 0;
  	} else
  		*next_delay = HZ / 10;
  
  	/* remember when we left the operating channel */
  	local->leave_oper_channel_time = jiffies;
  
  	/* advance to the next channel to be scanned */
de2ee84db   Mohammed Shafi Shajakhan   mac80211: fix sca...
969
  	local->next_scan_state = SCAN_SET_CHANNEL;
07ef03ee8   Johannes Berg   mac80211: simplif...
970
  }
c2b13452b   Johannes Berg   mac80211: clean u...
971
  void ieee80211_scan_work(struct work_struct *work)
0a51b27e9   Johannes Berg   mac80211: start m...
972
973
974
  {
  	struct ieee80211_local *local =
  		container_of(work, struct ieee80211_local, scan_work.work);
d07bfd8b6   Johannes Berg   mac80211: fix sca...
975
  	struct ieee80211_sub_if_data *sdata;
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
976
  	struct cfg80211_scan_request *scan_req;
0a51b27e9   Johannes Berg   mac80211: start m...
977
  	unsigned long next_delay = 0;
8bd2a2489   Eliad Peller   mac80211: determi...
978
  	bool aborted;
0a51b27e9   Johannes Berg   mac80211: start m...
979

259b62e35   Stanislaw Gruszka   mac80211: reduce ...
980
  	mutex_lock(&local->mtx);
8789d459b   Johannes Berg   mac80211: allow s...
981

332ff7fe3   Luciano Coelho   mac80211: complet...
982
983
984
985
  	if (!ieee80211_can_run_worker(local)) {
  		aborted = true;
  		goto out_complete;
  	}
e2fd5dbc1   Johannes Berg   mac80211: make sc...
986
987
  	sdata = rcu_dereference_protected(local->scan_sdata,
  					  lockdep_is_held(&local->mtx));
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
988
989
  	scan_req = rcu_dereference_protected(local->scan_req,
  					     lockdep_is_held(&local->mtx));
d07bfd8b6   Johannes Berg   mac80211: fix sca...
990

8a690674e   Ben Greear   mac80211: Support...
991
992
993
994
995
  	/* When scanning on-channel, the first-callback means completed. */
  	if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) {
  		aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning);
  		goto out_complete;
  	}
259b62e35   Stanislaw Gruszka   mac80211: reduce ...
996
  	if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) {
8789d459b   Johannes Berg   mac80211: allow s...
997
  		aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning);
259b62e35   Stanislaw Gruszka   mac80211: reduce ...
998
  		goto out_complete;
8789d459b   Johannes Berg   mac80211: allow s...
999
  	}
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
1000
  	if (!sdata || !scan_req)
259b62e35   Stanislaw Gruszka   mac80211: reduce ...
1001
  		goto out;
f3b85252f   Johannes Berg   mac80211: fix sca...
1002

ff5db4392   Eliad Peller   mac80211: remove ...
1003
  	if (!local->scanning) {
f3b85252f   Johannes Berg   mac80211: fix sca...
1004
  		int rc;
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
1005
  		RCU_INIT_POINTER(local->scan_req, NULL);
0c2bef462   Monam Agarwal   mac80211: use RCU...
1006
  		RCU_INIT_POINTER(local->scan_sdata, NULL);
f3b85252f   Johannes Berg   mac80211: fix sca...
1007

6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
1008
  		rc = __ieee80211_start_scan(sdata, scan_req);
259b62e35   Stanislaw Gruszka   mac80211: reduce ...
1009
  		if (rc) {
3aed49ef1   Stanislaw Gruszka   mac80211: compete...
1010
  			/* need to complete scan in cfg80211 */
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
1011
  			rcu_assign_pointer(local->scan_req, scan_req);
259b62e35   Stanislaw Gruszka   mac80211: reduce ...
1012
1013
1014
1015
  			aborted = true;
  			goto out_complete;
  		} else
  			goto out;
f3b85252f   Johannes Berg   mac80211: fix sca...
1016
  	}
5bc75728f   Johannes Berg   mac80211: fix sca...
1017
  	/*
f502d09b7   Helmut Schaa   mac80211: advance...
1018
1019
1020
1021
  	 * as long as no delay is required advance immediately
  	 * without scheduling a new work
  	 */
  	do {
c29acf201   Rajkumar Manoharan   mac80211: abort s...
1022
1023
1024
1025
  		if (!ieee80211_sdata_running(sdata)) {
  			aborted = true;
  			goto out_complete;
  		}
977923b00   Helmut Schaa   mac80211: rename ...
1026
  		switch (local->next_scan_state) {
2fb3f028a   Helmut Schaa   mac80211: introdu...
1027
  		case SCAN_DECISION:
e229f844d   Stanislaw Gruszka   mac80211: keep lo...
1028
  			/* if no more bands/channels left, complete scan */
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
1029
  			if (local->scan_channel_idx >= scan_req->n_channels) {
e229f844d   Stanislaw Gruszka   mac80211: keep lo...
1030
1031
1032
1033
  				aborted = false;
  				goto out_complete;
  			}
  			ieee80211_scan_state_decision(local, &next_delay);
f502d09b7   Helmut Schaa   mac80211: advance...
1034
  			break;
2fb3f028a   Helmut Schaa   mac80211: introdu...
1035
1036
1037
  		case SCAN_SET_CHANNEL:
  			ieee80211_scan_state_set_channel(local, &next_delay);
  			break;
f502d09b7   Helmut Schaa   mac80211: advance...
1038
1039
1040
  		case SCAN_SEND_PROBE:
  			ieee80211_scan_state_send_probe(local, &next_delay);
  			break;
07ef03ee8   Johannes Berg   mac80211: simplif...
1041
1042
  		case SCAN_SUSPEND:
  			ieee80211_scan_state_suspend(local, &next_delay);
142b9f507   Helmut Schaa   mac80211: impleme...
1043
  			break;
07ef03ee8   Johannes Berg   mac80211: simplif...
1044
1045
  		case SCAN_RESUME:
  			ieee80211_scan_state_resume(local, &next_delay);
142b9f507   Helmut Schaa   mac80211: impleme...
1046
  			break;
cd2bb512c   Sam Leffler   mac80211: add sup...
1047
1048
1049
  		case SCAN_ABORT:
  			aborted = true;
  			goto out_complete;
f502d09b7   Helmut Schaa   mac80211: advance...
1050
1051
  		}
  	} while (next_delay == 0);
0a51b27e9   Johannes Berg   mac80211: start m...
1052

42935ecaf   Luis R. Rodriguez   mac80211: redefin...
1053
  	ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay);
d07bfd8b6   Johannes Berg   mac80211: fix sca...
1054
  	goto out;
259b62e35   Stanislaw Gruszka   mac80211: reduce ...
1055
1056
  
  out_complete:
8bd2a2489   Eliad Peller   mac80211: determi...
1057
  	__ieee80211_scan_completed(&local->hw, aborted);
259b62e35   Stanislaw Gruszka   mac80211: reduce ...
1058
1059
  out:
  	mutex_unlock(&local->mtx);
0a51b27e9   Johannes Berg   mac80211: start m...
1060
  }
f3b85252f   Johannes Berg   mac80211: fix sca...
1061
1062
  int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
  			   struct cfg80211_scan_request *req)
0a51b27e9   Johannes Berg   mac80211: start m...
1063
  {
f3b85252f   Johannes Berg   mac80211: fix sca...
1064
  	int res;
de95a54b1   Johannes Berg   mac80211: pass al...
1065

a1699b75a   Johannes Berg   mac80211: unify s...
1066
  	mutex_lock(&sdata->local->mtx);
f3b85252f   Johannes Berg   mac80211: fix sca...
1067
  	res = __ieee80211_start_scan(sdata, req);
a1699b75a   Johannes Berg   mac80211: unify s...
1068
  	mutex_unlock(&sdata->local->mtx);
0a51b27e9   Johannes Berg   mac80211: start m...
1069

f3b85252f   Johannes Berg   mac80211: fix sca...
1070
  	return res;
0a51b27e9   Johannes Berg   mac80211: start m...
1071
  }
34bcf7150   Stanislaw Gruszka   mac80211: fix ibs...
1072
1073
  int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
  				const u8 *ssid, u8 ssid_len,
76bed0f43   Janusz.Dziedzic@tieto.com   mac80211: IBSS fi...
1074
1075
  				struct ieee80211_channel **channels,
  				unsigned int n_channels,
7ca15a0ae   Simon Wunderlich   mac80211: allow s...
1076
  				enum nl80211_bss_scan_width scan_width)
0a51b27e9   Johannes Berg   mac80211: start m...
1077
  {
0a51b27e9   Johannes Berg   mac80211: start m...
1078
  	struct ieee80211_local *local = sdata->local;
76bed0f43   Janusz.Dziedzic@tieto.com   mac80211: IBSS fi...
1079
  	int ret = -EBUSY, i, n_ch = 0;
57fbcce37   Johannes Berg   cfg80211: remove ...
1080
  	enum nl80211_band band;
2a5193119   Johannes Berg   cfg80211/nl80211:...
1081

a1699b75a   Johannes Berg   mac80211: unify s...
1082
  	mutex_lock(&local->mtx);
0a51b27e9   Johannes Berg   mac80211: start m...
1083

f3b85252f   Johannes Berg   mac80211: fix sca...
1084
1085
1086
  	/* busy scanning */
  	if (local->scan_req)
  		goto unlock;
9116dd011   Johannes Berg   mac80211: clarify...
1087

be4a4b6a5   Johannes Berg   mac80211: improve...
1088
  	/* fill internal scan request */
76bed0f43   Janusz.Dziedzic@tieto.com   mac80211: IBSS fi...
1089
1090
  	if (!channels) {
  		int max_n;
be4a4b6a5   Johannes Berg   mac80211: improve...
1091

57fbcce37   Johannes Berg   cfg80211: remove ...
1092
  		for (band = 0; band < NUM_NL80211_BANDS; band++) {
c8cb5b854   Tova Mussai   nl80211/cfg80211:...
1093
1094
  			if (!local->hw.wiphy->bands[band] ||
  			    band == NL80211_BAND_6GHZ)
be4a4b6a5   Johannes Berg   mac80211: improve...
1095
  				continue;
34bcf7150   Stanislaw Gruszka   mac80211: fix ibs...
1096
1097
1098
1099
  
  			max_n = local->hw.wiphy->bands[band]->n_channels;
  			for (i = 0; i < max_n; i++) {
  				struct ieee80211_channel *tmp_ch =
be4a4b6a5   Johannes Berg   mac80211: improve...
1100
  				    &local->hw.wiphy->bands[band]->channels[i];
34bcf7150   Stanislaw Gruszka   mac80211: fix ibs...
1101

8fe02e167   Luis R. Rodriguez   cfg80211: consoli...
1102
  				if (tmp_ch->flags & (IEEE80211_CHAN_NO_IR |
34bcf7150   Stanislaw Gruszka   mac80211: fix ibs...
1103
1104
1105
1106
1107
  						     IEEE80211_CHAN_DISABLED))
  					continue;
  
  				local->int_scan_req->channels[n_ch] = tmp_ch;
  				n_ch++;
be4a4b6a5   Johannes Berg   mac80211: improve...
1108
1109
  			}
  		}
34bcf7150   Stanislaw Gruszka   mac80211: fix ibs...
1110
1111
1112
1113
  		if (WARN_ON_ONCE(n_ch == 0))
  			goto unlock;
  
  		local->int_scan_req->n_channels = n_ch;
be4a4b6a5   Johannes Berg   mac80211: improve...
1114
  	} else {
76bed0f43   Janusz.Dziedzic@tieto.com   mac80211: IBSS fi...
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
  		for (i = 0; i < n_channels; i++) {
  			if (channels[i]->flags & (IEEE80211_CHAN_NO_IR |
  						  IEEE80211_CHAN_DISABLED))
  				continue;
  
  			local->int_scan_req->channels[n_ch] = channels[i];
  			n_ch++;
  		}
  
  		if (WARN_ON_ONCE(n_ch == 0))
34bcf7150   Stanislaw Gruszka   mac80211: fix ibs...
1125
  			goto unlock;
76bed0f43   Janusz.Dziedzic@tieto.com   mac80211: IBSS fi...
1126
  		local->int_scan_req->n_channels = n_ch;
be4a4b6a5   Johannes Berg   mac80211: improve...
1127
1128
1129
1130
  	}
  
  	local->int_scan_req->ssids = &local->scan_ssid;
  	local->int_scan_req->n_ssids = 1;
7ca15a0ae   Simon Wunderlich   mac80211: allow s...
1131
  	local->int_scan_req->scan_width = scan_width;
5ba63533b   Johannes Berg   cfg80211: fix ali...
1132
1133
  	memcpy(local->int_scan_req->ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN);
  	local->int_scan_req->ssids[0].ssid_len = ssid_len;
9116dd011   Johannes Berg   mac80211: clarify...
1134

5ba63533b   Johannes Berg   cfg80211: fix ali...
1135
  	ret = __ieee80211_start_scan(sdata, sdata->local->int_scan_req);
f3b85252f   Johannes Berg   mac80211: fix sca...
1136
   unlock:
a1699b75a   Johannes Berg   mac80211: unify s...
1137
  	mutex_unlock(&local->mtx);
f3b85252f   Johannes Berg   mac80211: fix sca...
1138
  	return ret;
0a51b27e9   Johannes Berg   mac80211: start m...
1139
  }
5bb644a0f   Johannes Berg   mac80211: cancel/...
1140

4136c4224   Stanislaw Gruszka   mac80211: assure ...
1141
1142
1143
  /*
   * Only call this function when a scan can't be queued -- under RTNL.
   */
5bb644a0f   Johannes Berg   mac80211: cancel/...
1144
1145
  void ieee80211_scan_cancel(struct ieee80211_local *local)
  {
5bb644a0f   Johannes Berg   mac80211: cancel/...
1146
  	/*
b856439b1   Eliad Peller   mac80211: add can...
1147
  	 * We are canceling software scan, or deferred scan that was not
4136c4224   Stanislaw Gruszka   mac80211: assure ...
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
  	 * yet really started (see __ieee80211_start_scan ).
  	 *
  	 * Regarding hardware scan:
  	 * - we can not call  __ieee80211_scan_completed() as when
  	 *   SCAN_HW_SCANNING bit is set this function change
  	 *   local->hw_scan_req to operate on 5G band, what race with
  	 *   driver which can use local->hw_scan_req
  	 *
  	 * - we can not cancel scan_work since driver can schedule it
  	 *   by ieee80211_scan_completed(..., true) to finish scan
  	 *
b856439b1   Eliad Peller   mac80211: add can...
1159
1160
1161
  	 * Hence we only call the cancel_hw_scan() callback, but the low-level
  	 * driver is still responsible for calling ieee80211_scan_completed()
  	 * after the scan was completed/aborted.
5bb644a0f   Johannes Berg   mac80211: cancel/...
1162
  	 */
4136c4224   Stanislaw Gruszka   mac80211: assure ...
1163

a1699b75a   Johannes Berg   mac80211: unify s...
1164
  	mutex_lock(&local->mtx);
b856439b1   Eliad Peller   mac80211: add can...
1165
1166
  	if (!local->scan_req)
  		goto out;
a754055a1   Emmanuel Grumbach   mac80211: correct...
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
  	/*
  	 * We have a scan running and the driver already reported completion,
  	 * but the worker hasn't run yet or is stuck on the mutex - mark it as
  	 * cancelled.
  	 */
  	if (test_bit(SCAN_HW_SCANNING, &local->scanning) &&
  	    test_bit(SCAN_COMPLETED, &local->scanning)) {
  		set_bit(SCAN_HW_CANCELLED, &local->scanning);
  		goto out;
  	}
b856439b1   Eliad Peller   mac80211: add can...
1177
  	if (test_bit(SCAN_HW_SCANNING, &local->scanning)) {
a754055a1   Emmanuel Grumbach   mac80211: correct...
1178
1179
1180
1181
1182
  		/*
  		 * Make sure that __ieee80211_scan_completed doesn't trigger a
  		 * scan on another band.
  		 */
  		set_bit(SCAN_HW_CANCELLED, &local->scanning);
b856439b1   Eliad Peller   mac80211: add can...
1183
  		if (local->ops->cancel_hw_scan)
e2fd5dbc1   Johannes Berg   mac80211: make sc...
1184
1185
1186
  			drv_cancel_hw_scan(local,
  				rcu_dereference_protected(local->scan_sdata,
  						lockdep_is_held(&local->mtx)));
b856439b1   Eliad Peller   mac80211: add can...
1187
  		goto out;
4136c4224   Stanislaw Gruszka   mac80211: assure ...
1188
  	}
b856439b1   Eliad Peller   mac80211: add can...
1189
1190
1191
1192
1193
1194
1195
1196
  
  	/*
  	 * 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 */
7947d3e07   Avraham Stern   mac80211: Add sup...
1197
  	memset(&local->scan_info, 0, sizeof(local->scan_info));
8bd2a2489   Eliad Peller   mac80211: determi...
1198
  	__ieee80211_scan_completed(&local->hw, true);
b856439b1   Eliad Peller   mac80211: add can...
1199
  out:
d07bfd8b6   Johannes Berg   mac80211: fix sca...
1200
  	mutex_unlock(&local->mtx);
5bb644a0f   Johannes Berg   mac80211: cancel/...
1201
  }
79f460ca4   Luciano Coelho   mac80211: add sup...
1202

d43c6b6e6   David Spinadel   mac80211: resched...
1203
1204
  int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
  					struct cfg80211_sched_scan_request *req)
79f460ca4   Luciano Coelho   mac80211: add sup...
1205
1206
  {
  	struct ieee80211_local *local = sdata->local;
633e27132   David Spinadel   mac80211: split s...
1207
  	struct ieee80211_scan_ies sched_scan_ies = {};
2103dec14   Simon Wunderlich   mac80211: select ...
1208
  	struct cfg80211_chan_def chandef;
633e27132   David Spinadel   mac80211: split s...
1209
  	int ret, i, iebufsz, num_bands = 0;
57fbcce37   Johannes Berg   cfg80211: remove ...
1210
  	u32 rate_masks[NUM_NL80211_BANDS] = {};
633e27132   David Spinadel   mac80211: split s...
1211
1212
  	u8 bands_used = 0;
  	u8 *ie;
b9771d41a   Johannes Berg   mac80211: support...
1213
  	u32 flags = 0;
c604b9f21   Johannes Berg   mac80211: make ie...
1214

e4dcbb375   David Spinadel   mac80211: fix IE ...
1215
  	iebufsz = local->scan_ies_len + req->ie_len;
79f460ca4   Luciano Coelho   mac80211: add sup...
1216

d43c6b6e6   David Spinadel   mac80211: resched...
1217
  	lockdep_assert_held(&local->mtx);
79f460ca4   Luciano Coelho   mac80211: add sup...
1218

d43c6b6e6   David Spinadel   mac80211: resched...
1219
1220
  	if (!local->ops->sched_scan_start)
  		return -ENOTSUPP;
79f460ca4   Luciano Coelho   mac80211: add sup...
1221

57fbcce37   Johannes Berg   cfg80211: remove ...
1222
  	for (i = 0; i < NUM_NL80211_BANDS; i++) {
633e27132   David Spinadel   mac80211: split s...
1223
1224
1225
1226
  		if (local->hw.wiphy->bands[i]) {
  			bands_used |= BIT(i);
  			rate_masks[i] = (u32) -1;
  			num_bands++;
79f460ca4   Luciano Coelho   mac80211: add sup...
1227
  		}
633e27132   David Spinadel   mac80211: split s...
1228
  	}
79f460ca4   Luciano Coelho   mac80211: add sup...
1229

b9771d41a   Johannes Berg   mac80211: support...
1230
1231
  	if (req->flags & NL80211_SCAN_FLAG_MIN_PREQ_CONTENT)
  		flags |= IEEE80211_PROBE_FLAG_MIN_CONTENT;
6396bb221   Kees Cook   treewide: kzalloc...
1232
  	ie = kcalloc(iebufsz, num_bands, GFP_KERNEL);
633e27132   David Spinadel   mac80211: split s...
1233
1234
1235
  	if (!ie) {
  		ret = -ENOMEM;
  		goto out;
79f460ca4   Luciano Coelho   mac80211: add sup...
1236
  	}
633e27132   David Spinadel   mac80211: split s...
1237
  	ieee80211_prepare_scan_chandef(&chandef, req->scan_width);
2ad2274c5   Ilan Peer   mac80211: Add HE ...
1238
  	ieee80211_build_preq_ies(sdata, ie, num_bands * iebufsz,
cd5861bde   Kirtika Ruchandani   mac80211: Remove ...
1239
  				 &sched_scan_ies, req->ie,
00387f321   Johannes Berg   mac80211: add pro...
1240
  				 req->ie_len, bands_used, rate_masks, &chandef,
b9771d41a   Johannes Berg   mac80211: support...
1241
  				 flags);
633e27132   David Spinadel   mac80211: split s...
1242

30dd3edf9   Johannes Berg   mac80211: don't h...
1243
  	ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies);
d43c6b6e6   David Spinadel   mac80211: resched...
1244
  	if (ret == 0) {
5260a5b2c   Johannes Berg   mac80211: track s...
1245
  		rcu_assign_pointer(local->sched_scan_sdata, sdata);
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
1246
  		rcu_assign_pointer(local->sched_scan_req, req);
d43c6b6e6   David Spinadel   mac80211: resched...
1247
  	}
79f460ca4   Luciano Coelho   mac80211: add sup...
1248

633e27132   David Spinadel   mac80211: split s...
1249
  	kfree(ie);
d43c6b6e6   David Spinadel   mac80211: resched...
1250

633e27132   David Spinadel   mac80211: split s...
1251
  out:
d43c6b6e6   David Spinadel   mac80211: resched...
1252
1253
  	if (ret) {
  		/* Clean in case of failure after HW restart or upon resume. */
0c2bef462   Monam Agarwal   mac80211: use RCU...
1254
  		RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
1255
  		RCU_INIT_POINTER(local->sched_scan_req, NULL);
d43c6b6e6   David Spinadel   mac80211: resched...
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
  	}
  
  	return ret;
  }
  
  int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
  				       struct cfg80211_sched_scan_request *req)
  {
  	struct ieee80211_local *local = sdata->local;
  	int ret;
  
  	mutex_lock(&local->mtx);
  
  	if (rcu_access_pointer(local->sched_scan_sdata)) {
  		mutex_unlock(&local->mtx);
  		return -EBUSY;
  	}
  
  	ret = __ieee80211_request_sched_scan_start(sdata, req);
5260a5b2c   Johannes Berg   mac80211: track s...
1275
  	mutex_unlock(&local->mtx);
79f460ca4   Luciano Coelho   mac80211: add sup...
1276
1277
  	return ret;
  }
0d440ea29   Eliad Peller   mac80211: don't r...
1278
  int ieee80211_request_sched_scan_stop(struct ieee80211_local *local)
79f460ca4   Luciano Coelho   mac80211: add sup...
1279
  {
0d440ea29   Eliad Peller   mac80211: don't r...
1280
1281
  	struct ieee80211_sub_if_data *sched_scan_sdata;
  	int ret = -ENOENT;
79f460ca4   Luciano Coelho   mac80211: add sup...
1282

5260a5b2c   Johannes Berg   mac80211: track s...
1283
  	mutex_lock(&local->mtx);
79f460ca4   Luciano Coelho   mac80211: add sup...
1284
1285
1286
1287
1288
  
  	if (!local->ops->sched_scan_stop) {
  		ret = -ENOTSUPP;
  		goto out;
  	}
d43c6b6e6   David Spinadel   mac80211: resched...
1289
  	/* We don't want to restart sched scan anymore. */
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
1290
  	RCU_INIT_POINTER(local->sched_scan_req, NULL);
d43c6b6e6   David Spinadel   mac80211: resched...
1291

0d440ea29   Eliad Peller   mac80211: don't r...
1292
1293
1294
1295
  	sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
  						lockdep_is_held(&local->mtx));
  	if (sched_scan_sdata) {
  		ret = drv_sched_scan_stop(local, sched_scan_sdata);
71228a1ea   Alexander Bondar   mac80211: release...
1296
  		if (!ret)
ad053a962   Andreea-Cristina Bernat   mac80211: scan: R...
1297
  			RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
71228a1ea   Alexander Bondar   mac80211: release...
1298
  	}
79f460ca4   Luciano Coelho   mac80211: add sup...
1299
  out:
5260a5b2c   Johannes Berg   mac80211: track s...
1300
  	mutex_unlock(&local->mtx);
79f460ca4   Luciano Coelho   mac80211: add sup...
1301
1302
1303
1304
1305
1306
1307
1308
1309
  
  	return ret;
  }
  
  void ieee80211_sched_scan_results(struct ieee80211_hw *hw)
  {
  	struct ieee80211_local *local = hw_to_local(hw);
  
  	trace_api_sched_scan_results(local);
b34939b98   Arend Van Spriel   cfg80211: add req...
1310
  	cfg80211_sched_scan_results(hw->wiphy, 0);
79f460ca4   Luciano Coelho   mac80211: add sup...
1311
1312
  }
  EXPORT_SYMBOL(ieee80211_sched_scan_results);
f6837ba8c   Johannes Berg   mac80211: handle ...
1313
  void ieee80211_sched_scan_end(struct ieee80211_local *local)
85a9994a0   Luciano Coelho   cfg80211/mac80211...
1314
  {
85a9994a0   Luciano Coelho   cfg80211/mac80211...
1315
  	mutex_lock(&local->mtx);
5260a5b2c   Johannes Berg   mac80211: track s...
1316
  	if (!rcu_access_pointer(local->sched_scan_sdata)) {
85a9994a0   Luciano Coelho   cfg80211/mac80211...
1317
1318
1319
  		mutex_unlock(&local->mtx);
  		return;
  	}
0c2bef462   Monam Agarwal   mac80211: use RCU...
1320
  	RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
85a9994a0   Luciano Coelho   cfg80211/mac80211...
1321

d43c6b6e6   David Spinadel   mac80211: resched...
1322
  	/* If sched scan was aborted by the driver. */
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
1323
  	RCU_INIT_POINTER(local->sched_scan_req, NULL);
d43c6b6e6   David Spinadel   mac80211: resched...
1324

85a9994a0   Luciano Coelho   cfg80211/mac80211...
1325
  	mutex_unlock(&local->mtx);
b34939b98   Arend Van Spriel   cfg80211: add req...
1326
  	cfg80211_sched_scan_stopped(local->hw.wiphy, 0);
85a9994a0   Luciano Coelho   cfg80211/mac80211...
1327
  }
f6837ba8c   Johannes Berg   mac80211: handle ...
1328
1329
1330
1331
1332
1333
1334
1335
  void ieee80211_sched_scan_stopped_work(struct work_struct *work)
  {
  	struct ieee80211_local *local =
  		container_of(work, struct ieee80211_local,
  			     sched_scan_stopped_work);
  
  	ieee80211_sched_scan_end(local);
  }
79f460ca4   Luciano Coelho   mac80211: add sup...
1336
1337
1338
1339
1340
  void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw)
  {
  	struct ieee80211_local *local = hw_to_local(hw);
  
  	trace_api_sched_scan_stopped(local);
2bc533bd9   Eliad Peller   mac80211: handle ...
1341
1342
1343
1344
1345
1346
1347
  	/*
  	 * this shouldn't really happen, so for simplicity
  	 * simply ignore it, and let mac80211 reconfigure
  	 * the sched scan later on.
  	 */
  	if (local->in_reconfig)
  		return;
18db594a1   Johannes Berg   mac80211: fix sch...
1348
  	schedule_work(&local->sched_scan_stopped_work);
79f460ca4   Luciano Coelho   mac80211: add sup...
1349
1350
  }
  EXPORT_SYMBOL(ieee80211_sched_scan_stopped);