[PATCHv3 05/12] vlan: add per-sta vif option

michael-dev at fami-braun.de michael-dev at fami-braun.de
Thu Jan 21 05:52:00 PST 2016


From: Michael Braun <michael-dev at fami-braun.de>

This allows the stations to be assigned to their own vif.
It does not need dynamic_vlan to be set.
Makes hostapd call ap_sta_set_vlan even if !vlan_desc.notempty,
so vlan_id can be assigned regardless.

Signed-off-by: Michael Braun <michael-dev at fami-braun.de>

--
v2: move on top of tagged vlan support

---
 hostapd/config_file.c |  2 ++
 hostapd/hostapd.conf  | 11 +++++++++++
 src/ap/ap_config.h    |  1 +
 src/ap/ieee802_11.c   | 30 +++++++++++++++---------------
 src/ap/sta_info.c     | 29 +++++++++++++++++++++++++++--
 src/ap/vlan_init.c    | 25 +++++++++++++++++++------
 6 files changed, 75 insertions(+), 23 deletions(-)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 9e49d7b..3178973 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2768,6 +2768,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 #ifndef CONFIG_NO_VLAN
 	} else if (os_strcmp(buf, "dynamic_vlan") == 0) {
 		bss->ssid.dynamic_vlan = atoi(pos);
+	} else if (os_strcmp(buf, "per_sta_vif") == 0) {
+		bss->ssid.per_sta_vif = atoi(pos);
 	} else if (os_strcmp(buf, "vlan_file") == 0) {
 		if (hostapd_config_read_vlan_file(bss, pos)) {
 			wpa_printf(MSG_ERROR, "Line %d: failed to read VLAN file '%s'",
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 2c083f5..c61c483 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -978,6 +978,17 @@ own_ip_addr=127.0.0.1
 # 2 = required; reject authentication if RADIUS server does not include VLAN ID
 #dynamic_vlan=0
 
+# Per-Station AP_VLAN interface mode
+# If enabled each station is assigned its own AP_VLAN interface.
+# This implies per-station group keying and ebtables filtering of inter-STA
+# traffic (when passed through the AP).
+# If the sta is not assigned to any VLAN, then its AP_VLAN interface will be
+# added to the bridge given by "bridge" configuration option (see above). Else,
+# it will be added to the per-VLAN bridge.
+# 0 = disabled (default)
+# 1 = enabled
+#per_sta_vif=0
+
 # VLAN interface list for dynamic VLAN mode is read from a separate text file.
 # This list is used to map VLAN ID from the RADIUS server to a network
 # interface. Each station is bound to one interface in the same way as with
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 84441a8..452f5b2 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -104,6 +104,7 @@ struct hostapd_ssid {
 #define DYNAMIC_VLAN_NAMING_WITH_DEVICE 1
 #define DYNAMIC_VLAN_NAMING_END 2
 	int vlan_naming;
+	int per_sta_vif;
 #ifdef CONFIG_FULL_DYNAMIC_VLAN
 	char *vlan_tagged_interface;
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index cba995a..c1c7f0a 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1097,23 +1097,23 @@ static void handle_auth(struct hostapd_data *hapd,
 	sta->last_seq_ctrl = seq_ctrl;
 	sta->last_subtype = WLAN_FC_STYPE_AUTH;
 
-	if (vlan_id.notempty) {
-		if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_id)) {
-			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
-				       HOSTAPD_LEVEL_INFO, "Invalid VLAN "
-				       "%d%s received from RADIUS server",
-				       vlan_id.untagged,
-				       vlan_id.tagged[0] ? "+" : "");
-			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
-			goto fail;
-		}
-		if (ap_sta_set_vlan(hapd, sta, &vlan_id) < 0) {
-			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
-			goto fail;
-		}
+	if (vlan_id.notempty &&
+	    !hostapd_vlan_valid(hapd->conf->vlan, &vlan_id)) {
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
-			       HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
+			       HOSTAPD_LEVEL_INFO, "Invalid VLAN "
+			       "%d%s received from RADIUS server",
+			       vlan_id.untagged,
+			       vlan_id.tagged[0] ? "+" : "");
+		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		goto fail;
 	}
+	if (ap_sta_set_vlan(hapd, sta, &vlan_id) < 0) {
+		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		goto fail;
+	}
+	if (sta->vlan_id)
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+			       HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
 
 	hostapd_free_psk_list(sta->psk);
 	if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index a41ce4b..bb02060 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -820,11 +820,36 @@ int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
 		vlan_desc = NULL;
 
 	/* check if there is something to do */
-	if (!vlan_compare(vlan_desc, sta->vlan_desc))
+	if (hapd->conf->ssid.per_sta_vif && !sta->vlan_id) {
+		/* this sta is lacking its own vif */
+	} else if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED &&
+		   !hapd->conf->ssid.per_sta_vif && sta->vlan_id) {
+		/* sta->vlan_id needs to be reset */
+	} else if (!vlan_compare(vlan_desc, sta->vlan_desc))
 		return 0; /* nothing to change */
 
 	/* now the real vlan changed or the sta just needs its own vif */
-	if (vlan_desc->notempty) {
+	if (hapd->conf->ssid.per_sta_vif) {
+		/* assign a new vif, always */
+		/* find a free vlan_id sufficiently big */
+		vlan_id = ap_sta_get_free_vlan_id(hapd);
+		/* get wildcard vlan */
+		vlan = hapd->conf->vlan;
+		while (vlan) {
+			if (vlan->vlan_id == VLAN_ID_WILDCARD)
+				break;
+			vlan = vlan->next;
+		}
+		if (!vlan) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_DEBUG, "per_sta_vif "
+				       "missing wildcard ");
+			vlan_id = 0;
+			ret = -1;
+			goto done;
+		}
+	} else if (vlan_desc && vlan_desc->notempty) {
 		vlan = hapd->conf->vlan;
 		while (vlan) {
 			if (!vlan_compare(&vlan->vlan_desc, vlan_desc))
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index 71abc4f..740496c 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -683,7 +683,7 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
 {
 	char br_name[IFNAMSIZ];
 	struct hostapd_vlan *vlan;
-	int untagged, *tagged, i;
+	int untagged, *tagged, i, notempty;
 
 	wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
 
@@ -695,10 +695,17 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
 
 		vlan->configured = 1;
 
+		notempty = vlan->vlan_desc.notempty;
 		untagged = vlan->vlan_desc.untagged;
 		tagged = vlan->vlan_desc.tagged;
 
-		if (untagged > 0 && untagged <= MAX_VLAN_ID) {
+		if (!notempty) {
+			/* non-VLAN sta */
+			if (hapd->conf->bridge[0]) {
+				if (!br_addif(hapd->conf->bridge, ifname))
+					vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
+			}
+		} else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
 			vlan_bridge_name(br_name, hapd, untagged);
 
 			vlan_get_bridge(br_name, hapd, untagged);
@@ -773,7 +780,7 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
 {
 	struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
 	char br_name[IFNAMSIZ];
-	int untagged, i, *tagged;
+	int untagged, i, *tagged, notempty;
 
 	wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
 
@@ -789,6 +796,7 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
 		if (!vlan->configured)
 			goto skip_counting;
 
+		notempty = vlan->vlan_desc.notempty;
 		untagged = vlan->vlan_desc.untagged;
 		tagged = vlan->vlan_desc.tagged;
 
@@ -805,7 +813,12 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
 			vlan_put_bridge(br_name, hapd, tagged[i]);
 		}
 
-		if (untagged > 0 && untagged <= MAX_VLAN_ID) {
+		if (!notempty) {
+			/* non-VLAN sta */
+			if (hapd->conf->bridge[0] &&
+			    vlan->clean & DVLAN_CLEAN_WLAN_PORT)
+				br_delif(hapd->conf->bridge, ifname);
+		} else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
 			vlan_bridge_name(br_name, hapd, untagged);
 
 			if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
@@ -1062,8 +1075,8 @@ int vlan_init(struct hostapd_data *hapd)
 	hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
 
-	if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED &&
-	    !hapd->conf->vlan) {
+	if ((hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED ||
+	     hapd->conf->ssid.per_sta_vif) && !hapd->conf->vlan) {
 		/* dynamic vlans enabled but no (or empty) vlan_file given */
 		struct hostapd_vlan *vlan;
 		vlan = os_zalloc(sizeof(*vlan));
-- 
2.1.4




More information about the Hostap mailing list