[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