History

nl80211/cfg80211: support 6 GHz scanning

Support 6 GHz scanning, by * a new scan flag to scan for colocated BSSes advertised by (and found) APs on 2.4 & 5 GHz * doing the necessary reduced neighbor report parsing for this, to find them * adding the ability to split the scan request in case the device by itself cannot support this. Also add some necessary bits in mac80211 to not break with these changes.

Tova Mussai committed 6 years ago

Commit c8cb5b81 parent dba04917 files · +552 −17Browse files

Unified · Split

7 files
  1. include/net/cfg80211.h +31 −1
  2. include/uapi/linux/nl80211.h +3 −0
  3. net/mac80211/scan.c +7 −2
  4. net/wireless/core.c +6 −2
  5. net/wireless/core.h +4 −1
  6. net/wireless/nl80211.c +7 −4
  7. net/wireless/scan.c +494 −7
include/net/cfg80211.h+31−1
@@ -2095,6 +2095,27 @@ struct cfg80211_scan_info { · 2094 unmodified lines
2095 bool aborted;2095 bool aborted;
2096};2096};
2097 2097
2098/**
2099 * struct cfg80211_scan_6ghz_params - relevant for 6 GHz only
2100 *
2101 * @short_bssid: short ssid to scan for
2102 * @bssid: bssid to scan for
2103 * @channel_idx: idx of the channel in the channel array in the scan request
2104 * which the above info relvant to
2105 * @unsolicited_probe: the AP transmits unsolicited probe response every 20 TU
2106 * @short_ssid_valid: short_ssid is valid and can be used
2107 * @psc_no_listen: when set, and the channel is a PSC channel, no need to wait
2108 * 20 TUs before starting to send probe requests.
2109 */
2110struct cfg80211_scan_6ghz_params {
2111 u32 short_ssid;
2112 u32 channel_idx;
2113 u8 bssid[ETH_ALEN];
2114 bool unsolicited_probe;
2115 bool short_ssid_valid;
2116 bool psc_no_listen;
2117};
2118
2098/**2119/**
2099 * struct cfg80211_scan_request - scan request description2120 * struct cfg80211_scan_request - scan request description
2100 *2121 *
@@ -2122,6 +2143,10 @@ struct cfg80211_scan_info { · 21 unmodified lines
2122 * @mac_addr_mask: MAC address mask used with randomisation, bits that2143 * @mac_addr_mask: MAC address mask used with randomisation, bits that
2123 * are 0 in the mask should be randomised, bits that are 1 should2144 * are 0 in the mask should be randomised, bits that are 1 should
2124 * be taken from the @mac_addr2145 * be taken from the @mac_addr
2146 * @scan_6ghz: relevant for split scan request only,
2147 * true if this is the second scan request
2148 * @n_6ghz_params: number of 6 GHz params
2149 * @scan_6ghz_params: 6 GHz params
2125 * @bssid: BSSID to scan for (most commonly, the wildcard BSSID)2150 * @bssid: BSSID to scan for (most commonly, the wildcard BSSID)
2126 */2151 */
2127struct cfg80211_scan_request {2152struct cfg80211_scan_request {
@@ -2149,6 +2174,9 @@ struct cfg80211_scan_request { · 21 unmodified lines
2149 struct cfg80211_scan_info info;2174 struct cfg80211_scan_info info;
2150 bool notified;2175 bool notified;
2151 bool no_cck;2176 bool no_cck;
2177 bool scan_6ghz;
2178 u32 n_6ghz_params;
2179 struct cfg80211_scan_6ghz_params *scan_6ghz_params;
2152 2180
2153 /* keep last */2181 /* keep last */
2154 struct ieee80211_channel *channels[];2182 struct ieee80211_channel *channels[];
@@ -4217,6 +4245,8 @@ struct cfg80211_ops { · 2062 unmodified lines
4217/**4245/**
4218 * enum wiphy_flags - wiphy capability flags4246 * enum wiphy_flags - wiphy capability flags
4219 *4247 *
4248 * @WIPHY_FLAG_SPLIT_SCAN_6GHZ: if set to true, the scan request will be split
4249 * into two, first for legacy bands and second for UHB.
4220 * @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this4250 * @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this
4221 * wiphy at all4251 * wiphy at all
4222 * @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled4252 * @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled
@@ -4260,7 +4290,7 @@ struct cfg80211_ops { · 37 unmodified lines
4260enum wiphy_flags {4290enum wiphy_flags {
4261 WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK = BIT(0),4291 WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK = BIT(0),
4262 /* use hole at 1 */4292 /* use hole at 1 */
4263 /* use hole at 2 */4293 WIPHY_FLAG_SPLIT_SCAN_6GHZ = BIT(2),
4264 WIPHY_FLAG_NETNS_OK = BIT(3),4294 WIPHY_FLAG_NETNS_OK = BIT(3),
4265 WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4),4295 WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4),
4266 WIPHY_FLAG_4ADDR_AP = BIT(5),4296 WIPHY_FLAG_4ADDR_AP = BIT(5),
include/uapi/linux/nl80211.h+3−0
@@ -6059,6 +6059,8 @@ enum nl80211_timeout_reason { · 6058 unmodified lines
6059 * @NL80211_SCAN_FLAG_FREQ_KHZ: report scan results with6059 * @NL80211_SCAN_FLAG_FREQ_KHZ: report scan results with
6060 * %NL80211_ATTR_SCAN_FREQ_KHZ. This also means6060 * %NL80211_ATTR_SCAN_FREQ_KHZ. This also means
6061 * %NL80211_ATTR_SCAN_FREQUENCIES will not be included.6061 * %NL80211_ATTR_SCAN_FREQUENCIES will not be included.
6062 * @NL80211_SCAN_FLAG_COLOCATED_6GHZ: scan for colocated APs reported by
6063 * 2.4/5 GHz APs
6062 */6064 */
6063enum nl80211_scan_flags {6065enum nl80211_scan_flags {
6064 NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,6066 NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,
@@ -6075,6 +6077,7 @@ enum nl80211_scan_flags { · 10 unmodified lines
6075 NL80211_SCAN_FLAG_RANDOM_SN = 1<<11,6077 NL80211_SCAN_FLAG_RANDOM_SN = 1<<11,
6076 NL80211_SCAN_FLAG_MIN_PREQ_CONTENT = 1<<12,6078 NL80211_SCAN_FLAG_MIN_PREQ_CONTENT = 1<<12,
6077 NL80211_SCAN_FLAG_FREQ_KHZ = 1<<13,6079 NL80211_SCAN_FLAG_FREQ_KHZ = 1<<13,
6080 NL80211_SCAN_FLAG_COLOCATED_6GHZ = 1<<14,
6078};6081};
6079 6082
6080/**6083/**
net/mac80211/scan.c+7−2
@@ -9,7 +9,7 @@ · 8 unmodified lines
9 * Copyright 2007, Michael Wu <flamingice@sourmilk.net>9 * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
10 * Copyright 2013-2015 Intel Mobile Communications GmbH10 * Copyright 2013-2015 Intel Mobile Communications GmbH
11 * Copyright 2016-2017 Intel Deutschland GmbH11 * Copyright 2016-2017 Intel Deutschland GmbH
12 * Copyright (C) 2018-2019 Intel Corporation12 * Copyright (C) 2018-2020 Intel Corporation
13 */13 */
14 14
15#include <linux/if_arp.h>15#include <linux/if_arp.h>
@@ -712,6 +712,10 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, · 696 unmodified lines
712 req->duration_mandatory;712 req->duration_mandatory;
713 713
714 local->hw_scan_band = 0;714 local->hw_scan_band = 0;
715 local->hw_scan_req->req.n_6ghz_params = req->n_6ghz_params;
716 local->hw_scan_req->req.scan_6ghz_params =
717 req->scan_6ghz_params;
718 local->hw_scan_req->req.scan_6ghz = req->scan_6ghz;
715 719
716 /*720 /*
717 * After allocating local->hw_scan_req, we must721 * After allocating local->hw_scan_req, we must
@@ -1124,7 +1128,8 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, · 406 unmodified lines
1124 int max_n;1128 int max_n;
1125 1129
1126 for (band = 0; band < NUM_NL80211_BANDS; band++) {1130 for (band = 0; band < NUM_NL80211_BANDS; band++) {
1127 if (!local->hw.wiphy->bands[band])1131 if (!local->hw.wiphy->bands[band] ||
1132 band == NL80211_BAND_6GHZ)
1128 continue;1133 continue;
1129 1134
1130 max_n = local->hw.wiphy->bands[band]->n_channels;1135 max_n = local->hw.wiphy->bands[band]->n_channels;
net/wireless/core.c+6−2
@@ -236,7 +236,9 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, · 235 unmodified lines
236 rdev->opencount--;236 rdev->opencount--;
237 237
238 if (rdev->scan_req && rdev->scan_req->wdev == wdev) {238 if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
239 if (WARN_ON(!rdev->scan_req->notified))239 if (WARN_ON(!rdev->scan_req->notified &&
240 (!rdev->int_scan_req ||
241 !rdev->int_scan_req->notified)))
240 rdev->scan_req->info.aborted = true;242 rdev->scan_req->info.aborted = true;
241 ___cfg80211_scan_done(rdev, false);243 ___cfg80211_scan_done(rdev, false);
242 }244 }
@@ -1336,7 +1338,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, · 1093 unmodified lines
1336 case NETDEV_DOWN:1338 case NETDEV_DOWN:
1337 cfg80211_update_iface_num(rdev, wdev->iftype, -1);1339 cfg80211_update_iface_num(rdev, wdev->iftype, -1);
1338 if (rdev->scan_req && rdev->scan_req->wdev == wdev) {1340 if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
1339 if (WARN_ON(!rdev->scan_req->notified))1341 if (WARN_ON(!rdev->scan_req->notified &&
1342 (!rdev->int_scan_req ||
1343 !rdev->int_scan_req->notified)))
1340 rdev->scan_req->info.aborted = true;1344 rdev->scan_req->info.aborted = true;
1341 ___cfg80211_scan_done(rdev, false);1345 ___cfg80211_scan_done(rdev, false);
1342 }1346 }
net/wireless/core.h+4−1
@@ -3,7 +3,7 @@ · 2 unmodified lines
3 * Wireless configuration interface internals.3 * Wireless configuration interface internals.
4 *4 *
5 * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>5 * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
6 * Copyright (C) 2018-2019 Intel Corporation6 * Copyright (C) 2018-2020 Intel Corporation
7 */7 */
8#ifndef __NET_WIRELESS_CORE_H8#ifndef __NET_WIRELESS_CORE_H
9#define __NET_WIRELESS_CORE_H9#define __NET_WIRELESS_CORE_H
@@ -72,6 +72,7 @@ struct cfg80211_registered_device { · 62 unmodified lines
72 u32 bss_generation;72 u32 bss_generation;
73 u32 bss_entries;73 u32 bss_entries;
74 struct cfg80211_scan_request *scan_req; /* protected by RTNL */74 struct cfg80211_scan_request *scan_req; /* protected by RTNL */
75 struct cfg80211_scan_request *int_scan_req;
75 struct sk_buff *scan_msg;76 struct sk_buff *scan_msg;
76 struct list_head sched_scan_req_list;77 struct list_head sched_scan_req_list;
77 time64_t suspend_at;78 time64_t suspend_at;
@@ -457,6 +458,8 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev); · 379 unmodified lines
457bool cfg80211_does_bw_fit_range(const struct ieee80211_freq_range *freq_range,458bool cfg80211_does_bw_fit_range(const struct ieee80211_freq_range *freq_range,
458 u32 center_freq_khz, u32 bw_khz);459 u32 center_freq_khz, u32 bw_khz);
459 460
461int cfg80211_scan(struct cfg80211_registered_device *rdev);
462
460extern struct work_struct cfg80211_disconnect_work;463extern struct work_struct cfg80211_disconnect_work;
461 464
462/**465/**
net/wireless/nl80211.c+7−4
@@ -8236,7 +8236,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) · 8235 unmodified lines
8236 request->scan_start = jiffies;8236 request->scan_start = jiffies;
8237 8237
8238 rdev->scan_req = request;8238 rdev->scan_req = request;
8239 err = rdev_scan(rdev, request);8239 err = cfg80211_scan(rdev);
8240 8240
8241 if (err)8241 if (err)
8242 goto out_free;8242 goto out_free;
@@ -15518,6 +15518,7 @@ static int nl80211_add_scan_req(struct sk_buff *msg, · 7275 unmodified lines
15518 struct cfg80211_scan_request *req = rdev->scan_req;15518 struct cfg80211_scan_request *req = rdev->scan_req;
15519 struct nlattr *nest;15519 struct nlattr *nest;
15520 int i;15520 int i;
15521 struct cfg80211_scan_info *info;
15521 15522
15522 if (WARN_ON(!req))15523 if (WARN_ON(!req))
15523 return 0;15524 return 0;
@@ -15561,11 +15562,13 @@ static int nl80211_add_scan_req(struct sk_buff *msg, · 37 unmodified lines
15561 nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags))15562 nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags))
15562 goto nla_put_failure;15563 goto nla_put_failure;
15563 15564
15564 if (req->info.scan_start_tsf &&15565 info = rdev->int_scan_req ? &rdev->int_scan_req->info :
15566 &rdev->scan_req->info;
15567 if (info->scan_start_tsf &&
15565 (nla_put_u64_64bit(msg, NL80211_ATTR_SCAN_START_TIME_TSF,15568 (nla_put_u64_64bit(msg, NL80211_ATTR_SCAN_START_TIME_TSF,
15566 req->info.scan_start_tsf, NL80211_BSS_PAD) ||15569 info->scan_start_tsf, NL80211_BSS_PAD) ||
15567 nla_put(msg, NL80211_ATTR_SCAN_START_TIME_TSF_BSSID, ETH_ALEN,15570 nla_put(msg, NL80211_ATTR_SCAN_START_TIME_TSF_BSSID, ETH_ALEN,
15568 req->info.tsf_bssid)))15571 info->tsf_bssid)))
15569 goto nla_put_failure;15572 goto nla_put_failure;
15570 15573
15571 return 0;15574 return 0;
net/wireless/scan.c+494−7
@@ -5,7 +5,7 @@ · 4 unmodified lines
5 * Copyright 2008 Johannes Berg <johannes@sipsolutions.net>5 * Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
6 * Copyright 2013-2014 Intel Mobile Communications GmbH6 * Copyright 2013-2014 Intel Mobile Communications GmbH
7 * Copyright 2016 Intel Deutschland GmbH7 * Copyright 2016 Intel Deutschland GmbH
8 * Copyright (C) 2018-2019 Intel Corporation8 * Copyright (C) 2018-2020 Intel Corporation
9 */9 */
10#include <linux/kernel.h>10#include <linux/kernel.h>
11#include <linux/slab.h>11#include <linux/slab.h>
@@ -14,6 +14,8 @@ · 2 unmodified lines
14#include <linux/wireless.h>14#include <linux/wireless.h>
15#include <linux/nl80211.h>15#include <linux/nl80211.h>
16#include <linux/etherdevice.h>16#include <linux/etherdevice.h>
17#include <linux/crc32.h>
18#include <linux/bitfield.h>
17#include <net/arp.h>19#include <net/arp.h>
18#include <net/cfg80211.h>20#include <net/cfg80211.h>
19#include <net/cfg80211-wext.h>21#include <net/cfg80211-wext.h>
@@ -74,6 +76,43 @@ MODULE_PARM_DESC(bss_entries_limit, · 54 unmodified lines
74 76
75#define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ)77#define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ)
76 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 */
100struct 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};
115
77static void bss_free(struct cfg80211_internal_bss *bss)116static void bss_free(struct cfg80211_internal_bss *bss)
78{117{
79 struct cfg80211_bss_ies *ies;118 struct cfg80211_bss_ies *ies;
@@ -448,10 +487,433 @@ static bool cfg80211_bss_expire_oldest(struct cfg80211_registered_device *rdev) · 368 unmodified lines
448 return ret;487 return ret;
449}488}
450 489
490static u8 cfg80211_parse_bss_param(u8 data,
491 struct cfg80211_colocated_ap *coloc_ap)
492{
493 coloc_ap->oct_recommended =
494 u8_get_bits(data, IEEE80211_RNR_TBTT_PARAMS_OCT_RECOMMENDED);
495 coloc_ap->same_ssid =
496 u8_get_bits(data, IEEE80211_RNR_TBTT_PARAMS_SAME_SSID);
497 coloc_ap->multi_bss =
498 u8_get_bits(data, IEEE80211_RNR_TBTT_PARAMS_MULTI_BSSID);
499 coloc_ap->transmitted_bssid =
500 u8_get_bits(data, IEEE80211_RNR_TBTT_PARAMS_TRANSMITTED_BSSID);
501 coloc_ap->unsolicited_probe =
502 u8_get_bits(data, IEEE80211_RNR_TBTT_PARAMS_PROBE_ACTIVE);
503 coloc_ap->colocated_ess =
504 u8_get_bits(data, IEEE80211_RNR_TBTT_PARAMS_COLOC_ESS);
505
506 return u8_get_bits(data, IEEE80211_RNR_TBTT_PARAMS_COLOC_AP);
507}
508
509static int cfg80211_calc_short_ssid(const struct cfg80211_bss_ies *ies,
510 const struct element **elem, u32 *s_ssid)
511{
512
513 *elem = cfg80211_find_elem(WLAN_EID_SSID, ies->data, ies->len);
514 if (!*elem || (*elem)->datalen > IEEE80211_MAX_SSID_LEN)
515 return -EINVAL;
516
517 *s_ssid = ~crc32_le(~0, (*elem)->data, (*elem)->datalen);
518 return 0;
519}
520
521static void cfg80211_free_coloc_ap_list(struct list_head *coloc_ap_list)
522{
523 struct cfg80211_colocated_ap *ap, *tmp_ap;
524
525 list_for_each_entry_safe(ap, tmp_ap, coloc_ap_list, list) {
526 list_del(&ap->list);
527 kfree(ap);
528 }
529}
530
531static int cfg80211_parse_ap_info(struct cfg80211_colocated_ap *entry,
532 const u8 *pos, u8 length,
533 const struct element *ssid_elem,
534 int s_ssid_tmp)
535{
536 /* skip the TBTT offset */
537 pos++;
538
539 memcpy(entry->bssid, pos, ETH_ALEN);
540 pos += ETH_ALEN;
541
542 if (length == IEEE80211_TBTT_INFO_OFFSET_BSSID_SSSID_BSS_PARAM) {
543 memcpy(&entry->short_ssid, pos,
544 sizeof(entry->short_ssid));
545 entry->short_ssid_valid = true;
546 pos += 4;
547 }
548
549 /* skip non colocated APs */
550 if (!cfg80211_parse_bss_param(*pos, entry))
551 return -EINVAL;
552 pos++;
553
554 if (length == IEEE80211_TBTT_INFO_OFFSET_BSSID_BSS_PARAM) {
555 /*
556 * no information about the short ssid. Consider the entry valid
557 * for now. It would later be dropped in case there are explicit
558 * SSIDs that need to be matched
559 */
560 if (!entry->same_ssid)
561 return 0;
562 }
563
564 if (entry->same_ssid) {
565 entry->short_ssid = s_ssid_tmp;
566 entry->short_ssid_valid = true;
567
568 /*
569 * This is safe because we validate datalen in
570 * cfg80211_parse_colocated_ap(), before calling this
571 * function.
572 */
573 memcpy(&entry->ssid, &ssid_elem->data,
574 ssid_elem->datalen);
575 entry->ssid_len = ssid_elem->datalen;
576 }
577 return 0;
578}
579
580static int cfg80211_parse_colocated_ap(const struct cfg80211_bss_ies *ies,
581 struct list_head *list)
582{
583 struct ieee80211_neighbor_ap_info *ap_info;
584 const struct element *elem, *ssid_elem;
585 const u8 *pos, *end;
586 u32 s_ssid_tmp;
587 int n_coloc = 0, ret;
588 LIST_HEAD(ap_list);
589
590 elem = cfg80211_find_elem(WLAN_EID_REDUCED_NEIGHBOR_REPORT, ies->data,
591 ies->len);
592 if (!elem || elem->datalen > IEEE80211_MAX_SSID_LEN)
593 return 0;
594
595 pos = elem->data;
596 end = pos + elem->datalen;
597
598 ret = cfg80211_calc_short_ssid(ies, &ssid_elem, &s_ssid_tmp);
599 if (ret)
600 return ret;
601
602 /* RNR IE may contain more than one NEIGHBOR_AP_INFO */
603 while (pos + sizeof(*ap_info) <= end) {
604 enum nl80211_band band;
605 int freq;
606 u8 length, i, count;
607
608 ap_info = (void *)pos;
609 count = u8_get_bits(ap_info->tbtt_info_hdr,
610 IEEE80211_AP_INFO_TBTT_HDR_COUNT) + 1;
611 length = ap_info->tbtt_info_len;
612
613 pos += sizeof(*ap_info);
614
615 if (!ieee80211_operating_class_to_band(ap_info->op_class,
616 &band))
617 break;
618
619 freq = ieee80211_channel_to_frequency(ap_info->channel, band);
620
621 if (end - pos < count * ap_info->tbtt_info_len)
622 break;
623
624 /*
625 * TBTT info must include bss param + BSSID +
626 * (short SSID or same_ssid bit to be set).
627 * ignore other options, and move to the
628 * next AP info
629 */
630 if (band != NL80211_BAND_6GHZ ||
631 (length != IEEE80211_TBTT_INFO_OFFSET_BSSID_BSS_PARAM &&
632 length < IEEE80211_TBTT_INFO_OFFSET_BSSID_SSSID_BSS_PARAM)) {
633 pos += count * ap_info->tbtt_info_len;
634 continue;
635 }
636
637 for (i = 0; i < count; i++) {
638 struct cfg80211_colocated_ap *entry;
639
640 entry = kzalloc(sizeof(*entry) + IEEE80211_MAX_SSID_LEN,
641 GFP_ATOMIC);
642
643 if (!entry)
644 break;
645
646 entry->center_freq = freq;
647
648 if (!cfg80211_parse_ap_info(entry, pos, length,
649 ssid_elem, s_ssid_tmp)) {
650 n_coloc++;
651 list_add_tail(&entry->list, &ap_list);
652 } else {
653 kfree(entry);
654 }
655
656 pos += ap_info->tbtt_info_len;
657 }
658 }
659
660 if (pos != end) {
661 cfg80211_free_coloc_ap_list(&ap_list);
662 return 0;
663 }
664
665 list_splice_tail(&ap_list, list);
666 return n_coloc;
667}
668
669static void cfg80211_scan_req_add_chan(struct cfg80211_scan_request *request,
670 struct ieee80211_channel *chan,
671 bool add_to_6ghz)
672{
673 int i;
674 u32 n_channels = request->n_channels;
675 struct cfg80211_scan_6ghz_params *params =
676 &request->scan_6ghz_params[request->n_6ghz_params];
677
678 for (i = 0; i < n_channels; i++) {
679 if (request->channels[i] == chan) {
680 if (add_to_6ghz)
681 params->channel_idx = i;
682 return;
683 }
684 }
685
686 request->channels[n_channels] = chan;
687 if (add_to_6ghz)
688 request->scan_6ghz_params[request->n_6ghz_params].channel_idx =
689 n_channels;
690
691 request->n_channels++;
692}
693
694static bool cfg80211_find_ssid_match(struct cfg80211_colocated_ap *ap,
695 struct cfg80211_scan_request *request)
696{
697 u8 i;
698 u32 s_ssid;
699
700 for (i = 0; i < request->n_ssids; i++) {
701 /* wildcard ssid in the scan request */
702 if (!request->ssids[i].ssid_len)
703 return true;
704
705 if (ap->ssid_len &&
706 ap->ssid_len == request->ssids[i].ssid_len) {
707 if (!memcmp(request->ssids[i].ssid, ap->ssid,
708 ap->ssid_len))
709 return true;
710 } else if (ap->short_ssid_valid) {
711 s_ssid = ~crc32_le(~0, request->ssids[i].ssid,
712 request->ssids[i].ssid_len);
713
714 if (ap->short_ssid == s_ssid)
715 return true;
716 }
717 }
718
719 return false;
720}
721
722static int cfg80211_scan_6ghz(struct cfg80211_registered_device *rdev)
723{
724 u8 i;
725 struct cfg80211_colocated_ap *ap;
726 int n_channels, count = 0, err;
727 struct cfg80211_scan_request *request, *rdev_req = rdev->scan_req;
728 LIST_HEAD(coloc_ap_list);
729 bool need_scan_psc;
730 const struct ieee80211_sband_iftype_data *iftd;
731
732 rdev_req->scan_6ghz = true;
733
734 if (!rdev->wiphy.bands[NL80211_BAND_6GHZ])
735 return -EOPNOTSUPP;
736
737 iftd = ieee80211_get_sband_iftype_data(rdev->wiphy.bands[NL80211_BAND_6GHZ],
738 rdev_req->wdev->iftype);
739 if (!iftd || !iftd->he_cap.has_he)
740 return -EOPNOTSUPP;
741
742 n_channels = rdev->wiphy.bands[NL80211_BAND_6GHZ]->n_channels;
743
744 if (rdev_req->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ) {
745 struct cfg80211_internal_bss *intbss;
746
747 spin_lock_bh(&rdev->bss_lock);
748 list_for_each_entry(intbss, &rdev->bss_list, list) {
749 struct cfg80211_bss *res = &intbss->pub;
750 const struct cfg80211_bss_ies *ies;
751
752 ies = rcu_access_pointer(res->ies);
753 count += cfg80211_parse_colocated_ap(ies,
754 &coloc_ap_list);
755 }
756 spin_unlock_bh(&rdev->bss_lock);
757 }
758
759 request = kzalloc(struct_size(request, channels, n_channels) +
760 sizeof(*request->scan_6ghz_params) * count,
761 GFP_KERNEL);
762 if (!request) {
763 cfg80211_free_coloc_ap_list(&coloc_ap_list);
764 return -ENOMEM;
765 }
766
767 *request = *rdev_req;
768 request->n_channels = 0;
769 request->scan_6ghz_params =
770 (void *)&request->channels[n_channels];
771
772 /*
773 * PSC channels should not be scanned if all the reported co-located APs
774 * are indicating that all APs in the same ESS are co-located
775 */
776 if (count) {
777 need_scan_psc = false;
778
779 list_for_each_entry(ap, &coloc_ap_list, list) {
780 if (!ap->colocated_ess) {
781 need_scan_psc = true;
782 break;
783 }
784 }
785 } else {
786 need_scan_psc = true;
787 }
788
789 /*
790 * add to the scan request the channels that need to be scanned
791 * regardless of the collocated APs (PSC channels or all channels
792 * in case that NL80211_SCAN_FLAG_COLOCATED_6GHZ is not set)
793 */
794 for (i = 0; i < rdev_req->n_channels; i++) {
795 if (rdev_req->channels[i]->band == NL80211_BAND_6GHZ &&
796 ((need_scan_psc &&
797 cfg80211_channel_is_psc(rdev_req->channels[i])) ||
798 !(rdev_req->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ))) {
799 cfg80211_scan_req_add_chan(request,
800 rdev_req->channels[i],
801 false);
802 }
803 }
804
805 if (!(rdev_req->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ))
806 goto skip;
807
808 list_for_each_entry(ap, &coloc_ap_list, list) {
809 bool found = false;
810 struct cfg80211_scan_6ghz_params *scan_6ghz_params =
811 &request->scan_6ghz_params[request->n_6ghz_params];
812 struct ieee80211_channel *chan =
813 ieee80211_get_channel(&rdev->wiphy, ap->center_freq);
814
815 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
816 continue;
817
818 for (i = 0; i < rdev_req->n_channels; i++) {
819 if (rdev_req->channels[i] == chan)
820 found = true;
821 }
822
823 if (!found)
824 continue;
825
826 if (request->n_ssids > 0 &&
827 !cfg80211_find_ssid_match(ap, request))
828 continue;
829
830 cfg80211_scan_req_add_chan(request, chan, true);
831 memcpy(scan_6ghz_params->bssid, ap->bssid, ETH_ALEN);
832 scan_6ghz_params->short_ssid = ap->short_ssid;
833 scan_6ghz_params->short_ssid_valid = ap->short_ssid_valid;
834 scan_6ghz_params->unsolicited_probe = ap->unsolicited_probe;
835
836 /*
837 * If a PSC channel is added to the scan and 'need_scan_psc' is
838 * set to false, then all the APs that the scan logic is
839 * interested with on the channel are collocated and thus there
840 * is no need to perform the initial PSC channel listen.
841 */
842 if (cfg80211_channel_is_psc(chan) && !need_scan_psc)
843 scan_6ghz_params->psc_no_listen = true;
844
845 request->n_6ghz_params++;
846 }
847
848skip:
849 cfg80211_free_coloc_ap_list(&coloc_ap_list);
850
851 if (request->n_channels) {
852 struct cfg80211_scan_request *old = rdev->int_scan_req;
853
854 rdev->int_scan_req = request;
855
856 /*
857 * If this scan follows a previous scan, save the scan start
858 * info from the first part of the scan
859 */
860 if (old)
861 rdev->int_scan_req->info = old->info;
862
863 err = rdev_scan(rdev, request);
864 if (err) {
865 rdev->int_scan_req = old;
866 kfree(request);
867 } else {
868 kfree(old);
869 }
870
871 return err;
872 }
873
874 kfree(request);
875 return -EINVAL;
876}
877
878int cfg80211_scan(struct cfg80211_registered_device *rdev)
879{
880 struct cfg80211_scan_request *request;
881 struct cfg80211_scan_request *rdev_req = rdev->scan_req;
882 u32 n_channels = 0, idx, i;
883
884 if (!(rdev->wiphy.flags & WIPHY_FLAG_SPLIT_SCAN_6GHZ))
885 return rdev_scan(rdev, rdev_req);
886
887 for (i = 0; i < rdev_req->n_channels; i++) {
888 if (rdev_req->channels[i]->band != NL80211_BAND_6GHZ)
889 n_channels++;
890 }
891
892 if (!n_channels)
893 return cfg80211_scan_6ghz(rdev);
894
895 request = kzalloc(struct_size(request, channels, n_channels),
896 GFP_KERNEL);
897 if (!request)
898 return -ENOMEM;
899
900 *request = *rdev_req;
901 request->n_channels = n_channels;
902
903 for (i = idx = 0; i < rdev_req->n_channels; i++) {
904 if (rdev_req->channels[i]->band != NL80211_BAND_6GHZ)
905 request->channels[idx++] = rdev_req->channels[i];
906 }
907
908 rdev_req->scan_6ghz = false;
909 rdev->int_scan_req = request;
910 return rdev_scan(rdev, request);
911}
912
451void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,913void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
452 bool send_message)914 bool send_message)
453{915{
454 struct cfg80211_scan_request *request;916 struct cfg80211_scan_request *request, *rdev_req;
455 struct wireless_dev *wdev;917 struct wireless_dev *wdev;
456 struct sk_buff *msg;918 struct sk_buff *msg;
457#ifdef CONFIG_CFG80211_WEXT919#ifdef CONFIG_CFG80211_WEXT
@@ -466,11 +928,18 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, · 8 unmodified lines
466 return;928 return;
467 }929 }
468 930
469 request = rdev->scan_req;931 rdev_req = rdev->scan_req;
470 if (!request)932 if (!rdev_req)
471 return;933 return;
472 934
473 wdev = request->wdev;935 wdev = rdev_req->wdev;
936 request = rdev->int_scan_req ? rdev->int_scan_req : rdev_req;
937
938 if (wdev_running(wdev) &&
939 (rdev->wiphy.flags & WIPHY_FLAG_SPLIT_SCAN_6GHZ) &&
940 !rdev_req->scan_6ghz && !request->info.aborted &&
941 !cfg80211_scan_6ghz(rdev))
942 return;
474 943
475 /*944 /*
476 * This must be before sending the other events!945 * This must be before sending the other events!
@@ -501,8 +970,11 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, · 24 unmodified lines
501 if (wdev->netdev)970 if (wdev->netdev)
502 dev_put(wdev->netdev);971 dev_put(wdev->netdev);
503 972
973 kfree(rdev->int_scan_req);
974 rdev->int_scan_req = NULL;
975
976 kfree(rdev->scan_req);
504 rdev->scan_req = NULL;977 rdev->scan_req = NULL;
505 kfree(request);
506 978
507 if (!send_message)979 if (!send_message)
508 rdev->scan_msg = msg;980 rdev->scan_msg = msg;
@@ -525,10 +997,25 @@ void __cfg80211_scan_done(struct work_struct *wk) · 16 unmodified lines
525void cfg80211_scan_done(struct cfg80211_scan_request *request,997void cfg80211_scan_done(struct cfg80211_scan_request *request,
526 struct cfg80211_scan_info *info)998 struct cfg80211_scan_info *info)
527{999{
1000 struct cfg80211_scan_info old_info = request->info;
1001
528 trace_cfg80211_scan_done(request, info);1002 trace_cfg80211_scan_done(request, info);
529 WARN_ON(request != wiphy_to_rdev(request->wiphy)->scan_req);1003 WARN_ON(request != wiphy_to_rdev(request->wiphy)->scan_req &&
1004 request != wiphy_to_rdev(request->wiphy)->int_scan_req);
530 1005
531 request->info = *info;1006 request->info = *info;
1007
1008 /*
1009 * In case the scan is split, the scan_start_tsf and tsf_bssid should
1010 * be of the first part. In such a case old_info.scan_start_tsf should
1011 * be non zero.
1012 */
1013 if (request->scan_6ghz && old_info.scan_start_tsf) {
1014 request->info.scan_start_tsf = old_info.scan_start_tsf;
1015 memcpy(request->info.tsf_bssid, old_info.tsf_bssid,
1016 sizeof(request->info.tsf_bssid));
1017 }
1018
532 request->notified = true;1019 request->notified = true;
533 queue_work(cfg80211_wq, &wiphy_to_rdev(request->wiphy)->scan_done_wk);1020 queue_work(cfg80211_wq, &wiphy_to_rdev(request->wiphy)->scan_done_wk);
534}1021}