diff mbox series

[1/2] band: support band lookup fallback for buggy APs

Message ID 20240514141923.291148-1-prestwoj@gmail.com (mailing list archive)
State Accepted, archived
Headers show
Series [1/2] band: support band lookup fallback for buggy APs | expand

Checks

Context Check Description
tedd_an/pre-ci_am success Success
prestwoj/iwd-alpine-ci-fetch success Fetch PR
prestwoj/iwd-ci-gitlint success GitLint
prestwoj/iwd-ci-fetch success Fetch PR
prestwoj/iwd-alpine-ci-setupell success Prep - Setup ELL
prestwoj/iwd-ci-setupell success Prep - Setup ELL
prestwoj/iwd-ci-makedistcheck success Make Distcheck
prestwoj/iwd-alpine-ci-makedistcheck success Make Distcheck
prestwoj/iwd-ci-build success Build - Configure
prestwoj/iwd-alpine-ci-build success Build - Configure
prestwoj/iwd-ci-makecheckvalgrind success Make Check w/Valgrind
prestwoj/iwd-ci-makecheck success Make Check
prestwoj/iwd-ci-clang success clang PASS
prestwoj/iwd-alpine-ci-makecheckvalgrind success Make Check w/Valgrind
prestwoj/iwd-alpine-ci-makecheck success Make Check
prestwoj/iwd-ci-incremental_build success Incremental Build with patches
prestwoj/iwd-alpine-ci-incremental_build success Incremental Build with patches
prestwoj/iwd-ci-testrunner success test-runner PASS

Commit Message

James Prestwood May 14, 2024, 2:19 p.m. UTC
Its been seen that some vendors incorrectly set the 3rd byte of the
country code which causes the band lookup to fail with the provided
operating class. This isn't compliant with the spec, but its been
seen out in the wild and it causes IWD to behave poorly, specifically
with roaming since it cannot parse neighbor reports. This then
requires IWD to do a full scan on each roam.

Instead of a hard rejection, IWD can instead attempt to determine
the band by ignoring that 3rd byte and only use the alpha2 string.
This makes IWD slightly less strict but at the advantage of not being
crippled when exposed to poor AP configurations.
---
 src/band.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 55 insertions(+), 3 deletions(-)

Comments

Denis Kenzior May 14, 2024, 3:33 p.m. UTC | #1
Hi James,

On 5/14/24 9:19 AM, James Prestwood wrote:
> Its been seen that some vendors incorrectly set the 3rd byte of the
> country code which causes the band lookup to fail with the provided
> operating class. This isn't compliant with the spec, but its been
> seen out in the wild and it causes IWD to behave poorly, specifically
> with roaming since it cannot parse neighbor reports. This then
> requires IWD to do a full scan on each roam.
> 
> Instead of a hard rejection, IWD can instead attempt to determine
> the band by ignoring that 3rd byte and only use the alpha2 string.
> This makes IWD slightly less strict but at the advantage of not being
> crippled when exposed to poor AP configurations.
> ---
>   src/band.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++---
>   1 file changed, 55 insertions(+), 3 deletions(-)
> 

Both applied, thanks.

Regards,
-Denis
diff mbox series

Patch

diff --git a/src/band.c b/src/band.c
index 906d6197..6891d06c 100644
--- a/src/band.c
+++ b/src/band.c
@@ -1485,15 +1485,48 @@  static const uint8_t oper_class_cn_to_global[] = {
 	/* 128 - 130 is a 1 to 1 mapping */
 };
 
-enum band_freq band_oper_class_to_band(const uint8_t *country,
-					uint8_t oper_class)
+/*
+ * Annex C describes the country string encoding.
+ *
+ * If it is a country, the first two octets of this string is the two character
+ * country code as described in document ISO 3166-1. The third octet is one of
+ * the following:
+ *  1. an ASCII space character, if the regulations under which the station is
+ *     operating encompass all environments for the current frequency band in
+ *     the country,
+ *  2. an ASCII 'O' character, if the regulations under which the station is
+ *     operating are for an outdoor environment only, or
+ *  3. an ASCII 'I' character, if the regulations under which the station is
+ *     operating are for an indoor environment only.
+ *  4. an ASCII 'X' character, if the station is operating under a noncountry
+ *     entity. The first two octets of the noncountry entity is two ASCII 'XX'
+ *     characters.
+ *  5. the hexadecimal representation of the Operating Class table number
+ *     currently in use, from the set of tables defined in Annex E, e.g.,
+ *     Table E-1 is represented as x'01'.
+ */
+static enum band_freq oper_class_to_band(const uint8_t *country,
+					uint8_t oper_class,
+					bool ignore_country3)
 {
 	unsigned int i;
 	int table = 0;
 
-	if (country && country[2] >= 1 && country[2] <= 5)
+	/*
+	 * If a country is set, and the 3rd byte maps to some E-* table in the
+	 * spec use that (case 5). Only caveat here is some APs erroneously set
+	 * this 3rd byte. To work around we can fall back to case 1, where only
+	 * the first two characters are used to lookup the table.
+	 */
+	if (!ignore_country3 && country && country[2] >= 1 && country[2] <= 5)
 		table = country[2];
 	else if (country) {
+		/*
+		 * Assuming case 1, although its unlikely you would handle
+		 * cases 2 (O) or 3 (I) any differently. Case 4 (X) is unlikely
+		 * and we really wouldn't have enough information to correctly
+		 * determine the band in some obscure non-country domain.
+		 */
 		for (i = 0; i < L_ARRAY_SIZE(oper_class_us_codes); i++)
 			if (!memcmp(oper_class_us_codes[i], country, 2)) {
 				/* Use table E-1 */
@@ -1542,6 +1575,25 @@  enum band_freq band_oper_class_to_band(const uint8_t *country,
 		return 0;
 }
 
+enum band_freq band_oper_class_to_band(const uint8_t *country,
+					uint8_t oper_class)
+{
+	enum band_freq band = oper_class_to_band(country, oper_class, false);
+	if (!band) {
+		/* Fallback with no country string won't change anything */
+		if (!country)
+			return 0;
+
+		l_warn("Failed to find band with country string '%c%c %u' and "
+			"oper class %u, trying fallback",
+			country[0], country[1], country[2], oper_class);
+
+		return oper_class_to_band(country, oper_class, true);
+	}
+
+	return band;
+}
+
 const char *band_chandef_width_to_string(enum band_chandef_width width)
 {
 	switch (width) {