aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hostapd/config_file.c2
-rw-r--r--hostapd/hostapd.conf11
-rw-r--r--src/ap/ap_config.h1
-rw-r--r--src/ap/ieee802_11.c30
-rw-r--r--src/ap/sta_info.c28
-rw-r--r--src/ap/vlan_init.c21
6 files changed, 72 insertions, 21 deletions
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 91eea9c..76f02ca 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2769,6 +2769,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..d535eec 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 the "bridge" configuration option (see above).
+# Otherwise, 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 7a15d18..763eaaa 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 0620fc4..de32f66 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 54b548d..a8c0308 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -831,11 +831,35 @@ 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 */
+ for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+ if (vlan->vlan_id == VLAN_ID_WILDCARD)
+ break;
+ }
+ 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) {
for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
if (!vlan_compare(&vlan->vlan_desc, vlan_desc))
break;
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index 56959e5..8709e3d 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -686,7 +686,7 @@ static void vlan_newlink(const 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);
@@ -701,10 +701,16 @@ static void vlan_newlink(const 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] &&
+ !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);
@@ -792,6 +798,7 @@ static void vlan_dellink(const char *ifname, struct hostapd_data *hapd)
return;
if (vlan->configured) {
+ int notempty = vlan->vlan_desc.notempty;
int untagged = vlan->vlan_desc.untagged;
int *tagged = vlan->vlan_desc.tagged;
char br_name[IFNAMSIZ];
@@ -808,7 +815,12 @@ static void vlan_dellink(const 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)
@@ -1064,7 +1076,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 &&
+ 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;