[PATCH 09/50] AP: Allow starting multiple interfaces within single MLD

Andrei Otcheretianski andrei.otcheretianski at intel.com
Wed Feb 15 15:08:23 PST 2023


Add support for including multiple hostapd interfaces in
the same AP MLD, i.e., all using the same underlying driver
network interface.

To do so, when a new hostapd interface is added, if there is
already another interface using the same underlying network
interface, associate the new interface with the same private
data object, instead of creating a new one.

As some of the BSS's are non first BSS's, meaning that they reuse
the drv_priv of the initial BSS, make sure not to double free it.

Currently multiple BSS entries are not supported so always use bss[0]
for MLD.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 hostapd/main.c      | 84 +++++++++++++++++++++++++++++++++++++++++++++
 src/ap/ap_drv_ops.h | 12 +++++++
 src/ap/hostapd.c    | 39 +++++++++++++++++----
 src/ap/hostapd.h    |  2 ++
 4 files changed, 131 insertions(+), 6 deletions(-)

diff --git a/hostapd/main.c b/hostapd/main.c
index ce2df81c4a..228ee44b1b 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -164,6 +164,59 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
 		return -1;
 	}
 
+#ifdef CONFIG_IEEE80211BE
+		if (conf->mld_ap) {
+			for (i = 0; i < iface->interfaces->count; i++) {
+				struct hostapd_iface *h = iface->interfaces->iface[i];
+				struct hostapd_data *h_hapd = h->bss[0];
+				struct hostapd_bss_config *hconf = h_hapd->conf;
+
+				if (h == iface) {
+					wpa_printf(MSG_ERROR, "Skip own iface");
+					continue;
+				}
+
+				if (!hconf->mld_ap || hconf->mld_id != conf->mld_id) {
+					wpa_printf(MSG_ERROR,
+						   "Skip non matching mld_id");
+					continue;
+				}
+
+				wpa_printf(MSG_DEBUG, "Found matching MLD iface");
+				if (!h_hapd->drv_priv) {
+					wpa_printf(MSG_ERROR,
+						   "Matching MLD BSS not initialized yet");
+					continue;
+				}
+
+				hapd->drv_priv = h_hapd->drv_priv;
+
+				/*
+				 * All interfaces participating in the MLD AP would have
+				 * the same MLD address, which in the interface HW
+				 * address,  while the interface address would be
+				 * derived from the original interface address if BSSID
+				 * is not configured, and otherwise it would be the
+				 * configured BSSID.
+				 */
+				os_memcpy(hapd->mld_addr, h_hapd->mld_addr, ETH_ALEN);
+				if (is_zero_ether_addr(b)) {
+					os_memcpy(hapd->own_addr, h_hapd->mld_addr, ETH_ALEN);
+					random_mac_addr_keep_oui(hapd->own_addr);
+				} else {
+					os_memcpy(hapd->own_addr, b, ETH_ALEN);
+				}
+
+				/*
+				 * mark the interface as a secondary interface, as this
+				 * is needed for the de-initialization flow
+				 */
+				hapd->mld_first_bss = h_hapd;
+				goto setup_mld;
+			}
+		}
+#endif /* CONFIG_IEEE80211BE */
+
 	/* Initialize the driver interface */
 	if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5]))
 		b = NULL;
@@ -214,6 +267,20 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
 		return -1;
 	}
 
+#ifdef CONFIG_IEEE80211BE
+		/*
+		 * This is the first interface added to the MLD AP, so have the
+		 * interface HW address be the MLD address and set a link address to
+		 * this interface
+		 */
+		if (hapd->conf->mld_ap) {
+			os_memcpy(hapd->mld_addr, hapd->own_addr, ETH_ALEN);
+			random_mac_addr_keep_oui(hapd->own_addr);
+		}
+
+	setup_mld:
+#endif /* CONFIG_IEEE80211BE */
+
 	if (hapd->driver->get_capa &&
 	    hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
 		struct wowlan_triggers *triggs;
@@ -246,6 +313,23 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
 		iface->ema_max_periodicity = capa.ema_max_periodicity;
 	}
 
+#ifdef CONFIG_IEEE80211BE
+	if (hapd->conf->mld_ap) {
+		if (!(iface->drv_flags2 & WPA_DRIVER_FLAGS2_MLO)) {
+			wpa_printf(MSG_DEBUG, "MLD: not supported by driver");
+			return -1;
+		}
+
+		wpa_printf(MSG_DEBUG,
+			   "MLD: Set link_id=%u, mld_addr=" MACSTR ", own_addr=" MACSTR,
+			   hapd->conf->mld_link_id,
+			   MAC2STR(hapd->mld_addr),
+			   MAC2STR(hapd->own_addr));
+
+		hostapd_drv_link_add(hapd, hapd->conf->mld_link_id,
+				     hapd->own_addr);
+	}
+#endif /* CONFIG_IEEE80211BE */
 	return 0;
 }
 
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 93b2244990..be280de218 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -435,4 +435,16 @@ hostapd_drv_register_frame(struct hostapd_data *hapd, u16 type,
 }
 #endif /* CONFIG_TESTING_OPTIONS */
 
+#ifdef CONFIG_IEEE80211BE
+static inline int hostapd_drv_link_add(struct hostapd_data *hapd,
+				       u8 link_id, const u8 *addr)
+{
+	if (!hapd->driver || !hapd->drv_priv || !hapd->driver->link_add)
+		return -1;
+
+	return hapd->driver->link_add(hapd->drv_priv, link_id, addr);
+
+}
+#endif /* CONFIG_IEEE80211BE */
+
 #endif /* AP_DRV_OPS */
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 58492e51ed..9abfb5fa5f 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -393,6 +393,25 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
 #endif /* CONFIG_WEP */
 
 
+static void hostapd_clear_drv_priv(struct hostapd_data *hapd)
+{
+	u8 i;
+
+	for (i = 0; i < hapd->iface->interfaces->count; i++) {
+		struct hostapd_iface *iface = hapd->iface->interfaces->iface[i];
+
+		if (hapd->iface == iface)
+			continue;
+
+		if (iface->bss && iface->bss[0] &&
+		    iface->bss[0]->mld_first_bss == hapd)
+			iface->bss[0]->drv_priv = NULL;
+	}
+
+	hapd->drv_priv = NULL;
+}
+
+
 void hostapd_free_hapd_data(struct hostapd_data *hapd)
 {
 	os_free(hapd->probereq_cb);
@@ -449,7 +468,7 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd)
 			 * driver wrapper may have removed its internal instance
 			 * and hapd->drv_priv is not valid anymore.
 			 */
-			hapd->drv_priv = NULL;
+			hostapd_clear_drv_priv(hapd);
 		}
 	}
 
@@ -2780,8 +2799,9 @@ void hostapd_interface_deinit_free(struct hostapd_iface *iface)
 	wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
 		   __func__, driver, drv_priv);
 	if (driver && driver->hapd_deinit && drv_priv) {
-		driver->hapd_deinit(drv_priv);
-		iface->bss[0]->drv_priv = NULL;
+		if (!iface->bss[0]->mld_first_bss)
+			driver->hapd_deinit(drv_priv);
+		hostapd_clear_drv_priv(iface->bss[0]);
 	}
 	hostapd_interface_free(iface);
 }
@@ -2796,13 +2816,14 @@ static void hostapd_deinit_driver(const struct wpa_driver_ops *driver,
 	wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
 		   __func__, driver, drv_priv);
 	if (driver && driver->hapd_deinit && drv_priv) {
-		driver->hapd_deinit(drv_priv);
+		if (!hapd_iface->bss[0]->mld_first_bss)
+			driver->hapd_deinit(drv_priv);
 		for (j = 0; j < hapd_iface->num_bss; j++) {
 			wpa_printf(MSG_DEBUG, "%s:bss[%d]->drv_priv=%p",
 				   __func__, (int) j,
 				   hapd_iface->bss[j]->drv_priv);
 			if (hapd_iface->bss[j]->drv_priv == drv_priv) {
-				hapd_iface->bss[j]->drv_priv = NULL;
+				hostapd_clear_drv_priv(hapd_iface->bss[j]);
 				hapd_iface->extended_capa = NULL;
 				hapd_iface->extended_capa_mask = NULL;
 				hapd_iface->extended_capa_len = 0;
@@ -3143,8 +3164,14 @@ int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
 		conf_file = ptr + 7;
 
 	for (i = 0; i < interfaces->count; i++) {
+		bool mld_ap = false;
+
+#ifdef CONFIG_IEEE80211BE
+		mld_ap = interfaces->iface[i]->conf->bss[0]->mld_ap;
+#endif /* CONFIG_IEEE80211BE */
+
 		if (!os_strcmp(interfaces->iface[i]->conf->bss[0]->iface,
-			       buf)) {
+			       buf) && !mld_ap) {
 			wpa_printf(MSG_INFO, "Cannot add interface - it "
 				   "already exists");
 			return -1;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index ed2ff45877..6c0cece36e 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -174,6 +174,8 @@ struct hostapd_data {
 	unsigned int reenable_beacon:1;
 
 	u8 own_addr[ETH_ALEN];
+	u8 mld_addr[ETH_ALEN];
+	struct hostapd_data *mld_first_bss;
 
 	int num_sta; /* number of entries in sta_list */
 	struct sta_info *sta_list; /* STA info list head */
-- 
2.38.1




More information about the Hostap mailing list