| .. | .. |
|---|
| 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); |
|---|