Blame view
net/mac80211/scan.c
25.9 KB
0a51b27e9 mac80211: start m... |
1 |
/* |
5484e2374 mac80211: move BS... |
2 3 |
* Scanning implementation * |
0a51b27e9 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 mac80211: start m... |
14 |
#include <linux/if_arp.h> |
888d04dfb mac80211: use com... |
15 |
#include <linux/etherdevice.h> |
078e1e60d mac80211: Add cap... |
16 |
#include <linux/rtnetlink.h> |
e8db0be12 PM QoS: Move and ... |
17 |
#include <linux/pm_qos.h> |
df13cce53 mac80211: Improve... |
18 |
#include <net/sch_generic.h> |
5a0e3ad6a include cleanup: ... |
19 |
#include <linux/slab.h> |
bc3b2d7fb net: Add export.h... |
20 |
#include <linux/export.h> |
0a51b27e9 mac80211: start m... |
21 |
#include <net/mac80211.h> |
0a51b27e9 mac80211: start m... |
22 23 |
#include "ieee80211_i.h" |
244879813 mac80211: add dri... |
24 |
#include "driver-ops.h" |
5484e2374 mac80211: move BS... |
25 |
#include "mesh.h" |
0a51b27e9 mac80211: start m... |
26 27 28 |
#define IEEE80211_PROBE_DELAY (HZ / 33) #define IEEE80211_CHANNEL_TIME (HZ / 33) |
3f892b61a mac80211: improve... |
29 |
#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 9) |
0a51b27e9 mac80211: start m... |
30 |
|
5484e2374 mac80211: move BS... |
31 |
void ieee80211_rx_bss_put(struct ieee80211_local *local, |
c2b13452b mac80211: clean u... |
32 |
struct ieee80211_bss *bss) |
5484e2374 mac80211: move BS... |
33 |
{ |
0c1ad2cac mac80211: proper ... |
34 35 |
if (!bss) return; |
5b112d3d0 cfg80211: pass wi... |
36 37 |
cfg80211_put_bss(local->hw.wiphy, container_of((void *)bss, struct cfg80211_bss, priv)); |
5484e2374 mac80211: move BS... |
38 |
} |
ab13315af 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; } |
c2b13452b mac80211: clean u... |
55 |
struct ieee80211_bss * |
5484e2374 mac80211: move BS... |
56 57 |
ieee80211_bss_info_update(struct ieee80211_local *local, struct ieee80211_rx_status *rx_status, |
d45c41722 mac82011: use fra... |
58 |
struct ieee80211_mgmt *mgmt, size_t len, |
5484e2374 mac80211: move BS... |
59 |
struct ieee802_11_elems *elems, |
d45c41722 mac82011: use fra... |
60 |
struct ieee80211_channel *channel) |
5484e2374 mac80211: move BS... |
61 |
{ |
d45c41722 mac82011: use fra... |
62 |
bool beacon = ieee80211_is_beacon(mgmt->frame_control); |
0c1ad2cac mac80211: proper ... |
63 |
struct cfg80211_bss *cbss; |
c2b13452b mac80211: clean u... |
64 |
struct ieee80211_bss *bss; |
f0b058b61 mac80211: do not ... |
65 |
int clen, srlen; |
2a5193119 cfg80211/nl80211:... |
66 |
s32 signal = 0; |
77965c970 cfg80211: clean u... |
67 |
if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) |
2a5193119 cfg80211/nl80211:... |
68 |
signal = rx_status->signal * 100; |
77965c970 cfg80211: clean u... |
69 |
else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) |
2a5193119 cfg80211/nl80211:... |
70 |
signal = (rx_status->signal * 100) / local->hw.max_signal; |
2a5193119 cfg80211/nl80211:... |
71 |
|
0c1ad2cac mac80211: proper ... |
72 73 |
cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel, mgmt, len, signal, GFP_ATOMIC); |
0c1ad2cac mac80211: proper ... |
74 |
if (!cbss) |
00d3f14cf mac80211: use cfg... |
75 |
return NULL; |
0c1ad2cac mac80211: proper ... |
76 |
bss = (void *)cbss->priv; |
5484e2374 mac80211: move BS... |
77 |
|
ef429dadf mac80211: introdu... |
78 79 80 81 |
if (beacon) bss->device_ts_beacon = rx_status->device_timestamp; else bss->device_ts_presp = rx_status->device_timestamp; |
8c358bcd0 mac80211: add tim... |
82 |
|
fcff4f108 mac80211: Filter ... |
83 84 85 86 87 88 89 90 91 92 93 |
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; } |
5484e2374 mac80211: move BS... |
94 |
/* save the ERP value so that it is available at association time */ |
1946bed95 mac80211: check E... |
95 96 |
if (elems->erp_info && (!elems->parse_error || !(bss->valid_data & IEEE80211_BSS_VALID_ERP))) { |
5484e2374 mac80211: move BS... |
97 |
bss->erp_value = elems->erp_info[0]; |
3db1cd5c0 net: fix assignme... |
98 |
bss->has_erp_value = true; |
fcff4f108 mac80211: Filter ... |
99 100 |
if (!elems->parse_error) bss->valid_data |= IEEE80211_BSS_VALID_ERP; |
5484e2374 mac80211: move BS... |
101 |
} |
f0b058b61 mac80211: do not ... |
102 |
/* replace old supported rates if we get new values */ |
fcff4f108 mac80211: Filter ... |
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
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; } |
5484e2374 mac80211: move BS... |
126 |
} |
5484e2374 mac80211: move BS... |
127 |
|
fcff4f108 mac80211: Filter ... |
128 129 130 131 132 133 134 |
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; } |
5484e2374 mac80211: move BS... |
135 |
|
5484e2374 mac80211: move BS... |
136 137 |
return bss; } |
0a51b27e9 mac80211: start m... |
138 |
|
d48b29685 mac80211: redesig... |
139 |
void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) |
98c8fccfa mac80211: refacto... |
140 |
{ |
f1d58c252 mac80211: push rx... |
141 |
struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); |
d48b29685 mac80211: redesig... |
142 143 |
struct ieee80211_sub_if_data *sdata1, *sdata2; struct ieee80211_mgmt *mgmt = (void *)skb->data; |
c2b13452b mac80211: clean u... |
144 |
struct ieee80211_bss *bss; |
98c8fccfa mac80211: refacto... |
145 146 147 |
u8 *elements; struct ieee80211_channel *channel; size_t baselen; |
98c8fccfa mac80211: refacto... |
148 |
struct ieee802_11_elems elems; |
d48b29685 mac80211: redesig... |
149 150 151 152 |
if (skb->len < 24 || (!ieee80211_is_probe_resp(mgmt->frame_control) && !ieee80211_is_beacon(mgmt->frame_control))) return; |
98c8fccfa mac80211: refacto... |
153 |
|
d48b29685 mac80211: redesig... |
154 155 |
sdata1 = rcu_dereference(local->scan_sdata); sdata2 = rcu_dereference(local->sched_scan_sdata); |
98c8fccfa mac80211: refacto... |
156 |
|
d48b29685 mac80211: redesig... |
157 158 |
if (likely(!sdata1 && !sdata2)) return; |
98c8fccfa mac80211: refacto... |
159 |
|
d48b29685 mac80211: redesig... |
160 |
if (ieee80211_is_probe_resp(mgmt->frame_control)) { |
98c8fccfa mac80211: refacto... |
161 |
/* ignore ProbeResp to foreign address */ |
d48b29685 mac80211: redesig... |
162 163 164 |
if ((!sdata1 || !ether_addr_equal(mgmt->da, sdata1->vif.addr)) && (!sdata2 || !ether_addr_equal(mgmt->da, sdata2->vif.addr))) return; |
98c8fccfa mac80211: refacto... |
165 |
|
98c8fccfa mac80211: refacto... |
166 167 168 |
elements = mgmt->u.probe_resp.variable; baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); } else { |
98c8fccfa mac80211: refacto... |
169 170 171 |
baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable); elements = mgmt->u.beacon.variable; } |
98c8fccfa mac80211: refacto... |
172 |
if (baselen > skb->len) |
d48b29685 mac80211: redesig... |
173 |
return; |
98c8fccfa mac80211: refacto... |
174 |
|
b2e506bfc mac80211: parse V... |
175 |
ieee802_11_parse_elems(elements, skb->len - baselen, false, &elems); |
98c8fccfa mac80211: refacto... |
176 |
|
0172bb750 cfg80211: use DS ... |
177 |
channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq); |
98c8fccfa mac80211: refacto... |
178 179 |
if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) |
d48b29685 mac80211: redesig... |
180 |
return; |
98c8fccfa mac80211: refacto... |
181 |
|
d48b29685 mac80211: redesig... |
182 |
bss = ieee80211_bss_info_update(local, rx_status, |
98c8fccfa mac80211: refacto... |
183 |
mgmt, skb->len, &elems, |
d45c41722 mac82011: use fra... |
184 |
channel); |
d048e503a mac80211: Fix sca... |
185 |
if (bss) |
d48b29685 mac80211: redesig... |
186 |
ieee80211_rx_bss_put(local, bss); |
98c8fccfa mac80211: refacto... |
187 |
} |
4d36ec582 mac80211: split h... |
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
/* 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, |
c604b9f21 mac80211: make ie... |
215 |
local->hw_scan_ies_bufsize, |
8ee310807 mac80211: restric... |
216 |
req->ie, req->ie_len, band, |
85a237fe3 mac80211: impleme... |
217 |
req->rates[band], 0); |
4d36ec582 mac80211: split h... |
218 |
local->hw_scan_req->ie_len = ielen; |
dcd83976b mac80211: pass no... |
219 |
local->hw_scan_req->no_cck = req->no_cck; |
4d36ec582 mac80211: split h... |
220 221 222 |
return true; } |
d07bfd8b6 mac80211: fix sca... |
223 |
static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, |
e229f844d mac80211: keep lo... |
224 |
bool was_hw_scan) |
0a51b27e9 mac80211: start m... |
225 226 |
{ struct ieee80211_local *local = hw_to_local(hw); |
0a51b27e9 mac80211: start m... |
227 |
|
e229f844d mac80211: keep lo... |
228 |
lockdep_assert_held(&local->mtx); |
5bc75728f mac80211: fix sca... |
229 |
|
6d3560d4f mac80211: fix sca... |
230 231 232 233 234 235 236 237 |
/* * 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 mac80211: fix sca... |
238 |
|
e229f844d mac80211: keep lo... |
239 |
if (WARN_ON(!local->scan_req)) |
d07bfd8b6 mac80211: fix sca... |
240 |
return; |
de95a54b1 mac80211: pass al... |
241 |
|
4d36ec582 mac80211: split h... |
242 |
if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { |
e2fd5dbc1 mac80211: make sc... |
243 244 245 246 247 248 |
int rc; rc = drv_hw_scan(local, rcu_dereference_protected(local->scan_sdata, lockdep_is_held(&local->mtx)), local->hw_scan_req); |
6eb11a9a3 mac80211: do not ... |
249 |
if (rc == 0) |
d07bfd8b6 mac80211: fix sca... |
250 |
return; |
4d36ec582 mac80211: split h... |
251 252 253 254 |
} kfree(local->hw_scan_req); local->hw_scan_req = NULL; |
f3b85252f mac80211: fix sca... |
255 |
|
5ba63533b cfg80211: fix ali... |
256 |
if (local->scan_req != local->int_scan_req) |
2a5193119 cfg80211/nl80211:... |
257 258 |
cfg80211_scan_done(local->scan_req, aborted); local->scan_req = NULL; |
3aa569c3f mac80211: fix sca... |
259 |
rcu_assign_pointer(local->scan_sdata, NULL); |
2a5193119 cfg80211/nl80211:... |
260 |
|
fbe9c429f mac80211: Replace... |
261 |
local->scanning = 0; |
58905ca5b mac80211: fix sca... |
262 |
local->scan_channel = NULL; |
f3b85252f mac80211: fix sca... |
263 |
|
07ef03ee8 mac80211: simplif... |
264 265 |
/* Set power back to normal operating levels. */ ieee80211_hw_config(local, 0); |
a0daa0e75 Revert "mac80211:... |
266 |
|
e229f844d mac80211: keep lo... |
267 268 269 |
if (!was_hw_scan) { ieee80211_configure_filter(local); drv_sw_scan_complete(local); |
aacde9ee4 mac80211: synchro... |
270 |
ieee80211_offchannel_return(local); |
e229f844d mac80211: keep lo... |
271 |
} |
0a51b27e9 mac80211: start m... |
272 |
|
5cff20e6c mac80211: tell dr... |
273 |
ieee80211_recalc_idle(local); |
e229f844d mac80211: keep lo... |
274 |
|
0a51b27e9 mac80211: start m... |
275 |
ieee80211_mlme_notify_scan_completed(local); |
469002983 mac80211: split I... |
276 |
ieee80211_ibss_notify_scan_completed(local); |
472dbc45d mac80211: split o... |
277 |
ieee80211_mesh_notify_scan_completed(local); |
2eb278e08 mac80211: unify S... |
278 |
ieee80211_start_next_roc(local); |
0a51b27e9 mac80211: start m... |
279 |
} |
8789d459b mac80211: allow s... |
280 281 282 283 284 285 286 287 288 289 290 291 |
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 mac80211: start m... |
292 |
EXPORT_SYMBOL(ieee80211_scan_completed); |
f3b85252f mac80211: fix sca... |
293 294 |
static int ieee80211_start_sw_scan(struct ieee80211_local *local) { |
fe57d9f5c mac80211: track w... |
295 296 297 |
/* Software scan is not supported in multi-channel cases */ if (local->use_chanctx) return -EOPNOTSUPP; |
f3b85252f mac80211: fix sca... |
298 299 300 301 302 303 304 305 306 307 308 309 310 |
/* * 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 mac80211: add dri... |
311 |
drv_sw_scan_start(local); |
f3b85252f mac80211: fix sca... |
312 |
|
de312db34 mac80211: fix ope... |
313 |
local->leave_oper_channel_time = jiffies; |
977923b00 mac80211: rename ... |
314 |
local->next_scan_state = SCAN_DECISION; |
f3b85252f mac80211: fix sca... |
315 |
local->scan_channel_idx = 0; |
aacde9ee4 mac80211: synchro... |
316 |
ieee80211_offchannel_stop_vifs(local); |
a80f7c0b0 mac80211: introdu... |
317 |
|
9c35d7d23 mac80211: Add flu... |
318 |
/* ensure nullfunc is transmitted before leaving operating channel */ |
39ecc01d1 mac80211: pass qu... |
319 |
ieee80211_flush_queues(local, NULL); |
9c35d7d23 mac80211: Add flu... |
320 |
|
3ac64beec mac80211: allow c... |
321 |
ieee80211_configure_filter(local); |
f3b85252f mac80211: fix sca... |
322 |
|
59bdf3b0f mac80211: Ensure ... |
323 324 |
/* We need to set power level at maximum rate for scanning. */ ieee80211_hw_config(local, 0); |
42935ecaf mac80211: redefin... |
325 |
ieee80211_queue_delayed_work(&local->hw, |
07ef03ee8 mac80211: simplif... |
326 |
&local->scan_work, 0); |
f3b85252f mac80211: fix sca... |
327 328 329 |
return 0; } |
133d40f9a mac80211: do not ... |
330 331 332 |
static bool ieee80211_can_scan(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata) { |
164eb02d0 mac80211: add rad... |
333 334 |
if (local->radar_detect_enabled) return false; |
2eb278e08 mac80211: unify S... |
335 |
if (!list_empty(&local->roc_list)) |
133d40f9a mac80211: do not ... |
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 |
return false; if (sdata->vif.type == NL80211_IFTYPE_STATION && sdata->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | IEEE80211_STA_CONNECTION_POLL)) 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 mac80211: make sc... |
352 353 354 355 |
if (!ieee80211_can_scan(local, rcu_dereference_protected( local->scan_sdata, lockdep_is_held(&local->mtx)))) |
133d40f9a mac80211: do not ... |
356 357 358 359 360 |
return; ieee80211_queue_delayed_work(&local->hw, &local->scan_work, round_jiffies_relative(0)); } |
f3b85252f mac80211: fix sca... |
361 |
|
8a690674e mac80211: Support... |
362 363 364 365 |
static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, unsigned long *next_delay) { int i; |
e2fd5dbc1 mac80211: make sc... |
366 |
struct ieee80211_sub_if_data *sdata; |
675a0b049 mac80211: Use a c... |
367 |
enum ieee80211_band band = local->hw.conf.chandef.chan->band; |
6c17b77b6 mac80211: Fix tx ... |
368 369 370 371 372 |
u32 tx_flags; tx_flags = IEEE80211_TX_INTFL_OFFCHAN_TX_OK; if (local->scan_req->no_cck) tx_flags |= IEEE80211_TX_CTL_NO_CCK_RATE; |
8a690674e mac80211: Support... |
373 |
|
e2fd5dbc1 mac80211: make sc... |
374 |
sdata = rcu_dereference_protected(local->scan_sdata, |
316b6b5df net/mac80211/scan... |
375 |
lockdep_is_held(&local->mtx)); |
e2fd5dbc1 mac80211: make sc... |
376 |
|
8a690674e mac80211: Support... |
377 378 379 380 381 382 383 |
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, local->scan_req->ie, local->scan_req->ie_len, local->scan_req->rates[band], false, |
675a0b049 mac80211: Use a c... |
384 |
tx_flags, local->hw.conf.chandef.chan, true); |
8a690674e mac80211: Support... |
385 386 387 388 389 390 391 392 |
/* * After sending probe requests, wait for probe responses * on the channel. */ *next_delay = IEEE80211_CHANNEL_TIME; local->next_scan_state = SCAN_DECISION; } |
f3b85252f mac80211: fix sca... |
393 394 395 396 |
static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, struct cfg80211_scan_request *req) { struct ieee80211_local *local = sdata->local; |
f3b85252f mac80211: fix sca... |
397 |
int rc; |
e229f844d mac80211: keep lo... |
398 |
lockdep_assert_held(&local->mtx); |
f3b85252f mac80211: fix sca... |
399 400 |
if (local->scan_req) return -EBUSY; |
133d40f9a mac80211: do not ... |
401 |
if (!ieee80211_can_scan(local, sdata)) { |
6e7e6213e Merge branch 'mas... |
402 |
/* wait for the work to finish/time out */ |
c0ce77b83 mac80211: fix def... |
403 |
local->scan_req = req; |
e2fd5dbc1 mac80211: make sc... |
404 |
rcu_assign_pointer(local->scan_sdata, sdata); |
c0ce77b83 mac80211: fix def... |
405 406 |
return 0; } |
f3b85252f mac80211: fix sca... |
407 408 |
if (local->ops->hw_scan) { u8 *ies; |
f3b85252f mac80211: fix sca... |
409 |
|
c604b9f21 mac80211: make ie... |
410 411 412 |
local->hw_scan_ies_bufsize = 2 + IEEE80211_MAX_SSID_LEN + local->scan_ies_len + req->ie_len; |
4d36ec582 mac80211: split h... |
413 414 415 |
local->hw_scan_req = kmalloc( sizeof(*local->hw_scan_req) + req->n_channels * sizeof(req->channels[0]) + |
c604b9f21 mac80211: make ie... |
416 |
local->hw_scan_ies_bufsize, GFP_KERNEL); |
4d36ec582 mac80211: split h... |
417 |
if (!local->hw_scan_req) |
f3b85252f mac80211: fix sca... |
418 |
return -ENOMEM; |
4d36ec582 mac80211: split h... |
419 420 421 422 423 424 |
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; |
cd2bb512c mac80211: add sup... |
425 |
local->hw_scan_req->flags = req->flags; |
4d36ec582 mac80211: split h... |
426 427 |
local->hw_scan_band = 0; |
6e7e6213e Merge branch 'mas... |
428 429 430 431 432 433 434 435 |
/* * 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 mac80211: fix sca... |
436 437 438 |
} local->scan_req = req; |
e2fd5dbc1 mac80211: make sc... |
439 |
rcu_assign_pointer(local->scan_sdata, sdata); |
f3b85252f mac80211: fix sca... |
440 |
|
8a690674e mac80211: Support... |
441 |
if (local->ops->hw_scan) { |
fbe9c429f mac80211: Replace... |
442 |
__set_bit(SCAN_HW_SCANNING, &local->scanning); |
8a690674e mac80211: Support... |
443 |
} else if ((req->n_channels == 1) && |
675a0b049 mac80211: Use a c... |
444 |
(req->channels[0] == local->_oper_chandef.chan)) { |
9b8648704 mac80211: check o... |
445 446 447 |
/* * If we are scanning only on the operating channel * then we do not need to stop normal activities |
8a690674e mac80211: Support... |
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 |
*/ 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. */ drv_sw_scan_start(local); ieee80211_configure_filter(local); /* accept probe-responses */ /* We need to ensure power level is at max for scanning. */ ieee80211_hw_config(local, 0); if ((req->channels[0]->flags & IEEE80211_CHAN_PASSIVE_SCAN) || !local->scan_req->n_ssids) { 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 mac80211: Replace... |
479 |
__set_bit(SCAN_SW_SCANNING, &local->scanning); |
8a690674e mac80211: Support... |
480 |
} |
6e7e6213e Merge branch 'mas... |
481 |
|
5cff20e6c mac80211: tell dr... |
482 |
ieee80211_recalc_idle(local); |
f3b85252f mac80211: fix sca... |
483 |
|
4d36ec582 mac80211: split h... |
484 485 |
if (local->ops->hw_scan) { WARN_ON(!ieee80211_prep_hw_scan(local)); |
a060bbfe4 mac80211: give vi... |
486 |
rc = drv_hw_scan(local, sdata, local->hw_scan_req); |
4d36ec582 mac80211: split h... |
487 |
} else |
f3b85252f mac80211: fix sca... |
488 |
rc = ieee80211_start_sw_scan(local); |
f3b85252f mac80211: fix sca... |
489 |
if (rc) { |
4d36ec582 mac80211: split h... |
490 491 |
kfree(local->hw_scan_req); local->hw_scan_req = NULL; |
fbe9c429f mac80211: Replace... |
492 |
local->scanning = 0; |
f3b85252f mac80211: fix sca... |
493 |
|
5cff20e6c mac80211: tell dr... |
494 |
ieee80211_recalc_idle(local); |
f3b85252f mac80211: fix sca... |
495 |
local->scan_req = NULL; |
e2fd5dbc1 mac80211: make sc... |
496 |
rcu_assign_pointer(local->scan_sdata, NULL); |
f3b85252f mac80211: fix sca... |
497 498 499 500 |
} return rc; } |
df13cce53 mac80211: Improve... |
501 502 503 504 505 506 507 508 509 510 511 |
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 mac80211: keep lo... |
512 513 |
static void ieee80211_scan_state_decision(struct ieee80211_local *local, unsigned long *next_delay) |
7d3be3cc4 mac80211: refacto... |
514 |
{ |
142b9f507 mac80211: impleme... |
515 |
bool associated = false; |
df13cce53 mac80211: Improve... |
516 517 |
bool tx_empty = true; bool bad_latency; |
142b9f507 mac80211: impleme... |
518 |
struct ieee80211_sub_if_data *sdata; |
df13cce53 mac80211: Improve... |
519 |
struct ieee80211_channel *next_chan; |
cd2bb512c mac80211: add sup... |
520 |
enum mac80211_scan_state next_scan_state; |
142b9f507 mac80211: impleme... |
521 |
|
df13cce53 mac80211: Improve... |
522 523 524 525 526 |
/* * 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 mac80211: impleme... |
527 528 |
mutex_lock(&local->iflist_mtx); list_for_each_entry(sdata, &local->interfaces, list) { |
9607e6b66 mac80211: add iee... |
529 |
if (!ieee80211_sdata_running(sdata)) |
142b9f507 mac80211: impleme... |
530 531 532 533 534 |
continue; if (sdata->vif.type == NL80211_IFTYPE_STATION) { if (sdata->u.mgd.associated) { associated = true; |
df13cce53 mac80211: Improve... |
535 |
|
df13cce53 mac80211: Improve... |
536 537 538 539 |
if (!qdisc_all_tx_empty(sdata->dev)) { tx_empty = false; break; } |
142b9f507 mac80211: impleme... |
540 541 542 543 |
} } } mutex_unlock(&local->iflist_mtx); |
b23b025fe mac80211: Optimiz... |
544 |
next_chan = local->scan_req->channels[local->scan_channel_idx]; |
a80f7c0b0 mac80211: introdu... |
545 |
/* |
07ef03ee8 mac80211: simplif... |
546 547 548 549 |
* we're currently scanning a different channel, let's * see if we can scan another channel without interfering * with the current traffic situation. * |
3f892b61a mac80211: improve... |
550 |
* Keep good latency, do not stay off-channel more than 125 ms. |
a80f7c0b0 mac80211: introdu... |
551 |
*/ |
a80f7c0b0 mac80211: introdu... |
552 |
|
07ef03ee8 mac80211: simplif... |
553 |
bad_latency = time_after(jiffies + |
3f892b61a mac80211: improve... |
554 555 |
ieee80211_scan_get_channel_time(next_chan), local->leave_oper_channel_time + HZ / 8); |
142b9f507 mac80211: impleme... |
556 |
|
cd2bb512c mac80211: add sup... |
557 558 559 560 561 |
if (associated && !tx_empty) { if (local->scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) next_scan_state = SCAN_ABORT; else next_scan_state = SCAN_SUSPEND; |
3f892b61a mac80211: improve... |
562 |
} else if (associated && bad_latency) { |
cd2bb512c mac80211: add sup... |
563 564 565 566 567 568 |
next_scan_state = SCAN_SUSPEND; } else { next_scan_state = SCAN_SET_CHANNEL; } local->next_scan_state = next_scan_state; |
142b9f507 mac80211: impleme... |
569 |
|
07ef03ee8 mac80211: simplif... |
570 |
*next_delay = 0; |
142b9f507 mac80211: impleme... |
571 |
} |
2fb3f028a mac80211: introdu... |
572 573 574 575 576 |
static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, unsigned long *next_delay) { int skip; struct ieee80211_channel *chan; |
2fb3f028a mac80211: introdu... |
577 |
|
7d3be3cc4 mac80211: refacto... |
578 579 |
skip = 0; chan = local->scan_req->channels[local->scan_channel_idx]; |
584991dcc cfg80211: validat... |
580 |
local->scan_channel = chan; |
b23b025fe mac80211: Optimiz... |
581 |
|
07ef03ee8 mac80211: simplif... |
582 583 |
if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL)) skip = 1; |
7d3be3cc4 mac80211: refacto... |
584 |
|
7d3be3cc4 mac80211: refacto... |
585 586 |
/* advance state machine to next channel/band */ local->scan_channel_idx++; |
0ee9c13c7 mac80211: fix an ... |
587 588 589 |
if (skip) { /* if we skip this channel return to the decision state */ local->next_scan_state = SCAN_DECISION; |
2fb3f028a mac80211: introdu... |
590 |
return; |
0ee9c13c7 mac80211: fix an ... |
591 |
} |
7d3be3cc4 mac80211: refacto... |
592 593 594 595 596 597 598 599 600 601 602 603 604 605 |
/* * 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 mac80211: rename ... |
606 |
local->next_scan_state = SCAN_DECISION; |
2fb3f028a mac80211: introdu... |
607 |
return; |
7d3be3cc4 mac80211: refacto... |
608 |
} |
2fb3f028a mac80211: introdu... |
609 |
/* active scan, send probes */ |
7d3be3cc4 mac80211: refacto... |
610 |
*next_delay = IEEE80211_PROBE_DELAY; |
977923b00 mac80211: rename ... |
611 |
local->next_scan_state = SCAN_SEND_PROBE; |
7d3be3cc4 mac80211: refacto... |
612 |
} |
07ef03ee8 mac80211: simplif... |
613 614 615 616 617 618 |
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); |
aacde9ee4 mac80211: synchro... |
619 620 |
/* disable PS */ ieee80211_offchannel_return(local); |
07ef03ee8 mac80211: simplif... |
621 622 623 624 625 626 627 628 629 |
*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 mac80211: synchro... |
630 |
ieee80211_offchannel_stop_vifs(local); |
07ef03ee8 mac80211: simplif... |
631 632 |
if (local->ops->flush) { |
39ecc01d1 mac80211: pass qu... |
633 |
ieee80211_flush_queues(local, NULL); |
07ef03ee8 mac80211: simplif... |
634 635 636 637 638 639 640 641 |
*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 mac80211: fix sca... |
642 |
local->next_scan_state = SCAN_SET_CHANNEL; |
07ef03ee8 mac80211: simplif... |
643 |
} |
c2b13452b mac80211: clean u... |
644 |
void ieee80211_scan_work(struct work_struct *work) |
0a51b27e9 mac80211: start m... |
645 646 647 |
{ struct ieee80211_local *local = container_of(work, struct ieee80211_local, scan_work.work); |
d07bfd8b6 mac80211: fix sca... |
648 |
struct ieee80211_sub_if_data *sdata; |
0a51b27e9 mac80211: start m... |
649 |
unsigned long next_delay = 0; |
d07bfd8b6 mac80211: fix sca... |
650 |
bool aborted, hw_scan; |
0a51b27e9 mac80211: start m... |
651 |
|
259b62e35 mac80211: reduce ... |
652 |
mutex_lock(&local->mtx); |
8789d459b mac80211: allow s... |
653 |
|
e2fd5dbc1 mac80211: make sc... |
654 655 |
sdata = rcu_dereference_protected(local->scan_sdata, lockdep_is_held(&local->mtx)); |
d07bfd8b6 mac80211: fix sca... |
656 |
|
8a690674e mac80211: Support... |
657 658 659 660 661 |
/* 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 mac80211: reduce ... |
662 |
if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) { |
8789d459b mac80211: allow s... |
663 |
aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning); |
259b62e35 mac80211: reduce ... |
664 |
goto out_complete; |
8789d459b mac80211: allow s... |
665 |
} |
259b62e35 mac80211: reduce ... |
666 667 |
if (!sdata || !local->scan_req) goto out; |
f3b85252f mac80211: fix sca... |
668 |
|
fbe9c429f mac80211: Replace... |
669 |
if (local->scan_req && !local->scanning) { |
f3b85252f mac80211: fix sca... |
670 671 672 673 |
struct cfg80211_scan_request *req = local->scan_req; int rc; local->scan_req = NULL; |
e2fd5dbc1 mac80211: make sc... |
674 |
rcu_assign_pointer(local->scan_sdata, NULL); |
f3b85252f mac80211: fix sca... |
675 676 |
rc = __ieee80211_start_scan(sdata, req); |
259b62e35 mac80211: reduce ... |
677 |
if (rc) { |
3aed49ef1 mac80211: compete... |
678 679 |
/* need to complete scan in cfg80211 */ local->scan_req = req; |
259b62e35 mac80211: reduce ... |
680 681 682 683 |
aborted = true; goto out_complete; } else goto out; |
f3b85252f mac80211: fix sca... |
684 |
} |
5bc75728f mac80211: fix sca... |
685 686 687 |
/* * Avoid re-scheduling when the sdata is going away. */ |
9607e6b66 mac80211: add iee... |
688 |
if (!ieee80211_sdata_running(sdata)) { |
259b62e35 mac80211: reduce ... |
689 690 |
aborted = true; goto out_complete; |
f3b85252f mac80211: fix sca... |
691 |
} |
0a51b27e9 mac80211: start m... |
692 |
|
f502d09b7 mac80211: advance... |
693 694 695 696 697 |
/* * as long as no delay is required advance immediately * without scheduling a new work */ do { |
c29acf201 mac80211: abort s... |
698 699 700 701 |
if (!ieee80211_sdata_running(sdata)) { aborted = true; goto out_complete; } |
977923b00 mac80211: rename ... |
702 |
switch (local->next_scan_state) { |
2fb3f028a mac80211: introdu... |
703 |
case SCAN_DECISION: |
e229f844d mac80211: keep lo... |
704 705 706 707 708 709 |
/* 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 mac80211: advance... |
710 |
break; |
2fb3f028a mac80211: introdu... |
711 712 713 |
case SCAN_SET_CHANNEL: ieee80211_scan_state_set_channel(local, &next_delay); break; |
f502d09b7 mac80211: advance... |
714 715 716 |
case SCAN_SEND_PROBE: ieee80211_scan_state_send_probe(local, &next_delay); break; |
07ef03ee8 mac80211: simplif... |
717 718 |
case SCAN_SUSPEND: ieee80211_scan_state_suspend(local, &next_delay); |
142b9f507 mac80211: impleme... |
719 |
break; |
07ef03ee8 mac80211: simplif... |
720 721 |
case SCAN_RESUME: ieee80211_scan_state_resume(local, &next_delay); |
142b9f507 mac80211: impleme... |
722 |
break; |
cd2bb512c mac80211: add sup... |
723 724 725 |
case SCAN_ABORT: aborted = true; goto out_complete; |
f502d09b7 mac80211: advance... |
726 727 |
} } while (next_delay == 0); |
0a51b27e9 mac80211: start m... |
728 |
|
42935ecaf mac80211: redefin... |
729 |
ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay); |
d07bfd8b6 mac80211: fix sca... |
730 |
goto out; |
259b62e35 mac80211: reduce ... |
731 732 |
out_complete: |
e229f844d mac80211: keep lo... |
733 |
hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); |
d07bfd8b6 mac80211: fix sca... |
734 |
__ieee80211_scan_completed(&local->hw, aborted, hw_scan); |
259b62e35 mac80211: reduce ... |
735 736 |
out: mutex_unlock(&local->mtx); |
0a51b27e9 mac80211: start m... |
737 |
} |
f3b85252f mac80211: fix sca... |
738 739 |
int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, struct cfg80211_scan_request *req) |
0a51b27e9 mac80211: start m... |
740 |
{ |
f3b85252f mac80211: fix sca... |
741 |
int res; |
de95a54b1 mac80211: pass al... |
742 |
|
a1699b75a mac80211: unify s... |
743 |
mutex_lock(&sdata->local->mtx); |
f3b85252f mac80211: fix sca... |
744 |
res = __ieee80211_start_scan(sdata, req); |
a1699b75a mac80211: unify s... |
745 |
mutex_unlock(&sdata->local->mtx); |
0a51b27e9 mac80211: start m... |
746 |
|
f3b85252f mac80211: fix sca... |
747 |
return res; |
0a51b27e9 mac80211: start m... |
748 |
} |
34bcf7150 mac80211: fix ibs... |
749 750 751 |
int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, const u8 *ssid, u8 ssid_len, struct ieee80211_channel *chan) |
0a51b27e9 mac80211: start m... |
752 |
{ |
0a51b27e9 mac80211: start m... |
753 |
struct ieee80211_local *local = sdata->local; |
f3b85252f mac80211: fix sca... |
754 |
int ret = -EBUSY; |
fb63bc417 mac80211: Fix com... |
755 |
enum ieee80211_band band; |
2a5193119 cfg80211/nl80211:... |
756 |
|
a1699b75a mac80211: unify s... |
757 |
mutex_lock(&local->mtx); |
0a51b27e9 mac80211: start m... |
758 |
|
f3b85252f mac80211: fix sca... |
759 760 761 |
/* busy scanning */ if (local->scan_req) goto unlock; |
9116dd011 mac80211: clarify... |
762 |
|
be4a4b6a5 mac80211: improve... |
763 764 |
/* fill internal scan request */ if (!chan) { |
34bcf7150 mac80211: fix ibs... |
765 766 |
int i, max_n; int n_ch = 0; |
be4a4b6a5 mac80211: improve... |
767 768 769 770 |
for (band = 0; band < IEEE80211_NUM_BANDS; band++) { if (!local->hw.wiphy->bands[band]) continue; |
34bcf7150 mac80211: fix ibs... |
771 772 773 774 |
max_n = local->hw.wiphy->bands[band]->n_channels; for (i = 0; i < max_n; i++) { struct ieee80211_channel *tmp_ch = |
be4a4b6a5 mac80211: improve... |
775 |
&local->hw.wiphy->bands[band]->channels[i]; |
34bcf7150 mac80211: fix ibs... |
776 777 778 779 780 781 782 |
if (tmp_ch->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_DISABLED)) continue; local->int_scan_req->channels[n_ch] = tmp_ch; n_ch++; |
be4a4b6a5 mac80211: improve... |
783 784 |
} } |
34bcf7150 mac80211: fix ibs... |
785 786 787 788 |
if (WARN_ON_ONCE(n_ch == 0)) goto unlock; local->int_scan_req->n_channels = n_ch; |
be4a4b6a5 mac80211: improve... |
789 |
} else { |
34bcf7150 mac80211: fix ibs... |
790 791 792 |
if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_DISABLED))) goto unlock; |
be4a4b6a5 mac80211: improve... |
793 794 795 796 797 798 |
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 cfg80211: fix ali... |
799 800 |
memcpy(local->int_scan_req->ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN); local->int_scan_req->ssids[0].ssid_len = ssid_len; |
9116dd011 mac80211: clarify... |
801 |
|
5ba63533b cfg80211: fix ali... |
802 |
ret = __ieee80211_start_scan(sdata, sdata->local->int_scan_req); |
f3b85252f mac80211: fix sca... |
803 |
unlock: |
a1699b75a mac80211: unify s... |
804 |
mutex_unlock(&local->mtx); |
f3b85252f mac80211: fix sca... |
805 |
return ret; |
0a51b27e9 mac80211: start m... |
806 |
} |
5bb644a0f mac80211: cancel/... |
807 |
|
4136c4224 mac80211: assure ... |
808 809 810 |
/* * Only call this function when a scan can't be queued -- under RTNL. */ |
5bb644a0f mac80211: cancel/... |
811 812 |
void ieee80211_scan_cancel(struct ieee80211_local *local) { |
5bb644a0f mac80211: cancel/... |
813 |
/* |
b856439b1 mac80211: add can... |
814 |
* We are canceling software scan, or deferred scan that was not |
4136c4224 mac80211: assure ... |
815 816 817 818 819 820 821 822 823 824 825 |
* 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 mac80211: add can... |
826 827 828 |
* 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 mac80211: cancel/... |
829 |
*/ |
4136c4224 mac80211: assure ... |
830 |
|
a1699b75a mac80211: unify s... |
831 |
mutex_lock(&local->mtx); |
b856439b1 mac80211: add can... |
832 833 834 835 836 |
if (!local->scan_req) goto out; if (test_bit(SCAN_HW_SCANNING, &local->scanning)) { if (local->ops->cancel_hw_scan) |
e2fd5dbc1 mac80211: make sc... |
837 838 839 |
drv_cancel_hw_scan(local, rcu_dereference_protected(local->scan_sdata, lockdep_is_held(&local->mtx))); |
b856439b1 mac80211: add can... |
840 |
goto out; |
4136c4224 mac80211: assure ... |
841 |
} |
b856439b1 mac80211: add can... |
842 843 844 845 846 847 848 849 850 851 |
/* * 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 mac80211: fix sca... |
852 |
mutex_unlock(&local->mtx); |
5bb644a0f mac80211: cancel/... |
853 |
} |
79f460ca4 mac80211: add sup... |
854 855 856 857 858 |
int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, struct cfg80211_sched_scan_request *req) { struct ieee80211_local *local = sdata->local; |
bca1e29fb mac80211: init sc... |
859 |
struct ieee80211_sched_scan_ies sched_scan_ies = {}; |
c604b9f21 mac80211: make ie... |
860 861 862 863 |
int ret, i, iebufsz; iebufsz = 2 + IEEE80211_MAX_SSID_LEN + local->scan_ies_len + req->ie_len; |
79f460ca4 mac80211: add sup... |
864 |
|
5260a5b2c mac80211: track s... |
865 |
mutex_lock(&local->mtx); |
79f460ca4 mac80211: add sup... |
866 |
|
5260a5b2c mac80211: track s... |
867 |
if (rcu_access_pointer(local->sched_scan_sdata)) { |
79f460ca4 mac80211: add sup... |
868 869 870 871 872 873 874 875 876 877 |
ret = -EBUSY; goto out; } if (!local->ops->sched_scan_start) { ret = -ENOTSUPP; goto out; } for (i = 0; i < IEEE80211_NUM_BANDS; i++) { |
d811b3d55 mac80211: fix inv... |
878 879 |
if (!local->hw.wiphy->bands[i]) continue; |
c604b9f21 mac80211: make ie... |
880 |
sched_scan_ies.ie[i] = kzalloc(iebufsz, GFP_KERNEL); |
30dd3edf9 mac80211: don't h... |
881 |
if (!sched_scan_ies.ie[i]) { |
79f460ca4 mac80211: add sup... |
882 883 884 |
ret = -ENOMEM; goto out_free; } |
30dd3edf9 mac80211: don't h... |
885 886 |
sched_scan_ies.len[i] = ieee80211_build_preq_ies(local, sched_scan_ies.ie[i], |
c604b9f21 mac80211: make ie... |
887 888 |
iebufsz, req->ie, req->ie_len, i, (u32) -1, 0); |
79f460ca4 mac80211: add sup... |
889 |
} |
30dd3edf9 mac80211: don't h... |
890 891 |
ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); if (ret == 0) |
5260a5b2c mac80211: track s... |
892 |
rcu_assign_pointer(local->sched_scan_sdata, sdata); |
79f460ca4 mac80211: add sup... |
893 894 895 |
out_free: while (i > 0) |
30dd3edf9 mac80211: don't h... |
896 |
kfree(sched_scan_ies.ie[--i]); |
79f460ca4 mac80211: add sup... |
897 |
out: |
5260a5b2c mac80211: track s... |
898 |
mutex_unlock(&local->mtx); |
79f460ca4 mac80211: add sup... |
899 900 |
return ret; } |
85a9994a0 cfg80211/mac80211... |
901 |
int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) |
79f460ca4 mac80211: add sup... |
902 903 |
{ struct ieee80211_local *local = sdata->local; |
30dd3edf9 mac80211: don't h... |
904 |
int ret = 0; |
79f460ca4 mac80211: add sup... |
905 |
|
5260a5b2c mac80211: track s... |
906 |
mutex_lock(&local->mtx); |
79f460ca4 mac80211: add sup... |
907 908 909 910 911 |
if (!local->ops->sched_scan_stop) { ret = -ENOTSUPP; goto out; } |
30dd3edf9 mac80211: don't h... |
912 |
if (rcu_access_pointer(local->sched_scan_sdata)) |
85a9994a0 cfg80211/mac80211... |
913 |
drv_sched_scan_stop(local, sdata); |
30dd3edf9 mac80211: don't h... |
914 |
|
79f460ca4 mac80211: add sup... |
915 |
out: |
5260a5b2c mac80211: track s... |
916 |
mutex_unlock(&local->mtx); |
79f460ca4 mac80211: add sup... |
917 918 919 920 921 922 923 924 925 926 927 928 929 |
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 cfg80211/mac80211... |
930 931 932 933 934 |
void ieee80211_sched_scan_stopped_work(struct work_struct *work) { struct ieee80211_local *local = container_of(work, struct ieee80211_local, sched_scan_stopped_work); |
85a9994a0 cfg80211/mac80211... |
935 936 |
mutex_lock(&local->mtx); |
5260a5b2c mac80211: track s... |
937 |
if (!rcu_access_pointer(local->sched_scan_sdata)) { |
85a9994a0 cfg80211/mac80211... |
938 939 940 |
mutex_unlock(&local->mtx); return; } |
5260a5b2c mac80211: track s... |
941 |
rcu_assign_pointer(local->sched_scan_sdata, NULL); |
85a9994a0 cfg80211/mac80211... |
942 943 944 945 946 |
mutex_unlock(&local->mtx); cfg80211_sched_scan_stopped(local->hw.wiphy); } |
79f460ca4 mac80211: add sup... |
947 948 949 950 951 |
void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); trace_api_sched_scan_stopped(local); |
85a9994a0 cfg80211/mac80211... |
952 |
ieee80211_queue_work(&local->hw, &local->sched_scan_stopped_work); |
79f460ca4 mac80211: add sup... |
953 954 |
} EXPORT_SYMBOL(ieee80211_sched_scan_stopped); |