All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 01/13] wiphy: fix runtime error from bit shift
@ 2022-08-03 21:36 James Prestwood
  2022-08-03 21:36 ` [PATCH v2 02/13] scan: track scanned frequencies for entire request James Prestwood
                   ` (11 more replies)
  0 siblings, 12 replies; 16+ messages in thread
From: James Prestwood @ 2022-08-03 21:36 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

The compiler treated the '1' as an int type which was not big enough
to hold a bit shift of 31:

runtime error: left shift of 1 by 31 places cannot be represented in
		type 'int'

Instead of doing the iftype check manually, refactor
wiphy_get_supported_iftypes by adding a subroutine which just parses
out iftypes from a mask into a char** list. This removes the need to
case each iftype into a string.
---
 src/wiphy.c | 50 +++++++++++++++-----------------------------------
 1 file changed, 15 insertions(+), 35 deletions(-)

diff --git a/src/wiphy.c b/src/wiphy.c
index 026605fe..2514c95a 100644
--- a/src/wiphy.c
+++ b/src/wiphy.c
@@ -716,17 +716,16 @@ bool wiphy_constrain_freq_set(const struct wiphy *wiphy,
 	return true;
 }
 
-static char **wiphy_get_supported_iftypes(struct wiphy *wiphy, uint16_t mask)
+static char **wiphy_iftype_mask_to_str(uint16_t mask)
 {
-	uint16_t supported_mask = wiphy->supported_iftypes & mask;
-	char **ret = l_new(char *, __builtin_popcount(supported_mask) + 1);
+	char **ret = l_new(char *, __builtin_popcount(mask) + 1);
 	unsigned int i;
 	unsigned int j;
 
-	for (j = 0, i = 0; i < sizeof(supported_mask) * 8; i++) {
+	for (j = 0, i = 0; i < sizeof(mask) * 8; i++) {
 		const char *str;
 
-		if (!(supported_mask & (1 << i)))
+		if (!(mask & (1 << i)))
 			continue;
 
 		str = netdev_iftype_to_string(i + 1);
@@ -737,6 +736,11 @@ static char **wiphy_get_supported_iftypes(struct wiphy *wiphy, uint16_t mask)
 	return ret;
 }
 
+static char **wiphy_get_supported_iftypes(struct wiphy *wiphy, uint16_t mask)
+{
+	return wiphy_iftype_mask_to_str(wiphy->supported_iftypes & mask);
+}
+
 bool wiphy_supports_iftype(struct wiphy *wiphy, uint32_t iftype)
 {
 	if (iftype > sizeof(wiphy->supported_iftypes) * 8)
@@ -960,38 +964,14 @@ static void wiphy_print_mcs_info(const uint8_t *mcs_map,
 static void wiphy_print_he_capabilities(struct band *band,
 				const struct band_he_capabilities *he_cap)
 {
-	int i;
-	char type_buf[128];
-	char *s = type_buf;
+	_auto_(l_strv_free) char **iftypes = NULL;
+	_auto_(l_free) char *joined = NULL;
 	uint8_t width_set = bit_field(he_cap->he_phy_capa[0], 1, 7);
 
-	for (i = 0; i < 32; i++) {
-		if (!(he_cap->iftypes & (1 << i)))
-			continue;
-
-		if (L_WARN_ON(s >= type_buf + sizeof(type_buf)))
-			return;
-
-		switch (i) {
-		case NETDEV_IFTYPE_ADHOC:
-			s += sprintf(s, "%s ", "Ad-Hoc");
-			break;
-		case NETDEV_IFTYPE_STATION:
-			s += sprintf(s, "%s ", "Station");
-			break;
-		case NETDEV_IFTYPE_AP:
-			s += sprintf(s, "%s ", "AP");
-			break;
-		case NETDEV_IFTYPE_P2P_CLIENT:
-			s += sprintf(s, "%s ", "P2P Client");
-			break;
-		case NETDEV_IFTYPE_P2P_GO:
-			s += sprintf(s, "%s ", "P2P GO");
-			break;
-		}
-	}
+	iftypes = wiphy_iftype_mask_to_str(he_cap->iftypes);
+	joined = l_strjoinv(iftypes, ' ');
 
-	l_info("\t\t\tInterface Types: %s", type_buf);
+	l_info("\t\t\tInterface Types: %s", joined);
 
 	switch (band->freq) {
 	case BAND_FREQ_2_4_GHZ:
@@ -1341,7 +1321,7 @@ static uint32_t get_iftypes(struct l_genl_attr *iftypes)
 		if (len != 0)
 			continue;
 
-		types |= (1 << type);
+		types |= (1 << (type - 1));
 	}
 
 	return types;
-- 
2.34.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 02/13] scan: track scanned frequencies for entire request
  2022-08-03 21:36 [PATCH v2 01/13] wiphy: fix runtime error from bit shift James Prestwood
@ 2022-08-03 21:36 ` James Prestwood
  2022-08-03 21:36 ` [PATCH v2 03/13] nl80211util: add nl80211_parse_supported_frequencies James Prestwood
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: James Prestwood @ 2022-08-03 21:36 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

The NEW_SCAN_RESULTS handling was written to only parse the frequency
list if there were no additional scan commands to send. This results in
the scan callback containing frequencies of only the last CMD_TRIGGER.

Until now this worked fine because a) the queue is only used for hidden
networks and b) frequencies were never defined by any callers scanning
for hidden networks (e.g. dbus/periodic scans).

Soon the scan command queue will be used to break up scan requests
meaning only the last scan request frequencies would be used in the
callback, breaking the logic in station.

Now the NEW_SCAN_RESULTS case will parse the frequencies for each scan
command rather than only the last.
---
 src/scan.c | 39 +++++++++++++++++++++------------------
 1 file changed, 21 insertions(+), 18 deletions(-)

diff --git a/src/scan.c b/src/scan.c
index 03e5b8d9..b666ba2e 100644
--- a/src/scan.c
+++ b/src/scan.c
@@ -98,6 +98,12 @@ struct scan_request {
 	/* The time the current scan was started. Reported in TRIGGER_SCAN */
 	uint64_t start_time_tsf;
 	struct wiphy_radio_work_item work;
+	/*
+	 * List of frequencies scanned so far. Since the NEW_SCAN_RESULTS event
+	 * contains frequencies of only the last CMD_TRIGGER we need to parse
+	 * and save these since there may be additional scan commands to run.
+	 */
+	struct scan_freq_set *freqs_scanned;
 };
 
 struct scan_context {
@@ -125,7 +131,6 @@ struct scan_context {
 struct scan_results {
 	struct scan_context *sc;
 	struct l_queue *bss_list;
-	struct scan_freq_set *freqs;
 	uint64_t time_stamp;
 	struct scan_request *sr;
 };
@@ -159,6 +164,8 @@ static void scan_request_free(struct wiphy_radio_work_item *item)
 
 	l_queue_destroy(sr->cmds, (l_queue_destroy_func_t) l_genl_msg_unref);
 
+	scan_freq_set_free(sr->freqs_scanned);
+
 	l_free(sr);
 }
 
@@ -609,6 +616,7 @@ static struct scan_request *scan_request_new(struct scan_context *sc,
 	sr->destroy = destroy;
 	sr->passive = passive;
 	sr->cmds = l_queue_new();
+	sr->freqs_scanned = scan_freq_set_new();
 
 	return sr;
 }
@@ -1624,14 +1632,11 @@ fail:
 	return NULL;
 }
 
-static struct scan_freq_set *scan_parse_attr_scan_frequencies(
-						struct l_genl_attr *attr)
+static void scan_parse_attr_scan_frequencies(struct l_genl_attr *attr,
+						struct scan_freq_set *set)
 {
 	uint16_t type, len;
 	const void *data;
-	struct scan_freq_set *set;
-
-	set = scan_freq_set_new();
 
 	while (l_genl_attr_next(attr, &type, &len, &data)) {
 		uint32_t freq;
@@ -1642,8 +1647,6 @@ static struct scan_freq_set *scan_parse_attr_scan_frequencies(
 		freq = *((uint32_t *) data);
 		scan_freq_set_add(set, freq);
 	}
-
-	return set;
 }
 
 static struct scan_bss *scan_parse_result(struct l_genl_msg *msg,
@@ -1927,14 +1930,12 @@ static void get_scan_done(void *user)
 
 	if (!results->sr || !results->sr->canceled)
 		scan_finished(sc, 0, results->bss_list,
-						results->freqs, results->sr);
+						results->sr->freqs_scanned,
+						results->sr);
 	else
 		l_queue_destroy(results->bss_list,
 				(l_queue_destroy_func_t) scan_bss_free);
 
-	if (results->freqs)
-		scan_freq_set_free(results->freqs);
-
 	l_free(results);
 }
 
@@ -1954,8 +1955,8 @@ static bool scan_parse_flush_flag_from_msg(struct l_genl_msg *msg)
 	return false;
 }
 
-static void scan_parse_new_scan_results(struct l_genl_msg *msg,
-					struct scan_results *results)
+static void scan_parse_result_frequencies(struct l_genl_msg *msg,
+					struct scan_freq_set *freqs)
 {
 	struct l_genl_attr attr, nested;
 	uint16_t type, len;
@@ -1972,8 +1973,7 @@ static void scan_parse_new_scan_results(struct l_genl_msg *msg,
 				break;
 			}
 
-			results->freqs =
-				scan_parse_attr_scan_frequencies(&nested);
+			scan_parse_attr_scan_frequencies(&nested, freqs);
 			break;
 		}
 	}
@@ -2052,8 +2052,11 @@ static void scan_notify(struct l_genl_msg *msg, void *user_data)
 			 */
 			if (l_queue_isempty(sr->cmds))
 				get_results = true;
-			else
+			else {
+				scan_parse_result_frequencies(msg,
+							sr->freqs_scanned);
 				send_next = true;
+			}
 		} else {
 			if (sc->get_scan_cmd_id)
 				break;
@@ -2098,7 +2101,7 @@ static void scan_notify(struct l_genl_msg *msg, void *user_data)
 		results->sr = sr;
 		results->bss_list = l_queue_new();
 
-		scan_parse_new_scan_results(msg, results);
+		scan_parse_result_frequencies(msg, sr->freqs_scanned);
 
 		scan_msg = l_genl_msg_new_sized(NL80211_CMD_GET_SCAN, 8);
 		l_genl_msg_append_attr(scan_msg, NL80211_ATTR_WDEV, 8,
-- 
2.34.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 03/13] nl80211util: add nl80211_parse_supported_frequencies
  2022-08-03 21:36 [PATCH v2 01/13] wiphy: fix runtime error from bit shift James Prestwood
  2022-08-03 21:36 ` [PATCH v2 02/13] scan: track scanned frequencies for entire request James Prestwood
@ 2022-08-03 21:36 ` James Prestwood
  2022-08-04 15:27   ` Denis Kenzior
  2022-08-03 21:36 ` [PATCH v2 04/13] wiphy: track self-managed flag James Prestwood
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 16+ messages in thread
From: James Prestwood @ 2022-08-03 21:36 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

A helper function to parse supported and disabled frequencies.
---
 src/nl80211util.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 src/nl80211util.h |  4 ++++
 2 files changed, 49 insertions(+)

diff --git a/src/nl80211util.c b/src/nl80211util.c
index 9092b204..78470014 100644
--- a/src/nl80211util.c
+++ b/src/nl80211util.c
@@ -32,6 +32,7 @@
 
 #include "src/nl80211util.h"
 #include "src/band.h"
+#include "src/util.h"
 
 typedef bool (*attr_handler)(const void *data, uint16_t len, void *o);
 
@@ -484,3 +485,47 @@ int nl80211_parse_chandef(struct l_genl_msg *msg, struct band_chandef *out)
 	memcpy(out, &t, sizeof(t));
 	return 0;
 }
+
+int nl80211_parse_supported_frequencies(struct l_genl_attr *band_freqs,
+					struct scan_freq_set *supported_list,
+					struct scan_freq_set *disabled_list)
+{
+	uint16_t type, len;
+	const void *data;
+	struct l_genl_attr attr;
+	struct l_genl_attr nested;
+
+	if (!l_genl_attr_recurse(band_freqs, &nested))
+		return -EBADMSG;
+
+	while (l_genl_attr_next(&nested, NULL, NULL, NULL)) {
+		uint32_t freq = 0;
+		bool disabled = false;
+
+		if (!l_genl_attr_recurse(&nested, &attr))
+			continue;
+
+		while (l_genl_attr_next(&attr, &type, &len, &data)) {
+
+			switch (type) {
+			case NL80211_FREQUENCY_ATTR_FREQ:
+				freq = *((uint32_t *) data);
+				break;
+			case NL80211_FREQUENCY_ATTR_DISABLED:
+				disabled = true;
+				break;
+			}
+		}
+
+		if (!freq)
+			continue;
+
+		if (supported_list)
+			scan_freq_set_add(supported_list, freq);
+
+		if (disabled && disabled_list)
+			scan_freq_set_add(disabled_list, freq);
+	}
+
+	return 0;
+}
diff --git a/src/nl80211util.h b/src/nl80211util.h
index 01777195..1d32b700 100644
--- a/src/nl80211util.h
+++ b/src/nl80211util.h
@@ -23,6 +23,7 @@
 #include <ell/ell.h>
 
 struct band_chandef;
+struct scan_freq_set;
 
 int nl80211_parse_attrs(struct l_genl_msg *msg, int tag, ...);
 
@@ -55,3 +56,6 @@ struct l_genl_msg *nl80211_build_cmd_frame(uint32_t ifindex,
 						size_t iov_len);
 
 int nl80211_parse_chandef(struct l_genl_msg *msg, struct band_chandef *out);
+int nl80211_parse_supported_frequencies(struct l_genl_attr *band_freqs,
+					struct scan_freq_set *supported,
+					struct scan_freq_set *disabled);
-- 
2.34.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 04/13] wiphy: track self-managed flag
  2022-08-03 21:36 [PATCH v2 01/13] wiphy: fix runtime error from bit shift James Prestwood
  2022-08-03 21:36 ` [PATCH v2 02/13] scan: track scanned frequencies for entire request James Prestwood
  2022-08-03 21:36 ` [PATCH v2 03/13] nl80211util: add nl80211_parse_supported_frequencies James Prestwood
@ 2022-08-03 21:36 ` James Prestwood
  2022-08-03 21:36 ` [PATCH v2 05/13] wiphy: use nl80211_parse_supported_frequencies James Prestwood
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: James Prestwood @ 2022-08-03 21:36 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

Check if the SELF_MANAGED_REG flag is set and set into wiphy.
---
 src/wiphy.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/wiphy.c b/src/wiphy.c
index 2514c95a..4a778699 100644
--- a/src/wiphy.c
+++ b/src/wiphy.c
@@ -133,6 +133,7 @@ struct wiphy {
 	bool offchannel_tx_ok : 1;
 	bool blacklisted : 1;
 	bool registered : 1;
+	bool self_managed : 1;
 };
 
 static struct l_queue *wiphy_list = NULL;
@@ -1647,6 +1648,9 @@ static void wiphy_parse_attributes(struct wiphy *wiphy,
 		case NL80211_ATTR_ROAM_SUPPORT:
 			wiphy->support_fw_roam = true;
 			break;
+		case NL80211_ATTR_WIPHY_SELF_MANAGED_REG:
+			wiphy->self_managed = true;
+			break;
 		}
 	}
 }
-- 
2.34.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 05/13] wiphy: use nl80211_parse_supported_frequencies
  2022-08-03 21:36 [PATCH v2 01/13] wiphy: fix runtime error from bit shift James Prestwood
                   ` (2 preceding siblings ...)
  2022-08-03 21:36 ` [PATCH v2 04/13] wiphy: track self-managed flag James Prestwood
@ 2022-08-03 21:36 ` James Prestwood
  2022-08-03 21:36 ` [PATCH v2 06/13] wiphy: add two regulatory domain state events James Prestwood
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: James Prestwood @ 2022-08-03 21:36 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

Removes the parser in wiphy and uses the helper instead
---
 src/wiphy.c | 44 +++-----------------------------------------
 1 file changed, 3 insertions(+), 41 deletions(-)

diff --git a/src/wiphy.c b/src/wiphy.c
index 4a778699..3a6cd48c 100644
--- a/src/wiphy.c
+++ b/src/wiphy.c
@@ -1190,42 +1190,6 @@ static void parse_supported_ciphers(struct wiphy *wiphy, const void *data,
 	}
 }
 
-static void parse_supported_frequencies(struct wiphy *wiphy,
-						struct l_genl_attr *freqs)
-{
-	uint16_t type, len;
-	const void *data;
-	struct l_genl_attr attr;
-
-	while (l_genl_attr_next(freqs, NULL, NULL, NULL)) {
-		uint32_t freq = 0;
-		bool disabled = false;
-
-		if (!l_genl_attr_recurse(freqs, &attr))
-			continue;
-
-		while (l_genl_attr_next(&attr, &type, &len, &data)) {
-
-			switch (type) {
-			case NL80211_FREQUENCY_ATTR_FREQ:
-				freq = *((uint32_t *) data);
-				break;
-			case NL80211_FREQUENCY_ATTR_DISABLED:
-				disabled = true;
-				break;
-			}
-		}
-
-		if (!freq)
-			continue;
-
-		scan_freq_set_add(wiphy->supported_freqs, freq);
-
-		if (disabled)
-			scan_freq_set_add(wiphy->disabled_freqs, freq);
-	}
-}
-
 static int parse_supported_rates(struct l_genl_attr *attr, struct band *band)
 {
 	uint16_t type;
@@ -1445,16 +1409,14 @@ static void parse_supported_bands(struct wiphy *wiphy,
 			band = *bandp;
 
 
-
 		while (l_genl_attr_next(&attr, &type, &len, &data)) {
 			struct l_genl_attr nested;
 
 			switch (type) {
 			case NL80211_BAND_ATTR_FREQS:
-				if (!l_genl_attr_recurse(&attr, &nested))
-					continue;
-
-				parse_supported_frequencies(wiphy, &nested);
+				nl80211_parse_supported_frequencies(&attr,
+							wiphy->supported_freqs,
+							wiphy->disabled_freqs);
 				break;
 
 			case NL80211_BAND_ATTR_RATES:
-- 
2.34.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 06/13] wiphy: add two regulatory domain state events
  2022-08-03 21:36 [PATCH v2 01/13] wiphy: fix runtime error from bit shift James Prestwood
                   ` (3 preceding siblings ...)
  2022-08-03 21:36 ` [PATCH v2 05/13] wiphy: use nl80211_parse_supported_frequencies James Prestwood
@ 2022-08-03 21:36 ` James Prestwood
  2022-08-04 15:31   ` Denis Kenzior
  2022-08-03 21:36 ` [PATCH v2 07/13] wiphy: dump wiphy's on regulatory domain change James Prestwood
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 16+ messages in thread
From: James Prestwood @ 2022-08-03 21:36 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

Events to indicate when a regulatory domain wiphy dump has
started and ended. This is important because certain actions
such as scanning need to be delayed until the dump has finished.
---
 src/device.c | 2 ++
 src/wiphy.h  | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/src/device.c b/src/device.c
index 02da2cdc..d7eb6adb 100644
--- a/src/device.c
+++ b/src/device.c
@@ -282,6 +282,8 @@ static void device_wiphy_state_changed_event(struct wiphy *wiphy,
 			netdev_set_powered(device->netdev, true,
 							NULL, NULL, NULL);
 		break;
+	default:
+		break;
 	}
 }
 
diff --git a/src/wiphy.h b/src/wiphy.h
index 9a3b96f9..070c8aea 100644
--- a/src/wiphy.h
+++ b/src/wiphy.h
@@ -56,6 +56,8 @@ enum {
 enum wiphy_state_watch_event {
 	WIPHY_STATE_WATCH_EVENT_POWERED,
 	WIPHY_STATE_WATCH_EVENT_RFKILLED,
+	WIPHY_STATE_WATCH_EVENT_REGDOM_STARTED,
+	WIPHY_STATE_WATCH_EVENT_REGDOM_DONE,
 };
 
 typedef void (*wiphy_state_watch_func_t)(struct wiphy *wiphy,
-- 
2.34.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 07/13] wiphy: dump wiphy's on regulatory domain change
  2022-08-03 21:36 [PATCH v2 01/13] wiphy: fix runtime error from bit shift James Prestwood
                   ` (4 preceding siblings ...)
  2022-08-03 21:36 ` [PATCH v2 06/13] wiphy: add two regulatory domain state events James Prestwood
@ 2022-08-03 21:36 ` James Prestwood
  2022-08-03 21:36 ` [PATCH v2 08/13] wiphy: add wiphy_regdom_is_updating James Prestwood
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: James Prestwood @ 2022-08-03 21:36 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

A change in regulatory domain can result in frequencies being
enabled or disabled depending on the domain. This effects the
frequencies stored in wiphy which other modules depend on
such as scanning, offchannel work etc.

When the regulatory domain changes re-dump the wiphy in order
to update any frequency restrictions.
---
 src/wiphy.c | 204 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 202 insertions(+), 2 deletions(-)

diff --git a/src/wiphy.c b/src/wiphy.c
index 3a6cd48c..b9f8009d 100644
--- a/src/wiphy.c
+++ b/src/wiphy.c
@@ -66,6 +66,7 @@ static char **blacklist_filter;
 static int mac_randomize_bytes = 6;
 static char regdom_country[2];
 static uint32_t work_ids;
+static unsigned int wiphy_dump_id;
 
 enum driver_flag {
 	DEFAULT_IF = 0x1,
@@ -105,6 +106,7 @@ struct wiphy {
 	uint16_t supported_ciphers;
 	struct scan_freq_set *supported_freqs;
 	struct scan_freq_set *disabled_freqs;
+	struct scan_freq_set *pending_freqs;
 	struct band *band_2g;
 	struct band *band_5g;
 	struct band *band_6g;
@@ -121,6 +123,8 @@ struct wiphy {
 	/* Work queue for this radio */
 	struct l_queue *work;
 	bool work_in_callback;
+	unsigned int get_reg_id;
+	unsigned int dump_id;
 
 	bool support_scheduled_scan:1;
 	bool support_rekey_offload:1;
@@ -341,6 +345,12 @@ static void wiphy_free(void *data)
 
 	l_debug("Freeing wiphy %s[%u]", wiphy->name, wiphy->id);
 
+	if (wiphy->dump_id)
+		l_genl_family_cancel(nl80211, wiphy->dump_id);
+
+	if (wiphy->get_reg_id)
+		l_genl_family_cancel(nl80211, wiphy->get_reg_id);
+
 	for (i = 0; i < NUM_NL80211_IFTYPES; i++)
 		l_free(wiphy->iftype_extended_capabilities[i]);
 
@@ -1819,6 +1829,182 @@ static void wiphy_setup_rm_enabled_capabilities(struct wiphy *wiphy)
 	 */
 }
 
+static void wiphy_dump_done(void *user_data)
+{
+	struct wiphy *wiphy = user_data;
+	const struct l_queue_entry *e;
+
+	/* This dump was canceled due to another dump */
+	if ((wiphy && !wiphy->dump_id) || (!wiphy && !wiphy_dump_id))
+		return;
+
+	if (wiphy) {
+		wiphy->dump_id = 0;
+		scan_freq_set_free(wiphy->disabled_freqs);
+		wiphy->disabled_freqs = wiphy->pending_freqs;
+		wiphy->pending_freqs = NULL;
+
+		WATCHLIST_NOTIFY(&wiphy->state_watches,
+				wiphy_state_watch_func_t, wiphy,
+				WIPHY_STATE_WATCH_EVENT_REGDOM_DONE);
+
+		return;
+	}
+
+	wiphy_dump_id = 0;
+
+	for (e = l_queue_get_entries(wiphy_list); e; e = e->next) {
+		wiphy = e->data;
+
+		if (!wiphy->pending_freqs || wiphy->self_managed)
+			continue;
+
+		scan_freq_set_free(wiphy->disabled_freqs);
+		wiphy->disabled_freqs = wiphy->pending_freqs;
+		wiphy->pending_freqs = NULL;
+
+		WATCHLIST_NOTIFY(&wiphy->state_watches,
+				wiphy_state_watch_func_t, wiphy,
+				WIPHY_STATE_WATCH_EVENT_REGDOM_DONE);
+	}
+}
+
+/* We are dumping wiphy(s) due to a regulatory change */
+static void wiphy_dump_callback(struct l_genl_msg *msg,
+						void *user_data)
+{
+	struct wiphy *wiphy;
+	uint32_t id;
+	struct l_genl_attr bands;
+	struct l_genl_attr attr;
+	uint16_t type;
+
+	if (nl80211_parse_attrs(msg, NL80211_ATTR_WIPHY, &id,
+					NL80211_ATTR_WIPHY_BANDS, &bands,
+					NL80211_ATTR_UNSPEC) < 0)
+		return;
+
+	wiphy = wiphy_find(id);
+	if (L_WARN_ON(!wiphy))
+		return;
+
+	while (l_genl_attr_next(&bands, NULL, NULL, NULL)) {
+		if (!l_genl_attr_recurse(&bands, &attr))
+			return;
+
+		while (l_genl_attr_next(&attr, &type, NULL, NULL)) {
+			if (type != NL80211_BAND_ATTR_FREQS)
+				continue;
+
+			nl80211_parse_supported_frequencies(&attr, NULL,
+							wiphy->pending_freqs);
+		}
+	}
+}
+
+static bool wiphy_cancel_last_dump(struct wiphy *wiphy)
+{
+	const struct l_queue_entry *e;
+	unsigned int id = 0;
+
+	/*
+	 * Zero command ID to signal that wiphy_dump_done doesn't need to do
+	 * anything. For a self-managed wiphy just free/NULL pending_freqs. For
+	 * a global dump each wiphy needs to be checked and dealt with.
+	 */
+	if (wiphy && wiphy->dump_id) {
+		id = wiphy->dump_id;
+		wiphy->dump_id = 0;
+
+		scan_freq_set_free(wiphy->pending_freqs);
+		wiphy->pending_freqs = NULL;
+	} else if (!wiphy && wiphy_dump_id) {
+		id = wiphy_dump_id;
+		wiphy_dump_id = 0;
+
+		for (e = l_queue_get_entries(wiphy_list); e; e = e->next) {
+			struct wiphy *w = e->data;
+
+			if (!w->pending_freqs || w->self_managed)
+				continue;
+
+			scan_freq_set_free(w->pending_freqs);
+			w->pending_freqs = NULL;
+		}
+	}
+
+	if (id) {
+		l_debug("Canceling pending regdom wiphy dump (%s)",
+					wiphy ? wiphy->name : "global");
+
+		l_genl_family_cancel(nl80211, id);
+	}
+
+	return id != 0;
+}
+
+static void wiphy_dump_after_regdom(struct wiphy *wiphy)
+{
+	const struct l_queue_entry *e;
+	struct l_genl_msg *msg;
+	unsigned int id;
+	bool no_start_event;
+
+	msg = l_genl_msg_new_sized(NL80211_CMD_GET_WIPHY, 128);
+
+	if (wiphy)
+		l_genl_msg_append_attr(msg, NL80211_ATTR_WIPHY, 4, &wiphy->id);
+
+	l_genl_msg_append_attr(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP, 0, NULL);
+	id = l_genl_family_dump(nl80211, msg, wiphy_dump_callback,
+						wiphy, wiphy_dump_done);
+	if (!id) {
+		l_error("Wiphy information dump failed");
+		l_genl_msg_unref(msg);
+		return;
+	}
+
+	/*
+	 * Another update while dumping wiphy. This next dump should supercede
+	 * the first and not result in a DONE event until this new dump is
+	 * finished. This is because the disabled frequencies are in an unknown
+	 * state and could cause incorrect behavior by any watchers.
+	 */
+	no_start_event = wiphy_cancel_last_dump(wiphy);
+
+	/* Limited dump so just emit the event for this wiphy */
+	if (wiphy) {
+		wiphy->dump_id = id;
+		wiphy->pending_freqs = scan_freq_set_new();
+
+		if (no_start_event)
+			return;
+
+		WATCHLIST_NOTIFY(&wiphy->state_watches,
+				wiphy_state_watch_func_t, wiphy,
+				WIPHY_STATE_WATCH_EVENT_REGDOM_STARTED);
+		return;
+	}
+
+	wiphy_dump_id = id;
+
+	/* Otherwise for a global regdom change notify for all wiphy's */
+	for (e = l_queue_get_entries(wiphy_list); e; e = e->next) {
+		struct wiphy *w = e->data;
+
+		if (w->self_managed)
+			continue;
+
+		w->pending_freqs = scan_freq_set_new();
+
+		if (no_start_event)
+			continue;
+
+		WATCHLIST_NOTIFY(&w->state_watches, wiphy_state_watch_func_t,
+				w, WIPHY_STATE_WATCH_EVENT_REGDOM_STARTED);
+	}
+}
+
 static void wiphy_update_reg_domain(struct wiphy *wiphy, bool global,
 					struct l_genl_msg *msg)
 {
@@ -1851,6 +2037,14 @@ static void wiphy_update_reg_domain(struct wiphy *wiphy, bool global,
 	l_debug("New reg domain country code for %s is %c%c",
 		global ? "(global)" : wiphy->name,
 		out_country[0], out_country[1]);
+
+	/* Don't dump wiphy from a GET_REG call */
+	if (wiphy && wiphy->get_reg_id) {
+		wiphy->get_reg_id = 0;
+		return;
+	}
+
+	wiphy_dump_after_regdom(wiphy);
 }
 
 static void wiphy_get_reg_cb(struct l_genl_msg *msg, void *user_data)
@@ -1876,8 +2070,9 @@ static void wiphy_get_reg_domain(struct wiphy *wiphy)
 	msg = l_genl_msg_new(NL80211_CMD_GET_REG);
 	l_genl_msg_append_attr(msg, NL80211_ATTR_WIPHY, 4, &wiphy->id);
 
-	if (!l_genl_family_send(wiphy->nl80211, msg, wiphy_get_reg_cb, wiphy,
-				NULL)) {
+	wiphy->get_reg_id = l_genl_family_send(wiphy->nl80211, msg,
+						wiphy_get_reg_cb, wiphy, NULL);
+	if (!wiphy->get_reg_id) {
 		l_error("Error sending NL80211_CMD_GET_REG for %s", wiphy->name);
 		l_genl_msg_unref(msg);
 	}
@@ -2290,6 +2485,11 @@ static void wiphy_exit(void)
 	l_strfreev(whitelist_filter);
 	l_strfreev(blacklist_filter);
 
+	if (wiphy_dump_id) {
+		l_genl_family_cancel(nl80211, wiphy_dump_id);
+		wiphy_dump_id = 0;
+	}
+
 	l_queue_destroy(wiphy_list, wiphy_free);
 	wiphy_list = NULL;
 
-- 
2.34.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 08/13] wiphy: add wiphy_regdom_is_updating
  2022-08-03 21:36 [PATCH v2 01/13] wiphy: fix runtime error from bit shift James Prestwood
                   ` (5 preceding siblings ...)
  2022-08-03 21:36 ` [PATCH v2 07/13] wiphy: dump wiphy's on regulatory domain change James Prestwood
@ 2022-08-03 21:36 ` James Prestwood
  2022-08-03 21:36 ` [PATCH v2 09/13] wiphy: add wiphy_country_is_unknown James Prestwood
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: James Prestwood @ 2022-08-03 21:36 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

This allows a module to check the current status of the regdom
in case it misses the wiphy event (e.g. registers after the
STARTED event).
---
 src/wiphy.c | 5 +++++
 src/wiphy.h | 1 +
 2 files changed, 6 insertions(+)

diff --git a/src/wiphy.c b/src/wiphy.c
index b9f8009d..6a109655 100644
--- a/src/wiphy.c
+++ b/src/wiphy.c
@@ -905,6 +905,11 @@ int wiphy_estimate_data_rate(struct wiphy *wiphy,
 						out_data_rate);
 }
 
+bool wiphy_regdom_is_updating(struct wiphy *wiphy)
+{
+	return wiphy->pending_freqs != NULL;
+}
+
 uint32_t wiphy_state_watch_add(struct wiphy *wiphy,
 				wiphy_state_watch_func_t func,
 				void *user_data, wiphy_destroy_func_t destroy)
diff --git a/src/wiphy.h b/src/wiphy.h
index 070c8aea..1fea6c23 100644
--- a/src/wiphy.h
+++ b/src/wiphy.h
@@ -133,6 +133,7 @@ int wiphy_estimate_data_rate(struct wiphy *wiphy,
 				const void *ies, uint16_t ies_len,
 				const struct scan_bss *bss,
 				uint64_t *out_data_rate);
+bool wiphy_regdom_is_updating(struct wiphy *wiphy);
 
 uint32_t wiphy_state_watch_add(struct wiphy *wiphy,
 				wiphy_state_watch_func_t func, void *user_data,
-- 
2.34.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 09/13] wiphy: add wiphy_country_is_unknown
  2022-08-03 21:36 [PATCH v2 01/13] wiphy: fix runtime error from bit shift James Prestwood
                   ` (6 preceding siblings ...)
  2022-08-03 21:36 ` [PATCH v2 08/13] wiphy: add wiphy_regdom_is_updating James Prestwood
@ 2022-08-03 21:36 ` James Prestwood
  2022-08-04 16:48   ` Denis Kenzior
  2022-08-03 21:36 ` [PATCH v2 10/13] station: do full passive scan if 6GHz is supported but disabled James Prestwood
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 16+ messages in thread
From: James Prestwood @ 2022-08-03 21:36 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

A helper to check whether the country code corresponds to a
real country, or some special code indicating the country isn't
yet set. For now, the special codes are OO (world roaming) and
XX (unknown entity).
---
 src/wiphy.c | 16 ++++++++++++++++
 src/wiphy.h |  1 +
 2 files changed, 17 insertions(+)

diff --git a/src/wiphy.c b/src/wiphy.c
index 6a109655..dec4b15e 100644
--- a/src/wiphy.c
+++ b/src/wiphy.c
@@ -800,6 +800,22 @@ void wiphy_get_reg_domain_country(struct wiphy *wiphy, char *out)
 	out[1] = country[1];
 }
 
+bool wiphy_country_is_unknown(struct wiphy *wiphy)
+{
+	char cc[2];
+
+	wiphy_get_reg_domain_country(wiphy, cc);
+
+	/*
+	 * Treat OO and XX as an unknown country. Additional codes could be
+	 * added here if needed. The purpose of this is to know if we can
+	 * expect the disabled frequency list to be updated once a country is
+	 * known.
+	 */
+	return ((cc[0] == 'O' && cc[1] == 'O') ||
+			(cc[0] == 'X' && cc[1] == 'X'));
+}
+
 int wiphy_estimate_data_rate(struct wiphy *wiphy,
 				const void *ies, uint16_t ies_len,
 				const struct scan_bss *bss,
diff --git a/src/wiphy.h b/src/wiphy.h
index 1fea6c23..2159fc00 100644
--- a/src/wiphy.h
+++ b/src/wiphy.h
@@ -124,6 +124,7 @@ const uint8_t *wiphy_get_extended_capabilities(struct wiphy *wiphy,
 const uint8_t *wiphy_get_rm_enabled_capabilities(struct wiphy *wiphy);
 bool wiphy_get_rsnxe(const struct wiphy *wiphy, uint8_t *buf, size_t len);
 void wiphy_get_reg_domain_country(struct wiphy *wiphy, char *out);
+bool wiphy_country_is_unknown(struct wiphy *wiphy);
 
 void wiphy_generate_random_address(struct wiphy *wiphy, uint8_t addr[static 6]);
 void wiphy_generate_address_from_ssid(struct wiphy *wiphy, const char *ssid,
-- 
2.34.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 10/13] station: do full passive scan if 6GHz is supported but disabled.
  2022-08-03 21:36 [PATCH v2 01/13] wiphy: fix runtime error from bit shift James Prestwood
                   ` (7 preceding siblings ...)
  2022-08-03 21:36 ` [PATCH v2 09/13] wiphy: add wiphy_country_is_unknown James Prestwood
@ 2022-08-03 21:36 ` James Prestwood
  2022-08-03 21:36 ` [PATCH v2 11/13] scan: split full scans by band to enable 6GHz James Prestwood
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: James Prestwood @ 2022-08-03 21:36 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

The kernel handles setting the regulatory domain by receiving beacons which
set the country IE. Presumably since most regulatory domains disallow 6GHz
the default (world) domain also disables it. This means until the country
is set, 6GHz is disabled.

This poses a problem for IWD's quick scanning since it only scans a few
frequencies and this likely isn't enough beacons for the firmware to update
the country, leaving 6Ghz inaccessable to the user without manual intervention
(e.g. iw scan passive, or periodic scans by IWD).

To try and work around this limitation the quick scan logic has been updated
to check if a 6GHz AP has been connected to before and if that frequency is
disabled (but supported). If this is the case IWD will opt for a full passive
scan rather than scanning a limited set of frequencies.
---
 src/station.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/src/station.c b/src/station.c
index 02f21c76..f002d7ef 100644
--- a/src/station.c
+++ b/src/station.c
@@ -112,6 +112,8 @@ struct station {
 	struct scan_freq_set *scan_freqs_order[3];
 	unsigned int dbus_scan_subset_idx;
 
+	uint32_t wiphy_watch;
+
 	bool preparing_roam : 1;
 	bool roam_scan_full : 1;
 	bool signal_low : 1;
@@ -119,6 +121,7 @@ struct station {
 	bool scanning : 1;
 	bool autoconnect : 1;
 	bool autoconnect_can_start : 1;
+	bool regdom_updating : 1;
 };
 
 struct anqp_entry {
@@ -1353,11 +1356,37 @@ static void station_quick_scan_destroy(void *userdata)
 static int station_quick_scan_trigger(struct station *station)
 {
 	struct scan_freq_set *known_freq_set;
+	bool known_6ghz;
+	const struct scan_freq_set *disabled = wiphy_get_disabled_freqs(
+								station->wiphy);
 
 	known_freq_set = known_networks_get_recent_frequencies(5);
 	if (!known_freq_set)
 		return -ENODATA;
 
+	if (station->regdom_updating) {
+		l_debug("regdom is updating, delaying quick scan");
+
+		scan_freq_set_free(known_freq_set);
+		return 0;
+	}
+
+	known_6ghz = scan_freq_set_get_bands(known_freq_set) & BAND_FREQ_6_GHZ;
+
+	/*
+	 * This means IWD has previously connected to a 6GHz AP before, but now
+	 * the regulatory domain disallows 6GHz likely caused by a reboot, the
+	 * firmware going down, or a regulatory update. The only way to
+	 * re-enable 6GHz is to get enough beacons via scanning for the firmware
+	 * to set the regulatory domain. A quick scan is very unlikely to do
+	 * this since its so limited, so return an error which will fall back to
+	 * full autoconnect.
+	 */
+	if ((scan_freq_set_get_bands(disabled) & BAND_FREQ_6_GHZ) &&
+				wiphy_country_is_unknown(station->wiphy) &&
+				known_6ghz)
+		return -EAGAIN;
+
 	if (!wiphy_constrain_freq_set(station->wiphy, known_freq_set)) {
 		scan_freq_set_free(known_freq_set);
 		return -ENOTSUP;
@@ -3977,6 +4006,37 @@ static void station_fill_scan_freq_subsets(struct station *station)
 	}
 }
 
+static void station_wiphy_watch(struct wiphy *wiphy,
+				enum wiphy_state_watch_event event,
+				void *user_data)
+{
+	struct station *station = user_data;
+
+	switch (event) {
+	case WIPHY_STATE_WATCH_EVENT_REGDOM_STARTED:
+		station->regdom_updating = true;
+		return;
+	case WIPHY_STATE_WATCH_EVENT_REGDOM_DONE:
+		station->regdom_updating = false;
+
+		/*
+		 * The only state that requires special handling is for
+		 * quick scans since the previous quick scan was delayed until
+		 * the regulatory domain updated. Try again in case 6Ghz is now
+		 * unlocked (unlikely), or advance to full autoconnect.
+		 */
+		if (station->state != STATION_STATE_AUTOCONNECT_QUICK)
+			return;
+
+		if (!station_quick_scan_trigger(station))
+			return;
+
+		station_enter_state(station, STATION_STATE_AUTOCONNECT_FULL);
+	default:
+		return;
+	}
+}
+
 static struct station *station_create(struct netdev *netdev)
 {
 	struct station *station;
@@ -3997,6 +4057,11 @@ static struct station *station_create(struct netdev *netdev)
 	station->wiphy = netdev_get_wiphy(netdev);
 	station->netdev = netdev;
 
+	station->wiphy_watch = wiphy_state_watch_add(station->wiphy,
+							station_wiphy_watch,
+							station, NULL);
+	station->regdom_updating = wiphy_regdom_is_updating(station->wiphy);
+
 	l_queue_push_head(station_list, station);
 
 	l_dbus_object_add_interface(dbus, netdev_get_path(netdev),
@@ -4106,6 +4171,8 @@ static void station_free(struct station *station)
 	if (station->scan_freqs_order[2])
 		scan_freq_set_free(station->scan_freqs_order[2]);
 
+	wiphy_state_watch_remove(station->wiphy, station->wiphy_watch);
+
 	l_free(station);
 }
 
-- 
2.34.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 11/13] scan: split full scans by band to enable 6GHz
  2022-08-03 21:36 [PATCH v2 01/13] wiphy: fix runtime error from bit shift James Prestwood
                   ` (8 preceding siblings ...)
  2022-08-03 21:36 ` [PATCH v2 10/13] station: do full passive scan if 6GHz is supported but disabled James Prestwood
@ 2022-08-03 21:36 ` James Prestwood
  2022-08-03 21:36 ` [PATCH v2 12/13] scan: watch for regdom updates " James Prestwood
  2022-08-03 21:36 ` [PATCH v2 13/13] wiphy: don't re-dump wiphy if the regdom didn't change James Prestwood
  11 siblings, 0 replies; 16+ messages in thread
From: James Prestwood @ 2022-08-03 21:36 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

The kernel's regulatory domain updates after some number of beacons
are processed. This triggers a regulatory domain update (and wiphy
dump) but only after a scan request. This means a full scan started
prior to the regdom being set will not include any 6Ghz BSS's even
if the regdom was unlocked during the scan.

This can be worked around by splitting up a large scan request into
multiple requests allowing one of the first commands to trigger a
regdom update. Once the regdom updates (and wiphy dumps) we are
hopefully still scanning and could append an additional request to
scan 6GHz.
---
 src/scan.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 89 insertions(+), 8 deletions(-)

diff --git a/src/scan.c b/src/scan.c
index b666ba2e..e016bd4d 100644
--- a/src/scan.c
+++ b/src/scan.c
@@ -352,9 +352,24 @@ static bool scan_mac_address_randomization_is_disabled(void)
 	return disabled;
 }
 
+static struct scan_freq_set *scan_get_allowed_freqs(struct scan_context *sc)
+{
+	struct scan_freq_set *allowed = scan_freq_set_new();
+
+	scan_freq_set_merge(allowed, wiphy_get_supported_freqs(sc->wiphy));
+
+	if (!wiphy_constrain_freq_set(sc->wiphy, allowed)) {
+		scan_freq_set_free(allowed);
+		allowed = NULL;
+	}
+
+	return allowed;
+}
+
 static struct l_genl_msg *scan_build_cmd(struct scan_context *sc,
 					bool ignore_flush_flag, bool is_passive,
-					const struct scan_parameters *params)
+					const struct scan_parameters *params,
+					const struct scan_freq_set *freqs)
 {
 	struct l_genl_msg *msg;
 	uint32_t flags = 0;
@@ -366,8 +381,8 @@ static struct l_genl_msg *scan_build_cmd(struct scan_context *sc,
 	if (wiphy_get_max_scan_ie_len(sc->wiphy))
 		scan_build_attr_ie(msg, sc, params);
 
-	if (params->freqs)
-		scan_build_attr_scan_frequencies(msg, params->freqs);
+	if (freqs)
+		scan_build_attr_scan_frequencies(msg, freqs);
 
 	if (params->flush && !ignore_flush_flag && wiphy_has_feature(sc->wiphy,
 						NL80211_FEATURE_SCAN_FLUSH))
@@ -524,16 +539,36 @@ static bool scan_cmds_add_hidden(const struct network_info *network,
 		 * of all scans in the batch after the last scan is finished.
 		 */
 		*data->cmd = scan_build_cmd(data->sc, true, false,
-								data->params);
+							data->params,
+							data->params->freqs);
 		l_genl_msg_enter_nested(*data->cmd, NL80211_ATTR_SCAN_SSIDS);
 	}
 
 	return true;
 }
 
-static void scan_cmds_add(struct l_queue *cmds, struct scan_context *sc,
+static void scan_foreach_freq_split_bands(uint32_t freq, void *user_data)
+{
+	struct scan_freq_set **subsets = user_data;
+	int idx;
+
+	if (freq < 3000)
+		idx = 0;
+	else if (freq < 6000)
+		idx = 1;
+	else
+		idx = 2;
+
+	if (!subsets[idx])
+		subsets[idx] = scan_freq_set_new();
+
+	scan_freq_set_add(subsets[idx], freq);
+}
+
+static void scan_build_next_cmd(struct l_queue *cmds, struct scan_context *sc,
 				bool passive,
-				const struct scan_parameters *params)
+				const struct scan_parameters *params,
+				const struct scan_freq_set *freqs)
 {
 	struct l_genl_msg *cmd;
 	struct scan_cmds_add_data data = {
@@ -544,7 +579,7 @@ static void scan_cmds_add(struct l_queue *cmds, struct scan_context *sc,
 		wiphy_get_max_num_ssids_per_scan(sc->wiphy),
 	};
 
-	cmd = scan_build_cmd(sc, false, passive, params);
+	cmd = scan_build_cmd(sc, false, passive, params, freqs);
 
 	if (passive) {
 		/* passive scan */
@@ -572,6 +607,52 @@ static void scan_cmds_add(struct l_queue *cmds, struct scan_context *sc,
 	l_queue_push_tail(cmds, cmd);
 }
 
+static void scan_cmds_add(struct l_queue *cmds, struct scan_context *sc,
+				bool passive,
+				const struct scan_parameters *params)
+{
+	unsigned int i;
+	struct scan_freq_set *subsets[3] = { 0 };
+	struct scan_freq_set *allowed;
+
+	/*
+	 * If the frequencies are explicit don't break up the request
+	 */
+	if (params->freqs) {
+		scan_build_next_cmd(cmds, sc, passive, params, params->freqs);
+		return;
+	}
+
+	/*
+	 * Otherwise a full spectrum scan will likely open up the 6GHz
+	 * band. The problem is the regdom update occurs after an
+	 * individual scan request so a single request isn't going to
+	 * include potential 6GHz results.
+	 *
+	 * Instead we can break this full scan up into individual bands
+	 * and increase our chances of the regdom updating after one of
+	 * the earlier requests. If it does update to allow 6GHz an
+	 * extra 6GHz-only passive scan can be appended to this request
+	 * at that time.
+	 */
+
+	allowed = scan_get_allowed_freqs(sc);
+	if (L_WARN_ON(!allowed))
+		return;
+
+	scan_freq_set_foreach(allowed, scan_foreach_freq_split_bands, subsets);
+	scan_freq_set_free(allowed);
+
+	for(i = 0; i < L_ARRAY_SIZE(subsets); i++) {
+		if (!subsets[i])
+			continue;
+
+		scan_build_next_cmd(cmds, sc, passive, params,
+					subsets[i]);
+		scan_freq_set_free(subsets[i]);
+	}
+}
+
 static int scan_request_send_trigger(struct scan_context *sc,
 					struct scan_request *sr)
 {
@@ -743,7 +824,7 @@ static void add_owe_scan_cmd(struct scan_context *sc, struct scan_request *sr,
 	params.ssid_len = bss->owe_trans->ssid_len;
 	params.flush = true;
 
-	cmd = scan_build_cmd(sc, ignore_flush, false, &params);
+	cmd = scan_build_cmd(sc, ignore_flush, false, &params, params.freqs);
 
 	l_genl_msg_enter_nested(cmd, NL80211_ATTR_SCAN_SSIDS);
 	l_genl_msg_append_attr(cmd, 0, params.ssid_len, params.ssid);
-- 
2.34.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 12/13] scan: watch for regdom updates to enable 6GHz
  2022-08-03 21:36 [PATCH v2 01/13] wiphy: fix runtime error from bit shift James Prestwood
                   ` (9 preceding siblings ...)
  2022-08-03 21:36 ` [PATCH v2 11/13] scan: split full scans by band to enable 6GHz James Prestwood
@ 2022-08-03 21:36 ` James Prestwood
  2022-08-03 21:36 ` [PATCH v2 13/13] wiphy: don't re-dump wiphy if the regdom didn't change James Prestwood
  11 siblings, 0 replies; 16+ messages in thread
From: James Prestwood @ 2022-08-03 21:36 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

This functionality works around the kernel's behavior of allowing
6GHz only after a regulatory domain update. If the regdom updates
scan.c needs to be aware in order to split up periodic scans, or
insert 6GHz frequencies into an ongoing periodic scan. Doing this
allows any 6GHz BSS's to show up in the scan results rather than
needing to issue an entirely new scan to see these BSS's.
---
 src/scan.c | 165 +++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 147 insertions(+), 18 deletions(-)

diff --git a/src/scan.c b/src/scan.c
index e016bd4d..40e527d9 100644
--- a/src/scan.c
+++ b/src/scan.c
@@ -71,6 +71,8 @@ struct scan_periodic {
 	void *userdata;
 	uint32_t id;
 	bool needs_active_scan:1;
+	/* Delay periodic scan results until regulatory domain updates */
+	bool wait_on_regdom:1;
 };
 
 struct scan_request {
@@ -108,6 +110,7 @@ struct scan_request {
 
 struct scan_context {
 	uint64_t wdev_id;
+	uint32_t wiphy_watch_id;
 	/*
 	 * Tells us whether a scan, our own or external, is running.
 	 * Set when scan gets triggered, cleared when scan done and
@@ -126,6 +129,8 @@ struct scan_context {
 	 */
 	unsigned int get_fw_scan_cmd_id;
 	struct wiphy *wiphy;
+	/* 6GHz may become available after a regdom update */
+	bool expect_6ghz : 1;
 };
 
 struct scan_results {
@@ -184,24 +189,6 @@ static void scan_request_failed(struct scan_context *sc,
 	wiphy_radio_work_done(sc->wiphy, sr->work.id);
 }
 
-static struct scan_context *scan_context_new(uint64_t wdev_id)
-{
-	struct wiphy *wiphy = wiphy_find_by_wdev(wdev_id);
-	struct scan_context *sc;
-
-	if (!wiphy)
-		return NULL;
-
-	sc = l_new(struct scan_context, 1);
-
-	sc->wdev_id = wdev_id;
-	sc->wiphy = wiphy;
-	sc->state = SCAN_STATE_NOT_RUNNING;
-	sc->requests = l_queue_new();
-
-	return sc;
-}
-
 static void scan_request_cancel(void *data)
 {
 	struct scan_request *sr = data;
@@ -227,6 +214,8 @@ static void scan_context_free(struct scan_context *sc)
 	if (sc->get_fw_scan_cmd_id && nl80211)
 		l_genl_family_cancel(nl80211, sc->get_fw_scan_cmd_id);
 
+	wiphy_state_watch_remove(sc->wiphy, sc->wiphy_watch_id);
+
 	l_free(sc);
 }
 
@@ -477,6 +466,142 @@ done:
 	return msg;
 }
 
+static void scan_add_6ghz(uint32_t freq, void *user_data)
+{
+	struct scan_freq_set *freqs = user_data;
+
+	if (freq < 6000)
+		return;
+
+	scan_freq_set_add(freqs, freq);
+}
+
+static void scan_wiphy_watch(struct wiphy *wiphy,
+				enum wiphy_state_watch_event event,
+				void *user_data)
+{
+	struct scan_context *sc = user_data;
+	struct scan_request *sr = NULL;
+	struct l_genl_msg *msg;
+	struct scan_parameters params = { 0 };
+	struct scan_freq_set *freqs_6ghz;
+	struct scan_freq_set *allowed;
+	bool allow_6g;
+	const struct scan_freq_set *supported =
+					wiphy_get_supported_freqs(wiphy);
+
+	/* Only care about regulatory events, and if 6GHz capable */
+	if ((event != WIPHY_STATE_WATCH_EVENT_REGDOM_STARTED &&
+			event != WIPHY_STATE_WATCH_EVENT_REGDOM_DONE) ||
+			!(scan_freq_set_get_bands(supported) & BAND_FREQ_6_GHZ))
+		return;
+
+	allowed = scan_get_allowed_freqs(sc);
+	allow_6g = scan_freq_set_get_bands(allowed) & BAND_FREQ_6_GHZ;
+
+	switch (event) {
+	case WIPHY_STATE_WATCH_EVENT_REGDOM_STARTED:
+		if (allow_6g)
+			goto done;
+
+		sc->expect_6ghz = true;
+
+		/*
+		 * If there is a running/queued periodic scan we may need to
+		 * delay the results if 6GHz becomes available.
+		 */
+		if (sc->sp.id)
+			sc->sp.wait_on_regdom = true;
+
+		goto done;
+	case WIPHY_STATE_WATCH_EVENT_REGDOM_DONE:
+		if (!sc->expect_6ghz)
+			goto done;
+
+		sc->expect_6ghz = false;
+
+		if (!sc->sp.id)
+			goto done;
+
+		sr = l_queue_find(sc->requests, scan_request_match,
+						L_UINT_TO_PTR(sc->sp.id));
+		if (!sr)
+			goto done;
+
+		/* This update did not allow 6GHz */
+		if (!allow_6g)
+			goto check_periodic;
+
+		/*
+		 * At this point we know there is an ongoing periodic scan.
+		 * Create a new 6GHz passive scan request and append to the
+		 * command list
+		 */
+		freqs_6ghz = scan_freq_set_new();
+
+		scan_freq_set_foreach(allowed, scan_add_6ghz, freqs_6ghz);
+
+		msg = scan_build_cmd(sc, false, true, &params, freqs_6ghz);
+		l_queue_push_tail(sr->cmds, msg);
+
+		scan_freq_set_free(freqs_6ghz);
+
+check_periodic:
+		if (sc->sp.wait_on_regdom) {
+			/* Periodic scan results delayed until this update */
+			if (sr && l_queue_peek_head(sc->requests) == sr)
+				start_next_scan_request(&sr->work);
+
+			sc->sp.wait_on_regdom = false;
+		}
+
+		break;
+	default:
+		return;
+	}
+
+done:
+	scan_freq_set_free(allowed);
+}
+
+/*
+ * Should only used to initialize 'expect_6ghz'. This is only to cover the case
+ * of a scan context being created during a regulatory update, which means it
+ * would miss the START event. If a DONE event comes, and expect_6ghz is false,
+ * no further action would be taken which may be incorrect.
+ */
+static bool scan_expect_6ghz(struct wiphy *wiphy)
+{
+	const struct scan_freq_set *supported =
+					wiphy_get_supported_freqs(wiphy);
+
+	if (!(scan_freq_set_get_bands(supported) & BAND_FREQ_6_GHZ))
+		return false;
+
+	return wiphy_regdom_is_updating(wiphy);
+}
+
+static struct scan_context *scan_context_new(uint64_t wdev_id)
+{
+	struct wiphy *wiphy = wiphy_find_by_wdev(wdev_id);
+	struct scan_context *sc;
+
+	if (!wiphy)
+		return NULL;
+
+	sc = l_new(struct scan_context, 1);
+
+	sc->wdev_id = wdev_id;
+	sc->wiphy = wiphy;
+	sc->state = SCAN_STATE_NOT_RUNNING;
+	sc->requests = l_queue_new();
+	sc->expect_6ghz = scan_expect_6ghz(wiphy);
+	sc->wiphy_watch_id = wiphy_state_watch_add(wiphy, scan_wiphy_watch,
+							sc, NULL);
+
+	return sc;
+}
+
 struct l_genl_msg *scan_build_trigger_scan_bss(uint32_t ifindex,
 						struct wiphy *wiphy,
 						uint32_t frequency,
@@ -2120,6 +2245,10 @@ static void scan_notify(struct l_genl_msg *msg, void *user_data)
 		if (sr && sr->triggered) {
 			sr->triggered = false;
 
+			/* Regdom changed during a periodic scan */
+			if (sc->sp.id == sr->work.id && sc->sp.wait_on_regdom)
+				return;
+
 			if (!sr->callback) {
 				scan_finished(sc, -ECANCELED, NULL, NULL, sr);
 				break;
-- 
2.34.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 13/13] wiphy: don't re-dump wiphy if the regdom didn't change
  2022-08-03 21:36 [PATCH v2 01/13] wiphy: fix runtime error from bit shift James Prestwood
                   ` (10 preceding siblings ...)
  2022-08-03 21:36 ` [PATCH v2 12/13] scan: watch for regdom updates " James Prestwood
@ 2022-08-03 21:36 ` James Prestwood
  11 siblings, 0 replies; 16+ messages in thread
From: James Prestwood @ 2022-08-03 21:36 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

For whatever reason the kernel will send regdom updates even if
the regdom didn't change. This ends up causing wiphy to dump
which isn't needed since there should be no changes in disabled
frequencies.

Now the previous country is checked against the new one, and if
they match the wiphy is not dumped again.
---
 src/wiphy.c | 38 +++++++++++++++++++++++++++-----------
 1 file changed, 27 insertions(+), 11 deletions(-)

diff --git a/src/wiphy.c b/src/wiphy.c
index dec4b15e..cf7bd9bd 100644
--- a/src/wiphy.c
+++ b/src/wiphy.c
@@ -2029,7 +2029,20 @@ static void wiphy_dump_after_regdom(struct wiphy *wiphy)
 static void wiphy_update_reg_domain(struct wiphy *wiphy, bool global,
 					struct l_genl_msg *msg)
 {
-	char *out_country;
+	char out_country[2];
+	char *orig;
+
+	/*
+	 * Write the new country code or XX if the reg domain is not a
+	 * country domain.
+	 */
+	if (nl80211_parse_attrs(msg, NL80211_ATTR_REG_ALPHA2, out_country,
+				NL80211_ATTR_UNSPEC) < 0)
+		out_country[0] = out_country[1] = 'X';
+
+	l_debug("New reg domain country code for %s is %c%c",
+		global ? "(global)" : wiphy->name,
+		out_country[0], out_country[1]);
 
 	if (global)
 		/*
@@ -2043,21 +2056,24 @@ static void wiphy_update_reg_domain(struct wiphy *wiphy, bool global,
 		 * wiphy created (that is not self-managed anyway) and we
 		 * haven't received any REG_CHANGE events yet.
 		 */
-		out_country = regdom_country;
+		orig = regdom_country;
+
 	else
-		out_country = wiphy->regdom_country;
+		orig = wiphy->regdom_country;
 
 	/*
-	 * Write the new country code or XX if the reg domain is not a
-	 * country domain.
+	 * The kernel seems to send regdom updates even if the country didn't
+	 * change. Skip these as there is no reason to re-dump.
 	 */
-	if (nl80211_parse_attrs(msg, NL80211_ATTR_REG_ALPHA2, out_country,
-				NL80211_ATTR_UNSPEC) < 0)
-		out_country[0] = out_country[1] = 'X';
+	if (orig[0] == out_country[0] && orig[1] == out_country[1]) {
+		if (wiphy && wiphy->get_reg_id)
+			wiphy->get_reg_id = 0;
 
-	l_debug("New reg domain country code for %s is %c%c",
-		global ? "(global)" : wiphy->name,
-		out_country[0], out_country[1]);
+		return;
+	}
+
+	orig[0] = out_country[0];
+	orig[1] = out_country[1];
 
 	/* Don't dump wiphy from a GET_REG call */
 	if (wiphy && wiphy->get_reg_id) {
-- 
2.34.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 03/13] nl80211util: add nl80211_parse_supported_frequencies
  2022-08-03 21:36 ` [PATCH v2 03/13] nl80211util: add nl80211_parse_supported_frequencies James Prestwood
@ 2022-08-04 15:27   ` Denis Kenzior
  0 siblings, 0 replies; 16+ messages in thread
From: Denis Kenzior @ 2022-08-04 15:27 UTC (permalink / raw)
  To: James Prestwood, iwd

Hi James,

On 8/3/22 16:36, James Prestwood wrote:
> A helper function to parse supported and disabled frequencies.
> ---
>   src/nl80211util.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
>   src/nl80211util.h |  4 ++++
>   2 files changed, 49 insertions(+)
> 

<snip>

> +int nl80211_parse_supported_frequencies(struct l_genl_attr *band_freqs,
> +					struct scan_freq_set *supported_list,
> +					struct scan_freq_set *disabled_list)
> +{
> +	uint16_t type, len;
> +	const void *data;
> +	struct l_genl_attr attr;
> +	struct l_genl_attr nested;
> +
> +	if (!l_genl_attr_recurse(band_freqs, &nested))
> +		return -EBADMSG;
> +
> +	while (l_genl_attr_next(&nested, NULL, NULL, NULL)) {
> +		uint32_t freq = 0;
> +		bool disabled = false;
> +
> +		if (!l_genl_attr_recurse(&nested, &attr))
> +			continue;
> +
> +		while (l_genl_attr_next(&attr, &type, &len, &data)) {
> +

I squished this empty line when applying.

> +			switch (type) {
> +			case NL80211_FREQUENCY_ATTR_FREQ:
> +				freq = *((uint32_t *) data);
> +				break;
> +			case NL80211_FREQUENCY_ATTR_DISABLED:
> +				disabled = true;
> +				break;
> +			}
> +		}
> +

Patches 1-5 applied, thanks.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 06/13] wiphy: add two regulatory domain state events
  2022-08-03 21:36 ` [PATCH v2 06/13] wiphy: add two regulatory domain state events James Prestwood
@ 2022-08-04 15:31   ` Denis Kenzior
  0 siblings, 0 replies; 16+ messages in thread
From: Denis Kenzior @ 2022-08-04 15:31 UTC (permalink / raw)
  To: James Prestwood, iwd

Hi James,

On 8/3/22 16:36, James Prestwood wrote:
> Events to indicate when a regulatory domain wiphy dump has
> started and ended. This is important because certain actions
> such as scanning need to be delayed until the dump has finished.
> ---
>   src/device.c | 2 ++
>   src/wiphy.h  | 2 ++
>   2 files changed, 4 insertions(+)
> 
> diff --git a/src/device.c b/src/device.c
> index 02da2cdc..d7eb6adb 100644
> --- a/src/device.c
> +++ b/src/device.c
> @@ -282,6 +282,8 @@ static void device_wiphy_state_changed_event(struct wiphy *wiphy,
>   			netdev_set_powered(device->netdev, true,
>   							NULL, NULL, NULL);
>   		break;
> +	default:
> +		break;

nit: Prefer to not use default: when possible.  The reason is that if a new 
enumeration is added (like you do here), the compiler will warn when it isn't 
handled.  Prefer to be paranoid and explicitly add all the enumerations instead, 
so that any new enumerations are not left mistakenly unhandled.

>   	}
>   }
>   

I amended this patch to do the above and applied, thanks!

Regards,
-Denis

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 09/13] wiphy: add wiphy_country_is_unknown
  2022-08-03 21:36 ` [PATCH v2 09/13] wiphy: add wiphy_country_is_unknown James Prestwood
@ 2022-08-04 16:48   ` Denis Kenzior
  0 siblings, 0 replies; 16+ messages in thread
From: Denis Kenzior @ 2022-08-04 16:48 UTC (permalink / raw)
  To: James Prestwood, iwd

Hi James,

On 8/3/22 16:36, James Prestwood wrote:
> A helper to check whether the country code corresponds to a
> real country, or some special code indicating the country isn't
> yet set. For now, the special codes are OO (world roaming) and
> XX (unknown entity).
> ---
>   src/wiphy.c | 16 ++++++++++++++++
>   src/wiphy.h |  1 +
>   2 files changed, 17 insertions(+)
> 

Applied, thanks.

Regards,
-Denis


^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2022-08-04 17:06 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-03 21:36 [PATCH v2 01/13] wiphy: fix runtime error from bit shift James Prestwood
2022-08-03 21:36 ` [PATCH v2 02/13] scan: track scanned frequencies for entire request James Prestwood
2022-08-03 21:36 ` [PATCH v2 03/13] nl80211util: add nl80211_parse_supported_frequencies James Prestwood
2022-08-04 15:27   ` Denis Kenzior
2022-08-03 21:36 ` [PATCH v2 04/13] wiphy: track self-managed flag James Prestwood
2022-08-03 21:36 ` [PATCH v2 05/13] wiphy: use nl80211_parse_supported_frequencies James Prestwood
2022-08-03 21:36 ` [PATCH v2 06/13] wiphy: add two regulatory domain state events James Prestwood
2022-08-04 15:31   ` Denis Kenzior
2022-08-03 21:36 ` [PATCH v2 07/13] wiphy: dump wiphy's on regulatory domain change James Prestwood
2022-08-03 21:36 ` [PATCH v2 08/13] wiphy: add wiphy_regdom_is_updating James Prestwood
2022-08-03 21:36 ` [PATCH v2 09/13] wiphy: add wiphy_country_is_unknown James Prestwood
2022-08-04 16:48   ` Denis Kenzior
2022-08-03 21:36 ` [PATCH v2 10/13] station: do full passive scan if 6GHz is supported but disabled James Prestwood
2022-08-03 21:36 ` [PATCH v2 11/13] scan: split full scans by band to enable 6GHz James Prestwood
2022-08-03 21:36 ` [PATCH v2 12/13] scan: watch for regdom updates " James Prestwood
2022-08-03 21:36 ` [PATCH v2 13/13] wiphy: don't re-dump wiphy if the regdom didn't change James Prestwood

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.