diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 2eb72055f..900d81131 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2641,6 +2641,14 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->r0_key_lifetime = atoi(pos); } else if (os_strcmp(buf, "reassociation_deadline") == 0) { bss->reassociation_deadline = atoi(pos); + } else if (os_strcmp(buf, "rkh_pos_timeout") == 0) { + bss->rkh_pos_timeout = atoi(pos); + } else if (os_strcmp(buf, "rkh_neg_timeout") == 0) { + bss->rkh_neg_timeout = atoi(pos); + } else if (os_strcmp(buf, "rkh_pull_timeout") == 0) { + bss->rkh_pull_timeout = atoi(pos); + } else if (os_strcmp(buf, "rkh_pull_retries") == 0) { + bss->rkh_pull_retries = atoi(pos); } else if (os_strcmp(buf, "r0kh") == 0) { if (add_r0kh(bss, pos) < 0) { wpa_printf(MSG_DEBUG, "Line %d: Invalid r0kh '%s'", diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index c5ba0e9cd..135715eb4 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1459,6 +1459,11 @@ own_ip_addr=127.0.0.1 #r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f #r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff # And so on.. One line per R0KH. +# Wildcard entry: +# Upon receiving a response from R0KH, it will be added to this list, so +# subsequent requests won't be broadcast. If R0KH does not reply, it will be +# blacklisted. +#r0kh=ff:ff:ff:ff:ff:ff * 00112233445566778899aabbccddeeff # List of R1KHs in the same Mobility Domain # format: <256-bit key as hex string> @@ -1468,6 +1473,25 @@ own_ip_addr=127.0.0.1 #r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f #r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff # And so on.. One line per R1KH. +# Wildcard entry: +# Upon receiving a request from an R1KH not yet known, it will be added to this +# list and thus will receive push notifications. +#r1kh=00:00:00:00:00:00 00:00:00:00:00:00 00112233445566778899aabbccddeeff + +# Timeout (seconds) for newly discovered R0KH/R1KH (see wildcard entries above) +# Special values: 0 -> do not expire +# Warning: do not cache implies no sequence number validation with wildcards +#rkh_pos_timeout=86400 (default = 1 day) + +# Timeout (milliseconds) for requesting PMK-R1 from R0KH using PULL request +# and number of retries. +#rkh_pull_timeout=1000 (default = 1 second) +#rkh_pull_retries=4 (default) + +# Timeout (seconds) for non replying R0KH (see wildcard entries above) +# Special values: 0 -> do not cache +# default: 60 seconds +#rkh_neg_timeout=60 # Note: The R0KH/R1KH keys used to be 128-bit in length before the message # format was changed. That shorter key length is still supported for backwards diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 6b3d4e862..09cbec3b3 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -93,6 +93,10 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) #ifdef CONFIG_IEEE80211R_AP bss->ft_over_ds = 1; + bss->rkh_pos_timeout = 86400; + bss->rkh_neg_timeout = 60; + bss->rkh_pull_timeout = 1000; + bss->rkh_pull_retries = 4; #endif /* CONFIG_IEEE80211R_AP */ bss->radius_das_time_window = 300; diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 498891c54..849c69d92 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -342,6 +342,10 @@ struct hostapd_bss_config { u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; u8 r1_key_holder[FT_R1KH_ID_LEN]; u32 r0_key_lifetime; + int rkh_pos_timeout; + int rkh_neg_timeout; + int rkh_pull_timeout; /* ms */ + int rkh_pull_retries; u32 reassociation_deadline; struct ft_remote_r0kh *r0kh_list; struct ft_remote_r1kh *r1kh_list; diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 9fceca65d..1f5885eea 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -706,6 +706,9 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm) sm->pending_1_of_4_timeout = 0; eloop_cancel_timeout(wpa_sm_call_step, sm, NULL); eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm); +#ifdef CONFIG_IEEE80211R_AP + wpa_ft_sta_deinit(sm); +#endif /* CONFIG_IEEE80211R_AP */ if (sm->in_step_loop) { /* Must not free state machine while wpa_sm_step() is running. * Freeing will be completed in the end of wpa_sm_step(). */ diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index bab56191b..5f8bb8726 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -103,7 +103,8 @@ struct ft_rrb_seq { * auth: * required: SEQ, NONCE, R0KH_ID, R1KH_ID * encrypted: - * required: S1KH_ID, session TLVs + * required: S1KH_ID + * optional: session TLVs * * push frame TLVs: * auth: @@ -185,9 +186,13 @@ struct wpa_auth_config { size_t r0_key_holder_len; u8 r1_key_holder[FT_R1KH_ID_LEN]; u32 r0_key_lifetime; + int rkh_pos_timeout; + int rkh_neg_timeout; + int rkh_pull_timeout; /* ms */ + int rkh_pull_retries; u32 reassociation_deadline; - struct ft_remote_r0kh *r0kh_list; - struct ft_remote_r1kh *r1kh_list; + struct ft_remote_r0kh **r0kh_list; + struct ft_remote_r1kh **r1kh_list; int pmk_r1_push; int ft_over_ds; int ft_psk_generate_local; @@ -370,6 +375,7 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, size_t data_len); void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr); void wpa_ft_deinit(struct wpa_authenticator *wpa_auth); +void wpa_ft_sta_deinit(struct wpa_state_machine *sm); #endif /* CONFIG_IEEE80211R_AP */ void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm); diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index 9db9b26c6..b73ea9944 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -34,6 +34,8 @@ static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm, const u8 *current_ap, const u8 *sta_addr, u16 status, const u8 *resp_ies, size_t resp_ies_len); +static void ft_finish_pull(struct wpa_state_machine *sm); +static void wpa_ft_expire_pull(void *eloop_ctx, void *timeout_ctx); static void wpa_ft_rrb_seq_timeout(void *eloop_ctx, void *timeout_ctx); struct tlv_list { @@ -1008,21 +1010,27 @@ static int wpa_ft_rrb_init_r0kh_seq(struct ft_remote_r0kh *r0kh) static void wpa_ft_rrb_lookup_r0kh(struct wpa_authenticator *wpa_auth, const u8 *f_r0kh_id, size_t f_r0kh_id_len, - struct ft_remote_r0kh **r0kh_out) + struct ft_remote_r0kh **r0kh_out, + struct ft_remote_r0kh **r0kh_wildcard) { struct ft_remote_r0kh *r0kh; + *r0kh_wildcard = NULL; *r0kh_out = NULL; - for (r0kh = wpa_auth->conf.r0kh_list; r0kh; r0kh = r0kh->next) { + if (wpa_auth->conf.r0kh_list) + r0kh = *wpa_auth->conf.r0kh_list; + else + r0kh = NULL; + for (; r0kh; r0kh = r0kh->next) { + if (r0kh->id_len == 1 && r0kh->id[0] == '*') + *r0kh_wildcard = r0kh; if (f_r0kh_id && r0kh->id_len == f_r0kh_id_len && - os_memcmp_const(f_r0kh_id, r0kh->id, f_r0kh_id_len) == 0) { + os_memcmp_const(f_r0kh_id, r0kh->id, f_r0kh_id_len) == 0) *r0kh_out = r0kh; - break; - } } - if (!*r0kh_out) + if (!*r0kh_out && !*r0kh_wildcard) wpa_printf(MSG_DEBUG, "FT: No matching R0KH found"); if (*r0kh_out && wpa_ft_rrb_init_r0kh_seq(*r0kh_out) < 0) @@ -1049,21 +1057,28 @@ static int wpa_ft_rrb_init_r1kh_seq(struct ft_remote_r1kh *r1kh) static void wpa_ft_rrb_lookup_r1kh(struct wpa_authenticator *wpa_auth, const u8 *f_r1kh_id, - struct ft_remote_r1kh **r1kh_out) + struct ft_remote_r1kh **r1kh_out, + struct ft_remote_r1kh **r1kh_wildcard) { struct ft_remote_r1kh *r1kh; + *r1kh_wildcard = NULL; *r1kh_out = NULL; - for (r1kh = wpa_auth->conf.r1kh_list; r1kh; r1kh = r1kh->next) { + if (wpa_auth->conf.r1kh_list) + r1kh = *wpa_auth->conf.r1kh_list; + else + r1kh = NULL; + for (; r1kh; r1kh = r1kh->next) { + if (is_zero_ether_addr(r1kh->addr) && + is_zero_ether_addr(r1kh->id)) + *r1kh_wildcard = r1kh; if (f_r1kh_id && - os_memcmp_const(r1kh->id, f_r1kh_id, FT_R1KH_ID_LEN) == 0) { + os_memcmp_const(r1kh->id, f_r1kh_id, FT_R1KH_ID_LEN) == 0) *r1kh_out = r1kh; - break; - } } - if (!*r1kh_out) + if (!*r1kh_out && !*r1kh_wildcard) wpa_printf(MSG_DEBUG, "FT: No matching R1KH found"); if (*r1kh_out && wpa_ft_rrb_init_r1kh_seq(*r1kh_out) < 0) @@ -1094,6 +1109,163 @@ static int wpa_ft_rrb_check_r1kh(struct wpa_authenticator *wpa_auth, } +static void wpa_ft_rrb_del_r0kh(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_authenticator *wpa_auth = eloop_ctx; + struct ft_remote_r0kh *r0kh, *prev = NULL; + + if (!wpa_auth->conf.r0kh_list) + return; + + for (r0kh = *wpa_auth->conf.r0kh_list; r0kh; r0kh = r0kh->next) { + if (r0kh == timeout_ctx) + break; + prev = r0kh; + } + if (!r0kh) + return; + if (prev) + prev->next = r0kh->next; + else + *wpa_auth->conf.r0kh_list = r0kh->next; + if (r0kh->seq) + wpa_ft_rrb_seq_flush(wpa_auth, r0kh->seq, 0); + os_free(r0kh->seq); + os_free(r0kh); +} + + +static void wpa_ft_rrb_r0kh_replenish(struct wpa_authenticator *wpa_auth, + struct ft_remote_r0kh *r0kh, int timeout) +{ + if (timeout > 0) + eloop_replenish_timeout(timeout, 0, wpa_ft_rrb_del_r0kh, + wpa_auth, r0kh); +} + + +static void wpa_ft_rrb_r0kh_timeout(struct wpa_authenticator *wpa_auth, + struct ft_remote_r0kh *r0kh, int timeout) +{ + eloop_cancel_timeout(wpa_ft_rrb_del_r0kh, wpa_auth, r0kh); + + if (timeout > 0) + eloop_register_timeout(timeout, 0, wpa_ft_rrb_del_r0kh, + wpa_auth, r0kh); +} + + +static struct ft_remote_r0kh * +wpa_ft_rrb_add_r0kh(struct wpa_authenticator *wpa_auth, + struct ft_remote_r0kh *r0kh_wildcard, + const u8 *src_addr, const u8 *r0kh_id, size_t id_len, + int timeout) +{ + struct ft_remote_r0kh *r0kh; + + if (!wpa_auth->conf.r0kh_list) + return NULL; + + r0kh = os_zalloc(sizeof(*r0kh)); + if (!r0kh) + return NULL; + + if (src_addr) + os_memcpy(r0kh->addr, src_addr, sizeof(r0kh->addr)); + + if (id_len > FT_R0KH_ID_MAX_LEN) + id_len = FT_R0KH_ID_MAX_LEN; + os_memcpy(r0kh->id, r0kh_id, id_len); + r0kh->id_len = id_len; + + os_memcpy(r0kh->key, r0kh_wildcard->key, sizeof(r0kh->key)); + + r0kh->next = *wpa_auth->conf.r0kh_list; + *wpa_auth->conf.r0kh_list = r0kh; + + if (timeout > 0) + eloop_register_timeout(timeout, 0, wpa_ft_rrb_del_r0kh, + wpa_auth, r0kh); + + if (wpa_ft_rrb_init_r0kh_seq(r0kh) < 0) + return NULL; + + return r0kh; +} + + +static void wpa_ft_rrb_del_r1kh(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_authenticator *wpa_auth = eloop_ctx; + struct ft_remote_r1kh *r1kh, *prev = NULL; + + if (!wpa_auth->conf.r1kh_list) + return; + + for (r1kh = *wpa_auth->conf.r1kh_list; r1kh; r1kh = r1kh->next) { + if (r1kh == timeout_ctx) + break; + prev = r1kh; + } + if (!r1kh) + return; + if (prev) + prev->next = r1kh->next; + else + *wpa_auth->conf.r1kh_list = r1kh->next; + if (r1kh->seq) + wpa_ft_rrb_seq_flush(wpa_auth, r1kh->seq, 0); + os_free(r1kh->seq); + os_free(r1kh); +} + + +static void wpa_ft_rrb_r1kh_replenish(struct wpa_authenticator *wpa_auth, + struct ft_remote_r1kh *r1kh, int timeout) +{ + if (timeout > 0) + eloop_replenish_timeout(timeout, 0, wpa_ft_rrb_del_r1kh, + wpa_auth, r1kh); +} + + +static struct ft_remote_r1kh * +wpa_ft_rrb_add_r1kh(struct wpa_authenticator *wpa_auth, + struct ft_remote_r1kh *r1kh_wildcard, + const u8 *src_addr, const u8 *r1kh_id, int timeout) +{ + struct ft_remote_r1kh *r1kh; + + if (!wpa_auth->conf.r1kh_list) + return NULL; + + r1kh = os_zalloc(sizeof(*r1kh)); + if (!r1kh) + return NULL; + + os_memcpy(r1kh->addr, src_addr, sizeof(r1kh->addr)); + os_memcpy(r1kh->id, r1kh_id, sizeof(r1kh->id)); + os_memcpy(r1kh->key, r1kh_wildcard->key, sizeof(r1kh->key)); + r1kh->next = *wpa_auth->conf.r1kh_list; + *wpa_auth->conf.r1kh_list = r1kh; + + if (timeout > 0) + eloop_register_timeout(timeout, 0, wpa_ft_rrb_del_r1kh, + wpa_auth, r1kh); + + if (wpa_ft_rrb_init_r1kh_seq(r1kh) < 0) + return NULL; + + return r1kh; +} + + +void wpa_ft_sta_deinit(struct wpa_state_machine *sm) +{ + eloop_cancel_timeout(wpa_ft_expire_pull, sm, NULL); +} + + static void wpa_ft_deinit_seq(struct wpa_authenticator *wpa_auth) { struct ft_remote_r0kh *r0kh; @@ -1101,7 +1273,11 @@ static void wpa_ft_deinit_seq(struct wpa_authenticator *wpa_auth) eloop_cancel_timeout(wpa_ft_rrb_seq_timeout, wpa_auth, ELOOP_ALL_CTX); - for (r0kh = wpa_auth->conf.r0kh_list; r0kh; r0kh = r0kh->next) { + if (wpa_auth->conf.r0kh_list) + r0kh = *wpa_auth->conf.r0kh_list; + else + r0kh = NULL; + for (; r0kh; r0kh = r0kh->next) { if (!r0kh->seq) continue; wpa_ft_rrb_seq_flush(wpa_auth, r0kh->seq, 0); @@ -1109,7 +1285,11 @@ static void wpa_ft_deinit_seq(struct wpa_authenticator *wpa_auth) r0kh->seq = NULL; } - for (r1kh = wpa_auth->conf.r1kh_list; r1kh; r1kh = r1kh->next) { + if (wpa_auth->conf.r1kh_list) + r1kh = *wpa_auth->conf.r1kh_list; + else + r1kh = NULL; + for (; r1kh; r1kh = r1kh->next) { if (!r1kh->seq) continue; wpa_ft_rrb_seq_flush(wpa_auth, r1kh->seq, 0); @@ -1119,9 +1299,100 @@ static void wpa_ft_deinit_seq(struct wpa_authenticator *wpa_auth) } +static void wpa_ft_deinit_rkh_tmp(struct wpa_authenticator *wpa_auth) +{ + struct ft_remote_r0kh *r0kh, *r0kh_next, *r0kh_prev = NULL; + struct ft_remote_r1kh *r1kh, *r1kh_next, *r1kh_prev = NULL; + + if (wpa_auth->conf.r0kh_list) + r0kh = *wpa_auth->conf.r0kh_list; + else + r0kh = NULL; + while (r0kh) { + r0kh_next = r0kh->next; + if (eloop_cancel_timeout(wpa_ft_rrb_del_r0kh, wpa_auth, + r0kh) > 0) { + if (r0kh_prev) + r0kh_prev->next = r0kh_next; + else + *wpa_auth->conf.r0kh_list = r0kh_next; + os_free(r0kh); + } else { + r0kh_prev = r0kh; + } + r0kh = r0kh_next; + } + + if (wpa_auth->conf.r1kh_list) + r1kh = *wpa_auth->conf.r1kh_list; + else + r1kh = NULL; + while (r1kh) { + r1kh_next = r1kh->next; + if (eloop_cancel_timeout(wpa_ft_rrb_del_r1kh, wpa_auth, + r1kh) > 0) { + if (r1kh_prev) + r1kh_prev->next = r1kh_next; + else + *wpa_auth->conf.r1kh_list = r1kh_next; + os_free(r1kh); + } else { + r1kh_prev = r1kh; + } + r1kh = r1kh_next; + } +} + + void wpa_ft_deinit(struct wpa_authenticator *wpa_auth) { wpa_ft_deinit_seq(wpa_auth); + wpa_ft_deinit_rkh_tmp(wpa_auth); +} + + +static void wpa_ft_block_r0kh(struct wpa_authenticator *wpa_auth, + const u8 *f_r0kh_id, size_t f_r0kh_id_len) +{ + struct ft_remote_r0kh *r0kh, *r0kh_wildcard; + + if (!wpa_auth->conf.rkh_neg_timeout) + return; + + wpa_ft_rrb_lookup_r0kh(wpa_auth, f_r0kh_id, f_r0kh_id_len, + &r0kh, &r0kh_wildcard); + + if (!r0kh_wildcard) { + /* r0kh removed after neg_timeout and might need re-adding */ + return; + } + + wpa_hexdump(MSG_DEBUG, "FT: Blacklist R0KH-ID", + f_r0kh_id, f_r0kh_id_len); + + if (r0kh) { + wpa_ft_rrb_r0kh_timeout(wpa_auth, r0kh, + wpa_auth->conf.rkh_neg_timeout); + os_memset(r0kh->addr, 0, ETH_ALEN); + } else + wpa_ft_rrb_add_r0kh(wpa_auth, r0kh_wildcard, NULL, f_r0kh_id, + f_r0kh_id_len, + wpa_auth->conf.rkh_neg_timeout); +} + + +static void wpa_ft_expire_pull(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_state_machine *sm = eloop_ctx; + + wpa_printf(MSG_DEBUG, "FT: Timeout pending pull request for " MACSTR, + MAC2STR(sm->addr)); + if (sm->ft_pending_pull_left_retries <= 0) + wpa_ft_block_r0kh(sm->wpa_auth, sm->r0kh_id, sm->r0kh_id_len); + + /* cancel multiple timeouts */ + eloop_cancel_timeout(wpa_ft_expire_pull, sm, NULL); + ft_finish_pull(sm); } @@ -1129,11 +1400,14 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm, const u8 *ies, size_t ies_len, const u8 *pmk_r0_name) { - struct ft_remote_r0kh *r0kh; + struct ft_remote_r0kh *r0kh, *r0kh_wildcard; u8 *packet = NULL; const u8 *key, *f_r1kh_id = sm->wpa_auth->conf.r1_key_holder; size_t packet_len, key_len; struct ft_rrb_seq f_seq; + int tsecs, tusecs, first; + struct wpabuf *ft_pending_req_ies; + int r0kh_timeout; struct tlv_list req_enc[] = { { .type = FT_RRB_PMK_R0_NAME, .len = WPA_PMK_NAME_LEN, .data = pmk_r0_name }, @@ -1153,13 +1427,38 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm, { .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL }, }; + if (sm->ft_pending_pull_left_retries <= 0) + return -1; + first = sm->ft_pending_pull_left_retries == + sm->wpa_auth->conf.rkh_pull_retries; + sm->ft_pending_pull_left_retries--; + wpa_ft_rrb_lookup_r0kh(sm->wpa_auth, sm->r0kh_id, sm->r0kh_id_len, - &r0kh); + &r0kh, &r0kh_wildcard); + + /* Keep r0kh sufficiently long in the list for seq num check */ + r0kh_timeout = sm->wpa_auth->conf.rkh_pull_timeout / 1000 + + 1 + ftRRBseqTimeout; + if (r0kh) { + wpa_ft_rrb_r0kh_replenish(sm->wpa_auth, r0kh, r0kh_timeout); + } else if (r0kh_wildcard) { + wpa_printf(MSG_DEBUG, "FT: Using wildcard R0KH-ID"); + /* r0kh->addr: updated by SEQ_RESP and wpa_ft_expire_pull */ + r0kh = wpa_ft_rrb_add_r0kh(sm->wpa_auth, r0kh_wildcard, + r0kh_wildcard->addr, + sm->r0kh_id, sm->r0kh_id_len, + r0kh_timeout); + } if (r0kh == NULL) { wpa_hexdump(MSG_DEBUG, "FT: Did not find R0KH-ID", sm->r0kh_id, sm->r0kh_id_len); return -1; } + if (is_zero_ether_addr(r0kh->addr)) { + wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID is blacklisted", + sm->r0kh_id, sm->r0kh_id_len); + return -1; + } key = r0kh->key; key_len = sizeof(r0kh->key); @@ -1175,7 +1474,8 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm, key_len, NULL, 0, NULL, 0, NULL); } - if (random_get_bytes(sm->ft_pending_pull_nonce, FT_RRB_NONCE_LEN) < 0) { + if (first && + random_get_bytes(sm->ft_pending_pull_nonce, FT_RRB_NONCE_LEN) < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to get random data for " "nonce"); return -1; @@ -1191,13 +1491,18 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm, &packet, &packet_len) < 0) return -1; + ft_pending_req_ies = wpabuf_alloc_copy(ies, ies_len); wpabuf_free(sm->ft_pending_req_ies); - sm->ft_pending_req_ies = wpabuf_alloc_copy(ies, ies_len); + sm->ft_pending_req_ies = ft_pending_req_ies; if (!sm->ft_pending_req_ies) { os_free(packet); return -1; } + tsecs = sm->wpa_auth->conf.rkh_pull_timeout / 1000; + tusecs = (sm->wpa_auth->conf.rkh_pull_timeout % 1000) * 1000; + eloop_register_timeout(tsecs, tusecs, wpa_ft_expire_pull, sm, NULL); + wpa_ft_rrb_oui_send(sm->wpa_auth, r0kh->addr, FT_PACKET_R0KH_R1KH_PULL, packet, packet_len); @@ -1816,8 +2121,8 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm, } else if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, pmk_r1, &pairwise) < 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"); + wpa_printf(MSG_DEBUG, + "FT: Did not have matching PMK-R1 and either unknown or blocked R0KH-ID or NAK from R0KH"); return WLAN_STATUS_INVALID_PMKID; } @@ -1908,6 +2213,7 @@ void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid, sm->ft_pending_cb = cb; sm->ft_pending_cb_ctx = ctx; sm->ft_pending_auth_transaction = auth_transaction; + sm->ft_pending_pull_left_retries = sm->wpa_auth->conf.rkh_pull_retries; res = wpa_ft_process_auth_req(sm, ies, ies_len, &resp_ies, &resp_ies_len); if (res < 0) { @@ -2189,6 +2495,7 @@ static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth, sm->ft_pending_cb = wpa_ft_rrb_rx_request_cb; sm->ft_pending_cb_ctx = sm; os_memcpy(sm->ft_pending_current_ap, current_ap, ETH_ALEN); + sm->ft_pending_pull_left_retries = sm->wpa_auth->conf.rkh_pull_retries; res = wpa_ft_process_auth_req(sm, body, len, &resp_ies, &resp_ies_len); if (res < 0) { @@ -2276,6 +2583,10 @@ static int wpa_ft_rrb_build_r0(const u8 *key, const size_t key_len, { .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL }, }; + if (!pmk_r0) + return wpa_ft_rrb_build(key, key_len, tlvs, NULL, tlv_auth, + src_addr, type, packet, packet_len); + if (wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh_id, s1kh_id, pmk_r1, pmk_r1_name) < 0) return -1; @@ -2301,7 +2612,7 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, const char *msgtype = "pull request"; u8 *plain = NULL, *packet = NULL; size_t plain_len = 0, packet_len = 0; - struct ft_remote_r1kh *r1kh; + struct ft_remote_r1kh *r1kh, *r1kh_wildcard; const u8 *key; size_t key_len; int seq_ret; @@ -2327,17 +2638,31 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, RRB_GET_AUTH(FT_RRB_R1KH_ID, r1kh_id, msgtype, FT_R1KH_ID_LEN); wpa_printf(MSG_DEBUG, "FT: R1KH-ID=" MACSTR, MAC2STR(f_r1kh_id)); - wpa_ft_rrb_lookup_r1kh(wpa_auth, f_r1kh_id, &r1kh); - if (!r1kh || os_memcmp(r1kh->addr, src_addr, ETH_ALEN) != 0) + wpa_ft_rrb_lookup_r1kh(wpa_auth, f_r1kh_id, &r1kh, &r1kh_wildcard); + if (r1kh) { + key = r1kh->key; + key_len = sizeof(r1kh->key); + } else if (r1kh_wildcard) { + wpa_printf(MSG_DEBUG, "FT: Using wildcard R1KH-ID"); + key = r1kh_wildcard->key; + key_len = sizeof(r1kh_wildcard->key); + } else { goto out; - key = r1kh->key; - key_len = sizeof(r1kh->key); + } RRB_GET_AUTH(FT_RRB_NONCE, nonce, "pull request", FT_RRB_NONCE_LEN); wpa_hexdump(MSG_DEBUG, "FT: nonce", f_nonce, f_nonce_len); - seq_ret = wpa_ft_rrb_seq_chk(r1kh->seq, src_addr, enc, enc_len, auth, - auth_len, msgtype, no_defer); + seq_ret = FT_RRB_SEQ_DROP; + if (r1kh) + seq_ret = wpa_ft_rrb_seq_chk(r1kh->seq, src_addr, enc, enc_len, + auth, auth_len, msgtype, no_defer); + if (!no_defer && r1kh_wildcard && + (!r1kh || os_memcmp(r1kh->addr, src_addr, ETH_ALEN) != 0)) { + /* wildcard: r1kh-id unknown or changed addr -> do a seq req */ + seq_ret = FT_RRB_SEQ_DEFER; + } + if (seq_ret == FT_RRB_SEQ_DROP) goto out; @@ -2346,6 +2671,13 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, &plain, &plain_len) < 0) goto out; + if (!r1kh) + r1kh = wpa_ft_rrb_add_r1kh(wpa_auth, r1kh_wildcard, src_addr, + f_r1kh_id, + wpa_auth->conf.rkh_pos_timeout); + if (!r1kh) + goto out; + if (seq_ret == FT_RRB_SEQ_DEFER) { wpa_ft_rrb_seq_req(wpa_auth, r1kh->seq, src_addr, f_r0kh_id, f_r0kh_id_len, f_r1kh_id, key, key_len, @@ -2356,6 +2688,8 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, wpa_ft_rrb_seq_accept(wpa_auth, r1kh->seq, src_addr, auth, auth_len, msgtype); + wpa_ft_rrb_r1kh_replenish(wpa_auth, r1kh, + wpa_auth->conf.rkh_pos_timeout); RRB_GET(FT_RRB_PMK_R0_NAME, pmk_r0_name, msgtype, WPA_PMK_NAME_LEN); wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", f_pmk_r0_name, @@ -2392,10 +2726,8 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, resp_auth[4].len = 0; resp_auth[4].data = NULL; - if (wpa_ft_fetch_pmk_r0(wpa_auth, f_s1kh_id, f_pmk_r0_name, &r0) < 0) { + if (wpa_ft_fetch_pmk_r0(wpa_auth, f_s1kh_id, f_pmk_r0_name, &r0) < 0) wpa_printf(MSG_DEBUG, "FT: No matching PMK-R0-Name found"); - goto out; - } ret = wpa_ft_rrb_build_r0(key, key_len, resp, r0, f_r1kh_id, f_s1kh_id, resp_auth, wpa_auth->addr, @@ -2417,6 +2749,7 @@ out: /* @returns 0 on success * -1 on error + * -2 if FR_RRB_PAIRWISE is missing */ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth, const u8 *src_addr, u8 type, @@ -2431,7 +2764,7 @@ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth, { u8 *plain = NULL; size_t plain_len = 0; - struct ft_remote_r0kh *r0kh; + struct ft_remote_r0kh *r0kh, *r0kh_wildcard; const u8 *key; size_t key_len; int seq_ret; @@ -2453,14 +2786,31 @@ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth, goto out; } - wpa_ft_rrb_lookup_r0kh(wpa_auth, f_r0kh_id, f_r0kh_id_len, &r0kh); - if (!r0kh || os_memcmp(r0kh->addr, src_addr, ETH_ALEN) != 0) + wpa_ft_rrb_lookup_r0kh(wpa_auth, f_r0kh_id, f_r0kh_id_len, &r0kh, + &r0kh_wildcard); + if (r0kh) { + key = r0kh->key; + key_len = sizeof(r0kh->key); + } else if (r0kh_wildcard) { + wpa_printf(MSG_DEBUG, "FT: Using wildcard R0KH-ID"); + key = r0kh_wildcard->key; + key_len = sizeof(r0kh_wildcard->key); + } else { goto out; - key = r0kh->key; - key_len = sizeof(r0kh->key); + } + + seq_ret = FT_RRB_SEQ_DROP; + if (r0kh) { + seq_ret = wpa_ft_rrb_seq_chk(r0kh->seq, src_addr, enc, enc_len, + auth, auth_len, msgtype, + cb ? 0 : 1); + } + if (cb && r0kh_wildcard && + (!r0kh || os_memcmp(r0kh->addr, src_addr, ETH_ALEN) != 0)) { + /* wildcard: r0kh-id unknown or changed addr -> do a seq req */ + seq_ret = FT_RRB_SEQ_DEFER; + } - seq_ret = wpa_ft_rrb_seq_chk(r0kh->seq, src_addr, enc, enc_len, auth, - auth_len, msgtype, cb ? 0 : 1); if (seq_ret == FT_RRB_SEQ_DROP) goto out; @@ -2468,6 +2818,13 @@ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth, src_addr, type, &plain, &plain_len) < 0) goto out; + if (!r0kh) + r0kh = wpa_ft_rrb_add_r0kh(wpa_auth, r0kh_wildcard, src_addr, + f_r0kh_id, f_r0kh_id_len, + wpa_auth->conf.rkh_pos_timeout); + if (!r0kh) + goto out; + if (seq_ret == FT_RRB_SEQ_DEFER) { wpa_ft_rrb_seq_req(wpa_auth, r0kh->seq, src_addr, f_r0kh_id, f_r0kh_id_len, f_r1kh_id, key, key_len, @@ -2477,6 +2834,8 @@ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth, wpa_ft_rrb_seq_accept(wpa_auth, r0kh->seq, src_addr, auth, auth_len, msgtype); + wpa_ft_rrb_r0kh_replenish(wpa_auth, r0kh, + wpa_auth->conf.rkh_pos_timeout); RRB_GET(FT_RRB_S1KH_ID, s1kh_id, msgtype, ETH_ALEN); wpa_printf(MSG_DEBUG, "FT: S1KH-ID=" MACSTR, MAC2STR(f_s1kh_id)); @@ -2484,9 +2843,11 @@ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth, if (s1kh_id_out) os_memcpy(s1kh_id_out, f_s1kh_id, ETH_ALEN); + ret = -2; RRB_GET(FT_RRB_PAIRWISE, pairwise, msgtype, sizeof(le16)); wpa_hexdump(MSG_DEBUG, "FT: pairwise", f_pairwise, f_pairwise_len); + ret = -1; RRB_GET(FT_RRB_PMK_R1_NAME, pmk_r1_name, msgtype, WPA_PMK_NAME_LEN); wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", f_pmk_r1_name, WPA_PMK_NAME_LEN); @@ -2519,13 +2880,20 @@ static void ft_finish_pull(struct wpa_state_machine *sm) size_t resp_ies_len; u16 status; + if (!sm->ft_pending_cb || !sm->ft_pending_req_ies) + return; + res = wpa_ft_process_auth_req(sm, wpabuf_head(sm->ft_pending_req_ies), wpabuf_len(sm->ft_pending_req_ies), &resp_ies, &resp_ies_len); + if (res < 0) { + /* this loop is broken by ft_pending_pull_left_retries */ + wpa_printf(MSG_DEBUG, + "FT: Callback postponed until response is available"); + return; + } wpabuf_free(sm->ft_pending_req_ies); sm->ft_pending_req_ies = NULL; - if (res < 0) - res = WLAN_STATUS_UNSPECIFIED_FAILURE; status = res; wpa_printf(MSG_DEBUG, "FT: Postponed auth callback result for " MACSTR " - status %u", MAC2STR(sm->addr), status); @@ -2568,7 +2936,7 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth, int no_defer) { const char *msgtype = "pull response"; - int ret = -1; + int nak, ret = -1; struct ft_get_sta_ctx ctx; u8 s1kh_id[ETH_ALEN]; const u8 *f_nonce; @@ -2590,6 +2958,12 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth, ret = wpa_ft_rrb_rx_r1(wpa_auth, src_addr, FT_PACKET_R0KH_R1KH_RESP, enc, enc_len, auth, auth_len, msgtype, s1kh_id, no_defer ? NULL : &wpa_ft_rrb_rx_resp); + if (ret == -2) { + ret = 0; + nak = 1; + } else { + nak = 0; + } if (ret < 0) return -1; @@ -2598,6 +2972,9 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth, wpa_printf(MSG_DEBUG, "FT: Response to a pending pull request for " MACSTR, MAC2STR(ctx.sm->addr)); + eloop_cancel_timeout(wpa_ft_expire_pull, ctx.sm, NULL); + if (nak) + ctx.sm->ft_pending_pull_left_retries = 0; ft_finish_pull(ctx.sm); } @@ -2629,7 +3006,11 @@ static int wpa_ft_rrb_rx_seq(struct wpa_authenticator *wpa_auth, const u8 *enc, size_t enc_len, const u8 *auth, size_t auth_len, struct ft_remote_seq **rkh_seq, - u8 **key, size_t *key_len) + u8 **key, size_t *key_len, + struct ft_remote_r0kh **r0kh_out, + struct ft_remote_r1kh **r1kh_out, + struct ft_remote_r0kh **r0kh_wildcard_out, + struct ft_remote_r1kh **r1kh_wildcard_out) { struct ft_remote_r0kh *r0kh = NULL; struct ft_remote_r1kh *r1kh = NULL; @@ -2638,6 +3019,8 @@ static int wpa_ft_rrb_rx_seq(struct wpa_authenticator *wpa_auth, int to_r0kh, to_r1kh; u8 *plain = NULL; size_t plain_len = 0; + struct ft_remote_r0kh *r0kh_wildcard; + struct ft_remote_r1kh *r1kh_wildcard; RRB_GET_AUTH(FT_RRB_R0KH_ID, r0kh_id, "seq", -1); RRB_GET_AUTH(FT_RRB_R1KH_ID, r1kh_id, "seq", FT_R1KH_ID_LEN); @@ -2657,29 +3040,38 @@ static int wpa_ft_rrb_rx_seq(struct wpa_authenticator *wpa_auth, if (!to_r0kh) { wpa_ft_rrb_lookup_r0kh(wpa_auth, f_r0kh_id, f_r0kh_id_len, - &r0kh); - if (!r0kh || os_memcmp(r0kh->addr, src_addr, ETH_ALEN) != 0) { + &r0kh, &r0kh_wildcard); + if (!r0kh_wildcard && + (!r0kh || os_memcmp(r0kh->addr, src_addr, ETH_ALEN) != 0)) { wpa_hexdump(MSG_DEBUG, "FT: Did not find R0KH-ID", f_r0kh_id, f_r0kh_id_len); goto out; } - - *key = r0kh->key; - *key_len = sizeof(r0kh->key); - *rkh_seq = r0kh->seq; + if (r0kh) { + *key = r0kh->key; + *key_len = sizeof(r0kh->key); + } else { + *key = r0kh_wildcard->key; + *key_len = sizeof(r0kh_wildcard->key); + } } if (!to_r1kh) { - wpa_ft_rrb_lookup_r1kh(wpa_auth, f_r1kh_id, &r1kh); - if (!r1kh || os_memcmp(r1kh->addr, src_addr, ETH_ALEN) != 0) { + wpa_ft_rrb_lookup_r1kh(wpa_auth, f_r1kh_id, &r1kh, + &r1kh_wildcard); + if (!r1kh_wildcard && + (!r1kh || os_memcmp(r1kh->addr, src_addr, ETH_ALEN) != 0)) { wpa_hexdump(MSG_DEBUG, "FT: Did not find R1KH-ID", f_r1kh_id, FT_R1KH_ID_LEN); goto out; } - - *key = r1kh->key; - *key_len = sizeof(r1kh->key); - *rkh_seq = r1kh->seq; + if (r1kh) { + *key = r1kh->key; + *key_len = sizeof(r1kh->key); + } else { + *key = r1kh_wildcard->key; + *key_len = sizeof(r1kh_wildcard->key); + } } if (wpa_ft_rrb_decrypt(*key, *key_len, enc, enc_len, auth, auth_len, @@ -2688,6 +3080,39 @@ static int wpa_ft_rrb_rx_seq(struct wpa_authenticator *wpa_auth, os_free(plain); + if (!to_r0kh) { + if (!r0kh) + r0kh = wpa_ft_rrb_add_r0kh(wpa_auth, r0kh_wildcard, + src_addr, f_r0kh_id, + f_r0kh_id_len, + ftRRBseqTimeout); + if (!r0kh) + goto out; + + wpa_ft_rrb_r0kh_replenish(wpa_auth, r0kh, ftRRBseqTimeout); + *rkh_seq = r0kh->seq; + if (r0kh_out) + *r0kh_out = r0kh; + if (r0kh_wildcard_out) + *r0kh_wildcard_out = r0kh_wildcard; + } + + if (!to_r1kh) { + if (!r1kh) + r1kh = wpa_ft_rrb_add_r1kh(wpa_auth, r1kh_wildcard, + src_addr, f_r1kh_id, + ftRRBseqTimeout); + if (!r1kh) + goto out; + + wpa_ft_rrb_r1kh_replenish(wpa_auth, r1kh, ftRRBseqTimeout); + *rkh_seq = r1kh->seq; + if (r1kh_out) + *r1kh_out = r1kh; + if (r1kh_wildcard_out) + *r1kh_wildcard_out = r1kh_wildcard; + } + return 0; out: return -1; @@ -2704,7 +3129,7 @@ static int wpa_ft_rrb_rx_seq_req(struct wpa_authenticator *wpa_auth, struct ft_rrb_seq f_seq; const u8 *f_nonce, *f_r0kh_id, *f_r1kh_id; size_t f_nonce_len, f_r0kh_id_len, f_r1kh_id_len; - struct ft_remote_seq *rkh_seq; + struct ft_remote_seq *rkh_seq = NULL; u8 *packet = NULL, *key = NULL; size_t packet_len = 0, key_len = 0; struct tlv_list seq_resp_auth[5]; @@ -2713,7 +3138,7 @@ static int wpa_ft_rrb_rx_seq_req(struct wpa_authenticator *wpa_auth, if (wpa_ft_rrb_rx_seq(wpa_auth, src_addr, FT_PACKET_R0KH_R1KH_SEQ_REQ, enc, enc_len, auth, auth_len, &rkh_seq, &key, - &key_len) < 0) + &key_len, NULL, NULL, NULL, NULL) < 0) goto out; RRB_GET_AUTH(FT_RRB_NONCE, nonce, "seq request", FT_RRB_NONCE_LEN); @@ -2767,6 +3192,8 @@ static int wpa_ft_rrb_rx_seq_resp(struct wpa_authenticator *wpa_auth, { u8 *key = NULL; size_t key_len = 0; + struct ft_remote_r0kh *r0kh = NULL, *r0kh_wildcard = NULL; + struct ft_remote_r1kh *r1kh = NULL, *r1kh_wildcard = NULL; const u8 *f_nonce, *f_seq; size_t f_nonce_len, f_seq_len; struct ft_remote_seq *rkh_seq = NULL; @@ -2780,7 +3207,8 @@ static int wpa_ft_rrb_rx_seq_resp(struct wpa_authenticator *wpa_auth, if (wpa_ft_rrb_rx_seq(wpa_auth, src_addr, FT_PACKET_R0KH_R1KH_SEQ_RESP, enc, enc_len, auth, auth_len, &rkh_seq, &key, - &key_len) < 0) + &key_len, &r0kh, &r1kh, &r0kh_wildcard, + &r1kh_wildcard) < 0) goto out; RRB_GET_AUTH(FT_RRB_NONCE, nonce, "seq response", FT_RRB_NONCE_LEN); @@ -2804,6 +3232,20 @@ static int wpa_ft_rrb_rx_seq_resp(struct wpa_authenticator *wpa_auth, goto out; } + if (r0kh) { + wpa_ft_rrb_r0kh_replenish(wpa_auth, r0kh, + wpa_auth->conf.rkh_pos_timeout); + if (r0kh_wildcard) + os_memcpy(r0kh->addr, src_addr, ETH_ALEN); + } + + if (r1kh) { + wpa_ft_rrb_r1kh_replenish(wpa_auth, r1kh, + wpa_auth->conf.rkh_pos_timeout); + if (r1kh_wildcard) + os_memcpy(r1kh->addr, src_addr, ETH_ALEN); + } + seq_ret = wpa_ft_rrb_seq_chk(rkh_seq, src_addr, enc, enc_len, auth, auth_len, "seq response", 1); if (seq_ret == FT_RRB_SEQ_OK) { @@ -2967,6 +3409,7 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, { const u8 *auth, *enc; size_t alen, elen; + int no_defer = 0; wpa_printf(MSG_DEBUG, "FT: RRB-OUI received frame from remote AP " MACSTR, MAC2STR(src_addr)); @@ -2984,7 +3427,7 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, "FT: RRB-OUI received frame from remote AP " MACSTR " to multicast address " MACSTR, MAC2STR(src_addr), MAC2STR(dst_addr)); - return; + no_defer = 1; } if (data_len < sizeof(u16)) { @@ -3005,23 +3448,23 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, switch (oui_suffix) { case FT_PACKET_R0KH_R1KH_PULL: wpa_ft_rrb_rx_pull(wpa_auth, src_addr, enc, elen, auth, alen, - 0); + no_defer); break; case FT_PACKET_R0KH_R1KH_RESP: wpa_ft_rrb_rx_resp(wpa_auth, src_addr, enc, elen, auth, alen, - 0); + no_defer); break; case FT_PACKET_R0KH_R1KH_PUSH: wpa_ft_rrb_rx_push(wpa_auth, src_addr, enc, elen, auth, alen, - 0); + no_defer); break; case FT_PACKET_R0KH_R1KH_SEQ_REQ: wpa_ft_rrb_rx_seq_req(wpa_auth, src_addr, enc, elen, auth, alen, - 0); + no_defer); break; case FT_PACKET_R0KH_R1KH_SEQ_RESP: wpa_ft_rrb_rx_seq_resp(wpa_auth, src_addr, enc, elen, auth, - alen, 0); + alen, no_defer); break; } } @@ -3079,6 +3522,8 @@ void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr) if (!wpa_auth->conf.pmk_r1_push) return; + if (!wpa_auth->conf.r1kh_list) + return; r0 = wpa_auth->ft_pmk_cache->pmk_r0; while (r0) { @@ -3094,7 +3539,10 @@ void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr) wpa_printf(MSG_DEBUG, "FT: Deriving and pushing PMK-R1 keys to R1KHs " "for STA " MACSTR, MAC2STR(addr)); - for (r1kh = wpa_auth->conf.r1kh_list; r1kh; r1kh = r1kh->next) { + for (r1kh = *wpa_auth->conf.r1kh_list; r1kh; r1kh = r1kh->next) { + if (is_zero_ether_addr(r1kh->addr) || + is_zero_ether_addr(r1kh->id)) + continue; if (wpa_ft_rrb_init_r1kh_seq(r1kh) < 0) continue; wpa_ft_generate_pmk_r1(wpa_auth, r0, r1kh, addr); diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index b364fcee6..316f5d50b 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -74,8 +74,12 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, os_memcpy(wconf->r1_key_holder, conf->r1_key_holder, FT_R1KH_ID_LEN); wconf->r0_key_lifetime = conf->r0_key_lifetime; wconf->reassociation_deadline = conf->reassociation_deadline; - wconf->r0kh_list = conf->r0kh_list; - wconf->r1kh_list = conf->r1kh_list; + wconf->rkh_pos_timeout = conf->rkh_pos_timeout; + wconf->rkh_neg_timeout = conf->rkh_neg_timeout; + wconf->rkh_pull_timeout = conf->rkh_pull_timeout; + wconf->rkh_pull_retries = conf->rkh_pull_retries; + wconf->r0kh_list = &conf->r0kh_list; + wconf->r1kh_list = &conf->r1kh_list; wconf->pmk_r1_push = conf->pmk_r1_push; wconf->ft_over_ds = conf->ft_over_ds; wconf->ft_psk_generate_local = conf->ft_psk_generate_local; diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index aebf75c1f..7ef817f54 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -126,6 +126,7 @@ struct wpa_state_machine { u8 ft_pending_pull_nonce[FT_RRB_NONCE_LEN]; u8 ft_pending_auth_transaction; u8 ft_pending_current_ap[ETH_ALEN]; + int ft_pending_pull_left_retries; #endif /* CONFIG_IEEE80211R_AP */ int pending_1_of_4_timeout;