Currently, whenever ap_free_sta() is called, it deletes the whole station entry from kernel as well. However, with MLD station, there is a requirement to delete only the link station. Add support to remove link station alone from a MLD station. If the link going to be removed is the assoc link, then whole station entry will be removed. Signed-off-by: Aditya Kumar Singh <quic_adisi@xxxxxxxxxxx> --- src/ap/ap_drv_ops.c | 4 ++-- src/ap/ap_drv_ops.h | 14 ++++++++++++++ src/ap/hostapd.c | 1 + src/ap/sta_info.c | 33 ++++++++++++++++++++++++++++++++- src/ap/sta_info.h | 4 ++++ src/drivers/driver.h | 9 +++++++++ src/drivers/driver_nl80211.c | 29 +++++++++++++++++++++++++++++ 7 files changed, 91 insertions(+), 3 deletions(-) diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index 5dfcdac3a137..587d42ee82f7 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -265,8 +265,8 @@ int hostapd_set_ap_wps_ie(struct hostapd_data *hapd) } -static bool hostapd_sta_is_link_sta(struct hostapd_data *hapd, - struct sta_info *sta) +bool hostapd_sta_is_link_sta(struct hostapd_data *hapd, + struct sta_info *sta) { #ifdef CONFIG_IEEE80211BE if (ap_sta_is_mld(hapd, sta) && diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index 9c74ef579b2f..b321f9847463 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -459,8 +459,22 @@ static inline int hostapd_drv_link_add(struct hostapd_data *hapd, } +static inline int hostapd_drv_link_sta_remove(struct hostapd_data *hapd, + const u8 *addr) +{ + if (!hapd->conf->mld_ap || !hapd->driver || !hapd->drv_priv || + !hapd->driver->link_sta_remove) + return -1; + + return hapd->driver->link_sta_remove(hapd->drv_priv, + hapd->mld_link_id, addr); +} + int hostapd_if_link_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type, const char *ifname, u8 link_id); #endif /* CONFIG_IEEE80211BE */ +bool hostapd_sta_is_link_sta(struct hostapd_data *hapd, + struct sta_info *sta); + #endif /* AP_DRV_OPS */ diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 9dd9e6c3fd8d..863547c0de33 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -422,6 +422,7 @@ static void hostapd_link_remove_timeout_handler(void *eloop_data, ieee802_11_set_beacon(hapd); if (!hapd->eht_mld_link_removal_count) { + hostapd_free_link_stas(hapd); hostapd_disable_iface(hapd->iface); return; } diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index 97ed805ca5c2..22d17c53bce3 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -187,6 +187,17 @@ void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta) #endif /* CONFIG_PASN */ +static void __ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) +{ +#ifdef CONFIG_IEEE80211BE + if (hostapd_sta_is_link_sta(hapd, sta)) + if (!hostapd_drv_link_sta_remove(hapd, sta->addr)) + return; +#endif /* CONFIG_IEEE80211BE */ + + hostapd_drv_sta_remove(hapd, sta->addr); +} + void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) { int set_beacon = 0; @@ -209,7 +220,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) if (!hapd->iface->driver_ap_teardown && !(sta->flags & WLAN_STA_PREAUTH)) { - hostapd_drv_sta_remove(hapd, sta->addr); + __ap_free_sta(hapd, sta); sta->added_unassoc = 0; } @@ -453,6 +464,26 @@ void hostapd_free_stas(struct hostapd_data *hapd) } } +#ifdef CONFIG_IEEE80211BE +void hostapd_free_link_stas(struct hostapd_data *hapd) +{ + struct sta_info *sta, *prev; + + sta = hapd->sta_list; + + while (sta) { + prev = sta; + sta = sta->next; + + if (!hostapd_sta_is_link_sta(hapd, prev)) + continue; + + wpa_printf(MSG_DEBUG, "Removing link station from MLD " MACSTR, + MAC2STR(prev->addr)); + ap_free_sta(hapd, prev); + } +} +#endif /* CONFIG_IEEE80211BE */ /** * ap_handle_timer - Per STA timer handler diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index b136ff7bfab8..546e42973a44 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -440,4 +440,8 @@ static inline void ap_sta_set_mld(struct sta_info *sta, bool mld) void ap_sta_free_sta_profile(struct mld_info *info); +#ifdef CONFIG_IEEE80211BE +void hostapd_free_link_stas(struct hostapd_data *hapd); +#endif /* CONFIG_IEEE80211BE */ + #endif /* STA_INFO_H */ diff --git a/src/drivers/driver.h b/src/drivers/driver.h index d50cbcdb26d1..e45fac77e187 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -5167,6 +5167,15 @@ struct wpa_driver_ops { * Returns: True if it is being used or else False. */ bool (*get_drv_shared_status)(void *priv, void *bss_ctx); + + /** + * link_sta_remove - Remove a link STA from a MLD STA. + * @priv: Private driver interface data + * @link_id: The link ID which the link STA is using + * @addr: The MLD MAC address of the MLD STA + * Returns: 0 on success, negative value on failure + */ + int (*link_sta_remove)(void *priv, u8 link_id, const u8 *addr); #endif /* CONFIG_IEEE80211BE */ #ifdef CONFIG_TESTING_OPTIONS diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index a0616ce39192..0f83621eca35 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -13922,6 +13922,34 @@ static int nl80211_link_add(void *priv, u8 link_id, const u8 *addr, void *bss_ct return 0; } +#ifdef CONFIG_IEEE80211BE +static int wpa_driver_nl80211_link_sta_remove(void *priv, u8 link_id, + const u8 *addr) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + int ret; + + if (!(bss->valid_links & BIT(link_id))) + return -ENOLINK; + + if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_REMOVE_LINK_STA)) || + nla_put(msg, NL80211_ATTR_MLD_ADDR, ETH_ALEN, addr) || + nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) { + nlmsg_free(msg); + return -ENOBUFS; + } + + ret = send_and_recv_cmd(drv, msg); + wpa_printf(MSG_DEBUG, + "nl80211: link_sta_remove -> REMOVE_LINK_STA on link_id %u " + "from MLD STA " MACSTR ", from %s --> %d (%s)", + link_id, MAC2STR(addr), bss->ifname, ret, strerror(-ret)); + + return ret; +} +#endif /* CONFIG_IEEE80211BE */ #ifdef CONFIG_TESTING_OPTIONS @@ -14120,6 +14148,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { #ifdef CONFIG_IEEE80211BE .if_link_remove = driver_nl80211_if_link_remove, .get_drv_shared_status = wpa_driver_get_shared_status, + .link_sta_remove = wpa_driver_nl80211_link_sta_remove, #endif /* CONFIG_IEEE80211BE */ #ifdef CONFIG_TESTING_OPTIONS .register_frame = testing_nl80211_register_frame, -- 2.25.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap