diff mbox

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

Message ID 1449434863-2555-6-git-send-email-michael-dev@fami-braun.de
State Changes Requested
Headers show

Commit Message

michael-dev Dec. 6, 2015, 8:47 p.m. UTC
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@fami-braun.de>

--
v2: move on top of tagged vlan support
---
 hostapd/config_file.c |  2 ++
 hostapd/hostapd.conf  |  8 ++++++++
 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, 72 insertions(+), 23 deletions(-)

Comments

Jouni Malinen Dec. 24, 2015, 7:02 p.m. UTC | #1
On Sun, Dec 06, 2015 at 09:47:36PM +0100, Michael Braun wrote:
> 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.

What's the expected way of using these new netdevs? In other words, is
there an expectation of some external program listening for new netdevs
to be added and then add them to a suitable bridge interface (etc.)? Or
is hostapd expected to make this fully usable? In either case, the
documentation in hostapd.conf could mention some more details on how
this should be used.


This was the last email in this thread that I had left in my queue, so
at this point, I don't have any more comments on this version of the
patch set.
michael-dev Jan. 7, 2016, 1:47 p.m. UTC | #2
Am 24.12.2015 um 20:02 schrieb Jouni Malinen:
> On Sun, Dec 06, 2015 at 09:47:36PM +0100, Michael Braun wrote:
>> 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.
> 
> What's the expected way of using these new netdevs? In other words, is
> there an expectation of some external program listening for new netdevs
> to be added and then add them to a suitable bridge interface (etc.)? Or
> is hostapd expected to make this fully usable? In either case, the
> documentation in hostapd.conf could mention some more details on how
> this should be used.

a) station with (non-empty) VLAN set

Hostapd will add this to the vlan-bridge as with all VLAN related netdevs.

b) station without VLAN set

Hostapd will add this to the bridge given using the bridge configuration
option.

I'll update the documentation.
diff mbox

Patch

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 2887a16..0e842b8 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2765,6 +2765,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 4f51140..65c223b 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -969,6 +969,14 @@  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).
+# 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 ec6a026..574e74a 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 1d30abb..f24eed8 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_id_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_id_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 342b6ab..51b41e1 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,
 		os_memset(&vlan_desc, 0, sizeof(vlan_desc));
 
 	/* check if there is something to do */
-	if (!os_memcmp(&vlan_desc, &sta->vlan_desc, sizeof(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 (!os_memcmp(&vlan_desc, &sta->vlan_desc, sizeof(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.notempty) {
 		vlan = hapd->conf->vlan;
 		while (vlan) {
 			if (!os_memcmp(&vlan->vlan_desc, &vlan_desc,
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index 85260d6..5307e9e 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));