From 07a7bcd7eab748f924dabe7b6ae8e0edecad7586 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 12 Apr 2023 18:46:53 +0300 Subject: [PATCH] WMM: Advertise support for 16 PTKSA replay counters for non-AP STA In theory, each device that supports WMM (or the IEEE 802.11 QoS for that matter) is expected to advertise how many replay counters it supports and the peer device is supposed to use that information to restrict the total number of different MSDU priorities (AC/UP) that might be used. In practice, this is not really done in deployed devices and instead, it is just assumed that everyone supports the eight different replay counters so that there is no need to restrict which MSDU priorities can be used. hostapd implementation of WMM has advertised support for 16 PTKSA replay counters from the beginning while wpa_supplicant has not had any code for setting the supported replay counter fields in RSNE, i.e., has left the value to 0 which implies that only a single replay counter is supported. While this does not really result in any real issues with deployed devices, this is not really correct behavior based on the current IEEE 802.11 standard and the WMM specification. Update wpa_supplicant to use similar design to the hostapd RSNE generation by setting the number of supported PTKSA replay counters to 16 whenever WMM is enabled. For now, this is done based on the association being for HT/VHT/HE/EHT and also based on the AP supporting WMM since it is much more likely for the local device to support WMM and eight replay counters (which can be indicated only with the value that implies support for 16 counters since there is no separate value for 8). Signed-off-by: Jouni Malinen --- src/rsn_supp/wpa.c | 3 +++ src/rsn_supp/wpa.h | 1 + src/rsn_supp/wpa_i.h | 2 ++ src/rsn_supp/wpa_ie.c | 4 ++++ tests/hwsim/test_ap_psk.py | 2 +- tests/hwsim/test_ocv.py | 4 ++-- tests/hwsim/test_sae.py | 4 ++-- wpa_supplicant/wpa_supplicant.c | 17 +++++++++++++++++ 8 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 2b3349d8c..9c7c526fc 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -4560,6 +4560,9 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param, sm->dpp_pfs = value; break; #endif /* CONFIG_DPP2 */ + case WPA_PARAM_WMM_ENABLED: + sm->wmm_enabled = value; + break; default: break; } diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index 76d603138..b3c8b6a7d 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -123,6 +123,7 @@ enum wpa_sm_conf_params { WPA_PARAM_USE_EXT_KEY_ID, WPA_PARAM_FT_RSNXE_USED, WPA_PARAM_DPP_PFS, + WPA_PARAM_WMM_ENABLED, WPA_PARAM_OCI_FREQ_EAPOL, WPA_PARAM_OCI_FREQ_EAPOL_G2, WPA_PARAM_OCI_FREQ_FT_ASSOC, diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index a3c13b116..300ef547d 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -220,6 +220,8 @@ struct wpa_sm { int dpp_pfs; #endif /* CONFIG_DPP2 */ struct wpa_sm_mlo mlo; + + bool wmm_enabled; }; diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c index 50bd2b276..2a6c79b26 100644 --- a/src/rsn_supp/wpa_ie.c +++ b/src/rsn_supp/wpa_ie.c @@ -109,6 +109,10 @@ u16 rsn_supp_capab(struct wpa_sm *sm) { u16 capab = 0; + if (sm->wmm_enabled) { + /* Advertise 16 PTKSA replay counters when using WMM */ + capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2; + } if (sm->mfp) capab |= WPA_CAPABILITY_MFPC; if (sm->mfp == 2) diff --git a/tests/hwsim/test_ap_psk.py b/tests/hwsim/test_ap_psk.py index b035c6ee2..aac104bb7 100644 --- a/tests/hwsim/test_ap_psk.py +++ b/tests/hwsim/test_ap_psk.py @@ -1533,7 +1533,7 @@ def eapol_test(apdev, dev, wpa2=True, ieee80211w=0): if ieee80211w == 2: rsne = binascii.unhexlify('30140100000fac040100000fac040100000fac02cc00') else: - rsne = binascii.unhexlify('30140100000fac040100000fac040100000fac020000') + rsne = binascii.unhexlify('30140100000fac040100000fac040100000fac020c00') else: rsne = binascii.unhexlify('dd160050f20101000050f20201000050f20201000050f202') snonce = binascii.unhexlify('1111111111111111111111111111111111111111111111111111111111111111') diff --git a/tests/hwsim/test_ocv.py b/tests/hwsim/test_ocv.py index 20f6600a9..cf19eeaf0 100644 --- a/tests/hwsim/test_ocv.py +++ b/tests/hwsim/test_ocv.py @@ -388,9 +388,9 @@ class APConnection: pmk = binascii.unhexlify("c2c6c255af836bed1b3f2f1ded98e052f5ad618bb554e2836757b55854a0eab7") if sta_ocv != "0": - self.rsne = binascii.unhexlify("301a0100000fac040100000fac040100000fac0280400000000fac06") + self.rsne = binascii.unhexlify("301a0100000fac040100000fac040100000fac028c400000000fac06") else: - self.rsne = binascii.unhexlify("301a0100000fac040100000fac040100000fac0280000000000fac06") + self.rsne = binascii.unhexlify("301a0100000fac040100000fac040100000fac028c000000000fac06") self.snonce = binascii.unhexlify('1111111111111111111111111111111111111111111111111111111111111111') dev.connect(self.ssid, raw_psk=self.psk, scan_freq=freq, ocv=sta_ocv, diff --git a/tests/hwsim/test_sae.py b/tests/hwsim/test_sae.py index f330ce395..ff58598b0 100644 --- a/tests/hwsim/test_sae.py +++ b/tests/hwsim/test_sae.py @@ -2370,7 +2370,7 @@ def test_sae_rsne_mismatch(dev, apdev): # First, test with matching RSNE to confirm testing capability dev[0].set("rsne_override_eapol", - "30140100000fac040100000fac040100000fac080000") + "30140100000fac040100000fac040100000fac080c00") dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE", scan_freq="2412") dev[0].request("REMOVE_NETWORK all") @@ -2378,7 +2378,7 @@ def test_sae_rsne_mismatch(dev, apdev): dev[0].dump_monitor() # Then, test with modified RSNE - tests = ["30140100000fac040100000fac040100000fac080010", "0000"] + tests = ["30140100000fac040100000fac040100000fac080c10", "0000"] for ie in tests: dev[0].set("rsne_override_eapol", ie) dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE", diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 93629e1f7..651c0ce9e 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1582,6 +1582,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, int sel, proto; enum sae_pwe sae_pwe; const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen; + bool wmm; if (bss) { bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); @@ -1978,6 +1979,22 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID, 0); } + /* Mark WMM enabled for any HT/VHT/HE/EHT association to get more + * appropriate advertisement of the supported number of PTKSA receive + * counters. In theory, this could be based on a driver capability, but + * in practice all cases using WMM support at least eight replay + * counters, so use a hardcoded value for now since there is no explicit + * driver capability indication for this. + * + * In addition, claim WMM to be enabled if the AP supports it since it + * is far more likely for any current device to support WMM. */ + wmm = wpa_s->connection_set && + (wpa_s->connection_ht || wpa_s->connection_vht || + wpa_s->connection_he || wpa_s->connection_eht); + if (!wmm && bss) + wmm = wpa_bss_get_vendor_ie(bss, WMM_IE_VENDOR_TYPE); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_WMM_ENABLED, wmm); + if (!skip_default_rsne) { if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {