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
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
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 */
.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,
}
+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)
{
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);
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)
{
}
+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];
{ "dscp_query", wpa_cli_cmd_dscp_query, NULL,
cli_cmd_flag_none,
"wildcard/domain_name=<string> = Send DSCP Query" },
+ { "setup_link_reconfig", wpa_cli_cmd_setup_link_reconfig, NULL,
+ cli_cmd_flag_none,
+ "<<add=/delete=><ID1> [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" },