All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5] scan: watch for regdom updates to enable 6GHz
@ 2022-08-05 17:45 James Prestwood
  2022-08-05 18:39 ` Denis Kenzior
  0 siblings, 1 reply; 2+ messages in thread
From: James Prestwood @ 2022-08-05 17:45 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 | 157 +++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 121 insertions(+), 36 deletions(-)

diff --git a/src/scan.c b/src/scan.c
index d50c703c..1db91f32 100644
--- a/src/scan.c
+++ b/src/scan.c
@@ -110,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
@@ -187,24 +188,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;
@@ -230,6 +213,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);
 }
 
@@ -2012,6 +1997,110 @@ static void get_scan_done(void *user)
 	l_free(results);
 }
 
+static void scan_get_results(struct scan_context *sc, struct scan_request *sr,
+				struct scan_freq_set *freqs)
+{
+	struct scan_results *results;
+	struct l_genl_msg *scan_msg;
+
+	results = l_new(struct scan_results, 1);
+	results->sc = sc;
+	results->time_stamp = l_time_now();
+	results->sr = sr;
+	results->bss_list = l_queue_new();
+	results->freqs = freqs;
+
+	scan_msg = l_genl_msg_new_sized(NL80211_CMD_GET_SCAN, 8);
+
+	l_genl_msg_append_attr(scan_msg, NL80211_ATTR_WDEV, 8,
+					&sc->wdev_id);
+	sc->get_scan_cmd_id = l_genl_family_dump(nl80211, scan_msg,
+						get_scan_callback,
+						results, get_scan_done);
+}
+
+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 = NULL;
+	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_DONE ||
+			!(scan_freq_set_get_bands(supported) & BAND_FREQ_6_GHZ))
+		return;
+
+	if (!sc->sp.id)
+		return;
+
+	sr = l_queue_find(sc->requests, scan_request_match,
+						L_UINT_TO_PTR(sc->sp.id));
+	if (!sr)
+		return;
+
+	allowed = scan_get_allowed_freqs(sc);
+	allow_6g = scan_freq_set_get_bands(allowed) & BAND_FREQ_6_GHZ;
+
+	/*
+	 * This update did not allow 6GHz, or the original request was
+	 * not expecting 6GHz. The periodic scan should now be ended.
+	 */
+	if (!allow_6g || !sr->split) {
+		scan_get_results(sc, sr, sr->freqs_scanned);
+		goto free_allowed;
+	}
+
+	/*
+	 * 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_clone(allowed, BAND_FREQ_6_GHZ);
+
+	msg = scan_build_cmd(sc, false, true, &params, freqs_6ghz);
+	l_queue_push_tail(sr->cmds, msg);
+
+	scan_freq_set_free(freqs_6ghz);
+
+	/*
+	 * If this periodic scan is at the top of the queue, continue
+	 * running it.
+	 */
+	if (l_queue_peek_head(sc->requests) == sr)
+		start_next_scan_request(&sr->work);
+
+free_allowed:
+	scan_freq_set_free(allowed);
+}
+
+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->wiphy_watch_id = wiphy_state_watch_add(wiphy, scan_wiphy_watch,
+							sc, NULL);
+
+	return sc;
+}
+
 static bool scan_parse_flush_flag_from_msg(struct l_genl_msg *msg)
 {
 	struct l_genl_attr attr;
@@ -2100,8 +2189,7 @@ static void scan_notify(struct l_genl_msg *msg, void *user_data)
 	switch (cmd) {
 	case NL80211_CMD_NEW_SCAN_RESULTS:
 	{
-		struct l_genl_msg *scan_msg;
-		struct scan_results *results;
+		struct scan_freq_set *freqs;
 		bool send_next = false;
 		bool retry = false;
 		bool get_results = false;
@@ -2117,6 +2205,14 @@ static void scan_notify(struct l_genl_msg *msg, void *user_data)
 				break;
 			}
 
+			/* Regdom changed during a periodic scan */
+			if (sc->sp.id == sr->work.id &&
+					wiphy_regdom_is_updating(sc->wiphy)) {
+				scan_parse_result_frequencies(msg,
+							sr->freqs_scanned);
+				return;
+			}
+
 			/*
 			 * If this was the last command for the current request
 			 * avoid starting the next request until the GET_SCAN
@@ -2168,29 +2264,18 @@ static void scan_notify(struct l_genl_msg *msg, void *user_data)
 		if (!get_results)
 			break;
 
-		results = l_new(struct scan_results, 1);
-		results->sc = sc;
-		results->time_stamp = l_time_now();
-		results->sr = sr;
-		results->bss_list = l_queue_new();
-
 		/*
 		 * In case this was an external scan, setup a new, temporary
 		 * frequency set to report the results to the periodic callback
 		 */
-		if (!results->sr)
-			results->freqs = scan_freq_set_new();
+		if (!sr)
+			freqs = scan_freq_set_new();
 		else
-			results->freqs = sr->freqs_scanned;
+			freqs = sr->freqs_scanned;
 
-		scan_parse_result_frequencies(msg, results->freqs);
+		scan_parse_result_frequencies(msg, freqs);
 
-		scan_msg = l_genl_msg_new_sized(NL80211_CMD_GET_SCAN, 8);
-		l_genl_msg_append_attr(scan_msg, NL80211_ATTR_WDEV, 8,
-					&sc->wdev_id);
-		sc->get_scan_cmd_id = l_genl_family_dump(nl80211, scan_msg,
-							get_scan_callback,
-							results, get_scan_done);
+		scan_get_results(sc, sr, freqs);
 
 		break;
 	}
-- 
2.34.3


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

* Re: [PATCH v5] scan: watch for regdom updates to enable 6GHz
  2022-08-05 17:45 [PATCH v5] scan: watch for regdom updates to enable 6GHz James Prestwood
@ 2022-08-05 18:39 ` Denis Kenzior
  0 siblings, 0 replies; 2+ messages in thread
From: Denis Kenzior @ 2022-08-05 18:39 UTC (permalink / raw)
  To: James Prestwood, iwd

Hi James,

On 8/5/22 12:45, James Prestwood wrote:
> 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 | 157 +++++++++++++++++++++++++++++++++++++++++------------
>   1 file changed, 121 insertions(+), 36 deletions(-)
> 

Applied, thanks.

Regards,
-Denis

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

end of thread, other threads:[~2022-08-05 18:40 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-05 17:45 [PATCH v5] scan: watch for regdom updates to enable 6GHz James Prestwood
2022-08-05 18:39 ` Denis Kenzior

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.