[PATCH v2] AP: Introduce support for testing ML link enable

Lorenzo Bianconi lorenzo at kernel.org
Thu Apr 9 01:52:05 PDT 2026


From: StanleyYP Wang <StanleyYP.Wang at mediatek.com>

Introduce LINK_ENABLE control interface command in order to enable a link
previously removed via hostapd_cli remove_link command.
The LINK_ENABLE command relies on the following syntax:

$hostapd_cli -i <interface> link_enable bss_conf=<phy>:<config-file>

Similar to ML link removal support added in commit 'd95838b7932b
("AP: Add support for testing ML link removal")', compile LINK_ENABLE
control interface command just if CONFIG_TESTING_OPTIONS is enabled
since it depends on remove_link counterpart.

Signed-off-by: StanleyYP Wang <StanleyYP.Wang at mediatek.com>
Co-developed-by: Lorenzo Bianconi <lorenzo at kernel.org>
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
Changes in v2:
- Fix compilation errors
- Rename the command in "link_enable" and limit it to enable link
  previously removed via hostapd_cli remove_link command.
---
 hostapd/ctrl_iface.c  | 87 +++++++++++++++++++++++++++++++++++++++++++
 hostapd/hostapd_cli.c | 10 +++++
 2 files changed, 97 insertions(+)

diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index d14b2660f..deb91bc7f 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -3576,6 +3576,89 @@ static int hostapd_ctrl_iface_link_remove(struct hostapd_data *hapd, char *cmd,
 
 	return ret;
 }
+
+
+static int hostapd_ctrl_iface_link_enable(struct hostapd_data *hapd, char *cmd,
+					  char *buf, size_t buflen)
+{
+	struct hapd_interfaces *interfaces = hapd->iface->interfaces;
+	const char *conf_file, *phy, *ifname;
+	struct hostapd_iface *iface = NULL;
+	size_t len = os_strlen(cmd) + 1;
+	struct hostapd_config *conf;
+	char *pos, *cmd_buf;
+	int ret = -1;
+	size_t i;
+
+	if (!hapd || !hapd->conf->mld_ap || !hapd->mld)
+		return -1;
+
+	if (os_strncmp(cmd, "bss_config=", 11))
+		return -1;
+
+	cmd_buf = os_malloc(len);
+	if (!cmd_buf)
+		return -1;
+
+	os_snprintf(cmd_buf, len, "%s", cmd);
+	phy = cmd_buf + 11;
+	pos = os_strchr(phy, ':');
+	if (!pos)
+		goto free_cmd_buffer;
+
+	*pos++ = '\0';
+	conf_file = pos;
+	if (!os_strlen(conf_file))
+		goto free_cmd_buffer;
+
+	conf = interfaces->config_read_cb(conf_file);
+	if (!conf)
+		goto free_cmd_buffer;
+
+	if (!conf->bss[0]->mld_ap)
+		goto free_config;
+
+	ifname = conf->bss[0]->iface;
+	if (!ifname || ifname[0] == '\0')
+		goto free_config;
+
+	for (i = 0; i < interfaces->count; i++) {
+		if (!os_strcmp(interfaces->iface[i]->phy, phy)) {
+			iface = interfaces->iface[i];
+			break;
+		}
+	}
+
+	if (!iface || iface->state != HAPD_IFACE_DISABLED)
+		goto free_config;
+
+	for (i = 0; i < iface->num_bss; i++) {
+		struct hostapd_data *h = iface->bss[i];
+
+		if (os_strncmp(ifname, h->conf->iface,
+			       sizeof(h->conf->iface)))
+			continue;
+
+		ret = hostapd_enable_iface(iface);
+		break;
+	}
+
+	if (ret < 0)
+		goto free_config;
+
+	ret = os_snprintf(buf, buflen, "%s\n", "OK");
+	if (os_snprintf_error(buflen, ret))
+		ret = -1;
+	else
+		ret = 0;
+
+free_config:
+	hostapd_config_free(conf);
+free_cmd_buffer:
+	os_free(cmd_buf);
+
+	return ret;
+}
 #endif /* CONFIG_TESTING_OPTIONS */
 #endif /* CONFIG_IEEE80211BE */
 
@@ -4566,6 +4649,10 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
 		if (hostapd_ctrl_iface_link_remove(hapd, buf + 12,
 						   reply, reply_size))
 			reply_len = -1;
+	} else if (os_strncmp(buf, "LINK_ENABLE ", 12) == 0) {
+		if (hostapd_ctrl_iface_link_enable(hapd, buf + 12, reply,
+						   reply_size))
+			reply_len = -1;
 #endif /* CONFIG_TESTING_OPTIONS */
 #endif /* CONFIG_IEEE80211BE */
 #ifdef CONFIG_SAE
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index cb42f3052..16f70fa23 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1293,6 +1293,13 @@ static int hostapd_cli_cmd_remove_link(struct wpa_ctrl *ctrl, int argc,
 
 	return wpa_ctrl_command(ctrl, buf);
 }
+
+
+static int hostapd_cli_cmd_link_enable(struct wpa_ctrl *ctrl, int argc,
+				    char *argv[])
+{
+	return hostapd_cli_cmd(ctrl, "LINK_ENABLE", 1, argc, argv);
+}
 #endif /* CONFIG_TESTING_OPTIONS */
 
 
@@ -1821,6 +1828,9 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
 #ifdef CONFIG_TESTING_OPTIONS
 	{ "remove_link", hostapd_cli_cmd_remove_link, NULL,
 	  "<count> = remove MLO link and send Reconfiguration MLE" },
+	{ "link_enable", hostapd_cli_cmd_link_enable, NULL,
+	  " bss_config=<phy>:<config file>\n"
+	  " = Enable a link previously removed from the MLD AP" },
 #endif /* CONFIG_TESTING_OPTIONS */
 	{ "disable_mld", hostapd_cli_cmd_disable_mld, NULL,
 	  "= disable AP MLD to which the interface is affiliated" },
-- 
2.53.0




More information about the Hostap mailing list