[PATCH RFC 1/3] Dynamic VLAN: Enable Dynamic VLAN for MLO
Muna Sinada
quic_msinada at quicinc.com
Mon Dec 23 16:49:47 PST 2024
This commit enables Dynamic VLAN for Multi-Link Operation (MLO)
in hostapd.
When Dynamic VLAN is enabled for AP MLD (Multi-Link Device), VLAN
list will be maintained in the first BSS (Basic Service Set).
Key changes include:
- Utilize MLD address for creating new VLAN interfaces.
- Access the VLAN list from first BSS for the MLD.
- If first bss is removed, move reference to VLAN list to new first
bss.
- When setting Group Temporal Key (GTK) per link, reference the
first BSS for the VLAN list.
- For non-AP MLD, copy the vlan_id from the primary link to other
links.
- Pass first bss when calling functions that iterate through the VLAN
list such as vlan_add_dynamic() and vlan_remove_dynamic()
Signed-off-by: Muna Sinada <quic_msinada at quicinc.com>
Signed-off-by: Pradeep Kumar Chitrapu <quic_pradeepc at quicinc.com>
---
src/ap/ap_drv_ops.c | 11 ++++++-
src/ap/hostapd.c | 19 +++++++++++
src/ap/ieee802_11.c | 1 +
src/ap/sta_info.c | 71 +++++++++++++++++++++++++++++++-----------
src/ap/vlan_full.c | 22 +++++++++++--
src/ap/wpa_auth_glue.c | 11 ++++++-
6 files changed, 112 insertions(+), 23 deletions(-)
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 65e83f468baa..fc044a4c7d93 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -372,7 +372,16 @@ int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname)
{
char force_ifname[IFNAMSIZ];
u8 if_addr[ETH_ALEN];
- return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, hapd->own_addr,
+ const u8 *addr;
+
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap)
+ addr = hapd->mld->mld_addr;
+ else
+#endif /* CONFIG_IEEE80211BE */
+ addr = hapd->own_addr;
+
+ return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, addr,
NULL, NULL, force_ifname, if_addr, NULL, 0);
}
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 9dfc21e00f3e..bf15bdaa4b12 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -616,6 +616,24 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd)
#endif /* CONFIG_IEEE80211AX */
}
+/* hostapd_mld_move_vlan_list - Move vlan list to new first bss
+ * @old_fbss
+ * @new_fbss
+ *
+ * This function is used to copy reference to vlan list from old first bss to
+ * new first bss when the first bss is removed.
+ */
+static void hostapd_mld_move_vlan_list(struct hostapd_data *old_fbss,
+ struct hostapd_data *new_fbss)
+{
+#ifdef CONFIG_IEEE80211BE
+ if (!old_fbss || !new_fbss)
+ return;
+
+ new_fbss->conf->vlan = old_fbss->conf->vlan;
+ old_fbss->conf->vlan = NULL;
+#endif /* CONFIG_IEEE80211BE */
+}
/* hostapd_bss_link_deinit - Per-BSS ML cleanup (deinitialization)
* @hapd: Pointer to BSS data
@@ -5006,6 +5024,7 @@ int hostapd_mld_remove_link(struct hostapd_data *hapd)
if (dl_list_empty(&mld->links)) {
mld->fbss = NULL;
} else {
+ hostapd_mld_move_vlan_list(mld->fbss, hapd);
next_fbss = dl_list_entry(mld->links.next, struct hostapd_data,
link);
mld->fbss = next_fbss;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 00fd5e4bf6ef..7ad59276ab84 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -4674,6 +4674,7 @@ static int ieee80211_ml_process_link(struct hostapd_data *hapd,
hapd->mld_link_id, sta->aid);
sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC_REQ_OK;
+ sta->vlan_id = origin_sta->vlan_id;
/* TODO: What other processing is required? */
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 857d3de50fd0..cc9786d6f361 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -224,6 +224,9 @@ static void clear_wpa_sm_for_each_partner_link(struct hostapd_data *hapd,
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
{
+#ifndef CONFIG_NO_VLAN
+ struct hostapd_data *vlan_bss = hapd;
+#endif /* CONFIG_NO_VLAN */
int set_beacon = 0;
accounting_sta_stop(hapd, sta);
@@ -362,13 +365,20 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
#endif /* CONFIG_NO_RADIUS */
#ifndef CONFIG_NO_VLAN
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap) {
+ vlan_bss = hostapd_mld_get_first_bss(hapd);
+ if (vlan_bss == NULL)
+ vlan_bss = hapd;
+ }
+#endif
/*
* sta->wpa_sm->group needs to be released before so that
* vlan_remove_dynamic() can check that no stations are left on the
* AP_VLAN netdev.
*/
if (sta->vlan_id)
- vlan_remove_dynamic(hapd, sta->vlan_id);
+ vlan_remove_dynamic(vlan_bss, sta->vlan_id);
if (sta->vlan_id_bound) {
/*
* Need to remove the STA entry before potentially removing the
@@ -379,7 +389,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
hostapd_drv_sta_remove(hapd, sta->addr);
sta->added_unassoc = 0;
}
- vlan_remove_dynamic(hapd, sta->vlan_id_bound);
+ vlan_remove_dynamic(vlan_bss, sta->vlan_id_bound);
}
#endif /* CONFIG_NO_VLAN */
@@ -1174,10 +1184,19 @@ int ap_sta_wps_cancel(struct hostapd_data *hapd,
static int ap_sta_get_free_vlan_id(struct hostapd_data *hapd)
{
struct hostapd_vlan *vlan;
+ struct hostapd_data *vlan_bss = hapd;
int vlan_id = MAX_VLAN_ID + 2;
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap) {
+ vlan_bss = hostapd_mld_get_first_bss(hapd);
+ if (vlan_bss == NULL)
+ vlan_bss = hapd;
+ }
+#endif
+
retry:
- for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+ for (vlan = vlan_bss->conf->vlan; vlan; vlan = vlan->next) {
if (vlan->vlan_id == vlan_id) {
vlan_id++;
goto retry;
@@ -1191,8 +1210,17 @@ int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
struct vlan_description *vlan_desc)
{
struct hostapd_vlan *vlan = NULL, *wildcard_vlan = NULL;
+ struct hostapd_data *vlan_bss = hapd;
int old_vlan_id, vlan_id = 0, ret = 0;
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap) {
+ vlan_bss = hostapd_mld_get_first_bss(hapd);
+ if (vlan_bss == NULL)
+ vlan_bss = hapd;
+ }
+#endif
+
/* Check if there is something to do */
if (hapd->conf->ssid.per_sta_vif && !sta->vlan_id) {
/* This sta is lacking its own vif */
@@ -1209,7 +1237,7 @@ int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
/* find a free vlan_id sufficiently big */
vlan_id = ap_sta_get_free_vlan_id(hapd);
/* Get wildcard VLAN */
- for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+ for (vlan = vlan_bss->conf->vlan; vlan; vlan = vlan->next) {
if (vlan->vlan_id == VLAN_ID_WILDCARD)
break;
}
@@ -1223,7 +1251,7 @@ int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
goto done;
}
} else if (vlan_desc && vlan_desc->notempty) {
- for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+ for (vlan = vlan_bss->conf->vlan; vlan; vlan = vlan->next) {
if (!vlan_compare(&vlan->vlan_desc, vlan_desc))
break;
if (vlan->vlan_id == VLAN_ID_WILDCARD)
@@ -1236,10 +1264,10 @@ int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
vlan_id = vlan_desc->untagged;
if (vlan_desc->tagged[0]) {
/* Tagged VLAN configuration */
- vlan_id = ap_sta_get_free_vlan_id(hapd);
+ vlan_id = ap_sta_get_free_vlan_id(vlan_bss);
}
} else {
- hostapd_logger(hapd, sta->addr,
+ hostapd_logger(vlan_bss, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"missing vlan and wildcard for vlan=%d%s",
@@ -1252,9 +1280,9 @@ int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
}
if (vlan && vlan->vlan_id == VLAN_ID_WILDCARD) {
- vlan = vlan_add_dynamic(hapd, vlan, vlan_id, vlan_desc);
+ vlan = vlan_add_dynamic(vlan_bss, vlan, vlan_id, vlan_desc);
if (vlan == NULL) {
- hostapd_logger(hapd, sta->addr,
+ hostapd_logger(vlan_bss, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"could not add dynamic VLAN interface for vlan=%d%s",
@@ -1266,13 +1294,13 @@ int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
goto done;
}
- hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ hostapd_logger(vlan_bss, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"added new dynamic VLAN interface '%s'",
vlan->ifname);
} else if (vlan && vlan->dynamic_vlan > 0) {
vlan->dynamic_vlan++;
- hostapd_logger(hapd, sta->addr,
+ hostapd_logger(vlan_bss, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"updated existing dynamic VLAN interface '%s'",
@@ -1284,7 +1312,7 @@ done:
sta->vlan_desc = vlan ? &vlan->vlan_desc : NULL;
if (vlan_id != old_vlan_id && old_vlan_id)
- vlan_remove_dynamic(hapd, old_vlan_id);
+ vlan_remove_dynamic(vlan_bss, old_vlan_id);
return ret;
}
@@ -1295,13 +1323,18 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
#ifndef CONFIG_NO_VLAN
const char *iface;
struct hostapd_vlan *vlan = NULL;
+ struct hostapd_data *vlan_bss = hapd;
int ret;
int old_vlanid = sta->vlan_id_bound;
int mld_link_id = -1;
#ifdef CONFIG_IEEE80211BE
- if (hapd->conf->mld_ap)
+ if (hapd->conf->mld_ap) {
mld_link_id = hapd->mld_link_id;
+ vlan_bss = hostapd_mld_get_first_bss(hapd);
+ if (vlan_bss == NULL)
+ vlan_bss = hapd;
+ }
#endif /* CONFIG_IEEE80211BE */
if ((sta->flags & WLAN_STA_WDS) && sta->vlan_id == 0) {
@@ -1316,7 +1349,7 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
iface = hapd->conf->ssid.vlan;
if (sta->vlan_id > 0) {
- for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+ for (vlan = vlan_bss->conf->vlan; vlan; vlan = vlan->next) {
if (vlan->vlan_id == sta->vlan_id)
break;
}
@@ -1334,7 +1367,7 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
if (sta->vlan_id > 0 && !vlan &&
!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
- hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ hostapd_logger(vlan_bss, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
"binding station to (vlan_id=%d)",
sta->vlan_id);
@@ -1342,7 +1375,7 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
goto done;
} else if (vlan && vlan->dynamic_vlan > 0) {
vlan->dynamic_vlan++;
- hostapd_logger(hapd, sta->addr,
+ hostapd_logger(vlan_bss, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"updated existing dynamic VLAN interface '%s'",
@@ -1353,7 +1386,7 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
sta->vlan_id_bound = sta->vlan_id;
skip_counting:
- hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ hostapd_logger(vlan_bss, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "binding station to interface "
"'%s'", iface);
@@ -1363,14 +1396,14 @@ skip_counting:
ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id,
mld_link_id);
if (ret < 0) {
- hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ hostapd_logger(vlan_bss, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not bind the STA "
"entry to vlan_id=%d", sta->vlan_id);
}
/* During 1x reauth, if the vlan id changes, then remove the old id. */
if (old_vlanid > 0 && old_vlanid != sta->vlan_id)
- vlan_remove_dynamic(hapd, old_vlanid);
+ vlan_remove_dynamic(vlan_bss, old_vlanid);
done:
return ret;
diff --git a/src/ap/vlan_full.c b/src/ap/vlan_full.c
index 19aa3c649a5d..bd79b35c9c10 100644
--- a/src/ap/vlan_full.c
+++ b/src/ap/vlan_full.c
@@ -462,11 +462,19 @@ void vlan_newlink(const char *ifname, struct hostapd_data *hapd)
{
char br_name[IFNAMSIZ];
struct hostapd_vlan *vlan;
+ struct hostapd_data *vlan_bss = hapd;
int untagged, *tagged, i, notempty;
wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
- for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap) {
+ vlan_bss = hostapd_mld_get_first_bss(hapd);
+ if (vlan_bss == NULL)
+ vlan_bss = hapd;
+ }
+#endif
+ for (vlan = vlan_bss->conf->vlan; vlan; vlan = vlan->next) {
if (vlan->configured ||
os_strcmp(ifname, vlan->ifname) != 0)
continue;
@@ -563,10 +571,20 @@ static void vlan_put_bridge(const char *br_name, struct hostapd_data *hapd,
void vlan_dellink(const char *ifname, struct hostapd_data *hapd)
{
- struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
+ struct hostapd_vlan *first, *prev, *vlan;
+ struct hostapd_data *vlan_bss = hapd;
wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap) {
+ vlan_bss = hostapd_mld_get_first_bss(hapd);
+ if (vlan_bss == NULL)
+ vlan_bss = hapd;
+ }
+#endif
+
+ vlan = vlan_bss->conf->vlan;
first = prev = vlan;
while (vlan) {
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 9fa9f19b7bc5..5d7884199f17 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -508,10 +508,19 @@ static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
size_t key_len, enum key_flag key_flag)
{
struct hostapd_data *hapd = ctx;
+ struct hostapd_data *link_bss = hapd;
const char *ifname = hapd->conf->iface;
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap) {
+ link_bss = hostapd_mld_get_first_bss(hapd);
+ if (link_bss == NULL)
+ link_bss = hapd;
+ }
+#endif
if (vlan_id > 0) {
- ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);
+ ifname = hostapd_get_vlan_id_ifname(link_bss->conf->vlan,
+ vlan_id);
if (!ifname) {
if (!(hapd->iface->drv_flags &
WPA_DRIVER_FLAGS_VLAN_OFFLOAD))
--
2.34.1
More information about the Hostap
mailing list