]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
RSNE/RSNXE overriding for STA
authorJouni Malinen <quic_jouni@quicinc.com>
Wed, 11 Oct 2023 09:50:05 +0000 (12:50 +0300)
committerJouni Malinen <j@w1.fi>
Sat, 20 Jul 2024 18:28:28 +0000 (21:28 +0300)
Add support for RSNE/RSNXE Override elements. Use these elements to
determine AP's extended RSN parameters.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
src/rsn_supp/wpa.c
src/rsn_supp/wpa_ie.c
wpa_supplicant/bss.c
wpa_supplicant/config.c
wpa_supplicant/config.h
wpa_supplicant/config_file.c
wpa_supplicant/events.c
wpa_supplicant/sme.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant.conf
wpa_supplicant/wpa_supplicant_i.h

index f23979cd9c980285e61ef04003fa8343a0f3ff93..e48982989b93ef7599151cc81198761fc064ad88 100644 (file)
@@ -4550,12 +4550,27 @@ int wpa_sm_set_mlo_params(struct wpa_sm *sm, const struct wpa_sm_mlo *mlo)
                } else {
                        wpa_hexdump_link(MSG_DEBUG, i, "RSN: Set AP RSNE",
                                         ie, len);
-                       sm->mlo.links[i].ap_rsne = os_memdup(ie, len);
-                       if (!sm->mlo.links[i].ap_rsne) {
-                               sm->mlo.links[i].ap_rsne_len = 0;
-                               return -1;
+                       if (ie[0] == WLAN_EID_VENDOR_SPECIFIC && len > 2 + 4) {
+                               sm->mlo.links[i].ap_rsne = os_malloc(len - 4);
+                               if (!sm->mlo.links[i].ap_rsne)
+                                       return -1;
+                               sm->mlo.links[i].ap_rsne[0] = WLAN_EID_RSN;
+                               sm->mlo.links[i].ap_rsne[1] = len - 2 - 4;
+                               os_memcpy(&sm->mlo.links[i].ap_rsne[2],
+                                         ie + 2 + 4, len - 2 - 4);
+                               sm->mlo.links[i].ap_rsne_len = len - 4;
+                               wpa_hexdump(MSG_DEBUG,
+                                           "RSN: Converted RSNE override to RSNE",
+                                           sm->mlo.links[i].ap_rsne,
+                                           sm->mlo.links[i].ap_rsne_len);
+                       } else {
+                               sm->mlo.links[i].ap_rsne = os_memdup(ie, len);
+                               if (!sm->mlo.links[i].ap_rsne) {
+                                       sm->mlo.links[i].ap_rsne_len = 0;
+                                       return -1;
+                               }
+                               sm->mlo.links[i].ap_rsne_len = len;
                        }
-                       sm->mlo.links[i].ap_rsne_len = len;
                }
 
                ie = mlo->links[i].ap_rsnxe;
@@ -4571,12 +4586,27 @@ int wpa_sm_set_mlo_params(struct wpa_sm *sm, const struct wpa_sm_mlo *mlo)
                } else {
                        wpa_hexdump_link(MSG_DEBUG, i, "RSN: Set AP RSNXE", ie,
                                         len);
-                       sm->mlo.links[i].ap_rsnxe = os_memdup(ie, len);
-                       if (!sm->mlo.links[i].ap_rsnxe) {
-                               sm->mlo.links[i].ap_rsnxe_len = 0;
-                               return -1;
+                       if (ie[0] == WLAN_EID_VENDOR_SPECIFIC && len > 2 + 4) {
+                               sm->mlo.links[i].ap_rsnxe = os_malloc(len - 4);
+                               if (!sm->mlo.links[i].ap_rsnxe)
+                                       return -1;
+                               sm->mlo.links[i].ap_rsnxe[0] = WLAN_EID_RSNX;
+                               sm->mlo.links[i].ap_rsnxe[1] = len - 2 - 4;
+                               os_memcpy(&sm->mlo.links[i].ap_rsnxe[2],
+                                         ie + 2 + 4, len - 2 - 4);
+                               sm->mlo.links[i].ap_rsnxe_len = len - 4;
+                               wpa_hexdump(MSG_DEBUG,
+                                           "RSN: Converted RSNXE override to RSNXE",
+                                           sm->mlo.links[i].ap_rsnxe,
+                                           sm->mlo.links[i].ap_rsnxe_len);
+                       } else {
+                               sm->mlo.links[i].ap_rsnxe = os_memdup(ie, len);
+                               if (!sm->mlo.links[i].ap_rsnxe) {
+                                       sm->mlo.links[i].ap_rsnxe_len = 0;
+                                       return -1;
+                               }
+                               sm->mlo.links[i].ap_rsnxe_len = len;
                        }
-                       sm->mlo.links[i].ap_rsnxe_len = len;
                }
        }
 
@@ -5077,11 +5107,24 @@ int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
                sm->ap_rsn_ie_len = 0;
        } else {
                wpa_hexdump(MSG_DEBUG, "WPA: set AP RSN IE", ie, len);
-               sm->ap_rsn_ie = os_memdup(ie, len);
-               if (sm->ap_rsn_ie == NULL)
-                       return -1;
+               if (ie[0] == WLAN_EID_VENDOR_SPECIFIC && len > 2 + 4) {
+                       sm->ap_rsn_ie = os_malloc(len - 4);
+                       if (!sm->ap_rsn_ie)
+                               return -1;
+                       sm->ap_rsn_ie[0] = WLAN_EID_RSN;
+                       sm->ap_rsn_ie[1] = len - 2 - 4;
+                       os_memcpy(&sm->ap_rsn_ie[2], ie + 2 + 4, len - 2 - 4);
+                       sm->ap_rsn_ie_len = len - 4;
+                       wpa_hexdump(MSG_DEBUG,
+                                   "RSN: Converted RSNE override to RSNE",
+                                   sm->ap_rsn_ie, sm->ap_rsn_ie_len);
+               } else {
+                       sm->ap_rsn_ie = os_memdup(ie, len);
+                       if (sm->ap_rsn_ie == NULL)
+                               return -1;
 
-               sm->ap_rsn_ie_len = len;
+                       sm->ap_rsn_ie_len = len;
+               }
        }
 
        return 0;
@@ -5110,11 +5153,24 @@ int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len)
                sm->ap_rsnxe_len = 0;
        } else {
                wpa_hexdump(MSG_DEBUG, "WPA: set AP RSNXE", ie, len);
-               sm->ap_rsnxe = os_memdup(ie, len);
-               if (!sm->ap_rsnxe)
-                       return -1;
+               if (ie[0] == WLAN_EID_VENDOR_SPECIFIC && len > 2 + 4) {
+                       sm->ap_rsnxe = os_malloc(len - 4);
+                       if (!sm->ap_rsnxe)
+                               return -1;
+                       sm->ap_rsnxe[0] = WLAN_EID_RSNX;
+                       sm->ap_rsnxe[1] = len - 2 - 4;
+                       os_memcpy(&sm->ap_rsnxe[2], ie + 2 + 4, len - 2 - 4);
+                       sm->ap_rsnxe_len = len - 4;
+                       wpa_hexdump(MSG_DEBUG,
+                                   "RSN: Converted RSNXE override to RSNXE",
+                                   sm->ap_rsnxe, sm->ap_rsnxe_len);
+               } else {
+                       sm->ap_rsnxe = os_memdup(ie, len);
+                       if (!sm->ap_rsnxe)
+                               return -1;
 
-               sm->ap_rsnxe_len = len;
+                       sm->ap_rsnxe_len = len;
+               }
        }
 
        return 0;
index eeedf8ba54a8b39ab1a107920c07d2587672c041..515f1b02751d0d896b3d7fa9374d2157f135062d 100644 (file)
@@ -33,8 +33,15 @@ int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
        if (wpa_ie_len >= 6 && wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC &&
            wpa_ie[1] >= 4 && WPA_GET_BE32(&wpa_ie[2]) == OSEN_IE_VENDOR_TYPE)
                return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
-       else
-               return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
+       if (wpa_ie_len >= 6 && wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC &&
+           wpa_ie[1] >= 4 &&
+           WPA_GET_BE32(&wpa_ie[2]) == RSNE_OVERRIDE_IE_VENDOR_TYPE)
+               return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
+       if (wpa_ie_len >= 6 && wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC &&
+           wpa_ie[1] >= 4 &&
+           WPA_GET_BE32(&wpa_ie[2]) == RSNE_OVERRIDE_2_IE_VENDOR_TYPE)
+               return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
+       return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
 }
 
 
index 6d702bb2e4c15bbba6f7016285a7057eb9d7e260..8dcda7848df6da9c855a0444100c8b87e6869255 100644 (file)
@@ -1657,10 +1657,22 @@ int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s,
 
        if (ssid) {
                struct wpa_ie_data ie;
-
-               if (!elems.rsn_ie ||
-                   wpa_parse_wpa_ie(elems.rsn_ie - 2, 2 + elems.rsn_ie_len,
-                                    &ie)) {
+               const u8 *rsne;
+               size_t rsne_len;
+
+               if (elems.rsne_override_2 && wpas_rsn_overriding(wpa_s)) {
+                       rsne = elems.rsne_override_2;
+                       rsne_len = elems.rsne_override_2_len;
+               } else if (elems.rsne_override &&
+                          wpas_rsn_overriding(wpa_s)) {
+                       rsne = elems.rsne_override;
+                       rsne_len = elems.rsne_override_len;
+               } else {
+                       rsne = elems.rsn_ie;
+                       rsne_len = elems.rsn_ie_len;
+               }
+               if (!rsne ||
+                   wpa_parse_wpa_ie(rsne - 2, 2 + rsne_len, &ie)) {
                        wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No RSN element");
                        goto out;
                }
@@ -1868,10 +1880,163 @@ out:
 }
 
 
+static bool wpa_bss_supported_cipher(struct wpa_supplicant *wpa_s,
+                                    int pairwise_cipher)
+{
+       if (!wpa_s->drv_enc)
+               return true;
+
+       if ((pairwise_cipher & WPA_CIPHER_CCMP) &&
+           (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_CCMP))
+               return true;
+
+       if ((pairwise_cipher & WPA_CIPHER_GCMP) &&
+           (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_GCMP))
+               return true;
+
+       if ((pairwise_cipher & WPA_CIPHER_CCMP_256) &&
+           (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_CCMP_256))
+               return true;
+
+       if ((pairwise_cipher & WPA_CIPHER_GCMP_256) &&
+           (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_GCMP_256))
+               return true;
+
+       return false;
+}
+
+
+static bool wpa_bss_supported_key_mgmt(struct wpa_supplicant *wpa_s,
+                                      int key_mgmt)
+{
+       if (!wpa_s->drv_key_mgmt)
+               return true;
+
+       if ((key_mgmt & WPA_KEY_MGMT_IEEE8021X) &&
+           (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA2))
+               return true;
+       if ((key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) &&
+           (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_802_1X_SHA256))
+               return true;
+       if ((key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) &&
+           (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT))
+               return true;
+       if ((key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) &&
+           (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_802_1X_SHA384))
+               return true;
+       if ((key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) &&
+           (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B))
+               return true;
+       if ((key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) &&
+           (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192))
+               return true;
+       if ((key_mgmt & WPA_KEY_MGMT_PSK) &&
+           (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK))
+               return true;
+       if ((key_mgmt & WPA_KEY_MGMT_FT_PSK) &&
+           (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK))
+               return true;
+       if ((key_mgmt & WPA_KEY_MGMT_PSK_SHA256) &&
+           (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_PSK_SHA256))
+               return true;
+       if ((key_mgmt & WPA_KEY_MGMT_SAE) &&
+           (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE))
+               return true;
+       if ((key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) &&
+           (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE_EXT_KEY))
+               return true;
+       if ((key_mgmt & WPA_KEY_MGMT_FT_SAE) &&
+           (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE))
+               return true;
+       if ((key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) &&
+           (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE_EXT_KEY))
+               return true;
+       if ((key_mgmt & WPA_KEY_MGMT_OWE) &&
+           (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE))
+               return true;
+       if ((key_mgmt & WPA_KEY_MGMT_DPP) &&
+           (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_DPP))
+               return true;
+       if ((key_mgmt & WPA_KEY_MGMT_FILS_SHA256) &&
+           (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256))
+               return true;
+       if ((key_mgmt & WPA_KEY_MGMT_FILS_SHA384) &&
+           (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384))
+               return true;
+       if ((key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) &&
+           (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256))
+               return true;
+       if ((key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) &&
+           (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384))
+               return true;
+
+       return false;
+}
+
+
+static bool wpa_bss_supported_rsne(struct wpa_supplicant *wpa_s,
+                                  struct wpa_ssid *ssid, const u8 *ie)
+{
+       struct wpa_ie_data data;
+
+       if (wpa_parse_wpa_ie_rsn(ie, 2 + ie[1], &data) < 0)
+               return false;
+
+       /* Check that there is a supported AKM and pairwise cipher based on
+        * overall capabilities */
+       if (!data.pairwise_cipher || !data.key_mgmt)
+               return false;
+
+       if (wpa_s->drv_capa_known) {
+               if (!wpa_bss_supported_cipher(wpa_s, data.pairwise_cipher) ||
+                   !wpa_bss_supported_key_mgmt(wpa_s, data.key_mgmt))
+                       return false;
+       }
+
+       if (ssid) {
+               /* Check that there is a supported AKM and pairwise cipher
+                * based on the specific network profile. */
+               if ((ssid->pairwise_cipher & data.pairwise_cipher) == 0)
+                       return false;
+               if ((ssid->key_mgmt & data.key_mgmt) == 0)
+                       return false;
+       }
+
+       return true;
+}
+
+
 const u8 * wpa_bss_get_rsne(struct wpa_supplicant *wpa_s,
                            const struct wpa_bss *bss, struct wpa_ssid *ssid,
                            bool mlo)
 {
+       const u8 *ie;
+
+       if (wpas_rsn_overriding(wpa_s)) {
+               if (!ssid)
+                       ssid = wpa_s->current_ssid;
+
+               /* MLO cases for RSN overriding are required to use RSNE
+                * Override 2 element and RSNXE Override element together. */
+               ie = wpa_bss_get_vendor_ie(bss, RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
+               if (mlo && ie &&
+                   !wpa_bss_get_vendor_ie(bss,
+                                          RSNXE_OVERRIDE_IE_VENDOR_TYPE)) {
+                       wpa_printf(MSG_DEBUG, "BSS " MACSTR
+                                  " advertises RSNE Override 2 element without RSNXE Override element - ignore RSNE Override 2 element for MLO",
+                                  MAC2STR(bss->bssid));
+               } else if (ie && wpa_bss_supported_rsne(wpa_s, ssid, ie)) {
+                       return ie;
+               }
+
+               if (!mlo) {
+                       ie = wpa_bss_get_vendor_ie(
+                               bss, RSNE_OVERRIDE_IE_VENDOR_TYPE);
+                       if (ie && wpa_bss_supported_rsne(wpa_s, ssid, ie))
+                               return ie;
+               }
+       }
+
        return wpa_bss_get_ie(bss, WLAN_EID_RSN);
 }
 
@@ -1880,5 +2045,33 @@ const u8 * wpa_bss_get_rsnxe(struct wpa_supplicant *wpa_s,
                             const struct wpa_bss *bss, struct wpa_ssid *ssid,
                             bool mlo)
 {
+       const u8 *ie;
+
+       if (wpas_rsn_overriding(wpa_s)) {
+               ie = wpa_bss_get_vendor_ie(bss, RSNXE_OVERRIDE_IE_VENDOR_TYPE);
+               if (ie) {
+                       const u8 *tmp;
+
+                       tmp = wpa_bss_get_rsne(wpa_s, bss, ssid, mlo);
+                       if (!tmp || tmp[0] == WLAN_EID_RSN) {
+                               /* An acceptable RSNE override element was not
+                                * found, so need to ignore RSNXE overriding. */
+                               return NULL;
+                       }
+
+                       return ie;
+               }
+
+               /* MLO cases for RSN overriding are required to use RSNE
+                * Override 2 element and RSNXE Override element together. */
+               if (mlo && wpa_bss_get_vendor_ie(
+                           bss, RSNE_OVERRIDE_2_IE_VENDOR_TYPE)) {
+                       wpa_printf(MSG_DEBUG, "BSS " MACSTR
+                                  " advertises RSNXE Override element without RSNE Override 2 element - ignore RSNXE Override element for MLO",
+                                  MAC2STR(bss->bssid));
+                       return NULL;
+               }
+       }
+
        return wpa_bss_get_ie(bss, WLAN_EID_RSNX);
 }
index 24861c68f0bd8957b4916f7dbfc390027e3c1477..b02b694a3ac62dbdacae1b76f05efd66a5dd4d66 100644 (file)
@@ -5579,6 +5579,7 @@ static const struct global_parse_data global_fields[] = {
        { INT_RANGE(extended_key_id, 0, 1), 0 },
 #endif /* CONFIG_WNM */
        { INT_RANGE(wowlan_disconnect_on_deinit, 0, 1), 0},
+       { INT_RANGE(rsn_overriding, 0, 2), 0},
 #ifdef CONFIG_PASN
 #ifdef CONFIG_TESTING_OPTIONS
        { INT_RANGE(force_kdk_derivation, 0, 1), 0 },
index 8981305c2a7ae884473d7ea6985bd6e0762d7f12..d74b5c45521a206d6780027b48035c84c6d8523c 100644 (file)
@@ -1774,6 +1774,19 @@ struct wpa_config {
         */
        int wowlan_disconnect_on_deinit;
 
+       /**
+        * rsn_overriding - RSN overriding
+        *
+        * 0 = Disabled
+        * 1 = Enabled automatically if the driver indicates support
+        * 2 = Forced to be enabled even without driver capability indication
+        */
+       enum rsn_overriding {
+               RSN_OVERRIDING_DISABLED = 0,
+               RSN_OVERRIDING_AUTO = 1,
+               RSN_OVERRIDING_ENABLED = 2,
+       } rsn_overriding;
+
 #ifdef CONFIG_PASN
 #ifdef CONFIG_TESTING_OPTIONS
        /*
index ad37bcf22f33bcfec587431a7e5fbd153ccebbf2..fd8eafe2b0e4521bbb5593dd3b717bc02714d49d 100644 (file)
@@ -1615,6 +1615,8 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
        if (config->wowlan_disconnect_on_deinit)
                fprintf(f, "wowlan_disconnect_on_deinit=%d\n",
                        config->wowlan_disconnect_on_deinit);
+       if (config->rsn_overriding)
+               fprintf(f, "rsn_overriding=%d\n", config->rsn_overriding);
 #ifdef CONFIG_TESTING_OPTIONS
        if (config->mld_force_single_link)
                fprintf(f, "mld_force_single_link=1\n");
index 4e55470bb3a32825f2bcb830809bc95d5378a038..4393c469cf5fd3d0cb13e505e6c8c175c88bec8e 100644 (file)
@@ -1296,7 +1296,9 @@ static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
 
 #ifdef CONFIG_SAE
        ie = wpa_bss_get_rsnxe(wpa_s, bss, ssid, false);
-       if (ie && ie[1] >= 1)
+       if (ie && ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie[1] >= 4 + 1)
+               rsnxe_capa = ie[4 + 2];
+       else if (ie && ie[1] >= 1)
                rsnxe_capa = ie[2];
 #endif /* CONFIG_SAE */
 
@@ -3665,9 +3667,29 @@ no_pfs:
                        wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len);
                }
 
+               if (wpas_rsn_overriding(wpa_s) &&
+                   p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
+                   WPA_GET_BE32(&p[2]) == RSNE_OVERRIDE_2_IE_VENDOR_TYPE) {
+                       rsn_found = 1;
+                       wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len);
+               }
+
+               if (!rsn_found &&
+                   wpas_rsn_overriding(wpa_s) &&
+                   p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
+                   WPA_GET_BE32(&p[2]) == RSNE_OVERRIDE_IE_VENDOR_TYPE) {
+                       rsn_found = 1;
+                       wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len);
+               }
+
                if (p[0] == WLAN_EID_RSNX && p[1] >= 1)
                        wpa_sm_set_ap_rsnxe(wpa_s->wpa, p, len);
 
+               if (wpas_rsn_overriding(wpa_s) &&
+                   p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
+                   WPA_GET_BE32(&p[2]) == RSNXE_OVERRIDE_IE_VENDOR_TYPE)
+                       wpa_sm_set_ap_rsnxe(wpa_s->wpa, p, len);
+
                l -= len;
                p += len;
        }
index 8df60393a1cc62feb00d6807430edf9b0c50639e..292897edd012d2940dc8dc7f9e097ad6015ebedc 100644 (file)
@@ -191,7 +191,10 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
                const u8 *rsnxe;
 
                rsnxe = wpa_bss_get_rsnxe(wpa_s, bss, ssid, false);
-               if (rsnxe && rsnxe[1] >= 1)
+               if (rsnxe && rsnxe[0] == WLAN_EID_VENDOR_SPECIFIC &&
+                   rsnxe[1] >= 1 + 4)
+                       rsnxe_capa = rsnxe[2 + 4];
+               else if (rsnxe && rsnxe[1] >= 1)
                        rsnxe_capa = rsnxe[2];
        }
 
@@ -2464,6 +2467,28 @@ mscs_fail:
                wpa_s->sme.assoc_req_ie_len += multi_ap_ie_len;
        }
 
+       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;
+
+               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 (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;
+               }
+       }
+
        params.bssid = bssid;
        params.ssid = wpa_s->sme.ssid;
        params.ssid_len = wpa_s->sme.ssid_len;
index c2797756017015733fa0fa4695d7ddd7c6963b03..3203446f1ddb8f742fb0dd5f3bd4f4abc54e6a31 100644 (file)
@@ -3943,6 +3943,57 @@ mscs_end:
                wpa_ie_len += multi_ap_ie_len;
        }
 
+       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;
+               const u8 *ie;
+
+               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 (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;
+               }
+       }
+
+       if (wpas_driver_bss_selection(wpa_s) &&
+           wpas_rsn_overriding(wpa_s)) {
+               if (wpa_ie_len + 2 + 4 <= max_wpa_ie_len) {
+                       u8 *pos = wpa_ie + wpa_ie_len;
+
+                       *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+                       *pos++ = 4;
+                       WPA_PUT_BE32(pos, RSNE_OVERRIDE_IE_VENDOR_TYPE);
+                       pos += 4;
+                       wpa_hexdump(MSG_MSGDUMP, "RSNE Override", wpa_ie,
+                                   pos - wpa_ie);
+                       wpa_ie_len += 2 + 4;
+               }
+
+               if (wpa_ie_len + 2 + 4 <= max_wpa_ie_len) {
+                       u8 *pos = wpa_ie + wpa_ie_len;
+
+                       *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+                       *pos++ = 4;
+                       WPA_PUT_BE32(pos, RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
+                       pos += 4;
+                       wpa_hexdump(MSG_MSGDUMP, "RSNE Override 2",
+                                   wpa_ie, pos - wpa_ie);
+                       wpa_ie_len += 2 + 4;
+               }
+       }
+
        params->wpa_ie = wpa_ie;
        params->wpa_ie_len = wpa_ie_len;
        params->auth_alg = algs;
@@ -8557,6 +8608,28 @@ int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s)
 }
 
 
+static bool wpas_driver_rsn_override(struct wpa_supplicant *wpa_s)
+{
+       return !!(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_RSN_OVERRIDE_STA);
+}
+
+
+bool wpas_rsn_overriding(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->conf->rsn_overriding == RSN_OVERRIDING_DISABLED)
+               return false;
+
+       if (wpa_s->conf->rsn_overriding == RSN_OVERRIDING_ENABLED)
+               return true;
+
+       if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) ||
+           wpas_driver_bss_selection(wpa_s))
+               return wpas_driver_rsn_override(wpa_s);
+
+       return true;
+}
+
+
 #if defined(CONFIG_CTRL_IFACE) || defined(CONFIG_CTRL_IFACE_DBUS_NEW)
 int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
                                              struct wpa_ssid *ssid,
@@ -9531,3 +9604,58 @@ bool wpas_is_6ghz_supported(struct wpa_supplicant *wpa_s, bool only_enabled)
 
        return false;
 }
+
+
+bool wpas_ap_supports_rsn_overriding(struct wpa_supplicant *wpa_s,
+                                    struct wpa_bss *bss)
+{
+       int i;
+
+       if (!bss)
+               return false;
+       if (wpa_bss_get_vendor_ie(bss, RSNE_OVERRIDE_IE_VENDOR_TYPE) ||
+           wpa_bss_get_vendor_ie(bss, RSNE_OVERRIDE_2_IE_VENDOR_TYPE))
+               return true;
+
+       if (!wpa_s->valid_links)
+               return false;
+
+       for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+               if (!(wpa_s->valid_links & BIT(i)))
+                       continue;
+               if (wpa_s->links[i].bss &&
+                   (wpa_bss_get_vendor_ie(wpa_s->links[i].bss,
+                                          RSNE_OVERRIDE_IE_VENDOR_TYPE) ||
+                    wpa_bss_get_vendor_ie(wpa_s->links[i].bss,
+                                          RSNE_OVERRIDE_2_IE_VENDOR_TYPE)))
+                       return true;
+       }
+
+       return false;
+}
+
+
+bool wpas_ap_supports_rsn_overriding_2(struct wpa_supplicant *wpa_s,
+                                      struct wpa_bss *bss)
+{
+       int i;
+
+       if (!bss)
+               return false;
+       if (wpa_bss_get_vendor_ie(bss, RSNE_OVERRIDE_2_IE_VENDOR_TYPE))
+               return true;
+
+       if (!wpa_s->valid_links)
+               return false;
+
+       for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+               if (!(wpa_s->valid_links & BIT(i)))
+                       continue;
+               if (wpa_s->links[i].bss &&
+                   wpa_bss_get_vendor_ie(wpa_s->links[i].bss,
+                                         RSNE_OVERRIDE_2_IE_VENDOR_TYPE))
+                       return true;
+       }
+
+       return false;
+}
index b08f5417ad88a7788bd51328c03562ceb42a2bc7..b721f65041ee6324ee3b50ee13f8434e9d3663e4 100644 (file)
@@ -878,6 +878,15 @@ fast_reauth=1
 # 1 = auto: Activate Extended Key ID support if the driver supports it
 #extended_key_id=0
 
+# RSN overriding
+# NOTE: The protocol used for this mechanism is still subject to change and as
+# such, this should not yet be enabled for production uses to avoid issues if
+# something were to change.
+# 0 = Disabled (default)
+# 1 = Enabled automatically if the driver indicates support
+# 2 = Forced to be enabled even without driver capability indication
+#rsn_overriding=0
+
 # network block
 #
 # Each network (usually AP's sharing the same SSID) is configured as a separate
index e92f6b147402ba8391237a7d8005f4d07b26f692..3043bc6543064dc04ce9eba43324e78301df74ad 100644 (file)
@@ -1727,6 +1727,7 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid,
 void fils_connection_failure(struct wpa_supplicant *wpa_s);
 void fils_pmksa_cache_flush(struct wpa_supplicant *wpa_s);
 int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s);
+bool wpas_rsn_overriding(struct wpa_supplicant *wpa_s);
 int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s);
 void wpas_auth_failed(struct wpa_supplicant *wpa_s, const char *reason,
                      const u8 *bssid);
@@ -2011,5 +2012,9 @@ bool wpas_is_6ghz_supported(struct wpa_supplicant *wpa_s, bool only_enabled);
 
 bool wpa_is_non_eht_scs_traffic_desc_supported(struct wpa_bss *bss);
 bool wpas_ap_link_address(struct wpa_supplicant *wpa_s, const u8 *addr);
+bool wpas_ap_supports_rsn_overriding(struct wpa_supplicant *wpa_s,
+                                    struct wpa_bss *bss);
+bool wpas_ap_supports_rsn_overriding_2(struct wpa_supplicant *wpa_s,
+                                      struct wpa_bss *bss);
 
 #endif /* WPA_SUPPLICANT_I_H */