hc
2023-12-06 08f87f769b595151be1afeff53e144f543faa614
kernel/net/wireless/scan.c
....@@ -5,7 +5,7 @@
55 * Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
66 * Copyright 2013-2014 Intel Mobile Communications GmbH
77 * Copyright 2016 Intel Deutschland GmbH
8
- * Copyright (C) 2018-2019 Intel Corporation
8
+ * Copyright (C) 2018-2020 Intel Corporation
99 */
1010 #include <linux/kernel.h>
1111 #include <linux/slab.h>
....@@ -14,6 +14,8 @@
1414 #include <linux/wireless.h>
1515 #include <linux/nl80211.h>
1616 #include <linux/etherdevice.h>
17
+#include <linux/crc32.h>
18
+#include <linux/bitfield.h>
1719 #include <net/arp.h>
1820 #include <net/cfg80211.h>
1921 #include <net/cfg80211-wext.h>
....@@ -55,7 +57,7 @@
5557 *
5658 * Also note that the hidden_beacon_bss pointer is only relevant
5759 * if the driver uses something other than the IEs, e.g. private
58
- * data stored stored in the BSS struct, since the beacon IEs are
60
+ * data stored in the BSS struct, since the beacon IEs are
5961 * also linked into the probe response struct.
6062 */
6163
....@@ -73,6 +75,43 @@
7375 "limit to number of scan BSS entries (per wiphy, default 1000)");
7476
7577 #define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ)
78
+
79
+/**
80
+ * struct cfg80211_colocated_ap - colocated AP information
81
+ *
82
+ * @list: linked list to all colocated aPS
83
+ * @bssid: BSSID of the reported AP
84
+ * @ssid: SSID of the reported AP
85
+ * @ssid_len: length of the ssid
86
+ * @center_freq: frequency the reported AP is on
87
+ * @unsolicited_probe: the reported AP is part of an ESS, where all the APs
88
+ * that operate in the same channel as the reported AP and that might be
89
+ * detected by a STA receiving this frame, are transmitting unsolicited
90
+ * Probe Response frames every 20 TUs
91
+ * @oct_recommended: OCT is recommended to exchange MMPDUs with the reported AP
92
+ * @same_ssid: the reported AP has the same SSID as the reporting AP
93
+ * @multi_bss: the reported AP is part of a multiple BSSID set
94
+ * @transmitted_bssid: the reported AP is the transmitting BSSID
95
+ * @colocated_ess: all the APs that share the same ESS as the reported AP are
96
+ * colocated and can be discovered via legacy bands.
97
+ * @short_ssid_valid: short_ssid is valid and can be used
98
+ * @short_ssid: the short SSID for this SSID
99
+ */
100
+struct cfg80211_colocated_ap {
101
+ struct list_head list;
102
+ u8 bssid[ETH_ALEN];
103
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
104
+ size_t ssid_len;
105
+ u32 short_ssid;
106
+ u32 center_freq;
107
+ u8 unsolicited_probe:1,
108
+ oct_recommended:1,
109
+ same_ssid:1,
110
+ multi_bss:1,
111
+ transmitted_bssid:1,
112
+ colocated_ess:1,
113
+ short_ssid_valid:1;
114
+};
76115
77116 static void bss_free(struct cfg80211_internal_bss *bss)
78117 {
....@@ -104,18 +143,12 @@
104143 lockdep_assert_held(&rdev->bss_lock);
105144
106145 bss->refcount++;
107
- if (bss->pub.hidden_beacon_bss) {
108
- bss = container_of(bss->pub.hidden_beacon_bss,
109
- struct cfg80211_internal_bss,
110
- pub);
111
- bss->refcount++;
112
- }
113
- if (bss->pub.transmitted_bss) {
114
- bss = container_of(bss->pub.transmitted_bss,
115
- struct cfg80211_internal_bss,
116
- pub);
117
- bss->refcount++;
118
- }
146
+
147
+ if (bss->pub.hidden_beacon_bss)
148
+ bss_from_pub(bss->pub.hidden_beacon_bss)->refcount++;
149
+
150
+ if (bss->pub.transmitted_bss)
151
+ bss_from_pub(bss->pub.transmitted_bss)->refcount++;
119152 }
120153
121154 static inline void bss_ref_put(struct cfg80211_registered_device *rdev,
....@@ -179,21 +212,71 @@
179212 return true;
180213 }
181214
215
+bool cfg80211_is_element_inherited(const struct element *elem,
216
+ const struct element *non_inherit_elem)
217
+{
218
+ u8 id_len, ext_id_len, i, loop_len, id;
219
+ const u8 *list;
220
+
221
+ if (elem->id == WLAN_EID_MULTIPLE_BSSID)
222
+ return false;
223
+
224
+ if (!non_inherit_elem || non_inherit_elem->datalen < 2)
225
+ return true;
226
+
227
+ /*
228
+ * non inheritance element format is:
229
+ * ext ID (56) | IDs list len | list | extension IDs list len | list
230
+ * Both lists are optional. Both lengths are mandatory.
231
+ * This means valid length is:
232
+ * elem_len = 1 (extension ID) + 2 (list len fields) + list lengths
233
+ */
234
+ id_len = non_inherit_elem->data[1];
235
+ if (non_inherit_elem->datalen < 3 + id_len)
236
+ return true;
237
+
238
+ ext_id_len = non_inherit_elem->data[2 + id_len];
239
+ if (non_inherit_elem->datalen < 3 + id_len + ext_id_len)
240
+ return true;
241
+
242
+ if (elem->id == WLAN_EID_EXTENSION) {
243
+ if (!ext_id_len)
244
+ return true;
245
+ loop_len = ext_id_len;
246
+ list = &non_inherit_elem->data[3 + id_len];
247
+ id = elem->data[0];
248
+ } else {
249
+ if (!id_len)
250
+ return true;
251
+ loop_len = id_len;
252
+ list = &non_inherit_elem->data[2];
253
+ id = elem->id;
254
+ }
255
+
256
+ for (i = 0; i < loop_len; i++) {
257
+ if (list[i] == id)
258
+ return false;
259
+ }
260
+
261
+ return true;
262
+}
263
+EXPORT_SYMBOL(cfg80211_is_element_inherited);
264
+
182265 static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
183266 const u8 *subelement, size_t subie_len,
184267 u8 *new_ie, gfp_t gfp)
185268 {
186269 u8 *pos, *tmp;
187270 const u8 *tmp_old, *tmp_new;
271
+ const struct element *non_inherit_elem;
188272 u8 *sub_copy;
189273
190274 /* copy subelement as we need to change its content to
191275 * mark an ie after it is processed.
192276 */
193
- sub_copy = kmalloc(subie_len, gfp);
277
+ sub_copy = kmemdup(subelement, subie_len, gfp);
194278 if (!sub_copy)
195279 return 0;
196
- memcpy(sub_copy, subelement, subie_len);
197280
198281 pos = &new_ie[0];
199282
....@@ -204,40 +287,57 @@
204287 pos += (tmp_new[1] + 2);
205288 }
206289
290
+ /* get non inheritance list if exists */
291
+ non_inherit_elem =
292
+ cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
293
+ sub_copy, subie_len);
294
+
207295 /* go through IEs in ie (skip SSID) and subelement,
208296 * merge them into new_ie
209297 */
210298 tmp_old = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen);
211299 tmp_old = (tmp_old) ? tmp_old + tmp_old[1] + 2 : ie;
212300
213
- while (tmp_old + tmp_old[1] + 2 - ie <= ielen) {
301
+ while (tmp_old + 2 - ie <= ielen &&
302
+ tmp_old + tmp_old[1] + 2 - ie <= ielen) {
214303 if (tmp_old[0] == 0) {
215304 tmp_old++;
216305 continue;
217306 }
218307
219
- tmp = (u8 *)cfg80211_find_ie(tmp_old[0], sub_copy, subie_len);
308
+ if (tmp_old[0] == WLAN_EID_EXTENSION)
309
+ tmp = (u8 *)cfg80211_find_ext_ie(tmp_old[2], sub_copy,
310
+ subie_len);
311
+ else
312
+ tmp = (u8 *)cfg80211_find_ie(tmp_old[0], sub_copy,
313
+ subie_len);
314
+
220315 if (!tmp) {
316
+ const struct element *old_elem = (void *)tmp_old;
317
+
221318 /* ie in old ie but not in subelement */
222
- if (tmp_old[0] != WLAN_EID_MULTIPLE_BSSID) {
319
+ if (cfg80211_is_element_inherited(old_elem,
320
+ non_inherit_elem)) {
223321 memcpy(pos, tmp_old, tmp_old[1] + 2);
224322 pos += tmp_old[1] + 2;
225323 }
226324 } else {
227325 /* ie in transmitting ie also in subelement,
228326 * copy from subelement and flag the ie in subelement
229
- * as copied (by setting eid field to 0xff). For
230
- * vendor ie, compare OUI + type + subType to
327
+ * as copied (by setting eid field to WLAN_EID_SSID,
328
+ * which is skipped anyway).
329
+ * For vendor ie, compare OUI + type + subType to
231330 * determine if they are the same ie.
232331 */
233332 if (tmp_old[0] == WLAN_EID_VENDOR_SPECIFIC) {
234
- if (!memcmp(tmp_old + 2, tmp + 2, 5)) {
333
+ if (tmp_old[1] >= 5 && tmp[1] >= 5 &&
334
+ !memcmp(tmp_old + 2, tmp + 2, 5)) {
235335 /* same vendor ie, copy from
236336 * subelement
237337 */
238338 memcpy(pos, tmp, tmp[1] + 2);
239339 pos += tmp[1] + 2;
240
- tmp[0] = 0xff;
340
+ tmp[0] = WLAN_EID_SSID;
241341 } else {
242342 memcpy(pos, tmp_old, tmp_old[1] + 2);
243343 pos += tmp_old[1] + 2;
....@@ -246,7 +346,7 @@
246346 /* copy ie from subelement into new ie */
247347 memcpy(pos, tmp, tmp[1] + 2);
248348 pos += tmp[1] + 2;
249
- tmp[0] = 0xff;
349
+ tmp[0] = WLAN_EID_SSID;
250350 }
251351 }
252352
....@@ -260,11 +360,10 @@
260360 * copied to new ie, skip ssid, capability, bssid-index ie
261361 */
262362 tmp_new = sub_copy;
263
- while (tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
363
+ while (tmp_new + 2 - sub_copy <= subie_len &&
364
+ tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
264365 if (!(tmp_new[0] == WLAN_EID_NON_TX_BSSID_CAP ||
265
- tmp_new[0] == WLAN_EID_SSID ||
266
- tmp_new[0] == WLAN_EID_MULTI_BSSID_IDX ||
267
- tmp_new[0] == 0xff)) {
366
+ tmp_new[0] == WLAN_EID_SSID)) {
268367 memcpy(pos, tmp_new, tmp_new[1] + 2);
269368 pos += tmp_new[1] + 2;
270369 }
....@@ -316,13 +415,25 @@
316415 }
317416 ssid_len = ssid[1];
318417 ssid = ssid + 2;
319
- rcu_read_unlock();
320418
321419 /* check if nontrans_bss is in the list */
322420 list_for_each_entry(bss, &trans_bss->nontrans_list, nontrans_list) {
323
- if (is_bss(bss, nontrans_bss->bssid, ssid, ssid_len))
421
+ if (is_bss(bss, nontrans_bss->bssid, ssid, ssid_len)) {
422
+ rcu_read_unlock();
324423 return 0;
424
+ }
325425 }
426
+
427
+ rcu_read_unlock();
428
+
429
+ /*
430
+ * This is a bit weird - it's not on the list, but already on another
431
+ * one! The only way that could happen is if there's some BSSID/SSID
432
+ * shared by multiple APs in their multi-BSSID profiles, potentially
433
+ * with hidden SSID mixed in ... ignore it.
434
+ */
435
+ if (!list_empty(&nontrans_bss->nontrans_list))
436
+ return -EINVAL;
326437
327438 /* add to the list */
328439 list_add_tail(&nontrans_bss->nontrans_list, &trans_bss->nontrans_list);
....@@ -385,10 +496,440 @@
385496 return ret;
386497 }
387498
499
+static u8 cfg80211_parse_bss_param(u8 data,
500
+ struct cfg80211_colocated_ap *coloc_ap)
501
+{
502
+ coloc_ap->oct_recommended =
503
+ u8_get_bits(data, IEEE80211_RNR_TBTT_PARAMS_OCT_RECOMMENDED);
504
+ coloc_ap->same_ssid =
505
+ u8_get_bits(data, IEEE80211_RNR_TBTT_PARAMS_SAME_SSID);
506
+ coloc_ap->multi_bss =
507
+ u8_get_bits(data, IEEE80211_RNR_TBTT_PARAMS_MULTI_BSSID);
508
+ coloc_ap->transmitted_bssid =
509
+ u8_get_bits(data, IEEE80211_RNR_TBTT_PARAMS_TRANSMITTED_BSSID);
510
+ coloc_ap->unsolicited_probe =
511
+ u8_get_bits(data, IEEE80211_RNR_TBTT_PARAMS_PROBE_ACTIVE);
512
+ coloc_ap->colocated_ess =
513
+ u8_get_bits(data, IEEE80211_RNR_TBTT_PARAMS_COLOC_ESS);
514
+
515
+ return u8_get_bits(data, IEEE80211_RNR_TBTT_PARAMS_COLOC_AP);
516
+}
517
+
518
+static int cfg80211_calc_short_ssid(const struct cfg80211_bss_ies *ies,
519
+ const struct element **elem, u32 *s_ssid)
520
+{
521
+
522
+ *elem = cfg80211_find_elem(WLAN_EID_SSID, ies->data, ies->len);
523
+ if (!*elem || (*elem)->datalen > IEEE80211_MAX_SSID_LEN)
524
+ return -EINVAL;
525
+
526
+ *s_ssid = ~crc32_le(~0, (*elem)->data, (*elem)->datalen);
527
+ return 0;
528
+}
529
+
530
+static void cfg80211_free_coloc_ap_list(struct list_head *coloc_ap_list)
531
+{
532
+ struct cfg80211_colocated_ap *ap, *tmp_ap;
533
+
534
+ list_for_each_entry_safe(ap, tmp_ap, coloc_ap_list, list) {
535
+ list_del(&ap->list);
536
+ kfree(ap);
537
+ }
538
+}
539
+
540
+static int cfg80211_parse_ap_info(struct cfg80211_colocated_ap *entry,
541
+ const u8 *pos, u8 length,
542
+ const struct element *ssid_elem,
543
+ int s_ssid_tmp)
544
+{
545
+ /* skip the TBTT offset */
546
+ pos++;
547
+
548
+ memcpy(entry->bssid, pos, ETH_ALEN);
549
+ pos += ETH_ALEN;
550
+
551
+ if (length == IEEE80211_TBTT_INFO_OFFSET_BSSID_SSSID_BSS_PARAM) {
552
+ memcpy(&entry->short_ssid, pos,
553
+ sizeof(entry->short_ssid));
554
+ entry->short_ssid_valid = true;
555
+ pos += 4;
556
+ }
557
+
558
+ /* skip non colocated APs */
559
+ if (!cfg80211_parse_bss_param(*pos, entry))
560
+ return -EINVAL;
561
+ pos++;
562
+
563
+ if (length == IEEE80211_TBTT_INFO_OFFSET_BSSID_BSS_PARAM) {
564
+ /*
565
+ * no information about the short ssid. Consider the entry valid
566
+ * for now. It would later be dropped in case there are explicit
567
+ * SSIDs that need to be matched
568
+ */
569
+ if (!entry->same_ssid)
570
+ return 0;
571
+ }
572
+
573
+ if (entry->same_ssid) {
574
+ entry->short_ssid = s_ssid_tmp;
575
+ entry->short_ssid_valid = true;
576
+
577
+ /*
578
+ * This is safe because we validate datalen in
579
+ * cfg80211_parse_colocated_ap(), before calling this
580
+ * function.
581
+ */
582
+ memcpy(&entry->ssid, &ssid_elem->data,
583
+ ssid_elem->datalen);
584
+ entry->ssid_len = ssid_elem->datalen;
585
+ }
586
+ return 0;
587
+}
588
+
589
+static int cfg80211_parse_colocated_ap(const struct cfg80211_bss_ies *ies,
590
+ struct list_head *list)
591
+{
592
+ struct ieee80211_neighbor_ap_info *ap_info;
593
+ const struct element *elem, *ssid_elem;
594
+ const u8 *pos, *end;
595
+ u32 s_ssid_tmp;
596
+ int n_coloc = 0, ret;
597
+ LIST_HEAD(ap_list);
598
+
599
+ elem = cfg80211_find_elem(WLAN_EID_REDUCED_NEIGHBOR_REPORT, ies->data,
600
+ ies->len);
601
+ if (!elem || elem->datalen > IEEE80211_MAX_SSID_LEN)
602
+ return 0;
603
+
604
+ pos = elem->data;
605
+ end = pos + elem->datalen;
606
+
607
+ ret = cfg80211_calc_short_ssid(ies, &ssid_elem, &s_ssid_tmp);
608
+ if (ret)
609
+ return ret;
610
+
611
+ /* RNR IE may contain more than one NEIGHBOR_AP_INFO */
612
+ while (pos + sizeof(*ap_info) <= end) {
613
+ enum nl80211_band band;
614
+ int freq;
615
+ u8 length, i, count;
616
+
617
+ ap_info = (void *)pos;
618
+ count = u8_get_bits(ap_info->tbtt_info_hdr,
619
+ IEEE80211_AP_INFO_TBTT_HDR_COUNT) + 1;
620
+ length = ap_info->tbtt_info_len;
621
+
622
+ pos += sizeof(*ap_info);
623
+
624
+ if (!ieee80211_operating_class_to_band(ap_info->op_class,
625
+ &band))
626
+ break;
627
+
628
+ freq = ieee80211_channel_to_frequency(ap_info->channel, band);
629
+
630
+ if (end - pos < count * ap_info->tbtt_info_len)
631
+ break;
632
+
633
+ /*
634
+ * TBTT info must include bss param + BSSID +
635
+ * (short SSID or same_ssid bit to be set).
636
+ * ignore other options, and move to the
637
+ * next AP info
638
+ */
639
+ if (band != NL80211_BAND_6GHZ ||
640
+ (length != IEEE80211_TBTT_INFO_OFFSET_BSSID_BSS_PARAM &&
641
+ length < IEEE80211_TBTT_INFO_OFFSET_BSSID_SSSID_BSS_PARAM)) {
642
+ pos += count * ap_info->tbtt_info_len;
643
+ continue;
644
+ }
645
+
646
+ for (i = 0; i < count; i++) {
647
+ struct cfg80211_colocated_ap *entry;
648
+
649
+ entry = kzalloc(sizeof(*entry) + IEEE80211_MAX_SSID_LEN,
650
+ GFP_ATOMIC);
651
+
652
+ if (!entry)
653
+ break;
654
+
655
+ entry->center_freq = freq;
656
+
657
+ if (!cfg80211_parse_ap_info(entry, pos, length,
658
+ ssid_elem, s_ssid_tmp)) {
659
+ n_coloc++;
660
+ list_add_tail(&entry->list, &ap_list);
661
+ } else {
662
+ kfree(entry);
663
+ }
664
+
665
+ pos += ap_info->tbtt_info_len;
666
+ }
667
+ }
668
+
669
+ if (pos != end) {
670
+ cfg80211_free_coloc_ap_list(&ap_list);
671
+ return 0;
672
+ }
673
+
674
+ list_splice_tail(&ap_list, list);
675
+ return n_coloc;
676
+}
677
+
678
+static void cfg80211_scan_req_add_chan(struct cfg80211_scan_request *request,
679
+ struct ieee80211_channel *chan,
680
+ bool add_to_6ghz)
681
+{
682
+ int i;
683
+ u32 n_channels = request->n_channels;
684
+ struct cfg80211_scan_6ghz_params *params =
685
+ &request->scan_6ghz_params[request->n_6ghz_params];
686
+
687
+ for (i = 0; i < n_channels; i++) {
688
+ if (request->channels[i] == chan) {
689
+ if (add_to_6ghz)
690
+ params->channel_idx = i;
691
+ return;
692
+ }
693
+ }
694
+
695
+ request->channels[n_channels] = chan;
696
+ if (add_to_6ghz)
697
+ request->scan_6ghz_params[request->n_6ghz_params].channel_idx =
698
+ n_channels;
699
+
700
+ request->n_channels++;
701
+}
702
+
703
+static bool cfg80211_find_ssid_match(struct cfg80211_colocated_ap *ap,
704
+ struct cfg80211_scan_request *request)
705
+{
706
+ int i;
707
+ u32 s_ssid;
708
+
709
+ for (i = 0; i < request->n_ssids; i++) {
710
+ /* wildcard ssid in the scan request */
711
+ if (!request->ssids[i].ssid_len) {
712
+ if (ap->multi_bss && !ap->transmitted_bssid)
713
+ continue;
714
+
715
+ return true;
716
+ }
717
+
718
+ if (ap->ssid_len &&
719
+ ap->ssid_len == request->ssids[i].ssid_len) {
720
+ if (!memcmp(request->ssids[i].ssid, ap->ssid,
721
+ ap->ssid_len))
722
+ return true;
723
+ } else if (ap->short_ssid_valid) {
724
+ s_ssid = ~crc32_le(~0, request->ssids[i].ssid,
725
+ request->ssids[i].ssid_len);
726
+
727
+ if (ap->short_ssid == s_ssid)
728
+ return true;
729
+ }
730
+ }
731
+
732
+ return false;
733
+}
734
+
735
+static int cfg80211_scan_6ghz(struct cfg80211_registered_device *rdev)
736
+{
737
+ u8 i;
738
+ struct cfg80211_colocated_ap *ap;
739
+ int n_channels, count = 0, err;
740
+ struct cfg80211_scan_request *request, *rdev_req = rdev->scan_req;
741
+ LIST_HEAD(coloc_ap_list);
742
+ bool need_scan_psc;
743
+ const struct ieee80211_sband_iftype_data *iftd;
744
+
745
+ rdev_req->scan_6ghz = true;
746
+
747
+ if (!rdev->wiphy.bands[NL80211_BAND_6GHZ])
748
+ return -EOPNOTSUPP;
749
+
750
+ iftd = ieee80211_get_sband_iftype_data(rdev->wiphy.bands[NL80211_BAND_6GHZ],
751
+ rdev_req->wdev->iftype);
752
+ if (!iftd || !iftd->he_cap.has_he)
753
+ return -EOPNOTSUPP;
754
+
755
+ n_channels = rdev->wiphy.bands[NL80211_BAND_6GHZ]->n_channels;
756
+
757
+ if (rdev_req->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ) {
758
+ struct cfg80211_internal_bss *intbss;
759
+
760
+ spin_lock_bh(&rdev->bss_lock);
761
+ list_for_each_entry(intbss, &rdev->bss_list, list) {
762
+ struct cfg80211_bss *res = &intbss->pub;
763
+ const struct cfg80211_bss_ies *ies;
764
+
765
+ ies = rcu_access_pointer(res->ies);
766
+ count += cfg80211_parse_colocated_ap(ies,
767
+ &coloc_ap_list);
768
+ }
769
+ spin_unlock_bh(&rdev->bss_lock);
770
+ }
771
+
772
+ request = kzalloc(struct_size(request, channels, n_channels) +
773
+ sizeof(*request->scan_6ghz_params) * count,
774
+ GFP_KERNEL);
775
+ if (!request) {
776
+ cfg80211_free_coloc_ap_list(&coloc_ap_list);
777
+ return -ENOMEM;
778
+ }
779
+
780
+ *request = *rdev_req;
781
+ request->n_channels = 0;
782
+ request->scan_6ghz_params =
783
+ (void *)&request->channels[n_channels];
784
+
785
+ /*
786
+ * PSC channels should not be scanned if all the reported co-located APs
787
+ * are indicating that all APs in the same ESS are co-located
788
+ */
789
+ if (count) {
790
+ need_scan_psc = false;
791
+
792
+ list_for_each_entry(ap, &coloc_ap_list, list) {
793
+ if (!ap->colocated_ess) {
794
+ need_scan_psc = true;
795
+ break;
796
+ }
797
+ }
798
+ } else {
799
+ need_scan_psc = true;
800
+ }
801
+
802
+ /*
803
+ * add to the scan request the channels that need to be scanned
804
+ * regardless of the collocated APs (PSC channels or all channels
805
+ * in case that NL80211_SCAN_FLAG_COLOCATED_6GHZ is not set)
806
+ */
807
+ for (i = 0; i < rdev_req->n_channels; i++) {
808
+ if (rdev_req->channels[i]->band == NL80211_BAND_6GHZ &&
809
+ ((need_scan_psc &&
810
+ cfg80211_channel_is_psc(rdev_req->channels[i])) ||
811
+ !(rdev_req->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ))) {
812
+ cfg80211_scan_req_add_chan(request,
813
+ rdev_req->channels[i],
814
+ false);
815
+ }
816
+ }
817
+
818
+ if (!(rdev_req->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ))
819
+ goto skip;
820
+
821
+ list_for_each_entry(ap, &coloc_ap_list, list) {
822
+ bool found = false;
823
+ struct cfg80211_scan_6ghz_params *scan_6ghz_params =
824
+ &request->scan_6ghz_params[request->n_6ghz_params];
825
+ struct ieee80211_channel *chan =
826
+ ieee80211_get_channel(&rdev->wiphy, ap->center_freq);
827
+
828
+ if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
829
+ continue;
830
+
831
+ for (i = 0; i < rdev_req->n_channels; i++) {
832
+ if (rdev_req->channels[i] == chan)
833
+ found = true;
834
+ }
835
+
836
+ if (!found)
837
+ continue;
838
+
839
+ if (request->n_ssids > 0 &&
840
+ !cfg80211_find_ssid_match(ap, request))
841
+ continue;
842
+
843
+ if (!request->n_ssids && ap->multi_bss && !ap->transmitted_bssid)
844
+ continue;
845
+
846
+ cfg80211_scan_req_add_chan(request, chan, true);
847
+ memcpy(scan_6ghz_params->bssid, ap->bssid, ETH_ALEN);
848
+ scan_6ghz_params->short_ssid = ap->short_ssid;
849
+ scan_6ghz_params->short_ssid_valid = ap->short_ssid_valid;
850
+ scan_6ghz_params->unsolicited_probe = ap->unsolicited_probe;
851
+
852
+ /*
853
+ * If a PSC channel is added to the scan and 'need_scan_psc' is
854
+ * set to false, then all the APs that the scan logic is
855
+ * interested with on the channel are collocated and thus there
856
+ * is no need to perform the initial PSC channel listen.
857
+ */
858
+ if (cfg80211_channel_is_psc(chan) && !need_scan_psc)
859
+ scan_6ghz_params->psc_no_listen = true;
860
+
861
+ request->n_6ghz_params++;
862
+ }
863
+
864
+skip:
865
+ cfg80211_free_coloc_ap_list(&coloc_ap_list);
866
+
867
+ if (request->n_channels) {
868
+ struct cfg80211_scan_request *old = rdev->int_scan_req;
869
+
870
+ rdev->int_scan_req = request;
871
+
872
+ /*
873
+ * If this scan follows a previous scan, save the scan start
874
+ * info from the first part of the scan
875
+ */
876
+ if (old)
877
+ rdev->int_scan_req->info = old->info;
878
+
879
+ err = rdev_scan(rdev, request);
880
+ if (err) {
881
+ rdev->int_scan_req = old;
882
+ kfree(request);
883
+ } else {
884
+ kfree(old);
885
+ }
886
+
887
+ return err;
888
+ }
889
+
890
+ kfree(request);
891
+ return -EINVAL;
892
+}
893
+
894
+int cfg80211_scan(struct cfg80211_registered_device *rdev)
895
+{
896
+ struct cfg80211_scan_request *request;
897
+ struct cfg80211_scan_request *rdev_req = rdev->scan_req;
898
+ u32 n_channels = 0, idx, i;
899
+
900
+ if (!(rdev->wiphy.flags & WIPHY_FLAG_SPLIT_SCAN_6GHZ))
901
+ return rdev_scan(rdev, rdev_req);
902
+
903
+ for (i = 0; i < rdev_req->n_channels; i++) {
904
+ if (rdev_req->channels[i]->band != NL80211_BAND_6GHZ)
905
+ n_channels++;
906
+ }
907
+
908
+ if (!n_channels)
909
+ return cfg80211_scan_6ghz(rdev);
910
+
911
+ request = kzalloc(struct_size(request, channels, n_channels),
912
+ GFP_KERNEL);
913
+ if (!request)
914
+ return -ENOMEM;
915
+
916
+ *request = *rdev_req;
917
+ request->n_channels = n_channels;
918
+
919
+ for (i = idx = 0; i < rdev_req->n_channels; i++) {
920
+ if (rdev_req->channels[i]->band != NL80211_BAND_6GHZ)
921
+ request->channels[idx++] = rdev_req->channels[i];
922
+ }
923
+
924
+ rdev_req->scan_6ghz = false;
925
+ rdev->int_scan_req = request;
926
+ return rdev_scan(rdev, request);
927
+}
928
+
388929 void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
389930 bool send_message)
390931 {
391
- struct cfg80211_scan_request *request;
932
+ struct cfg80211_scan_request *request, *rdev_req;
392933 struct wireless_dev *wdev;
393934 struct sk_buff *msg;
394935 #ifdef CONFIG_CFG80211_WEXT
....@@ -403,11 +944,18 @@
403944 return;
404945 }
405946
406
- request = rdev->scan_req;
407
- if (!request)
947
+ rdev_req = rdev->scan_req;
948
+ if (!rdev_req)
408949 return;
409950
410
- wdev = request->wdev;
951
+ wdev = rdev_req->wdev;
952
+ request = rdev->int_scan_req ? rdev->int_scan_req : rdev_req;
953
+
954
+ if (wdev_running(wdev) &&
955
+ (rdev->wiphy.flags & WIPHY_FLAG_SPLIT_SCAN_6GHZ) &&
956
+ !rdev_req->scan_6ghz && !request->info.aborted &&
957
+ !cfg80211_scan_6ghz(rdev))
958
+ return;
411959
412960 /*
413961 * This must be before sending the other events!
....@@ -438,8 +986,11 @@
438986 if (wdev->netdev)
439987 dev_put(wdev->netdev);
440988
989
+ kfree(rdev->int_scan_req);
990
+ rdev->int_scan_req = NULL;
991
+
992
+ kfree(rdev->scan_req);
441993 rdev->scan_req = NULL;
442
- kfree(request);
443994
444995 if (!send_message)
445996 rdev->scan_msg = msg;
....@@ -462,10 +1013,25 @@
4621013 void cfg80211_scan_done(struct cfg80211_scan_request *request,
4631014 struct cfg80211_scan_info *info)
4641015 {
1016
+ struct cfg80211_scan_info old_info = request->info;
1017
+
4651018 trace_cfg80211_scan_done(request, info);
466
- WARN_ON(request != wiphy_to_rdev(request->wiphy)->scan_req);
1019
+ WARN_ON(request != wiphy_to_rdev(request->wiphy)->scan_req &&
1020
+ request != wiphy_to_rdev(request->wiphy)->int_scan_req);
4671021
4681022 request->info = *info;
1023
+
1024
+ /*
1025
+ * In case the scan is split, the scan_start_tsf and tsf_bssid should
1026
+ * be of the first part. In such a case old_info.scan_start_tsf should
1027
+ * be non zero.
1028
+ */
1029
+ if (request->scan_6ghz && old_info.scan_start_tsf) {
1030
+ request->info.scan_start_tsf = old_info.scan_start_tsf;
1031
+ memcpy(request->info.tsf_bssid, old_info.tsf_bssid,
1032
+ sizeof(request->info.tsf_bssid));
1033
+ }
1034
+
4691035 request->notified = true;
4701036 queue_work(cfg80211_wq, &wiphy_to_rdev(request->wiphy)->scan_done_wk);
4711037 }
....@@ -493,9 +1059,8 @@
4931059 {
4941060 struct cfg80211_sched_scan_request *pos;
4951061
496
- WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_rtnl_is_held());
497
-
498
- list_for_each_entry_rcu(pos, &rdev->sched_scan_req_list, list) {
1062
+ list_for_each_entry_rcu(pos, &rdev->sched_scan_req_list, list,
1063
+ lockdep_rtnl_is_held()) {
4991064 if (pos->reqid == reqid)
5001065 return pos;
5011066 }
....@@ -650,48 +1215,53 @@
6501215 __cfg80211_bss_expire(rdev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE);
6511216 }
6521217
653
-const u8 *cfg80211_find_ie_match(u8 eid, const u8 *ies, int len,
654
- const u8 *match, int match_len,
655
- int match_offset)
1218
+void cfg80211_bss_flush(struct wiphy *wiphy)
1219
+{
1220
+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
1221
+
1222
+ spin_lock_bh(&rdev->bss_lock);
1223
+ __cfg80211_bss_expire(rdev, jiffies);
1224
+ spin_unlock_bh(&rdev->bss_lock);
1225
+}
1226
+EXPORT_SYMBOL(cfg80211_bss_flush);
1227
+
1228
+const struct element *
1229
+cfg80211_find_elem_match(u8 eid, const u8 *ies, unsigned int len,
1230
+ const u8 *match, unsigned int match_len,
1231
+ unsigned int match_offset)
6561232 {
6571233 const struct element *elem;
6581234
659
- /* match_offset can't be smaller than 2, unless match_len is
660
- * zero, in which case match_offset must be zero as well.
661
- */
662
- if (WARN_ON((match_len && match_offset < 2) ||
663
- (!match_len && match_offset)))
664
- return NULL;
665
-
6661235 for_each_element_id(elem, eid, ies, len) {
667
- if (elem->datalen >= match_offset - 2 + match_len &&
668
- !memcmp(elem->data + match_offset - 2, match, match_len))
669
- return (void *)elem;
1236
+ if (elem->datalen >= match_offset + match_len &&
1237
+ !memcmp(elem->data + match_offset, match, match_len))
1238
+ return elem;
6701239 }
6711240
6721241 return NULL;
6731242 }
674
-EXPORT_SYMBOL(cfg80211_find_ie_match);
1243
+EXPORT_SYMBOL(cfg80211_find_elem_match);
6751244
676
-const u8 *cfg80211_find_vendor_ie(unsigned int oui, int oui_type,
677
- const u8 *ies, int len)
1245
+const struct element *cfg80211_find_vendor_elem(unsigned int oui, int oui_type,
1246
+ const u8 *ies,
1247
+ unsigned int len)
6781248 {
679
- const u8 *ie;
1249
+ const struct element *elem;
6801250 u8 match[] = { oui >> 16, oui >> 8, oui, oui_type };
6811251 int match_len = (oui_type < 0) ? 3 : sizeof(match);
6821252
6831253 if (WARN_ON(oui_type > 0xff))
6841254 return NULL;
6851255
686
- ie = cfg80211_find_ie_match(WLAN_EID_VENDOR_SPECIFIC, ies, len,
687
- match, match_len, 2);
1256
+ elem = cfg80211_find_elem_match(WLAN_EID_VENDOR_SPECIFIC, ies, len,
1257
+ match, match_len, 0);
6881258
689
- if (ie && (ie[1] < 4))
1259
+ if (!elem || elem->datalen < 4)
6901260 return NULL;
6911261
692
- return ie;
1262
+ return elem;
6931263 }
694
-EXPORT_SYMBOL(cfg80211_find_vendor_ie);
1264
+EXPORT_SYMBOL(cfg80211_find_vendor_elem);
6951265
6961266 /**
6971267 * enum bss_compare_mode - BSS compare mode
....@@ -1033,6 +1603,102 @@
10331603 u8 bssid_index;
10341604 };
10351605
1606
+static void cfg80211_update_hidden_bsses(struct cfg80211_internal_bss *known,
1607
+ const struct cfg80211_bss_ies *new_ies,
1608
+ const struct cfg80211_bss_ies *old_ies)
1609
+{
1610
+ struct cfg80211_internal_bss *bss;
1611
+
1612
+ /* Assign beacon IEs to all sub entries */
1613
+ list_for_each_entry(bss, &known->hidden_list, hidden_list) {
1614
+ const struct cfg80211_bss_ies *ies;
1615
+
1616
+ ies = rcu_access_pointer(bss->pub.beacon_ies);
1617
+ WARN_ON(ies != old_ies);
1618
+
1619
+ rcu_assign_pointer(bss->pub.beacon_ies, new_ies);
1620
+ }
1621
+}
1622
+
1623
+static bool
1624
+cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
1625
+ struct cfg80211_internal_bss *known,
1626
+ struct cfg80211_internal_bss *new,
1627
+ bool signal_valid)
1628
+{
1629
+ lockdep_assert_held(&rdev->bss_lock);
1630
+
1631
+ /* Update IEs */
1632
+ if (rcu_access_pointer(new->pub.proberesp_ies)) {
1633
+ const struct cfg80211_bss_ies *old;
1634
+
1635
+ old = rcu_access_pointer(known->pub.proberesp_ies);
1636
+
1637
+ rcu_assign_pointer(known->pub.proberesp_ies,
1638
+ new->pub.proberesp_ies);
1639
+ /* Override possible earlier Beacon frame IEs */
1640
+ rcu_assign_pointer(known->pub.ies,
1641
+ new->pub.proberesp_ies);
1642
+ if (old)
1643
+ kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
1644
+ } else if (rcu_access_pointer(new->pub.beacon_ies)) {
1645
+ const struct cfg80211_bss_ies *old;
1646
+
1647
+ if (known->pub.hidden_beacon_bss &&
1648
+ !list_empty(&known->hidden_list)) {
1649
+ const struct cfg80211_bss_ies *f;
1650
+
1651
+ /* The known BSS struct is one of the probe
1652
+ * response members of a group, but we're
1653
+ * receiving a beacon (beacon_ies in the new
1654
+ * bss is used). This can only mean that the
1655
+ * AP changed its beacon from not having an
1656
+ * SSID to showing it, which is confusing so
1657
+ * drop this information.
1658
+ */
1659
+
1660
+ f = rcu_access_pointer(new->pub.beacon_ies);
1661
+ kfree_rcu((struct cfg80211_bss_ies *)f, rcu_head);
1662
+ return false;
1663
+ }
1664
+
1665
+ old = rcu_access_pointer(known->pub.beacon_ies);
1666
+
1667
+ rcu_assign_pointer(known->pub.beacon_ies, new->pub.beacon_ies);
1668
+
1669
+ /* Override IEs if they were from a beacon before */
1670
+ if (old == rcu_access_pointer(known->pub.ies))
1671
+ rcu_assign_pointer(known->pub.ies, new->pub.beacon_ies);
1672
+
1673
+ cfg80211_update_hidden_bsses(known,
1674
+ rcu_access_pointer(new->pub.beacon_ies),
1675
+ old);
1676
+
1677
+ if (old)
1678
+ kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
1679
+ }
1680
+
1681
+ known->pub.beacon_interval = new->pub.beacon_interval;
1682
+
1683
+ /* don't update the signal if beacon was heard on
1684
+ * adjacent channel.
1685
+ */
1686
+ if (signal_valid)
1687
+ known->pub.signal = new->pub.signal;
1688
+ known->pub.capability = new->pub.capability;
1689
+ known->ts = new->ts;
1690
+ known->ts_boottime = new->ts_boottime;
1691
+ known->parent_tsf = new->parent_tsf;
1692
+ known->pub.chains = new->pub.chains;
1693
+ memcpy(known->pub.chain_signal, new->pub.chain_signal,
1694
+ IEEE80211_MAX_CHAINS);
1695
+ ether_addr_copy(known->parent_bssid, new->parent_bssid);
1696
+ known->pub.max_bssid_indicator = new->pub.max_bssid_indicator;
1697
+ known->pub.bssid_index = new->pub.bssid_index;
1698
+
1699
+ return true;
1700
+}
1701
+
10361702 /* Returned bss is reference counted and must be cleaned up appropriately. */
10371703 struct cfg80211_internal_bss *
10381704 cfg80211_bss_update(struct cfg80211_registered_device *rdev,
....@@ -1056,88 +1722,8 @@
10561722 found = rb_find_bss(rdev, tmp, BSS_CMP_REGULAR);
10571723
10581724 if (found) {
1059
- /* Update IEs */
1060
- if (rcu_access_pointer(tmp->pub.proberesp_ies)) {
1061
- const struct cfg80211_bss_ies *old;
1062
-
1063
- old = rcu_access_pointer(found->pub.proberesp_ies);
1064
-
1065
- rcu_assign_pointer(found->pub.proberesp_ies,
1066
- tmp->pub.proberesp_ies);
1067
- /* Override possible earlier Beacon frame IEs */
1068
- rcu_assign_pointer(found->pub.ies,
1069
- tmp->pub.proberesp_ies);
1070
- if (old)
1071
- kfree_rcu((struct cfg80211_bss_ies *)old,
1072
- rcu_head);
1073
- } else if (rcu_access_pointer(tmp->pub.beacon_ies)) {
1074
- const struct cfg80211_bss_ies *old;
1075
- struct cfg80211_internal_bss *bss;
1076
-
1077
- if (found->pub.hidden_beacon_bss &&
1078
- !list_empty(&found->hidden_list)) {
1079
- const struct cfg80211_bss_ies *f;
1080
-
1081
- /*
1082
- * The found BSS struct is one of the probe
1083
- * response members of a group, but we're
1084
- * receiving a beacon (beacon_ies in the tmp
1085
- * bss is used). This can only mean that the
1086
- * AP changed its beacon from not having an
1087
- * SSID to showing it, which is confusing so
1088
- * drop this information.
1089
- */
1090
-
1091
- f = rcu_access_pointer(tmp->pub.beacon_ies);
1092
- kfree_rcu((struct cfg80211_bss_ies *)f,
1093
- rcu_head);
1094
- goto drop;
1095
- }
1096
-
1097
- old = rcu_access_pointer(found->pub.beacon_ies);
1098
-
1099
- rcu_assign_pointer(found->pub.beacon_ies,
1100
- tmp->pub.beacon_ies);
1101
-
1102
- /* Override IEs if they were from a beacon before */
1103
- if (old == rcu_access_pointer(found->pub.ies))
1104
- rcu_assign_pointer(found->pub.ies,
1105
- tmp->pub.beacon_ies);
1106
-
1107
- /* Assign beacon IEs to all sub entries */
1108
- list_for_each_entry(bss, &found->hidden_list,
1109
- hidden_list) {
1110
- const struct cfg80211_bss_ies *ies;
1111
-
1112
- ies = rcu_access_pointer(bss->pub.beacon_ies);
1113
- WARN_ON(ies != old);
1114
-
1115
- rcu_assign_pointer(bss->pub.beacon_ies,
1116
- tmp->pub.beacon_ies);
1117
- }
1118
-
1119
- if (old)
1120
- kfree_rcu((struct cfg80211_bss_ies *)old,
1121
- rcu_head);
1122
- }
1123
-
1124
- found->pub.beacon_interval = tmp->pub.beacon_interval;
1125
- /*
1126
- * don't update the signal if beacon was heard on
1127
- * adjacent channel.
1128
- */
1129
- if (signal_valid)
1130
- found->pub.signal = tmp->pub.signal;
1131
- found->pub.capability = tmp->pub.capability;
1132
- found->ts = tmp->ts;
1133
- found->ts_boottime = tmp->ts_boottime;
1134
- found->parent_tsf = tmp->parent_tsf;
1135
- found->pub.chains = tmp->pub.chains;
1136
- memcpy(found->pub.chain_signal, tmp->pub.chain_signal,
1137
- IEEE80211_MAX_CHAINS);
1138
- ether_addr_copy(found->parent_bssid, tmp->parent_bssid);
1139
- found->pub.max_bssid_indicator = tmp->pub.max_bssid_indicator;
1140
- found->pub.bssid_index = tmp->pub.bssid_index;
1725
+ if (!cfg80211_update_known_bss(rdev, found, tmp, signal_valid))
1726
+ goto drop;
11411727 } else {
11421728 struct cfg80211_internal_bss *new;
11431729 struct cfg80211_internal_bss *hidden;
....@@ -1163,6 +1749,8 @@
11631749 new->refcount = 1;
11641750 INIT_LIST_HEAD(&new->hidden_list);
11651751 INIT_LIST_HEAD(&new->pub.nontrans_list);
1752
+ /* we'll set this later if it was non-NULL */
1753
+ new->pub.transmitted_bss = NULL;
11661754
11671755 if (rcu_access_pointer(tmp->pub.proberesp_ies)) {
11681756 hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN);
....@@ -1241,15 +1829,24 @@
12411829 int channel_number = -1;
12421830 struct ieee80211_channel *alt_channel;
12431831
1244
- tmp = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ie, ielen);
1245
- if (tmp && tmp[1] == 1) {
1246
- channel_number = tmp[2];
1247
- } else {
1248
- tmp = cfg80211_find_ie(WLAN_EID_HT_OPERATION, ie, ielen);
1249
- if (tmp && tmp[1] >= sizeof(struct ieee80211_ht_operation)) {
1250
- struct ieee80211_ht_operation *htop = (void *)(tmp + 2);
1832
+ if (channel->band == NL80211_BAND_S1GHZ) {
1833
+ tmp = cfg80211_find_ie(WLAN_EID_S1G_OPERATION, ie, ielen);
1834
+ if (tmp && tmp[1] >= sizeof(struct ieee80211_s1g_oper_ie)) {
1835
+ struct ieee80211_s1g_oper_ie *s1gop = (void *)(tmp + 2);
12511836
1252
- channel_number = htop->primary_chan;
1837
+ channel_number = s1gop->primary_ch;
1838
+ }
1839
+ } else {
1840
+ tmp = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ie, ielen);
1841
+ if (tmp && tmp[1] == 1) {
1842
+ channel_number = tmp[2];
1843
+ } else {
1844
+ tmp = cfg80211_find_ie(WLAN_EID_HT_OPERATION, ie, ielen);
1845
+ if (tmp && tmp[1] >= sizeof(struct ieee80211_ht_operation)) {
1846
+ struct ieee80211_ht_operation *htop = (void *)(tmp + 2);
1847
+
1848
+ channel_number = htop->primary_chan;
1849
+ }
12531850 }
12541851 }
12551852
....@@ -1258,8 +1855,8 @@
12581855 return channel;
12591856 }
12601857
1261
- freq = ieee80211_channel_to_frequency(channel_number, channel->band);
1262
- alt_channel = ieee80211_get_channel(wiphy, freq);
1858
+ freq = ieee80211_channel_to_freq_khz(channel_number, channel->band);
1859
+ alt_channel = ieee80211_get_channel_khz(wiphy, freq);
12631860 if (!alt_channel) {
12641861 if (channel->band == NL80211_BAND_2GHZ) {
12651862 /*
....@@ -1310,6 +1907,7 @@
13101907 struct cfg80211_internal_bss tmp = {}, *res;
13111908 int bss_type;
13121909 bool signal_valid;
1910
+ unsigned long ts;
13131911
13141912 if (WARN_ON(!wiphy))
13151913 return NULL;
....@@ -1332,8 +1930,11 @@
13321930 tmp.ts_boottime = data->boottime_ns;
13331931 if (non_tx_data) {
13341932 tmp.pub.transmitted_bss = non_tx_data->tx_bss;
1933
+ ts = bss_from_pub(non_tx_data->tx_bss)->ts;
13351934 tmp.pub.bssid_index = non_tx_data->bssid_index;
13361935 tmp.pub.max_bssid_indicator = non_tx_data->max_bssid_indicator;
1936
+ } else {
1937
+ ts = jiffies;
13371938 }
13381939
13391940 /*
....@@ -1355,7 +1956,7 @@
13551956 switch (ftype) {
13561957 case CFG80211_BSS_FTYPE_BEACON:
13571958 ies->from_beacon = true;
1358
- /* fall through to assign */
1959
+ fallthrough;
13591960 case CFG80211_BSS_FTYPE_UNKNOWN:
13601961 rcu_assign_pointer(tmp.pub.beacon_ies, ies);
13611962 break;
....@@ -1365,10 +1966,8 @@
13651966 }
13661967 rcu_assign_pointer(tmp.pub.ies, ies);
13671968
1368
- signal_valid = abs(data->chan->center_freq - channel->center_freq) <=
1369
- wiphy->max_adj_channel_rssi_comp;
1370
- res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid,
1371
- jiffies);
1969
+ signal_valid = data->chan == channel;
1970
+ res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid, ts);
13721971 if (!res)
13731972 return NULL;
13741973
....@@ -1382,21 +1981,100 @@
13821981 regulatory_hint_found_beacon(wiphy, channel, gfp);
13831982 }
13841983
1385
- if (non_tx_data && non_tx_data->tx_bss) {
1984
+ if (non_tx_data) {
13861985 /* this is a nontransmitting bss, we need to add it to
13871986 * transmitting bss' list if it is not there
13881987 */
1988
+ spin_lock_bh(&rdev->bss_lock);
13891989 if (cfg80211_add_nontrans_list(non_tx_data->tx_bss,
13901990 &res->pub)) {
1391
- if (__cfg80211_unlink_bss(rdev, res))
1991
+ if (__cfg80211_unlink_bss(rdev, res)) {
13921992 rdev->bss_generation++;
1993
+ res = NULL;
1994
+ }
13931995 }
1996
+ spin_unlock_bh(&rdev->bss_lock);
1997
+
1998
+ if (!res)
1999
+ return NULL;
13942000 }
13952001
13962002 trace_cfg80211_return_bss(&res->pub);
13972003 /* cfg80211_bss_update gives us a referenced result */
13982004 return &res->pub;
13992005 }
2006
+
2007
+static const struct element
2008
+*cfg80211_get_profile_continuation(const u8 *ie, size_t ielen,
2009
+ const struct element *mbssid_elem,
2010
+ const struct element *sub_elem)
2011
+{
2012
+ const u8 *mbssid_end = mbssid_elem->data + mbssid_elem->datalen;
2013
+ const struct element *next_mbssid;
2014
+ const struct element *next_sub;
2015
+
2016
+ next_mbssid = cfg80211_find_elem(WLAN_EID_MULTIPLE_BSSID,
2017
+ mbssid_end,
2018
+ ielen - (mbssid_end - ie));
2019
+
2020
+ /*
2021
+ * If it is not the last subelement in current MBSSID IE or there isn't
2022
+ * a next MBSSID IE - profile is complete.
2023
+ */
2024
+ if ((sub_elem->data + sub_elem->datalen < mbssid_end - 1) ||
2025
+ !next_mbssid)
2026
+ return NULL;
2027
+
2028
+ /* For any length error, just return NULL */
2029
+
2030
+ if (next_mbssid->datalen < 4)
2031
+ return NULL;
2032
+
2033
+ next_sub = (void *)&next_mbssid->data[1];
2034
+
2035
+ if (next_mbssid->data + next_mbssid->datalen <
2036
+ next_sub->data + next_sub->datalen)
2037
+ return NULL;
2038
+
2039
+ if (next_sub->id != 0 || next_sub->datalen < 2)
2040
+ return NULL;
2041
+
2042
+ /*
2043
+ * Check if the first element in the next sub element is a start
2044
+ * of a new profile
2045
+ */
2046
+ return next_sub->data[0] == WLAN_EID_NON_TX_BSSID_CAP ?
2047
+ NULL : next_mbssid;
2048
+}
2049
+
2050
+size_t cfg80211_merge_profile(const u8 *ie, size_t ielen,
2051
+ const struct element *mbssid_elem,
2052
+ const struct element *sub_elem,
2053
+ u8 *merged_ie, size_t max_copy_len)
2054
+{
2055
+ size_t copied_len = sub_elem->datalen;
2056
+ const struct element *next_mbssid;
2057
+
2058
+ if (sub_elem->datalen > max_copy_len)
2059
+ return 0;
2060
+
2061
+ memcpy(merged_ie, sub_elem->data, sub_elem->datalen);
2062
+
2063
+ while ((next_mbssid = cfg80211_get_profile_continuation(ie, ielen,
2064
+ mbssid_elem,
2065
+ sub_elem))) {
2066
+ const struct element *next_sub = (void *)&next_mbssid->data[1];
2067
+
2068
+ if (copied_len + next_sub->datalen > max_copy_len)
2069
+ break;
2070
+ memcpy(merged_ie + copied_len, next_sub->data,
2071
+ next_sub->datalen);
2072
+ copied_len += next_sub->datalen;
2073
+ }
2074
+
2075
+ return copied_len;
2076
+}
2077
+EXPORT_SYMBOL(cfg80211_merge_profile);
14002078
14012079 static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
14022080 struct cfg80211_inform_bss *data,
....@@ -1411,7 +2089,8 @@
14112089 const struct element *elem, *sub;
14122090 size_t new_ie_len;
14132091 u8 new_bssid[ETH_ALEN];
1414
- u8 *new_ie;
2092
+ u8 *new_ie, *profile;
2093
+ u64 seen_indices = 0;
14152094 u16 capability;
14162095 struct cfg80211_bss *bss;
14172096
....@@ -1429,10 +2108,18 @@
14292108 if (!new_ie)
14302109 return;
14312110
2111
+ profile = kmalloc(ielen, gfp);
2112
+ if (!profile)
2113
+ goto out;
2114
+
14322115 for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, ie, ielen) {
14332116 if (elem->datalen < 4)
14342117 continue;
2118
+ if (elem->data[0] < 1 || (int)elem->data[0] > 8)
2119
+ continue;
14352120 for_each_element(sub, elem->data + 1, elem->datalen - 1) {
2121
+ u8 profile_len;
2122
+
14362123 if (sub->id != 0 || sub->datalen < 4) {
14372124 /* not a valid BSS profile */
14382125 continue;
....@@ -1447,15 +2134,30 @@
14472134 continue;
14482135 }
14492136
2137
+ memset(profile, 0, ielen);
2138
+ profile_len = cfg80211_merge_profile(ie, ielen,
2139
+ elem,
2140
+ sub,
2141
+ profile,
2142
+ ielen);
2143
+
14502144 /* found a Nontransmitted BSSID Profile */
14512145 mbssid_index_ie = cfg80211_find_ie
14522146 (WLAN_EID_MULTI_BSSID_IDX,
1453
- sub->data, sub->datalen);
2147
+ profile, profile_len);
14542148 if (!mbssid_index_ie || mbssid_index_ie[1] < 1 ||
1455
- mbssid_index_ie[2] == 0) {
2149
+ mbssid_index_ie[2] == 0 ||
2150
+ mbssid_index_ie[2] > 46) {
14562151 /* No valid Multiple BSSID-Index element */
14572152 continue;
14582153 }
2154
+
2155
+ if (seen_indices & BIT_ULL(mbssid_index_ie[2]))
2156
+ /* We don't support legacy split of a profile */
2157
+ net_dbg_ratelimited("Partial info for BSSID index %d\n",
2158
+ mbssid_index_ie[2]);
2159
+
2160
+ seen_indices |= BIT_ULL(mbssid_index_ie[2]);
14592161
14602162 non_tx_data->bssid_index = mbssid_index_ie[2];
14612163 non_tx_data->max_bssid_indicator = elem->data[0];
....@@ -1465,13 +2167,14 @@
14652167 non_tx_data->bssid_index,
14662168 new_bssid);
14672169 memset(new_ie, 0, IEEE80211_MAX_DATA_LEN);
1468
- new_ie_len = cfg80211_gen_new_ie(ie, ielen, sub->data,
1469
- sub->datalen, new_ie,
2170
+ new_ie_len = cfg80211_gen_new_ie(ie, ielen,
2171
+ profile,
2172
+ profile_len, new_ie,
14702173 gfp);
14712174 if (!new_ie_len)
14722175 continue;
14732176
1474
- capability = get_unaligned_le16(sub->data + 2);
2177
+ capability = get_unaligned_le16(profile + 2);
14752178 bss = cfg80211_inform_single_bss_data(wiphy, data,
14762179 ftype,
14772180 new_bssid, tsf,
....@@ -1487,7 +2190,9 @@
14872190 }
14882191 }
14892192
2193
+out:
14902194 kfree(new_ie);
2195
+ kfree(profile);
14912196 }
14922197
14932198 struct cfg80211_bss *
....@@ -1504,6 +2209,8 @@
15042209 res = cfg80211_inform_single_bss_data(wiphy, data, ftype, bssid, tsf,
15052210 capability, beacon_interval, ie,
15062211 ielen, NULL, gfp);
2212
+ if (!res)
2213
+ return NULL;
15072214 non_tx_data.tx_bss = res;
15082215 cfg80211_parse_mbssid_data(wiphy, data, ftype, bssid, tsf,
15092216 beacon_interval, ie, ielen, &non_tx_data,
....@@ -1536,8 +2243,7 @@
15362243 static void
15372244 cfg80211_update_notlisted_nontrans(struct wiphy *wiphy,
15382245 struct cfg80211_bss *nontrans_bss,
1539
- struct ieee80211_mgmt *mgmt, size_t len,
1540
- gfp_t gfp)
2246
+ struct ieee80211_mgmt *mgmt, size_t len)
15412247 {
15422248 u8 *ie, *new_ie, *pos;
15432249 const u8 *nontrans_ssid, *trans_ssid, *mbssid;
....@@ -1546,7 +2252,9 @@
15462252 size_t new_ie_len;
15472253 struct cfg80211_bss_ies *new_ies;
15482254 const struct cfg80211_bss_ies *old;
1549
- u8 cpy_len;
2255
+ size_t cpy_len;
2256
+
2257
+ lockdep_assert_held(&wiphy_to_rdev(wiphy)->bss_lock);
15502258
15512259 ie = mgmt->u.probe_resp.variable;
15522260
....@@ -1564,27 +2272,24 @@
15642272 if (!mbssid || mbssid < trans_ssid)
15652273 return;
15662274 new_ie_len -= mbssid[1];
1567
- rcu_read_lock();
2275
+
15682276 nontrans_ssid = ieee80211_bss_get_ie(nontrans_bss, WLAN_EID_SSID);
1569
- if (!nontrans_ssid) {
1570
- rcu_read_unlock();
2277
+ if (!nontrans_ssid)
15712278 return;
1572
- }
2279
+
15732280 new_ie_len += nontrans_ssid[1];
1574
- rcu_read_unlock();
15752281
15762282 /* generate new ie for nontrans BSS
15772283 * 1. replace SSID with nontrans BSS' SSID
15782284 * 2. skip MBSSID IE
15792285 */
1580
- new_ie = kzalloc(new_ie_len, gfp);
2286
+ new_ie = kzalloc(new_ie_len, GFP_ATOMIC);
15812287 if (!new_ie)
15822288 return;
1583
- new_ies = kzalloc(sizeof(*new_ies) + new_ie_len, gfp);
1584
- if (!new_ies) {
1585
- kfree(new_ie);
1586
- return;
1587
- }
2289
+
2290
+ new_ies = kzalloc(sizeof(*new_ies) + new_ie_len, GFP_ATOMIC);
2291
+ if (!new_ies)
2292
+ goto out_free;
15882293
15892294 pos = new_ie;
15902295
....@@ -1614,10 +2319,15 @@
16142319 } else {
16152320 old = rcu_access_pointer(nontrans_bss->beacon_ies);
16162321 rcu_assign_pointer(nontrans_bss->beacon_ies, new_ies);
2322
+ cfg80211_update_hidden_bsses(bss_from_pub(nontrans_bss),
2323
+ new_ies, old);
16172324 rcu_assign_pointer(nontrans_bss->ies, new_ies);
16182325 if (old)
16192326 kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
16202327 }
2328
+
2329
+out_free:
2330
+ kfree(new_ie);
16212331 }
16222332
16232333 /* cfg80211_inform_bss_width_frame helper */
....@@ -1625,15 +2335,17 @@
16252335 cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
16262336 struct cfg80211_inform_bss *data,
16272337 struct ieee80211_mgmt *mgmt, size_t len,
1628
- struct cfg80211_non_tx_bss *non_tx_data,
16292338 gfp_t gfp)
16302339 {
16312340 struct cfg80211_internal_bss tmp = {}, *res;
16322341 struct cfg80211_bss_ies *ies;
16332342 struct ieee80211_channel *channel;
16342343 bool signal_valid;
1635
- size_t ielen = len - offsetof(struct ieee80211_mgmt,
1636
- u.probe_resp.variable);
2344
+ struct ieee80211_ext *ext = NULL;
2345
+ u8 *bssid, *variable;
2346
+ u16 capability, beacon_int;
2347
+ size_t ielen, min_hdr_len = offsetof(struct ieee80211_mgmt,
2348
+ u.probe_resp.variable);
16372349 int bss_type;
16382350
16392351 BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=
....@@ -1651,21 +2363,59 @@
16512363 (data->signal < 0 || data->signal > 100)))
16522364 return NULL;
16532365
1654
- if (WARN_ON(len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable)))
2366
+ if (ieee80211_is_s1g_beacon(mgmt->frame_control)) {
2367
+ ext = (void *) mgmt;
2368
+ min_hdr_len = offsetof(struct ieee80211_ext, u.s1g_beacon);
2369
+ if (ieee80211_is_s1g_short_beacon(mgmt->frame_control))
2370
+ min_hdr_len = offsetof(struct ieee80211_ext,
2371
+ u.s1g_short_beacon.variable);
2372
+ }
2373
+
2374
+ if (WARN_ON(len < min_hdr_len))
16552375 return NULL;
16562376
1657
- channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable,
2377
+ ielen = len - min_hdr_len;
2378
+ variable = mgmt->u.probe_resp.variable;
2379
+ if (ext) {
2380
+ if (ieee80211_is_s1g_short_beacon(mgmt->frame_control))
2381
+ variable = ext->u.s1g_short_beacon.variable;
2382
+ else
2383
+ variable = ext->u.s1g_beacon.variable;
2384
+ }
2385
+
2386
+ channel = cfg80211_get_bss_channel(wiphy, variable,
16582387 ielen, data->chan, data->scan_width);
16592388 if (!channel)
16602389 return NULL;
2390
+
2391
+ if (ext) {
2392
+ const struct ieee80211_s1g_bcn_compat_ie *compat;
2393
+ const struct element *elem;
2394
+
2395
+ elem = cfg80211_find_elem(WLAN_EID_S1G_BCN_COMPAT,
2396
+ variable, ielen);
2397
+ if (!elem)
2398
+ return NULL;
2399
+ if (elem->datalen < sizeof(*compat))
2400
+ return NULL;
2401
+ compat = (void *)elem->data;
2402
+ bssid = ext->u.s1g_beacon.sa;
2403
+ capability = le16_to_cpu(compat->compat_info);
2404
+ beacon_int = le16_to_cpu(compat->beacon_int);
2405
+ } else {
2406
+ bssid = mgmt->bssid;
2407
+ beacon_int = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
2408
+ capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
2409
+ }
16612410
16622411 ies = kzalloc(sizeof(*ies) + ielen, gfp);
16632412 if (!ies)
16642413 return NULL;
16652414 ies->len = ielen;
16662415 ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
1667
- ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control);
1668
- memcpy(ies->data, mgmt->u.probe_resp.variable, ielen);
2416
+ ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control) ||
2417
+ ieee80211_is_s1g_beacon(mgmt->frame_control);
2418
+ memcpy(ies->data, variable, ielen);
16692419
16702420 if (ieee80211_is_probe_resp(mgmt->frame_control))
16712421 rcu_assign_pointer(tmp.pub.proberesp_ies, ies);
....@@ -1673,25 +2423,19 @@
16732423 rcu_assign_pointer(tmp.pub.beacon_ies, ies);
16742424 rcu_assign_pointer(tmp.pub.ies, ies);
16752425
1676
- memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN);
2426
+ memcpy(tmp.pub.bssid, bssid, ETH_ALEN);
2427
+ tmp.pub.beacon_interval = beacon_int;
2428
+ tmp.pub.capability = capability;
16772429 tmp.pub.channel = channel;
16782430 tmp.pub.scan_width = data->scan_width;
16792431 tmp.pub.signal = data->signal;
1680
- tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
1681
- tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
16822432 tmp.ts_boottime = data->boottime_ns;
16832433 tmp.parent_tsf = data->parent_tsf;
16842434 tmp.pub.chains = data->chains;
16852435 memcpy(tmp.pub.chain_signal, data->chain_signal, IEEE80211_MAX_CHAINS);
16862436 ether_addr_copy(tmp.parent_bssid, data->parent_bssid);
1687
- if (non_tx_data) {
1688
- tmp.pub.transmitted_bss = non_tx_data->tx_bss;
1689
- tmp.pub.bssid_index = non_tx_data->bssid_index;
1690
- tmp.pub.max_bssid_indicator = non_tx_data->max_bssid_indicator;
1691
- }
16922437
1693
- signal_valid = abs(data->chan->center_freq - channel->center_freq) <=
1694
- wiphy->max_adj_channel_rssi_comp;
2438
+ signal_valid = data->chan == channel;
16952439 res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid,
16962440 jiffies);
16972441 if (!res)
....@@ -1723,10 +2467,15 @@
17232467 const struct cfg80211_bss_ies *ies1, *ies2;
17242468 size_t ielen = len - offsetof(struct ieee80211_mgmt,
17252469 u.probe_resp.variable);
1726
- struct cfg80211_non_tx_bss non_tx_data;
2470
+ struct cfg80211_non_tx_bss non_tx_data = {};
17272471
17282472 res = cfg80211_inform_single_bss_frame_data(wiphy, data, mgmt,
1729
- len, NULL, gfp);
2473
+ len, gfp);
2474
+
2475
+ /* don't do any further MBSSID handling for S1G */
2476
+ if (ieee80211_is_s1g_beacon(mgmt->frame_control))
2477
+ return res;
2478
+
17302479 if (!res || !wiphy->support_mbssid ||
17312480 !cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen))
17322481 return res;
....@@ -1738,6 +2487,8 @@
17382487 /* process each non-transmitting bss */
17392488 cfg80211_parse_mbssid_frame_data(wiphy, data, mgmt, len,
17402489 &non_tx_data, gfp);
2490
+
2491
+ spin_lock_bh(&wiphy_to_rdev(wiphy)->bss_lock);
17412492
17422493 /* check if the res has other nontransmitting bss which is not
17432494 * in MBSSID IE
....@@ -1753,8 +2504,9 @@
17532504 ies2 = rcu_access_pointer(tmp_bss->ies);
17542505 if (ies2->tsf < ies1->tsf)
17552506 cfg80211_update_notlisted_nontrans(wiphy, tmp_bss,
1756
- mgmt, len, gfp);
2507
+ mgmt, len);
17572508 }
2509
+ spin_unlock_bh(&wiphy_to_rdev(wiphy)->bss_lock);
17582510
17592511 return res;
17602512 }
....@@ -1823,6 +2575,110 @@
18232575 }
18242576 EXPORT_SYMBOL(cfg80211_unlink_bss);
18252577
2578
+void cfg80211_bss_iter(struct wiphy *wiphy,
2579
+ struct cfg80211_chan_def *chandef,
2580
+ void (*iter)(struct wiphy *wiphy,
2581
+ struct cfg80211_bss *bss,
2582
+ void *data),
2583
+ void *iter_data)
2584
+{
2585
+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
2586
+ struct cfg80211_internal_bss *bss;
2587
+
2588
+ spin_lock_bh(&rdev->bss_lock);
2589
+
2590
+ list_for_each_entry(bss, &rdev->bss_list, list) {
2591
+ if (!chandef || cfg80211_is_sub_chan(chandef, bss->pub.channel))
2592
+ iter(wiphy, &bss->pub, iter_data);
2593
+ }
2594
+
2595
+ spin_unlock_bh(&rdev->bss_lock);
2596
+}
2597
+EXPORT_SYMBOL(cfg80211_bss_iter);
2598
+
2599
+void cfg80211_update_assoc_bss_entry(struct wireless_dev *wdev,
2600
+ struct ieee80211_channel *chan)
2601
+{
2602
+ struct wiphy *wiphy = wdev->wiphy;
2603
+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
2604
+ struct cfg80211_internal_bss *cbss = wdev->current_bss;
2605
+ struct cfg80211_internal_bss *new = NULL;
2606
+ struct cfg80211_internal_bss *bss;
2607
+ struct cfg80211_bss *nontrans_bss;
2608
+ struct cfg80211_bss *tmp;
2609
+
2610
+ spin_lock_bh(&rdev->bss_lock);
2611
+
2612
+ /*
2613
+ * Some APs use CSA also for bandwidth changes, i.e., without actually
2614
+ * changing the control channel, so no need to update in such a case.
2615
+ */
2616
+ if (cbss->pub.channel == chan)
2617
+ goto done;
2618
+
2619
+ /* use transmitting bss */
2620
+ if (cbss->pub.transmitted_bss)
2621
+ cbss = container_of(cbss->pub.transmitted_bss,
2622
+ struct cfg80211_internal_bss,
2623
+ pub);
2624
+
2625
+ cbss->pub.channel = chan;
2626
+
2627
+ list_for_each_entry(bss, &rdev->bss_list, list) {
2628
+ if (!cfg80211_bss_type_match(bss->pub.capability,
2629
+ bss->pub.channel->band,
2630
+ wdev->conn_bss_type))
2631
+ continue;
2632
+
2633
+ if (bss == cbss)
2634
+ continue;
2635
+
2636
+ if (!cmp_bss(&bss->pub, &cbss->pub, BSS_CMP_REGULAR)) {
2637
+ new = bss;
2638
+ break;
2639
+ }
2640
+ }
2641
+
2642
+ if (new) {
2643
+ /* to save time, update IEs for transmitting bss only */
2644
+ if (cfg80211_update_known_bss(rdev, cbss, new, false)) {
2645
+ new->pub.proberesp_ies = NULL;
2646
+ new->pub.beacon_ies = NULL;
2647
+ }
2648
+
2649
+ list_for_each_entry_safe(nontrans_bss, tmp,
2650
+ &new->pub.nontrans_list,
2651
+ nontrans_list) {
2652
+ bss = container_of(nontrans_bss,
2653
+ struct cfg80211_internal_bss, pub);
2654
+ if (__cfg80211_unlink_bss(rdev, bss))
2655
+ rdev->bss_generation++;
2656
+ }
2657
+
2658
+ WARN_ON(atomic_read(&new->hold));
2659
+ if (!WARN_ON(!__cfg80211_unlink_bss(rdev, new)))
2660
+ rdev->bss_generation++;
2661
+ }
2662
+
2663
+ rb_erase(&cbss->rbn, &rdev->bss_tree);
2664
+ rb_insert_bss(rdev, cbss);
2665
+ rdev->bss_generation++;
2666
+
2667
+ list_for_each_entry_safe(nontrans_bss, tmp,
2668
+ &cbss->pub.nontrans_list,
2669
+ nontrans_list) {
2670
+ bss = container_of(nontrans_bss,
2671
+ struct cfg80211_internal_bss, pub);
2672
+ bss->pub.channel = chan;
2673
+ rb_erase(&bss->rbn, &rdev->bss_tree);
2674
+ rb_insert_bss(rdev, bss);
2675
+ rdev->bss_generation++;
2676
+ }
2677
+
2678
+done:
2679
+ spin_unlock_bh(&rdev->bss_lock);
2680
+}
2681
+
18262682 #ifdef CONFIG_CFG80211_WEXT
18272683 static struct cfg80211_registered_device *
18282684 cfg80211_get_dev_from_ifindex(struct net *net, int ifindex)