diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index ab37f03b5..f3584c5b2 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1174,6 +1174,8 @@ own_ip_addr=127.0.0.1 # Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value # VLANID as a string). Optionally, the local MAC ACL list (accept_mac_file) can # be used to set static client MAC address to VLAN ID mapping. +# Dynamic VLAN mode is also used with VLAN ID assignment based on WPA/WPA2 +# passphrase from wpa_psk_file. # 0 = disabled (default); only VLAN IDs from accept_mac_file will be used # 1 = optional; use default interface if RADIUS server does not include VLAN ID # 2 = required; reject authentication if RADIUS server does not include VLAN ID diff --git a/hostapd/hostapd.wpa_psk b/hostapd/hostapd.wpa_psk index 834d44133..166e59e9c 100644 --- a/hostapd/hostapd.wpa_psk +++ b/hostapd/hostapd.wpa_psk @@ -5,8 +5,11 @@ # characters or as a 256-bit hex PSK (64 hex digits). # An optional key identifier can be added by prefixing the line with # keyid= +# An optional VLAN ID can be specified by prefixing the line with +# vlanid=. 00:00:00:00:00:00 secret passphrase 00:11:22:33:44:55 another passphrase 00:22:33:44:55:66 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef keyid=example_id 00:11:22:33:44:77 passphrase with keyid +vlanid=3 00:00:00:00:00:00 passphrase with vlanid 00:00:00:00:00:00 another passphrase for all STAs diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 9611dc0b3..89ba399e9 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -279,6 +279,8 @@ static int hostapd_config_read_wpa_psk(const char *fname, } while (fgets(buf, sizeof(buf), f)) { + int vlan_id = 0; + line++; if (buf[0] == '#') @@ -306,6 +308,8 @@ static int hostapd_config_read_wpa_psk(const char *fname, value = ""; if (!os_strcmp(name, "keyid")) { keyid = value; + } else if (!os_strcmp(name, "vlanid")) { + vlan_id = atoi(value); } else { wpa_printf(MSG_ERROR, "Unrecognized '%s=%s' on line %d in '%s'", @@ -333,6 +337,7 @@ static int hostapd_config_read_wpa_psk(const char *fname, ret = -1; break; } + psk->vlan_id = vlan_id; if (is_zero_ether_addr(addr)) psk->group = 1; else @@ -858,11 +863,14 @@ const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id) const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf, const u8 *addr, const u8 *p2p_dev_addr, - const u8 *prev_psk) + const u8 *prev_psk, int *vlan_id) { struct hostapd_wpa_psk *psk; int next_ok = prev_psk == NULL; + if (vlan_id) + *vlan_id = 0; + if (p2p_dev_addr && !is_zero_ether_addr(p2p_dev_addr)) { wpa_printf(MSG_DEBUG, "Searching a PSK for " MACSTR " p2p_dev_addr=" MACSTR " prev_psk=%p", @@ -880,8 +888,11 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf, (addr && os_memcmp(psk->addr, addr, ETH_ALEN) == 0) || (!addr && p2p_dev_addr && os_memcmp(psk->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) == - 0))) + 0))) { + if (vlan_id) + *vlan_id = psk->vlan_id; return psk->psk; + } if (psk->psk == prev_psk) next_ok = 1; diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 6963df460..ac07b577c 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -152,6 +152,7 @@ struct hostapd_wpa_psk { u8 psk[PMK_LEN]; u8 addr[ETH_ALEN]; u8 p2p_dev_addr[ETH_ALEN]; + int vlan_id; }; struct hostapd_eap_user { @@ -872,7 +873,7 @@ int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries, 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); + const u8 *prev_psk, int *vlan_id); int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf); int hostapd_vlan_valid(struct hostapd_vlan *vlan, struct vlan_description *vlan_desc); diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 3021a8c9c..02f0ec6a7 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -114,12 +114,13 @@ static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth, static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth, const u8 *addr, const u8 *p2p_dev_addr, - const u8 *prev_psk, size_t *psk_len) + const u8 *prev_psk, size_t *psk_len, + int *vlan_id) { if (wpa_auth->cb->get_psk == NULL) return NULL; return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr, - prev_psk, psk_len); + prev_psk, psk_len, vlan_id); } @@ -251,6 +252,15 @@ static int wpa_channel_info(struct wpa_authenticator *wpa_auth, #endif /* CONFIG_OCV */ +static int wpa_auth_update_vlan(struct wpa_authenticator *wpa_auth, + const u8 *addr, int vlan_id) +{ + if (!wpa_auth->cb->update_vlan) + return -1; + return wpa_auth->cb->update_vlan(wpa_auth->cb_ctx, addr, vlan_id); +} + + static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx) { struct wpa_authenticator *wpa_auth = eloop_ctx; @@ -852,13 +862,15 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data, int ok = 0; const u8 *pmk = NULL; size_t pmk_len; + int vlan_id = 0; os_memset(&PTK, 0, sizeof(PTK)); for (;;) { if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) && !wpa_key_mgmt_sae(sm->wpa_key_mgmt)) { pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, - sm->p2p_dev_addr, pmk, &pmk_len); + sm->p2p_dev_addr, pmk, &pmk_len, + &vlan_id); if (pmk == NULL) break; #ifdef CONFIG_IEEE80211R_AP @@ -897,6 +909,11 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data, wpa_printf(MSG_DEBUG, "WPA: Earlier SNonce resulted in matching MIC"); sm->alt_snonce_valid = 0; + + if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) && + wpa_auth_update_vlan(sm->wpa_auth, sm->addr, vlan_id) < 0) + return -1; + os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN); os_memcpy(&sm->PTK, &PTK, sizeof(PTK)); sm->PTK_valid = TRUE; @@ -2024,7 +2041,7 @@ SM_STATE(WPA_PTK, INITPSK) SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk); psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL, - &psk_len); + &psk_len, NULL); if (psk) { os_memcpy(sm->PMK, psk, psk_len); sm->pmk_len = psk_len; @@ -2712,6 +2729,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) struct ieee802_1x_hdr *hdr; struct wpa_eapol_key *key; struct wpa_eapol_ie_parse kde; + int vlan_id; SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk); sm->EAPOLKeyReceived = FALSE; @@ -2727,7 +2745,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) && !wpa_key_mgmt_sae(sm->wpa_key_mgmt)) { pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, - sm->p2p_dev_addr, pmk, &pmk_len); + sm->p2p_dev_addr, pmk, &pmk_len, + &vlan_id); if (pmk == NULL) break; psk_found = 1; @@ -2896,6 +2915,13 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) } #endif /* CONFIG_IEEE80211R_AP */ + if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) && + wpa_auth_update_vlan(wpa_auth, sm->addr, vlan_id) < 0) { + wpa_sta_disconnect(wpa_auth, sm->addr, + WLAN_REASON_PREV_AUTH_NOT_VALID); + return; + } + sm->pending_1_of_4_timeout = 0; eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm); @@ -3335,7 +3361,7 @@ SM_STEP(WPA_PTK) break; case WPA_PTK_INITPSK: if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, - NULL, NULL)) { + NULL, NULL, NULL)) { SM_ENTER(WPA_PTK, PTKSTART); #ifdef CONFIG_SAE } else if (wpa_auth_uses_sae(sm) && sm->pmksa) { diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index e61648d94..4fc4ec3fb 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -254,7 +254,8 @@ struct wpa_auth_callbacks { int value); int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var); const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *p2p_dev_addr, - const u8 *prev_psk, size_t *psk_len); + const u8 *prev_psk, size_t *psk_len, + int *vlan_id); int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len); int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg, const u8 *addr, int idx, u8 *key, size_t key_len); @@ -270,6 +271,7 @@ struct wpa_auth_callbacks { int (*send_oui)(void *ctx, const u8 *dst, u8 oui_suffix, const u8 *data, size_t data_len); int (*channel_info)(void *ctx, struct wpa_channel_info *ci); + int (*update_vlan)(void *ctx, const u8 *addr, int vlan_id); int (*get_sta_tx_params)(void *ctx, const u8 *addr, int ap_max_chanwidth, int ap_seg1_idx, int *bandwidth, int *seg1_idx); diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index ac736f062..31ca4e5d0 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -620,7 +620,7 @@ static const u8 * wpa_ft_get_psk(struct wpa_authenticator *wpa_auth, if (wpa_auth->cb->get_psk == NULL) return NULL; return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr, - prev_psk, NULL); + prev_psk, NULL, NULL); } diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index 9091f43f7..45172c69a 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -246,12 +246,15 @@ static int hostapd_wpa_auth_get_eapol(void *ctx, const u8 *addr, static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr, const u8 *p2p_dev_addr, - const u8 *prev_psk, size_t *psk_len) + const u8 *prev_psk, size_t *psk_len, + int *vlan_id) { struct hostapd_data *hapd = ctx; struct sta_info *sta = ap_get_sta(hapd, addr); const u8 *psk; + if (vlan_id) + *vlan_id = 0; if (psk_len) *psk_len = PMK_LEN; @@ -287,7 +290,8 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr, } #endif /* CONFIG_OWE */ - psk = hostapd_get_psk(hapd->conf, addr, p2p_dev_addr, prev_psk); + psk = hostapd_get_psk(hapd->conf, addr, p2p_dev_addr, prev_psk, + vlan_id); /* * This is about to iterate over all psks, prev_psk gives the last * returned psk which should not be returned again. @@ -295,6 +299,9 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr, */ if (sta && sta->psk && !psk) { struct hostapd_sta_wpa_psk_short *pos; + + if (vlan_id) + *vlan_id = 0; psk = sta->psk->psk; for (pos = sta->psk; pos; pos = pos->next) { if (pos->is_passphrase) { @@ -788,6 +795,45 @@ static int hostapd_channel_info(void *ctx, struct wpa_channel_info *ci) } +static int hostapd_wpa_auth_update_vlan(void *ctx, const u8 *addr, int vlan_id) +{ +#ifndef CONFIG_NO_VLAN + struct hostapd_data *hapd = ctx; + struct sta_info *sta; + struct vlan_description vlan_desc; + + sta = ap_get_sta(hapd, addr); + if (!sta) + return -1; + + os_memset(&vlan_desc, 0, sizeof(vlan_desc)); + vlan_desc.notempty = 1; + vlan_desc.untagged = vlan_id; + if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) { + wpa_printf(MSG_INFO, "Invalid VLAN ID %d in wpa_psk_file", + vlan_id); + return -1; + } + + if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0) { + wpa_printf(MSG_INFO, + "Failed to assign VLAN ID %d from wpa_psk_file to " + MACSTR, vlan_id, MAC2STR(sta->addr)); + return -1; + } + + wpa_printf(MSG_INFO, + "Assigned VLAN ID %d from wpa_psk_file to " MACSTR, + vlan_id, MAC2STR(sta->addr)); + if ((sta->flags & WLAN_STA_ASSOC) && + ap_sta_bind_vlan(hapd, sta) < 0) + return -1; +#endif /* CONFIG_NO_VLAN */ + + return 0; +} + + #ifdef CONFIG_OCV static int hostapd_get_sta_tx_params(void *ctx, const u8 *addr, int ap_max_chanwidth, int ap_seg1_idx, @@ -1229,6 +1275,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) .send_ether = hostapd_wpa_auth_send_ether, .send_oui = hostapd_wpa_auth_send_oui, .channel_info = hostapd_channel_info, + .update_vlan = hostapd_wpa_auth_update_vlan, #ifdef CONFIG_OCV .get_sta_tx_params = hostapd_get_sta_tx_params, #endif /* CONFIG_OCV */ diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c index 00919d14a..187e95127 100644 --- a/wpa_supplicant/ibss_rsn.c +++ b/wpa_supplicant/ibss_rsn.c @@ -260,12 +260,14 @@ static void auth_logger(void *ctx, const u8 *addr, logger_level level, static const u8 * auth_get_psk(void *ctx, const u8 *addr, const u8 *p2p_dev_addr, const u8 *prev_psk, - size_t *psk_len) + size_t *psk_len, int *vlan_id) { struct ibss_rsn *ibss_rsn = ctx; if (psk_len) *psk_len = PMK_LEN; + if (vlan_id) + *vlan_id = 0; wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)", __func__, MAC2STR(addr), prev_psk); if (prev_psk) diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c index 04ac7472f..64fc52ba1 100644 --- a/wpa_supplicant/mesh_rsn.c +++ b/wpa_supplicant/mesh_rsn.c @@ -76,7 +76,7 @@ static void auth_logger(void *ctx, const u8 *addr, logger_level level, static const u8 *auth_get_psk(void *ctx, const u8 *addr, const u8 *p2p_dev_addr, const u8 *prev_psk, - size_t *psk_len) + size_t *psk_len, int *vlan_id) { struct mesh_rsn *mesh_rsn = ctx; struct hostapd_data *hapd = mesh_rsn->wpa_s->ifmsh->bss[0]; @@ -84,6 +84,8 @@ static const u8 *auth_get_psk(void *ctx, const u8 *addr, if (psk_len) *psk_len = PMK_LEN; + if (vlan_id) + *vlan_id = 0; wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)", __func__, MAC2STR(addr), prev_psk);