]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
VLAN assignment based on used WPA/WPA2 passphrase/PSK
authorJouni Malinen <jouni@codeaurora.org>
Thu, 14 Feb 2019 11:34:33 +0000 (13:34 +0200)
committerJouni Malinen <j@w1.fi>
Thu, 14 Feb 2019 11:36:54 +0000 (13:36 +0200)
Extend wpa_psk_file to allow an optional VLAN ID to be specified with
"vlanid=<VLAN ID>" prefix on the line. If VLAN ID is specified and the
particular wpa_psk_file entry is used for a station, that station is
bound to the specified VLAN. This can be used to operate a single
WPA2-Personal BSS with multiple VLANs based on the used passphrase/PSK.
This is similar to the WPA2-Enterprise case where the RADIUS server can
assign stations to different VLANs.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
hostapd/hostapd.conf
hostapd/hostapd.wpa_psk
src/ap/ap_config.c
src/ap/ap_config.h
src/ap/wpa_auth.c
src/ap/wpa_auth.h
src/ap/wpa_auth_ft.c
src/ap/wpa_auth_glue.c
wpa_supplicant/ibss_rsn.c
wpa_supplicant/mesh_rsn.c

index ab37f03b54a65a9ff23d11fcb47ca6e0a1fe110a..f3584c5b26bd59a34a72ba16863eed65a0a5c028 100644 (file)
@@ -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
index 834d4413340455787a2a6f7a023eddf74e5f1ba2..166e59e9c64ff5d7b4d53ab08a09a3ec56994e9a 100644 (file)
@@ -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=<keyid_string>
+# An optional VLAN ID can be specified by prefixing the line with
+# vlanid=<VLAN ID>.
 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
index 9611dc0b3fdb30019ee59a0e869922cbdec17b0e..89ba399e9be2d4fc7785b2f1d8df51cc87ad08b4 100644 (file)
@@ -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;
index 6963df460217c95a196392bbc39657e448d93693..ac07b577c3ec4788db18ddc29a4eb30ec38f8c61 100644 (file)
@@ -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);
index 3021a8c9cad0a674b556468ec3298ebd223ad324..02f0ec6a7905a8a4f2c435abf7b259477dd561f2 100644 (file)
@@ -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) {
index e61648d94658320458375ab8126b951c3973b188..4fc4ec3fb665a962874d7e6e14a45b675ddc563f 100644 (file)
@@ -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);
index ac736f062d6b7f3e452d882dd162ec24aba96b4d..31ca4e5d023354676d98bdc2a5fce46af4f859bc 100644 (file)
@@ -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);
 }
 
 
index 9091f43f767ccf98cbbd8c6040b0bacb736bb05c..45172c69a9fadb6798dfbe597bcf2ab6e8aa574f 100644 (file)
@@ -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 */
index 00919d14a55e97949c6e26a5794a411ef211445c..187e951271fc58e78cb21b830556f0e79bf078ee 100644 (file)
@@ -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)
index 04ac7472f661fc5ccfd0288fb1b02cce09c77b1c..64fc52ba1e6de7bca7a04db1d32e187dcbed6d08 100644 (file)
@@ -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);