[PATCH RFC 1/3] Dynamic VLAN: Enable Dynamic VLAN for MLO

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxx>
Signed-off-by: Pradeep Kumar Chitrapu <quic_pradeepc@xxxxxxxxxxx>
---
 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


_______________________________________________
Hostap mailing list
Hostap@xxxxxxxxxxxxxxxxxxx
http://lists.infradead.org/mailman/listinfo/hostap



[Index of Archives]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux