AP MLD: De-initialize/disable link BSS properly

When the first link BSS of an interface was de-initialized/disabled, the
whole MLD was brought down. All other links were stopped beaconing and
links were removed. And if the non-first link BSS was
de-initialized/disabled, nothing happened. Even beaconing was not
stopped which is wrong.

Fix this by properly bringing down the intended link alone from the
interface.

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
This commit is contained in:
Aditya Kumar Singh 2024-03-06 12:10:16 +05:30 committed by Jouni Malinen
parent 63982fd094
commit df34c2ced3
4 changed files with 96 additions and 30 deletions

View file

@ -397,27 +397,6 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
#endif /* CONFIG_WEP */
static void hostapd_clear_drv_priv(struct hostapd_data *hapd)
{
#ifdef CONFIG_IEEE80211BE
unsigned int i;
for (i = 0; i < hapd->iface->interfaces->count; i++) {
struct hostapd_iface *iface = hapd->iface->interfaces->iface[i];
if (hapd->iface == iface || !iface)
continue;
if (iface->bss && iface->bss[0] &&
hostapd_mld_get_first_bss(iface->bss[0]) == hapd)
iface->bss[0]->drv_priv = NULL;
}
#endif /* CONFIG_IEEE80211BE */
hapd->drv_priv = NULL;
}
#ifdef CONFIG_IEEE80211BE
#ifdef CONFIG_TESTING_OPTIONS
@ -554,10 +533,20 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd)
* 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 the interface was not added as well as it is not the first BSS,
* at least the link should be removed here since deinit will take care
* of only 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;
@ -3304,6 +3293,37 @@ hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
}
static void hostapd_cleanup_driver(const struct wpa_driver_ops *driver,
void *drv_priv, struct hostapd_iface *iface)
{
#ifdef CONFIG_IEEE80211BE
if (!driver || !driver->hapd_deinit || !drv_priv)
return;
/* In case of non-ML operation, de-init. But if ML operation exist,
* even if that's the last BSS in the interface, the driver (drv) could
* be in use for a different AP MLD. Hence, need to check if drv is
* still being used by some other BSS before de-initiallizing. */
if (!iface->bss[0]->conf->mld_ap) {
driver->hapd_deinit(drv_priv);
} else if (hostapd_mld_is_first_bss(iface->bss[0]) &&
driver->is_drv_shared &&
!driver->is_drv_shared(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);
}
#else /* CONFIG_IEEE80211BE */
driver->hapd_deinit(drv_priv);
#endif /* CONFIG_IEEE80211BE */
iface->bss[0]->drv_priv = NULL;
}
void hostapd_interface_deinit_free(struct hostapd_iface *iface)
{
const struct wpa_driver_ops *driver;
@ -3320,11 +3340,7 @@ void hostapd_interface_deinit_free(struct hostapd_iface *iface)
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) {
if (hostapd_mld_is_first_bss(iface->bss[0]))
driver->hapd_deinit(drv_priv);
hostapd_clear_drv_priv(iface->bss[0]);
}
hostapd_cleanup_driver(driver, drv_priv, iface);
hostapd_interface_free(iface);
}
@ -3337,15 +3353,16 @@ static void hostapd_deinit_driver(const struct wpa_driver_ops *driver,
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) {
if (hostapd_mld_is_first_bss(hapd_iface->bss[0]))
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->bss[j]->drv_priv = NULL;
hapd_iface->extended_capa = NULL;
hapd_iface->extended_capa_mask = NULL;
hapd_iface->extended_capa_len = 0;