From 8b5ddda5fba0dc9838f05d856cb5f831dbd7a1ea Mon Sep 17 00:00:00 2001 From: Jeffin Mammen Date: Thu, 6 Jul 2017 13:57:54 +0300 Subject: [PATCH] FILS: Add HLP support with driver-based AP SME This allows HLP processing to postpone association processing in hostapd_notify_assoc(). Signed-off-by: Jouni Malinen --- src/ap/drv_callbacks.c | 109 +++++++++++++++++++++++++++++++++++++++-- src/ap/fils_hlp.c | 6 ++- src/ap/hostapd.h | 2 + src/ap/ieee802_11.c | 6 ++- src/ap/sta_info.h | 1 + src/ap/wpa_auth.c | 9 +++- src/ap/wpa_auth.h | 3 +- 7 files changed, 127 insertions(+), 9 deletions(-) diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index 9e30abf02..7e948d25e 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -38,6 +38,68 @@ #include "beacon.h" #include "mbo_ap.h" #include "dpp_hostapd.h" +#include "fils_hlp.h" + + +#ifdef CONFIG_FILS +void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd, + struct sta_info *sta) +{ + u16 reply_res = WLAN_STATUS_SUCCESS; + struct ieee802_11_elems elems; + u8 buf[IEEE80211_MAX_MMPDU_SIZE], *p = buf; + int new_assoc; + + wpa_printf(MSG_DEBUG, "%s FILS: Finish association with " MACSTR, + __func__, MAC2STR(sta->addr)); + eloop_cancel_timeout(fils_hlp_timeout, hapd, sta); + if (!sta->fils_pending_assoc_req) + return; + + ieee802_11_parse_elems(sta->fils_pending_assoc_req, + sta->fils_pending_assoc_req_len, &elems, 0); + if (!elems.fils_session) { + wpa_printf(MSG_DEBUG, "%s failed to find FILS Session element", + __func__); + return; + } + + p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p, + elems.fils_session, + sta->fils_hlp_resp); + + reply_res = hostapd_sta_assoc(hapd, sta->addr, + sta->fils_pending_assoc_is_reassoc, + WLAN_STATUS_SUCCESS, + buf, p - buf); + ap_sta_set_authorized(hapd, sta, 1); + new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; + sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; + sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; + hostapd_set_sta_flags(hapd, sta); + wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS); + ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); + hostapd_new_assoc_sta(hapd, sta, !new_assoc); + os_free(sta->fils_pending_assoc_req); + sta->fils_pending_assoc_req = NULL; + sta->fils_pending_assoc_req_len = 0; + wpabuf_free(sta->fils_hlp_resp); + sta->fils_hlp_resp = NULL; + wpabuf_free(sta->hlp_dhcp_discover); + sta->hlp_dhcp_discover = NULL; + fils_hlp_deinit(hapd); + + /* + * Remove the station in case transmission of a success response fails + * (the STA was added associated to the driver) or if the station was + * previously added unassociated. + */ + if (reply_res != WLAN_STATUS_SUCCESS || sta->added_unassoc) { + hostapd_drv_sta_remove(hapd, sta->addr); + sta->added_unassoc = 0; + } +} +#endif /* CONFIG_FILS */ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, @@ -388,6 +450,8 @@ skip_wpa_check: if (sta->auth_alg == WLAN_AUTH_FILS_SK || sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || sta->auth_alg == WLAN_AUTH_FILS_PK) { + int delay_assoc = 0; + if (!wpa_fils_validate_fils_session(sta->wpa_sm, req_ies, req_ies_len, sta->fils_session)) { @@ -404,14 +468,51 @@ skip_wpa_check: return WLAN_STATUS_UNSPECIFIED_FAILURE; } - if (!elems.fils_session) { + if (fils_process_hlp(hapd, sta, req_ies, req_ies_len) > 0) { wpa_printf(MSG_DEBUG, - "FILS: Session element not found"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; + "FILS: Delaying Assoc Response (HLP)"); + delay_assoc = 1; + } else { + wpa_printf(MSG_DEBUG, + "FILS: Going ahead with Assoc Response (no HLP)"); } + if (sta) { + wpa_printf(MSG_DEBUG, "FILS: HLP callback cleanup"); + eloop_cancel_timeout(fils_hlp_timeout, hapd, sta); + os_free(sta->fils_pending_assoc_req); + sta->fils_pending_assoc_req = NULL; + sta->fils_pending_assoc_req_len = 0; + wpabuf_free(sta->fils_hlp_resp); + sta->fils_hlp_resp = NULL; + sta->fils_drv_assoc_finish = 0; + } + + if (sta && delay_assoc && status == WLAN_STATUS_SUCCESS) { + u8 *req_tmp; + + req_tmp = os_malloc(req_ies_len); + if (!req_tmp) { + wpa_printf(MSG_DEBUG, + "FILS: buffer allocation failed for assoc req"); + goto fail; + } + os_memcpy(req_tmp, req_ies, req_ies_len); + sta->fils_pending_assoc_req = req_tmp; + sta->fils_pending_assoc_req_len = req_ies_len; + sta->fils_pending_assoc_is_reassoc = reassoc; + sta->fils_drv_assoc_finish = 1; + wpa_printf(MSG_DEBUG, + "FILS: Waiting for HLP processing before sending (Re)Association Response frame to " + MACSTR, MAC2STR(sta->addr)); + eloop_register_timeout( + 0, hapd->conf->fils_hlp_wait_time * 1024, + fils_hlp_timeout, hapd, sta); + return 0; + } p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p, - elems.fils_session); + elems.fils_session, + sta->fils_hlp_resp); wpa_hexdump(MSG_DEBUG, "FILS Assoc Resp BUF (IEs)", buf, p - buf); } diff --git a/src/ap/fils_hlp.c b/src/ap/fils_hlp.c index c5e7aec4a..2370a8bbd 100644 --- a/src/ap/fils_hlp.c +++ b/src/ap/fils_hlp.c @@ -314,7 +314,11 @@ static void fils_dhcp_handler(int sd, void *eloop_ctx, void *sock_ctx) left -= len; } wpabuf_free(resp); - fils_hlp_finish_assoc(hapd, sta); + + if (sta->fils_drv_assoc_finish) + hostapd_notify_assoc_fils_finish(hapd, sta); + else + fils_hlp_finish_assoc(hapd, sta); } diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 2afeee218..8580d8073 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -552,6 +552,8 @@ int hostapd_register_probereq_cb(struct hostapd_data *hapd, void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr); /* drv_callbacks.c (TODO: move to somewhere else?) */ +void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd, + struct sta_info *sta); int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, const u8 *ie, size_t ielen, int reassoc); void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr); diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index ac89c908e..64db441ac 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -2850,7 +2850,10 @@ void fils_hlp_timeout(void *eloop_ctx, void *eloop_data) wpa_printf(MSG_DEBUG, "FILS: HLP response timeout - continue with association response for " MACSTR, MAC2STR(sta->addr)); - fils_hlp_finish_assoc(hapd, sta); + if (sta->fils_drv_assoc_finish) + hostapd_notify_assoc_fils_finish(hapd, sta); + else + fils_hlp_finish_assoc(hapd, sta); } #endif /* CONFIG_FILS */ @@ -3204,6 +3207,7 @@ static void handle_assoc(struct hostapd_data *hapd, sta->fils_pending_assoc_req = tmp; sta->fils_pending_assoc_req_len = left; sta->fils_pending_assoc_is_reassoc = reassoc; + sta->fils_drv_assoc_finish = 0; wpa_printf(MSG_DEBUG, "FILS: Waiting for HLP processing before sending (Re)Association Response frame to " MACSTR, MAC2STR(sta->addr)); diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index 0a2305084..271128b9e 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -232,6 +232,7 @@ struct sta_info { unsigned int fils_pending_assoc_is_reassoc:1; unsigned int fils_dhcp_rapid_commit_proxy:1; unsigned int fils_erp_pmkid_set:1; + unsigned int fils_drv_assoc_finish:1; struct wpabuf *fils_hlp_resp; struct wpabuf *hlp_dhcp_discover; void (*fils_pending_cb)(struct hostapd_data *hapd, struct sta_info *sta, diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index bb86a92c4..b1edce813 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -2282,6 +2282,11 @@ int wpa_fils_validate_key_confirm(struct wpa_state_machine *sm, const u8 *ies, return -1; } + if (!elems.fils_session) { + wpa_printf(MSG_DEBUG, "FILS: No FILS Session element"); + return -1; + } + if (!elems.fils_key_confirm) { wpa_printf(MSG_DEBUG, "FILS: No FILS Key Confirm element"); return -1; @@ -2565,7 +2570,7 @@ int fils_set_tk(struct wpa_state_machine *sm) u8 * hostapd_eid_assoc_fils_session(struct wpa_state_machine *sm, u8 *buf, - const u8 *fils_session) + const u8 *fils_session, struct wpabuf *hlp) { struct wpabuf *plain; u8 *pos = buf; @@ -2577,7 +2582,7 @@ u8 * hostapd_eid_assoc_fils_session(struct wpa_state_machine *sm, u8 *buf, os_memcpy(pos, fils_session, FILS_SESSION_LEN); pos += FILS_SESSION_LEN; - plain = fils_prepare_plainbuf(sm, NULL); + plain = fils_prepare_plainbuf(sm, hlp); if (!plain) { wpa_printf(MSG_DEBUG, "FILS: Plain buffer prep failed"); return NULL; diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 3b69789a1..df4fac5cf 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -409,7 +409,8 @@ int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf, const struct wpabuf *hlp); int fils_set_tk(struct wpa_state_machine *sm); u8 * hostapd_eid_assoc_fils_session(struct wpa_state_machine *sm, u8 *eid, - const u8 *fils_session); + const u8 *fils_session, + struct wpabuf *fils_hlp_resp); const u8 * wpa_fils_validate_fils_session(struct wpa_state_machine *sm, const u8 *ies, size_t ies_len, const u8 *fils_session);