[PATCH v2 07/33] FT: resend pull request

M. Braun michael-dev at fami-braun.de
Sat Sep 24 14:07:51 PDT 2016


From: Michael Braun <michael-dev at fami-braun.de>

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 at fami-braun.de>
---
 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




More information about the Hostap mailing list