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@xxxxxxxxx> Signed-off-by: Ilan Peer <ilan.peer@xxxxxxxxx> --- 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 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap