Patchwork [v4,19/25] VLAN: use untagged/tagged for interface configuration

login
register
mail settings
Submitter michael-dev@fami-braun.de
Date July 27, 2013, 7:56 p.m.
Message ID <20130727195602.17627.4719.stgit@ray-controller>
Download mbox | patch
Permalink /patch/262521/
State Superseded
Headers show

Comments

michael-dev@fami-braun.de - July 27, 2013, 7:56 p.m.
Signed-hostap: Michael Braun <michael-dev@fami-braun.de>
---
 src/ap/ap_config.h |    6 +
 src/ap/vlan_init.c |  355 ++++++++++++++++++++++++++++++++--------------------
 2 files changed, 223 insertions(+), 138 deletions(-)

Patch

diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index c450219..5c5b15a 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -84,6 +84,10 @@  struct hostapd_vlan {
 	/* untagged = VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
 	vlan_t vlan_id;
 	char ifname[IFNAMSIZ + 1];
+	/* VLANs created automatically for a WILDCARD entry use this id for id
+	 * generation. The linked list is sorted by this id (ascending);
+	 * non-dynamically generated entries get value zero */
+	int artifical_id;
 	int dynamic_vlan;
 #ifdef CONFIG_FULL_DYNAMIC_VLAN
 
@@ -91,7 +95,7 @@  struct hostapd_vlan {
 #define DVLAN_CLEAN_VLAN	0x2
 #define DVLAN_CLEAN_VLAN_PORT	0x4
 #define DVLAN_CLEAN_WLAN_PORT	0x8
-	int clean;
+	int *clean;
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
 };
 
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index 3b024fa..11de5af 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -597,165 +597,212 @@  static int hapd_put_dynamic_iface(const char *parent, const char *ifname,
 }
 
 
-static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
+static void vlan_newlink_vlan(const int vlan_id, char *ifname, int *clean,
+                              struct hostapd_data *hapd)
 {
-	char vlan_ifname[IFNAMSIZ];
-	char br_name[IFNAMSIZ];
-	struct hostapd_vlan *vlan = hapd->conf->vlan;
+	char vlan_ifname[IFNAMSIZ+1];
+	char br_name[IFNAMSIZ+1];
 	char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
 	int vlan_naming = hapd->conf->ssid.vlan_naming;
 	int ret;
 
+	if (hapd->conf->vlan_bridge[0]) {
+		os_snprintf(br_name, sizeof(br_name), "%s%d",
+		            hapd->conf->vlan_bridge, vlan_id);
+	} else if (tagged_interface) {
+		os_snprintf(br_name, sizeof(br_name), "br%s.%d",
+		            tagged_interface, vlan_id);
+	} else {
+		os_snprintf(br_name, sizeof(br_name), "brvlan%d", vlan_id);
+	}
+
+	ret = br_addbr(br_name);
+	if (hapd_get_dynamic_iface(NULL, br_name, (ret == 0), hapd))
+		if (clean)
+			*clean |= DVLAN_CLEAN_BR;
+	ifconfig_up(br_name);
+
+	if (tagged_interface) {
+		if (vlan_naming ==  DYNAMIC_VLAN_NAMING_WITH_DEVICE)
+			os_snprintf(vlan_ifname, sizeof(vlan_ifname),
+			                  "%s.%d", tagged_interface, vlan_id);
+		else
+			os_snprintf(vlan_ifname, sizeof(vlan_ifname),
+			                  "vlan%d", vlan_id);
+
+		ifconfig_up(tagged_interface);
+		ret = vlan_add(tagged_interface, vlan_id, vlan_ifname);
+		if (hapd_get_dynamic_iface(NULL, vlan_ifname, (ret == 0), hapd))
+			if (clean)
+				*clean |= DVLAN_CLEAN_VLAN;
+		ifconfig_up(vlan_ifname);
+
+		ret = br_addif(br_name, vlan_ifname);
+		if (hapd_get_dynamic_iface(br_name, vlan_ifname, (ret == 0),
+		                           hapd))
+			if (clean)
+				*clean |= DVLAN_CLEAN_VLAN_PORT;
+	}
+
+	ifconfig_up(ifname);
+
+	ret = br_addif(br_name, ifname);
+	if (hapd_get_dynamic_iface(br_name, ifname, (ret == 0), hapd))
+		if (clean)
+			*clean |= DVLAN_CLEAN_WLAN_PORT;
+}
+
+
+static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
+{
+	struct hostapd_vlan *vlan;
+	char vlan_ifname[IFNAMSIZ+1];
+	int i, ret;
+
 	wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
 
-	while (vlan) {
-		if (os_strcmp(ifname, vlan->ifname) == 0) {
-
-			if (hapd->conf->vlan_bridge[0]) {
-				os_snprintf(br_name, sizeof(br_name), "%s%d",
-					    hapd->conf->vlan_bridge,
-					    vlan_untagged(&vlan->vlan_id));
-			} else if (tagged_interface) {
-				os_snprintf(br_name, sizeof(br_name),
-				            "br%s.%d", tagged_interface,
-					    vlan_untagged(&vlan->vlan_id));
-			} else {
-				os_snprintf(br_name, sizeof(br_name),
-				            "brvlan%d",
-					    vlan_untagged(&vlan->vlan_id));
-			}
+	for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+		if (os_strcmp(ifname, vlan->ifname) != 0)
+			continue;
 
-			ret = br_addbr(br_name);
-			if (hapd_get_dynamic_iface(NULL, br_name, ret == 0,
-			                           hapd))
-				vlan->clean |= DVLAN_CLEAN_BR;
-
-			ifconfig_up(br_name);
-
-			if (tagged_interface) {
-				if (vlan_naming ==
-				    DYNAMIC_VLAN_NAMING_WITH_DEVICE)
-					os_snprintf(vlan_ifname,
-						    sizeof(vlan_ifname),
-						    "%s.%d", tagged_interface,
-						    vlan_untagged(
-						      &vlan->vlan_id));
-				else
-					os_snprintf(vlan_ifname,
-						    sizeof(vlan_ifname),
-						    "vlan%d",
-						    vlan_untagged(
-						      &vlan->vlan_id));
-
-				ifconfig_up(tagged_interface);
-				ret = vlan_add(tagged_interface,
-				               vlan_untagged(&vlan->vlan_id),
-					       vlan_ifname);
-				if (hapd_get_dynamic_iface(NULL, vlan_ifname,
-				                           ret == 0, hapd))
-					vlan->clean |= DVLAN_CLEAN_VLAN;
-
-				ret = br_addif(br_name, vlan_ifname);
-				if (hapd_get_dynamic_iface(br_name,
-							   vlan_ifname,
-							   ret == 0, hapd))
-					vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
-
-				ifconfig_up(vlan_ifname);
-			}
+		int untagged, num_tagged, *tagged;
+		num_tagged = vlan_tagged(&vlan->vlan_id, &tagged);
+		untagged = vlan_untagged(&vlan->vlan_id);
 
-			ret = br_addif(br_name, ifname);
-			if (hapd_get_dynamic_iface(br_name, ifname, ret == 0,
-						   hapd))
-				vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
+		if (!vlan->clean)
+			vlan->clean = os_zalloc((num_tagged + 1) *
+			                        sizeof(*(vlan->clean)));
 
+		if (untagged > 0) {
+			vlan_newlink_vlan(untagged, ifname, vlan->clean, hapd);
+		} else {
 			ifconfig_up(ifname);
+		}
+		for (i = 0; i < num_tagged; i++) {
+			const int tagged_vlan_id = tagged[i];
+			// add tagged interface on wlan
+			ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname),
+				          "%s.%d", ifname, tagged_vlan_id);
+			if (ret >= sizeof(vlan_ifname) || ret < 0) {
+				wpa_printf(MSG_ERROR, "VLAN: length limit for "
+				           "interfaces names reached.");
+				continue;
+			}
+			vlan_add(ifname, tagged_vlan_id, vlan_ifname);
+			// add this to bridge
+			int *clean = NULL;
+			if (vlan->clean)
+				clean = &(vlan->clean[i+1]);
+			vlan_newlink_vlan(tagged_vlan_id, vlan_ifname, clean,
+			                  hapd);
+		}
+		break;
+	}
+}
 
-			break;
+
+static void vlan_dellink_vlan(int vlan_id, char* ifname, int *clean,
+                              struct hostapd_data *hapd)
+{
+	char vlan_ifname[IFNAMSIZ+1];
+	char br_name[IFNAMSIZ+1];
+	char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+	int vlan_naming = hapd->conf->ssid.vlan_naming;
+
+	if (hapd->conf->vlan_bridge[0]) {
+		os_snprintf(br_name, sizeof(br_name), "%s%d",
+		            hapd->conf->vlan_bridge, vlan_id);
+	} else if (tagged_interface) {
+		os_snprintf(br_name, sizeof(br_name), "br%s.%d",
+		            tagged_interface, vlan_id);
+	} else {
+		os_snprintf(br_name, sizeof(br_name), "brvlan%d", vlan_id);
+	}
+
+	if (clean && (*clean & DVLAN_CLEAN_WLAN_PORT) &&
+	    hapd_put_dynamic_iface(br_name, ifname, hapd))
+		br_delif(br_name, ifname);
+
+	if (tagged_interface) {
+		if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
+			os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
+			            tagged_interface, vlan_id);
+		else
+			os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d",
+			            vlan_id);
+		if (clean && (*clean & DVLAN_CLEAN_VLAN_PORT) &&
+		    hapd_put_dynamic_iface(br_name, vlan_ifname, hapd))
+			br_delif(br_name, vlan_ifname);
+
+		if (clean && (*clean & DVLAN_CLEAN_VLAN) &&
+		    hapd_put_dynamic_iface(NULL, vlan_ifname, hapd)) {
+			ifconfig_down(vlan_ifname);
+			vlan_rem(vlan_ifname);
 		}
-		vlan = vlan->next;
 	}
+
+	if (clean && (*clean & DVLAN_CLEAN_BR) &&
+	    hapd_put_dynamic_iface(NULL, br_name, hapd) &&
+	    br_getnumports(br_name) == 0) {
+		ifconfig_down(br_name);
+		br_delbr(br_name);
+	}
+
+	if (clean)
+		*clean = 0;
 }
 
 
 static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
 {
+	struct hostapd_vlan *first, *prev, *vlan;
 	char vlan_ifname[IFNAMSIZ];
-	char br_name[IFNAMSIZ];
-	struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
-	char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
-	int vlan_naming = hapd->conf->ssid.vlan_naming;
+	int i, ret;
 
 	wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
 
-	first = prev = vlan;
-
-	while (vlan) {
-		if (os_strcmp(ifname, vlan->ifname) == 0) {
-			if (hapd->conf->vlan_bridge[0]) {
-				os_snprintf(br_name, sizeof(br_name), "%s%d",
-					    hapd->conf->vlan_bridge,
-					    vlan_untagged(&vlan->vlan_id));
-			} else if (tagged_interface) {
-				os_snprintf(br_name, sizeof(br_name), "br%s.%d",
-					    tagged_interface,
-					    vlan_untagged(&vlan->vlan_id));
-			} else {
-				os_snprintf(br_name, sizeof(br_name),
-				            "brvlan%d",
-					    vlan_untagged(&vlan->vlan_id));
-			}
+	for (first = prev = vlan = hapd->conf->vlan; vlan;
+	     prev = vlan, vlan = vlan->next) {
+		if (os_strcmp(ifname, vlan->ifname) != 0)
+			continue;
 
-			if ((vlan->clean & DVLAN_CLEAN_WLAN_PORT) &&
-			    hapd_put_dynamic_iface(br_name, vlan->ifname, hapd))
-				br_delif(br_name, vlan->ifname);
-
-			if (tagged_interface) {
-				if (vlan_naming ==
-				    DYNAMIC_VLAN_NAMING_WITH_DEVICE)
-					os_snprintf(vlan_ifname,
-						    sizeof(vlan_ifname),
-						    "%s.%d", tagged_interface,
-						    vlan_untagged(
-						      &vlan->vlan_id));
-				else
-					os_snprintf(vlan_ifname,
-						    sizeof(vlan_ifname),
-						    "vlan%d",
-						    vlan_untagged(
-						      &vlan->vlan_id));
-				if ((vlan->clean & DVLAN_CLEAN_VLAN_PORT) &&
-				    hapd_put_dynamic_iface(br_name, vlan_ifname,
-							   hapd))
-					br_delif(br_name, vlan_ifname);
-				ifconfig_down(vlan_ifname);
-
-				if ((vlan->clean & DVLAN_CLEAN_VLAN) &&
-				    hapd_put_dynamic_iface(NULL, vlan_ifname,
-							   hapd))
-					vlan_rem(vlan_ifname);
-			}
+		int untagged = vlan_untagged(&vlan->vlan_id);
+		if (untagged > 0) {
+			vlan_dellink_vlan(untagged, ifname, vlan->clean, hapd);
+		}
 
-			if ((vlan->clean & DVLAN_CLEAN_BR) &&
-			    hapd_put_dynamic_iface(NULL, br_name, hapd) &&
-			    br_getnumports(br_name) == 0) {
-				ifconfig_down(br_name);
-				br_delbr(br_name);
+		int num_tagged, *tagged;
+		num_tagged = vlan_tagged(&vlan->vlan_id, &tagged);
+		for (i = 0; i < num_tagged; i++) {
+			const int tagged_vlan_id = tagged[i];
+			// add tagged interface on wlan
+			ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname),
+			                  "%s.%d", ifname, tagged_vlan_id);
+			if (ret >= sizeof(vlan_ifname) || ret < 0) {
+				wpa_printf(MSG_ERROR, "VLAN: length limit for "
+				           "interfaces names reached.");
+				continue;
 			}
+			int *clean = NULL;
+			if (vlan->clean)
+				clean = &(vlan->clean[i+1]);
+			vlan_dellink_vlan(tagged_vlan_id, vlan_ifname, clean,
+			                  hapd);
+			vlan_rem(vlan_ifname);
+		}
+		if (vlan == first) {
+			hapd->conf->vlan = vlan->next;
+		} else {
+			prev->next = vlan->next;
+		}
 
-			if (vlan == first) {
-				hapd->conf->vlan = vlan->next;
-			} else {
-				prev->next = vlan->next;
-			}
+		vlan_free(&vlan->vlan_id);
+		os_free(vlan->clean);
+		vlan->clean = NULL;
 
-			vlan_free(&vlan->vlan_id);
-			os_free(vlan);
+		os_free(vlan);
 
-			break;
-		}
-		prev = vlan;
-		vlan = vlan->next;
+		break;
 	}
 }
 
@@ -1040,12 +1087,14 @@  struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
 				       struct hostapd_vlan *vlan,
 				       vlan_t vlan_id)
 {
-	struct hostapd_vlan *n;
+	struct hostapd_vlan *n, *i, *prev;
 	char *ifname, *pos;
 
-	if (vlan == NULL || vlan_untagged(&vlan_id) <= 0 ||
-	    vlan_untagged(&vlan_id) > MAX_VLAN_ID ||
-	    vlan_untagged(&vlan->vlan_id) != VLAN_ID_WILDCARD)
+	if (vlan == NULL
+	    || vlan_untagged(&vlan_id) <= 0
+	    || vlan_untagged(&vlan_id) > MAX_VLAN_ID
+	    || !vlan_notempty(&vlan_id)
+	    || vlan_untagged(&vlan->vlan_id) != VLAN_ID_WILDCARD)
 		return NULL;
 
 	wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%s ifname=%s)",
@@ -1069,8 +1118,34 @@  struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
 	vlan_alloc_copy(&n->vlan_id, &vlan_id);
 	n->dynamic_vlan = 1;
 
+	/* artifical id := untagged vlan id (if no tagged vlan id given)
+	 *              := MAX_VLAN_ID + seq (if tagged vlan is set)
+	 */
+	int artifical_id = vlan_untagged(&vlan_id);
+	int num_tagged, *tagged;
+	num_tagged = vlan_tagged(&vlan_id, &tagged);
+	if (num_tagged > 0) {
+		/* get free artifical id, start searching at 4096 */
+		artifical_id = MAX_VLAN_ID + 2;
+		prev = NULL;
+		for (i = hapd->conf->vlan;
+		     i && i->artifical_id <= artifical_id;
+		     i = i->next) {
+			if ( artifical_id == i->artifical_id )
+				artifical_id++;
+			prev = i;
+		}
+	} else {
+		prev = NULL;
+		for (i = hapd->conf->vlan;
+		     i && i->artifical_id <= artifical_id;
+		     i = i->next) {
+			prev = i;
+		}
+	}
+	n->artifical_id = artifical_id;
 	os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname,
-	            vlan_untagged(&vlan_id), pos);
+	            artifical_id, pos);
 	os_free(ifname);
 
 	if (hostapd_vlan_if_add(hapd, n->ifname)) {
@@ -1078,8 +1153,14 @@  struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
 		return NULL;
 	}
 
-	n->next = hapd->conf->vlan;
-	hapd->conf->vlan = n;
+	/* insert into list */
+	if (!prev) {
+		n->next = hapd->conf->vlan;
+		hapd->conf->vlan = n;
+	} else {
+		n->next = prev->next;
+		prev->next = n;
+	}
 
 #ifdef CONFIG_FULL_DYNAMIC_VLAN
 	ifconfig_up(n->ifname);