| 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 |
| |