public inbox for iwd@lists.linux.dev
 help / color / mirror / Atom feed
* [PATCH v3 1/3] wiphy: add flag for supporting remain on channel
@ 2024-08-29 11:41 James Prestwood
  2024-08-29 11:41 ` [PATCH v3 2/3] station: don't allow FT-over-Air without offchannel support James Prestwood
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: James Prestwood @ 2024-08-29 11:41 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

---
 src/wiphy.c | 9 +++++++++
 src/wiphy.h | 1 +
 2 files changed, 10 insertions(+)

diff --git a/src/wiphy.c b/src/wiphy.c
index 13d498a5..cdaa89ad 100644
--- a/src/wiphy.c
+++ b/src/wiphy.c
@@ -149,6 +149,7 @@ struct wiphy {
 	bool self_managed : 1;
 	bool ap_probe_resp_offload : 1;
 	bool supports_uapsd : 1;
+	bool supports_cmd_offchannel : 1;
 };
 
 static struct l_queue *wiphy_list = NULL;
@@ -939,6 +940,11 @@ bool wiphy_supports_uapsd(const struct wiphy *wiphy)
 	return wiphy->supports_uapsd;
 }
 
+bool wiphy_supports_cmd_offchannel(const struct wiphy *wiphy)
+{
+	return wiphy->supports_cmd_offchannel;
+}
+
 const uint8_t *wiphy_get_ht_capabilities(const struct wiphy *wiphy,
 						enum band_freq band,
 						size_t *size)
@@ -1385,6 +1391,9 @@ static void parse_supported_commands(struct wiphy *wiphy,
 		case NL80211_CMD_ASSOCIATE:
 			assoc = true;
 			break;
+		case NL80211_CMD_REMAIN_ON_CHANNEL:
+			wiphy->supports_cmd_offchannel = true;
+			break;
 		}
 	}
 
diff --git a/src/wiphy.h b/src/wiphy.h
index bc82a007..17e53075 100644
--- a/src/wiphy.h
+++ b/src/wiphy.h
@@ -141,6 +141,7 @@ 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);
 bool wiphy_supports_uapsd(const struct wiphy *wiphy);
+bool wiphy_supports_cmd_offchannel(const struct wiphy *wiphy);
 
 const uint8_t *wiphy_get_ht_capabilities(const struct wiphy *wiphy,
 						enum band_freq band,
-- 
2.34.1


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

* [PATCH v3 2/3] station: don't allow FT-over-Air without offchannel support
  2024-08-29 11:41 [PATCH v3 1/3] wiphy: add flag for supporting remain on channel James Prestwood
@ 2024-08-29 11:41 ` James Prestwood
  2024-08-29 11:41 ` [PATCH v3 3/3] netdev: fall back to RSSI polling if SET_CQM fails James Prestwood
  2024-09-03 15:11 ` [PATCH v3 1/3] wiphy: add flag for supporting remain on channel Denis Kenzior
  2 siblings, 0 replies; 5+ messages in thread
From: James Prestwood @ 2024-08-29 11:41 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

If CMD_REMAIN_ON_CHANNEL isn't supported, don't allow FT-over-Air
---
 src/station.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/src/station.c b/src/station.c
index 30a1232a..5f174a70 100644
--- a/src/station.c
+++ b/src/station.c
@@ -2105,7 +2105,8 @@ static void station_early_neighbor_report_cb(struct netdev *netdev, int err,
 				&station->roam_freqs);
 }
 
-static bool station_can_fast_transition(struct handshake_state *hs,
+static bool station_can_fast_transition(struct station *station,
+					struct handshake_state *hs,
 					struct scan_bss *bss)
 {
 	uint16_t mdid;
@@ -2133,6 +2134,16 @@ static bool station_can_fast_transition(struct handshake_state *hs,
 			return false;
 	}
 
+	/*
+	 * FT-over-Air in its current form relies on CMD_REMAIN_ON_CHANNEL. Some
+	 * drivers do not support this so only allow over-DS if this is the case
+	 */
+	if (!(hs->mde[4] & 1) &&
+			!wiphy_supports_cmd_offchannel(station->wiphy)) {
+		l_debug("FT-over-Air needs offchannel, using reassociation");
+		return false;
+	}
+
 	return true;
 }
 
@@ -2596,7 +2607,7 @@ static bool station_try_next_transition(struct station *station,
 	station->ap_directed_roaming = false;
 
 	/* Can we use Fast Transition? */
-	if (station_can_fast_transition(hs, bss) && !no_ft)
+	if (station_can_fast_transition(station, hs, bss) && !no_ft)
 		return station_fast_transition(station, bss);
 
 	/* Non-FT transition */
-- 
2.34.1


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

* [PATCH v3 3/3] netdev: fall back to RSSI polling if SET_CQM fails
  2024-08-29 11:41 [PATCH v3 1/3] wiphy: add flag for supporting remain on channel James Prestwood
  2024-08-29 11:41 ` [PATCH v3 2/3] station: don't allow FT-over-Air without offchannel support James Prestwood
@ 2024-08-29 11:41 ` James Prestwood
  2024-09-03 15:15   ` Denis Kenzior
  2024-09-03 15:11 ` [PATCH v3 1/3] wiphy: add flag for supporting remain on channel Denis Kenzior
  2 siblings, 1 reply; 5+ messages in thread
From: James Prestwood @ 2024-08-29 11:41 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

Some drivers fail to set a CQM threshold and report not supported.
Its unclear exactly why but if this happens roaming is effectively
broken.

To work around this enable RSSI polling if -ENOTSUP is returned.
The polling callback has been changed to emit the HIGH/LOW signal
threshold events instead of just the RSSI level index, just as if
a CQM event came from the kernel.
---
 src/netdev.c | 142 ++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 94 insertions(+), 48 deletions(-)

v3:
 * Rebaed on top of upstream

diff --git a/src/netdev.c b/src/netdev.c
index 73fbf0c1..a3f72deb 100644
--- a/src/netdev.c
+++ b/src/netdev.c
@@ -190,6 +190,7 @@ struct netdev {
 	bool retry_auth : 1;
 	bool in_reassoc : 1;
 	bool privacy : 1;
+	bool cqm_poll_fallback : 1;
 };
 
 struct netdev_preauth_state {
@@ -650,6 +651,47 @@ static void netdev_set_rssi_level_idx(struct netdev *netdev)
 	netdev->cur_rssi_level_idx = new_level;
 }
 
+static void netdev_cqm_event_rssi_value(struct netdev *netdev, int rssi_val)
+{
+	bool new_rssi_low;
+	uint8_t prev_rssi_level_idx = netdev->cur_rssi_level_idx;
+	int threshold = netdev->frequency > 4000 ?
+					netdev->low_signal_threshold_5ghz :
+					netdev->low_signal_threshold;
+
+	if (!netdev->connected)
+		return;
+
+	if (rssi_val > 127)
+		rssi_val = 127;
+	else if (rssi_val < -127)
+		rssi_val = -127;
+
+	netdev->cur_rssi = rssi_val;
+
+	if (!netdev->event_filter)
+		return;
+
+	new_rssi_low = rssi_val < threshold;
+	if (netdev->cur_rssi_low != new_rssi_low) {
+		int event = new_rssi_low ?
+			NETDEV_EVENT_RSSI_THRESHOLD_LOW :
+			NETDEV_EVENT_RSSI_THRESHOLD_HIGH;
+
+		netdev->cur_rssi_low = new_rssi_low;
+		netdev->event_filter(netdev, event, NULL, netdev->user_data);
+	}
+
+	if (!netdev->rssi_levels_num)
+		return;
+
+	netdev_set_rssi_level_idx(netdev);
+	if (netdev->cur_rssi_level_idx != prev_rssi_level_idx)
+		netdev->event_filter(netdev, NETDEV_EVENT_RSSI_LEVEL_NOTIFY,
+					&netdev->cur_rssi_level_idx,
+					netdev->user_data);
+}
+
 static void netdev_rssi_poll_cb(struct l_genl_msg *msg, void *user_data)
 {
 	struct netdev *netdev = user_data;
@@ -686,11 +728,16 @@ static void netdev_rssi_poll_cb(struct l_genl_msg *msg, void *user_data)
 	netdev->cur_rssi = info.cur_rssi;
 
 	/*
-	 * Note we don't have to handle LOW_SIGNAL_THRESHOLD here.  The
-	 * CQM single threshold RSSI monitoring should work even if the
-	 * kernel driver doesn't support multiple thresholds.  So the
-	 * polling only handles the client-supplied threshold list.
+	 * If the CMD_SET_CQM call failed RSSI polling was started. In this case
+	 * we should behave just like its a CQM event and check both the RSSI
+	 * level indexes and the HIGH/LOW thresholds.
 	 */
+	if (netdev->cqm_poll_fallback) {
+		netdev_cqm_event_rssi_value(netdev, info.cur_rssi);
+		goto done;
+	}
+
+	/* Otherwise just update the level notifications, CQM events work */
 	netdev_set_rssi_level_idx(netdev);
 	if (netdev->cur_rssi_level_idx != prev_rssi_level_idx)
 		netdev->event_filter(netdev, NETDEV_EVENT_RSSI_LEVEL_NOTIFY,
@@ -1039,6 +1086,9 @@ static void netdev_free(void *data)
 		netdev->get_link_cmd_id = 0;
 	}
 
+	if (netdev->rssi_poll_timeout)
+		l_timeout_remove(netdev->rssi_poll_timeout);
+
 	scan_wdev_remove(netdev->wdev_id);
 
 	watchlist_destroy(&netdev->station_watches);
@@ -1093,47 +1143,6 @@ static void netdev_cqm_event_rssi_threshold(struct netdev *netdev,
 	netdev->event_filter(netdev, event, NULL, netdev->user_data);
 }
 
-static void netdev_cqm_event_rssi_value(struct netdev *netdev, int rssi_val)
-{
-	bool new_rssi_low;
-	uint8_t prev_rssi_level_idx = netdev->cur_rssi_level_idx;
-	int threshold = netdev->frequency > 4000 ?
-					netdev->low_signal_threshold_5ghz :
-					netdev->low_signal_threshold;
-
-	if (!netdev->connected)
-		return;
-
-	if (rssi_val > 127)
-		rssi_val = 127;
-	else if (rssi_val < -127)
-		rssi_val = -127;
-
-	netdev->cur_rssi = rssi_val;
-
-	if (!netdev->event_filter)
-		return;
-
-	new_rssi_low = rssi_val < threshold;
-	if (netdev->cur_rssi_low != new_rssi_low) {
-		int event = new_rssi_low ?
-			NETDEV_EVENT_RSSI_THRESHOLD_LOW :
-			NETDEV_EVENT_RSSI_THRESHOLD_HIGH;
-
-		netdev->cur_rssi_low = new_rssi_low;
-		netdev->event_filter(netdev, event, NULL, netdev->user_data);
-	}
-
-	if (!netdev->rssi_levels_num)
-		return;
-
-	netdev_set_rssi_level_idx(netdev);
-	if (netdev->cur_rssi_level_idx != prev_rssi_level_idx)
-		netdev->event_filter(netdev, NETDEV_EVENT_RSSI_LEVEL_NOTIFY,
-					&netdev->cur_rssi_level_idx,
-					netdev->user_data);
-}
-
 static void netdev_cqm_event(struct l_genl_msg *msg, struct netdev *netdev)
 {
 	struct l_genl_attr attr;
@@ -3644,11 +3653,48 @@ static struct l_genl_msg *netdev_build_cmd_cqm_rssi_update(
 
 static void netdev_cmd_set_cqm_cb(struct l_genl_msg *msg, void *user_data)
 {
+	struct netdev *netdev = user_data;
 	int err = l_genl_msg_get_error(msg);
 	const char *ext_error;
 
-	if (err >= 0)
+	if (err >= 0) {
+		/*
+		 * Looking at some driver code it appears that the -ENOTSUP CQM
+		 * failure could be transient. Just in case, reset the fallback
+		 * flag if CQM happens to start working again.
+		 */
+		if (netdev->cqm_poll_fallback) {
+			l_debug("CMD_SET_CQM succeeded, stop polling fallback");
+
+			if (netdev->rssi_poll_timeout) {
+				l_timeout_remove(netdev->rssi_poll_timeout);
+				netdev->rssi_poll_timeout = NULL;
+			}
+
+			netdev->cqm_poll_fallback = false;
+		}
+
 		return;
+	}
+
+	/*
+	 * Some drivers enable beacon filtering but also use software CQM which
+	 * mac80211 detects and returns -ENOTSUP. There is no way to check this
+	 * ahead of time so if we see this start polling in order to get RSSI
+	 * updates.
+	 */
+	if (err == -ENOTSUP) {
+		l_debug("CMD_SET_CQM not supported, falling back to polling");
+		netdev->cqm_poll_fallback = true;
+
+		if (netdev->rssi_poll_timeout)
+			return;
+
+		netdev->rssi_poll_timeout = l_timeout_create(1,
+						netdev_rssi_poll, netdev, NULL);
+
+		return;
+	}
 
 	ext_error = l_genl_msg_get_extended_error(msg);
 	l_error("CMD_SET_CQM failed: %s",
@@ -3672,7 +3718,7 @@ static int netdev_cqm_rssi_update(struct netdev *netdev)
 		return -EINVAL;
 
 	if (!l_genl_family_send(nl80211, msg, netdev_cmd_set_cqm_cb,
-				NULL, NULL)) {
+				netdev, NULL)) {
 		l_genl_msg_unref(msg);
 		return -EIO;
 	}
@@ -5310,7 +5356,7 @@ int netdev_set_rssi_report_levels(struct netdev *netdev, const int8_t *levels,
 		return -EINVAL;
 
 	if (!l_genl_family_send(nl80211, cmd_set_cqm, netdev_cmd_set_cqm_cb,
-				NULL, NULL)) {
+				netdev, NULL)) {
 		l_genl_msg_unref(cmd_set_cqm);
 		return -EIO;
 	}
-- 
2.34.1


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

* Re: [PATCH v3 1/3] wiphy: add flag for supporting remain on channel
  2024-08-29 11:41 [PATCH v3 1/3] wiphy: add flag for supporting remain on channel James Prestwood
  2024-08-29 11:41 ` [PATCH v3 2/3] station: don't allow FT-over-Air without offchannel support James Prestwood
  2024-08-29 11:41 ` [PATCH v3 3/3] netdev: fall back to RSSI polling if SET_CQM fails James Prestwood
@ 2024-09-03 15:11 ` Denis Kenzior
  2 siblings, 0 replies; 5+ messages in thread
From: Denis Kenzior @ 2024-09-03 15:11 UTC (permalink / raw)
  To: James Prestwood, iwd

Hi James,

On 8/29/24 6:41 AM, James Prestwood wrote:
> ---
>   src/wiphy.c | 9 +++++++++
>   src/wiphy.h | 1 +
>   2 files changed, 10 insertions(+)
> 

Patch 1 & 2 applied, thanks.

Regards,
-Denis


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

* Re: [PATCH v3 3/3] netdev: fall back to RSSI polling if SET_CQM fails
  2024-08-29 11:41 ` [PATCH v3 3/3] netdev: fall back to RSSI polling if SET_CQM fails James Prestwood
@ 2024-09-03 15:15   ` Denis Kenzior
  0 siblings, 0 replies; 5+ messages in thread
From: Denis Kenzior @ 2024-09-03 15:15 UTC (permalink / raw)
  To: James Prestwood, iwd

Hi James,

On 8/29/24 6:41 AM, James Prestwood wrote:
> Some drivers fail to set a CQM threshold and report not supported.
> Its unclear exactly why but if this happens roaming is effectively
> broken.
> 
> To work around this enable RSSI polling if -ENOTSUP is returned.
> The polling callback has been changed to emit the HIGH/LOW signal
> threshold events instead of just the RSSI level index, just as if
> a CQM event came from the kernel.
> ---
>   src/netdev.c | 142 ++++++++++++++++++++++++++++++++++-----------------
>   1 file changed, 94 insertions(+), 48 deletions(-)
> 
> v3:
>   * Rebaed on top of upstream
> 

<snip>

> @@ -3672,7 +3718,7 @@ static int netdev_cqm_rssi_update(struct netdev *netdev)
>   		return -EINVAL;
>   
>   	if (!l_genl_family_send(nl80211, msg, netdev_cmd_set_cqm_cb,
> -				NULL, NULL)) {
> +				netdev, NULL)) {
>   		l_genl_msg_unref(msg);
>   		return -EIO;
>   	}
> @@ -5310,7 +5356,7 @@ int netdev_set_rssi_report_levels(struct netdev *netdev, const int8_t *levels,
>   		return -EINVAL;
>   
>   	if (!l_genl_family_send(nl80211, cmd_set_cqm, netdev_cmd_set_cqm_cb,
> -				NULL, NULL)) {
> +				netdev, NULL)) {
>   		l_genl_msg_unref(cmd_set_cqm);
>   		return -EIO;
>   	}

Since userdata is now used in these l_genl_family_send callbacks, you really 
should track the command id in case netdev gets removed.  Alternatively, switch 
netdev to start using a dedicated l_genl_family handle so that all outstanding 
requests get auto-canceled.

Regards,
-Denis

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

end of thread, other threads:[~2024-09-03 15:15 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-29 11:41 [PATCH v3 1/3] wiphy: add flag for supporting remain on channel James Prestwood
2024-08-29 11:41 ` [PATCH v3 2/3] station: don't allow FT-over-Air without offchannel support James Prestwood
2024-08-29 11:41 ` [PATCH v3 3/3] netdev: fall back to RSSI polling if SET_CQM fails James Prestwood
2024-09-03 15:15   ` Denis Kenzior
2024-09-03 15:11 ` [PATCH v3 1/3] wiphy: add flag for supporting remain on channel Denis Kenzior

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox