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 <quic_adisi@quicinc.com>
This commit is contained in:
Aditya Kumar Singh 2024-03-06 12:07:13 +05:30 committed by Jouni Malinen
parent e51f1109b0
commit 2f0e5303e8
3 changed files with 222 additions and 0 deletions

View file

@ -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[]) int main(int argc, char *argv[])
{ {
struct hapd_interfaces interfaces; struct hapd_interfaces interfaces;
@ -1035,6 +1058,8 @@ int main(int argc, char *argv[])
interfaces.iface = NULL; interfaces.iface = NULL;
interfaces.count = 0; interfaces.count = 0;
hostapd_global_cleanup_mld(&interfaces);
#ifdef CONFIG_DPP #ifdef CONFIG_DPP
dpp_global_deinit(interfaces.dpp); dpp_global_deinit(interfaces.dpp);
#endif /* CONFIG_DPP */ #endif /* CONFIG_DPP */

View file

@ -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 * hostapd_init - Allocate and initialize per-interface data
* @config_file: Path to the configuration file * @config_file: Path to the configuration file
@ -2909,6 +2968,7 @@ struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
if (hapd == NULL) if (hapd == NULL)
goto fail; goto fail;
hapd->msg_ctx = hapd; hapd->msg_ctx = hapd;
hostapd_bss_setup_multi_link(hapd, interfaces);
} }
return hapd_iface; return hapd_iface;
@ -3030,6 +3090,8 @@ hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
iface->conf->last_bss = bss; iface->conf->last_bss = bss;
iface->bss[iface->num_bss] = hapd; iface->bss[iface->num_bss] = hapd;
hapd->msg_ctx = hapd; hapd->msg_ctx = hapd;
hostapd_bss_setup_multi_link(hapd, interfaces);
bss_idx = iface->num_bss++; bss_idx = iface->num_bss++;
conf->num_bss--; conf->num_bss--;
@ -3370,6 +3432,7 @@ static int hostapd_data_alloc(struct hostapd_iface *hapd_iface,
return -1; return -1;
} }
hapd->msg_ctx = hapd; hapd->msg_ctx = hapd;
hostapd_bss_setup_multi_link(hapd, hapd_iface->interfaces);
} }
hapd_iface->conf = conf; hapd_iface->conf = conf;
@ -4446,6 +4509,104 @@ u8 hostapd_get_mld_id(struct hostapd_data *hapd)
/* TODO: MLD ID for Multiple BSS cases */ /* 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 */ #endif /* CONFIG_IEEE80211BE */

View file

@ -44,6 +44,7 @@ struct mesh_conf;
#endif /* CONFIG_CTRL_IFACE_UDP */ #endif /* CONFIG_CTRL_IFACE_UDP */
struct hostapd_iface; struct hostapd_iface;
struct hostapd_mld;
struct hapd_interfaces { struct hapd_interfaces {
int (*reload_config)(struct hostapd_iface *iface); int (*reload_config)(struct hostapd_iface *iface);
@ -93,6 +94,10 @@ struct hapd_interfaces {
unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN]; unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
#endif /* CONFIG_CTRL_IFACE_UDP */ #endif /* CONFIG_CTRL_IFACE_UDP */
#ifdef CONFIG_IEEE80211BE
struct hostapd_mld **mld;
size_t mld_count;
#endif /* CONFIG_IEEE80211BE */
}; };
enum hostapd_chan_status { enum hostapd_chan_status {
@ -472,6 +477,8 @@ struct hostapd_data {
#ifdef CONFIG_IEEE80211BE #ifdef CONFIG_IEEE80211BE
u8 eht_mld_bss_param_change; u8 eht_mld_bss_param_change;
struct hostapd_mld *mld;
struct dl_list link;
#ifdef CONFIG_TESTING_OPTIONS #ifdef CONFIG_TESTING_OPTIONS
u8 eht_mld_link_removal_count; u8 eht_mld_link_removal_count;
#endif /* CONFIG_TESTING_OPTIONS */ #endif /* CONFIG_TESTING_OPTIONS */
@ -493,6 +500,21 @@ struct hostapd_sta_info {
#endif /* CONFIG_TAXONOMY */ #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 * 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, bool hostapd_is_ml_partner(struct hostapd_data *hapd1,
struct hostapd_data *hapd2); struct hostapd_data *hapd2);
u8 hostapd_get_mld_id(struct hostapd_data *hapd); 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 #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) \ #define for_each_mld_link(_link, _bss_idx, _iface_idx, _ifaces, _mld_id) \
for (_iface_idx = 0; \ for (_iface_idx = 0; \
_iface_idx < (_ifaces)->count; \ _iface_idx < (_ifaces)->count; \
@ -799,9 +827,17 @@ u8 hostapd_get_mld_id(struct hostapd_data *hapd);
_link && _link->conf->mld_ap && \ _link && _link->conf->mld_ap && \
hostapd_get_mld_id(_link) == _mld_id; \ hostapd_get_mld_id(_link) == _mld_id; \
_link = NULL) _link = NULL)
#else /* CONFIG_IEEE80211BE */ #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) \ #define for_each_mld_link(_link, _bss_idx, _iface_idx, _ifaces, _mld_id) \
if (false) if (false)
#endif /* CONFIG_IEEE80211BE */ #endif /* CONFIG_IEEE80211BE */
u16 hostapd_get_punct_bitmap(struct hostapd_data *hapd); u16 hostapd_get_punct_bitmap(struct hostapd_data *hapd);