From 2f0e5303e8bbda01e13ba9f5f4e6a7f4dcc1e50f Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Wed, 6 Mar 2024 12:07:13 +0530 Subject: [PATCH] AP MLD: Add a separate MLD level structure MLD level information like MLD MAC address, next link ID, etc. was stored in each BSS. However, only the first link BSS assigns values to these members and the other link BSSs store references to the first BSS. However, if the first BSS is disabled, the first BSS reference in all BSS should be updated which is an overhead. Also, this does not seem to scale. Instead, a separate MLD level structure can be maintained which can store all this ML related information. All affiliated link BSSs can keep reference to this MLD structure. This commit adds that MLD level structure. However, assigning values to it and using that instead of BSS level members will be done in subsequent commits. Signed-off-by: Aditya Kumar Singh --- hostapd/main.c | 25 ++++++++ src/ap/hostapd.c | 161 +++++++++++++++++++++++++++++++++++++++++++++++ src/ap/hostapd.h | 36 +++++++++++ 3 files changed, 222 insertions(+) diff --git a/hostapd/main.c b/hostapd/main.c index ec3d112fc..602c3c082 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -755,6 +755,29 @@ static void hostapd_periodic(void *eloop_ctx, void *timeout_ctx) } +static void hostapd_global_cleanup_mld(struct hapd_interfaces *interfaces) +{ +#ifdef CONFIG_IEEE80211BE + size_t i; + + if (!interfaces || !interfaces->mld) + return; + + for (i = 0; i < interfaces->mld_count; i++) { + if (!interfaces->mld[i]) + continue; + + os_free(interfaces->mld[i]); + interfaces->mld[i] = NULL; + } + + os_free(interfaces->mld); + interfaces->mld = NULL; + interfaces->mld_count = 0; +#endif /* CONFIG_IEEE80211BE */ +} + + int main(int argc, char *argv[]) { struct hapd_interfaces interfaces; @@ -1035,6 +1058,8 @@ int main(int argc, char *argv[]) interfaces.iface = NULL; interfaces.count = 0; + hostapd_global_cleanup_mld(&interfaces); + #ifdef CONFIG_DPP dpp_global_deinit(interfaces.dpp); #endif /* CONFIG_DPP */ diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index aaabd4644..bf3335a6a 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -2866,6 +2866,65 @@ struct hostapd_iface * hostapd_alloc_iface(void) } +static void hostapd_bss_setup_multi_link(struct hostapd_data *hapd, + struct hapd_interfaces *interfaces) +{ +#ifdef CONFIG_IEEE80211BE + struct hostapd_mld *mld, **all_mld; + struct hostapd_bss_config *conf; + size_t i; + + conf = hapd->conf; + + if (!hapd->iconf || !hapd->iconf->ieee80211be || !conf->mld_ap || + conf->disable_11be) + return; + + for (i = 0; i < interfaces->mld_count; i++) { + mld = interfaces->mld[i]; + + if (!mld || os_strcmp(conf->iface, mld->name) != 0) + continue; + + hapd->mld = mld; + break; + } + + if (hapd->mld) + return; + + mld = os_zalloc(sizeof(struct hostapd_mld)); + if (!mld) + goto fail; + + os_strlcpy(mld->name, conf->iface, sizeof(conf->iface)); + dl_list_init(&mld->links); + + wpa_printf(MSG_DEBUG, "AP MLD %s created", mld->name); + + hapd->mld = mld; + + all_mld = os_realloc_array(interfaces->mld, interfaces->mld_count + 1, + sizeof(struct hostapd_mld *)); + if (!all_mld) + goto fail; + + interfaces->mld = all_mld; + interfaces->mld[interfaces->mld_count] = mld; + interfaces->mld_count++; + + return; +fail: + if (!mld) + return; + + wpa_printf(MSG_DEBUG, "AP MLD %s: free mld %p", mld->name, mld); + os_free(mld); + hapd->mld = NULL; +#endif /* CONFIG_IEEE80211BE */ +} + + /** * hostapd_init - Allocate and initialize per-interface data * @config_file: Path to the configuration file @@ -2909,6 +2968,7 @@ struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces, if (hapd == NULL) goto fail; hapd->msg_ctx = hapd; + hostapd_bss_setup_multi_link(hapd, interfaces); } return hapd_iface; @@ -3030,6 +3090,8 @@ hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy, iface->conf->last_bss = bss; iface->bss[iface->num_bss] = hapd; hapd->msg_ctx = hapd; + hostapd_bss_setup_multi_link(hapd, interfaces); + bss_idx = iface->num_bss++; conf->num_bss--; @@ -3370,6 +3432,7 @@ static int hostapd_data_alloc(struct hostapd_iface *hapd_iface, return -1; } hapd->msg_ctx = hapd; + hostapd_bss_setup_multi_link(hapd, hapd_iface->interfaces); } hapd_iface->conf = conf; @@ -4446,6 +4509,104 @@ u8 hostapd_get_mld_id(struct hostapd_data *hapd) /* TODO: MLD ID for Multiple BSS cases */ } + +int hostapd_mld_add_link(struct hostapd_data *hapd) +{ + struct hostapd_mld *mld = hapd->mld; + + if (!hapd->conf->mld_ap) + return 0; + + /* Should not happen */ + if (!mld) + return -1; + + dl_list_add_tail(&mld->links, &hapd->link); + mld->num_links++; + + wpa_printf(MSG_DEBUG, "AP MLD %s: Link ID %d added. num_links: %d", + mld->name, hapd->mld_link_id, mld->num_links); + + if (mld->fbss) + return 0; + + mld->fbss = hapd; + wpa_printf(MSG_DEBUG, "AP MLD %s: First link BSS set to %p", + mld->name, mld->fbss); + return 0; +} + + +int hostapd_mld_remove_link(struct hostapd_data *hapd) +{ + struct hostapd_mld *mld = hapd->mld; + struct hostapd_data *next_fbss; + + if (!hapd->conf->mld_ap) + return 0; + + /* Should not happen */ + if (!mld) + return -1; + + dl_list_del(&hapd->link); + mld->num_links--; + + wpa_printf(MSG_DEBUG, "AP MLD %s: Link ID %d removed. num_links: %d", + mld->name, hapd->mld_link_id, mld->num_links); + + if (mld->fbss != hapd) + return 0; + + /* If the list is empty, all links are removed */ + if (dl_list_empty(&mld->links)) { + mld->fbss = NULL; + } else { + next_fbss = dl_list_entry(mld->links.next, struct hostapd_data, + link); + mld->fbss = next_fbss; + } + + wpa_printf(MSG_DEBUG, "AP MLD %s: First link BSS set to %p", + mld->name, mld->fbss); + return 0; +} + + +bool hostapd_mld_is_first_bss(struct hostapd_data *hapd) +{ + struct hostapd_mld *mld = hapd->mld; + + if (!hapd->conf->mld_ap) + return true; + + /* Should not happen */ + if (!mld) + return false; + + /* If fbss is not set, it is safe to assume the caller is the first BSS. + */ + if (!mld->fbss) + return true; + + return hapd == mld->fbss; +} + + +struct hostapd_data * hostapd_mld_get_first_bss(struct hostapd_data *hapd) +{ + struct hostapd_mld *mld = hapd->mld; + + if (!hapd->conf->mld_ap) + return NULL; + + /* Should not happen */ + if (!mld) + return NULL; + + return mld->fbss; +} + #endif /* CONFIG_IEEE80211BE */ diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index b3249a0b0..a5f1e5df2 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -44,6 +44,7 @@ struct mesh_conf; #endif /* CONFIG_CTRL_IFACE_UDP */ struct hostapd_iface; +struct hostapd_mld; struct hapd_interfaces { int (*reload_config)(struct hostapd_iface *iface); @@ -93,6 +94,10 @@ struct hapd_interfaces { unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN]; #endif /* CONFIG_CTRL_IFACE_UDP */ +#ifdef CONFIG_IEEE80211BE + struct hostapd_mld **mld; + size_t mld_count; +#endif /* CONFIG_IEEE80211BE */ }; enum hostapd_chan_status { @@ -472,6 +477,8 @@ struct hostapd_data { #ifdef CONFIG_IEEE80211BE u8 eht_mld_bss_param_change; + struct hostapd_mld *mld; + struct dl_list link; #ifdef CONFIG_TESTING_OPTIONS u8 eht_mld_link_removal_count; #endif /* CONFIG_TESTING_OPTIONS */ @@ -493,6 +500,21 @@ struct hostapd_sta_info { #endif /* CONFIG_TAXONOMY */ }; +#ifdef CONFIG_IEEE80211BE +/** + * struct hostapd_mld - hostapd per-mld data structure + */ +struct hostapd_mld { + char name[IFNAMSIZ + 1]; + u8 mld_addr[ETH_ALEN]; + u8 next_link_id; + u8 num_links; + + struct hostapd_data *fbss; + struct dl_list links; /* List head of all affiliated links */ +}; +#endif /* CONFIG_IEEE80211BE */ + /** * struct hostapd_iface - hostapd per-interface data structure */ @@ -784,8 +806,14 @@ int hostapd_link_remove(struct hostapd_data *hapd, u32 count); bool hostapd_is_ml_partner(struct hostapd_data *hapd1, struct hostapd_data *hapd2); u8 hostapd_get_mld_id(struct hostapd_data *hapd); +int hostapd_mld_add_link(struct hostapd_data *hapd); +int hostapd_mld_remove_link(struct hostapd_data *hapd); +struct hostapd_data * hostapd_mld_get_first_bss(struct hostapd_data *hapd); #ifdef CONFIG_IEEE80211BE + +bool hostapd_mld_is_first_bss(struct hostapd_data *hapd); + #define for_each_mld_link(_link, _bss_idx, _iface_idx, _ifaces, _mld_id) \ for (_iface_idx = 0; \ _iface_idx < (_ifaces)->count; \ @@ -799,9 +827,17 @@ u8 hostapd_get_mld_id(struct hostapd_data *hapd); _link && _link->conf->mld_ap && \ hostapd_get_mld_id(_link) == _mld_id; \ _link = NULL) + #else /* CONFIG_IEEE80211BE */ + +static inline bool hostapd_mld_is_first_bss(struct hostapd_data *hapd) +{ + return true; +} + #define for_each_mld_link(_link, _bss_idx, _iface_idx, _ifaces, _mld_id) \ if (false) + #endif /* CONFIG_IEEE80211BE */ u16 hostapd_get_punct_bitmap(struct hostapd_data *hapd);