From 8c41734e5de118a6a20589bde306a11bef922e1d Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 1 Dec 2018 20:10:54 +0200 Subject: [PATCH] FT: Fix Reassociation Request IEs during FT protocol The previous implementation ended up replacing all pending IEs prepared for Association Request frame with the FT specific IEs (RSNE, MDE, FTE) when going through FT protocol reassociation with the wpa_supplicant SME. This resulted in dropping all other IEs that might have been prepared for the association (e.g., Extended Capabilities, RM Enabled Capabilities, Supported Operating Classes, vendor specific additions). Fix this by replacing only the known FT specific IEs with the appropriate values for FT protocol while maintaining other already prepared elements. Signed-off-by: Jouni Malinen --- wpa_supplicant/sme.c | 80 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 2f5924e73..dd42a1925 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -1559,6 +1559,8 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, params.wpa_ie = wpa_s->sme.assoc_req_ie_len ? wpa_s->sme.assoc_req_ie : NULL; params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len; + wpa_hexdump(MSG_DEBUG, "SME: Association Request IEs", + params.wpa_ie, params.wpa_ie_len); params.pairwise_suite = wpa_s->pairwise_cipher; params.group_suite = wpa_s->group_cipher; params.mgmt_group_suite = wpa_s->mgmt_group_cipher; @@ -1579,9 +1581,85 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, ¶ms); #endif /* CONFIG_VHT_OVERRIDES */ #ifdef CONFIG_IEEE80211R - if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) { + if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies && + get_ie(wpa_s->sme.ft_ies, wpa_s->sme.ft_ies_len, + WLAN_EID_RIC_DATA)) { + /* There seems to be a pretty inconvenient bug in the Linux + * kernel IE splitting functionality when RIC is used. For now, + * skip correct behavior in IE construction here (i.e., drop the + * additional non-FT-specific IEs) to avoid kernel issues. This + * is fine since RIC is used only for testing purposes in the + * current implementation. */ + wpa_printf(MSG_INFO, + "SME: Linux kernel workaround - do not try to include additional IEs with RIC"); params.wpa_ie = wpa_s->sme.ft_ies; params.wpa_ie_len = wpa_s->sme.ft_ies_len; + } else if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) { + const u8 *rm_en, *pos, *end; + size_t rm_en_len = 0; + u8 *rm_en_dup = NULL, *wpos; + + /* Remove RSNE, MDE, FTE to allow them to be overridden with + * FT specific values */ + remove_ie(wpa_s->sme.assoc_req_ie, + &wpa_s->sme.assoc_req_ie_len, + WLAN_EID_RSN); + remove_ie(wpa_s->sme.assoc_req_ie, + &wpa_s->sme.assoc_req_ie_len, + WLAN_EID_MOBILITY_DOMAIN); + remove_ie(wpa_s->sme.assoc_req_ie, + &wpa_s->sme.assoc_req_ie_len, + WLAN_EID_FAST_BSS_TRANSITION); + rm_en = get_ie(wpa_s->sme.assoc_req_ie, + wpa_s->sme.assoc_req_ie_len, + WLAN_EID_RRM_ENABLED_CAPABILITIES); + if (rm_en) { + /* Need to remove RM Enabled Capabilities element as + * well temporarily, so that it can be placed between + * RSNE and MDE. */ + rm_en_len = 2 + rm_en[1]; + rm_en_dup = os_memdup(rm_en, rm_en_len); + remove_ie(wpa_s->sme.assoc_req_ie, + &wpa_s->sme.assoc_req_ie_len, + WLAN_EID_RRM_ENABLED_CAPABILITIES); + } + wpa_hexdump(MSG_DEBUG, + "SME: Association Request IEs after FT IE removal", + wpa_s->sme.assoc_req_ie, + wpa_s->sme.assoc_req_ie_len); + if (wpa_s->sme.assoc_req_ie_len + wpa_s->sme.ft_ies_len + + rm_en_len > sizeof(wpa_s->sme.assoc_req_ie)) { + wpa_printf(MSG_ERROR, + "SME: Not enough buffer room for FT IEs in Association Request frame"); + os_free(rm_en_dup); + return; + } + + os_memmove(wpa_s->sme.assoc_req_ie + wpa_s->sme.ft_ies_len + + rm_en_len, + wpa_s->sme.assoc_req_ie, + wpa_s->sme.assoc_req_ie_len); + pos = wpa_s->sme.ft_ies; + end = pos + wpa_s->sme.ft_ies_len; + wpos = wpa_s->sme.assoc_req_ie; + if (*pos == WLAN_EID_RSN) { + os_memcpy(wpos, pos, 2 + pos[1]); + wpos += 2 + pos[1]; + pos += 2 + pos[1]; + } + if (rm_en_dup) { + os_memcpy(wpos, rm_en_dup, rm_en_len); + wpos += rm_en_len; + os_free(rm_en_dup); + } + os_memcpy(wpos, pos, end - pos); + wpa_s->sme.assoc_req_ie_len += wpa_s->sme.ft_ies_len + + rm_en_len; + params.wpa_ie = wpa_s->sme.assoc_req_ie; + params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len; + wpa_hexdump(MSG_DEBUG, + "SME: Association Request IEs after FT override", + params.wpa_ie, params.wpa_ie_len); } #endif /* CONFIG_IEEE80211R */ params.mode = mode;