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);