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:
parent
e51f1109b0
commit
2f0e5303e8
3 changed files with 222 additions and 0 deletions
|
@ -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 */
|
||||
|
|
161
src/ap/hostapd.c
161
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 */
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue