From: Michael Braun <michael-dev@xxxxxxxxxxxxx> This introduces set_vlan and get_vlan callbacks for wpa_auth and uses them to fetch and configure vlan of sta. The struct vlan_description is converted into a network encoding (struct ft_vlan) for byter order reasons. Signed-off-by: Michael Braun <michael-dev@xxxxxxxxxxxxx> --- src/ap/wpa_auth.h | 18 +++++++- src/ap/wpa_auth_ft.c | 78 ++++++++++++++++++++++++++++------ src/ap/wpa_auth_glue.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 194 insertions(+), 14 deletions(-) diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index ded9441..5ad837a 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -42,12 +42,22 @@ struct ft_rrb_frame { #define FT_PACKET_R0KH_R1KH_RESP 201 #define FT_PACKET_R0KH_R1KH_PUSH 202 +#define FT_MAX_NUM_TAGGED_VLAN 32 +#define FT_VLAN_DATA_LEN sizeof(struct ft_vlan) + #define FT_R0KH_R1KH_PULL_NONCE_LEN 16 #define FT_R0KH_R1KH_PULL_DATA_LEN (FT_R0KH_R1KH_PULL_NONCE_LEN + \ WPA_PMK_NAME_LEN + FT_R1KH_ID_LEN + \ ETH_ALEN) #define FT_R0KH_R1KH_PULL_PAD_LEN (8 - FT_R0KH_R1KH_PULL_DATA_LEN % 8) +struct ft_vlan { + le16 untagged; + le16 tagged[FT_MAX_NUM_TAGGED_VLAN]; /* ordered by value, + * non-zero first + */ +} STRUCT_PACKED; + struct ft_r0kh_r1kh_pull_frame { u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */ u8 packet_type; /* FT_PACKET_R0KH_R1KH_PULL */ @@ -64,7 +74,7 @@ struct ft_r0kh_r1kh_pull_frame { #define FT_R0KH_R1KH_RESP_DATA_LEN (FT_R0KH_R1KH_PULL_NONCE_LEN + \ FT_R1KH_ID_LEN + ETH_ALEN + PMK_LEN + \ - WPA_PMK_NAME_LEN + 2) + WPA_PMK_NAME_LEN + FT_VLAN_DATA_LEN + 2) #define FT_R0KH_R1KH_RESP_PAD_LEN (8 - FT_R0KH_R1KH_RESP_DATA_LEN % 8) struct ft_r0kh_r1kh_resp_frame { u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */ @@ -78,13 +88,14 @@ struct ft_r0kh_r1kh_resp_frame { u8 pmk_r1[PMK_LEN]; u8 pmk_r1_name[WPA_PMK_NAME_LEN]; le16 pairwise; + struct ft_vlan vlan; u8 pad[FT_R0KH_R1KH_RESP_PAD_LEN]; /* 8-octet boundary for AES block */ u8 key_wrap_extra[8]; } STRUCT_PACKED; #define FT_R0KH_R1KH_PUSH_DATA_LEN (4 + FT_R1KH_ID_LEN + ETH_ALEN + \ WPA_PMK_NAME_LEN + PMK_LEN + \ - WPA_PMK_NAME_LEN + 2) + WPA_PMK_NAME_LEN + FT_VLAN_DATA_LEN + 2) #define FT_R0KH_R1KH_PUSH_PAD_LEN (8 - FT_R0KH_R1KH_PUSH_DATA_LEN % 8) struct ft_r0kh_r1kh_push_frame { u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */ @@ -101,6 +112,7 @@ struct ft_r0kh_r1kh_push_frame { u8 pmk_r1[PMK_LEN]; u8 pmk_r1_name[WPA_PMK_NAME_LEN]; le16 pairwise; + struct ft_vlan vlan; u8 pad[FT_R0KH_R1KH_PUSH_PAD_LEN]; /* 8-octet boundary for AES block */ u8 key_wrap_extra[8]; } STRUCT_PACKED; @@ -222,6 +234,8 @@ struct wpa_auth_callbacks { size_t data_len); #ifdef CONFIG_IEEE80211R struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr); + int (*set_vlan)(void *ctx, const u8 *sta_addr, struct ft_vlan *vlan); + int (*get_vlan)(void *ctx, const u8 *sta_addr, struct ft_vlan *vlan); int (*send_ft_action)(void *ctx, const u8 *dst, const u8 *data, size_t data_len); int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie, diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index 42242a5..f600aa7 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -60,6 +60,26 @@ wpa_ft_add_sta(struct wpa_authenticator *wpa_auth, const u8 *sta_addr) } +static int +wpa_ft_set_vlan(struct wpa_authenticator *wpa_auth, const u8 *sta_addr, + struct ft_vlan *vlan) +{ + if (wpa_auth->cb.set_vlan == NULL) + return -1; + return wpa_auth->cb.set_vlan(wpa_auth->cb.ctx, sta_addr, vlan); +} + + +static int +wpa_ft_get_vlan(struct wpa_authenticator *wpa_auth, const u8 *sta_addr, + struct ft_vlan *vlan) +{ + if (wpa_auth->cb.get_vlan == NULL) + return -1; + return wpa_auth->cb.get_vlan(wpa_auth->cb.ctx, sta_addr, vlan); +} + + static int wpa_ft_add_tspec(struct wpa_authenticator *wpa_auth, const u8 *sta_addr, u8 *tspec_ie, size_t tspec_ielen) @@ -148,7 +168,8 @@ struct wpa_ft_pmk_r0_sa { u8 pmk_r0_name[WPA_PMK_NAME_LEN]; u8 spa[ETH_ALEN]; int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */ - /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */ + struct ft_vlan vlan; + /* TODO: expiration, identity, radius_class, EAP type */ int pmk_r1_pushed; }; @@ -158,7 +179,8 @@ struct wpa_ft_pmk_r1_sa { u8 pmk_r1_name[WPA_PMK_NAME_LEN]; u8 spa[ETH_ALEN]; int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */ - /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */ + struct ft_vlan vlan; + /* TODO: expiration, identity, radius_class, EAP type */ }; struct wpa_ft_pmk_cache { @@ -203,7 +225,8 @@ void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache) static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth, const u8 *spa, const u8 *pmk_r0, - const u8 *pmk_r0_name, int pairwise) + const u8 *pmk_r0_name, int pairwise, + const struct ft_vlan vlan) { struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache; struct wpa_ft_pmk_r0_sa *r0; @@ -218,6 +241,7 @@ static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth, os_memcpy(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN); os_memcpy(r0->spa, spa, ETH_ALEN); r0->pairwise = pairwise; + os_memcpy(&r0->vlan, &vlan, FT_VLAN_DATA_LEN); r0->next = cache->pmk_r0; cache->pmk_r0 = r0; @@ -228,7 +252,8 @@ static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth, static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth, const u8 *spa, const u8 *pmk_r0_name, - u8 *pmk_r0, int *pairwise) + u8 *pmk_r0, int *pairwise, + struct ft_vlan *vlan) { struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache; struct wpa_ft_pmk_r0_sa *r0; @@ -241,6 +266,8 @@ static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth, os_memcpy(pmk_r0, r0->pmk_r0, PMK_LEN); if (pairwise) *pairwise = r0->pairwise; + if (vlan) + os_memcpy(vlan, &r0->vlan, FT_VLAN_DATA_LEN); return 0; } @@ -253,7 +280,8 @@ static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth, static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *spa, const u8 *pmk_r1, - const u8 *pmk_r1_name, int pairwise) + const u8 *pmk_r1_name, int pairwise, + const struct ft_vlan vlan) { struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache; struct wpa_ft_pmk_r1_sa *r1; @@ -268,6 +296,7 @@ static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth, os_memcpy(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN); os_memcpy(r1->spa, spa, ETH_ALEN); r1->pairwise = pairwise; + os_memcpy(&r1->vlan, &vlan, FT_VLAN_DATA_LEN); r1->next = cache->pmk_r1; cache->pmk_r1 = r1; @@ -278,7 +307,8 @@ static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth, static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *spa, const u8 *pmk_r1_name, - u8 *pmk_r1, int *pairwise) + u8 *pmk_r1, int *pairwise, + struct ft_vlan *vlan) { struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache; struct wpa_ft_pmk_r1_sa *r1; @@ -291,6 +321,8 @@ static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth, os_memcpy(pmk_r1, r1->pmk_r1, PMK_LEN); if (pairwise) *pairwise = r1->pairwise; + if (vlan) + os_memcpy(vlan, &r1->vlan, FT_VLAN_DATA_LEN); return 0; } @@ -373,6 +405,7 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, const u8 *r1kh = sm->wpa_auth->conf.r1_key_holder; const u8 *ssid = sm->wpa_auth->conf.ssid; size_t ssid_len = sm->wpa_auth->conf.ssid_len; + struct ft_vlan vlan; if (sm->xxkey_len == 0) { wpa_printf(MSG_DEBUG, "FT: XXKey not available for key " @@ -380,12 +413,18 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, return -1; } + if (wpa_ft_get_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) { + wpa_printf(MSG_DEBUG, "FT: vlan not available for STA " MACSTR, + MAC2STR(sm->addr)); + return -1; + } + wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid, r0kh, r0kh_len, sm->addr, pmk_r0, pmk_r0_name); wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, PMK_LEN); wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN); wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_name, - sm->pairwise); + sm->pairwise, vlan); wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr, pmk_r1, sm->pmk_r1_name); @@ -393,7 +432,7 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name, WPA_PMK_NAME_LEN); wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, sm->pmk_r1_name, - sm->pairwise); + sm->pairwise, vlan); return wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr, sm->wpa_auth->addr, sm->pmk_r1_name, @@ -809,6 +848,7 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm, int ret; u8 *pos, *end; int pairwise; + struct ft_vlan vlan; *resp_ies = NULL; *resp_ies_len = 0; @@ -865,7 +905,7 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm, pmk_r1_name, WPA_PMK_NAME_LEN); if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, pmk_r1, - &pairwise) < 0) { + &pairwise, &vlan) < 0) { if (wpa_ft_pull_pmk_r1(sm, ies, ies_len, parse.rsn_pmkid) < 0) { wpa_printf(MSG_DEBUG, "FT: Did not have matching " "PMK-R1 and unknown R0KH-ID"); @@ -900,6 +940,11 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm, sm->PTK_valid = TRUE; wpa_ft_install_ptk(sm); + if (wpa_ft_set_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) { + wpa_printf(MSG_DEBUG, "FT: Failed to configure VLAN"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) + 2 + FT_R1KH_ID_LEN + 200; *resp_ies = os_zalloc(buflen); @@ -1317,6 +1362,7 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, struct ft_r0kh_r1kh_resp_frame resp, r; u8 pmk_r0[PMK_LEN]; int pairwise; + struct ft_vlan vlan; wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull"); @@ -1368,7 +1414,7 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, os_memcpy(r.r1kh_id, f.r1kh_id, FT_R1KH_ID_LEN); os_memcpy(r.s1kh_id, f.s1kh_id, ETH_ALEN); if (wpa_ft_fetch_pmk_r0(wpa_auth, f.s1kh_id, f.pmk_r0_name, pmk_r0, - &pairwise) < 0) { + &pairwise, &vlan) < 0) { wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name found for " "PMK-R1 pull"); return -1; @@ -1380,6 +1426,7 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name, WPA_PMK_NAME_LEN); r.pairwise = host_to_le16(pairwise); + os_memcpy(&r.vlan, &vlan, FT_VLAN_DATA_LEN); os_memset(r.pad, 0, sizeof(r.pad)); if (aes_wrap(r1kh->key, sizeof(r1kh->key), @@ -1500,9 +1547,12 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth, f.pmk_r1, PMK_LEN); wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR1Name", f.pmk_r1_name, WPA_PMK_NAME_LEN); + wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - vlan %d%s", + le_to_host16(f.vlan.untagged), + f.vlan.tagged[0] ? "+" : ""); res = wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name, - pairwise); + pairwise, f.vlan); wpa_printf(MSG_DEBUG, "FT: Look for pending pull request"); wpa_auth_for_each_sta(wpa_auth, ft_pull_resp_cb, &f); os_memset(f.pmk_r1, 0, PMK_LEN); @@ -1582,9 +1632,12 @@ static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth, f.pmk_r1, PMK_LEN); wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 push - PMKR1Name", f.pmk_r1_name, WPA_PMK_NAME_LEN); + wpa_printf(MSG_DEBUG, "FT: PMK-R1 push - vlan %d%s", + le_to_host16(f.vlan.untagged), + f.vlan.tagged[0] ? "+" : ""); wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name, - pairwise); + pairwise, f.vlan); os_memset(f.pmk_r1, 0, PMK_LEN); return 0; @@ -1746,6 +1799,7 @@ static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth, os_get_time(&now); WPA_PUT_LE32(f.timestamp, now.sec); f.pairwise = host_to_le16(pairwise); + f.vlan = pmk_r0->vlan; os_memset(f.pad, 0, sizeof(f.pad)); plain = ((const u8 *) &f) + offsetof(struct ft_r0kh_r1kh_push_frame, timestamp); diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index ffd0790..8dbc2c4 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -553,6 +553,116 @@ hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr) } +/* sanity check for vlan definitions */ +#if FT_MAX_NUM_TAGGED_VLAN != MAX_NUM_TAGGED_VLAN +#error FT_MAX_NUM_TAGGED_VLAN and MAX_NUM_TAGGED_VLAN differ +#endif + +static void hostapd_wpa_vlan_to_ft(struct ft_vlan *ft_vlan, + struct vlan_description *vlan_desc) +{ + int i; + + os_memset(ft_vlan, 0, sizeof(*ft_vlan)); + + if (!vlan_desc) + return; + + ft_vlan->untagged = host_to_le16(vlan_desc->untagged); + for (i = 0; + i < FT_MAX_NUM_TAGGED_VLAN && i < MAX_NUM_TAGGED_VLAN; + i++) { + if (!vlan_desc->tagged[i]) + break; + ft_vlan->tagged[i] = host_to_le16(vlan_desc->tagged[i]); + } +} + + +static int hostapd_wpa_ft_to_vlan(struct hostapd_data *hapd, + struct vlan_description *vlan_desc, + struct ft_vlan *ft_vlan) +{ + int i; + + /* convert ft_vlan into vlan_description */ + os_memset(vlan_desc, 0, sizeof(*vlan_desc)); + + if (!ft_vlan) + return 0; + + vlan_desc->untagged = le_to_host16(ft_vlan->untagged); + for (i = 0; + i < FT_MAX_NUM_TAGGED_VLAN && i < MAX_NUM_TAGGED_VLAN; + i++) { + if (!ft_vlan->tagged[i]) + break; + vlan_desc->tagged[i] = le_to_host16(ft_vlan->tagged[i]); + } + vlan_desc->notempty = vlan_desc->untagged || vlan_desc->tagged[0]; + + /* fail early so that does not get connected if invalid vlan */ + if (vlan_desc->notempty && + !hostapd_vlan_valid(hapd->conf->vlan, vlan_desc)) + return -1; + return 0; +} + + +static int hostapd_wpa_auth_set_vlan(void *ctx, const u8 *sta_addr, + struct ft_vlan *ft_vlan) +{ + struct hostapd_data *hapd = ctx; + struct sta_info *sta; + struct vlan_description vlan_desc; + + sta = ap_get_sta(hapd, sta_addr); + if (sta == NULL) + return -1; + + if (!sta->wpa_sm) + return -1; + + if (hostapd_wpa_ft_to_vlan(hapd, &vlan_desc, ft_vlan) < 0) { + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, "Invalid VLAN " + "%d%s received from FT", + vlan_desc.untagged, + vlan_desc.tagged[0] ? "+" : ""); + return -1; + } + + if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0) + return -1; + /* configure wpa_group for GTK but ignore error due to driver not + * knowing this sta + */ + ap_sta_bind_vlan(hapd, sta); + + if (sta->vlan_id) + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id); + + return 0; +} + + +static int +hostapd_wpa_auth_get_vlan(void *ctx, const u8 *sta_addr, + struct ft_vlan *ft_vlan) +{ + struct hostapd_data *hapd = ctx; + struct sta_info *sta; + + sta = ap_get_sta(hapd, sta_addr); + if (sta == NULL) + return -1; + + hostapd_wpa_vlan_to_ft(ft_vlan, sta->vlan_desc); + return 0; +} + + static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) { @@ -609,6 +719,8 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) #ifdef CONFIG_IEEE80211R cb.send_ft_action = hostapd_wpa_auth_send_ft_action; cb.add_sta = hostapd_wpa_auth_add_sta; + cb.set_vlan = hostapd_wpa_auth_set_vlan; + cb.get_vlan = hostapd_wpa_auth_get_vlan; cb.add_tspec = hostapd_wpa_auth_add_tspec; #endif /* CONFIG_IEEE80211R */ hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb); -- 1.9.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap