From a42135dfd6e0292330c20aa5e6dd8477582bed9d Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Wed, 18 Oct 2023 14:34:07 +0530 Subject: [PATCH 1/4] hostapd: re-factor nl80211_remove_links() function Currently, nl80211_remove_links() iterates over all active links in the given BSS and remove all of them. However, at times it is required to remove only one link and not all links. Hence, add a helper function nl80211_remove_link() which will remove just the given link_id from the passed BSS. nl80211_remove_links() will use this and will call this for each of the active link to be removed. While at it, also make the NL remove link command to be formed per bss instead of per drv since the command is expected to be per interface and not per wiphy. Signed-off-by: Aditya Kumar Singh --- src/drivers/driver_nl80211.c | 108 +++++++++++++++++++++++------------ 1 file changed, 70 insertions(+), 38 deletions(-) --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -9338,57 +9338,90 @@ fail: return -1; } - -static void nl80211_remove_links(struct i802_bss *bss) +static int nl80211_remove_link(struct i802_bss *bss, int link_id) { struct wpa_driver_nl80211_data *drv = bss->drv; + struct i802_link *link = NULL; struct nl_msg *msg; - int ret; - u8 link_id; + int i, ret; + + wpa_printf(MSG_DEBUG, "nl80211: Remove link (ifindex=%d)", bss->ifindex); + wpa_printf(MSG_DEBUG, "nl80211: MLD: remove link_id=%u", link_id); + + for (i = 0; i < bss->n_links; i++) { + if (bss->links[i].link_id != link_id) + continue; + + link = &bss->links[i]; + break; + } - while (bss->links[0].link_id != NL80211_DRV_LINK_ID_NA) { - struct i802_link *link = &bss->links[0]; + if (!link) { + wpa_printf(MSG_DEBUG, "nl80211: MLD: remove link: Link not found"); + return -1; + } - wpa_printf(MSG_DEBUG, "nl80211: MLD: remove link_id=%u", - link->link_id); + /* Already removed */ + if (link->link_id == NL80211_DRV_LINK_ID_NA) { + wpa_printf(MSG_DEBUG, "nl80211: MLD: remove link_id=%u, already removed", link_id); + return 0; + } - wpa_driver_nl80211_del_beacon(bss, link); - - link_id = link->link_id; - - /* First remove the link locally */ - if (bss->n_links == 1) { - bss->flink->link_id = NL80211_DRV_LINK_ID_NA; - os_memcpy(bss->flink->addr, bss->addr, ETH_ALEN); - } else { - struct i802_link *other = &bss->links[bss->n_links - 1]; - - os_memcpy(link, other, sizeof(*link)); - other->link_id = NL80211_DRV_LINK_ID_NA; - os_memset(other->addr, 0, ETH_ALEN); - - bss->n_links--; - } - - /* Remove the link from the kernel */ - msg = nl80211_drv_msg(drv, 0, NL80211_CMD_REMOVE_LINK); - if (!msg || - nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) { - nlmsg_free(msg); - wpa_printf(MSG_ERROR, - "nl80211: remove link (%d) failed", - link_id); - return; - } - - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); - if (ret) { - wpa_printf(MSG_ERROR, - "nl80211: remove link (%d) failed. ret=%d (%s)", - link_id, ret, strerror(-ret)); - return; - } + /* First remove the link locally. In order to remove a link[i] from links[], + * shift left next all links[j] where j >= i + 1 to max size + */ + for (; i < bss->n_links - 1; i++) + os_memcpy(&bss->links[i], &bss->links[i + 1], sizeof(*link)); + + /* the last element can be memset back to initial values */ + os_memset(&bss->links[bss->n_links - 1], 0, sizeof(*link)); + bss->links[bss->n_links - 1].link_id = -1; + + bss->flink = &bss->links[0]; + + if (bss->n_links > 1) + bss->n_links--; + + /* Remove the link from the kernel */ + msg = nl80211_bss_msg(bss, 0, NL80211_CMD_REMOVE_LINK); + if (!msg || + nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) { + nlmsg_free(msg); + wpa_printf(MSG_ERROR, + "nl80211: remove link (%d) failed", + link_id); + return -1; } + + ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + if (ret) + wpa_printf(MSG_ERROR, + "nl80211: remove link (%d) failed. ret=%d (%s)", + link_id, ret, strerror(-ret)); + + return ret; +} + +static void nl80211_remove_links(struct i802_bss *bss) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + int ret, i; + + for (i = bss->n_links - 1; i >= 0; i--) { + if (bss->links[i].link_id == NL80211_DRV_LINK_ID_NA) + continue; + + ret = nl80211_remove_link(bss, bss->links[i].link_id); + if (ret) + break; + } + + if (bss->flink) + os_memcpy(bss->flink->addr, bss->addr, ETH_ALEN); + + if (i >= 0) + wpa_printf(MSG_DEBUG, "nl80211: failed to remove links, ret=%d", + ret); }