public inbox for iwd@lists.linux.dev
 help / color / mirror / Atom feed
From: James Prestwood <prestwoj@gmail.com>
To: iwd@lists.linux.dev
Cc: James Prestwood <prestwoj@gmail.com>
Subject: [PATCH] ap: implement pre-scanning to "unlock" frequencies
Date: Mon, 19 May 2025 07:39:30 -0700	[thread overview]
Message-ID: <20250519143930.182695-1-prestwoj@gmail.com> (raw)

Some drivers/hardware are more strict about limiting use of
certain frequencies on startup until the regulatory domain has
been set. For most cards the only way to set the regulatory domain
is to scan and see BSS's nearby that advertise the country they
reside in.

This is particularly important for AP mode since AP's are always
emitting radiation from beacons and will not start until the desired
frequency is both enabled and allows IR. To make this process
seamless in IWD we will first check that the desired frequency is
enabled/IR and if not issue a scan to (hopefully) get the regulatory
domain set.
---
 src/ap.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)

diff --git a/src/ap.c b/src/ap.c
index d52b7e55..af6a1709 100644
--- a/src/ap.c
+++ b/src/ap.c
@@ -109,6 +109,8 @@ struct ap_state {
 	struct l_timeout *rekey_timeout;
 	unsigned int rekey_time;
 
+	uint32_t pre_scan_cmd_id;
+
 	bool started : 1;
 	bool gtk_set : 1;
 	bool netconfig_set_addr4 : 1;
@@ -354,6 +356,12 @@ static void ap_reset(struct ap_state *ap)
 		l_timeout_remove(ap->rekey_timeout);
 		ap->rekey_timeout = NULL;
 	}
+
+	if (ap->pre_scan_cmd_id) {
+		scan_cancel(netdev_get_wdev_id(ap->netdev),
+				ap->pre_scan_cmd_id);
+		ap->pre_scan_cmd_id = 0;
+	}
 }
 
 static bool ap_event_done(struct ap_state *ap, bool prev_in_event)
@@ -3852,6 +3860,70 @@ static int ap_load_config(struct ap_state *ap, const struct l_settings *config,
 	return 0;
 }
 
+static void ap_pre_scan_trigger(int err, void *user_data)
+{
+	struct ap_state *ap = user_data;
+
+	if (err < 0) {
+		l_error("AP pre-scan failed: %i", err);
+		ap_start_failed(ap, err);
+		return;
+	}
+}
+
+static bool ap_check_channel(struct ap_state *ap)
+{
+	const struct band_freq_attrs *freq_attr;
+
+	freq_attr = wiphy_get_frequency_info(netdev_get_wiphy(ap->netdev),
+				band_channel_to_freq(ap->channel, ap->band));
+	if (L_WARN_ON(!freq_attr))
+		return false;
+
+	/* Check if disabled/no-IR */
+	if (freq_attr->disabled || freq_attr->no_ir)
+		return false;
+
+	return true;
+}
+
+static bool ap_pre_scan_notify(int err, struct l_queue *bss_list,
+				const struct scan_freq_set *freqs,
+				void *user_data)
+{
+	struct ap_state *ap = user_data;
+
+	if (!ap_check_channel(ap)) {
+		l_error("Unable to channel %u even after pre-scan",
+			ap->channel);
+		goto error;
+	}
+
+	if (ap_start_send(ap))
+		return false;
+
+error:
+	ap_start_failed(ap, -ENOTSUP);
+	return false;
+}
+
+static void ap_pre_scan_destroy(void *user_data)
+{
+	struct ap_state *ap = user_data;
+
+	ap->pre_scan_cmd_id = 0;
+}
+
+static bool ap_pre_scan(struct ap_state *ap)
+{
+	ap->pre_scan_cmd_id = scan_passive(netdev_get_wdev_id(ap->netdev),
+						NULL, ap_pre_scan_trigger,
+						ap_pre_scan_notify,
+						ap, ap_pre_scan_destroy);
+
+	return ap->pre_scan_cmd_id != 0;
+}
+
 /*
  * Start a simple independent WPA2 AP on given netdev.
  *
@@ -3962,6 +4034,20 @@ struct ap_state *ap_start(struct netdev *netdev, struct l_settings *config,
 		return ap;
 	}
 
+	if (!ap_check_channel(ap)) {
+		l_debug("Channel %u is disabled/no-IR, pre-scanning",
+			ap->channel);
+
+		if (ap_pre_scan(ap)) {
+			if (err_out)
+				*err_out = 0;
+
+			return ap;
+		}
+
+		goto error;
+	}
+
 	if (ap_start_send(ap)) {
 		if (err_out)
 			*err_out = 0;
-- 
2.34.1


             reply	other threads:[~2025-05-19 14:39 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-05-19 14:39 James Prestwood [this message]
2025-05-19 21:37 ` [PATCH] ap: implement pre-scanning to "unlock" frequencies Denis Kenzior

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250519143930.182695-1-prestwoj@gmail.com \
    --to=prestwoj@gmail.com \
    --cc=iwd@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox