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 <j@w1.fi>
This commit is contained in:
Jouni Malinen 2018-12-01 20:10:54 +02:00
parent 4ff7e05951
commit 8c41734e5d

View File

@ -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, &params);
#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;