Blame view

net/mac80211/scan.c 37 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
4abb52a46   Sara Sharon   mac80211: pass bs...
12
   * Copyright (C) 2018-2019 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
132
  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];
  	}
  }
c2b13452b   Johannes Berg   mac80211: clean u...
133
  struct ieee80211_bss *
5484e2374   Johannes Berg   mac80211: move BS...
134
135
  ieee80211_bss_info_update(struct ieee80211_local *local,
  			  struct ieee80211_rx_status *rx_status,
d45c41722   Emmanuel Grumbach   mac82011: use fra...
136
  			  struct ieee80211_mgmt *mgmt, size_t len,
d45c41722   Emmanuel Grumbach   mac82011: use fra...
137
  			  struct ieee80211_channel *channel)
5484e2374   Johannes Berg   mac80211: move BS...
138
  {
d45c41722   Emmanuel Grumbach   mac82011: use fra...
139
  	bool beacon = ieee80211_is_beacon(mgmt->frame_control);
78ac51f81   Sara Sharon   mac80211: support...
140
141
  	struct cfg80211_bss *cbss, *non_tx_cbss;
  	struct ieee80211_bss *bss, *non_tx_bss;
162dd6a72   Johannes Berg   mac80211: allow d...
142
143
144
  	struct cfg80211_inform_bss bss_meta = {
  		.boottime_ns = rx_status->boottime_ns,
  	};
74d803b60   Sara Sharon   mac80211: ignore ...
145
  	bool signal_valid;
7947d3e07   Avraham Stern   mac80211: Add sup...
146
  	struct ieee80211_sub_if_data *scan_sdata;
4abb52a46   Sara Sharon   mac80211: pass bs...
147
148
149
  	struct ieee802_11_elems elems;
  	size_t baselen;
  	u8 *elements;
2a5193119   Johannes Berg   cfg80211/nl80211:...
150

1ad22fb5b   Tosoni   mac80211: inform ...
151
152
153
  	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...
154
  		bss_meta.signal = rx_status->signal * 100;
30686bf7f   Johannes Berg   mac80211: convert...
155
  	else if (ieee80211_hw_check(&local->hw, SIGNAL_UNSPEC))
61f6bba00   Johannes Berg   mac80211: use new...
156
  		bss_meta.signal = (rx_status->signal * 100) / local->hw.max_signal;
2a5193119   Johannes Berg   cfg80211/nl80211:...
157

61f6bba00   Johannes Berg   mac80211: use new...
158
  	bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_20;
da6a4352e   Johannes Berg   mac80211: separat...
159
  	if (rx_status->bw == RATE_INFO_BW_5)
61f6bba00   Johannes Berg   mac80211: use new...
160
  		bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_5;
da6a4352e   Johannes Berg   mac80211: separat...
161
  	else if (rx_status->bw == RATE_INFO_BW_10)
61f6bba00   Johannes Berg   mac80211: use new...
162
  		bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_10;
7ca15a0ae   Simon Wunderlich   mac80211: allow s...
163

61f6bba00   Johannes Berg   mac80211: use new...
164
  	bss_meta.chan = channel;
7947d3e07   Avraham Stern   mac80211: Add sup...
165
166
167
168
169
170
171
172
173
174
175
176
177
  
  	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...
178
179
  	cbss = cfg80211_inform_bss_frame_data(local->hw.wiphy, &bss_meta,
  					      mgmt, len, GFP_ATOMIC);
0c1ad2cac   Johannes Berg   mac80211: proper ...
180
  	if (!cbss)
00d3f14cf   Johannes Berg   mac80211: use cfg...
181
  		return NULL;
4abb52a46   Sara Sharon   mac80211: pass bs...
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  
  	if (ieee80211_is_probe_resp(mgmt->frame_control)) {
  		elements = mgmt->u.probe_resp.variable;
  		baselen = offsetof(struct ieee80211_mgmt,
  				   u.probe_resp.variable);
  	} 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 ...
197
198
199
200
201
  	/* In case the signal is invalid update the status */
  	signal_valid = abs(channel->center_freq - cbss->channel->center_freq)
  		<= local->hw.wiphy->max_adj_channel_rssi_comp;
  	if (!signal_valid)
  		rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
00d3f14cf   Johannes Berg   mac80211: use cfg...
202

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

78ac51f81   Sara Sharon   mac80211: support...
206
207
208
209
210
211
  	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...
212
213
  	return bss;
  }
0a51b27e9   Johannes Berg   mac80211: start m...
214

40b0bd249   Roee Zamir   mac80211: oce: en...
215
216
217
218
219
220
221
222
223
224
225
226
227
  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...
228
  void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
98c8fccfa   Johannes Berg   mac80211: refacto...
229
  {
f1d58c252   Johannes Berg   mac80211: push rx...
230
  	struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
d48b29685   Johannes Berg   mac80211: redesig...
231
232
  	struct ieee80211_sub_if_data *sdata1, *sdata2;
  	struct ieee80211_mgmt *mgmt = (void *)skb->data;
c2b13452b   Johannes Berg   mac80211: clean u...
233
  	struct ieee80211_bss *bss;
98c8fccfa   Johannes Berg   mac80211: refacto...
234
  	struct ieee80211_channel *channel;
98c8fccfa   Johannes Berg   mac80211: refacto...
235

d48b29685   Johannes Berg   mac80211: redesig...
236
237
238
239
  	if (skb->len < 24 ||
  	    (!ieee80211_is_probe_resp(mgmt->frame_control) &&
  	     !ieee80211_is_beacon(mgmt->frame_control)))
  		return;
98c8fccfa   Johannes Berg   mac80211: refacto...
240

d48b29685   Johannes Berg   mac80211: redesig...
241
242
  	sdata1 = rcu_dereference(local->scan_sdata);
  	sdata2 = rcu_dereference(local->sched_scan_sdata);
98c8fccfa   Johannes Berg   mac80211: refacto...
243

d48b29685   Johannes Berg   mac80211: redesig...
244
245
  	if (likely(!sdata1 && !sdata2))
  		return;
98c8fccfa   Johannes Berg   mac80211: refacto...
246

d48b29685   Johannes Berg   mac80211: redesig...
247
  	if (ieee80211_is_probe_resp(mgmt->frame_control)) {
a344d6778   Johannes Berg   mac80211: allow d...
248
249
  		struct cfg80211_scan_request *scan_req;
  		struct cfg80211_sched_scan_request *sched_scan_req;
40b0bd249   Roee Zamir   mac80211: oce: en...
250
  		u32 scan_req_flags = 0, sched_scan_req_flags = 0;
a344d6778   Johannes Berg   mac80211: allow d...
251
252
253
  
  		scan_req = rcu_dereference(local->scan_req);
  		sched_scan_req = rcu_dereference(local->sched_scan_req);
40b0bd249   Roee Zamir   mac80211: oce: en...
254
255
256
257
258
259
260
261
  		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...
262
  		 */
40b0bd249   Roee Zamir   mac80211: oce: en...
263
264
265
266
  		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...
267
  			return;
98c8fccfa   Johannes Berg   mac80211: refacto...
268
  	}
0172bb750   Johannes Berg   cfg80211: use DS ...
269
  	channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
98c8fccfa   Johannes Berg   mac80211: refacto...
270
271
  
  	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
d48b29685   Johannes Berg   mac80211: redesig...
272
  		return;
98c8fccfa   Johannes Berg   mac80211: refacto...
273

d48b29685   Johannes Berg   mac80211: redesig...
274
  	bss = ieee80211_bss_info_update(local, rx_status,
4abb52a46   Sara Sharon   mac80211: pass bs...
275
  					mgmt, skb->len,
d45c41722   Emmanuel Grumbach   mac82011: use fra...
276
  					channel);
d048e503a   Jouni Malinen   mac80211: Fix sca...
277
  	if (bss)
d48b29685   Johannes Berg   mac80211: redesig...
278
  		ieee80211_rx_bss_put(local, bss);
98c8fccfa   Johannes Berg   mac80211: refacto...
279
  }
2103dec14   Simon Wunderlich   mac80211: select ...
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
  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...
297
298
299
  /* return false if no more work */
  static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
  {
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
300
  	struct cfg80211_scan_request *req;
2103dec14   Simon Wunderlich   mac80211: select ...
301
  	struct cfg80211_chan_def chandef;
c56ef6725   David Spinadel   mac80211: support...
302
  	u8 bands_used = 0;
4d36ec582   Johannes Berg   mac80211: split h...
303
  	int i, ielen, n_chans;
b9771d41a   Johannes Berg   mac80211: support...
304
  	u32 flags = 0;
4d36ec582   Johannes Berg   mac80211: split h...
305

6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
306
307
  	req = rcu_dereference_protected(local->scan_req,
  					lockdep_is_held(&local->mtx));
a754055a1   Emmanuel Grumbach   mac80211: correct...
308
309
  	if (test_bit(SCAN_HW_CANCELLED, &local->scanning))
  		return false;
30686bf7f   Johannes Berg   mac80211: convert...
310
  	if (ieee80211_hw_check(&local->hw, SINGLE_SCAN_ON_ALL_BANDS)) {
4d36ec582   Johannes Berg   mac80211: split h...
311
  		for (i = 0; i < req->n_channels; i++) {
c56ef6725   David Spinadel   mac80211: support...
312
313
314
315
316
317
318
  			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 ...
319
  			if (local->hw_scan_band == NUM_NL80211_BANDS)
c56ef6725   David Spinadel   mac80211: support...
320
321
322
323
324
325
326
327
328
  				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...
329
330
  							req->channels[i];
  				n_chans++;
c56ef6725   David Spinadel   mac80211: support...
331
  				bands_used |= BIT(req->channels[i]->band);
4d36ec582   Johannes Berg   mac80211: split h...
332
  			}
4d36ec582   Johannes Berg   mac80211: split h...
333

c56ef6725   David Spinadel   mac80211: support...
334
335
336
  			local->hw_scan_band++;
  		} while (!n_chans);
  	}
4d36ec582   Johannes Berg   mac80211: split h...
337

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

b9771d41a   Johannes Berg   mac80211: support...
341
342
  	if (req->flags & NL80211_SCAN_FLAG_MIN_PREQ_CONTENT)
  		flags |= IEEE80211_PROBE_FLAG_MIN_CONTENT;
c56ef6725   David Spinadel   mac80211: support...
343
344
  	ielen = ieee80211_build_preq_ies(local,
  					 (u8 *)local->hw_scan_req->req.ie,
c604b9f21   Johannes Berg   mac80211: make ie...
345
  					 local->hw_scan_ies_bufsize,
c56ef6725   David Spinadel   mac80211: support...
346
347
  					 &local->hw_scan_req->ies,
  					 req->ie, req->ie_len,
b9771d41a   Johannes Berg   mac80211: support...
348
349
  					 bands_used, req->rates, &chandef,
  					 flags);
c56ef6725   David Spinadel   mac80211: support...
350
351
  	local->hw_scan_req->req.ie_len = ielen;
  	local->hw_scan_req->req.no_cck = req->no_cck;
a344d6778   Johannes Berg   mac80211: allow d...
352
353
354
  	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...
355
  	ether_addr_copy(local->hw_scan_req->req.bssid, req->bssid);
4d36ec582   Johannes Berg   mac80211: split h...
356
357
358
  
  	return true;
  }
8bd2a2489   Eliad Peller   mac80211: determi...
359
  static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
0a51b27e9   Johannes Berg   mac80211: start m...
360
361
  {
  	struct ieee80211_local *local = hw_to_local(hw);
e9da68dde   Johannes Berg   mac80211: allow h...
362
  	bool hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
a2b70e833   Eliad Peller   mac80211: start_n...
363
  	bool was_scanning = local->scanning;
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
364
  	struct cfg80211_scan_request *scan_req;
a344d6778   Johannes Berg   mac80211: allow d...
365
  	struct ieee80211_sub_if_data *scan_sdata;
4fa11ec72   Sachin Kulkarni   mac80211: Requeue...
366
  	struct ieee80211_sub_if_data *sdata;
0a51b27e9   Johannes Berg   mac80211: start m...
367

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

6d3560d4f   Johannes Berg   mac80211: fix sca...
370
371
372
373
374
375
376
377
  	/*
  	 * 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...
378

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

c56ef6725   David Spinadel   mac80211: support...
382
  	if (hw_scan && !aborted &&
30686bf7f   Johannes Berg   mac80211: convert...
383
  	    !ieee80211_hw_check(&local->hw, SINGLE_SCAN_ON_ALL_BANDS) &&
c56ef6725   David Spinadel   mac80211: support...
384
  	    ieee80211_prep_hw_scan(local)) {
e2fd5dbc1   Johannes Berg   mac80211: make sc...
385
386
387
388
389
390
  		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 ...
391
  		if (rc == 0)
d07bfd8b6   Johannes Berg   mac80211: fix sca...
392
  			return;
7947d3e07   Avraham Stern   mac80211: Add sup...
393

7d10f6b17   Johannes Berg   mac80211: report ...
394
395
  		/* HW scan failed and is going to be reported as aborted,
  		 * so clear old scan info.
7947d3e07   Avraham Stern   mac80211: Add sup...
396
397
  		 */
  		memset(&local->scan_info, 0, sizeof(local->scan_info));
7d10f6b17   Johannes Berg   mac80211: report ...
398
  		aborted = true;
4d36ec582   Johannes Berg   mac80211: split h...
399
400
401
402
  	}
  
  	kfree(local->hw_scan_req);
  	local->hw_scan_req = NULL;
f3b85252f   Johannes Berg   mac80211: fix sca...
403

6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
404
405
  	scan_req = rcu_dereference_protected(local->scan_req,
  					     lockdep_is_held(&local->mtx));
1d76250bd   Avraham Stern   nl80211: support ...
406
  	if (scan_req != local->int_scan_req) {
7947d3e07   Avraham Stern   mac80211: Add sup...
407
408
  		local->scan_info.aborted = aborted;
  		cfg80211_scan_done(scan_req, &local->scan_info);
1d76250bd   Avraham Stern   nl80211: support ...
409
  	}
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
410
  	RCU_INIT_POINTER(local->scan_req, NULL);
a344d6778   Johannes Berg   mac80211: allow d...
411
412
413
  
  	scan_sdata = rcu_dereference_protected(local->scan_sdata,
  					       lockdep_is_held(&local->mtx));
0c2bef462   Monam Agarwal   mac80211: use RCU...
414
  	RCU_INIT_POINTER(local->scan_sdata, NULL);
2a5193119   Johannes Berg   cfg80211/nl80211:...
415

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

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

8bd2a2489   Eliad Peller   mac80211: determi...
422
  	if (!hw_scan) {
e229f844d   Stanislaw Gruszka   mac80211: keep lo...
423
  		ieee80211_configure_filter(local);
a344d6778   Johannes Berg   mac80211: allow d...
424
  		drv_sw_scan_complete(local, scan_sdata);
aacde9ee4   Stanislaw Gruszka   mac80211: synchro...
425
  		ieee80211_offchannel_return(local);
e229f844d   Stanislaw Gruszka   mac80211: keep lo...
426
  	}
0a51b27e9   Johannes Berg   mac80211: start m...
427

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

0a51b27e9   Johannes Berg   mac80211: start m...
430
  	ieee80211_mlme_notify_scan_completed(local);
469002983   Johannes Berg   mac80211: split I...
431
  	ieee80211_ibss_notify_scan_completed(local);
4fa11ec72   Sachin Kulkarni   mac80211: Requeue...
432
433
434
435
436
437
438
439
440
  
  	/* 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...
441
442
  	if (was_scanning)
  		ieee80211_start_next_roc(local);
0a51b27e9   Johannes Berg   mac80211: start m...
443
  }
8789d459b   Johannes Berg   mac80211: allow s...
444

7947d3e07   Avraham Stern   mac80211: Add sup...
445
446
  void ieee80211_scan_completed(struct ieee80211_hw *hw,
  			      struct cfg80211_scan_info *info)
8789d459b   Johannes Berg   mac80211: allow s...
447
448
  {
  	struct ieee80211_local *local = hw_to_local(hw);
58bd7f115   Johannes Berg   mac80211: fix sca...
449
  	trace_api_scan_completed(local, info->aborted);
8789d459b   Johannes Berg   mac80211: allow s...
450
451
  
  	set_bit(SCAN_COMPLETED, &local->scanning);
7947d3e07   Avraham Stern   mac80211: Add sup...
452
  	if (info->aborted)
8789d459b   Johannes Berg   mac80211: allow s...
453
  		set_bit(SCAN_ABORTED, &local->scanning);
7947d3e07   Avraham Stern   mac80211: Add sup...
454
455
  
  	memcpy(&local->scan_info, info, sizeof(*info));
8789d459b   Johannes Berg   mac80211: allow s...
456
457
  	ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0);
  }
0a51b27e9   Johannes Berg   mac80211: start m...
458
  EXPORT_SYMBOL(ieee80211_scan_completed);
a344d6778   Johannes Berg   mac80211: allow d...
459
460
  static int ieee80211_start_sw_scan(struct ieee80211_local *local,
  				   struct ieee80211_sub_if_data *sdata)
f3b85252f   Johannes Berg   mac80211: fix sca...
461
  {
fe57d9f5c   Johannes Berg   mac80211: track w...
462
463
464
  	/* Software scan is not supported in multi-channel cases */
  	if (local->use_chanctx)
  		return -EOPNOTSUPP;
f3b85252f   Johannes Berg   mac80211: fix sca...
465
466
467
468
469
470
471
472
473
474
475
476
477
  	/*
  	 * 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...
478
  	drv_sw_scan_start(local, sdata, local->scan_addr);
f3b85252f   Johannes Berg   mac80211: fix sca...
479

de312db34   Rajkumar Manoharan   mac80211: fix ope...
480
  	local->leave_oper_channel_time = jiffies;
977923b00   Helmut Schaa   mac80211: rename ...
481
  	local->next_scan_state = SCAN_DECISION;
f3b85252f   Johannes Berg   mac80211: fix sca...
482
  	local->scan_channel_idx = 0;
aacde9ee4   Stanislaw Gruszka   mac80211: synchro...
483
  	ieee80211_offchannel_stop_vifs(local);
a80f7c0b0   Johannes Berg   mac80211: introdu...
484

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

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

59bdf3b0f   Ben Greear   mac80211: Ensure ...
490
491
  	/* We need to set power level at maximum rate for scanning. */
  	ieee80211_hw_config(local, 0);
42935ecaf   Luis R. Rodriguez   mac80211: redefin...
492
  	ieee80211_queue_delayed_work(&local->hw,
07ef03ee8   Johannes Berg   mac80211: simplif...
493
  				     &local->scan_work, 0);
f3b85252f   Johannes Berg   mac80211: fix sca...
494
495
496
  
  	return 0;
  }
dc0c18ed2   Aaron Komisar   mac80211: fix sca...
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
  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 ...
519
520
521
  static bool ieee80211_can_scan(struct ieee80211_local *local,
  			       struct ieee80211_sub_if_data *sdata)
  {
dc0c18ed2   Aaron Komisar   mac80211: fix sca...
522
  	if (!__ieee80211_can_leave_ch(sdata))
164eb02d0   Simon Wunderlich   mac80211: add rad...
523
  		return false;
2eb278e08   Johannes Berg   mac80211: unify S...
524
  	if (!list_empty(&local->roc_list))
133d40f9a   Stanislaw Gruszka   mac80211: do not ...
525
526
527
  		return false;
  
  	if (sdata->vif.type == NL80211_IFTYPE_STATION &&
392b9ffb0   Stanislaw Gruszka   mac80211: change ...
528
  	    sdata->u.mgd.flags & IEEE80211_STA_CONNECTION_POLL)
133d40f9a   Stanislaw Gruszka   mac80211: do not ...
529
530
531
532
533
534
535
536
537
538
539
  		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...
540
541
542
543
  	if (!ieee80211_can_scan(local,
  				rcu_dereference_protected(
  					local->scan_sdata,
  					lockdep_is_held(&local->mtx))))
133d40f9a   Stanislaw Gruszka   mac80211: do not ...
544
545
546
547
548
  		return;
  
  	ieee80211_queue_delayed_work(&local->hw, &local->scan_work,
  				     round_jiffies_relative(0));
  }
f3b85252f   Johannes Berg   mac80211: fix sca...
549

45ad68348   Johannes Berg   mac80211: split i...
550
551
552
553
554
555
556
557
  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;
b9771d41a   Johannes Berg   mac80211: support...
558
  	u32 txdata_flags = 0;
45ad68348   Johannes Berg   mac80211: split i...
559
560
561
562
  
  	skb = ieee80211_build_probe_req(sdata, src, dst, ratemask, channel,
  					ssid, ssid_len,
  					ie, ie_len, flags);
b9771d41a   Johannes Berg   mac80211: support...
563

45ad68348   Johannes Berg   mac80211: split i...
564
  	if (skb) {
b9771d41a   Johannes Berg   mac80211: support...
565
566
567
568
569
570
571
572
  		if (flags & IEEE80211_PROBE_FLAG_RANDOM_SN) {
  			struct ieee80211_hdr *hdr = (void *)skb->data;
  			u16 sn = get_random_u32();
  
  			txdata_flags |= IEEE80211_TX_NO_SEQNO;
  			hdr->seq_ctrl =
  				cpu_to_le16(IEEE80211_SN_TO_SEQ(sn));
  		}
45ad68348   Johannes Berg   mac80211: split i...
573
  		IEEE80211_SKB_CB(skb)->flags |= tx_flags;
b9771d41a   Johannes Berg   mac80211: support...
574
575
  		ieee80211_tx_skb_tid_band(sdata, skb, 7, channel->band,
  					  txdata_flags);
45ad68348   Johannes Berg   mac80211: split i...
576
577
  	}
  }
8a690674e   Ben Greear   mac80211: Support...
578
579
580
581
  static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
  					    unsigned long *next_delay)
  {
  	int i;
e2fd5dbc1   Johannes Berg   mac80211: make sc...
582
  	struct ieee80211_sub_if_data *sdata;
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
583
  	struct cfg80211_scan_request *scan_req;
57fbcce37   Johannes Berg   cfg80211: remove ...
584
  	enum nl80211_band band = local->hw.conf.chandef.chan->band;
b9771d41a   Johannes Berg   mac80211: support...
585
  	u32 flags = 0, tx_flags;
6c17b77b6   Seth Forshee   mac80211: Fix tx ...
586

6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
587
588
  	scan_req = rcu_dereference_protected(local->scan_req,
  					     lockdep_is_held(&local->mtx));
6c17b77b6   Seth Forshee   mac80211: Fix tx ...
589
  	tx_flags = IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
590
  	if (scan_req->no_cck)
6c17b77b6   Seth Forshee   mac80211: Fix tx ...
591
  		tx_flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
b9771d41a   Johannes Berg   mac80211: support...
592
593
594
595
  	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...
596

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

6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
600
  	for (i = 0; i < scan_req->n_ssids; i++)
45ad68348   Johannes Berg   mac80211: split i...
601
  		ieee80211_send_scan_probe_req(
e345f44f2   Jouni Malinen   mac80211: Support...
602
  			sdata, local->scan_addr, scan_req->bssid,
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
603
604
  			scan_req->ssids[i].ssid, scan_req->ssids[i].ssid_len,
  			scan_req->ie, scan_req->ie_len,
b9771d41a   Johannes Berg   mac80211: support...
605
  			scan_req->rates[band], flags,
45ad68348   Johannes Berg   mac80211: split i...
606
  			tx_flags, local->hw.conf.chandef.chan);
8a690674e   Ben Greear   mac80211: Support...
607
608
609
610
611
612
613
614
  
  	/*
  	 * 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...
615
616
617
618
  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...
619
  	bool hw_scan = local->ops->hw_scan;
f3b85252f   Johannes Berg   mac80211: fix sca...
620
  	int rc;
e229f844d   Stanislaw Gruszka   mac80211: keep lo...
621
  	lockdep_assert_held(&local->mtx);
dc0c18ed2   Aaron Komisar   mac80211: fix sca...
622
623
624
625
  	if (local->scan_req)
  		return -EBUSY;
  
  	if (!__ieee80211_can_leave_ch(sdata))
f3b85252f   Johannes Berg   mac80211: fix sca...
626
  		return -EBUSY;
133d40f9a   Stanislaw Gruszka   mac80211: do not ...
627
  	if (!ieee80211_can_scan(local, sdata)) {
6e7e6213e   John W. Linville   Merge branch 'mas...
628
  		/* wait for the work to finish/time out */
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
629
  		rcu_assign_pointer(local->scan_req, req);
e2fd5dbc1   Johannes Berg   mac80211: make sc...
630
  		rcu_assign_pointer(local->scan_sdata, sdata);
c0ce77b83   Johannes Berg   mac80211: fix def...
631
632
  		return 0;
  	}
e9da68dde   Johannes Berg   mac80211: allow h...
633
634
   again:
  	if (hw_scan) {
f3b85252f   Johannes Berg   mac80211: fix sca...
635
  		u8 *ies;
f3b85252f   Johannes Berg   mac80211: fix sca...
636

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

30686bf7f   Johannes Berg   mac80211: convert...
639
  		if (ieee80211_hw_check(&local->hw, SINGLE_SCAN_ON_ALL_BANDS)) {
c56ef6725   David Spinadel   mac80211: support...
640
641
642
643
644
645
646
647
648
649
650
651
  			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...
652
653
654
  		local->hw_scan_req = kmalloc(
  				sizeof(*local->hw_scan_req) +
  				req->n_channels * sizeof(req->channels[0]) +
c604b9f21   Johannes Berg   mac80211: make ie...
655
  				local->hw_scan_ies_bufsize, GFP_KERNEL);
4d36ec582   Johannes Berg   mac80211: split h...
656
  		if (!local->hw_scan_req)
f3b85252f   Johannes Berg   mac80211: fix sca...
657
  			return -ENOMEM;
c56ef6725   David Spinadel   mac80211: support...
658
659
  		local->hw_scan_req->req.ssids = req->ssids;
  		local->hw_scan_req->req.n_ssids = req->n_ssids;
4d36ec582   Johannes Berg   mac80211: split h...
660
661
662
  		ies = (u8 *)local->hw_scan_req +
  			sizeof(*local->hw_scan_req) +
  			req->n_channels * sizeof(req->channels[0]);
c56ef6725   David Spinadel   mac80211: support...
663
664
  		local->hw_scan_req->req.ie = ies;
  		local->hw_scan_req->req.flags = req->flags;
e345f44f2   Jouni Malinen   mac80211: Support...
665
  		eth_broadcast_addr(local->hw_scan_req->req.bssid);
7947d3e07   Avraham Stern   mac80211: Add sup...
666
667
668
  		local->hw_scan_req->req.duration = req->duration;
  		local->hw_scan_req->req.duration_mandatory =
  			req->duration_mandatory;
4d36ec582   Johannes Berg   mac80211: split h...
669
670
  
  		local->hw_scan_band = 0;
6e7e6213e   John W. Linville   Merge branch 'mas...
671
672
673
674
675
676
677
678
  
  		/*
  		 * 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...
679
  	}
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
680
  	rcu_assign_pointer(local->scan_req, req);
e2fd5dbc1   Johannes Berg   mac80211: make sc...
681
  	rcu_assign_pointer(local->scan_sdata, sdata);
f3b85252f   Johannes Berg   mac80211: fix sca...
682

a344d6778   Johannes Berg   mac80211: allow d...
683
684
685
686
687
688
  	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...
689
  	if (hw_scan) {
fbe9c429f   Helmut Schaa   mac80211: Replace...
690
  		__set_bit(SCAN_HW_SCANNING, &local->scanning);
8a690674e   Ben Greear   mac80211: Support...
691
  	} else if ((req->n_channels == 1) &&
675a0b049   Karl Beldan   mac80211: Use a c...
692
  		   (req->channels[0] == local->_oper_chandef.chan)) {
9b8648704   Johannes Berg   mac80211: check o...
693
694
695
  		/*
  		 * If we are scanning only on the operating channel
  		 * then we do not need to stop normal activities
8a690674e   Ben Greear   mac80211: Support...
696
697
698
699
700
701
702
703
704
  		 */
  		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...
705
  		drv_sw_scan_start(local, sdata, local->scan_addr);
8a690674e   Ben Greear   mac80211: Support...
706
707
708
709
710
  
  		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 ...
711
712
  		if ((req->channels[0]->flags & (IEEE80211_CHAN_NO_IR |
  						IEEE80211_CHAN_RADAR)) ||
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
713
  		    !req->n_ssids) {
8a690674e   Ben Greear   mac80211: Support...
714
715
716
717
718
719
720
721
722
723
724
725
  			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...
726
  		__set_bit(SCAN_SW_SCANNING, &local->scanning);
8a690674e   Ben Greear   mac80211: Support...
727
  	}
6e7e6213e   John W. Linville   Merge branch 'mas...
728

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

e9da68dde   Johannes Berg   mac80211: allow h...
731
  	if (hw_scan) {
4d36ec582   Johannes Berg   mac80211: split h...
732
  		WARN_ON(!ieee80211_prep_hw_scan(local));
a060bbfe4   Johannes Berg   mac80211: give vi...
733
  		rc = drv_hw_scan(local, sdata, local->hw_scan_req);
a344d6778   Johannes Berg   mac80211: allow d...
734
735
736
  	} else {
  		rc = ieee80211_start_sw_scan(local, sdata);
  	}
f3b85252f   Johannes Berg   mac80211: fix sca...
737

f3b85252f   Johannes Berg   mac80211: fix sca...
738
  	if (rc) {
4d36ec582   Johannes Berg   mac80211: split h...
739
740
  		kfree(local->hw_scan_req);
  		local->hw_scan_req = NULL;
fbe9c429f   Helmut Schaa   mac80211: Replace...
741
  		local->scanning = 0;
f3b85252f   Johannes Berg   mac80211: fix sca...
742

5cff20e6c   Johannes Berg   mac80211: tell dr...
743
  		ieee80211_recalc_idle(local);
f3b85252f   Johannes Berg   mac80211: fix sca...
744
  		local->scan_req = NULL;
0c2bef462   Monam Agarwal   mac80211: use RCU...
745
  		RCU_INIT_POINTER(local->scan_sdata, NULL);
f3b85252f   Johannes Berg   mac80211: fix sca...
746
  	}
e9da68dde   Johannes Berg   mac80211: allow h...
747
748
749
750
751
752
753
754
755
756
757
  	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...
758
759
  	return rc;
  }
df13cce53   Helmut Schaa   mac80211: Improve...
760
761
762
763
764
765
766
  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 ...
767
  	if (chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR))
df13cce53   Helmut Schaa   mac80211: Improve...
768
769
770
  		return IEEE80211_PASSIVE_CHANNEL_TIME;
  	return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME;
  }
e229f844d   Stanislaw Gruszka   mac80211: keep lo...
771
772
  static void ieee80211_scan_state_decision(struct ieee80211_local *local,
  					  unsigned long *next_delay)
7d3be3cc4   Helmut Schaa   mac80211: refacto...
773
  {
142b9f507   Helmut Schaa   mac80211: impleme...
774
  	bool associated = false;
df13cce53   Helmut Schaa   mac80211: Improve...
775
776
  	bool tx_empty = true;
  	bool bad_latency;
142b9f507   Helmut Schaa   mac80211: impleme...
777
  	struct ieee80211_sub_if_data *sdata;
df13cce53   Helmut Schaa   mac80211: Improve...
778
  	struct ieee80211_channel *next_chan;
cd2bb512c   Sam Leffler   mac80211: add sup...
779
  	enum mac80211_scan_state next_scan_state;
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
780
  	struct cfg80211_scan_request *scan_req;
142b9f507   Helmut Schaa   mac80211: impleme...
781

df13cce53   Helmut Schaa   mac80211: Improve...
782
783
784
785
786
  	/*
  	 * 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...
787
788
  	mutex_lock(&local->iflist_mtx);
  	list_for_each_entry(sdata, &local->interfaces, list) {
9607e6b66   Johannes Berg   mac80211: add iee...
789
  		if (!ieee80211_sdata_running(sdata))
142b9f507   Helmut Schaa   mac80211: impleme...
790
791
792
793
794
  			continue;
  
  		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
  			if (sdata->u.mgd.associated) {
  				associated = true;
df13cce53   Helmut Schaa   mac80211: Improve...
795

df13cce53   Helmut Schaa   mac80211: Improve...
796
797
798
799
  				if (!qdisc_all_tx_empty(sdata->dev)) {
  					tx_empty = false;
  					break;
  				}
142b9f507   Helmut Schaa   mac80211: impleme...
800
801
802
803
  			}
  		}
  	}
  	mutex_unlock(&local->iflist_mtx);
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
804
805
806
807
  	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...
808

a80f7c0b0   Johannes Berg   mac80211: introdu...
809
  	/*
07ef03ee8   Johannes Berg   mac80211: simplif...
810
811
812
813
  	 * 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...
814
  	 * Keep good latency, do not stay off-channel more than 125 ms.
a80f7c0b0   Johannes Berg   mac80211: introdu...
815
  	 */
a80f7c0b0   Johannes Berg   mac80211: introdu...
816

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

cd2bb512c   Sam Leffler   mac80211: add sup...
821
  	if (associated && !tx_empty) {
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
822
  		if (scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY)
cd2bb512c   Sam Leffler   mac80211: add sup...
823
824
825
  			next_scan_state = SCAN_ABORT;
  		else
  			next_scan_state = SCAN_SUSPEND;
3f892b61a   Stanislaw Gruszka   mac80211: improve...
826
  	} else if (associated && bad_latency) {
cd2bb512c   Sam Leffler   mac80211: add sup...
827
828
829
830
831
832
  		next_scan_state = SCAN_SUSPEND;
  	} else {
  		next_scan_state = SCAN_SET_CHANNEL;
  	}
  
  	local->next_scan_state = next_scan_state;
142b9f507   Helmut Schaa   mac80211: impleme...
833

07ef03ee8   Johannes Berg   mac80211: simplif...
834
  	*next_delay = 0;
142b9f507   Helmut Schaa   mac80211: impleme...
835
  }
2fb3f028a   Helmut Schaa   mac80211: introdu...
836
837
838
839
840
  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...
841
  	enum nl80211_bss_scan_width oper_scan_width;
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
842
843
844
845
  	struct cfg80211_scan_request *scan_req;
  
  	scan_req = rcu_dereference_protected(local->scan_req,
  					     lockdep_is_held(&local->mtx));
2fb3f028a   Helmut Schaa   mac80211: introdu...
846

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

7ca15a0ae   Simon Wunderlich   mac80211: allow s...
850
851
852
  	local->scan_chandef.chan = chan;
  	local->scan_chandef.center_freq1 = chan->center_freq;
  	local->scan_chandef.center_freq2 = 0;
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
853
  	switch (scan_req->scan_width) {
7ca15a0ae   Simon Wunderlich   mac80211: allow s...
854
855
856
857
858
859
860
861
862
863
864
865
866
  	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;
  	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...
867
  		    oper_scan_width == scan_req->scan_width)
7ca15a0ae   Simon Wunderlich   mac80211: allow s...
868
869
870
871
872
  			local->scan_chandef = local->_oper_chandef;
  		else
  			local->scan_chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
  		break;
  	}
b23b025fe   Ben Greear   mac80211: Optimiz...
873

07ef03ee8   Johannes Berg   mac80211: simplif...
874
875
  	if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL))
  		skip = 1;
7d3be3cc4   Helmut Schaa   mac80211: refacto...
876

7d3be3cc4   Helmut Schaa   mac80211: refacto...
877
878
  	/* advance state machine to next channel/band */
  	local->scan_channel_idx++;
0ee9c13c7   Helmut Schaa   mac80211: fix an ...
879
880
881
  	if (skip) {
  		/* if we skip this channel return to the decision state */
  		local->next_scan_state = SCAN_DECISION;
2fb3f028a   Helmut Schaa   mac80211: introdu...
882
  		return;
0ee9c13c7   Helmut Schaa   mac80211: fix an ...
883
  	}
7d3be3cc4   Helmut Schaa   mac80211: refacto...
884
885
886
887
888
889
890
891
892
893
894
  
  	/*
  	 * 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 ...
895
896
  	if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) ||
  	    !scan_req->n_ssids) {
7d3be3cc4   Helmut Schaa   mac80211: refacto...
897
  		*next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
977923b00   Helmut Schaa   mac80211: rename ...
898
  		local->next_scan_state = SCAN_DECISION;
2fb3f028a   Helmut Schaa   mac80211: introdu...
899
  		return;
7d3be3cc4   Helmut Schaa   mac80211: refacto...
900
  	}
2fb3f028a   Helmut Schaa   mac80211: introdu...
901
  	/* active scan, send probes */
7d3be3cc4   Helmut Schaa   mac80211: refacto...
902
  	*next_delay = IEEE80211_PROBE_DELAY;
977923b00   Helmut Schaa   mac80211: rename ...
903
  	local->next_scan_state = SCAN_SEND_PROBE;
7d3be3cc4   Helmut Schaa   mac80211: refacto...
904
  }
07ef03ee8   Johannes Berg   mac80211: simplif...
905
906
907
908
  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...
909
  	local->scan_chandef.chan = NULL;
07ef03ee8   Johannes Berg   mac80211: simplif...
910
  	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
aacde9ee4   Stanislaw Gruszka   mac80211: synchro...
911
912
  	/* disable PS */
  	ieee80211_offchannel_return(local);
07ef03ee8   Johannes Berg   mac80211: simplif...
913
914
915
916
917
918
919
920
921
  
  	*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...
922
  	ieee80211_offchannel_stop_vifs(local);
07ef03ee8   Johannes Berg   mac80211: simplif...
923
924
  
  	if (local->ops->flush) {
3b24f4c65   Emmanuel Grumbach   mac80211: let flu...
925
  		ieee80211_flush_queues(local, NULL, false);
07ef03ee8   Johannes Berg   mac80211: simplif...
926
927
928
929
930
931
932
933
  		*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...
934
  	local->next_scan_state = SCAN_SET_CHANNEL;
07ef03ee8   Johannes Berg   mac80211: simplif...
935
  }
c2b13452b   Johannes Berg   mac80211: clean u...
936
  void ieee80211_scan_work(struct work_struct *work)
0a51b27e9   Johannes Berg   mac80211: start m...
937
938
939
  {
  	struct ieee80211_local *local =
  		container_of(work, struct ieee80211_local, scan_work.work);
d07bfd8b6   Johannes Berg   mac80211: fix sca...
940
  	struct ieee80211_sub_if_data *sdata;
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
941
  	struct cfg80211_scan_request *scan_req;
0a51b27e9   Johannes Berg   mac80211: start m...
942
  	unsigned long next_delay = 0;
8bd2a2489   Eliad Peller   mac80211: determi...
943
  	bool aborted;
0a51b27e9   Johannes Berg   mac80211: start m...
944

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

332ff7fe3   Luciano Coelho   mac80211: complet...
947
948
949
950
  	if (!ieee80211_can_run_worker(local)) {
  		aborted = true;
  		goto out_complete;
  	}
e2fd5dbc1   Johannes Berg   mac80211: make sc...
951
952
  	sdata = rcu_dereference_protected(local->scan_sdata,
  					  lockdep_is_held(&local->mtx));
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
953
954
  	scan_req = rcu_dereference_protected(local->scan_req,
  					     lockdep_is_held(&local->mtx));
d07bfd8b6   Johannes Berg   mac80211: fix sca...
955

8a690674e   Ben Greear   mac80211: Support...
956
957
958
959
960
  	/* 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 ...
961
  	if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) {
8789d459b   Johannes Berg   mac80211: allow s...
962
  		aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning);
259b62e35   Stanislaw Gruszka   mac80211: reduce ...
963
  		goto out_complete;
8789d459b   Johannes Berg   mac80211: allow s...
964
  	}
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
965
  	if (!sdata || !scan_req)
259b62e35   Stanislaw Gruszka   mac80211: reduce ...
966
  		goto out;
f3b85252f   Johannes Berg   mac80211: fix sca...
967

ff5db4392   Eliad Peller   mac80211: remove ...
968
  	if (!local->scanning) {
f3b85252f   Johannes Berg   mac80211: fix sca...
969
  		int rc;
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
970
  		RCU_INIT_POINTER(local->scan_req, NULL);
0c2bef462   Monam Agarwal   mac80211: use RCU...
971
  		RCU_INIT_POINTER(local->scan_sdata, NULL);
f3b85252f   Johannes Berg   mac80211: fix sca...
972

6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
973
  		rc = __ieee80211_start_scan(sdata, scan_req);
259b62e35   Stanislaw Gruszka   mac80211: reduce ...
974
  		if (rc) {
3aed49ef1   Stanislaw Gruszka   mac80211: compete...
975
  			/* need to complete scan in cfg80211 */
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
976
  			rcu_assign_pointer(local->scan_req, scan_req);
259b62e35   Stanislaw Gruszka   mac80211: reduce ...
977
978
979
980
  			aborted = true;
  			goto out_complete;
  		} else
  			goto out;
f3b85252f   Johannes Berg   mac80211: fix sca...
981
  	}
5bc75728f   Johannes Berg   mac80211: fix sca...
982
  	/*
f502d09b7   Helmut Schaa   mac80211: advance...
983
984
985
986
  	 * as long as no delay is required advance immediately
  	 * without scheduling a new work
  	 */
  	do {
c29acf201   Rajkumar Manoharan   mac80211: abort s...
987
988
989
990
  		if (!ieee80211_sdata_running(sdata)) {
  			aborted = true;
  			goto out_complete;
  		}
977923b00   Helmut Schaa   mac80211: rename ...
991
  		switch (local->next_scan_state) {
2fb3f028a   Helmut Schaa   mac80211: introdu...
992
  		case SCAN_DECISION:
e229f844d   Stanislaw Gruszka   mac80211: keep lo...
993
  			/* if no more bands/channels left, complete scan */
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
994
  			if (local->scan_channel_idx >= scan_req->n_channels) {
e229f844d   Stanislaw Gruszka   mac80211: keep lo...
995
996
997
998
  				aborted = false;
  				goto out_complete;
  			}
  			ieee80211_scan_state_decision(local, &next_delay);
f502d09b7   Helmut Schaa   mac80211: advance...
999
  			break;
2fb3f028a   Helmut Schaa   mac80211: introdu...
1000
1001
1002
  		case SCAN_SET_CHANNEL:
  			ieee80211_scan_state_set_channel(local, &next_delay);
  			break;
f502d09b7   Helmut Schaa   mac80211: advance...
1003
1004
1005
  		case SCAN_SEND_PROBE:
  			ieee80211_scan_state_send_probe(local, &next_delay);
  			break;
07ef03ee8   Johannes Berg   mac80211: simplif...
1006
1007
  		case SCAN_SUSPEND:
  			ieee80211_scan_state_suspend(local, &next_delay);
142b9f507   Helmut Schaa   mac80211: impleme...
1008
  			break;
07ef03ee8   Johannes Berg   mac80211: simplif...
1009
1010
  		case SCAN_RESUME:
  			ieee80211_scan_state_resume(local, &next_delay);
142b9f507   Helmut Schaa   mac80211: impleme...
1011
  			break;
cd2bb512c   Sam Leffler   mac80211: add sup...
1012
1013
1014
  		case SCAN_ABORT:
  			aborted = true;
  			goto out_complete;
f502d09b7   Helmut Schaa   mac80211: advance...
1015
1016
  		}
  	} while (next_delay == 0);
0a51b27e9   Johannes Berg   mac80211: start m...
1017

42935ecaf   Luis R. Rodriguez   mac80211: redefin...
1018
  	ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay);
d07bfd8b6   Johannes Berg   mac80211: fix sca...
1019
  	goto out;
259b62e35   Stanislaw Gruszka   mac80211: reduce ...
1020
1021
  
  out_complete:
8bd2a2489   Eliad Peller   mac80211: determi...
1022
  	__ieee80211_scan_completed(&local->hw, aborted);
259b62e35   Stanislaw Gruszka   mac80211: reduce ...
1023
1024
  out:
  	mutex_unlock(&local->mtx);
0a51b27e9   Johannes Berg   mac80211: start m...
1025
  }
f3b85252f   Johannes Berg   mac80211: fix sca...
1026
1027
  int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
  			   struct cfg80211_scan_request *req)
0a51b27e9   Johannes Berg   mac80211: start m...
1028
  {
f3b85252f   Johannes Berg   mac80211: fix sca...
1029
  	int res;
de95a54b1   Johannes Berg   mac80211: pass al...
1030

a1699b75a   Johannes Berg   mac80211: unify s...
1031
  	mutex_lock(&sdata->local->mtx);
f3b85252f   Johannes Berg   mac80211: fix sca...
1032
  	res = __ieee80211_start_scan(sdata, req);
a1699b75a   Johannes Berg   mac80211: unify s...
1033
  	mutex_unlock(&sdata->local->mtx);
0a51b27e9   Johannes Berg   mac80211: start m...
1034

f3b85252f   Johannes Berg   mac80211: fix sca...
1035
  	return res;
0a51b27e9   Johannes Berg   mac80211: start m...
1036
  }
34bcf7150   Stanislaw Gruszka   mac80211: fix ibs...
1037
1038
  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...
1039
1040
  				struct ieee80211_channel **channels,
  				unsigned int n_channels,
7ca15a0ae   Simon Wunderlich   mac80211: allow s...
1041
  				enum nl80211_bss_scan_width scan_width)
0a51b27e9   Johannes Berg   mac80211: start m...
1042
  {
0a51b27e9   Johannes Berg   mac80211: start m...
1043
  	struct ieee80211_local *local = sdata->local;
76bed0f43   Janusz.Dziedzic@tieto.com   mac80211: IBSS fi...
1044
  	int ret = -EBUSY, i, n_ch = 0;
57fbcce37   Johannes Berg   cfg80211: remove ...
1045
  	enum nl80211_band band;
2a5193119   Johannes Berg   cfg80211/nl80211:...
1046

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

f3b85252f   Johannes Berg   mac80211: fix sca...
1049
1050
1051
  	/* busy scanning */
  	if (local->scan_req)
  		goto unlock;
9116dd011   Johannes Berg   mac80211: clarify...
1052

be4a4b6a5   Johannes Berg   mac80211: improve...
1053
  	/* fill internal scan request */
76bed0f43   Janusz.Dziedzic@tieto.com   mac80211: IBSS fi...
1054
1055
  	if (!channels) {
  		int max_n;
be4a4b6a5   Johannes Berg   mac80211: improve...
1056

57fbcce37   Johannes Berg   cfg80211: remove ...
1057
  		for (band = 0; band < NUM_NL80211_BANDS; band++) {
be4a4b6a5   Johannes Berg   mac80211: improve...
1058
1059
  			if (!local->hw.wiphy->bands[band])
  				continue;
34bcf7150   Stanislaw Gruszka   mac80211: fix ibs...
1060
1061
1062
1063
  
  			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...
1064
  				    &local->hw.wiphy->bands[band]->channels[i];
34bcf7150   Stanislaw Gruszka   mac80211: fix ibs...
1065

8fe02e167   Luis R. Rodriguez   cfg80211: consoli...
1066
  				if (tmp_ch->flags & (IEEE80211_CHAN_NO_IR |
34bcf7150   Stanislaw Gruszka   mac80211: fix ibs...
1067
1068
1069
1070
1071
  						     IEEE80211_CHAN_DISABLED))
  					continue;
  
  				local->int_scan_req->channels[n_ch] = tmp_ch;
  				n_ch++;
be4a4b6a5   Johannes Berg   mac80211: improve...
1072
1073
  			}
  		}
34bcf7150   Stanislaw Gruszka   mac80211: fix ibs...
1074
1075
1076
1077
  		if (WARN_ON_ONCE(n_ch == 0))
  			goto unlock;
  
  		local->int_scan_req->n_channels = n_ch;
be4a4b6a5   Johannes Berg   mac80211: improve...
1078
  	} else {
76bed0f43   Janusz.Dziedzic@tieto.com   mac80211: IBSS fi...
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
  		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...
1089
  			goto unlock;
76bed0f43   Janusz.Dziedzic@tieto.com   mac80211: IBSS fi...
1090
  		local->int_scan_req->n_channels = n_ch;
be4a4b6a5   Johannes Berg   mac80211: improve...
1091
1092
1093
1094
  	}
  
  	local->int_scan_req->ssids = &local->scan_ssid;
  	local->int_scan_req->n_ssids = 1;
7ca15a0ae   Simon Wunderlich   mac80211: allow s...
1095
  	local->int_scan_req->scan_width = scan_width;
5ba63533b   Johannes Berg   cfg80211: fix ali...
1096
1097
  	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...
1098

5ba63533b   Johannes Berg   cfg80211: fix ali...
1099
  	ret = __ieee80211_start_scan(sdata, sdata->local->int_scan_req);
f3b85252f   Johannes Berg   mac80211: fix sca...
1100
   unlock:
a1699b75a   Johannes Berg   mac80211: unify s...
1101
  	mutex_unlock(&local->mtx);
f3b85252f   Johannes Berg   mac80211: fix sca...
1102
  	return ret;
0a51b27e9   Johannes Berg   mac80211: start m...
1103
  }
5bb644a0f   Johannes Berg   mac80211: cancel/...
1104

4136c4224   Stanislaw Gruszka   mac80211: assure ...
1105
1106
1107
  /*
   * Only call this function when a scan can't be queued -- under RTNL.
   */
5bb644a0f   Johannes Berg   mac80211: cancel/...
1108
1109
  void ieee80211_scan_cancel(struct ieee80211_local *local)
  {
5bb644a0f   Johannes Berg   mac80211: cancel/...
1110
  	/*
b856439b1   Eliad Peller   mac80211: add can...
1111
  	 * We are canceling software scan, or deferred scan that was not
4136c4224   Stanislaw Gruszka   mac80211: assure ...
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
  	 * 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...
1123
1124
1125
  	 * 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/...
1126
  	 */
4136c4224   Stanislaw Gruszka   mac80211: assure ...
1127

a1699b75a   Johannes Berg   mac80211: unify s...
1128
  	mutex_lock(&local->mtx);
b856439b1   Eliad Peller   mac80211: add can...
1129
1130
  	if (!local->scan_req)
  		goto out;
a754055a1   Emmanuel Grumbach   mac80211: correct...
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
  	/*
  	 * 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...
1141
  	if (test_bit(SCAN_HW_SCANNING, &local->scanning)) {
a754055a1   Emmanuel Grumbach   mac80211: correct...
1142
1143
1144
1145
1146
  		/*
  		 * 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...
1147
  		if (local->ops->cancel_hw_scan)
e2fd5dbc1   Johannes Berg   mac80211: make sc...
1148
1149
1150
  			drv_cancel_hw_scan(local,
  				rcu_dereference_protected(local->scan_sdata,
  						lockdep_is_held(&local->mtx)));
b856439b1   Eliad Peller   mac80211: add can...
1151
  		goto out;
4136c4224   Stanislaw Gruszka   mac80211: assure ...
1152
  	}
b856439b1   Eliad Peller   mac80211: add can...
1153
1154
1155
1156
1157
1158
1159
1160
  
  	/*
  	 * 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...
1161
  	memset(&local->scan_info, 0, sizeof(local->scan_info));
8bd2a2489   Eliad Peller   mac80211: determi...
1162
  	__ieee80211_scan_completed(&local->hw, true);
b856439b1   Eliad Peller   mac80211: add can...
1163
  out:
d07bfd8b6   Johannes Berg   mac80211: fix sca...
1164
  	mutex_unlock(&local->mtx);
5bb644a0f   Johannes Berg   mac80211: cancel/...
1165
  }
79f460ca4   Luciano Coelho   mac80211: add sup...
1166

d43c6b6e6   David Spinadel   mac80211: resched...
1167
1168
  int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
  					struct cfg80211_sched_scan_request *req)
79f460ca4   Luciano Coelho   mac80211: add sup...
1169
1170
  {
  	struct ieee80211_local *local = sdata->local;
633e27132   David Spinadel   mac80211: split s...
1171
  	struct ieee80211_scan_ies sched_scan_ies = {};
2103dec14   Simon Wunderlich   mac80211: select ...
1172
  	struct cfg80211_chan_def chandef;
633e27132   David Spinadel   mac80211: split s...
1173
  	int ret, i, iebufsz, num_bands = 0;
57fbcce37   Johannes Berg   cfg80211: remove ...
1174
  	u32 rate_masks[NUM_NL80211_BANDS] = {};
633e27132   David Spinadel   mac80211: split s...
1175
1176
  	u8 bands_used = 0;
  	u8 *ie;
b9771d41a   Johannes Berg   mac80211: support...
1177
  	u32 flags = 0;
c604b9f21   Johannes Berg   mac80211: make ie...
1178

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

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

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

57fbcce37   Johannes Berg   cfg80211: remove ...
1186
  	for (i = 0; i < NUM_NL80211_BANDS; i++) {
633e27132   David Spinadel   mac80211: split s...
1187
1188
1189
1190
  		if (local->hw.wiphy->bands[i]) {
  			bands_used |= BIT(i);
  			rate_masks[i] = (u32) -1;
  			num_bands++;
79f460ca4   Luciano Coelho   mac80211: add sup...
1191
  		}
633e27132   David Spinadel   mac80211: split s...
1192
  	}
79f460ca4   Luciano Coelho   mac80211: add sup...
1193

b9771d41a   Johannes Berg   mac80211: support...
1194
1195
  	if (req->flags & NL80211_SCAN_FLAG_MIN_PREQ_CONTENT)
  		flags |= IEEE80211_PROBE_FLAG_MIN_CONTENT;
6396bb221   Kees Cook   treewide: kzalloc...
1196
  	ie = kcalloc(iebufsz, num_bands, GFP_KERNEL);
633e27132   David Spinadel   mac80211: split s...
1197
1198
1199
  	if (!ie) {
  		ret = -ENOMEM;
  		goto out;
79f460ca4   Luciano Coelho   mac80211: add sup...
1200
  	}
633e27132   David Spinadel   mac80211: split s...
1201
  	ieee80211_prepare_scan_chandef(&chandef, req->scan_width);
cd5861bde   Kirtika Ruchandani   mac80211: Remove ...
1202
1203
  	ieee80211_build_preq_ies(local, ie, num_bands * iebufsz,
  				 &sched_scan_ies, req->ie,
00387f321   Johannes Berg   mac80211: add pro...
1204
  				 req->ie_len, bands_used, rate_masks, &chandef,
b9771d41a   Johannes Berg   mac80211: support...
1205
  				 flags);
633e27132   David Spinadel   mac80211: split s...
1206

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

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

633e27132   David Spinadel   mac80211: split s...
1215
  out:
d43c6b6e6   David Spinadel   mac80211: resched...
1216
1217
  	if (ret) {
  		/* Clean in case of failure after HW restart or upon resume. */
0c2bef462   Monam Agarwal   mac80211: use RCU...
1218
  		RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
1219
  		RCU_INIT_POINTER(local->sched_scan_req, NULL);
d43c6b6e6   David Spinadel   mac80211: resched...
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
  	}
  
  	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...
1239
  	mutex_unlock(&local->mtx);
79f460ca4   Luciano Coelho   mac80211: add sup...
1240
1241
  	return ret;
  }
0d440ea29   Eliad Peller   mac80211: don't r...
1242
  int ieee80211_request_sched_scan_stop(struct ieee80211_local *local)
79f460ca4   Luciano Coelho   mac80211: add sup...
1243
  {
0d440ea29   Eliad Peller   mac80211: don't r...
1244
1245
  	struct ieee80211_sub_if_data *sched_scan_sdata;
  	int ret = -ENOENT;
79f460ca4   Luciano Coelho   mac80211: add sup...
1246

5260a5b2c   Johannes Berg   mac80211: track s...
1247
  	mutex_lock(&local->mtx);
79f460ca4   Luciano Coelho   mac80211: add sup...
1248
1249
1250
1251
1252
  
  	if (!local->ops->sched_scan_stop) {
  		ret = -ENOTSUPP;
  		goto out;
  	}
d43c6b6e6   David Spinadel   mac80211: resched...
1253
  	/* We don't want to restart sched scan anymore. */
6ea0a69ca   Johannes Berg   mac80211: rcu-ify...
1254
  	RCU_INIT_POINTER(local->sched_scan_req, NULL);
d43c6b6e6   David Spinadel   mac80211: resched...
1255

0d440ea29   Eliad Peller   mac80211: don't r...
1256
1257
1258
1259
  	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...
1260
  		if (!ret)
ad053a962   Andreea-Cristina Bernat   mac80211: scan: R...
1261
  			RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
71228a1ea   Alexander Bondar   mac80211: release...
1262
  	}
79f460ca4   Luciano Coelho   mac80211: add sup...
1263
  out:
5260a5b2c   Johannes Berg   mac80211: track s...
1264
  	mutex_unlock(&local->mtx);
79f460ca4   Luciano Coelho   mac80211: add sup...
1265
1266
1267
1268
1269
1270
1271
1272
1273
  
  	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...
1274
  	cfg80211_sched_scan_results(hw->wiphy, 0);
79f460ca4   Luciano Coelho   mac80211: add sup...
1275
1276
  }
  EXPORT_SYMBOL(ieee80211_sched_scan_results);
f6837ba8c   Johannes Berg   mac80211: handle ...
1277
  void ieee80211_sched_scan_end(struct ieee80211_local *local)
85a9994a0   Luciano Coelho   cfg80211/mac80211...
1278
  {
85a9994a0   Luciano Coelho   cfg80211/mac80211...
1279
  	mutex_lock(&local->mtx);
5260a5b2c   Johannes Berg   mac80211: track s...
1280
  	if (!rcu_access_pointer(local->sched_scan_sdata)) {
85a9994a0   Luciano Coelho   cfg80211/mac80211...
1281
1282
1283
  		mutex_unlock(&local->mtx);
  		return;
  	}
0c2bef462   Monam Agarwal   mac80211: use RCU...
1284
  	RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
85a9994a0   Luciano Coelho   cfg80211/mac80211...
1285

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

85a9994a0   Luciano Coelho   cfg80211/mac80211...
1289
  	mutex_unlock(&local->mtx);
b34939b98   Arend Van Spriel   cfg80211: add req...
1290
  	cfg80211_sched_scan_stopped(local->hw.wiphy, 0);
85a9994a0   Luciano Coelho   cfg80211/mac80211...
1291
  }
f6837ba8c   Johannes Berg   mac80211: handle ...
1292
1293
1294
1295
1296
1297
1298
1299
  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...
1300
1301
1302
1303
1304
  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 ...
1305
1306
1307
1308
1309
1310
1311
  	/*
  	 * 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...
1312
  	schedule_work(&local->sched_scan_stopped_work);
79f460ca4   Luciano Coelho   mac80211: add sup...
1313
1314
  }
  EXPORT_SYMBOL(ieee80211_sched_scan_stopped);