]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
RSNO: Use the RSN Selection element to indicate which variant was used
authorJouni Malinen <quic_jouni@quicinc.com>
Mon, 29 Jul 2024 12:41:59 +0000 (15:41 +0300)
committerJouni Malinen <j@w1.fi>
Tue, 30 Jul 2024 09:16:05 +0000 (12:16 +0300)
This replaces the use of the RSNE Override and RSNE Override 2 elements
with empty payload to indicate which RSNE variant was used.

In addition, this adds stricter validation of the RSNE in
(Re)Association Request frame to allow only the pairwise cipher suites
and AKMs listed in the indicated RSNE variant to be used.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
17 files changed:
src/ap/drv_callbacks.c
src/ap/ieee802_11.c
src/ap/wpa_auth.c
src/ap/wpa_auth.h
src/ap/wpa_auth_i.h
src/ap/wpa_auth_ie.c
src/common/ieee802_11_common.c
src/common/ieee802_11_common.h
src/common/ieee802_11_defs.h
src/common/wpa_common.c
src/common/wpa_common.h
src/rsn_supp/wpa.c
src/rsn_supp/wpa.h
src/rsn_supp/wpa_i.h
wpa_supplicant/events.c
wpa_supplicant/sme.c
wpa_supplicant/wpa_supplicant.c

index 364cfe4e42ea15a8fe8a7d4f39e5f82b25ad158c..c74e551c5a55229c5e15784a9ffb9bca4abebfea 100644 (file)
@@ -515,10 +515,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
                                   "Failed to initialize WPA state machine");
                        return -1;
                }
-               wpa_auth_set_rsn_override(sta->wpa_sm,
-                                         elems.rsne_override != NULL);
-               wpa_auth_set_rsn_override_2(sta->wpa_sm,
-                                           elems.rsne_override_2 != NULL);
+               wpa_auth_set_rsn_selection(sta->wpa_sm, elems.rsn_selection,
+                                          elems.rsn_selection_len);
 #ifdef CONFIG_IEEE80211BE
                if (ap_sta_is_mld(hapd, sta)) {
                        wpa_printf(MSG_DEBUG,
index 1cd76ca785831df853a5ad7787a0e0e6cf01ab84..63047671c204a907ab5c2bde429db6e1d7616c01 100644 (file)
@@ -1935,6 +1935,8 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
                goto fail;
        }
 
+       wpa_auth_set_rsn_selection(sta->wpa_sm, elems.rsn_selection,
+                                  elems.rsn_selection_len);
        res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
                                  hapd->iface->freq,
                                  elems.rsn_ie - 2, elems.rsn_ie_len + 2,
@@ -1945,9 +1947,6 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
        if (resp != WLAN_STATUS_SUCCESS)
                goto fail;
 
-       wpa_auth_set_rsn_override(sta->wpa_sm, elems.rsne_override != NULL);
-       wpa_auth_set_rsn_override_2(sta->wpa_sm, elems.rsne_override_2 != NULL);
-
        if (!elems.fils_nonce) {
                wpa_printf(MSG_DEBUG, "FILS: No FILS Nonce field");
                resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -4134,10 +4133,8 @@ static int __check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
 #endif /* CONFIG_IEEE80211BE */
 
                wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg);
-               wpa_auth_set_rsn_override(sta->wpa_sm,
-                                         elems->rsne_override != NULL);
-               wpa_auth_set_rsn_override_2(sta->wpa_sm,
-                                           elems->rsne_override_2 != NULL);
+               wpa_auth_set_rsn_selection(sta->wpa_sm, elems->rsn_selection,
+                                          elems->rsn_selection_len);
                res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
                                          hapd->iface->freq,
                                          wpa_ie, wpa_ie_len,
index e0d09abf7d74c155ffd28086637f5370f48581ff..cf6b07c1fa2b4051f52bb873efa026c1aeb05814 100644 (file)
@@ -1046,6 +1046,7 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
        os_free(sm->last_rx_eapol_key);
        os_free(sm->wpa_ie);
        os_free(sm->rsnxe);
+       os_free(sm->rsn_selection);
 #ifdef CONFIG_IEEE80211BE
        for_each_sm_auth(sm, link_id) {
                wpa_group_put(sm->mld_links[link_id].wpa_auth,
@@ -3919,6 +3920,27 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
                goto out;
        }
 #endif /* CONFIG_IEEE80211R_AP */
+
+       /* Verify RSN Selection element for RSN overriding */
+       if ((sm->rsn_selection && !kde.rsn_selection) ||
+           (!sm->rsn_selection && kde.rsn_selection) ||
+           (sm->rsn_selection && kde.rsn_selection &&
+            (sm->rsn_selection_len != kde.rsn_selection_len ||
+             os_memcmp(sm->rsn_selection, kde.rsn_selection,
+                       sm->rsn_selection_len) != 0))) {
+               wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
+                               "RSN Selection element from (Re)AssocReq did not match the one in EAPOL-Key msg 2/4");
+               wpa_hexdump(MSG_DEBUG, "RSN Selection in AssocReq",
+                           sm->rsn_selection, sm->rsn_selection_len);
+               wpa_hexdump(MSG_DEBUG, "RSN Selection in EAPOL-Key msg 2/4",
+                           kde.rsn_selection, kde.rsn_selection_len);
+               /* MLME-DEAUTHENTICATE.request */
+               wpa_sta_disconnect(wpa_auth, sm->addr,
+                                  WLAN_REASON_PREV_AUTH_NOT_VALID);
+               goto out;
+
+       }
+
 #ifdef CONFIG_P2P
        if (kde.ip_addr_req && kde.ip_addr_req[0] &&
            wpa_auth->ip_pool && WPA_GET_BE32(sm->ip_addr) == 0) {
@@ -6965,17 +6987,27 @@ void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg)
 }
 
 
-void wpa_auth_set_rsn_override(struct wpa_state_machine *sm, bool val)
+void wpa_auth_set_rsn_selection(struct wpa_state_machine *sm, const u8 *ie,
+                               size_t len)
 {
-       if (sm)
-               sm->rsn_override = val;
-}
-
-
-void wpa_auth_set_rsn_override_2(struct wpa_state_machine *sm, bool val)
-{
-       if (sm)
-               sm->rsn_override_2 = val;
+       if (!sm)
+               return;
+       os_free(sm->rsn_selection);
+       sm->rsn_selection = NULL;
+       sm->rsn_selection_len = 0;
+       sm->rsn_override = false;
+       sm->rsn_override_2 = false;
+       if (ie) {
+               if (len >=  1) {
+                       if (ie[0] == RSN_SELECTION_RSNE_OVERRIDE)
+                               sm->rsn_override = true;
+                       else if (ie[0] == RSN_SELECTION_RSNE_OVERRIDE_2)
+                               sm->rsn_override_2 = true;
+               }
+               sm->rsn_selection = os_memdup(ie, len);
+               if (sm->rsn_selection)
+                       sm->rsn_selection_len = len;
+       }
 }
 
 
index c3b2d49924fca1b8c182d1ddc6000e84e8924ca1..b22c4199b00881c7f099bbb07449d42f7cb614a7 100644 (file)
@@ -629,8 +629,8 @@ u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
 bool wpa_auth_write_fd_rsn_info(struct wpa_authenticator *wpa_auth,
                                u8 *fd_rsn_info);
 void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg);
-void wpa_auth_set_rsn_override(struct wpa_state_machine *sm, bool val);
-void wpa_auth_set_rsn_override_2(struct wpa_state_machine *sm, bool val);
+void wpa_auth_set_rsn_selection(struct wpa_state_machine *sm, const u8 *ie,
+                               size_t len);
 void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z);
 void wpa_auth_set_ssid_protection(struct wpa_state_machine *sm, bool val);
 void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
index 9f47b2961d81f6ec15d006574a6884435ac8477e..cb902e42b9f129779942e23f04c8eb38117b943c 100644 (file)
@@ -111,6 +111,8 @@ struct wpa_state_machine {
        size_t wpa_ie_len;
        u8 *rsnxe;
        size_t rsnxe_len;
+       u8 *rsn_selection;
+       size_t rsn_selection_len;
 
        enum {
                WPA_VERSION_NO_WPA = 0 /* WPA not used */,
index 11e3ab16f07bb2791590e0ab55a57be76a7d792a..43d9c1d321f16429c31ed99db174c8015106e69b 100644 (file)
@@ -1014,9 +1014,13 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
                return WPA_INVALID_GROUP;
        }
 
-       key_mgmt = data.key_mgmt & (wpa_auth->conf.wpa_key_mgmt |
-                                   wpa_auth->conf.rsn_override_key_mgmt |
-                                   wpa_auth->conf.rsn_override_key_mgmt_2);
+       if (sm->rsn_override_2)
+               key_mgmt = data.key_mgmt &
+                       wpa_auth->conf.rsn_override_key_mgmt_2;
+       else if (sm->rsn_override)
+               key_mgmt = data.key_mgmt & wpa_auth->conf.rsn_override_key_mgmt;
+       else
+               key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt;
        if (!key_mgmt) {
                wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from "
                           MACSTR, data.key_mgmt, MAC2STR(sm->addr));
@@ -1085,11 +1089,14 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
        else
                sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
 
-       if (version == WPA_PROTO_RSN)
+       if (version == WPA_PROTO_RSN && sm->rsn_override_2)
+               ciphers = data.pairwise_cipher &
+                       wpa_auth->conf.rsn_override_pairwise_2;
+       else if (version == WPA_PROTO_RSN && sm->rsn_override)
                ciphers = data.pairwise_cipher &
-                       (wpa_auth->conf.rsn_pairwise |
-                        wpa_auth->conf.rsn_override_pairwise |
-                        wpa_auth->conf.rsn_override_pairwise_2);
+                       wpa_auth->conf.rsn_override_pairwise;
+       else if (version == WPA_PROTO_RSN)
+               ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise;
        else
                ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise;
        if (!ciphers) {
index 3ca1ffe7e036dcd562bdec77896126ed99f631f7..3e6fba5bd1e93baf62534dd353c6d76e6847980e 100644 (file)
@@ -148,6 +148,15 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
                        elems->rsne_override_2 = pos;
                        elems->rsne_override_2_len = elen;
                        break;
+               case WFA_RSN_SELECTION_OUI_TYPE:
+                       if (elen < 4 + 1) {
+                               wpa_printf(MSG_DEBUG,
+                                          "Too short RSN Selection element ignored");
+                               return -1;
+                       }
+                       elems->rsn_selection = pos + 4;
+                       elems->rsn_selection_len = elen - 4;
+                       break;
                default:
                        wpa_printf(MSG_MSGDUMP, "Unknown WFA "
                                   "information element ignored "
index 46a86096e88fa3fe76077ce78d5dbe7e9c6a9965..d4c691e1b1499cb056be050ca181c8a9e9f4d981 100644 (file)
@@ -118,6 +118,7 @@ struct ieee802_11_elems {
        const u8 *mbssid;
        const u8 *rsne_override;
        const u8 *rsne_override_2;
+       const u8 *rsn_selection;
 
        u8 ssid_len;
        u8 supp_rates_len;
@@ -183,6 +184,7 @@ struct ieee802_11_elems {
        u8 mbssid_len;
        size_t rsne_override_len;
        size_t rsne_override_2_len;
+       size_t rsn_selection_len;
 
        struct mb_ies_info mb_ies;
 
index e2c132a403f5f43a4c6f5e47e8d0d44370daa1f1..db9e90355d3ef6465c1c446cf93e6b1e833a040c 100644 (file)
@@ -1449,9 +1449,11 @@ struct ieee80211_ampe_ie {
 #define WFA_RSNE_OVERRIDE_OUI_TYPE 0x29
 #define WFA_RSNE_OVERRIDE_2_OUI_TYPE 0x2a
 #define WFA_RSNXE_OVERRIDE_OUI_TYPE 0x2b
+#define WFA_RSN_SELECTION_OUI_TYPE 0x2c
 #define RSNE_OVERRIDE_IE_VENDOR_TYPE 0x506f9a29
 #define RSNE_OVERRIDE_2_IE_VENDOR_TYPE 0x506f9a2a
 #define RSNXE_OVERRIDE_IE_VENDOR_TYPE 0x506f9a2b
+#define RSN_SELECTION_IE_VENDOR_TYPE 0x506f9a2c
 
 #define MULTI_AP_SUB_ELEM_TYPE 0x06
 #define MULTI_AP_PROFILE_SUB_ELEM_TYPE 0x07
index 8eb4a1dabd64f93d7f8c14f4d2027b8539690f85..bfaca912882a379e38e777ebb84e3a17960585a4 100644 (file)
@@ -3629,6 +3629,12 @@ static int wpa_parse_generic(const u8 *pos, struct wpa_eapol_ie_parse *ie)
                return 0;
        }
 
+       if (selector == RSN_SELECTION_IE_VENDOR_TYPE) {
+               ie->rsn_selection = p;
+               ie->rsn_selection_len = left;
+               return 0;
+       }
+
        return 2;
 }
 
index 1e3136843437250cf3ba94345cf34dc8d8a8a35a..c8cdf748d71b9b1afeeb6952f807df7740300e87 100644 (file)
@@ -643,6 +643,14 @@ struct wpa_pasn_params_data {
 #define WPA_PASN_PUBKEY_COMPRESSED_1 0x03
 #define WPA_PASN_PUBKEY_UNCOMPRESSED 0x04
 
+/* WPA3 specification - RSN Selection element */
+enum rsn_selection_variant {
+       RSN_SELECTION_RSNE = 0,
+       RSN_SELECTION_RSNE_OVERRIDE = 1,
+       RSN_SELECTION_RSNE_OVERRIDE_2 = 2,
+};
+
+
 int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
                     int key_mgmt, bool reassoc_resp);
 void wpa_ft_parse_ies_free(struct wpa_ft_ies *parse);
@@ -704,6 +712,8 @@ struct wpa_eapol_ie_parse {
        u16 aid;
        const u8 *wmm;
        size_t wmm_len;
+       const u8 *rsn_selection;
+       size_t rsn_selection_len;
        u16 valid_mlo_gtks; /* bitmap of valid link GTK KDEs */
        const u8 *mlo_gtk[MAX_NUM_MLD_LINKS];
        size_t mlo_gtk_len[MAX_NUM_MLD_LINKS];
index e48982989b93ef7599151cc81198761fc064ad88..9b13b3a8403db1ae6eba0be3e812dccc4bff9545 100644 (file)
@@ -531,7 +531,7 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
        size_t mic_len, hdrlen, rlen, extra_len = 0;
        struct wpa_eapol_key *reply;
        u8 *rbuf, *key_mic;
-       u8 *rsn_ie_buf = NULL;
+       u8 *rsn_ie_buf = NULL, *buf2 = NULL;
        u16 key_info;
 #ifdef CONFIG_TESTING_OPTIONS
        size_t pad_len = 0;
@@ -581,6 +581,37 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
        }
 #endif /* CONFIG_IEEE80211R */
 
+       if (sm->rsn_override != RSN_OVERRIDE_NOT_USED) {
+               u8 *pos;
+
+               buf2 = os_malloc(wpa_ie_len + 2 + 4 + 1);
+               if (!buf2) {
+                       os_free(rsn_ie_buf);
+                       return -1;
+               }
+               os_memcpy(buf2, wpa_ie, wpa_ie_len);
+               pos = buf2 + wpa_ie_len;
+               *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+               *pos++ = 4 + 1;
+               WPA_PUT_BE32(pos, RSN_SELECTION_IE_VENDOR_TYPE);
+               pos += 4;
+               if (sm->rsn_override == RSN_OVERRIDE_RSNE) {
+                       *pos++ = RSN_SELECTION_RSNE;
+               } else if (sm->rsn_override == RSN_OVERRIDE_RSNE_OVERRIDE) {
+                       *pos++ = RSN_SELECTION_RSNE_OVERRIDE;
+               } else if (sm->rsn_override == RSN_OVERRIDE_RSNE_OVERRIDE_2) {
+                       *pos++ = RSN_SELECTION_RSNE_OVERRIDE_2;
+               } else {
+                       os_free(rsn_ie_buf);
+                       os_free(buf2);
+                       return -1;
+               }
+
+               wpa_ie = buf2;
+               wpa_ie_len += 2 + 4 + 1;
+
+       }
+
        wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len);
 
 #ifdef CONFIG_TESTING_OPTIONS
@@ -601,6 +632,7 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
                                  &rlen, (void *) &reply);
        if (rbuf == NULL) {
                os_free(rsn_ie_buf);
+               os_free(buf2);
                return -1;
        }
 
@@ -633,6 +665,7 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
        WPA_PUT_BE16(key_mic + mic_len, wpa_ie_len + extra_len);
        os_memcpy(key_mic + mic_len + 2, wpa_ie, wpa_ie_len); /* Key Data */
        os_free(rsn_ie_buf);
+       os_free(buf2);
 #ifdef CONFIG_TESTING_OPTIONS
        if (sm->test_eapol_m2_elems) {
                os_memcpy(key_mic + mic_len + 2 + wpa_ie_len,
@@ -4767,6 +4800,9 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
        case WPA_PARAM_SSID_PROTECTION:
                sm->ssid_protection = value;
                break;
+       case WPA_PARAM_RSN_OVERRIDE:
+               sm->rsn_override = value;
+               break;
        default:
                break;
        }
index 2bef093e3fa00e18f8f09cba6f62cbbb14b6c701..f8346e1ef494f4598b9aca36ea39e25b6502e985 100644 (file)
@@ -137,6 +137,14 @@ enum wpa_sm_conf_params {
        WPA_PARAM_ENCRYPT_EAPOL_M4,
        WPA_PARAM_FT_PREPEND_PMKID,
        WPA_PARAM_SSID_PROTECTION,
+       WPA_PARAM_RSN_OVERRIDE,
+};
+
+enum wpa_rsn_override {
+       RSN_OVERRIDE_NOT_USED,
+       RSN_OVERRIDE_RSNE,
+       RSN_OVERRIDE_RSNE_OVERRIDE,
+       RSN_OVERRIDE_RSNE_OVERRIDE_2,
 };
 
 struct rsn_supp_config {
index d7e780519cdb177d4f97a9f3420050bf9bbf45a6..6e47975771908617a27325328cbf249e1cd8bef6 100644 (file)
@@ -229,6 +229,8 @@ struct wpa_sm {
        bool wmm_enabled;
        bool driver_bss_selection;
        bool ft_prepend_pmkid;
+
+       enum wpa_rsn_override rsn_override;
 };
 
 
index 698fb57ef66ed8891a9a89e720df04ab375734ae..2b91194889cb0276db84c88291f54d2a87f6d951 100644 (file)
@@ -3371,9 +3371,10 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
                                          union wpa_event_data *data)
 {
        int l, len, found = 0, found_x = 0, wpa_found, rsn_found;
-       const u8 *p;
+       const u8 *p, *ie;
        u8 bssid[ETH_ALEN];
        bool bssid_known;
+       enum wpa_rsn_override rsn_override;
 
        wpa_dbg(wpa_s, MSG_DEBUG, "Association info event");
        wpa_s->ssid_verified = false;
@@ -3485,6 +3486,25 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
        if (!found_x && data->assoc_info.req_ies)
                wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
 
+       rsn_override = RSN_OVERRIDE_NOT_USED;
+       ie = get_vendor_ie(data->assoc_info.req_ies,
+                          data->assoc_info.req_ies_len,
+                          RSN_SELECTION_IE_VENDOR_TYPE);
+       if (ie && ie[1] >= 4 + 1) {
+               switch (ie[2 + 4]) {
+               case RSN_SELECTION_RSNE:
+                       rsn_override = RSN_OVERRIDE_RSNE;
+                       break;
+               case RSN_SELECTION_RSNE_OVERRIDE:
+                       rsn_override = RSN_OVERRIDE_RSNE_OVERRIDE;
+                       break;
+               case RSN_SELECTION_RSNE_OVERRIDE_2:
+                       rsn_override = RSN_OVERRIDE_RSNE_OVERRIDE_2;
+                       break;
+               }
+       }
+       wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE, rsn_override);
+
 #ifdef CONFIG_FILS
 #ifdef CONFIG_SME
        if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS ||
index 292897edd012d2940dc8dc7f9e097ad6015ebedc..443b0b6676f58bd6aeadfb70f48fed5c7fb8471f 100644 (file)
@@ -2467,26 +2467,44 @@ mscs_fail:
                wpa_s->sme.assoc_req_ie_len += multi_ap_ie_len;
        }
 
+       wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE,
+                        RSN_OVERRIDE_NOT_USED);
        if (wpas_rsn_overriding(wpa_s) &&
            wpas_ap_supports_rsn_overriding(wpa_s, wpa_s->current_bss) &&
            wpa_s->sme.assoc_req_ie_len + 2 + 4 <=
            sizeof(wpa_s->sme.assoc_req_ie)) {
                u8 *pos = wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len;
-               u32 type = 0;
                const u8 *ie;
+               enum rsn_selection_variant variant = RSN_SELECTION_RSNE;
 
+               wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE,
+                                RSN_OVERRIDE_RSNE);
                ie = wpa_bss_get_rsne(wpa_s, wpa_s->current_bss, ssid,
                                      wpa_s->valid_links);
-               if (ie && ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie[1] >= 4)
-                       type = WPA_GET_BE32(&ie[2]);
+               if (ie && ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie[1] >= 4) {
+                       u32 type;
 
-               if (type) {
-                       /* Indicate support for RSN overriding */
-                       *pos++ = WLAN_EID_VENDOR_SPECIFIC;
-                       *pos++ = 4;
-                       WPA_PUT_BE32(pos, type);
-                       wpa_s->sme.assoc_req_ie_len += 2 + 4;
+                       type = WPA_GET_BE32(&ie[2]);
+                       if (type == RSNE_OVERRIDE_IE_VENDOR_TYPE) {
+                               variant = RSN_SELECTION_RSNE_OVERRIDE;
+                               wpa_sm_set_param(wpa_s->wpa,
+                                                WPA_PARAM_RSN_OVERRIDE,
+                                                RSN_OVERRIDE_RSNE_OVERRIDE);
+                       } else if (type == RSNE_OVERRIDE_2_IE_VENDOR_TYPE) {
+                               variant = RSN_SELECTION_RSNE_OVERRIDE_2;
+                               wpa_sm_set_param(wpa_s->wpa,
+                                                WPA_PARAM_RSN_OVERRIDE,
+                                                RSN_OVERRIDE_RSNE_OVERRIDE_2);
+                       }
                }
+
+               /* Indicate which RSNE variant was used */
+               *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+               *pos++ = 4 + 1;
+               WPA_PUT_BE32(pos, RSN_SELECTION_IE_VENDOR_TYPE);
+               pos += 4;
+               *pos = variant;
+               wpa_s->sme.assoc_req_ie_len += 2 + 4 + 1;
        }
 
        params.bssid = bssid;
index b04fcb9875ec61e90e3213925491dea0abe81887..acb8f0168c7d887fb89d9c6b2887145b16b64c5d 100644 (file)
@@ -3943,32 +3943,51 @@ mscs_end:
                wpa_ie_len += multi_ap_ie_len;
        }
 
+       wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE,
+                        RSN_OVERRIDE_NOT_USED);
        if (!wpas_driver_bss_selection(wpa_s) &&
            wpas_rsn_overriding(wpa_s) &&
            wpas_ap_supports_rsn_overriding(wpa_s, bss) &&
-           wpa_ie_len + 2 + 4 <= max_wpa_ie_len) {
-               u8 *pos = wpa_ie + wpa_ie_len;
-               u32 type = 0;
+           wpa_ie_len + 2 + 4 + 1 <= max_wpa_ie_len) {
+               u8 *pos = wpa_ie + wpa_ie_len, *start = pos;
                const u8 *ie;
+               enum rsn_selection_variant variant = RSN_SELECTION_RSNE;
 
+               wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE,
+                                RSN_OVERRIDE_RSNE);
                ie = wpa_bss_get_rsne(wpa_s, bss, ssid, wpa_s->valid_links);
-               if (ie && ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie[1] >= 4)
-                       type = WPA_GET_BE32(&ie[2]);
+               if (ie && ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie[1] >= 4) {
+                       u32 type;
 
-               if (type) {
-                       /* Indicate support for RSN overriding */
-                       *pos++ = WLAN_EID_VENDOR_SPECIFIC;
-                       *pos++ = 4;
-                       WPA_PUT_BE32(pos, type);
-                       pos += 4;
-                       wpa_hexdump(MSG_MSGDUMP, "RSNE Override", wpa_ie,
-                                   pos - wpa_ie);
-                       wpa_ie_len += 2 + 4;
+                       type = WPA_GET_BE32(&ie[2]);
+                       if (type == RSNE_OVERRIDE_IE_VENDOR_TYPE) {
+                               variant = RSN_SELECTION_RSNE_OVERRIDE;
+                               wpa_sm_set_param(wpa_s->wpa,
+                                                WPA_PARAM_RSN_OVERRIDE,
+                                                RSN_OVERRIDE_RSNE_OVERRIDE);
+                       } else if (type == RSNE_OVERRIDE_2_IE_VENDOR_TYPE) {
+                               variant = RSN_SELECTION_RSNE_OVERRIDE_2;
+                               wpa_sm_set_param(wpa_s->wpa,
+                                                WPA_PARAM_RSN_OVERRIDE,
+                                                RSN_OVERRIDE_RSNE_OVERRIDE_2);
+                       }
                }
+
+               /* Indicate which RSNE variant was used */
+               *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+               *pos++ = 4 + 1;
+               WPA_PUT_BE32(pos, RSN_SELECTION_IE_VENDOR_TYPE);
+               pos += 4;
+               *pos++ = variant;
+               wpa_hexdump(MSG_MSGDUMP, "RSN Selection", start, pos - start);
+               wpa_ie_len += pos - start;
        }
 
        if (wpas_driver_bss_selection(wpa_s) &&
            wpas_rsn_overriding(wpa_s)) {
+               /* TODO: Replace this indication of support for RSN overriding
+                * to the driver in driver-based BSS selection cases with
+                * something cleaner. */
                if (wpa_ie_len + 2 + 4 <= max_wpa_ie_len) {
                        u8 *pos = wpa_ie + wpa_ie_len;