Blame view

net/mac80211/scan.c 23.7 KB
0a51b27e9   Johannes Berg   mac80211: start m...
1
  /*
5484e2374   Johannes Berg   mac80211: move BS...
2
3
   * Scanning implementation
   *
0a51b27e9   Johannes Berg   mac80211: start m...
4
5
6
7
8
9
10
11
12
13
   * 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>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
0a51b27e9   Johannes Berg   mac80211: start m...
14
  #include <linux/if_arp.h>
078e1e60d   Johannes Berg   mac80211: Add cap...
15
  #include <linux/rtnetlink.h>
e8db0be12   Jean Pihet   PM QoS: Move and ...
16
  #include <linux/pm_qos.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>
0a51b27e9   Johannes Berg   mac80211: start m...
20
  #include <net/mac80211.h>
0a51b27e9   Johannes Berg   mac80211: start m...
21
22
  
  #include "ieee80211_i.h"
244879813   Johannes Berg   mac80211: add dri...
23
  #include "driver-ops.h"
5484e2374   Johannes Berg   mac80211: move BS...
24
  #include "mesh.h"
0a51b27e9   Johannes Berg   mac80211: start m...
25
26
27
  
  #define IEEE80211_PROBE_DELAY (HZ / 33)
  #define IEEE80211_CHANNEL_TIME (HZ / 33)
96f7e7393   Helmut Schaa   mac80211: shorten...
28
  #define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 8)
0a51b27e9   Johannes Berg   mac80211: start m...
29

c2b13452b   Johannes Berg   mac80211: clean u...
30
  struct ieee80211_bss *
5484e2374   Johannes Berg   mac80211: move BS...
31
32
33
  ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
  		     u8 *ssid, u8 ssid_len)
  {
0c1ad2cac   Johannes Berg   mac80211: proper ...
34
35
36
37
38
39
40
41
  	struct cfg80211_bss *cbss;
  
  	cbss = cfg80211_get_bss(local->hw.wiphy,
  				ieee80211_get_channel(local->hw.wiphy, freq),
  				bssid, ssid, ssid_len, 0, 0);
  	if (!cbss)
  		return NULL;
  	return (void *)cbss->priv;
5484e2374   Johannes Berg   mac80211: move BS...
42
  }
00d3f14cf   Johannes Berg   mac80211: use cfg...
43
  static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss)
5484e2374   Johannes Berg   mac80211: move BS...
44
  {
0c1ad2cac   Johannes Berg   mac80211: proper ...
45
  	struct ieee80211_bss *bss = (void *)cbss->priv;
5484e2374   Johannes Berg   mac80211: move BS...
46

5484e2374   Johannes Berg   mac80211: move BS...
47
48
  	kfree(bss_mesh_id(bss));
  	kfree(bss_mesh_cfg(bss));
5484e2374   Johannes Berg   mac80211: move BS...
49
50
51
  }
  
  void ieee80211_rx_bss_put(struct ieee80211_local *local,
c2b13452b   Johannes Berg   mac80211: clean u...
52
  			  struct ieee80211_bss *bss)
5484e2374   Johannes Berg   mac80211: move BS...
53
  {
0c1ad2cac   Johannes Berg   mac80211: proper ...
54
55
56
  	if (!bss)
  		return;
  	cfg80211_put_bss(container_of((void *)bss, struct cfg80211_bss, priv));
5484e2374   Johannes Berg   mac80211: move BS...
57
  }
ab13315af   Kalle Valo   mac80211: add U-A...
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
  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;
  }
c2b13452b   Johannes Berg   mac80211: clean u...
74
  struct ieee80211_bss *
5484e2374   Johannes Berg   mac80211: move BS...
75
76
77
78
79
  ieee80211_bss_info_update(struct ieee80211_local *local,
  			  struct ieee80211_rx_status *rx_status,
  			  struct ieee80211_mgmt *mgmt,
  			  size_t len,
  			  struct ieee802_11_elems *elems,
2a5193119   Johannes Berg   cfg80211/nl80211:...
80
81
  			  struct ieee80211_channel *channel,
  			  bool beacon)
5484e2374   Johannes Berg   mac80211: move BS...
82
  {
0c1ad2cac   Johannes Berg   mac80211: proper ...
83
  	struct cfg80211_bss *cbss;
c2b13452b   Johannes Berg   mac80211: clean u...
84
  	struct ieee80211_bss *bss;
f0b058b61   Stanislaw Gruszka   mac80211: do not ...
85
  	int clen, srlen;
2a5193119   Johannes Berg   cfg80211/nl80211:...
86
  	s32 signal = 0;
77965c970   Johannes Berg   cfg80211: clean u...
87
  	if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
2a5193119   Johannes Berg   cfg80211/nl80211:...
88
  		signal = rx_status->signal * 100;
77965c970   Johannes Berg   cfg80211: clean u...
89
  	else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
2a5193119   Johannes Berg   cfg80211/nl80211:...
90
  		signal = (rx_status->signal * 100) / local->hw.max_signal;
2a5193119   Johannes Berg   cfg80211/nl80211:...
91

0c1ad2cac   Johannes Berg   mac80211: proper ...
92
93
  	cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel,
  					 mgmt, len, signal, GFP_ATOMIC);
5484e2374   Johannes Berg   mac80211: move BS...
94

0c1ad2cac   Johannes Berg   mac80211: proper ...
95
  	if (!cbss)
00d3f14cf   Johannes Berg   mac80211: use cfg...
96
  		return NULL;
0c1ad2cac   Johannes Berg   mac80211: proper ...
97
98
  	cbss->free_priv = ieee80211_rx_bss_free;
  	bss = (void *)cbss->priv;
5484e2374   Johannes Berg   mac80211: move BS...
99
100
101
102
  
  	/* save the ERP value so that it is available at association time */
  	if (elems->erp_info && elems->erp_info_len >= 1) {
  		bss->erp_value = elems->erp_info[0];
3db1cd5c0   Rusty Russell   net: fix assignme...
103
  		bss->has_erp_value = true;
5484e2374   Johannes Berg   mac80211: move BS...
104
  	}
5484e2374   Johannes Berg   mac80211: move BS...
105
106
107
108
109
  	if (elems->tim) {
  		struct ieee80211_tim_ie *tim_ie =
  			(struct ieee80211_tim_ie *)elems->tim;
  		bss->dtim_period = tim_ie->dtim_period;
  	}
e5b900d22   Johannes Berg   mac80211: allow d...
110
111
112
  	/* If the beacon had no TIM IE, or it was invalid, use 1 */
  	if (beacon && !bss->dtim_period)
  		bss->dtim_period = 1;
f0b058b61   Stanislaw Gruszka   mac80211: do not ...
113
114
  	/* replace old supported rates if we get new values */
  	srlen = 0;
5484e2374   Johannes Berg   mac80211: move BS...
115
  	if (elems->supp_rates) {
f0b058b61   Stanislaw Gruszka   mac80211: do not ...
116
  		clen = IEEE80211_MAX_SUPP_RATES;
5484e2374   Johannes Berg   mac80211: move BS...
117
118
  		if (clen > elems->supp_rates_len)
  			clen = elems->supp_rates_len;
f0b058b61   Stanislaw Gruszka   mac80211: do not ...
119
120
  		memcpy(bss->supp_rates, elems->supp_rates, clen);
  		srlen += clen;
5484e2374   Johannes Berg   mac80211: move BS...
121
122
  	}
  	if (elems->ext_supp_rates) {
f0b058b61   Stanislaw Gruszka   mac80211: do not ...
123
  		clen = IEEE80211_MAX_SUPP_RATES - srlen;
5484e2374   Johannes Berg   mac80211: move BS...
124
125
  		if (clen > elems->ext_supp_rates_len)
  			clen = elems->ext_supp_rates_len;
f0b058b61   Stanislaw Gruszka   mac80211: do not ...
126
127
  		memcpy(bss->supp_rates + srlen, elems->ext_supp_rates, clen);
  		srlen += clen;
5484e2374   Johannes Berg   mac80211: move BS...
128
  	}
f0b058b61   Stanislaw Gruszka   mac80211: do not ...
129
130
  	if (srlen)
  		bss->supp_rates_len = srlen;
5484e2374   Johannes Berg   mac80211: move BS...
131

5484e2374   Johannes Berg   mac80211: move BS...
132
  	bss->wmm_used = elems->wmm_param || elems->wmm_info;
ab13315af   Kalle Valo   mac80211: add U-A...
133
  	bss->uapsd_supported = is_uapsd_supported(elems);
5484e2374   Johannes Berg   mac80211: move BS...
134
135
136
  
  	if (!beacon)
  		bss->last_probe_resp = jiffies;
5484e2374   Johannes Berg   mac80211: move BS...
137
138
  	return bss;
  }
0a51b27e9   Johannes Berg   mac80211: start m...
139

98c8fccfa   Johannes Berg   mac80211: refacto...
140
  ieee80211_rx_result
f1d58c252   Johannes Berg   mac80211: push rx...
141
  ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
98c8fccfa   Johannes Berg   mac80211: refacto...
142
  {
f1d58c252   Johannes Berg   mac80211: push rx...
143
  	struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
98c8fccfa   Johannes Berg   mac80211: refacto...
144
  	struct ieee80211_mgmt *mgmt;
c2b13452b   Johannes Berg   mac80211: clean u...
145
  	struct ieee80211_bss *bss;
98c8fccfa   Johannes Berg   mac80211: refacto...
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
  	u8 *elements;
  	struct ieee80211_channel *channel;
  	size_t baselen;
  	int freq;
  	__le16 fc;
  	bool presp, beacon = false;
  	struct ieee802_11_elems elems;
  
  	if (skb->len < 2)
  		return RX_DROP_UNUSABLE;
  
  	mgmt = (struct ieee80211_mgmt *) skb->data;
  	fc = mgmt->frame_control;
  
  	if (ieee80211_is_ctl(fc))
  		return RX_CONTINUE;
  
  	if (skb->len < 24)
306fe9384   Luciano Coelho   mac80211: don't d...
164
  		return RX_CONTINUE;
98c8fccfa   Johannes Berg   mac80211: refacto...
165
166
167
168
  
  	presp = ieee80211_is_probe_resp(fc);
  	if (presp) {
  		/* ignore ProbeResp to foreign address */
47846c9b0   Johannes Berg   mac80211: reduce ...
169
  		if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN))
98c8fccfa   Johannes Berg   mac80211: refacto...
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
  			return RX_DROP_MONITOR;
  
  		presp = true;
  		elements = mgmt->u.probe_resp.variable;
  		baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
  	} else {
  		beacon = ieee80211_is_beacon(fc);
  		baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
  		elements = mgmt->u.beacon.variable;
  	}
  
  	if (!presp && !beacon)
  		return RX_CONTINUE;
  
  	if (baselen > skb->len)
  		return RX_DROP_MONITOR;
  
  	ieee802_11_parse_elems(elements, skb->len - baselen, &elems);
  
  	if (elems.ds_params && elems.ds_params_len == 1)
59eb21a65   Bruno Randolf   cfg80211: Extend ...
190
191
  		freq = ieee80211_channel_to_frequency(elems.ds_params[0],
  						      rx_status->band);
98c8fccfa   Johannes Berg   mac80211: refacto...
192
193
194
195
196
197
198
199
200
201
  	else
  		freq = rx_status->freq;
  
  	channel = ieee80211_get_channel(sdata->local->hw.wiphy, freq);
  
  	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
  		return RX_DROP_MONITOR;
  
  	bss = ieee80211_bss_info_update(sdata->local, rx_status,
  					mgmt, skb->len, &elems,
2a5193119   Johannes Berg   cfg80211/nl80211:...
202
  					channel, beacon);
d048e503a   Jouni Malinen   mac80211: Fix sca...
203
204
  	if (bss)
  		ieee80211_rx_bss_put(sdata->local, bss);
98c8fccfa   Johannes Berg   mac80211: refacto...
205

07ef03ee8   Johannes Berg   mac80211: simplif...
206
  	if (channel == sdata->local->oper_channel)
b23b025fe   Ben Greear   mac80211: Optimiz...
207
  		return RX_CONTINUE;
98c8fccfa   Johannes Berg   mac80211: refacto...
208
209
210
  	dev_kfree_skb(skb);
  	return RX_QUEUED;
  }
4d36ec582   Johannes Berg   mac80211: split h...
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  /* return false if no more work */
  static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
  {
  	struct cfg80211_scan_request *req = local->scan_req;
  	enum ieee80211_band band;
  	int i, ielen, n_chans;
  
  	do {
  		if (local->hw_scan_band == IEEE80211_NUM_BANDS)
  			return false;
  
  		band = local->hw_scan_band;
  		n_chans = 0;
  		for (i = 0; i < req->n_channels; i++) {
  			if (req->channels[i]->band == band) {
  				local->hw_scan_req->channels[n_chans] =
  							req->channels[i];
  				n_chans++;
  			}
  		}
  
  		local->hw_scan_band++;
  	} while (!n_chans);
  
  	local->hw_scan_req->n_channels = n_chans;
  
  	ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie,
8ee310807   Johannes Berg   mac80211: restric...
238
  					 req->ie, req->ie_len, band,
85a237fe3   Johannes Berg   mac80211: impleme...
239
  					 req->rates[band], 0);
4d36ec582   Johannes Berg   mac80211: split h...
240
  	local->hw_scan_req->ie_len = ielen;
dcd83976b   Johannes Berg   mac80211: pass no...
241
  	local->hw_scan_req->no_cck = req->no_cck;
4d36ec582   Johannes Berg   mac80211: split h...
242
243
244
  
  	return true;
  }
d07bfd8b6   Johannes Berg   mac80211: fix sca...
245
  static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
e229f844d   Stanislaw Gruszka   mac80211: keep lo...
246
  				       bool was_hw_scan)
0a51b27e9   Johannes Berg   mac80211: start m...
247
248
  {
  	struct ieee80211_local *local = hw_to_local(hw);
0a51b27e9   Johannes Berg   mac80211: start m...
249

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

6d3560d4f   Johannes Berg   mac80211: fix sca...
252
253
254
255
256
257
258
259
  	/*
  	 * 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...
260

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

4d36ec582   Johannes Berg   mac80211: split h...
264
  	if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) {
6eb11a9a3   Stanislaw Gruszka   mac80211: do not ...
265
266
  		int rc = drv_hw_scan(local, local->scan_sdata, local->hw_scan_req);
  		if (rc == 0)
d07bfd8b6   Johannes Berg   mac80211: fix sca...
267
  			return;
4d36ec582   Johannes Berg   mac80211: split h...
268
269
270
271
  	}
  
  	kfree(local->hw_scan_req);
  	local->hw_scan_req = NULL;
f3b85252f   Johannes Berg   mac80211: fix sca...
272

5ba63533b   Johannes Berg   cfg80211: fix ali...
273
  	if (local->scan_req != local->int_scan_req)
2a5193119   Johannes Berg   cfg80211/nl80211:...
274
275
  		cfg80211_scan_done(local->scan_req, aborted);
  	local->scan_req = NULL;
15db0b7fd   Johannes Berg   mac80211: fix sca...
276
  	local->scan_sdata = NULL;
2a5193119   Johannes Berg   cfg80211/nl80211:...
277

fbe9c429f   Helmut Schaa   mac80211: Replace...
278
  	local->scanning = 0;
58905ca5b   Johannes Berg   mac80211: fix sca...
279
  	local->scan_channel = NULL;
f3b85252f   Johannes Berg   mac80211: fix sca...
280

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

e229f844d   Stanislaw Gruszka   mac80211: keep lo...
284
285
286
  	if (!was_hw_scan) {
  		ieee80211_configure_filter(local);
  		drv_sw_scan_complete(local);
e76aadc57   Johannes Berg   mac80211: revert ...
287
  		ieee80211_offchannel_return(local, true);
e229f844d   Stanislaw Gruszka   mac80211: keep lo...
288
  	}
0a51b27e9   Johannes Berg   mac80211: start m...
289

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

0a51b27e9   Johannes Berg   mac80211: start m...
292
  	ieee80211_mlme_notify_scan_completed(local);
469002983   Johannes Berg   mac80211: split I...
293
  	ieee80211_ibss_notify_scan_completed(local);
472dbc45d   Johannes Berg   mac80211: split o...
294
  	ieee80211_mesh_notify_scan_completed(local);
81ac3462d   Johannes Berg   mac80211: fix a f...
295
  	ieee80211_queue_work(&local->hw, &local->work_work);
0a51b27e9   Johannes Berg   mac80211: start m...
296
  }
8789d459b   Johannes Berg   mac80211: allow s...
297
298
299
300
301
302
303
304
305
306
307
308
  
  void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
  {
  	struct ieee80211_local *local = hw_to_local(hw);
  
  	trace_api_scan_completed(local, aborted);
  
  	set_bit(SCAN_COMPLETED, &local->scanning);
  	if (aborted)
  		set_bit(SCAN_ABORTED, &local->scanning);
  	ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0);
  }
0a51b27e9   Johannes Berg   mac80211: start m...
309
  EXPORT_SYMBOL(ieee80211_scan_completed);
f3b85252f   Johannes Berg   mac80211: fix sca...
310
311
  static int ieee80211_start_sw_scan(struct ieee80211_local *local)
  {
f3b85252f   Johannes Berg   mac80211: fix sca...
312
313
314
315
316
317
318
319
320
321
322
323
324
  	/*
  	 * 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().
  	 */
244879813   Johannes Berg   mac80211: add dri...
325
  	drv_sw_scan_start(local);
f3b85252f   Johannes Berg   mac80211: fix sca...
326

df13cce53   Helmut Schaa   mac80211: Improve...
327
  	local->leave_oper_channel_time = 0;
977923b00   Helmut Schaa   mac80211: rename ...
328
  	local->next_scan_state = SCAN_DECISION;
f3b85252f   Johannes Berg   mac80211: fix sca...
329
  	local->scan_channel_idx = 0;
07ef03ee8   Johannes Berg   mac80211: simplif...
330
  	ieee80211_offchannel_stop_vifs(local, true);
a80f7c0b0   Johannes Berg   mac80211: introdu...
331

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

59bdf3b0f   Ben Greear   mac80211: Ensure ...
334
335
  	/* We need to set power level at maximum rate for scanning. */
  	ieee80211_hw_config(local, 0);
42935ecaf   Luis R. Rodriguez   mac80211: redefin...
336
  	ieee80211_queue_delayed_work(&local->hw,
07ef03ee8   Johannes Berg   mac80211: simplif...
337
  				     &local->scan_work, 0);
f3b85252f   Johannes Berg   mac80211: fix sca...
338
339
340
341
342
343
344
345
346
  
  	return 0;
  }
  
  
  static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
  				  struct cfg80211_scan_request *req)
  {
  	struct ieee80211_local *local = sdata->local;
f3b85252f   Johannes Berg   mac80211: fix sca...
347
  	int rc;
e229f844d   Stanislaw Gruszka   mac80211: keep lo...
348
  	lockdep_assert_held(&local->mtx);
f3b85252f   Johannes Berg   mac80211: fix sca...
349
350
  	if (local->scan_req)
  		return -EBUSY;
6e7e6213e   John W. Linville   Merge branch 'mas...
351
352
  	if (!list_empty(&local->work_list)) {
  		/* wait for the work to finish/time out */
c0ce77b83   Johannes Berg   mac80211: fix def...
353
354
355
356
  		local->scan_req = req;
  		local->scan_sdata = sdata;
  		return 0;
  	}
f3b85252f   Johannes Berg   mac80211: fix sca...
357
358
  	if (local->ops->hw_scan) {
  		u8 *ies;
f3b85252f   Johannes Berg   mac80211: fix sca...
359

4d36ec582   Johannes Berg   mac80211: split h...
360
361
362
363
364
365
  		local->hw_scan_req = kmalloc(
  				sizeof(*local->hw_scan_req) +
  				req->n_channels * sizeof(req->channels[0]) +
  				2 + IEEE80211_MAX_SSID_LEN + local->scan_ies_len +
  				req->ie_len, GFP_KERNEL);
  		if (!local->hw_scan_req)
f3b85252f   Johannes Berg   mac80211: fix sca...
366
  			return -ENOMEM;
4d36ec582   Johannes Berg   mac80211: split h...
367
368
369
370
371
372
373
374
  		local->hw_scan_req->ssids = req->ssids;
  		local->hw_scan_req->n_ssids = req->n_ssids;
  		ies = (u8 *)local->hw_scan_req +
  			sizeof(*local->hw_scan_req) +
  			req->n_channels * sizeof(req->channels[0]);
  		local->hw_scan_req->ie = ies;
  
  		local->hw_scan_band = 0;
6e7e6213e   John W. Linville   Merge branch 'mas...
375
376
377
378
379
380
381
382
  
  		/*
  		 * 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...
383
384
385
386
  	}
  
  	local->scan_req = req;
  	local->scan_sdata = sdata;
f3b85252f   Johannes Berg   mac80211: fix sca...
387
  	if (local->ops->hw_scan)
fbe9c429f   Helmut Schaa   mac80211: Replace...
388
  		__set_bit(SCAN_HW_SCANNING, &local->scanning);
f3b85252f   Johannes Berg   mac80211: fix sca...
389
  	else
fbe9c429f   Helmut Schaa   mac80211: Replace...
390
  		__set_bit(SCAN_SW_SCANNING, &local->scanning);
6e7e6213e   John W. Linville   Merge branch 'mas...
391

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

4d36ec582   Johannes Berg   mac80211: split h...
394
395
  	if (local->ops->hw_scan) {
  		WARN_ON(!ieee80211_prep_hw_scan(local));
a060bbfe4   Johannes Berg   mac80211: give vi...
396
  		rc = drv_hw_scan(local, sdata, local->hw_scan_req);
4d36ec582   Johannes Berg   mac80211: split h...
397
  	} else
f3b85252f   Johannes Berg   mac80211: fix sca...
398
  		rc = ieee80211_start_sw_scan(local);
f3b85252f   Johannes Berg   mac80211: fix sca...
399
  	if (rc) {
4d36ec582   Johannes Berg   mac80211: split h...
400
401
  		kfree(local->hw_scan_req);
  		local->hw_scan_req = NULL;
fbe9c429f   Helmut Schaa   mac80211: Replace...
402
  		local->scanning = 0;
f3b85252f   Johannes Berg   mac80211: fix sca...
403

5cff20e6c   Johannes Berg   mac80211: tell dr...
404
  		ieee80211_recalc_idle(local);
f3b85252f   Johannes Berg   mac80211: fix sca...
405
406
407
408
409
410
  		local->scan_req = NULL;
  		local->scan_sdata = NULL;
  	}
  
  	return rc;
  }
df13cce53   Helmut Schaa   mac80211: Improve...
411
412
413
414
415
416
417
418
419
420
421
  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
  	 */
  	if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
  		return IEEE80211_PASSIVE_CHANNEL_TIME;
  	return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME;
  }
e229f844d   Stanislaw Gruszka   mac80211: keep lo...
422
423
  static void ieee80211_scan_state_decision(struct ieee80211_local *local,
  					  unsigned long *next_delay)
7d3be3cc4   Helmut Schaa   mac80211: refacto...
424
  {
142b9f507   Helmut Schaa   mac80211: impleme...
425
  	bool associated = false;
df13cce53   Helmut Schaa   mac80211: Improve...
426
427
428
429
  	bool tx_empty = true;
  	bool bad_latency;
  	bool listen_int_exceeded;
  	unsigned long min_beacon_int = 0;
142b9f507   Helmut Schaa   mac80211: impleme...
430
  	struct ieee80211_sub_if_data *sdata;
df13cce53   Helmut Schaa   mac80211: Improve...
431
  	struct ieee80211_channel *next_chan;
142b9f507   Helmut Schaa   mac80211: impleme...
432

df13cce53   Helmut Schaa   mac80211: Improve...
433
434
435
436
437
  	/*
  	 * 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...
438
439
  	mutex_lock(&local->iflist_mtx);
  	list_for_each_entry(sdata, &local->interfaces, list) {
9607e6b66   Johannes Berg   mac80211: add iee...
440
  		if (!ieee80211_sdata_running(sdata))
142b9f507   Helmut Schaa   mac80211: impleme...
441
442
443
444
445
  			continue;
  
  		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
  			if (sdata->u.mgd.associated) {
  				associated = true;
df13cce53   Helmut Schaa   mac80211: Improve...
446
447
448
449
450
451
452
453
454
455
  
  				if (sdata->vif.bss_conf.beacon_int <
  				    min_beacon_int || min_beacon_int == 0)
  					min_beacon_int =
  						sdata->vif.bss_conf.beacon_int;
  
  				if (!qdisc_all_tx_empty(sdata->dev)) {
  					tx_empty = false;
  					break;
  				}
142b9f507   Helmut Schaa   mac80211: impleme...
456
457
458
459
  			}
  		}
  	}
  	mutex_unlock(&local->iflist_mtx);
b23b025fe   Ben Greear   mac80211: Optimiz...
460
  	next_chan = local->scan_req->channels[local->scan_channel_idx];
a80f7c0b0   Johannes Berg   mac80211: introdu...
461
  	/*
07ef03ee8   Johannes Berg   mac80211: simplif...
462
463
464
465
466
467
468
469
470
471
472
473
474
  	 * we're currently scanning a different channel, let's
  	 * see if we can scan another channel without interfering
  	 * with the current traffic situation.
  	 *
  	 * Since we don't know if the AP has pending frames for us
  	 * we can only check for our tx queues and use the current
  	 * pm_qos requirements for rx. Hence, if no tx traffic occurs
  	 * at all we will scan as many channels in a row as the pm_qos
  	 * latency allows us to. Additionally we also check for the
  	 * currently negotiated listen interval to prevent losing
  	 * frames unnecessarily.
  	 *
  	 * Otherwise switch back to the operating channel.
a80f7c0b0   Johannes Berg   mac80211: introdu...
475
  	 */
a80f7c0b0   Johannes Berg   mac80211: introdu...
476

07ef03ee8   Johannes Berg   mac80211: simplif...
477
478
479
480
  	bad_latency = time_after(jiffies +
  			ieee80211_scan_get_channel_time(next_chan),
  			local->leave_oper_channel_time +
  			usecs_to_jiffies(pm_qos_request(PM_QOS_NETWORK_LATENCY)));
df13cce53   Helmut Schaa   mac80211: Improve...
481

07ef03ee8   Johannes Berg   mac80211: simplif...
482
483
484
485
486
  	listen_int_exceeded = time_after(jiffies +
  			ieee80211_scan_get_channel_time(next_chan),
  			local->leave_oper_channel_time +
  			usecs_to_jiffies(min_beacon_int * 1024) *
  			local->hw.conf.listen_interval);
142b9f507   Helmut Schaa   mac80211: impleme...
487

07ef03ee8   Johannes Berg   mac80211: simplif...
488
489
490
491
  	if (associated && (!tx_empty || bad_latency || listen_int_exceeded))
  		local->next_scan_state = SCAN_SUSPEND;
  	else
  		local->next_scan_state = SCAN_SET_CHANNEL;
142b9f507   Helmut Schaa   mac80211: impleme...
492

07ef03ee8   Johannes Berg   mac80211: simplif...
493
  	*next_delay = 0;
142b9f507   Helmut Schaa   mac80211: impleme...
494
  }
2fb3f028a   Helmut Schaa   mac80211: introdu...
495
496
497
498
499
  static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
  					     unsigned long *next_delay)
  {
  	int skip;
  	struct ieee80211_channel *chan;
2fb3f028a   Helmut Schaa   mac80211: introdu...
500

7d3be3cc4   Helmut Schaa   mac80211: refacto...
501
502
  	skip = 0;
  	chan = local->scan_req->channels[local->scan_channel_idx];
584991dcc   Johannes Berg   cfg80211: validat...
503
  	local->scan_channel = chan;
b23b025fe   Ben Greear   mac80211: Optimiz...
504

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

7d3be3cc4   Helmut Schaa   mac80211: refacto...
508
509
  	/* advance state machine to next channel/band */
  	local->scan_channel_idx++;
0ee9c13c7   Helmut Schaa   mac80211: fix an ...
510
511
512
  	if (skip) {
  		/* if we skip this channel return to the decision state */
  		local->next_scan_state = SCAN_DECISION;
2fb3f028a   Helmut Schaa   mac80211: introdu...
513
  		return;
0ee9c13c7   Helmut Schaa   mac80211: fix an ...
514
  	}
7d3be3cc4   Helmut Schaa   mac80211: refacto...
515
516
517
518
519
520
521
522
523
524
525
526
527
528
  
  	/*
  	 * 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.
  	 */
  	if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
  	    !local->scan_req->n_ssids) {
  		*next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
977923b00   Helmut Schaa   mac80211: rename ...
529
  		local->next_scan_state = SCAN_DECISION;
2fb3f028a   Helmut Schaa   mac80211: introdu...
530
  		return;
7d3be3cc4   Helmut Schaa   mac80211: refacto...
531
  	}
2fb3f028a   Helmut Schaa   mac80211: introdu...
532
  	/* active scan, send probes */
7d3be3cc4   Helmut Schaa   mac80211: refacto...
533
  	*next_delay = IEEE80211_PROBE_DELAY;
977923b00   Helmut Schaa   mac80211: rename ...
534
  	local->next_scan_state = SCAN_SEND_PROBE;
7d3be3cc4   Helmut Schaa   mac80211: refacto...
535
536
537
538
539
540
541
  }
  
  static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
  					    unsigned long *next_delay)
  {
  	int i;
  	struct ieee80211_sub_if_data *sdata = local->scan_sdata;
85a237fe3   Johannes Berg   mac80211: impleme...
542
  	enum ieee80211_band band = local->hw.conf.channel->band;
7d3be3cc4   Helmut Schaa   mac80211: refacto...
543
544
545
546
547
548
  
  	for (i = 0; i < local->scan_req->n_ssids; i++)
  		ieee80211_send_probe_req(
  			sdata, NULL,
  			local->scan_req->ssids[i].ssid,
  			local->scan_req->ssids[i].ssid_len,
a806c558e   Paul Stewart   mac80211: Drop DS...
549
  			local->scan_req->ie, local->scan_req->ie_len,
aad14ceb4   Rajkumar Manoharan   mac80211: Send th...
550
551
  			local->scan_req->rates[band], false,
  			local->scan_req->no_cck);
7d3be3cc4   Helmut Schaa   mac80211: refacto...
552
553
554
555
556
557
  
  	/*
  	 * After sending probe requests, wait for probe responses
  	 * on the channel.
  	 */
  	*next_delay = IEEE80211_CHANNEL_TIME;
977923b00   Helmut Schaa   mac80211: rename ...
558
  	local->next_scan_state = SCAN_DECISION;
7d3be3cc4   Helmut Schaa   mac80211: refacto...
559
  }
07ef03ee8   Johannes Berg   mac80211: simplif...
560
561
562
563
564
565
566
567
568
569
570
571
  static void ieee80211_scan_state_suspend(struct ieee80211_local *local,
  					 unsigned long *next_delay)
  {
  	/* switch back to the operating channel */
  	local->scan_channel = NULL;
  	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
  
  	/*
  	 * Re-enable vifs and beaconing.  Leave PS
  	 * in off-channel state..will put that back
  	 * on-channel at the end of scanning.
  	 */
e76aadc57   Johannes Berg   mac80211: revert ...
572
  	ieee80211_offchannel_return(local, false);
07ef03ee8   Johannes Berg   mac80211: simplif...
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
  
  	*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)
  {
  	/* PS already is in off-channel mode */
  	ieee80211_offchannel_stop_vifs(local, false);
  
  	if (local->ops->flush) {
  		drv_flush(local, false);
  		*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...
595
  	local->next_scan_state = SCAN_SET_CHANNEL;
07ef03ee8   Johannes Berg   mac80211: simplif...
596
  }
c2b13452b   Johannes Berg   mac80211: clean u...
597
  void ieee80211_scan_work(struct work_struct *work)
0a51b27e9   Johannes Berg   mac80211: start m...
598
599
600
  {
  	struct ieee80211_local *local =
  		container_of(work, struct ieee80211_local, scan_work.work);
d07bfd8b6   Johannes Berg   mac80211: fix sca...
601
  	struct ieee80211_sub_if_data *sdata;
0a51b27e9   Johannes Berg   mac80211: start m...
602
  	unsigned long next_delay = 0;
d07bfd8b6   Johannes Berg   mac80211: fix sca...
603
  	bool aborted, hw_scan;
0a51b27e9   Johannes Berg   mac80211: start m...
604

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

d07bfd8b6   Johannes Berg   mac80211: fix sca...
607
  	sdata = local->scan_sdata;
259b62e35   Stanislaw Gruszka   mac80211: reduce ...
608
  	if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) {
8789d459b   Johannes Berg   mac80211: allow s...
609
  		aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning);
259b62e35   Stanislaw Gruszka   mac80211: reduce ...
610
  		goto out_complete;
8789d459b   Johannes Berg   mac80211: allow s...
611
  	}
259b62e35   Stanislaw Gruszka   mac80211: reduce ...
612
613
  	if (!sdata || !local->scan_req)
  		goto out;
f3b85252f   Johannes Berg   mac80211: fix sca...
614

fbe9c429f   Helmut Schaa   mac80211: Replace...
615
  	if (local->scan_req && !local->scanning) {
f3b85252f   Johannes Berg   mac80211: fix sca...
616
617
618
619
  		struct cfg80211_scan_request *req = local->scan_req;
  		int rc;
  
  		local->scan_req = NULL;
15db0b7fd   Johannes Berg   mac80211: fix sca...
620
  		local->scan_sdata = NULL;
f3b85252f   Johannes Berg   mac80211: fix sca...
621
622
  
  		rc = __ieee80211_start_scan(sdata, req);
259b62e35   Stanislaw Gruszka   mac80211: reduce ...
623
  		if (rc) {
3aed49ef1   Stanislaw Gruszka   mac80211: compete...
624
625
  			/* need to complete scan in cfg80211 */
  			local->scan_req = req;
259b62e35   Stanislaw Gruszka   mac80211: reduce ...
626
627
628
629
  			aborted = true;
  			goto out_complete;
  		} else
  			goto out;
f3b85252f   Johannes Berg   mac80211: fix sca...
630
  	}
5bc75728f   Johannes Berg   mac80211: fix sca...
631
632
633
  	/*
  	 * Avoid re-scheduling when the sdata is going away.
  	 */
9607e6b66   Johannes Berg   mac80211: add iee...
634
  	if (!ieee80211_sdata_running(sdata)) {
259b62e35   Stanislaw Gruszka   mac80211: reduce ...
635
636
  		aborted = true;
  		goto out_complete;
f3b85252f   Johannes Berg   mac80211: fix sca...
637
  	}
0a51b27e9   Johannes Berg   mac80211: start m...
638

f502d09b7   Helmut Schaa   mac80211: advance...
639
640
641
642
643
  	/*
  	 * as long as no delay is required advance immediately
  	 * without scheduling a new work
  	 */
  	do {
c29acf201   Rajkumar Manoharan   mac80211: abort s...
644
645
646
647
  		if (!ieee80211_sdata_running(sdata)) {
  			aborted = true;
  			goto out_complete;
  		}
977923b00   Helmut Schaa   mac80211: rename ...
648
  		switch (local->next_scan_state) {
2fb3f028a   Helmut Schaa   mac80211: introdu...
649
  		case SCAN_DECISION:
e229f844d   Stanislaw Gruszka   mac80211: keep lo...
650
651
652
653
654
655
  			/* if no more bands/channels left, complete scan */
  			if (local->scan_channel_idx >= local->scan_req->n_channels) {
  				aborted = false;
  				goto out_complete;
  			}
  			ieee80211_scan_state_decision(local, &next_delay);
f502d09b7   Helmut Schaa   mac80211: advance...
656
  			break;
2fb3f028a   Helmut Schaa   mac80211: introdu...
657
658
659
  		case SCAN_SET_CHANNEL:
  			ieee80211_scan_state_set_channel(local, &next_delay);
  			break;
f502d09b7   Helmut Schaa   mac80211: advance...
660
661
662
  		case SCAN_SEND_PROBE:
  			ieee80211_scan_state_send_probe(local, &next_delay);
  			break;
07ef03ee8   Johannes Berg   mac80211: simplif...
663
664
  		case SCAN_SUSPEND:
  			ieee80211_scan_state_suspend(local, &next_delay);
142b9f507   Helmut Schaa   mac80211: impleme...
665
  			break;
07ef03ee8   Johannes Berg   mac80211: simplif...
666
667
  		case SCAN_RESUME:
  			ieee80211_scan_state_resume(local, &next_delay);
142b9f507   Helmut Schaa   mac80211: impleme...
668
  			break;
f502d09b7   Helmut Schaa   mac80211: advance...
669
670
  		}
  	} while (next_delay == 0);
0a51b27e9   Johannes Berg   mac80211: start m...
671

42935ecaf   Luis R. Rodriguez   mac80211: redefin...
672
  	ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay);
d07bfd8b6   Johannes Berg   mac80211: fix sca...
673
  	goto out;
259b62e35   Stanislaw Gruszka   mac80211: reduce ...
674
675
  
  out_complete:
e229f844d   Stanislaw Gruszka   mac80211: keep lo...
676
  	hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
d07bfd8b6   Johannes Berg   mac80211: fix sca...
677
  	__ieee80211_scan_completed(&local->hw, aborted, hw_scan);
259b62e35   Stanislaw Gruszka   mac80211: reduce ...
678
679
  out:
  	mutex_unlock(&local->mtx);
0a51b27e9   Johannes Berg   mac80211: start m...
680
  }
f3b85252f   Johannes Berg   mac80211: fix sca...
681
682
  int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
  			   struct cfg80211_scan_request *req)
0a51b27e9   Johannes Berg   mac80211: start m...
683
  {
f3b85252f   Johannes Berg   mac80211: fix sca...
684
  	int res;
de95a54b1   Johannes Berg   mac80211: pass al...
685

a1699b75a   Johannes Berg   mac80211: unify s...
686
  	mutex_lock(&sdata->local->mtx);
f3b85252f   Johannes Berg   mac80211: fix sca...
687
  	res = __ieee80211_start_scan(sdata, req);
a1699b75a   Johannes Berg   mac80211: unify s...
688
  	mutex_unlock(&sdata->local->mtx);
0a51b27e9   Johannes Berg   mac80211: start m...
689

f3b85252f   Johannes Berg   mac80211: fix sca...
690
  	return res;
0a51b27e9   Johannes Berg   mac80211: start m...
691
  }
f3b85252f   Johannes Berg   mac80211: fix sca...
692
  int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
be4a4b6a5   Johannes Berg   mac80211: improve...
693
694
  				    const u8 *ssid, u8 ssid_len,
  				    struct ieee80211_channel *chan)
0a51b27e9   Johannes Berg   mac80211: start m...
695
  {
0a51b27e9   Johannes Berg   mac80211: start m...
696
  	struct ieee80211_local *local = sdata->local;
f3b85252f   Johannes Berg   mac80211: fix sca...
697
  	int ret = -EBUSY;
fb63bc417   Gertjan van Wingerde   mac80211: Fix com...
698
  	enum ieee80211_band band;
2a5193119   Johannes Berg   cfg80211/nl80211:...
699

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

f3b85252f   Johannes Berg   mac80211: fix sca...
702
703
704
  	/* busy scanning */
  	if (local->scan_req)
  		goto unlock;
9116dd011   Johannes Berg   mac80211: clarify...
705

be4a4b6a5   Johannes Berg   mac80211: improve...
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
  	/* fill internal scan request */
  	if (!chan) {
  		int i, nchan = 0;
  
  		for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
  			if (!local->hw.wiphy->bands[band])
  				continue;
  			for (i = 0;
  			     i < local->hw.wiphy->bands[band]->n_channels;
  			     i++) {
  				local->int_scan_req->channels[nchan] =
  				    &local->hw.wiphy->bands[band]->channels[i];
  				nchan++;
  			}
  		}
  
  		local->int_scan_req->n_channels = nchan;
  	} else {
  		local->int_scan_req->channels[0] = chan;
  		local->int_scan_req->n_channels = 1;
  	}
  
  	local->int_scan_req->ssids = &local->scan_ssid;
  	local->int_scan_req->n_ssids = 1;
5ba63533b   Johannes Berg   cfg80211: fix ali...
730
731
  	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...
732

5ba63533b   Johannes Berg   cfg80211: fix ali...
733
  	ret = __ieee80211_start_scan(sdata, sdata->local->int_scan_req);
f3b85252f   Johannes Berg   mac80211: fix sca...
734
   unlock:
a1699b75a   Johannes Berg   mac80211: unify s...
735
  	mutex_unlock(&local->mtx);
f3b85252f   Johannes Berg   mac80211: fix sca...
736
  	return ret;
0a51b27e9   Johannes Berg   mac80211: start m...
737
  }
5bb644a0f   Johannes Berg   mac80211: cancel/...
738

4136c4224   Stanislaw Gruszka   mac80211: assure ...
739
740
741
  /*
   * Only call this function when a scan can't be queued -- under RTNL.
   */
5bb644a0f   Johannes Berg   mac80211: cancel/...
742
743
  void ieee80211_scan_cancel(struct ieee80211_local *local)
  {
5bb644a0f   Johannes Berg   mac80211: cancel/...
744
  	/*
b856439b1   Eliad Peller   mac80211: add can...
745
  	 * We are canceling software scan, or deferred scan that was not
4136c4224   Stanislaw Gruszka   mac80211: assure ...
746
747
748
749
750
751
752
753
754
755
756
  	 * 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...
757
758
759
  	 * 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/...
760
  	 */
4136c4224   Stanislaw Gruszka   mac80211: assure ...
761

a1699b75a   Johannes Berg   mac80211: unify s...
762
  	mutex_lock(&local->mtx);
b856439b1   Eliad Peller   mac80211: add can...
763
764
765
766
767
768
769
  	if (!local->scan_req)
  		goto out;
  
  	if (test_bit(SCAN_HW_SCANNING, &local->scanning)) {
  		if (local->ops->cancel_hw_scan)
  			drv_cancel_hw_scan(local, local->scan_sdata);
  		goto out;
4136c4224   Stanislaw Gruszka   mac80211: assure ...
770
  	}
b856439b1   Eliad Peller   mac80211: add can...
771
772
773
774
775
776
777
778
779
780
  
  	/*
  	 * If the work is currently running, it must be blocked on
  	 * the mutex, but we'll set scan_sdata = NULL and it'll
  	 * simply exit once it acquires the mutex.
  	 */
  	cancel_delayed_work(&local->scan_work);
  	/* and clean up */
  	__ieee80211_scan_completed(&local->hw, true, false);
  out:
d07bfd8b6   Johannes Berg   mac80211: fix sca...
781
  	mutex_unlock(&local->mtx);
5bb644a0f   Johannes Berg   mac80211: cancel/...
782
  }
79f460ca4   Luciano Coelho   mac80211: add sup...
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
  
  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, i;
  
  	mutex_lock(&sdata->local->mtx);
  
  	if (local->sched_scanning) {
  		ret = -EBUSY;
  		goto out;
  	}
  
  	if (!local->ops->sched_scan_start) {
  		ret = -ENOTSUPP;
  		goto out;
  	}
  
  	for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
  		local->sched_scan_ies.ie[i] = kzalloc(2 +
  						      IEEE80211_MAX_SSID_LEN +
1186980da   Luciano Coelho   mac80211: fix ie ...
805
806
  						      local->scan_ies_len +
  						      req->ie_len,
79f460ca4   Luciano Coelho   mac80211: add sup...
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
  						      GFP_KERNEL);
  		if (!local->sched_scan_ies.ie[i]) {
  			ret = -ENOMEM;
  			goto out_free;
  		}
  
  		local->sched_scan_ies.len[i] =
  			ieee80211_build_preq_ies(local,
  						 local->sched_scan_ies.ie[i],
  						 req->ie, req->ie_len, i,
  						 (u32) -1, 0);
  	}
  
  	ret = drv_sched_scan_start(local, sdata, req,
  				   &local->sched_scan_ies);
  	if (ret == 0) {
  		local->sched_scanning = true;
  		goto out;
  	}
  
  out_free:
  	while (i > 0)
  		kfree(local->sched_scan_ies.ie[--i]);
  out:
  	mutex_unlock(&sdata->local->mtx);
  	return ret;
  }
85a9994a0   Luciano Coelho   cfg80211/mac80211...
834
  int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
79f460ca4   Luciano Coelho   mac80211: add sup...
835
836
837
838
839
840
841
842
843
844
845
846
847
848
  {
  	struct ieee80211_local *local = sdata->local;
  	int ret = 0, i;
  
  	mutex_lock(&sdata->local->mtx);
  
  	if (!local->ops->sched_scan_stop) {
  		ret = -ENOTSUPP;
  		goto out;
  	}
  
  	if (local->sched_scanning) {
  		for (i = 0; i < IEEE80211_NUM_BANDS; i++)
  			kfree(local->sched_scan_ies.ie[i]);
85a9994a0   Luciano Coelho   cfg80211/mac80211...
849
  		drv_sched_scan_stop(local, sdata);
79f460ca4   Luciano Coelho   mac80211: add sup...
850
851
  		local->sched_scanning = false;
  	}
79f460ca4   Luciano Coelho   mac80211: add sup...
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
  out:
  	mutex_unlock(&sdata->local->mtx);
  
  	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);
  
  	cfg80211_sched_scan_results(hw->wiphy);
  }
  EXPORT_SYMBOL(ieee80211_sched_scan_results);
85a9994a0   Luciano Coelho   cfg80211/mac80211...
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
  void ieee80211_sched_scan_stopped_work(struct work_struct *work)
  {
  	struct ieee80211_local *local =
  		container_of(work, struct ieee80211_local,
  			     sched_scan_stopped_work);
  	int i;
  
  	mutex_lock(&local->mtx);
  
  	if (!local->sched_scanning) {
  		mutex_unlock(&local->mtx);
  		return;
  	}
  
  	for (i = 0; i < IEEE80211_NUM_BANDS; i++)
  		kfree(local->sched_scan_ies.ie[i]);
  
  	local->sched_scanning = false;
  
  	mutex_unlock(&local->mtx);
  
  	cfg80211_sched_scan_stopped(local->hw.wiphy);
  }
79f460ca4   Luciano Coelho   mac80211: add sup...
890
891
892
893
894
  void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw)
  {
  	struct ieee80211_local *local = hw_to_local(hw);
  
  	trace_api_sched_scan_stopped(local);
85a9994a0   Luciano Coelho   cfg80211/mac80211...
895
  	ieee80211_queue_work(&local->hw, &local->sched_scan_stopped_work);
79f460ca4   Luciano Coelho   mac80211: add sup...
896
897
  }
  EXPORT_SYMBOL(ieee80211_sched_scan_stopped);