hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
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,101 +212,202 @@
179212 return true;
180213 }
181214
182
-static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
183
- const u8 *subelement, size_t subie_len,
184
- u8 *new_ie, gfp_t gfp)
215
+bool cfg80211_is_element_inherited(const struct element *elem,
216
+ const struct element *non_inherit_elem)
185217 {
186
- u8 *pos, *tmp;
187
- const u8 *tmp_old, *tmp_new;
188
- u8 *sub_copy;
218
+ u8 id_len, ext_id_len, i, loop_len, id;
219
+ const u8 *list;
189220
190
- /* copy subelement as we need to change its content to
191
- * mark an ie after it is processed.
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
192233 */
193
- sub_copy = kmalloc(subie_len, gfp);
194
- if (!sub_copy)
195
- return 0;
196
- memcpy(sub_copy, subelement, subie_len);
234
+ id_len = non_inherit_elem->data[1];
235
+ if (non_inherit_elem->datalen < 3 + id_len)
236
+ return true;
197237
198
- pos = &new_ie[0];
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;
199241
200
- /* set new ssid */
201
- tmp_new = cfg80211_find_ie(WLAN_EID_SSID, sub_copy, subie_len);
202
- if (tmp_new) {
203
- memcpy(pos, tmp_new, tmp_new[1] + 2);
204
- pos += (tmp_new[1] + 2);
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;
205254 }
206255
207
- /* go through IEs in ie (skip SSID) and subelement,
208
- * merge them into new_ie
209
- */
210
- tmp_old = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen);
211
- tmp_old = (tmp_old) ? tmp_old + tmp_old[1] + 2 : ie;
256
+ for (i = 0; i < loop_len; i++) {
257
+ if (list[i] == id)
258
+ return false;
259
+ }
212260
213
- while (tmp_old + tmp_old[1] + 2 - ie <= ielen) {
214
- if (tmp_old[0] == 0) {
215
- tmp_old++;
261
+ return true;
262
+}
263
+EXPORT_SYMBOL(cfg80211_is_element_inherited);
264
+
265
+static size_t cfg80211_copy_elem_with_frags(const struct element *elem,
266
+ const u8 *ie, size_t ie_len,
267
+ u8 **pos, u8 *buf, size_t buf_len)
268
+{
269
+ if (WARN_ON((u8 *)elem < ie || elem->data > ie + ie_len ||
270
+ elem->data + elem->datalen > ie + ie_len))
271
+ return 0;
272
+
273
+ if (elem->datalen + 2 > buf + buf_len - *pos)
274
+ return 0;
275
+
276
+ memcpy(*pos, elem, elem->datalen + 2);
277
+ *pos += elem->datalen + 2;
278
+
279
+ /* Finish if it is not fragmented */
280
+ if (elem->datalen != 255)
281
+ return *pos - buf;
282
+
283
+ ie_len = ie + ie_len - elem->data - elem->datalen;
284
+ ie = (const u8 *)elem->data + elem->datalen;
285
+
286
+ for_each_element(elem, ie, ie_len) {
287
+ if (elem->id != WLAN_EID_FRAGMENT)
288
+ break;
289
+
290
+ if (elem->datalen + 2 > buf + buf_len - *pos)
291
+ return 0;
292
+
293
+ memcpy(*pos, elem, elem->datalen + 2);
294
+ *pos += elem->datalen + 2;
295
+
296
+ if (elem->datalen != 255)
297
+ break;
298
+ }
299
+
300
+ return *pos - buf;
301
+}
302
+
303
+static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
304
+ const u8 *subie, size_t subie_len,
305
+ u8 *new_ie, size_t new_ie_len)
306
+{
307
+ const struct element *non_inherit_elem, *parent, *sub;
308
+ u8 *pos = new_ie;
309
+ u8 id, ext_id;
310
+ unsigned int match_len;
311
+
312
+ non_inherit_elem = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
313
+ subie, subie_len);
314
+
315
+ /* We copy the elements one by one from the parent to the generated
316
+ * elements.
317
+ * If they are not inherited (included in subie or in the non
318
+ * inheritance element), then we copy all occurrences the first time
319
+ * we see this element type.
320
+ */
321
+ for_each_element(parent, ie, ielen) {
322
+ if (parent->id == WLAN_EID_FRAGMENT)
323
+ continue;
324
+
325
+ if (parent->id == WLAN_EID_EXTENSION) {
326
+ if (parent->datalen < 1)
327
+ continue;
328
+
329
+ id = WLAN_EID_EXTENSION;
330
+ ext_id = parent->data[0];
331
+ match_len = 1;
332
+ } else {
333
+ id = parent->id;
334
+ match_len = 0;
335
+ }
336
+
337
+ /* Find first occurrence in subie */
338
+ sub = cfg80211_find_elem_match(id, subie, subie_len,
339
+ &ext_id, match_len, 0);
340
+
341
+ /* Copy from parent if not in subie and inherited */
342
+ if (!sub &&
343
+ cfg80211_is_element_inherited(parent, non_inherit_elem)) {
344
+ if (!cfg80211_copy_elem_with_frags(parent,
345
+ ie, ielen,
346
+ &pos, new_ie,
347
+ new_ie_len))
348
+ return 0;
349
+
216350 continue;
217351 }
218352
219
- tmp = (u8 *)cfg80211_find_ie(tmp_old[0], sub_copy, subie_len);
220
- if (!tmp) {
221
- /* ie in old ie but not in subelement */
222
- if (tmp_old[0] != WLAN_EID_MULTIPLE_BSSID) {
223
- memcpy(pos, tmp_old, tmp_old[1] + 2);
224
- pos += tmp_old[1] + 2;
225
- }
226
- } else {
227
- /* ie in transmitting ie also in subelement,
228
- * 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
231
- * determine if they are the same ie.
232
- */
233
- if (tmp_old[0] == WLAN_EID_VENDOR_SPECIFIC) {
234
- if (!memcmp(tmp_old + 2, tmp + 2, 5)) {
235
- /* same vendor ie, copy from
236
- * subelement
237
- */
238
- memcpy(pos, tmp, tmp[1] + 2);
239
- pos += tmp[1] + 2;
240
- tmp[0] = 0xff;
241
- } else {
242
- memcpy(pos, tmp_old, tmp_old[1] + 2);
243
- pos += tmp_old[1] + 2;
244
- }
245
- } else {
246
- /* copy ie from subelement into new ie */
247
- memcpy(pos, tmp, tmp[1] + 2);
248
- pos += tmp[1] + 2;
249
- tmp[0] = 0xff;
250
- }
353
+ /* Already copied if an earlier element had the same type */
354
+ if (cfg80211_find_elem_match(id, ie, (u8 *)parent - ie,
355
+ &ext_id, match_len, 0))
356
+ continue;
357
+
358
+ /* Not inheriting, copy all similar elements from subie */
359
+ while (sub) {
360
+ if (!cfg80211_copy_elem_with_frags(sub,
361
+ subie, subie_len,
362
+ &pos, new_ie,
363
+ new_ie_len))
364
+ return 0;
365
+
366
+ sub = cfg80211_find_elem_match(id,
367
+ sub->data + sub->datalen,
368
+ subie_len + subie -
369
+ (sub->data +
370
+ sub->datalen),
371
+ &ext_id, match_len, 0);
251372 }
252
-
253
- if (tmp_old + tmp_old[1] + 2 - ie == ielen)
254
- break;
255
-
256
- tmp_old += tmp_old[1] + 2;
257373 }
258374
259
- /* go through subelement again to check if there is any ie not
260
- * copied to new ie, skip ssid, capability, bssid-index ie
375
+ /* The above misses elements that are included in subie but not in the
376
+ * parent, so do a pass over subie and append those.
377
+ * Skip the non-tx BSSID caps and non-inheritance element.
261378 */
262
- tmp_new = sub_copy;
263
- while (tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
264
- 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)) {
268
- memcpy(pos, tmp_new, tmp_new[1] + 2);
269
- pos += tmp_new[1] + 2;
379
+ for_each_element(sub, subie, subie_len) {
380
+ if (sub->id == WLAN_EID_NON_TX_BSSID_CAP)
381
+ continue;
382
+
383
+ if (sub->id == WLAN_EID_FRAGMENT)
384
+ continue;
385
+
386
+ if (sub->id == WLAN_EID_EXTENSION) {
387
+ if (sub->datalen < 1)
388
+ continue;
389
+
390
+ id = WLAN_EID_EXTENSION;
391
+ ext_id = sub->data[0];
392
+ match_len = 1;
393
+
394
+ if (ext_id == WLAN_EID_EXT_NON_INHERITANCE)
395
+ continue;
396
+ } else {
397
+ id = sub->id;
398
+ match_len = 0;
270399 }
271
- if (tmp_new + tmp_new[1] + 2 - sub_copy == subie_len)
272
- break;
273
- tmp_new += tmp_new[1] + 2;
400
+
401
+ /* Processed if one was included in the parent */
402
+ if (cfg80211_find_elem_match(id, ie, ielen,
403
+ &ext_id, match_len, 0))
404
+ continue;
405
+
406
+ if (!cfg80211_copy_elem_with_frags(sub, subie, subie_len,
407
+ &pos, new_ie, new_ie_len))
408
+ return 0;
274409 }
275410
276
- kfree(sub_copy);
277411 return pos - new_ie;
278412 }
279413
....@@ -316,13 +450,25 @@
316450 }
317451 ssid_len = ssid[1];
318452 ssid = ssid + 2;
319
- rcu_read_unlock();
320453
321454 /* check if nontrans_bss is in the list */
322455 list_for_each_entry(bss, &trans_bss->nontrans_list, nontrans_list) {
323
- if (is_bss(bss, nontrans_bss->bssid, ssid, ssid_len))
456
+ if (is_bss(bss, nontrans_bss->bssid, ssid, ssid_len)) {
457
+ rcu_read_unlock();
324458 return 0;
459
+ }
325460 }
461
+
462
+ rcu_read_unlock();
463
+
464
+ /*
465
+ * This is a bit weird - it's not on the list, but already on another
466
+ * one! The only way that could happen is if there's some BSSID/SSID
467
+ * shared by multiple APs in their multi-BSSID profiles, potentially
468
+ * with hidden SSID mixed in ... ignore it.
469
+ */
470
+ if (!list_empty(&nontrans_bss->nontrans_list))
471
+ return -EINVAL;
326472
327473 /* add to the list */
328474 list_add_tail(&nontrans_bss->nontrans_list, &trans_bss->nontrans_list);
....@@ -385,10 +531,440 @@
385531 return ret;
386532 }
387533
534
+static u8 cfg80211_parse_bss_param(u8 data,
535
+ struct cfg80211_colocated_ap *coloc_ap)
536
+{
537
+ coloc_ap->oct_recommended =
538
+ u8_get_bits(data, IEEE80211_RNR_TBTT_PARAMS_OCT_RECOMMENDED);
539
+ coloc_ap->same_ssid =
540
+ u8_get_bits(data, IEEE80211_RNR_TBTT_PARAMS_SAME_SSID);
541
+ coloc_ap->multi_bss =
542
+ u8_get_bits(data, IEEE80211_RNR_TBTT_PARAMS_MULTI_BSSID);
543
+ coloc_ap->transmitted_bssid =
544
+ u8_get_bits(data, IEEE80211_RNR_TBTT_PARAMS_TRANSMITTED_BSSID);
545
+ coloc_ap->unsolicited_probe =
546
+ u8_get_bits(data, IEEE80211_RNR_TBTT_PARAMS_PROBE_ACTIVE);
547
+ coloc_ap->colocated_ess =
548
+ u8_get_bits(data, IEEE80211_RNR_TBTT_PARAMS_COLOC_ESS);
549
+
550
+ return u8_get_bits(data, IEEE80211_RNR_TBTT_PARAMS_COLOC_AP);
551
+}
552
+
553
+static int cfg80211_calc_short_ssid(const struct cfg80211_bss_ies *ies,
554
+ const struct element **elem, u32 *s_ssid)
555
+{
556
+
557
+ *elem = cfg80211_find_elem(WLAN_EID_SSID, ies->data, ies->len);
558
+ if (!*elem || (*elem)->datalen > IEEE80211_MAX_SSID_LEN)
559
+ return -EINVAL;
560
+
561
+ *s_ssid = ~crc32_le(~0, (*elem)->data, (*elem)->datalen);
562
+ return 0;
563
+}
564
+
565
+static void cfg80211_free_coloc_ap_list(struct list_head *coloc_ap_list)
566
+{
567
+ struct cfg80211_colocated_ap *ap, *tmp_ap;
568
+
569
+ list_for_each_entry_safe(ap, tmp_ap, coloc_ap_list, list) {
570
+ list_del(&ap->list);
571
+ kfree(ap);
572
+ }
573
+}
574
+
575
+static int cfg80211_parse_ap_info(struct cfg80211_colocated_ap *entry,
576
+ const u8 *pos, u8 length,
577
+ const struct element *ssid_elem,
578
+ int s_ssid_tmp)
579
+{
580
+ /* skip the TBTT offset */
581
+ pos++;
582
+
583
+ memcpy(entry->bssid, pos, ETH_ALEN);
584
+ pos += ETH_ALEN;
585
+
586
+ if (length == IEEE80211_TBTT_INFO_OFFSET_BSSID_SSSID_BSS_PARAM) {
587
+ memcpy(&entry->short_ssid, pos,
588
+ sizeof(entry->short_ssid));
589
+ entry->short_ssid_valid = true;
590
+ pos += 4;
591
+ }
592
+
593
+ /* skip non colocated APs */
594
+ if (!cfg80211_parse_bss_param(*pos, entry))
595
+ return -EINVAL;
596
+ pos++;
597
+
598
+ if (length == IEEE80211_TBTT_INFO_OFFSET_BSSID_BSS_PARAM) {
599
+ /*
600
+ * no information about the short ssid. Consider the entry valid
601
+ * for now. It would later be dropped in case there are explicit
602
+ * SSIDs that need to be matched
603
+ */
604
+ if (!entry->same_ssid)
605
+ return 0;
606
+ }
607
+
608
+ if (entry->same_ssid) {
609
+ entry->short_ssid = s_ssid_tmp;
610
+ entry->short_ssid_valid = true;
611
+
612
+ /*
613
+ * This is safe because we validate datalen in
614
+ * cfg80211_parse_colocated_ap(), before calling this
615
+ * function.
616
+ */
617
+ memcpy(&entry->ssid, &ssid_elem->data,
618
+ ssid_elem->datalen);
619
+ entry->ssid_len = ssid_elem->datalen;
620
+ }
621
+ return 0;
622
+}
623
+
624
+static int cfg80211_parse_colocated_ap(const struct cfg80211_bss_ies *ies,
625
+ struct list_head *list)
626
+{
627
+ struct ieee80211_neighbor_ap_info *ap_info;
628
+ const struct element *elem, *ssid_elem;
629
+ const u8 *pos, *end;
630
+ u32 s_ssid_tmp;
631
+ int n_coloc = 0, ret;
632
+ LIST_HEAD(ap_list);
633
+
634
+ elem = cfg80211_find_elem(WLAN_EID_REDUCED_NEIGHBOR_REPORT, ies->data,
635
+ ies->len);
636
+ if (!elem || elem->datalen > IEEE80211_MAX_SSID_LEN)
637
+ return 0;
638
+
639
+ pos = elem->data;
640
+ end = pos + elem->datalen;
641
+
642
+ ret = cfg80211_calc_short_ssid(ies, &ssid_elem, &s_ssid_tmp);
643
+ if (ret)
644
+ return 0;
645
+
646
+ /* RNR IE may contain more than one NEIGHBOR_AP_INFO */
647
+ while (pos + sizeof(*ap_info) <= end) {
648
+ enum nl80211_band band;
649
+ int freq;
650
+ u8 length, i, count;
651
+
652
+ ap_info = (void *)pos;
653
+ count = u8_get_bits(ap_info->tbtt_info_hdr,
654
+ IEEE80211_AP_INFO_TBTT_HDR_COUNT) + 1;
655
+ length = ap_info->tbtt_info_len;
656
+
657
+ pos += sizeof(*ap_info);
658
+
659
+ if (!ieee80211_operating_class_to_band(ap_info->op_class,
660
+ &band))
661
+ break;
662
+
663
+ freq = ieee80211_channel_to_frequency(ap_info->channel, band);
664
+
665
+ if (end - pos < count * ap_info->tbtt_info_len)
666
+ break;
667
+
668
+ /*
669
+ * TBTT info must include bss param + BSSID +
670
+ * (short SSID or same_ssid bit to be set).
671
+ * ignore other options, and move to the
672
+ * next AP info
673
+ */
674
+ if (band != NL80211_BAND_6GHZ ||
675
+ (length != IEEE80211_TBTT_INFO_OFFSET_BSSID_BSS_PARAM &&
676
+ length < IEEE80211_TBTT_INFO_OFFSET_BSSID_SSSID_BSS_PARAM)) {
677
+ pos += count * ap_info->tbtt_info_len;
678
+ continue;
679
+ }
680
+
681
+ for (i = 0; i < count; i++) {
682
+ struct cfg80211_colocated_ap *entry;
683
+
684
+ entry = kzalloc(sizeof(*entry) + IEEE80211_MAX_SSID_LEN,
685
+ GFP_ATOMIC);
686
+
687
+ if (!entry)
688
+ break;
689
+
690
+ entry->center_freq = freq;
691
+
692
+ if (!cfg80211_parse_ap_info(entry, pos, length,
693
+ ssid_elem, s_ssid_tmp)) {
694
+ n_coloc++;
695
+ list_add_tail(&entry->list, &ap_list);
696
+ } else {
697
+ kfree(entry);
698
+ }
699
+
700
+ pos += ap_info->tbtt_info_len;
701
+ }
702
+ }
703
+
704
+ if (pos != end) {
705
+ cfg80211_free_coloc_ap_list(&ap_list);
706
+ return 0;
707
+ }
708
+
709
+ list_splice_tail(&ap_list, list);
710
+ return n_coloc;
711
+}
712
+
713
+static void cfg80211_scan_req_add_chan(struct cfg80211_scan_request *request,
714
+ struct ieee80211_channel *chan,
715
+ bool add_to_6ghz)
716
+{
717
+ int i;
718
+ u32 n_channels = request->n_channels;
719
+ struct cfg80211_scan_6ghz_params *params =
720
+ &request->scan_6ghz_params[request->n_6ghz_params];
721
+
722
+ for (i = 0; i < n_channels; i++) {
723
+ if (request->channels[i] == chan) {
724
+ if (add_to_6ghz)
725
+ params->channel_idx = i;
726
+ return;
727
+ }
728
+ }
729
+
730
+ request->channels[n_channels] = chan;
731
+ if (add_to_6ghz)
732
+ request->scan_6ghz_params[request->n_6ghz_params].channel_idx =
733
+ n_channels;
734
+
735
+ request->n_channels++;
736
+}
737
+
738
+static bool cfg80211_find_ssid_match(struct cfg80211_colocated_ap *ap,
739
+ struct cfg80211_scan_request *request)
740
+{
741
+ int i;
742
+ u32 s_ssid;
743
+
744
+ for (i = 0; i < request->n_ssids; i++) {
745
+ /* wildcard ssid in the scan request */
746
+ if (!request->ssids[i].ssid_len) {
747
+ if (ap->multi_bss && !ap->transmitted_bssid)
748
+ continue;
749
+
750
+ return true;
751
+ }
752
+
753
+ if (ap->ssid_len &&
754
+ ap->ssid_len == request->ssids[i].ssid_len) {
755
+ if (!memcmp(request->ssids[i].ssid, ap->ssid,
756
+ ap->ssid_len))
757
+ return true;
758
+ } else if (ap->short_ssid_valid) {
759
+ s_ssid = ~crc32_le(~0, request->ssids[i].ssid,
760
+ request->ssids[i].ssid_len);
761
+
762
+ if (ap->short_ssid == s_ssid)
763
+ return true;
764
+ }
765
+ }
766
+
767
+ return false;
768
+}
769
+
770
+static int cfg80211_scan_6ghz(struct cfg80211_registered_device *rdev)
771
+{
772
+ u8 i;
773
+ struct cfg80211_colocated_ap *ap;
774
+ int n_channels, count = 0, err;
775
+ struct cfg80211_scan_request *request, *rdev_req = rdev->scan_req;
776
+ LIST_HEAD(coloc_ap_list);
777
+ bool need_scan_psc;
778
+ const struct ieee80211_sband_iftype_data *iftd;
779
+
780
+ rdev_req->scan_6ghz = true;
781
+
782
+ if (!rdev->wiphy.bands[NL80211_BAND_6GHZ])
783
+ return -EOPNOTSUPP;
784
+
785
+ iftd = ieee80211_get_sband_iftype_data(rdev->wiphy.bands[NL80211_BAND_6GHZ],
786
+ rdev_req->wdev->iftype);
787
+ if (!iftd || !iftd->he_cap.has_he)
788
+ return -EOPNOTSUPP;
789
+
790
+ n_channels = rdev->wiphy.bands[NL80211_BAND_6GHZ]->n_channels;
791
+
792
+ if (rdev_req->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ) {
793
+ struct cfg80211_internal_bss *intbss;
794
+
795
+ spin_lock_bh(&rdev->bss_lock);
796
+ list_for_each_entry(intbss, &rdev->bss_list, list) {
797
+ struct cfg80211_bss *res = &intbss->pub;
798
+ const struct cfg80211_bss_ies *ies;
799
+
800
+ ies = rcu_access_pointer(res->ies);
801
+ count += cfg80211_parse_colocated_ap(ies,
802
+ &coloc_ap_list);
803
+ }
804
+ spin_unlock_bh(&rdev->bss_lock);
805
+ }
806
+
807
+ request = kzalloc(struct_size(request, channels, n_channels) +
808
+ sizeof(*request->scan_6ghz_params) * count,
809
+ GFP_KERNEL);
810
+ if (!request) {
811
+ cfg80211_free_coloc_ap_list(&coloc_ap_list);
812
+ return -ENOMEM;
813
+ }
814
+
815
+ *request = *rdev_req;
816
+ request->n_channels = 0;
817
+ request->scan_6ghz_params =
818
+ (void *)&request->channels[n_channels];
819
+
820
+ /*
821
+ * PSC channels should not be scanned if all the reported co-located APs
822
+ * are indicating that all APs in the same ESS are co-located
823
+ */
824
+ if (count) {
825
+ need_scan_psc = false;
826
+
827
+ list_for_each_entry(ap, &coloc_ap_list, list) {
828
+ if (!ap->colocated_ess) {
829
+ need_scan_psc = true;
830
+ break;
831
+ }
832
+ }
833
+ } else {
834
+ need_scan_psc = true;
835
+ }
836
+
837
+ /*
838
+ * add to the scan request the channels that need to be scanned
839
+ * regardless of the collocated APs (PSC channels or all channels
840
+ * in case that NL80211_SCAN_FLAG_COLOCATED_6GHZ is not set)
841
+ */
842
+ for (i = 0; i < rdev_req->n_channels; i++) {
843
+ if (rdev_req->channels[i]->band == NL80211_BAND_6GHZ &&
844
+ ((need_scan_psc &&
845
+ cfg80211_channel_is_psc(rdev_req->channels[i])) ||
846
+ !(rdev_req->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ))) {
847
+ cfg80211_scan_req_add_chan(request,
848
+ rdev_req->channels[i],
849
+ false);
850
+ }
851
+ }
852
+
853
+ if (!(rdev_req->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ))
854
+ goto skip;
855
+
856
+ list_for_each_entry(ap, &coloc_ap_list, list) {
857
+ bool found = false;
858
+ struct cfg80211_scan_6ghz_params *scan_6ghz_params =
859
+ &request->scan_6ghz_params[request->n_6ghz_params];
860
+ struct ieee80211_channel *chan =
861
+ ieee80211_get_channel(&rdev->wiphy, ap->center_freq);
862
+
863
+ if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
864
+ continue;
865
+
866
+ for (i = 0; i < rdev_req->n_channels; i++) {
867
+ if (rdev_req->channels[i] == chan)
868
+ found = true;
869
+ }
870
+
871
+ if (!found)
872
+ continue;
873
+
874
+ if (request->n_ssids > 0 &&
875
+ !cfg80211_find_ssid_match(ap, request))
876
+ continue;
877
+
878
+ if (!request->n_ssids && ap->multi_bss && !ap->transmitted_bssid)
879
+ continue;
880
+
881
+ cfg80211_scan_req_add_chan(request, chan, true);
882
+ memcpy(scan_6ghz_params->bssid, ap->bssid, ETH_ALEN);
883
+ scan_6ghz_params->short_ssid = ap->short_ssid;
884
+ scan_6ghz_params->short_ssid_valid = ap->short_ssid_valid;
885
+ scan_6ghz_params->unsolicited_probe = ap->unsolicited_probe;
886
+
887
+ /*
888
+ * If a PSC channel is added to the scan and 'need_scan_psc' is
889
+ * set to false, then all the APs that the scan logic is
890
+ * interested with on the channel are collocated and thus there
891
+ * is no need to perform the initial PSC channel listen.
892
+ */
893
+ if (cfg80211_channel_is_psc(chan) && !need_scan_psc)
894
+ scan_6ghz_params->psc_no_listen = true;
895
+
896
+ request->n_6ghz_params++;
897
+ }
898
+
899
+skip:
900
+ cfg80211_free_coloc_ap_list(&coloc_ap_list);
901
+
902
+ if (request->n_channels) {
903
+ struct cfg80211_scan_request *old = rdev->int_scan_req;
904
+
905
+ rdev->int_scan_req = request;
906
+
907
+ /*
908
+ * If this scan follows a previous scan, save the scan start
909
+ * info from the first part of the scan
910
+ */
911
+ if (old)
912
+ rdev->int_scan_req->info = old->info;
913
+
914
+ err = rdev_scan(rdev, request);
915
+ if (err) {
916
+ rdev->int_scan_req = old;
917
+ kfree(request);
918
+ } else {
919
+ kfree(old);
920
+ }
921
+
922
+ return err;
923
+ }
924
+
925
+ kfree(request);
926
+ return -EINVAL;
927
+}
928
+
929
+int cfg80211_scan(struct cfg80211_registered_device *rdev)
930
+{
931
+ struct cfg80211_scan_request *request;
932
+ struct cfg80211_scan_request *rdev_req = rdev->scan_req;
933
+ u32 n_channels = 0, idx, i;
934
+
935
+ if (!(rdev->wiphy.flags & WIPHY_FLAG_SPLIT_SCAN_6GHZ))
936
+ return rdev_scan(rdev, rdev_req);
937
+
938
+ for (i = 0; i < rdev_req->n_channels; i++) {
939
+ if (rdev_req->channels[i]->band != NL80211_BAND_6GHZ)
940
+ n_channels++;
941
+ }
942
+
943
+ if (!n_channels)
944
+ return cfg80211_scan_6ghz(rdev);
945
+
946
+ request = kzalloc(struct_size(request, channels, n_channels),
947
+ GFP_KERNEL);
948
+ if (!request)
949
+ return -ENOMEM;
950
+
951
+ *request = *rdev_req;
952
+ request->n_channels = n_channels;
953
+
954
+ for (i = idx = 0; i < rdev_req->n_channels; i++) {
955
+ if (rdev_req->channels[i]->band != NL80211_BAND_6GHZ)
956
+ request->channels[idx++] = rdev_req->channels[i];
957
+ }
958
+
959
+ rdev_req->scan_6ghz = false;
960
+ rdev->int_scan_req = request;
961
+ return rdev_scan(rdev, request);
962
+}
963
+
388964 void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
389965 bool send_message)
390966 {
391
- struct cfg80211_scan_request *request;
967
+ struct cfg80211_scan_request *request, *rdev_req;
392968 struct wireless_dev *wdev;
393969 struct sk_buff *msg;
394970 #ifdef CONFIG_CFG80211_WEXT
....@@ -403,11 +979,18 @@
403979 return;
404980 }
405981
406
- request = rdev->scan_req;
407
- if (!request)
982
+ rdev_req = rdev->scan_req;
983
+ if (!rdev_req)
408984 return;
409985
410
- wdev = request->wdev;
986
+ wdev = rdev_req->wdev;
987
+ request = rdev->int_scan_req ? rdev->int_scan_req : rdev_req;
988
+
989
+ if (wdev_running(wdev) &&
990
+ (rdev->wiphy.flags & WIPHY_FLAG_SPLIT_SCAN_6GHZ) &&
991
+ !rdev_req->scan_6ghz && !request->info.aborted &&
992
+ !cfg80211_scan_6ghz(rdev))
993
+ return;
411994
412995 /*
413996 * This must be before sending the other events!
....@@ -438,8 +1021,11 @@
4381021 if (wdev->netdev)
4391022 dev_put(wdev->netdev);
4401023
1024
+ kfree(rdev->int_scan_req);
1025
+ rdev->int_scan_req = NULL;
1026
+
1027
+ kfree(rdev->scan_req);
4411028 rdev->scan_req = NULL;
442
- kfree(request);
4431029
4441030 if (!send_message)
4451031 rdev->scan_msg = msg;
....@@ -462,10 +1048,25 @@
4621048 void cfg80211_scan_done(struct cfg80211_scan_request *request,
4631049 struct cfg80211_scan_info *info)
4641050 {
1051
+ struct cfg80211_scan_info old_info = request->info;
1052
+
4651053 trace_cfg80211_scan_done(request, info);
466
- WARN_ON(request != wiphy_to_rdev(request->wiphy)->scan_req);
1054
+ WARN_ON(request != wiphy_to_rdev(request->wiphy)->scan_req &&
1055
+ request != wiphy_to_rdev(request->wiphy)->int_scan_req);
4671056
4681057 request->info = *info;
1058
+
1059
+ /*
1060
+ * In case the scan is split, the scan_start_tsf and tsf_bssid should
1061
+ * be of the first part. In such a case old_info.scan_start_tsf should
1062
+ * be non zero.
1063
+ */
1064
+ if (request->scan_6ghz && old_info.scan_start_tsf) {
1065
+ request->info.scan_start_tsf = old_info.scan_start_tsf;
1066
+ memcpy(request->info.tsf_bssid, old_info.tsf_bssid,
1067
+ sizeof(request->info.tsf_bssid));
1068
+ }
1069
+
4691070 request->notified = true;
4701071 queue_work(cfg80211_wq, &wiphy_to_rdev(request->wiphy)->scan_done_wk);
4711072 }
....@@ -493,9 +1094,8 @@
4931094 {
4941095 struct cfg80211_sched_scan_request *pos;
4951096
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) {
1097
+ list_for_each_entry_rcu(pos, &rdev->sched_scan_req_list, list,
1098
+ lockdep_rtnl_is_held()) {
4991099 if (pos->reqid == reqid)
5001100 return pos;
5011101 }
....@@ -650,48 +1250,53 @@
6501250 __cfg80211_bss_expire(rdev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE);
6511251 }
6521252
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)
1253
+void cfg80211_bss_flush(struct wiphy *wiphy)
1254
+{
1255
+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
1256
+
1257
+ spin_lock_bh(&rdev->bss_lock);
1258
+ __cfg80211_bss_expire(rdev, jiffies);
1259
+ spin_unlock_bh(&rdev->bss_lock);
1260
+}
1261
+EXPORT_SYMBOL(cfg80211_bss_flush);
1262
+
1263
+const struct element *
1264
+cfg80211_find_elem_match(u8 eid, const u8 *ies, unsigned int len,
1265
+ const u8 *match, unsigned int match_len,
1266
+ unsigned int match_offset)
6561267 {
6571268 const struct element *elem;
6581269
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
-
6661270 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;
1271
+ if (elem->datalen >= match_offset + match_len &&
1272
+ !memcmp(elem->data + match_offset, match, match_len))
1273
+ return elem;
6701274 }
6711275
6721276 return NULL;
6731277 }
674
-EXPORT_SYMBOL(cfg80211_find_ie_match);
1278
+EXPORT_SYMBOL(cfg80211_find_elem_match);
6751279
676
-const u8 *cfg80211_find_vendor_ie(unsigned int oui, int oui_type,
677
- const u8 *ies, int len)
1280
+const struct element *cfg80211_find_vendor_elem(unsigned int oui, int oui_type,
1281
+ const u8 *ies,
1282
+ unsigned int len)
6781283 {
679
- const u8 *ie;
1284
+ const struct element *elem;
6801285 u8 match[] = { oui >> 16, oui >> 8, oui, oui_type };
6811286 int match_len = (oui_type < 0) ? 3 : sizeof(match);
6821287
6831288 if (WARN_ON(oui_type > 0xff))
6841289 return NULL;
6851290
686
- ie = cfg80211_find_ie_match(WLAN_EID_VENDOR_SPECIFIC, ies, len,
687
- match, match_len, 2);
1291
+ elem = cfg80211_find_elem_match(WLAN_EID_VENDOR_SPECIFIC, ies, len,
1292
+ match, match_len, 0);
6881293
689
- if (ie && (ie[1] < 4))
1294
+ if (!elem || elem->datalen < 4)
6901295 return NULL;
6911296
692
- return ie;
1297
+ return elem;
6931298 }
694
-EXPORT_SYMBOL(cfg80211_find_vendor_ie);
1299
+EXPORT_SYMBOL(cfg80211_find_vendor_elem);
6951300
6961301 /**
6971302 * enum bss_compare_mode - BSS compare mode
....@@ -1033,18 +1638,114 @@
10331638 u8 bssid_index;
10341639 };
10351640
1641
+static void cfg80211_update_hidden_bsses(struct cfg80211_internal_bss *known,
1642
+ const struct cfg80211_bss_ies *new_ies,
1643
+ const struct cfg80211_bss_ies *old_ies)
1644
+{
1645
+ struct cfg80211_internal_bss *bss;
1646
+
1647
+ /* Assign beacon IEs to all sub entries */
1648
+ list_for_each_entry(bss, &known->hidden_list, hidden_list) {
1649
+ const struct cfg80211_bss_ies *ies;
1650
+
1651
+ ies = rcu_access_pointer(bss->pub.beacon_ies);
1652
+ WARN_ON(ies != old_ies);
1653
+
1654
+ rcu_assign_pointer(bss->pub.beacon_ies, new_ies);
1655
+ }
1656
+}
1657
+
1658
+static bool
1659
+cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
1660
+ struct cfg80211_internal_bss *known,
1661
+ struct cfg80211_internal_bss *new,
1662
+ bool signal_valid)
1663
+{
1664
+ lockdep_assert_held(&rdev->bss_lock);
1665
+
1666
+ /* Update IEs */
1667
+ if (rcu_access_pointer(new->pub.proberesp_ies)) {
1668
+ const struct cfg80211_bss_ies *old;
1669
+
1670
+ old = rcu_access_pointer(known->pub.proberesp_ies);
1671
+
1672
+ rcu_assign_pointer(known->pub.proberesp_ies,
1673
+ new->pub.proberesp_ies);
1674
+ /* Override possible earlier Beacon frame IEs */
1675
+ rcu_assign_pointer(known->pub.ies,
1676
+ new->pub.proberesp_ies);
1677
+ if (old)
1678
+ kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
1679
+ } else if (rcu_access_pointer(new->pub.beacon_ies)) {
1680
+ const struct cfg80211_bss_ies *old;
1681
+
1682
+ if (known->pub.hidden_beacon_bss &&
1683
+ !list_empty(&known->hidden_list)) {
1684
+ const struct cfg80211_bss_ies *f;
1685
+
1686
+ /* The known BSS struct is one of the probe
1687
+ * response members of a group, but we're
1688
+ * receiving a beacon (beacon_ies in the new
1689
+ * bss is used). This can only mean that the
1690
+ * AP changed its beacon from not having an
1691
+ * SSID to showing it, which is confusing so
1692
+ * drop this information.
1693
+ */
1694
+
1695
+ f = rcu_access_pointer(new->pub.beacon_ies);
1696
+ kfree_rcu((struct cfg80211_bss_ies *)f, rcu_head);
1697
+ return false;
1698
+ }
1699
+
1700
+ old = rcu_access_pointer(known->pub.beacon_ies);
1701
+
1702
+ rcu_assign_pointer(known->pub.beacon_ies, new->pub.beacon_ies);
1703
+
1704
+ /* Override IEs if they were from a beacon before */
1705
+ if (old == rcu_access_pointer(known->pub.ies))
1706
+ rcu_assign_pointer(known->pub.ies, new->pub.beacon_ies);
1707
+
1708
+ cfg80211_update_hidden_bsses(known,
1709
+ rcu_access_pointer(new->pub.beacon_ies),
1710
+ old);
1711
+
1712
+ if (old)
1713
+ kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
1714
+ }
1715
+
1716
+ known->pub.beacon_interval = new->pub.beacon_interval;
1717
+
1718
+ /* don't update the signal if beacon was heard on
1719
+ * adjacent channel.
1720
+ */
1721
+ if (signal_valid)
1722
+ known->pub.signal = new->pub.signal;
1723
+ known->pub.capability = new->pub.capability;
1724
+ known->ts = new->ts;
1725
+ known->ts_boottime = new->ts_boottime;
1726
+ known->parent_tsf = new->parent_tsf;
1727
+ known->pub.chains = new->pub.chains;
1728
+ memcpy(known->pub.chain_signal, new->pub.chain_signal,
1729
+ IEEE80211_MAX_CHAINS);
1730
+ ether_addr_copy(known->parent_bssid, new->parent_bssid);
1731
+ known->pub.max_bssid_indicator = new->pub.max_bssid_indicator;
1732
+ known->pub.bssid_index = new->pub.bssid_index;
1733
+
1734
+ return true;
1735
+}
1736
+
10361737 /* Returned bss is reference counted and must be cleaned up appropriately. */
1037
-static struct cfg80211_internal_bss *
1738
+struct cfg80211_internal_bss *
10381739 cfg80211_bss_update(struct cfg80211_registered_device *rdev,
10391740 struct cfg80211_internal_bss *tmp,
1040
- bool signal_valid)
1741
+ bool signal_valid, unsigned long ts)
10411742 {
10421743 struct cfg80211_internal_bss *found = NULL;
10431744
10441745 if (WARN_ON(!tmp->pub.channel))
10451746 return NULL;
10461747
1047
- tmp->ts = jiffies;
1748
+ tmp->ts = ts;
10481749
10491750 spin_lock_bh(&rdev->bss_lock);
10501751
....@@ -1056,88 +1757,8 @@
10561757 found = rb_find_bss(rdev, tmp, BSS_CMP_REGULAR);
10571758
10581759 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;
1760
+ if (!cfg80211_update_known_bss(rdev, found, tmp, signal_valid))
1761
+ goto drop;
11411762 } else {
11421763 struct cfg80211_internal_bss *new;
11431764 struct cfg80211_internal_bss *hidden;
....@@ -1163,6 +1784,8 @@
11631784 new->refcount = 1;
11641785 INIT_LIST_HEAD(&new->hidden_list);
11651786 INIT_LIST_HEAD(&new->pub.nontrans_list);
1787
+ /* we'll set this later if it was non-NULL */
1788
+ new->pub.transmitted_bss = NULL;
11661789
11671790 if (rcu_access_pointer(tmp->pub.proberesp_ies)) {
11681791 hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN);
....@@ -1241,15 +1864,24 @@
12411864 int channel_number = -1;
12421865 struct ieee80211_channel *alt_channel;
12431866
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);
1867
+ if (channel->band == NL80211_BAND_S1GHZ) {
1868
+ tmp = cfg80211_find_ie(WLAN_EID_S1G_OPERATION, ie, ielen);
1869
+ if (tmp && tmp[1] >= sizeof(struct ieee80211_s1g_oper_ie)) {
1870
+ struct ieee80211_s1g_oper_ie *s1gop = (void *)(tmp + 2);
12511871
1252
- channel_number = htop->primary_chan;
1872
+ channel_number = s1gop->primary_ch;
1873
+ }
1874
+ } else {
1875
+ tmp = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ie, ielen);
1876
+ if (tmp && tmp[1] == 1) {
1877
+ channel_number = tmp[2];
1878
+ } else {
1879
+ tmp = cfg80211_find_ie(WLAN_EID_HT_OPERATION, ie, ielen);
1880
+ if (tmp && tmp[1] >= sizeof(struct ieee80211_ht_operation)) {
1881
+ struct ieee80211_ht_operation *htop = (void *)(tmp + 2);
1882
+
1883
+ channel_number = htop->primary_chan;
1884
+ }
12531885 }
12541886 }
12551887
....@@ -1258,8 +1890,8 @@
12581890 return channel;
12591891 }
12601892
1261
- freq = ieee80211_channel_to_frequency(channel_number, channel->band);
1262
- alt_channel = ieee80211_get_channel(wiphy, freq);
1893
+ freq = ieee80211_channel_to_freq_khz(channel_number, channel->band);
1894
+ alt_channel = ieee80211_get_channel_khz(wiphy, freq);
12631895 if (!alt_channel) {
12641896 if (channel->band == NL80211_BAND_2GHZ) {
12651897 /*
....@@ -1310,6 +1942,7 @@
13101942 struct cfg80211_internal_bss tmp = {}, *res;
13111943 int bss_type;
13121944 bool signal_valid;
1945
+ unsigned long ts;
13131946
13141947 if (WARN_ON(!wiphy))
13151948 return NULL;
....@@ -1332,8 +1965,11 @@
13321965 tmp.ts_boottime = data->boottime_ns;
13331966 if (non_tx_data) {
13341967 tmp.pub.transmitted_bss = non_tx_data->tx_bss;
1968
+ ts = bss_from_pub(non_tx_data->tx_bss)->ts;
13351969 tmp.pub.bssid_index = non_tx_data->bssid_index;
13361970 tmp.pub.max_bssid_indicator = non_tx_data->max_bssid_indicator;
1971
+ } else {
1972
+ ts = jiffies;
13371973 }
13381974
13391975 /*
....@@ -1355,7 +1991,7 @@
13551991 switch (ftype) {
13561992 case CFG80211_BSS_FTYPE_BEACON:
13571993 ies->from_beacon = true;
1358
- /* fall through to assign */
1994
+ fallthrough;
13591995 case CFG80211_BSS_FTYPE_UNKNOWN:
13601996 rcu_assign_pointer(tmp.pub.beacon_ies, ies);
13611997 break;
....@@ -1365,9 +2001,8 @@
13652001 }
13662002 rcu_assign_pointer(tmp.pub.ies, ies);
13672003
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);
2004
+ signal_valid = data->chan == channel;
2005
+ res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid, ts);
13712006 if (!res)
13722007 return NULL;
13732008
....@@ -1381,21 +2016,100 @@
13812016 regulatory_hint_found_beacon(wiphy, channel, gfp);
13822017 }
13832018
1384
- if (non_tx_data && non_tx_data->tx_bss) {
2019
+ if (non_tx_data) {
13852020 /* this is a nontransmitting bss, we need to add it to
13862021 * transmitting bss' list if it is not there
13872022 */
2023
+ spin_lock_bh(&rdev->bss_lock);
13882024 if (cfg80211_add_nontrans_list(non_tx_data->tx_bss,
13892025 &res->pub)) {
1390
- if (__cfg80211_unlink_bss(rdev, res))
2026
+ if (__cfg80211_unlink_bss(rdev, res)) {
13912027 rdev->bss_generation++;
2028
+ res = NULL;
2029
+ }
13922030 }
2031
+ spin_unlock_bh(&rdev->bss_lock);
2032
+
2033
+ if (!res)
2034
+ return NULL;
13932035 }
13942036
13952037 trace_cfg80211_return_bss(&res->pub);
13962038 /* cfg80211_bss_update gives us a referenced result */
13972039 return &res->pub;
13982040 }
2041
+
2042
+static const struct element
2043
+*cfg80211_get_profile_continuation(const u8 *ie, size_t ielen,
2044
+ const struct element *mbssid_elem,
2045
+ const struct element *sub_elem)
2046
+{
2047
+ const u8 *mbssid_end = mbssid_elem->data + mbssid_elem->datalen;
2048
+ const struct element *next_mbssid;
2049
+ const struct element *next_sub;
2050
+
2051
+ next_mbssid = cfg80211_find_elem(WLAN_EID_MULTIPLE_BSSID,
2052
+ mbssid_end,
2053
+ ielen - (mbssid_end - ie));
2054
+
2055
+ /*
2056
+ * If it is not the last subelement in current MBSSID IE or there isn't
2057
+ * a next MBSSID IE - profile is complete.
2058
+ */
2059
+ if ((sub_elem->data + sub_elem->datalen < mbssid_end - 1) ||
2060
+ !next_mbssid)
2061
+ return NULL;
2062
+
2063
+ /* For any length error, just return NULL */
2064
+
2065
+ if (next_mbssid->datalen < 4)
2066
+ return NULL;
2067
+
2068
+ next_sub = (void *)&next_mbssid->data[1];
2069
+
2070
+ if (next_mbssid->data + next_mbssid->datalen <
2071
+ next_sub->data + next_sub->datalen)
2072
+ return NULL;
2073
+
2074
+ if (next_sub->id != 0 || next_sub->datalen < 2)
2075
+ return NULL;
2076
+
2077
+ /*
2078
+ * Check if the first element in the next sub element is a start
2079
+ * of a new profile
2080
+ */
2081
+ return next_sub->data[0] == WLAN_EID_NON_TX_BSSID_CAP ?
2082
+ NULL : next_mbssid;
2083
+}
2084
+
2085
+size_t cfg80211_merge_profile(const u8 *ie, size_t ielen,
2086
+ const struct element *mbssid_elem,
2087
+ const struct element *sub_elem,
2088
+ u8 *merged_ie, size_t max_copy_len)
2089
+{
2090
+ size_t copied_len = sub_elem->datalen;
2091
+ const struct element *next_mbssid;
2092
+
2093
+ if (sub_elem->datalen > max_copy_len)
2094
+ return 0;
2095
+
2096
+ memcpy(merged_ie, sub_elem->data, sub_elem->datalen);
2097
+
2098
+ while ((next_mbssid = cfg80211_get_profile_continuation(ie, ielen,
2099
+ mbssid_elem,
2100
+ sub_elem))) {
2101
+ const struct element *next_sub = (void *)&next_mbssid->data[1];
2102
+
2103
+ if (copied_len + next_sub->datalen > max_copy_len)
2104
+ break;
2105
+ memcpy(merged_ie + copied_len, next_sub->data,
2106
+ next_sub->datalen);
2107
+ copied_len += next_sub->datalen;
2108
+ }
2109
+
2110
+ return copied_len;
2111
+}
2112
+EXPORT_SYMBOL(cfg80211_merge_profile);
13992113
14002114 static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
14012115 struct cfg80211_inform_bss *data,
....@@ -1410,7 +2124,8 @@
14102124 const struct element *elem, *sub;
14112125 size_t new_ie_len;
14122126 u8 new_bssid[ETH_ALEN];
1413
- u8 *new_ie;
2127
+ u8 *new_ie, *profile;
2128
+ u64 seen_indices = 0;
14142129 u16 capability;
14152130 struct cfg80211_bss *bss;
14162131
....@@ -1428,10 +2143,18 @@
14282143 if (!new_ie)
14292144 return;
14302145
2146
+ profile = kmalloc(ielen, gfp);
2147
+ if (!profile)
2148
+ goto out;
2149
+
14312150 for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, ie, ielen) {
14322151 if (elem->datalen < 4)
14332152 continue;
2153
+ if (elem->data[0] < 1 || (int)elem->data[0] > 8)
2154
+ continue;
14342155 for_each_element(sub, elem->data + 1, elem->datalen - 1) {
2156
+ u8 profile_len;
2157
+
14352158 if (sub->id != 0 || sub->datalen < 4) {
14362159 /* not a valid BSS profile */
14372160 continue;
....@@ -1446,15 +2169,30 @@
14462169 continue;
14472170 }
14482171
2172
+ memset(profile, 0, ielen);
2173
+ profile_len = cfg80211_merge_profile(ie, ielen,
2174
+ elem,
2175
+ sub,
2176
+ profile,
2177
+ ielen);
2178
+
14492179 /* found a Nontransmitted BSSID Profile */
14502180 mbssid_index_ie = cfg80211_find_ie
14512181 (WLAN_EID_MULTI_BSSID_IDX,
1452
- sub->data, sub->datalen);
2182
+ profile, profile_len);
14532183 if (!mbssid_index_ie || mbssid_index_ie[1] < 1 ||
1454
- mbssid_index_ie[2] == 0) {
2184
+ mbssid_index_ie[2] == 0 ||
2185
+ mbssid_index_ie[2] > 46) {
14552186 /* No valid Multiple BSSID-Index element */
14562187 continue;
14572188 }
2189
+
2190
+ if (seen_indices & BIT_ULL(mbssid_index_ie[2]))
2191
+ /* We don't support legacy split of a profile */
2192
+ net_dbg_ratelimited("Partial info for BSSID index %d\n",
2193
+ mbssid_index_ie[2]);
2194
+
2195
+ seen_indices |= BIT_ULL(mbssid_index_ie[2]);
14582196
14592197 non_tx_data->bssid_index = mbssid_index_ie[2];
14602198 non_tx_data->max_bssid_indicator = elem->data[0];
....@@ -1464,13 +2202,14 @@
14642202 non_tx_data->bssid_index,
14652203 new_bssid);
14662204 memset(new_ie, 0, IEEE80211_MAX_DATA_LEN);
1467
- new_ie_len = cfg80211_gen_new_ie(ie, ielen, sub->data,
1468
- sub->datalen, new_ie,
1469
- gfp);
2205
+ new_ie_len = cfg80211_gen_new_ie(ie, ielen,
2206
+ profile,
2207
+ profile_len, new_ie,
2208
+ IEEE80211_MAX_DATA_LEN);
14702209 if (!new_ie_len)
14712210 continue;
14722211
1473
- capability = get_unaligned_le16(sub->data + 2);
2212
+ capability = get_unaligned_le16(profile + 2);
14742213 bss = cfg80211_inform_single_bss_data(wiphy, data,
14752214 ftype,
14762215 new_bssid, tsf,
....@@ -1486,7 +2225,9 @@
14862225 }
14872226 }
14882227
2228
+out:
14892229 kfree(new_ie);
2230
+ kfree(profile);
14902231 }
14912232
14922233 struct cfg80211_bss *
....@@ -1503,6 +2244,8 @@
15032244 res = cfg80211_inform_single_bss_data(wiphy, data, ftype, bssid, tsf,
15042245 capability, beacon_interval, ie,
15052246 ielen, NULL, gfp);
2247
+ if (!res)
2248
+ return NULL;
15062249 non_tx_data.tx_bss = res;
15072250 cfg80211_parse_mbssid_data(wiphy, data, ftype, bssid, tsf,
15082251 beacon_interval, ie, ielen, &non_tx_data,
....@@ -1535,8 +2278,7 @@
15352278 static void
15362279 cfg80211_update_notlisted_nontrans(struct wiphy *wiphy,
15372280 struct cfg80211_bss *nontrans_bss,
1538
- struct ieee80211_mgmt *mgmt, size_t len,
1539
- gfp_t gfp)
2281
+ struct ieee80211_mgmt *mgmt, size_t len)
15402282 {
15412283 u8 *ie, *new_ie, *pos;
15422284 const u8 *nontrans_ssid, *trans_ssid, *mbssid;
....@@ -1545,7 +2287,9 @@
15452287 size_t new_ie_len;
15462288 struct cfg80211_bss_ies *new_ies;
15472289 const struct cfg80211_bss_ies *old;
1548
- u8 cpy_len;
2290
+ size_t cpy_len;
2291
+
2292
+ lockdep_assert_held(&wiphy_to_rdev(wiphy)->bss_lock);
15492293
15502294 ie = mgmt->u.probe_resp.variable;
15512295
....@@ -1563,27 +2307,24 @@
15632307 if (!mbssid || mbssid < trans_ssid)
15642308 return;
15652309 new_ie_len -= mbssid[1];
1566
- rcu_read_lock();
2310
+
15672311 nontrans_ssid = ieee80211_bss_get_ie(nontrans_bss, WLAN_EID_SSID);
1568
- if (!nontrans_ssid) {
1569
- rcu_read_unlock();
2312
+ if (!nontrans_ssid)
15702313 return;
1571
- }
2314
+
15722315 new_ie_len += nontrans_ssid[1];
1573
- rcu_read_unlock();
15742316
15752317 /* generate new ie for nontrans BSS
15762318 * 1. replace SSID with nontrans BSS' SSID
15772319 * 2. skip MBSSID IE
15782320 */
1579
- new_ie = kzalloc(new_ie_len, gfp);
2321
+ new_ie = kzalloc(new_ie_len, GFP_ATOMIC);
15802322 if (!new_ie)
15812323 return;
1582
- new_ies = kzalloc(sizeof(*new_ies) + new_ie_len, gfp);
1583
- if (!new_ies) {
1584
- kfree(new_ie);
1585
- return;
1586
- }
2324
+
2325
+ new_ies = kzalloc(sizeof(*new_ies) + new_ie_len, GFP_ATOMIC);
2326
+ if (!new_ies)
2327
+ goto out_free;
15872328
15882329 pos = new_ie;
15892330
....@@ -1613,10 +2354,15 @@
16132354 } else {
16142355 old = rcu_access_pointer(nontrans_bss->beacon_ies);
16152356 rcu_assign_pointer(nontrans_bss->beacon_ies, new_ies);
2357
+ cfg80211_update_hidden_bsses(bss_from_pub(nontrans_bss),
2358
+ new_ies, old);
16162359 rcu_assign_pointer(nontrans_bss->ies, new_ies);
16172360 if (old)
16182361 kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
16192362 }
2363
+
2364
+out_free:
2365
+ kfree(new_ie);
16202366 }
16212367
16222368 /* cfg80211_inform_bss_width_frame helper */
....@@ -1624,15 +2370,17 @@
16242370 cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
16252371 struct cfg80211_inform_bss *data,
16262372 struct ieee80211_mgmt *mgmt, size_t len,
1627
- struct cfg80211_non_tx_bss *non_tx_data,
16282373 gfp_t gfp)
16292374 {
16302375 struct cfg80211_internal_bss tmp = {}, *res;
16312376 struct cfg80211_bss_ies *ies;
16322377 struct ieee80211_channel *channel;
16332378 bool signal_valid;
1634
- size_t ielen = len - offsetof(struct ieee80211_mgmt,
1635
- u.probe_resp.variable);
2379
+ struct ieee80211_ext *ext = NULL;
2380
+ u8 *bssid, *variable;
2381
+ u16 capability, beacon_int;
2382
+ size_t ielen, min_hdr_len = offsetof(struct ieee80211_mgmt,
2383
+ u.probe_resp.variable);
16362384 int bss_type;
16372385
16382386 BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=
....@@ -1650,21 +2398,59 @@
16502398 (data->signal < 0 || data->signal > 100)))
16512399 return NULL;
16522400
1653
- if (WARN_ON(len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable)))
2401
+ if (ieee80211_is_s1g_beacon(mgmt->frame_control)) {
2402
+ ext = (void *) mgmt;
2403
+ min_hdr_len = offsetof(struct ieee80211_ext, u.s1g_beacon);
2404
+ if (ieee80211_is_s1g_short_beacon(mgmt->frame_control))
2405
+ min_hdr_len = offsetof(struct ieee80211_ext,
2406
+ u.s1g_short_beacon.variable);
2407
+ }
2408
+
2409
+ if (WARN_ON(len < min_hdr_len))
16542410 return NULL;
16552411
1656
- channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable,
2412
+ ielen = len - min_hdr_len;
2413
+ variable = mgmt->u.probe_resp.variable;
2414
+ if (ext) {
2415
+ if (ieee80211_is_s1g_short_beacon(mgmt->frame_control))
2416
+ variable = ext->u.s1g_short_beacon.variable;
2417
+ else
2418
+ variable = ext->u.s1g_beacon.variable;
2419
+ }
2420
+
2421
+ channel = cfg80211_get_bss_channel(wiphy, variable,
16572422 ielen, data->chan, data->scan_width);
16582423 if (!channel)
16592424 return NULL;
2425
+
2426
+ if (ext) {
2427
+ const struct ieee80211_s1g_bcn_compat_ie *compat;
2428
+ const struct element *elem;
2429
+
2430
+ elem = cfg80211_find_elem(WLAN_EID_S1G_BCN_COMPAT,
2431
+ variable, ielen);
2432
+ if (!elem)
2433
+ return NULL;
2434
+ if (elem->datalen < sizeof(*compat))
2435
+ return NULL;
2436
+ compat = (void *)elem->data;
2437
+ bssid = ext->u.s1g_beacon.sa;
2438
+ capability = le16_to_cpu(compat->compat_info);
2439
+ beacon_int = le16_to_cpu(compat->beacon_int);
2440
+ } else {
2441
+ bssid = mgmt->bssid;
2442
+ beacon_int = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
2443
+ capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
2444
+ }
16602445
16612446 ies = kzalloc(sizeof(*ies) + ielen, gfp);
16622447 if (!ies)
16632448 return NULL;
16642449 ies->len = ielen;
16652450 ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
1666
- ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control);
1667
- memcpy(ies->data, mgmt->u.probe_resp.variable, ielen);
2451
+ ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control) ||
2452
+ ieee80211_is_s1g_beacon(mgmt->frame_control);
2453
+ memcpy(ies->data, variable, ielen);
16682454
16692455 if (ieee80211_is_probe_resp(mgmt->frame_control))
16702456 rcu_assign_pointer(tmp.pub.proberesp_ies, ies);
....@@ -1672,26 +2458,21 @@
16722458 rcu_assign_pointer(tmp.pub.beacon_ies, ies);
16732459 rcu_assign_pointer(tmp.pub.ies, ies);
16742460
1675
- memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN);
2461
+ memcpy(tmp.pub.bssid, bssid, ETH_ALEN);
2462
+ tmp.pub.beacon_interval = beacon_int;
2463
+ tmp.pub.capability = capability;
16762464 tmp.pub.channel = channel;
16772465 tmp.pub.scan_width = data->scan_width;
16782466 tmp.pub.signal = data->signal;
1679
- tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
1680
- tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
16812467 tmp.ts_boottime = data->boottime_ns;
16822468 tmp.parent_tsf = data->parent_tsf;
16832469 tmp.pub.chains = data->chains;
16842470 memcpy(tmp.pub.chain_signal, data->chain_signal, IEEE80211_MAX_CHAINS);
16852471 ether_addr_copy(tmp.parent_bssid, data->parent_bssid);
1686
- if (non_tx_data) {
1687
- tmp.pub.transmitted_bss = non_tx_data->tx_bss;
1688
- tmp.pub.bssid_index = non_tx_data->bssid_index;
1689
- tmp.pub.max_bssid_indicator = non_tx_data->max_bssid_indicator;
1690
- }
16912472
1692
- signal_valid = abs(data->chan->center_freq - channel->center_freq) <=
1693
- wiphy->max_adj_channel_rssi_comp;
1694
- res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid);
2473
+ signal_valid = data->chan == channel;
2474
+ res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid,
2475
+ jiffies);
16952476 if (!res)
16962477 return NULL;
16972478
....@@ -1721,10 +2502,15 @@
17212502 const struct cfg80211_bss_ies *ies1, *ies2;
17222503 size_t ielen = len - offsetof(struct ieee80211_mgmt,
17232504 u.probe_resp.variable);
1724
- struct cfg80211_non_tx_bss non_tx_data;
2505
+ struct cfg80211_non_tx_bss non_tx_data = {};
17252506
17262507 res = cfg80211_inform_single_bss_frame_data(wiphy, data, mgmt,
1727
- len, NULL, gfp);
2508
+ len, gfp);
2509
+
2510
+ /* don't do any further MBSSID handling for S1G */
2511
+ if (ieee80211_is_s1g_beacon(mgmt->frame_control))
2512
+ return res;
2513
+
17282514 if (!res || !wiphy->support_mbssid ||
17292515 !cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen))
17302516 return res;
....@@ -1736,6 +2522,8 @@
17362522 /* process each non-transmitting bss */
17372523 cfg80211_parse_mbssid_frame_data(wiphy, data, mgmt, len,
17382524 &non_tx_data, gfp);
2525
+
2526
+ spin_lock_bh(&wiphy_to_rdev(wiphy)->bss_lock);
17392527
17402528 /* check if the res has other nontransmitting bss which is not
17412529 * in MBSSID IE
....@@ -1751,8 +2539,9 @@
17512539 ies2 = rcu_access_pointer(tmp_bss->ies);
17522540 if (ies2->tsf < ies1->tsf)
17532541 cfg80211_update_notlisted_nontrans(wiphy, tmp_bss,
1754
- mgmt, len, gfp);
2542
+ mgmt, len);
17552543 }
2544
+ spin_unlock_bh(&wiphy_to_rdev(wiphy)->bss_lock);
17562545
17572546 return res;
17582547 }
....@@ -1821,6 +2610,110 @@
18212610 }
18222611 EXPORT_SYMBOL(cfg80211_unlink_bss);
18232612
2613
+void cfg80211_bss_iter(struct wiphy *wiphy,
2614
+ struct cfg80211_chan_def *chandef,
2615
+ void (*iter)(struct wiphy *wiphy,
2616
+ struct cfg80211_bss *bss,
2617
+ void *data),
2618
+ void *iter_data)
2619
+{
2620
+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
2621
+ struct cfg80211_internal_bss *bss;
2622
+
2623
+ spin_lock_bh(&rdev->bss_lock);
2624
+
2625
+ list_for_each_entry(bss, &rdev->bss_list, list) {
2626
+ if (!chandef || cfg80211_is_sub_chan(chandef, bss->pub.channel))
2627
+ iter(wiphy, &bss->pub, iter_data);
2628
+ }
2629
+
2630
+ spin_unlock_bh(&rdev->bss_lock);
2631
+}
2632
+EXPORT_SYMBOL(cfg80211_bss_iter);
2633
+
2634
+void cfg80211_update_assoc_bss_entry(struct wireless_dev *wdev,
2635
+ struct ieee80211_channel *chan)
2636
+{
2637
+ struct wiphy *wiphy = wdev->wiphy;
2638
+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
2639
+ struct cfg80211_internal_bss *cbss = wdev->current_bss;
2640
+ struct cfg80211_internal_bss *new = NULL;
2641
+ struct cfg80211_internal_bss *bss;
2642
+ struct cfg80211_bss *nontrans_bss;
2643
+ struct cfg80211_bss *tmp;
2644
+
2645
+ spin_lock_bh(&rdev->bss_lock);
2646
+
2647
+ /*
2648
+ * Some APs use CSA also for bandwidth changes, i.e., without actually
2649
+ * changing the control channel, so no need to update in such a case.
2650
+ */
2651
+ if (cbss->pub.channel == chan)
2652
+ goto done;
2653
+
2654
+ /* use transmitting bss */
2655
+ if (cbss->pub.transmitted_bss)
2656
+ cbss = container_of(cbss->pub.transmitted_bss,
2657
+ struct cfg80211_internal_bss,
2658
+ pub);
2659
+
2660
+ cbss->pub.channel = chan;
2661
+
2662
+ list_for_each_entry(bss, &rdev->bss_list, list) {
2663
+ if (!cfg80211_bss_type_match(bss->pub.capability,
2664
+ bss->pub.channel->band,
2665
+ wdev->conn_bss_type))
2666
+ continue;
2667
+
2668
+ if (bss == cbss)
2669
+ continue;
2670
+
2671
+ if (!cmp_bss(&bss->pub, &cbss->pub, BSS_CMP_REGULAR)) {
2672
+ new = bss;
2673
+ break;
2674
+ }
2675
+ }
2676
+
2677
+ if (new) {
2678
+ /* to save time, update IEs for transmitting bss only */
2679
+ if (cfg80211_update_known_bss(rdev, cbss, new, false)) {
2680
+ new->pub.proberesp_ies = NULL;
2681
+ new->pub.beacon_ies = NULL;
2682
+ }
2683
+
2684
+ list_for_each_entry_safe(nontrans_bss, tmp,
2685
+ &new->pub.nontrans_list,
2686
+ nontrans_list) {
2687
+ bss = container_of(nontrans_bss,
2688
+ struct cfg80211_internal_bss, pub);
2689
+ if (__cfg80211_unlink_bss(rdev, bss))
2690
+ rdev->bss_generation++;
2691
+ }
2692
+
2693
+ WARN_ON(atomic_read(&new->hold));
2694
+ if (!WARN_ON(!__cfg80211_unlink_bss(rdev, new)))
2695
+ rdev->bss_generation++;
2696
+ }
2697
+
2698
+ rb_erase(&cbss->rbn, &rdev->bss_tree);
2699
+ rb_insert_bss(rdev, cbss);
2700
+ rdev->bss_generation++;
2701
+
2702
+ list_for_each_entry_safe(nontrans_bss, tmp,
2703
+ &cbss->pub.nontrans_list,
2704
+ nontrans_list) {
2705
+ bss = container_of(nontrans_bss,
2706
+ struct cfg80211_internal_bss, pub);
2707
+ bss->pub.channel = chan;
2708
+ rb_erase(&bss->rbn, &rdev->bss_tree);
2709
+ rb_insert_bss(rdev, bss);
2710
+ rdev->bss_generation++;
2711
+ }
2712
+
2713
+done:
2714
+ spin_unlock_bh(&rdev->bss_lock);
2715
+}
2716
+
18242717 #ifdef CONFIG_CFG80211_WEXT
18252718 static struct cfg80211_registered_device *
18262719 cfg80211_get_dev_from_ifindex(struct net *net, int ifindex)