From: Kavita Kavita Date: Fri, 9 May 2025 15:50:28 +0000 (+0530) Subject: MLD STA: Add SETUP_LINK_RECONFIG control interface command X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=80ca096191a6df9da4290ed23342f70619ee2066;p=thirdparty%2Fhostap.git MLD STA: Add SETUP_LINK_RECONFIG control interface command Add support for SETUP_LINK_RECONFIG control interface command that allows users to add new setup links and/or remove existing ones for the current MLO connection in STA mode. Signed-off-by: Kavita Kavita --- diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 54b4a9b18..97b0e2e57 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -2762,6 +2762,22 @@ struct wpa_mlo_signal_info { struct wpa_signal_info links[MAX_NUM_MLD_LINKS]; }; +/** + * struct wpa_mlo_reconfig_info - Information about user-requested add and/or + * remove setup links for the current MLO association. + * + * @add_links: Bitmask of links to be added + * @add_link_bssid: Array of BSSIDs for the links to be added + * @add_link_freq: Array of frequencies for the links to be added + * @delete_links: Bitmask of links to be removed + */ +struct wpa_mlo_reconfig_info { + u16 add_links; + u8 add_link_bssid[MAX_NUM_MLD_LINKS][ETH_ALEN]; + int add_link_freq[MAX_NUM_MLD_LINKS]; + u16 delete_links; +}; + /** * struct wpa_channel_info - Information about the current channel * @frequency: Center frequency of the primary 20 MHz channel @@ -4466,6 +4482,15 @@ struct wpa_driver_ops { int (*mlo_signal_poll)(void *priv, struct wpa_mlo_signal_info *mlo_signal_info); + /** + * setup_link_reconfig - Used to initiate Link Reconfiguration request + * for the current MLO association. + * @priv: Private driver interface data + * @info: Link reconfiguration request info + */ + int (*setup_link_reconfig)(void *priv, + struct wpa_mlo_reconfig_info *info); + /** * channel_info - Get parameters of the current operating channel * @priv: Private driver interface data diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index b7c666db4..46d049159 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -14713,6 +14713,77 @@ free_all: return ret; } + +static int +nl80211_send_link_reconfig_request(void *priv, + struct wpa_mlo_reconfig_info *info) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + struct nlattr *add_links, *attr; + int ret = -1; + u8 link_id; + + if (!drv->sta_mlo_info.valid_links) + return -1; + + wpa_printf(MSG_DEBUG, "nl80211: Send ML Link Reconfiguration Request"); + + if (info->add_links) + wpa_printf(MSG_DEBUG, "Add Setup Links Bitmask: 0x%x", + info->add_links); + + if (info->delete_links) + wpa_printf(MSG_DEBUG, "Remove Setup Links Bitmask: 0x%x", + info->delete_links); + + msg = nl80211_drv_msg(drv, 0, NL80211_CMD_ASSOC_MLO_RECONF); + if (!msg) + goto error; + + add_links = nla_nest_start(msg, NL80211_ATTR_MLO_LINKS); + if (!add_links) + goto error; + + for_each_link(info->add_links, link_id) { + attr = nla_nest_start(msg, 0); + if (!attr) + goto error; + + if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id) || + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, + info->add_link_bssid[link_id]) || + nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, + info->add_link_freq[link_id])) + goto error; + + nla_nest_end(msg, attr); + } + + nla_nest_end(msg, add_links); + + if (nla_put_u16(msg, NL80211_ATTR_MLO_RECONF_REM_LINKS, + info->delete_links)) + goto error; + + ret = send_and_recv(drv, bss->nl_connect, msg, NULL, NULL, NULL, NULL, + NULL); + if (ret) { + wpa_printf(MSG_INFO, + "nl80211: Failed to send Link Reconfiguration Request err=%d (%s)", + ret, strerror(-ret)); + return ret; + } + return 0; + +error: + nlmsg_free(msg); + wpa_printf(MSG_ERROR, + "nl80211: Could not build Link Reconfiguration Request"); + return ret; +} + #endif /* CONFIG_IEEE80211BE */ @@ -14934,6 +15005,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .is_drv_shared = nl80211_is_drv_shared, .link_sta_remove = wpa_driver_nl80211_link_sta_remove, .can_share_drv = wpa_driver_nl80211_can_share_drv, + .setup_link_reconfig = nl80211_send_link_reconfig_request, #endif /* CONFIG_IEEE80211BE */ #ifdef CONFIG_TESTING_OPTIONS .register_frame = testing_nl80211_register_frame, diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 97d9ae1f0..afad3d18b 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -12286,6 +12286,85 @@ static int wpas_ctrl_iface_mlo_signal_poll(struct wpa_supplicant *wpa_s, } +static int +wpa_supplicant_ctrl_iface_setup_link_reconfig(struct wpa_supplicant *wpa_s, + const char *cmd) +{ + const char *pos, *add_pos, *dlt_pos; + struct wpa_mlo_reconfig_info info; + int link_id; + + add_pos = os_strstr(cmd, "add="); + dlt_pos = os_strstr(cmd, "delete="); + + if (!add_pos && !dlt_pos) { + wpa_printf(MSG_INFO, "No add or delete links info"); + return -1; + } + + if (!wpa_s->current_bss) { + wpa_printf(MSG_INFO, "%s: Not connected", __func__); + return -1; + } + + info.add_links = 0; + info.delete_links = 0; + + if (add_pos) { + pos = add_pos + 4; + + do { + link_id = atoi(pos); + if (link_id < 0 || link_id >= MAX_NUM_MLD_LINKS) + return -1; + + if (wpa_s->current_bss->valid_links & BIT(link_id)) { + info.add_links |= BIT(link_id); + os_memcpy(info.add_link_bssid[link_id], + wpa_s->current_bss->mld_links[link_id].bssid, + ETH_ALEN); + info.add_link_freq[link_id] = + wpa_s->current_bss->mld_links[link_id].freq; + } else { + wpa_printf(MSG_INFO, + "%s: add link info not present", + __func__); + return -1; + } + + pos = os_strchr(pos, ' '); + if (pos) + pos++; + } while (pos && pos != dlt_pos); + } + + if (dlt_pos) { + pos = dlt_pos + 7; + + do { + link_id = atoi(pos); + if (link_id < 0 || link_id >= MAX_NUM_MLD_LINKS) + return -1; + + if (wpa_s->valid_links & BIT(link_id)) + info.delete_links |= BIT(link_id); + else { + wpa_printf(MSG_INFO, + "%s: not a valid delete link", + __func__); + return -1; + } + + pos = os_strchr(pos, ' '); + if (pos) + pos++; + } while (pos && pos != add_pos); + } + + return wpa_drv_setup_link_reconfig(wpa_s, &info); +} + + static int wpas_ctrl_iface_mlo_status(struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { @@ -13852,6 +13931,10 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (wpas_ctrl_iface_send_dscp_query(wpa_s, buf + 11)) reply_len = -1; #endif /* CONFIG_NO_ROBUST_AV */ + } else if (os_strncmp(buf, "SETUP_LINK_RECONFIG", 19) == 0) { + if (wpa_supplicant_ctrl_iface_setup_link_reconfig(wpa_s, + buf + 19) < 0) + reply_len = -1; } else if (os_strcmp(buf, "MLO_STATUS") == 0) { reply_len = wpas_ctrl_iface_mlo_status(wpa_s, reply, reply_size); diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 43847cf4a..ccebd2cbe 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -532,6 +532,16 @@ static inline int wpa_drv_mlo_signal_poll(struct wpa_supplicant *wpa_s, return -1; } +static inline int +wpa_drv_setup_link_reconfig(struct wpa_supplicant *wpa_s, + struct wpa_mlo_reconfig_info *info) +{ + if (wpa_s->driver->setup_link_reconfig) + return wpa_s->driver->setup_link_reconfig(wpa_s->drv_priv, + info); + return -1; +} + static inline int wpa_drv_channel_info(struct wpa_supplicant *wpa_s, struct wpa_channel_info *ci) { diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index 2ab291712..b13bf4992 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -425,6 +425,13 @@ static int wpa_cli_cmd_mlo_signal_poll(struct wpa_ctrl *ctrl, int argc, char *ar } +static int wpa_cli_cmd_setup_link_reconfig(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "SETUP_LINK_RECONFIG", 1, argc, argv); +} + + static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[256]; @@ -4092,6 +4099,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { { "dscp_query", wpa_cli_cmd_dscp_query, NULL, cli_cmd_flag_none, "wildcard/domain_name= = Send DSCP Query" }, + { "setup_link_reconfig", wpa_cli_cmd_setup_link_reconfig, NULL, + cli_cmd_flag_none, + "< [ID2]...> = Add new setup links and/or remove existing ones for the current MLO connection in STA mode" }, { "mlo_status", wpa_cli_cmd_mlo_status, NULL, cli_cmd_flag_none, "= get MLO status" },