From: Michael Braun <michael-dev@xxxxxxxxxxxxx> 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@xxxxxxxxxxxxx> -- 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 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap