diff mbox series

[v3,4/7] station: do full passive scan if 6GHz is supported but disabled.

Message ID 20220804185112.457670-4-prestwoj@gmail.com (mailing list archive)
State Not Applicable, archived
Headers show
Series [v3,1/7] wiphy: track GET_REG ID | expand

Checks

Context Check Description
tedd_an/pre-ci_am success Success
prestwoj/iwd-ci-gitlint fail [v3,4/7] station: do full passive scan if 6GHz is supported but disabled. 1: T3 Title has trailing punctuation (.): "[v3,4/7] station: do full passive scan if 6GHz is supported but disabled."

Commit Message

James Prestwood Aug. 4, 2022, 6:51 p.m. UTC
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 | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 68 insertions(+), 1 deletion(-)

v3:
 * Return -EAGAIN in the case of a regdom update rather than 0. Check this
   along with 0 in both calls.
 * Re-worked the wiphy state event to focus only on the DONE event, and set
   regdom_updated based on wiphy_regdom_is_updating. This avoids a switch
   statement when its mainly the DONE event we care about.
 * Check quick_scan_id if regdom update so we aren't accidentally re-triggering
   a quick scan.

Comments

Denis Kenzior Aug. 4, 2022, 7:20 p.m. UTC | #1
Hi James,

On 8/4/22 13:51, James Prestwood wrote:
> 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.

I tweaked the patch header and re-flowed the description to keep gitlint happy.

> ---
>   src/station.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++-
>   1 file changed, 68 insertions(+), 1 deletion(-)
> 
> v3:
>   * Return -EAGAIN in the case of a regdom update rather than 0. Check this
>     along with 0 in both calls.
>   * Re-worked the wiphy state event to focus only on the DONE event, and set
>     regdom_updated based on wiphy_regdom_is_updating. This avoids a switch
>     statement when its mainly the DONE event we care about.
>   * Check quick_scan_id if regdom update so we aren't accidentally re-triggering
>     a quick scan.
> 

<snip>

> @@ -119,6 +121,7 @@ struct station {
>   	bool scanning : 1;
>   	bool autoconnect : 1;
>   	bool autoconnect_can_start : 1;
> +	bool regdom_updating : 1;

I also got rid of this bit to use wiphy_regdom_is_updating() directly.

>   };
>   
>   struct anqp_entry {

<snip>

> +static void station_wiphy_watch(struct wiphy *wiphy,
> +				enum wiphy_state_watch_event event,
> +				void *user_data)
> +{
> +	struct station *station = user_data;
> +	int ret;
> +
> +	station->regdom_updating = wiphy_regdom_is_updating(wiphy);
> +
> +	if (event != WIPHY_STATE_WATCH_EVENT_REGDOM_DONE)
> +		return;
> +
> +	/*
> +	 * 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. Just in
> +	 * case this update came during a quick scan, ignore it.
> +	 */
> +	if (station->state != STATION_STATE_AUTOCONNECT_QUICK ||
> +			station->quick_scan_id)
> +		return;
> +
> +	ret = station_quick_scan_trigger(station);
> +	if (ret == 0 || ret == -EAGAIN)

Since -EAGAIN shouldn't actually be possible here, I changed this to:
if (!ret)

and added an L_WARN for -EAGAIN afterwards

> +		return;
> +
> +	station_enter_state(station, STATION_STATE_AUTOCONNECT_FULL);
> +}
> +

Applied, thanks.

Regards,
-Denis
diff mbox series

Patch

diff --git a/src/station.c b/src/station.c
index e39e9d4b..e3a36f46 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,36 @@  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);
+
+	if (station->regdom_updating) {
+		l_debug("regdom is updating, delaying quick scan");
+
+		return -EAGAIN;
+	}
 
 	known_freq_set = known_networks_get_recent_frequencies(5);
 	if (!known_freq_set)
 		return -ENODATA;
 
+	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 -ENOTSUP;
+
 	if (!wiphy_constrain_freq_set(station->wiphy, known_freq_set)) {
 		scan_freq_set_free(known_freq_set);
 		return -ENOTSUP;
@@ -1446,6 +1474,7 @@  static void station_enter_state(struct station *station,
 	uint64_t id = netdev_get_wdev_id(station->netdev);
 	struct l_dbus *dbus = dbus_get_bus();
 	bool disconnected;
+	int ret;
 
 	l_debug("Old State: %s, new state: %s",
 			station_state_to_string(station->state),
@@ -1462,7 +1491,8 @@  static void station_enter_state(struct station *station,
 
 	switch (state) {
 	case STATION_STATE_AUTOCONNECT_QUICK:
-		if (!station_quick_scan_trigger(station))
+		ret = station_quick_scan_trigger(station);
+		if (ret == 0 || ret == -EAGAIN)
 			break;
 
 		station->state = STATION_STATE_AUTOCONNECT_FULL;
@@ -3988,6 +4018,36 @@  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;
+	int ret;
+
+	station->regdom_updating = wiphy_regdom_is_updating(wiphy);
+
+	if (event != WIPHY_STATE_WATCH_EVENT_REGDOM_DONE)
+		return;
+
+	/*
+	 * 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. Just in
+	 * case this update came during a quick scan, ignore it.
+	 */
+	if (station->state != STATION_STATE_AUTOCONNECT_QUICK ||
+			station->quick_scan_id)
+		return;
+
+	ret = station_quick_scan_trigger(station);
+	if (ret == 0 || ret == -EAGAIN)
+		return;
+
+	station_enter_state(station, STATION_STATE_AUTOCONNECT_FULL);
+}
+
 static struct station *station_create(struct netdev *netdev)
 {
 	struct station *station;
@@ -4008,6 +4068,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),
@@ -4117,6 +4182,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);
 }