aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hostapd/Android.mk1
-rw-r--r--hostapd/Makefile1
-rw-r--r--hostapd/config_file.c7
-rw-r--r--hostapd/ctrl_iface.c8
-rw-r--r--src/ap/ap_config.c13
-rw-r--r--src/ap/ap_config.h9
-rw-r--r--src/ap/ieee802_11.c19
-rw-r--r--src/ap/ieee802_11_auth.c28
-rw-r--r--src/ap/ieee802_11_auth.h6
-rw-r--r--src/ap/ieee802_1x.c52
-rw-r--r--src/ap/pmksa_cache_auth.c29
-rw-r--r--src/ap/pmksa_cache_auth.h5
-rw-r--r--src/ap/sta_info.c107
-rw-r--r--src/ap/sta_info.h4
-rw-r--r--src/ap/vlan.c29
-rw-r--r--src/ap/vlan.h27
-rw-r--r--src/ap/vlan_init.c38
-rw-r--r--src/ap/vlan_init.h9
-rw-r--r--src/ap/wpa_auth_ie.c8
19 files changed, 291 insertions, 109 deletions
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index cead731..799d150 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -176,6 +176,7 @@ ifdef CONFIG_NO_VLAN
L_CFLAGS += -DCONFIG_NO_VLAN
else
OBJS += src/ap/vlan_init.c
+OBJS += src/ap/vlan.c
ifdef CONFIG_VLAN_NETLINK
ifdef CONFIG_FULL_DYNAMIC_VLAN
OBJS += src/ap/vlan_util.c
diff --git a/hostapd/Makefile b/hostapd/Makefile
index fd3105e..306f19d 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -194,6 +194,7 @@ ifdef CONFIG_NO_VLAN
CFLAGS += -DCONFIG_NO_VLAN
else
OBJS += ../src/ap/vlan_init.o
+OBJS += ../src/ap/vlan.o
ifdef CONFIG_VLAN_NETLINK
ifdef CONFIG_FULL_DYNAMIC_VLAN
OBJS += ../src/ap/vlan_util.o
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 503d479..91eea9c 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -97,6 +97,8 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
}
vlan->vlan_id = vlan_id;
+ vlan->vlan_desc.untagged = vlan_id;
+ vlan->vlan_desc.notempty = !!vlan_id;
os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname));
vlan->next = bss->vlan;
bss->vlan = vlan;
@@ -197,7 +199,10 @@ static int hostapd_config_read_maclist(const char *fname,
*acl = newacl;
os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
- (*acl)[*num].vlan_id = vlan_id;
+ os_memset(&(*acl)[*num].vlan_id, 0,
+ sizeof((*acl)[*num].vlan_id));
+ (*acl)[*num].vlan_id.untagged = vlan_id;
+ (*acl)[*num].vlan_id.notempty = !!vlan_id;
(*num)++;
}
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index cb6fb17..d56599b 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -1322,7 +1322,7 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
#endif /* CONFIG_TESTING_OPTIONS */
} else {
struct sta_info *sta;
- int vlan_id;
+ struct vlan_description vlan_id;
ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
if (ret)
@@ -1334,7 +1334,8 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
hapd->conf->deny_mac,
hapd->conf->num_deny_mac, sta->addr,
&vlan_id) &&
- (!vlan_id || vlan_id == sta->vlan_id))
+ (!vlan_id.notempty ||
+ !vlan_compare(&vlan_id, sta->vlan_desc)))
ap_sta_disconnect(
hapd, sta, sta->addr,
WLAN_REASON_UNSPECIFIED);
@@ -1346,7 +1347,8 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
hapd->conf->accept_mac,
hapd->conf->num_accept_mac,
sta->addr, &vlan_id) ||
- (vlan_id && vlan_id != sta->vlan_id))
+ (vlan_id.notempty &&
+ vlan_compare(&vlan_id, sta->vlan_desc)))
ap_sta_disconnect(
hapd, sta, sta->addr,
WLAN_REASON_UNSPECIFIED);
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 88074f2..c66aae8 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -629,7 +629,7 @@ void hostapd_config_free(struct hostapd_config *conf)
* Perform a binary search for given MAC address from a pre-sorted list.
*/
int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
- const u8 *addr, int *vlan_id)
+ const u8 *addr, struct vlan_description *vlan_id)
{
int start, end, middle, res;
@@ -669,11 +669,18 @@ int hostapd_rate_found(int *list, int rate)
}
-int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id)
+int hostapd_vlan_valid(struct hostapd_vlan *vlan,
+ struct vlan_description *vlan_desc)
{
struct hostapd_vlan *v = vlan;
+
+ if (!vlan_desc->notempty || vlan_desc->untagged <= 0 ||
+ vlan_desc->untagged > MAX_VLAN_ID)
+ return 0;
+
while (v) {
- if (v->vlan_id == vlan_id || v->vlan_id == VLAN_ID_WILDCARD)
+ if (!vlan_compare(&v->vlan_desc, vlan_desc) ||
+ v->vlan_id == VLAN_ID_WILDCARD)
return 1;
v = v->next;
}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index e68ec28..7a15d18 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -17,6 +17,7 @@
#include "common/ieee802_11_common.h"
#include "wps/wps.h"
#include "fst/fst.h"
+#include "vlan.h"
/**
* mesh_conf - local MBSS state and settings
@@ -53,7 +54,7 @@ typedef u8 macaddr[ETH_ALEN];
struct mac_acl_entry {
macaddr addr;
- int vlan_id;
+ struct vlan_description vlan_id;
};
struct hostapd_radius_servers;
@@ -114,6 +115,7 @@ struct hostapd_ssid {
struct hostapd_vlan {
struct hostapd_vlan *next;
int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
+ struct vlan_description vlan_desc;
char ifname[IFNAMSIZ + 1];
int configured;
int dynamic_vlan;
@@ -690,13 +692,14 @@ void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p);
void hostapd_config_free_bss(struct hostapd_bss_config *conf);
void hostapd_config_free(struct hostapd_config *conf);
int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
- const u8 *addr, int *vlan_id);
+ const u8 *addr, struct vlan_description *vlan_id);
int hostapd_rate_found(int *list, int rate);
const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
const u8 *addr, const u8 *p2p_dev_addr,
const u8 *prev_psk);
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
-int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id);
+int hostapd_vlan_valid(struct hostapd_vlan *vlan,
+ struct vlan_description *vlan_desc);
const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
int vlan_id);
struct hostapd_radius_attr *
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index ec6f8a7..b1d1660 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -886,7 +886,7 @@ static void handle_auth(struct hostapd_data *hapd,
u16 fc;
const u8 *challenge = NULL;
u32 session_timeout, acct_interim_interval;
- int vlan_id = 0;
+ struct vlan_description vlan_id;
struct hostapd_sta_wpa_psk_short *psk = NULL;
u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
size_t resp_ies_len = 0;
@@ -894,6 +894,8 @@ static void handle_auth(struct hostapd_data *hapd,
char *radius_cui = NULL;
u16 seq_ctrl;
+ os_memset(&vlan_id, 0, sizeof(vlan_id));
+
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
(unsigned long) len);
@@ -1095,16 +1097,19 @@ static void handle_auth(struct hostapd_data *hapd,
sta->last_seq_ctrl = seq_ctrl;
sta->last_subtype = WLAN_FC_STYPE_AUTH;
- if (vlan_id > 0) {
- if (!hostapd_vlan_id_valid(hapd->conf->vlan, vlan_id)) {
+ 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 ID "
- "%d received from RADIUS server",
- vlan_id);
+ HOSTAPD_LEVEL_INFO,
+ "Invalid VLAN %d received from RADIUS server",
+ vlan_id.untagged);
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ if (ap_sta_set_vlan(hapd, sta, &vlan_id) < 0) {
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
- sta->vlan_id = vlan_id;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
}
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index ec0037a..d46f389 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -35,7 +35,7 @@ struct hostapd_cached_radius_acl {
struct hostapd_cached_radius_acl *next;
u32 session_timeout;
u32 acct_interim_interval;
- int vlan_id;
+ struct vlan_description vlan_id;
struct hostapd_sta_wpa_psk_short *psk;
char *identity;
char *radius_cui;
@@ -99,7 +99,8 @@ static void copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
u32 *session_timeout,
- u32 *acct_interim_interval, int *vlan_id,
+ u32 *acct_interim_interval,
+ struct vlan_description *vlan_id,
struct hostapd_sta_wpa_psk_short **psk,
char **identity, char **radius_cui)
{
@@ -222,7 +223,8 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
* @vlan_id: Buffer for returning VLAN ID
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
*/
- int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr, int *vlan_id)
+int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
+ struct vlan_description *vlan_id)
{
if (hostapd_maclist_found(hapd->conf->accept_mac,
hapd->conf->num_accept_mac, addr, vlan_id))
@@ -260,7 +262,8 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
*/
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval, int *vlan_id,
+ u32 *acct_interim_interval,
+ struct vlan_description *vlan_id,
struct hostapd_sta_wpa_psk_short **psk,
char **identity, char **radius_cui)
{
@@ -271,7 +274,7 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
if (acct_interim_interval)
*acct_interim_interval = 0;
if (vlan_id)
- *vlan_id = 0;
+ os_memset(vlan_id, 0, sizeof(*vlan_id));
if (psk)
*psk = NULL;
if (identity)
@@ -556,7 +559,8 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
cache->acct_interim_interval = 0;
}
- cache->vlan_id = radius_msg_get_vlanid(msg);
+ cache->vlan_id.untagged = radius_msg_get_vlanid(msg);
+ cache->vlan_id.notempty = !!cache->vlan_id.untagged;
decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
msg, req, cache);
@@ -579,17 +583,17 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
!cache->psk)
cache->accepted = HOSTAPD_ACL_REJECT;
- if (cache->vlan_id &&
- !hostapd_vlan_id_valid(hapd->conf->vlan, cache->vlan_id)) {
+ if (cache->vlan_id.notempty &&
+ !hostapd_vlan_valid(hapd->conf->vlan, &cache->vlan_id)) {
hostapd_logger(hapd, query->addr,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
- "Invalid VLAN ID %d received from RADIUS server",
- cache->vlan_id);
- cache->vlan_id = 0;
+ "Invalid VLAN %d received from RADIUS server",
+ cache->vlan_id.untagged);
+ os_memset(&cache->vlan_id, 0, sizeof(cache->vlan_id));
}
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
- !cache->vlan_id)
+ !cache->vlan_id.notempty)
cache->accepted = HOSTAPD_ACL_REJECT;
} else
cache->accepted = HOSTAPD_ACL_REJECT;
diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h
index da81c14..71f53b9 100644
--- a/src/ap/ieee802_11_auth.h
+++ b/src/ap/ieee802_11_auth.h
@@ -16,10 +16,12 @@ enum {
HOSTAPD_ACL_ACCEPT_TIMEOUT = 3
};
-int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr, int *vlan_id);
+int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
+ struct vlan_description *vlan_id);
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval, int *vlan_id,
+ u32 *acct_interim_interval,
+ struct vlan_description *vlan_id,
struct hostapd_sta_wpa_psk_short **psk,
char **identity, char **radius_cui);
int hostapd_acl_init(struct hostapd_data *hapd);
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index d399b1e..ff32e8b 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -222,7 +222,7 @@ static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
MAC2STR(sta->addr));
#ifndef CONFIG_NO_VLAN
- if (sta->vlan_id > 0 && sta->vlan_id <= MAX_VLAN_ID) {
+ if (sta->vlan_id > 0) {
wpa_printf(MSG_ERROR, "Using WEP with vlans is not supported.");
return;
}
@@ -1151,7 +1151,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
sta->eapol_sm->authFail = FALSE;
if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap);
- pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm);
+ pmksa_cache_to_eapol_data(hapd, pmksa, sta->eapol_sm);
ap_sta_bind_vlan(hapd, sta);
} else {
if (reassoc) {
@@ -1617,10 +1617,13 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
struct hostapd_data *hapd = data;
struct sta_info *sta;
u32 session_timeout = 0, termination_action, acct_interim_interval;
- int session_timeout_set, vlan_id = 0;
+ int session_timeout_set;
struct eapol_state_machine *sm;
int override_eapReq = 0;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
+ struct vlan_description vlan_desc;
+
+ os_memset(&vlan_desc, 0, sizeof(vlan_desc));
sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier);
if (sm == NULL) {
@@ -1684,27 +1687,27 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
switch (hdr->code) {
case RADIUS_CODE_ACCESS_ACCEPT:
- if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
- vlan_id = 0;
#ifndef CONFIG_NO_VLAN
- else
- vlan_id = radius_msg_get_vlanid(msg);
- if (vlan_id > 0 &&
- hostapd_vlan_id_valid(hapd->conf->vlan, vlan_id)) {
- hostapd_logger(hapd, sta->addr,
- HOSTAPD_MODULE_RADIUS,
- HOSTAPD_LEVEL_INFO,
- "VLAN ID %d", vlan_id);
- } else if (vlan_id > 0) {
+ if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED) {
+ vlan_desc.untagged = radius_msg_get_vlanid(msg);
+ vlan_desc.notempty = !!vlan_desc.untagged;
+ }
+
+ if (vlan_desc.notempty &&
+ !hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
sta->eapol_sm->authFail = TRUE;
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
- "Invalid VLAN ID %d received from RADIUS server",
- vlan_id);
+ "Invalid VLAN %d received from RADIUS server",
+ vlan_desc.untagged);
+ os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+ ap_sta_set_vlan(hapd, sta, &vlan_desc);
break;
- } else if (hapd->conf->ssid.dynamic_vlan ==
- DYNAMIC_VLAN_REQUIRED) {
+ }
+
+ if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
+ !vlan_desc.notempty) {
sta->eapol_sm->authFail = TRUE;
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE8021X,
@@ -1715,7 +1718,18 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
}
#endif /* CONFIG_NO_VLAN */
- sta->vlan_id = vlan_id;
+ if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0)
+ break;
+
+#ifndef CONFIG_NO_VLAN
+ if (sta->vlan_id > 0) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO,
+ "VLAN ID %d", sta->vlan_id);
+ }
+#endif /* CONFIG_NO_VLAN */
+
if ((sta->flags & WLAN_STA_ASSOC) &&
ap_sta_bind_vlan(hapd, sta) < 0)
break;
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index eb37c78..1021be0 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -38,6 +38,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
{
+ os_free(entry->vlan_desc);
os_free(entry->identity);
wpabuf_free(entry->cui);
#ifndef CONFIG_NO_RADIUS
@@ -126,6 +127,8 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
struct eapol_state_machine *eapol)
{
+ struct vlan_description *vlan_desc;
+
if (eapol == NULL)
return;
@@ -146,15 +149,26 @@ static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
#endif /* CONFIG_NO_RADIUS */
entry->eap_type_authsrv = eapol->eap_type_authsrv;
- entry->vlan_id = ((struct sta_info *) eapol->sta)->vlan_id;
+
+ vlan_desc = ((struct sta_info *) eapol->sta)->vlan_desc;
+ if (vlan_desc && vlan_desc->notempty) {
+ entry->vlan_desc = os_zalloc(sizeof(struct vlan_description));
+ if (entry->vlan_desc)
+ *entry->vlan_desc = *vlan_desc;
+ } else {
+ entry->vlan_desc = NULL;
+ }
entry->acct_multi_session_id = eapol->acct_multi_session_id;
}
-void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
+void pmksa_cache_to_eapol_data(struct hostapd_data *hapd,
+ struct rsn_pmksa_cache_entry *entry,
struct eapol_state_machine *eapol)
{
+ struct sta_info *sta;
+
if (entry == NULL || eapol == NULL)
return;
@@ -185,7 +199,8 @@ void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
}
eapol->eap_type_authsrv = entry->eap_type_authsrv;
- ((struct sta_info *) eapol->sta)->vlan_id = entry->vlan_id;
+ sta = (struct sta_info *) eapol->sta;
+ ap_sta_set_vlan(hapd, sta, entry->vlan_desc);
eapol->acct_multi_session_id = entry->acct_multi_session_id;
}
@@ -335,7 +350,13 @@ pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
radius_copy_class(&entry->radius_class, &old_entry->radius_class);
#endif /* CONFIG_NO_RADIUS */
entry->eap_type_authsrv = old_entry->eap_type_authsrv;
- entry->vlan_id = old_entry->vlan_id;
+ if (old_entry->vlan_desc) {
+ entry->vlan_desc = os_zalloc(sizeof(struct vlan_description));
+ if (entry->vlan_desc)
+ *entry->vlan_desc = *old_entry->vlan_desc;
+ } else {
+ entry->vlan_desc = NULL;
+ }
entry->opportunistic = 1;
pmksa_cache_link_entry(pmksa, entry);
diff --git a/src/ap/pmksa_cache_auth.h b/src/ap/pmksa_cache_auth.h
index 4dc841f..daf0834 100644
--- a/src/ap/pmksa_cache_auth.h
+++ b/src/ap/pmksa_cache_auth.h
@@ -28,7 +28,7 @@ struct rsn_pmksa_cache_entry {
struct wpabuf *cui;
struct radius_class_data radius_class;
u8 eap_type_authsrv;
- int vlan_id;
+ struct vlan_description *vlan_desc;
int opportunistic;
u64 acct_multi_session_id;
@@ -56,7 +56,8 @@ struct rsn_pmksa_cache_entry *
pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
const struct rsn_pmksa_cache_entry *old_entry,
const u8 *aa, const u8 *pmkid);
-void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
+void pmksa_cache_to_eapol_data(struct hostapd_data *hapd,
+ struct rsn_pmksa_cache_entry *entry,
struct eapol_state_machine *eapol);
void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry);
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 3d7c839..47b35f0 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -34,6 +34,7 @@
#include "wnm_ap.h"
#include "ndisc_snoop.h"
#include "sta_info.h"
+#include "vlan.h"
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
struct sta_info *sta);
@@ -266,6 +267,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
* vlan_remove_dynamic() can check that no stations are left on the
* AP_VLAN netdev.
*/
+ if (sta->vlan_id)
+ vlan_remove_dynamic(hapd, sta->vlan_id);
if (sta->vlan_id_bound) {
/*
* Need to remove the STA entry before potentially removing the
@@ -802,6 +805,78 @@ int ap_sta_wps_cancel(struct hostapd_data *hapd,
#endif /* CONFIG_WPS */
+int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
+ struct vlan_description *vlan_desc)
+{
+ struct hostapd_vlan *vlan = NULL, *wildcard_vlan = NULL;
+ int old_vlan_id, vlan_id = 0, ret = 0;
+
+ if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED) {
+ vlan_desc = NULL;
+ } else if (vlan_desc && vlan_desc->notempty) {
+ if (!vlan_compare(vlan_desc, sta->vlan_desc))
+ return 0; /* nothing to change */
+
+ for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+ if (!vlan_compare(&vlan->vlan_desc, vlan_desc))
+ break;
+ if (vlan->vlan_id == VLAN_ID_WILDCARD)
+ wildcard_vlan = vlan;
+ }
+ if (vlan) {
+ vlan_id = vlan->vlan_id;
+ } else if (wildcard_vlan) {
+ vlan = wildcard_vlan;
+ vlan_id = vlan_desc->untagged;
+ } else {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "missing VLAN and wildcard for vlan=%d",
+ vlan_desc->untagged);
+ vlan_id = 0;
+ ret = -1;
+ goto done;
+ }
+ }
+
+ if (vlan && vlan->vlan_id == VLAN_ID_WILDCARD) {
+ vlan = vlan_add_dynamic(hapd, vlan, vlan_id, vlan_desc);
+ if (vlan == NULL) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "could not add dynamic VLAN interface for vlan=%d",
+ vlan_desc->untagged);
+ vlan_id = 0;
+ ret = -1;
+ goto done;
+ }
+
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "added new dynamic VLAN interface '%s'",
+ vlan->ifname);
+ } else if (vlan && vlan->dynamic_vlan > 0) {
+ vlan->dynamic_vlan++;
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "updated existing dynamic VLAN interface '%s'",
+ vlan->ifname);
+ }
+done:
+ old_vlan_id = sta->vlan_id;
+ sta->vlan_id = vlan_id;
+ sta->vlan_desc = vlan ? &vlan->vlan_desc : NULL;
+
+ if (vlan_id != old_vlan_id && old_vlan_id)
+ vlan_remove_dynamic(hapd, old_vlan_id);
+
+ return ret;
+}
+
+
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
{
#ifndef CONFIG_NO_VLAN
@@ -814,20 +889,11 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
if (hapd->conf->ssid.vlan[0])
iface = hapd->conf->ssid.vlan;
- if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
- sta->vlan_id = 0;
- else if (sta->vlan_id > 0) {
- struct hostapd_vlan *wildcard_vlan = NULL;
- vlan = hapd->conf->vlan;
- while (vlan) {
+ if (sta->vlan_id > 0) {
+ for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
if (vlan->vlan_id == sta->vlan_id)
break;
- if (vlan->vlan_id == VLAN_ID_WILDCARD)
- wildcard_vlan = vlan;
- vlan = vlan->next;
}
- if (!vlan)
- vlan = wildcard_vlan;
if (vlan)
iface = vlan->ifname;
}
@@ -847,24 +913,7 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
sta->vlan_id);
ret = -1;
goto done;
- } else if (sta->vlan_id > 0 && vlan->vlan_id == VLAN_ID_WILDCARD) {
- vlan = vlan_add_dynamic(hapd, vlan, sta->vlan_id);
- if (vlan == NULL) {
- hostapd_logger(hapd, sta->addr,
- HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_DEBUG, "could not add "
- "dynamic VLAN interface for vlan_id=%d",
- sta->vlan_id);
- ret = -1;
- goto done;
- }
-
- iface = vlan->ifname;
- hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN "
- "interface '%s'", iface);
- } else if (vlan && vlan->vlan_id == sta->vlan_id &&
- vlan->dynamic_vlan > 0) {
+ } else if (vlan && vlan->dynamic_vlan > 0) {
vlan->dynamic_vlan++;
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 359f480..c382ffd 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -15,6 +15,7 @@
#endif /* CONFIG_MESH */
#include "list.h"
+#include "vlan.h"
/* STA flags */
#define WLAN_STA_AUTH BIT(0)
@@ -118,6 +119,7 @@ struct sta_info {
struct rsn_preauth_interface *preauth_iface;
int vlan_id; /* 0: none, >0: VID */
+ struct vlan_description *vlan_desc;
int vlan_id_bound; /* updated by ap_sta_bind_vlan() */
/* PSKs from RADIUS authentication server */
struct hostapd_sta_wpa_psk_short *psk;
@@ -220,6 +222,8 @@ int ap_sta_wps_cancel(struct hostapd_data *hapd,
struct sta_info *sta, void *ctx);
#endif /* CONFIG_WPS */
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta);
+int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
+ struct vlan_description *vlan_desc);
void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
diff --git a/src/ap/vlan.c b/src/ap/vlan.c
new file mode 100644
index 0000000..80ae984
--- /dev/null
+++ b/src/ap/vlan.c
@@ -0,0 +1,29 @@
+/*
+ * hostapd / VLAN definition
+ * Copyright (c) 2016, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "ap/vlan.h"
+
+/* compare the two arguments, NULL is treated as empty
+ * return zero iff they are equal
+ */
+int vlan_compare(struct vlan_description *a, struct vlan_description *b)
+{
+ const int a_empty = !a || !a->notempty;
+ const int b_empty = !b || !b->notempty;
+
+ if (a_empty && b_empty)
+ return 0;
+ if (a_empty || b_empty)
+ return 1;
+ if (a->untagged != b->untagged)
+ return 1;
+ return 0;
+}
diff --git a/src/ap/vlan.h b/src/ap/vlan.h
new file mode 100644
index 0000000..e93bbcf
--- /dev/null
+++ b/src/ap/vlan.h
@@ -0,0 +1,27 @@
+/*
+ * hostapd / VLAN definition
+ * Copyright (c) 2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef VLAN_H
+#define VLAN_H
+
+struct vlan_description {
+ int notempty; /* 0 : no vlan information present, 1: else */
+ int untagged; /* >0 802.1q vid */
+};
+
+#ifndef CONFIG_NO_VLAN
+int vlan_compare(struct vlan_description *a, struct vlan_description *b);
+#else /* CONFIG_NO_VLAN */
+static inline int
+vlan_compare(struct vlan_description *a, struct vlan_description *b)
+{
+ return 0;
+}
+#endif /* CONFIG_NO_VLAN */
+
+#endif /* VLAN_H */
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index e3df164..4d93a70 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -630,25 +630,26 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
struct hostapd_vlan *vlan = hapd->conf->vlan;
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
int vlan_naming = hapd->conf->ssid.vlan_naming;
- int clean;
+ int clean, untagged;
wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
while (vlan) {
+ untagged = vlan->vlan_desc.untagged;
if (os_strcmp(ifname, vlan->ifname) == 0 && !vlan->configured) {
vlan->configured = 1;
if (hapd->conf->vlan_bridge[0]) {
os_snprintf(br_name, sizeof(br_name), "%s%d",
hapd->conf->vlan_bridge,
- vlan->vlan_id);
+ untagged);
} else if (tagged_interface) {
os_snprintf(br_name, sizeof(br_name),
"br%s.%d", tagged_interface,
- vlan->vlan_id);
+ untagged);
} else {
os_snprintf(br_name, sizeof(br_name),
- "brvlan%d", vlan->vlan_id);
+ "brvlan%d", untagged);
}
dyn_iface_get(hapd, br_name,
@@ -662,15 +663,15 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
os_snprintf(vlan_ifname,
sizeof(vlan_ifname),
"%s.%d", tagged_interface,
- vlan->vlan_id);
+ untagged);
else
os_snprintf(vlan_ifname,
sizeof(vlan_ifname),
- "vlan%d", vlan->vlan_id);
+ "vlan%d", untagged);
clean = 0;
ifconfig_up(tagged_interface);
- if (!vlan_add(tagged_interface, vlan->vlan_id,
+ if (!vlan_add(tagged_interface, untagged,
vlan_ifname))
clean |= DVLAN_CLEAN_VLAN;
@@ -701,26 +702,27 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
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 clean;
+ int clean, untagged;
wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
first = prev = vlan;
while (vlan) {
+ untagged = vlan->vlan_desc.untagged;
if (os_strcmp(ifname, vlan->ifname) == 0 &&
vlan->configured) {
if (hapd->conf->vlan_bridge[0]) {
os_snprintf(br_name, sizeof(br_name), "%s%d",
hapd->conf->vlan_bridge,
- vlan->vlan_id);
+ untagged);
} else if (tagged_interface) {
os_snprintf(br_name, sizeof(br_name),
"br%s.%d", tagged_interface,
- vlan->vlan_id);
+ untagged);
} else {
os_snprintf(br_name, sizeof(br_name),
- "brvlan%d", vlan->vlan_id);
+ "brvlan%d", untagged);
}
if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
@@ -732,11 +734,11 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
os_snprintf(vlan_ifname,
sizeof(vlan_ifname),
"%s.%d", tagged_interface,
- vlan->vlan_id);
+ untagged);
else
os_snprintf(vlan_ifname,
sizeof(vlan_ifname),
- "vlan%d", vlan->vlan_id);
+ "vlan%d", untagged);
clean = dyn_iface_put(hapd, vlan_ifname);
@@ -1037,13 +1039,13 @@ void vlan_deinit(struct hostapd_data *hapd)
struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
struct hostapd_vlan *vlan,
- int vlan_id)
+ int vlan_id,
+ struct vlan_description *vlan_desc)
{
struct hostapd_vlan *n = NULL;
char *ifname, *pos;
- if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
- vlan->vlan_id != VLAN_ID_WILDCARD)
+ if (vlan == NULL || vlan->vlan_id != VLAN_ID_WILDCARD)
return NULL;
wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
@@ -1061,6 +1063,8 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
goto free_ifname;
n->vlan_id = vlan_id;
+ if (vlan_desc)
+ n->vlan_desc = *vlan_desc;
n->dynamic_vlan = 1;
os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
@@ -1087,7 +1091,7 @@ int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
{
struct hostapd_vlan *vlan;
- if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
+ if (vlan_id <= 0)
return 1;
wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)",
diff --git a/src/ap/vlan_init.h b/src/ap/vlan_init.h
index aeb2dc6..d17c82c 100644
--- a/src/ap/vlan_init.h
+++ b/src/ap/vlan_init.h
@@ -15,7 +15,8 @@ int vlan_init(struct hostapd_data *hapd);
void vlan_deinit(struct hostapd_data *hapd);
struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
struct hostapd_vlan *vlan,
- int vlan_id);
+ int vlan_id,
+ struct vlan_description *vlan_desc);
int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id);
#else /* CONFIG_NO_VLAN */
static inline int vlan_init(struct hostapd_data *hapd)
@@ -27,9 +28,9 @@ static inline void vlan_deinit(struct hostapd_data *hapd)
{
}
-static inline struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
- struct hostapd_vlan *vlan,
- int vlan_id)
+static inline struct hostapd_vlan *
+vlan_add_dynamic(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
+ int vlan_id, struct vlan_description *vlan_desc)
{
return NULL;
}
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 52ccac3..a3eb521 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -712,11 +712,13 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
}
}
if (sm->pmksa && pmkid) {
+ struct vlan_description *vlan_desc;
+
+ vlan_desc = sm->pmksa->vlan_desc;
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "PMKID found from PMKSA cache "
- "eap_type=%d vlan_id=%d",
+ "PMKID found from PMKSA cache eap_type=%d vlan=%d",
sm->pmksa->eap_type_authsrv,
- sm->pmksa->vlan_id);
+ vlan_desc ? vlan_desc->untagged : 0);
os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN);
}