diff mbox series

[03/16] hostapd: MLO: add separate MLD level structure

Message ID 20240306173947.2611965-4-quic_adisi@quicinc.com
State Accepted
Headers show
Series hostapd: scale up MLO flows | expand

Commit Message

Aditya Kumar Singh March 6, 2024, 5:39 p.m. UTC
Currently, MLD level info like, MLD address, next link ID, etc are stored
in each BSS. However, only first link BSS assign values to these members
and rest other stores reference to the first BSS. However, if first BSS
is disabled, then 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 these ML related information. All affiliated link BSS can keep
reference to this MLD structure.

This change adds that MLD level structure. However, assigning values to it
and using that instead of BSS level members would be done in subsequent
changes.

Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
---
 hostapd/main.c   |  26 ++++++++
 src/ap/hostapd.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++
 src/ap/hostapd.h |  28 ++++++++
 3 files changed, 220 insertions(+)
diff mbox series

Patch

diff --git a/hostapd/main.c b/hostapd/main.c
index a7610b8a54f5..2c0f44719300 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -737,6 +737,28 @@  static int gen_uuid(const char *txt_addr)
 #define HOSTAPD_CLEANUP_INTERVAL 10
 #endif /* HOSTAPD_CLEANUP_INTERVAL */
 
+#ifdef CONFIG_IEEE80211BE
+static void hostapd_global_cleanup_mld(struct hapd_interfaces *interfaces)
+{
+	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 */
+
 static int hostapd_periodic_call(struct hostapd_iface *iface, void *ctx)
 {
 	hostapd_periodic_iface(iface);
@@ -1035,6 +1057,10 @@  int main(int argc, char *argv[])
 	interfaces.iface = NULL;
 	interfaces.count = 0;
 
+#ifdef CONFIG_IEEE80211BE
+	hostapd_global_cleanup_mld(&interfaces);
+#endif /* CONFIG_IEEE80211BE */
+
 #ifdef CONFIG_DPP
 	dpp_global_deinit(interfaces.dpp);
 #endif /* CONFIG_DPP */
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index adb5b001a784..f75edaf71692 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -2865,6 +2865,69 @@  struct hostapd_iface * hostapd_alloc_iface(void)
 	return hapd_iface;
 }
 
+#ifdef CONFIG_IEEE80211BE
+static void hostapd_bss_setup_multi_link(struct hostapd_data *hapd,
+					 struct hapd_interfaces *interfaces)
+{
+	struct hostapd_mld *mld, **all_mld;
+	struct hostapd_bss_config *conf;
+	size_t i;
+
+	if (!hapd || !interfaces)
+		return;
+
+	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));
+	mld->next_link_id = 0;
+	mld->num_links = 0;
+	mld->fbss = NULL;
+	dl_list_init(&mld->links);
+
+	wpa_printf(MSG_DEBUG, "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, "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
@@ -2909,6 +2972,9 @@  struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
 		if (hapd == NULL)
 			goto fail;
 		hapd->msg_ctx = hapd;
+#ifdef CONFIG_IEEE80211BE
+		hostapd_bss_setup_multi_link(hapd, interfaces);
+#endif /* CONFIG_IEEE80211BE */
 	}
 
 	return hapd_iface;
@@ -3030,6 +3096,10 @@  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;
+#ifdef CONFIG_IEEE80211BE
+		hostapd_bss_setup_multi_link(hapd, interfaces);
+#endif /* CONFIG_IEEE80211BE */
+
 
 		bss_idx = iface->num_bss++;
 		conf->num_bss--;
@@ -3371,6 +3441,9 @@  static int hostapd_data_alloc(struct hostapd_iface *hapd_iface,
 			return -1;
 		}
 		hapd->msg_ctx = hapd;
+#ifdef CONFIG_IEEE80211BE
+		hostapd_bss_setup_multi_link(hapd, hapd_iface->interfaces);
+#endif /* CONFIG_IEEE80211BE */
 	}
 
 	hapd_iface->conf = conf;
@@ -4442,4 +4515,97 @@  u8 hostapd_get_mld_id(struct hostapd_data *hapd)
 
 	/* TODO MLD ID for MBSS 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, "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, "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, "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 len is 0, all links are removed */
+	if (!dl_list_len(&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, "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 1;
+
+	/* should not happen */
+	if (!mld)
+		return 0;
+
+	/* if fbss is not set, safe to assume the caller is the first BSS */
+	if (!mld->fbss)
+		return 1;
+
+	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 4c84fb8f56d9..9aa0651c876f 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -44,6 +44,9 @@  struct mesh_conf;
 #endif /* CONFIG_CTRL_IFACE_UDP */
 
 struct hostapd_iface;
+#ifdef CONFIG_IEEE80211BE
+struct hostapd_mld;
+#endif /* CONFIG_IEEE80211BE */
 
 struct hapd_interfaces {
 	int (*reload_config)(struct hostapd_iface *iface);
@@ -93,6 +96,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 +479,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 +502,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
  */
@@ -786,6 +810,10 @@  int hostapd_link_remove(struct hostapd_data *hapd, u32 count);
 u8 hostapd_get_mld_id(struct hostapd_data *hapd);
 bool hostapd_is_ml_partner(struct hostapd_data *hapd1,
 			   struct hostapd_data *hapd2);
+int hostapd_mld_add_link(struct hostapd_data *hapd);
+int hostapd_mld_remove_link(struct hostapd_data *hapd);
+bool hostapd_mld_is_first_bss(struct hostapd_data *hapd);
+struct hostapd_data *hostapd_mld_get_first_bss(struct hostapd_data *hapd);
 
 #define for_each_mld_link(_link, _bss_idx, _iface_idx, _ifaces, _mld_id) \
 	for (_iface_idx = 0;						\