wlan-ap-Telecominfraproject/feeds/qca/hostapd/patches/r00-009-hostapd-de-initialize-disable-link-BSS-properly.patch
John Crispin 008ca9618d
Some checks failed
Build OpenWrt/uCentral images / build (cig_wf186h) (push) Has been cancelled
Build OpenWrt/uCentral images / build (cig_wf186w) (push) Has been cancelled
Build OpenWrt/uCentral images / build (cig_wf188n) (push) Has been cancelled
Build OpenWrt/uCentral images / build (cig_wf189) (push) Has been cancelled
Build OpenWrt/uCentral images / build (cig_wf196) (push) Has been cancelled
Build OpenWrt/uCentral images / build (cybertan_eww631-a1) (push) Has been cancelled
Build OpenWrt/uCentral images / build (cybertan_eww631-b1) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_eap101) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_eap102) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_eap104) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_eap105) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_eap111) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_eap112) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_oap101) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_oap101-6e) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_oap101e) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_oap101e-6e) (push) Has been cancelled
Build OpenWrt/uCentral images / build (hfcl_ion4x) (push) Has been cancelled
Build OpenWrt/uCentral images / build (hfcl_ion4x_2) (push) Has been cancelled
Build OpenWrt/uCentral images / build (hfcl_ion4x_3) (push) Has been cancelled
Build OpenWrt/uCentral images / build (hfcl_ion4x_w) (push) Has been cancelled
Build OpenWrt/uCentral images / build (hfcl_ion4xe) (push) Has been cancelled
Build OpenWrt/uCentral images / build (hfcl_ion4xi) (push) Has been cancelled
Build OpenWrt/uCentral images / build (hfcl_ion4xi_w) (push) Has been cancelled
Build OpenWrt/uCentral images / build (indio_um-305ax) (push) Has been cancelled
Build OpenWrt/uCentral images / build (sercomm_ap72tip) (push) Has been cancelled
Build OpenWrt/uCentral images / build (sonicfi_rap630c-311g) (push) Has been cancelled
Build OpenWrt/uCentral images / build (sonicfi_rap630w-211g) (push) Has been cancelled
Build OpenWrt/uCentral images / build (sonicfi_rap630w-311g) (push) Has been cancelled
Build OpenWrt/uCentral images / build (udaya_a6-id2) (push) Has been cancelled
Build OpenWrt/uCentral images / build (udaya_a6-od2) (push) Has been cancelled
Build OpenWrt/uCentral images / build (wallys_dr5018) (push) Has been cancelled
Build OpenWrt/uCentral images / build (wallys_dr6018) (push) Has been cancelled
Build OpenWrt/uCentral images / build (wallys_dr6018-v4) (push) Has been cancelled
Build OpenWrt/uCentral images / build (yuncore_ax820) (push) Has been cancelled
Build OpenWrt/uCentral images / build (yuncore_ax840) (push) Has been cancelled
Build OpenWrt/uCentral images / build (yuncore_fap640) (push) Has been cancelled
Build OpenWrt/uCentral images / build (yuncore_fap650) (push) Has been cancelled
Build OpenWrt/uCentral images / build (yuncore_fap655) (push) Has been cancelled
Build OpenWrt/uCentral images / trigger-testing (push) Has been cancelled
Build OpenWrt/uCentral images / create-x64_vm-ami (push) Has been cancelled
ipq95xx: import ath12.4-cs kernel and drivers
Signed-off-by: John Crispin <john@phrozen.org>
2024-10-20 09:25:13 +02:00

505 lines
16 KiB
Diff

From c3bd1ff2d9f67eb39c39b58bf3b3679d9a9a4894 Mon Sep 17 00:00:00 2001
From: Aditya Kumar Singh <quic_adisi@quicinc.com>
Date: Wed, 18 Oct 2023 14:57:14 +0530
Subject: [PATCH 3/4] hostapd: de-initialize/disable link BSS properly
Currently, if first link BSS of an interface is getting de-initialized/
disabled, then whole MLD is brought down. All other links are made
to stop beaconing and links are removed. And if, non-first link BSS
is de-initialized/disabled, nothing happens. Even beaconing is not
stopped which is wrong.
Fix the above by properly bringing down the intended link alone from the
interface. If only 1 link was there, then the interface will be removed.
And if first link BSS is removed, make the next link as the the new first
link of the BSS. Accordingly, cache the bss->ctx and drv->ctx as well.
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
---
hostapd/main.c | 1 +
src/ap/ap_drv_ops.c | 17 +++++
src/ap/ap_drv_ops.h | 2 +
src/ap/hostapd.c | 128 ++++++++++++++++++++++++-----------
src/drivers/driver.h | 27 ++++++++
src/drivers/driver_nl80211.c | 84 +++++++++++++++++++++++
src/drivers/driver_nl80211.h | 1 +
7 files changed, 219 insertions(+), 41 deletions(-)
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -181,6 +181,7 @@ static int hostapd_driver_init(struct ho
if (h_hapd) {
hapd->drv_priv = h_hapd->drv_priv;
+ hapd->interface_added = h_hapd->interface_added;
/*
* All interfaces participating in the AP MLD would have
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -535,12 +535,29 @@ int hostapd_if_add(struct hostapd_data *
}
+int hostapd_if_link_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
+ const char *ifname, u8 link_id)
+{
+ if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+ hapd->driver->if_link_remove == NULL)
+ return -1;
+
+ return hapd->driver->if_link_remove(hapd->drv_priv, type, ifname,
+ hapd->mld_link_id);
+}
+
int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname)
{
if (hapd->driver == NULL || hapd->drv_priv == NULL ||
hapd->driver->if_remove == NULL)
return -1;
+
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap)
+ return hostapd_if_link_remove(hapd, type, ifname, hapd->mld_link_id);
+#endif /* CONFIG_IEEE80211BE */
+
return hapd->driver->if_remove(hapd->drv_priv, type, ifname);
}
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -61,6 +61,8 @@ int hostapd_if_add(struct hostapd_data *
const char *bridge, int use_existing);
int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname);
+int hostapd_if_link_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
+ const char *ifname, u8 link_id);
int hostapd_set_ieee8021x(struct hostapd_data *hapd,
struct wpa_bss_params *params);
int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -472,30 +472,6 @@ static int hostapd_broadcast_wep_set(str
#endif /* CONFIG_WEP */
-
-static void hostapd_clear_drv_priv(struct hostapd_data *hapd)
-{
-#ifdef CONFIG_IEEE80211BE
- unsigned int i, j;
-
- for (i = 0; i < hapd->iface->interfaces->count && hapd->conf->mld_ap; i++) {
- struct hostapd_iface *iface = hapd->iface->interfaces->iface[i];
-
- if (!iface || hapd->iface == iface)
- continue;
-
- for (j = 0; j < iface->num_bss; j++) {
- if (iface->bss && iface->bss[j] &&
- hostapd_mld_get_first_bss(iface->bss[j]) == hapd)
- iface->bss[j]->drv_priv = NULL;
- }
- }
-#endif /* CONFIG_IEEE80211BE */
-
- hapd->drv_priv = NULL;
-}
-
-
void hostapd_free_hapd_data(struct hostapd_data *hapd)
{
os_free(hapd->probereq_cb);
@@ -559,10 +535,22 @@ void hostapd_free_hapd_data(struct hosta
* driver wrapper may have removed its internal instance
* and hapd->drv_priv is not valid anymore.
*/
- hostapd_clear_drv_priv(hapd);
+ hapd->drv_priv = NULL;
}
}
+#ifdef CONFIG_IEEE80211BE
+ /* If interface was not added as well as it is not the first bss, then
+ * at least link should be removed here since deinit will take care only
+ * for the first bss.
+ */
+ if (hapd->conf->mld_ap && !hapd->interface_added &&
+ hapd->iface->bss[0] != hapd) {
+ hostapd_if_link_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface,
+ hapd->mld_link_id);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
wpabuf_free(hapd->time_adv);
hapd->time_adv = NULL;
@@ -616,6 +604,39 @@ void hostapd_free_hapd_data(struct hosta
#endif /* CONFIG_IEEE80211AX */
}
+/* hostapd_bss_link_deinit - Per-BSS ML cleanup (deinitialization)
+ * @hapd: Pointer to BSS data
+ *
+ * This function is used to unlink the BSS from the MLD.
+ * If the BSS being removed is the first link, then the next link
+ * becomes the first BSS.
+ */
+static void hostapd_bss_link_deinit(struct hostapd_data *hapd)
+{
+#ifdef CONFIG_IEEE80211BE
+ if (!hapd->conf->mld_ap)
+ return;
+
+ /* if not started then not yet linked to the MLD. However, first BSS,
+ * is always linked since it is linked during driver_init(), hence
+ * need to remove it from MLD
+ */
+ if (!hapd->started && hapd->iface->bss[0] != hapd)
+ return;
+
+ /* first BSS can also be only linked when at least driver_init() is
+ * executd. But, if previous interface fails, then it will not, hence
+ * safe to skip
+ */
+ if (hapd->iface->bss[0] == hapd && !hapd->drv_priv)
+ return;
+
+ if (!hapd->mld->num_links)
+ return;
+
+ hostapd_mld_remove_link(hapd);
+#endif
+}
/**
* hostapd_cleanup - Per-BSS cleanup (deinitialization)
@@ -1361,6 +1382,7 @@ static int hostapd_setup_bss(struct host
if (h_hapd) {
hapd->drv_priv = h_hapd->drv_priv;
+ hapd->interface_added = h_hapd->interface_added;
hostapd_mld_add_link(hapd);
wpa_printf(MSG_DEBUG, "TSetup of non first link BSS(link id %d) of MLD %s",
hapd->mld_link_id, hapd->conf->iface);
@@ -1783,6 +1805,7 @@ static int start_ctrl_iface(struct hosta
static void hostapd_no_ir_cleanup(struct hostapd_data *bss)
{
hostapd_bss_deinit_no_free(bss);
+ hostapd_bss_link_deinit(bss);
hostapd_free_hapd_data(bss);
hostapd_cleanup_iface_partial(bss->iface);
}
@@ -2518,6 +2541,7 @@ static int hostapd_setup_interface_compl
for (;;) {
hapd = iface->bss[j];
hostapd_bss_deinit_no_free(hapd);
+ hostapd_bss_link_deinit(hapd);
hostapd_free_hapd_data(hapd);
if (j == 0)
break;
@@ -2536,6 +2560,7 @@ static int hostapd_setup_interface_compl
for (;;) {
hapd = iface->bss[j];
hostapd_bss_deinit_no_free(hapd);
+ hostapd_bss_link_deinit(hapd);
hostapd_free_hapd_data(hapd);
if (j == 0)
break;
@@ -2847,10 +2872,8 @@ static void hostapd_bss_deinit(struct ho
hapd->rad_attr_db = NULL;
}
#endif /* CONFIG_SQLITE */
-#ifdef CONFIG_IEEE80211BE
- if (hapd->conf->mld_ap)
- hostapd_mld_remove_link(hapd);
-#endif
+
+ hostapd_bss_link_deinit(hapd);
hostapd_cleanup(hapd);
}
@@ -3193,6 +3216,40 @@ hostapd_interface_init_bss(struct hapd_i
return iface;
}
+static void hostapd_cleanup_driver(const struct wpa_driver_ops *driver,
+ void *drv_priv,
+ struct hostapd_iface *iface)
+{
+ bool ap_mld = false;
+
+ if (!driver || !driver->hapd_deinit || !drv_priv)
+ return;
+
+#ifdef CONFIG_IEEE80211BE
+ ap_mld = !!iface->bss[0]->conf->mld_ap;
+#endif /* CONFIG_IEEE80211BE */
+
+ /* In case of non-ML operation, de-init. But, if ML operation exist, then
+ * even if thats the last BSS in the interface, the driver (drv) could
+ * be in use for a different MLD. Hence, need to check if drv is still
+ * being used by some other bss before de-initiallizing
+ */
+ if (!ap_mld)
+ driver->hapd_deinit(drv_priv);
+ else if (hostapd_mld_is_first_bss(iface->bss[0]) &&
+ driver->get_drv_shared_status &&
+ !driver->get_drv_shared_status(drv_priv, iface->bss[0])) {
+ driver->hapd_deinit(drv_priv);
+ } else if (hostapd_if_link_remove(iface->bss[0],
+ WPA_IF_AP_BSS,
+ iface->bss[0]->conf->iface,
+ iface->bss[0]->mld_link_id)) {
+ wpa_printf(MSG_WARNING, "Failed to remove BSS interface %s",
+ iface->bss[0]->conf->iface);
+ }
+
+ iface->bss[0]->drv_priv = NULL;
+}
void hostapd_interface_deinit_free(struct hostapd_iface *iface)
{
@@ -3211,13 +3268,7 @@ void hostapd_interface_deinit_free(struc
hostapd_interface_deinit(iface);
wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
__func__, driver, drv_priv);
- if (driver && driver->hapd_deinit && drv_priv) {
-#ifdef CONFIG_IEEE80211BE
- if (hostapd_mld_is_first_bss(iface->bss[0]))
-#endif /* CONFIG_IEEE80211BE */
- driver->hapd_deinit(drv_priv);
- hostapd_clear_drv_priv(iface->bss[0]);
- }
+ hostapd_cleanup_driver(driver, drv_priv, iface);
hostapd_interface_free(iface);
}
@@ -3256,21 +3307,22 @@ static void hostapd_deinit_driver(const
wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
__func__, driver, drv_priv);
+
+ hostapd_cleanup_driver(driver, drv_priv, hapd_iface);
+
if (driver && driver->hapd_deinit && drv_priv) {
-#ifdef CONFIG_IEEE80211BE
- if (hostapd_mld_is_first_bss(iface->bss[0]))
-#endif /* CONFIG_IEEE80211BE */
- driver->hapd_deinit(drv_priv);
for (j = 0; j < hapd_iface->num_bss; j++) {
wpa_printf(MSG_DEBUG, "%s:bss[%d]->drv_priv=%p",
__func__, (int) j,
hapd_iface->bss[j]->drv_priv);
- if (hapd_iface->bss[j]->drv_priv == drv_priv) {
- hostapd_clear_drv_priv(hapd_iface->bss[j]);
- hapd_iface->extended_capa = NULL;
- hapd_iface->extended_capa_mask = NULL;
- hapd_iface->extended_capa_len = 0;
- }
+
+ if (hapd_iface->bss[j]->drv_priv != drv_priv)
+ continue;
+
+ hapd_iface->bss[j]->drv_priv = NULL;
+ hapd_iface->extended_capa = NULL;
+ hapd_iface->extended_capa_mask = NULL;
+ hapd_iface->extended_capa_len = 0;
}
}
}
@@ -3389,6 +3441,7 @@ int hostapd_disable_iface(struct hostapd
for (j = 0; j < hapd_iface->num_bss; j++) {
struct hostapd_data *hapd = hapd_iface->bss[j];
hostapd_bss_deinit_no_free(hapd);
+ hostapd_bss_link_deinit(hapd);
hostapd_free_hapd_data(hapd);
}
@@ -3587,6 +3640,7 @@ int hostapd_add_iface(struct hapd_interf
if (start_ctrl_iface_bss(hapd) < 0 ||
(hapd_iface->state == HAPD_IFACE_ENABLED &&
hostapd_setup_bss(hapd, -1, true))) {
+ hostapd_bss_link_deinit(hapd);
hostapd_cleanup(hapd);
hapd_iface->bss[hapd_iface->num_bss - 1] = NULL;
hapd_iface->conf->num_bss--;
@@ -3684,6 +3738,7 @@ fail:
wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)",
__func__, hapd_iface->bss[i],
hapd->conf->iface);
+ hostapd_bss_link_deinit(hapd);
hostapd_cleanup(hapd);
os_free(hapd);
hapd_iface->bss[i] = NULL;
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -5184,6 +5184,33 @@ struct wpa_driver_ops {
const u8 *match, size_t match_len,
bool multicast);
#endif /* CONFIG_TESTING_OPTIONS */
+
+#ifdef CONFIG_IEEE80211BE
+ /**
+ * if_link_remove - Remove a link alone from virtual interface
+ * @priv: Private driver interface data
+ * @type: Interface type
+ * @ifname: Interface name of the virtual interface from where link is
+ * to be removed
+ * @link_id: Valid link ID to remove
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*if_link_remove)(void *priv, enum wpa_driver_if_type type,
+ const char *ifname, int link_id);
+
+ /**
+ * get_drv_shared_status - Get shared status of driver interface
+ * @priv: private driver interface data from init()
+ * @bss_ctx: BSS context for %WPA_IF_AP_BSS interfaces
+ *
+ * Checks whether driver interface is being used by other partner BSS(s)
+ * or not. This is used to decide whether driver interface needs to be
+ * deinitilized when one iface is getting deinitialized.
+ *
+ * Returns: True if it is being used or else False.
+ */
+ bool (*get_drv_shared_status)(void *priv, void *bss_ctx);
+#endif /* CONFIG_IEEE80211BE */
};
/**
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -4121,6 +4121,19 @@ int wpa_driver_nl80211_authenticate_retr
return wpa_driver_nl80211_authenticate(bss, &params);
}
+int nl80211_valid_link(struct i802_bss *bss, s8 link_id)
+{
+ unsigned int i;
+
+ for (i = 0; i < bss->n_links; i++) {
+ if (bss->links[i].link_id != link_id)
+ continue;
+
+ return 1;
+ }
+
+ return 0;
+}
struct i802_link * nl80211_get_link(struct i802_bss *bss, s8 link_id)
{
@@ -8958,6 +8971,37 @@ static int wpa_driver_nl80211_if_remove(
return 0;
}
+static int wpa_driver_nl80211_if_link_remove(struct i802_bss *bss,
+ enum wpa_driver_if_type type,
+ const char *ifname,
+ int link_id)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct i802_link *link;
+ int num_links = bss->n_links;
+
+ wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s num_links=%d) link_id=%d",
+ __func__, type, ifname, num_links, link_id);
+
+ link = nl80211_get_link(bss, link_id);
+
+ wpa_printf(MSG_DEBUG, "nl80211: Teardown AP(%s) link %d", bss->ifname,
+ link_id);
+ wpa_driver_nl80211_del_beacon(bss, link);
+ nl80211_remove_link(bss, link_id);
+
+ bss->ctx = bss->links[0].ctx;
+
+ if (drv->first_bss == bss && num_links > 1)
+ drv->ctx = bss->ctx;
+
+ if (num_links == 1) {
+ wpa_printf(MSG_DEBUG, "nl80211: Only 1 link was there hence remove interface");
+ return wpa_driver_nl80211_if_remove(bss, type, ifname);
+ }
+
+ return 0;
+}
static int cookie_handler(struct nl_msg *msg, void *arg)
{
@@ -10602,6 +10646,22 @@ static int driver_nl80211_if_remove(void
return wpa_driver_nl80211_if_remove(bss, type, ifname);
}
+static int driver_nl80211_if_link_remove(void *priv, enum wpa_driver_if_type type,
+ const char *ifname, int link_id)
+{
+ struct i802_bss *bss = priv;
+
+ if (link_id < 0 || link_id >= MAX_NUM_MLD_LINKS)
+ return -1;
+
+ if (type != WPA_IF_AP_BSS)
+ return -1;
+
+ if (!nl80211_valid_link(bss, link_id))
+ return -1;
+
+ return wpa_driver_nl80211_if_link_remove(bss, type, ifname, link_id);
+}
static int driver_nl80211_send_mlme(void *priv, const u8 *data,
size_t data_len, int noack,
@@ -13794,6 +13854,29 @@ fail:
return ret;
}
+static bool wpa_driver_get_shared_status(void *priv, void *bss_ctx)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int num_bss = 0;
+
+ /* more than one links means some one is still using */
+ if (bss->n_links > 1)
+ return true;
+
+ /* If any other bss exist, means someone else is using since at this
+ * time, we would have removed all bss created by this driver and only
+ * this bss should be remaining if driver is not shared by anyone
+ */
+ for (bss = drv->first_bss; bss; bss = bss->next)
+ num_bss++;
+
+ if (num_bss > 1)
+ return true;
+
+ return false;
+}
+
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
@@ -13948,4 +14031,8 @@ const struct wpa_driver_ops wpa_driver_n
.radio_disable = testing_nl80211_radio_disable,
#endif /* CONFIG_TESTING_OPTIONS */
.set_6gclient_type = nl80211_set_6gclient_type,
+#ifdef CONFIG_IEEE80211BE
+ .if_link_remove = driver_nl80211_if_link_remove,
+ .get_drv_shared_status = wpa_driver_get_shared_status,
+#endif /* CONFIG_IEEE80211BE */
};
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -326,6 +326,7 @@ const char * nl80211_iftype_str(enum nl8
void nl80211_restore_ap_mode(struct i802_bss *bss);
struct i802_link * nl80211_get_link(struct i802_bss *bss, s8 link_id);
+int nl80211_valid_link(struct i802_bss *bss, s8 link_id);
#ifdef ANDROID
int android_nl_socket_set_nonblocking(struct nl_sock *handle);