[PATCH] hostapd_cli: Introduce add_link command

Lorenzo Bianconi lorenzo at kernel.org
Thu Mar 12 10:28:45 PDT 2026


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

Introduce add_link command in order to re-add a previously link removed
via hostapd_cli remove_link comand. The add_link command relies on the
following syntax:

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

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>
---
 hostapd/ctrl_iface.c  | 90 +++++++++++++++++++++++++++++++++++++++++++
 hostapd/hostapd_cli.c |  9 +++++
 2 files changed, 99 insertions(+)

diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 248f808bb..77a519644 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -3546,6 +3546,92 @@ static int hostapd_ctrl_iface_disable_mld(struct hostapd_iface *iface)
 
 
 #ifdef CONFIG_TESTING_OPTIONS
+static int hostapd_ctrl_iface_link_add(struct hostapd_data *hapd, char *cmd,
+				       char *buf, size_t buflen)
+{
+	struct hapd_interfaces *interfaces = hapd->iface->interfaces;
+	struct hostapd_iface *iface = NULL;
+	size_t len = os_strlen(cmd) + 1;
+	const char *conf_file, *phy;
+	struct hostapd_config *conf;
+	bool hapd_exist = false;
+	char *pos, *cmd_buf;
+	int i, ret;
+
+	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;
+
+	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) {
+		const char *ifname = conf->bss[0]->iface;
+
+		if (ifname && ifname[0] != '\0') {
+			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))) {
+					hapd_exist = true;
+					break;
+				}
+			}
+		}
+	}
+
+	if (hapd_exist)
+		ret = hostapd_enable_iface(iface);
+	else
+		ret = hostapd_add_iface(interfaces, cmd);
+
+	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;
+}
+
+
 static int hostapd_ctrl_iface_link_remove(struct hostapd_data *hapd, char *cmd,
 					  char *buf, size_t buflen)
 {
@@ -4552,6 +4638,10 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
 		if (hostapd_ctrl_iface_disable_mld(hapd->iface))
 			reply_len = -1;
 #ifdef CONFIG_TESTING_OPTIONS
+	} else if (os_strncmp(buf, "LINK_ADD ", 9) == 0) {
+		if (hostapd_ctrl_iface_link_add(hapd, buf + 9, reply,
+						reply_size))
+			reply_len = -1;
 	} else if (os_strncmp(buf, "LINK_REMOVE ", 12) == 0) {
 		if (hostapd_ctrl_iface_link_remove(hapd, buf + 12,
 						   reply, reply_size))
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 797fd41f8..622499430 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1281,6 +1281,12 @@ static int hostapd_cli_cmd_enable_mld(struct wpa_ctrl *ctrl, int argc,
 
 
 #ifdef CONFIG_TESTING_OPTIONS
+static int hostapd_cli_cmd_add_link(struct wpa_ctrl *ctrl, int argc,
+				    char *argv[])
+{
+	return hostapd_cli_cmd(ctrl, "LINK_ADD", 1, argc, argv);
+}
+
 static int hostapd_cli_cmd_remove_link(struct wpa_ctrl *ctrl, int argc,
 				       char *argv[])
 {
@@ -1817,6 +1823,9 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
 	{ "enable_mld", hostapd_cli_cmd_enable_mld, NULL,
 	  "= enable AP MLD to which the interface is affiliated" },
 #ifdef CONFIG_TESTING_OPTIONS
+	{ "link_add", hostapd_cli_cmd_add_link, NULL,
+	  " bss_config=<phy>:<config file>\n"
+	  " = add a new link to the MLD AP" },
 	{ "remove_link", hostapd_cli_cmd_remove_link, NULL,
 	  "<count> = remove MLO link and send Reconfiguration MLE" },
 #endif /* CONFIG_TESTING_OPTIONS */
-- 
2.53.0




More information about the Hostap mailing list