diff mbox series

wifi: cfg80211: reject non-conformant 6 GHz center frequencies

Message ID 20240602102200.876b10a2beda.I0d3d0daea4014e99654437ff6691378dbe452652@changeid (mailing list archive)
State Accepted
Delegated to: Johannes Berg
Headers show
Series wifi: cfg80211: reject non-conformant 6 GHz center frequencies | expand

Commit Message

Korenblit, Miriam Rachel June 2, 2024, 7:22 a.m. UTC
From: Benjamin Berg <benjamin.berg@intel.com>

On 6 GHz (and also 5 GHz to some degree), only a specific set of center
frequencies should be used depending on the channel bandwidth. Verify
this is the case on 6 GHz. For 5 GHz, we are more accepting as there are
APs that got it wrong historically.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 net/wireless/chan.c       | 38 ++++++++++++++++++++++++++++++++++++++
 net/wireless/tests/chan.c | 22 +++++++++++-----------
 2 files changed, 49 insertions(+), 11 deletions(-)
diff mbox series

Patch

diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 3414b2c3abcc..bc98573f36be 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -263,6 +263,37 @@  static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
 	return nl80211_chan_width_to_mhz(c->width);
 }
 
+static bool cfg80211_valid_center_freq(u32 center,
+				       enum nl80211_chan_width width)
+{
+	int bw;
+	int step;
+
+	/* We only do strict verification on 6 GHz */
+	if (center < 5955 || center > 7115)
+		return true;
+
+	bw = nl80211_chan_width_to_mhz(width);
+	if (bw < 0)
+		return false;
+
+	/* Validate that the channels bw is entirely within the 6 GHz band */
+	if (center - bw / 2 < 5945 || center + bw / 2 > 7125)
+		return false;
+
+	/* With 320 MHz the permitted channels overlap */
+	if (bw == 320)
+		step = 160;
+	else
+		step = bw;
+
+	/*
+	 * Valid channels are packed from lowest frequency towards higher ones.
+	 * So test that the lower frequency alignes with one of these steps.
+	 */
+	return (center - bw / 2 - 5945) % step == 0;
+}
+
 bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
 {
 	u32 control_freq, oper_freq;
@@ -374,6 +405,13 @@  bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
 		return false;
 	}
 
+	if (!cfg80211_valid_center_freq(chandef->center_freq1, chandef->width))
+		return false;
+
+	if (chandef->width == NL80211_CHAN_WIDTH_80P80 &&
+	    !cfg80211_valid_center_freq(chandef->center_freq2, chandef->width))
+		return false;
+
 	/* channel 14 is only for IEEE 802.11b */
 	if (chandef->center_freq1 == 2484 &&
 	    chandef->width != NL80211_CHAN_WIDTH_20_NOHT)
diff --git a/net/wireless/tests/chan.c b/net/wireless/tests/chan.c
index d02258ac2dab..74bbee25085f 100644
--- a/net/wireless/tests/chan.c
+++ b/net/wireless/tests/chan.c
@@ -113,16 +113,16 @@  static const struct chandef_compat_case {
 		},
 	},
 	{
-		.desc = "different primary 160 MHz",
+		.desc = "different primary 320 MHz",
 		.c1 = {
 			.width = NL80211_CHAN_WIDTH_320,
 			.chan = &chan_6ghz_105,
-			.center_freq1 = 6475 + 150,
+			.center_freq1 = 6475 + 110,
 		},
 		.c2 = {
 			.width = NL80211_CHAN_WIDTH_320,
 			.chan = &chan_6ghz_105,
-			.center_freq1 = 6475 - 10,
+			.center_freq1 = 6475 - 50,
 		},
 	},
 	{
@@ -131,12 +131,12 @@  static const struct chandef_compat_case {
 		.c1 = {
 			.width = NL80211_CHAN_WIDTH_160,
 			.chan = &chan_6ghz_105,
-			.center_freq1 = 6475 + 70,
+			.center_freq1 = 6475 + 30,
 		},
 		.c2 = {
 			.width = NL80211_CHAN_WIDTH_320,
 			.chan = &chan_6ghz_105,
-			.center_freq1 = 6475 - 10,
+			.center_freq1 = 6475 - 50,
 		},
 		.compat = true,
 	},
@@ -145,12 +145,12 @@  static const struct chandef_compat_case {
 		.c1 = {
 			.width = NL80211_CHAN_WIDTH_160,
 			.chan = &chan_6ghz_105,
-			.center_freq1 = 6475 + 70,
+			.center_freq1 = 6475 + 30,
 		},
 		.c2 = {
 			.width = NL80211_CHAN_WIDTH_320,
 			.chan = &chan_6ghz_105,
-			.center_freq1 = 6475 - 10,
+			.center_freq1 = 6475 - 50,
 			.punctured = 0xf,
 		},
 		.compat = true,
@@ -160,13 +160,13 @@  static const struct chandef_compat_case {
 		.c1 = {
 			.width = NL80211_CHAN_WIDTH_160,
 			.chan = &chan_6ghz_105,
-			.center_freq1 = 6475 + 70,
+			.center_freq1 = 6475 + 30,
 			.punctured = 0xc0,
 		},
 		.c2 = {
 			.width = NL80211_CHAN_WIDTH_320,
 			.chan = &chan_6ghz_105,
-			.center_freq1 = 6475 - 10,
+			.center_freq1 = 6475 - 50,
 			.punctured = 0xc000,
 		},
 		.compat = true,
@@ -176,13 +176,13 @@  static const struct chandef_compat_case {
 		.c1 = {
 			.width = NL80211_CHAN_WIDTH_160,
 			.chan = &chan_6ghz_105,
-			.center_freq1 = 6475 + 70,
+			.center_freq1 = 6475 + 30,
 			.punctured = 0x80,
 		},
 		.c2 = {
 			.width = NL80211_CHAN_WIDTH_320,
 			.chan = &chan_6ghz_105,
-			.center_freq1 = 6475 - 10,
+			.center_freq1 = 6475 - 50,
 			.punctured = 0xc000,
 		},
 	},