]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
FT: Fix Reassociation Request IEs during FT protocol
authorJouni Malinen <j@w1.fi>
Sat, 1 Dec 2018 18:10:54 +0000 (20:10 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 1 Dec 2018 20:02:55 +0000 (22:02 +0200)
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>
wpa_supplicant/sme.c

index 2f5924e734f215873bb33ec4538dfb7c43d71a7b..dd42a192521333fb70075efb931173687c299854 100644 (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;