diff mbox series

[4/4] hostapd: support MBO in bss_transition_request

Message ID 20220621133610.4018404-4-stijn@linux-ipv6.be
State Accepted, archived
Delegated to: Stijn Tintel
Headers show
Series [1/4] hostapd: add config symbol to enable MBO | expand

Commit Message

Stijn Tintel June 21, 2022, 1:36 p.m. UTC
Support the use of MBO in the bss_transition_request ubus method.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
---
 package/network/services/hostapd/README.md    |  3 +
 .../services/hostapd/src/src/ap/ubus.c        | 61 ++++++++++++++++++-
 2 files changed, 61 insertions(+), 3 deletions(-)

Comments

Strontium June 27, 2022, 11:05 p.m. UTC | #1
Hi Stijn,

I am wanting to test these patches on an AP.  Is this a case of applying 
this, configure MBO enabled, and it just works?  I ask, because it looks 
like a daemon of some kind needs to manage the MBO transitions of the 
attached STA using UBUS transition requests, is that correct?


On 21/6/22 20:36, Stijn Tintel wrote:
> Support the use of MBO in the bss_transition_request ubus method.
>
> Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
> ---
>   package/network/services/hostapd/README.md    |  3 +
>   .../services/hostapd/src/src/ap/ubus.c        | 61 ++++++++++++++++++-
>   2 files changed, 61 insertions(+), 3 deletions(-)
>
> diff --git a/package/network/services/hostapd/README.md b/package/network/services/hostapd/README.md
> index bd347c61dd..2150863306 100644
> --- a/package/network/services/hostapd/README.md
> +++ b/package/network/services/hostapd/README.md
> @@ -29,6 +29,9 @@ Initiate an 802.11v transition request.
>   | neighbors | array | no | BSS Transition Candidate List |
>   | abridged | bool | no | prefer APs in the BSS Transition Candidate List |
>   | dialog_token | int32 | no | identifier for the request/report transaction |
> +| mbo_reason | int32 | no | MBO Transition Reason Code Attribute |
> +| cell_pref | int32 | no | MBO Cellular Data Connection Preference Attribute |
> +| reassoc_delay | int32 | no | MBO Re-association retry delay |
>   
>   ### example
>   `ubus call hostapd.wl5-fb bss_transition_request '{ "addr": "68:2F:67:8B:98:ED", "disassociation_imminent": false, "disassociation_timer": 0, "validity_period": 30, "neighbors": ["b6a7b9cbeebabf5900008064090603026a00"], "abridged": 1 }'`
> diff --git a/package/network/services/hostapd/src/src/ap/ubus.c b/package/network/services/hostapd/src/src/ap/ubus.c
> index 1199098b1e..182aae7d05 100644
> --- a/package/network/services/hostapd/src/src/ap/ubus.c
> +++ b/package/network/services/hostapd/src/src/ap/ubus.c
> @@ -1454,7 +1454,7 @@ void hostapd_ubus_handle_link_measurement(struct hostapd_data *hapd, const u8 *d
>   static int
>   hostapd_bss_tr_send(struct hostapd_data *hapd, u8 *addr, bool disassoc_imminent, bool abridged,
>   		    u16 disassoc_timer, u8 validity_period, u8 dialog_token,
> -		    struct blob_attr *neighbors)
> +		    struct blob_attr *neighbors, u8 mbo_reason, u8 cell_pref, u8 reassoc_delay)
>   {
>   	struct blob_attr *cur;
>   	struct sta_info *sta;
> @@ -1462,6 +1462,8 @@ hostapd_bss_tr_send(struct hostapd_data *hapd, u8 *addr, bool disassoc_imminent,
>   	int rem;
>   	u8 *nr = NULL;
>   	u8 req_mode = 0;
> +	u8 mbo[10];
> +	size_t mbo_len = 0;
>   
>   	sta = ap_get_sta(hapd, addr);
>   	if (!sta)
> @@ -1513,8 +1515,37 @@ hostapd_bss_tr_send(struct hostapd_data *hapd, u8 *addr, bool disassoc_imminent,
>   	if (disassoc_imminent)
>   		req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
>   
> +#ifdef CONFIG_MBO
> +	u8 *mbo_pos = mbo;
> +
> +	if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP)
> +		return UBUS_STATUS_INVALID_ARGUMENT;
> +
> +	if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255)
> +		return UBUS_STATUS_INVALID_ARGUMENT;
> +
> +	if (reassoc_delay > 65535 || (reassoc_delay && !disassoc_imminent))
> +		return UBUS_STATUS_INVALID_ARGUMENT;
> +
> +	*mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
> +	*mbo_pos++ = 1;
> +	*mbo_pos++ = mbo_reason;
> +	*mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
> +	*mbo_pos++ = 1;
> +	*mbo_pos++ = cell_pref;
> +
> +	if (reassoc_delay) {
> +		*mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
> +		*mbo_pos++ = 2;
> +		WPA_PUT_LE16(mbo_pos, reassoc_delay);
> +		mbo_pos += 2;
> +	}
> +
> +	mbo_len = mbo_pos - mbo;
> +#endif
> +
>   	if (wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer, validity_period, NULL,
> -				dialog_token, NULL, nr, nr_len, NULL, 0))
> +				dialog_token, NULL, nr, nr_len, mbo_len ? mbo : NULL, mbo_len))
>   		return UBUS_STATUS_UNKNOWN_ERROR;
>   
>   	return 0;
> @@ -1528,6 +1559,11 @@ enum {
>   	BSS_TR_NEIGHBORS,
>   	BSS_TR_ABRIDGED,
>   	BSS_TR_DIALOG_TOKEN,
> +#ifdef CONFIG_MBO
> +	BSS_TR_MBO_REASON,
> +	BSS_TR_CELL_PREF,
> +	BSS_TR_REASSOC_DELAY,
> +#endif
>   	__BSS_TR_DISASSOC_MAX
>   };
>   
> @@ -1539,6 +1575,11 @@ static const struct blobmsg_policy bss_tr_policy[__BSS_TR_DISASSOC_MAX] = {
>   	[BSS_TR_NEIGHBORS] = { "neighbors", BLOBMSG_TYPE_ARRAY },
>   	[BSS_TR_ABRIDGED] = { "abridged", BLOBMSG_TYPE_BOOL },
>   	[BSS_TR_DIALOG_TOKEN] = { "dialog_token", BLOBMSG_TYPE_INT32 },
> +#ifdef CONFIG_MBO
> +	[BSS_TR_MBO_REASON] = { "mbo_reason", BLOBMSG_TYPE_INT32 },
> +	[BSS_TR_CELL_PREF] = { "cell_pref", BLOBMSG_TYPE_INT32 },
> +	[BSS_TR_REASSOC_DELAY] = { "reassoc_delay", BLOBMSG_TYPE_INT32 },
> +#endif
>   };
>   
>   static int
> @@ -1555,6 +1596,9 @@ hostapd_bss_transition_request(struct ubus_context *ctx, struct ubus_object *obj
>   	u32 dialog_token = 1;
>   	bool abridged;
>   	bool da_imminent;
> +	u8 mbo_reason;
> +	u8 cell_pref;
> +	u8 reassoc_delay;
>   
>   	blobmsg_parse(bss_tr_policy, __BSS_TR_DISASSOC_MAX, tb, blob_data(msg), blob_len(msg));
>   
> @@ -1576,8 +1620,19 @@ hostapd_bss_transition_request(struct ubus_context *ctx, struct ubus_object *obj
>   	da_imminent = !!(tb[BSS_TR_DA_IMMINENT] && blobmsg_get_bool(tb[BSS_TR_DA_IMMINENT]));
>   	abridged = !!(tb[BSS_TR_ABRIDGED] && blobmsg_get_bool(tb[BSS_TR_ABRIDGED]));
>   
> +#ifdef CONFIG_MBO
> +	if (tb[BSS_TR_MBO_REASON])
> +		mbo_reason = blobmsg_get_u32(tb[BSS_TR_MBO_REASON]);
> +
> +	if (tb[BSS_TR_CELL_PREF])
> +		cell_pref = blobmsg_get_u32(tb[BSS_TR_CELL_PREF]);
> +
> +	if (tb[BSS_TR_REASSOC_DELAY])
> +		reassoc_delay = blobmsg_get_u32(tb[BSS_TR_REASSOC_DELAY]);
> +#endif
> +
>   	return hostapd_bss_tr_send(hapd, addr, da_imminent, abridged, da_timer, valid_period,
> -				   dialog_token, tb[BSS_TR_NEIGHBORS]);
> +				   dialog_token, tb[BSS_TR_NEIGHBORS], mbo_reason, cell_pref, reassoc_delay);
>   }
>   #endif
>
Stijn Tintel June 27, 2022, 11:26 p.m. UTC | #2
On 28/06/2022 02:05, Strontium wrote:
> Hi Stijn,
>
> I am wanting to test these patches on an AP.  Is this a case of 
> applying this, configure MBO enabled, and it just works?  I ask, 
> because it looks like a daemon of some kind needs to manage the MBO 
> transitions of the attached STA using UBUS transition requests, is 
> that correct?
>
This patch merely adds support for MBO to the existing ubus method 
bss_transition_request. This method is used by [1] and [2] to steer 
clients between different BSSes in an ESS, but does nothing on its own. 
Once this patch is in OpenWrt, these daemons could be updated to make 
use of the new MBO attributes for improved steering.

Stijn

[1] https://git.openwrt.org/?p=project/usteer.git
[2] https://github.com/berlin-open-wireless-lab/DAWN
diff mbox series

Patch

diff --git a/package/network/services/hostapd/README.md b/package/network/services/hostapd/README.md
index bd347c61dd..2150863306 100644
--- a/package/network/services/hostapd/README.md
+++ b/package/network/services/hostapd/README.md
@@ -29,6 +29,9 @@  Initiate an 802.11v transition request.
 | neighbors | array | no | BSS Transition Candidate List |
 | abridged | bool | no | prefer APs in the BSS Transition Candidate List |
 | dialog_token | int32 | no | identifier for the request/report transaction |
+| mbo_reason | int32 | no | MBO Transition Reason Code Attribute |
+| cell_pref | int32 | no | MBO Cellular Data Connection Preference Attribute |
+| reassoc_delay | int32 | no | MBO Re-association retry delay |
 
 ### example
 `ubus call hostapd.wl5-fb bss_transition_request '{ "addr": "68:2F:67:8B:98:ED", "disassociation_imminent": false, "disassociation_timer": 0, "validity_period": 30, "neighbors": ["b6a7b9cbeebabf5900008064090603026a00"], "abridged": 1 }'`
diff --git a/package/network/services/hostapd/src/src/ap/ubus.c b/package/network/services/hostapd/src/src/ap/ubus.c
index 1199098b1e..182aae7d05 100644
--- a/package/network/services/hostapd/src/src/ap/ubus.c
+++ b/package/network/services/hostapd/src/src/ap/ubus.c
@@ -1454,7 +1454,7 @@  void hostapd_ubus_handle_link_measurement(struct hostapd_data *hapd, const u8 *d
 static int
 hostapd_bss_tr_send(struct hostapd_data *hapd, u8 *addr, bool disassoc_imminent, bool abridged,
 		    u16 disassoc_timer, u8 validity_period, u8 dialog_token,
-		    struct blob_attr *neighbors)
+		    struct blob_attr *neighbors, u8 mbo_reason, u8 cell_pref, u8 reassoc_delay)
 {
 	struct blob_attr *cur;
 	struct sta_info *sta;
@@ -1462,6 +1462,8 @@  hostapd_bss_tr_send(struct hostapd_data *hapd, u8 *addr, bool disassoc_imminent,
 	int rem;
 	u8 *nr = NULL;
 	u8 req_mode = 0;
+	u8 mbo[10];
+	size_t mbo_len = 0;
 
 	sta = ap_get_sta(hapd, addr);
 	if (!sta)
@@ -1513,8 +1515,37 @@  hostapd_bss_tr_send(struct hostapd_data *hapd, u8 *addr, bool disassoc_imminent,
 	if (disassoc_imminent)
 		req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
 
+#ifdef CONFIG_MBO
+	u8 *mbo_pos = mbo;
+
+	if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP)
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255)
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	if (reassoc_delay > 65535 || (reassoc_delay && !disassoc_imminent))
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	*mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
+	*mbo_pos++ = 1;
+	*mbo_pos++ = mbo_reason;
+	*mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
+	*mbo_pos++ = 1;
+	*mbo_pos++ = cell_pref;
+
+	if (reassoc_delay) {
+		*mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
+		*mbo_pos++ = 2;
+		WPA_PUT_LE16(mbo_pos, reassoc_delay);
+		mbo_pos += 2;
+	}
+
+	mbo_len = mbo_pos - mbo;
+#endif
+
 	if (wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer, validity_period, NULL,
-				dialog_token, NULL, nr, nr_len, NULL, 0))
+				dialog_token, NULL, nr, nr_len, mbo_len ? mbo : NULL, mbo_len))
 		return UBUS_STATUS_UNKNOWN_ERROR;
 
 	return 0;
@@ -1528,6 +1559,11 @@  enum {
 	BSS_TR_NEIGHBORS,
 	BSS_TR_ABRIDGED,
 	BSS_TR_DIALOG_TOKEN,
+#ifdef CONFIG_MBO
+	BSS_TR_MBO_REASON,
+	BSS_TR_CELL_PREF,
+	BSS_TR_REASSOC_DELAY,
+#endif
 	__BSS_TR_DISASSOC_MAX
 };
 
@@ -1539,6 +1575,11 @@  static const struct blobmsg_policy bss_tr_policy[__BSS_TR_DISASSOC_MAX] = {
 	[BSS_TR_NEIGHBORS] = { "neighbors", BLOBMSG_TYPE_ARRAY },
 	[BSS_TR_ABRIDGED] = { "abridged", BLOBMSG_TYPE_BOOL },
 	[BSS_TR_DIALOG_TOKEN] = { "dialog_token", BLOBMSG_TYPE_INT32 },
+#ifdef CONFIG_MBO
+	[BSS_TR_MBO_REASON] = { "mbo_reason", BLOBMSG_TYPE_INT32 },
+	[BSS_TR_CELL_PREF] = { "cell_pref", BLOBMSG_TYPE_INT32 },
+	[BSS_TR_REASSOC_DELAY] = { "reassoc_delay", BLOBMSG_TYPE_INT32 },
+#endif
 };
 
 static int
@@ -1555,6 +1596,9 @@  hostapd_bss_transition_request(struct ubus_context *ctx, struct ubus_object *obj
 	u32 dialog_token = 1;
 	bool abridged;
 	bool da_imminent;
+	u8 mbo_reason;
+	u8 cell_pref;
+	u8 reassoc_delay;
 
 	blobmsg_parse(bss_tr_policy, __BSS_TR_DISASSOC_MAX, tb, blob_data(msg), blob_len(msg));
 
@@ -1576,8 +1620,19 @@  hostapd_bss_transition_request(struct ubus_context *ctx, struct ubus_object *obj
 	da_imminent = !!(tb[BSS_TR_DA_IMMINENT] && blobmsg_get_bool(tb[BSS_TR_DA_IMMINENT]));
 	abridged = !!(tb[BSS_TR_ABRIDGED] && blobmsg_get_bool(tb[BSS_TR_ABRIDGED]));
 
+#ifdef CONFIG_MBO
+	if (tb[BSS_TR_MBO_REASON])
+		mbo_reason = blobmsg_get_u32(tb[BSS_TR_MBO_REASON]);
+
+	if (tb[BSS_TR_CELL_PREF])
+		cell_pref = blobmsg_get_u32(tb[BSS_TR_CELL_PREF]);
+
+	if (tb[BSS_TR_REASSOC_DELAY])
+		reassoc_delay = blobmsg_get_u32(tb[BSS_TR_REASSOC_DELAY]);
+#endif
+
 	return hostapd_bss_tr_send(hapd, addr, da_imminent, abridged, da_timer, valid_period,
-				   dialog_token, tb[BSS_TR_NEIGHBORS]);
+				   dialog_token, tb[BSS_TR_NEIGHBORS], mbo_reason, cell_pref, reassoc_delay);
 }
 #endif