.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Scanning implementation |
---|
3 | 4 | * |
---|
.. | .. |
---|
8 | 9 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> |
---|
9 | 10 | * Copyright 2013-2015 Intel Mobile Communications GmbH |
---|
10 | 11 | * Copyright 2016-2017 Intel Deutschland GmbH |
---|
11 | | - * |
---|
12 | | - * This program is free software; you can redistribute it and/or modify |
---|
13 | | - * it under the terms of the GNU General Public License version 2 as |
---|
14 | | - * published by the Free Software Foundation. |
---|
| 12 | + * Copyright (C) 2018-2020 Intel Corporation |
---|
15 | 13 | */ |
---|
16 | 14 | |
---|
17 | 15 | #include <linux/if_arp.h> |
---|
.. | .. |
---|
57 | 55 | return qos_info & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD; |
---|
58 | 56 | } |
---|
59 | 57 | |
---|
60 | | -struct ieee80211_bss * |
---|
61 | | -ieee80211_bss_info_update(struct ieee80211_local *local, |
---|
62 | | - struct ieee80211_rx_status *rx_status, |
---|
63 | | - struct ieee80211_mgmt *mgmt, size_t len, |
---|
64 | | - struct ieee802_11_elems *elems, |
---|
65 | | - struct ieee80211_channel *channel) |
---|
| 58 | +static void |
---|
| 59 | +ieee80211_update_bss_from_elems(struct ieee80211_local *local, |
---|
| 60 | + struct ieee80211_bss *bss, |
---|
| 61 | + struct ieee802_11_elems *elems, |
---|
| 62 | + struct ieee80211_rx_status *rx_status, |
---|
| 63 | + bool beacon) |
---|
66 | 64 | { |
---|
67 | | - bool beacon = ieee80211_is_beacon(mgmt->frame_control); |
---|
68 | | - struct cfg80211_bss *cbss; |
---|
69 | | - struct ieee80211_bss *bss; |
---|
70 | 65 | int clen, srlen; |
---|
71 | | - struct cfg80211_inform_bss bss_meta = { |
---|
72 | | - .boottime_ns = rx_status->boottime_ns, |
---|
73 | | - }; |
---|
74 | | - bool signal_valid; |
---|
75 | | - struct ieee80211_sub_if_data *scan_sdata; |
---|
76 | | - |
---|
77 | | - if (rx_status->flag & RX_FLAG_NO_SIGNAL_VAL) |
---|
78 | | - bss_meta.signal = 0; /* invalid signal indication */ |
---|
79 | | - else if (ieee80211_hw_check(&local->hw, SIGNAL_DBM)) |
---|
80 | | - bss_meta.signal = rx_status->signal * 100; |
---|
81 | | - else if (ieee80211_hw_check(&local->hw, SIGNAL_UNSPEC)) |
---|
82 | | - bss_meta.signal = (rx_status->signal * 100) / local->hw.max_signal; |
---|
83 | | - |
---|
84 | | - bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_20; |
---|
85 | | - if (rx_status->bw == RATE_INFO_BW_5) |
---|
86 | | - bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_5; |
---|
87 | | - else if (rx_status->bw == RATE_INFO_BW_10) |
---|
88 | | - bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_10; |
---|
89 | | - |
---|
90 | | - bss_meta.chan = channel; |
---|
91 | | - |
---|
92 | | - rcu_read_lock(); |
---|
93 | | - scan_sdata = rcu_dereference(local->scan_sdata); |
---|
94 | | - if (scan_sdata && scan_sdata->vif.type == NL80211_IFTYPE_STATION && |
---|
95 | | - scan_sdata->vif.bss_conf.assoc && |
---|
96 | | - ieee80211_have_rx_timestamp(rx_status)) { |
---|
97 | | - bss_meta.parent_tsf = |
---|
98 | | - ieee80211_calculate_rx_timestamp(local, rx_status, |
---|
99 | | - len + FCS_LEN, 24); |
---|
100 | | - ether_addr_copy(bss_meta.parent_bssid, |
---|
101 | | - scan_sdata->vif.bss_conf.bssid); |
---|
102 | | - } |
---|
103 | | - rcu_read_unlock(); |
---|
104 | | - |
---|
105 | | - cbss = cfg80211_inform_bss_frame_data(local->hw.wiphy, &bss_meta, |
---|
106 | | - mgmt, len, GFP_ATOMIC); |
---|
107 | | - if (!cbss) |
---|
108 | | - return NULL; |
---|
109 | | - /* In case the signal is invalid update the status */ |
---|
110 | | - signal_valid = abs(channel->center_freq - cbss->channel->center_freq) |
---|
111 | | - <= local->hw.wiphy->max_adj_channel_rssi_comp; |
---|
112 | | - if (!signal_valid) |
---|
113 | | - rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; |
---|
114 | | - |
---|
115 | | - bss = (void *)cbss->priv; |
---|
116 | 66 | |
---|
117 | 67 | if (beacon) |
---|
118 | 68 | bss->device_ts_beacon = rx_status->device_timestamp; |
---|
.. | .. |
---|
183 | 133 | &sband->bitrates[rx_status->rate_idx]; |
---|
184 | 134 | } |
---|
185 | 135 | |
---|
| 136 | + if (elems->vht_cap_elem) |
---|
| 137 | + bss->vht_cap_info = |
---|
| 138 | + le32_to_cpu(elems->vht_cap_elem->vht_cap_info); |
---|
| 139 | + else |
---|
| 140 | + bss->vht_cap_info = 0; |
---|
| 141 | +} |
---|
| 142 | + |
---|
| 143 | +struct ieee80211_bss * |
---|
| 144 | +ieee80211_bss_info_update(struct ieee80211_local *local, |
---|
| 145 | + struct ieee80211_rx_status *rx_status, |
---|
| 146 | + struct ieee80211_mgmt *mgmt, size_t len, |
---|
| 147 | + struct ieee80211_channel *channel) |
---|
| 148 | +{ |
---|
| 149 | + bool beacon = ieee80211_is_beacon(mgmt->frame_control) || |
---|
| 150 | + ieee80211_is_s1g_beacon(mgmt->frame_control); |
---|
| 151 | + struct cfg80211_bss *cbss, *non_tx_cbss; |
---|
| 152 | + struct ieee80211_bss *bss, *non_tx_bss; |
---|
| 153 | + struct cfg80211_inform_bss bss_meta = { |
---|
| 154 | + .boottime_ns = rx_status->boottime_ns, |
---|
| 155 | + }; |
---|
| 156 | + bool signal_valid; |
---|
| 157 | + struct ieee80211_sub_if_data *scan_sdata; |
---|
| 158 | + struct ieee802_11_elems elems; |
---|
| 159 | + size_t baselen; |
---|
| 160 | + u8 *elements; |
---|
| 161 | + |
---|
| 162 | + if (rx_status->flag & RX_FLAG_NO_SIGNAL_VAL) |
---|
| 163 | + bss_meta.signal = 0; /* invalid signal indication */ |
---|
| 164 | + else if (ieee80211_hw_check(&local->hw, SIGNAL_DBM)) |
---|
| 165 | + bss_meta.signal = rx_status->signal * 100; |
---|
| 166 | + else if (ieee80211_hw_check(&local->hw, SIGNAL_UNSPEC)) |
---|
| 167 | + bss_meta.signal = (rx_status->signal * 100) / local->hw.max_signal; |
---|
| 168 | + |
---|
| 169 | + bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_20; |
---|
| 170 | + if (rx_status->bw == RATE_INFO_BW_5) |
---|
| 171 | + bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_5; |
---|
| 172 | + else if (rx_status->bw == RATE_INFO_BW_10) |
---|
| 173 | + bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_10; |
---|
| 174 | + |
---|
| 175 | + bss_meta.chan = channel; |
---|
| 176 | + |
---|
| 177 | + rcu_read_lock(); |
---|
| 178 | + scan_sdata = rcu_dereference(local->scan_sdata); |
---|
| 179 | + if (scan_sdata && scan_sdata->vif.type == NL80211_IFTYPE_STATION && |
---|
| 180 | + scan_sdata->vif.bss_conf.assoc && |
---|
| 181 | + ieee80211_have_rx_timestamp(rx_status)) { |
---|
| 182 | + bss_meta.parent_tsf = |
---|
| 183 | + ieee80211_calculate_rx_timestamp(local, rx_status, |
---|
| 184 | + len + FCS_LEN, 24); |
---|
| 185 | + ether_addr_copy(bss_meta.parent_bssid, |
---|
| 186 | + scan_sdata->vif.bss_conf.bssid); |
---|
| 187 | + } |
---|
| 188 | + rcu_read_unlock(); |
---|
| 189 | + |
---|
| 190 | + cbss = cfg80211_inform_bss_frame_data(local->hw.wiphy, &bss_meta, |
---|
| 191 | + mgmt, len, GFP_ATOMIC); |
---|
| 192 | + if (!cbss) |
---|
| 193 | + return NULL; |
---|
| 194 | + |
---|
| 195 | + if (ieee80211_is_probe_resp(mgmt->frame_control)) { |
---|
| 196 | + elements = mgmt->u.probe_resp.variable; |
---|
| 197 | + baselen = offsetof(struct ieee80211_mgmt, |
---|
| 198 | + u.probe_resp.variable); |
---|
| 199 | + } else if (ieee80211_is_s1g_beacon(mgmt->frame_control)) { |
---|
| 200 | + struct ieee80211_ext *ext = (void *) mgmt; |
---|
| 201 | + |
---|
| 202 | + baselen = offsetof(struct ieee80211_ext, u.s1g_beacon.variable); |
---|
| 203 | + elements = ext->u.s1g_beacon.variable; |
---|
| 204 | + } else { |
---|
| 205 | + baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable); |
---|
| 206 | + elements = mgmt->u.beacon.variable; |
---|
| 207 | + } |
---|
| 208 | + |
---|
| 209 | + if (baselen > len) |
---|
| 210 | + return NULL; |
---|
| 211 | + |
---|
| 212 | + ieee802_11_parse_elems(elements, len - baselen, false, &elems, |
---|
| 213 | + mgmt->bssid, cbss->bssid); |
---|
| 214 | + |
---|
| 215 | + /* In case the signal is invalid update the status */ |
---|
| 216 | + signal_valid = channel == cbss->channel; |
---|
| 217 | + if (!signal_valid) |
---|
| 218 | + rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; |
---|
| 219 | + |
---|
| 220 | + bss = (void *)cbss->priv; |
---|
| 221 | + ieee80211_update_bss_from_elems(local, bss, &elems, rx_status, beacon); |
---|
| 222 | + |
---|
| 223 | + list_for_each_entry(non_tx_cbss, &cbss->nontrans_list, nontrans_list) { |
---|
| 224 | + non_tx_bss = (void *)non_tx_cbss->priv; |
---|
| 225 | + |
---|
| 226 | + ieee80211_update_bss_from_elems(local, non_tx_bss, &elems, |
---|
| 227 | + rx_status, beacon); |
---|
| 228 | + } |
---|
| 229 | + |
---|
| 230 | + kfree(elems.nontx_profile); |
---|
| 231 | + |
---|
186 | 232 | return bss; |
---|
187 | 233 | } |
---|
188 | 234 | |
---|
.. | .. |
---|
206 | 252 | struct ieee80211_sub_if_data *sdata1, *sdata2; |
---|
207 | 253 | struct ieee80211_mgmt *mgmt = (void *)skb->data; |
---|
208 | 254 | struct ieee80211_bss *bss; |
---|
209 | | - u8 *elements; |
---|
210 | 255 | struct ieee80211_channel *channel; |
---|
211 | | - size_t baselen; |
---|
212 | | - struct ieee802_11_elems elems; |
---|
| 256 | + size_t min_hdr_len = offsetof(struct ieee80211_mgmt, |
---|
| 257 | + u.probe_resp.variable); |
---|
213 | 258 | |
---|
214 | | - if (skb->len < 24 || |
---|
215 | | - (!ieee80211_is_probe_resp(mgmt->frame_control) && |
---|
216 | | - !ieee80211_is_beacon(mgmt->frame_control))) |
---|
| 259 | + if (!ieee80211_is_probe_resp(mgmt->frame_control) && |
---|
| 260 | + !ieee80211_is_beacon(mgmt->frame_control) && |
---|
| 261 | + !ieee80211_is_s1g_beacon(mgmt->frame_control)) |
---|
| 262 | + return; |
---|
| 263 | + |
---|
| 264 | + if (ieee80211_is_s1g_beacon(mgmt->frame_control)) { |
---|
| 265 | + if (ieee80211_is_s1g_short_beacon(mgmt->frame_control)) |
---|
| 266 | + min_hdr_len = offsetof(struct ieee80211_ext, |
---|
| 267 | + u.s1g_short_beacon.variable); |
---|
| 268 | + else |
---|
| 269 | + min_hdr_len = offsetof(struct ieee80211_ext, |
---|
| 270 | + u.s1g_beacon); |
---|
| 271 | + } |
---|
| 272 | + |
---|
| 273 | + if (skb->len < min_hdr_len) |
---|
217 | 274 | return; |
---|
218 | 275 | |
---|
219 | 276 | sdata1 = rcu_dereference(local->scan_sdata); |
---|
.. | .. |
---|
221 | 278 | |
---|
222 | 279 | if (likely(!sdata1 && !sdata2)) |
---|
223 | 280 | return; |
---|
| 281 | + |
---|
| 282 | + if (test_and_clear_bit(SCAN_BEACON_WAIT, &local->scanning)) { |
---|
| 283 | + /* |
---|
| 284 | + * we were passive scanning because of radar/no-IR, but |
---|
| 285 | + * the beacon/proberesp rx gives us an opportunity to upgrade |
---|
| 286 | + * to active scan |
---|
| 287 | + */ |
---|
| 288 | + set_bit(SCAN_BEACON_DONE, &local->scanning); |
---|
| 289 | + ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0); |
---|
| 290 | + } |
---|
224 | 291 | |
---|
225 | 292 | if (ieee80211_is_probe_resp(mgmt->frame_control)) { |
---|
226 | 293 | struct cfg80211_scan_request *scan_req; |
---|
.. | .. |
---|
244 | 311 | !ieee80211_scan_accept_presp(sdata2, sched_scan_req_flags, |
---|
245 | 312 | mgmt->da)) |
---|
246 | 313 | return; |
---|
247 | | - |
---|
248 | | - elements = mgmt->u.probe_resp.variable; |
---|
249 | | - baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); |
---|
250 | | - } else { |
---|
251 | | - baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable); |
---|
252 | | - elements = mgmt->u.beacon.variable; |
---|
253 | 314 | } |
---|
254 | 315 | |
---|
255 | | - if (baselen > skb->len) |
---|
256 | | - return; |
---|
257 | | - |
---|
258 | | - ieee802_11_parse_elems(elements, skb->len - baselen, false, &elems); |
---|
259 | | - |
---|
260 | | - channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq); |
---|
| 316 | + channel = ieee80211_get_channel_khz(local->hw.wiphy, |
---|
| 317 | + ieee80211_rx_status_to_khz(rx_status)); |
---|
261 | 318 | |
---|
262 | 319 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) |
---|
263 | 320 | return; |
---|
264 | 321 | |
---|
265 | 322 | bss = ieee80211_bss_info_update(local, rx_status, |
---|
266 | | - mgmt, skb->len, &elems, |
---|
| 323 | + mgmt, skb->len, |
---|
267 | 324 | channel); |
---|
268 | 325 | if (bss) |
---|
269 | 326 | ieee80211_rx_bss_put(local, bss); |
---|
.. | .. |
---|
288 | 345 | } |
---|
289 | 346 | |
---|
290 | 347 | /* return false if no more work */ |
---|
291 | | -static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) |
---|
| 348 | +static bool ieee80211_prep_hw_scan(struct ieee80211_sub_if_data *sdata) |
---|
292 | 349 | { |
---|
| 350 | + struct ieee80211_local *local = sdata->local; |
---|
293 | 351 | struct cfg80211_scan_request *req; |
---|
294 | 352 | struct cfg80211_chan_def chandef; |
---|
295 | 353 | u8 bands_used = 0; |
---|
.. | .. |
---|
336 | 394 | if (req->flags & NL80211_SCAN_FLAG_MIN_PREQ_CONTENT) |
---|
337 | 395 | flags |= IEEE80211_PROBE_FLAG_MIN_CONTENT; |
---|
338 | 396 | |
---|
339 | | - ielen = ieee80211_build_preq_ies(local, |
---|
| 397 | + ielen = ieee80211_build_preq_ies(sdata, |
---|
340 | 398 | (u8 *)local->hw_scan_req->req.ie, |
---|
341 | 399 | local->hw_scan_ies_bufsize, |
---|
342 | 400 | &local->hw_scan_req->ies, |
---|
.. | .. |
---|
356 | 414 | static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) |
---|
357 | 415 | { |
---|
358 | 416 | struct ieee80211_local *local = hw_to_local(hw); |
---|
359 | | - bool hw_scan = local->ops->hw_scan; |
---|
| 417 | + bool hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); |
---|
360 | 418 | bool was_scanning = local->scanning; |
---|
361 | 419 | struct cfg80211_scan_request *scan_req; |
---|
362 | 420 | struct ieee80211_sub_if_data *scan_sdata; |
---|
.. | .. |
---|
376 | 434 | if (WARN_ON(!local->scan_req)) |
---|
377 | 435 | return; |
---|
378 | 436 | |
---|
| 437 | + scan_sdata = rcu_dereference_protected(local->scan_sdata, |
---|
| 438 | + lockdep_is_held(&local->mtx)); |
---|
| 439 | + |
---|
379 | 440 | if (hw_scan && !aborted && |
---|
380 | 441 | !ieee80211_hw_check(&local->hw, SINGLE_SCAN_ON_ALL_BANDS) && |
---|
381 | | - ieee80211_prep_hw_scan(local)) { |
---|
| 442 | + ieee80211_prep_hw_scan(scan_sdata)) { |
---|
382 | 443 | int rc; |
---|
383 | 444 | |
---|
384 | 445 | rc = drv_hw_scan(local, |
---|
.. | .. |
---|
402 | 463 | scan_req = rcu_dereference_protected(local->scan_req, |
---|
403 | 464 | lockdep_is_held(&local->mtx)); |
---|
404 | 465 | |
---|
405 | | - if (scan_req != local->int_scan_req) { |
---|
406 | | - local->scan_info.aborted = aborted; |
---|
407 | | - cfg80211_scan_done(scan_req, &local->scan_info); |
---|
408 | | - } |
---|
409 | 466 | RCU_INIT_POINTER(local->scan_req, NULL); |
---|
410 | | - |
---|
411 | | - scan_sdata = rcu_dereference_protected(local->scan_sdata, |
---|
412 | | - lockdep_is_held(&local->mtx)); |
---|
413 | 467 | RCU_INIT_POINTER(local->scan_sdata, NULL); |
---|
414 | 468 | |
---|
415 | 469 | local->scanning = 0; |
---|
416 | 470 | local->scan_chandef.chan = NULL; |
---|
| 471 | + |
---|
| 472 | + synchronize_rcu(); |
---|
| 473 | + |
---|
| 474 | + if (scan_req != local->int_scan_req) { |
---|
| 475 | + local->scan_info.aborted = aborted; |
---|
| 476 | + cfg80211_scan_done(scan_req, &local->scan_info); |
---|
| 477 | + } |
---|
417 | 478 | |
---|
418 | 479 | /* Set power back to normal operating levels. */ |
---|
419 | 480 | ieee80211_hw_config(local, 0); |
---|
.. | .. |
---|
501 | 562 | return 0; |
---|
502 | 563 | } |
---|
503 | 564 | |
---|
| 565 | +static bool __ieee80211_can_leave_ch(struct ieee80211_sub_if_data *sdata) |
---|
| 566 | +{ |
---|
| 567 | + struct ieee80211_local *local = sdata->local; |
---|
| 568 | + struct ieee80211_sub_if_data *sdata_iter; |
---|
| 569 | + |
---|
| 570 | + if (!ieee80211_is_radar_required(local)) |
---|
| 571 | + return true; |
---|
| 572 | + |
---|
| 573 | + if (!regulatory_pre_cac_allowed(local->hw.wiphy)) |
---|
| 574 | + return false; |
---|
| 575 | + |
---|
| 576 | + mutex_lock(&local->iflist_mtx); |
---|
| 577 | + list_for_each_entry(sdata_iter, &local->interfaces, list) { |
---|
| 578 | + if (sdata_iter->wdev.cac_started) { |
---|
| 579 | + mutex_unlock(&local->iflist_mtx); |
---|
| 580 | + return false; |
---|
| 581 | + } |
---|
| 582 | + } |
---|
| 583 | + mutex_unlock(&local->iflist_mtx); |
---|
| 584 | + |
---|
| 585 | + return true; |
---|
| 586 | +} |
---|
| 587 | + |
---|
504 | 588 | static bool ieee80211_can_scan(struct ieee80211_local *local, |
---|
505 | 589 | struct ieee80211_sub_if_data *sdata) |
---|
506 | 590 | { |
---|
507 | | - if (ieee80211_is_radar_required(local)) |
---|
| 591 | + if (!__ieee80211_can_leave_ch(sdata)) |
---|
508 | 592 | return false; |
---|
509 | 593 | |
---|
510 | 594 | if (!list_empty(&local->roc_list)) |
---|
.. | .. |
---|
542 | 626 | struct ieee80211_channel *channel) |
---|
543 | 627 | { |
---|
544 | 628 | struct sk_buff *skb; |
---|
545 | | - u32 txdata_flags = 0; |
---|
546 | 629 | |
---|
547 | 630 | skb = ieee80211_build_probe_req(sdata, src, dst, ratemask, channel, |
---|
548 | 631 | ssid, ssid_len, |
---|
.. | .. |
---|
551 | 634 | if (skb) { |
---|
552 | 635 | if (flags & IEEE80211_PROBE_FLAG_RANDOM_SN) { |
---|
553 | 636 | struct ieee80211_hdr *hdr = (void *)skb->data; |
---|
| 637 | + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
---|
554 | 638 | u16 sn = get_random_u32(); |
---|
555 | 639 | |
---|
556 | | - txdata_flags |= IEEE80211_TX_NO_SEQNO; |
---|
| 640 | + info->control.flags |= IEEE80211_TX_CTRL_NO_SEQNO; |
---|
557 | 641 | hdr->seq_ctrl = |
---|
558 | 642 | cpu_to_le16(IEEE80211_SN_TO_SEQ(sn)); |
---|
559 | 643 | } |
---|
560 | 644 | IEEE80211_SKB_CB(skb)->flags |= tx_flags; |
---|
561 | | - ieee80211_tx_skb_tid_band(sdata, skb, 7, channel->band, |
---|
562 | | - txdata_flags); |
---|
| 645 | + ieee80211_tx_skb_tid_band(sdata, skb, 7, channel->band); |
---|
563 | 646 | } |
---|
564 | 647 | } |
---|
565 | 648 | |
---|
.. | .. |
---|
606 | 689 | struct cfg80211_scan_request *req) |
---|
607 | 690 | { |
---|
608 | 691 | struct ieee80211_local *local = sdata->local; |
---|
| 692 | + bool hw_scan = local->ops->hw_scan; |
---|
609 | 693 | int rc; |
---|
610 | 694 | |
---|
611 | 695 | lockdep_assert_held(&local->mtx); |
---|
612 | 696 | |
---|
613 | | - if (local->scan_req || ieee80211_is_radar_required(local)) |
---|
| 697 | + if (local->scan_req) |
---|
| 698 | + return -EBUSY; |
---|
| 699 | + |
---|
| 700 | + if (!__ieee80211_can_leave_ch(sdata)) |
---|
614 | 701 | return -EBUSY; |
---|
615 | 702 | |
---|
616 | 703 | if (!ieee80211_can_scan(local, sdata)) { |
---|
.. | .. |
---|
620 | 707 | return 0; |
---|
621 | 708 | } |
---|
622 | 709 | |
---|
623 | | - if (local->ops->hw_scan) { |
---|
| 710 | + again: |
---|
| 711 | + if (hw_scan) { |
---|
624 | 712 | u8 *ies; |
---|
625 | 713 | |
---|
626 | 714 | local->hw_scan_ies_bufsize = local->scan_ies_len + req->ie_len; |
---|
.. | .. |
---|
659 | 747 | req->duration_mandatory; |
---|
660 | 748 | |
---|
661 | 749 | local->hw_scan_band = 0; |
---|
| 750 | + local->hw_scan_req->req.n_6ghz_params = req->n_6ghz_params; |
---|
| 751 | + local->hw_scan_req->req.scan_6ghz_params = |
---|
| 752 | + req->scan_6ghz_params; |
---|
| 753 | + local->hw_scan_req->req.scan_6ghz = req->scan_6ghz; |
---|
662 | 754 | |
---|
663 | 755 | /* |
---|
664 | 756 | * After allocating local->hw_scan_req, we must |
---|
.. | .. |
---|
679 | 771 | else |
---|
680 | 772 | memcpy(local->scan_addr, sdata->vif.addr, ETH_ALEN); |
---|
681 | 773 | |
---|
682 | | - if (local->ops->hw_scan) { |
---|
| 774 | + if (hw_scan) { |
---|
683 | 775 | __set_bit(SCAN_HW_SCANNING, &local->scanning); |
---|
684 | 776 | } else if ((req->n_channels == 1) && |
---|
685 | 777 | (req->channels[0] == local->_oper_chandef.chan)) { |
---|
.. | .. |
---|
706 | 798 | IEEE80211_CHAN_RADAR)) || |
---|
707 | 799 | !req->n_ssids) { |
---|
708 | 800 | next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; |
---|
| 801 | + if (req->n_ssids) |
---|
| 802 | + set_bit(SCAN_BEACON_WAIT, &local->scanning); |
---|
709 | 803 | } else { |
---|
710 | 804 | ieee80211_scan_state_send_probe(local, &next_delay); |
---|
711 | 805 | next_delay = IEEE80211_CHANNEL_TIME; |
---|
.. | .. |
---|
722 | 816 | |
---|
723 | 817 | ieee80211_recalc_idle(local); |
---|
724 | 818 | |
---|
725 | | - if (local->ops->hw_scan) { |
---|
726 | | - WARN_ON(!ieee80211_prep_hw_scan(local)); |
---|
| 819 | + if (hw_scan) { |
---|
| 820 | + WARN_ON(!ieee80211_prep_hw_scan(sdata)); |
---|
727 | 821 | rc = drv_hw_scan(local, sdata, local->hw_scan_req); |
---|
728 | 822 | } else { |
---|
729 | 823 | rc = ieee80211_start_sw_scan(local, sdata); |
---|
.. | .. |
---|
738 | 832 | |
---|
739 | 833 | local->scan_req = NULL; |
---|
740 | 834 | RCU_INIT_POINTER(local->scan_sdata, NULL); |
---|
| 835 | + } |
---|
| 836 | + |
---|
| 837 | + if (hw_scan && rc == 1) { |
---|
| 838 | + /* |
---|
| 839 | + * we can't fall back to software for P2P-GO |
---|
| 840 | + * as it must update NoA etc. |
---|
| 841 | + */ |
---|
| 842 | + if (ieee80211_vif_type_p2p(&sdata->vif) == |
---|
| 843 | + NL80211_IFTYPE_P2P_GO) |
---|
| 844 | + return -EOPNOTSUPP; |
---|
| 845 | + hw_scan = false; |
---|
| 846 | + goto again; |
---|
741 | 847 | } |
---|
742 | 848 | |
---|
743 | 849 | return rc; |
---|
.. | .. |
---|
838 | 944 | |
---|
839 | 945 | local->scan_chandef.chan = chan; |
---|
840 | 946 | local->scan_chandef.center_freq1 = chan->center_freq; |
---|
| 947 | + local->scan_chandef.freq1_offset = chan->freq_offset; |
---|
841 | 948 | local->scan_chandef.center_freq2 = 0; |
---|
| 949 | + |
---|
| 950 | + /* For scanning on the S1G band, ignore scan_width (which is constant |
---|
| 951 | + * across all channels) for now since channel width is specific to each |
---|
| 952 | + * channel. Detect the required channel width here and likely revisit |
---|
| 953 | + * later. Maybe scan_width could be used to build the channel scan list? |
---|
| 954 | + */ |
---|
| 955 | + if (chan->band == NL80211_BAND_S1GHZ) { |
---|
| 956 | + local->scan_chandef.width = ieee80211_s1g_channel_width(chan); |
---|
| 957 | + goto set_channel; |
---|
| 958 | + } |
---|
| 959 | + |
---|
842 | 960 | switch (scan_req->scan_width) { |
---|
843 | 961 | case NL80211_BSS_CHAN_WIDTH_5: |
---|
844 | 962 | local->scan_chandef.width = NL80211_CHAN_WIDTH_5; |
---|
.. | .. |
---|
846 | 964 | case NL80211_BSS_CHAN_WIDTH_10: |
---|
847 | 965 | local->scan_chandef.width = NL80211_CHAN_WIDTH_10; |
---|
848 | 966 | break; |
---|
| 967 | + default: |
---|
849 | 968 | case NL80211_BSS_CHAN_WIDTH_20: |
---|
850 | 969 | /* If scanning on oper channel, use whatever channel-type |
---|
851 | 970 | * is currently in use. |
---|
.. | .. |
---|
858 | 977 | else |
---|
859 | 978 | local->scan_chandef.width = NL80211_CHAN_WIDTH_20_NOHT; |
---|
860 | 979 | break; |
---|
| 980 | + case NL80211_BSS_CHAN_WIDTH_1: |
---|
| 981 | + case NL80211_BSS_CHAN_WIDTH_2: |
---|
| 982 | + /* shouldn't get here, S1G handled above */ |
---|
| 983 | + WARN_ON(1); |
---|
| 984 | + break; |
---|
861 | 985 | } |
---|
862 | 986 | |
---|
| 987 | +set_channel: |
---|
863 | 988 | if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL)) |
---|
864 | 989 | skip = 1; |
---|
865 | 990 | |
---|
.. | .. |
---|
886 | 1011 | !scan_req->n_ssids) { |
---|
887 | 1012 | *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; |
---|
888 | 1013 | local->next_scan_state = SCAN_DECISION; |
---|
| 1014 | + if (scan_req->n_ssids) |
---|
| 1015 | + set_bit(SCAN_BEACON_WAIT, &local->scanning); |
---|
889 | 1016 | return; |
---|
890 | 1017 | } |
---|
891 | 1018 | |
---|
.. | .. |
---|
978 | 1105 | goto out; |
---|
979 | 1106 | } |
---|
980 | 1107 | |
---|
| 1108 | + clear_bit(SCAN_BEACON_WAIT, &local->scanning); |
---|
| 1109 | + |
---|
981 | 1110 | /* |
---|
982 | 1111 | * as long as no delay is required advance immediately |
---|
983 | 1112 | * without scheduling a new work |
---|
.. | .. |
---|
987 | 1116 | aborted = true; |
---|
988 | 1117 | goto out_complete; |
---|
989 | 1118 | } |
---|
| 1119 | + |
---|
| 1120 | + if (test_and_clear_bit(SCAN_BEACON_DONE, &local->scanning) && |
---|
| 1121 | + local->next_scan_state == SCAN_DECISION) |
---|
| 1122 | + local->next_scan_state = SCAN_SEND_PROBE; |
---|
990 | 1123 | |
---|
991 | 1124 | switch (local->next_scan_state) { |
---|
992 | 1125 | case SCAN_DECISION: |
---|
.. | .. |
---|
1057 | 1190 | int max_n; |
---|
1058 | 1191 | |
---|
1059 | 1192 | for (band = 0; band < NUM_NL80211_BANDS; band++) { |
---|
1060 | | - if (!local->hw.wiphy->bands[band]) |
---|
| 1193 | + if (!local->hw.wiphy->bands[band] || |
---|
| 1194 | + band == NL80211_BAND_6GHZ) |
---|
1061 | 1195 | continue; |
---|
1062 | 1196 | |
---|
1063 | 1197 | max_n = local->hw.wiphy->bands[band]->n_channels; |
---|
.. | .. |
---|
1208 | 1342 | |
---|
1209 | 1343 | ieee80211_prepare_scan_chandef(&chandef, req->scan_width); |
---|
1210 | 1344 | |
---|
1211 | | - ieee80211_build_preq_ies(local, ie, num_bands * iebufsz, |
---|
| 1345 | + ieee80211_build_preq_ies(sdata, ie, num_bands * iebufsz, |
---|
1212 | 1346 | &sched_scan_ies, req->ie, |
---|
1213 | 1347 | req->ie_len, bands_used, rate_masks, &chandef, |
---|
1214 | 1348 | flags); |
---|