From 765c48d5adcf8996b2568a7b2ec9d3a9c34ec902 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 11 Oct 2023 12:50:05 +0300 Subject: [PATCH] RSNE/RSNXE overriding for STA Add support for RSNE/RSNXE Override elements. Use these elements to determine AP's extended RSN parameters. Signed-off-by: Jouni Malinen --- src/rsn_supp/wpa.c | 92 ++++++++++--- src/rsn_supp/wpa_ie.c | 11 +- wpa_supplicant/bss.c | 199 ++++++++++++++++++++++++++++- wpa_supplicant/config.c | 1 + wpa_supplicant/config.h | 13 ++ wpa_supplicant/config_file.c | 2 + wpa_supplicant/events.c | 24 +++- wpa_supplicant/sme.c | 27 +++- wpa_supplicant/wpa_supplicant.c | 128 +++++++++++++++++++ wpa_supplicant/wpa_supplicant.conf | 9 ++ wpa_supplicant/wpa_supplicant_i.h | 5 + 11 files changed, 486 insertions(+), 25 deletions(-) diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index f23979cd9..e48982989 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -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; diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c index eeedf8ba5..515f1b027 100644 --- a/src/rsn_supp/wpa_ie.c +++ b/src/rsn_supp/wpa_ie.c @@ -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); } diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index 6d702bb2e..8dcda7848 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -1657,10 +1657,22 @@ int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s, if (ssid) { struct wpa_ie_data ie; + const u8 *rsne; + size_t rsne_len; - if (!elems.rsn_ie || - wpa_parse_wpa_ie(elems.rsn_ie - 2, 2 + elems.rsn_ie_len, - &ie)) { + 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); } diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 24861c68f..b02b694a3 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -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 }, diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 8981305c2..d74b5c455 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -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 /* diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index ad37bcf22..fd8eafe2b 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -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"); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 4e55470bb..4393c469c 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -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; } diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 8df60393a..292897edd 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -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; diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index c27977560..3203446f1 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -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; +} diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index b08f5417a..b721f6504 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -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 diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index e92f6b147..3043bc654 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -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 */