diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 2bc0679b5..d53436751 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -4462,6 +4462,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, conf->rssi_reject_assoc_timeout = atoi(pos); } else if (os_strcmp(buf, "pbss") == 0) { bss->pbss = atoi(pos); + } else if (os_strcmp(buf, "transition_disable") == 0) { + bss->transition_disable = strtol(pos, NULL, 16); #ifdef CONFIG_AIRTIME_POLICY } else if (os_strcmp(buf, "airtime_mode") == 0) { int val = atoi(pos); diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index b09f6ed0a..6a8c2c5cf 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1905,6 +1905,23 @@ own_ip_addr=127.0.0.1 # default: 30 TUs (= 30.72 milliseconds) #fils_hlp_wait_time=30 +# Transition Disable indication +# The AP can notify authenticated stations to disable transition mode in their +# network profiles when the network has completed transition steps, i.e., once +# sufficiently large number of APs in the ESS have been updated to support the +# more secure alternative. When this indication is used, the stations are +# expected to automatically disable transition mode and less secure security +# options. This includes use of WEP, TKIP (including use of TKIP as the group +# cipher), and connections without PMF. +# Bitmap bits: +# bit 0 (0x01): WPA3-Personal (i.e., disable WPA2-Personal = WPA-PSK and only +# allow SAE to be used) +# bit 1 (0x02): SAE-PK (disable SAE without use of SAE-PK) +# bit 2 (0x04): WPA3-Enterprise (move to requiring PMF) +# bit 3 (0x08): Enhanced Open (disable use of open network; require OWE) +# (default: 0 = do not include Transition Disable KDE) +#transition_disable=0x01 + ##### IEEE 802.11r configuration ############################################## # Mobility Domain identifier (dot11FTMobilityDomainID, MDID) diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 5f4665c07..f24257091 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -756,6 +756,8 @@ struct hostapd_bss_config { u8 send_probe_response; + u8 transition_disable; + #define BACKHAUL_BSS 1 #define FRONTHAUL_BSS 2 int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */ diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 6512c0194..1e3afd6f2 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -2712,8 +2712,13 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm, u8 *gtk, dummy_gtk[32]; size_t gtk_len; struct wpa_group *gsm; + size_t plain_len; + struct wpa_auth_config *conf = &sm->wpa_auth->conf; - plain = wpabuf_alloc(1000 + ieee80211w_kde_len(sm)); + plain_len = 1000 + ieee80211w_kde_len(sm); + if (conf->transition_disable) + plain_len += 2 + RSN_SELECTOR_LEN + 1; + plain = wpabuf_alloc(plain_len); if (!plain) return NULL; @@ -2766,6 +2771,13 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm, tmp2 = ieee80211w_kde_add(sm, tmp); wpabuf_put(plain, tmp2 - tmp); + if (conf->transition_disable) { + tmp = wpabuf_put(plain, 0); + tmp2 = wpa_add_kde(tmp, WFA_KEY_DATA_TRANSITION_DISABLE, + &conf->transition_disable, 1, NULL, 0); + wpabuf_put(plain, tmp2 - tmp); + } + *len = (u8 *) wpabuf_put(plain, 0) - len - 1; #ifdef CONFIG_OCV @@ -3276,6 +3288,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) int secure, gtkidx, encr = 0; u8 *wpa_ie_buf = NULL, *wpa_ie_buf2 = NULL; u8 hdr[2]; + struct wpa_auth_config *conf = &sm->wpa_auth->conf; SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk); sm->TimeoutEvt = FALSE; @@ -3400,6 +3413,10 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) if (WPA_GET_BE32(sm->ip_addr) > 0) kde_len += 2 + RSN_SELECTOR_LEN + 3 * 4; #endif /* CONFIG_P2P */ + + if (conf->transition_disable) + kde_len += 2 + RSN_SELECTOR_LEN + 1; + kde = os_malloc(kde_len); if (kde == NULL) goto done; @@ -3442,9 +3459,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) #ifdef CONFIG_IEEE80211R_AP if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { int res; - struct wpa_auth_config *conf; - conf = &sm->wpa_auth->conf; if (sm->assoc_resp_ftie && kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) { os_memcpy(pos, sm->assoc_resp_ftie, @@ -3493,6 +3508,10 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) } #endif /* CONFIG_P2P */ + if (conf->transition_disable) + pos = wpa_add_kde(pos, WFA_KEY_DATA_TRANSITION_DISABLE, + &conf->transition_disable, 1, NULL, 0); + wpa_send_eapol(sm->wpa_auth, sm, (secure ? WPA_KEY_INFO_SECURE : 0) | (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ? diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 528516195..955445209 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -251,6 +251,7 @@ struct wpa_auth_config { #endif /* CONFIG_FILS */ int sae_pwe; int owe_ptk_workaround; + u8 transition_disable; }; typedef enum { diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index 70d32818a..41df213b9 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -195,6 +195,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, #ifdef CONFIG_OWE wconf->owe_ptk_workaround = conf->owe_ptk_workaround; #endif /* CONFIG_OWE */ + wconf->transition_disable = conf->transition_disable; }