From 5732b770f436b73f12d1b73a8f574dbba2a4aa2a Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 29 Jan 2017 14:07:20 +0200 Subject: [PATCH] FILS: Allow FILS HLP requests to be added The new wpa_supplicant control interface commands FILS_HLP_REQ_FLUSH and FILS_HLP_REQ_ADD can now be used to request FILS HLP requests to be added to the (Re)Association Request frame whenever FILS authentication is used. FILS_HLP_REQ_ADD parameters use the following format: Signed-off-by: Jouni Malinen --- src/rsn_supp/wpa.c | 40 +++++++++++++++++++++++++++--- src/rsn_supp/wpa.h | 4 ++- wpa_supplicant/ctrl_iface.c | 41 +++++++++++++++++++++++++++++++ wpa_supplicant/sme.c | 27 +++++++++++++++++++- wpa_supplicant/wpa_supplicant.c | 16 ++++++++++++ wpa_supplicant/wpa_supplicant_i.h | 12 ++++++++- 6 files changed, 134 insertions(+), 6 deletions(-) diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index b2fc0ba7d..696ea04a3 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -3483,11 +3483,18 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *data, size_t len) struct wpabuf * fils_build_assoc_req(struct wpa_sm *sm, const u8 **kek, size_t *kek_len, const u8 **snonce, - const u8 **anonce) + const u8 **anonce, + const struct wpabuf **hlp, + unsigned int num_hlp) { struct wpabuf *buf; + size_t len; + unsigned int i; - buf = wpabuf_alloc(1000); + len = 1000; + for (i = 0; hlp && i < num_hlp; i++) + len += 10 + wpabuf_len(hlp[i]); + buf = wpabuf_alloc(len); if (!buf) return NULL; @@ -3510,7 +3517,34 @@ struct wpabuf * fils_build_assoc_req(struct wpa_sm *sm, const u8 **kek, wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_KEY_CONFIRM); wpabuf_put_data(buf, sm->fils_key_auth_sta, sm->fils_key_auth_len); - /* TODO: FILS HLP Container */ + /* FILS HLP Container */ + for (i = 0; hlp && i < num_hlp; i++) { + const u8 *pos = wpabuf_head(hlp[i]); + size_t left = wpabuf_len(hlp[i]); + + wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */ + if (left <= 254) + len = 1 + left; + else + len = 255; + wpabuf_put_u8(buf, len); /* Length */ + /* Element ID Extension */ + wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_HLP_CONTAINER); + /* Destination MAC Address, Source MAC Address, HLP Packet. + * HLP Packet is in MSDU format (i.e., included the LLC/SNAP + * header when LPD is used). */ + wpabuf_put_data(buf, pos, len - 1); + pos += len - 1; + left -= len - 1; + while (left) { + wpabuf_put_u8(buf, WLAN_EID_FRAGMENT); + len = left > 255 ? 255 : left; + wpabuf_put_u8(buf, len); + wpabuf_put_data(buf, pos, len); + pos += len; + left -= len; + } + } /* TODO: FILS IP Address Assignment */ diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index c9f278aab..f0eeec810 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -436,7 +436,9 @@ struct wpabuf * fils_build_auth(struct wpa_sm *sm); int fils_process_auth(struct wpa_sm *sm, const u8 *data, size_t len); struct wpabuf * fils_build_assoc_req(struct wpa_sm *sm, const u8 **kek, size_t *kek_len, const u8 **snonce, - const u8 **anonce); + const u8 **anonce, + const struct wpabuf **hlp, + unsigned int num_hlp); int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len); int wpa_fils_is_completed(struct wpa_sm *sm); diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 39d2ff9ce..ead5fe638 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -9153,6 +9153,40 @@ static int wpas_ctrl_iface_mesh_pmksa_add(struct wpa_supplicant *wpa_s, #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ +#ifdef CONFIG_FILS +static int wpas_ctrl_iface_fils_hlp_req_add(struct wpa_supplicant *wpa_s, + const char *cmd) +{ + struct fils_hlp_req *req; + const char *pos; + + /* format: */ + + req = os_zalloc(sizeof(*req)); + if (!req) + return -1; + + if (hwaddr_aton(cmd, req->dst)) + goto fail; + + pos = os_strchr(cmd, ' '); + if (!pos) + goto fail; + pos++; + req->pkt = wpabuf_parse_bin(pos); + if (!req->pkt) + goto fail; + + dl_list_add_tail(&wpa_s->fils_hlp_req, &req->list); + return 0; +fail: + wpabuf_free(req->pkt); + os_free(req); + return -1; +} +#endif /* CONFIG_FILS */ + + static int wpas_ctrl_cmd_debug_level(const char *cmd) { if (os_strcmp(cmd, "PING") == 0 || @@ -9881,6 +9915,13 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "GET_PREF_FREQ_LIST ", 19) == 0) { reply_len = wpas_ctrl_iface_get_pref_freq_list( wpa_s, buf + 19, reply, reply_size); +#ifdef CONFIG_FILS + } else if (os_strncmp(buf, "FILS_HLP_REQ_ADD ", 17) == 0) { + if (wpas_ctrl_iface_fils_hlp_req_add(wpa_s, buf + 17)) + reply_len = -1; + } else if (os_strcmp(buf, "FILS_HLP_REQ_FLUSH") == 0) { + wpas_flush_fils_hlp_req(wpa_s); +#endif /* CONFIG_FILS */ } else { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index f478836db..744bc7b66 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -995,10 +995,35 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, if (auth_type == WLAN_AUTH_FILS_SK) { struct wpabuf *buf; const u8 *snonce, *anonce; + const unsigned int max_hlp = 20; + struct wpabuf *hlp[max_hlp]; + unsigned int i, num_hlp = 0; + struct fils_hlp_req *req; + + dl_list_for_each(req, &wpa_s->fils_hlp_req, struct fils_hlp_req, + list) { + hlp[num_hlp] = wpabuf_alloc(2 * ETH_ALEN + 6 + + wpabuf_len(req->pkt)); + if (!hlp[num_hlp]) + break; + wpabuf_put_data(hlp[num_hlp], req->dst, ETH_ALEN); + wpabuf_put_data(hlp[num_hlp], wpa_s->own_addr, + ETH_ALEN); + wpabuf_put_data(hlp[num_hlp], + "\xaa\xaa\x03\x00\x00\x00", 6); + wpabuf_put_buf(hlp[num_hlp], req->pkt); + num_hlp++; + if (num_hlp >= max_hlp) + break; + } buf = fils_build_assoc_req(wpa_s->wpa, ¶ms.fils_kek, ¶ms.fils_kek_len, &snonce, - &anonce); + &anonce, + (const struct wpabuf **) hlp, + num_hlp); + for (i = 0; i < num_hlp; i++) + wpabuf_free(hlp[i]); if (!buf) return; /* TODO: Make wpa_s->sme.assoc_req_ie use dynamic allocation */ diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index bc59c6760..39d57663c 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -420,6 +420,19 @@ static void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s) } +void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s) +{ + struct fils_hlp_req *req; + + while ((req = dl_list_first(&wpa_s->fils_hlp_req, struct fils_hlp_req, + list)) != NULL) { + dl_list_del(&req->list); + wpabuf_free(req->pkt); + os_free(req); + } +} + + static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) { int i; @@ -602,6 +615,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) } #endif /* CONFIG_MESH */ #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ + + wpas_flush_fils_hlp_req(wpa_s); } @@ -3719,6 +3734,7 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent) wpa_s->sched_scanning = 0; dl_list_init(&wpa_s->bss_tmp_disallowed); + dl_list_init(&wpa_s->fils_hlp_req); return wpa_s; } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 2fb32e28f..cb6484783 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -466,6 +466,12 @@ struct external_pmksa_cache { void *pmksa_cache; }; +struct fils_hlp_req { + struct dl_list list; + u8 dst[ETH_ALEN]; + struct wpabuf *pkt; +}; + /** * struct wpa_supplicant - Internal data for wpa_supplicant interface * @@ -747,7 +753,7 @@ struct wpa_supplicant { u8 ssid[SSID_MAX_LEN]; size_t ssid_len; int freq; - u8 assoc_req_ie[300]; + u8 assoc_req_ie[1500]; size_t assoc_req_ie_len; int mfp; int ft_used; @@ -1103,6 +1109,9 @@ struct wpa_supplicant { struct os_reltime lci_time; struct os_reltime beacon_rep_scan; + + /* FILS HLP requests (struct fils_hlp_req) */ + struct dl_list fils_hlp_req; }; @@ -1227,6 +1236,7 @@ int wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res, struct scan_info *info); void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s); +void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s); /* MBO functions */