[PATCH v2 06/33] FT: cache newly detected R0KH / R1KH when using wildcard
M. Braun
michael-dev at fami-braun.de
Sat Sep 24 14:07:50 PDT 2016
From: Michael Braun <michael-dev at fami-braun.de>
This implements temporary positive caching for R0KH and R1KH seen when
using wilcard r0kh/r1kh configuration. Cache entries expire after 1d.
In order to free newly created stations later, the r*kh_list start pointer
in conf needs to be updateable from wpa_auto_ft.c, where only wconf is
accessed.
Signed-off-by: Michael Braun <michael-dev at fami-braun.de>
---
hostapd/config_file.c | 2 +
hostapd/hostapd.conf | 11 +++-
src/ap/ap_config.c | 1 +
src/ap/ap_config.h | 1 +
src/ap/wpa_auth.c | 1 +
src/ap/wpa_auth.h | 6 +-
src/ap/wpa_auth_ft.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++---
src/ap/wpa_auth_glue.c | 5 +-
8 files changed, 169 insertions(+), 13 deletions(-)
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 2d67282..288cdf1 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2543,6 +2543,8 @@ 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, "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 26546de..c6b8cae 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1306,7 +1306,9 @@ own_ip_addr=127.0.0.1
#r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f
#r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff
# And so on.. One line per R0KH.
-# Wildcard entry:
+# Wildcard entry: Upon receiving a request from an R1KH not yet known,
+# it will be added to this list and thus receive push
+# notifications.
#r0kh=ff:ff:ff:ff:ff:ff * 00112233445566778899aabbccddeeff
# List of R1KHs in the same Mobility Domain
@@ -1317,9 +1319,14 @@ own_ip_addr=127.0.0.1
#r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f
#r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff
# And so on.. One line per R1KH.
-# Wildcard entry:
+# Wildcard entry: Upon receiving a response from R0KH, it will be added to this
+# list, so subsequent requests won't be broadcasted.
#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 cache; -1 -> do not expire
+#rkh_pos_timeout = 86400 (default = 1d)
+
# 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 228de2b..b43890d 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -90,6 +90,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
#ifdef CONFIG_IEEE80211R
bss->ft_over_ds = 1;
+ bss->rkh_pos_timeout = 86400;
#endif /* CONFIG_IEEE80211R */
bss->radius_das_time_window = 300;
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index f9b4306..51f9d5d 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -334,6 +334,7 @@ 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;
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 3587086..4d88376 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -516,6 +516,7 @@ void wpa_deinit(struct wpa_authenticator *wpa_auth)
#ifdef CONFIG_IEEE80211R
wpa_ft_pmk_cache_deinit(wpa_auth->ft_pmk_cache);
wpa_auth->ft_pmk_cache = NULL;
+ wpa_ft_deinit(wpa_auth);
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_P2P
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 39a1afd..8abb5e2 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -168,9 +168,10 @@ 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;
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;
@@ -331,6 +332,7 @@ int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len);
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);
#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 04e9bf8..fd727fe 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -312,6 +312,113 @@ static int wpa_ft_fetch_pmk_r1(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;
+ r0kh = *wpa_auth->conf.r0kh_list;
+ while (r0kh) {
+ if (r0kh != timeout_ctx) {
+ r0kh = r0kh->next;
+ continue;
+ }
+ if (prev)
+ prev->next = r0kh->next;
+ else
+ *wpa_auth->conf.r0kh_list = r0kh->next;
+ os_free(r0kh);
+ break;
+ }
+}
+
+
+static void wpa_ft_rrb_add_r0kh(struct wpa_authenticator *wpa_auth,
+ struct ft_remote_r0kh *r0kh_wildcard,
+ const u8 *src_addr,
+ u8 *r0kh_id, size_t id_len, int timeout)
+{
+ struct ft_remote_r0kh *r0kh;
+
+ if (!wpa_auth->conf.r0kh_list)
+ return;
+
+ r0kh = os_zalloc(sizeof(*r0kh));
+ if (r0kh == NULL)
+ return;
+
+ os_memcpy(r0kh->addr, src_addr, sizeof(r0kh->addr));
+ os_memcpy(r0kh->id, r0kh_id, sizeof(r0kh->id));
+ r0kh->id_len = id_len;
+ if (r0kh_wildcard)
+ os_memcpy(r0kh->key, r0kh_wildcard->key, sizeof(r0kh->key));
+ r0kh->next = *wpa_auth->conf.r0kh_list;
+ *wpa_auth->conf.r0kh_list = r0kh;
+ timeout = wpa_auth->conf.rkh_pos_timeout;
+
+ if (timeout > 0)
+ eloop_register_timeout(timeout, 0, wpa_ft_rrb_del_r0kh,
+ wpa_auth, 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;
+ r1kh = *wpa_auth->conf.r1kh_list;
+ while (r1kh) {
+ if (r1kh != timeout_ctx) {
+ r1kh = r1kh->next;
+ continue;
+ }
+ if (prev)
+ prev->next = r1kh->next;
+ else
+ *wpa_auth->conf.r1kh_list = r1kh->next;
+ os_free(r1kh);
+ break;
+ }
+}
+
+
+static void wpa_ft_rrb_add_r1kh(struct wpa_authenticator *wpa_auth,
+ struct ft_remote_r1kh *r1kh_wildcard,
+ const u8 *src_addr, u8 *r1kh_id, int timeout)
+{
+ struct ft_remote_r1kh *r1kh;
+
+ if (!wpa_auth->conf.r1kh_list)
+ return;
+
+ r1kh = os_zalloc(sizeof(*r1kh));
+ if (r1kh == NULL)
+ return;
+
+ 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);
+}
+
+
+void wpa_ft_deinit(struct wpa_authenticator *wpa_auth)
+{
+ eloop_cancel_timeout(wpa_ft_rrb_del_r1kh, wpa_auth, ELOOP_ALL_CTX);
+ eloop_cancel_timeout(wpa_ft_rrb_del_r0kh, wpa_auth, ELOOP_ALL_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)
@@ -319,7 +426,9 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
struct ft_remote_r0kh *r0kh, *r0kh_wildcard = NULL;
struct ft_r0kh_r1kh_pull_frame frame, f;
- r0kh = sm->wpa_auth->conf.r0kh_list;
+ if (!sm->wpa_auth->conf.r0kh_list)
+ return -1;
+ r0kh = *sm->wpa_auth->conf.r0kh_list;
while (r0kh) {
if (r0kh->id_len == sm->r0kh_id_len &&
os_memcmp_const(r0kh->id, sm->r0kh_id, sm->r0kh_id_len) ==
@@ -1441,7 +1550,9 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
if (data_len < sizeof(f))
return -1;
- r1kh = wpa_auth->conf.r1kh_list;
+ if (!wpa_auth->conf.r1kh_list)
+ return -1;
+ r1kh = *wpa_auth->conf.r1kh_list;
while (r1kh) {
if (os_memcmp(r1kh->addr, src_addr, ETH_ALEN) == 0)
break;
@@ -1486,6 +1597,10 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR " S1KH-ID="
MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id));
+ if (r1kh == r1kh_wildcard && wpa_auth->conf.rkh_pos_timeout)
+ wpa_ft_rrb_add_r1kh(wpa_auth, r1kh_wildcard, src_addr,
+ f.r1kh_id, wpa_auth->conf.rkh_pos_timeout);
+
os_memset(&resp, 0, sizeof(resp));
resp.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
resp.packet_type = FT_PACKET_R0KH_R1KH_RESP;
@@ -1553,9 +1668,16 @@ static void ft_pull_resp_cb_finish(void *eloop_ctx, void *timeout_ctx)
}
+struct ft_pull_resp_cb_ctx {
+ struct ft_r0kh_r1kh_resp_frame *frame;
+ struct ft_remote_r0kh *r0kh_wildcard;
+ u8 src_addr[ETH_ALEN];
+};
+
static int ft_pull_resp_cb(struct wpa_state_machine *sm, void *ctx)
{
- struct ft_r0kh_r1kh_resp_frame *frame = ctx;
+ struct ft_pull_resp_cb_ctx *info = ctx;
+ struct ft_r0kh_r1kh_resp_frame *frame = info->frame;
if (os_memcmp(frame->s1kh_id, sm->addr, ETH_ALEN) != 0)
return 0;
@@ -1568,6 +1690,13 @@ 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_register_timeout(0, 0, ft_pull_resp_cb_finish, sm, NULL);
+
+ if (info->r0kh_wildcard && sm->wpa_auth->conf.rkh_pos_timeout)
+ wpa_ft_rrb_add_r0kh(sm->wpa_auth, info->r0kh_wildcard,
+ info->src_addr, sm->r0kh_id,
+ sm->r0kh_id_len,
+ sm->wpa_auth->conf.rkh_pos_timeout);
+
return 1;
}
@@ -1581,13 +1710,16 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
u8 *plain;
struct ft_remote_r0kh *r0kh, *r0kh_wildcard = NULL;
int pairwise, res;
+ struct ft_pull_resp_cb_ctx ctx;
wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull response");
if (data_len < sizeof(f))
return -1;
- r0kh = wpa_auth->conf.r0kh_list;
+ if (!wpa_auth->conf.r0kh_list)
+ return -1;
+ r0kh = *wpa_auth->conf.r0kh_list;
while (r0kh) {
if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
break;
@@ -1640,7 +1772,12 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
res = wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
pairwise);
wpa_printf(MSG_DEBUG, "FT: Look for pending pull request");
- wpa_auth_for_each_sta(wpa_auth, ft_pull_resp_cb, &f);
+
+ ctx.frame = &f;
+ os_memcpy(ctx.src_addr, src_addr, ETH_ALEN);
+ ctx.r0kh_wildcard = (r0kh == r0kh_wildcard) ? r0kh_wildcard : NULL;
+
+ wpa_auth_for_each_sta(wpa_auth, ft_pull_resp_cb, &ctx);
os_memset(f.pmk_r1, 0, PMK_LEN);
return res ? 0 : -1;
@@ -1664,7 +1801,9 @@ static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
if (data_len < sizeof(f))
return -1;
- r0kh = wpa_auth->conf.r0kh_list;
+ if (!wpa_auth->conf.r0kh_list)
+ return -1;
+ r0kh = *wpa_auth->conf.r0kh_list;
while (r0kh) {
if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
break;
@@ -1909,6 +2048,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) {
@@ -1924,7 +2065,7 @@ 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;
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 12b9ccc..c99aefc 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -69,8 +69,9 @@ 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->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;
--
2.1.4
More information about the Hostap
mailing list