diff mbox series

[04/16] cfg80211: Use the HE operation IE to determine a 6GHz BSS channel

Message ID iwlwifi.20211129152938.8efcf1856975.I130f678e4aa390973ab39d838bbfe7b2d54bff8e@changeid (mailing list archive)
State Superseded
Delegated to: Johannes Berg
Headers show
Series cfg80211/mac80211 patches from our internal tree 2021-11-29 | expand

Commit Message

Luca Coelho Nov. 29, 2021, 1:32 p.m. UTC
From: Ayala Beker <ayala.beker@intel.com>

A non-collocated AP whose primary channel is not a PSC channel
may transmit a duplicated beacon on the corresponding PSC channel
in which it would indicate its true primary channel.
Use this inforamtion contained in the HE operation IE to determine
the primary channel of the AP.
In case of invalid infomration ignore it and use the channel
the frame was received on.

Signed-off-by: Ayala Beker <ayala.beker@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 net/wireless/scan.c | 46 ++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 41 insertions(+), 5 deletions(-)

Comments

Luca Coelho Dec. 2, 2021, 12:28 p.m. UTC | #1
On Mon, 2021-11-29 at 15:32 +0200, Luca Coelho wrote:
> From: Ayala Beker <ayala.beker@intel.com>
> 
> A non-collocated AP whose primary channel is not a PSC channel
> may transmit a duplicated beacon on the corresponding PSC channel
> in which it would indicate its true primary channel.
> Use this inforamtion contained in the HE operation IE to determine
> the primary channel of the AP.
> In case of invalid infomration ignore it and use the channel
> the frame was received on.
> 
> Signed-off-by: Ayala Beker <ayala.beker@intel.com>
> Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
> ---

As you know already (but for the record), this is totally broken. 
There were some conflicts due to the refactor that happened in this
function and I accidentally ran the wrong script to test compilation
before sending this series out... :(

V2 coming up soon.

--
Cheers,
Luca.
diff mbox series

Patch

diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 22e92be61938..3fd0757ead29 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -1800,7 +1800,33 @@  int cfg80211_get_ies_channel_number(const u8 *ie, size_t ielen,
 	const u8 *tmp;
 	int channel_number = -1;
 
-	if (band == NL80211_BAND_S1GHZ) {
+	if (channel->band == NL80211_BAND_6GHZ) {
+		const struct element *elem;
+
+		elem = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ie,
+					      ielen);
+		if (elem && elem->datalen >= ieee80211_he_oper_size(&elem->data[1])) {
+			struct ieee80211_he_operation *he_oper =
+				(void *)(&elem->data[1]);
+			const struct ieee80211_he_6ghz_oper *he_6ghz_oper;
+
+			he_6ghz_oper = ieee80211_he_6ghz_oper(he_oper);
+			if (!he_6ghz_oper)
+				return channel;
+
+			freq = ieee80211_channel_to_frequency(he_6ghz_oper->primary,
+							      NL80211_BAND_6GHZ);
+
+			/* duplicated beacon indication is relevant for beacons
+			 * only
+			 */
+			if (freq != channel->center_freq &&
+			    abs(freq - channel->center_freq) <= 80 &&
+			    (ftype != CFG80211_BSS_FTYPE_BEACON ||
+			     he_6ghz_oper->control & IEEE80211_HE_6GHZ_OPER_CTRL_DUP_BEACON))
+				channel_number = he_6ghz_oper->primary;
+		}
+	} else if (band == NL80211_BAND_S1GHZ) {
 		tmp = cfg80211_find_ie(WLAN_EID_S1G_OPERATION, ie, ielen);
 		if (tmp && tmp[1] >= sizeof(struct ieee80211_s1g_oper_ie)) {
 			struct ieee80211_s1g_oper_ie *s1gop = (void *)(tmp + 2);
@@ -1831,12 +1857,13 @@  EXPORT_SYMBOL(cfg80211_get_ies_channel_number);
  * from neighboring channels and the Beacon frames use the DSSS Parameter Set
  * element to indicate the current (transmitting) channel, but this might also
  * be needed on other bands if RX frequency does not match with the actual
- * operating channel of a BSS.
+ * operating channel of a BSS, or if the AP reports a different primary channel.
  */
 static struct ieee80211_channel *
 cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
 			 struct ieee80211_channel *channel,
-			 enum nl80211_bss_scan_width scan_width)
+			 enum nl80211_bss_scan_width scan_width,
+			 enum cfg80211_bss_frame_type ftype)
 {
 	u32 freq;
 	int channel_number;
@@ -1911,7 +1938,7 @@  cfg80211_inform_single_bss_data(struct wiphy *wiphy,
 		return NULL;
 
 	channel = cfg80211_get_bss_channel(wiphy, ie, ielen, data->chan,
-					   data->scan_width);
+					   data->scan_width, ftype);
 	if (!channel)
 		return NULL;
 
@@ -2333,6 +2360,7 @@  cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
 	size_t ielen, min_hdr_len = offsetof(struct ieee80211_mgmt,
 					     u.probe_resp.variable);
 	int bss_type;
+	enum cfg80211_bss_frame_type ftype;
 
 	BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=
 			offsetof(struct ieee80211_mgmt, u.beacon.variable));
@@ -2369,8 +2397,16 @@  cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
 			variable = ext->u.s1g_beacon.variable;
 	}
 
+	if (ieee80211_is_beacon(mgmt->frame_control))
+		ftype = CFG80211_BSS_FTYPE_BEACON;
+	else if (ieee80211_is_probe_resp(mgmt->frame_control))
+		ftype = CFG80211_BSS_FTYPE_PRESP;
+	else
+		ftype = CFG80211_BSS_FTYPE_UNKNOWN;
+
 	channel = cfg80211_get_bss_channel(wiphy, variable,
-					   ielen, data->chan, data->scan_width);
+					   ielen, data->chan, data->scan_width,
+					   ftype);
 	if (!channel)
 		return NULL;