blob: d6f13f15a2f79cacd092a51eda8c716d95f1b0c9 [file] [log] [blame]
From cc04411d78f2569cc235e0f5620b3476091a1af1 Mon Sep 17 00:00:00 2001
From: Michael-CY Lee <michael-cy.lee@mediatek.com>
Date: Thu, 14 Dec 2023 14:42:58 +0800
Subject: [PATCH 1/2] hostapd: mtk: add support for removeing the main BSS
The first hostapd_data/i802_bss are important to hostapd since many
operations/events are directly operated on the first BSS.
(such as iface->bss[0], drv->first_bss, etc)
To remove the main BSS, the 1st and 2nd hostapd_data/i802_bss are
switched, then the new 2nd hostapd_data/i802_bss are removed as it is
done to remove BSS other than the first one.
This patch add the new command to remove the BSS (including the first
one):
$ hostapd_cli -i global raw REMOVE_BSS <ifname>
Note that if the command is used in OpenWrt, an additional step is
needed:
update the "aplist" in /var/state/wireless according to the removed ifname
Therefore the "wifi" command can work normally.
Signed-off-by: Michael-CY Lee <michael-cy.lee@mediatek.com>
---
hostapd/ctrl_iface.c | 14 ++++++
src/ap/ap_drv_ops.h | 10 +++++
src/ap/hostapd.c | 85 +++++++++++++++++++++++++++++++++++-
src/ap/hostapd.h | 1 +
src/drivers/driver.h | 2 +
src/drivers/driver_nl80211.c | 43 ++++++++++++++++++
6 files changed, 153 insertions(+), 2 deletions(-)
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 6552bc4..650af3b 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -5028,6 +5028,17 @@ static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces,
}
+static int hostapd_ctrl_bss_remove(struct hapd_interfaces *interfaces,
+ char *buf)
+{
+ if (hostapd_remove_bss(interfaces, buf) < 0) {
+ wpa_printf(MSG_ERROR, "Removing interface %s failed", buf);
+ return -1;
+ }
+ return 0;
+}
+
+
static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
char *buf)
{
@@ -5444,6 +5455,9 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
} else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "REMOVE_BSS ", 11) == 0) {
+ if (hostapd_ctrl_bss_remove(interfaces, buf + 11) < 0)
+ reply_len = -1;
} else if (os_strcmp(buf, "ATTACH") == 0) {
if (hostapd_global_ctrl_iface_attach(interfaces, &from,
fromlen, NULL))
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 2a89b99..95db664 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -310,6 +310,16 @@ static inline const char * hostapd_drv_get_radio_name(struct hostapd_data *hapd)
return hapd->driver->get_radio_name(hapd->drv_priv);
}
+static inline int hostapd_drv_move_bss_to_first(struct hostapd_data *hapd,
+ const char *ifname)
+{
+ if (hapd->driver == NULL || hapd->driver->move_bss_to_first == NULL ||
+ hapd->drv_priv == NULL)
+ return -1;
+
+ return hapd->driver->move_bss_to_first(hapd->drv_priv, ifname);
+}
+
static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd,
struct csa_settings *settings)
{
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 250c168..7f58354 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -3297,7 +3297,35 @@ fail:
}
-static int hostapd_remove_bss(struct hostapd_iface *iface, unsigned int idx)
+int hostapd_move_bss_to_first(struct hostapd_iface *iface, int idx)
+{
+ struct hostapd_data *target_hapd, *first_hapd;
+
+ if (idx == 0 || idx >= iface->num_bss)
+ return -1;
+
+ target_hapd = iface->bss[idx];
+ first_hapd = iface->bss[0];
+ if (hostapd_drv_move_bss_to_first(first_hapd, target_hapd->conf->iface))
+ return -1;
+
+ iface->bss[0] = target_hapd;
+ iface->bss[idx] = first_hapd;
+ iface->conf->bss[0] = iface->bss[0]->conf;
+ iface->conf->bss[idx] = iface->bss[idx]->conf;
+
+ first_hapd->interface_added = 1;
+ target_hapd->interface_added = 0;
+
+ if (idx == iface->num_bss - 1)
+ iface->conf->last_bss = iface->bss[idx]->conf;
+
+ return 0;
+}
+
+
+static int hostapd_remove_bss_by_idx(struct hostapd_iface *iface,
+ unsigned int idx)
{
size_t i;
@@ -3331,6 +3359,59 @@ static int hostapd_remove_bss(struct hostapd_iface *iface, unsigned int idx)
}
+int hostapd_remove_bss(struct hapd_interfaces *interfaces, char *buf)
+{
+ struct hostapd_iface *hapd_iface;
+ size_t i, j, k = 0;
+ int ret;
+
+ for (i = 0; i < interfaces->count; i++) {
+ hapd_iface = interfaces->iface[i];
+ if (hapd_iface == NULL)
+ return -1;
+
+ if (!os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) {
+ if (hapd_iface->conf->num_bss == 1) {
+ wpa_printf(MSG_INFO, "Remove interface '%s'", buf);
+ hapd_iface->driver_ap_teardown =
+ !!(hapd_iface->drv_flags &
+ WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
+
+ hostapd_interface_deinit_free(hapd_iface);
+ k = i;
+ while (k < (interfaces->count - 1)) {
+ interfaces->iface[k] =
+ interfaces->iface[k + 1];
+ k++;
+ }
+ interfaces->count--;
+ return 0;
+ } else {
+ wpa_printf(MSG_INFO, "Switch interface to %s",
+ hapd_iface->bss[1]->conf->iface);
+
+ ret = hostapd_move_bss_to_first(hapd_iface, 1);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ "Interface switch failed");
+ return ret;
+ }
+ }
+ }
+
+ for (j = 0; j < hapd_iface->conf->num_bss; j++) {
+ if (!os_strcmp(hapd_iface->conf->bss[j]->iface, buf)) {
+ hapd_iface->driver_ap_teardown =
+ !(hapd_iface->drv_flags &
+ WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
+ return hostapd_remove_bss_by_idx(hapd_iface, j);
+ }
+ }
+ }
+ return -1;
+}
+
+
int hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf)
{
struct hostapd_iface *hapd_iface;
@@ -3362,7 +3443,7 @@ int hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf)
hapd_iface->driver_ap_teardown =
!(hapd_iface->drv_flags &
WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
- return hostapd_remove_bss(hapd_iface, j);
+ return hostapd_remove_bss_by_idx(hapd_iface, j);
}
}
}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 3b51050..824a24a 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -701,6 +701,7 @@ void hostapd_bss_deinit_no_free(struct hostapd_data *hapd);
void hostapd_free_hapd_data(struct hostapd_data *hapd);
void hostapd_cleanup_iface_partial(struct hostapd_iface *iface);
int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
+int hostapd_remove_bss(struct hapd_interfaces *ifaces, char *buf);
int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator);
void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 01281a1..ab19794 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -3185,6 +3185,8 @@ struct wpa_driver_ops {
*/
void (*hapd_deinit)(void *priv);
+ int (*move_bss_to_first)(void *priv, const char *ifname);
+
/**
* set_ieee8021x - Enable/disable IEEE 802.1X support (AP only)
* @priv: Private driver interface data
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index e744a18..cef502f 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -7986,6 +7986,48 @@ static void i802_deinit(void *priv)
wpa_driver_nl80211_deinit(bss);
}
+static int i802_move_bss_to_first(void *priv, const char *ifname)
+{
+ struct i802_bss *bss = priv;
+ struct i802_bss *first_bss, *target_bss, *prev_bss, *tmp_bss;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ if (!os_strcmp(bss->ifname, ifname)) {
+ wpa_printf(MSG_ERROR, "nl80211: BSS is already the first one");
+ return -1;
+ }
+
+ prev_bss = drv->first_bss;
+ target_bss = drv->first_bss->next;
+ while (target_bss) {
+ if (!os_strcmp(target_bss->ifname, ifname))
+ break;
+
+ prev_bss = target_bss;
+ target_bss = target_bss->next;
+ }
+
+ if (!target_bss) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to find the target BSS");
+ return -1;
+ }
+
+ first_bss = drv->first_bss;
+ drv->first_bss = target_bss;
+ prev_bss->next = first_bss;
+
+ tmp_bss = first_bss->next;
+ first_bss->next = target_bss->next;
+ target_bss->next = tmp_bss;
+
+ memcpy(drv->perm_addr, drv->first_bss->addr, ETH_ALEN);
+ drv->ifindex = if_nametoindex(drv->first_bss->ifname);
+ drv->ctx = drv->first_bss->ctx;
+
+ first_bss->added_if = 1;
+ target_bss->added_if = 0;
+ return 0;
+}
static enum nl80211_iftype wpa_driver_nl80211_if_type(
enum wpa_driver_if_type type)
@@ -13433,6 +13475,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.sta_set_airtime_weight = driver_nl80211_sta_set_airtime_weight,
.hapd_init = i802_init,
.hapd_deinit = i802_deinit,
+ .move_bss_to_first = i802_move_bss_to_first,
.set_wds_sta = i802_set_wds_sta,
.get_seqnum = i802_get_seqnum,
.flush = i802_flush,
--
2.25.1