[PATCH 23/44] FT: negative caching when using wilcard r0kh

michael-dev at fami-braun.de michael-dev at fami-braun.de
Wed Feb 24 03:53:29 PST 2016


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

When a station uses an invalid or offline r0kh_id, requests are always
broadcasted. To avoid this, r0kh is required to always reply using a NACK
and target ap uses a timer to detect non replying r0kh.

If r0kh does not reply, a temporary blacklist entry is added to r0kh_list.

Signed-off-by: Michael Braun <michael-dev at fami-braun.de>
---
 hostapd/config_file.c  |  2 ++
 hostapd/hostapd.conf   |  6 ++++
 src/ap/ap_config.c     |  1 +
 src/ap/ap_config.h     |  1 +
 src/ap/wpa_auth.h      |  3 +-
 src/ap/wpa_auth_ft.c   | 89 ++++++++++++++++++++++++++++++++++----------------
 src/ap/wpa_auth_glue.c |  1 +
 7 files changed, 73 insertions(+), 30 deletions(-)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 8998b0f..2631e8d 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2545,6 +2545,8 @@ 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_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) {
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 1274566..728712e 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1305,6 +1305,7 @@ own_ip_addr=127.0.0.1
 # Wildcard entry: Upon receiving a request from an R1KH not yet known,
 #                 it will be added to this list and thus receive push
 #                 notifications.
+#                 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
@@ -1328,6 +1329,11 @@ own_ip_addr=127.0.0.1
 #rkh_pull_timeout = 1000 (default = 1s)
 #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 = 86400
+
 # 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 cffcc30..c2361e0 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -94,6 +94,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
 	bss->ft_over_ds = 1;
 	bss->r0_key_lifetime = 60; /* same as eap_reauth_period */
 	bss->rkh_pos_timeout = 86400;
+	bss->rkh_neg_timeout = 60;
 	bss->rkh_pull_timeout = 1000;
 	bss->rkh_pull_retries = 4;
 #endif /* CONFIG_IEEE80211R */
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 57d0b15..4d1aee5 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -326,6 +326,7 @@ struct hostapd_bss_config {
 	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;
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 317a9be..b73c046 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -91,7 +91,7 @@ struct ft_r0kh_r1kh_resp_frame {
 	u8 pmk_r1[PMK_LEN];
 	u8 pmk_r1_name[WPA_PMK_NAME_LEN];
 	le16 pairwise;
-	le16 expiresIn;
+	le16 expiresIn; /* 0xffff for no-entry */
 	struct ft_vlan vlan;
 	u8 pad[FT_R0KH_R1KH_RESP_PAD_LEN]; /* 8-octet boundary for AES block */
 	u8 key_wrap_extra[8];
@@ -183,6 +183,7 @@ struct wpa_auth_config {
 	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;
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 918ceaf..6158212 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -550,9 +550,21 @@ void wpa_ft_deinit(struct wpa_authenticator *wpa_auth)
 
 static void wpa_ft_expire_pull(void *eloop_ctx, void *timeout_ctx)
 {
+	struct wpa_state_machine *sm = eloop_ctx;
+
+	if (sm->ft_pending_pull_left_retries <= 0 &&
+	    sm->wpa_auth->conf.rkh_neg_timeout) {
+		/* final timeout, block this r0kh_id */
+		wpa_hexdump(MSG_DEBUG, "FT: Blacklist R0KH-ID",
+			    sm->r0kh_id, sm->r0kh_id_len);
+		wpa_ft_rrb_add_r0kh(sm->wpa_auth, NULL,
+				    (u8 *) "\x00\x00\x00\x00\x00\x00",
+				    sm->r0kh_id, sm->r0kh_id_len,
+				    sm->wpa_auth->conf.rkh_neg_timeout);
+	}
 	/* cancel multiple timeouts */
-	eloop_cancel_timeout(wpa_ft_expire_pull, eloop_ctx, NULL);
-	eloop_cancel_timeout(ft_pull_resp_cb_finish, eloop_ctx, NULL);
+	eloop_cancel_timeout(wpa_ft_expire_pull, sm, NULL);
+	eloop_cancel_timeout(ft_pull_resp_cb_finish, sm, NULL);
 	ft_pull_resp_cb_finish(eloop_ctx, timeout_ctx);
 }
 
@@ -593,6 +605,11 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
 			    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;
+	}
 
 	wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH "
 		   "address " MACSTR, MAC2STR(r0kh->addr));
@@ -1840,17 +1857,17 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
 				&pairwise, &vlan, &expiresIn) < 0) {
 		wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name found for "
 			   "PMK-R1 pull");
-		return -1;
+		r.expiresIn = 0xffff;
+	} else {
+		wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id,
+				  r.pmk_r1, r.pmk_r1_name);
+		wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", r.pmk_r1, PMK_LEN);
+		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);
+		r.expiresIn = host_to_le16(expiresIn);
 	}
-
-	wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id,
-			  r.pmk_r1, r.pmk_r1_name);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", r.pmk_r1, PMK_LEN);
-	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);
-	r.expiresIn = host_to_le16(expiresIn);
 	os_memset(r.pad, 0, sizeof(r.pad));
 
 	if (aes_wrap(r1kh->key, sizeof(r1kh->key),
@@ -1923,6 +1940,8 @@ 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));
 
+	if (frame->expiresIn == 0xffff)
+		sm->ft_pending_pull_left_retries = 0;
 	eloop_cancel_timeout(wpa_ft_expire_pull, sm, NULL);
 	eloop_cancel_timeout(ft_pull_resp_cb_finish, sm, NULL);
 
@@ -1998,24 +2017,36 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
 	}
 
 	pairwise = le_to_host16(f.pairwise);
-	expiresIn = le_to_host16(f.expiresIn);
-	wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
-		    f.nonce, sizeof(f.nonce));
-	wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR " S1KH-ID="
-		   MACSTR " pairwise=0x%x expiresIn=%d",
-		   MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise, expiresIn);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 pull - PMK-R1",
-			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] ? "+" : "");
+	if (f.expiresIn == 0xffff) {
+		res = 0;
+		wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
+			    f.nonce, sizeof(f.nonce));
+		wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR
+			   " S1KH-ID=" MACSTR " NACK",
+			   MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id));
+	} else {
+		expiresIn = le_to_host16(f.expiresIn);
+		wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
+			    f.nonce, sizeof(f.nonce));
+		wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR
+			   " S1KH-ID=" MACSTR " pairwise=0x%x expiresIn=%d",
+			   MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise,
+			   expiresIn);
+		wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 pull - PMK-R1",
+				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] ? "+" : "");
+
+		if (expiresIn <= 0 || expiresIn > maxExpiresIn)
+			expiresIn = maxExpiresIn;
+		res = wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1,
+					  f.pmk_r1_name, pairwise, f.vlan,
+					  expiresIn);
+	}
 
-	if (expiresIn <= 0 || expiresIn > maxExpiresIn)
-		expiresIn = maxExpiresIn;
-	res = wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
-				  pairwise, f.vlan, expiresIn);
 	wpa_printf(MSG_DEBUG, "FT: Look for pending pull request");
 
 	ctx.frame = &f;
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 2cd1260..e7fc46a 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -78,6 +78,7 @@ 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_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;
-- 
1.9.1




More information about the Hostap mailing list