Add a timeout and retry pull request. Do not change nonce during resend in order to accept response to initial request. Signed-off-by: Michael Braun <michael-dev@xxxxxxxxxxxxx> --- hostapd/config_file.c | 4 +++ hostapd/hostapd.conf | 5 ++++ src/ap/ap_config.c | 2 ++ src/ap/ap_config.h | 2 ++ src/ap/wpa_auth.c | 3 +++ src/ap/wpa_auth.h | 3 +++ src/ap/wpa_auth_ft.c | 68 ++++++++++++++++++++++++++++++++++++++++++-------- src/ap/wpa_auth_glue.c | 2 ++ src/ap/wpa_auth_i.h | 1 + 9 files changed, 80 insertions(+), 10 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 288cdf1..1a8b5f2 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2545,6 +2545,10 @@ static int hostapd_config_fill(struct hostapd_config *conf, 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_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 c6b8cae..24cd3e1 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1327,6 +1327,11 @@ own_ip_addr=127.0.0.1 # Special values: 0 -> do not cache; -1 -> do not expire #rkh_pos_timeout = 86400 (default = 1d) +# Timeout (milli seconds) for requesting PMK-R1 from R0KH using PULL request +# and number of retries. +#rkh_pull_timeout = 1000 (default = 1s) +#rkh_pull_retries = 4 (default) + # Whether PMK-R1 push is enabled at R0KH # 0 = do not push PMK-R1 to all configured R1KHs (default) # 1 = push PMK-R1 to all configured R1KHs whenever a new PMK-R0 is derived diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index b43890d..35fe74d 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -91,6 +91,8 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) #ifdef CONFIG_IEEE80211R bss->ft_over_ds = 1; bss->rkh_pos_timeout = 86400; + bss->rkh_pull_timeout = 1000; + bss->rkh_pull_retries = 4; #endif /* CONFIG_IEEE80211R */ bss->radius_das_time_window = 300; diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 51f9d5d..438da47 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -335,6 +335,8 @@ struct hostapd_bss_config { u8 r1_key_holder[FT_R1KH_ID_LEN]; u32 r0_key_lifetime; int rkh_pos_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 4d88376..9101665 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -690,6 +690,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 + wpa_ft_sta_deinit(sm); +#endif /* CONFIG_IEEE80211R */ 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 8abb5e2..6a3497a 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -169,6 +169,8 @@ struct wpa_auth_config { u8 r1_key_holder[FT_R1KH_ID_LEN]; u32 r0_key_lifetime; int rkh_pos_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; @@ -333,6 +335,7 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, const u8 *data, 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 */ 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 fd727fe..4e66fde 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -28,6 +28,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_pull_resp_cb_finish(void *eloop_ctx, void *timeout_ctx); +static void wpa_ft_expire_pull(void *eloop_ctx, void *timeout_ctx); static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst, @@ -412,6 +414,13 @@ static void wpa_ft_rrb_add_r1kh(struct wpa_authenticator *wpa_auth, } +void wpa_ft_sta_deinit(struct wpa_state_machine *sm) +{ + eloop_cancel_timeout(wpa_ft_expire_pull, sm, NULL); + eloop_cancel_timeout(ft_pull_resp_cb_finish, sm, NULL); +} + + void wpa_ft_deinit(struct wpa_authenticator *wpa_auth) { eloop_cancel_timeout(wpa_ft_rrb_del_r1kh, wpa_auth, ELOOP_ALL_CTX); @@ -419,12 +428,29 @@ void wpa_ft_deinit(struct wpa_authenticator *wpa_auth) } +static void wpa_ft_expire_pull(void *eloop_ctx, void *timeout_ctx) +{ + /* cancel multiple timeouts */ + eloop_cancel_timeout(wpa_ft_expire_pull, eloop_ctx, NULL); + eloop_cancel_timeout(ft_pull_resp_cb_finish, eloop_ctx, NULL); + ft_pull_resp_cb_finish(eloop_ctx, timeout_ctx); +} + + 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, *r0kh_wildcard = NULL; struct ft_r0kh_r1kh_pull_frame frame, f; + int tsecs, tusecs, first; + struct wpabuf *ft_pending_req_ies; + + 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--; if (!sm->wpa_auth->conf.r0kh_list) return -1; @@ -459,13 +485,17 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm, /* aes_wrap() does not support inplace encryption, so use a temporary * buffer for the data. */ - if (random_get_bytes(f.nonce, FT_R0KH_R1KH_PULL_NONCE_LEN)) { - wpa_printf(MSG_DEBUG, "FT: Failed to get random data for " - "nonce"); - return -1; - } - os_memcpy(sm->ft_pending_pull_nonce, f.nonce, - FT_R0KH_R1KH_PULL_NONCE_LEN); + if (first) { + if (random_get_bytes(f.nonce, FT_R0KH_R1KH_PULL_NONCE_LEN)) { + wpa_printf(MSG_DEBUG, "FT: Failed to get random data " + "for nonce"); + return -1; + } + os_memcpy(sm->ft_pending_pull_nonce, f.nonce, + FT_R0KH_R1KH_PULL_NONCE_LEN); + } else + os_memcpy(f.nonce, sm->ft_pending_pull_nonce, + FT_R0KH_R1KH_PULL_NONCE_LEN); os_memcpy(f.r0kh_id, sm->r0kh_id, FT_R0KH_ID_MAX_LEN); f.r0kh_id_len = sm->r0kh_id_len; os_memcpy(f.pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN); @@ -478,11 +508,16 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm, f.nonce, frame.nonce) < 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 == NULL) 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_send(sm->wpa_auth, r0kh->addr, (u8 *) &frame, sizeof(frame)); return 0; @@ -1192,6 +1227,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) { @@ -1468,6 +1504,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) { @@ -1650,13 +1687,20 @@ static void ft_pull_resp_cb_finish(void *eloop_ctx, void *timeout_ctx) size_t resp_ies_len; u16 status; + if (sm->ft_pending_cb == NULL || sm->ft_pending_req_ies == NULL) + 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); @@ -1689,6 +1733,10 @@ static int ft_pull_resp_cb(struct wpa_state_machine *sm, void *ctx) wpa_printf(MSG_DEBUG, "FT: Response to a pending pull request for " MACSTR " - process from timeout", MAC2STR(sm->addr)); + + eloop_cancel_timeout(wpa_ft_expire_pull, sm, NULL); + eloop_cancel_timeout(ft_pull_resp_cb_finish, sm, NULL); + eloop_register_timeout(0, 0, ft_pull_resp_cb_finish, sm, NULL); if (info->r0kh_wildcard && sm->wpa_auth->conf.rkh_pos_timeout) diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index c99aefc..57ca999 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -70,6 +70,8 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, wconf->r0_key_lifetime = conf->r0_key_lifetime; wconf->reassociation_deadline = conf->reassociation_deadline; wconf->rkh_pos_timeout = conf->rkh_pos_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; diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index 72b7eb3..c634c32 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -131,6 +131,7 @@ struct wpa_state_machine { u8 ft_pending_pull_nonce[FT_R0KH_R1KH_PULL_NONCE_LEN]; u8 ft_pending_auth_transaction; u8 ft_pending_current_ap[ETH_ALEN]; + int ft_pending_pull_left_retries; #endif /* CONFIG_IEEE80211R */ int pending_1_of_4_timeout; -- 2.1.4 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap