aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hostapd/config_file.c106
-rw-r--r--hostapd/ctrl_iface.c23
-rw-r--r--hostapd/hostapd.conf12
-rw-r--r--hostapd/sae_pk_gen.c70
-rw-r--r--src/ap/ap_config.c12
-rw-r--r--src/ap/ap_config.h11
-rw-r--r--src/ap/beacon.c10
-rw-r--r--src/ap/dpp_hostapd.c100
-rw-r--r--src/ap/drv_callbacks.c15
-rw-r--r--src/ap/ieee802_11.c125
-rw-r--r--src/ap/ieee802_11_he.c35
-rw-r--r--src/ap/ieee802_11_vht.c57
-rw-r--r--src/ap/wpa_auth.c8
-rw-r--r--src/ap/wpa_auth.h2
-rw-r--r--src/ap/wpa_auth_ft.c4
-rw-r--r--src/common/common_module_tests.c27
-rw-r--r--src/common/dpp.c300
-rw-r--r--src/common/dpp.h61
-rw-r--r--src/common/dpp_crypto.c515
-rw-r--r--src/common/dpp_i.h11
-rw-r--r--src/common/dpp_reconfig.c215
-rw-r--r--src/common/dpp_tcp.c392
-rw-r--r--src/common/gas_server.c123
-rw-r--r--src/common/gas_server.h8
-rw-r--r--src/common/hw_features_common.c2
-rw-r--r--src/common/ieee802_11_common.c134
-rw-r--r--src/common/ieee802_11_common.h14
-rw-r--r--src/common/ieee802_11_defs.h63
-rw-r--r--src/common/qca-vendor.h608
-rw-r--r--src/common/sae.c36
-rw-r--r--src/common/sae.h19
-rw-r--r--src/common/sae_pk.c543
-rw-r--r--src/common/wpa_ctrl.h10
-rw-r--r--src/crypto/crypto_module_tests.c150
-rw-r--r--src/crypto/crypto_openssl.c39
-rw-r--r--src/crypto/tls.h14
-rw-r--r--src/crypto/tls_openssl.c63
-rw-r--r--src/drivers/driver.h20
-rw-r--r--src/drivers/driver_common.c1
-rw-r--r--src/drivers/driver_nl80211.c344
-rw-r--r--src/drivers/driver_nl80211.h5
-rw-r--r--src/drivers/driver_nl80211_capa.c49
-rw-r--r--src/drivers/driver_nl80211_event.c50
-rw-r--r--src/drivers/driver_nl80211_scan.c23
-rw-r--r--src/drivers/nl80211_copy.h126
-rw-r--r--src/eap_peer/eap_teap.c9
-rw-r--r--src/eap_server/eap_server_teap.c24
-rw-r--r--src/rsn_supp/pmksa_cache.c3
-rw-r--r--src/rsn_supp/preauth.c3
-rw-r--r--src/rsn_supp/wpa.c30
-rw-r--r--src/rsn_supp/wpa.h6
-rw-r--r--src/rsn_supp/wpa_ft.c8
-rw-r--r--src/rsn_supp/wpa_i.h8
-rw-r--r--src/rsn_supp/wpa_ie.c9
-rw-r--r--src/utils/base64.c24
-rw-r--r--src/utils/base64.h1
-rw-r--r--src/utils/json.c36
-rw-r--r--src/utils/json.h4
-rw-r--r--src/wps/wps_er.c2
-rw-r--r--src/wps/wps_upnp.c53
-rw-r--r--src/wps/wps_upnp_ap.c4
-rw-r--r--src/wps/wps_upnp_event.c7
-rw-r--r--src/wps/wps_upnp_i.h3
-rw-r--r--tests/fuzzing/eapol-supp/eapol-supp.c2
-rw-r--r--tests/hwsim/auth_serv/eap_user.conf2
-rwxr-xr-xtests/hwsim/start.sh2
-rw-r--r--tests/hwsim/test_ap_hs20.py55
-rw-r--r--tests/hwsim/test_ap_pmf.py41
-rw-r--r--tests/hwsim/test_ap_psk.py9
-rw-r--r--tests/hwsim/test_ap_roam.py29
-rw-r--r--tests/hwsim/test_ap_tdls.py4
-rw-r--r--tests/hwsim/test_ap_vht.py7
-rw-r--r--tests/hwsim/test_dpp.py423
-rw-r--r--tests/hwsim/test_eap.py26
-rw-r--r--tests/hwsim/test_gas.py19
-rw-r--r--tests/hwsim/test_he.py7
-rw-r--r--tests/hwsim/test_ocv.py2
-rw-r--r--tests/hwsim/test_owe.py21
-rw-r--r--tests/hwsim/test_pmksa_cache.py60
-rw-r--r--tests/hwsim/test_rrm.py1
-rw-r--r--tests/hwsim/test_sae.py71
-rw-r--r--tests/hwsim/test_sae_pk.py420
-rw-r--r--tests/hwsim/test_sigma_dut.py634
-rw-r--r--tests/hwsim/wpasupplicant.py16
-rw-r--r--wpa_supplicant/Android.mk1
-rw-r--r--wpa_supplicant/Makefile1
-rw-r--r--wpa_supplicant/ap.c3
-rw-r--r--wpa_supplicant/config.c38
-rw-r--r--wpa_supplicant/config.h1
-rw-r--r--wpa_supplicant/config_file.c1
-rw-r--r--wpa_supplicant/config_ssid.h16
-rw-r--r--wpa_supplicant/ctrl_iface.c189
-rw-r--r--wpa_supplicant/dpp_supplicant.c422
-rw-r--r--wpa_supplicant/dpp_supplicant.h3
-rw-r--r--wpa_supplicant/driver_i.h12
-rw-r--r--wpa_supplicant/events.c816
-rwxr-xr-xwpa_supplicant/examples/dpp-nfc.py657
-rw-r--r--wpa_supplicant/gas_query.c16
-rw-r--r--wpa_supplicant/interworking.c25
-rw-r--r--wpa_supplicant/interworking.h2
-rw-r--r--wpa_supplicant/mesh_mpm.c2
-rw-r--r--wpa_supplicant/op_classes.c6
-rw-r--r--wpa_supplicant/preauth_test.c3
-rw-r--r--wpa_supplicant/robust_av.c157
-rw-r--r--wpa_supplicant/scan.c134
-rw-r--r--wpa_supplicant/sme.c66
-rw-r--r--wpa_supplicant/wnm_sta.c9
-rw-r--r--wpa_supplicant/wpa_cli.c74
-rw-r--r--wpa_supplicant/wpa_supplicant.c75
-rw-r--r--wpa_supplicant/wpa_supplicant.conf52
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h32
-rw-r--r--wpa_supplicant/wpas_glue.c37
112 files changed, 7834 insertions, 1656 deletions
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 49894c5..1861b52 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -943,104 +943,6 @@ static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
}
-/* convert floats with one decimal place to value*10 int, i.e.,
- * "1.5" will return 15 */
-static int hostapd_config_read_int10(const char *value)
-{
- int i, d;
- char *pos;
-
- i = atoi(value);
- pos = os_strchr(value, '.');
- d = 0;
- if (pos) {
- pos++;
- if (*pos >= '0' && *pos <= '9')
- d = *pos - '0';
- }
-
- return i * 10 + d;
-}
-
-
-static int valid_cw(int cw)
-{
- return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
- cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023 ||
- cw == 2047 || cw == 4095 || cw == 8191 || cw == 16383 ||
- cw == 32767);
-}
-
-
-enum {
- IEEE80211_TX_QUEUE_DATA0 = 0, /* used for EDCA AC_VO data */
- IEEE80211_TX_QUEUE_DATA1 = 1, /* used for EDCA AC_VI data */
- IEEE80211_TX_QUEUE_DATA2 = 2, /* used for EDCA AC_BE data */
- IEEE80211_TX_QUEUE_DATA3 = 3 /* used for EDCA AC_BK data */
-};
-
-static int hostapd_config_tx_queue(struct hostapd_config *conf,
- const char *name, const char *val)
-{
- int num;
- const char *pos;
- struct hostapd_tx_queue_params *queue;
-
- /* skip 'tx_queue_' prefix */
- pos = name + 9;
- if (os_strncmp(pos, "data", 4) == 0 &&
- pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
- num = pos[4] - '0';
- pos += 6;
- } else if (os_strncmp(pos, "after_beacon_", 13) == 0 ||
- os_strncmp(pos, "beacon_", 7) == 0) {
- wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
- return 0;
- } else {
- wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
- return -1;
- }
-
- if (num >= NUM_TX_QUEUES) {
- /* for backwards compatibility, do not trigger failure */
- wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
- return 0;
- }
-
- queue = &conf->tx_queue[num];
-
- if (os_strcmp(pos, "aifs") == 0) {
- queue->aifs = atoi(val);
- if (queue->aifs < 0 || queue->aifs > 255) {
- wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
- queue->aifs);
- return -1;
- }
- } else if (os_strcmp(pos, "cwmin") == 0) {
- queue->cwmin = atoi(val);
- if (!valid_cw(queue->cwmin)) {
- wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
- queue->cwmin);
- return -1;
- }
- } else if (os_strcmp(pos, "cwmax") == 0) {
- queue->cwmax = atoi(val);
- if (!valid_cw(queue->cwmax)) {
- wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
- queue->cwmax);
- return -1;
- }
- } else if (os_strcmp(pos, "burst") == 0) {
- queue->burst = hostapd_config_read_int10(val);
- } else {
- wpa_printf(MSG_ERROR, "Unknown tx_queue field '%s'", pos);
- return -1;
- }
-
- return 0;
-}
-
-
#ifdef CONFIG_IEEE80211R_AP
static int rkh_derive_key(const char *pos, u8 *key, size_t key_len)
@@ -2653,7 +2555,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "eap_teap_auth") == 0) {
int val = atoi(pos);
- if (val < 0 || val > 1) {
+ if (val < 0 || val > 2) {
wpa_printf(MSG_ERROR,
"Line %d: Invalid eap_teap_auth value",
line);
@@ -3424,7 +3326,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "ap_table_expiration_time") == 0) {
conf->ap_table_expiration_time = atoi(pos);
} else if (os_strncmp(buf, "tx_queue_", 9) == 0) {
- if (hostapd_config_tx_queue(conf, buf, pos)) {
+ if (hostapd_config_tx_queue(conf->tx_queue, buf, pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid TX queue item",
line);
return 1;
@@ -4231,6 +4133,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->own_ie_override = tmp;
} else if (os_strcmp(buf, "sae_reflection_attack") == 0) {
bss->sae_reflection_attack = atoi(pos);
+ } else if (os_strcmp(buf, "sae_commit_status") == 0) {
+ bss->sae_commit_status = atoi(pos);
+ } else if (os_strcmp(buf, "sae_pk_omit") == 0) {
+ bss->sae_pk_omit = atoi(pos);
} else if (os_strcmp(buf, "sae_commit_override") == 0) {
wpabuf_free(bss->sae_commit_override);
bss->sae_commit_override = wpabuf_parse_bin(pos);
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 8a79ef7..ae63acd 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -47,6 +47,7 @@
#include "ap/ap_config.h"
#include "ap/ieee802_1x.h"
#include "ap/wpa_auth.h"
+#include "ap/pmksa_cache_auth.h"
#include "ap/ieee802_11.h"
#include "ap/sta_info.h"
#include "ap/wps_hostapd.h"
@@ -1478,6 +1479,9 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
os_strcmp(cmd, "sae_pwe") == 0) {
if (hapd->started)
hostapd_setup_sae_pt(hapd->conf);
+ } else if (os_strcasecmp(cmd, "transition_disable") == 0) {
+ wpa_auth_set_transition_disable(hapd->wpa_auth,
+ hapd->conf->transition_disable);
}
#ifdef CONFIG_TESTING_OPTIONS
@@ -2453,6 +2457,19 @@ static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd,
}
+static int hostapd_ctrl_get_pmksa_pmk(struct hostapd_data *hapd, const u8 *addr,
+ char *buf, size_t buflen)
+{
+ struct rsn_pmksa_cache_entry *pmksa;
+
+ pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, addr, NULL);
+ if (!pmksa)
+ return -1;
+
+ return wpa_snprintf_hex(buf, buflen, pmksa->pmk, pmksa->pmk_len);
+}
+
+
static int hostapd_ctrl_get_pmk(struct hostapd_data *hapd, const char *cmd,
char *buf, size_t buflen)
{
@@ -2468,13 +2485,13 @@ static int hostapd_ctrl_get_pmk(struct hostapd_data *hapd, const char *cmd,
if (!sta || !sta->wpa_sm) {
wpa_printf(MSG_DEBUG, "No STA WPA state machine for " MACSTR,
MAC2STR(addr));
- return -1;
+ return hostapd_ctrl_get_pmksa_pmk(hapd, addr, buf, buflen);
}
pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
- if (!pmk) {
+ if (!pmk || !pmk_len) {
wpa_printf(MSG_DEBUG, "No PMK stored for " MACSTR,
MAC2STR(addr));
- return -1;
+ return hostapd_ctrl_get_pmksa_pmk(hapd, addr, buf, buflen);
}
return wpa_snprintf_hex(buf, buflen, pmk, pmk_len);
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 2b0f762..25b4e49 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -210,7 +210,7 @@ channel=1
# Frequency list can be provided as range using hyphen ('-') or individual
# frequencies can be specified by comma (',') separated values
# Default: all frequencies allowed in selected hw_mode
-#freqlist=2437,5945,5965
+#freqlist=2437,5955,5975
#freqlist=2437,5985-6105
# Exclude DFS channels from ACS
@@ -822,11 +822,11 @@ wmm_ac_vo_acm=0
#he_rts_threshold=0
# HE operating channel information; see matching vht_* parameters for details.
-# On the 6 GHz band the center freq calculation starts from 5.940 GHz offset.
-# For example idx=3 would result in 5955 MHz center frequency. In addition,
+# On the 6 GHz band the center freq calculation starts from 5.950 GHz offset.
+# For example idx=3 would result in 5965 MHz center frequency. In addition,
# he_oper_chwidth is ignored, and the channel width is derived from the
# configured operating class or center frequency indexes (see
-# IEEE P802.11ax/D4.3 Annex E, Table E-4).
+# IEEE P802.11ax/D6.1 Annex E, Table E-4).
#he_oper_chwidth
#he_oper_centr_freq_seg0_idx
#he_oper_centr_freq_seg1_idx
@@ -1229,6 +1229,8 @@ eap_server=0
# EAP-TEAP authentication type
# 0 = inner EAP (default)
# 1 = Basic-Password-Auth
+# 2 = Do not require Phase 2 authentication if client can be authenticated
+# during Phase 1
#eap_teap_auth=0
# EAP-TEAP authentication behavior when using PAC
@@ -1966,7 +1968,7 @@ own_ip_addr=127.0.0.1
# Wildcard entry:
# Upon receiving a response from R0KH, it will be added to this list, so
# subsequent requests won't be broadcast. If R0KH does not reply, it will be
-# blacklisted.
+# temporarily blocked (see rkh_neg_timeout).
#r0kh=ff:ff:ff:ff:ff:ff * 00112233445566778899aabbccddeeff
# List of R1KHs in the same Mobility Domain
diff --git a/hostapd/sae_pk_gen.c b/hostapd/sae_pk_gen.c
index 6570e9e..c31eff7 100644
--- a/hostapd/sae_pk_gen.c
+++ b/hostapd/sae_pk_gen.c
@@ -25,11 +25,15 @@ int main(int argc, char *argv[])
char *b64 = NULL, *pw = NULL, *pos, *src;
int sec, j;
int ret = -1;
- u8 hash[SAE_MAX_HASH_LEN], fingerprint[SAE_MAX_HASH_LEN];
+ u8 hash[SAE_MAX_HASH_LEN];
+ char hash_hex[2 * SAE_MAX_HASH_LEN + 1];
+ u8 pw_base_bin[SAE_MAX_HASH_LEN];
+ u8 *dst;
int group;
size_t hash_len;
unsigned long long i, expected;
char m_hex[2 * SAE_PK_M_LEN + 1];
+ u32 sec_1b, val20;
wpa_debug_level = MSG_INFO;
if (os_program_init() < 0)
@@ -37,15 +41,17 @@ int main(int argc, char *argv[])
if (argc != 4) {
fprintf(stderr,
- "usage: sae_pk_gen <DER ECPrivateKey file> <Sec:2..5> <SSID>\n");
+ "usage: sae_pk_gen <DER ECPrivateKey file> <Sec:3|5> <SSID>\n");
goto fail;
}
sec = atoi(argv[2]);
- if (sec < 2 || sec > 5) {
- fprintf(stderr, "Invalid Sec value (allowed range: 2..5)\n");
+ if (sec != 3 && sec != 5) {
+ fprintf(stderr,
+ "Invalid Sec value (allowed values: 3 and 5)\n");
goto fail;
}
+ sec_1b = sec == 3;
expected = 1;
for (j = 0; j < sec; j++)
expected *= 256;
@@ -106,7 +112,7 @@ int main(int argc, char *argv[])
goto fail;
}
if (hash[0] == 0 && hash[1] == 0) {
- if (sec == 2 || (hash[2] & 0xf0) == 0)
+ if ((hash[2] & 0xf0) == 0)
fprintf(stderr, "\r%3.2f%%",
100.0 * (double) i / (double) expected);
for (j = 2; j < sec; j++) {
@@ -119,18 +125,14 @@ int main(int argc, char *argv[])
inc_byte_array(m, SAE_PK_M_LEN);
}
- fprintf(stderr, "\nFound a valid hash in %llu iterations\n", i);
- wpa_hexdump(MSG_DEBUG, "Valid hash", hash, hash_len);
- fingerprint[0] = (sec - 2) << 6 | hash[sec] >> 2;
- for (i = 1; i < hash_len - sec; i++)
- fingerprint[i] = hash[sec + i - 1] << 6 | hash[sec + i] >> 2;
- wpa_hexdump(MSG_DEBUG, "Fingerprint part for password",
- fingerprint, hash_len - sec);
+ if (wpa_snprintf_hex(m_hex, sizeof(m_hex), m, SAE_PK_M_LEN) < 0 ||
+ wpa_snprintf_hex(hash_hex, sizeof(hash_hex), hash, hash_len) < 0)
+ goto fail;
+ fprintf(stderr, "\nFound a valid hash in %llu iterations: %s\n",
+ i + 1, hash_hex);
b64 = base64_encode(der, der_len, NULL);
- pw = sae_pk_base32_encode(fingerprint, (hash_len - sec) * 8 - 2);
- if (!b64 || !pw ||
- wpa_snprintf_hex(m_hex, sizeof(m_hex), m, SAE_PK_M_LEN) < 0)
+ if (!b64)
goto fail;
src = pos = b64;
while (*src) {
@@ -140,10 +142,44 @@ int main(int argc, char *argv[])
}
*pos = '\0';
+ /* Skip 8*Sec bits and add Sec_1b as the every 20th bit starting with
+ * one. */
+ os_memset(pw_base_bin, 0, sizeof(pw_base_bin));
+ dst = pw_base_bin;
+ for (j = 0; j < 8 * (int) hash_len / 20; j++) {
+ val20 = sae_pk_get_be19(hash + sec);
+ val20 |= sec_1b << 19;
+ sae_pk_buf_shift_left_19(hash + sec, hash_len - sec);
+
+ if (j & 1) {
+ *dst |= (val20 >> 16) & 0x0f;
+ dst++;
+ *dst++ = (val20 >> 8) & 0xff;
+ *dst++ = val20 & 0xff;
+ } else {
+ *dst++ = (val20 >> 12) & 0xff;
+ *dst++ = (val20 >> 4) & 0xff;
+ *dst = (val20 << 4) & 0xf0;
+ }
+ }
+ if (wpa_snprintf_hex(hash_hex, sizeof(hash_hex),
+ pw_base_bin, hash_len - sec) >= 0)
+ fprintf(stderr, "PasswordBase binary data for base32: %s",
+ hash_hex);
+
+ pw = sae_pk_base32_encode(pw_base_bin, 20 * 3 - 5);
+ if (!pw)
+ goto fail;
+
printf("# SAE-PK password/M/private key for Sec=%d.\n", sec);
- printf("# The password can be truncated from right to improve\n");
- printf("# usability at the cost of security.\n");
printf("sae_password=%s|pk=%s:%s\n", pw, m_hex, b64);
+ printf("# Longer passwords can be used for improved security at the cost of usability:\n");
+ for (j = 4; j <= ((int) hash_len * 8 + 5 - 8 * sec) / 19; j++) {
+ os_free(pw);
+ pw = sae_pk_base32_encode(pw_base_bin, 20 * j - 5);
+ if (pw)
+ printf("# %s\n", pw);
+ }
ret = 0;
fail:
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index a4e1bbb..769f7fa 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -160,6 +160,10 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
/* Default to strict CRL checking. */
bss->check_crl_strict = 1;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ bss->sae_commit_status = -1;
+#endif /* CONFIG_TESTING_OPTIONS */
}
@@ -1119,17 +1123,21 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
static bool hostapd_sae_pk_password_without_pk(struct hostapd_bss_config *bss)
{
struct sae_password_entry *pw;
+ bool res = false;
if (bss->ssid.wpa_passphrase &&
sae_pk_valid_password(bss->ssid.wpa_passphrase))
- return true;
+ res = true;
for (pw = bss->sae_passwords; pw; pw = pw->next) {
if (!pw->pk && sae_pk_valid_password(pw->password))
return true;
+ if (bss->ssid.wpa_passphrase && res && pw->pk &&
+ os_strcmp(bss->ssid.wpa_passphrase, pw->password) == 0)
+ res = false;
}
- return false;
+ return res;
}
#endif /* CONFIG_SAE_PK */
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index cafc44e..b705c37 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -197,15 +197,6 @@ struct hostapd_radius_attr {
#define NUM_TX_QUEUES 4
-
-struct hostapd_tx_queue_params {
- int aifs;
- int cwmin;
- int cwmax;
- int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
-};
-
-
#define MAX_ROAMING_CONSORTIUM_LEN 15
struct hostapd_roaming_consortium {
@@ -678,6 +669,8 @@ struct hostapd_bss_config {
u8 bss_load_test_set;
struct wpabuf *own_ie_override;
int sae_reflection_attack;
+ int sae_commit_status;
+ int sae_pk_omit;
struct wpabuf *sae_commit_override;
struct wpabuf *rsne_override_eapol;
struct wpabuf *rsnxe_override_eapol;
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 22e672c..b3b33b7 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -560,10 +560,13 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
pos = hostapd_eid_vht_operation(hapd, pos);
pos = hostapd_eid_txpower_envelope(hapd, pos);
- pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
}
#endif /* CONFIG_IEEE80211AC */
+ if ((hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) ||
+ hapd->iconf->ieee80211ax)
+ pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
+
pos = hostapd_eid_fils_indic(hapd, pos, 0);
pos = hostapd_get_rsnxe(hapd, pos, epos - pos);
@@ -1281,10 +1284,13 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = hostapd_eid_vht_capabilities(hapd, tailpos, 0);
tailpos = hostapd_eid_vht_operation(hapd, tailpos);
tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
- tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
}
#endif /* CONFIG_IEEE80211AC */
+ if ((hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) ||
+ hapd->iconf->ieee80211ax)
+ tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
+
tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
tailpos = hostapd_get_rsnxe(hapd, tailpos, tailend - tailpos);
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index 178fd12..c886103 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -29,6 +29,9 @@ static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd);
#ifdef CONFIG_DPP2
static void hostapd_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
void *timeout_ctx);
+static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf);
#endif /* CONFIG_DPP2 */
static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@@ -486,12 +489,35 @@ static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd)
}
+#ifdef CONFIG_DPP2
+static int hostapd_dpp_process_conf_obj(void *ctx,
+ struct dpp_authentication *auth)
+{
+ struct hostapd_data *hapd = ctx;
+ unsigned int i;
+
+ for (i = 0; i < auth->num_conf_obj; i++)
+ hostapd_dpp_handle_config_obj(hapd, auth,
+ &auth->conf_obj[i]);
+
+ return 0;
+}
+#endif /* CONFIG_DPP2 */
+
+
int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
{
const char *pos;
struct dpp_bootstrap_info *peer_bi, *own_bi = NULL;
+ struct dpp_authentication *auth;
u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
unsigned int neg_freq = 0;
+ int tcp = 0;
+#ifdef CONFIG_DPP2
+ int tcp_port = DPP_TCP_PORT;
+ struct hostapd_ip_addr ipaddr;
+ char *addr;
+#endif /* CONFIG_DPP2 */
pos = os_strstr(cmd, " peer=");
if (!pos)
@@ -504,6 +530,25 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
return -1;
}
+#ifdef CONFIG_DPP2
+ pos = os_strstr(cmd, " tcp_port=");
+ if (pos) {
+ pos += 10;
+ tcp_port = atoi(pos);
+ }
+
+ addr = get_param(cmd, " tcp_addr=");
+ if (addr) {
+ int res;
+
+ res = hostapd_parse_ip_addr(addr, &ipaddr);
+ os_free(addr);
+ if (res)
+ return -1;
+ tcp = 1;
+ }
+#endif /* CONFIG_DPP2 */
+
pos = os_strstr(cmd, " own=");
if (pos) {
pos += 5;
@@ -541,7 +586,7 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
if (pos)
neg_freq = atoi(pos + 10);
- if (hapd->dpp_auth) {
+ if (!tcp && hapd->dpp_auth) {
eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
hapd, NULL);
@@ -555,26 +600,32 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
dpp_auth_deinit(hapd->dpp_auth);
}
- hapd->dpp_auth = dpp_auth_init(hapd->iface->interfaces->dpp,
- hapd->msg_ctx, peer_bi, own_bi,
- allowed_roles, neg_freq,
- hapd->iface->hw_features,
- hapd->iface->num_hw_features);
- if (!hapd->dpp_auth)
+ auth = dpp_auth_init(hapd->iface->interfaces->dpp, hapd->msg_ctx,
+ peer_bi, own_bi, allowed_roles, neg_freq,
+ hapd->iface->hw_features,
+ hapd->iface->num_hw_features);
+ if (!auth)
goto fail;
- hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
- if (dpp_set_configurator(hapd->dpp_auth, cmd) < 0) {
- dpp_auth_deinit(hapd->dpp_auth);
- hapd->dpp_auth = NULL;
+ hostapd_dpp_set_testing_options(hapd, auth);
+ if (dpp_set_configurator(auth, cmd) < 0) {
+ dpp_auth_deinit(auth);
goto fail;
}
- hapd->dpp_auth->neg_freq = neg_freq;
+ auth->neg_freq = neg_freq;
if (!is_zero_ether_addr(peer_bi->mac_addr))
- os_memcpy(hapd->dpp_auth->peer_mac_addr, peer_bi->mac_addr,
- ETH_ALEN);
+ os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
+
+#ifdef CONFIG_DPP2
+ if (tcp)
+ return dpp_tcp_init(hapd->iface->interfaces->dpp, auth,
+ &ipaddr, tcp_port, hapd->conf->dpp_name,
+ DPP_NETROLE_AP, hapd->msg_ctx, hapd,
+ hostapd_dpp_process_conf_obj);
+#endif /* CONFIG_DPP2 */
+ hapd->dpp_auth = auth;
return hostapd_dpp_auth_init_next(hapd);
fail:
return -1;
@@ -1235,11 +1286,12 @@ hostapd_dpp_rx_reconfig_announcement(struct hostapd_data *hapd, const u8 *src,
const u8 *hdr, const u8 *buf, size_t len,
unsigned int freq)
{
- const u8 *csign_hash;
- u16 csign_hash_len;
+ const u8 *csign_hash, *fcgroup, *a_nonce, *e_id;
+ u16 csign_hash_len, fcgroup_len, a_nonce_len, e_id_len;
struct dpp_configurator *conf;
struct dpp_authentication *auth;
unsigned int wait_time, max_wait_time;
+ u16 group;
if (hapd->dpp_auth) {
wpa_printf(MSG_DEBUG,
@@ -1271,8 +1323,22 @@ hostapd_dpp_rx_reconfig_announcement(struct hostapd_data *hapd, const u8 *src,
return;
}
+ fcgroup = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
+ &fcgroup_len);
+ if (!fcgroup || fcgroup_len != 2) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Finite Cyclic Group attribute");
+ return;
+ }
+ group = WPA_GET_LE16(fcgroup);
+ wpa_printf(MSG_DEBUG, "DPP: Enrollee finite cyclic group: %u", group);
+
+ a_nonce = dpp_get_attr(buf, len, DPP_ATTR_A_NONCE, &a_nonce_len);
+ e_id = dpp_get_attr(buf, len, DPP_ATTR_E_PRIME_ID, &e_id_len);
+
auth = dpp_reconfig_init(hapd->iface->interfaces->dpp, hapd->msg_ctx,
- conf, freq);
+ conf, freq, group, a_nonce, a_nonce_len,
+ e_id, e_id_len);
if (!auth)
return;
hostapd_dpp_set_testing_options(hapd, auth);
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 173549e..9faac0d 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -439,7 +439,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
#ifdef CONFIG_SAE
if (hapd->conf->sae_pwe == 2 &&
sta->auth_alg == WLAN_AUTH_SAE &&
- sta->sae && sta->sae->tmp && !sta->sae->tmp->h2e &&
+ sta->sae && !sta->sae->h2e &&
elems.rsnxe && elems.rsnxe_len >= 1 &&
(elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
wpa_printf(MSG_INFO, "SAE: " MACSTR
@@ -893,9 +893,18 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
switch (hapd->iface->current_mode->mode) {
case HOSTAPD_MODE_IEEE80211A:
- if (cf1 > 5000)
+ if (cf1 == 5935)
+ seg0_idx = (cf1 - 5925) / 5;
+ else if (cf1 > 5950)
+ seg0_idx = (cf1 - 5950) / 5;
+ else if (cf1 > 5000)
seg0_idx = (cf1 - 5000) / 5;
- if (cf2 > 5000)
+
+ if (cf2 == 5935)
+ seg1_idx = (cf2 - 5925) / 5;
+ else if (cf2 > 5950)
+ seg1_idx = (cf2 - 5950) / 5;
+ else if (cf2 > 5000)
seg1_idx = (cf2 - 5000) / 5;
break;
default:
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 0822dfd..b916400 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -483,7 +483,7 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
if (sta->sae->tmp) {
rx_id = sta->sae->tmp->pw_id;
- use_pt = sta->sae->tmp->h2e;
+ use_pt = sta->sae->h2e;
#ifdef CONFIG_SAE_PK
os_memcpy(sta->sae->tmp->own_addr, hapd->own_addr, ETH_ALEN);
os_memcpy(sta->sae->tmp->peer_addr, sta->addr, ETH_ALEN);
@@ -567,6 +567,13 @@ static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
if (buf == NULL)
return NULL;
+#ifdef CONFIG_SAE_PK
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sta->sae->tmp)
+ sta->sae->tmp->omit_pk_elem = hapd->conf->sae_pk_omit;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_SAE_PK */
+
if (sae_write_confirm(sta->sae, buf) < 0) {
wpabuf_free(buf);
return NULL;
@@ -587,19 +594,24 @@ static int auth_sae_send_commit(struct hostapd_data *hapd,
data = auth_build_sae_commit(hapd, sta, update, status_code);
if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
-#ifdef CONFIG_SAE_PK
- if (!data && sta->sae->tmp && sta->sae->tmp->reject_group)
- return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
-#endif /* CONFIG_SAE_PK */
if (data == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- if (sta->sae->tmp && sta->sae->tmp->pk)
+ if (sta->sae->tmp && sta->sae->pk)
status = WLAN_STATUS_SAE_PK;
- else if (sta->sae->tmp && sta->sae->tmp->h2e)
+ else if (sta->sae->tmp && sta->sae->h2e)
status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
else
status = WLAN_STATUS_SUCCESS;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->sae_commit_status >= 0 &&
+ hapd->conf->sae_commit_status != status) {
+ wpa_printf(MSG_INFO,
+ "TESTING: Override SAE commit status code %u --> %d",
+ status, hapd->conf->sae_commit_status);
+ status = hapd->conf->sae_commit_status;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
WLAN_AUTH_SAE, 1,
status, wpabuf_head(data),
@@ -921,11 +933,11 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
case SAE_NOTHING:
if (auth_transaction == 1) {
if (sta->sae->tmp) {
- sta->sae->tmp->h2e =
+ sta->sae->h2e =
(status_code ==
WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
status_code == WLAN_STATUS_SAE_PK);
- sta->sae->tmp->pk =
+ sta->sae->pk =
status_code == WLAN_STATUS_SAE_PK;
}
ret = auth_sae_send_commit(hapd, sta, bssid,
@@ -1179,7 +1191,7 @@ static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
static int check_sae_rejected_groups(struct hostapd_data *hapd,
- struct sae_data *sae, bool pk)
+ struct sae_data *sae)
{
const struct wpabuf *groups;
size_t i, count;
@@ -1200,29 +1212,8 @@ static int check_sae_rejected_groups(struct hostapd_data *hapd,
group = WPA_GET_LE16(pos);
pos += 2;
enabled = sae_is_group_enabled(hapd, group);
-
-#ifdef CONFIG_SAE_PK
- /* TODO: Could check more explicitly against the matching
- * sae_password entry only for the somewhat theoretical case of
- * different passwords using different groups for SAE-PK K_AP
- * values. */
- if (pk) {
- struct sae_password_entry *pw;
-
- enabled = false;
- for (pw = hapd->conf->sae_passwords; pw;
- pw = pw->next) {
- if (pw->pk && pw->pk->group == group) {
- enabled = true;
- break;
- }
- }
- }
-#endif /* CONFIG_SAE_PK */
-
- wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s%s",
- group, enabled ? "enabled" : "disabled",
- pk ? " (PK)" : "");
+ wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
+ group, enabled ? "enabled" : "disabled");
if (enabled)
return 1;
}
@@ -1426,9 +1417,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
if (resp != WLAN_STATUS_SUCCESS)
goto reply;
- if (check_sae_rejected_groups(hapd, sta->sae,
- status_code ==
- WLAN_STATUS_SAE_PK)) {
+ if (check_sae_rejected_groups(hapd, sta->sae)) {
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto reply;
}
@@ -1440,7 +1429,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
"SAE: Request anti-clogging token from "
MACSTR, MAC2STR(sta->addr));
if (sta->sae->tmp)
- h2e = sta->sae->tmp->h2e;
+ h2e = sta->sae->h2e;
if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
status_code == WLAN_STATUS_SAE_PK)
h2e = 1;
@@ -3241,6 +3230,13 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
if (resp != WLAN_STATUS_SUCCESS)
return resp;
if (is_6ghz_op_class(hapd->iconf->op_class)) {
+ if (!(sta->flags & WLAN_STA_HE)) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Station does not support mandatory HE PHY - reject association");
+ return WLAN_STATUS_DENIED_HE_NOT_SUPPORTED;
+ }
resp = copy_sta_he_6ghz_capab(hapd, sta,
elems.he_6ghz_band_cap);
if (resp != WLAN_STATUS_SUCCESS)
@@ -3405,7 +3401,7 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
if (hapd->conf->sae_pwe == 2 &&
sta->auth_alg == WLAN_AUTH_SAE &&
- sta->sae && sta->sae->tmp && !sta->sae->tmp->h2e &&
+ sta->sae && !sta->sae->h2e &&
elems.rsnxe && elems.rsnxe_len >= 1 &&
(elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
wpa_printf(MSG_INFO, "SAE: " MACSTR
@@ -5568,4 +5564,57 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
}
+u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 bw, chan1, chan2 = 0;
+ int freq1;
+
+ if (!hapd->cs_freq_params.channel ||
+ (!hapd->cs_freq_params.vht_enabled &&
+ !hapd->cs_freq_params.he_enabled))
+ return eid;
+
+ /* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */
+ switch (hapd->cs_freq_params.bandwidth) {
+ case 40:
+ bw = 0;
+ break;
+ case 80:
+ /* check if it's 80+80 */
+ if (!hapd->cs_freq_params.center_freq2)
+ bw = 1;
+ else
+ bw = 3;
+ break;
+ case 160:
+ bw = 2;
+ break;
+ default:
+ /* not valid VHT bandwidth or not in CSA */
+ return eid;
+ }
+
+ freq1 = hapd->cs_freq_params.center_freq1 ?
+ hapd->cs_freq_params.center_freq1 :
+ hapd->cs_freq_params.freq;
+ if (ieee80211_freq_to_chan(freq1, &chan1) !=
+ HOSTAPD_MODE_IEEE80211A)
+ return eid;
+
+ if (hapd->cs_freq_params.center_freq2 &&
+ ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
+ &chan2) != HOSTAPD_MODE_IEEE80211A)
+ return eid;
+
+ *eid++ = WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER;
+ *eid++ = 5; /* Length of Channel Switch Wrapper */
+ *eid++ = WLAN_EID_VHT_WIDE_BW_CHSWITCH;
+ *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
+ *eid++ = bw; /* New Channel Width */
+ *eid++ = chan1; /* New Channel Center Frequency Segment 0 */
+ *eid++ = chan2; /* New Channel Center Frequency Segment 1 */
+
+ return eid;
+}
+
#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index f1f2442..85b7140 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -314,45 +314,26 @@ u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid)
u8 * hostapd_eid_he_6ghz_band_cap(struct hostapd_data *hapd, u8 *eid)
{
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
+ struct he_capabilities *he_cap;
struct ieee80211_he_6ghz_band_cap *cap;
- u32 vht_cap;
- u8 ht_info;
- u8 params;
+ u16 capab;
u8 *pos;
- if (!mode || !is_6ghz_op_class(hapd->iconf->op_class))
+ if (!mode || !is_6ghz_op_class(hapd->iconf->op_class) ||
+ !is_6ghz_freq(hapd->iface->freq))
return eid;
- vht_cap = hapd->iface->conf->vht_capab;
- ht_info = mode->a_mpdu_params;
+ he_cap = &mode->he_capab[IEEE80211_MODE_AP];
+ capab = he_cap->he_6ghz_capa;
+ capab |= HE_6GHZ_BAND_CAP_SMPS_DISABLED;
pos = eid;
*pos++ = WLAN_EID_EXTENSION;
*pos++ = 1 + sizeof(*cap);
*pos++ = WLAN_EID_EXT_HE_6GHZ_BAND_CAP;
- /* Minimum MPDU Start Spacing B0..B2 */
- params = (ht_info >> 2) & HE_6GHZ_BAND_CAP_MIN_MPDU_START_SPACE_MASK;
-
- /* Maximum A-MPDU Length Exponent B3..B5 */
- params |= ((((vht_cap & VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX) >>
- VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX_SHIFT) &
- HE_6GHZ_BAND_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) <<
- HE_6GHZ_BAND_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
-
- /* Maximum MPDU Length B6..B7 */
- params |= ((((vht_cap & VHT_CAP_MAX_MPDU_LENGTH_MASK) >>
- VHT_CAP_MAX_MPDU_LENGTH_MASK_SHIFT) &
- HE_6GHZ_BAND_CAP_MAX_MPDU_LENGTH_MASK) <<
- HE_6GHZ_BAND_CAP_MAX_MPDU_LENGTH_SHIFT);
-
cap = (struct ieee80211_he_6ghz_band_cap *) pos;
- cap->a_mpdu_params = params;
- cap->info = HE_6GHZ_BAND_CAP_SMPS_DISABLED;
- if (vht_cap & VHT_CAP_RX_ANTENNA_PATTERN)
- cap->info |= HE_6GHZ_BAND_CAP_RX_ANTENNA_PATTERN;
- if (vht_cap & VHT_CAP_TX_ANTENNA_PATTERN)
- cap->info |= HE_6GHZ_BAND_CAP_TX_ANTENNA_PATTERN;
+ cap->capab = host_to_le16(capab);
pos += sizeof(*cap);
return pos;
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index f50f142..c925bf1 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -167,59 +167,6 @@ static int check_valid_vht_mcs(struct hostapd_hw_modes *mode,
}
-u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
-{
- u8 bw, chan1, chan2 = 0;
- int freq1;
-
- if (!hapd->cs_freq_params.channel ||
- !hapd->cs_freq_params.vht_enabled)
- return eid;
-
- /* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */
- switch (hapd->cs_freq_params.bandwidth) {
- case 40:
- bw = 0;
- break;
- case 80:
- /* check if it's 80+80 */
- if (!hapd->cs_freq_params.center_freq2)
- bw = 1;
- else
- bw = 3;
- break;
- case 160:
- bw = 2;
- break;
- default:
- /* not valid VHT bandwidth or not in CSA */
- return eid;
- }
-
- freq1 = hapd->cs_freq_params.center_freq1 ?
- hapd->cs_freq_params.center_freq1 :
- hapd->cs_freq_params.freq;
- if (ieee80211_freq_to_chan(freq1, &chan1) !=
- HOSTAPD_MODE_IEEE80211A)
- return eid;
-
- if (hapd->cs_freq_params.center_freq2 &&
- ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
- &chan2) != HOSTAPD_MODE_IEEE80211A)
- return eid;
-
- *eid++ = WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER;
- *eid++ = 5; /* Length of Channel Switch Wrapper */
- *eid++ = WLAN_EID_VHT_WIDE_BW_CHSWITCH;
- *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
- *eid++ = bw; /* New Channel Width */
- *eid++ = chan1; /* New Channel Center Frequency Segment 0 */
- *eid++ = chan2; /* New Channel Center Frequency Segment 1 */
-
- return eid;
-}
-
-
u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
{
struct hostapd_iface *iface = hapd->iface;
@@ -425,7 +372,9 @@ u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
- if (!hapd->iface->current_mode)
+ /* Vendor VHT is applicable only to 2.4 GHz */
+ if (!hapd->iface->current_mode ||
+ hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
return eid;
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 0efa287..9e6c0ca 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -5288,6 +5288,14 @@ void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z)
#endif /* CONFIG_DPP2 */
+void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
+ u8 val)
+{
+ if (wpa_auth)
+ wpa_auth->conf.transition_disable = val;
+}
+
+
#ifdef CONFIG_TESTING_OPTIONS
int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 59794a7..5f9df9c 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -517,6 +517,8 @@ u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
const u8 *req_ies, size_t req_ies_len);
void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg);
void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z);
+void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
+ u8 val);
int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
void (*cb)(void *ctx1, void *ctx2),
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index db272d4..9caac19 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -1898,7 +1898,7 @@ static void wpa_ft_block_r0kh(struct wpa_authenticator *wpa_auth,
return;
}
- wpa_hexdump(MSG_DEBUG, "FT: Blacklist R0KH-ID",
+ wpa_hexdump(MSG_DEBUG, "FT: Temporarily block R0KH-ID",
f_r0kh_id, f_r0kh_id_len);
if (r0kh) {
@@ -1986,7 +1986,7 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
return -1;
}
if (is_zero_ether_addr(r0kh->addr)) {
- wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID is blacklisted",
+ wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID is temporarily blocked",
sm->r0kh_id, sm->r0kh_id_len);
return -1;
}
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
index 77d6001..00308d4 100644
--- a/src/common/common_module_tests.c
+++ b/src/common/common_module_tests.c
@@ -551,31 +551,14 @@ fail:
static int sae_pk_tests(void)
{
#ifdef CONFIG_SAE_PK
- const char *invalid[] = { "a2bc-de3f-ghi4-", "a2bcde3fghi4", "", NULL };
+ const char *invalid[] = { "a2bc-de3f-ghim-", "a2bcde3fghim", "", NULL };
struct {
const char *pw;
const u8 *val;
} valid[] = {
- { "a2bc-de3f-ghi4", (u8 *) "\x06\x82\x21\x93\x65\x31\xd1\xc0" },
- { "ci2f-m6e2", (u8 *) "\x12\x34\x56\x78\x9a" },
- { "aaaa-aaaa-aaaa-a",
- (u8 *) "\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
- { "aaaa-aaaa-aaaa", (u8 *) "\x00\x00\x00\x00\x00\x00\x00\x00" },
- { "aaaa-aaaa-aa", (u8 *) "\x00\x00\x00\x00\x00\x00\x00" },
- { "aaaa-aaaa", (u8 *) "\x00\x00\x00\x00\x00" },
- { "aaaa-aaa", (u8 *) "\x00\x00\x00\x00\x00" },
- { "aaaa-a", (u8 *) "\x00\x00\x00\x00" },
- { "aeaa-a", (u8 *) "\x01\x00\x00\x00" },
- { "7777-7", (u8 *) "\xff\xff\xff\x80" },
- { "7777-77", (u8 *) "\xff\xff\xff\xfc" },
- { "7777-777", (u8 *) "\xff\xff\xff\xff\xe0" },
- { "7777-7777", (u8 *) "\xff\xff\xff\xff\xff" },
- { "7777-7777-7", (u8 *) "\xff\xff\xff\xff\xff\xf8" },
- { "7777-7777-77", (u8 *) "\xff\xff\xff\xff\xff\xff\xc0" },
- { "7777-7777-777", (u8 *) "\xff\xff\xff\xff\xff\xff\xfe" },
- { "7777-7777-7777", (u8 *) "\xff\xff\xff\xff\xff\xff\xff\xf0" },
- { "7777-7777-7777-7",
- (u8 *) "\xff\xff\xff\xff\xff\xff\xff\xff\x80" },
+ { "a2bc-de3f-ghim", (u8 *) "\x06\x82\x21\x93\x65\x31\xd0\xc0" },
+ { "aaaa-aaaa-aaaj", (u8 *) "\x00\x00\x00\x00\x00\x00\x00\x90" },
+ { "7777-7777-777f", (u8 *) "\xff\xff\xff\xff\xff\xff\xfe\x50" },
{ NULL, NULL }
};
int i;
@@ -629,7 +612,7 @@ static int sae_pk_tests(void)
}
os_free(res);
- b32 = sae_pk_base32_encode(val, bits);
+ b32 = sae_pk_base32_encode(val, bits - 5);
if (!b32) {
wpa_printf(MSG_ERROR,
"SAE-PK: Failed to encode password '%s'",
diff --git a/src/common/dpp.c b/src/common/dpp.c
index ca3b8b5..bc34922 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -17,6 +17,7 @@
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "common/gas.h"
+#include "eap_common/eap_defs.h"
#include "crypto/crypto.h"
#include "crypto/random.h"
#include "crypto/aes.h"
@@ -244,6 +245,7 @@ int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
wpa_printf(MSG_DEBUG,
"DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
opclass, channel, freq);
+ bi->channels_listed = true;
if (freq < 0) {
wpa_printf(MSG_DEBUG,
"DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
@@ -828,6 +830,7 @@ struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
const char *tech = "infra";
const char *dpp_name;
struct wpabuf *buf, *json;
+ char *csr = NULL;
#ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
@@ -844,6 +847,17 @@ struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
len = 100 + name_len * 6 + 1 + int_array_len(opclasses) * 4;
if (mud_url && mud_url[0])
len += 10 + os_strlen(mud_url);
+#ifdef CONFIG_DPP2
+ if (auth->csr) {
+ size_t csr_len;
+
+ csr = base64_encode_no_lf(wpabuf_head(auth->csr),
+ wpabuf_len(auth->csr), &csr_len);
+ if (!csr)
+ return NULL;
+ len += 30 + csr_len;
+ }
+#endif /* CONFIG_DPP2 */
json = wpabuf_alloc(len);
if (!json)
return NULL;
@@ -870,10 +884,15 @@ struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
wpabuf_printf(json, "%s%u", i ? "," : "", opclasses[i]);
json_end_array(json);
}
+ if (csr) {
+ json_value_sep(json);
+ json_add_string(json, "pkcs10", csr);
+ }
json_end_object(json);
buf = dpp_build_conf_req(auth, wpabuf_head(json));
wpabuf_free(json);
+ os_free(csr);
return buf;
}
@@ -916,6 +935,8 @@ struct dpp_configuration * dpp_configuration_alloc(const char *type)
conf->akm = DPP_AKM_PSK_SAE_DPP;
else if (bin_str_eq(type, len, "dpp"))
conf->akm = DPP_AKM_DPP;
+ else if (bin_str_eq(type, len, "dot1x"))
+ conf->akm = DPP_AKM_DOT1X;
else
goto fail;
@@ -978,6 +999,7 @@ void dpp_configuration_free(struct dpp_configuration *conf)
return;
str_clear_free(conf->passphrase);
os_free(conf->group_id);
+ os_free(conf->csrattrs);
bin_clear_free(conf, sizeof(*conf));
}
@@ -988,6 +1010,7 @@ static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
const char *pos, *end;
struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
struct dpp_configuration *conf = NULL;
+ size_t len;
pos = os_strstr(cmd, " conf=sta-");
if (pos) {
@@ -1092,6 +1115,17 @@ static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
conf->netaccesskey_expiry = val;
}
+ pos = os_strstr(cmd, " csrattrs=");
+ if (pos) {
+ pos += 10;
+ end = os_strchr(pos, ' ');
+ len = end ? (size_t) (end - pos) : os_strlen(pos);
+ conf->csrattrs = os_zalloc(len + 1);
+ if (!conf->csrattrs)
+ goto fail;
+ os_memcpy(conf->csrattrs, pos, len);
+ }
+
if (!dpp_configuration_valid(conf))
goto fail;
@@ -1247,12 +1281,27 @@ void dpp_auth_deinit(struct dpp_authentication *auth)
os_free(conf->connector);
wpabuf_free(conf->c_sign_key);
+ wpabuf_free(conf->certbag);
+ wpabuf_free(conf->certs);
+ wpabuf_free(conf->cacert);
+ os_free(conf->server_name);
}
#ifdef CONFIG_DPP2
dpp_free_asymmetric_key(auth->conf_key_pkg);
+ os_free(auth->csrattrs);
+ wpabuf_free(auth->csr);
+ wpabuf_free(auth->priv_key);
+ wpabuf_free(auth->cacert);
+ wpabuf_free(auth->certbag);
+ os_free(auth->trusted_eap_server_name);
+ wpabuf_free(auth->conf_resp_tcp);
#endif /* CONFIG_DPP2 */
wpabuf_free(auth->net_access_key);
dpp_bootstrap_info_free(auth->tmp_own_bi);
+ if (auth->tmp_peer_bi) {
+ dl_list_del(&auth->tmp_peer_bi->list);
+ dpp_bootstrap_info_free(auth->tmp_peer_bi);
+ }
#ifdef CONFIG_TESTING_OPTIONS
os_free(auth->config_obj_override);
os_free(auth->discovery_override);
@@ -1480,6 +1529,15 @@ skip_groups:
tailroom += os_strlen(signed_conn);
if (incl_legacy)
tailroom += 1000;
+ if (akm == DPP_AKM_DOT1X) {
+ if (auth->certbag)
+ tailroom += 2 * wpabuf_len(auth->certbag);
+ if (auth->cacert)
+ tailroom += 2 * wpabuf_len(auth->cacert);
+ if (auth->trusted_eap_server_name)
+ tailroom += os_strlen(auth->trusted_eap_server_name);
+ tailroom += 1000;
+ }
buf = dpp_build_conf_start(auth, conf, tailroom);
if (!buf)
goto fail;
@@ -1495,6 +1553,30 @@ skip_groups:
dpp_build_legacy_cred_params(buf, conf);
json_value_sep(buf);
}
+ if (akm == DPP_AKM_DOT1X) {
+ json_start_object(buf, "entCreds");
+ if (!auth->certbag)
+ goto fail;
+ json_add_base64(buf, "certBag", wpabuf_head(auth->certbag),
+ wpabuf_len(auth->certbag));
+ if (auth->cacert) {
+ json_value_sep(buf);
+ json_add_base64(buf, "caCert",
+ wpabuf_head(auth->cacert),
+ wpabuf_len(auth->cacert));
+ }
+ if (auth->trusted_eap_server_name) {
+ json_value_sep(buf);
+ json_add_string(buf, "trustedEapServerName",
+ auth->trusted_eap_server_name);
+ }
+ json_value_sep(buf);
+ json_start_array(buf, "eapMethods");
+ wpabuf_printf(buf, "%d", EAP_TYPE_TLS);
+ json_end_array(buf);
+ json_end_object(buf);
+ json_value_sep(buf);
+ }
wpabuf_put_str(buf, "\"signedConnector\":\"");
wpabuf_put_str(buf, signed_conn);
wpabuf_put_str(buf, "\"");
@@ -1554,7 +1636,7 @@ dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
static struct wpabuf *
dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
- int idx)
+ int idx, bool cert_req)
{
struct dpp_configuration *conf = NULL;
@@ -1587,15 +1669,28 @@ dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
return NULL;
}
+ if (conf->akm == DPP_AKM_DOT1X) {
+ if (!auth->conf) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No Configurator data available");
+ return NULL;
+ }
+ if (!cert_req && !auth->certbag) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No certificate data available for dot1x configuration");
+ return NULL;
+ }
+ return dpp_build_conf_obj_dpp(auth, conf);
+ }
if (dpp_akm_dpp(conf->akm) || (auth->peer_version >= 2 && auth->conf))
return dpp_build_conf_obj_dpp(auth, conf);
return dpp_build_conf_obj_legacy(auth, conf);
}
-static struct wpabuf *
+struct wpabuf *
dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
- u16 e_nonce_len, enum dpp_netrole netrole)
+ u16 e_nonce_len, enum dpp_netrole netrole, bool cert_req)
{
struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL;
size_t clear_len, attr_len;
@@ -1605,21 +1700,33 @@ dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
size_t len[1];
enum dpp_status_error status;
+ if (auth->force_conf_resp_status != DPP_STATUS_OK) {
+ status = auth->force_conf_resp_status;
+ goto forced_status;
+ }
+
if (netrole == DPP_NETROLE_CONFIGURATOR) {
#ifdef CONFIG_DPP2
env_data = dpp_build_enveloped_data(auth);
#endif /* CONFIG_DPP2 */
} else {
- conf = dpp_build_conf_obj(auth, netrole, 0);
+ conf = dpp_build_conf_obj(auth, netrole, 0, cert_req);
if (conf) {
wpa_hexdump_ascii(MSG_DEBUG,
"DPP: configurationObject JSON",
wpabuf_head(conf), wpabuf_len(conf));
- conf2 = dpp_build_conf_obj(auth, netrole, 1);
+ conf2 = dpp_build_conf_obj(auth, netrole, 1, cert_req);
}
}
- status = (conf || env_data) ? DPP_STATUS_OK :
- DPP_STATUS_CONFIGURE_FAILURE;
+
+ if (conf || env_data)
+ status = DPP_STATUS_OK;
+ else if (!cert_req && netrole == DPP_NETROLE_STA && auth->conf_sta &&
+ auth->conf_sta->akm == DPP_AKM_DOT1X && !auth->waiting_csr)
+ status = DPP_STATUS_CSR_NEEDED;
+ else
+ status = DPP_STATUS_CONFIGURE_FAILURE;
+forced_status:
auth->conf_resp_status = status;
/* { E-nonce, configurationObject[, sendConnStatus]}ke */
@@ -1633,6 +1740,9 @@ dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
if (auth->peer_version >= 2 && auth->send_conn_status &&
netrole == DPP_NETROLE_STA)
clear_len += 4;
+ if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
+ auth->conf_sta->csrattrs)
+ clear_len += 4 + os_strlen(auth->conf_sta->csrattrs);
clear = wpabuf_alloc(clear_len);
attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
#ifdef CONFIG_TESTING_OPTIONS
@@ -1695,12 +1805,21 @@ skip_e_nonce:
}
if (auth->peer_version >= 2 && auth->send_conn_status &&
- netrole == DPP_NETROLE_STA) {
+ netrole == DPP_NETROLE_STA && status == DPP_STATUS_OK) {
wpa_printf(MSG_DEBUG, "DPP: sendConnStatus");
wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS);
wpabuf_put_le16(clear, 0);
}
+ if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
+ auth->conf_sta->csrattrs) {
+ auth->waiting_csr = true;
+ wpa_printf(MSG_DEBUG, "DPP: CSR Attributes Request");
+ wpabuf_put_le16(clear, DPP_ATTR_CSR_ATTR_REQ);
+ wpabuf_put_le16(clear, os_strlen(auth->conf_sta->csrattrs));
+ wpabuf_put_str(clear, auth->conf_sta->csrattrs);
+ }
+
#ifdef CONFIG_TESTING_OPTIONS
skip_config_obj:
if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
@@ -1771,6 +1890,7 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
struct wpabuf *resp = NULL;
struct json_token *root = NULL, *token;
enum dpp_netrole netrole;
+ struct wpabuf *cert_req = NULL;
#ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
@@ -1879,6 +1999,7 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
dpp_auth_fail(auth, "Unsupported netRole");
goto fail;
}
+ auth->e_netrole = netrole;
token = json_get_member(root, "mudurl");
if (token && token->type == JSON_STRING) {
@@ -1925,9 +2046,56 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
txt);
}
- resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole);
+#ifdef CONFIG_DPP2
+ cert_req = json_get_member_base64(root, "pkcs10");
+ if (cert_req) {
+ char *txt;
+ int id;
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: CertificateRequest", cert_req);
+ if (dpp_validate_csr(auth, cert_req) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: CSR is not valid");
+ auth->force_conf_resp_status = DPP_STATUS_CSR_BAD;
+ goto cont;
+ }
+
+ if (auth->peer_bi) {
+ id = auth->peer_bi->id;
+ } else if (auth->tmp_peer_bi) {
+ id = auth->tmp_peer_bi->id;
+ } else {
+ struct dpp_bootstrap_info *bi;
+
+ bi = os_zalloc(sizeof(*bi));
+ if (!bi)
+ goto fail;
+ bi->id = dpp_next_id(auth->global);
+ dl_list_add(&auth->global->bootstrap, &bi->list);
+ auth->tmp_peer_bi = bi;
+ id = bi->id;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: CSR is valid - forward to CA/RA");
+ txt = base64_encode_no_lf(wpabuf_head(cert_req),
+ wpabuf_len(cert_req), NULL);
+ if (!txt)
+ goto fail;
+
+ wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_CSR "peer=%d csr=%s",
+ id, txt);
+ os_free(txt);
+ auth->waiting_csr = false;
+ auth->waiting_cert = true;
+ goto fail;
+ }
+cont:
+#endif /* CONFIG_DPP2 */
+
+ resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole,
+ cert_req);
fail:
+ wpabuf_free(cert_req);
json_free(root);
os_free(unwrapped);
return resp;
@@ -2356,6 +2524,58 @@ fail:
}
+#ifdef CONFIG_DPP2
+static int dpp_parse_cred_dot1x(struct dpp_authentication *auth,
+ struct dpp_config_obj *conf,
+ struct json_token *cred)
+{
+ struct json_token *ent, *name;
+
+ ent = json_get_member(cred, "entCreds");
+ if (!ent || ent->type != JSON_OBJECT) {
+ dpp_auth_fail(auth, "No entCreds in JSON");
+ return -1;
+ }
+
+ conf->certbag = json_get_member_base64(ent, "certBag");
+ if (!conf->certbag) {
+ dpp_auth_fail(auth, "No certBag in JSON");
+ return -1;
+ }
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received certBag", conf->certbag);
+ conf->certs = dpp_pkcs7_certs(conf->certbag);
+ if (!conf->certs) {
+ dpp_auth_fail(auth, "No certificates in certBag");
+ return -1;
+ }
+
+ conf->cacert = json_get_member_base64(ent, "caCert");
+ if (conf->cacert)
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received caCert",
+ conf->cacert);
+
+ name = json_get_member(ent, "trustedEapServerName");
+ if (name &&
+ (name->type != JSON_STRING ||
+ has_ctrl_char((const u8 *) name->string,
+ os_strlen(name->string)))) {
+ dpp_auth_fail(auth,
+ "Invalid trustedEapServerName type in JSON");
+ return -1;
+ }
+ if (name && name->string) {
+ wpa_printf(MSG_DEBUG, "DPP: Received trustedEapServerName: %s",
+ name->string);
+ conf->server_name = os_strdup(name->string);
+ if (!conf->server_name)
+ return -1;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_DPP2 */
+
+
const char * dpp_akm_str(enum dpp_akm akm)
{
switch (akm) {
@@ -2371,6 +2591,8 @@ const char * dpp_akm_str(enum dpp_akm akm)
return "dpp+sae";
case DPP_AKM_PSK_SAE_DPP:
return "dpp+psk+sae";
+ case DPP_AKM_DOT1X:
+ return "dot1x";
default:
return "??";
}
@@ -2392,6 +2614,8 @@ const char * dpp_akm_selector_str(enum dpp_akm akm)
return "506F9A02+000FAC08";
case DPP_AKM_PSK_SAE_DPP:
return "506F9A02+000FAC08+000FAC02+000FAC06";
+ case DPP_AKM_DOT1X:
+ return "000FAC01+000FAC05";
default:
return "??";
}
@@ -2401,7 +2625,7 @@ const char * dpp_akm_selector_str(enum dpp_akm akm)
static enum dpp_akm dpp_akm_from_str(const char *akm)
{
const char *pos;
- int dpp = 0, psk = 0, sae = 0;
+ int dpp = 0, psk = 0, sae = 0, dot1x = 0;
if (os_strcmp(akm, "psk") == 0)
return DPP_AKM_PSK;
@@ -2415,6 +2639,8 @@ static enum dpp_akm dpp_akm_from_str(const char *akm)
return DPP_AKM_SAE_DPP;
if (os_strcmp(akm, "dpp+psk+sae") == 0)
return DPP_AKM_PSK_SAE_DPP;
+ if (os_strcmp(akm, "dot1x") == 0)
+ return DPP_AKM_DOT1X;
pos = akm;
while (*pos) {
@@ -2428,6 +2654,10 @@ static enum dpp_akm dpp_akm_from_str(const char *akm)
psk = 1;
else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
sae = 1;
+ else if (os_strncasecmp(pos, "000FAC01", 8) == 0)
+ dot1x = 1;
+ else if (os_strncasecmp(pos, "000FAC05", 8) == 0)
+ dot1x = 1;
pos += 8;
if (*pos != '+')
break;
@@ -2446,6 +2676,8 @@ static enum dpp_akm dpp_akm_from_str(const char *akm)
return DPP_AKM_SAE;
if (psk)
return DPP_AKM_PSK;
+ if (dot1x)
+ return DPP_AKM_DOT1X;
return DPP_AKM_UNKNOWN;
}
@@ -2563,6 +2795,12 @@ static int dpp_parse_conf_obj(struct dpp_authentication *auth,
(auth->peer_version >= 2 && dpp_akm_legacy(conf->akm))) {
if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
goto fail;
+#ifdef CONFIG_DPP2
+ } else if (conf->akm == DPP_AKM_DOT1X) {
+ if (dpp_parse_cred_dot1x(auth, conf, cred) < 0 ||
+ dpp_parse_cred_dpp(auth, conf, cred) < 0)
+ goto fail;
+#endif /* CONFIG_DPP2 */
} else {
wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
token->string);
@@ -2579,6 +2817,20 @@ fail:
}
+#ifdef CONFIG_DPP2
+static u8 * dpp_get_csr_attrs(const u8 *attrs, size_t attrs_len, size_t *len)
+{
+ const u8 *b64;
+ u16 b64_len;
+
+ b64 = dpp_get_attr(attrs, attrs_len, DPP_ATTR_CSR_ATTR_REQ, &b64_len);
+ if (!b64)
+ return NULL;
+ return base64_decode((const char *) b64, b64_len, len);
+}
+#endif /* CONFIG_DPP2 */
+
+
int dpp_conf_resp_rx(struct dpp_authentication *auth,
const struct wpabuf *resp)
{
@@ -2656,6 +2908,28 @@ int dpp_conf_resp_rx(struct dpp_authentication *auth,
}
auth->conf_resp_status = status[0];
wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
+#ifdef CONFIG_DPP2
+ if (status[0] == DPP_STATUS_CSR_NEEDED) {
+ u8 *csrattrs;
+ size_t csrattrs_len;
+
+ wpa_printf(MSG_DEBUG, "DPP: Configurator requested CSR");
+
+ csrattrs = dpp_get_csr_attrs(unwrapped, unwrapped_len,
+ &csrattrs_len);
+ if (!csrattrs) {
+ dpp_auth_fail(auth,
+ "Missing or invalid CSR Attributes Request attribute");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: CsrAttrs", csrattrs, csrattrs_len);
+ os_free(auth->csrattrs);
+ auth->csrattrs = csrattrs;
+ auth->csrattrs_len = csrattrs_len;
+ ret = -2;
+ goto fail;
+ }
+#endif /* CONFIG_DPP2 */
if (status[0] != DPP_STATUS_OK) {
dpp_auth_fail(auth, "Configurator rejected configuration");
goto fail;
@@ -3202,7 +3476,7 @@ int dpp_configurator_own_config(struct dpp_authentication *auth,
auth->peer_protocol_key = auth->own_protocol_key;
dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
- conf_obj = dpp_build_conf_obj(auth, ap, 0);
+ conf_obj = dpp_build_conf_obj(auth, ap, 0, NULL);
if (!conf_obj) {
wpabuf_free(auth->conf_obj[0].c_sign_key);
auth->conf_obj[0].c_sign_key = NULL;
@@ -3757,11 +4031,11 @@ static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info *own_bi,
u8 op_class, channel;
char chan[20];
- if (peer_bi->num_freq == 0)
+ if (peer_bi->num_freq == 0 && !peer_bi->channels_listed)
return 0; /* no channel preference/constraint */
for (i = 0; i < peer_bi->num_freq; i++) {
- if (own_bi->num_freq == 0 ||
+ if ((own_bi->num_freq == 0 && !own_bi->channels_listed) ||
freq_included(own_bi->freq, own_bi->num_freq,
peer_bi->freq[i])) {
freq = peer_bi->freq[i];
diff --git a/src/common/dpp.h b/src/common/dpp.h
index c0927d9..b3d505c 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -21,6 +21,7 @@ struct crypto_ecdh;
struct hostapd_ip_addr;
struct dpp_global;
struct json_token;
+struct dpp_reconfig_id;
#ifdef CONFIG_TESTING_OPTIONS
#define DPP_VERSION (dpp_version_override)
@@ -87,6 +88,8 @@ enum dpp_attribute_id {
DPP_ATTR_RECONFIG_FLAGS = 0x101D,
DPP_ATTR_C_SIGN_KEY_HASH = 0x101E,
DPP_ATTR_CSR_ATTR_REQ = 0x101F,
+ DPP_ATTR_A_NONCE = 0x1020,
+ DPP_ATTR_E_PRIME_ID = 0x1021,
};
enum dpp_status_error {
@@ -120,6 +123,7 @@ enum dpp_connector_key {
#define DPP_MAX_NONCE_LEN 32
#define DPP_MAX_HASH_LEN 64
#define DPP_MAX_SHARED_SECRET_LEN 66
+#define DPP_CP_LEN 64
struct dpp_curve_params {
const char *name;
@@ -149,6 +153,7 @@ struct dpp_bootstrap_info {
char *pk;
unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
unsigned int num_freq;
+ bool channels_listed;
u8 version;
int own;
EVP_PKEY *pubkey;
@@ -196,6 +201,7 @@ enum dpp_akm {
DPP_AKM_PSK_SAE,
DPP_AKM_SAE_DPP,
DPP_AKM_PSK_SAE_DPP,
+ DPP_AKM_DOT1X,
};
enum dpp_netrole {
@@ -221,6 +227,8 @@ struct dpp_configuration {
char *passphrase;
u8 psk[32];
int psk_set;
+
+ char *csrattrs;
};
struct dpp_asymmetric_key {
@@ -240,18 +248,21 @@ struct dpp_authentication {
struct dpp_bootstrap_info *peer_bi;
struct dpp_bootstrap_info *own_bi;
struct dpp_bootstrap_info *tmp_own_bi;
+ struct dpp_bootstrap_info *tmp_peer_bi;
u8 waiting_pubkey_hash[SHA256_MAC_LEN];
int response_pending;
int reconfig;
enum dpp_connector_key reconfig_connector_key;
enum dpp_status_error auth_resp_status;
enum dpp_status_error conf_resp_status;
+ enum dpp_status_error force_conf_resp_status;
u8 peer_mac_addr[ETH_ALEN];
u8 i_nonce[DPP_MAX_NONCE_LEN];
u8 r_nonce[DPP_MAX_NONCE_LEN];
u8 e_nonce[DPP_MAX_NONCE_LEN];
u8 i_capab;
u8 r_capab;
+ enum dpp_netrole e_netrole;
EVP_PKEY *own_protocol_key;
EVP_PKEY *peer_protocol_key;
EVP_PKEY *reconfig_old_protocol_key;
@@ -292,6 +303,7 @@ struct dpp_authentication {
bool reconfig_success;
struct wpabuf *conf_req;
const struct wpabuf *conf_resp; /* owned by GAS server */
+ struct wpabuf *conf_resp_tcp;
struct dpp_configuration *conf_ap;
struct dpp_configuration *conf2_ap;
struct dpp_configuration *conf_sta;
@@ -308,6 +320,10 @@ struct dpp_authentication {
int psk_set;
enum dpp_akm akm;
struct wpabuf *c_sign_key;
+ struct wpabuf *certbag;
+ struct wpabuf *certs;
+ struct wpabuf *cacert;
+ char *server_name;
} conf_obj[DPP_MAX_CONF_OBJ];
unsigned int num_conf_obj;
struct dpp_asymmetric_key *conf_key_pkg;
@@ -318,6 +334,16 @@ struct dpp_authentication {
int akm_use_selector;
int configurator_set;
u8 transaction_id;
+ u8 *csrattrs;
+ size_t csrattrs_len;
+ bool waiting_csr;
+ struct wpabuf *csr;
+ struct wpabuf *priv_key; /* DER-encoded private key used for csr */
+ bool waiting_cert;
+ char *trusted_eap_server_name;
+ struct wpabuf *cacert;
+ struct wpabuf *certbag;
+ void *cert_resp_ctx;
#ifdef CONFIG_TESTING_OPTIONS
char *config_obj_override;
char *discovery_override;
@@ -359,6 +385,7 @@ struct dpp_controller_config {
const char *configurator_params;
int tcp_port;
u8 allowed_roles;
+ int qr_mutual;
};
#ifdef CONFIG_TESTING_OPTIONS
@@ -516,6 +543,10 @@ void dpp_configuration_free(struct dpp_configuration *conf);
int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd);
void dpp_auth_deinit(struct dpp_authentication *auth);
struct wpabuf *
+dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
+ u16 e_nonce_len, enum dpp_netrole netrole,
+ bool cert_req);
+struct wpabuf *
dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
size_t attr_len);
int dpp_conf_resp_rx(struct dpp_authentication *auth,
@@ -592,6 +623,11 @@ struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len);
void dpp_pfs_free(struct dpp_pfs *pfs);
+struct wpabuf * dpp_build_csr(struct dpp_authentication *auth,
+ const char *name);
+struct wpabuf * dpp_pkcs7_certs(const struct wpabuf *pkcs7);
+int dpp_validate_csr(struct dpp_authentication *auth, const struct wpabuf *csr);
+
struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
const char *uri);
struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
@@ -631,8 +667,17 @@ int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data,
int dpp_controller_start(struct dpp_global *dpp,
struct dpp_controller_config *config);
void dpp_controller_stop(struct dpp_global *dpp);
+struct dpp_authentication * dpp_controller_get_auth(struct dpp_global *dpp,
+ unsigned int id);
+void dpp_controller_new_qr_code(struct dpp_global *dpp,
+ struct dpp_bootstrap_info *bi);
int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
- const struct hostapd_ip_addr *addr, int port);
+ const struct hostapd_ip_addr *addr, int port,
+ const char *name, enum dpp_netrole netrole, void *msg_ctx,
+ void *cb_ctx,
+ int (*process_conf_obj)(void *ctx,
+ struct dpp_authentication *auth));
+
struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi);
struct dpp_global_config {
@@ -649,10 +694,15 @@ void dpp_global_deinit(struct dpp_global *dpp);
/* dpp_reconfig.c */
struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key,
- size_t csign_key_len);
+ size_t csign_key_len,
+ const u8 *net_access_key,
+ size_t net_access_key_len,
+ struct dpp_reconfig_id *id);
struct dpp_authentication *
dpp_reconfig_init(struct dpp_global *dpp, void *msg_ctx,
- struct dpp_configurator *conf, unsigned int freq);
+ struct dpp_configurator *conf, unsigned int freq, u16 group,
+ const u8 *a_nonce_attr, size_t a_nonce_len,
+ const u8 *e_id_attr, size_t e_id_len);
struct dpp_authentication *
dpp_reconfig_auth_req_rx(struct dpp_global *dpp, void *msg_ctx,
const char *own_connector,
@@ -666,5 +716,10 @@ dpp_reconfig_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
int dpp_reconfig_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
const u8 *attr_start, size_t attr_len);
+struct dpp_reconfig_id * dpp_gen_reconfig_id(const u8 *csign_key,
+ size_t csign_key_len);
+int dpp_update_reconfig_id(struct dpp_reconfig_id *id);
+void dpp_free_reconfig_id(struct dpp_reconfig_id *id);
+
#endif /* CONFIG_DPP */
#endif /* DPP_H */
diff --git a/src/common/dpp_crypto.c b/src/common/dpp_crypto.c
index 8f884fd..9dff7c6 100644
--- a/src/common/dpp_crypto.c
+++ b/src/common/dpp_crypto.c
@@ -12,6 +12,7 @@
#include <openssl/err.h>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
+#include <openssl/pem.h>
#include "utils/common.h"
#include "utils/base64.h"
@@ -129,6 +130,18 @@ const struct dpp_curve_params * dpp_get_curve_nid(int nid)
}
+const struct dpp_curve_params * dpp_get_curve_ike_group(u16 group)
+{
+ int i;
+
+ for (i = 0; dpp_curves[i].name; i++) {
+ if (dpp_curves[i].ike_group == group)
+ return &dpp_curves[i];
+ }
+ return NULL;
+}
+
+
void dpp_debug_print_point(const char *title, const EC_GROUP *group,
const EC_POINT *point)
{
@@ -2271,7 +2284,7 @@ int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
if (auth->curve != curve) {
wpa_printf(MSG_DEBUG,
- "DPP: Mismatching netAccessKey curves (%s != %s)",
+ "DPP: Mismatching netAccessKey curves (own=%s != peer=%s)",
auth->curve->name, curve->name);
goto fail;
}
@@ -2380,7 +2393,7 @@ int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth,
dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
if (auth->curve != curve) {
wpa_printf(MSG_DEBUG,
- "DPP: Mismatching netAccessKey curves (%s != %s)",
+ "DPP: Mismatching netAccessKey curves (own=%s != peer=%s)",
auth->curve->name, curve->name);
goto fail;
}
@@ -2664,6 +2677,504 @@ void dpp_pfs_free(struct dpp_pfs *pfs)
os_free(pfs);
}
+
+struct wpabuf * dpp_build_csr(struct dpp_authentication *auth, const char *name)
+{
+ X509_REQ *req = NULL;
+ struct wpabuf *buf = NULL;
+ unsigned char *der;
+ int der_len;
+ EVP_PKEY *key;
+ const EVP_MD *sign_md;
+ unsigned int hash_len = auth->curve->hash_len;
+ EC_KEY *eckey;
+ BIO *out = NULL;
+ u8 cp[DPP_CP_LEN];
+ char *password;
+ size_t password_len;
+ int res;
+
+ /* TODO: use auth->csrattrs */
+
+ /* TODO: support generation of a new private key if csrAttrs requests
+ * a specific group to be used */
+ key = auth->own_protocol_key;
+
+ eckey = EVP_PKEY_get1_EC_KEY(key);
+ if (!eckey)
+ goto fail;
+ der = NULL;
+ der_len = i2d_ECPrivateKey(eckey, &der);
+ if (der_len <= 0)
+ goto fail;
+ wpabuf_free(auth->priv_key);
+ auth->priv_key = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
+ if (!auth->priv_key)
+ goto fail;
+
+ req = X509_REQ_new();
+ if (!req || !X509_REQ_set_pubkey(req, key))
+ goto fail;
+
+ if (name) {
+ X509_NAME *n;
+
+ n = X509_REQ_get_subject_name(req);
+ if (!n)
+ goto fail;
+
+ if (X509_NAME_add_entry_by_txt(
+ n, "CN", MBSTRING_UTF8,
+ (const unsigned char *) name, -1, -1, 0) != 1)
+ goto fail;
+ }
+
+ /* cp = HKDF-Expand(bk, "CSR challengePassword", 64) */
+ if (dpp_hkdf_expand(hash_len, auth->bk, hash_len,
+ "CSR challengePassword", cp, DPP_CP_LEN) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG,
+ "DPP: cp = HKDF-Expand(bk, \"CSR challengePassword\", 64)",
+ cp, DPP_CP_LEN);
+ password = base64_encode_no_lf(cp, DPP_CP_LEN, &password_len);
+ forced_memzero(cp, DPP_CP_LEN);
+ if (!password)
+ goto fail;
+
+ res = X509_REQ_add1_attr_by_NID(req, NID_pkcs9_challengePassword,
+ V_ASN1_UTF8STRING,
+ (const unsigned char *) password,
+ password_len);
+ bin_clear_free(password, password_len);
+ if (!res)
+ goto fail;
+
+ /* TODO */
+
+ /* TODO: hash func selection based on csrAttrs */
+ if (hash_len == SHA256_MAC_LEN) {
+ sign_md = EVP_sha256();
+ } else if (hash_len == SHA384_MAC_LEN) {
+ sign_md = EVP_sha384();
+ } else if (hash_len == SHA512_MAC_LEN) {
+ sign_md = EVP_sha512();
+ } else {
+ wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
+ goto fail;
+ }
+
+ if (!X509_REQ_sign(req, key, sign_md))
+ goto fail;
+
+ der = NULL;
+ der_len = i2d_X509_REQ(req, &der);
+ if (der_len < 0)
+ goto fail;
+ buf = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: CSR", buf);
+
+fail:
+ BIO_free_all(out);
+ X509_REQ_free(req);
+ return buf;
+}
+
+
+struct wpabuf * dpp_pkcs7_certs(const struct wpabuf *pkcs7)
+{
+#ifdef OPENSSL_IS_BORINGSSL
+ CBS pkcs7_cbs;
+#else /* OPENSSL_IS_BORINGSSL */
+ PKCS7 *p7 = NULL;
+ const unsigned char *p = wpabuf_head(pkcs7);
+#endif /* OPENSSL_IS_BORINGSSL */
+ STACK_OF(X509) *certs;
+ int i, num;
+ BIO *out = NULL;
+ size_t rlen;
+ struct wpabuf *pem = NULL;
+ int res;
+
+#ifdef OPENSSL_IS_BORINGSSL
+ certs = sk_X509_new_null();
+ if (!certs)
+ goto fail;
+ CBS_init(&pkcs7_cbs, wpabuf_head(pkcs7), wpabuf_len(pkcs7));
+ if (!PKCS7_get_certificates(certs, &pkcs7_cbs)) {
+ wpa_printf(MSG_INFO, "DPP: Could not parse PKCS#7 object: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+#else /* OPENSSL_IS_BORINGSSL */
+ p7 = d2i_PKCS7(NULL, &p, wpabuf_len(pkcs7));
+ if (!p7) {
+ wpa_printf(MSG_INFO, "DPP: Could not parse PKCS#7 object: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ switch (OBJ_obj2nid(p7->type)) {
+ case NID_pkcs7_signed:
+ certs = p7->d.sign->cert;
+ break;
+ case NID_pkcs7_signedAndEnveloped:
+ certs = p7->d.signed_and_enveloped->cert;
+ break;
+ default:
+ certs = NULL;
+ break;
+ }
+#endif /* OPENSSL_IS_BORINGSSL */
+
+ if (!certs || ((num = sk_X509_num(certs)) == 0)) {
+ wpa_printf(MSG_INFO,
+ "DPP: No certificates found in PKCS#7 object");
+ goto fail;
+ }
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ goto fail;
+
+ for (i = 0; i < num; i++) {
+ X509 *cert = sk_X509_value(certs, i);
+
+ PEM_write_bio_X509(out, cert);
+ }
+
+ rlen = BIO_ctrl_pending(out);
+ pem = wpabuf_alloc(rlen);
+ if (!pem)
+ goto fail;
+ res = BIO_read(out, wpabuf_put(pem, 0), rlen);
+ if (res <= 0) {
+ wpabuf_free(pem);
+ goto fail;
+ }
+ wpabuf_put(pem, res);
+
+fail:
+#ifdef OPENSSL_IS_BORINGSSL
+ if (certs)
+ sk_X509_pop_free(certs, X509_free);
+#else /* OPENSSL_IS_BORINGSSL */
+ PKCS7_free(p7);
+#endif /* OPENSSL_IS_BORINGSSL */
+ if (out)
+ BIO_free_all(out);
+
+ return pem;
+}
+
+
+int dpp_validate_csr(struct dpp_authentication *auth, const struct wpabuf *csr)
+{
+ X509_REQ *req;
+ const unsigned char *pos;
+ EVP_PKEY *pkey;
+ int res, loc, ret = -1;
+ X509_ATTRIBUTE *attr;
+ ASN1_TYPE *type;
+ ASN1_STRING *str;
+ unsigned char *utf8 = NULL;
+ unsigned char *cp = NULL;
+ size_t cp_len;
+ u8 exp_cp[DPP_CP_LEN];
+ unsigned int hash_len = auth->curve->hash_len;
+
+ pos = wpabuf_head(csr);
+ req = d2i_X509_REQ(NULL, &pos, wpabuf_len(csr));
+ if (!req) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to parse CSR");
+ return -1;
+ }
+
+ pkey = X509_REQ_get_pubkey(req);
+ if (!pkey) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to get public key from CSR");
+ goto fail;
+ }
+
+ res = X509_REQ_verify(req, pkey);
+ EVP_PKEY_free(pkey);
+ if (res != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: CSR does not have a valid signature");
+ goto fail;
+ }
+
+ loc = X509_REQ_get_attr_by_NID(req, NID_pkcs9_challengePassword, -1);
+ if (loc < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: CSR does not include challengePassword");
+ goto fail;
+ }
+
+ attr = X509_REQ_get_attr(req, loc);
+ if (!attr) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not get challengePassword attribute");
+ goto fail;
+ }
+
+ type = X509_ATTRIBUTE_get0_type(attr, 0);
+ if (!type) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not get challengePassword attribute type");
+ goto fail;
+ }
+
+ res = ASN1_TYPE_get(type);
+ /* This is supposed to be UTF8String, but allow other strings as well
+ * since challengePassword is using ASCII (base64 encoded). */
+ if (res != V_ASN1_UTF8STRING && res != V_ASN1_PRINTABLESTRING &&
+ res != V_ASN1_IA5STRING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected challengePassword attribute type %d",
+ res);
+ goto fail;
+ }
+
+ str = X509_ATTRIBUTE_get0_data(attr, 0, res, NULL);
+ if (!str) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not get ASN.1 string for challengePassword");
+ goto fail;
+ }
+
+ res = ASN1_STRING_to_UTF8(&utf8, str);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not get UTF8 version of challengePassword");
+ goto fail;
+ }
+
+ cp = base64_decode((const char *) utf8, res, &cp_len);
+ OPENSSL_free(utf8);
+ if (!cp) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not base64 decode challengePassword");
+ goto fail;
+ }
+ if (cp_len != DPP_CP_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected cp length (%zu) in CSR challengePassword",
+ cp_len);
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "DPP: cp from CSR challengePassword",
+ cp, cp_len);
+
+ /* cp = HKDF-Expand(bk, "CSR challengePassword", 64) */
+ if (dpp_hkdf_expand(hash_len, auth->bk, hash_len,
+ "CSR challengePassword", exp_cp, DPP_CP_LEN) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG,
+ "DPP: cp = HKDF-Expand(bk, \"CSR challengePassword\", 64)",
+ exp_cp, DPP_CP_LEN);
+ if (os_memcmp_const(cp, exp_cp, DPP_CP_LEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: CSR challengePassword does not match calculated cp");
+ goto fail;
+ }
+
+ ret = 0;
+fail:
+ os_free(cp);
+ X509_REQ_free(req);
+ return ret;
+}
+
+
+struct dpp_reconfig_id * dpp_gen_reconfig_id(const u8 *csign_key,
+ size_t csign_key_len)
+{
+ const unsigned char *p;
+ EVP_PKEY *csign = NULL;
+ struct dpp_reconfig_id *id = NULL;
+ BN_CTX *ctx = NULL;
+ BIGNUM *bn = NULL, *q = NULL;
+ const EC_KEY *eckey;
+ const EC_GROUP *group;
+ EC_POINT *e_id = NULL;
+
+ p = csign_key;
+ csign = d2i_PUBKEY(NULL, &p, csign_key_len);
+ if (!csign)
+ goto fail;
+
+ eckey = EVP_PKEY_get0_EC_KEY(csign);
+ if (!eckey)
+ goto fail;
+ group = EC_KEY_get0_group(eckey);
+ if (!group)
+ goto fail;
+
+ e_id = EC_POINT_new(group);
+ ctx = BN_CTX_new();
+ bn = BN_new();
+ q = BN_new();
+ if (!e_id || !ctx || !bn || !q ||
+ !EC_GROUP_get_order(group, q, ctx) ||
+ !BN_rand_range(bn, q) ||
+ !EC_POINT_mul(group, e_id, bn, NULL, NULL, ctx))
+ goto fail;
+
+ dpp_debug_print_point("DPP: Generated random point E-id", group, e_id);
+
+ id = os_zalloc(sizeof(*id));
+ if (!id)
+ goto fail;
+ id->group = group;
+ id->e_id = e_id;
+ e_id = NULL;
+ id->csign = csign;
+ csign = NULL;
+fail:
+ EC_POINT_free(e_id);
+ EVP_PKEY_free(csign);
+ BN_clear_free(bn);
+ BN_CTX_free(ctx);
+ return id;
+}
+
+
+static EVP_PKEY * dpp_pkey_from_point(const EC_GROUP *group,
+ const EC_POINT *point)
+{
+ EC_KEY *eckey;
+ EVP_PKEY *pkey = NULL;
+
+ eckey = EC_KEY_new();
+ if (!eckey ||
+ EC_KEY_set_group(eckey, group) != 1 ||
+ EC_KEY_set_public_key(eckey, point) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to set EC_KEY: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
+
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: Could not create EVP_PKEY");
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ goto fail;
+ }
+
+fail:
+ EC_KEY_free(eckey);
+ return pkey;
+}
+
+
+int dpp_update_reconfig_id(struct dpp_reconfig_id *id)
+{
+ BN_CTX *ctx = NULL;
+ BIGNUM *bn = NULL, *q = NULL;
+ EC_POINT *e_prime_id = NULL, *a_nonce = NULL;
+ int ret = -1;
+ const EC_KEY *csign;
+ const EC_POINT *csign_point;
+
+ csign = EVP_PKEY_get0_EC_KEY(id->csign);
+ if (!csign)
+ goto fail;
+ csign_point = EC_KEY_get0_public_key(csign);
+ e_prime_id = EC_POINT_new(id->group);
+ a_nonce = EC_POINT_new(id->group);
+ ctx = BN_CTX_new();
+ bn = BN_new();
+ q = BN_new();
+ /* Generate random 0 <= a-nonce < q
+ * A-NONCE = a-nonce * G
+ * E'-id = E-id + a-nonce * S_C */
+ if (!csign_point || !e_prime_id || !a_nonce || !ctx || !bn || !q ||
+ !EC_GROUP_get_order(id->group, q, ctx) ||
+ !BN_rand_range(bn, q) || /* bn = a-nonce */
+ !EC_POINT_mul(id->group, a_nonce, bn, NULL, NULL, ctx) ||
+ !EC_POINT_mul(id->group, e_prime_id, NULL, csign_point, bn, ctx) ||
+ !EC_POINT_add(id->group, e_prime_id, id->e_id, e_prime_id, ctx))
+ goto fail;
+
+ dpp_debug_print_point("DPP: Generated A-NONCE", id->group, a_nonce);
+ dpp_debug_print_point("DPP: Encrypted E-id to E'-id",
+ id->group, e_prime_id);
+
+ EVP_PKEY_free(id->a_nonce);
+ EVP_PKEY_free(id->e_prime_id);
+ id->a_nonce = dpp_pkey_from_point(id->group, a_nonce);
+ id->e_prime_id = dpp_pkey_from_point(id->group, e_prime_id);
+ if (!id->a_nonce || !id->e_prime_id)
+ goto fail;
+
+ ret = 0;
+
+fail:
+ EC_POINT_free(e_prime_id);
+ EC_POINT_free(a_nonce);
+ BN_clear_free(bn);
+ BN_CTX_free(ctx);
+ return ret;
+}
+
+
+void dpp_free_reconfig_id(struct dpp_reconfig_id *id)
+{
+ if (id) {
+ EC_POINT_clear_free(id->e_id);
+ EVP_PKEY_free(id->csign);
+ EVP_PKEY_free(id->a_nonce);
+ EVP_PKEY_free(id->e_prime_id);
+ os_free(id);
+ }
+}
+
+
+EC_POINT * dpp_decrypt_e_id(EVP_PKEY *csign, EVP_PKEY *a_nonce,
+ EVP_PKEY *e_prime_id)
+{
+ const EC_KEY *csign_ec, *a_nonce_ec, *e_prime_id_ec;
+ const BIGNUM *csign_bn;
+ const EC_GROUP *group;
+ EC_POINT *e_id = NULL;
+ const EC_POINT *a_nonce_point, *e_prime_id_point;
+ BN_CTX *ctx = NULL;
+
+ /* E-id = E'-id - s_C * A-NONCE */
+ csign_ec = EVP_PKEY_get0_EC_KEY(csign);
+ a_nonce_ec = EVP_PKEY_get0_EC_KEY(a_nonce);
+ e_prime_id_ec = EVP_PKEY_get0_EC_KEY(e_prime_id);
+ if (!csign_ec || !a_nonce_ec || !e_prime_id_ec)
+ return NULL;
+ csign_bn = EC_KEY_get0_private_key(csign_ec);
+ group = EC_KEY_get0_group(csign_ec);
+ a_nonce_point = EC_KEY_get0_public_key(a_nonce_ec);
+ e_prime_id_point = EC_KEY_get0_public_key(e_prime_id_ec);
+ ctx = BN_CTX_new();
+ if (!csign_bn || !group || !a_nonce_point || !e_prime_id_point || !ctx)
+ goto fail;
+ e_id = EC_POINT_new(group);
+ if (!e_id ||
+ !EC_POINT_mul(group, e_id, NULL, a_nonce_point, csign_bn, ctx) ||
+ !EC_POINT_invert(group, e_id, ctx) ||
+ !EC_POINT_add(group, e_id, e_prime_id_point, e_id, ctx)) {
+ EC_POINT_clear_free(e_id);
+ goto fail;
+ }
+
+ dpp_debug_print_point("DPP: Decrypted E-id", group, e_id);
+
+fail:
+ BN_CTX_free(ctx);
+ return e_id;
+}
+
#endif /* CONFIG_DPP2 */
diff --git a/src/common/dpp_i.h b/src/common/dpp_i.h
index e66eb6c..f2164c7 100644
--- a/src/common/dpp_i.h
+++ b/src/common/dpp_i.h
@@ -73,6 +73,7 @@ dpp_check_signed_connector(struct dpp_signed_connector_info *info,
const struct dpp_curve_params * dpp_get_curve_name(const char *name);
const struct dpp_curve_params * dpp_get_curve_jwk_crv(const char *name);
const struct dpp_curve_params * dpp_get_curve_nid(int nid);
+const struct dpp_curve_params * dpp_get_curve_ike_group(u16 group);
int dpp_bi_pubkey_hash(struct dpp_bootstrap_info *bi,
const u8 *data, size_t data_len);
struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix);
@@ -132,11 +133,21 @@ int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth,
const u8 *r_proto, u16 r_proto_len,
struct json_token *net_access_key);
+EC_POINT * dpp_decrypt_e_id(EVP_PKEY *csign, EVP_PKEY *a_nonce,
+ EVP_PKEY *e_prime_id);
char * dpp_sign_connector(struct dpp_configurator *conf,
const struct wpabuf *dppcon);
int dpp_test_gen_invalid_key(struct wpabuf *msg,
const struct dpp_curve_params *curve);
+struct dpp_reconfig_id {
+ const EC_GROUP *group;
+ EC_POINT *e_id; /* E-id */
+ EVP_PKEY *csign;
+ EVP_PKEY *a_nonce; /* A-NONCE */
+ EVP_PKEY *e_prime_id; /* E'-id */
+};
+
/* dpp_tcp.c */
void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
diff --git a/src/common/dpp_reconfig.c b/src/common/dpp_reconfig.c
index 0bb00cc..a361131 100644
--- a/src/common/dpp_reconfig.c
+++ b/src/common/dpp_reconfig.c
@@ -34,9 +34,12 @@ static void dpp_build_attr_csign_key_hash(struct wpabuf *msg, const u8 *hash)
struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key,
- size_t csign_key_len)
+ size_t csign_key_len,
+ const u8 *net_access_key,
+ size_t net_access_key_len,
+ struct dpp_reconfig_id *id)
{
- struct wpabuf *msg;
+ struct wpabuf *msg = NULL;
EVP_PKEY *csign = NULL;
const unsigned char *p;
struct wpabuf *uncomp;
@@ -44,39 +47,86 @@ struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key,
const u8 *addr[1];
size_t len[1];
int res;
+ size_t attr_len;
+ const struct dpp_curve_params *own_curve;
+ EVP_PKEY *own_key;
+ struct wpabuf *a_nonce = NULL, *e_id = NULL;
wpa_printf(MSG_DEBUG, "DPP: Build Reconfig Announcement frame");
+ own_key = dpp_set_keypair(&own_curve, net_access_key,
+ net_access_key_len);
+ if (!own_key) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
+ goto fail;
+ }
+
p = csign_key;
csign = d2i_PUBKEY(NULL, &p, csign_key_len);
if (!csign) {
wpa_printf(MSG_ERROR,
"DPP: Failed to parse local C-sign-key information");
- return NULL;
+ goto fail;
}
uncomp = dpp_get_pubkey_point(csign, 1);
EVP_PKEY_free(csign);
if (!uncomp)
- return NULL;
+ goto fail;
addr[0] = wpabuf_head(uncomp);
len[0] = wpabuf_len(uncomp);
wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed C-sign key", addr[0], len[0]);
res = sha256_vector(1, addr, len, hash);
wpabuf_free(uncomp);
if (res < 0)
- return NULL;
+ goto fail;
wpa_hexdump(MSG_DEBUG, "DPP: kid = SHA256(uncompressed C-sign key)",
hash, SHA256_MAC_LEN);
- msg = dpp_alloc_msg(DPP_PA_RECONFIG_ANNOUNCEMENT, 4 + SHA256_MAC_LEN);
+ if (dpp_update_reconfig_id(id) < 0) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to generate E'-id");
+ goto fail;
+ }
+
+ a_nonce = dpp_get_pubkey_point(id->a_nonce, 0);
+ e_id = dpp_get_pubkey_point(id->e_prime_id, 0);
+ if (!a_nonce || !e_id)
+ goto fail;
+
+ attr_len = 4 + SHA256_MAC_LEN;
+ attr_len += 4 + 2;
+ attr_len += 4 + wpabuf_len(a_nonce);
+ attr_len += 4 + wpabuf_len(e_id);
+ msg = dpp_alloc_msg(DPP_PA_RECONFIG_ANNOUNCEMENT, attr_len);
if (!msg)
- return NULL;
+ goto fail;
/* Configurator C-sign key Hash */
dpp_build_attr_csign_key_hash(msg, hash);
+
+ /* Finite Cyclic Group attribute */
+ wpa_printf(MSG_DEBUG, "DPP: Finite Cyclic Group: %u",
+ own_curve->ike_group);
+ wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
+ wpabuf_put_le16(msg, 2);
+ wpabuf_put_le16(msg, own_curve->ike_group);
+
+ /* A-NONCE */
+ wpabuf_put_le16(msg, DPP_ATTR_A_NONCE);
+ wpabuf_put_le16(msg, wpabuf_len(a_nonce));
+ wpabuf_put_buf(msg, a_nonce);
+
+ /* E'-id */
+ wpabuf_put_le16(msg, DPP_ATTR_E_PRIME_ID);
+ wpabuf_put_le16(msg, wpabuf_len(e_id));
+ wpabuf_put_buf(msg, e_id);
+
wpa_hexdump_buf(MSG_DEBUG,
"DPP: Reconfig Announcement frame attributes", msg);
+fail:
+ wpabuf_free(a_nonce);
+ wpabuf_free(e_id);
+ EVP_PKEY_free(own_key);
return msg;
}
@@ -121,7 +171,9 @@ static struct wpabuf * dpp_reconfig_build_req(struct dpp_authentication *auth)
}
-static int dpp_configurator_build_own_connector(struct dpp_configurator *conf)
+static int
+dpp_configurator_build_own_connector(struct dpp_configurator *conf,
+ const struct dpp_curve_params *curve)
{
struct wpabuf *dppcon = NULL;
int ret = -1;
@@ -132,12 +184,12 @@ static int dpp_configurator_build_own_connector(struct dpp_configurator *conf)
wpa_printf(MSG_DEBUG,
"DPP: Sign own Configurator Connector for reconfiguration with curve %s",
conf->curve->name);
- conf->connector_key = dpp_gen_keypair(conf->curve);
+ conf->connector_key = dpp_gen_keypair(curve);
if (!conf->connector_key)
goto fail;
/* Connector (JSON dppCon object) */
- dppcon = wpabuf_alloc(1000 + 2 * conf->curve->prime_len * 4 / 3);
+ dppcon = wpabuf_alloc(1000 + 2 * curve->prime_len * 4 / 3);
if (!dppcon)
goto fail;
json_start_object(dppcon, NULL);
@@ -150,7 +202,7 @@ static int dpp_configurator_build_own_connector(struct dpp_configurator *conf)
json_end_array(dppcon);
json_value_sep(dppcon);
if (dpp_build_jwk(dppcon, "netAccessKey", conf->connector_key, NULL,
- conf->curve) < 0) {
+ curve) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
goto fail;
}
@@ -172,9 +224,58 @@ fail:
struct dpp_authentication *
dpp_reconfig_init(struct dpp_global *dpp, void *msg_ctx,
- struct dpp_configurator *conf, unsigned int freq)
+ struct dpp_configurator *conf, unsigned int freq, u16 group,
+ const u8 *a_nonce_attr, size_t a_nonce_len,
+ const u8 *e_id_attr, size_t e_id_len)
{
struct dpp_authentication *auth;
+ const struct dpp_curve_params *curve;
+ EVP_PKEY *a_nonce, *e_prime_id;
+ EC_POINT *e_id;
+
+ curve = dpp_get_curve_ike_group(group);
+ if (!curve) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unsupported group %u - cannot reconfigure",
+ group);
+ return NULL;
+ }
+
+ if (!a_nonce_attr) {
+ wpa_printf(MSG_INFO, "DPP: Missing required A-NONCE attribute");
+ return NULL;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: A-NONCE", a_nonce_attr, a_nonce_len);
+ a_nonce = dpp_set_pubkey_point(conf->csign, a_nonce_attr, a_nonce_len);
+ if (!a_nonce) {
+ wpa_printf(MSG_INFO, "DPP: Invalid A-NONCE");
+ return NULL;
+ }
+ dpp_debug_print_key("A-NONCE", a_nonce);
+
+ if (!e_id_attr) {
+ wpa_printf(MSG_INFO, "DPP: Missing required E'-id attribute");
+ return NULL;
+ }
+ e_prime_id = dpp_set_pubkey_point(conf->csign, e_id_attr, e_id_len);
+ if (!e_prime_id) {
+ wpa_printf(MSG_INFO, "DPP: Invalid E'-id");
+ EVP_PKEY_free(a_nonce);
+ return NULL;
+ }
+ dpp_debug_print_key("E'-id", e_prime_id);
+ e_id = dpp_decrypt_e_id(conf->csign, a_nonce, e_prime_id);
+ EVP_PKEY_free(a_nonce);
+ EVP_PKEY_free(e_prime_id);
+ if (!e_id) {
+ wpa_printf(MSG_INFO, "DPP: Could not decrypt E'-id");
+ return NULL;
+ }
+ /* TODO: could use E-id to determine whether reconfiguration with this
+ * Enrollee has already been started and is waiting for updated
+ * configuration instead of replying again before such configuration
+ * becomes available */
+ EC_POINT_clear_free(e_id);
auth = dpp_alloc_auth(dpp, msg_ctx);
if (!auth)
@@ -186,12 +287,12 @@ dpp_reconfig_init(struct dpp_global *dpp, void *msg_ctx,
auth->waiting_auth_resp = 1;
auth->allowed_roles = DPP_CAPAB_CONFIGURATOR;
auth->configurator = 1;
- auth->curve = conf->curve;
+ auth->curve = curve;
auth->transaction_id = 1;
if (freq && dpp_prepare_channel_list(auth, freq, NULL, 0) < 0)
goto fail;
- if (dpp_configurator_build_own_connector(conf) < 0)
+ if (dpp_configurator_build_own_connector(conf, curve) < 0)
goto fail;
if (random_get_bytes(auth->i_nonce, auth->curve->nonce_len)) {
@@ -462,40 +563,19 @@ fail:
}
-static struct wpabuf *
-dpp_build_reconfig_flags(enum dpp_connector_key connector_key)
-{
- struct wpabuf *json;
-
- json = wpabuf_alloc(100);
- if (!json)
- return NULL;
- json_start_object(json, NULL);
- json_add_int(json, "connectorKey", connector_key);
- json_end_object(json);
- wpa_hexdump_ascii(MSG_DEBUG, "DPP: Reconfig-Flags JSON",
- wpabuf_head(json), wpabuf_len(json));
-
- return json;
-}
-
-
struct wpabuf *
dpp_reconfig_build_conf(struct dpp_authentication *auth)
{
- struct wpabuf *msg = NULL, *clear = NULL, *reconfig_flags;
+ struct wpabuf *msg = NULL, *clear;
u8 *attr_start, *attr_end;
size_t clear_len, attr_len, len[2];
const u8 *addr[2];
u8 *wrapped;
-
- reconfig_flags = dpp_build_reconfig_flags(DPP_CONFIG_REPLACEKEY);
- if (!reconfig_flags)
- goto fail;
+ u8 flags;
/* Build DPP Reconfig Authentication Confirm frame attributes */
clear_len = 4 + 1 + 4 + 1 + 2 * (4 + auth->curve->nonce_len) +
- 4 + wpabuf_len(reconfig_flags);
+ 4 + 1;
clear = wpabuf_alloc(clear_len);
if (!clear)
goto fail;
@@ -521,16 +601,22 @@ dpp_reconfig_build_conf(struct dpp_authentication *auth)
wpabuf_put_data(clear, auth->r_nonce, auth->curve->nonce_len);
/* Reconfig-Flags (wrapped) */
+ flags = DPP_CONFIG_REPLACEKEY;
wpabuf_put_le16(clear, DPP_ATTR_RECONFIG_FLAGS);
- wpabuf_put_le16(clear, wpabuf_len(reconfig_flags));
- wpabuf_put_buf(clear, reconfig_flags);
+ wpabuf_put_le16(clear, 1);
+ wpabuf_put_u8(clear, flags);
attr_len = 4 + wpabuf_len(clear) + AES_BLOCK_SIZE;
+ attr_len += 4 + 1;
msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_CONF, attr_len);
if (!msg)
goto fail;
attr_start = wpabuf_put(msg, 0);
+
+ /* DPP Status */
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+
attr_end = wpabuf_put(msg, 0);
/* OUI, OUI type, Crypto Suite, DPP frame type */
@@ -559,7 +645,6 @@ dpp_reconfig_build_conf(struct dpp_authentication *auth)
msg);
out:
- wpabuf_free(reconfig_flags);
wpabuf_free(clear);
return msg;
fail:
@@ -759,15 +844,15 @@ int dpp_reconfig_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
const u8 *attr_start, size_t attr_len)
{
const u8 *trans_id, *version, *wrapped_data, *i_nonce, *r_nonce,
- *reconfig_flags;
+ *reconfig_flags, *status;
u16 trans_id_len, version_len, wrapped_data_len, i_nonce_len,
- r_nonce_len, reconfig_flags_len;
+ r_nonce_len, reconfig_flags_len, status_len;
const u8 *addr[2];
size_t len[2];
u8 *unwrapped = NULL;
size_t unwrapped_len = 0;
- struct json_token *root = NULL, *token;
int res = -1;
+ u8 flags;
if (!auth->reconfig || auth->configurator)
goto fail;
@@ -781,11 +866,26 @@ int dpp_reconfig_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
}
wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
wrapped_data, wrapped_data_len);
+ attr_len = wrapped_data - 4 - attr_start;
+
+ status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
+ &status_len);
+ if (!status || status_len < 1) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required DPP Status attribute");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
+ if (status[0] != DPP_STATUS_OK) {
+ dpp_auth_fail(auth,
+ "Reconfiguration did not complete successfully");
+ goto fail;
+ }
addr[0] = hdr;
len[0] = DPP_HDR_LEN;
addr[1] = attr_start;
- len[1] = 0;
+ len[1] = attr_len;
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
@@ -846,34 +946,17 @@ int dpp_reconfig_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
reconfig_flags = dpp_get_attr(unwrapped, unwrapped_len,
DPP_ATTR_RECONFIG_FLAGS,
&reconfig_flags_len);
- if (!reconfig_flags) {
+ if (!reconfig_flags || reconfig_flags_len < 1) {
dpp_auth_fail(auth, "Missing or invalid Reconfig-Flags");
goto fail;
}
- wpa_hexdump_ascii(MSG_DEBUG, "DPP: Reconfig-Flags",
- reconfig_flags, reconfig_flags_len);
- root = json_parse((const char *) reconfig_flags, reconfig_flags_len);
- if (!root) {
- dpp_auth_fail(auth, "Could not parse Reconfig-Flags");
- goto fail;
- }
- token = json_get_member(root, "connectorKey");
- if (!token || token->type != JSON_NUMBER) {
- dpp_auth_fail(auth, "No connectorKey in Reconfig-Flags");
- goto fail;
- }
- if (token->number != DPP_CONFIG_REUSEKEY &&
- token->number != DPP_CONFIG_REPLACEKEY) {
- dpp_auth_fail(auth,
- "Unsupported connectorKey value in Reconfig-Flags");
- goto fail;
- }
- auth->reconfig_connector_key = token->number;
+ flags = reconfig_flags[0] & BIT(0);
+ wpa_printf(MSG_DEBUG, "DPP: Reconfig Flags connectorKey=%u", flags);
+ auth->reconfig_connector_key = flags;
auth->reconfig_success = true;
res = 0;
fail:
- json_free(root);
bin_clear_free(unwrapped, unwrapped_len);
return res;
}
diff --git a/src/common/dpp_tcp.c b/src/common/dpp_tcp.c
index fc53b8a..e243a6d 100644
--- a/src/common/dpp_tcp.c
+++ b/src/common/dpp_tcp.c
@@ -25,6 +25,9 @@ struct dpp_connection {
struct dpp_relay_controller *relay;
struct dpp_global *global;
struct dpp_authentication *auth;
+ void *msg_ctx;
+ void *cb_ctx;
+ int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
int sock;
u8 mac_addr[ETH_ALEN];
unsigned int freq;
@@ -38,6 +41,10 @@ struct dpp_connection {
unsigned int on_tcp_tx_complete_gas_done:1;
unsigned int on_tcp_tx_complete_remove:1;
unsigned int on_tcp_tx_complete_auth_ok:1;
+ unsigned int gas_comeback_in_progress:1;
+ u8 gas_dialog_token;
+ char *name;
+ enum dpp_netrole netrole;
};
/* Remote Controller */
@@ -68,6 +75,8 @@ static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx);
static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx);
static void dpp_controller_auth_success(struct dpp_connection *conn,
int initiator);
+static void dpp_tcp_build_csr(void *eloop_ctx, void *timeout_ctx);
+static void dpp_tcp_gas_query_comeback(void *eloop_ctx, void *timeout_ctx);
static void dpp_connection_free(struct dpp_connection *conn)
@@ -81,9 +90,12 @@ static void dpp_connection_free(struct dpp_connection *conn)
}
eloop_cancel_timeout(dpp_controller_conn_status_result_wait_timeout,
conn, NULL);
+ eloop_cancel_timeout(dpp_tcp_build_csr, conn, NULL);
+ eloop_cancel_timeout(dpp_tcp_gas_query_comeback, conn, NULL);
wpabuf_free(conn->msg);
wpabuf_free(conn->msg_out);
dpp_auth_deinit(conn->auth);
+ os_free(conn->name);
os_free(conn);
}
@@ -139,7 +151,12 @@ dpp_relay_controller_get(struct dpp_global *dpp, const u8 *pkhash)
static void dpp_controller_gas_done(struct dpp_connection *conn)
{
struct dpp_authentication *auth = conn->auth;
- void *msg_ctx;
+
+ if (auth->waiting_csr) {
+ wpa_printf(MSG_DEBUG, "DPP: Waiting for CSR");
+ conn->on_tcp_tx_complete_gas_done = 0;
+ return;
+ }
if (auth->peer_version >= 2 &&
auth->conf_resp_status == DPP_STATUS_OK) {
@@ -148,11 +165,7 @@ static void dpp_controller_gas_done(struct dpp_connection *conn)
return;
}
- if (conn->ctrl)
- msg_ctx = conn->ctrl->global->msg_ctx;
- else
- msg_ctx = auth->msg_ctx;
- wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
+ wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
dpp_connection_remove(conn);
}
@@ -243,9 +256,11 @@ static void dpp_controller_start_gas_client(struct dpp_connection *conn)
{
struct dpp_authentication *auth = conn->auth;
struct wpabuf *buf;
- int netrole_ap = 0; /* TODO: make this configurable */
+ const char *dpp_name;
- buf = dpp_build_conf_req_helper(auth, "Test", netrole_ap, NULL, NULL);
+ dpp_name = conn->name ? conn->name : "Test";
+ buf = dpp_build_conf_req_helper(auth, dpp_name, conn->netrole, NULL,
+ NULL);
if (!buf) {
wpa_printf(MSG_DEBUG,
"DPP: No configuration request data available");
@@ -266,7 +281,7 @@ static void dpp_controller_auth_success(struct dpp_connection *conn,
return;
wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
- wpa_msg(conn->global->msg_ctx, MSG_INFO,
+ wpa_msg(conn->msg_ctx, MSG_INFO,
DPP_EVENT_AUTH_SUCCESS "init=%d", initiator);
#ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
@@ -356,6 +371,9 @@ dpp_relay_new_conn(struct dpp_relay_controller *ctrl, const u8 *src,
conn->global = ctrl->global;
conn->relay = ctrl;
+ conn->msg_ctx = ctrl->global->msg_ctx;
+ conn->cb_ctx = ctrl->global->cb_ctx;
+ conn->process_conf_obj = ctrl->global->process_conf_obj;
os_memcpy(conn->mac_addr, src, ETH_ALEN);
conn->freq = freq;
@@ -608,8 +626,7 @@ static int dpp_controller_rx_auth_req(struct dpp_connection *conn,
return 0;
}
- conn->auth = dpp_auth_req_rx(conn->ctrl->global,
- conn->ctrl->global->msg_ctx,
+ conn->auth = dpp_auth_req_rx(conn->ctrl->global, conn->msg_ctx,
conn->ctrl->allowed_roles,
conn->ctrl->qr_mutual,
peer_bi, own_bi, -1, hdr, buf, len);
@@ -645,7 +662,7 @@ static int dpp_controller_rx_auth_resp(struct dpp_connection *conn,
if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
wpa_printf(MSG_DEBUG,
"DPP: Start wait for full response");
- return -1;
+ return 0;
}
wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
dpp_connection_remove(conn);
@@ -692,7 +709,7 @@ void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
wpa_printf(MSG_DEBUG,
"DPP: Timeout while waiting for Connection Status Result");
- wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
+ wpa_msg(conn->msg_ctx, MSG_INFO,
DPP_EVENT_CONN_STATUS_RESULT "timeout");
dpp_connection_remove(conn);
}
@@ -704,7 +721,7 @@ static int dpp_controller_rx_conf_result(struct dpp_connection *conn,
{
struct dpp_authentication *auth = conn->auth;
enum dpp_status_error status;
- void *msg_ctx;
+ void *msg_ctx = conn->msg_ctx;
if (!conn->ctrl && (!auth || !auth->configurator))
return 0;
@@ -716,10 +733,6 @@ static int dpp_controller_rx_conf_result(struct dpp_connection *conn,
"DPP: No DPP Configuration waiting for result - drop");
return -1;
}
- if (conn->ctrl)
- msg_ctx = conn->ctrl->global->msg_ctx;
- else
- msg_ctx = auth->msg_ctx;
status = dpp_conf_result_rx(auth, hdr, buf, len);
if (status == DPP_STATUS_OK && auth->send_conn_status) {
@@ -765,8 +778,7 @@ static int dpp_controller_rx_conn_status_result(struct dpp_connection *conn,
status = dpp_conn_status_result_rx(auth, hdr, buf, len,
ssid, &ssid_len, &channel_list);
- wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
- DPP_EVENT_CONN_STATUS_RESULT
+ wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT
"result=%d ssid=%s channel_list=%s",
status, wpa_ssid_txt(ssid, ssid_len),
channel_list ? channel_list : "N/A");
@@ -796,7 +808,7 @@ static int dpp_controller_rx_presence_announcement(struct dpp_connection *conn,
r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
&r_bootstrap_len);
if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
- wpa_msg(dpp->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
"Missing or invalid required Responder Bootstrapping Key Hash attribute");
return -1;
}
@@ -809,7 +821,7 @@ static int dpp_controller_rx_presence_announcement(struct dpp_connection *conn,
return -1;
}
- auth = dpp_auth_init(dpp, dpp->msg_ctx, peer_bi, NULL,
+ auth = dpp_auth_init(dpp, conn->msg_ctx, peer_bi, NULL,
DPP_CAPAB_CONFIGURATOR, -1, NULL, 0);
if (!auth)
return -1;
@@ -828,11 +840,12 @@ static int dpp_controller_rx_reconfig_announcement(struct dpp_connection *conn,
const u8 *hdr, const u8 *buf,
size_t len)
{
- const u8 *csign_hash;
- u16 csign_hash_len;
+ const u8 *csign_hash, *fcgroup, *a_nonce, *e_id;
+ u16 csign_hash_len, fcgroup_len, a_nonce_len, e_id_len;
struct dpp_configurator *conf;
struct dpp_global *dpp = conn->ctrl->global;
struct dpp_authentication *auth;
+ u16 group;
if (conn->auth) {
wpa_printf(MSG_DEBUG,
@@ -845,7 +858,7 @@ static int dpp_controller_rx_reconfig_announcement(struct dpp_connection *conn,
csign_hash = dpp_get_attr(buf, len, DPP_ATTR_C_SIGN_KEY_HASH,
&csign_hash_len);
if (!csign_hash || csign_hash_len != SHA256_MAC_LEN) {
- wpa_msg(dpp->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
"Missing or invalid required Configurator C-sign key Hash attribute");
return -1;
}
@@ -858,7 +871,21 @@ static int dpp_controller_rx_reconfig_announcement(struct dpp_connection *conn,
return -1;
}
- auth = dpp_reconfig_init(dpp, dpp->msg_ctx, conf, 0);
+ fcgroup = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
+ &fcgroup_len);
+ if (!fcgroup || fcgroup_len != 2) {
+ wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Finite Cyclic Group attribute");
+ return -1;
+ }
+ group = WPA_GET_LE16(fcgroup);
+ wpa_printf(MSG_DEBUG, "DPP: Enrollee finite cyclic group: %u", group);
+
+ a_nonce = dpp_get_attr(buf, len, DPP_ATTR_A_NONCE, &a_nonce_len);
+ e_id = dpp_get_attr(buf, len, DPP_ATTR_E_PRIME_ID, &e_id_len);
+
+ auth = dpp_reconfig_init(dpp, conn->msg_ctx, conf, 0, group,
+ a_nonce, a_nonce_len, e_id, e_id_len);
if (!auth)
return -1;
if (dpp_set_configurator(auth, conn->ctrl->configurator_params) < 0) {
@@ -965,14 +992,91 @@ static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg,
}
+static int dpp_tcp_send_comeback_delay(struct dpp_connection *conn, u8 action)
+{
+ struct wpabuf *buf;
+ size_t len = 18;
+
+ if (action == WLAN_PA_GAS_COMEBACK_RESP)
+ len++;
+
+ buf = wpabuf_alloc(4 + len);
+ if (!buf)
+ return -1;
+
+ wpabuf_put_be32(buf, len);
+
+ wpabuf_put_u8(buf, action);
+ wpabuf_put_u8(buf, conn->gas_dialog_token);
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ if (action == WLAN_PA_GAS_COMEBACK_RESP)
+ wpabuf_put_u8(buf, 0);
+ wpabuf_put_le16(buf, 500); /* GAS Comeback Delay */
+
+ dpp_write_adv_proto(buf);
+ wpabuf_put_le16(buf, 0); /* Query Response Length */
+
+ /* Send Config Response over TCP */
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", buf);
+ wpabuf_free(conn->msg_out);
+ conn->msg_out_pos = 0;
+ conn->msg_out = buf;
+ dpp_tcp_send(conn);
+ return 0;
+}
+
+
+static int dpp_tcp_send_gas_resp(struct dpp_connection *conn, u8 action,
+ struct wpabuf *resp)
+{
+ struct wpabuf *buf;
+ size_t len;
+
+ if (!resp)
+ return -1;
+
+ len = 18 + wpabuf_len(resp);
+ if (action == WLAN_PA_GAS_COMEBACK_RESP)
+ len++;
+
+ buf = wpabuf_alloc(4 + len);
+ if (!buf) {
+ wpabuf_free(resp);
+ return -1;
+ }
+
+ wpabuf_put_be32(buf, len);
+
+ wpabuf_put_u8(buf, action);
+ wpabuf_put_u8(buf, conn->gas_dialog_token);
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ if (action == WLAN_PA_GAS_COMEBACK_RESP)
+ wpabuf_put_u8(buf, 0);
+ wpabuf_put_le16(buf, 0); /* GAS Comeback Delay */
+
+ dpp_write_adv_proto(buf);
+ dpp_write_gas_query(buf, resp);
+ wpabuf_free(resp);
+
+ /* Send Config Response over TCP; GAS fragmentation is taken care of by
+ * the Relay */
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", buf);
+ wpabuf_free(conn->msg_out);
+ conn->msg_out_pos = 0;
+ conn->msg_out = buf;
+ conn->on_tcp_tx_complete_gas_done = 1;
+ dpp_tcp_send(conn);
+ return 0;
+}
+
+
static int dpp_controller_rx_gas_req(struct dpp_connection *conn, const u8 *msg,
size_t len)
{
const u8 *pos, *end, *next;
- u8 dialog_token;
const u8 *adv_proto;
u16 slen;
- struct wpabuf *resp, *buf;
+ struct wpabuf *resp;
struct dpp_authentication *auth = conn->auth;
if (len < 1 + 2)
@@ -990,7 +1094,7 @@ static int dpp_controller_rx_gas_req(struct dpp_connection *conn, const u8 *msg,
pos = msg;
end = msg + len;
- dialog_token = *pos++;
+ conn->gas_dialog_token = *pos++;
adv_proto = pos++;
slen = *pos++;
if (*adv_proto != WLAN_EID_ADV_PROTO ||
@@ -1015,35 +1119,76 @@ static int dpp_controller_rx_gas_req(struct dpp_connection *conn, const u8 *msg,
return -1;
resp = dpp_conf_req_rx(auth, pos, slen);
- if (!resp)
+ if (!resp && auth->waiting_cert) {
+ wpa_printf(MSG_DEBUG, "DPP: Certificate not yet ready");
+ conn->gas_comeback_in_progress = 1;
+ return dpp_tcp_send_comeback_delay(conn,
+ WLAN_PA_GAS_INITIAL_RESP);
+ }
+
+ return dpp_tcp_send_gas_resp(conn, WLAN_PA_GAS_INITIAL_RESP, resp);
+}
+
+
+static int dpp_controller_rx_gas_comeback_req(struct dpp_connection *conn,
+ const u8 *msg, size_t len)
+{
+ u8 dialog_token;
+ struct dpp_authentication *auth = conn->auth;
+ struct wpabuf *resp;
+
+ if (len < 1)
return -1;
- buf = wpabuf_alloc(4 + 18 + wpabuf_len(resp));
- if (!buf) {
- wpabuf_free(resp);
+ wpa_printf(MSG_DEBUG,
+ "DPP: Received DPP Configuration Request over TCP (comeback)");
+
+ if (!auth || (!conn->ctrl && !auth->configurator) ||
+ (!auth->auth_success && !auth->reconfig_success) ||
+ !conn->gas_comeback_in_progress) {
+ wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
return -1;
}
- wpabuf_put_be32(buf, 18 + wpabuf_len(resp));
+ dialog_token = msg[0];
+ if (dialog_token != conn->gas_dialog_token) {
+ wpa_printf(MSG_DEBUG, "DPP: Dialog token mismatch (%u != %u)",
+ dialog_token, conn->gas_dialog_token);
+ return -1;
+ }
- wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_RESP);
- wpabuf_put_u8(buf, dialog_token);
- wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
- wpabuf_put_le16(buf, 0); /* GAS Comeback Delay */
+ if (!auth->conf_resp_tcp) {
+ wpa_printf(MSG_DEBUG, "DPP: Certificate not yet ready");
+ return dpp_tcp_send_comeback_delay(conn,
+ WLAN_PA_GAS_COMEBACK_RESP);
+ }
- dpp_write_adv_proto(buf);
- dpp_write_gas_query(buf, resp);
- wpabuf_free(resp);
+ wpa_printf(MSG_DEBUG,
+ "DPP: Configuration response is ready to be sent out");
+ resp = auth->conf_resp_tcp;
+ auth->conf_resp_tcp = NULL;
+ return dpp_tcp_send_gas_resp(conn, WLAN_PA_GAS_COMEBACK_RESP, resp);
+}
- /* Send Config Response over TCP; GAS fragmentation is taken care of by
- * the Relay */
- wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", buf);
- wpabuf_free(conn->msg_out);
- conn->msg_out_pos = 0;
- conn->msg_out = buf;
- conn->on_tcp_tx_complete_gas_done = 1;
- dpp_tcp_send(conn);
- return 0;
+
+static void dpp_tcp_build_csr(void *eloop_ctx, void *timeout_ctx)
+{
+ struct dpp_connection *conn = eloop_ctx;
+ struct dpp_authentication *auth = conn->auth;
+
+ if (!auth || !auth->csrattrs)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Build CSR");
+ wpabuf_free(auth->csr);
+ /* TODO: Additional information needed for CSR based on csrAttrs */
+ auth->csr = dpp_build_csr(auth, conn->name ? conn->name : "Test");
+ if (!auth->csr) {
+ dpp_connection_remove(conn);
+ return;
+ }
+
+ dpp_controller_start_gas_client(conn);
}
@@ -1062,14 +1207,18 @@ static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp)
else
res = -1;
wpabuf_free(resp);
+ if (res == -2) {
+ wpa_printf(MSG_DEBUG, "DPP: CSR needed");
+ eloop_register_timeout(0, 0, dpp_tcp_build_csr, conn, NULL);
+ return 0;
+ }
if (res < 0) {
wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
return -1;
}
- if (conn->global->process_conf_obj)
- res = conn->global->process_conf_obj(conn->global->cb_ctx,
- auth);
+ if (conn->process_conf_obj)
+ res = conn->process_conf_obj(conn->cb_ctx, auth);
else
res = 0;
@@ -1092,15 +1241,40 @@ static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp)
}
+static void dpp_tcp_gas_query_comeback(void *eloop_ctx, void *timeout_ctx)
+{
+ struct dpp_connection *conn = eloop_ctx;
+ struct dpp_authentication *auth = conn->auth;
+ struct wpabuf *msg;
+
+ if (!auth)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Send GAS Comeback Request");
+ msg = wpabuf_alloc(4 + 2);
+ if (!msg)
+ return;
+ wpabuf_put_be32(msg, 2);
+ wpabuf_put_u8(msg, WLAN_PA_GAS_COMEBACK_REQ);
+ wpabuf_put_u8(msg, conn->gas_dialog_token);
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg);
+
+ wpabuf_free(conn->msg_out);
+ conn->msg_out_pos = 0;
+ conn->msg_out = msg;
+ dpp_tcp_send(conn);
+}
+
+
static int dpp_rx_gas_resp(struct dpp_connection *conn, const u8 *msg,
- size_t len)
+ size_t len, bool comeback)
{
struct wpabuf *buf;
u8 dialog_token;
const u8 *pos, *end, *next, *adv_proto;
- u16 status, slen;
+ u16 status, slen, comeback_delay;
- if (len < 5 + 2)
+ if (len < 5 + 2 + (comeback ? 1 : 0))
return -1;
wpa_printf(MSG_DEBUG,
@@ -1116,7 +1290,10 @@ static int dpp_rx_gas_resp(struct dpp_connection *conn, const u8 *msg,
return -1;
}
pos += 2;
- pos += 2; /* ignore GAS Comeback Delay */
+ if (comeback)
+ pos++; /* ignore Fragment ID */
+ comeback_delay = WPA_GET_LE16(pos);
+ pos += 2;
adv_proto = pos++;
slen = *pos++;
@@ -1141,6 +1318,20 @@ static int dpp_rx_gas_resp(struct dpp_connection *conn, const u8 *msg,
if (slen > end - pos)
return -1;
+ if (comeback_delay) {
+ unsigned int secs, usecs;
+
+ conn->gas_dialog_token = dialog_token;
+ secs = (comeback_delay * 1024) / 1000000;
+ usecs = comeback_delay * 1024 - secs * 1000000;
+ wpa_printf(MSG_DEBUG, "DPP: Comeback delay: %u",
+ comeback_delay);
+ eloop_cancel_timeout(dpp_tcp_gas_query_comeback, conn, NULL);
+ eloop_register_timeout(secs, usecs, dpp_tcp_gas_query_comeback,
+ conn, NULL);
+ return 0;
+ }
+
buf = wpabuf_alloc(slen);
if (!buf)
return -1;
@@ -1264,8 +1455,15 @@ static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx)
dpp_connection_remove(conn);
break;
case WLAN_PA_GAS_INITIAL_RESP:
+ case WLAN_PA_GAS_COMEBACK_RESP:
if (dpp_rx_gas_resp(conn, pos + 1,
- wpabuf_len(conn->msg) - 1) < 0)
+ wpabuf_len(conn->msg) - 1,
+ *pos == WLAN_PA_GAS_COMEBACK_RESP) < 0)
+ dpp_connection_remove(conn);
+ break;
+ case WLAN_PA_GAS_COMEBACK_REQ:
+ if (dpp_controller_rx_gas_comeback_req(
+ conn, pos + 1, wpabuf_len(conn->msg) - 1) < 0)
dpp_connection_remove(conn);
break;
default:
@@ -1302,6 +1500,9 @@ static void dpp_controller_tcp_cb(int sd, void *eloop_ctx, void *sock_ctx)
conn->global = ctrl->global;
conn->ctrl = ctrl;
+ conn->msg_ctx = ctrl->global->msg_ctx;
+ conn->cb_ctx = ctrl->global->cb_ctx;
+ conn->process_conf_obj = ctrl->global->process_conf_obj;
conn->sock = fd;
if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
@@ -1327,7 +1528,10 @@ fail:
int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
- const struct hostapd_ip_addr *addr, int port)
+ const struct hostapd_ip_addr *addr, int port, const char *name,
+ enum dpp_netrole netrole, void *msg_ctx, void *cb_ctx,
+ int (*process_conf_obj)(void *ctx,
+ struct dpp_authentication *auth))
{
struct dpp_connection *conn;
struct sockaddr_storage saddr;
@@ -1349,6 +1553,11 @@ int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
return -1;
}
+ conn->msg_ctx = msg_ctx;
+ conn->cb_ctx = cb_ctx;
+ conn->process_conf_obj = process_conf_obj;
+ conn->name = os_strdup(name ? name : "Test");
+ conn->netrole = netrole;
conn->global = dpp;
conn->auth = auth;
conn->sock = socket(AF_INET, SOCK_STREAM, 0);
@@ -1418,7 +1627,7 @@ int dpp_controller_start(struct dpp_global *dpp,
os_strdup(config->configurator_params);
dl_list_init(&ctrl->conn);
ctrl->allowed_roles = config->allowed_roles;
- ctrl->qr_mutual = 0;
+ ctrl->qr_mutual = config->qr_mutual;
ctrl->sock = socket(AF_INET, SOCK_STREAM, 0);
if (ctrl->sock < 0)
@@ -1474,6 +1683,69 @@ void dpp_controller_stop(struct dpp_global *dpp)
}
+static bool dpp_tcp_peer_id_match(struct dpp_authentication *auth,
+ unsigned int id)
+{
+ return auth &&
+ ((auth->peer_bi && auth->peer_bi->id == id) ||
+ (auth->tmp_peer_bi && auth->tmp_peer_bi->id == id));
+}
+
+
+static struct dpp_authentication * dpp_tcp_get_auth(struct dpp_global *dpp,
+ unsigned int id)
+{
+ struct dpp_connection *conn;
+
+ dl_list_for_each(conn, &dpp->tcp_init, struct dpp_connection, list) {
+ if (dpp_tcp_peer_id_match(conn->auth, id))
+ return conn->auth;
+ }
+
+ return NULL;
+}
+
+
+struct dpp_authentication * dpp_controller_get_auth(struct dpp_global *dpp,
+ unsigned int id)
+{
+ struct dpp_controller *ctrl = dpp->controller;
+ struct dpp_connection *conn;
+
+ if (!ctrl)
+ return dpp_tcp_get_auth(dpp, id);
+
+ dl_list_for_each(conn, &ctrl->conn, struct dpp_connection, list) {
+ if (dpp_tcp_peer_id_match(conn->auth, id))
+ return conn->auth;
+ }
+
+ return dpp_tcp_get_auth(dpp, id);
+}
+
+
+void dpp_controller_new_qr_code(struct dpp_global *dpp,
+ struct dpp_bootstrap_info *bi)
+{
+ struct dpp_controller *ctrl = dpp->controller;
+ struct dpp_connection *conn;
+
+ if (!ctrl)
+ return;
+
+ dl_list_for_each(conn, &ctrl->conn, struct dpp_connection, list) {
+ struct dpp_authentication *auth = conn->auth;
+
+ if (!auth->response_pending ||
+ dpp_notify_new_qr_code(auth, bi) != 1)
+ continue;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Sending out pending authentication response");
+ dpp_tcp_send_msg(conn, conn->auth->resp_msg);
+ }
+}
+
+
void dpp_tcp_init_flush(struct dpp_global *dpp)
{
struct dpp_connection *conn, *tmp;
diff --git a/src/common/gas_server.c b/src/common/gas_server.c
index ca46758..5a1ea78 100644
--- a/src/common/gas_server.c
+++ b/src/common/gas_server.c
@@ -1,6 +1,7 @@
/*
* Generic advertisement service (GAS) server
* Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -23,8 +24,9 @@ struct gas_server_handler {
struct dl_list list;
u8 adv_proto_id[MAX_ADV_PROTO_ID_LEN];
u8 adv_proto_id_len;
- struct wpabuf * (*req_cb)(void *ctx, const u8 *sa,
- const u8 *query, size_t query_len);
+ struct wpabuf * (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
+ const u8 *query, size_t query_len,
+ u16 *comeback_delay);
void (*status_cb)(void *ctx, struct wpabuf *resp, int ok);
void *ctx;
struct gas_server *gas;
@@ -39,6 +41,7 @@ struct gas_server_response {
u8 dst[ETH_ALEN];
u8 dialog_token;
struct gas_server_handler *handler;
+ u16 comeback_delay;
};
struct gas_server {
@@ -61,7 +64,8 @@ static void gas_server_response_timeout(void *eloop_ctx, void *user_ctx)
response, MAC2STR(response->dst), response->dialog_token,
response->freq, response->frag_id,
(unsigned long) response->offset,
- (unsigned long) wpabuf_len(response->resp));
+ (unsigned long) (response->resp ?
+ wpabuf_len(response->resp) : 0));
response->handler->status_cb(response->handler->ctx,
response->resp, 0);
response->resp = NULL;
@@ -83,30 +87,27 @@ static void gas_server_free_response(struct gas_server_response *response)
static void
gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler,
+ struct gas_server_response *response,
const u8 *da, int freq, u8 dialog_token,
- struct wpabuf *query_resp)
+ struct wpabuf *query_resp, u16 comeback_delay)
{
size_t max_len = (freq > 56160) ? 928 : 1400;
size_t hdr_len = 24 + 2 + 5 + 3 + handler->adv_proto_id_len + 2;
size_t resp_frag_len;
struct wpabuf *resp;
- u16 comeback_delay;
- struct gas_server_response *response;
- if (!query_resp)
+ if (comeback_delay == 0 && !query_resp)
return;
- response = os_zalloc(sizeof(*response));
- if (!response) {
- wpabuf_free(query_resp);
- return;
- }
- wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response);
response->freq = freq;
response->handler = handler;
os_memcpy(response->dst, da, ETH_ALEN);
response->dialog_token = dialog_token;
- if (hdr_len + wpabuf_len(query_resp) > max_len) {
+ if (comeback_delay) {
+ /* Need more time to prepare the response */
+ resp_frag_len = 0;
+ response->comeback_delay = comeback_delay;
+ } else if (hdr_len + wpabuf_len(query_resp) > max_len) {
/* Need to use comeback to initiate fragmentation */
comeback_delay = 1;
resp_frag_len = 0;
@@ -135,10 +136,12 @@ gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler,
/* Query Response Length */
wpabuf_put_le16(resp, resp_frag_len);
- if (!comeback_delay)
+ if (!comeback_delay && query_resp)
wpabuf_put_buf(resp, query_resp);
- if (comeback_delay) {
+ if (comeback_delay && !query_resp) {
+ wpa_printf(MSG_DEBUG, "GAS: No response available yet");
+ } else if (comeback_delay) {
wpa_printf(MSG_DEBUG,
"GAS: Need to fragment query response");
} else {
@@ -165,6 +168,7 @@ gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
u16 query_req_len;
struct gas_server_handler *handler;
struct wpabuf *resp;
+ struct gas_server_response *response;
wpa_hexdump(MSG_MSGDUMP, "GAS: Received GAS Initial Request frame",
data, len);
@@ -210,8 +214,15 @@ gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
pos, end - pos);
}
+ response = os_zalloc(sizeof(*response));
+ if (!response)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response);
dl_list_for_each(handler, &gas->handlers, struct gas_server_handler,
list) {
+ u16 comeback_delay = 0;
+
if (adv_proto_len < 1 + handler->adv_proto_id_len ||
os_memcmp(adv_proto + 1, handler->adv_proto_id,
handler->adv_proto_id_len) != 0)
@@ -219,17 +230,22 @@ gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
wpa_printf(MSG_DEBUG,
"GAS: Calling handler for the requested Advertisement Protocol ID");
- resp = handler->req_cb(handler->ctx, sa, query_req,
- query_req_len);
+ resp = handler->req_cb(handler->ctx, response, sa, query_req,
+ query_req_len, &comeback_delay);
wpa_hexdump_buf(MSG_MSGDUMP, "GAS: Response from the handler",
resp);
- gas_server_send_resp(gas, handler, sa, freq, dialog_token,
- resp);
+ if (comeback_delay)
+ wpa_printf(MSG_DEBUG,
+ "GAS: Handler requested comeback delay: %u TU",
+ comeback_delay);
+ gas_server_send_resp(gas, handler, response, sa, freq,
+ dialog_token, resp, comeback_delay);
return 0;
}
wpa_printf(MSG_DEBUG,
"GAS: No registered handler for the requested Advertisement Protocol ID");
+ gas_server_free_response(response);
return -1;
}
@@ -243,6 +259,31 @@ gas_server_handle_rx_comeback_req(struct gas_server_response *response)
size_t hdr_len = 24 + 2 + 6 + 3 + handler->adv_proto_id_len + 2;
size_t remaining, resp_frag_len;
struct wpabuf *resp;
+ unsigned int wait_time = 0;
+
+ if (!response->resp) {
+ resp = gas_build_comeback_resp(response->dialog_token,
+ WLAN_STATUS_SUCCESS, 0, 0,
+ response->comeback_delay,
+ handler->adv_proto_id_len);
+ if (!resp) {
+ dl_list_del(&response->list);
+ gas_server_free_response(response);
+ return;
+ }
+
+ /* Advertisement Protocol element */
+ wpabuf_put_u8(resp, WLAN_EID_ADV_PROTO);
+ wpabuf_put_u8(resp, 1 + handler->adv_proto_id_len); /* Length */
+ wpabuf_put_u8(resp, 0x7f);
+ /* Advertisement Protocol ID */
+ wpabuf_put_data(resp, handler->adv_proto_id,
+ handler->adv_proto_id_len);
+
+ /* Query Response Length */
+ wpabuf_put_le16(resp, 0);
+ goto send_resp;
+ }
remaining = wpabuf_len(response->resp) - response->offset;
if (hdr_len + remaining > max_len)
@@ -279,8 +320,11 @@ gas_server_handle_rx_comeback_req(struct gas_server_response *response)
response->offset += resp_frag_len;
- gas->tx(gas->ctx, response->freq, response->dst, resp,
- remaining > resp_frag_len ? 2000 : 0);
+ if (remaining > resp_frag_len)
+ wait_time = 2000;
+
+send_resp:
+ gas->tx(gas->ctx, response->freq, response->dst, resp, wait_time);
wpabuf_free(resp);
}
@@ -359,12 +403,19 @@ int gas_server_rx(struct gas_server *gas, const u8 *da, const u8 *sa,
static void gas_server_handle_tx_status(struct gas_server_response *response,
int ack)
{
- if (ack && response->offset < wpabuf_len(response->resp)) {
+ if (ack && response->resp &&
+ response->offset < wpabuf_len(response->resp)) {
wpa_printf(MSG_DEBUG,
"GAS: More fragments remaining - keep pending entry");
return;
}
+ if (ack && !response->resp && response->comeback_delay) {
+ wpa_printf(MSG_DEBUG,
+ "GAS: Waiting for response - keep pending entry");
+ return;
+ }
+
if (!ack)
wpa_printf(MSG_DEBUG,
"GAS: No ACK received - drop pending entry");
@@ -415,6 +466,27 @@ void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data,
}
+int gas_server_set_resp(struct gas_server *gas, void *resp_ctx,
+ struct wpabuf *resp)
+{
+ struct gas_server_response *tmp, *response = NULL;
+
+ dl_list_for_each(tmp, &gas->responses, struct gas_server_response,
+ list) {
+ if (tmp == resp_ctx) {
+ response = tmp;
+ break;
+ }
+ }
+
+ if (!response || response->resp)
+ return -1;
+
+ response->resp = resp;
+ return 0;
+}
+
+
struct gas_server * gas_server_init(void *ctx,
void (*tx)(void *ctx, int freq,
const u8 *da,
@@ -461,8 +533,9 @@ void gas_server_deinit(struct gas_server *gas)
int gas_server_register(struct gas_server *gas,
const u8 *adv_proto_id, u8 adv_proto_id_len,
struct wpabuf *
- (*req_cb)(void *ctx, const u8 *sa,
- const u8 *query, size_t query_len),
+ (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
+ const u8 *query, size_t query_len,
+ u16 *comeback_delay),
void (*status_cb)(void *ctx, struct wpabuf *resp,
int ok),
void *ctx)
diff --git a/src/common/gas_server.h b/src/common/gas_server.h
index 299f529..2611dde 100644
--- a/src/common/gas_server.h
+++ b/src/common/gas_server.h
@@ -1,6 +1,7 @@
/*
* Generic advertisement service (GAS) server
* Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -22,8 +23,9 @@ void gas_server_deinit(struct gas_server *gas);
int gas_server_register(struct gas_server *gas,
const u8 *adv_proto_id, u8 adv_proto_id_len,
struct wpabuf *
- (*req_cb)(void *ctx, const u8 *sa,
- const u8 *query, size_t query_len),
+ (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
+ const u8 *query, size_t query_len,
+ u16 *comeback_delay),
void (*status_cb)(void *ctx, struct wpabuf *resp,
int ok),
void *ctx);
@@ -32,6 +34,8 @@ int gas_server_rx(struct gas_server *gas, const u8 *da, const u8 *sa,
int freq);
void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data,
size_t data_len, int ack);
+int gas_server_set_resp(struct gas_server *gas, void *resp_ctx,
+ struct wpabuf *resp);
#else /* CONFIG_GAS_SERVER */
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index f6c67a3..1d9387f 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -415,7 +415,7 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
return -1;
}
- if (center_idx_to_bw_6ghz(channel) != 0) {
+ if (center_idx_to_bw_6ghz(channel) < 0) {
wpa_printf(MSG_ERROR,
"Invalid control channel for 6 GHz band");
return -1;
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 981652e..c0c569b 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -136,6 +136,10 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
case DPP_CC_OUI_TYPE:
/* DPP Configurator Connectivity element */
break;
+ case SAE_PK_OUI_TYPE:
+ elems->sae_pk = pos + 4;
+ elems->sae_pk_len = elen - 4;
+ break;
default:
wpa_printf(MSG_MSGDUMP, "Unknown WFA "
"information element ignored "
@@ -763,6 +767,98 @@ int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
}
+/* convert floats with one decimal place to value*10 int, i.e.,
+ * "1.5" will return 15
+ */
+static int hostapd_config_read_int10(const char *value)
+{
+ int i, d;
+ char *pos;
+
+ i = atoi(value);
+ pos = os_strchr(value, '.');
+ d = 0;
+ if (pos) {
+ pos++;
+ if (*pos >= '0' && *pos <= '9')
+ d = *pos - '0';
+ }
+
+ return i * 10 + d;
+}
+
+
+static int valid_cw(int cw)
+{
+ return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
+ cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023 ||
+ cw == 2047 || cw == 4095 || cw == 8191 || cw == 16383 ||
+ cw == 32767);
+}
+
+
+int hostapd_config_tx_queue(struct hostapd_tx_queue_params tx_queue[],
+ const char *name, const char *val)
+{
+ int num;
+ const char *pos;
+ struct hostapd_tx_queue_params *queue;
+
+ /* skip 'tx_queue_' prefix */
+ pos = name + 9;
+ if (os_strncmp(pos, "data", 4) == 0 &&
+ pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
+ num = pos[4] - '0';
+ pos += 6;
+ } else if (os_strncmp(pos, "after_beacon_", 13) == 0 ||
+ os_strncmp(pos, "beacon_", 7) == 0) {
+ wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
+ return 0;
+ } else {
+ wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
+ return -1;
+ }
+
+ if (num >= NUM_TX_QUEUES) {
+ /* for backwards compatibility, do not trigger failure */
+ wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
+ return 0;
+ }
+
+ queue = &tx_queue[num];
+
+ if (os_strcmp(pos, "aifs") == 0) {
+ queue->aifs = atoi(val);
+ if (queue->aifs < 0 || queue->aifs > 255) {
+ wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
+ queue->aifs);
+ return -1;
+ }
+ } else if (os_strcmp(pos, "cwmin") == 0) {
+ queue->cwmin = atoi(val);
+ if (!valid_cw(queue->cwmin)) {
+ wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
+ queue->cwmin);
+ return -1;
+ }
+ } else if (os_strcmp(pos, "cwmax") == 0) {
+ queue->cwmax = atoi(val);
+ if (!valid_cw(queue->cwmax)) {
+ wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
+ queue->cwmax);
+ return -1;
+ }
+ } else if (os_strcmp(pos, "burst") == 0) {
+ queue->burst = hostapd_config_read_int10(val);
+ } else {
+ wpa_printf(MSG_ERROR, "Unknown queue field '%s'", pos);
+ return -1;
+ }
+
+ return 0;
+}
+
+
enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
{
u8 op_class;
@@ -933,9 +1029,9 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
return HOSTAPD_MODE_IEEE80211A;
}
- if (freq > 5940 && freq <= 7105) {
+ if (freq > 5950 && freq <= 7115) {
int bw;
- u8 idx = (freq - 5940) / 5;
+ u8 idx = (freq - 5950) / 5;
bw = center_idx_to_bw_6ghz(idx);
if (bw < 0)
@@ -946,6 +1042,12 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
return HOSTAPD_MODE_IEEE80211A;
}
+ if (freq == 5935) {
+ *op_class = 136;
+ *channel = (freq - 5925) / 5;
+ return HOSTAPD_MODE_IEEE80211A;
+ }
+
/* 56.16 GHz, channel 1..6 */
if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 6) {
if (sec_channel)
@@ -1322,7 +1424,11 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
if (chan < 1 || chan > 233)
return -1;
- return 5940 + chan * 5;
+ return 5950 + chan * 5;
+ case 136: /* UHB channels, 20 MHz: 2 */
+ if (chan == 2)
+ return 5935;
+ return -1;
case 180: /* 60 GHz band, channels 1..8 */
if (chan < 1 || chan > 8)
return -1;
@@ -1666,6 +1772,7 @@ const char * status2str(u16 status)
S2S(FILS_AUTHENTICATION_FAILURE)
S2S(UNKNOWN_AUTHENTICATION_SERVER)
S2S(UNKNOWN_PASSWORD_IDENTIFIER)
+ S2S(DENIED_HE_NOT_SUPPORTED)
S2S(SAE_HASH_TO_ELEMENT)
S2S(SAE_PK)
}
@@ -2111,10 +2218,13 @@ int center_idx_to_bw_6ghz(u8 idx)
int is_6ghz_freq(int freq)
{
- if (freq < 5940 || freq > 7105)
+ if (freq < 5935 || freq > 7115)
return 0;
- if (center_idx_to_bw_6ghz((freq - 5940) / 5) < 0)
+ if (freq == 5935)
+ return 1;
+
+ if (center_idx_to_bw_6ghz((freq - 5950) / 5) < 0)
return 0;
return 1;
@@ -2123,7 +2233,7 @@ int is_6ghz_freq(int freq)
int is_6ghz_op_class(u8 op_class)
{
- return op_class >= 131 && op_class <= 135;
+ return op_class >= 131 && op_class <= 136;
}
@@ -2131,14 +2241,14 @@ int is_6ghz_psc_frequency(int freq)
{
int i;
- if (!is_6ghz_freq(freq))
+ if (!is_6ghz_freq(freq) || freq == 5935)
return 0;
- if ((((freq - 5940) / 5) & 0x3) != 0x1)
+ if ((((freq - 5950) / 5) & 0x3) != 0x1)
return 0;
- i = (freq - 5940 + 55) % 80;
+ i = (freq - 5950 + 55) % 80;
if (i == 0)
- i = (freq - 5940 + 55) / 80;
+ i = (freq - 5950 + 55) / 80;
if (i >= 1 && i <= 15)
return 1;
@@ -2374,6 +2484,8 @@ int op_class_to_bandwidth(u8 op_class)
case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
return 160;
+ case 136: /* UHB channels, 20 MHz: 2 */
+ return 20;
case 180: /* 60 GHz band, channels 1..8 */
return 2160;
case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
@@ -2434,6 +2546,8 @@ int op_class_to_ch_width(u8 op_class)
return CHANWIDTH_160MHZ;
case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
return CHANWIDTH_80P80MHZ;
+ case 136: /* UHB channels, 20 MHz: 2 */
+ return CHANWIDTH_USE_HT;
case 180: /* 60 GHz band, channels 1..8 */
return CHANWIDTH_2160MHZ;
case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index cf48650..0ddba06 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -114,6 +114,7 @@ struct ieee802_11_elems {
const u8 *he_operation;
const u8 *short_ssid_list;
const u8 *he_6ghz_band_cap;
+ const u8 *sae_pk;
u8 ssid_len;
u8 supp_rates_len;
@@ -166,6 +167,7 @@ struct ieee802_11_elems {
u8 he_capabilities_len;
u8 he_operation_len;
u8 short_ssid_list_len;
+ u8 sae_pk_len;
struct mb_ies_info mb_ies;
struct frag_ies_info frag_ies;
@@ -192,6 +194,18 @@ struct hostapd_wmm_ac_params {
int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
const char *name, const char *val);
+
+struct hostapd_tx_queue_params {
+ int aifs;
+ int cwmin;
+ int cwmax;
+ int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
+};
+
+#define NUM_TX_QUEUES 4
+
+int hostapd_config_tx_queue(struct hostapd_tx_queue_params queue[],
+ const char *name, const char *val);
enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan);
enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 3fc4200..86d71c1 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -204,6 +204,7 @@
#define WLAN_STATUS_FILS_AUTHENTICATION_FAILURE 112
#define WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER 113
#define WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER 123
+#define WLAN_STATUS_DENIED_HE_NOT_SUPPORTED 124
#define WLAN_STATUS_SAE_HASH_TO_ELEMENT 126
#define WLAN_STATUS_SAE_PK 127
@@ -477,6 +478,8 @@
#define WLAN_EID_EXT_HE_6GHZ_BAND_CAP 59
#define WLAN_EID_EXT_EDMG_CAPABILITIES 61
#define WLAN_EID_EXT_EDMG_OPERATION 62
+#define WLAN_EID_EXT_MSCS_DESCRIPTOR 88
+#define WLAN_EID_EXT_TCLAS_MASK 89
#define WLAN_EID_EXT_REJECTED_GROUPS 92
#define WLAN_EID_EXT_ANTI_CLOGGING_TOKEN 93
@@ -561,6 +564,7 @@
#define WLAN_EXT_CAPAB_SAE_PW_ID 81
#define WLAN_EXT_CAPAB_SAE_PW_ID_EXCLUSIVELY 82
#define WLAN_EXT_CAPAB_BEACON_PROTECTION 84
+#define WLAN_EXT_CAPAB_MSCS 85
#define WLAN_EXT_CAPAB_SAE_PK_EXCLUSIVELY 88
/* Extended RSN Capabilities */
@@ -1323,6 +1327,7 @@ struct ieee80211_ampe_ie {
#define DPP_CC_IE_VENDOR_TYPE 0x506f9a1e
#define DPP_CC_OUI_TYPE 0x1e
#define SAE_PK_IE_VENDOR_TYPE 0x506f9a1f
+#define SAE_PK_OUI_TYPE 0x1f
#define MULTI_AP_SUB_ELEM_TYPE 0x06
#define MULTI_AP_TEAR_DOWN BIT(4)
@@ -2172,23 +2177,30 @@ struct ieee80211_he_6ghz_band_cap {
/* Minimum MPDU Start Spacing B0..B2
* Maximum A-MPDU Length Exponent B3..B5
* Maximum MPDU Length B6..B7 */
- u8 a_mpdu_params; /* B0..B7 */
- u8 info; /* B8..B15 */
+ le16 capab;
} STRUCT_PACKED;
-#define HE_6GHZ_BAND_CAP_MIN_MPDU_START_SPACE_MASK 0x7
-#define HE_6GHZ_BAND_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK 0x7
-#define HE_6GHZ_BAND_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT 3
-#define HE_6GHZ_BAND_CAP_MAX_MPDU_LENGTH_MASK 0x3
-#define HE_6GHZ_BAND_CAP_MAX_MPDU_LENGTH_SHIFT 6
-
-#define HE_6GHZ_BAND_CAP_SMPS_MASK (BIT(1) | BIT(2))
-#define HE_6GHZ_BAND_CAP_SMPS_STATIC 0
-#define HE_6GHZ_BAND_CAP_SMPS_DYNAMIC BIT(1)
-#define HE_6GHZ_BAND_CAP_SMPS_DISABLED (BIT(1) | BIT(2))
-#define HE_6GHZ_BAND_CAP_RD_RESPONDER BIT(3)
-#define HE_6GHZ_BAND_CAP_RX_ANTENNA_PATTERN BIT(4)
-#define HE_6GHZ_BAND_CAP_TX_ANTENNA_PATTERN BIT(5)
+#define HE_6GHZ_BAND_CAP_MIN_MPDU_START (BIT(0) | BIT(1) | BIT(2))
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_16K BIT(3)
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_32K BIT(4)
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_64K (BIT(3) | BIT(4))
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_128K BIT(5)
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_256K (BIT(3) | BIT(5))
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_512K (BIT(4) | BIT(5))
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_1024K (BIT(3) | BIT(4) | BIT(5))
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_MASK (BIT(3) | BIT(4) | BIT(5))
+#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_SHIFT 3
+#define HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_7991 BIT(6)
+#define HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_11454 BIT(7)
+#define HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_MASK (BIT(6) | BIT(7))
+#define HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_SHIFT 6
+#define HE_6GHZ_BAND_CAP_SMPS_MASK (BIT(9) | BIT(10))
+#define HE_6GHZ_BAND_CAP_SMPS_STATIC 0
+#define HE_6GHZ_BAND_CAP_SMPS_DYNAMIC BIT(9)
+#define HE_6GHZ_BAND_CAP_SMPS_DISABLED (BIT(9) | BIT(10))
+#define HE_6GHZ_BAND_CAP_RD_RESPONDER BIT(11)
+#define HE_6GHZ_BAND_CAP_RX_ANTPAT_CONS BIT(12)
+#define HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS BIT(13)
/*
* IEEE P802.11ax/D4.0, 9.4.2.246 Spatial Reuse Parameter Set element
@@ -2331,4 +2343,25 @@ enum edmg_bw_config {
/* DPP Public Action frame identifiers - OUI_WFA */
#define DPP_OUI_TYPE 0x1A
+/* Robust AV streaming Action field values */
+enum robust_av_streaming_action {
+ ROBUST_AV_SCS_REQ = 0,
+ ROBUST_AV_SCS_RESP = 1,
+ ROBUST_AV_GROUP_MEMBERSHIP_REQ = 2,
+ ROBUST_AV_GROUP_MEMBERSHIP_RESP = 3,
+ ROBUST_AV_MSCS_REQ = 4,
+ ROBUST_AV_MSCS_RESP = 5,
+};
+
+enum scs_request_type {
+ SCS_REQ_ADD = 0,
+ SCS_REQ_REMOVE = 1,
+ SCS_REQ_CHANGE = 2,
+};
+
+/* Optional subelement IDs for MSCS Descriptor element */
+enum mscs_description_subelem {
+ MCSC_SUBELEM_STATUS = 1,
+};
+
#endif /* IEEE802_11_DEFS_H */
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index ea68bec..b7dc1c7 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -1,7 +1,7 @@
/*
* Qualcomm Atheros OUI and vendor specific assignments
* Copyright (c) 2014-2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -174,6 +174,22 @@ enum qca_radiotap_vendor_ids {
* to notify the connected station's status. The attributes for this
* command are defined in enum qca_wlan_vendor_attr_link_properties.
*
+ * @QCA_NL80211_VENDOR_SUBCMD_SETBAND: Command to configure the enabled band(s)
+ * to the driver. This command sets the band(s) through either the
+ * attribute QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE or
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_MASK (or both).
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE refers enum qca_set_band as unsigned
+ * integer values and QCA_WLAN_VENDOR_ATTR_SETBAND_MASK refers it as 32
+ * bit unsigned bitmask values. The allowed values for
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE are limited to QCA_SETBAND_AUTO,
+ * QCA_SETBAND_5G, and QCA_SETBAND_2G. Other values/bitmasks are valid for
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_MASK. The attribute
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE is deprecated and the recommendation
+ * is to use the QCA_WLAN_VENDOR_ATTR_SETBAND_MASK. If the both attributes
+ * are included for backwards compatibility, the configurations through
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_MASK will take the precedence with drivers
+ * that support both attributes.
+ *
* @QCA_NL80211_VENDOR_SUBCMD_ACS_POLICY: This command is used to configure
* DFS policy and channel hint for ACS operation. This command uses the
* attributes defined in enum qca_wlan_vendor_attr_acs_config and
@@ -652,6 +668,21 @@ enum qca_radiotap_vendor_ids {
* This command can only be used in STA mode and the STA must be
* associated with an AP when the command is issued. Uses attributes
* defined in enum qca_wlan_vendor_attr_config_tspec.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT: Vendor subcommand to configure TWT.
+ * Uses attributes defined in enum qca_wlan_vendor_attr_config_twt.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GETBAND: Command to get the enabled band(s) from
+ * the driver. The band configurations obtained are referred through
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_MASK.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS: Vendor subcommand/event for medium
+ * assessment.
+ * Uses attributes defined in enum qca_wlan_vendor_attr_medium_assess.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_UPDATE_SSID: This acts as a vendor event and is
+ * used to update SSID information in hostapd when it is updated in the
+ * driver. Uses the attribute NL80211_ATTR_SSID.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -832,6 +863,10 @@ enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO = 188,
QCA_NL80211_VENDOR_SUBCMD_DRIVER_DISCONNECT_REASON = 189,
QCA_NL80211_VENDOR_SUBCMD_CONFIG_TSPEC = 190,
+ QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT = 191,
+ QCA_NL80211_VENDOR_SUBCMD_GETBAND = 192,
+ QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS = 193,
+ QCA_NL80211_VENDOR_SUBCMD_UPDATE_SSID = 194,
};
enum qca_wlan_vendor_attr {
@@ -862,7 +897,11 @@ enum qca_wlan_vendor_attr {
QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_2_4_BAND = 10,
/* Unsigned 32-bit value */
QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND = 11,
- /* Unsigned 32-bit value from enum qca_set_band. */
+ /* Unsigned 32-bit value from enum qca_set_band. The allowed values for
+ * this attribute are limited to QCA_SETBAND_AUTO, QCA_SETBAND_5G, and
+ * QCA_SETBAND_2G. This attribute is deprecated. Recommendation is to
+ * use QCA_WLAN_VENDOR_ATTR_SETBAND_MASK instead.
+ */
QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE = 12,
/* Dummy (NOP) attribute for 64 bit padding */
QCA_WLAN_VENDOR_ATTR_PAD = 13,
@@ -1025,6 +1064,15 @@ enum qca_wlan_vendor_attr {
*/
QCA_WLAN_VENDOR_ATTR_FW_STATE = 42,
+ /* Unsigned 32-bitmask value from enum qca_set_band. Substitutes the
+ * attribute QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE for which only a subset
+ * of single values from enum qca_set_band are valid. This attribute
+ * uses bitmask combinations to define the respective allowed band
+ * combinations and this attributes takes precedence over
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE if both attributes are included.
+ */
+ QCA_WLAN_VENDOR_ATTR_SETBAND_MASK = 43,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
@@ -1572,9 +1620,10 @@ enum qca_iface_type {
};
enum qca_set_band {
- QCA_SETBAND_AUTO,
- QCA_SETBAND_5G,
- QCA_SETBAND_2G,
+ QCA_SETBAND_AUTO = 0,
+ QCA_SETBAND_5G = BIT(0),
+ QCA_SETBAND_2G = BIT(1),
+ QCA_SETBAND_6G = BIT(2),
};
/**
@@ -1702,6 +1751,8 @@ enum qca_vendor_attr_wisa_cmd {
* (not including the Element ID Extension field). Please note that the
* draft is still work in progress and this element payload is subject to
* change.
+ *
+ * @QCA_VENDOR_ELEM_ALLPLAY: Allplay element
*/
enum qca_vendor_element_id {
QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST = 0,
@@ -1710,6 +1761,7 @@ enum qca_vendor_element_id {
QCA_VENDOR_ELEM_RAPS = 3,
QCA_VENDOR_ELEM_MU_EDCA_PARAMS = 4,
QCA_VENDOR_ELEM_BSS_COLOR_CHANGE = 5,
+ QCA_VENDOR_ELEM_ALLPLAY = 6,
};
/**
@@ -2135,6 +2187,28 @@ enum qca_wlan_vendor_attr_config {
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_PHY_MODE = 62,
+ /* 8-bit unsigned value to configure the maximum supported channel width
+ * for STA mode. If this value is configured when STA is in connected
+ * state, it should not exceed the negotiated channel width. If it is
+ * configured when STA is in disconnected state, the configured value
+ * will take effect for the next immediate connection.
+ * Possible values are:
+ * NL80211_CHAN_WIDTH_20
+ * NL80211_CHAN_WIDTH_40
+ * NL80211_CHAN_WIDTH_80
+ * NL80211_CHAN_WIDTH_80P80
+ * NL80211_CHAN_WIDTH_160
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_WIDTH = 63,
+
+ /* 8-bit unsigned value to enable/disable dynamic bandwidth adjustment.
+ * This attribute is only applicable for STA mode. When dynamic
+ * bandwidth adjustment is disabled, STA will use static channel width
+ * the value of which is negotiated during connection.
+ * 1-enable (default), 0-disable
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_DYNAMIC_BW = 64,
+
/* 8-bit unsigned value to configure the maximum number of subframes of
* TX MSDU for aggregation. Possible values are 0-31. When set to 0,
* it is decided by the hardware.
@@ -2183,6 +2257,52 @@ enum qca_wlan_vendor_attr_config {
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_RX_STBC = 69,
+ /* 8-bit unsigned value. This attribute is used to dynamically configure
+ * the number of spatial streams. When configured in the disconnected
+ * state, the updated configuration will be considered for the
+ * immediately following connection attempt. If the NSS is updated after
+ * the connection, the updated NSS value is notified to the peer using
+ * the Operating Mode Notification/Spatial Multiplexing Power Save
+ * frame. The updated NSS value after the connection shall not be
+ * greater than the one negotiated during the connection. Any such
+ * higher value configuration shall be returned with a failure.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_NSS = 70,
+ /* 8-bit unsigned value to trigger Optimized Power Management:
+ * 1-Enable, 0-Disable
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT = 71,
+
+ /* 8-bit unsigned value. This attribute takes the QoS/access category
+ * value represented by the enum qca_wlan_ac_type and expects the driver
+ * to upgrade the UDP frames to this access category. The value of
+ * QCA_WLAN_AC_ALL is invalid for this attribute. This will override the
+ * DSCP value configured in the frame with the intention to only upgrade
+ * the access category. That said, it is not intended to downgrade the
+ * access category for the frames.
+ * Set the value to QCA_WLAN_AC_BK if the QoS upgrade needs to be
+ * disabled, as BK is of the lowest priority and an upgrade to it does
+ * not result in any changes for the frames.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_UDP_QOS_UPGRADE = 72,
+
+ /* 8-bit unsigned value. This attribute is used to dynamically configure
+ * the number of chains to be used for transmitting data. This
+ * configuration is allowed only when in connected state and will be
+ * effective until disconnected. The driver rejects this configuration
+ * if the number of spatial streams being used in the current connection
+ * cannot be supported by this configuration.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_TX_CHAINS = 73,
+ /* 8-bit unsigned value. This attribute is used to dynamically configure
+ * the number of chains to be used for receiving data. This
+ * configuration is allowed only when in connected state and will be
+ * effective until disconnected. The driver rejects this configuration
+ * if the number of spatial streams being used in the current connection
+ * cannot be supported by this configuration.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_RX_CHAINS = 74,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
@@ -3360,7 +3480,7 @@ enum qca_wlan_vendor_attr_ll_stats_results {
QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS = 66,
/* Signifies the nested list of channel attributes
- * QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_*
+ * QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_*
*/
QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO = 67,
@@ -3422,6 +3542,17 @@ enum qca_wlan_vendor_attr_ll_stats_results {
*/
QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_PENDING_MSDU = 83,
+ /* u32 value representing total time in milliseconds for which the radio
+ * is transmitting on this channel. This attribute will be nested
+ * within QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_TX_TIME = 84,
+ /* u32 value representing total time in milliseconds for which the radio
+ * is receiving all 802.11 frames intended for this device on this
+ * channel. This attribute will be nested within
+ * QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_RX_TIME = 85,
/* keep last */
QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX =
@@ -3989,7 +4120,7 @@ enum qca_vendor_attr_roam_control {
* Represents the Request ID for the specific set of commands.
* This also helps to map specific set of commands to the respective
* ID / client. e.g., helps to identify the user entity configuring the
- * Blacklist BSSID and accordingly clear the respective ones with the
+ * ignored BSSIDs and accordingly clear the respective ones with the
* matching ID.
*
* @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS: Unsigned
@@ -4056,17 +4187,18 @@ enum qca_vendor_attr_roam_control {
* the BSSID for the purpose of comparing it with other roam candidate.
*
* @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS: Nested attribute,
- * represents the BSSIDs to get blacklisted for roaming.
+ * represents the BSSIDs to get ignored for roaming.
*
* @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID: Unsigned
- * 32-bit value, represents the number of blacklisted BSSIDs.
+ * 32-bit value, represents the number of ignored BSSIDs.
*
* @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID: 6-byte MAC
- * address representing the Blacklisted BSSID.
+ * address representing the ignored BSSID.
*
* @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_HINT: Flag attribute,
- * indicates this BSSID blacklist as a hint to the driver. The driver can
- * select this BSSID in the worst case (when no other BSSIDs are better).
+ * indicates this request to ignore the BSSID as a hint to the driver. The
+ * driver can select this BSSID in the worst case (when no other BSSIDs are
+ * better).
*
* @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL: Nested attribute to
* set/get/clear the roam control config as
@@ -4101,11 +4233,11 @@ enum qca_wlan_vendor_attr_roaming_config_params {
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID = 16,
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER = 17,
- /* Attribute for set_blacklist bssid params */
+ /* Attribute for setting ignored BSSID parameters */
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS = 18,
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID = 19,
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID = 20,
- /* Flag attribute indicates this BSSID blacklist as a hint */
+ /* Flag attribute indicates this entry as a hint */
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_HINT = 21,
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL = 22,
@@ -4141,9 +4273,9 @@ enum qca_wlan_vendor_attr_roaming_config_params {
* QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS to set the BSSID
* preference.
*
- * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID: Sets the Blacklist
- * BSSIDs. Refers QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS to
- * set the same.
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID: Sets the list of BSSIDs
+ * to ignore in roaming decision. Uses
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS to set the list.
*
* @QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET: Command to set the
* roam control config to the driver with the attribute
@@ -4805,9 +4937,9 @@ enum qca_wlan_vendor_channel_prop_flags_ext {
QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_DISALLOW_ADHOC = 1 << 6,
/* Station only channel */
QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_DISALLOW_HOSTAP = 1 << 7,
- /* DFS radar history for slave device (STA mode) */
+ /* DFS radar history for client device (STA mode) */
QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_HISTORY_RADAR = 1 << 8,
- /* DFS CAC valid for slave device (STA mode) */
+ /* DFS CAC valid for client device (STA mode) */
QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_CAC_VALID = 1 << 9,
};
@@ -7271,6 +7403,45 @@ enum qca_wlan_vendor_attr_wifi_test_config {
*/
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_DISASSOC_TX = 39,
+ /* 8-bit unsigned value to configure an override for the RSNXE Used
+ * subfield in the MIC control field of the FTE in FT Reassociation
+ * Request frame.
+ * 0 - Default behavior, 1 - override with 1, 2 - override with 0.
+ * This attribute is used to configure the testbed device.
+ * This attribute can be configured only when STA is in associated state
+ * and the configuration is valid until the disconnection.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_FT_REASSOCREQ_RSNXE_USED = 40,
+
+ /* 8-bit unsigned value to configure the driver to ignore CSA (Channel
+ * Switch Announcement) when STA is in connected state.
+ * 0 - Default behavior, 1 - Ignore CSA.
+ * This attribute is used to configure the testbed device.
+ * This attribute can be configured only when STA is in associated state
+ * and the configuration is valid until the disconnection.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_IGNORE_CSA = 41,
+
+ /* Nested attribute values required to configure OCI (Operating Channel
+ * Information). Attributes defined in enum
+ * qca_wlan_vendor_attr_oci_override are nested within this attribute.
+ * This attribute is used to configure the testbed device.
+ * This attribute can be configured only when STA is in associated state
+ * and the configuration is valid until the disconnection.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OCI_OVERRIDE = 42,
+
+ /* 8-bit unsigned value to configure the driver/firmware to ignore SA
+ * Query timeout. If this configuration is enabled STA shall not send
+ * Deauthentication frmae when SA Query times out (mainly, after a
+ * channel switch when OCV is enabled).
+ * 0 - Default behavior, 1 - Ignore SA Query timeout.
+ * This attribute is used to configure the testbed device.
+ * This attribute can be configured only when STA is in associated state
+ * and the configuration is valid until the disconnection.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_IGNORE_SA_QUERY_TIMEOUT = 43,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX =
@@ -7278,6 +7449,63 @@ enum qca_wlan_vendor_attr_wifi_test_config {
};
/**
+ * enum qca_wlan_twt_operation - Operation of the config TWT request
+ * Values for %QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION.
+ *
+ * @QCA_WLAN_TWT_SET: Setup a TWT session. Required parameters are configured
+ * through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the enum
+ * qca_wlan_vendor_attr_twt_setup.
+ *
+ * @QCA_WLAN_TWT_GET: Get the configured TWT parameters. Required parameters are
+ * obtained through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the enum
+ * qca_wlan_vendor_attr_twt_setup.
+ *
+ * @QCA_WLAN_TWT_TERMINATE: Terminate the TWT session. Required parameters are
+ * obtained through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the enum
+ * qca_wlan_vendor_attr_twt_setup. Valid only after the TWT session is setup.
+ *
+ * @QCA_WLAN_TWT_SUSPEND: Suspend the TWT session. Required parameters are
+ * obtained through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the enum
+ * qca_wlan_vendor_attr_twt_setup. Valid only after the TWT session is setup.
+ *
+ * @QCA_WLAN_TWT_RESUME: Resume the TWT session. Required parameters are
+ * configured through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the enum
+ * qca_wlan_vendor_attr_twt_resume. Valid only after the TWT session is setup.
+ */
+enum qca_wlan_twt_operation {
+ QCA_WLAN_TWT_SET = 0,
+ QCA_WLAN_TWT_GET = 1,
+ QCA_WLAN_TWT_TERMINATE = 2,
+ QCA_WLAN_TWT_SUSPEND = 3,
+ QCA_WLAN_TWT_RESUME = 4,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_config_twt: Defines attributes used by
+ * %QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION: u8 attribute. Specify the TWT
+ * operation of this request. Possible values are defined in enum
+ * qca_wlan_twt_operation. The parameters for the respective operation is
+ * specified through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS: Nested attribute representing the
+ * parameters configured for TWT. These parameters are represented by
+ * enum qca_wlan_vendor_attr_twt_setup or enum qca_wlan_vendor_attr_twt_resume
+ * based on the operation.
+ */
+enum qca_wlan_vendor_attr_config_twt {
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION = 1,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX =
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_AFTER_LAST - 1,
+};
+
+/**
* enum qca_wlan_vendor_attr_bss_filter - Used by the vendor command
* QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
* The user can add/delete the filter by specifying the BSSID/STA MAC address in
@@ -7428,7 +7656,8 @@ enum qca_wlan_vendor_attr_nan_params {
* enum qca_wlan_vendor_attr_twt_setup: Represents attributes for
* TWT (Target Wake Time) setup request. These attributes are sent as part of
* %QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_SETUP and
- * %QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION.
+ * %QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION. Also used by
+ * attributes through %QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT.
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST: Flag attribute.
* Disable (flag attribute not present) - Individual TWT
@@ -7438,10 +7667,13 @@ enum qca_wlan_vendor_attr_nan_params {
* STA and AP.
* Broadcast means the session is across multiple STAs and an AP. The
* configuration parameters are announced in Beacon frames by the AP.
+ * This is used in
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE: Required (u8).
* Unsigned 8-bit qca_wlan_vendor_twt_setup_req_type to
- * specify the TWT request type
+ * specify the TWT request type. This is used in TWT SET operation.
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER: Flag attribute
* Enable (flag attribute present) - TWT with trigger support.
@@ -7449,40 +7681,113 @@ enum qca_wlan_vendor_attr_nan_params {
* Trigger means the AP will send the trigger frame to allow STA to send data.
* Without trigger, the STA will wait for the MU EDCA timer before
* transmitting the data.
+ * This is used in
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE: Required (u8)
* 0 - Announced TWT - In this mode, STA may skip few service periods to
* save more power. If STA wants to wake up, it will send a PS-POLL/QoS
* NULL frame to AP.
* 1 - Unannounced TWT - The STA will wakeup during every SP.
+ * This is a required parameter for
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID: Optional (u8)
* Flow ID is the unique identifier for each TWT session.
- * Currently this is not required and dialog ID will be set to zero.
+ * If not provided then dialog ID will be set to zero.
+ * This is an optional parameter for
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Request and Response
+ * 3. TWT TERMINATE Request and Response
+ * 4. TWT SUSPEND Request and Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP: Required (u8)
* This attribute (exp) is used along with the mantissa to derive the
* wake interval using the following formula:
* pow(2,exp) = wake_intvl_us/wake_intvl_mantis
* Wake interval is the interval between 2 successive SP.
+ * This is a required parameter for
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION: Flag attribute
* Enable (flag attribute present) - Protection required.
* Disable (flag attribute not present) - Protection not required.
* If protection is enabled, then the AP will use protection
* mechanism using RTS/CTS to self to reserve the airtime.
+ * This is used in
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME: Optional (u32)
* This attribute is used as the SP offset which is the offset from
* TSF after which the wake happens. The units are in microseconds. If
* this attribute is not provided, then the value will be set to zero.
+ * This is an optional parameter for
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION: Required (u32)
- * This is the duration of the service period. The units are in TU.
+ * This is the duration of the service period. This is specified as
+ * multiples of 256 microseconds. Valid values are 0x1 to 0xFF.
+ * This is a required parameter for
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA: Required (u32)
* This attribute is used to configure wake interval mantissa.
* The units are in TU.
+ * This is a required parameter for
+ * 1. TWT SET Request and Response
+ * 2. TWT GET Response
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS: Required (u8)
+ * This field is applicable for TWT response only.
+ * This contains status values in enum qca_wlan_vendor_twt_status
+ * and is passed to the userspace. This is used in TWT SET operation.
+ * This is a required parameter for
+ * 1. TWT SET Response
+ * 2. TWT TERMINATE Response
+ * 3. TWT SUSPEND Response
+ * 4. TWT RESUME Response
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESP_TYPE: Required (u8)
+ * This field is applicable for TWT response only.
+ * This field contains response type from the TWT responder and is
+ * passed to the userspace. The values for this field are defined in
+ * enum qca_wlan_vendor_twt_setup_resp_type. This is used in TWT SET
+ * response.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF: Required (u64)
+ * This field is applicable for TWT response only.
+ * This field contains absolute TSF value of the wake time received
+ * from the TWT responder and is passed to the userspace.
+ * This is a required parameter for
+ * 1. TWT SET Response
+ * 2. TWT GET Response
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED: Flag attribute.
+ * Enable (flag attribute present) - Indicates that the TWT responder
+ * supports reception of TWT information frame from the TWT requestor.
+ * Disable (flag attribute not present) - Indicates that the responder
+ * doesn't support reception of TWT information frame from requestor.
+ * This is used in
+ * 1. TWT SET Response
+ * 2. TWT GET Response
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR: 6-byte MAC address
+ * Represents the MAC address of the peer for which the TWT session
+ * is being configured. This is used in AP mode to represent the respective
+ * client. In AP mode, this is an optional parameter for response and is
+ * a required parameter for
+ * 1. TWT SET Request
+ * 2. TWT GET Request
+ * 3. TWT TERMINATE Request
+ * 4. TWT SUSPEND Request
+ * In STA mode, this is an optional parameter in request and response for
+ * the above four TWT operations.
*/
enum qca_wlan_vendor_attr_twt_setup {
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_INVALID = 0,
@@ -7497,6 +7802,14 @@ enum qca_wlan_vendor_attr_twt_setup {
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION = 9,
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA = 10,
+ /* TWT Response only attributes */
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS = 11,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESP_TYPE = 12,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF = 13,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED = 14,
+
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR = 15,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX =
@@ -7504,24 +7817,80 @@ enum qca_wlan_vendor_attr_twt_setup {
};
/**
- * enum qca_wlan_vendor_attr_twt_resume: Represents attributes for
+ * enum qca_wlan_vendor_twt_status - Represents the status of the requested
+ * TWT operation
+ *
+ * @QCA_WLAN_VENDOR_TWT_STATUS_OK: TWT request successfully completed
+ * @QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_ENABLED: TWT not enabled
+ * @QCA_WLAN_VENDOR_TWT_STATUS_USED_DIALOG_ID: TWT dialog ID is already used
+ * @QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY: TWT session is busy
+ * @QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST: TWT session does not exist
+ * @QCA_WLAN_VENDOR_TWT_STATUS_NOT_SUSPENDED: TWT session not in suspend state
+ * @QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM: Invalid parameters
+ * @QCA_WLAN_VENDOR_TWT_STATUS_NOT_READY: FW not ready
+ * @QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE: FW resource exhausted
+ * @QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK: Peer AP/STA did not ACK the
+ * request/response frame
+ * @QCA_WLAN_VENDOR_TWT_STATUS_NO_RESPONSE: Peer AP did not send the response
+ * frame
+ * @QCA_WLAN_VENDOR_TWT_STATUS_DENIED: AP did not accept the request
+ * @QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR: Adding TWT dialog failed due to an
+ * unknown reason
+ */
+enum qca_wlan_vendor_twt_status {
+ QCA_WLAN_VENDOR_TWT_STATUS_OK = 0,
+ QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_ENABLED = 1,
+ QCA_WLAN_VENDOR_TWT_STATUS_USED_DIALOG_ID = 2,
+ QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY = 3,
+ QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST = 4,
+ QCA_WLAN_VENDOR_TWT_STATUS_NOT_SUSPENDED = 5,
+ QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM = 6,
+ QCA_WLAN_VENDOR_TWT_STATUS_NOT_READY = 7,
+ QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE = 8,
+ QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK = 9,
+ QCA_WLAN_VENDOR_TWT_STATUS_NO_RESPONSE = 10,
+ QCA_WLAN_VENDOR_TWT_STATUS_DENIED = 11,
+ QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR = 12,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_twt_resume - Represents attributes for
* TWT (Target Wake Time) resume request. These attributes are sent as part of
* %QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_RESUME and
- * %QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION.
+ * %QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION. Also used by
+ * attributes through %QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT.
*
* @QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT: Optional (u8)
- * This attribute is used as the SP offset which is the offset from
- * TSF after which the wake happens. The units are in microseconds.
- * If this attribute is not provided, then the value will be set to
- * zero.
+ * @QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT2_TWT: Optional (u32)
+ * These attributes are used as the SP offset which is the offset from TSF after
+ * which the wake happens. The units are in microseconds. Please note that
+ * _NEXT_TWT is limited to u8 whereas _NEXT2_TWT takes the u32 data.
+ * _NEXT2_TWT takes the precedence over _NEXT_TWT and thus the recommendation
+ * is to use _NEXT2_TWT. If neither of these attributes is provided, the value
+ * will be set to zero.
*
* @QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE: Required (u32)
* This attribute represents the next TWT subfield size.
+ * Value 0 represents 0 bits, 1 represents 32 bits, 2 for 48 bits,
+ * and 4 for 64 bits.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID: Required (u8).
+ * Flow ID is the unique identifier for each TWT session. This attribute
+ * represents the respective TWT session to resume.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAC_ADDR: 6-byte MAC address
+ * Represents the MAC address of the peer to which TWT Resume is
+ * being sent. This is used in AP mode to represent the respective
+ * client and is a required parameter. In STA mode, this is an optional
+ * parameter
*/
enum qca_wlan_vendor_attr_twt_resume {
QCA_WLAN_VENDOR_ATTR_TWT_RESUME_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT = 1,
QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE = 2,
+ QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID = 3,
+ QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT2_TWT = 4,
+ QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAC_ADDR = 5,
/* keep last */
QCA_WLAN_VENDOR_ATTR_TWT_RESUME_AFTER_LAST,
@@ -7530,6 +7899,28 @@ enum qca_wlan_vendor_attr_twt_resume {
};
/**
+ * enum qca_wlan_vendor_twt_setup_resp_type - Represents the response type by
+ * the TWT responder
+ *
+ * @QCA_WLAN_VENDOR_TWT_RESP_ALTERNATE: TWT responder suggests TWT
+ * parameters that are different from TWT requesting STA suggested
+ * or demanded TWT parameters
+ * @QCA_WLAN_VENDOR_TWT_RESP_DICTATE: TWT responder demands TWT
+ * parameters that are different from TWT requesting STA TWT suggested
+ * or demanded parameters
+ * @QCA_WLAN_VENDOR_TWT_RESP_REJECT: TWT responder rejects TWT
+ * setup
+ * @QCA_WLAN_VENDOR_TWT_RESP_ACCEPT: TWT responder accepts the TWT
+ * setup.
+ */
+enum qca_wlan_vendor_twt_setup_resp_type {
+ QCA_WLAN_VENDOR_TWT_RESP_ALTERNATE = 1,
+ QCA_WLAN_VENDOR_TWT_RESP_DICTATE = 2,
+ QCA_WLAN_VENDOR_TWT_RESP_REJECT = 3,
+ QCA_WLAN_VENDOR_TWT_RESP_ACCEPT = 4,
+};
+
+/**
* enum qca_wlan_vendor_twt_setup_req_type - Required (u8)
* Represents the setup type being requested for TWT.
* @QCA_WLAN_VENDOR_TWT_SETUP_REQUEST: STA is not specifying all the TWT
@@ -8821,6 +9212,26 @@ enum qca_vendor_wlan_sta_guard_interval {
* disconnect reason for the last disconnection if the disconnection is
* triggered from the host driver. The values are referred from
* enum qca_disconnect_reason_codes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BIP_MIC_ERROR_COUNT: u32, used in STA mode
+ * only. This represents the number of group addressed robust management frames
+ * received from this station with an invalid MIC or a missing MME when PMF is
+ * enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BIP_REPLAY_COUNT: u32, used in STA mode
+ * only. This represents the number of group addressed robust management frames
+ * received from this station with the packet number less than or equal to the
+ * last received packet number when PMF is enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_MIC_ERROR_COUNT: u32, used in STA
+ * mode only. This represents the number of Beacon frames received from this
+ * station with an invalid MIC or a missing MME when beacon protection is
+ * enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_REPLAY_COUNT: u32, used in STA mode
+ * only. This represents number of Beacon frames received from this station with
+ * the packet number less than or equal to the last received packet number when
+ * beacon protection is enabled.
*/
enum qca_wlan_vendor_attr_get_sta_info {
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_INVALID = 0,
@@ -8862,6 +9273,10 @@ enum qca_wlan_vendor_attr_get_sta_info {
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_IES = 36,
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PROBE_RESP_IES = 37,
QCA_WLAN_VENDOR_ATTR_GET_STA_DRIVER_DISCONNECT_REASON = 38,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BIP_MIC_ERROR_COUNT = 39,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BIP_REPLAY_COUNT = 40,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_MIC_ERROR_COUNT = 41,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_REPLAY_COUNT = 42,
/* keep last */
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_AFTER_LAST,
@@ -9017,7 +9432,7 @@ enum qca_wlan_tspec_direction {
/**
* enum qca_wlan_tspec_ack_policy - MAC acknowledgement policy in TSPEC
- * As what is defined in IEEE Std 802.11-201, Table 9-141.
+ * As what is defined in IEEE Std 802.11-2016, Table 9-141.
*
* Values for %QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_ACK_POLICY.
*/
@@ -9159,4 +9574,137 @@ enum qca_wlan_vendor_attr_config_tspec {
QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_AFTER_LAST - 1,
};
+/**
+ * enum qca_wlan_vendor_oci_override_frame_type - OCI override frame type
+ * @QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_SA_QUERY_REQ: SA Query Request frame
+ * @QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_SA_QUERY_RESP: SA Query Response frame
+ * @QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_FT_REASSOC_REQ: FT Reassociation Request
+ * frame
+ * @QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_FILS_REASSOC_REQ: FILS Reassociation
+ * Request frame.
+ */
+enum qca_wlan_vendor_oci_override_frame_type {
+ QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_SA_QUERY_REQ = 1,
+ QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_SA_QUERY_RESP = 2,
+ QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_FT_REASSOC_REQ = 3,
+ QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_FILS_REASSOC_REQ = 4,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_oci_override: Represents attributes for
+ * OCI override request. These attributes are used inside nested attribute
+ * %QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OCI_OVERRIDE in QCA vendor command
+ * %QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_FRAME_TYPE: Required attribute, u8.
+ * Values from enum qca_wlan_vendor_oci_override_frame_type used in this
+ * attribute to specify the frame type in which the OCI is to be overridden.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_FREQUENCY: Required (u32)
+ * OCI frequency (in MHz) to override in the specified frame type.
+ */
+enum qca_wlan_vendor_attr_oci_override {
+ QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_FRAME_TYPE = 1,
+ QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_FREQUENCY = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_MAX =
+ QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_medium_assess_type - Type of medium assess request
+ *
+ * Values for %QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TYPE.
+ */
+enum qca_wlan_medium_assess_type {
+ QCA_WLAN_MEDIUM_ASSESS_CCA = 0,
+ QCA_WLAN_MEDIUM_ASSESS_CONGESTION_REPORT = 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_medium_assess - Attributes used by
+ * %QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TYPE:
+ * u8 attribute. Mandatory in all kinds of medium assess requests/responses.
+ * Specify the type of medium assess request and indicate its type in response.
+ * Possible values are defined in enum qca_wlan_medium_assess_type.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_PERIOD:
+ * u32 attribute. Mandatory in CCA request.
+ * Specify the assessment period in terms of seconds. Assessment result will be
+ * sent as the response to the CCA request after the assessment period.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TOTAL_CYCLE_COUNT:
+ * u32 attribute. Mandatory in response to CCA request.
+ * Total timer tick count of the assessment cycle.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IDLE_COUNT:
+ * u32 attribute. Mandatory in response to CCA request.
+ * Timer tick count of idle time in the assessment cycle.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IBSS_RX_COUNT:
+ * u32 attribute. Mandatory in response to CCA request.
+ * Timer tick count of Intra BSS traffic RX time in the assessment cycle.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_OBSS_RX_COUNT:
+ * u32 attribute. Mandatory in response to CCA request.
+ * Timer tick count of Overlapping BSS traffic RX time in the assessment cycle.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX_IBSS_RSSI:
+ * s32 attribute. Mandatory in response to CCA request.
+ * Maximum RSSI of Intra BSS traffic in the assessment cycle.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MIN_IBSS_RSSI:
+ * s32 attribute. Mandatory in response to CCA request.
+ * Minimum RSSI of Intra BSS traffic in the assessment cycle.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_ENABLE:
+ * u8 attribute. Mandatory in congestion report request.
+ * 1-enable 0-disable.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_THRESHOLD:
+ * u8 attribute. Mandatory in congestion report enable request and will be
+ * ignored if present in congestion report disable request. Possible values are
+ * 0-100. A vendor event QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS with the type
+ * QCA_WLAN_MEDIUM_ASSESS_CONGESTION_REPORT will be sent to userspace if
+ * congestion percentage reaches the configured threshold.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_INTERVAL:
+ * u8 attribute. Optional in congestion report enable request and will be
+ * ignored if present in congestion report disable request.
+ * Specify the interval of congestion report event in terms of seconds. Possible
+ * values are 1-255. Default value 1 will be used if this attribute is omitted
+ * or using invalid values.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_PERCENTAGE:
+ * u8 attribute. Mandatory in congestion report event.
+ * Indicate the actual congestion percentage. Possible values are 0-100.
+ */
+enum qca_wlan_vendor_attr_medium_assess {
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TYPE = 1,
+
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_PERIOD = 2,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TOTAL_CYCLE_COUNT = 3,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IDLE_COUNT = 4,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IBSS_RX_COUNT = 5,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_OBSS_RX_COUNT = 6,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX_IBSS_RSSI = 7,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MIN_IBSS_RSSI = 8,
+
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_ENABLE = 9,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_THRESHOLD = 10,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_INTERVAL = 11,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_PERCENTAGE = 12,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX =
+ QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_AFTER_LAST - 1,
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index a298212..72b5f3f 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -112,9 +112,6 @@ void sae_clear_temp_data(struct sae_data *sae)
wpabuf_free(tmp->own_rejected_groups);
wpabuf_free(tmp->peer_rejected_groups);
os_free(tmp->pw_id);
-#ifdef CONFIG_SAE_PK
- bin_clear_free(tmp->pw, tmp->pw_len);
-#endif /* CONFIG_SAE_PK */
bin_clear_free(tmp, sizeof(*tmp));
sae->tmp = NULL;
}
@@ -1364,8 +1361,8 @@ int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
identifier) < 0))
return -1;
- sae->tmp->h2e = 0;
- sae->tmp->pk = 0;
+ sae->h2e = 0;
+ sae->pk = 0;
return sae_derive_commit(sae);
}
@@ -1392,15 +1389,6 @@ int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
os_memcpy(sae->tmp->ssid, pt->ssid, pt->ssid_len);
sae->tmp->ssid_len = pt->ssid_len;
sae->tmp->ap_pk = pk;
- /* TODO: Could support alternative groups as long as the combination
- * meets the requirements. */
- if (pk && pk->group != sae->group) {
- wpa_printf(MSG_DEBUG,
- "SAE-PK: Reject attempt to use group %d since K_AP use group %d",
- sae->group, pk->group);
- sae->tmp->reject_group = true;
- return -1;
- }
#endif /* CONFIG_SAE_PK */
sae->tmp->own_addr_higher = os_memcmp(addr1, addr2, ETH_ALEN) > 0;
wpabuf_free(sae->tmp->own_rejected_groups);
@@ -1434,7 +1422,7 @@ int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
return -1;
}
- sae->tmp->h2e = 1;
+ sae->h2e = 1;
return sae_derive_commit(sae);
}
@@ -1559,14 +1547,14 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
* When SAE-PK is used,
* KCK || PMK || KEK = KDF-Hash-Length(keyseed, "SAE-PK keys", context)
*/
- if (!sae->tmp->h2e)
+ if (!sae->h2e)
hash_len = SHA256_MAC_LEN;
else if (sae->tmp->dh)
hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
else
hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
- if (sae->tmp->h2e && (sae->tmp->own_rejected_groups ||
- sae->tmp->peer_rejected_groups)) {
+ if (sae->h2e && (sae->tmp->own_rejected_groups ||
+ sae->tmp->peer_rejected_groups)) {
struct wpabuf *own, *peer;
own = sae->tmp->own_rejected_groups;
@@ -1617,13 +1605,13 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
* octets). */
crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->order_len);
wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
- if (!sae->tmp->pk &&
+ if (!sae->pk &&
sae_kdf_hash(hash_len, keyseed, "SAE KCK and PMK",
val, sae->tmp->order_len,
keys, hash_len + SAE_PMK_LEN) < 0)
goto fail;
#ifdef CONFIG_SAE_PK
- if (sae->tmp->pk &&
+ if (sae->pk &&
sae_kdf_hash(hash_len, keyseed, "SAE-PK keys",
val, sae->tmp->order_len,
keys, 2 * hash_len + SAE_PMK_LEN) < 0)
@@ -1635,7 +1623,7 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
os_memcpy(sae->pmk, keys + hash_len, SAE_PMK_LEN);
os_memcpy(sae->pmkid, val, SAE_PMKID_LEN);
#ifdef CONFIG_SAE_PK
- if (sae->tmp->pk) {
+ if (sae->pk) {
os_memcpy(sae->tmp->kek, keys + hash_len + SAE_PMK_LEN,
hash_len);
sae->tmp->kek_len = hash_len;
@@ -1677,7 +1665,7 @@ int sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
return -1;
wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
- if (!sae->tmp->h2e && token) {
+ if (!sae->h2e && token) {
wpabuf_put_buf(buf, token);
wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token",
wpabuf_head(token), wpabuf_len(token));
@@ -1718,7 +1706,7 @@ int sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
identifier);
}
- if (sae->tmp->h2e && sae->tmp->own_rejected_groups) {
+ if (sae->h2e && sae->tmp->own_rejected_groups) {
wpa_hexdump_buf(MSG_DEBUG, "SAE: own Rejected Groups",
sae->tmp->own_rejected_groups);
wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
@@ -1728,7 +1716,7 @@ int sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
wpabuf_put_buf(buf, sae->tmp->own_rejected_groups);
}
- if (sae->tmp->h2e && token) {
+ if (sae->h2e && token) {
wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
wpabuf_put_u8(buf, 1 + wpabuf_len(token));
wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
diff --git a/src/common/sae.h b/src/common/sae.h
index 61b2288..2243c0f 100644
--- a/src/common/sae.h
+++ b/src/common/sae.h
@@ -31,6 +31,9 @@ struct sae_pk {
struct crypto_ec_key *key;
int group;
struct wpabuf *pubkey; /* DER encoded subjectPublicKey */
+#ifdef CONFIG_TESTING_OPTIONS
+ struct crypto_ec_key *sign_key_override;
+#endif /* CONFIG_TESTING_OPTIONS */
};
@@ -59,8 +62,6 @@ struct sae_temporary_data {
u8 bssid[ETH_ALEN];
struct wpabuf *own_rejected_groups;
struct wpabuf *peer_rejected_groups;
- unsigned int h2e:1;
- unsigned int pk:1;
unsigned int own_addr_higher:1;
#ifdef CONFIG_SAE_PK
@@ -69,12 +70,16 @@ struct sae_temporary_data {
const struct sae_pk *ap_pk;
u8 own_addr[ETH_ALEN];
u8 peer_addr[ETH_ALEN];
- u8 *pw;
- size_t pw_len;
+ u8 fingerprint[SAE_MAX_HASH_LEN];
+ size_t fingerprint_bytes;
+ size_t fingerprint_bits;
size_t lambda;
+ unsigned int sec;
u8 ssid[32];
size_t ssid_len;
- bool reject_group;
+#ifdef CONFIG_TESTING_OPTIONS
+ bool omit_pk_elem;
+#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_SAE_PK */
};
@@ -106,6 +111,8 @@ struct sae_data {
int group;
unsigned int sync; /* protocol instance variable: Sync */
u16 rc; /* protocol instance variable: Rc (received send-confirm) */
+ unsigned int h2e:1;
+ unsigned int pk:1;
struct sae_temporary_data *tmp;
};
@@ -159,5 +166,7 @@ struct sae_pk * sae_parse_pk(const char *val);
int sae_write_confirm_pk(struct sae_data *sae, struct wpabuf *buf);
int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len);
int sae_hash(size_t hash_len, const u8 *data, size_t len, u8 *hash);
+u32 sae_pk_get_be19(const u8 *buf);
+void sae_pk_buf_shift_left_19(u8 *buf, size_t len);
#endif /* SAE_H */
diff --git a/src/common/sae_pk.c b/src/common/sae_pk.c
index df0f7db..df79e5f 100644
--- a/src/common/sae_pk.c
+++ b/src/common/sae_pk.c
@@ -23,28 +23,173 @@
static const char *sae_pk_base32_table = "abcdefghijklmnopqrstuvwxyz234567";
+static const u8 d_mult_table[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16,
+ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22,
+ 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7,
+ 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23,
+ 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+ 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17,
+ 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
+ 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18,
+ 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2,
+ 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19,
+ 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3,
+ 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20,
+ 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4,
+ 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21,
+ 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5,
+ 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22,
+ 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6,
+ 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23,
+ 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7,
+ 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24,
+ 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8,
+ 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25,
+ 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9,
+ 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26,
+ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10,
+ 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27,
+ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11,
+ 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28,
+ 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12,
+ 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29,
+ 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13,
+ 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30,
+ 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14,
+ 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31,
+ 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15,
+ 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16,
+ 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
+};
+
+static const u8 d_perm_table[] = {
+ 7, 2, 1, 30, 16, 20, 27, 11, 31, 6, 8, 13, 29, 5, 10, 21,
+ 22, 3, 24, 0, 23, 25, 12, 9, 28, 14, 4, 15, 17, 18, 19, 26
+};
+
+
+static u8 d_permute(u8 val, unsigned int iter)
+{
+ if (iter == 0)
+ return val;
+ return d_permute(d_perm_table[val], iter - 1);
+}
+
+
+static u8 d_invert(u8 val)
+{
+ if (val > 0 && val < 16)
+ return 16 - val;
+ return val;
+}
+
+
+static char d_check_char(const char *str, size_t len)
+{
+ size_t i;
+ u8 val = 0;
+ u8 dtable[256];
+ unsigned int iter = 1;
+ int j;
+
+ os_memset(dtable, 0x80, 256);
+ for (i = 0; sae_pk_base32_table[i]; i++)
+ dtable[(u8) sae_pk_base32_table[i]] = i;
+
+ for (j = len - 1; j >= 0; j--) {
+ u8 c, p;
+
+ c = dtable[(u8) str[j]];
+ if (c == 0x80)
+ continue;
+ p = d_permute(c, iter);
+ iter++;
+ val = d_mult_table[val * 32 + p];
+ }
+
+ return sae_pk_base32_table[d_invert(val)];
+}
+
+
bool sae_pk_valid_password(const char *pw)
{
int pos;
+ size_t i, pw_len = os_strlen(pw);
+ u8 sec_1b;
+ u8 dtable[256];
- /* Minimum password length for SAE-PK is not defined, but the automatic
- * password style determination is more reliable if at least one hyphen
- * is forced to be present in the password. */
- if (os_strlen(pw) < 6)
+ os_memset(dtable, 0x80, 256);
+ for (i = 0; sae_pk_base32_table[i]; i++)
+ dtable[(u8) sae_pk_base32_table[i]] = i;
+
+ /* SAE-PK password has at least three four character components
+ * separated by hyphens. */
+ if (pw_len < 14 || pw_len % 5 != 4) {
+ wpa_printf(MSG_DEBUG, "SAE-PK: Not a valid password (length)");
return false;
+ }
for (pos = 0; pw[pos]; pos++) {
if (pos && pos % 5 == 4) {
- if (pw[pos] != '-')
+ if (pw[pos] != '-') {
+ wpa_printf(MSG_DEBUG,
+ "SAE-PK: Not a valid password (separator)");
return false;
+ }
continue;
}
- if (!os_strchr(sae_pk_base32_table, pw[pos]))
+ if (dtable[(u8) pw[pos]] == 0x80) {
+ wpa_printf(MSG_DEBUG,
+ "SAE-PK: Not a valid password (character)");
return false;
+ }
}
- if (pos == 0)
+
+ /* Verify that the checksum character is valid */
+ if (pw[pw_len - 1] != d_check_char(pw, pw_len - 1)) {
+ wpa_printf(MSG_DEBUG,
+ "SAE-PK: Not a valid password (checksum)");
return false;
- return pw[pos - 1] != '-';
+ }
+
+ /* Verify that Sec_1b bits match */
+ sec_1b = dtable[(u8) pw[0]] & BIT(4);
+ for (i = 5; i < pw_len; i += 5) {
+ if (sec_1b != (dtable[(u8) pw[i]] & BIT(4))) {
+ wpa_printf(MSG_DEBUG,
+ "SAE-PK: Not a valid password (Sec_1b)");
+ return false;
+ }
+ }
+ return true;
}
@@ -64,6 +209,7 @@ static char * add_char(const char *start, char *pos, u8 idx, size_t *bits)
}
+/* Base32 encode a password and add hyper separators and checksum */
char * sae_pk_base32_encode(const u8 *src, size_t len_bits)
{
char *out, *pos;
@@ -78,7 +224,7 @@ char * sae_pk_base32_encode(const u8 *src, size_t len_bits)
return NULL;
olen = len * 8 / 5 + 1;
olen += olen / 4; /* hyphen separators */
- pos = out = os_zalloc(olen + 1);
+ pos = out = os_zalloc(olen + 2); /* include room for ChkSum and nul */
if (!out)
return NULL;
@@ -95,6 +241,8 @@ char * sae_pk_base32_encode(const u8 *src, size_t len_bits)
}
}
+ *pos = d_check_char(out, os_strlen(out));
+
return out;
}
@@ -166,19 +314,122 @@ u8 * sae_pk_base32_decode(const char *src, size_t len, size_t *out_len)
}
+u32 sae_pk_get_be19(const u8 *buf)
+{
+ return (buf[0] << 11) | (buf[1] << 3) | (buf[2] >> 5);
+}
+
+
+/* shift left by two octets and three bits; fill in zeros from right;
+ * len must be at least three */
+void sae_pk_buf_shift_left_19(u8 *buf, size_t len)
+{
+ u8 *dst, *src, *end;
+
+ dst = buf;
+ src = buf + 2;
+ end = buf + len;
+
+ while (src + 1 < end) {
+ *dst++ = (src[0] << 3) | (src[1] >> 5);
+ src++;
+ }
+ *dst++ = *src << 3;
+ *dst++ = 0;
+ *dst++ = 0;
+}
+
+
+static void sae_pk_buf_shift_left_1(u8 *buf, size_t len)
+{
+ u8 *dst, *src, *end;
+
+ dst = buf;
+ src = buf;
+ end = buf + len;
+
+ while (src + 1 < end) {
+ *dst++ = (src[0] << 1) | (src[1] >> 7);
+ src++;
+ }
+ *dst++ = *src << 1;
+}
+
+
int sae_pk_set_password(struct sae_data *sae, const char *password)
{
struct sae_temporary_data *tmp = sae->tmp;
- size_t len;
+ size_t len, pw_len;
+ u8 *pw, *pos;
+ int bits;
+ u32 val = 0, val19;
+ unsigned int val_bits = 0;
+
+ if (!tmp)
+ return -1;
+
+ os_memset(tmp->fingerprint, 0, sizeof(tmp->fingerprint));
+ tmp->fingerprint_bytes = tmp->fingerprint_bits = 0;
len = os_strlen(password);
- if (!tmp || len < 1)
+ if (len < 1 || !sae_pk_valid_password(password))
return -1;
- bin_clear_free(tmp->pw, tmp->pw_len);
- tmp->pw = sae_pk_base32_decode(password, len, &tmp->pw_len);
+ pw = sae_pk_base32_decode(password, len, &pw_len);
+ if (!pw)
+ return -1;
+
+ tmp->sec = (pw[0] & BIT(7)) ? 3 : 5;
tmp->lambda = len - len / 5;
- return tmp->pw ? 0 : -1;
+ tmp->fingerprint_bits = 8 * tmp->sec + 19 * tmp->lambda / 4 - 5;
+ wpa_printf(MSG_DEBUG, "SAE-PK: Sec=%u Lambda=%zu fingerprint_bits=%zu",
+ tmp->sec, tmp->lambda, tmp->fingerprint_bits);
+
+ /* Construct Fingerprint from PasswordBase by prefixing with Sec zero
+ * octets and skipping the Sec_1b bits */
+ pos = &tmp->fingerprint[tmp->sec];
+ bits = tmp->fingerprint_bits - 8 * tmp->sec;
+ wpa_hexdump_key(MSG_DEBUG, "SAE-PK: PasswordBase", pw, pw_len);
+ while (bits > 0) {
+ if (val_bits < 8) {
+ sae_pk_buf_shift_left_1(pw, pw_len); /* Sec_1b */
+ val19 = sae_pk_get_be19(pw);
+ sae_pk_buf_shift_left_19(pw, pw_len);
+ val = (val << 19) | val19;
+ val_bits += 19;
+ }
+ if (val_bits >= 8) {
+ if (bits < 8)
+ break;
+ *pos++ = (val >> (val_bits - 8)) & 0xff;
+ val_bits -= 8;
+ bits -= 8;
+ }
+ }
+ if (bits > 0) {
+ val >>= val_bits - bits;
+ *pos++ = val << (8 - bits);
+ }
+ tmp->fingerprint_bytes = pos - tmp->fingerprint;
+ wpa_hexdump_key(MSG_DEBUG, "SAE-PK: Fingerprint",
+ tmp->fingerprint, tmp->fingerprint_bytes);
+ bin_clear_free(pw, pw_len);
+ return 0;
+}
+
+
+static size_t sae_group_2_hash_len(int group)
+{
+ switch (group) {
+ case 19:
+ return 32;
+ case 20:
+ return 48;
+ case 21:
+ return 64;
+ }
+
+ return 0;
}
@@ -187,6 +438,9 @@ void sae_deinit_pk(struct sae_pk *pk)
if (pk) {
wpabuf_free(pk->m);
crypto_ec_key_deinit(pk->key);
+#ifdef CONFIG_TESTING_OPTIONS
+ crypto_ec_key_deinit(pk->sign_key_override);
+#endif /* CONFIG_TESTING_OPTIONS */
wpabuf_free(pk->pubkey);
os_free(pk);
}
@@ -197,9 +451,12 @@ struct sae_pk * sae_parse_pk(const char *val)
{
struct sae_pk *pk;
const char *pos;
+#ifdef CONFIG_TESTING_OPTIONS
+ const char *pos2;
+#endif /* CONFIG_TESTING_OPTIONS */
size_t len;
unsigned char *der;
- size_t der_len;
+ size_t der_len, b_len;
/* <m-as-hexdump>:<base64-encoded-DER-encoded-key> */
@@ -223,7 +480,15 @@ struct sae_pk * sae_parse_pk(const char *val)
}
pos++;
- der = base64_decode(pos, os_strlen(pos), &der_len);
+ b_len = os_strlen(pos);
+#ifdef CONFIG_TESTING_OPTIONS
+ pos2 = os_strchr(pos, ':');
+ if (pos2) {
+ b_len = pos2 - pos;
+ pos2++;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ der = base64_decode(pos, b_len, &der_len);
if (!der) {
wpa_printf(MSG_INFO, "SAE: Failed to base64 decode PK key");
goto fail;
@@ -238,6 +503,22 @@ struct sae_pk * sae_parse_pk(const char *val)
if (!pk->pubkey)
goto fail;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (pos2) {
+ der = base64_decode(pos2, os_strlen(pos2), &der_len);
+ if (!der) {
+ wpa_printf(MSG_INFO,
+ "SAE: Failed to base64 decode PK key");
+ goto fail;
+ }
+
+ pk->sign_key_override = crypto_ec_key_parse_priv(der, der_len);
+ bin_clear_free(der, der_len);
+ if (!pk->sign_key_override)
+ goto fail;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
return pk;
fail:
sae_deinit_pk(pk);
@@ -318,24 +599,36 @@ fail:
int sae_write_confirm_pk(struct sae_data *sae, struct wpabuf *buf)
{
struct sae_temporary_data *tmp = sae->tmp;
- struct wpabuf *elem = NULL, *sig = NULL;
- size_t extra;
+ struct wpabuf *sig = NULL;
+ size_t need;
int ret = -1;
u8 *encr_mod;
size_t encr_mod_len;
const struct sae_pk *pk;
u8 hash[SAE_MAX_HASH_LEN];
size_t hash_len;
+ struct crypto_ec_key *key;
if (!tmp)
return -1;
pk = tmp->ap_pk;
- if (!pk)
+ if (!sae->pk || !pk)
return 0;
+ key = pk->key;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (tmp->omit_pk_elem)
+ return 0;
+ if (pk->sign_key_override) {
+ wpa_printf(MSG_INFO, "TESTING: Override SAE-PK signing key");
+ key = pk->sign_key_override;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
if (tmp->kek_len != 32 && tmp->kek_len != 48 && tmp->kek_len != 64) {
- wpa_printf(MSG_INFO, "SAE-PK: No KEK available for confirm");
+ wpa_printf(MSG_INFO,
+ "SAE-PK: No KEK available for writing confirm");
return -1;
}
@@ -347,65 +640,60 @@ int sae_write_confirm_pk(struct sae_data *sae, struct wpabuf *buf)
return -1;
}
- hash_len = sae_ecc_prime_len_2_hash_len(tmp->prime_len);
+ hash_len = sae_group_2_hash_len(pk->group);
if (sae_pk_hash_sig_data(sae, hash_len, true, wpabuf_head(pk->m),
wpabuf_len(pk->m), wpabuf_head(pk->pubkey),
wpabuf_len(pk->pubkey), hash) < 0)
goto fail;
- sig = crypto_ec_key_sign(pk->key, hash, hash_len);
+ sig = crypto_ec_key_sign(key, hash, hash_len);
if (!sig)
goto fail;
wpa_hexdump_buf(MSG_DEBUG, "SAE-PK: KeyAuth = Sig_AP()", sig);
- elem = wpabuf_alloc(1500 + wpabuf_len(sig));
- if (!elem)
- goto fail;
+ /* TODO: fragmentation if any of the elements needs it for a group
+ * using sufficiently large primes (none of the currently supported
+ * ones do) */
- /* EncryptedModifier = AES-SIV-Q(M); no AAD */
encr_mod_len = wpabuf_len(pk->m) + AES_BLOCK_SIZE;
- wpabuf_put_u8(elem, encr_mod_len);
- encr_mod = wpabuf_put(elem, encr_mod_len);
- if (aes_siv_encrypt(tmp->kek, tmp->kek_len,
- wpabuf_head(pk->m), wpabuf_len(pk->m),
- 0, NULL, NULL, encr_mod) < 0)
+ need = 4 + wpabuf_len(pk->pubkey) + 3 + wpabuf_len(sig) +
+ 6 + encr_mod_len;
+ if (wpabuf_tailroom(buf) < need) {
+ wpa_printf(MSG_INFO,
+ "SAE-PK: No room in message buffer for SAE-PK elements (%zu < %zu)",
+ wpabuf_tailroom(buf), need);
goto fail;
- wpa_hexdump(MSG_DEBUG, "SAE-PK: EncryptedModifier",
- encr_mod, encr_mod_len);
+ }
/* FILS Public Key element */
- wpabuf_put_u8(elem, WLAN_EID_EXTENSION);
- wpabuf_put_u8(elem, 2 + wpabuf_len(pk->pubkey));
- wpabuf_put_u8(elem, WLAN_EID_EXT_FILS_PUBLIC_KEY);
- wpabuf_put_u8(elem, 3); /* Key Type: ECDSA public key */
- wpabuf_put_buf(elem, pk->pubkey);
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 2 + wpabuf_len(pk->pubkey));
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_PUBLIC_KEY);
+ wpabuf_put_u8(buf, 2); /* Key Type: ECDSA public key */
+ wpabuf_put_buf(buf, pk->pubkey);
/* FILS Key Confirmation element (KeyAuth) */
- wpabuf_put_u8(elem, WLAN_EID_EXTENSION);
- wpabuf_put_u8(elem, 1 + wpabuf_len(sig));
- wpabuf_put_u8(elem, WLAN_EID_EXT_FILS_KEY_CONFIRM);
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + wpabuf_len(sig));
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_KEY_CONFIRM);
/* KeyAuth = Sig_AP(eleAP || eleSTA || scaAP || scaSTA || M || K_AP ||
* AP-BSSID || STA-MAC) */
- wpabuf_put_buf(elem, sig);
-
- /* TODO: fragmentation */
- extra = 6; /* Vendor specific element header */
-
- if (wpabuf_tailroom(elem) < extra + wpabuf_len(buf)) {
- wpa_printf(MSG_INFO,
- "SAE-PK: No room in message buffer for SAE-PK element (%zu < %zu)",
- wpabuf_tailroom(buf), extra + wpabuf_len(buf));
- goto fail;
- }
+ wpabuf_put_buf(buf, sig);
/* SAE-PK element */
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
- wpabuf_put_u8(buf, 4 + wpabuf_len(elem));
+ wpabuf_put_u8(buf, 4 + encr_mod_len);
wpabuf_put_be32(buf, SAE_PK_IE_VENDOR_TYPE);
- wpabuf_put_buf(buf, elem);
+ /* EncryptedModifier = AES-SIV-Q(M); no AAD */
+ encr_mod = wpabuf_put(buf, encr_mod_len);
+ if (aes_siv_encrypt(tmp->kek, tmp->kek_len,
+ wpabuf_head(pk->m), wpabuf_len(pk->m),
+ 0, NULL, NULL, encr_mod) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: EncryptedModifier",
+ encr_mod, encr_mod_len);
ret = 0;
fail:
- wpabuf_free(elem);
wpabuf_free(sig);
return ret;
@@ -414,24 +702,24 @@ fail:
static bool sae_pk_valid_fingerprint(struct sae_data *sae,
const u8 *m, size_t m_len,
- const u8 *k_ap, size_t k_ap_len)
+ const u8 *k_ap, size_t k_ap_len, int group)
{
struct sae_temporary_data *tmp = sae->tmp;
- size_t sec, i;
- u8 *fingerprint_exp, *hash_data, *pos;
- size_t hash_len, hash_data_len, fingerprint_bits, fingerprint_bytes;
+ u8 *hash_data, *pos;
+ size_t hash_len, hash_data_len;
u8 hash[SAE_MAX_HASH_LEN];
int res;
- if (!tmp->pw || tmp->pw_len < 1) {
+ if (!tmp->fingerprint_bytes) {
wpa_printf(MSG_DEBUG,
"SAE-PK: No PW available for K_AP fingerprint check");
return false;
}
- /* Fingerprint = L(Hash(SSID || M || K_AP), 0, 8*Sec + 5*Lambda - 2) */
+ /* Fingerprint = L(Hash(SSID || M || K_AP), 0, 8*Sec + 19*Lambda/4 - 5)
+ */
- hash_len = sae_ecc_prime_len_2_hash_len(tmp->prime_len);
+ hash_len = sae_group_2_hash_len(group);
hash_data_len = tmp->ssid_len + m_len + k_ap_len;
hash_data = os_malloc(hash_data_len);
if (!hash_data)
@@ -452,44 +740,26 @@ static bool sae_pk_valid_fingerprint(struct sae_data *sae,
wpa_hexdump(MSG_DEBUG, "SAE-PK: Hash(SSID || M || K_AP)",
hash, hash_len);
- wpa_hexdump_key(MSG_DEBUG, "SAE-PK: PW", tmp->pw, tmp->pw_len);
- sec = (tmp->pw[0] >> 6) + 2;
- fingerprint_bits = 8 * sec + 5 * tmp->lambda - 2;
- wpa_printf(MSG_DEBUG, "SAE-PK: Sec=%zu Lambda=%zu fingerprint_bits=%zu",
- sec, tmp->lambda, fingerprint_bits);
- if (fingerprint_bits > hash_len * 8) {
+ if (tmp->fingerprint_bits > hash_len * 8) {
wpa_printf(MSG_INFO,
"SAE-PK: Not enough hash output bits for the fingerprint");
return false;
}
- fingerprint_bytes = (fingerprint_bits + 7) / 8;
- if (fingerprint_bits % 8) {
+ if (tmp->fingerprint_bits % 8) {
size_t extra;
/* Zero out the extra bits in the last octet */
- extra = 8 - fingerprint_bits % 8;
- pos = &hash[fingerprint_bits / 8];
+ extra = 8 - tmp->fingerprint_bits % 8;
+ pos = &hash[tmp->fingerprint_bits / 8];
*pos = (*pos >> extra) << extra;
}
- wpa_hexdump(MSG_DEBUG, "SAE-PK: Fingerprint", hash, fingerprint_bytes);
-
- fingerprint_exp = os_zalloc(sec + tmp->pw_len);
- if (!fingerprint_exp)
- return false;
- pos = fingerprint_exp + sec;
- for (i = 0; i < tmp->pw_len; i++) {
- u8 next = i + 1 < tmp->pw_len ? tmp->pw[i + 1] : 0;
-
- *pos++ = tmp->pw[i] << 2 | next >> 6;
- }
-
- wpa_hexdump(MSG_DEBUG, "SAE-PK: Fingerprint_Expected",
- fingerprint_exp, fingerprint_bytes);
- res = os_memcmp_const(hash, fingerprint_exp, fingerprint_bytes);
- bin_clear_free(fingerprint_exp, tmp->pw_len);
-
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: Fingerprint", hash,
+ tmp->fingerprint_bytes);
+ res = os_memcmp_const(hash, tmp->fingerprint, tmp->fingerprint_bytes);
if (res) {
wpa_printf(MSG_DEBUG, "SAE-PK: K_AP fingerprint mismatch");
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: Expected fingerprint",
+ tmp->fingerprint, tmp->fingerprint_bytes);
return false;
}
@@ -501,22 +771,24 @@ static bool sae_pk_valid_fingerprint(struct sae_data *sae,
int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len)
{
struct sae_temporary_data *tmp = sae->tmp;
- const u8 *sae_pk, *pos, *end, *encr_mod, *k_ap, *key_auth;
+ const u8 *k_ap;
u8 m[SAE_PK_M_LEN];
- size_t k_ap_len, key_auth_len;
+ size_t k_ap_len;
struct crypto_ec_key *key;
int res;
u8 hash[SAE_MAX_HASH_LEN];
size_t hash_len;
int group;
+ struct ieee802_11_elems elems;
if (!tmp)
return -1;
- if (!tmp->pk || tmp->ap_pk)
+ if (!sae->pk || tmp->ap_pk)
return 0;
if (tmp->kek_len != 32 && tmp->kek_len != 48 && tmp->kek_len != 64) {
- wpa_printf(MSG_INFO, "SAE-PK: No KEK available for confirm");
+ wpa_printf(MSG_INFO,
+ "SAE-PK: No KEK available for checking confirm");
return -1;
}
@@ -529,71 +801,29 @@ int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len)
}
wpa_hexdump(MSG_DEBUG, "SAE-PK: Received confirm IEs", ies, ies_len);
- sae_pk = get_vendor_ie(ies, ies_len, SAE_PK_IE_VENDOR_TYPE);
- if (!sae_pk) {
- wpa_printf(MSG_INFO, "SAE-PK: No SAE-PK element included");
- return -1;
- }
- /* TODO: Fragment reassembly */
- pos = sae_pk + 2;
- end = pos + sae_pk[1];
-
- if (end - pos < 4 + 1 + SAE_PK_M_LEN + AES_BLOCK_SIZE) {
- wpa_printf(MSG_INFO,
- "SAE-PK: No room for EncryptedModifier in SAE-PK element");
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_INFO, "SAE-PK: Failed to parse confirm IEs");
return -1;
}
- pos += 4;
- if (*pos != SAE_PK_M_LEN + AES_BLOCK_SIZE) {
+ if (!elems.fils_pk || !elems.fils_key_confirm || !elems.sae_pk) {
wpa_printf(MSG_INFO,
- "SAE-PK: Unexpected EncryptedModifier length %u",
- *pos);
+ "SAE-PK: Not all mandatory IEs included in confirm");
return -1;
}
- pos++;
- encr_mod = pos;
- pos += SAE_PK_M_LEN + AES_BLOCK_SIZE;
- if (end - pos < 4 || pos[0] != WLAN_EID_EXTENSION || pos[1] < 2 ||
- pos[1] > end - pos - 2 ||
- pos[2] != WLAN_EID_EXT_FILS_PUBLIC_KEY) {
- wpa_printf(MSG_INFO,
- "SAE-PK: No FILS Public Key element in SAE-PK element");
- return -1;
- }
- if (pos[3] != 3) {
- wpa_printf(MSG_INFO, "SAE-PK: Unsupported public key type %u",
- pos[3]);
- return -1;
- }
- k_ap_len = pos[1] - 2;
- pos += 4;
- k_ap = pos;
- pos += k_ap_len;
+ /* TODO: Fragment reassembly */
- if (end - pos < 4 || pos[0] != WLAN_EID_EXTENSION || pos[1] < 1 ||
- pos[1] > end - pos - 2 ||
- pos[2] != WLAN_EID_EXT_FILS_KEY_CONFIRM) {
+ if (elems.sae_pk_len < SAE_PK_M_LEN + AES_BLOCK_SIZE) {
wpa_printf(MSG_INFO,
- "SAE-PK: No FILS Key Confirm element in SAE-PK element");
+ "SAE-PK: No room for EncryptedModifier in SAE-PK element");
return -1;
}
- key_auth_len = pos[1] - 1;
- pos += 3;
- key_auth = pos;
- pos += key_auth_len;
-
- if (pos < end) {
- wpa_hexdump(MSG_DEBUG,
- "SAE-PK: Extra data at the end of SAE-PK element",
- pos, end - pos);
- }
wpa_hexdump(MSG_DEBUG, "SAE-PK: EncryptedModifier",
- encr_mod, SAE_PK_M_LEN + AES_BLOCK_SIZE);
+ elems.sae_pk, SAE_PK_M_LEN + AES_BLOCK_SIZE);
if (aes_siv_decrypt(tmp->kek, tmp->kek_len,
- encr_mod, SAE_PK_M_LEN + AES_BLOCK_SIZE,
+ elems.sae_pk, SAE_PK_M_LEN + AES_BLOCK_SIZE,
0, NULL, NULL, m) < 0) {
wpa_printf(MSG_INFO,
"SAE-PK: Failed to decrypt EncryptedModifier");
@@ -601,13 +831,17 @@ int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len)
}
wpa_hexdump_key(MSG_DEBUG, "SAE-PK: Modifier M", m, SAE_PK_M_LEN);
+ if (elems.fils_pk[0] != 2) {
+ wpa_printf(MSG_INFO, "SAE-PK: Unsupported public key type %u",
+ elems.fils_pk[0]);
+ return -1;
+ }
+ k_ap_len = elems.fils_pk_len - 1;
+ k_ap = elems.fils_pk + 1;
wpa_hexdump(MSG_DEBUG, "SAE-PK: Received K_AP", k_ap, k_ap_len);
/* TODO: Check against the public key, if one is stored in the network
* profile */
- if (!sae_pk_valid_fingerprint(sae, m, SAE_PK_M_LEN, k_ap, k_ap_len))
- return -1;
-
key = crypto_ec_key_parse_pub(k_ap, k_ap_len);
if (!key) {
wpa_printf(MSG_INFO, "SAE-PK: Failed to parse K_AP");
@@ -615,20 +849,16 @@ int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len)
}
group = crypto_ec_key_group(key);
- /* TODO: Could support alternative groups as long as the combination
- * meets the requirements. */
- if (group != sae->group) {
- wpa_printf(MSG_INFO,
- "SAE-PK: K_AP group %d does not match SAE group %d",
- group, sae->group);
+ if (!sae_pk_valid_fingerprint(sae, m, SAE_PK_M_LEN, k_ap, k_ap_len,
+ group)) {
crypto_ec_key_deinit(key);
return -1;
}
wpa_hexdump(MSG_DEBUG, "SAE-PK: Received KeyAuth",
- key_auth, key_auth_len);
+ elems.fils_key_confirm, elems.fils_key_confirm_len);
- hash_len = sae_ecc_prime_len_2_hash_len(tmp->prime_len);
+ hash_len = sae_group_2_hash_len(group);
if (sae_pk_hash_sig_data(sae, hash_len, false, m, SAE_PK_M_LEN,
k_ap, k_ap_len, hash) < 0) {
crypto_ec_key_deinit(key);
@@ -636,7 +866,8 @@ int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len)
}
res = crypto_ec_key_verify_signature(key, hash, hash_len,
- key_auth, key_auth_len);
+ elems.fils_key_confirm,
+ elems.fils_key_confirm_len);
crypto_ec_key_deinit(key);
if (res != 1) {
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 488e4ad..4e42c89 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -97,6 +97,10 @@ extern "C" {
"CTRL-EVENT-SAE-UNKNOWN-PASSWORD-IDENTIFIER "
/** Unprotected Beacon frame dropped */
#define WPA_EVENT_UNPROT_BEACON "CTRL-EVENT-UNPROT-BEACON "
+/** Decision made to do a within-ESS roam */
+#define WPA_EVENT_DO_ROAM "CTRL-EVENT-DO-ROAM "
+/** Decision made to skip a within-ESS roam */
+#define WPA_EVENT_SKIP_ROAM "CTRL-EVENT-SKIP-ROAM "
/** IP subnet status change notification
*
@@ -122,6 +126,8 @@ extern "C" {
#define WPA_EVENT_FREQ_CONFLICT "CTRL-EVENT-FREQ-CONFLICT "
/** Frequency ranges that the driver recommends to avoid */
#define WPA_EVENT_AVOID_FREQ "CTRL-EVENT-AVOID-FREQ "
+/** Result of MSCS setup */
+#define WPA_EVENT_MSCS_RESULT "CTRL-EVENT-MSCS-RESULT "
/** WPS overlap detected in PBC mode */
#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
/** Available WPS AP with active PBC found in scan results */
@@ -179,6 +185,9 @@ extern "C" {
#define DPP_EVENT_CONNECTOR "DPP-CONNECTOR "
#define DPP_EVENT_C_SIGN_KEY "DPP-C-SIGN-KEY "
#define DPP_EVENT_NET_ACCESS_KEY "DPP-NET-ACCESS-KEY "
+#define DPP_EVENT_SERVER_NAME "DPP-SERVER-NAME "
+#define DPP_EVENT_CERTBAG "DPP-CERTBAG "
+#define DPP_EVENT_CACERT "DPP-CACERT "
#define DPP_EVENT_MISSING_CONNECTOR "DPP-MISSING-CONNECTOR "
#define DPP_EVENT_NETWORK_ID "DPP-NETWORK-ID "
#define DPP_EVENT_CONFIGURATOR_ID "DPP-CONFIGURATOR-ID "
@@ -192,6 +201,7 @@ extern "C" {
#define DPP_EVENT_CHIRP_STOPPED "DPP-CHIRP-STOPPED "
#define DPP_EVENT_MUD_URL "DPP-MUD-URL "
#define DPP_EVENT_BAND_SUPPORT "DPP-BAND-SUPPORT "
+#define DPP_EVENT_CSR "DPP-CSR "
/* MESH events */
#define MESH_GROUP_STARTED "MESH-GROUP-STARTED "
diff --git a/src/crypto/crypto_module_tests.c b/src/crypto/crypto_module_tests.c
index 1cc73d8..fafb688 100644
--- a/src/crypto/crypto_module_tests.c
+++ b/src/crypto/crypto_module_tests.c
@@ -744,6 +744,155 @@ static int test_key_wrap(void)
}
+static int test_aes_ctr(void)
+{
+ int res = 0;
+
+#if defined(CONFIG_MESH) || defined(CONFIG_PSK)
+ /* CTR-AES*.Encrypt test vectors from NIST SP 800-38a */
+ const u8 key128[] = {
+ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
+ };
+ const u8 counter128[] = {
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+ };
+ const u8 plain128[] = {
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+ 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
+ };
+ const u8 cipher128[] = {
+ 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26,
+ 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
+ 0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff,
+ 0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff,
+ 0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e,
+ 0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab,
+ 0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1,
+ 0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee
+ };
+ const u8 key192[] = {
+ 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52,
+ 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
+ 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b
+ };
+ const u8 counter192[] = {
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+ };
+ const u8 plain192[] = {
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+ 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
+ };
+ const u8 cipher192[] = {
+ 0x1a, 0xbc, 0x93, 0x24, 0x17, 0x52, 0x1c, 0xa2,
+ 0x4f, 0x2b, 0x04, 0x59, 0xfe, 0x7e, 0x6e, 0x0b,
+ 0x09, 0x03, 0x39, 0xec, 0x0a, 0xa6, 0xfa, 0xef,
+ 0xd5, 0xcc, 0xc2, 0xc6, 0xf4, 0xce, 0x8e, 0x94,
+ 0x1e, 0x36, 0xb2, 0x6b, 0xd1, 0xeb, 0xc6, 0x70,
+ 0xd1, 0xbd, 0x1d, 0x66, 0x56, 0x20, 0xab, 0xf7,
+ 0x4f, 0x78, 0xa7, 0xf6, 0xd2, 0x98, 0x09, 0x58,
+ 0x5a, 0x97, 0xda, 0xec, 0x58, 0xc6, 0xb0, 0x50
+ };
+ const u8 key256[] = {
+ 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
+ 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
+ 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7,
+ 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4
+ };
+ const u8 counter256[] = {
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+ };
+ const u8 plain256[] = {
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+ 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
+ };
+ const u8 cipher256[] = {
+ 0x60, 0x1e, 0xc3, 0x13, 0x77, 0x57, 0x89, 0xa5,
+ 0xb7, 0xa7, 0xf5, 0x04, 0xbb, 0xf3, 0xd2, 0x28,
+ 0xf4, 0x43, 0xe3, 0xca, 0x4d, 0x62, 0xb5, 0x9a,
+ 0xca, 0x84, 0xe9, 0x90, 0xca, 0xca, 0xf5, 0xc5,
+ 0x2b, 0x09, 0x30, 0xda, 0xa2, 0x3d, 0xe9, 0x4c,
+ 0xe8, 0x70, 0x17, 0xba, 0x2d, 0x84, 0x98, 0x8d,
+ 0xdf, 0xc9, 0xc5, 0x8d, 0xb6, 0x7a, 0xad, 0xa6,
+ 0x13, 0xc2, 0xdd, 0x08, 0x45, 0x79, 0x41, 0xa6
+ };
+ size_t len;
+ u8 *tmp;
+
+ wpa_printf(MSG_DEBUG, "CTR-AES128.Encrypt");
+ len = sizeof(plain128);
+ tmp = os_malloc(len);
+ if (!tmp)
+ return -1;
+ os_memcpy(tmp, plain128, len);
+ if (aes_ctr_encrypt(key128, sizeof(key128), counter128, tmp, len) < 0) {
+ wpa_printf(MSG_ERROR, "aes_ctr_encrypt() failed");
+ res = -1;
+ } else if (os_memcmp(tmp, cipher128, len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "CTR-AES128.Encrypt test vector did not match");
+ res = -1;
+ }
+ os_free(tmp);
+
+ wpa_printf(MSG_DEBUG, "CTR-AES192.Encrypt");
+ len = sizeof(plain192);
+ tmp = os_malloc(len);
+ if (!tmp)
+ return -1;
+ os_memcpy(tmp, plain192, len);
+ if (aes_ctr_encrypt(key192, sizeof(key192), counter192, tmp, len) < 0) {
+ wpa_printf(MSG_ERROR, "aes_ctr_encrypt() failed");
+ res = -1;
+ } else if (os_memcmp(tmp, cipher192, len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "CTR-AES192.Encrypt test vector did not match");
+ res = -1;
+ }
+ os_free(tmp);
+
+ wpa_printf(MSG_DEBUG, "CTR-AES256.Encrypt");
+ len = sizeof(plain256);
+ tmp = os_malloc(len);
+ if (!tmp)
+ return -1;
+ os_memcpy(tmp, plain256, len);
+ if (aes_ctr_encrypt(key256, sizeof(key256), counter256, tmp, len) < 0) {
+ wpa_printf(MSG_ERROR, "aes_ctr_encrypt() failed");
+ res = -1;
+ } else if (os_memcmp(tmp, cipher256, len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "CTR-AES256.Encrypt test vector did not match");
+ res = -1;
+ }
+ os_free(tmp);
+#endif
+
+ return res;
+}
+
+
static int test_md5(void)
{
#ifndef CONFIG_FIPS
@@ -2154,6 +2303,7 @@ int crypto_module_tests(void)
test_cbc() ||
test_ecb() ||
test_key_wrap() ||
+ test_aes_ctr() ||
test_md5() ||
test_sha1() ||
test_sha256() ||
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 54bfcd2..72f93c1 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -2187,8 +2187,6 @@ size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh)
struct crypto_ec_key {
EVP_PKEY *pkey;
EC_KEY *eckey;
- BIGNUM *kinv;
- BIGNUM *rp;
};
@@ -2215,8 +2213,6 @@ struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len)
goto fail;
}
- if (ECDSA_sign_setup(key->eckey, NULL, &key->kinv, &key->rp) != 1)
- goto fail;
return key;
fail:
crypto_ec_key_deinit(key);
@@ -2253,8 +2249,6 @@ void crypto_ec_key_deinit(struct crypto_ec_key *key)
{
if (key) {
EVP_PKEY_free(key->pkey);
- BN_clear_free(key->kinv);
- BN_clear_free(key->rp);
os_free(key);
}
}
@@ -2282,22 +2276,27 @@ struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key)
struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data,
size_t len)
{
+ EVP_PKEY_CTX *pkctx;
struct wpabuf *sig_der;
- int res;
- unsigned int sig_len;
+ size_t sig_len;
- sig_len = ECDSA_size(key->eckey);
+ sig_len = EVP_PKEY_size(key->pkey);
sig_der = wpabuf_alloc(sig_len);
if (!sig_der)
return NULL;
- res = ECDSA_sign_ex(0, data, len, wpabuf_put(sig_der, 0), &sig_len,
- key->kinv, key->rp, key->eckey);
- if (res != 1) {
+
+ pkctx = EVP_PKEY_CTX_new(key->pkey, NULL);
+ if (!pkctx ||
+ EVP_PKEY_sign_init(pkctx) <= 0 ||
+ EVP_PKEY_sign(pkctx, wpabuf_put(sig_der, 0), &sig_len,
+ data, len) <= 0) {
wpabuf_free(sig_der);
- return NULL;
+ sig_der = NULL;
+ } else {
+ wpabuf_put(sig_der, sig_len);
}
- wpabuf_put(sig_der, sig_len);
+ EVP_PKEY_CTX_free(pkctx);
return sig_der;
}
@@ -2305,15 +2304,21 @@ struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data,
int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data,
size_t len, const u8 *sig, size_t sig_len)
{
+ EVP_PKEY_CTX *pkctx;
int ret;
- ret = ECDSA_verify(0, data, len, sig, sig_len, key->eckey);
+ pkctx = EVP_PKEY_CTX_new(key->pkey, NULL);
+ if (!pkctx || EVP_PKEY_verify_init(pkctx) <= 0) {
+ EVP_PKEY_CTX_free(pkctx);
+ return -1;
+ }
+
+ ret = EVP_PKEY_verify(pkctx, sig, sig_len, data, len);
+ EVP_PKEY_CTX_free(pkctx);
if (ret == 1)
return 1; /* signature ok */
if (ret == 0)
return 0; /* incorrect signature */
- wpa_printf(MSG_INFO, "OpenSSL: ECDSA_verify() failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
return -1;
}
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index c8b1a82..09fb73b 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -670,4 +670,18 @@ int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len);
*/
u16 tls_connection_get_cipher_suite(struct tls_connection *conn);
+/**
+ * tls_connection_get_peer_subject - Get peer subject
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: Peer subject or %NULL if not authenticated or not available
+ */
+const char * tls_connection_get_peer_subject(struct tls_connection *conn);
+
+/**
+ * tls_connection_get_own_cert_used - Was own certificate used
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: true if own certificate was used during authentication
+ */
+bool tls_connection_get_own_cert_used(struct tls_connection *conn);
+
#endif /* TLS_H */
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index a6a4ce4..0f9664e 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -265,6 +265,7 @@ struct tls_connection {
X509 *peer_cert;
X509 *peer_issuer;
X509 *peer_issuer_issuer;
+ char *peer_subject; /* peer subject info for authenticated peer */
unsigned char client_random[SSL3_RANDOM_SIZE];
unsigned char server_random[SSL3_RANDOM_SIZE];
@@ -1629,6 +1630,7 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
os_free(conn->domain_match);
os_free(conn->check_cert_subject);
os_free(conn->session_ticket);
+ os_free(conn->peer_subject);
os_free(conn);
}
@@ -2579,6 +2581,11 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
context->event_cb(context->cb_ctx,
TLS_CERT_CHAIN_SUCCESS, NULL);
+ if (depth == 0 && preverify_ok) {
+ os_free(conn->peer_subject);
+ conn->peer_subject = os_strdup(buf);
+ }
+
return preverify_ok;
}
@@ -3180,7 +3187,11 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
if (conn == NULL)
return -1;
- if (verify_peer) {
+ if (verify_peer == 2) {
+ conn->ca_cert_verify = 1;
+ SSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
+ SSL_VERIFY_CLIENT_ONCE, tls_verify_cb);
+ } else if (verify_peer) {
conn->ca_cert_verify = 1;
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
@@ -3241,8 +3252,31 @@ static int tls_connection_client_cert(struct tls_connection *conn,
"OK");
return 0;
} else if (client_cert_blob) {
+ BIO *bio;
+ X509 *x509;
+
tls_show_errors(MSG_DEBUG, __func__,
"SSL_use_certificate_ASN1 failed");
+ bio = BIO_new(BIO_s_mem());
+ if (!bio)
+ return -1;
+ BIO_write(bio, client_cert_blob, client_cert_blob_len);
+ x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+ if (!x509 || SSL_use_certificate(conn->ssl, x509) != 1) {
+ X509_free(x509);
+ BIO_free(bio);
+ return -1;
+ }
+ X509_free(x509);
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Found PEM encoded certificate from blob");
+ while ((x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL))) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Added an additional certificate into the chain");
+ SSL_add0_chain_cert(conn->ssl, x509);
+ }
+ BIO_free(bio);
+ return 0;
}
if (client_cert == NULL)
@@ -3749,6 +3783,17 @@ static int tls_connection_private_key(struct tls_data *data,
break;
}
+#ifndef OPENSSL_NO_EC
+ if (SSL_use_PrivateKey_ASN1(EVP_PKEY_EC, conn->ssl,
+ (u8 *) private_key_blob,
+ private_key_blob_len) == 1) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: SSL_use_PrivateKey_ASN1(EVP_PKEY_EC) --> OK");
+ ok = 1;
+ break;
+ }
+#endif /* OPENSSL_NO_EC */
+
if (SSL_use_RSAPrivateKey_ASN1(conn->ssl,
(u8 *) private_key_blob,
private_key_blob_len) == 1) {
@@ -5649,3 +5694,19 @@ u16 tls_connection_get_cipher_suite(struct tls_connection *conn)
return SSL_CIPHER_get_id(cipher) & 0xFFFF;
#endif
}
+
+
+const char * tls_connection_get_peer_subject(struct tls_connection *conn)
+{
+ if (conn)
+ return conn->peer_subject;
+ return NULL;
+}
+
+
+bool tls_connection_get_own_cert_used(struct tls_connection *conn)
+{
+ if (conn)
+ return SSL_get_certificate(conn->ssl) != NULL;
+ return false;
+}
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 1e2e332..e8defab 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -197,6 +197,7 @@ struct he_capabilities {
u8 mac_cap[HE_MAX_MAC_CAPAB_SIZE];
u8 mcs[HE_MAX_MCS_CAPAB_SIZE];
u8 ppet[HE_MAX_PPET_CAPAB_SIZE];
+ u16 he_6ghz_capa;
};
#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
@@ -1747,6 +1748,13 @@ struct wpa_driver_capa {
#define WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256 0x00004000
#define WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384 0x00008000
#define WPA_DRIVER_CAPA_KEY_MGMT_SAE 0x00010000
+#define WPA_DRIVER_CAPA_KEY_MGMT_802_1X_SHA256 0x00020000
+#define WPA_DRIVER_CAPA_KEY_MGMT_PSK_SHA256 0x00040000
+#define WPA_DRIVER_CAPA_KEY_MGMT_TPK_HANDSHAKE 0x00080000
+#define WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE 0x00100000
+#define WPA_DRIVER_CAPA_KEY_MGMT_FT_802_1X_SHA384 0x00200000
+#define WPA_DRIVER_CAPA_KEY_MGMT_CCKM 0x00400000
+#define WPA_DRIVER_CAPA_KEY_MGMT_OSEN 0x00800000
/** Bitfield of supported key management suites */
unsigned int key_mgmt;
unsigned int key_mgmt_iftype[WPA_IF_MAX];
@@ -1923,6 +1931,8 @@ struct wpa_driver_capa {
/** Driver supports a separate control port RX for EAPOL frames */
#define WPA_DRIVER_FLAGS2_CONTROL_PORT_RX 0x0000000000000001ULL
+/** Driver supports TX status reports for EAPOL frames through control port */
+#define WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS 0x0000000000000002ULL
u64 flags2;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@@ -4377,13 +4387,13 @@ struct wpa_driver_ops {
int (*ignore_assoc_disallow)(void *priv, int ignore_disallow);
/**
- * set_bssid_blacklist - Set blacklist of BSSIDs to the driver
+ * set_bssid_tmp_disallow - Set disallowed BSSIDs to the driver
* @priv: Private driver interface data
- * @num_bssid: Number of blacklist BSSIDs
- * @bssids: List of blacklisted BSSIDs
+ * @num_bssid: Number of temporarily disallowed BSSIDs
+ * @bssids: List of temporarily disallowed BSSIDs
*/
- int (*set_bssid_blacklist)(void *priv, unsigned int num_bssid,
- const u8 *bssid);
+ int (*set_bssid_tmp_disallow)(void *priv, unsigned int num_bssid,
+ const u8 *bssid);
/**
* update_connect_params - Update the connection parameters
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 23a6a42..a7ebe95 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -328,6 +328,7 @@ const char * driver_flag2_to_string(u64 flag2)
#define DF2S(x) case WPA_DRIVER_FLAGS2_ ## x: return #x
switch (flag2) {
DF2S(CONTROL_PORT_RX);
+ DF2S(CONTROL_PORT_TX_STATUS);
}
return "UNKNOWN";
#undef DF2S
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 72189da..2ee34d1 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -278,6 +278,43 @@ static int ack_handler(struct nl_msg *msg, void *arg)
return NL_STOP;
}
+
+struct nl80211_ack_ext_arg {
+ int *err;
+ void *ext_data;
+};
+
+
+static int ack_handler_cookie(struct nl_msg *msg, void *arg)
+{
+ struct nl80211_ack_ext_arg *ext_arg = arg;
+ struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
+ u64 *cookie = ext_arg->ext_data;
+ struct nlattr *attrs;
+ size_t ack_len, attr_len;
+
+ *ext_arg->err = 0;
+ ack_len = sizeof(struct nlmsghdr) + sizeof(int) +
+ sizeof(struct nlmsghdr);
+ attrs = (struct nlattr *)
+ ((u8 *) nlmsg_data(nlmsg_hdr(msg)) + sizeof(struct nlmsghdr) +
+ sizeof(int));
+ if (nlmsg_hdr(msg)->nlmsg_len <= ack_len)
+ return NL_STOP;
+
+ attr_len = nlmsg_hdr(msg)->nlmsg_len - ack_len;
+
+ if(!(nlmsg_hdr(msg)->nlmsg_flags & NLM_F_ACK_TLVS))
+ return NL_STOP;
+
+ nla_parse(tb, NLMSGERR_ATTR_MAX, attrs, attr_len, NULL);
+ if (tb[NLMSGERR_ATTR_COOKIE])
+ *cookie = nla_get_u64(tb[NLMSGERR_ATTR_COOKIE]);
+
+ return NL_STOP;
+}
+
+
static int finish_handler(struct nl_msg *msg, void *arg)
{
int *ret = arg;
@@ -352,7 +389,9 @@ static void nl80211_nlmsg_clear(struct nl_msg *msg)
static int send_and_recv(struct nl80211_global *global,
struct nl_sock *nl_handle, struct nl_msg *msg,
int (*valid_handler)(struct nl_msg *, void *),
- void *valid_data)
+ void *valid_data,
+ int (*ack_handler_custom)(struct nl_msg *, void *),
+ void *ack_data)
{
struct nl_cb *cb;
int err = -ENOMEM, opt;
@@ -390,7 +429,15 @@ static int send_and_recv(struct nl80211_global *global,
nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
- nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
+ if (ack_handler_custom) {
+ struct nl80211_ack_ext_arg *ext_arg = ack_data;
+
+ ext_arg->err = &err;
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM,
+ ack_handler_custom, ack_data);
+ } else {
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
+ }
if (valid_handler)
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
@@ -430,10 +477,13 @@ static int send_and_recv(struct nl80211_global *global,
int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
struct nl_msg *msg,
int (*valid_handler)(struct nl_msg *, void *),
- void *valid_data)
+ void *valid_data,
+ int (*ack_handler_custom)(struct nl_msg *, void *),
+ void *ack_data)
{
return send_and_recv(drv->global, drv->global->nl, msg,
- valid_handler, valid_data);
+ valid_handler, valid_data,
+ ack_handler_custom, ack_data);
}
@@ -447,7 +497,10 @@ static int send_and_recv_msgs_owner(struct wpa_driver_nl80211_data *drv,
struct nl_sock *handle, int set_owner,
int (*valid_handler)(struct nl_msg *,
void *),
- void *valid_data)
+ void *valid_data,
+ int (*ack_handler_custom)(struct nl_msg *,
+ void *),
+ void *ack_data)
{
/* Control port over nl80211 needs the flags and attributes below.
*
@@ -469,7 +522,8 @@ static int send_and_recv_msgs_owner(struct wpa_driver_nl80211_data *drv,
return -1;
return send_and_recv(drv->global, handle ? handle : drv->global->nl,
- msg, valid_handler, valid_data);
+ msg, valid_handler, valid_data,
+ ack_handler_custom, ack_data);
}
@@ -537,7 +591,8 @@ static int nl_get_multicast_id(struct nl80211_global *global,
return -1;
}
- ret = send_and_recv(global, global->nl, msg, family_handler, &res);
+ ret = send_and_recv(global, global->nl, msg, family_handler, &res,
+ NULL, NULL);
if (ret == 0)
ret = res.id;
return ret;
@@ -654,7 +709,8 @@ int nl80211_get_wiphy_index(struct i802_bss *bss)
if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
return -1;
- if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
+ if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
+ NULL, NULL) == 0)
return data.wiphy_idx;
return -1;
}
@@ -671,7 +727,8 @@ static enum nl80211_iftype nl80211_get_ifmode(struct i802_bss *bss)
if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
return NL80211_IFTYPE_UNSPECIFIED;
- if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
+ if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
+ NULL, NULL) == 0)
return data.nlmode;
return NL80211_IFTYPE_UNSPECIFIED;
}
@@ -687,7 +744,8 @@ static int nl80211_get_macaddr(struct i802_bss *bss)
if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
return -1;
- return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data);
+ return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
+ NULL, NULL);
}
@@ -707,7 +765,8 @@ static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
return -1;
}
- ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL);
+ ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL,
+ NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
"failed: ret=%d (%s)",
@@ -1403,7 +1462,7 @@ try_again:
os_memset(&arg, 0, sizeof(arg));
arg.drv = drv;
ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
- &arg);
+ &arg, NULL, NULL);
if (ret == -EAGAIN) {
count++;
if (count >= 10) {
@@ -1437,7 +1496,7 @@ try_again:
os_memset(&arg, 0, sizeof(arg));
arg.drv = drv;
ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
- &arg);
+ &arg, NULL, NULL);
if (ret == -EAGAIN) {
count++;
if (count >= 10) {
@@ -1540,7 +1599,7 @@ int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
return -ENOBUFS;
}
- return send_and_recv_msgs(drv, msg, get_link_signal, sig);
+ return send_and_recv_msgs(drv, msg, get_link_signal, sig, NULL, NULL);
}
@@ -1597,7 +1656,8 @@ int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
sig_change->frequency = drv->assoc_freq;
msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
- return send_and_recv_msgs(drv, msg, get_link_noise, sig_change);
+ return send_and_recv_msgs(drv, msg, get_link_noise, sig_change,
+ NULL, NULL);
}
@@ -1661,7 +1721,7 @@ static int nl80211_channel_info(void *priv, struct wpa_channel_info *ci)
struct nl_msg *msg;
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
- return send_and_recv_msgs(drv, msg, get_channel_info, ci);
+ return send_and_recv_msgs(drv, msg, get_channel_info, ci, NULL, NULL);
}
@@ -1710,7 +1770,7 @@ static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
nlmsg_free(msg);
return -EINVAL;
}
- if (send_and_recv_msgs(drv, msg, NULL, NULL))
+ if (send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL))
return -EINVAL;
return 0;
}
@@ -1746,7 +1806,8 @@ static int wpa_driver_nl80211_get_country(void *priv, char *alpha2)
nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
alpha2[0] = '\0';
- ret = send_and_recv_msgs(drv, msg, nl80211_get_country, alpha2);
+ ret = send_and_recv_msgs(drv, msg, nl80211_get_country, alpha2,
+ NULL, NULL);
if (!alpha2[0])
ret = -1;
@@ -2111,6 +2172,11 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1, driver_params))
goto failed;
+ if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS) {
+ drv->control_port_ap = 1;
+ goto skip_wifi_status;
+ }
+
drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
if (drv->eapol_tx_sock < 0)
goto failed;
@@ -2121,17 +2187,20 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
&enabled, sizeof(enabled)) < 0) {
wpa_printf(MSG_DEBUG,
- "nl80211: wifi status sockopt failed\n");
+ "nl80211: wifi status sockopt failed: %s",
+ strerror(errno));
drv->data_tx_status = 0;
if (!drv->use_monitor)
drv->capa.flags &=
~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
} else {
- eloop_register_read_sock(drv->eapol_tx_sock,
+ eloop_register_read_sock(
+ drv->eapol_tx_sock,
wpa_driver_nl80211_handle_eapol_tx_status,
drv, NULL);
}
}
+skip_wifi_status:
if (drv->global) {
nl80211_check_global(drv->global);
@@ -2187,7 +2256,8 @@ static int nl80211_register_frame(struct i802_bss *bss,
return -1;
}
- ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL);
+ ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL,
+ NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
"failed (type=%u): ret=%d (%s)",
@@ -2381,6 +2451,10 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
(nl80211_register_action_frame(bss, (u8 *) "\x05\x02", 2) < 0))
ret = -1;
+ /* Robust AV MSCS Response */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x13\x05", 2) < 0)
+ ret = -1;
+
nl80211_mgmt_handle_register_eloop(bss);
return ret;
@@ -2427,7 +2501,8 @@ static int nl80211_register_spurious_class3(struct i802_bss *bss)
int ret;
msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UNEXPECTED_FRAME);
- ret = send_and_recv(bss->drv->global, bss->nl_mgmt, msg, NULL, NULL);
+ ret = send_and_recv(bss->drv->global, bss->nl_mgmt, msg, NULL, NULL,
+ NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
"failed: ret=%d (%s)",
@@ -2581,7 +2656,7 @@ static void nl80211_del_p2pdev(struct i802_bss *bss)
int ret;
msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_INTERFACE);
- ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
bss->ifname, (long long unsigned int) bss->wdev_id,
@@ -2596,7 +2671,7 @@ static int nl80211_set_p2pdev(struct i802_bss *bss, int start)
msg = nl80211_cmd_msg(bss, 0, start ? NL80211_CMD_START_P2P_DEVICE :
NL80211_CMD_STOP_P2P_DEVICE);
- ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
start ? "Start" : "Stop",
@@ -2667,7 +2742,8 @@ static void qca_vendor_test(struct wpa_driver_nl80211_data *drv)
}
nla_nest_end(msg, params);
- ret = send_and_recv_msgs(drv, msg, qca_vendor_test_cmd_handler, drv);
+ ret = send_and_recv_msgs(drv, msg, qca_vendor_test_cmd_handler, drv,
+ NULL, NULL);
wpa_printf(MSG_DEBUG,
"nl80211: QCA vendor test command returned %d (%s)",
ret, strerror(-ret));
@@ -2792,7 +2868,7 @@ static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss)
drv->ifindex);
nl80211_put_wiphy_data_ap(bss);
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON);
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
@@ -3054,7 +3130,7 @@ static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
nlmsg_free(msg);
return -1;
}
- ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
+ ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG,
"nl80211: Key management set key failed: ret=%d (%s)",
@@ -3094,7 +3170,7 @@ static int nl80211_set_pmk(struct wpa_driver_nl80211_data *drv,
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
+ ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Set PMK failed: ret=%d (%s)",
ret, strerror(-ret));
@@ -3260,7 +3336,8 @@ static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
goto fail;
}
- ret = send_and_recv_msgs(drv, msg, NULL, key ? (void *) -1 : NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, key ? (void *) -1 : NULL,
+ NULL, NULL);
if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
ret = 0;
if (ret)
@@ -3322,7 +3399,7 @@ static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
goto fail;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret)
wpa_printf(MSG_DEBUG,
"nl80211: set_key default failed; err=%d %s",
@@ -3446,9 +3523,10 @@ int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
}
if (nl_connect)
- ret = send_and_recv(drv->global, nl_connect, msg, NULL, NULL);
+ ret = send_and_recv(drv->global, nl_connect, msg, NULL, NULL,
+ NULL, NULL);
else
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_dbg(drv->ctx, MSG_DEBUG,
"nl80211: MLME command failed: reason=%u ret=%d (%s)",
@@ -3696,7 +3774,7 @@ retry:
goto fail;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_dbg(drv->ctx, MSG_DEBUG,
@@ -3974,7 +4052,7 @@ static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
return -ENOBUFS;
}
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
@@ -4018,7 +4096,7 @@ static int wpa_driver_nl80211_set_acl(void *priv,
}
nlmsg_free(acl);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)",
ret, strerror(-ret));
@@ -4070,7 +4148,7 @@ static int nl80211_set_mesh_config(void *priv,
return ret;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_ERROR,
"nl80211: Mesh config set failed: %d (%s)",
@@ -4195,7 +4273,7 @@ static int nl80211_set_multicast_to_unicast(struct i802_bss *bss,
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
switch (ret) {
case 0:
@@ -4484,7 +4562,7 @@ static int wpa_driver_nl80211_set_ap(void *priv,
#endif /* CONFIG_IEEE80211AX */
ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 1,
- NULL, NULL);
+ NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
ret, strerror(-ret));
@@ -4653,7 +4731,7 @@ static int nl80211_set_channel(struct i802_bss *bss,
return -1;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret == 0) {
bss->freq = freq->freq;
return 0;
@@ -4931,7 +5009,7 @@ static int wpa_driver_nl80211_sta_add(void *priv,
nla_nest_end(msg, wme);
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
@@ -5003,7 +5081,7 @@ static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr,
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR
" --> %d (%s)",
bss->ifname, MAC2STR(addr), ret, strerror(-ret));
@@ -5034,7 +5112,7 @@ void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx)
}
msg = nl80211_ifindex_msg(drv, ifidx, 0, NL80211_CMD_DEL_INTERFACE);
- if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
+ if (send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL) == 0)
return;
wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
}
@@ -5114,7 +5192,7 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
goto fail;
- ret = send_and_recv_msgs(drv, msg, handler, arg);
+ ret = send_and_recv_msgs(drv, msg, handler, arg, NULL, NULL);
msg = NULL;
if (ret) {
fail:
@@ -5269,8 +5347,10 @@ static int nl80211_tx_control_port(void *priv, const u8 *dest,
u16 proto, const u8 *buf, size_t len,
int no_encrypt)
{
+ struct nl80211_ack_ext_arg ext_arg;
struct i802_bss *bss = priv;
struct nl_msg *msg;
+ u64 cookie = 0;
int ret;
wpa_printf(MSG_DEBUG,
@@ -5289,11 +5369,22 @@ static int nl80211_tx_control_port(void *priv, const u8 *dest,
return -ENOBUFS;
}
- ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
- if (ret)
+ os_memset(&ext_arg, 0, sizeof(struct nl80211_ack_ext_arg));
+ ext_arg.ext_data = &cookie;
+ ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL,
+ ack_handler_cookie, &ext_arg);
+ if (ret) {
wpa_printf(MSG_DEBUG,
"nl80211: tx_control_port failed: ret=%d (%s)",
ret, strerror(-ret));
+ } else {
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: tx_control_port cookie=0x%llx",
+ (long long unsigned int) cookie);
+ drv->eapol_tx_cookie = cookie;
+ }
return ret;
}
@@ -5445,7 +5536,7 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
goto fail;
- return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
fail:
nlmsg_free(msg);
return -ENOBUFS;
@@ -5467,7 +5558,7 @@ static int driver_nl80211_sta_set_airtime_weight(void *priv, const u8 *addr,
nla_put_u16(msg, NL80211_ATTR_AIRTIME_WEIGHT, weight))
goto fail;
- return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
fail:
nlmsg_free(msg);
return -ENOBUFS;
@@ -5513,7 +5604,7 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_IBSS);
ret = send_and_recv_msgs_owner(drv, msg,
get_connect_handle(drv->first_bss), 1,
- NULL, NULL);
+ NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
"(%s)", ret, strerror(-ret));
@@ -5647,7 +5738,7 @@ retry:
ret = send_and_recv_msgs_owner(drv, msg,
get_connect_handle(drv->first_bss), 1,
- NULL, NULL);
+ NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
@@ -5694,13 +5785,13 @@ static int nl80211_put_fils_connect_params(struct wpa_driver_nl80211_data *drv,
return -1;
}
- wpa_printf(MSG_DEBUG, " * FILS ERP next seq %u",
- params->fils_erp_next_seq_num);
- if (nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
- params->fils_erp_next_seq_num))
- return -1;
-
if (params->fils_erp_rrk_len) {
+ wpa_printf(MSG_DEBUG, " * FILS ERP next seq %u",
+ params->fils_erp_next_seq_num);
+ if (nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
+ params->fils_erp_next_seq_num))
+ return -1;
+
wpa_printf(MSG_DEBUG, " * FILS ERP rRK (len=%lu)",
(unsigned long) params->fils_erp_rrk_len);
if (nla_put(msg, NL80211_ATTR_FILS_ERP_RRK,
@@ -6049,7 +6140,7 @@ skip_auth_type:
goto fail;
ret = send_and_recv_msgs_owner(drv, msg, nl_connect, 1, NULL,
- (void *) -1);
+ (void *) -1, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
@@ -6165,7 +6256,7 @@ static int wpa_driver_nl80211_associate(
ret = send_and_recv_msgs_owner(drv, msg,
get_connect_handle(drv->first_bss), 1,
- NULL, NULL);
+ NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_dbg(drv->ctx, MSG_DEBUG,
@@ -6196,7 +6287,7 @@ static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
if (!msg || nla_put_u32(msg, NL80211_ATTR_IFTYPE, mode))
goto fail;
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (!ret)
return 0;
@@ -6457,7 +6548,7 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (!ret)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: Failed to set STA flag: %d (%s)",
@@ -6522,7 +6613,7 @@ static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
memset(seq, 0, 6);
- return send_and_recv_msgs(drv, msg, get_key_handler, seq);
+ return send_and_recv_msgs(drv, msg, get_key_handler, seq, NULL, NULL);
}
@@ -6545,7 +6636,7 @@ static int i802_set_rts(void *priv, int rts)
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (!ret)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
@@ -6573,7 +6664,7 @@ static int i802_set_frag(void *priv, int frag)
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (!ret)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
@@ -6595,7 +6686,7 @@ static int i802_flush(void *priv)
* XXX: FIX! this needs to flush all VLANs too
*/
msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION);
- res = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ res = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
if (res) {
wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
"(%s)", res, strerror(-res));
@@ -6804,7 +6895,8 @@ static int i802_read_sta_data(struct i802_bss *bss,
return -ENOBUFS;
}
- return send_and_recv_msgs(bss->drv, msg, get_sta_handler, data);
+ return send_and_recv_msgs(bss->drv, msg, get_sta_handler, data,
+ NULL, NULL);
}
@@ -6861,7 +6953,7 @@ static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
nla_nest_end(msg, txq);
- res = send_and_recv_msgs(drv, msg, NULL, NULL);
+ res = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
wpa_printf(MSG_DEBUG,
"nl80211: TX queue param set: queue=%d aifs=%d cw_min=%d cw_max=%d burst_time=%d --> res=%d",
queue, aifs, cw_min, cw_max, burst_time, res);
@@ -6887,14 +6979,14 @@ static int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr,
MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id);
if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
- ((drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD) &&
+ (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD) &&
nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id)) ||
nla_put_u32(msg, NL80211_ATTR_STA_VLAN, if_nametoindex(ifname))) {
nlmsg_free(msg);
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret < 0) {
wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
@@ -7741,7 +7833,7 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
goto fail;
cookie = 0;
- ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
+ ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d "
@@ -7848,7 +7940,7 @@ static void nl80211_frame_wait_cancel(struct i802_bss *bss, u64 cookie)
return;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d "
"(%s)", ret, strerror(-ret));
@@ -7896,7 +7988,7 @@ static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
}
cookie = 0;
- ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
+ ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL);
if (ret == 0) {
wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
"0x%llx for freq=%u MHz duration=%u",
@@ -7936,7 +8028,7 @@ static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
return -1;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret == 0)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
@@ -8033,7 +8125,7 @@ static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
nla_nest_end(msg, bands);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
"(%s)", ret, strerror(-ret));
@@ -8130,7 +8222,7 @@ static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
}
nla_nest_end(msg, cqm);
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
@@ -8168,7 +8260,7 @@ static int nl80211_get_channel_width(struct wpa_driver_nl80211_data *drv,
struct nl_msg *msg;
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
- return send_and_recv_msgs(drv, msg, get_channel_width, sig);
+ return send_and_recv_msgs(drv, msg, get_channel_width, sig, NULL, NULL);
}
@@ -8231,12 +8323,19 @@ static int nl80211_set_param(void *priv, const char *param)
if (os_strstr(param, "control_port=0")) {
drv->capa.flags &= ~WPA_DRIVER_FLAGS_CONTROL_PORT;
- drv->capa.flags2 &= ~WPA_DRIVER_FLAGS2_CONTROL_PORT_RX;
+ drv->capa.flags2 &= ~(WPA_DRIVER_FLAGS2_CONTROL_PORT_RX |
+ WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS);
+ drv->control_port_ap = 0;
}
if (os_strstr(param, "control_port_ap=1"))
drv->control_port_ap = 1;
+ if (os_strstr(param, "control_port_ap=0")) {
+ drv->capa.flags2 &= ~WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS;
+ drv->control_port_ap = 0;
+ }
+
if (os_strstr(param, "full_ap_client_state=0"))
drv->capa.flags &= ~WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE;
@@ -8366,7 +8465,7 @@ static int nl80211_pmkid(struct i802_bss *bss, int cmd,
return -ENOBUFS;
}
- return send_and_recv_msgs(bss->drv, msg, NULL, (void *) -1);
+ return send_and_recv_msgs(bss->drv, msg, NULL, (void *) -1, NULL, NULL);
}
@@ -8431,7 +8530,7 @@ static int nl80211_flush_pmkid(void *priv)
msg = nl80211_bss_msg(bss, 0, NL80211_CMD_FLUSH_PMKSA);
if (!msg)
return -ENOBUFS;
- return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
}
@@ -8596,7 +8695,7 @@ static int wpa_driver_nl80211_get_survey(void *priv, unsigned int freq)
do {
wpa_printf(MSG_DEBUG, "nl80211: Fetch survey data");
err = send_and_recv_msgs(drv, msg, survey_handler,
- survey_results);
+ survey_results, NULL, NULL);
} while (err > 0);
if (err)
@@ -8636,7 +8735,7 @@ static void nl80211_set_rekey_info(void *priv, const u8 *kek, size_t kek_len,
nla_nest_end(msg, replay_nested);
- ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
+ ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1, NULL, NULL);
if (ret == -EOPNOTSUPP) {
wpa_printf(MSG_DEBUG,
"nl80211: Driver does not support rekey offload");
@@ -8703,7 +8802,7 @@ static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
return;
}
- ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
+ ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "nl80211: Client probe request for "
MACSTR " failed: ret=%d (%s)",
@@ -8729,7 +8828,7 @@ static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
return -ENOBUFS;
}
- ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
if (ret < 0) {
wpa_printf(MSG_DEBUG,
"nl80211: Setting PS state %s failed: %d (%s)",
@@ -8789,7 +8888,7 @@ static int nl80211_start_radar_detection(void *priv,
return -1;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret == 0)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
@@ -8836,7 +8935,7 @@ static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
nla_put(msg, NL80211_ATTR_IE, len, buf))
goto fail;
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
fail:
nlmsg_free(msg);
@@ -8886,7 +8985,7 @@ static int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer)
return -ENOBUFS;
}
- res = send_and_recv_msgs(drv, msg, NULL, NULL);
+ res = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
wpa_printf(MSG_DEBUG, "nl80211: TDLS_OPER: oper=%d mac=" MACSTR
" --> res=%d (%s)", nl80211_oper, MAC2STR(peer), res,
strerror(-res));
@@ -8920,7 +9019,7 @@ nl80211_tdls_enable_channel_switch(void *priv, const u8 *addr, u8 oper_class,
return ret;
}
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
@@ -8946,7 +9045,7 @@ nl80211_tdls_disable_channel_switch(void *priv, const u8 *addr)
return -ENOBUFS;
}
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
#endif /* CONFIG TDLS */
@@ -9089,7 +9188,7 @@ static int wpa_driver_nl80211_update_ft_ies(void *priv, const u8 *md,
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: update_ft_ies failed "
"err=%d (%s)", ret, strerror(-ret));
@@ -9117,7 +9216,7 @@ static int nl80211_update_dh_ie(void *priv, const u8 *peer_mac,
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG,
"nl80211: update_dh_ie failed err=%d (%s)",
@@ -9322,7 +9421,7 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG) &&
nla_put_u32(msg, NL80211_ATTR_WIPHY, drv->wiphy_idx) == 0) {
if (send_and_recv_msgs(drv, msg, nl80211_get_country,
- alpha2) == 0 &&
+ alpha2, NULL, NULL) == 0 &&
alpha2[0]) {
res = os_snprintf(pos, end - pos, "country=%s\n",
alpha2);
@@ -9473,7 +9572,7 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
goto fail;
nla_nest_end(msg, beacon_csa);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: switch_channel failed err=%d (%s)",
ret, strerror(-ret));
@@ -9514,7 +9613,7 @@ static int nl80211_add_ts(void *priv, u8 tsid, const u8 *addr,
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: add_ts failed err=%d (%s)",
ret, strerror(-ret));
@@ -9541,7 +9640,7 @@ static int nl80211_del_ts(void *priv, u8 tsid, const u8 *addr)
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: del_ts failed err=%d (%s)",
ret, strerror(-ret));
@@ -9626,7 +9725,8 @@ static int nl80211_vendor_cmd(void *priv, unsigned int vendor_id,
* of send_and_recv_msgs(). */
ret = send_and_recv_msgs_owner(drv, msg,
get_connect_handle(bss), 0,
- cmd_reply_handler, buf);
+ cmd_reply_handler, buf,
+ NULL, NULL);
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: command failed err=%d",
ret);
@@ -9641,7 +9741,8 @@ static int nl80211_vendor_cmd(void *priv, unsigned int vendor_id,
nla_put(msg, NL80211_ATTR_VENDOR_DATA, data_len, data)))
goto fail;
- ret = send_and_recv_msgs(drv, msg, vendor_reply_handler, buf);
+ ret = send_and_recv_msgs(drv, msg, vendor_reply_handler, buf,
+ NULL, NULL);
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: vendor command failed err=%d",
ret);
@@ -9670,7 +9771,7 @@ static int nl80211_set_qos_map(void *priv, const u8 *qos_map_set,
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: Setting QoS Map failed");
@@ -9705,7 +9806,8 @@ static int nl80211_get_wowlan(void *priv)
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_WOWLAN);
- ret = send_and_recv_msgs(drv, msg, get_wowlan_handler, &wowlan_enabled);
+ ret = send_and_recv_msgs(drv, msg, get_wowlan_handler, &wowlan_enabled,
+ NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status failed");
return 0;
@@ -9752,7 +9854,7 @@ static int nl80211_set_wowlan(void *priv,
nla_nest_end(msg, wowlan_triggers);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan failed");
@@ -9791,7 +9893,7 @@ static int nl80211_roaming(void *priv, int allowed, const u8 *bssid)
}
nla_nest_end(msg, params);
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
@@ -9819,15 +9921,15 @@ static int nl80211_disable_fils(void *priv, int disable)
}
nla_nest_end(msg, params);
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
/* Reserved QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID value for wpa_supplicant */
#define WPA_SUPPLICANT_CLIENT_ID 1
-static int nl80211_set_bssid_blacklist(void *priv, unsigned int num_bssid,
- const u8 *bssid)
+static int nl80211_set_bssid_tmp_disallow(void *priv, unsigned int num_bssid,
+ const u8 *bssid)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -9835,7 +9937,8 @@ static int nl80211_set_bssid_blacklist(void *priv, unsigned int num_bssid,
struct nlattr *params, *nlbssids, *attr;
unsigned int i;
- wpa_printf(MSG_DEBUG, "nl80211: Set blacklist BSSID (num=%u)",
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Set temporarily disallowed BSSIDs (num=%u)",
num_bssid);
if (!drv->roam_vendor_cmd_avail)
@@ -9875,7 +9978,7 @@ static int nl80211_set_bssid_blacklist(void *priv, unsigned int num_bssid,
nla_nest_end(msg, nlbssids);
nla_nest_end(msg, params);
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
fail:
nlmsg_free(msg);
@@ -9913,7 +10016,7 @@ static int nl80211_add_sta_node(void *priv, const u8 *addr, u16 auth_alg)
}
nla_nest_end(msg, params);
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
#endif /* CONFIG_DRIVER_NL80211_QCA */
@@ -10082,7 +10185,7 @@ static int nl80211_join_mesh(struct i802_bss *bss,
goto fail;
ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 1,
- NULL, NULL);
+ NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d (%s)",
@@ -10140,7 +10243,7 @@ static int wpa_driver_nl80211_leave_mesh(void *priv)
wpa_printf(MSG_DEBUG, "nl80211: mesh leave (ifindex=%d)", drv->ifindex);
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_MESH);
ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 0,
- NULL, NULL);
+ NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d (%s)",
ret, strerror(-ret));
@@ -10174,7 +10277,7 @@ static int nl80211_probe_mesh_link(void *priv, const u8 *addr, const u8 *eth,
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: mesh link probe to " MACSTR
" failed: ret=%d (%s)",
@@ -10586,7 +10689,7 @@ static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
params->hw_mode, params->ht_enabled, params->ht40_enabled,
params->vht_enabled, params->ch_width, params->edmg_enabled);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG,
"nl80211: Failed to invoke driver ACS function: %s",
@@ -10633,7 +10736,7 @@ static int nl80211_set_band(void *priv, enum set_band band)
}
nla_nest_end(msg, data);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG,
"nl80211: Driver setband function failed: %s",
@@ -10766,7 +10869,8 @@ static int nl80211_get_pref_freq_list(void *priv,
nla_nest_end(msg, params);
os_memset(freq_list, 0, *num * sizeof(freq_list[0]));
- ret = send_and_recv_msgs(drv, msg, preferred_freq_info_handler, &param);
+ ret = send_and_recv_msgs(drv, msg, preferred_freq_info_handler, &param,
+ NULL, NULL);
if (ret) {
wpa_printf(MSG_ERROR,
"%s: err in send_and_recv_msgs", __func__);
@@ -10818,7 +10922,7 @@ static int nl80211_set_prob_oper_freq(void *priv, unsigned int freq)
}
nla_nest_end(msg, params);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_ERROR, "%s: err in send_and_recv_msgs",
@@ -10874,7 +10978,7 @@ static int nl80211_p2p_lo_start(void *priv, unsigned int freq,
goto fail;
nla_nest_end(msg, container);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG,
@@ -10909,7 +11013,7 @@ static int nl80211_p2p_lo_stop(void *priv)
return -1;
}
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
@@ -10948,7 +11052,7 @@ static int nl80211_set_tdls_mode(void *priv, int tdls_external_control)
nla_nest_end(msg, params);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_ERROR,
@@ -11141,7 +11245,7 @@ nl80211_get_bss_transition_status(void *priv, struct wpa_bss_trans_info *params)
ret = send_and_recv_msgs(drv, msg,
nl80211_get_bss_transition_status_handler,
- info);
+ info, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_ERROR,
@@ -11194,7 +11298,7 @@ static int nl80211_ignore_assoc_disallow(void *priv, int ignore_disallow)
nla_nest_end(msg, attr);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_ERROR,
@@ -11397,7 +11501,7 @@ static int nl80211_update_connection_params(
nl80211_put_fils_connect_params(drv, params, msg))
goto fail;
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret)
wpa_dbg(drv->ctx, MSG_DEBUG,
@@ -11440,7 +11544,7 @@ static int nl80211_send_external_auth_status(void *priv,
(params->bssid &&
nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid)))
goto fail;
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG,
@@ -11480,7 +11584,7 @@ static int nl80211_set_4addr_mode(void *priv, const char *bridge_ifname,
bss->added_if_into_bridge = 0;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (!ret) {
if (bridge_ifname[0] && val &&
@@ -11646,7 +11750,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.get_bss_transition_status = nl80211_get_bss_transition_status,
.ignore_assoc_disallow = nl80211_ignore_assoc_disallow,
#endif /* CONFIG_MBO */
- .set_bssid_blacklist = nl80211_set_bssid_blacklist,
+ .set_bssid_tmp_disallow = nl80211_set_bssid_tmp_disallow,
.add_sta_node = nl80211_add_sta_node,
#endif /* CONFIG_DRIVER_NL80211_QCA */
.configure_data_frame_filters = nl80211_configure_data_frame_filters,
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 1dd5aee..017c025 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -181,6 +181,7 @@ struct wpa_driver_nl80211_data {
#define MAX_SEND_FRAME_COOKIES 20
u64 send_frame_cookies[MAX_SEND_FRAME_COOKIES];
unsigned int num_send_frame_cookies;
+ u64 eapol_tx_cookie;
unsigned int last_mgmt_freq;
@@ -231,7 +232,9 @@ struct nl_msg * nl80211_drv_msg(struct wpa_driver_nl80211_data *drv, int flags,
struct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd);
int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg,
int (*valid_handler)(struct nl_msg *, void *),
- void *valid_data);
+ void *valid_data,
+ int (*ack_handler_custom)(struct nl_msg *, void *),
+ void *ack_data);
struct nl_sock * get_connect_handle(struct i802_bss *bss);
int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
const char *ifname, enum nl80211_iftype iftype,
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index a3341a0..46f61fd 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -49,7 +49,8 @@ static u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv)
return 0;
}
- if (send_and_recv_msgs(drv, msg, protocol_feature_handler, &feat) == 0)
+ if (send_and_recv_msgs(drv, msg, protocol_feature_handler, &feat,
+ NULL, NULL) == 0)
return feat;
return 0;
@@ -281,6 +282,27 @@ static unsigned int get_akm_suites_info(struct nlattr *tb)
case RSN_AUTH_KEY_MGMT_FT_PSK:
key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
break;
+ case RSN_AUTH_KEY_MGMT_802_1X_SHA256:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_802_1X_SHA256;
+ break;
+ case RSN_AUTH_KEY_MGMT_PSK_SHA256:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_PSK_SHA256;
+ break;
+ case RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_TPK_HANDSHAKE;
+ break;
+ case RSN_AUTH_KEY_MGMT_FT_SAE:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE;
+ break;
+ case RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_802_1X_SHA384;
+ break;
+ case RSN_AUTH_KEY_MGMT_CCKM:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_CCKM;
+ break;
+ case RSN_AUTH_KEY_MGMT_OSEN:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_OSEN;
+ break;
case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B:
key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B;
break;
@@ -598,6 +620,10 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH))
capa->flags2 |= WPA_DRIVER_FLAGS2_CONTROL_PORT_RX;
+ if (ext_feature_isset(
+ ext_features, len,
+ NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS))
+ capa->flags2 |= WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS;
if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_VLAN_OFFLOAD))
@@ -1031,7 +1057,7 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
return -1;
}
- if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
+ if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info, NULL, NULL))
return -1;
if (info->auth_supported)
@@ -1137,7 +1163,8 @@ static void qca_nl80211_check_dfs_capa(struct wpa_driver_nl80211_data *drv)
return;
}
- ret = send_and_recv_msgs(drv, msg, dfs_info_handler, &dfs_capability);
+ ret = send_and_recv_msgs(drv, msg, dfs_info_handler, &dfs_capability,
+ NULL, NULL);
if (!ret && dfs_capability)
drv->capa.flags |= WPA_DRIVER_FLAGS_DFS_OFFLOAD;
}
@@ -1224,7 +1251,8 @@ static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv)
os_memset(&info, 0, sizeof(info));
info.capa = &drv->capa;
- ret = send_and_recv_msgs(drv, msg, features_info_handler, &info);
+ ret = send_and_recv_msgs(drv, msg, features_info_handler, &info,
+ NULL, NULL);
if (ret || !info.flags)
return;
@@ -1769,6 +1797,13 @@ static void phy_info_iftype_copy(struct he_capabilities *he_capab,
nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]),
len);
}
+
+ if (tb[NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA]) {
+ u16 capa;
+
+ capa = nla_get_u16(tb[NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA]);
+ he_capab->he_6ghz_capa = le_to_host16(capa);
+ }
}
@@ -2299,7 +2334,8 @@ static int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data *drv,
}
}
- return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
+ return send_and_recv_msgs(drv, msg, nl80211_get_reg, results,
+ NULL, NULL);
}
@@ -2388,7 +2424,8 @@ nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags,
return NULL;
}
- if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
+ if (send_and_recv_msgs(drv, msg, phy_info_handler, &result,
+ NULL, NULL) == 0) {
struct hostapd_hw_modes *modes;
nl80211_set_regulatory_flags(drv, &result);
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 6a2de1f..ce95e9c 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -20,6 +20,12 @@
#include "driver_nl80211.h"
+static void
+nl80211_control_port_frame_tx_status(struct wpa_driver_nl80211_data *drv,
+ const u8 *frame, size_t len,
+ struct nlattr *ack, struct nlattr *cookie);
+
+
static const char * nl80211_command_to_string(enum nl80211_commands cmd)
{
#define C2S(x) case x: return #x;
@@ -138,6 +144,8 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd)
C2S(NL80211_CMD_CONTROL_PORT_FRAME)
C2S(NL80211_CMD_UPDATE_OWE_INFO)
C2S(NL80211_CMD_UNPROT_BEACON)
+ C2S(NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS)
+
default:
return "NL80211_CMD_UNKNOWN";
}
@@ -698,6 +706,16 @@ static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
WLAN_FC_GET_STYPE(fc), (long long unsigned int) cookie_val,
cookie ? "" : "(N/A)", ack != NULL);
+ if (cookie_val && cookie_val == drv->eapol_tx_cookie &&
+ len >= ETH_HLEN &&
+ WPA_GET_BE16(frame + 2 * ETH_ALEN) == ETH_P_PAE) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Work around misdelivered control port TX status for EAPOL");
+ nl80211_control_port_frame_tx_status(drv, frame, len, ack,
+ cookie);
+ return;
+ }
+
if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
return;
@@ -2557,6 +2575,29 @@ static void nl80211_control_port_frame(struct wpa_driver_nl80211_data *drv,
}
+static void
+nl80211_control_port_frame_tx_status(struct wpa_driver_nl80211_data *drv,
+ const u8 *frame, size_t len,
+ struct nlattr *ack, struct nlattr *cookie)
+{
+ union wpa_event_data event;
+
+ if (!cookie || len < ETH_HLEN)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Control port TX status (ack=%d), cookie=%llu",
+ ack != NULL, (long long unsigned int) nla_get_u64(cookie));
+
+ os_memset(&event, 0, sizeof(event));
+ event.eapol_tx_status.dst = frame;
+ event.eapol_tx_status.data = frame + ETH_HLEN;
+ event.eapol_tx_status.data_len = len - ETH_HLEN;
+ event.eapol_tx_status.ack = ack != NULL;
+ wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
+}
+
+
static void do_process_drv_event(struct i802_bss *bss, int cmd,
struct nlattr **tb)
{
@@ -2775,6 +2816,15 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
mlme_event_unprot_beacon(drv, nla_data(frame),
nla_len(frame));
break;
+ case NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS:
+ if (!frame)
+ break;
+ nl80211_control_port_frame_tx_status(drv,
+ nla_data(frame),
+ nla_len(frame),
+ tb[NL80211_ATTR_ACK],
+ tb[NL80211_ATTR_COOKIE]);
+ break;
default:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", cmd);
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index dc91a29..233175d 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -82,7 +82,8 @@ static int nl80211_get_noise_for_scan_results(
os_memset(info, 0, sizeof(*info));
msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
- return send_and_recv_msgs(drv, msg, get_noise_for_scan_results, info);
+ return send_and_recv_msgs(drv, msg, get_noise_for_scan_results, info,
+ NULL, NULL);
}
@@ -94,7 +95,7 @@ static int nl80211_abort_scan(struct i802_bss *bss)
wpa_printf(MSG_DEBUG, "nl80211: Abort scan");
msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_ABORT_SCAN);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Abort scan failed: ret=%d (%s)",
ret, strerror(-ret));
@@ -125,7 +126,7 @@ static int nl80211_abort_vendor_scan(struct wpa_driver_nl80211_data *drv,
nla_nest_end(msg, params);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_INFO,
@@ -365,7 +366,7 @@ int wpa_driver_nl80211_scan(struct i802_bss *bss,
goto fail;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
@@ -618,7 +619,7 @@ int wpa_driver_nl80211_sched_scan(void *priv,
params->sched_scan_start_delay))
goto fail;
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
/* TODO: if we get an error here, we should fall back to normal scan */
@@ -655,7 +656,7 @@ int wpa_driver_nl80211_stop_sched_scan(void *priv)
#endif /* ANDROID */
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_STOP_SCHED_SCAN);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG,
"nl80211: Sched scan stop failed: ret=%d (%s)",
@@ -944,7 +945,7 @@ try_again:
arg.drv = drv;
arg.res = res;
- ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
+ ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg, NULL, NULL);
if (ret == -EAGAIN) {
count++;
if (count >= 10) {
@@ -1028,7 +1029,8 @@ void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
ctx.idx = 0;
msg = nl80211_cmd_msg(drv->first_bss, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
if (msg)
- send_and_recv_msgs(drv, msg, nl80211_dump_scan_handler, &ctx);
+ send_and_recv_msgs(drv, msg, nl80211_dump_scan_handler, &ctx,
+ NULL, NULL);
}
@@ -1221,7 +1223,8 @@ int wpa_driver_nl80211_vendor_scan(struct i802_bss *bss,
nla_nest_end(msg, attr);
- ret = send_and_recv_msgs(drv, msg, scan_cookie_handler, &cookie);
+ ret = send_and_recv_msgs(drv, msg, scan_cookie_handler, &cookie,
+ NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG,
@@ -1284,7 +1287,7 @@ int nl80211_set_default_scan_ies(void *priv, const u8 *ies, size_t ies_len)
nla_nest_end(msg, attr);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_ERROR,
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 9679d56..dad8c8f 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -296,13 +296,14 @@
* to get a list of all present wiphys.
* @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
* %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
- * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ (and the
- * attributes determining the channel width; this is used for setting
- * monitor mode channel), %NL80211_ATTR_WIPHY_RETRY_SHORT,
- * %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
- * and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
- * However, for setting the channel, see %NL80211_CMD_SET_CHANNEL
- * instead, the support here is for backward compatibility only.
+ * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ,
+ * %NL80211_ATTR_WIPHY_FREQ_OFFSET (and the attributes determining the
+ * channel width; this is used for setting monitor mode channel),
+ * %NL80211_ATTR_WIPHY_RETRY_SHORT, %NL80211_ATTR_WIPHY_RETRY_LONG,
+ * %NL80211_ATTR_WIPHY_FRAG_THRESHOLD, and/or
+ * %NL80211_ATTR_WIPHY_RTS_THRESHOLD. However, for setting the channel,
+ * see %NL80211_CMD_SET_CHANNEL instead, the support here is for backward
+ * compatibility only.
* @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
* or rename notification. Has attributes %NL80211_ATTR_WIPHY and
* %NL80211_ATTR_WIPHY_NAME.
@@ -351,7 +352,8 @@
* %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_INACTIVITY_TIMEOUT,
* %NL80211_ATTR_ACL_POLICY and %NL80211_ATTR_MAC_ADDRS.
* The channel to use can be set on the interface or be given using the
- * %NL80211_ATTR_WIPHY_FREQ and the attributes determining channel width.
+ * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_WIPHY_FREQ_OFFSET, and the
+ * attributes determining channel width.
* @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
* @NL80211_CMD_STOP_AP: Stop AP operation on the given interface
* @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP
@@ -536,11 +538,12 @@
* interface. %NL80211_ATTR_MAC is used to specify PeerSTAAddress (and
* BSSID in case of station mode). %NL80211_ATTR_SSID is used to specify
* the SSID (mainly for association, but is included in authentication
- * request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ is used
- * to specify the frequence of the channel in MHz. %NL80211_ATTR_AUTH_TYPE
- * is used to specify the authentication type. %NL80211_ATTR_IE is used to
- * define IEs (VendorSpecificInfo, but also including RSN IE and FT IEs)
- * to be added to the frame.
+ * request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ +
+ * %NL80211_ATTR_WIPHY_FREQ_OFFSET is used to specify the frequence of the
+ * channel in MHz. %NL80211_ATTR_AUTH_TYPE is used to specify the
+ * authentication type. %NL80211_ATTR_IE is used to define IEs
+ * (VendorSpecificInfo, but also including RSN IE and FT IEs) to be added
+ * to the frame.
* When used as an event, this reports reception of an Authentication
* frame in station and IBSS modes when the local MLME processed the
* frame, i.e., it was for the local STA and was received in correct
@@ -595,8 +598,9 @@
* requests to connect to a specified network but without separating
* auth and assoc steps. For this, you need to specify the SSID in a
* %NL80211_ATTR_SSID attribute, and can optionally specify the association
- * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
- * %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
+ * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE,
+ * %NL80211_ATTR_USE_MFP, %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ,
+ * %NL80211_ATTR_WIPHY_FREQ_OFFSET, %NL80211_ATTR_CONTROL_PORT,
* %NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
* %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
* %NL80211_ATTR_CONTROL_PORT_OVER_NL80211, %NL80211_ATTR_MAC_HINT, and
@@ -1160,6 +1164,12 @@
* dropped because it did not include a valid MME MIC while beacon
* protection was enabled (BIGTK configured in station mode).
*
+ * @NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS: Report TX status of a control
+ * port frame transmitted with %NL80211_CMD_CONTROL_PORT_FRAME.
+ * %NL80211_ATTR_COOKIE identifies the TX command and %NL80211_ATTR_FRAME
+ * includes the contents of the frame. %NL80211_ATTR_ACK flag is included
+ * if the recipient acknowledged the frame.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1388,6 +1398,8 @@ enum nl80211_commands {
NL80211_CMD_UNPROT_BEACON,
+ NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1433,7 +1445,8 @@ enum nl80211_commands {
* of &enum nl80211_chan_width, describing the channel width. See the
* documentation of the enum for more information.
* @NL80211_ATTR_CENTER_FREQ1: Center frequency of the first part of the
- * channel, used for anything but 20 MHz bandwidth
+ * channel, used for anything but 20 MHz bandwidth. In S1G this is the
+ * operating channel center frequency.
* @NL80211_ATTR_CENTER_FREQ2: Center frequency of the second part of the
* channel, used only for 80+80 MHz bandwidth
* @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ
@@ -2480,9 +2493,17 @@ enum nl80211_commands {
* entry without having to force a disconnection after the PMK timeout. If
* no roaming occurs between the reauth threshold and PMK expiration,
* disassociation is still forced.
- *
* @NL80211_ATTR_RECEIVE_MULTICAST: multicast flag for the
* %NL80211_CMD_REGISTER_FRAME command, see the description there.
+ * @NL80211_ATTR_WIPHY_FREQ_OFFSET: offset of the associated
+ * %NL80211_ATTR_WIPHY_FREQ in positive KHz. Only valid when supplied with
+ * an %NL80211_ATTR_WIPHY_FREQ_OFFSET.
+ * @NL80211_ATTR_CENTER_FREQ1_OFFSET: Center frequency offset in KHz for the
+ * first channel segment specified in %NL80211_ATTR_CENTER_FREQ1.
+ * @NL80211_ATTR_SCAN_FREQ_KHZ: nested attribute with KHz frequencies
+ *
+ * @NL80211_ATTR_HE_6GHZ_CAPABILITY: HE 6 GHz Band Capability element (from
+ * association request when used with NL80211_CMD_NEW_STATION).
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
@@ -2960,6 +2981,11 @@ enum nl80211_attrs {
NL80211_ATTR_PMK_REAUTH_THRESHOLD,
NL80211_ATTR_RECEIVE_MULTICAST,
+ NL80211_ATTR_WIPHY_FREQ_OFFSET,
+ NL80211_ATTR_CENTER_FREQ1_OFFSET,
+ NL80211_ATTR_SCAN_FREQ_KHZ,
+
+ NL80211_ATTR_HE_6GHZ_CAPABILITY,
/* add attributes here, update the policy in nl80211.c */
@@ -3539,6 +3565,8 @@ enum nl80211_mpath_info {
* defined in HE capabilities IE
* @NL80211_BAND_IFTYPE_ATTR_MAX: highest band HE capability attribute currently
* defined
+ * @NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA: HE 6GHz band capabilities (__le16),
+ * given for all 6 GHz band channels
* @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use
*/
enum nl80211_band_iftype_attr {
@@ -3549,6 +3577,7 @@ enum nl80211_band_iftype_attr {
NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY,
NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET,
NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE,
+ NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA,
/* keep last */
__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST,
@@ -3682,6 +3711,7 @@ enum nl80211_wmm_rule {
* (see &enum nl80211_wmm_rule)
* @NL80211_FREQUENCY_ATTR_NO_HE: HE operation is not allowed on this channel
* in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_OFFSET: frequency offset in KHz
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -3712,6 +3742,7 @@ enum nl80211_frequency_attr {
NL80211_FREQUENCY_ATTR_NO_10MHZ,
NL80211_FREQUENCY_ATTR_WMM,
NL80211_FREQUENCY_ATTR_NO_HE,
+ NL80211_FREQUENCY_ATTR_OFFSET,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -4482,6 +4513,7 @@ enum nl80211_bss_scan_width {
* @NL80211_BSS_CHAIN_SIGNAL: per-chain signal strength of last BSS update.
* Contains a nested array of signal strength attributes (u8, dBm),
* using the nesting index as the antenna number.
+ * @NL80211_BSS_FREQUENCY_OFFSET: frequency offset in KHz
* @__NL80211_BSS_AFTER_LAST: internal
* @NL80211_BSS_MAX: highest BSS attribute
*/
@@ -4506,6 +4538,7 @@ enum nl80211_bss {
NL80211_BSS_PARENT_TSF,
NL80211_BSS_PARENT_BSSID,
NL80211_BSS_CHAIN_SIGNAL,
+ NL80211_BSS_FREQUENCY_OFFSET,
/* keep last */
__NL80211_BSS_AFTER_LAST,
@@ -4816,6 +4849,17 @@ enum nl80211_tid_config {
NL80211_TID_CONFIG_DISABLE,
};
+/* enum nl80211_tx_rate_setting - TX rate configuration type
+ * @NL80211_TX_RATE_AUTOMATIC: automatically determine TX rate
+ * @NL80211_TX_RATE_LIMITED: limit the TX rate by the TX rate parameter
+ * @NL80211_TX_RATE_FIXED: fix TX rate to the TX rate parameter
+ */
+enum nl80211_tx_rate_setting {
+ NL80211_TX_RATE_AUTOMATIC,
+ NL80211_TX_RATE_LIMITED,
+ NL80211_TX_RATE_FIXED,
+};
+
/* enum nl80211_tid_config_attr - TID specific configuration.
* @NL80211_TID_CONFIG_ATTR_PAD: pad attribute for 64-bit values
* @NL80211_TID_CONFIG_ATTR_VIF_SUPP: a bitmap (u64) of attributes supported
@@ -4823,12 +4867,10 @@ enum nl80211_tid_config {
* (%NL80211_TID_CONFIG_ATTR_TIDS, %NL80211_TID_CONFIG_ATTR_OVERRIDE).
* @NL80211_TID_CONFIG_ATTR_PEER_SUPP: same as the previous per-vif one, but
* per peer instead.
- * @NL80211_TID_CONFIG_ATTR_OVERRIDE: flag attribue, if no peer
- * is selected, if set indicates that the new configuration overrides
- * all previous peer configurations, otherwise previous peer specific
- * configurations should be left untouched. If peer is selected then
- * it will reset particular TID configuration of that peer and it will
- * not accept other TID config attributes along with peer.
+ * @NL80211_TID_CONFIG_ATTR_OVERRIDE: flag attribue, if set indicates
+ * that the new configuration overrides all previous peer
+ * configurations, otherwise previous peer specific configurations
+ * should be left untouched.
* @NL80211_TID_CONFIG_ATTR_TIDS: a bitmask value of TIDs (bit 0 to 7)
* Its type is u16.
* @NL80211_TID_CONFIG_ATTR_NOACK: Configure ack policy for the TID.
@@ -4844,12 +4886,23 @@ enum nl80211_tid_config {
* &NL80211_CMD_SET_TID_CONFIG. Its type is u8, min value is 1 and
* the max value is advertised by the driver in this attribute on
* output in wiphy capabilities.
- * @NL80211_TID_CONFIG_ATTR_AMPDU_CTRL: Enable/Disable aggregation for the TIDs
- * specified in %NL80211_TID_CONFIG_ATTR_TIDS. Its type is u8, using
- * the values from &nl80211_tid_config.
+ * @NL80211_TID_CONFIG_ATTR_AMPDU_CTRL: Enable/Disable MPDU aggregation
+ * for the TIDs specified in %NL80211_TID_CONFIG_ATTR_TIDS.
+ * Its type is u8, using the values from &nl80211_tid_config.
* @NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL: Enable/Disable RTS_CTS for the TIDs
* specified in %NL80211_TID_CONFIG_ATTR_TIDS. It is u8 type, using
* the values from &nl80211_tid_config.
+ * @NL80211_TID_CONFIG_ATTR_AMSDU_CTRL: Enable/Disable MSDU aggregation
+ * for the TIDs specified in %NL80211_TID_CONFIG_ATTR_TIDS.
+ * Its type is u8, using the values from &nl80211_tid_config.
+ * @NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE: This attribute will be useful
+ * to notfiy the driver that what type of txrate should be used
+ * for the TIDs specified in %NL80211_TID_CONFIG_ATTR_TIDS. using
+ * the values form &nl80211_tx_rate_setting.
+ * @NL80211_TID_CONFIG_ATTR_TX_RATE: Data frame TX rate mask should be applied
+ * with the parameters passed through %NL80211_ATTR_TX_RATES.
+ * configuration is applied to the data frame for the tid to that connected
+ * station.
*/
enum nl80211_tid_config_attr {
__NL80211_TID_CONFIG_ATTR_INVALID,
@@ -4863,6 +4916,9 @@ enum nl80211_tid_config_attr {
NL80211_TID_CONFIG_ATTR_RETRY_LONG,
NL80211_TID_CONFIG_ATTR_AMPDU_CTRL,
NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL,
+ NL80211_TID_CONFIG_ATTR_AMSDU_CTRL,
+ NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE,
+ NL80211_TID_CONFIG_ATTR_TX_RATE,
/* keep last */
__NL80211_TID_CONFIG_ATTR_AFTER_LAST,
@@ -5340,6 +5396,8 @@ enum plink_actions {
#define NL80211_KCK_LEN 16
#define NL80211_KEK_LEN 16
+#define NL80211_KCK_EXT_LEN 24
+#define NL80211_KEK_EXT_LEN 32
#define NL80211_REPLAY_CTR_LEN 8
/**
@@ -5348,6 +5406,7 @@ enum plink_actions {
* @NL80211_REKEY_DATA_KEK: key encryption key (binary)
* @NL80211_REKEY_DATA_KCK: key confirmation key (binary)
* @NL80211_REKEY_DATA_REPLAY_CTR: replay counter (binary)
+ * @NL80211_REKEY_DATA_AKM: AKM data (OUI, suite type)
* @NUM_NL80211_REKEY_DATA: number of rekey attributes (internal)
* @MAX_NL80211_REKEY_DATA: highest rekey attribute (internal)
*/
@@ -5356,6 +5415,7 @@ enum nl80211_rekey_data {
NL80211_REKEY_DATA_KEK,
NL80211_REKEY_DATA_KCK,
NL80211_REKEY_DATA_REPLAY_CTR,
+ NL80211_REKEY_DATA_AKM,
/* keep last */
NUM_NL80211_REKEY_DATA,
@@ -5705,6 +5765,14 @@ enum nl80211_feature_flags {
* @NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS: management frame registrations
* are possible for multicast frames and those will be reported properly.
*
+ * @NL80211_EXT_FEATURE_SCAN_FREQ_KHZ: This driver supports receiving and
+ * reporting scan request with %NL80211_ATTR_SCAN_FREQ_KHZ. In order to
+ * report %NL80211_ATTR_SCAN_FREQ_KHZ, %NL80211_SCAN_FLAG_FREQ_KHZ must be
+ * included in the scan request.
+ *
+ * @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS: The driver
+ * can report tx status for control port over nl80211 tx operations.
+ *
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@@ -5758,6 +5826,8 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_DEL_IBSS_STA,
NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS,
NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT,
+ NL80211_EXT_FEATURE_SCAN_FREQ_KHZ,
+ NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@@ -5869,6 +5939,9 @@ enum nl80211_timeout_reason {
* @NL80211_SCAN_FLAG_MIN_PREQ_CONTENT: minimize probe request content to
* only have supported rates and no additional capabilities (unless
* added by userspace explicitly.)
+ * @NL80211_SCAN_FLAG_FREQ_KHZ: report scan results with
+ * %NL80211_ATTR_SCAN_FREQ_KHZ. This also means
+ * %NL80211_ATTR_SCAN_FREQUENCIES will not be included.
*/
enum nl80211_scan_flags {
NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,
@@ -5884,6 +5957,7 @@ enum nl80211_scan_flags {
NL80211_SCAN_FLAG_HIGH_ACCURACY = 1<<10,
NL80211_SCAN_FLAG_RANDOM_SN = 1<<11,
NL80211_SCAN_FLAG_MIN_PREQ_CONTENT = 1<<12,
+ NL80211_SCAN_FLAG_FREQ_KHZ = 1<<13,
};
/**
diff --git a/src/eap_peer/eap_teap.c b/src/eap_peer/eap_teap.c
index 76179a3..e8cc784 100644
--- a/src/eap_peer/eap_teap.c
+++ b/src/eap_peer/eap_teap.c
@@ -1388,6 +1388,15 @@ static int eap_teap_process_decrypted(struct eap_sm *sm,
"EAP-TEAP: PAC used - server may decide to skip inner authentication");
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_COND_SUCC;
+ } else if (data->result_success_done &&
+ tls_connection_get_own_cert_used(data->ssl.conn) &&
+ eap_teap_derive_msk(data) == 0) {
+ /* Assume the server might accept authentication without going
+ * through inner authentication. */
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Client certificate used - server may decide to skip inner authentication");
+ ret->methodState = METHOD_MAY_CONT;
+ ret->decision = DECISION_COND_SUCC;
}
if (tlv.pac) {
diff --git a/src/eap_server/eap_server_teap.c b/src/eap_server/eap_server_teap.c
index d7b1b09..691b44a 100644
--- a/src/eap_server/eap_server_teap.c
+++ b/src/eap_server/eap_server_teap.c
@@ -64,7 +64,7 @@ struct eap_teap_data {
struct wpabuf *pending_phase2_resp;
struct wpabuf *server_outer_tlvs;
struct wpabuf *peer_outer_tlvs;
- u8 *identity; /* from PAC-Opaque */
+ u8 *identity; /* from PAC-Opaque or client certificate */
size_t identity_len;
int eap_seq;
int tnc_started;
@@ -365,7 +365,9 @@ static void * eap_teap_init(struct eap_sm *sm)
data->teap_version = EAP_TEAP_VERSION;
data->state = START;
- if (eap_server_tls_ssl_init(sm, &data->ssl, 0, EAP_TYPE_TEAP)) {
+ if (eap_server_tls_ssl_init(sm, &data->ssl,
+ sm->cfg->eap_teap_auth == 2 ? 2 : 0,
+ EAP_TYPE_TEAP)) {
wpa_printf(MSG_INFO, "EAP-TEAP: Failed to initialize SSL.");
eap_teap_reset(sm, data);
return NULL;
@@ -502,6 +504,19 @@ static int eap_teap_phase1_done(struct eap_sm *sm, struct eap_teap_data *data)
wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 1 done, starting Phase 2");
+ if (!data->identity && sm->cfg->eap_teap_auth == 2) {
+ const char *subject;
+
+ subject = tls_connection_get_peer_subject(data->ssl.conn);
+ if (subject) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Peer subject from Phase 1 client certificate: '%s'",
+ subject);
+ data->identity = (u8 *) os_strdup(subject);
+ data->identity_len = os_strlen(subject);
+ }
+ }
+
data->tls_cs = tls_connection_get_cipher_suite(data->ssl.conn);
wpa_printf(MSG_DEBUG, "EAP-TEAP: TLS cipher suite 0x%04x",
data->tls_cs);
@@ -1775,9 +1790,10 @@ static int eap_teap_process_phase2_start(struct eap_sm *sm,
next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_NONE;
eap_teap_state(data, PHASE2_METHOD);
- } else if (sm->cfg->eap_teap_pac_no_inner) {
+ } else if (sm->cfg->eap_teap_pac_no_inner ||
+ sm->cfg->eap_teap_auth == 2) {
wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Used PAC and identity already known - skip inner auth");
+ "EAP-TEAP: Used PAC or client certificate and identity already known - skip inner auth");
data->skipped_inner_auth = 1;
/* FIX: Need to derive CMK here. However, how is that
* supposed to be done? RFC 7170 does not tell that for
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index 4a175f1..e481dd5 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -269,7 +269,8 @@ pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
entry->fils_cache_id_set ? entry->fils_cache_id : NULL,
entry->pmk, entry->pmk_len,
pmksa->sm->dot11RSNAConfigPMKLifetime,
- pmksa->sm->dot11RSNAConfigPMKReauthThreshold);
+ pmksa->sm->dot11RSNAConfigPMKReauthThreshold,
+ entry->akmp);
return entry;
}
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index d4d1307..1a38bf6 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -349,7 +349,8 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm)
* PMKIDs again, so report the existing data now. */
if (p) {
wpa_sm_add_pmkid(sm, NULL, candidate->bssid, p->pmkid,
- NULL, p->pmk, p->pmk_len, 0, 0);
+ NULL, p->pmk, p->pmk_len, 0, 0,
+ p->akmp);
}
dl_list_del(&candidate->list);
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 0ae73e8..7b1218f 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -2039,6 +2039,15 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
os_free(rbuf);
return -1;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->oci_freq_override_eapol_g2) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %d MHz",
+ ci.frequency,
+ sm->oci_freq_override_eapol_g2);
+ ci.frequency = sm->oci_freq_override_eapol_g2;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
pos = key_mic + mic_len + 2; /* Key Data */
if (ocv_insert_oci_kde(&ci, &pos) < 0) {
@@ -3289,6 +3298,9 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
case WPA_PARAM_SAE_PWE:
sm->sae_pwe = value;
break;
+ case WPA_PARAM_SAE_PK:
+ sm->sae_pk = value;
+ break;
case WPA_PARAM_DENY_PTK0_REKEY:
sm->wpa_deny_ptk0_rekey = value;
break;
@@ -3305,6 +3317,15 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
case WPA_PARAM_OCI_FREQ_EAPOL:
sm->oci_freq_override_eapol = value;
break;
+ case WPA_PARAM_OCI_FREQ_EAPOL_G2:
+ sm->oci_freq_override_eapol_g2 = value;
+ break;
+ case WPA_PARAM_OCI_FREQ_FT_ASSOC:
+ sm->oci_freq_override_ft_assoc = value;
+ break;
+ case WPA_PARAM_OCI_FREQ_FILS_ASSOC:
+ sm->oci_freq_override_fils_assoc = value;
+ break;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_DPP2
case WPA_PARAM_DPP_PFS:
@@ -4562,6 +4583,15 @@ struct wpabuf * fils_build_assoc_req(struct wpa_sm *sm, const u8 **kek,
wpabuf_free(buf);
return NULL;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->oci_freq_override_fils_assoc) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %d MHz",
+ ci.frequency,
+ sm->oci_freq_override_fils_assoc);
+ ci.frequency = sm->oci_freq_override_fils_assoc;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
pos = wpabuf_put(buf, OCV_OCI_EXTENDED_LEN);
if (ocv_insert_extended_oci(&ci, pos) < 0) {
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index f3901e0..2142772 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -43,7 +43,7 @@ struct wpa_sm_ctx {
int (*add_pmkid)(void *ctx, void *network_ctx, const u8 *bssid,
const u8 *pmkid, const u8 *fils_cache_id,
const u8 *pmk, size_t pmk_len, u32 pmk_lifetime,
- u8 pmk_reauth_threshold);
+ u8 pmk_reauth_threshold, int akmp);
int (*remove_pmkid)(void *ctx, void *network_ctx, const u8 *bssid,
const u8 *pmkid, const u8 *fils_cache_id);
void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
@@ -103,12 +103,16 @@ enum wpa_sm_conf_params {
WPA_PARAM_MFP,
WPA_PARAM_OCV,
WPA_PARAM_SAE_PWE,
+ WPA_PARAM_SAE_PK,
WPA_PARAM_DENY_PTK0_REKEY,
WPA_PARAM_EXT_KEY_ID,
WPA_PARAM_USE_EXT_KEY_ID,
WPA_PARAM_FT_RSNXE_USED,
WPA_PARAM_DPP_PFS,
WPA_PARAM_OCI_FREQ_EAPOL,
+ WPA_PARAM_OCI_FREQ_EAPOL_G2,
+ WPA_PARAM_OCI_FREQ_FT_ASSOC,
+ WPA_PARAM_OCI_FREQ_FILS_ASSOC,
};
struct rsn_supp_config {
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 00151df..bcaf42f 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -353,6 +353,14 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
os_free(buf);
return NULL;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->oci_freq_override_ft_assoc) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %d MHz",
+ ci.frequency, sm->oci_freq_override_ft_assoc);
+ ci.frequency = sm->oci_freq_override_ft_assoc;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
*pos++ = FTIE_SUBELEM_OCI;
*pos++ = OCV_OCI_LEN;
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 4db9256..96b07fc 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -95,6 +95,7 @@ struct wpa_sm {
int mfp; /* 0 = disabled, 1 = optional, 2 = mandatory */
int ocv; /* Operating Channel Validation */
int sae_pwe; /* SAE PWE generation options */
+ int sae_pk; /* whether SAE-PK is used */
u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
size_t assoc_wpa_ie_len;
@@ -155,6 +156,9 @@ struct wpa_sm {
struct wpabuf *test_assoc_ie;
int ft_rsnxe_used;
unsigned int oci_freq_override_eapol;
+ unsigned int oci_freq_override_eapol_g2;
+ unsigned int oci_freq_override_ft_assoc;
+ unsigned int oci_freq_override_fils_assoc;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_FILS
@@ -268,12 +272,12 @@ static inline int wpa_sm_add_pmkid(struct wpa_sm *sm, void *network_ctx,
const u8 *bssid, const u8 *pmkid,
const u8 *cache_id, const u8 *pmk,
size_t pmk_len, u32 pmk_lifetime,
- u8 pmk_reauth_threshold)
+ u8 pmk_reauth_threshold, int akmp)
{
WPA_ASSERT(sm->ctx->add_pmkid);
return sm->ctx->add_pmkid(sm->ctx->ctx, network_ctx, bssid, pmkid,
cache_id, pmk, pmk_len, pmk_lifetime,
- pmk_reauth_threshold);
+ pmk_reauth_threshold, akmp);
}
static inline int wpa_sm_remove_pmkid(struct wpa_sm *sm, void *network_ctx,
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 9068781..20fdd69 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -357,7 +357,7 @@ int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len)
if (!wpa_key_mgmt_sae(sm->key_mgmt))
return 0; /* SAE not in use */
- if (sm->sae_pwe != 1 && sm->sae_pwe != 2)
+ if (sm->sae_pwe != 1 && sm->sae_pwe != 2 && !sm->sae_pk)
return 0; /* no supported extended RSN capabilities */
if (rsnxe_len < 3)
@@ -367,7 +367,12 @@ int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len)
*pos++ = 1;
/* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
* used for now */
- *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+ *pos = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+#ifdef CONFIG_SAE_PK
+ if (sm->sae_pk)
+ *pos |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+#endif /* CONFIG_SAE_PK */
+ pos++;
return pos - rsnxe;
}
diff --git a/src/utils/base64.c b/src/utils/base64.c
index a17d2d3..0d121c1 100644
--- a/src/utils/base64.c
+++ b/src/utils/base64.c
@@ -9,6 +9,7 @@
#include "includes.h"
#include <stdint.h>
+#include "utils/common.h"
#include "os.h"
#include "base64.h"
@@ -18,6 +19,10 @@ static const char base64_url_table[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+#define BASE64_PAD BIT(0)
+#define BASE64_LF BIT(1)
+
+
static char * base64_gen_encode(const unsigned char *src, size_t len,
size_t *out_len, const char *table, int add_pad)
{
@@ -29,7 +34,7 @@ static char * base64_gen_encode(const unsigned char *src, size_t len,
if (len >= SIZE_MAX / 4)
return NULL;
olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
- if (add_pad)
+ if (add_pad & BASE64_LF)
olen += olen / 72; /* line feeds */
olen++; /* nul termination */
if (olen < len)
@@ -49,7 +54,7 @@ static char * base64_gen_encode(const unsigned char *src, size_t len,
*pos++ = table[in[2] & 0x3f];
in += 3;
line_len += 4;
- if (add_pad && line_len >= 72) {
+ if ((add_pad & BASE64_LF) && line_len >= 72) {
*pos++ = '\n';
line_len = 0;
}
@@ -59,19 +64,19 @@ static char * base64_gen_encode(const unsigned char *src, size_t len,
*pos++ = table[(in[0] >> 2) & 0x3f];
if (end - in == 1) {
*pos++ = table[((in[0] & 0x03) << 4) & 0x3f];
- if (add_pad)
+ if (add_pad & BASE64_PAD)
*pos++ = '=';
} else {
*pos++ = table[(((in[0] & 0x03) << 4) |
(in[1] >> 4)) & 0x3f];
*pos++ = table[((in[1] & 0x0f) << 2) & 0x3f];
}
- if (add_pad)
+ if (add_pad & BASE64_PAD)
*pos++ = '=';
line_len += 4;
}
- if (add_pad && line_len)
+ if ((add_pad & BASE64_LF) && line_len)
*pos++ = '\n';
*pos = '\0';
@@ -164,7 +169,14 @@ static unsigned char * base64_gen_decode(const char *src, size_t len,
*/
char * base64_encode(const void *src, size_t len, size_t *out_len)
{
- return base64_gen_encode(src, len, out_len, base64_table, 1);
+ return base64_gen_encode(src, len, out_len, base64_table,
+ BASE64_PAD | BASE64_LF);
+}
+
+
+char * base64_encode_no_lf(const void *src, size_t len, size_t *out_len)
+{
+ return base64_gen_encode(src, len, out_len, base64_table, BASE64_PAD);
}
diff --git a/src/utils/base64.h b/src/utils/base64.h
index 6216f44..d545b29 100644
--- a/src/utils/base64.h
+++ b/src/utils/base64.h
@@ -10,6 +10,7 @@
#define BASE64_H
char * base64_encode(const void *src, size_t len, size_t *out_len);
+char * base64_encode_no_lf(const void *src, size_t len, size_t *out_len);
unsigned char * base64_decode(const char *src, size_t len, size_t *out_len);
char * base64_url_encode(const void *src, size_t len, size_t *out_len);
unsigned char * base64_url_decode(const char *src, size_t len, size_t *out_len);
diff --git a/src/utils/json.c b/src/utils/json.c
index 5a0edf2..dd12f1b 100644
--- a/src/utils/json.c
+++ b/src/utils/json.c
@@ -528,6 +528,28 @@ struct wpabuf * json_get_member_base64url(struct json_token *json,
}
+struct wpabuf * json_get_member_base64(struct json_token *json,
+ const char *name)
+{
+ struct json_token *token;
+ unsigned char *buf;
+ size_t buflen;
+ struct wpabuf *ret;
+
+ token = json_get_member(json, name);
+ if (!token || token->type != JSON_STRING)
+ return NULL;
+ buf = base64_decode(token->string, os_strlen(token->string), &buflen);
+ if (!buf)
+ return NULL;
+ ret = wpabuf_alloc_ext_data(buf, buflen);
+ if (!ret)
+ os_free(buf);
+
+ return ret;
+}
+
+
static const char * json_type_str(enum json_type type)
{
switch (type) {
@@ -620,6 +642,20 @@ int json_add_base64url(struct wpabuf *json, const char *name, const void *val,
}
+int json_add_base64(struct wpabuf *json, const char *name, const void *val,
+ size_t len)
+{
+ char *b64;
+
+ b64 = base64_encode_no_lf(val, len, NULL);
+ if (!b64)
+ return -1;
+ json_add_string(json, name, b64);
+ os_free(b64);
+ return 0;
+}
+
+
void json_start_object(struct wpabuf *json, const char *name)
{
if (name)
diff --git a/src/utils/json.h b/src/utils/json.h
index ca4a2e4..8448bb0 100644
--- a/src/utils/json.h
+++ b/src/utils/json.h
@@ -37,6 +37,8 @@ void json_free(struct json_token *json);
struct json_token * json_get_member(struct json_token *json, const char *name);
struct wpabuf * json_get_member_base64url(struct json_token *json,
const char *name);
+struct wpabuf * json_get_member_base64(struct json_token *json,
+ const char *name);
void json_print_tree(struct json_token *root, char *buf, size_t buflen);
void json_add_int(struct wpabuf *json, const char *name, int val);
void json_add_string(struct wpabuf *json, const char *name, const char *val);
@@ -44,6 +46,8 @@ int json_add_string_escape(struct wpabuf *json, const char *name,
const void *val, size_t len);
int json_add_base64url(struct wpabuf *json, const char *name, const void *val,
size_t len);
+int json_add_base64(struct wpabuf *json, const char *name, const void *val,
+ size_t len);
void json_start_object(struct wpabuf *json, const char *name);
void json_end_object(struct wpabuf *json);
void json_start_array(struct wpabuf *json, const char *name);
diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c
index 6bded14..31d2e50 100644
--- a/src/wps/wps_er.c
+++ b/src/wps/wps_er.c
@@ -1298,7 +1298,7 @@ wps_er_init(struct wps_context *wps, const char *ifname, const char *filter)
"with %s", filter);
}
if (get_netif_info(er->ifname, &er->ip_addr, &er->ip_addr_text,
- er->mac_addr)) {
+ NULL, er->mac_addr)) {
wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
"for %s. Does it have IP address?", er->ifname);
wps_er_deinit(er, NULL, NULL);
diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c
index 6e10e4b..ff58cb9 100644
--- a/src/wps/wps_upnp.c
+++ b/src/wps/wps_upnp.c
@@ -303,6 +303,14 @@ static void subscr_addr_free_all(struct subscription *s)
}
+static int local_network_addr(struct upnp_wps_device_sm *sm,
+ struct sockaddr_in *addr)
+{
+ return (addr->sin_addr.s_addr & sm->netmask.s_addr) ==
+ (sm->ip_addr & sm->netmask.s_addr);
+}
+
+
/* subscr_addr_add_url -- add address(es) for one url to subscription */
static void subscr_addr_add_url(struct subscription *s, const char *url,
size_t url_len)
@@ -320,9 +328,14 @@ static void subscr_addr_add_url(struct subscription *s, const char *url,
int rerr;
size_t host_len, path_len;
- /* url MUST begin with http: */
- if (url_len < 7 || os_strncasecmp(url, "http://", 7))
+ /* URL MUST begin with HTTP scheme. In addition, limit the length of
+ * the URL to 700 characters which is around the limit that was
+ * implicitly enforced for more than 10 years due to a bug in
+ * generating the event messages. */
+ if (url_len < 7 || os_strncasecmp(url, "http://", 7) || url_len > 700) {
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Reject an unacceptable URL");
goto fail;
+ }
url += 7;
url_len -= 7;
@@ -381,6 +394,7 @@ static void subscr_addr_add_url(struct subscription *s, const char *url,
for (rp = result; rp; rp = rp->ai_next) {
struct subscr_addr *a;
+ struct sockaddr_in *addr = (struct sockaddr_in *) rp->ai_addr;
/* Limit no. of address to avoid denial of service attack */
if (dl_list_len(&s->addr_list) >= MAX_ADDR_PER_SUBSCRIPTION) {
@@ -389,6 +403,13 @@ static void subscr_addr_add_url(struct subscription *s, const char *url,
break;
}
+ if (!local_network_addr(s->sm, addr)) {
+ wpa_printf(MSG_INFO,
+ "WPS UPnP: Ignore a delivery URL that points to another network %s",
+ inet_ntoa(addr->sin_addr));
+ continue;
+ }
+
a = os_zalloc(sizeof(*a) + alloc_len);
if (a == NULL)
break;
@@ -841,7 +862,7 @@ fail:
}
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
#include <sys/sysctl.h>
#include <net/route.h>
#include <net/if_dl.h>
@@ -882,7 +903,7 @@ static int eth_get(const char *device, u8 ea[ETH_ALEN])
}
return 0;
}
-#endif /* __FreeBSD__ */
+#endif /* __FreeBSD__ || __APPLE__ */
/**
@@ -890,11 +911,12 @@ static int eth_get(const char *device, u8 ea[ETH_ALEN])
* @net_if: Selected network interface name
* @ip_addr: Buffer for returning IP address in network byte order
* @ip_addr_text: Buffer for returning a pointer to allocated IP address text
+ * @netmask: Buffer for returning netmask or %NULL if not needed
* @mac: Buffer for returning MAC address
* Returns: 0 on success, -1 on failure
*/
int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
- u8 mac[ETH_ALEN])
+ struct in_addr *netmask, u8 mac[ETH_ALEN])
{
struct ifreq req;
int sock = -1;
@@ -920,6 +942,19 @@ int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
in_addr.s_addr = *ip_addr;
os_snprintf(*ip_addr_text, 16, "%s", inet_ntoa(in_addr));
+ if (netmask) {
+ os_memset(&req, 0, sizeof(req));
+ os_strlcpy(req.ifr_name, net_if, sizeof(req.ifr_name));
+ if (ioctl(sock, SIOCGIFNETMASK, &req) < 0) {
+ wpa_printf(MSG_ERROR,
+ "WPS UPnP: SIOCGIFNETMASK failed: %d (%s)",
+ errno, strerror(errno));
+ goto fail;
+ }
+ addr = (struct sockaddr_in *) &req.ifr_addr;
+ netmask->s_addr = addr->sin_addr.s_addr;
+ }
+
#ifdef __linux__
os_strlcpy(req.ifr_name, net_if, sizeof(req.ifr_name));
if (ioctl(sock, SIOCGIFHWADDR, &req) < 0) {
@@ -928,7 +963,7 @@ int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
goto fail;
}
os_memcpy(mac, req.ifr_addr.sa_data, 6);
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
if (eth_get(net_if, mac) < 0) {
wpa_printf(MSG_ERROR, "WPS UPnP: Failed to get MAC address");
goto fail;
@@ -1026,11 +1061,15 @@ static int upnp_wps_device_start(struct upnp_wps_device_sm *sm, char *net_if)
/* Determine which IP and mac address we're using */
if (get_netif_info(net_if, &sm->ip_addr, &sm->ip_addr_text,
- sm->mac_addr)) {
+ &sm->netmask, sm->mac_addr)) {
wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
"for %s. Does it have IP address?", net_if);
goto fail;
}
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Local IP address %s netmask %s hwaddr "
+ MACSTR,
+ sm->ip_addr_text, inet_ntoa(sm->netmask),
+ MAC2STR(sm->mac_addr));
/* Listen for incoming TCP connections so that others
* can fetch our "xml files" from us.
diff --git a/src/wps/wps_upnp_ap.c b/src/wps/wps_upnp_ap.c
index cca3905..b6c9478 100644
--- a/src/wps/wps_upnp_ap.c
+++ b/src/wps/wps_upnp_ap.c
@@ -76,8 +76,10 @@ int upnp_er_set_selected_registrar(struct wps_registrar *reg,
void upnp_er_remove_notification(struct wps_registrar *reg,
struct subscription *s)
{
+ bool was_sel_reg = s->selected_registrar;
+
s->selected_registrar = 0;
eloop_cancel_timeout(upnp_er_set_selected_timeout, s, reg);
- if (reg)
+ if (reg && was_sel_reg)
wps_registrar_selected_registrar_changed(reg, 0);
}
diff --git a/src/wps/wps_upnp_event.c b/src/wps/wps_upnp_event.c
index d7e6edc..c0d9e41 100644
--- a/src/wps/wps_upnp_event.c
+++ b/src/wps/wps_upnp_event.c
@@ -147,7 +147,8 @@ static struct wpabuf * event_build_message(struct wps_event_ *e)
struct wpabuf *buf;
char *b;
- buf = wpabuf_alloc(1000 + wpabuf_len(e->data));
+ buf = wpabuf_alloc(1000 + os_strlen(e->addr->path) +
+ wpabuf_len(e->data));
if (buf == NULL)
return NULL;
wpabuf_printf(buf, "NOTIFY %s HTTP/1.1\r\n", e->addr->path);
@@ -293,7 +294,7 @@ static int event_send_start(struct subscription *s)
buf = event_build_message(e);
if (buf == NULL) {
- event_retry(e, 0);
+ event_addr_failure(e);
return -1;
}
@@ -301,7 +302,7 @@ static int event_send_start(struct subscription *s)
event_http_cb, e);
if (e->http_event == NULL) {
wpabuf_free(buf);
- event_retry(e, 0);
+ event_addr_failure(e);
return -1;
}
diff --git a/src/wps/wps_upnp_i.h b/src/wps/wps_upnp_i.h
index e87a932..6ead7b4 100644
--- a/src/wps/wps_upnp_i.h
+++ b/src/wps/wps_upnp_i.h
@@ -128,6 +128,7 @@ struct upnp_wps_device_sm {
u8 mac_addr[ETH_ALEN]; /* mac addr of network i.f. we use */
char *ip_addr_text; /* IP address of network i.f. we use */
unsigned ip_addr; /* IP address of network i.f. we use (host order) */
+ struct in_addr netmask;
int multicast_sd; /* send multicast messages over this socket */
int ssdp_sd; /* receive discovery UPD packets on socket */
int ssdp_sd_registered; /* nonzero if we must unregister */
@@ -158,7 +159,7 @@ struct subscription * subscription_find(struct upnp_wps_device_sm *sm,
const u8 uuid[UUID_LEN]);
void subscr_addr_delete(struct subscr_addr *a);
int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
- u8 mac[ETH_ALEN]);
+ struct in_addr *netmask, u8 mac[ETH_ALEN]);
/* wps_upnp_ssdp.c */
void msearchreply_state_machine_stop(struct advertisement_state_machine *a);
diff --git a/tests/fuzzing/eapol-supp/eapol-supp.c b/tests/fuzzing/eapol-supp/eapol-supp.c
index 6f0b8cb..94e0147 100644
--- a/tests/fuzzing/eapol-supp/eapol-supp.c
+++ b/tests/fuzzing/eapol-supp/eapol-supp.c
@@ -33,7 +33,7 @@ static void test_send_eapol(void *eloop_data, void *user_ctx)
wpa_hexdump(MSG_MSGDUMP, "fuzzer - EAPOL", ctx->data, ctx->data_len);
- eapol_sm_notify_portEnabled(ctx->eapol, TRUE);
+ eapol_sm_notify_portEnabled(ctx->eapol, true);
wpa_sm_set_param(ctx->wpa, WPA_PARAM_PROTO, WPA_PROTO_RSN);
wpa_sm_set_param(ctx->wpa, WPA_PARAM_RSN_ENABLED, 1);
diff --git a/tests/hwsim/auth_serv/eap_user.conf b/tests/hwsim/auth_serv/eap_user.conf
index 7343f40..b5c65f1 100644
--- a/tests/hwsim/auth_serv/eap_user.conf
+++ b/tests/hwsim/auth_serv/eap_user.conf
@@ -83,6 +83,8 @@ radius_accept_attr=27:d:3
"phase1-user" MSCHAPV2,MD5,GTC "password"
+"/C=FI/O=w1.fi/CN=Test User" TLS [2]
+
"020000000000" MACACL "020000000000"
"020000000100" MACACL "020000000100"
diff --git a/tests/hwsim/start.sh b/tests/hwsim/start.sh
index 7a26d28..ac43d10 100755
--- a/tests/hwsim/start.sh
+++ b/tests/hwsim/start.sh
@@ -110,7 +110,7 @@ else
NUM_CH=1
fi
-test -f /proc/modules && sudo modprobe mac80211_hwsim radios=7 channels=$NUM_CH support_p2p_device=0 dyndbg=+p
+test -d /sys/module/mac80211_hwsim || sudo modprobe mac80211_hwsim radios=7 channels=$NUM_CH support_p2p_device=0 dyndbg=+p
sudo ifconfig hwsim0 up
sudo $WLANTEST -i hwsim0 -n $LOGDIR/hwsim0.pcapng -c -dtN -L $LOGDIR/hwsim0 &
diff --git a/tests/hwsim/test_ap_hs20.py b/tests/hwsim/test_ap_hs20.py
index d9f2e08..c8ba767 100644
--- a/tests/hwsim/test_ap_hs20.py
+++ b/tests/hwsim/test_ap_hs20.py
@@ -727,6 +727,61 @@ def test_ap_hs20_auto_interworking(dev, apdev):
if status['hs20'] != "3":
raise Exception("Unexpected HS 2.0 support indication")
+def test_ap_hs20_auto_interworking_global_pmf(dev, apdev):
+ """Hotspot 2.0 connection with auto_interworking=1 and pmf=2"""
+ check_eap_capa(dev[0], "MSCHAPV2")
+ bssid = apdev[0]['bssid']
+ params = hs20_ap_params()
+ params['hessid'] = bssid
+ hostapd.add_ap(apdev[0], params)
+
+ dev[0].hs20_enable(auto_interworking=True)
+ id = dev[0].add_cred_values({'realm': "example.com",
+ 'username': "hs20-test",
+ 'password': "password",
+ 'ca_cert': "auth_serv/ca.pem",
+ 'domain': "example.com",
+ 'update_identifier': "1234"})
+ try:
+ dev[0].set("pmf", "2")
+ dev[0].request("REASSOCIATE")
+ dev[0].wait_connected(timeout=15)
+ pmf = dev[0].get_status_field("pmf")
+ if pmf != "1":
+ raise Exception("Unexpected PMF state: " + str(pmf))
+ finally:
+ dev[0].set("pmf", "0")
+
+def test_ap_hs20_auto_interworking_global_pmf_fail(dev, apdev):
+ """Hotspot 2.0 connection with auto_interworking=1 and pmf=2 failure"""
+ check_eap_capa(dev[0], "MSCHAPV2")
+ bssid = apdev[0]['bssid']
+ params = hs20_ap_params()
+ params['ieee80211w'] = "0"
+ params['hessid'] = bssid
+ hostapd.add_ap(apdev[0], params)
+
+ dev[0].hs20_enable(auto_interworking=True)
+ id = dev[0].add_cred_values({'realm': "example.com",
+ 'username': "hs20-test",
+ 'password': "password",
+ 'ca_cert': "auth_serv/ca.pem",
+ 'domain': "example.com",
+ 'update_identifier': "1234"})
+ try:
+ dev[0].set("pmf", "2")
+ dev[0].request("REASSOCIATE")
+ for i in range(2):
+ ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
+ "INTERWORKING-SELECTED"], timeout=15)
+ if ev is None:
+ raise Exception("Connection result not reported")
+ if "CTRL-EVENT-CONNECTED" in ev:
+ raise Exception("Unexpected connection")
+ dev[0].request("DISCONNECT")
+ finally:
+ dev[0].set("pmf", "0")
+
@remote_compatible
def test_ap_hs20_auto_interworking_no_match(dev, apdev):
"""Hotspot 2.0 connection with auto_interworking=1 and no matching network"""
diff --git a/tests/hwsim/test_ap_pmf.py b/tests/hwsim/test_ap_pmf.py
index 2bb4a36..e0a6225 100644
--- a/tests/hwsim/test_ap_pmf.py
+++ b/tests/hwsim/test_ap_pmf.py
@@ -1133,3 +1133,44 @@ def run_ap_pmf_beacon_protection_mismatch(dev, apdev, clear):
ev = hapd.wait_event(["CTRL-EVENT-UNPROT-BEACON"], timeout=5)
if ev is None:
raise Exception("WNM-Notification Request frame not reported")
+
+def test_ap_pmf_sta_global_require(dev, apdev):
+ """WPA2-PSK AP with PMF optional and wpa_supplicant pmf=2"""
+ ssid = "test-pmf-optional"
+ params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+ params["wpa_key_mgmt"] = "WPA-PSK"
+ params["ieee80211w"] = "1"
+ hapd = hostapd.add_ap(apdev[0], params)
+ try:
+ dev[0].set("pmf", "2")
+ dev[0].connect(ssid, psk="12345678",
+ key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2",
+ scan_freq="2412")
+ pmf = dev[0].get_status_field("pmf")
+ if pmf != "1":
+ raise Exception("Unexpected PMF state: " + str(pmf))
+ finally:
+ dev[0].set("pmf", "0")
+
+def test_ap_pmf_sta_global_require2(dev, apdev):
+ """WPA2-PSK AP with PMF optional and wpa_supplicant pmf=2 (2)"""
+ ssid = "test-pmf-optional"
+ params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+ params["wpa_key_mgmt"] = "WPA-PSK"
+ params["ieee80211w"] = "0"
+ hapd = hostapd.add_ap(apdev[0], params)
+ bssid = hapd.own_addr()
+ try:
+ dev[0].scan_for_bss(bssid, freq=2412)
+ dev[0].set("pmf", "2")
+ dev[0].connect(ssid, psk="12345678",
+ key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2",
+ scan_freq="2412", wait_connect=False)
+ ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
+ "CTRL-EVENT-NETWORK-NOT-FOUND"], timeout=10)
+ if ev is None:
+ raise Exception("Connection result not reported")
+ if "CTRL-EVENT-CONNECTED" in ev:
+ raise Exception("Unexpected connection")
+ finally:
+ dev[0].set("pmf", "0")
diff --git a/tests/hwsim/test_ap_psk.py b/tests/hwsim/test_ap_psk.py
index 116733a..e79380e 100644
--- a/tests/hwsim/test_ap_psk.py
+++ b/tests/hwsim/test_ap_psk.py
@@ -3362,10 +3362,17 @@ def test_ap_wpa2_psk_no_control_port(dev, apdev):
def test_ap_wpa2_psk_ap_control_port(dev, apdev):
"""WPA2-PSK AP with nl80211 control port in AP mode"""
+ run_ap_wpa2_psk_ap_control_port(dev, apdev, ctrl_val=1)
+
+def test_ap_wpa2_psk_ap_control_port_disabled(dev, apdev):
+ """WPA2-PSK AP with nl80211 control port in AP mode disabled"""
+ run_ap_wpa2_psk_ap_control_port(dev, apdev, ctrl_val=0)
+
+def run_ap_wpa2_psk_ap_control_port(dev, apdev, ctrl_val):
ssid = "test-wpa2-psk"
passphrase = 'qwertyuiop'
params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
- params['driver_params'] = "control_port_ap=1"
+ params['driver_params'] = "control_port_ap=%d" % ctrl_val
hapd = hostapd.add_ap(apdev[0], params)
flags = hapd.request("DRIVER_FLAGS").splitlines()[1:]
diff --git a/tests/hwsim/test_ap_roam.py b/tests/hwsim/test_ap_roam.py
index 9047c7a..50b4c72 100644
--- a/tests/hwsim/test_ap_roam.py
+++ b/tests/hwsim/test_ap_roam.py
@@ -26,6 +26,35 @@ def test_ap_roam_open(dev, apdev):
dev[0].roam(apdev[0]['bssid'])
hwsim_utils.test_connectivity(dev[0], hapd0)
+def test_ap_blacklist_all(dev, apdev, params):
+ """Ensure we clear the blacklist if all visible APs reject"""
+ hapd0 = hostapd.add_ap(apdev[0], {"ssid": "test-open", "max_num_sta": "0"})
+ hapd1 = hostapd.add_ap(apdev[1], {"ssid": "test-open", "max_num_sta": "0"})
+ bss0 = hapd0.own_addr()
+ bss1 = hapd1.own_addr()
+
+ dev[0].connect("test-open", key_mgmt="NONE", scan_freq="2412",
+ wait_connect=False, bssid=bss0)
+ if not dev[0].wait_event(["CTRL-EVENT-AUTH-REJECT"], timeout=10):
+ raise Exception("AP 0 didn't reject us")
+ dev[0].request("REMOVE_NETWORK all")
+ dev[0].dump_monitor()
+ dev[0].connect("test-open", key_mgmt="NONE", scan_freq="2412",
+ wait_connect=False, bssid=bss1)
+ if not dev[0].wait_event(["CTRL-EVENT-AUTH-REJECT"], timeout=10):
+ raise Exception("AP 1 didn't reject us")
+ blacklist = get_blacklist(dev[0])
+ if len(blacklist) != 2:
+ raise Exception("Unexpected blacklist: %s" % blacklist)
+ dev[0].request("REMOVE_NETWORK all")
+ dev[0].dump_monitor()
+
+ hapd0.set("max_num_sta", "1")
+ # All visible APs were blacklisted; we should clear the blacklist and find
+ # the AP that now accepts us.
+ dev[0].scan_for_bss(bss0, freq=2412)
+ dev[0].connect("test-open", key_mgmt="NONE", scan_freq="2412", bssid=bss0)
+
@remote_compatible
def test_ap_roam_open_failed(dev, apdev):
"""Roam failure due to rejected authentication"""
diff --git a/tests/hwsim/test_ap_tdls.py b/tests/hwsim/test_ap_tdls.py
index 05c4ca3..ea14a08 100644
--- a/tests/hwsim/test_ap_tdls.py
+++ b/tests/hwsim/test_ap_tdls.py
@@ -413,6 +413,7 @@ def test_ap_open_tdls_vht80(dev, apdev):
"hw_mode": "a",
"channel": "36",
"ht_capab": "[HT40+]",
+ "vht_capab": "[VHT160]",
"ieee80211n": "1",
"ieee80211ac": "1",
"vht_capab": "",
@@ -452,7 +453,7 @@ def test_ap_open_tdls_vht80plus80(dev, apdev):
"ht_capab": "[HT40+]",
"ieee80211n": "1",
"ieee80211ac": "1",
- "vht_capab": "",
+ "vht_capab": "[VHT160-80PLUS80]",
"vht_oper_chwidth": "3",
"vht_oper_centr_freq_seg0_idx": "42",
"vht_oper_centr_freq_seg1_idx": "155"}
@@ -494,6 +495,7 @@ def test_ap_open_tdls_vht160(dev, apdev):
"hw_mode": "a",
"channel": "104",
"ht_capab": "[HT40-]",
+ "vht_capab": "[VHT160]",
"ieee80211n": "1",
"ieee80211ac": "1",
"vht_oper_chwidth": "2",
diff --git a/tests/hwsim/test_ap_vht.py b/tests/hwsim/test_ap_vht.py
index 358e192..2b691ff 100644
--- a/tests/hwsim/test_ap_vht.py
+++ b/tests/hwsim/test_ap_vht.py
@@ -361,6 +361,7 @@ def test_ap_vht160(dev, apdev):
"hw_mode": "a",
"channel": "36",
"ht_capab": "[HT40+]",
+ "vht_capab": "[VHT160]",
"ieee80211n": "1",
"ieee80211ac": "1",
"vht_oper_chwidth": "2",
@@ -436,6 +437,7 @@ def test_ap_vht160b(dev, apdev):
"hw_mode": "a",
"channel": "104",
"ht_capab": "[HT40-]",
+ "vht_capab": "[VHT160]",
"ieee80211n": "1",
"ieee80211ac": "1",
"vht_oper_chwidth": "2",
@@ -538,6 +540,7 @@ def run_ap_vht160_no_dfs(dev, apdev, channel, ht_capab):
"hw_mode": "a",
"channel": channel,
"ht_capab": ht_capab,
+ "vht_capab": "[VHT160]",
"ieee80211n": "1",
"ieee80211ac": "1",
"vht_oper_chwidth": "2",
@@ -550,7 +553,7 @@ def run_ap_vht160_no_dfs(dev, apdev, channel, ht_capab):
cmd = subprocess.Popen(["iw", "reg", "get"], stdout=subprocess.PIPE)
reg = cmd.stdout.readlines()
for r in reg:
- if "5490" in r and "DFS" in r:
+ if b"5490" in r and b"DFS" in r:
raise HwsimSkip("ZA regulatory rule did not have DFS requirement removed")
raise Exception("AP setup timed out")
@@ -616,6 +619,7 @@ def test_ap_vht80plus80(dev, apdev):
"hw_mode": "a",
"channel": "52",
"ht_capab": "[HT40+]",
+ "vht_capab": "[VHT160-80PLUS80]",
"ieee80211n": "1",
"ieee80211ac": "1",
"vht_oper_chwidth": "3",
@@ -633,6 +637,7 @@ def test_ap_vht80plus80(dev, apdev):
"hw_mode": "a",
"channel": "36",
"ht_capab": "[HT40+]",
+ "vht_capab": "[VHT160-80PLUS80]",
"ieee80211n": "1",
"ieee80211ac": "1",
"vht_oper_chwidth": "3",
diff --git a/tests/hwsim/test_dpp.py b/tests/hwsim/test_dpp.py
index a15a8a6..736248f 100644
--- a/tests/hwsim/test_dpp.py
+++ b/tests/hwsim/test_dpp.py
@@ -303,6 +303,34 @@ def test_dpp_configurator_enrollee_brainpoolP512r1(dev, apdev):
"""DPP Configurator enrolling (brainpoolP512r1)"""
run_dpp_configurator_enrollee(dev, apdev, conf_curve="brainpoolP512r1")
+def test_dpp_configurator_enroll_conf(dev, apdev):
+ """DPP Configurator enrolling followed by use of the new Configurator"""
+ try:
+ dev[0].set("dpp_config_processing", "2")
+ run_dpp_configurator_enroll_conf(dev, apdev)
+ finally:
+ dev[0].set("dpp_config_processing", "0", allow_fail=True)
+
+def run_dpp_configurator_enroll_conf(dev, apdev):
+ run_dpp_qr_code_auth_unicast(dev, apdev, None, netrole="configurator",
+ configurator=True, conf="configurator",
+ qr="mutual", stop_responder=False)
+ ev = dev[0].wait_event(["DPP-CONFIGURATOR-ID"], timeout=2)
+ if ev is None:
+ raise Exception("No Configurator instance added")
+ dev[1].reset()
+ dev[0].dump_monitor()
+
+ ssid = "test-network"
+ passphrase = "test-passphrase"
+ dev[0].set("dpp_configurator_params",
+ "conf=sta-psk ssid=%s pass=%s" % (binascii.hexlify(ssid.encode()).decode(), binascii.hexlify(passphrase.encode()).decode()))
+ dev[0].dpp_listen(2412, role="configurator")
+ id0 = dev[0].dpp_bootstrap_gen(chan="81/1")
+ uri0 = dev[0].request("DPP_BOOTSTRAP_GET_URI %d" % id0)
+ dev[1].dpp_auth_init(uri=uri0, role="enrollee")
+ wait_auth_success(dev[0], dev[1], configurator=dev[0], enrollee=dev[1])
+
def test_dpp_qr_code_curve_prime256v1(dev, apdev):
"""DPP QR Code and curve prime256v1"""
run_dpp_qr_code_auth_unicast(dev, apdev, "prime256v1")
@@ -335,7 +363,7 @@ def run_dpp_qr_code_auth_unicast(dev, apdev, curve, netrole=None, key=None,
require_conf_success=False, init_extra=None,
require_conf_failure=False,
configurator=False, conf_curve=None,
- conf=None):
+ conf=None, qr=None, stop_responder=True):
check_dpp_capab(dev[0], curve and "brainpool" in curve)
check_dpp_capab(dev[1], curve and "brainpool" in curve)
if configurator:
@@ -343,19 +371,27 @@ def run_dpp_qr_code_auth_unicast(dev, apdev, curve, netrole=None, key=None,
else:
conf_id = None
+ if qr == "mutual":
+ logger.info("dev1 displays QR Code and dev0 scans it")
+ id1 = dev[1].dpp_bootstrap_gen(chan="81/1", mac=True, curve=curve)
+ uri1 = dev[1].request("DPP_BOOTSTRAP_GET_URI %d" % id1)
+ id1c = dev[0].dpp_qr_code(uri1)
+ else:
+ id1 = None
+
logger.info("dev0 displays QR Code")
id0 = dev[0].dpp_bootstrap_gen(chan="81/1", mac=True, curve=curve, key=key)
uri0 = dev[0].request("DPP_BOOTSTRAP_GET_URI %d" % id0)
logger.info("dev1 scans QR Code and initiates DPP Authentication")
- dev[0].dpp_listen(2412, netrole=netrole)
+ dev[0].dpp_listen(2412, netrole=netrole, qr=qr)
dev[1].dpp_auth_init(uri=uri0, extra=init_extra, configurator=conf_id,
- conf=conf)
+ conf=conf, own=id1)
wait_auth_success(dev[0], dev[1], configurator=dev[1], enrollee=dev[0],
allow_enrollee_failure=True,
allow_configurator_failure=not require_conf_success,
require_configurator_failure=require_conf_failure,
- stop_responder=True)
+ stop_responder=stop_responder)
def test_dpp_qr_code_auth_mutual(dev, apdev):
"""DPP QR Code and authentication exchange (mutual)"""
@@ -4751,7 +4787,15 @@ def test_dpp_tcp_port(dev, apdev, params):
finally:
dev[1].request("DPP_CONTROLLER_STOP")
-def run_dpp_tcp(dev, apdev, cap_lo, port=None):
+def test_dpp_tcp_mutual(dev, apdev, params):
+ """DPP over TCP (mutual)"""
+ cap_lo = os.path.join(params['prefix'], ".lo.pcap")
+ try:
+ run_dpp_tcp(dev, apdev, cap_lo, mutual=True)
+ finally:
+ dev[1].request("DPP_CONTROLLER_STOP")
+
+def run_dpp_tcp(dev, apdev, cap_lo, port=None, mutual=False):
check_dpp_capab(dev[0])
check_dpp_capab(dev[1])
@@ -4776,12 +4820,36 @@ def run_dpp_tcp(dev, apdev, cap_lo, port=None):
req = "DPP_CONTROLLER_START"
if port:
req += " tcp_port=" + port
+ if mutual:
+ req += " qr=mutual"
+ id0 = dev[0].dpp_bootstrap_gen()
+ uri0 = dev[0].request("DPP_BOOTSTRAP_GET_URI %d" % id0)
+ own = id0
+ else:
+ own = None
if "OK" not in dev[1].request(req):
raise Exception("Failed to start Controller")
# Initiate from Enrollee with broadcast DPP Authentication Request
- dev[0].dpp_auth_init(uri=uri_c, role="enrollee", tcp_addr="127.0.0.1",
- tcp_port=port)
+ dev[0].dpp_auth_init(uri=uri_c, own=own, role="enrollee",
+ tcp_addr="127.0.0.1", tcp_port=port)
+
+ if mutual:
+ ev = dev[0].wait_event(["DPP-RESPONSE-PENDING"], timeout=5)
+ if ev is None:
+ raise Exception("Pending response not reported")
+ ev = dev[1].wait_event(["DPP-SCAN-PEER-QR-CODE"], timeout=5)
+ if ev is None:
+ raise Exception("QR Code scan for mutual authentication not requested")
+
+ id1 = dev[1].dpp_qr_code(uri0)
+
+ ev = dev[0].wait_event(["DPP-AUTH-DIRECTION"], timeout=5)
+ if ev is None:
+ raise Exception("DPP authentication direction not indicated (Initiator)")
+ if "mutual=1" not in ev:
+ raise Exception("Mutual authentication not used")
+
wait_auth_success(dev[1], dev[0], configurator=dev[1], enrollee=dev[0],
allow_enrollee_failure=True,
allow_configurator_failure=True)
@@ -5401,7 +5469,28 @@ def test_dpp_reconfig_connector(dev, apdev):
finally:
dev[0].set("dpp_config_processing", "0", allow_fail=True)
-def run_dpp_reconfig_connector(dev, apdev):
+def test_dpp_reconfig_connector_different_groups(dev, apdev):
+ """DPP reconfiguration connector with different groups"""
+ try:
+ run_dpp_reconfig_connector(dev, apdev, conf_curve="secp384r1")
+ finally:
+ dev[0].set("dpp_config_processing", "0", allow_fail=True)
+
+@long_duration_test
+def test_dpp_reconfig_retries(dev, apdev):
+ """DPP reconfiguration retries"""
+ try:
+ run_dpp_reconfig_connector(dev, apdev, test_retries=True)
+ for i in range(4):
+ ev = dev[0].wait_event(["DPP-TX "], timeout=120)
+ if ev is None or "type=14" not in ev:
+ raise Exception("Reconfig Announcement not sent")
+ dev[0].request("DPP_STOP_LISTEN")
+ finally:
+ dev[0].set("dpp_config_processing", "0", allow_fail=True)
+
+def run_dpp_reconfig_connector(dev, apdev, conf_curve=None,
+ test_retries=False):
check_dpp_capab(dev[0], min_ver=2)
check_dpp_capab(dev[1], min_ver=2)
@@ -5415,7 +5504,7 @@ def run_dpp_reconfig_connector(dev, apdev):
id0 = dev[0].dpp_bootstrap_gen(chan="81/1", mac=True)
uri0 = dev[0].request("DPP_BOOTSTRAP_GET_URI %d" % id0)
dev[0].dpp_listen(2412)
- configurator = dev[1].dpp_configurator_add()
+ configurator = dev[1].dpp_configurator_add(curve=conf_curve)
conf = 'sta-psk'
dev[1].dpp_auth_init(uri=uri0, conf=conf, ssid=ssid,
passphrase=passphrase, configurator=configurator,
@@ -5486,6 +5575,12 @@ def run_dpp_reconfig_connector(dev, apdev):
dev[0].dump_monitor()
dev[1].dump_monitor()
+ if test_retries:
+ dev[1].request("DPP_STOP_LISTEN")
+ if "OK" not in dev[0].request("DPP_RECONFIG %s iter=10" % id):
+ raise Exception("Failed to start reconfiguration")
+ return
+
dev[1].set("dpp_configurator_params",
"conf=sta-psk ssid=%s pass=%s conn_status=1" % (binascii.hexlify(ssid.encode()).decode(), binascii.hexlify(passphrase2.encode()).decode()))
dev[1].dpp_listen(2437)
@@ -5619,3 +5714,313 @@ def test_dpp_qr_code_auth_rand_mac_addr(dev, apdev):
run_dpp_qr_code_auth_unicast(dev, apdev, None)
finally:
dev[0].set("gas_rand_mac_addr", "0")
+
+def dpp_sign_cert(cacert, cakey, csr_der):
+ csr = OpenSSL.crypto.load_certificate_request(OpenSSL.crypto.FILETYPE_ASN1,
+ csr_der)
+ cert = OpenSSL.crypto.X509()
+ cert.set_serial_number(12345)
+ cert.gmtime_adj_notBefore(-10)
+ cert.gmtime_adj_notAfter(100000)
+ cert.set_pubkey(csr.get_pubkey())
+ dn = csr.get_subject()
+ cert.set_subject(dn)
+ cert.set_version(2)
+ cert.add_extensions([
+ OpenSSL.crypto.X509Extension(b"basicConstraints", True,
+ b"CA:FALSE"),
+ OpenSSL.crypto.X509Extension(b"subjectKeyIdentifier", False,
+ b"hash", subject=cert),
+ OpenSSL.crypto.X509Extension(b"authorityKeyIdentifier", False,
+ b"keyid:always", issuer=cacert),
+ ])
+ cert.set_issuer(cacert.get_subject())
+ cert.sign(cakey, "sha256")
+ return cert
+
+def test_dpp_enterprise(dev, apdev, params):
+ """DPP and enterprise EAP-TLS provisioning"""
+ try:
+ dev[0].set("dpp_config_processing", "2")
+ run_dpp_enterprise(dev, apdev, params)
+ finally:
+ dev[0].set("dpp_config_processing", "0", allow_fail=True)
+
+def run_dpp_enterprise(dev, apdev, params):
+ if not openssl_imported:
+ raise HwsimSkip("OpenSSL python method not available")
+ check_dpp_capab(dev[0])
+ check_dpp_capab(dev[1])
+
+ cert_file = params['prefix'] + ".cert.pem"
+ pkcs7_file = params['prefix'] + ".pkcs7.der"
+
+ params = {"ssid": "dpp-ent",
+ "wpa": "2",
+ "wpa_key_mgmt": "WPA-EAP",
+ "rsn_pairwise": "CCMP",
+ "ieee8021x": "1",
+ "eap_server": "1",
+ "eap_user_file": "auth_serv/eap_user.conf",
+ "ca_cert": "auth_serv/ec-ca.pem",
+ "server_cert": "auth_serv/ec-server.pem",
+ "private_key": "auth_serv/ec-server.key"}
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ with open("auth_serv/ec-ca.pem", "rb") as f:
+ res = f.read()
+ cacert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
+ res)
+
+ with open("auth_serv/ec-ca.key", "rb") as f:
+ res = f.read()
+ cakey = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, res)
+
+ conf_id = dev[1].dpp_configurator_add()
+ id0 = dev[0].dpp_bootstrap_gen(chan="81/1", mac=True)
+ uri0 = dev[0].request("DPP_BOOTSTRAP_GET_URI %d" % id0)
+ dev[0].dpp_listen(2412)
+ csrattrs = "MAsGCSqGSIb3DQEJBw=="
+ id1 = dev[1].dpp_auth_init(uri=uri0, configurator=conf_id, conf="sta-dot1x",
+ csrattrs=csrattrs, ssid="dpp-ent")
+
+ ev = dev[1].wait_event(["DPP-CSR"], timeout=10)
+ if ev is None:
+ raise Exception("Configurator did not receive CSR")
+ id1_csr = int(ev.split(' ')[1].split('=')[1])
+ if id1 != id1_csr:
+ raise Exception("Peer bootstrapping ID mismatch in CSR event")
+ csr = ev.split(' ')[2]
+ if not csr.startswith("csr="):
+ raise Exception("Could not parse CSR event: " + ev)
+ csr = csr[4:]
+ csr = base64.b64decode(csr.encode())
+ logger.info("CSR: " + binascii.hexlify(csr).decode())
+
+ cert = dpp_sign_cert(cacert, cakey, csr)
+ with open(cert_file, 'wb') as f:
+ f.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM,
+ cert))
+ subprocess.check_call(['openssl', 'crl2pkcs7', '-nocrl',
+ '-certfile', cert_file,
+ '-certfile', 'auth_serv/ec-ca.pem',
+ '-outform', 'DER', '-out', pkcs7_file])
+
+ #caCert = base64.b64encode(b"TODO").decode()
+ #res = dev[1].request("DPP_CA_SET peer=%d name=caCert value=%s" % (id1, caCert))
+ #if "OK" not in res:
+ # raise Exception("Failed to set caCert")
+
+ name = "server.w1.fi"
+ res = dev[1].request("DPP_CA_SET peer=%d name=trustedEapServerName value=%s" % (id1, name))
+ if "OK" not in res:
+ raise Exception("Failed to set trustedEapServerName")
+
+ with open(pkcs7_file, 'rb') as f:
+ pkcs7_der = f.read()
+ certbag = base64.b64encode(pkcs7_der).decode()
+ res = dev[1].request("DPP_CA_SET peer=%d name=certBag value=%s" % (id1, certbag))
+ if "OK" not in res:
+ raise Exception("Failed to set certBag")
+
+ ev = dev[1].wait_event(["DPP-CONF-SENT", "DPP-CONF-FAILED"], timeout=5)
+ if ev is None:
+ raise Exception("DPP configuration not completed (Configurator)")
+ if "DPP-CONF-FAILED" in ev:
+ raise Exception("DPP configuration did not succeed (Configurator)")
+
+ ev = dev[0].wait_event(["DPP-CONF-RECEIVED", "DPP-CONF-FAILED"],
+ timeout=1)
+ if ev is None:
+ raise Exception("DPP configuration not completed (Enrollee)")
+ if "DPP-CONF-FAILED" in ev:
+ raise Exception("DPP configuration did not succeed (Enrollee)")
+
+ ev = dev[0].wait_event(["DPP-CERTBAG"], timeout=1)
+ if ev is None:
+ raise Exception("DPP-CERTBAG not reported")
+ certbag = base64.b64decode(ev.split(' ')[1].encode())
+ if certbag != pkcs7_der:
+ raise Exception("DPP-CERTBAG mismatch")
+
+ #ev = dev[0].wait_event(["DPP-CACERT"], timeout=1)
+ #if ev is None:
+ # raise Exception("DPP-CACERT not reported")
+
+ ev = dev[0].wait_event(["DPP-SERVER-NAME"], timeout=1)
+ if ev is None:
+ raise Exception("DPP-SERVER-NAME not reported")
+ if ev.split(' ')[1] != name:
+ raise Exception("DPP-SERVER-NAME mismatch: " + ev)
+
+ ev = dev[0].wait_event(["DPP-NETWORK-ID"], timeout=1)
+ if ev is None:
+ raise Exception("DPP network profile not generated")
+ id = ev.split(' ')[1]
+
+ dev[0].wait_connected()
+
+def test_dpp_enterprise_reject(dev, apdev, params):
+ """DPP and enterprise EAP-TLS provisioning and CSR getting rejected"""
+ check_dpp_capab(dev[0])
+ check_dpp_capab(dev[1])
+
+ conf_id = dev[1].dpp_configurator_add()
+ id0 = dev[0].dpp_bootstrap_gen(chan="81/1", mac=True)
+ uri0 = dev[0].request("DPP_BOOTSTRAP_GET_URI %d" % id0)
+ dev[0].dpp_listen(2412)
+ csrattrs = "MAsGCSqGSIb3DQEJBw=="
+ id1 = dev[1].dpp_auth_init(uri=uri0, configurator=conf_id, conf="sta-dot1x",
+ csrattrs=csrattrs, ssid="dpp-ent")
+
+ ev = dev[1].wait_event(["DPP-CSR"], timeout=10)
+ if ev is None:
+ raise Exception("Configurator did not receive CSR")
+
+ res = dev[1].request("DPP_CA_SET peer=%d name=status value=5" % id1)
+ if "OK" not in res:
+ raise Exception("Failed to set status")
+
+ ev = dev[1].wait_event(["DPP-CONF-SENT", "DPP-CONF-FAILED"], timeout=5)
+ if ev is None:
+ raise Exception("DPP configuration not completed (Configurator)")
+ if "DPP-CONF-FAILED" in ev:
+ raise Exception("DPP configuration did not succeed (Configurator)")
+
+ ev = dev[0].wait_event(["DPP-CONF-RECEIVED", "DPP-CONF-FAILED"],
+ timeout=1)
+ if ev is None:
+ raise Exception("DPP configuration not completed (Enrollee)")
+ if "DPP-CONF-FAILED" not in ev:
+ raise Exception("DPP configuration did not fail (Enrollee)")
+
+def test_dpp_enterprise_tcp(dev, apdev, params):
+ """DPP over TCP for enterprise provisioning"""
+ try:
+ run_dpp_enterprise_tcp(dev, apdev, params)
+ finally:
+ dev[1].request("DPP_CONTROLLER_STOP")
+
+def run_dpp_enterprise_tcp(dev, apdev, params):
+ check_dpp_capab(dev[0])
+ check_dpp_capab(dev[1])
+
+ cap_lo = params['prefix'] + ".lo.pcap"
+
+ wt = WlantestCapture('lo', cap_lo)
+ time.sleep(1)
+
+ # Controller
+ conf_id = dev[1].dpp_configurator_add()
+ csrattrs = "MAsGCSqGSIb3DQEJBw=="
+ dev[1].set("dpp_configurator_params",
+ "conf=sta-dot1x configurator=%d csrattrs=%s" % (conf_id, csrattrs))
+ id_c = dev[1].dpp_bootstrap_gen()
+ uri_c = dev[1].request("DPP_BOOTSTRAP_GET_URI %d" % id_c)
+ res = dev[1].request("DPP_BOOTSTRAP_INFO %d" % id_c)
+ req = "DPP_CONTROLLER_START"
+ if "OK" not in dev[1].request(req):
+ raise Exception("Failed to start Controller")
+
+ dev[0].dpp_auth_init(uri=uri_c, role="enrollee", tcp_addr="127.0.0.1")
+ run_dpp_enterprise_tcp_end(params, dev, wt)
+
+def run_dpp_enterprise_tcp_end(params, dev, wt):
+ cert_file = params['prefix'] + ".cert.pem"
+ pkcs7_file = params['prefix'] + ".pkcs7.der"
+
+ with open("auth_serv/ec-ca.pem", "rb") as f:
+ res = f.read()
+ cacert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
+ res)
+
+ with open("auth_serv/ec-ca.key", "rb") as f:
+ res = f.read()
+ cakey = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, res)
+
+ ev = dev[1].wait_event(["DPP-CSR"], timeout=10)
+ if ev is None:
+ raise Exception("Configurator did not receive CSR")
+ id1_csr = int(ev.split(' ')[1].split('=')[1])
+ csr = ev.split(' ')[2]
+ if not csr.startswith("csr="):
+ raise Exception("Could not parse CSR event: " + ev)
+ csr = csr[4:]
+ csr = base64.b64decode(csr.encode())
+ logger.info("CSR: " + binascii.hexlify(csr).decode())
+
+ cert = dpp_sign_cert(cacert, cakey, csr)
+ with open(cert_file, 'wb') as f:
+ f.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM,
+ cert))
+ subprocess.check_call(['openssl', 'crl2pkcs7', '-nocrl',
+ '-certfile', cert_file,
+ '-certfile', 'auth_serv/ec-ca.pem',
+ '-outform', 'DER', '-out', pkcs7_file])
+
+ with open(pkcs7_file, 'rb') as f:
+ pkcs7_der = f.read()
+ certbag = base64.b64encode(pkcs7_der).decode()
+ res = dev[1].request("DPP_CA_SET peer=%d name=certBag value=%s" % (id1_csr, certbag))
+ if "OK" not in res:
+ raise Exception("Failed to set certBag")
+
+ ev = dev[1].wait_event(["DPP-CONF-SENT", "DPP-CONF-FAILED"], timeout=5)
+ if ev is None:
+ raise Exception("DPP configuration not completed (Configurator)")
+ if "DPP-CONF-FAILED" in ev:
+ raise Exception("DPP configuration did not succeed (Configurator)")
+
+ ev = dev[0].wait_event(["DPP-CONF-RECEIVED", "DPP-CONF-FAILED"],
+ timeout=1)
+ if ev is None:
+ raise Exception("DPP configuration not completed (Enrollee)")
+ if "DPP-CONF-RECEIVED" not in ev:
+ raise Exception("DPP configuration did not succeed (Enrollee)")
+
+ time.sleep(0.5)
+ wt.close()
+
+def test_dpp_enterprise_tcp2(dev, apdev, params):
+ """DPP over TCP for enterprise provisioning (Controller initiating)"""
+ try:
+ run_dpp_enterprise_tcp2(dev, apdev, params)
+ finally:
+ dev[0].request("DPP_CONTROLLER_STOP")
+ dev[1].request("DPP_CONTROLLER_STOP")
+
+def run_dpp_enterprise_tcp2(dev, apdev, params):
+ check_dpp_capab(dev[0])
+ check_dpp_capab(dev[1])
+
+ cap_lo = params['prefix'] + ".lo.pcap"
+ cert_file = params['prefix'] + ".cert.pem"
+ pkcs7_file = params['prefix'] + ".pkcs7.der"
+
+ with open("auth_serv/ec-ca.pem", "rb") as f:
+ res = f.read()
+ cacert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
+ res)
+
+ with open("auth_serv/ec-ca.key", "rb") as f:
+ res = f.read()
+ cakey = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, res)
+
+ wt = WlantestCapture('lo', cap_lo)
+ time.sleep(1)
+
+ # Client/Enrollee/Responder
+ id_e = dev[0].dpp_bootstrap_gen()
+ uri_e = dev[0].request("DPP_BOOTSTRAP_GET_URI %d" % id_e)
+ req = "DPP_CONTROLLER_START"
+ if "OK" not in dev[0].request(req):
+ raise Exception("Failed to start Client/Enrollee")
+
+ # Controller/Configurator/Initiator
+ conf_id = dev[1].dpp_configurator_add()
+ csrattrs = "MAsGCSqGSIb3DQEJBw=="
+ dev[1].dpp_auth_init(uri=uri_e, role="configurator", configurator=conf_id,
+ conf="sta-dot1x", csrattrs=csrattrs,
+ tcp_addr="127.0.0.1")
+
+ run_dpp_enterprise_tcp_end(params, dev, wt)
diff --git a/tests/hwsim/test_eap.py b/tests/hwsim/test_eap.py
index f1bf904..144e4d3 100644
--- a/tests/hwsim/test_eap.py
+++ b/tests/hwsim/test_eap.py
@@ -574,3 +574,29 @@ def test_eap_teap_eap_vendor(dev, apdev):
anonymous_identity="TEAP",
ca_cert="auth_serv/ca.pem", phase2="auth=VENDOR-TEST",
pac_file="blob://teap_pac")
+
+def test_eap_teap_client_cert(dev, apdev):
+ """EAP-TEAP with client certificate in Phase 1"""
+ check_eap_capa(dev[0], "TEAP")
+ params = int_teap_server_params(eap_teap_auth="2")
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ # verify server accept a client with certificate, but no Phase 2
+ # configuration
+ eap_connect(dev[0], hapd, "TEAP", "user",
+ anonymous_identity="TEAP",
+ phase1="teap_provisioning=2",
+ client_cert="auth_serv/user.pem",
+ private_key="auth_serv/user.key",
+ ca_cert="auth_serv/ca.pem",
+ pac_file="blob://teap_pac")
+ dev[0].dump_monitor()
+ res = eap_reauth(dev[0], "TEAP")
+ if res['tls_session_reused'] != '1':
+ raise Exception("EAP-TEAP could not use PAC session ticket")
+
+ # verify server accepts a client without certificate
+ eap_connect(dev[1], hapd, "TEAP", "user",
+ anonymous_identity="TEAP", password="password",
+ ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
+ pac_file="blob://teap_pac")
diff --git a/tests/hwsim/test_gas.py b/tests/hwsim/test_gas.py
index ec132f7..5d60779 100644
--- a/tests/hwsim/test_gas.py
+++ b/tests/hwsim/test_gas.py
@@ -487,6 +487,25 @@ def test_gas_anqp_get(dev, apdev):
if "FAIL" not in dev[0].request("HS20_ANQP_GET " + cmd):
raise Exception("Invalid HS20_ANQP_GET accepted")
+def test_gas_anqp_get_no_scan(dev, apdev):
+ """GAS/ANQP query without scan"""
+ hapd = start_ap(apdev[0])
+ bssid = apdev[0]['bssid']
+ if "OK" not in dev[0].request("ANQP_GET " + bssid + " freq=2412 258"):
+ raise Exception("ANQP_GET command failed")
+ ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
+ if ev is None:
+ raise Exception("ANQP query timed out")
+ dev[0].dump_monitor()
+
+ if "OK" not in dev[0].request("ANQP_GET 02:11:22:33:44:55 freq=2417 258"):
+ raise Exception("ANQP_GET command failed")
+ ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
+ if ev is None:
+ raise Exception("ANQP query timed out [2]")
+ if "result=FAILURE" not in ev:
+ raise Exception("Unexpected result: " + ev)
+
def test_gas_anqp_get_oom(dev, apdev):
"""GAS/ANQP query OOM"""
hapd = start_ap(apdev[0])
diff --git a/tests/hwsim/test_he.py b/tests/hwsim/test_he.py
index ce31992..28123e8 100644
--- a/tests/hwsim/test_he.py
+++ b/tests/hwsim/test_he.py
@@ -428,6 +428,7 @@ def test_he160(dev, apdev):
"hw_mode": "a",
"channel": "36",
"ht_capab": "[HT40+]",
+ "vht_capab": "[VHT160]",
"ieee80211n": "1",
"ieee80211ac": "1",
"ieee80211ax": "1",
@@ -500,6 +501,7 @@ def test_he160b(dev, apdev):
"hw_mode": "a",
"channel": "104",
"ht_capab": "[HT40-]",
+ "vht_capab": "[VHT160]",
"ieee80211n": "1",
"ieee80211ac": "1",
"ieee80211ax": "1",
@@ -605,6 +607,7 @@ def run_ap_he160_no_dfs(dev, apdev, channel, ht_capab):
"hw_mode": "a",
"channel": channel,
"ht_capab": ht_capab,
+ "vht_capab": "[VHT160]",
"ieee80211n": "1",
"ieee80211ac": "1",
"ieee80211ax": "1",
@@ -620,7 +623,7 @@ def run_ap_he160_no_dfs(dev, apdev, channel, ht_capab):
cmd = subprocess.Popen(["iw", "reg", "get"], stdout=subprocess.PIPE)
reg = cmd.stdout.readlines()
for r in reg:
- if "5490" in r and "DFS" in r:
+ if b"5490" in r and b"DFS" in r:
raise HwsimSkip("ZA regulatory rule did not have DFS requirement removed")
raise Exception("AP setup timed out")
@@ -689,6 +692,7 @@ def test_he80plus80(dev, apdev):
"hw_mode": "a",
"channel": "52",
"ht_capab": "[HT40+]",
+ "vht_capab": "[VHT160-80PLUS80]",
"ieee80211n": "1",
"ieee80211ac": "1",
"ieee80211ax": "1",
@@ -710,6 +714,7 @@ def test_he80plus80(dev, apdev):
"hw_mode": "a",
"channel": "36",
"ht_capab": "[HT40+]",
+ "vht_capab": "[VHT160-80PLUS80]",
"ieee80211n": "1",
"ieee80211ac": "1",
"ieee80211ax": "1",
diff --git a/tests/hwsim/test_ocv.py b/tests/hwsim/test_ocv.py
index bfefcf6..fc939ff 100644
--- a/tests/hwsim/test_ocv.py
+++ b/tests/hwsim/test_ocv.py
@@ -259,6 +259,7 @@ def run_wpa2_ocv_vht160(dev, apdev):
"channel": channel,
"country_code": "ZA",
"ht_capab": capab,
+ "vht_capab": "[VHT160]",
"ieee80211n": "1",
"ieee80211ac": "1",
"vht_oper_chwidth": "2",
@@ -301,6 +302,7 @@ def run_wpa2_ocv_vht80plus80(dev, apdev):
"channel": channel,
"country_code": "US",
"ht_capab": capab,
+ "vht_capab": "[VHT160-80PLUS80]",
"ieee80211n": "1",
"ieee80211ac": "1",
"vht_oper_chwidth": "3",
diff --git a/tests/hwsim/test_owe.py b/tests/hwsim/test_owe.py
index e0d3568..52c5949 100644
--- a/tests/hwsim/test_owe.py
+++ b/tests/hwsim/test_owe.py
@@ -149,23 +149,38 @@ def test_owe_transition_mode_connect_cmd(dev, apdev):
wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
run_owe_transition_mode([wpas], apdev)
-def run_owe_transition_mode(dev, apdev):
+def test_owe_transition_mode_mismatch1(dev, apdev):
+ """Opportunistic Wireless Encryption transition mode (mismatch 1)"""
+ run_owe_transition_mode(dev, apdev, adv_bssid0="02:11:22:33:44:55")
+
+def test_owe_transition_mode_mismatch2(dev, apdev):
+ """Opportunistic Wireless Encryption transition mode (mismatch 2)"""
+ run_owe_transition_mode(dev, apdev, adv_bssid1="02:11:22:33:44:66")
+
+def test_owe_transition_mode_mismatch3(dev, apdev):
+ """Opportunistic Wireless Encryption transition mode (mismatch 3)"""
+ run_owe_transition_mode(dev, apdev, adv_bssid0="02:11:22:33:44:55",
+ adv_bssid1="02:11:22:33:44:66")
+
+def run_owe_transition_mode(dev, apdev, adv_bssid0=None, adv_bssid1=None):
if "OWE" not in dev[0].get_capability("key_mgmt"):
raise HwsimSkip("OWE not supported")
dev[0].flush_scan_cache()
+ adv_bssid = adv_bssid0 if adv_bssid0 else apdev[1]['bssid']
params = {"ssid": "owe-random",
"wpa": "2",
"wpa_key_mgmt": "OWE",
"rsn_pairwise": "CCMP",
"ieee80211w": "2",
- "owe_transition_bssid": apdev[1]['bssid'],
+ "owe_transition_bssid": adv_bssid,
"owe_transition_ssid": '"owe-test"',
"ignore_broadcast_ssid": "1"}
hapd = hostapd.add_ap(apdev[0], params)
bssid = hapd.own_addr()
+ adv_bssid = adv_bssid1 if adv_bssid1 else apdev[0]['bssid']
params = {"ssid": "owe-test",
- "owe_transition_bssid": apdev[0]['bssid'],
+ "owe_transition_bssid": adv_bssid,
"owe_transition_ssid": '"owe-random"'}
hapd2 = hostapd.add_ap(apdev[1], params)
bssid2 = hapd2.own_addr()
diff --git a/tests/hwsim/test_pmksa_cache.py b/tests/hwsim/test_pmksa_cache.py
index 22db7e8..526f7f4 100644
--- a/tests/hwsim/test_pmksa_cache.py
+++ b/tests/hwsim/test_pmksa_cache.py
@@ -1098,6 +1098,66 @@ def test_pmksa_cache_ctrl_ext(dev, apdev):
if "CTRL-EVENT-EAP-STARTED" in ev:
raise Exception("Unexpected EAP exchange after external PMKSA cache restore")
+def test_pmksa_cache_ctrl_ext_ft(dev, apdev):
+ """PMKSA cache control interface for external management (FT)"""
+ params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
+ params['wpa_key_mgmt'] = "FT-EAP"
+ params['nas_identifier'] = "nas.w1.fi"
+ params['r1_key_holder'] = "000102030406"
+ params["mobility_domain"] = "a1b2"
+ hapd = hostapd.add_ap(apdev[0], params)
+ bssid = apdev[0]['bssid']
+
+ id = dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="FT-EAP",
+ eap="GPSK", identity="gpsk user",
+ password="abcdefghijklmnop0123456789abcdef",
+ scan_freq="2412")
+
+ res1 = dev[0].request("PMKSA_GET %d" % id)
+ logger.info("PMKSA_GET: " + res1)
+ if "UNKNOWN COMMAND" in res1:
+ raise HwsimSkip("PMKSA_GET not supported in the build")
+ if bssid not in res1:
+ raise Exception("PMKSA cache entry missing")
+
+ dev[0].request("REMOVE_NETWORK all")
+ dev[0].wait_disconnected()
+ dev[0].dump_monitor()
+ dev[0].request("PMKSA_FLUSH")
+
+ id = dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="FT-EAP",
+ eap="GPSK", identity="gpsk user",
+ password="abcdefghijklmnop0123456789abcdef",
+ ft_eap_pmksa_caching="1",
+ scan_freq="2412", only_add_network=True)
+ res3 = dev[0].request("PMKSA_GET %d" % id)
+ if res3 != '':
+ raise Exception("Unexpected PMKSA cache entry remains: " + res3)
+
+ for entry in res1.splitlines():
+ if "OK" not in dev[0].request("PMKSA_ADD %d %s" % (id, entry)):
+ raise Exception("Failed to add PMKSA entry")
+
+ dev[0].select_network(id)
+ ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
+ "CTRL-EVENT-CONNECTED"], timeout=15)
+ if ev is None:
+ raise Exception("Connection with the AP timed out")
+ if "CTRL-EVENT-EAP-STARTED" in ev:
+ raise Exception("Unexpected EAP exchange after external PMKSA cache restore")
+
+ dev[0].request("DISCONNECT")
+ dev[0].wait_disconnected()
+ dev[0].dump_monitor()
+ dev[0].request("PMKSA_FLUSH")
+ # Add a PMKSA cache entry for FT-EAP with PMKSA caching disabled to confirm
+ # that the PMKID is not configured to the driver (this part requires manual
+ # check of the debug log currently).
+ dev[0].set_network(id, "ft_eap_pmksa_caching", "0")
+ for entry in res1.splitlines():
+ if "OK" not in dev[0].request("PMKSA_ADD %d %s" % (id, entry)):
+ raise Exception("Failed to add PMKSA entry")
+
def test_rsn_preauth_processing(dev, apdev):
"""RSN pre-authentication processing on AP"""
params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
diff --git a/tests/hwsim/test_rrm.py b/tests/hwsim/test_rrm.py
index 2b43c4c..b9de82d 100644
--- a/tests/hwsim/test_rrm.py
+++ b/tests/hwsim/test_rrm.py
@@ -1729,6 +1729,7 @@ def test_rrm_beacon_req_passive_scan_vht160(dev, apdev):
"hw_mode": "a",
"channel": "104",
"ht_capab": "[HT40-]",
+ "vht_capab": "[VHT160]",
"ieee80211n": "1",
"ieee80211ac": "1",
"vht_oper_chwidth": "2",
diff --git a/tests/hwsim/test_sae.py b/tests/hwsim/test_sae.py
index ed6ae89..3ab29be 100644
--- a/tests/hwsim/test_sae.py
+++ b/tests/hwsim/test_sae.py
@@ -1788,8 +1788,10 @@ def build_sae_commit(bssid, addr, group=21, token=None):
def sae_rx_commit_token_req(sock, radiotap, send_two=False):
msg = sock.recv(1500)
- ver, pad, len, present = struct.unpack('<BBHL', msg[0:8])
- frame = msg[len:]
+ ver, pad, length, present = struct.unpack('<BBHL', msg[0:8])
+ frame = msg[length:]
+ if len(frame) < 4:
+ return False
fc, duration = struct.unpack('<HH', frame[0:4])
if fc != 0xb0:
return False
@@ -2603,3 +2605,68 @@ def test_sae_pmf_roam(dev, apdev):
dev[0].roam(bssid)
dev[0].dump_monitor()
+
+def test_sae_ocv_pmk(dev, apdev):
+ """SAE with OCV and fetching PMK (successful 4-way handshake)"""
+ check_sae_capab(dev[0])
+ params = hostapd.wpa2_params(ssid="test-sae",
+ passphrase="12345678")
+ params['wpa_key_mgmt'] = 'SAE'
+ params['ieee80211w'] = '2'
+ params['ocv'] = '1'
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ dev[0].set("sae_groups", "")
+ id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", ocv="1",
+ ieee80211w="2", scan_freq="2412")
+ hapd.wait_sta()
+
+ pmk_h = hapd.request("GET_PMK " + dev[0].own_addr())
+ if "FAIL" in pmk_h or len(pmk_h) == 0:
+ raise Exception("Failed to fetch PMK from hostapd during a successful authentication")
+
+ pmk_w = dev[0].get_pmk(id)
+ if pmk_h != pmk_w:
+ raise Exception("Fetched PMK does not match: hostapd %s, wpa_supplicant %s" % (pmk_h, pmk_w))
+
+def test_sae_ocv_pmk_failure(dev, apdev):
+ """SAE with OCV and fetching PMK (failed 4-way handshake)"""
+ check_sae_capab(dev[0])
+ params = hostapd.wpa2_params(ssid="test-sae",
+ passphrase="12345678")
+ params['wpa_key_mgmt'] = 'SAE'
+ params['ieee80211w'] = '2'
+ params['ocv'] = '1'
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ dev[0].set("sae_groups", "")
+ dev[0].set("oci_freq_override_eapol", "2462")
+ id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", ocv="1",
+ ieee80211w="2", scan_freq="2412", wait_connect=False)
+ ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
+ "CTRL-EVENT-DISCONNECTED"], timeout=15)
+ if ev is None:
+ raise Exception("No connection result reported")
+ if "CTRL-EVENT-CONNECTED" in ev:
+ raise Exception("Unexpected connection")
+
+ pmk_h = hapd.request("GET_PMK " + dev[0].own_addr())
+ if "FAIL" in pmk_h or len(pmk_h) == 0:
+ raise Exception("Failed to fetch PMK from hostapd during a successful authentication")
+
+ res = dev[0].request("PMKSA_GET %d" % id)
+ if not res.startswith(hapd.own_addr()):
+ raise Exception("PMKSA from wpa_supplicant does not have matching BSSID")
+ pmk_w = res.split(' ')[2]
+ if pmk_h != pmk_w:
+ raise Exception("Fetched PMK does not match: hostapd %s, wpa_supplicant %s" % (pmk_h, pmk_w))
+
+ dev[0].request("DISCONNECT")
+ time.sleep(0.1)
+ pmk_h2 = hapd.request("GET_PMK " + dev[0].own_addr())
+ res = dev[0].request("PMKSA_GET %d" % id)
+ pmk_w2 = res.split(' ')[2]
+ if pmk_h2 != pmk_h:
+ raise Exception("hostapd did not report correct PMK after disconnection")
+ if pmk_w2 != pmk_w:
+ raise Exception("wpa_supplicant did not report correct PMK after disconnection")
diff --git a/tests/hwsim/test_sae_pk.py b/tests/hwsim/test_sae_pk.py
index dfecbc5..b425b90 100644
--- a/tests/hwsim/test_sae_pk.py
+++ b/tests/hwsim/test_sae_pk.py
@@ -7,12 +7,29 @@
import hostapd
from utils import *
-def run_sae_pk(apdev, dev, ssid, pw, m, pk, ap_groups=None):
+SAE_PK_SSID = "SAE-PK test"
+
+SAE_PK_SEC3_PW = "r6cr-6ksa-56og"
+SAE_PK_SEC3_M = "089ec11475d55f0d38403f5117a6d64d"
+SAE_PK_19_PK = "MHcCAQEEIAJIGlfnteonDb7rQyP/SGQjwzrZAnfrXIm4280VWajYoAoGCCqGSM49AwEHoUQDQgAEeRkstKQV+FSAMqBayqFknn2nAQsdsh/MhdX6tiHOTAFin/sUMFRMyspPtIu7YvlKdsexhI0jPVhaYZn1jKWhZg=="
+
+SAE_PK_20_PW = "4zsy-uspe-xbfr-3ifo"
+SAE_PK_20_M = "206902f9f09b62e3fafcd487c65f5c64"
+SAE_PK_20_PK = "MIGkAgEBBDA4wpA6w/fK0g3a2V6QmcoxNoFCVuQPyzWvKYimJkgXsVsXt2ERXQ7dGOVXeycM5DqgBwYFK4EEACKhZANiAARTdszGBNe2PGCnc8Wvs+IDvdVEf4PPBrty0meRZf6UTbGouquTHpy6KKTq5sxrulYzsQFimg4op0UJBGxAzqo0EtTgMlLiBvY0I3Nl3N69MhWo8nvnmguvGGN32AAPXpQ="
+
+SAE_PK_21_PW = "vluk-umpa-3mbw-zrhe-s2n2"
+SAE_PK_21_M = "1c63c1b17e9a999f0693b4341a970a63"
+SAE_PK_21_PK = "MIHcAgEBBEIBnFBjU0ywxo1dLTYcg2aZdMfNY7JHt4GTADRTgJ7RRo9qzRIlfmK7p+BP1c8YM8ia8v7YDTut00rDOfzkdmLOi0WgBwYFK4EEACOhgYkDgYYABAD6n3DHI+qaj/lElhe2sUSKqAe4sweckMlr9bhdmwp8Wsx5lKR/Tt7WPexeqFrA47nChw5WMWy6qJanCKNFvGYG0ADUWnxesYczGtCdUYJQgs3X5tHSapMssz6tP8QL0X9adTI/H3tFYhiVIdor03eZDUVnej78/F31CcHcjGBEyItVfw=="
+
+def run_sae_pk(apdev, dev, ssid, pw, m, pk, ap_groups=None,
+ confirm_immediate=False):
params = hostapd.wpa2_params(ssid=ssid)
params['wpa_key_mgmt'] = 'SAE'
params['sae_password'] = ['%s|pk=%s:%s' % (pw, m, pk)]
if ap_groups:
params['sae_groups'] = ap_groups
+ if confirm_immediate:
+ params['sae_confirm_immediate'] = '1'
hapd = hostapd.add_ap(apdev, params)
bssid = hapd.own_addr()
@@ -22,6 +39,10 @@ def run_sae_pk(apdev, dev, ssid, pw, m, pk, ap_groups=None):
raise Exception("Could not get BSS flags from BSS table")
if "[SAE-H2E]" not in bss['flags'] or "[SAE-PK]" not in bss['flags']:
raise Exception("Unexpected BSS flags: " + bss['flags'])
+ status = dev.get_status()
+ if "sae_h2e" not in status or "sae_pk" not in status or \
+ status["sae_h2e"] != "1" or status["sae_pk"] != "1":
+ raise Exception("SAE-PK or H2E not indicated in STATUS")
dev.request("REMOVE_NETWORK *")
dev.wait_disconnected()
hapd.disable()
@@ -29,93 +50,382 @@ def run_sae_pk(apdev, dev, ssid, pw, m, pk, ap_groups=None):
def test_sae_pk(dev, apdev):
"""SAE-PK"""
check_sae_pk_capab(dev[0])
+ dev[0].flush_scan_cache()
dev[0].set("sae_groups", "")
- ssid = "SAE-PK test"
- pw = "dwxm-zv66-p5ue-fotp-owjy-lfby-2xpg-vmwq-chtz-hilu-m3t2-qleg"
- m = "431ff8322f93b9dc50ded9f3d14ace22"
- pk = "MHcCAQEEIAJIGlfnteonDb7rQyP/SGQjwzrZAnfrXIm4280VWajYoAoGCCqGSM49AwEHoUQDQgAEeRkstKQV+FSAMqBayqFknn2nAQsdsh/MhdX6tiHOTAFin/sUMFRMyspPtIu7YvlKdsexhI0jPVhaYZn1jKWhZg=="
-
- for i in range(6, len(pw) + 1):
- p = pw[:i]
- if p.endswith('-'):
- continue
- run_sae_pk(apdev[0], dev[0], ssid, p, m, pk)
+ passwords = [SAE_PK_SEC3_PW,
+ "r6cr-6ksa-56oo-5557",
+ "r6cr-6ksa-56oo-555p-wi44",
+ "r6cr-6ksa-56oo-555p-wi4b-vghb",
+ "r6cr-6ksa-56oo-555p-wi4b-vghv-vwro",
+ "r6cr-6ksa-56oo-555p-wi4b-vghv-vwrp-taqj",
+ "r6cr-6ksa-56oo-555p-wi4b-vghv-vwrp-taq5-4zfq",
+ "r6cr-6ksa-56oo-555p-wi4b-vghv-vwrp-taq5-4zfa-ye3x",
+ "r6cr-6ksa-56oo-555p-wi4b-vghv-vwrp-taq5-4zfa-ye35-4rne",
+ "r6cr-6ksa-56oo-555p-wi4b-vghv-vwrp-taq5-4zfa-ye35-4rny-5yqz"]
+ for p in passwords:
+ run_sae_pk(apdev[0], dev[0], SAE_PK_SSID, p, SAE_PK_SEC3_M,
+ SAE_PK_19_PK)
def test_sae_pk_group_negotiation(dev, apdev):
"""SAE-PK"""
check_sae_pk_capab(dev[0])
+ dev[0].flush_scan_cache()
dev[0].set("sae_groups", "20 19")
- ssid = "SAE-PK test"
- pw = "dwxm-zv66-p5ue-fotp-owjy-lfby-2xpg-vmwq-chtz-hilu-m3t2-qleg"
- m = "431ff8322f93b9dc50ded9f3d14ace22"
- pk = "MHcCAQEEIAJIGlfnteonDb7rQyP/SGQjwzrZAnfrXIm4280VWajYoAoGCCqGSM49AwEHoUQDQgAEeRkstKQV+FSAMqBayqFknn2nAQsdsh/MhdX6tiHOTAFin/sUMFRMyspPtIu7YvlKdsexhI0jPVhaYZn1jKWhZg=="
+ try:
+ run_sae_pk(apdev[0], dev[0], SAE_PK_SSID, SAE_PK_SEC3_PW,
+ SAE_PK_SEC3_M, SAE_PK_19_PK, ap_groups="19 20")
+ finally:
+ dev[0].set("sae_groups", "")
+
+def test_sae_pk_sec_3(dev, apdev):
+ """SAE-PK with Sec 3"""
+ check_sae_pk_capab(dev[0])
+ dev[0].flush_scan_cache()
+ dev[0].set("sae_groups", "")
+
+ run_sae_pk(apdev[0], dev[0], SAE_PK_SSID, SAE_PK_SEC3_PW, SAE_PK_SEC3_M,
+ SAE_PK_19_PK)
+
+def test_sae_pk_sec_5(dev, apdev):
+ """SAE-PK with Sec 5"""
+ check_sae_pk_capab(dev[0])
+ dev[0].flush_scan_cache()
+ dev[0].set("sae_groups", "")
+
+ pw = "hbbi-f4xq-b457-jjew-muei"
+ m = "d2e5fa27d1be8897f987f2d480d2af6b"
+ run_sae_pk(apdev[0], dev[0], SAE_PK_SSID, pw, m, SAE_PK_19_PK)
+
+def test_sae_pk_group_20(dev, apdev):
+ """SAE-PK with group 20"""
+ check_sae_pk_capab(dev[0])
+ dev[0].flush_scan_cache()
+ dev[0].set("sae_groups", "20")
+
+ try:
+ run_sae_pk(apdev[0], dev[0], SAE_PK_SSID, SAE_PK_20_PW,
+ SAE_PK_20_M, SAE_PK_20_PK, ap_groups="20")
+ finally:
+ dev[0].set("sae_groups", "")
+
+def test_sae_pk_group_21(dev, apdev):
+ """SAE-PK with group 21"""
+ check_sae_pk_capab(dev[0])
+ dev[0].flush_scan_cache()
+ dev[0].set("sae_groups", "21")
+
+ try:
+ run_sae_pk(apdev[0], dev[0], SAE_PK_SSID, SAE_PK_21_PW,
+ SAE_PK_21_M, SAE_PK_21_PK, ap_groups="21")
+ finally:
+ dev[0].set("sae_groups", "")
+def test_sae_pk_group_20_sae_group_19(dev, apdev):
+ """SAE-PK with group 20 with SAE group 19"""
+ check_sae_pk_capab(dev[0])
+ dev[0].flush_scan_cache()
+ dev[0].set("sae_groups", "19")
try:
- run_sae_pk(apdev[0], dev[0], ssid, pw, m, pk, ap_groups="19 20")
+ run_sae_pk(apdev[0], dev[0], SAE_PK_SSID, SAE_PK_20_PW,
+ SAE_PK_20_M, SAE_PK_20_PK, ap_groups="19")
finally:
dev[0].set("sae_groups", "")
-def test_sae_pk_sec_2(dev, apdev):
- """SAE-PK with Sec 2"""
+def test_sae_pk_group_20_sae_group_21(dev, apdev):
+ """SAE-PK with group 20 with SAE group 21"""
+ check_sae_pk_capab(dev[0])
+ dev[0].flush_scan_cache()
+ dev[0].set("sae_groups", "21")
+ try:
+ run_sae_pk(apdev[0], dev[0], SAE_PK_SSID, SAE_PK_20_PW,
+ SAE_PK_20_M, SAE_PK_20_PK, ap_groups="21")
+ finally:
+ dev[0].set("sae_groups", "")
+
+def test_sae_pk_group_19_sae_group_20(dev, apdev):
+ """SAE-PK with group 19 with SAE group 20"""
+ check_sae_pk_capab(dev[0])
+ dev[0].flush_scan_cache()
+ dev[0].set("sae_groups", "20")
+ try:
+ run_sae_pk(apdev[0], dev[0], SAE_PK_SSID, SAE_PK_SEC3_PW,
+ SAE_PK_SEC3_M, SAE_PK_19_PK, ap_groups="20")
+ finally:
+ dev[0].set("sae_groups", "")
+
+def test_sae_pk_password_without_pk(dev, apdev):
+ """SAE-PK password but not SAE-PK on the AP"""
check_sae_pk_capab(dev[0])
dev[0].set("sae_groups", "")
- ssid = "SAE-PK test"
- pw = "dwxm-zv66-p5ue"
- m = "431ff8322f93b9dc50ded9f3d14ace22"
- pk = "MHcCAQEEIAJIGlfnteonDb7rQyP/SGQjwzrZAnfrXIm4280VWajYoAoGCCqGSM49AwEHoUQDQgAEeRkstKQV+FSAMqBayqFknn2nAQsdsh/MhdX6tiHOTAFin/sUMFRMyspPtIu7YvlKdsexhI0jPVhaYZn1jKWhZg=="
+ params = hostapd.wpa2_params(ssid=SAE_PK_SSID)
+ params['wpa_key_mgmt'] = 'SAE'
+ params['sae_password'] = SAE_PK_SEC3_PW
+ hapd = hostapd.add_ap(apdev[0], params)
- run_sae_pk(apdev[0], dev[0], ssid, pw, m, pk)
+ dev[0].connect(SAE_PK_SSID, sae_password=SAE_PK_SEC3_PW,
+ key_mgmt="SAE", scan_freq="2412")
+ if dev[0].get_status_field("sae_pk") != "0":
+ raise Exception("Unexpected sae_pk STATUS value")
-def test_sae_pk_sec_3(dev, apdev):
- """SAE-PK with Sec 3"""
+def test_sae_pk_only(dev, apdev):
+ """SAE-PK only"""
check_sae_pk_capab(dev[0])
dev[0].set("sae_groups", "")
- ssid = "SAE-PK test"
- pw = "iian-qey6-pu5t"
- m = "128e51ddb5e2e24388f9ed14b687e2eb"
- pk = "MHcCAQEEIAJIGlfnteonDb7rQyP/SGQjwzrZAnfrXIm4280VWajYoAoGCCqGSM49AwEHoUQDQgAEeRkstKQV+FSAMqBayqFknn2nAQsdsh/MhdX6tiHOTAFin/sUMFRMyspPtIu7YvlKdsexhI0jPVhaYZn1jKWhZg=="
+ params = hostapd.wpa2_params(ssid=SAE_PK_SSID)
+ params['wpa_key_mgmt'] = 'SAE'
+ params['sae_password'] = SAE_PK_SEC3_PW
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ dev[0].connect(SAE_PK_SSID, sae_password=SAE_PK_SEC3_PW,
+ key_mgmt="SAE", sae_pk="1",
+ scan_freq="2412", wait_connect=False)
+ ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
+ "CTRL-EVENT-NETWORK-NOT-FOUND"], timeout=10)
+ if ev is None:
+ raise Exception("No result for the connection attempt")
+ if "CTRL-EVENT-CONNECTED" in ev:
+ raise Exception("Unexpected connection without SAE-PK")
+ dev[0].request("DISCONNECT")
+ dev[0].dump_monitor()
+
+ params = hostapd.wpa2_params(ssid=SAE_PK_SSID)
+ params['wpa_key_mgmt'] = 'SAE'
+ params['sae_password'] = ['%s|pk=%s:%s' % (SAE_PK_SEC3_PW, SAE_PK_SEC3_M,
+ SAE_PK_19_PK)]
+ hapd2 = hostapd.add_ap(apdev[1], params)
+ bssid2 = hapd2.own_addr()
- run_sae_pk(apdev[0], dev[0], ssid, pw, m, pk)
+ dev[0].scan_for_bss(bssid2, freq=2412, force_scan=True)
+ dev[0].request("RECONNECT")
+ ev = dev[0].wait_connected()
+ if bssid2 not in ev:
+ raise Exception("Unexpected connection BSSID")
+ if dev[0].get_status_field("sae_pk") != "1":
+ raise Exception("SAE-PK was not used")
-def test_sae_pk_sec_4(dev, apdev):
- """SAE-PK with Sec 4"""
+def test_sae_pk_modes(dev, apdev):
+ """SAE-PK modes"""
check_sae_pk_capab(dev[0])
dev[0].set("sae_groups", "")
- ssid = "SAE-PK test"
- pw = "ssko-2lmu-7hzs-bqct"
- m = "a5e38c7251ea310cc348fbcdadfa8bcb"
- pk = "MHcCAQEEIAJIGlfnteonDb7rQyP/SGQjwzrZAnfrXIm4280VWajYoAoGCCqGSM49AwEHoUQDQgAEeRkstKQV+FSAMqBayqFknn2nAQsdsh/MhdX6tiHOTAFin/sUMFRMyspPtIu7YvlKdsexhI0jPVhaYZn1jKWhZg=="
+ params = hostapd.wpa2_params(ssid=SAE_PK_SSID)
+ params['wpa_key_mgmt'] = 'SAE'
+ params["ieee80211w"] = "2"
+ params['sae_password'] = ['%s|pk=%s:%s' % (SAE_PK_SEC3_PW, SAE_PK_SEC3_M,
+ SAE_PK_19_PK)]
+ hapd = hostapd.add_ap(apdev[0], params)
- run_sae_pk(apdev[0], dev[0], ssid, pw, m, pk)
+ tests = [(2, 0), (1, 1), (0, 1)]
+ for sae_pk, expected in tests:
+ dev[0].connect(SAE_PK_SSID, sae_password=SAE_PK_SEC3_PW,
+ key_mgmt="SAE", sae_pk=str(sae_pk), ieee80211w="2",
+ scan_freq="2412")
+ val = dev[0].get_status_field("sae_pk")
+ if val != str(expected):
+ raise Exception("Unexpected sae_pk=%d result %s" % (sae_pk, val))
+ dev[0].request("REMOVE_NETWORK *")
+ dev[0].wait_disconnected()
+ dev[0].dump_monitor()
-def test_sae_pk_sec_5(dev, apdev):
- """SAE-PK with Sec 5"""
+def test_sae_pk_not_on_ap(dev, apdev):
+ """SAE-PK password, but no PK on AP"""
check_sae_pk_capab(dev[0])
dev[0].set("sae_groups", "")
- ssid = "SAE-PK test"
- pw = "3qqu-f4xq-dz37-fes3-fbgc"
- m = "d2e5fa27d1be8897f987f2d480d2af6b"
- pk = "MHcCAQEEIAJIGlfnteonDb7rQyP/SGQjwzrZAnfrXIm4280VWajYoAoGCCqGSM49AwEHoUQDQgAEeRkstKQV+FSAMqBayqFknn2nAQsdsh/MhdX6tiHOTAFin/sUMFRMyspPtIu7YvlKdsexhI0jPVhaYZn1jKWhZg=="
+ params = hostapd.wpa2_params(ssid=SAE_PK_SSID)
+ params['wpa_key_mgmt'] = 'SAE'
+ params['sae_password'] = SAE_PK_SEC3_PW
+ hapd = hostapd.add_ap(apdev[0], params)
- run_sae_pk(apdev[0], dev[0], ssid, pw, m, pk)
+ dev[0].connect(SAE_PK_SSID, sae_password=SAE_PK_SEC3_PW,
+ key_mgmt="SAE", scan_freq="2412")
+ if dev[0].get_status_field("sae_pk") == "1":
+ raise Exception("SAE-PK was claimed to be used")
-def test_sae_pk_group_20(dev, apdev):
- """SAE-PK with group 20"""
+def test_sae_pk_transition_disable(dev, apdev):
+ """SAE-PK transition disable indication"""
check_sae_pk_capab(dev[0])
- dev[0].set("sae_groups", "20")
+ dev[0].set("sae_groups", "")
- ssid = "SAE-PK test"
- pw = "f3bh-5un3-wz7o-al3p"
- m = "50bf37ba0033ed110a74e3a7aa52f4e9"
- pk = "MIGkAgEBBDA4wpA6w/fK0g3a2V6QmcoxNoFCVuQPyzWvKYimJkgXsVsXt2ERXQ7dGOVXeycM5DqgBwYFK4EEACKhZANiAARTdszGBNe2PGCnc8Wvs+IDvdVEf4PPBrty0meRZf6UTbGouquTHpy6KKTq5sxrulYzsQFimg4op0UJBGxAzqo0EtTgMlLiBvY0I3Nl3N69MhWo8nvnmguvGGN32AAPXpQ="
+ params = hostapd.wpa2_params(ssid=SAE_PK_SSID)
+ params['wpa_key_mgmt'] = 'SAE'
+ params['sae_password'] = ['%s|pk=%s:%s' % (SAE_PK_SEC3_PW, SAE_PK_SEC3_M,
+ SAE_PK_19_PK)]
+ params['transition_disable'] = '0x02'
+ hapd = hostapd.add_ap(apdev[0], params)
- try:
- run_sae_pk(apdev[0], dev[0], ssid, pw, m, pk, ap_groups="20")
- finally:
- dev[0].set("sae_groups", "")
+ id = dev[0].connect(SAE_PK_SSID, sae_password=SAE_PK_SEC3_PW,
+ key_mgmt="SAE", scan_freq="2412")
+ ev = dev[0].wait_event(["TRANSITION-DISABLE"], timeout=1)
+ if ev is None:
+ raise Exception("Transition disable not indicated")
+ if ev.split(' ')[1] != "02":
+ raise Exception("Unexpected transition disable bitmap: " + ev)
+
+ val = dev[0].get_network(id, "sae_pk")
+ if val != "1":
+ raise Exception("Unexpected sae_pk value: " + str(val))
+
+def test_sae_pk_mixed(dev, apdev):
+ """SAE-PK mixed deployment"""
+ run_sae_pk_mixed(dev, apdev)
+
+def test_sae_pk_mixed_immediate_confirm(dev, apdev):
+ """SAE-PK mixed deployment with immediate confirm on AP"""
+ run_sae_pk_mixed(dev, apdev, confirm_immediate=True)
+
+def run_sae_pk_mixed(dev, apdev, confirm_immediate=False):
+ check_sae_pk_capab(dev[0])
+ dev[0].set("sae_groups", "")
+
+ params = hostapd.wpa2_params(ssid=SAE_PK_SSID)
+ params['wpa_key_mgmt'] = 'SAE'
+ params['sae_password'] = SAE_PK_SEC3_PW
+ if confirm_immediate:
+ params['sae_confirm_immediate'] = '1'
+ hapd = hostapd.add_ap(apdev[0], params)
+ bssid = hapd.own_addr()
+
+ params = hostapd.wpa2_params(ssid=SAE_PK_SSID)
+ params['wpa_key_mgmt'] = 'SAE'
+ params['sae_password'] = ['%s|pk=%s:%s' % (SAE_PK_SEC3_PW, SAE_PK_SEC3_M,
+ SAE_PK_19_PK)]
+ # Disable HT from the SAE-PK BSS to make the station prefer the other BSS
+ # by default.
+ params['ieee80211n'] = '0'
+ hapd2 = hostapd.add_ap(apdev[1], params)
+ bssid2 = hapd2.own_addr()
+
+ dev[0].scan_for_bss(bssid, freq=2412)
+ dev[0].scan_for_bss(bssid2, freq=2412)
+
+ dev[0].connect(SAE_PK_SSID, sae_password=SAE_PK_SEC3_PW,
+ key_mgmt="SAE", scan_freq="2412")
+
+ if dev[0].get_status_field("sae_pk") != "1":
+ raise Exception("SAE-PK was not used")
+ if dev[0].get_status_field("bssid") != bssid2:
+ raise Exception("Unexpected BSSID selected")
+
+def check_sae_pk_sta_connect_failure(dev):
+ dev.connect(SAE_PK_SSID, sae_password=SAE_PK_SEC3_PW,
+ key_mgmt="SAE", scan_freq="2412", wait_connect=False)
+ ev = dev.wait_event(["CTRL-EVENT-CONNECTED",
+ "CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=10)
+ if ev is None:
+ raise Exception("No result for the connection attempt")
+ if "CTRL-EVENT-CONNECTED" in ev:
+ raise Exception("Unexpected connection")
+
+def test_sae_pk_missing_ie(dev, apdev):
+ """SAE-PK and missing SAE-PK IE in confirm"""
+ check_sae_pk_capab(dev[0])
+ dev[0].set("sae_groups", "")
+
+ params = hostapd.wpa2_params(ssid=SAE_PK_SSID)
+ params['wpa_key_mgmt'] = 'SAE'
+ params['sae_password'] = ['%s|pk=%s:%s' % (SAE_PK_SEC3_PW, SAE_PK_SEC3_M,
+ SAE_PK_19_PK)]
+ params['sae_pk_omit'] = '1'
+ hapd = hostapd.add_ap(apdev[0], params)
+ check_sae_pk_sta_connect_failure(dev[0])
+
+def test_sae_pk_unexpected_status(dev, apdev):
+ """SAE-PK and unexpected status code in commit"""
+ check_sae_pk_capab(dev[0])
+ dev[0].set("sae_groups", "")
+
+ params = hostapd.wpa2_params(ssid=SAE_PK_SSID)
+ params['wpa_key_mgmt'] = 'SAE'
+ params['sae_password'] = ['%s|pk=%s:%s' % (SAE_PK_SEC3_PW, SAE_PK_SEC3_M,
+ SAE_PK_19_PK)]
+ params['sae_commit_status'] = '126'
+ hapd = hostapd.add_ap(apdev[0], params)
+ check_sae_pk_sta_connect_failure(dev[0])
+
+def test_sae_pk_invalid_signature(dev, apdev):
+ """SAE-PK and invalid signature"""
+ check_sae_pk_capab(dev[0])
+ dev[0].set("sae_groups", "")
+
+ other = "MHcCAQEEILw+nTjFzRyhVea0G6KbwZu18oWrfhzppxj+MceUO3YLoAoGCCqGSM49AwEHoUQDQgAELdou6LuTDNiMVlMB65KsWhQFbPXR9url0EA6luWzUfAuGoDXYJUBTVz6Nv3mz6oQcDrSiDmz/LejndJ0YHGgfQ=="
+ params = hostapd.wpa2_params(ssid=SAE_PK_SSID)
+ params['wpa_key_mgmt'] = 'SAE'
+ params['sae_password'] = ['%s|pk=%s:%s:%s' % (SAE_PK_SEC3_PW, SAE_PK_SEC3_M,
+ SAE_PK_19_PK, other)]
+ hapd = hostapd.add_ap(apdev[0], params)
+ check_sae_pk_sta_connect_failure(dev[0])
+
+def test_sae_pk_invalid_fingerprint(dev, apdev):
+ """SAE-PK and invalid fingerprint"""
+ check_sae_pk_capab(dev[0])
+ dev[0].set("sae_groups", "")
+
+ other = "431ff8322f93b9dc50ded9f3d14ace21"
+ params = hostapd.wpa2_params(ssid=SAE_PK_SSID)
+ params['wpa_key_mgmt'] = 'SAE'
+ params['sae_password'] = ['%s|pk=%s:%s' % (SAE_PK_SEC3_PW, other,
+ SAE_PK_19_PK)]
+ hapd = hostapd.add_ap(apdev[0], params)
+ check_sae_pk_sta_connect_failure(dev[0])
+
+def test_sae_pk_confirm_immediate(dev, apdev):
+ """SAE-PK with immediate confirm on AP"""
+ check_sae_pk_capab(dev[0])
+ dev[0].flush_scan_cache()
+ dev[0].set("sae_groups", "")
+
+ run_sae_pk(apdev[0], dev[0], SAE_PK_SSID, SAE_PK_SEC3_PW,
+ SAE_PK_SEC3_M, SAE_PK_19_PK, confirm_immediate=True)
+
+def test_sae_pk_and_psk(dev, apdev):
+ """SAE-PK and PSK"""
+ check_sae_pk_capab(dev[0])
+ dev[0].flush_scan_cache()
+ dev[0].set("sae_groups", "")
+ dev[2].set("sae_groups", "")
+
+ params = hostapd.wpa2_params(ssid=SAE_PK_SSID)
+ params['wpa_key_mgmt'] = 'SAE WPA-PSK'
+ params['sae_password'] = ['%s|pk=%s:%s' % (SAE_PK_SEC3_PW,
+ SAE_PK_SEC3_M,
+ SAE_PK_19_PK)]
+ params['wpa_passphrase'] = SAE_PK_SEC3_PW
+ hapd = hostapd.add_ap(apdev[0], params)
+ bssid = hapd.own_addr()
+
+ dev[0].connect(SAE_PK_SSID, sae_password=SAE_PK_SEC3_PW, key_mgmt="SAE",
+ scan_freq="2412")
+ dev[1].connect(SAE_PK_SSID, psk=SAE_PK_SEC3_PW, key_mgmt="WPA-PSK",
+ scan_freq="2412")
+ dev[2].connect(SAE_PK_SSID, sae_password=SAE_PK_SEC3_PW, key_mgmt="SAE",
+ sae_pk="2", scan_freq="2412")
+ dev[0].request("REMOVE_NETWORK *")
+ dev[0].wait_disconnected()
+ dev[0].dump_monitor()
+ dev[0].connect(SAE_PK_SSID, psk=SAE_PK_SEC3_PW, key_mgmt="SAE",
+ scan_freq="2412")
+ status = dev[0].get_status()
+ if "sae_h2e" not in status or "sae_pk" not in status or \
+ status["sae_h2e"] != "1" or status["sae_pk"] != "1":
+ raise Exception("SAE-PK or H2E not indicated in STATUS")
+
+def test_sae_pk_and_psk_invalid_password(dev, apdev):
+ """SAE-PK and PSK using invalid password combination"""
+ check_sae_pk_capab(dev[0])
+ dev[0].flush_scan_cache()
+
+ params = hostapd.wpa2_params(ssid=SAE_PK_SSID)
+ params['wpa_key_mgmt'] = 'SAE WPA-PSK'
+ params['sae_password'] = ['%s|pk=%s:%s' % (SAE_PK_SEC3_PW,
+ SAE_PK_SEC3_M,
+ SAE_PK_19_PK)]
+ params['wpa_passphrase'] = SAE_PK_20_PW
+ hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
+ res = hapd.request("ENABLE")
+ if "FAIL" not in res:
+ raise Exception("Invalid configuration accepted")
diff --git a/tests/hwsim/test_sigma_dut.py b/tests/hwsim/test_sigma_dut.py
index b87f44b..e2151cf 100644
--- a/tests/hwsim/test_sigma_dut.py
+++ b/tests/hwsim/test_sigma_dut.py
@@ -23,11 +23,13 @@ from utils import *
from hwsim import HWSimRadio
import hwsim_utils
from wlantest import Wlantest
+from tshark import run_tshark
from test_dpp import check_dpp_capab, update_hapd_config, wait_auth_success
from test_suite_b import check_suite_b_192_capa, suite_b_as_params, suite_b_192_rsa_ap_params
from test_ap_eap import check_eap_capa, int_eap_server_params, check_domain_match, check_domain_suffix_match
from test_ap_hs20 import hs20_ap_params
from test_ap_pmf import check_mac80211_bigtk
+from test_ocv import check_ocv_failure
def check_sigma_dut():
if not os.path.exists("./sigma_dut"):
@@ -1529,6 +1531,23 @@ def test_sigma_dut_dpp_qr_resp_10(dev, apdev):
"""sigma_dut DPP/QR responder (conf index 10)"""
run_sigma_dut_dpp_qr_resp(dev, apdev, 10)
+def test_sigma_dut_dpp_qr_resp_11(dev, apdev, params):
+ """sigma_dut DPP/QR responder (conf index 11)"""
+ if not os.path.exists("./dpp-ca.py"):
+ raise HwsimSkip("dpp-ca.py not available")
+ logdir = params['logdir']
+ with open("auth_serv/ec-ca.pem", "rb") as f:
+ res = f.read()
+ with open(os.path.join(logdir, "dpp-ca.pem"), "wb") as f:
+ f.write(res)
+ with open("auth_serv/ec-ca.key", "rb") as f:
+ res = f.read()
+ with open(os.path.join(logdir, "dpp-ca.key"), "wb") as f:
+ f.write(res)
+ with open(os.path.join(logdir, "dpp-ca-csrattrs"), "wb") as f:
+ f.write(b'MAsGCSqGSIb3DQEJBw==')
+ run_sigma_dut_dpp_qr_resp(dev, apdev, 11, cert_path=logdir)
+
def test_sigma_dut_dpp_qr_resp_chan_list(dev, apdev):
"""sigma_dut DPP/QR responder (channel list override)"""
run_sigma_dut_dpp_qr_resp(dev, apdev, 1, chan_list='81/2 81/6 81/1',
@@ -1553,10 +1572,10 @@ def test_sigma_dut_dpp_qr_resp_configurator(dev, apdev):
def run_sigma_dut_dpp_qr_resp(dev, apdev, conf_idx, chan_list=None,
listen_chan=None, status_query=False,
- enrollee_role="STA"):
+ enrollee_role="STA", cert_path=None):
check_dpp_capab(dev[0])
check_dpp_capab(dev[1])
- sigma = start_sigma_dut(dev[0].ifname)
+ sigma = start_sigma_dut(dev[0].ifname, cert_path=cert_path)
try:
cmd = "dev_exec_action,program,DPP,DPPActionType,GetLocalBootstrap,DPPCryptoIdentifier,P-256,DPPBS,QR"
if chan_list:
@@ -2004,9 +2023,14 @@ def test_sigma_dut_dpp_qr_init_configurator_neg_freq(dev, apdev):
"""sigma_dut DPP/QR initiator as Configurator (neg_freq)"""
run_sigma_dut_dpp_qr_init_configurator(dev, apdev, 1, extra='DPPSubsequentChannel,81/11')
+def test_sigma_dut_dpp_qr_init_configurator_mud_url(dev, apdev):
+ """sigma_dut DPP/QR initiator as Configurator (MUD URL)"""
+ run_sigma_dut_dpp_qr_init_configurator(dev, apdev, 1,
+ mud_url="https://example.com/mud")
+
def run_sigma_dut_dpp_qr_init_configurator(dev, apdev, conf_idx,
prov_role="Configurator",
- extra=None):
+ extra=None, mud_url=None):
check_dpp_capab(dev[0])
check_dpp_capab(dev[1])
sigma = start_sigma_dut(dev[0].ifname)
@@ -2014,6 +2038,8 @@ def run_sigma_dut_dpp_qr_init_configurator(dev, apdev, conf_idx,
id0 = dev[1].dpp_bootstrap_gen(chan="81/6", mac=True)
uri0 = dev[1].request("DPP_BOOTSTRAP_GET_URI %d" % id0)
+ if mud_url:
+ dev[1].set("dpp_mud_url", mud_url)
cmd = "DPP_LISTEN 2437 role=enrollee"
if "OK" not in dev[1].request(cmd):
raise Exception("Failed to start listen operation")
@@ -2028,7 +2054,10 @@ def run_sigma_dut_dpp_qr_init_configurator(dev, apdev, conf_idx,
res = sigma_dut_cmd(cmd)
if "BootstrapResult,OK,AuthResult,OK,ConfResult,OK" not in res:
raise Exception("Unexpected result: " + res)
+ if mud_url and ",MUDURL," + mud_url not in res:
+ raise Exception("Unexpected result (missing MUD URL): " + res)
finally:
+ dev[1].set("dpp_mud_url", "")
stop_sigma_dut(sigma)
def test_sigma_dut_dpp_incompatible_roles_init(dev, apdev):
@@ -3055,6 +3084,37 @@ def test_sigma_dut_dpp_tcp_enrollee_init(dev, apdev):
stop_sigma_dut(sigma)
dev[1].request("DPP_CONTROLLER_STOP")
+def test_sigma_dut_ap_dpp_tcp_enrollee_init(dev, apdev, params):
+ """sigma_dut DPP AP as TCP Enrollee/initiator"""
+ logdir = params['prefix'] + ".sigma-hostapd"
+ with HWSimRadio() as (radio, iface):
+ sigma = start_sigma_dut(iface, hostapd_logdir=logdir)
+ try:
+ run_sigma_dut_ap_dpp_tcp_enrollee_init(dev, apdev)
+ finally:
+ stop_sigma_dut(sigma)
+ dev[1].request("DPP_CONTROLLER_STOP")
+
+def run_sigma_dut_ap_dpp_tcp_enrollee_init(dev, apdev):
+ check_dpp_capab(dev[1])
+ # Controller
+ conf_id = dev[1].dpp_configurator_add()
+ dev[1].set("dpp_configurator_params",
+ "conf=ap-dpp configurator=%d" % conf_id)
+ id_c = dev[1].dpp_bootstrap_gen()
+ uri_c = dev[1].request("DPP_BOOTSTRAP_GET_URI %d" % id_c)
+ if "OK" not in dev[1].request("DPP_CONTROLLER_START"):
+ raise Exception("Failed to start Controller")
+
+ sigma_dut_cmd_check("ap_reset_default,program,DPP")
+ sigma_dut_cmd_check("ap_preset_testparameters,Program,DPP,NAME,AP,oper_chn,6")
+ sigma_dut_cmd_check("dev_exec_action,program,DPP,DPPActionType,SetPeerBootstrap,DPPBootstrappingdata,%s,DPPBS,QR" % to_hex(uri_c))
+
+ cmd = "dev_exec_action,program,DPP,DPPActionType,AutomaticDPP,DPPAuthRole,Initiator,DPPProvisioningRole,Enrollee,DPPBS,QR,DPPOverTCP,127.0.0.1,DPPTimeout,6"
+ res = sigma_dut_cmd(cmd, timeout=10)
+ if "BootstrapResult,OK,AuthResult,OK,ConfResult,OK" not in res:
+ raise Exception("Unexpected result: " + res)
+
def test_sigma_dut_dpp_tcp_enrollee_init_mutual(dev, apdev):
"""sigma_dut DPP TCP Enrollee as initiator with mutual authentication"""
check_dpp_capab(dev[0], min_ver=2)
@@ -3275,6 +3335,140 @@ def test_sigma_dut_dpp_nfc_static_write_enrollee(dev, apdev):
dev[0].set("dpp_config_processing", "0")
stop_sigma_dut(sigma)
+def test_sigma_dut_dpp_reconfig_enrollee(dev, apdev):
+ """sigma_dut DPP reconfiguration (Enrollee)"""
+ check_dpp_capab(dev[0])
+ check_dpp_capab(dev[1])
+ hapd = start_dpp_ap(apdev[0])
+ sigma = start_sigma_dut(dev[0].ifname)
+ try:
+ cmd = "DPP_CONFIGURATOR_ADD key=" + csign
+ res = dev[1].request(cmd)
+ if "FAIL" in res:
+ raise Exception("Failed to add configurator")
+ conf_id = int(res)
+
+ id0 = dev[1].dpp_bootstrap_gen(chan="81/6", mac=True)
+ uri0 = dev[1].request("DPP_BOOTSTRAP_GET_URI %d" % id0)
+
+ dev[1].set("dpp_configurator_params",
+ " conf=sta-dpp ssid=%s configurator=%d" % (to_hex("DPPNET01"), conf_id))
+ cmd = "DPP_LISTEN 2437 role=configurator"
+ if "OK" not in dev[1].request(cmd):
+ raise Exception("Failed to start listen operation")
+
+ ifname = dev[0].ifname
+ sigma_dut_cmd_check("sta_reset_default,interface,%s,prog,DPP" % ifname)
+
+ res = sigma_dut_cmd("dev_exec_action,program,DPP,DPPActionType,SetPeerBootstrap,DPPBootstrappingdata,%s,DPPBS,QR" % to_hex(uri0))
+ if "status,COMPLETE" not in res:
+ raise Exception("dev_exec_action did not succeed: " + res)
+
+ res = sigma_dut_cmd("dev_exec_action,program,DPP,DPPActionType,AutomaticDPP,DPPAuthRole,Initiator,DPPAuthDirection,Single,DPPProvisioningRole,Enrollee,DPPBS,QR,DPPTimeout,6,DPPWaitForConnect,Yes", timeout=10)
+ if "BootstrapResult,OK,AuthResult,OK,ConfResult,OK,NetworkIntroResult,OK,NetworkConnectResult,OK" not in res:
+ raise Exception("Unexpected result: " + res)
+
+ hapd.disable()
+ dev[0].dump_monitor()
+
+ ssid = "reconfig"
+ passphrase = "secret passphrase"
+ params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ dev[1].set("dpp_configurator_params",
+ "conf=sta-psk ssid=%s pass=%s conn_status=1" % (binascii.hexlify(ssid.encode()).decode(), binascii.hexlify(passphrase.encode()).decode()))
+ cmd = "DPP_LISTEN 2437 role=configurator"
+ if "OK" not in dev[1].request(cmd):
+ raise Exception("Failed to start listen operation")
+ dev[1].dump_monitor()
+
+ res = sigma_dut_cmd("dev_exec_action,program,DPP,DPPActionType,DPPReconfigure,DPPTimeout,6,DPPWaitForConnect,Yes", timeout=10)
+ if "status,COMPLETE,ReconfigAuthResult,OK,ConfResult,OK,NetworkConnectResult,OK" not in res:
+ raise Exception("Unexpected reconfiguration result: " + res)
+
+ ev = dev[1].wait_event(["DPP-CONF-SENT"], timeout=15)
+ if ev is None:
+ raise Exception("DPP Config Response (reconfig) not transmitted")
+
+ dev[0].wait_connected()
+ ev = dev[1].wait_event(["DPP-CONN-STATUS-RESULT"], timeout=20)
+ if ev is None:
+ raise Exception("No connection status reported")
+ if "result=0" not in ev:
+ raise Exception("Connection status did not report success: " + ev)
+
+ time.sleep(1)
+ cmd = "DPP_LISTEN 2437 role=configurator"
+ if "OK" not in dev[1].request(cmd):
+ raise Exception("Failed to start listen operation")
+ dev[0].dump_monitor()
+ dev[1].dump_monitor()
+
+ res = sigma_dut_cmd("dev_exec_action,program,DPP,DPPActionType,DPPReconfigure,DPPTimeout,6,DPPWaitForConnect,Yes", timeout=30)
+ if "status,COMPLETE,ReconfigAuthResult,OK,ConfResult,OK,NetworkConnectResult,OK" not in res:
+ raise Exception("Unexpected reconfiguration [2] result: " + res)
+
+ ev = dev[1].wait_event(["DPP-CONF-SENT"], timeout=5)
+ if ev is None:
+ raise Exception("DPP Config Response (reconfig) not transmitted [2]")
+
+ dev[0].wait_connected()
+ finally:
+ dev[0].set("dpp_config_processing", "0")
+ stop_sigma_dut(sigma)
+
+def test_sigma_dut_dpp_reconfig_configurator(dev, apdev):
+ """sigma_dut DPP reconfiguration (Configurator)"""
+ check_dpp_capab(dev[0])
+ check_dpp_capab(dev[1])
+ sigma = start_sigma_dut(dev[0].ifname)
+ try:
+ dev[1].set("dpp_config_processing", "1")
+ id0 = dev[1].dpp_bootstrap_gen(chan="81/6", mac=True)
+ uri0 = dev[1].request("DPP_BOOTSTRAP_GET_URI %d" % id0)
+ cmd = "DPP_LISTEN 2437"
+ if "OK" not in dev[1].request(cmd):
+ raise Exception("Failed to start listen operation")
+
+ ifname = dev[0].ifname
+ sigma_dut_cmd_check("sta_reset_default,interface,%s,prog,DPP" % ifname)
+
+ res = sigma_dut_cmd("dev_exec_action,program,DPP,DPPActionType,SetPeerBootstrap,DPPBootstrappingdata,%s,DPPBS,QR" % to_hex(uri0))
+ if "status,COMPLETE" not in res:
+ raise Exception("dev_exec_action did not succeed: " + res)
+
+ res = sigma_dut_cmd("dev_exec_action,program,DPP,DPPActionType,AutomaticDPP,DPPAuthRole,Initiator,DPPAuthDirection,Single,DPPProvisioningRole,Configurator,DPPConfEnrolleeRole,STA,DPPSigningKeyECC,P-256,DPPConfIndex,1,DPPBS,QR,DPPTimeout,6", timeout=10)
+ if "BootstrapResult,OK,AuthResult,OK,ConfResult,OK" not in res:
+ raise Exception("Unexpected result: " + res)
+
+ dev[0].dump_monitor()
+
+ ev = dev[1].wait_event(["DPP-NETWORK-ID"], timeout=1)
+ if ev is None:
+ raise Exception("No network profile created")
+ id = int(ev.split(' ')[1])
+
+ ev = dev[1].wait_event(["DPP-TX-STATUS"], timeout=5)
+ if ev is None:
+ raise Exception("Configuration Result not sent")
+ dev[1].dump_monitor()
+ cmd = "DPP_RECONFIG %d" % id
+ if "OK" not in dev[1].request(cmd):
+ raise Exception("Failed to start reconfiguration")
+
+ res = sigma_dut_cmd("dev_exec_action,program,DPP,DPPActionType,DPPReconfigure,DPPProvisioningRole,Configurator,DPPConfEnrolleeRole,STA,DPPSigningKeyECC,P-256,DPPConfIndex,2,DPPListenChannel,6,DPPTimeout,6", timeout=10)
+ if "status,COMPLETE,ReconfigAuthResult,OK,ConfResult,OK" not in res:
+ raise Exception("Unexpected reconfiguration result: " + res)
+
+ ev = dev[1].wait_event(["DPP-CONF-RECEIVED"], timeout=15)
+ if ev is None:
+ raise Exception("DPP Config Response (reconfig) not received")
+ finally:
+ dev[0].set("dpp_config_processing", "0")
+ dev[1].set("dpp_config_processing", "0")
+ stop_sigma_dut(sigma)
+
@reset_ignore_old_scan_res
def test_sigma_dut_preconfigured_profile(dev, apdev):
"""sigma_dut controlled connection using preconfigured profile"""
@@ -3377,6 +3571,15 @@ def test_sigma_dut_sta_scan_short_ssid(dev, apdev):
if not found:
raise Exception("AP not found in scan results")
+def test_sigma_dut_sta_scan_wait_completion(dev, apdev):
+ """sigma_dut sta_scan WaitCompletion,1"""
+ sigma = start_sigma_dut(dev[0].ifname)
+ try:
+ cmd = "sta_scan,Interface,%s,ChnlFreq,2412,WaitCompletion,1" % dev[0].ifname
+ res = sigma_dut_cmd(cmd, timeout=10)
+ finally:
+ stop_sigma_dut(sigma)
+
def test_sigma_dut_ap_osen(dev, apdev, params):
"""sigma_dut controlled AP with OSEN"""
logdir = os.path.join(params['logdir'],
@@ -4438,6 +4641,7 @@ def test_sigma_dut_ap_beacon_prot(dev, apdev, params):
sigma_dut_cmd_check("ap_set_security,NAME,AP,KEYMGNT,WPA2-PSK,PSK,12345678,PMF,Required,BeaconProtection,1")
sigma_dut_cmd_check("ap_config_commit,NAME,AP")
bssid = sigma_dut_cmd_check("ap_get_mac_address,NAME,AP")
+ bssid = bssid.split(',')[3]
dev[0].connect("test-psk", key_mgmt="WPA-PSK-SHA256",
psk="12345678", scan_freq="2412",
@@ -4466,7 +4670,6 @@ def test_sigma_dut_ap_transition_disable(dev, apdev, params):
sigma_dut_cmd_check("ap_set_wireless,NAME,AP,CHANNEL,1,SSID,test-sae,MODE,11ng")
sigma_dut_cmd_check("ap_set_security,NAME,AP,KEYMGNT,WPA2-SAE,PSK,12345678,PMF,Required,Transition_Disable,1,Transition_Disable_Index,0")
sigma_dut_cmd_check("ap_config_commit,NAME,AP")
- bssid = sigma_dut_cmd_check("ap_get_mac_address,NAME,AP")
dev[0].set("sae_groups", "")
dev[0].connect("test-sae", key_mgmt="SAE", psk="12345678",
@@ -4481,6 +4684,40 @@ def test_sigma_dut_ap_transition_disable(dev, apdev, params):
finally:
stop_sigma_dut(sigma)
+def test_sigma_dut_ap_transition_disable_change(dev, apdev, params):
+ """sigma_dut controlled AP and transition disabled indication change"""
+ logdir = params['prefix'] + ".sigma-hostapd"
+
+ with HWSimRadio() as (radio, iface):
+ sigma = start_sigma_dut(iface, hostapd_logdir=logdir)
+ try:
+ sigma_dut_cmd_check("ap_reset_default")
+ sigma_dut_cmd_check("ap_set_wireless,NAME,AP,CHANNEL,1,SSID,test-sae,MODE,11ng")
+ sigma_dut_cmd_check("ap_set_security,NAME,AP,KEYMGNT,WPA2-SAE,PSK,12345678,PMF,Required")
+ sigma_dut_cmd_check("ap_config_commit,NAME,AP")
+ dev[0].set("sae_groups", "")
+ dev[0].connect("test-sae", key_mgmt="SAE", psk="12345678",
+ ieee80211w="2", scan_freq="2412")
+ ev = dev[0].wait_event(["TRANSITION-DISABLE"], timeout=1)
+ if ev is not None:
+ raise Exception("Unexpected transition disable indication")
+ dev[0].request("DISCONNECT")
+ dev[0].wait_disconnected()
+ dev[0].dump_monitor()
+
+ sigma_dut_cmd_check("ap_set_rfeature,NAME,AP,Transition_Disable,1,Transition_Disable_Index,0")
+ dev[0].request("RECONNECT")
+ dev[0].wait_connected()
+ ev = dev[0].wait_event(["TRANSITION-DISABLE"], timeout=1)
+ if ev is None:
+ raise Exception("Transition disable not indicated")
+ if ev.split(' ')[1] != "01":
+ raise Exception("Unexpected transition disable bitmap: " + ev)
+
+ sigma_dut_cmd_check("ap_reset_default")
+ finally:
+ stop_sigma_dut(sigma)
+
def test_sigma_dut_ft_rsnxe_used_mismatch(dev, apdev):
"""sigma_dut controlled FT protocol with RSNXE Used mismatch"""
if "SAE" not in dev[0].get_capability("auth_alg"):
@@ -4632,3 +4869,392 @@ def test_sigma_dut_ocv(dev, apdev):
sigma_dut_cmd_check("sta_reset_default,interface," + ifname)
finally:
stop_sigma_dut(sigma)
+
+def test_sigma_dut_ap_ocv(dev, apdev, params):
+ """sigma_dut controlled AP using OCV"""
+ logdir = params['prefix'] + ".sigma-hostapd"
+ conffile = params['prefix'] + ".sigma-conf"
+ if "SAE" not in dev[0].get_capability("auth_alg"):
+ raise HwsimSkip("SAE not supported")
+ with HWSimRadio() as (radio, iface):
+ sigma = start_sigma_dut(iface, hostapd_logdir=logdir)
+ try:
+ sigma_dut_cmd_check("ap_reset_default")
+ sigma_dut_cmd_check("ap_set_wireless,NAME,AP,CHANNEL,1,SSID,test-sae,MODE,11ng")
+ sigma_dut_cmd_check("ap_set_wireless,NAME,AP,ocvc,1")
+ sigma_dut_cmd_check("ap_set_security,NAME,AP,KEYMGNT,WPA2-SAE,PSK,12345678")
+ sigma_dut_cmd_check("ap_config_commit,NAME,AP")
+ bssid = sigma_dut_cmd_check("ap_get_mac_address,NAME,AP")
+ bssid = bssid.split(',')[3]
+
+ with open("/tmp/sigma_dut-ap.conf", "rb") as f:
+ with open(conffile, "wb") as f2:
+ f2.write(f.read())
+
+ dev[0].set("sae_groups", "")
+ dev[0].connect("test-sae", key_mgmt="SAE", psk="12345678",
+ ieee80211w="2", ocv="1", scan_freq="2412")
+ dev[0].request("REMOVE_NETWORK all")
+ dev[0].wait_disconnected()
+ dev[0].dump_monitor()
+
+ sigma_dut_cmd_check("ap_set_rfeature,NAME,AP,type,WPA3,OCIFrameType,eapolM3,OCIChannel,3")
+ dev[0].connect("test-sae", key_mgmt="SAE", psk="12345678",
+ ieee80211w="2", ocv="1", scan_freq="2412",
+ wait_connect=False)
+ check_ocv_failure(dev[0], "EAPOL-Key msg 3/4", "eapol-key-m3",
+ bssid)
+ dev[0].request("REMOVE_NETWORK all")
+ dev[0].wait_disconnected()
+ dev[0].dump_monitor()
+
+ sigma_dut_cmd_check("ap_reset_default")
+ finally:
+ stop_sigma_dut(sigma)
+
+def test_sigma_dut_gtk_rekey(dev, apdev):
+ """sigma_dut controlled STA requesting GTK rekeying"""
+ if "SAE" not in dev[0].get_capability("auth_alg"):
+ raise HwsimSkip("SAE not supported")
+
+ ifname = dev[0].ifname
+ sigma = start_sigma_dut(ifname)
+
+ try:
+ ssid = "test-sae"
+ params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+ params['wpa_key_mgmt'] = 'SAE'
+ params["ieee80211w"] = "2"
+ params['sae_groups'] = '19'
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ sigma_dut_cmd_check("sta_reset_default,interface,%s,prog,WPA3" % ifname)
+ sigma_dut_cmd_check("sta_set_ip_config,interface,%s,dhcp,0,ip,127.0.0.11,mask,255.255.255.0" % ifname)
+ sigma_dut_cmd_check("sta_set_wireless,interface,%s,program,WPA3,ocvc,1" % ifname)
+ sigma_dut_cmd_check("sta_set_security,interface,%s,ssid,%s,passphrase,%s,type,SAE,encpType,aes-ccmp,keymgmttype,wpa2" % (ifname, "test-sae", "12345678"))
+ sigma_dut_cmd_check("sta_associate,interface,%s,ssid,%s,channel,1" % (ifname, "test-sae"),
+ timeout=10)
+ sigma_dut_wait_connected(ifname)
+
+ dev[0].dump_monitor()
+ sigma_dut_cmd_check("dev_exec_action,interface,%s,program,WPA3,KeyRotation,1" % ifname)
+ ev = dev[0].wait_event(["WPA: Group rekeying completed"], timeout=5)
+ if ev is None:
+ raise Exception("GTK rekeying not seen")
+
+ sigma_dut_cmd_check("sta_reset_default,interface," + ifname)
+ finally:
+ stop_sigma_dut(sigma)
+
+def test_sigma_dut_ap_gtk_rekey(dev, apdev, params):
+ """sigma_dut controlled AP and requested GTK rekeying"""
+ logdir = params['prefix'] + ".sigma-hostapd"
+ if "SAE" not in dev[0].get_capability("auth_alg"):
+ raise HwsimSkip("SAE not supported")
+ with HWSimRadio() as (radio, iface):
+ sigma = start_sigma_dut(iface, hostapd_logdir=logdir)
+ try:
+ sigma_dut_cmd_check("ap_reset_default")
+ sigma_dut_cmd_check("ap_set_wireless,NAME,AP,CHANNEL,1,SSID,test-sae,MODE,11ng")
+ sigma_dut_cmd_check("ap_set_security,NAME,AP,KEYMGNT,WPA2-SAE,PSK,12345678")
+ sigma_dut_cmd_check("ap_config_commit,NAME,AP")
+
+ dev[0].set("sae_groups", "")
+ dev[0].connect("test-sae", key_mgmt="SAE", psk="12345678",
+ ieee80211w="2", scan_freq="2412")
+ dev[0].dump_monitor()
+
+ sigma_dut_cmd_check("dev_exec_action,name,AP,interface,%s,program,WPA3,KeyRotation,1" % iface)
+
+ ev = dev[0].wait_event(["WPA: Group rekeying completed"], timeout=5)
+ if ev is None:
+ raise Exception("GTK rekeying not seen")
+
+ sigma_dut_cmd_check("ap_reset_default")
+ finally:
+ stop_sigma_dut(sigma)
+
+def test_sigma_dut_sae_pk(dev, apdev):
+ """sigma_dut controlled STA using SAE-PK"""
+ if "SAE" not in dev[0].get_capability("auth_alg"):
+ raise HwsimSkip("SAE not supported")
+
+ ifname = dev[0].ifname
+ sigma = start_sigma_dut(ifname)
+
+ ssid = "SAE-PK test"
+ pw = "hbbi-f4xq-b45g"
+ m = "d2e5fa27d1be8897f987f2d480d2af6b"
+ pk = "MHcCAQEEIAJIGlfnteonDb7rQyP/SGQjwzrZAnfrXIm4280VWajYoAoGCCqGSM49AwEHoUQDQgAEeRkstKQV+FSAMqBayqFknn2nAQsdsh/MhdX6tiHOTAFin/sUMFRMyspPtIu7YvlKdsexhI0jPVhaYZn1jKWhZg=="
+
+ try:
+ params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+ params['wpa_key_mgmt'] = 'SAE'
+ params["ieee80211w"] = "2"
+ params['sae_groups'] = '19'
+ params['sae_password'] = ['%s|pk=%s:%s' % (pw, m, pk)]
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ sigma_dut_cmd_check("sta_reset_default,interface,%s,prog,WPA3" % ifname)
+ sigma_dut_cmd_check("sta_set_ip_config,interface,%s,dhcp,0,ip,127.0.0.11,mask,255.255.255.0" % ifname)
+ sigma_dut_cmd_check("sta_set_wireless,interface,%s,program,WPA3" % ifname)
+ sigma_dut_cmd_check("sta_set_security,interface,%s,ssid,%s,passphrase,%s,type,SAE,encpType,aes-ccmp,keymgmttype,wpa2,sae_pk,1" % (ifname, ssid, pw))
+ sigma_dut_cmd_check("sta_associate,interface,%s,ssid,%s,channel,1" % (ifname, ssid),
+ timeout=10)
+ sigma_dut_wait_connected(ifname)
+ dev[0].dump_monitor()
+
+ sigma_dut_cmd_check("sta_reset_default,interface," + ifname)
+ finally:
+ stop_sigma_dut(sigma)
+
+def run_sigma_dut_ap_sae_pk(conffile, dev, ssid, pw, keypair, m, failure,
+ status=None, omit=False, immediate=False, sig=None):
+ sigma_dut_cmd_check("ap_reset_default")
+ sigma_dut_cmd_check("ap_set_wireless,NAME,AP,CHANNEL,1,SSID,%s,MODE,11ng" % ssid)
+ cmd = "ap_set_security,NAME,AP,AKMSuiteType,8,PairwiseCipher,AES-CCMP-128,GroupCipher,AES-CCMP-128,GroupMgntCipher,BIP-CMAC-128,PMF,Required,PSK,%s,sae_pk,1,Transition_Disable,1,Transition_Disable_Index,0,SAE_PK_KeyPair,%s,SAE_PK_Modifier,%s" % (pw, keypair, m)
+ if status is not None:
+ cmd += ",SAE_Commit_StatusCode,%d" % status
+ if omit:
+ cmd += ",SAE_PK_Omit,1"
+ if immediate:
+ cmd += ",SAE_Confirm_Immediate,1"
+ if sig:
+ cmd += ",SAE_PK_KeyPairSigOverride," + sig
+ sigma_dut_cmd_check(cmd)
+ sigma_dut_cmd_check("ap_config_commit,NAME,AP")
+ bssid = sigma_dut_cmd_check("ap_get_mac_address,NAME,AP")
+ bssid = bssid.split(',')[3]
+
+ with open("/tmp/sigma_dut-ap.conf", "rb") as f:
+ with open(conffile, "ab") as f2:
+ f2.write(f.read())
+ f2.write('\n'.encode())
+
+ dev.set("sae_groups", "")
+ dev.connect(ssid, key_mgmt="SAE", sae_password=pw, ieee80211w="2",
+ scan_freq="2412", wait_connect=False)
+
+ ev = dev.wait_event(["CTRL-EVENT-CONNECTED",
+ "CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=15)
+ if ev is None:
+ raise Exception("No connection result reported")
+
+ bss = dev.get_bss(bssid)
+ if 'flags' not in bss:
+ raise Exception("Could not get BSS flags from BSS table")
+ if "[SAE-H2E]" not in bss['flags'] or "[SAE-PK]" not in bss['flags']:
+ raise Exception("Unexpected BSS flags: " + bss['flags'])
+
+ if failure:
+ if "CTRL-EVENT-CONNECTED" in ev:
+ raise Exception("Unexpected connection")
+ dev.request("REMOVE_NETWORK all")
+ else:
+ if "CTRL-EVENT-CONNECTED" not in ev:
+ raise Exception("Connection failed")
+ dev.request("REMOVE_NETWORK all")
+ dev.wait_disconnected()
+ dev.dump_monitor()
+
+ sigma_dut_cmd_check("ap_reset_default")
+
+def test_sigma_dut_ap_sae_pk(dev, apdev, params):
+ """sigma_dut controlled AP using SAE-PK"""
+ logdir = params['prefix'] + ".sigma-hostapd"
+ conffile = params['prefix'] + ".sigma-conf"
+ if "SAE" not in dev[0].get_capability("auth_alg"):
+ raise HwsimSkip("SAE not supported")
+ tests = [("SAEPK-4.7.1.1", "ya3o-zvm2-r4so", "saepk1.pem",
+ "faa1ef5094bdb4cb2836332ca2c09839", False),
+ ("SAEPK-4.7.1.2", "xcc2-qwru-yg23", "saepk1.pem",
+ "b1b30107eb74de2f25afd079bb4196c1", False),
+ ("SAEPK-4.7.1.3", "skqz-6scq-zcqv", "saepk1.pem",
+ "4c0ff61465e0f298510254ff54916c71", False),
+ ("SAEPK-4.7.1.4", "r6em-rya4-tqfa", "saepkP384.pem",
+ "fb811655209e9edf347a675ddd3e9c82", False),
+ ("SAEPK-4.7.1.5", "6kjo-umvi-7x3w", "saepkP521.pem",
+ "cccb76bc0f113ab754826ba9538d66f5", False),
+ ("SAEPK-5.7.1.1", "sw4h-re63-wgqg", "saepk1.pem",
+ "0d126f302d85ac809a6a4229dbbe3c75", False),
+ ("SAEPK-5.7.1.2", "wewq-r4kg-4ioz-xb2p", "saepk1.pem",
+ "d6b1d8924b1a462677e67b3bbfe73977", False),
+ ("SAEPK-5.7.1.3", "vb3v-5skk-5eft-v4hu-w2c5", "saepk1.pem",
+ "41f8cfceb96ebc5c8af9677d22749fad", False),
+ ("SAEPK-5.7.1.4", "2qsw-6tgy-xnwa-s7lo-75tq-qggr", "saepk1.pem",
+ "089e8d4a3a79ec637c54dd7bd61972f2", False),
+ ("SAE-PK test", "hbbi-f4xq-b45g", "saepkP256.pem",
+ "d2e5fa27d1be8897f987f2d480d2af6b", False),
+ ("SAE-PK test", "hbbi-f4xq-b457-jje4", "saepkP256.pem",
+ "d2e5fa27d1be8897f987f2d480d2af6b", False),
+ ("SAE-PK test", "hbbi-f4xq-b457-jjew-muei", "saepkP256.pem",
+ "d2e5fa27d1be8897f987f2d480d2af6b", False),
+ ("SAE-PK test", "hbbi-f4xq-b457-jjew-muey-fod3", "saepkP256.pem",
+ "d2e5fa27d1be8897f987f2d480d2af6b", False),
+ ("SAEPK-5.7.1.1", "sw4h-re63-wgqg", "saepk1.pem",
+ "0d126f302d85ac809a6a4229dbbe3c75", False),
+ ("SAEPK-5.7.1.10", "tkor-7nb3-r7tv", "saepkP384.pem",
+ "af1a3df913fc0103f65f105ed1472277", False),
+ ("SAEPK-5.7.1.11", "yjl3-vfvu-w6r3", "saepkP521.pem",
+ "24dadf9d253c4169c9647a21cb54fc57", False),
+ ("SAEPK-5.7.2.1", "rntm-tkrp-xgke", "saepk1.pem",
+ "cd38ccce3baff627d09bee7b9530d6ce", False),
+ ("SAEPK-5.7.2.2", "7lt7-7dqt-6abk", "saepk1.pem",
+ "a22fc8489932597c9e83de62dec02b21", False),
+ ("SAEPK-5.7.2.3", "sw4h-re63-wgqg", "saepk2.pem",
+ "1f4a4c7d290d97e0b6ab0cbbbfa0726d", True),
+ ("SAEPK-5.7.2.4", "rmj3-ya7b-42k4", "saepk1.pem",
+ "5f65e2bc37f8494de7a605ff615c8b6a", False),
+ ("SAEPK-5.7.2.4", "rmj3-ya7b-42k4", "saepk2.pem",
+ "5f65e2bc37f8494de7a605ff615c8b6a", True),
+ ("SAEPK-5.7.3", "4322-ufus-4bhm", "saepk1.pem",
+ "21ede99abc46679646693cafe4677d4e", False)]
+
+ with HWSimRadio() as (radio, iface):
+ sigma = start_sigma_dut(iface, hostapd_logdir=logdir)
+ try:
+ for ssid, pw, keypair, m, failure in tests:
+ run_sigma_dut_ap_sae_pk(conffile, dev[0], ssid, pw, keypair, m,
+ failure)
+ finally:
+ stop_sigma_dut(sigma)
+
+def test_sigma_dut_ap_sae_pk_misbehavior(dev, apdev, params):
+ """sigma_dut controlled AP using SAE-PK misbehavior"""
+ logdir = params['prefix'] + ".sigma-hostapd"
+ conffile = params['prefix'] + ".sigma-conf"
+ if "SAE" not in dev[0].get_capability("auth_alg"):
+ raise HwsimSkip("SAE not supported")
+ ssid = "SAEPK-4.7.1.1"
+ pw = "rmj3-ya7b-42k4"
+ keypair = "saepk1.pem"
+ m = "faa1ef5094bdb4cb2836332ca2c09839"
+
+ with HWSimRadio() as (radio, iface):
+ sigma = start_sigma_dut(iface, hostapd_logdir=logdir)
+ try:
+ run_sigma_dut_ap_sae_pk(conffile, dev[0], ssid, pw, keypair, m,
+ True, status=126)
+ run_sigma_dut_ap_sae_pk(conffile, dev[0], ssid, pw, keypair, m,
+ True, omit=True)
+ run_sigma_dut_ap_sae_pk(conffile, dev[0], ssid, pw, keypair, m,
+ True, status=126, omit=True, immediate=True)
+ run_sigma_dut_ap_sae_pk(conffile, dev[0], ssid, pw, keypair, m,
+ True, sig="saepk2.pem")
+ finally:
+ stop_sigma_dut(sigma)
+
+def run_sigma_dut_ap_sae_pk_mixed(conffile, dev, ssid, pw, keypair, m, failure):
+ sigma_dut_cmd_check("ap_reset_default")
+ sigma_dut_cmd_check("ap_set_wireless,NAME,AP,CHANNEL,1,SSID,%s,MODE,11ng" % ssid)
+ cmd = "ap_set_security,NAME,AP,AKMSuiteType,2;8,PairwiseCipher,AES-CCMP-128,GroupCipher,AES-CCMP-128,GroupMgntCipher,BIP-CMAC-128,PMF,Required,PSK,%s,sae_pk,0,Transition_Disable,0" % (pw)
+ sigma_dut_cmd_check(cmd)
+ sigma_dut_cmd_check("ap_config_commit,NAME,AP")
+ bssid = sigma_dut_cmd_check("ap_get_mac_address,NAME,AP")
+ bssid = bssid.split(',')[3]
+
+ with open("/tmp/sigma_dut-ap.conf", "rb") as f:
+ with open(conffile, "ab") as f2:
+ f2.write(f.read())
+ f2.write('\n'.encode())
+
+ sigma_dut_cmd_check("ap_set_rfeature,NAME,AP,type,WPA3,Transition_Disable,1,Transition_Disable_Index,0")
+
+ dev[0].set("sae_groups", "")
+ dev[0].connect(ssid, key_mgmt="SAE", sae_password=pw, ieee80211w="2",
+ scan_freq="2412")
+ dev[1].connect(ssid, key_mgmt="WPA-PSK", psk=pw, ieee80211w="2",
+ scan_freq="2412")
+
+ sigma_dut_cmd_check("ap_reset_default")
+
+def test_sigma_dut_ap_sae_pk_mixed(dev, apdev, params):
+ """sigma_dut controlled AP using SAE-PK(disabled) and PSK"""
+ logdir = params['prefix'] + ".sigma-hostapd"
+ conffile = params['prefix'] + ".sigma-conf"
+ if "SAE" not in dev[0].get_capability("auth_alg"):
+ raise HwsimSkip("SAE not supported")
+ ssid = "SAEPK-5.7.3"
+ pw = "4322-ufus-4bhm"
+ keypair = "saepk1.pem"
+ m = "21ede99abc46679646693cafe4677d4e"
+
+ with HWSimRadio() as (radio, iface):
+ sigma = start_sigma_dut(iface, hostapd_logdir=logdir)
+ try:
+ run_sigma_dut_ap_sae_pk_mixed(conffile, dev, ssid, pw, keypair,
+ m, False)
+ finally:
+ stop_sigma_dut(sigma)
+
+def test_sigma_dut_client_privacy(dev, apdev, params):
+ """sigma_dut client privacy"""
+ logdir = params['logdir']
+
+ ssid = "test"
+ params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ ifname = dev[0].ifname
+ addr = dev[0].own_addr()
+ sigma = start_sigma_dut(ifname)
+ try:
+ sigma_dut_cmd_check("sta_reset_default,interface,%s,prog,WPA3" % ifname)
+ sigma_dut_cmd_check("sta_set_wireless,interface,%s,program,WPA3,ClientPrivacy,1" % ifname)
+ cmd = "sta_scan,Interface,%s,ChnlFreq,2412,WaitCompletion,1" % dev[0].ifname
+ sigma_dut_cmd_check(cmd, timeout=10)
+ time.sleep(2)
+ sigma_dut_cmd_check("sta_set_ip_config,interface,%s,dhcp,0,ip,127.0.0.11,mask,255.255.255.0" % ifname)
+ sigma_dut_cmd_check("sta_set_psk,interface,%s,ssid,%s,passphrase,%s,encpType,aes-ccmp,keymgmttype,wpa2" % (ifname, ssid, "12345678"))
+ sigma_dut_cmd_check("sta_associate,interface,%s,ssid,%s,channel,1" % (ifname, ssid),
+ timeout=10)
+ sigma_dut_wait_connected(ifname)
+ sigma_dut_cmd_check("sta_get_ip_config,interface," + ifname)
+ sigma_dut_cmd_check("sta_disconnect,interface," + ifname)
+ sigma_dut_cmd_check("sta_reset_default,interface," + ifname)
+ finally:
+ stop_sigma_dut(sigma)
+ dev[1].set("mac_addr", "0", allow_fail=True)
+ dev[1].set("rand_addr_lifetime", "60", allow_fail=True)
+ dev[1].set("preassoc_mac_addr", "0", allow_fail=True)
+ dev[1].set("gas_rand_mac_addr", "0", allow_fail=True)
+ dev[1].set("gas_rand_addr_lifetime", "60", allow_fail=True)
+
+ out = run_tshark(os.path.join(logdir, "hwsim0.pcapng"),
+ "wlan.addr == " + addr,
+ display=["wlan.ta"])
+ res = out.splitlines()
+ if len(res) > 0:
+ raise Exception("Permanent address used unexpectedly")
+
+def test_sigma_dut_wpa3_inject_frame(dev, apdev):
+ """sigma_dut and WPA3 frame inject"""
+ if "SAE" not in dev[0].get_capability("auth_alg"):
+ raise HwsimSkip("SAE not supported")
+
+ ifname = dev[0].ifname
+ sigma = start_sigma_dut(ifname)
+
+ try:
+ ssid = "test-sae"
+ params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+ params['wpa_key_mgmt'] = 'SAE'
+ params["ieee80211w"] = "2"
+ params["ocv"] = "1"
+ params['sae_groups'] = '19 20 21'
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ sigma_dut_cmd_check("sta_reset_default,interface,%s,prog,WPA3" % ifname)
+ sigma_dut_cmd_check("sta_set_ip_config,interface,%s,dhcp,0,ip,127.0.0.11,mask,255.255.255.0" % ifname)
+ sigma_dut_cmd_check("sta_set_wireless,interface,%s,program,WPA3,ocvc,1" % ifname)
+ sigma_dut_cmd_check("sta_set_security,interface,%s,ssid,%s,passphrase,%s,type,SAE,encpType,aes-ccmp,keymgmttype,wpa2" % (ifname, "test-sae", "12345678"))
+ sigma_dut_cmd_check("sta_associate,interface,%s,ssid,%s,channel,1" % (ifname, "test-sae"),
+ timeout=10)
+ sigma_dut_wait_connected(ifname)
+ sigma_dut_cmd("dev_send_frame,interface,%s,program,WPA3,framename,SAQueryReq,OCIChannel,2" % ifname)
+ sigma_dut_cmd("dev_send_frame,interface,%s,program,WPA3,framename,SAQueryReq,OCIChannel,1" % ifname)
+ sigma_dut_cmd("dev_send_frame,interface,%s,program,WPA3,framename,ReassocReq" % ifname)
+ hwsim_utils.test_connectivity(dev[0], hapd)
+ sigma_dut_cmd_check("sta_reset_default,interface," + ifname)
+ finally:
+ stop_sigma_dut(sigma)
diff --git a/tests/hwsim/wpasupplicant.py b/tests/hwsim/wpasupplicant.py
index 0ed0438..92c8552 100644
--- a/tests/hwsim/wpasupplicant.py
+++ b/tests/hwsim/wpasupplicant.py
@@ -1102,6 +1102,7 @@ class WpaSupplicant:
"dpp_netaccesskey", "dpp_netaccesskey_expiry", "dpp_pfs",
"group_mgmt", "owe_group", "owe_only",
"owe_ptk_workaround",
+ "transition_disable", "sae_pk",
"roaming_consortium_selection", "ocv",
"multi_ap_backhaul_sta", "rx_stbc", "tx_stbc",
"ft_eap_pmksa_caching", "beacon_prot",
@@ -1110,6 +1111,15 @@ class WpaSupplicant:
if field in kwargs and kwargs[field]:
self.set_network(id, field, kwargs[field])
+ known_args = {"raw_psk", "password_hex", "peerkey", "okc", "ocsp",
+ "only_add_network", "wait_connect"}
+ unknown = set(kwargs.keys())
+ unknown -= set(quoted)
+ unknown -= set(not_quoted)
+ unknown -= known_args
+ if unknown:
+ raise Exception("Unknown WpaSupplicant::connect() arguments: " + str(unknown))
+
if "raw_psk" in kwargs and kwargs['raw_psk']:
self.set_network(id, "psk", kwargs['raw_psk'])
if "password_hex" in kwargs and kwargs['password_hex']:
@@ -1519,7 +1529,8 @@ class WpaSupplicant:
extra=None, own=None, role=None, neg_freq=None,
ssid=None, passphrase=None, expect_fail=False,
tcp_addr=None, tcp_port=None, conn_status=False,
- ssid_charset=None, nfc_uri=None, netrole=None):
+ ssid_charset=None, nfc_uri=None, netrole=None,
+ csrattrs=None):
cmd = "DPP_AUTH_INIT"
if peer is None:
if nfc_uri:
@@ -1553,6 +1564,8 @@ class WpaSupplicant:
cmd += " conn_status=1"
if netrole:
cmd += " netrole=" + netrole
+ if csrattrs:
+ cmd += " csrattrs=" + csrattrs
res = self.request(cmd)
if expect_fail:
if "FAIL" not in res:
@@ -1560,6 +1573,7 @@ class WpaSupplicant:
return
if "OK" not in res:
raise Exception("Failed to initiate DPP Authentication")
+ return int(peer)
def dpp_pkex_init(self, identifier, code, role=None, key=None, curve=None,
extra=None, use_id=None, allow_fail=False):
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 0f24d7b..ed7e358 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -98,6 +98,7 @@ OBJS += src/utils/crc32.c
OBJS += wmm_ac.c
OBJS += op_classes.c
OBJS += rrm.c
+OBJS += robust_av.c
OBJS_p = wpa_passphrase.c
OBJS_p += src/utils/common.c
OBJS_p += src/utils/wpa_debug.c
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 09ac7a4..a01a329 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -107,6 +107,7 @@ OBJS += ../src/utils/ip_addr.o
OBJS += ../src/utils/crc32.o
OBJS += op_classes.o
OBJS += rrm.o
+OBJS += robust_av.o
OBJS_p = wpa_passphrase.o
OBJS_p += ../src/utils/common.o
OBJS_p += ../src/utils/wpa_debug.o
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 6241682..2accf92 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -858,6 +858,9 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
wpa_s->conf->wmm_ac_params,
sizeof(wpa_s->conf->wmm_ac_params));
+ os_memcpy(wpa_s->ap_iface->conf->tx_queue, wpa_s->conf->tx_queue,
+ sizeof(wpa_s->conf->tx_queue));
+
if (params.uapsd > 0) {
conf->bss[0]->wmm_enabled = 1;
conf->bss[0]->wmm_uapsd = 1;
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 49b25f1..0b4a66a 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2582,6 +2582,7 @@ static const struct parse_data ssid_fields[] = {
{ INT_RANGE(ft_eap_pmksa_caching, 0, 1) },
{ INT_RANGE(beacon_prot, 0, 1) },
{ INT_RANGE(transition_disable, 0, 255) },
+ { INT_RANGE(sae_pk, 0, 2) },
};
#undef OFFSET
@@ -4254,6 +4255,8 @@ int wpa_config_remove_blob(struct wpa_config *config, const char *name)
struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
const char *driver_param)
{
+#define ecw2cw(ecw) ((1 << (ecw)) - 1)
+
struct wpa_config *config;
const int aCWmin = 4, aCWmax = 10;
const struct hostapd_wmm_ac_params ac_bk =
@@ -4264,6 +4267,17 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
{ aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
{ aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
+ const struct hostapd_tx_queue_params txq_bk =
+ { 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 };
+ const struct hostapd_tx_queue_params txq_be =
+ { 3, ecw2cw(aCWmin), 4 * (ecw2cw(aCWmin) + 1) - 1, 0 };
+ const struct hostapd_tx_queue_params txq_vi =
+ { 1, (ecw2cw(aCWmin) + 1) / 2 - 1, ecw2cw(aCWmin), 30 };
+ const struct hostapd_tx_queue_params txq_vo =
+ { 1, (ecw2cw(aCWmin) + 1) / 4 - 1,
+ (ecw2cw(aCWmin) + 1) / 2 - 1, 15 };
+
+#undef ecw2cw
config = os_zalloc(sizeof(*config));
if (config == NULL)
@@ -4293,6 +4307,10 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
config->wmm_ac_params[1] = ac_bk;
config->wmm_ac_params[2] = ac_vi;
config->wmm_ac_params[3] = ac_vo;
+ config->tx_queue[0] = txq_vo;
+ config->tx_queue[1] = txq_vi;
+ config->tx_queue[2] = txq_be;
+ config->tx_queue[3] = txq_bk;
config->p2p_search_delay = DEFAULT_P2P_SEARCH_DELAY;
config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
@@ -5164,6 +5182,26 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
}
if (i == NUM_GLOBAL_FIELDS) {
#ifdef CONFIG_AP
+ if (os_strncmp(pos, "tx_queue_", 9) == 0) {
+ char *tmp = os_strchr(pos, '=');
+
+ if (!tmp) {
+ if (line < 0)
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid line %s",
+ line, pos);
+ return -1;
+ }
+ *tmp++ = '\0';
+ if (hostapd_config_tx_queue(config->tx_queue, pos,
+ tmp)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid TX queue item",
+ line);
+ return -1;
+ }
+ }
+
if (os_strncmp(pos, "wmm_ac_", 7) == 0) {
char *tmp = os_strchr(pos, '=');
if (tmp == NULL) {
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 2d4cb1b..a385da5 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -1058,6 +1058,7 @@ struct wpa_config {
int p2p_go_max_inactivity;
struct hostapd_wmm_ac_params wmm_ac_params[4];
+ struct hostapd_tx_queue_params tx_queue[4];
/**
* auto_interworking - Whether to use network selection automatically
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index a69c4cc..1ca2548 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -937,6 +937,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT(ft_eap_pmksa_caching);
INT(beacon_prot);
INT(transition_disable);
+ INT(sae_pk);
#ifdef CONFIG_HT_OVERRIDES
INT_DEF(disable_ht, DEFAULT_DISABLE_HT);
INT_DEF(disable_ht40, DEFAULT_DISABLE_HT40);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 1e2c322..2c08c02 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -62,6 +62,12 @@ enum wpas_mode {
WPAS_MODE_MESH = 5,
};
+enum sae_pk_mode {
+ SAE_PK_MODE_AUTOMATIC = 0,
+ SAE_PK_MODE_ONLY = 1,
+ SAE_PK_MODE_DISABLED = 2,
+};
+
/**
* struct wpa_ssid - Network configuration data
*
@@ -1121,6 +1127,16 @@ struct wpa_ssid {
* OWE)
*/
u8 transition_disable;
+
+ /**
+ * sae_pk - SAE-PK mode
+ * 0 = automatic SAE/SAE-PK selection based on password; enable
+ * transition mode (allow SAE authentication without SAE-PK)
+ * 1 = SAE-PK only (disable transition mode; allow SAE authentication
+ * only with SAE-PK)
+ * 2 = disable SAE-PK (allow SAE authentication only without SAE-PK)
+ */
+ enum sae_pk_mode sae_pk;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index e727dc5..5048ee8 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -757,6 +757,20 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
wpa_s->oci_freq_override_saquery_req = atoi(value);
} else if (os_strcasecmp(cmd, "oci_freq_override_saquery_resp") == 0) {
wpa_s->oci_freq_override_saquery_resp = atoi(value);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_eapol_g2") == 0) {
+ wpa_s->oci_freq_override_eapol_g2 = atoi(value);
+ /* Populate value to wpa_sm if already associated. */
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_EAPOL_G2,
+ wpa_s->oci_freq_override_eapol_g2);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_ft_assoc") == 0) {
+ wpa_s->oci_freq_override_ft_assoc = atoi(value);
+ /* Populate value to wpa_sm if already associated. */
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FT_ASSOC,
+ wpa_s->oci_freq_override_ft_assoc);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_fils_assoc") == 0) {
+ wpa_s->oci_freq_override_fils_assoc = atoi(value);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_wnm_sleep") == 0) {
+ wpa_s->oci_freq_override_wnm_sleep = atoi(value);
} else if (os_strcasecmp(cmd, "rsne_override_eapol") == 0) {
wpabuf_free(wpa_s->rsne_override_eapol);
if (os_strcmp(value, "NULL") == 0)
@@ -2283,8 +2297,12 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
!wpa_s->ap_iface &&
#endif /* CONFIG_AP */
wpa_s->sme.sae.state == SAE_ACCEPTED) {
- ret = os_snprintf(pos, end - pos, "sae_group=%d\n",
- wpa_s->sme.sae.group);
+ ret = os_snprintf(pos, end - pos, "sae_group=%d\n"
+ "sae_h2e=%d\n"
+ "sae_pk=%d\n",
+ wpa_s->sme.sae.group,
+ wpa_s->sme.sae.h2e,
+ wpa_s->sme.sae.pk);
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -4217,6 +4235,27 @@ static int ctrl_iface_get_capability_key_mgmt(int res, bool strict,
pos += ret;
}
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WAPI_PSK) {
+ ret = os_snprintf(pos, end - pos, " WAPI-PSK");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_TPK_HANDSHAKE) {
+ ret = os_snprintf(pos, end - pos, " TPK-HANDSHAKE");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_CCKM) {
+ ret = os_snprintf(pos, end - pos, " CCKM");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
#ifdef CONFIG_SUITEB
if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B) {
ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B");
@@ -4284,6 +4323,28 @@ static int ctrl_iface_get_capability_key_mgmt(int res, bool strict,
return pos - buf;
pos += ret;
}
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) {
+ ret = os_snprintf(pos, end - pos, " FT-EAP");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#ifdef CONFIG_SAE
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE) {
+ ret = os_snprintf(pos, end - pos, " FT-SAE");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_SHA384
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_802_1X_SHA384) {
+ ret = os_snprintf(pos, end - pos, " FT-EAP-SHA384");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_SAE
if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) {
@@ -4293,6 +4354,29 @@ static int ctrl_iface_get_capability_key_mgmt(int res, bool strict,
pos += ret;
}
#endif /* CONFIG_SAE */
+#ifdef CONFIG_SHA256
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_802_1X_SHA256) {
+ ret = os_snprintf(pos, end - pos, " WPA-EAP-SHA256");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_PSK_SHA256) {
+ ret = os_snprintf(pos, end - pos, " WPA-PSK-SHA256");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SHA256 */
+#ifdef CONFIG_HS20
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OSEN) {
+ ret = os_snprintf(pos, end - pos, " OSEN");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_HS20 */
return pos - buf;
}
@@ -7382,7 +7466,7 @@ static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst,
static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
{
u8 dst_addr[ETH_ALEN];
- int used;
+ int used, freq = 0;
char *pos;
#define MAX_ANQP_INFO_ID 100
u16 id[MAX_ANQP_INFO_ID];
@@ -7396,6 +7480,15 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
pos = dst + used;
if (*pos == ' ')
pos++;
+
+ if (os_strncmp(pos, "freq=", 5) == 0) {
+ freq = atoi(pos + 5);
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ return -1;
+ pos++;
+ }
+
while (num_id < MAX_ANQP_INFO_ID) {
if (os_strncmp(pos, "hs20:", 5) == 0) {
#ifdef CONFIG_HS20
@@ -7430,7 +7523,7 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
if (num_id == 0 && !subtypes && !mbo_subtypes)
return -1;
- return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes,
+ return anqp_send_req(wpa_s, dst_addr, freq, id, num_id, subtypes,
mbo_subtypes);
}
@@ -8368,6 +8461,10 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->oci_freq_override_eapol = 0;
wpa_s->oci_freq_override_saquery_req = 0;
wpa_s->oci_freq_override_saquery_resp = 0;
+ wpa_s->oci_freq_override_eapol_g2 = 0;
+ wpa_s->oci_freq_override_ft_assoc = 0;
+ wpa_s->oci_freq_override_fils_assoc = 0;
+ wpa_s->oci_freq_override_wnm_sleep = 0;
#ifdef CONFIG_DPP
os_free(wpa_s->dpp_config_obj_override);
wpa_s->dpp_config_obj_override = NULL;
@@ -8386,6 +8483,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->next_scan_bssid_wildcard_ssid = 0;
os_free(wpa_s->select_network_scan_freqs);
wpa_s->select_network_scan_freqs = NULL;
+ os_memset(&wpa_s->robust_av, 0, sizeof(struct robust_av_data));
wpa_bss_flush(wpa_s);
if (!dl_list_empty(&wpa_s->bss)) {
@@ -8411,6 +8509,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_supplicant_update_channel_list(wpa_s, NULL);
free_bss_tmp_disallowed(wpa_s);
+
+ os_memset(&wpa_s->robust_av, 0, sizeof(struct robust_av_data));
}
@@ -10245,6 +10345,76 @@ static int wpas_ctrl_cmd_debug_level(const char *cmd)
}
+static int wpas_ctrl_iface_configure_mscs(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ size_t frame_classifier_len;
+ const char *pos, *end;
+ struct robust_av_data *robust_av = &wpa_s->robust_av;
+ int val;
+
+ /*
+ * format:
+ * <add|remove|change> [up_bitmap=<hex byte>] [up_limit=<integer>]
+ * [stream_timeout=<in TUs>] [frame_classifier=<hex bytes>]
+ */
+ os_memset(robust_av, 0, sizeof(struct robust_av_data));
+ if (os_strncmp(cmd, "add ", 4) == 0) {
+ robust_av->request_type = SCS_REQ_ADD;
+ } else if (os_strcmp(cmd, "remove") == 0) {
+ robust_av->request_type = SCS_REQ_REMOVE;
+ robust_av->valid_config = false;
+ return wpas_send_mscs_req(wpa_s);
+ } else if (os_strncmp(cmd, "change ", 7) == 0) {
+ robust_av->request_type = SCS_REQ_CHANGE;
+ } else {
+ return -1;
+ }
+
+ pos = os_strstr(cmd, "up_bitmap=");
+ if (!pos)
+ return -1;
+
+ val = hex2byte(pos + 10);
+ if (val < 0)
+ return -1;
+ robust_av->up_bitmap = val;
+
+ pos = os_strstr(cmd, "up_limit=");
+ if (!pos)
+ return -1;
+
+ robust_av->up_limit = atoi(pos + 9);
+
+ pos = os_strstr(cmd, "stream_timeout=");
+ if (!pos)
+ return -1;
+
+ robust_av->stream_timeout = atoi(pos + 15);
+ if (robust_av->stream_timeout == 0)
+ return -1;
+
+ pos = os_strstr(cmd, "frame_classifier=");
+ if (!pos)
+ return -1;
+
+ pos += 17;
+ end = os_strchr(pos, ' ');
+ if (!end)
+ end = pos + os_strlen(pos);
+
+ frame_classifier_len = (end - pos) / 2;
+ if (frame_classifier_len > sizeof(robust_av->frame_classifier) ||
+ hexstr2bin(pos, robust_av->frame_classifier, frame_classifier_len))
+ return -1;
+
+ robust_av->frame_classifier_len = frame_classifier_len;
+ robust_av->valid_config = true;
+
+ return wpas_send_mscs_req(wpa_s);
+}
+
+
char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len)
{
@@ -11129,13 +11299,16 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) {
wpas_dpp_chirp_stop(wpa_s);
} else if (os_strncmp(buf, "DPP_RECONFIG ", 13) == 0) {
- struct wpa_ssid *ssid;
-
- ssid = wpa_config_get_network(wpa_s->conf, atoi(buf + 13));
- if (!ssid || wpas_dpp_reconfig(wpa_s, ssid) < 0)
+ if (wpas_dpp_reconfig(wpa_s, buf + 13) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DPP_CA_SET ", 11) == 0) {
+ if (wpas_dpp_ca_set(wpa_s, buf + 10) < 0)
reply_len = -1;
#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
+ } else if (os_strncmp(buf, "MSCS ", 5) == 0) {
+ if (wpas_ctrl_iface_configure_mscs(wpa_s, buf + 5))
+ reply_len = -1;
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index a41b3f5..fdb9cbd 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -12,6 +12,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/ip_addr.h"
+#include "utils/base64.h"
#include "common/dpp.h"
#include "common/gas.h"
#include "common/gas_server.h"
@@ -48,6 +49,9 @@ wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_DPP2
static void wpas_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
void *timeout_ctx);
+static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s);
+static int wpas_dpp_process_conf_obj(void *ctx,
+ struct dpp_authentication *auth);
#endif /* CONFIG_DPP2 */
static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@@ -88,6 +92,10 @@ int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd)
500, wpas_dpp_tx_status, 0);
}
+#ifdef CONFIG_DPP2
+ dpp_controller_new_qr_code(wpa_s->dpp, bi);
+#endif /* CONFIG_DPP2 */
+
return bi->id;
}
@@ -829,7 +837,9 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
#ifdef CONFIG_DPP2
if (tcp)
- return dpp_tcp_init(wpa_s->dpp, auth, &ipaddr, tcp_port);
+ return dpp_tcp_init(wpa_s->dpp, auth, &ipaddr, tcp_port,
+ wpa_s->conf->dpp_name, DPP_NETROLE_STA,
+ wpa_s, wpa_s, wpas_dpp_process_conf_obj);
#endif /* CONFIG_DPP2 */
wpa_s->dpp_auth = auth;
@@ -1217,6 +1227,102 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
}
}
+#ifdef CONFIG_DPP2
+ if (conf->akm == DPP_AKM_DOT1X) {
+ int i;
+ char name[100], blobname[128];
+ struct wpa_config_blob *blob;
+
+ ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X |
+ WPA_KEY_MGMT_IEEE8021X_SHA256 |
+ WPA_KEY_MGMT_IEEE8021X_SHA256;
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
+
+ if (conf->cacert) {
+ /* caCert is DER-encoded X.509v3 certificate for the
+ * server certificate if that is different from the
+ * trust root included in certBag. */
+ /* TODO: ssid->eap.cert.ca_cert */
+ }
+
+ if (conf->certs) {
+ for (i = 0; ; i++) {
+ os_snprintf(name, sizeof(name), "dpp-certs-%d",
+ i);
+ if (!wpa_config_get_blob(wpa_s->conf, name))
+ break;
+ }
+
+ blob = os_zalloc(sizeof(*blob));
+ if (!blob)
+ goto fail;
+ blob->len = wpabuf_len(conf->certs);
+ blob->name = os_strdup(name);
+ blob->data = os_malloc(blob->len);
+ if (!blob->name || !blob->data) {
+ wpa_config_free_blob(blob);
+ goto fail;
+ }
+ os_memcpy(blob->data, wpabuf_head(conf->certs),
+ blob->len);
+ os_snprintf(blobname, sizeof(blobname), "blob://%s",
+ name);
+ wpa_config_set_blob(wpa_s->conf, blob);
+ wpa_printf(MSG_DEBUG, "DPP: Added certificate blob %s",
+ name);
+ ssid->eap.cert.client_cert = os_strdup(blobname);
+ if (!ssid->eap.cert.client_cert)
+ goto fail;
+
+ /* TODO: ssid->eap.identity from own certificate */
+ if (wpa_config_set(ssid, "identity", "\"dpp-ent\"",
+ 0) < 0)
+ goto fail;
+ }
+
+ if (auth->priv_key) {
+ for (i = 0; ; i++) {
+ os_snprintf(name, sizeof(name), "dpp-key-%d",
+ i);
+ if (!wpa_config_get_blob(wpa_s->conf, name))
+ break;
+ }
+
+ blob = os_zalloc(sizeof(*blob));
+ if (!blob)
+ goto fail;
+ blob->len = wpabuf_len(auth->priv_key);
+ blob->name = os_strdup(name);
+ blob->data = os_malloc(blob->len);
+ if (!blob->name || !blob->data) {
+ wpa_config_free_blob(blob);
+ goto fail;
+ }
+ os_memcpy(blob->data, wpabuf_head(auth->priv_key),
+ blob->len);
+ os_snprintf(blobname, sizeof(blobname), "blob://%s",
+ name);
+ wpa_config_set_blob(wpa_s->conf, blob);
+ wpa_printf(MSG_DEBUG, "DPP: Added private key blob %s",
+ name);
+ ssid->eap.cert.private_key = os_strdup(blobname);
+ if (!ssid->eap.cert.private_key)
+ goto fail;
+ }
+
+ if (conf->server_name) {
+ ssid->eap.cert.domain_suffix_match =
+ os_strdup(conf->server_name);
+ if (!ssid->eap.cert.domain_suffix_match)
+ goto fail;
+ }
+
+ /* TODO: Use entCreds::eapMethods */
+ if (wpa_config_set(ssid, "eap", "TLS", 0) < 0)
+ goto fail;
+ }
+#endif /* CONFIG_DPP2 */
+
os_memcpy(wpa_s->dpp_last_ssid, conf->ssid, conf->ssid_len);
wpa_s->dpp_last_ssid_len = conf->ssid_len;
@@ -1345,6 +1451,32 @@ static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
}
}
+#ifdef CONFIG_DPP2
+ if (conf->certbag) {
+ char *b64;
+
+ b64 = base64_encode_no_lf(wpabuf_head(conf->certbag),
+ wpabuf_len(conf->certbag), NULL);
+ if (b64)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CERTBAG "%s", b64);
+ os_free(b64);
+ }
+
+ if (conf->cacert) {
+ char *b64;
+
+ b64 = base64_encode_no_lf(wpabuf_head(conf->cacert),
+ wpabuf_len(conf->cacert), NULL);
+ if (b64)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CACERT "%s", b64);
+ os_free(b64);
+ }
+
+ if (conf->server_name)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_SERVER_NAME "%s",
+ conf->server_name);
+#endif /* CONFIG_DPP2 */
+
return wpas_dpp_process_config(wpa_s, auth, conf);
}
@@ -1360,6 +1492,7 @@ static int wpas_dpp_handle_key_pkg(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "DPP: Received Configurator backup");
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
+ wpa_s->dpp_conf_backup_received = true;
while (key) {
res = dpp_configurator_from_backup(wpa_s->dpp, key);
@@ -1375,6 +1508,31 @@ static int wpas_dpp_handle_key_pkg(struct wpa_supplicant *wpa_s,
}
+#ifdef CONFIG_DPP2
+static void wpas_dpp_build_csr(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!auth || !auth->csrattrs)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Build CSR");
+ wpabuf_free(auth->csr);
+ /* TODO: Additional information needed for CSR based on csrAttrs */
+ auth->csr = dpp_build_csr(auth, wpa_s->conf->dpp_name ?
+ wpa_s->conf->dpp_name : "Test");
+ if (!auth->csr) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
+
+ wpas_dpp_start_gas_client(wpa_s);
+}
+#endif /* CONFIG_DPP2 */
+
+
static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
enum gas_query_result result,
const struct wpabuf *adv_proto,
@@ -1419,11 +1577,20 @@ static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
goto fail;
}
- if (dpp_conf_resp_rx(auth, resp) < 0) {
+ res = dpp_conf_resp_rx(auth, resp);
+#ifdef CONFIG_DPP2
+ if (res == -2) {
+ wpa_printf(MSG_DEBUG, "DPP: CSR needed");
+ eloop_register_timeout(0, 0, wpas_dpp_build_csr, wpa_s, NULL);
+ return;
+ }
+#endif /* CONFIG_DPP2 */
+ if (res < 0) {
wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
goto fail;
}
+ wpa_s->dpp_conf_backup_received = false;
for (i = 0; i < auth->num_conf_obj; i++) {
res = wpas_dpp_handle_config_obj(wpa_s, auth,
&auth->conf_obj[i]);
@@ -1467,6 +1634,9 @@ fail:
wpabuf_free(msg);
/* This exchange will be terminated in the TX status handler */
+ if (wpa_s->conf->dpp_config_processing < 2 ||
+ wpa_s->dpp_conf_backup_received)
+ auth->remove_on_tx_status = 1;
return;
}
fail2:
@@ -1859,11 +2029,12 @@ wpas_dpp_rx_reconfig_announcement(struct wpa_supplicant *wpa_s, const u8 *src,
const u8 *hdr, const u8 *buf, size_t len,
unsigned int freq)
{
- const u8 *csign_hash;
- u16 csign_hash_len;
+ const u8 *csign_hash, *fcgroup, *a_nonce, *e_id;
+ u16 csign_hash_len, fcgroup_len, a_nonce_len, e_id_len;
struct dpp_configurator *conf;
struct dpp_authentication *auth;
unsigned int wait_time, max_wait_time;
+ u16 group;
if (!wpa_s->dpp)
return;
@@ -1893,7 +2064,21 @@ wpas_dpp_rx_reconfig_announcement(struct wpa_supplicant *wpa_s, const u8 *src,
return;
}
- auth = dpp_reconfig_init(wpa_s->dpp, wpa_s, conf, freq);
+ fcgroup = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
+ &fcgroup_len);
+ if (!fcgroup || fcgroup_len != 2) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Finite Cyclic Group attribute");
+ return;
+ }
+ group = WPA_GET_LE16(fcgroup);
+ wpa_printf(MSG_DEBUG, "DPP: Enrollee finite cyclic group: %u", group);
+
+ a_nonce = dpp_get_attr(buf, len, DPP_ATTR_A_NONCE, &a_nonce_len);
+ e_id = dpp_get_attr(buf, len, DPP_ATTR_E_PRIME_ID, &e_id_len);
+
+ auth = dpp_reconfig_init(wpa_s->dpp, wpa_s, conf, freq, group,
+ a_nonce, a_nonce_len, e_id, e_id_len);
if (!auth)
return;
wpas_dpp_set_testing_options(wpa_s, auth);
@@ -1943,17 +2128,29 @@ wpas_dpp_rx_reconfig_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Request from "
MACSTR, MAC2STR(src));
- if (!wpa_s->dpp || wpa_s->dpp_auth ||
- !wpa_s->dpp_reconfig_announcement || !wpa_s->dpp_reconfig_ssid)
+ if (!wpa_s->dpp)
+ return;
+ if (wpa_s->dpp_auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not ready for reconfiguration - pending authentication exchange in progress");
return;
+ }
+ if (!wpa_s->dpp_reconfig_ssid) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not ready for reconfiguration - not requested");
+ return;
+ }
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
if (ssid == wpa_s->dpp_reconfig_ssid &&
ssid->id == wpa_s->dpp_reconfig_ssid_id)
break;
}
if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
- !ssid->dpp_csign)
+ !ssid->dpp_csign) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not ready for reconfiguration - no matching network profile with Connector found");
return;
+ }
auth = dpp_reconfig_auth_req_rx(wpa_s->dpp, wpa_s, ssid->dpp_connector,
ssid->dpp_netaccesskey,
@@ -2647,8 +2844,8 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
static struct wpabuf *
-wpas_dpp_gas_req_handler(void *ctx, const u8 *sa, const u8 *query,
- size_t query_len)
+wpas_dpp_gas_req_handler(void *ctx, void *resp_ctx, const u8 *sa,
+ const u8 *query, size_t query_len, u16 *comeback_delay)
{
struct wpa_supplicant *wpa_s = ctx;
struct dpp_authentication *auth = wpa_s->dpp_auth;
@@ -2679,6 +2876,16 @@ wpas_dpp_gas_req_handler(void *ctx, const u8 *sa, const u8 *query,
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_REQ_RX "src=" MACSTR,
MAC2STR(sa));
resp = dpp_conf_req_rx(auth, query, query_len);
+
+#ifdef CONFIG_DPP2
+ if (!resp && auth->waiting_cert) {
+ wpa_printf(MSG_DEBUG, "DPP: Certificate not yet ready");
+ auth->cert_resp_ctx = resp_ctx;
+ *comeback_delay = 500;
+ return NULL;
+ }
+#endif /* CONFIG_DPP2 */
+
if (!resp)
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
auth->conf_resp = resp;
@@ -2704,6 +2911,14 @@ wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok)
return;
}
+#ifdef CONFIG_DPP2
+ if (auth->waiting_csr && ok) {
+ wpa_printf(MSG_DEBUG, "DPP: Waiting for CSR");
+ wpabuf_free(resp);
+ return;
+ }
+#endif /* CONFIG_DPP2 */
+
wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
ok);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
@@ -3084,7 +3299,6 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_TESTING_OPTIONS */
if (!wpa_s->dpp)
return;
- dpp_global_clear(wpa_s->dpp);
eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
@@ -3096,9 +3310,12 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout,
wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_build_csr, wpa_s, NULL);
dpp_pfs_free(wpa_s->dpp_pfs);
wpa_s->dpp_pfs = NULL;
wpas_dpp_chirp_stop(wpa_s);
+ dpp_free_reconfig_id(wpa_s->dpp_reconfig_id);
+ wpa_s->dpp_reconfig_id = NULL;
#endif /* CONFIG_DPP2 */
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
@@ -3107,6 +3324,7 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
os_memset(wpa_s->dpp_intro_bssid, 0, ETH_ALEN);
os_free(wpa_s->dpp_configurator_params);
wpa_s->dpp_configurator_params = NULL;
+ dpp_global_clear(wpa_s->dpp);
}
@@ -3139,6 +3357,8 @@ int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd)
else
return -1;
}
+
+ config.qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
}
config.configurator_params = wpa_s->dpp_configurator_params;
return dpp_controller_start(wpa_s->dpp, &config);
@@ -3181,13 +3401,26 @@ static void wpas_dpp_chirp_tx_status(struct wpa_supplicant *wpa_s,
static void wpas_dpp_chirp_start(struct wpa_supplicant *wpa_s)
{
- struct wpabuf *msg;
+ struct wpabuf *msg, *announce = NULL;
int type;
msg = wpa_s->dpp_presence_announcement;
type = DPP_PA_PRESENCE_ANNOUNCEMENT;
if (!msg) {
- msg = wpa_s->dpp_reconfig_announcement;
+ struct wpa_ssid *ssid = wpa_s->dpp_reconfig_ssid;
+
+ if (ssid && wpa_s->dpp_reconfig_id &&
+ wpa_config_get_network(wpa_s->conf,
+ wpa_s->dpp_reconfig_ssid_id) ==
+ ssid) {
+ announce = dpp_build_reconfig_announcement(
+ ssid->dpp_csign,
+ ssid->dpp_csign_len,
+ ssid->dpp_netaccesskey,
+ ssid->dpp_netaccesskey_len,
+ wpa_s->dpp_reconfig_id);
+ msg = announce;
+ }
if (!msg)
return;
type = DPP_PA_RECONFIG_ANNOUNCEMENT;
@@ -3201,6 +3434,8 @@ static void wpas_dpp_chirp_start(struct wpa_supplicant *wpa_s)
wpabuf_head(msg), wpabuf_len(msg),
2000, wpas_dpp_chirp_tx_status, 0) < 0)
wpas_dpp_chirp_stop(wpa_s);
+
+ wpabuf_free(announce);
}
@@ -3213,7 +3448,7 @@ static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s,
int c;
struct wpa_bss *bss;
- if (!bi && !wpa_s->dpp_reconfig_announcement)
+ if (!bi && !wpa_s->dpp_reconfig_ssid)
return;
wpa_s->dpp_chirp_scan_done = 1;
@@ -3401,15 +3636,13 @@ int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd)
void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s)
{
if (wpa_s->dpp_presence_announcement ||
- wpa_s->dpp_reconfig_announcement) {
+ wpa_s->dpp_reconfig_ssid) {
offchannel_send_action_done(wpa_s);
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CHIRP_STOPPED);
}
wpa_s->dpp_chirp_bi = NULL;
wpabuf_free(wpa_s->dpp_presence_announcement);
wpa_s->dpp_presence_announcement = NULL;
- wpabuf_free(wpa_s->dpp_reconfig_announcement);
- wpa_s->dpp_reconfig_announcement = NULL;
if (wpa_s->dpp_chirp_listen)
wpas_dpp_listen_stop(wpa_s);
wpa_s->dpp_chirp_listen = 0;
@@ -3425,23 +3658,53 @@ void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s)
}
-int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, const char *cmd)
{
- if (!ssid->dpp_connector || !ssid->dpp_netaccesskey ||
- !ssid->dpp_csign)
+ struct wpa_ssid *ssid;
+ int iter = 1;
+ const char *pos;
+
+ ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd));
+ if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
+ !ssid->dpp_csign) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not a valid network profile for reconfiguration");
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " iter=");
+ if (pos) {
+ iter = atoi(pos + 6);
+ if (iter <= 0)
+ return -1;
+ }
+
+ if (wpa_s->dpp_auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not ready to start reconfiguration - pending authentication exchange in progress");
return -1;
+ }
+ dpp_free_reconfig_id(wpa_s->dpp_reconfig_id);
+ wpa_s->dpp_reconfig_id = dpp_gen_reconfig_id(ssid->dpp_csign,
+ ssid->dpp_csign_len);
+ if (!wpa_s->dpp_reconfig_id) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to generate E-id for reconfiguration");
+ return -1;
+ }
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+ wpa_printf(MSG_DEBUG, "DPP: Disconnect for reconfiguration");
+ wpa_s->own_disconnect_req = 1;
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ }
wpas_dpp_chirp_stop(wpa_s);
wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
wpa_s->dpp_qr_mutual = 0;
- wpa_s->dpp_reconfig_announcement =
- dpp_build_reconfig_announcement(ssid->dpp_csign,
- ssid->dpp_csign_len);
- if (!wpa_s->dpp_reconfig_announcement)
- return -1;
wpa_s->dpp_reconfig_ssid = ssid;
wpa_s->dpp_reconfig_ssid_id = ssid->id;
- wpa_s->dpp_chirp_iter = 1;
+ wpa_s->dpp_chirp_iter = iter;
wpa_s->dpp_chirp_round = 0;
wpa_s->dpp_chirp_scan_done = 0;
wpa_s->dpp_chirp_listen = 0;
@@ -3449,4 +3712,111 @@ int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
return eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL);
}
+
+static int wpas_dpp_build_conf_resp(struct wpa_supplicant *wpa_s,
+ struct dpp_authentication *auth, bool tcp)
+{
+ struct wpabuf *resp;
+
+ resp = dpp_build_conf_resp(auth, auth->e_nonce, auth->curve->nonce_len,
+ auth->e_netrole, true);
+ if (!resp)
+ return -1;
+
+ if (tcp) {
+ auth->conf_resp_tcp = resp;
+ return 0;
+ }
+
+ if (gas_server_set_resp(wpa_s->gas_server, auth->cert_resp_ctx,
+ resp) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not find pending GAS response");
+ wpabuf_free(resp);
+ return -1;
+ }
+ auth->conf_resp = resp;
+ return 0;
+}
+
+
+int wpas_dpp_ca_set(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ int peer = -1;
+ const char *pos, *value;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ u8 *bin;
+ size_t bin_len;
+ struct wpabuf *buf;
+ bool tcp = false;
+
+ pos = os_strstr(cmd, " peer=");
+ if (pos) {
+ peer = atoi(pos + 6);
+ if (!auth || !auth->waiting_cert ||
+ (auth->peer_bi &&
+ (unsigned int) peer != auth->peer_bi->id)) {
+ auth = dpp_controller_get_auth(wpa_s->dpp, peer);
+ tcp = true;
+ }
+ }
+
+ if (!auth || !auth->waiting_cert) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No authentication exchange waiting for certificate information");
+ return -1;
+ }
+
+ if (peer >= 0 &&
+ (!auth->peer_bi ||
+ (unsigned int) peer != auth->peer_bi->id) &&
+ (!auth->tmp_peer_bi ||
+ (unsigned int) peer != auth->tmp_peer_bi->id)) {
+ wpa_printf(MSG_DEBUG, "DPP: Peer mismatch");
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " value=");
+ if (!pos)
+ return -1;
+ value = pos + 7;
+
+ pos = os_strstr(cmd, " name=");
+ if (!pos)
+ return -1;
+ pos += 6;
+
+ if (os_strncmp(pos, "status ", 7) == 0) {
+ auth->force_conf_resp_status = atoi(value);
+ return wpas_dpp_build_conf_resp(wpa_s, auth, tcp);
+ }
+
+ if (os_strncmp(pos, "trustedEapServerName ", 21) == 0) {
+ os_free(auth->trusted_eap_server_name);
+ auth->trusted_eap_server_name = os_strdup(value);
+ return auth->trusted_eap_server_name ? 0 : -1;
+ }
+
+ bin = base64_decode(value, os_strlen(value), &bin_len);
+ if (!bin)
+ return -1;
+ buf = wpabuf_alloc_copy(bin, bin_len);
+ os_free(bin);
+
+ if (os_strncmp(pos, "caCert ", 7) == 0) {
+ wpabuf_free(auth->cacert);
+ auth->cacert = buf;
+ return 0;
+ }
+
+ if (os_strncmp(pos, "certBag ", 8) == 0) {
+ wpabuf_free(auth->certbag);
+ auth->certbag = buf;
+ return wpas_dpp_build_conf_resp(wpa_s, auth, tcp);
+ }
+
+ wpabuf_free(buf);
+ return -1;
+}
+
#endif /* CONFIG_DPP2 */
diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h
index 2dc86e0..b0d5fcf 100644
--- a/wpa_supplicant/dpp_supplicant.h
+++ b/wpa_supplicant/dpp_supplicant.h
@@ -39,6 +39,7 @@ void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s,
enum dpp_status_error result);
int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd);
void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s);
-int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_ca_set(struct wpa_supplicant *wpa_s, const char *cmd);
#endif /* DPP_SUPPLICANT_H */
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 54ae03b..ba8cc55 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -1069,14 +1069,14 @@ static inline int wpa_drv_ignore_assoc_disallow(struct wpa_supplicant *wpa_s,
return wpa_s->driver->ignore_assoc_disallow(wpa_s->drv_priv, val);
}
-static inline int wpa_drv_set_bssid_blacklist(struct wpa_supplicant *wpa_s,
- unsigned int num_bssid,
- const u8 *bssids)
+static inline int wpa_drv_set_bssid_tmp_disallow(struct wpa_supplicant *wpa_s,
+ unsigned int num_bssid,
+ const u8 *bssids)
{
- if (!wpa_s->driver->set_bssid_blacklist)
+ if (!wpa_s->driver->set_bssid_tmp_disallow)
return -1;
- return wpa_s->driver->set_bssid_blacklist(wpa_s->drv_priv, num_bssid,
- bssids);
+ return wpa_s->driver->set_bssid_tmp_disallow(wpa_s->drv_priv, num_bssid,
+ bssids);
}
static inline int wpa_drv_update_connect_params(
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index f0f9189..80b803f 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1083,32 +1083,407 @@ static int disabled_freq(struct wpa_supplicant *wpa_s, int freq)
}
+static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ const u8 *match_ssid, size_t match_ssid_len,
+ struct wpa_bss *bss, struct wpa_blacklist *e,
+ bool debug_print);
+
+
+#ifdef CONFIG_SAE_PK
+static bool sae_pk_acceptable_bss_with_pk(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *orig_bss,
+ struct wpa_ssid *ssid,
+ const u8 *match_ssid,
+ size_t match_ssid_len)
+{
+ struct wpa_bss *bss;
+
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ struct wpa_blacklist *e;
+ const u8 *ie;
+ u8 rsnxe_capa = 0;
+
+ if (bss == orig_bss)
+ continue;
+ ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ if (ie && ie[1] >= 1)
+ rsnxe_capa = ie[2];
+ if (!(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)))
+ continue;
+
+ /* TODO: Could be more thorough in checking what kind of
+ * signal strength or throughput estimate would be acceptable
+ * compared to the originally selected BSS. */
+ if (bss->est_throughput < 2000)
+ return false;
+
+ e = wpa_blacklist_get(wpa_s, bss->bssid);
+ if (wpa_scan_res_ok(wpa_s, ssid, match_ssid, match_ssid_len,
+ bss, e, 0))
+ return true;
+ }
+
+ return false;
+}
+#endif /* CONFIG_SAE_PK */
+
+
+static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ const u8 *match_ssid, size_t match_ssid_len,
+ struct wpa_bss *bss, struct wpa_blacklist *e,
+ bool debug_print)
+{
+ int res;
+ bool wpa, check_ssid, osen, rsn_osen = false;
+ struct wpa_ie_data data;
+#ifdef CONFIG_MBO
+ const u8 *assoc_disallow;
+#endif /* CONFIG_MBO */
+#ifdef CONFIG_SAE
+ u8 rsnxe_capa = 0;
+#endif /* CONFIG_SAE */
+ const u8 *ie;
+
+ ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+ wpa = ie && ie[1];
+ ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ wpa |= ie && ie[1];
+ if (ie && wpa_parse_wpa_ie_rsn(ie, 2 + ie[1], &data) == 0 &&
+ (data.key_mgmt & WPA_KEY_MGMT_OSEN))
+ rsn_osen = true;
+ ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
+ osen = ie != NULL;
+
+#ifdef CONFIG_SAE
+ ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ if (ie && ie[1] >= 1)
+ rsnxe_capa = ie[2];
+#endif /* CONFIG_SAE */
+
+ check_ssid = wpa || ssid->ssid_len > 0;
+
+ if (wpas_network_disabled(wpa_s, ssid)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled");
+ return false;
+ }
+
+ res = wpas_temp_disabled(wpa_s, ssid);
+ if (res > 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - disabled temporarily for %d second(s)",
+ res);
+ return false;
+ }
+
+#ifdef CONFIG_WPS
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - blacklisted (WPS)");
+ return false;
+ }
+
+ if (wpa && ssid->ssid_len == 0 &&
+ wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
+ check_ssid = false;
+
+ if (!wpa && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
+ /* Only allow wildcard SSID match if an AP advertises active
+ * WPS operation that matches our mode. */
+ check_ssid = ssid->ssid_len > 0 ||
+ !wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss);
+ }
+#endif /* CONFIG_WPS */
+
+ if (ssid->bssid_set && ssid->ssid_len == 0 &&
+ os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) == 0)
+ check_ssid = false;
+
+ if (check_ssid &&
+ (match_ssid_len != ssid->ssid_len ||
+ os_memcmp(match_ssid, ssid->ssid, match_ssid_len) != 0)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID mismatch");
+ return false;
+ }
+
+ if (ssid->bssid_set &&
+ os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID mismatch");
+ return false;
+ }
+
+ /* check blacklist */
+ if (ssid->num_bssid_blacklist &&
+ addr_in_list(bss->bssid, ssid->bssid_blacklist,
+ ssid->num_bssid_blacklist)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID blacklisted");
+ return false;
+ }
+
+ /* if there is a whitelist, only accept those APs */
+ if (ssid->num_bssid_whitelist &&
+ !addr_in_list(bss->bssid, ssid->bssid_whitelist,
+ ssid->num_bssid_whitelist)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID not in whitelist");
+ return false;
+ }
+
+ if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss, debug_print))
+ return false;
+
+ if (!osen && !wpa &&
+ !(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
+ !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
+ !(ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+ !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - non-WPA network not allowed");
+ return false;
+ }
+
+#ifdef CONFIG_WEP
+ if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) && has_wep_key(ssid)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - ignore WPA/WPA2 AP for WEP network block");
+ return false;
+ }
+#endif /* CONFIG_WEP */
+
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen && !rsn_osen) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - non-OSEN network not allowed");
+ return false;
+ }
+
+ if (!wpa_supplicant_match_privacy(bss, ssid)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - privacy mismatch");
+ return false;
+ }
+
+ if (ssid->mode != WPAS_MODE_MESH && !bss_is_ess(bss) &&
+ !bss_is_pbss(bss)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - not ESS, PBSS, or MBSS");
+ return false;
+ }
+
+ if (ssid->pbss != 2 && ssid->pbss != bss_is_pbss(bss)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - PBSS mismatch (ssid %d bss %d)",
+ ssid->pbss, bss_is_pbss(bss));
+ return false;
+ }
+
+ if (!freq_allowed(ssid->freq_list, bss->freq)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - frequency not allowed");
+ return false;
+ }
+
+#ifdef CONFIG_MESH
+ if (ssid->mode == WPAS_MODE_MESH && ssid->frequency > 0 &&
+ ssid->frequency != bss->freq) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - frequency not allowed (mesh)");
+ return false;
+ }
+#endif /* CONFIG_MESH */
+
+ if (!rate_match(wpa_s, ssid, bss, debug_print)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - rate sets do not match");
+ return false;
+ }
+
+#ifdef CONFIG_SAE
+ if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) &&
+ wpa_s->conf->sae_pwe != 3 && wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ !(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - SAE H2E required, but not supported by the AP");
+ return false;
+ }
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_SAE_PK
+ if (ssid->sae_pk == SAE_PK_MODE_ONLY &&
+ !(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK))) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - SAE-PK required, but not supported by the AP");
+ return false;
+ }
+#endif /* CONFIG_SAE_PK */
+
+#ifndef CONFIG_IBSS_RSN
+ if (ssid->mode == WPAS_MODE_IBSS &&
+ !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPA_NONE))) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - IBSS RSN not supported in the build");
+ return false;
+ }
+#endif /* !CONFIG_IBSS_RSN */
+
+#ifdef CONFIG_P2P
+ if (ssid->p2p_group &&
+ !wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
+ !wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - no P2P IE seen");
+ return false;
+ }
+
+ if (!is_zero_ether_addr(ssid->go_p2p_dev_addr)) {
+ struct wpabuf *p2p_ie;
+ u8 dev_addr[ETH_ALEN];
+
+ ie = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
+ if (!ie) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no P2P element");
+ return false;
+ }
+ p2p_ie = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
+ if (!p2p_ie) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - could not fetch P2P element");
+ return false;
+ }
+
+ if (p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr) < 0 ||
+ os_memcmp(dev_addr, ssid->go_p2p_dev_addr, ETH_ALEN) != 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no matching GO P2P Device Address in P2P element");
+ wpabuf_free(p2p_ie);
+ return false;
+ }
+ wpabuf_free(p2p_ie);
+ }
+
+ /*
+ * TODO: skip the AP if its P2P IE has Group Formation bit set in the
+ * P2P Group Capability Bitmap and we are not in Group Formation with
+ * that device.
+ */
+#endif /* CONFIG_P2P */
+
+ if (os_reltime_before(&bss->last_update, &wpa_s->scan_min_time)) {
+ struct os_reltime diff;
+
+ os_reltime_sub(&wpa_s->scan_min_time, &bss->last_update, &diff);
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - scan result not recent enough (%u.%06u seconds too old)",
+ (unsigned int) diff.sec,
+ (unsigned int) diff.usec);
+ return false;
+ }
+#ifdef CONFIG_MBO
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ignore_assoc_disallow)
+ goto skip_assoc_disallow;
+#endif /* CONFIG_TESTING_OPTIONS */
+ assoc_disallow = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_ASSOC_DISALLOW);
+ if (assoc_disallow && assoc_disallow[1] >= 1) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - MBO association disallowed (reason %u)",
+ assoc_disallow[2]);
+ return false;
+ }
+
+ if (wpa_is_bss_tmp_disallowed(wpa_s, bss)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - AP temporarily disallowed");
+ return false;
+ }
+#ifdef CONFIG_TESTING_OPTIONS
+skip_assoc_disallow:
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_MBO */
+
+#ifdef CONFIG_DPP
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
+ !wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid) &&
+ (!ssid->dpp_connector || !ssid->dpp_netaccesskey ||
+ !ssid->dpp_csign)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no PMKSA entry for DPP");
+ return false;
+ }
+#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_SAE_PK
+ if (ssid->sae_pk == SAE_PK_MODE_AUTOMATIC &&
+ wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ ((ssid->sae_password &&
+ sae_pk_valid_password(ssid->sae_password)) ||
+ (!ssid->sae_password && ssid->passphrase &&
+ sae_pk_valid_password(ssid->passphrase))) &&
+ !(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)) &&
+ sae_pk_acceptable_bss_with_pk(wpa_s, bss, ssid, match_ssid,
+ match_ssid_len)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - another acceptable BSS with SAE-PK in the same ESS");
+ return false;
+ }
+#endif /* CONFIG_SAE_PK */
+
+ if (bss->ssid_len == 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no SSID known for the BSS");
+ return false;
+ }
+
+ /* Matching configuration found */
+ return true;
+}
+
+
struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
int i, struct wpa_bss *bss,
struct wpa_ssid *group,
int only_first_ssid, int debug_print)
{
u8 wpa_ie_len, rsn_ie_len;
- int wpa;
struct wpa_blacklist *e;
const u8 *ie;
struct wpa_ssid *ssid;
- int osen, rsn_osen = 0;
-#ifdef CONFIG_MBO
- const u8 *assoc_disallow;
-#endif /* CONFIG_MBO */
+ int osen;
const u8 *match_ssid;
size_t match_ssid_len;
- struct wpa_ie_data data;
ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
wpa_ie_len = ie ? ie[1] : 0;
ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
rsn_ie_len = ie ? ie[1] : 0;
- if (ie && wpa_parse_wpa_ie_rsn(ie, 2 + ie[1], &data) == 0 &&
- (data.key_mgmt & WPA_KEY_MGMT_OSEN))
- rsn_osen = 1;
ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
osen = ie != NULL;
@@ -1180,299 +1555,10 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
return NULL;
}
- wpa = wpa_ie_len > 0 || rsn_ie_len > 0;
-
for (ssid = group; ssid; ssid = only_first_ssid ? NULL : ssid->pnext) {
- int check_ssid = wpa ? 1 : (ssid->ssid_len != 0);
- int res;
-
- if (wpas_network_disabled(wpa_s, ssid)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled");
- continue;
- }
-
- res = wpas_temp_disabled(wpa_s, ssid);
- if (res > 0) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - disabled temporarily for %d second(s)",
- res);
- continue;
- }
-
-#ifdef CONFIG_WPS
- if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - blacklisted (WPS)");
- continue;
- }
-
- if (wpa && ssid->ssid_len == 0 &&
- wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
- check_ssid = 0;
-
- if (!wpa && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
- /* Only allow wildcard SSID match if an AP
- * advertises active WPS operation that matches
- * with our mode. */
- check_ssid = 1;
- if (ssid->ssid_len == 0 &&
- wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
- check_ssid = 0;
- }
-#endif /* CONFIG_WPS */
-
- if (ssid->bssid_set && ssid->ssid_len == 0 &&
- os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) == 0)
- check_ssid = 0;
-
- if (check_ssid &&
- (match_ssid_len != ssid->ssid_len ||
- os_memcmp(match_ssid, ssid->ssid, match_ssid_len) != 0)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - SSID mismatch");
- continue;
- }
-
- if (ssid->bssid_set &&
- os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - BSSID mismatch");
- continue;
- }
-
- /* check blacklist */
- if (ssid->num_bssid_blacklist &&
- addr_in_list(bss->bssid, ssid->bssid_blacklist,
- ssid->num_bssid_blacklist)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - BSSID blacklisted");
- continue;
- }
-
- /* if there is a whitelist, only accept those APs */
- if (ssid->num_bssid_whitelist &&
- !addr_in_list(bss->bssid, ssid->bssid_whitelist,
- ssid->num_bssid_whitelist)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - BSSID not in whitelist");
- continue;
- }
-
- if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss,
- debug_print))
- continue;
-
- if (!osen && !wpa &&
- !(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
- !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
- !(ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
- !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - non-WPA network not allowed");
- continue;
- }
-
-#ifdef CONFIG_WEP
- if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
- has_wep_key(ssid)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - ignore WPA/WPA2 AP for WEP network block");
- continue;
- }
-#endif /* CONFIG_WEP */
-
- if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen &&
- !rsn_osen) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - non-OSEN network not allowed");
- continue;
- }
-
- if (!wpa_supplicant_match_privacy(bss, ssid)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - privacy mismatch");
- continue;
- }
-
- if (ssid->mode != WPAS_MODE_MESH && !bss_is_ess(bss) &&
- !bss_is_pbss(bss)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - not ESS, PBSS, or MBSS");
- continue;
- }
-
- if (ssid->pbss != 2 && ssid->pbss != bss_is_pbss(bss)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - PBSS mismatch (ssid %d bss %d)",
- ssid->pbss, bss_is_pbss(bss));
- continue;
- }
-
- if (!freq_allowed(ssid->freq_list, bss->freq)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - frequency not allowed");
- continue;
- }
-
-#ifdef CONFIG_MESH
- if (ssid->mode == WPAS_MODE_MESH && ssid->frequency > 0 &&
- ssid->frequency != bss->freq) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - frequency not allowed (mesh)");
- continue;
- }
-#endif /* CONFIG_MESH */
-
- if (!rate_match(wpa_s, ssid, bss, debug_print)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - rate sets do not match");
- continue;
- }
-
-#ifdef CONFIG_SAE
- if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) &&
- wpa_s->conf->sae_pwe != 3 &&
- wpa_key_mgmt_sae(ssid->key_mgmt) &&
- (!(ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX)) ||
- ie[1] < 1 ||
- !(ie[2] & BIT(WLAN_RSNX_CAPAB_SAE_H2E)))) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - SAE H2E required, but not supported by the AP");
- continue;
- }
-#endif /* CONFIG_SAE */
-
-#ifndef CONFIG_IBSS_RSN
- if (ssid->mode == WPAS_MODE_IBSS &&
- !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE |
- WPA_KEY_MGMT_WPA_NONE))) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - IBSS RSN not supported in the build");
- continue;
- }
-#endif /* !CONFIG_IBSS_RSN */
-
-#ifdef CONFIG_P2P
- if (ssid->p2p_group &&
- !wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
- !wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - no P2P IE seen");
- continue;
- }
-
- if (!is_zero_ether_addr(ssid->go_p2p_dev_addr)) {
- struct wpabuf *p2p_ie;
- u8 dev_addr[ETH_ALEN];
-
- ie = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
- if (ie == NULL) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - no P2P element");
- continue;
- }
- p2p_ie = wpa_bss_get_vendor_ie_multi(
- bss, P2P_IE_VENDOR_TYPE);
- if (p2p_ie == NULL) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - could not fetch P2P element");
- continue;
- }
-
- if (p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr) < 0
- || os_memcmp(dev_addr, ssid->go_p2p_dev_addr,
- ETH_ALEN) != 0) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - no matching GO P2P Device Address in P2P element");
- wpabuf_free(p2p_ie);
- continue;
- }
- wpabuf_free(p2p_ie);
- }
-
- /*
- * TODO: skip the AP if its P2P IE has Group Formation
- * bit set in the P2P Group Capability Bitmap and we
- * are not in Group Formation with that device.
- */
-#endif /* CONFIG_P2P */
-
- if (os_reltime_before(&bss->last_update, &wpa_s->scan_min_time))
- {
- struct os_reltime diff;
-
- os_reltime_sub(&wpa_s->scan_min_time,
- &bss->last_update, &diff);
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - scan result not recent enough (%u.%06u seconds too old)",
- (unsigned int) diff.sec,
- (unsigned int) diff.usec);
- continue;
- }
-#ifdef CONFIG_MBO
-#ifdef CONFIG_TESTING_OPTIONS
- if (wpa_s->ignore_assoc_disallow)
- goto skip_assoc_disallow;
-#endif /* CONFIG_TESTING_OPTIONS */
- assoc_disallow = wpas_mbo_get_bss_attr(
- bss, MBO_ATTR_ID_ASSOC_DISALLOW);
- if (assoc_disallow && assoc_disallow[1] >= 1) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - MBO association disallowed (reason %u)",
- assoc_disallow[2]);
- continue;
- }
-
- if (wpa_is_bss_tmp_disallowed(wpa_s, bss)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - AP temporarily disallowed");
- continue;
- }
-#ifdef CONFIG_TESTING_OPTIONS
- skip_assoc_disallow:
-#endif /* CONFIG_TESTING_OPTIONS */
-#endif /* CONFIG_MBO */
-
-#ifdef CONFIG_DPP
- if ((ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
- !wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid) &&
- (!ssid->dpp_connector ||
- !ssid->dpp_netaccesskey ||
- !ssid->dpp_csign)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - no PMKSA entry for DPP");
- continue;
- }
-#endif /* CONFIG_DPP */
-
- /* Matching configuration found */
- return ssid;
+ if (wpa_scan_res_ok(wpa_s, ssid, match_ssid, match_ssid_len,
+ bss, e, debug_print))
+ return ssid;
}
/* No matching configuration found */
@@ -1772,52 +1858,19 @@ wpas_get_est_throughput_from_bss_snr(const struct wpa_supplicant *wpa_s,
return wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr);
}
-#endif /* CONFIG_NO_ROAMING */
-
-static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
- struct wpa_bss *selected,
- struct wpa_ssid *ssid)
+int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *current_bss,
+ struct wpa_bss *selected)
{
- struct wpa_bss *current_bss = NULL;
-#ifndef CONFIG_NO_ROAMING
int min_diff, diff;
int to_5ghz;
int cur_level;
unsigned int cur_est, sel_est;
struct wpa_signal_info si;
int cur_snr = 0;
-#endif /* CONFIG_NO_ROAMING */
-
- if (wpa_s->reassociate)
- return 1; /* explicit request to reassociate */
- if (wpa_s->wpa_state < WPA_ASSOCIATED)
- return 1; /* we are not associated; continue */
- if (wpa_s->current_ssid == NULL)
- return 1; /* unknown current SSID */
- if (wpa_s->current_ssid != ssid)
- return 1; /* different network block */
-
- if (wpas_driver_bss_selection(wpa_s))
- return 0; /* Driver-based roaming */
-
- if (wpa_s->current_ssid->ssid)
- current_bss = wpa_bss_get(wpa_s, wpa_s->bssid,
- wpa_s->current_ssid->ssid,
- wpa_s->current_ssid->ssid_len);
- if (!current_bss)
- current_bss = wpa_bss_get_bssid(wpa_s, wpa_s->bssid);
-
- if (!current_bss)
- return 1; /* current BSS not seen in scan results */
-
- if (current_bss == selected)
- return 0;
-
- if (selected->last_update_idx > current_bss->last_update_idx)
- return 1; /* current BSS not seen in the last scan */
+ int ret = 0;
-#ifndef CONFIG_NO_ROAMING
wpa_dbg(wpa_s, MSG_DEBUG, "Considering within-ESS reassociation");
wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR
" freq=%d level=%d snr=%d est_throughput=%u",
@@ -1936,13 +1989,64 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG,
"Skip roam - too small difference in signal level (%d < %d)",
diff, min_diff);
- return 0;
+ ret = 0;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Allow reassociation due to difference in signal level (%d >= %d)",
+ diff, min_diff);
+ ret = 1;
}
+ wpa_msg_ctrl(wpa_s, MSG_INFO, "%scur_bssid=" MACSTR
+ " cur_freq=%d cur_level=%d cur_est=%d sel_bssid=" MACSTR
+ " sel_freq=%d sel_level=%d sel_est=%d",
+ ret ? WPA_EVENT_DO_ROAM : WPA_EVENT_SKIP_ROAM,
+ MAC2STR(current_bss->bssid),
+ current_bss->freq, cur_level, cur_est,
+ MAC2STR(selected->bssid),
+ selected->freq, selected->level, sel_est);
+ return ret;
+}
- wpa_dbg(wpa_s, MSG_DEBUG,
- "Allow reassociation due to difference in signal level (%d >= %d)",
- diff, min_diff);
- return 1;
+#endif /* CONFIG_NO_ROAMING */
+
+
+static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *selected,
+ struct wpa_ssid *ssid)
+{
+ struct wpa_bss *current_bss = NULL;
+
+ if (wpa_s->reassociate)
+ return 1; /* explicit request to reassociate */
+ if (wpa_s->wpa_state < WPA_ASSOCIATED)
+ return 1; /* we are not associated; continue */
+ if (wpa_s->current_ssid == NULL)
+ return 1; /* unknown current SSID */
+ if (wpa_s->current_ssid != ssid)
+ return 1; /* different network block */
+
+ if (wpas_driver_bss_selection(wpa_s))
+ return 0; /* Driver-based roaming */
+
+ if (wpa_s->current_ssid->ssid)
+ current_bss = wpa_bss_get(wpa_s, wpa_s->bssid,
+ wpa_s->current_ssid->ssid,
+ wpa_s->current_ssid->ssid_len);
+ if (!current_bss)
+ current_bss = wpa_bss_get_bssid(wpa_s, wpa_s->bssid);
+
+ if (!current_bss)
+ return 1; /* current BSS not seen in scan results */
+
+ if (current_bss == selected)
+ return 0;
+
+ if (selected->last_update_idx > current_bss->last_update_idx)
+ return 1; /* current BSS not seen in the last scan */
+
+#ifndef CONFIG_NO_ROAMING
+ return wpa_supplicant_need_to_roam_within_ess(wpa_s, current_bss,
+ selected);
#else /* CONFIG_NO_ROAMING */
return 0;
#endif /* CONFIG_NO_ROAMING */
@@ -2574,11 +2678,11 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
{
int l, len, found = 0, found_x = 0, wpa_found, rsn_found;
const u8 *p;
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_OWE)
u8 bssid[ETH_ALEN];
-#endif /* CONFIG_IEEE80211R || CONFIG_OWE */
+ bool bssid_known;
wpa_dbg(wpa_s, MSG_DEBUG, "Association info event");
+ bssid_known = wpa_drv_get_bssid(wpa_s, bssid) == 0;
if (data->assoc_info.req_ies)
wpa_hexdump(MSG_DEBUG, "req_ies", data->assoc_info.req_ies,
data->assoc_info.req_ies_len);
@@ -2695,7 +2799,7 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_OWE
if (wpa_s->key_mgmt == WPA_KEY_MGMT_OWE &&
- (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+ (!bssid_known ||
owe_process_assoc_resp(wpa_s->wpa, bssid,
data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len) < 0)) {
@@ -2730,7 +2834,7 @@ no_pfs:
#ifdef CONFIG_IEEE80211R
#ifdef CONFIG_SME
if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) {
- if (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+ if (!bssid_known ||
wpa_ft_validate_reassoc_resp(wpa_s->wpa,
data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len,
@@ -2790,7 +2894,7 @@ no_pfs:
/* Process FT when SME is in the driver */
if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
wpa_ft_is_completed(wpa_s->wpa)) {
- if (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+ if (!bssid_known ||
wpa_ft_validate_reassoc_resp(wpa_s->wpa,
data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len,
@@ -2808,6 +2912,11 @@ no_pfs:
data->assoc_info.resp_ies_len);
#endif /* CONFIG_IEEE80211R */
+ if (bssid_known)
+ wpas_handle_assoc_resp_mscs(wpa_s, bssid,
+ data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len);
+
/* WPA/RSN IE from Beacon/ProbeResp */
p = data->assoc_info.beacon_ies;
l = data->assoc_info.beacon_ies_len;
@@ -4141,6 +4250,13 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_DPP */
+ if (category == WLAN_ACTION_ROBUST_AV_STREAMING &&
+ payload[0] == ROBUST_AV_MSCS_RESP) {
+ wpas_handle_robust_av_recv_action(wpa_s, mgmt->sa,
+ payload + 1, plen - 1);
+ return;
+ }
+
wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
category, payload, plen, freq);
if (wpa_s->ifmsh)
@@ -4841,7 +4957,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
#endif /* CONFIG_AP */
- sme_event_ch_switch(wpa_s);
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+ sme_event_ch_switch(wpa_s);
+
wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_CS);
wnm_clear_coloc_intf_reporting(wpa_s);
break;
diff --git a/wpa_supplicant/examples/dpp-nfc.py b/wpa_supplicant/examples/dpp-nfc.py
index 1883545..9f7fefb 100755
--- a/wpa_supplicant/examples/dpp-nfc.py
+++ b/wpa_supplicant/examples/dpp-nfc.py
@@ -7,6 +7,8 @@
# This software may be distributed under the terms of the BSD license.
# See README for more details.
+import binascii
+import errno
import os
import struct
import sys
@@ -29,20 +31,28 @@ init_on_touch = False
in_raw_mode = False
prev_tcgetattr = 0
no_input = False
-srv = None
continue_loop = True
terminate_now = False
summary_file = None
success_file = None
-my_crn_ready = False
-my_crn = None
-peer_crn = None
-hs_sent = False
+netrole = None
+operation_success = False
mutex = threading.Lock()
-def summary(txt):
+C_NORMAL = '\033[0m'
+C_RED = '\033[91m'
+C_GREEN = '\033[92m'
+C_YELLOW = '\033[93m'
+C_BLUE = '\033[94m'
+C_MAGENTA = '\033[95m'
+C_CYAN = '\033[96m'
+
+def summary(txt, color=None):
with mutex:
- print(txt)
+ if color:
+ print(color + txt + C_NORMAL)
+ else:
+ print(txt)
if summary_file:
with open(summary_file, 'a') as f:
f.write(txt + "\n")
@@ -67,15 +77,18 @@ def wpas_connect():
return None
for ctrl in ifaces:
- if ifname:
- if ifname not in ctrl:
- continue
+ if ifname and ifname not in ctrl:
+ continue
+ if os.path.basename(ctrl).startswith("p2p-dev-"):
+ # skip P2P management interface
+ continue
try:
summary("Trying to use control interface " + ctrl)
wpas = wpaspy.Ctrl(ctrl)
return wpas
except Exception as e:
pass
+ summary("Could not connect to wpa_supplicant")
return None
def dpp_nfc_uri_process(uri):
@@ -84,7 +97,7 @@ def dpp_nfc_uri_process(uri):
return False
peer_id = wpas.request("DPP_NFC_URI " + uri)
if "FAIL" in peer_id:
- summary("Could not parse DPP URI from NFC URI record")
+ summary("Could not parse DPP URI from NFC URI record", color=C_RED)
return False
peer_id = int(peer_id)
summary("peer_id=%d for URI from NFC Tag: %s" % (peer_id, uri))
@@ -99,7 +112,7 @@ def dpp_nfc_uri_process(uri):
summary("Initiate DPP authentication: " + cmd)
res = wpas.request(cmd)
if "OK" not in res:
- summary("Failed to initiate DPP Authentication")
+ summary("Failed to initiate DPP Authentication", color=C_RED)
return False
summary("DPP Authentication initiated")
return True
@@ -110,20 +123,20 @@ def dpp_hs_tag_read(record):
return False
summary(record)
if len(record.data) < 5:
- summary("Too short DPP HS")
+ summary("Too short DPP HS", color=C_RED)
return False
if record.data[0] != 0:
- summary("Unexpected URI Identifier Code")
+ summary("Unexpected URI Identifier Code", color=C_RED)
return False
uribuf = record.data[1:]
try:
uri = uribuf.decode()
except:
- summary("Invalid URI payload")
+ summary("Invalid URI payload", color=C_RED)
return False
summary("URI: " + uri)
if not uri.startswith("DPP:"):
- summary("Not a DPP URI")
+ summary("Not a DPP URI", color=C_RED)
return False
return dpp_nfc_uri_process(uri)
@@ -179,12 +192,18 @@ def dpp_bootstrap_gen(wpas, type="qrcode", chan=None, mac=None, info=None,
raise Exception("Failed to generate bootstrapping info")
return int(res)
-def wpas_get_nfc_uri(start_listen=True, pick_channel=False):
+def wpas_get_nfc_uri(start_listen=True, pick_channel=False, chan_override=None):
+ listen_freq = 2412
wpas = wpas_connect()
if wpas is None:
return None
global own_id, chanlist
- chan = chanlist
+ if chan_override:
+ chan = chan_override
+ else:
+ chan = chanlist
+ if chan and chan.startswith("81/"):
+ listen_freq = int(chan[3:].split(',')[0]) * 5 + 2407
if chan is None and get_status_field(wpas, "bssid[0]"):
freq = get_status_field(wpas, "freq")
if freq:
@@ -192,15 +211,23 @@ def wpas_get_nfc_uri(start_listen=True, pick_channel=False):
if freq >= 2412 and freq <= 2462:
chan = "81/%d" % ((freq - 2407) / 5)
summary("Use current AP operating channel (%d MHz) as the URI channel list (%s)" % (freq, chan))
+ listen_freq = freq
if chan is None and pick_channel:
chan = "81/6"
summary("Use channel 2437 MHz since no other preference provided")
+ listen_freq = 2437
own_id = dpp_bootstrap_gen(wpas, type="nfc-uri", chan=chan, mac=True)
res = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
if "FAIL" in res:
return None
if start_listen:
- wpas.request("DPP_LISTEN 2412 netrole=configurator")
+ cmd = "DPP_LISTEN %d" % listen_freq
+ global netrole
+ if netrole:
+ cmd += " netrole=" + netrole
+ res2 = wpas.request(cmd)
+ if "OK" not in res2:
+ raise Exception("Failed to start listen operation (%s)" % cmd)
return res
def wpas_report_handover_req(uri):
@@ -219,82 +246,180 @@ def wpas_report_handover_sel(uri):
cmd = "DPP_NFC_HANDOVER_SEL own=%d uri=%s" % (own_id, uri)
return wpas.request(cmd)
-def dpp_handover_client(llc):
- uri = wpas_get_nfc_uri(start_listen=False)
+def dpp_handover_client(handover, alt=False):
+ summary("About to start run_dpp_handover_client (alt=%s)" % str(alt))
+ if alt:
+ handover.i_m_selector = False
+ run_dpp_handover_client(handover, alt)
+ summary("Done run_dpp_handover_client (alt=%s)" % str(alt))
+
+def run_client_alt(handover, alt):
+ if handover.start_client_alt and not alt:
+ handover.start_client_alt = False
+ summary("Try to send alternative handover request")
+ dpp_handover_client(handover, alt=True)
+
+class HandoverClient(nfc.handover.HandoverClient):
+ def __init__(self, handover, llc):
+ super(HandoverClient, self).__init__(llc)
+ self.handover = handover
+
+ def recv_records(self, timeout=None):
+ msg = self.recv_octets(timeout)
+ if msg is None:
+ return None
+ records = list(ndef.message_decoder(msg, 'relax'))
+ if records and records[0].type == 'urn:nfc:wkt:Hs':
+ summary("Handover client received message '{0}'".format(records[0].type))
+ return list(ndef.message_decoder(msg, 'relax'))
+ summary("Handover client received invalid message: %s" + binascii.hexlify(msg))
+ return None
+
+ def recv_octets(self, timeout=None):
+ start = time.time()
+ msg = bytearray()
+ while True:
+ poll_timeout = 0.1 if timeout is None or timeout > 0.1 else timeout
+ if not self.socket.poll('recv', poll_timeout):
+ if timeout:
+ timeout -= time.time() - start
+ if timeout <= 0:
+ return None
+ start = time.time()
+ continue
+ try:
+ r = self.socket.recv()
+ if r is None:
+ return None
+ msg += r
+ except TypeError:
+ return b''
+ try:
+ list(ndef.message_decoder(msg, 'strict', {}))
+ return bytes(msg)
+ except ndef.DecodeError:
+ if timeout:
+ timeout -= time.time() - start
+ if timeout <= 0:
+ return None
+ start = time.time()
+ continue
+ return None
+
+def run_dpp_handover_client(handover, alt=False):
+ chan_override = None
+ if alt:
+ chan_override = handover.altchanlist
+ handover.alt_proposal_used = True
+ global test_uri, test_alt_uri
+ if test_uri:
+ summary("TEST MODE: Using specified URI (alt=%s)" % str(alt))
+ uri = test_alt_uri if alt else test_uri
+ else:
+ uri = wpas_get_nfc_uri(start_listen=False, chan_override=chan_override)
if uri is None:
- summary("Cannot start handover client - no bootstrap URI available")
+ summary("Cannot start handover client - no bootstrap URI available",
+ color=C_RED)
return
+ handover.my_uri = uri
uri = ndef.UriRecord(uri)
summary("NFC URI record for DPP: " + str(uri))
carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
- crn = os.urandom(2)
+ global test_crn
+ if test_crn:
+ prev, = struct.unpack('>H', test_crn)
+ summary("TEST MODE: Use specified crn %d" % prev)
+ crn = test_crn
+ test_crn = struct.pack('>H', prev + 0x10)
+ else:
+ crn = os.urandom(2)
hr = ndef.HandoverRequestRecord(version="1.4", crn=crn)
hr.add_alternative_carrier('active', carrier.name)
message = [hr, carrier]
summary("NFC Handover Request message for DPP: " + str(message))
- global peer_crn
- if peer_crn is not None:
+ if handover.peer_crn is not None and not alt:
summary("NFC handover request from peer was already received - do not send own")
return
- client = nfc.handover.HandoverClient(llc)
- try:
- summary("Trying to initiate NFC connection handover")
- client.connect()
- summary("Connected for handover")
- except nfc.llcp.ConnectRefused:
- summary("Handover connection refused")
- client.close()
- return
- except Exception as e:
- summary("Other exception: " + str(e))
- client.close()
- return
+ if handover.client:
+ summary("Use already started handover client")
+ client = handover.client
+ else:
+ summary("Start handover client")
+ client = HandoverClient(handover, handover.llc)
+ try:
+ summary("Trying to initiate NFC connection handover")
+ client.connect()
+ summary("Connected for handover")
+ except nfc.llcp.ConnectRefused:
+ summary("Handover connection refused")
+ client.close()
+ return
+ except Exception as e:
+ summary("Other exception: " + str(e))
+ client.close()
+ return
+ handover.client = client
- if peer_crn is not None:
+ if handover.peer_crn is not None and not alt:
summary("NFC handover request from peer was already received - do not send own")
- client.close()
return
summary("Sending handover request")
- global my_crn, my_crn_ready, hs_sent
- my_crn_ready = True
+ handover.my_crn_ready = True
if not client.send_records(message):
- my_crn_ready = False
- summary("Failed to send handover request")
- client.close()
+ handover.my_crn_ready = False
+ summary("Failed to send handover request", color=C_RED)
+ run_client_alt(handover, alt)
return
- my_crn, = struct.unpack('>H', crn)
+ handover.my_crn, = struct.unpack('>H', crn)
summary("Receiving handover response")
try:
+ start = time.time()
message = client.recv_records(timeout=3.0)
+ end = time.time()
+ summary("Received {} record(s) in {} seconds".format(len(message) if message is not None else -1, end - start))
except Exception as e:
# This is fine if we are the handover selector
- if hs_sent:
+ if handover.hs_sent:
summary("Client receive failed as expected since I'm the handover server: %s" % str(e))
+ elif handover.alt_proposal_used and not alt:
+ summary("Client received failed for initial proposal as expected since alternative proposal was also used: %s" % str(e))
else:
- summary("Client receive failed: %s" % str(e))
+ summary("Client receive failed: %s" % str(e), color=C_RED)
message = None
if message is None:
- if hs_sent:
+ if handover.hs_sent:
summary("No response received as expected since I'm the handover server")
+ elif handover.alt_proposal_used and not alt:
+ summary("No response received for initial proposal as expected since alternative proposal was also used")
+ elif handover.try_own and not alt:
+ summary("No response received for initial proposal as expected since alternative proposal will also be sent")
else:
- summary("No response received")
- client.close()
+ summary("No response received", color=C_RED)
+ run_client_alt(handover, alt)
return
summary("Received message: " + str(message))
if len(message) < 1 or \
not isinstance(message[0], ndef.HandoverSelectRecord):
summary("Response was not Hs - received: " + message.type)
- client.close()
return
summary("Received handover select message")
summary("alternative carriers: " + str(message[0].alternative_carriers))
+ if handover.i_m_selector:
+ summary("Ignore the received select since I'm the handover selector")
+ run_client_alt(handover, alt)
+ return
+
+ if handover.alt_proposal_used and not alt:
+ summary("Ignore received handover select for the initial proposal since alternative proposal was sent")
+ client.close()
+ return
dpp_found = False
for carrier in message:
@@ -303,15 +428,19 @@ def dpp_handover_client(llc):
summary("Remote carrier type: " + carrier.type)
if carrier.type == "application/vnd.wfa.dpp":
if len(carrier.data) == 0 or carrier.data[0] != 0:
- summary("URI Identifier Code 'None' not seen")
+ summary("URI Identifier Code 'None' not seen", color=C_RED)
continue
summary("DPP carrier type match - send to wpa_supplicant")
dpp_found = True
uri = carrier.data[1:].decode("utf-8")
summary("DPP URI: " + uri)
+ handover.peer_uri = uri
+ if test_uri:
+ summary("TEST MODE: Fake processing")
+ break
res = wpas_report_handover_sel(uri)
if res is None or "FAIL" in res:
- summary("DPP handover report rejected")
+ summary("DPP handover report rejected", color=C_RED)
break
success_report("DPP handover reported successfully (initiator)")
@@ -331,7 +460,7 @@ def dpp_handover_client(llc):
# TODO: Single Configurator instance
res = wpas.request("DPP_CONFIGURATOR_ADD")
if "FAIL" in res:
- summary("Failed to initiate Configurator")
+ summary("Failed to initiate Configurator", color=C_RED)
break
conf_id = int(res)
extra = " conf=sta-dpp configurator=%d" % conf_id
@@ -341,17 +470,23 @@ def dpp_handover_client(llc):
cmd += extra
res = wpas.request(cmd)
if "FAIL" in res:
- summary("Failed to initiate DPP authentication")
+ summary("Failed to initiate DPP authentication", color=C_RED)
break
- if not dpp_found:
+ if not dpp_found and handover.no_alt_proposal:
+ summary("DPP carrier not seen in response - do not allow alternative proposal anymore")
+ elif not dpp_found:
summary("DPP carrier not seen in response - allow peer to initiate a new handover with different parameters")
- client.close()
+ handover.alt_proposal = True
+ handover.my_crn_ready = False
+ handover.my_crn = None
+ handover.peer_crn = None
+ handover.hs_sent = False
summary("Returning from dpp_handover_client")
return
summary("Remove peer")
- client.close()
+ handover.close()
summary("Done with handover")
global only_one
if only_one:
@@ -360,22 +495,67 @@ def dpp_handover_client(llc):
continue_loop = False
global no_wait
- if no_wait:
- print("Trying to exit..")
+ if no_wait or only_one:
+ summary("Trying to exit..")
global terminate_now
terminate_now = True
summary("Returning from dpp_handover_client")
class HandoverServer(nfc.handover.HandoverServer):
- def __init__(self, llc):
+ def __init__(self, handover, llc):
super(HandoverServer, self).__init__(llc)
self.sent_carrier = None
self.ho_server_processing = False
self.success = False
- self.try_own = False
+ self.llc = llc
+ self.handover = handover
+
+ def serve(self, socket):
+ peer_sap = socket.getpeername()
+ summary("Serving handover client on remote sap {0}".format(peer_sap))
+ send_miu = socket.getsockopt(nfc.llcp.SO_SNDMIU)
+ try:
+ while socket.poll("recv"):
+ req = bytearray()
+ while socket.poll("recv"):
+ r = socket.recv()
+ if r is None:
+ return None
+ summary("Received %d octets" % len(r))
+ req += r
+ if len(req) == 0:
+ continue
+ try:
+ list(ndef.message_decoder(req, 'strict', {}))
+ except ndef.DecodeError:
+ continue
+ summary("Full message received")
+ resp = self._process_request_data(req)
+ if resp is None or len(resp) == 0:
+ summary("No handover select to send out - wait for a possible alternative handover request")
+ handover.alt_proposal = True
+ req = bytearray()
+ continue
+
+ for offset in range(0, len(resp), send_miu):
+ if not socket.send(resp[offset:offset + send_miu]):
+ summary("Failed to send handover select - connection closed")
+ return
+ summary("Sent out full handover select")
+ if handover.terminate_on_hs_send_completion:
+ handover.delayed_exit()
+
+ except nfc.llcp.Error as e:
+ global terminate_now
+ summary("HandoverServer exception: %s" % e,
+ color=None if e.errno == errno.EPIPE or terminate_now else C_RED)
+ finally:
+ socket.close()
+ summary("Handover serve thread exiting")
def process_handover_request_message(self, records):
+ handover = self.handover
self.ho_server_processing = True
global in_raw_mode
was_in_raw_mode = in_raw_mode
@@ -384,33 +564,33 @@ class HandoverServer(nfc.handover.HandoverServer):
print("\n")
summary("HandoverServer - request received: " + str(records))
- global my_crn, peer_crn, my_crn_ready
-
for carrier in records:
if not isinstance(carrier, ndef.HandoverRequestRecord):
continue
if carrier.collision_resolution_number:
- peer_crn = carrier.collision_resolution_number
- summary("peer_crn: %d" % peer_crn)
+ handover.peer_crn = carrier.collision_resolution_number
+ summary("peer_crn: %d" % handover.peer_crn)
- if my_crn is None and my_crn_ready:
+ if handover.my_crn is None and handover.my_crn_ready:
summary("Still trying to send own handover request - wait a moment to see if that succeeds before checking crn values")
for i in range(10):
- if my_crn is not None:
+ if handover.my_crn is not None:
break
time.sleep(0.01)
- if my_crn is not None:
- summary("my_crn: %d" % my_crn)
+ if handover.my_crn is not None:
+ summary("my_crn: %d" % handover.my_crn)
- if my_crn is not None and peer_crn is not None:
- if my_crn == peer_crn:
+ if handover.my_crn is not None and handover.peer_crn is not None:
+ if handover.my_crn == handover.peer_crn:
summary("Same crn used - automatic collision resolution failed")
# TODO: Should generate a new Handover Request message
return ''
- if ((my_crn & 1) == (peer_crn & 1) and my_crn > peer_crn) or \
- ((my_crn & 1) != (peer_crn & 1) and my_crn < peer_crn):
+ if ((handover.my_crn & 1) == (handover.peer_crn & 1) and \
+ handover.my_crn > handover.peer_crn) or \
+ ((handover.my_crn & 1) != (handover.peer_crn & 1) and \
+ handover.my_crn < handover.peer_crn):
summary("I'm the Handover Selector Device")
- pass
+ handover.i_m_selector = True
else:
summary("Peer is the Handover Selector device")
summary("Ignore the received request.")
@@ -428,61 +608,90 @@ class HandoverServer(nfc.handover.HandoverServer):
if carrier.type == "application/vnd.wfa.dpp":
summary("DPP carrier type match - add DPP carrier record")
if len(carrier.data) == 0 or carrier.data[0] != 0:
- summary("URI Identifier Code 'None' not seen")
+ summary("URI Identifier Code 'None' not seen", color=C_RED)
continue
uri = carrier.data[1:].decode("utf-8")
summary("Received DPP URI: " + uri)
- data = wpas_get_nfc_uri(start_listen=False, pick_channel=True)
+ global test_uri, test_alt_uri
+ if test_uri:
+ summary("TEST MODE: Using specified URI")
+ data = test_sel_uri if test_sel_uri else test_uri
+ elif handover.alt_proposal and handover.altchanlist:
+ summary("Use alternative channel list while processing alternative proposal from peer")
+ data = wpas_get_nfc_uri(start_listen=False,
+ chan_override=handover.altchanlist,
+ pick_channel=True)
+ else:
+ data = wpas_get_nfc_uri(start_listen=False,
+ pick_channel=True)
summary("Own URI (pre-processing): %s" % data)
- res = wpas_report_handover_req(uri)
+ if test_uri:
+ summary("TEST MODE: Fake processing")
+ res = "OK"
+ data += " [%s]" % uri
+ else:
+ res = wpas_report_handover_req(uri)
if res is None or "FAIL" in res:
- summary("DPP handover request processing failed")
+ summary("DPP handover request processing failed",
+ color=C_RED)
+ if handover.altchanlist:
+ data = wpas_get_nfc_uri(start_listen=False,
+ chan_override=handover.altchanlist)
+ summary("Own URI (try another channel list): %s" % data)
+ continue
+
+ if test_alt_uri:
+ summary("TEST MODE: Reject initial proposal")
continue
found = True
- wpas = wpas_connect()
- if wpas is None:
- continue
- global own_id
- data = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
- if "FAIL" in data:
- continue
+ if not test_uri:
+ wpas = wpas_connect()
+ if wpas is None:
+ continue
+ global own_id
+ data = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
+ if "FAIL" in data:
+ continue
summary("Own URI (post-processing): %s" % data)
+ handover.my_uri = data
+ handover.peer_uri = uri
uri = ndef.UriRecord(data)
summary("Own bootstrapping NFC URI record: " + str(uri))
- info = wpas.request("DPP_BOOTSTRAP_INFO %d" % own_id)
- freq = None
- for line in info.splitlines():
- if line.startswith("use_freq="):
- freq = int(line.split('=')[1])
- if freq is None or freq == 0:
- summary("No channel negotiated over NFC - use channel 6")
- freq = 2437
- else:
- summary("Negotiated channel: %d MHz" % freq)
- if get_status_field(wpas, "bssid[0]"):
- summary("Own AP freq: %s MHz" % str(get_status_field(wpas, "freq")))
- if get_status_field(wpas, "beacon_set", extra="DRIVER") is None:
- summary("Enable beaconing to have radio ready for RX")
- wpas.request("DISABLE")
- wpas.request("SET start_disabled 0")
- wpas.request("ENABLE")
- cmd = "DPP_LISTEN %d" % freq
- global enrollee_only
- global configurator_only
- if enrollee_only:
- cmd += " role=enrollee"
- elif configurator_only:
- cmd += " role=configurator"
- summary(cmd)
- res = wpas.request(cmd)
- if "OK" not in res:
- summary("Failed to start DPP listen")
- break
+ if not test_uri:
+ info = wpas.request("DPP_BOOTSTRAP_INFO %d" % own_id)
+ freq = None
+ for line in info.splitlines():
+ if line.startswith("use_freq="):
+ freq = int(line.split('=')[1])
+ if freq is None or freq == 0:
+ summary("No channel negotiated over NFC - use channel 6")
+ freq = 2437
+ else:
+ summary("Negotiated channel: %d MHz" % freq)
+ if get_status_field(wpas, "bssid[0]"):
+ summary("Own AP freq: %s MHz" % str(get_status_field(wpas, "freq")))
+ if get_status_field(wpas, "beacon_set", extra="DRIVER") is None:
+ summary("Enable beaconing to have radio ready for RX")
+ wpas.request("DISABLE")
+ wpas.request("SET start_disabled 0")
+ wpas.request("ENABLE")
+ cmd = "DPP_LISTEN %d" % freq
+ global enrollee_only
+ global configurator_only
+ if enrollee_only:
+ cmd += " role=enrollee"
+ elif configurator_only:
+ cmd += " role=configurator"
+ summary(cmd)
+ res = wpas.request(cmd)
+ if "OK" not in res:
+ summary("Failed to start DPP listen", color=C_RED)
+ break
carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
summary("Own DPP carrier record: " + str(carrier))
@@ -492,11 +701,26 @@ class HandoverServer(nfc.handover.HandoverServer):
summary("Sending handover select: " + str(sel))
if found:
+ summary("Handover completed successfully")
+ handover.terminate_on_hs_send_completion = True
self.success = True
+ handover.hs_sent = True
+ handover.i_m_selector = True
+ elif handover.no_alt_proposal:
+ summary("Do not try alternative proposal anymore - handover failed",
+ color=C_RED)
+ handover.hs_sent = True
else:
- self.try_own = True
- global hs_sent
- hs_sent = True
+ summary("Try to initiate with alternative parameters")
+ handover.try_own = True
+ handover.hs_sent = False
+ handover.no_alt_proposal = True
+ if handover.client_thread:
+ handover.start_client_alt = True
+ else:
+ handover.client_thread = threading.Thread(target=llcp_worker,
+ args=(self.llc, True))
+ handover.client_thread.start()
return sel
def clear_raw_mode():
@@ -553,17 +777,25 @@ def dpp_tag_read(tag):
def rdwr_connected_write_tag(tag):
summary("Tag found - writing - " + str(tag))
+ if not tag.ndef:
+ summary("Not a formatted NDEF tag", color=C_RED)
+ return
if not tag.ndef.is_writeable:
- summary("Not a writable tag")
+ summary("Not a writable tag", color=C_RED)
return
global dpp_tag_data
if tag.ndef.capacity < len(dpp_tag_data):
summary("Not enough room for the message")
return
- tag.ndef.records = dpp_tag_data
+ try:
+ tag.ndef.records = dpp_tag_data
+ except ValueError as e:
+ summary("Writing the tag failed: %s" % str(e), color=C_RED)
+ return
success_report("Tag write succeeded")
- summary("Done - remove tag")
- global only_one
+ summary("Tag writing completed - remove tag", color=C_GREEN)
+ global only_one, operation_success
+ operation_success = True
if only_one:
global continue_loop
continue_loop = False
@@ -574,7 +806,7 @@ def write_nfc_uri(clf, wait_remove=True):
summary("Write NFC URI record")
data = wpas_get_nfc_uri()
if data is None:
- summary("Could not get NFC URI from wpa_supplicant")
+ summary("Could not get NFC URI from wpa_supplicant", color=C_RED)
return
global dpp_sel_wait_remove
@@ -583,7 +815,7 @@ def write_nfc_uri(clf, wait_remove=True):
uri = ndef.UriRecord(data)
summary(uri)
- summary("Touch an NFC tag")
+ summary("Touch an NFC tag to write URI record", color=C_CYAN)
global dpp_tag_data
dpp_tag_data = [uri]
clf.connect(rdwr={'on-connect': rdwr_connected_write_tag})
@@ -592,7 +824,7 @@ def write_nfc_hs(clf, wait_remove=True):
summary("Write NFC Handover Select record on a tag")
data = wpas_get_nfc_uri()
if data is None:
- summary("Could not get NFC URI from wpa_supplicant")
+ summary("Could not get NFC URI from wpa_supplicant", color=C_RED)
return
global dpp_sel_wait_remove
@@ -606,7 +838,7 @@ def write_nfc_hs(clf, wait_remove=True):
summary(hs)
summary(carrier)
- summary("Touch an NFC tag")
+ summary("Touch an NFC tag to write HS record", color=C_CYAN)
global dpp_tag_data
dpp_tag_data = [hs, carrier]
summary(dpp_tag_data)
@@ -624,17 +856,24 @@ def rdwr_connected(tag):
global continue_loop
continue_loop = False
else:
- summary("Not an NDEF tag - remove tag")
+ summary("Not an NDEF tag - remove tag", color=C_RED)
return True
return not no_wait
-def llcp_worker(llc):
+def llcp_worker(llc, try_alt):
+ global handover
+ print("Start of llcp_worker()")
+ if try_alt:
+ summary("Starting handover client (try_alt)")
+ dpp_handover_client(handover, alt=True)
+ summary("Exiting llcp_worker thread (try_alt)")
+ return
global init_on_touch
if init_on_touch:
- summary("Starting handover client")
- dpp_handover_client(llc)
- summary("Exiting llcp_worker thread (init_in_touch)")
+ summary("Starting handover client (init_on_touch)")
+ dpp_handover_client(handover)
+ summary("Exiting llcp_worker thread (init_on_touch)")
return
global no_input
@@ -642,16 +881,18 @@ def llcp_worker(llc):
summary("Wait for handover to complete")
else:
print("Wait for handover to complete - press 'i' to initiate")
- global srv
- global wait_connection
- while not wait_connection and srv.sent_carrier is None:
- if srv.try_own:
- srv.try_own = False
+ while not handover.wait_connection and handover.srv.sent_carrier is None:
+ if handover.try_own:
+ handover.try_own = False
summary("Try to initiate another handover with own parameters")
- dpp_handover_client(llc)
+ handover.my_crn_ready = False
+ handover.my_crn = None
+ handover.peer_crn = None
+ handover.hs_sent = False
+ dpp_handover_client(handover, alt=True)
summary("Exiting llcp_worker thread (retry with own parameters)")
return
- if srv.ho_server_processing:
+ if handover.srv.ho_server_processing:
time.sleep(0.025)
elif no_input:
time.sleep(0.5)
@@ -661,7 +902,7 @@ def llcp_worker(llc):
continue
clear_raw_mode()
summary("Starting handover client")
- dpp_handover_client(llc)
+ dpp_handover_client(handover)
summary("Exiting llcp_worker thread (manual init)")
return
@@ -672,28 +913,73 @@ def llcp_worker(llc):
print("\r")
summary("Exiting llcp_worker thread")
+class ConnectionHandover():
+ def __init__(self):
+ self.client = None
+ self.client_thread = None
+ self.reset()
+ self.exit_thread = None
+
+ def reset(self):
+ self.wait_connection = False
+ self.my_crn_ready = False
+ self.my_crn = None
+ self.peer_crn = None
+ self.hs_sent = False
+ self.no_alt_proposal = False
+ self.alt_proposal_used = False
+ self.i_m_selector = False
+ self.start_client_alt = False
+ self.terminate_on_hs_send_completion = False
+ self.try_own = False
+ self.my_uri = None
+ self.peer_uri = None
+ self.connected = False
+ self.alt_proposal = False
+
+ def start_handover_server(self, llc):
+ summary("Start handover server")
+ self.llc = llc
+ self.srv = HandoverServer(self, llc)
+
+ def close(self):
+ if self.client:
+ self.client.close()
+ self.client = None
+
+ def run_delayed_exit(self):
+ summary("Trying to exit (delayed)..")
+ time.sleep(0.25)
+ summary("Trying to exit (after wait)..")
+ global terminate_now
+ terminate_now = True
+
+ def delayed_exit(self):
+ global only_one
+ if only_one:
+ self.exit_thread = threading.Thread(target=self.run_delayed_exit)
+ self.exit_thread.start()
+
def llcp_startup(llc):
- summary("Start LLCP server")
- global srv
- srv = HandoverServer(llc)
+ global handover
+ handover.start_handover_server(llc)
return llc
def llcp_connected(llc):
summary("P2P LLCP connected")
- global wait_connection, my_crn, peer_crn, my_crn_ready, hs_sent
- wait_connection = False
- my_crn_ready = False
- my_crn = None
- peer_crn = None
- hs_sent = False
- global srv
- srv.start()
+ global handover
+ handover.connected = True
+ handover.srv.start()
if init_on_touch or not no_input:
- threading.Thread(target=llcp_worker, args=(llc,)).start()
+ handover.client_thread = threading.Thread(target=llcp_worker,
+ args=(llc, False))
+ handover.client_thread.start()
return True
def llcp_release(llc):
summary("LLCP release")
+ global handover
+ handover.close()
return True
def terminate_loop():
@@ -737,22 +1023,53 @@ def main():
help='success file for writing success update')
parser.add_argument('--device', default='usb', help='NFC device to open')
parser.add_argument('--chan', default=None, help='channel list')
+ parser.add_argument('--altchan', default=None, help='alternative channel list')
+ parser.add_argument('--netrole', default=None, help='netrole for Enrollee')
+ parser.add_argument('--test-uri', default=None,
+ help='test mode: initial URI')
+ parser.add_argument('--test-alt-uri', default=None,
+ help='test mode: alternative URI')
+ parser.add_argument('--test-sel-uri', default=None,
+ help='test mode: handover select URI')
+ parser.add_argument('--test-crn', default=None,
+ help='test mode: hardcoded crn')
parser.add_argument('command', choices=['write-nfc-uri',
'write-nfc-hs'],
nargs='?')
args = parser.parse_args()
summary(args)
+ global handover
+ handover = ConnectionHandover()
+
global only_one
only_one = args.only_one
global no_wait
no_wait = args.no_wait
- global chanlist
+ global chanlist, netrole, test_uri, test_alt_uri, test_sel_uri
+ global test_crn
chanlist = args.chan
+ handover.altchanlist = args.altchan
+ netrole = args.netrole
+ test_uri = args.test_uri
+ test_alt_uri = args.test_alt_uri
+ test_sel_uri = args.test_sel_uri
+ if args.test_crn:
+ test_crn = struct.pack('>H', int(args.test_crn))
+ else:
+ test_crn = None
logging.basicConfig(level=args.loglevel)
+ for l in ['nfc.clf.rcs380',
+ 'nfc.clf.transport',
+ 'nfc.clf.device',
+ 'nfc.clf.__init__',
+ 'nfc.llcp',
+ 'nfc.handover']:
+ log = logging.getLogger(l)
+ log.setLevel(args.loglevel)
global init_on_touch
init_on_touch = args.init_on_touch
@@ -788,19 +1105,22 @@ def main():
no_input = True
clf = nfc.ContactlessFrontend()
- global wait_connection
try:
if not clf.open(args.device):
- summary("Could not open connection with an NFC device")
- raise SystemExit
+ summary("Could not open connection with an NFC device", color=C_RED)
+ raise SystemExit(1)
if args.command == "write-nfc-uri":
write_nfc_uri(clf, wait_remove=not args.no_wait)
+ if not operation_success:
+ raise SystemExit(1)
raise SystemExit
if args.command == "write-nfc-hs":
write_nfc_hs(clf, wait_remove=not args.no_wait)
+ if not operation_success:
+ raise SystemExit(1)
raise SystemExit
global continue_loop
@@ -810,8 +1130,14 @@ def main():
clear_raw_mode()
if was_in_raw_mode:
print("\r")
- summary("Waiting for a tag or peer to be touched")
- wait_connection = True
+ if args.handover_only:
+ summary("Waiting a peer to be touched", color=C_MAGENTA)
+ elif args.tag_read_only:
+ summary("Waiting for a tag to be touched", color=C_BLUE)
+ else:
+ summary("Waiting for a tag or peer to be touched",
+ color=C_GREEN)
+ handover.wait_connection = True
try:
if args.tag_read_only:
if not clf.connect(rdwr={'on-connect': rdwr_connected}):
@@ -833,9 +1159,18 @@ def main():
summary("clf.connect failed: " + str(e))
break
- global srv
- if only_one and srv and srv.success:
- raise SystemExit
+ if only_one and handover.connected:
+ role = "selector" if handover.i_m_selector else "requestor"
+ summary("Connection handover result: I'm the %s" % role,
+ color=C_YELLOW)
+ if handover.peer_uri:
+ summary("Peer URI: " + handover.peer_uri, color=C_YELLOW)
+ if handover.my_uri:
+ summary("My URI: " + handover.my_uri, color=C_YELLOW)
+ if not (handover.peer_uri and handover.my_uri):
+ summary("Negotiated connection handover failed",
+ color=C_YELLOW)
+ break
except KeyboardInterrupt:
raise SystemExit
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 4b3fcfc..e60a8c1 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -694,13 +694,15 @@ static void gas_query_start_cb(struct wpa_radio_work *work, int deinit)
return;
}
- if (!query->maintain_addr &&
- wpas_update_random_addr_disassoc(wpa_s) < 0) {
- wpa_msg(wpa_s, MSG_INFO,
- "Failed to assign random MAC address for GAS");
- gas_query_free(query, 1);
- radio_work_done(work);
- return;
+ if (!query->maintain_addr && !wpa_s->conf->gas_rand_mac_addr) {
+ if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Failed to assign random MAC address for GAS");
+ gas_query_free(query, 1);
+ radio_work_done(work);
+ return;
+ }
+ os_memcpy(query->sa, wpa_s->own_addr, ETH_ALEN);
}
gas->work = work;
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index a380123..00e1492 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -959,7 +959,9 @@ static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
"WPA-EAP WPA-EAP-SHA256" : "WPA-EAP";
if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0 ||
wpa_config_set(ssid, "proto", "RSN", 0) < 0 ||
- wpa_config_set(ssid, "ieee80211w", "1", 0) < 0 ||
+ wpa_config_set(ssid, "ieee80211w",
+ wpa_s->conf->pmf == MGMT_FRAME_PROTECTION_REQUIRED ?
+ "2" : "1", 0) < 0 ||
wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
return -1;
return 0;
@@ -2748,27 +2750,27 @@ void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s)
}
-int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
+int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, int freq,
u16 info_ids[], size_t num_ids, u32 subtypes,
u32 mbo_subtypes)
{
struct wpabuf *buf;
struct wpabuf *extra_buf = NULL;
int ret = 0;
- int freq;
struct wpa_bss *bss;
int res;
bss = wpa_bss_get_bssid(wpa_s, dst);
- if (!bss) {
+ if (!bss && !freq) {
wpa_printf(MSG_WARNING,
- "ANQP: Cannot send query to unknown BSS "
- MACSTR, MAC2STR(dst));
+ "ANQP: Cannot send query without BSS freq info");
return -1;
}
- wpa_bss_anqp_unshare_alloc(bss);
- freq = bss->freq;
+ if (bss)
+ wpa_bss_anqp_unshare_alloc(bss);
+ if (bss && !freq)
+ freq = bss->freq;
wpa_msg(wpa_s, MSG_DEBUG,
"ANQP: Query Request to " MACSTR " for %u id(s)",
@@ -2787,6 +2789,13 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
if (mbo_subtypes) {
struct wpabuf *mbo;
+ if (!bss) {
+ wpa_printf(MSG_WARNING,
+ "ANQP: Cannot send MBO query to unknown BSS "
+ MACSTR, MAC2STR(dst));
+ return -1;
+ }
+
mbo = mbo_build_anqp_buf(wpa_s, bss, mbo_subtypes);
if (mbo) {
if (wpabuf_resize(&extra_buf, wpabuf_len(mbo))) {
diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h
index 37ee2e9..77b2c91 100644
--- a/wpa_supplicant/interworking.h
+++ b/wpa_supplicant/interworking.h
@@ -11,7 +11,7 @@
enum gas_query_result;
-int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
+int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, int freq,
u16 info_ids[], size_t num_ids, u32 subtypes,
u32 mbo_subtypes);
void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index ea62abf..3abbe09 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -533,6 +533,8 @@ static int mesh_mpm_plink_close(struct hostapd_data *hapd, struct sta_info *sta,
int reason = WLAN_REASON_MESH_PEERING_CANCELLED;
if (sta) {
+ if (sta->plink_state == PLINK_ESTAB)
+ hapd->num_plinks--;
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason);
wpa_printf(MSG_DEBUG, "MPM closing plink sta=" MACSTR,
diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c
index 983801f..bd97fee 100644
--- a/wpa_supplicant/op_classes.c
+++ b/wpa_supplicant/op_classes.c
@@ -22,13 +22,13 @@ static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode,
unsigned int *flags)
{
int i;
- int is_6ghz = op_class >= 131 && op_class <= 135;
+ int is_6ghz = op_class >= 131 && op_class <= 136;
for (i = 0; i < mode->num_channels; i++) {
int chan_is_6ghz;
- chan_is_6ghz = mode->channels[i].freq > 5940 &&
- mode->channels[i].freq <= 7105;
+ chan_is_6ghz = mode->channels[i].freq >= 5935 &&
+ mode->channels[i].freq <= 7115;
if (is_6ghz == chan_is_6ghz && mode->channels[i].chan == chan)
break;
}
diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c
index 4a8f4ff..de49948 100644
--- a/wpa_supplicant/preauth_test.c
+++ b/wpa_supplicant/preauth_test.c
@@ -154,7 +154,8 @@ static int wpa_supplicant_add_pmkid(void *wpa_s, void *network_ctx,
const u8 *bssid, const u8 *pmkid,
const u8 *fils_cache_id,
const u8 *pmk, size_t pmk_len,
- u32 pmk_lifetime, u8 pmk_reauth_threshold)
+ u32 pmk_lifetime, u8 pmk_reauth_threshold,
+ int akmp)
{
printf("%s - not implemented\n", __func__);
return -1;
diff --git a/wpa_supplicant/robust_av.c b/wpa_supplicant/robust_av.c
new file mode 100644
index 0000000..3131551
--- /dev/null
+++ b/wpa_supplicant/robust_av.c
@@ -0,0 +1,157 @@
+/*
+ * wpa_supplicant - Robust AV procedures
+ * Copyright (c) 2020, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "common/wpa_ctrl.h"
+#include "common/ieee802_11_common.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "bss.h"
+
+
+void wpas_populate_mscs_descriptor_ie(struct robust_av_data *robust_av,
+ struct wpabuf *buf)
+{
+ u8 *len, *len1;
+
+ /* MSCS descriptor element */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ len = wpabuf_put(buf, 1);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_MSCS_DESCRIPTOR);
+ wpabuf_put_u8(buf, robust_av->request_type);
+ wpabuf_put_u8(buf, robust_av->up_bitmap);
+ wpabuf_put_u8(buf, robust_av->up_limit);
+ wpabuf_put_le32(buf, robust_av->stream_timeout);
+
+ if (robust_av->request_type != SCS_REQ_REMOVE) {
+ /* TCLAS mask element */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ len1 = wpabuf_put(buf, 1);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_TCLAS_MASK);
+
+ /* Frame classifier */
+ wpabuf_put_data(buf, robust_av->frame_classifier,
+ robust_av->frame_classifier_len);
+ *len1 = (u8 *) wpabuf_put(buf, 0) - len1 - 1;
+ }
+
+ *len = (u8 *) wpabuf_put(buf, 0) - len - 1;
+}
+
+
+int wpas_send_mscs_req(struct wpa_supplicant *wpa_s)
+{
+ struct wpabuf *buf;
+ const u8 *ext_capab = NULL;
+ size_t buf_len;
+ int ret;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid)
+ return 0;
+
+ if (wpa_s->current_bss)
+ ext_capab = wpa_bss_get_ie(wpa_s->current_bss,
+ WLAN_EID_EXT_CAPAB);
+
+ if (!ext_capab || ext_capab[1] < 11 || !(ext_capab[12] & 0x20)) {
+ wpa_dbg(wpa_s, MSG_INFO,
+ "AP does not support MSCS - could not send MSCS Req");
+ return -1;
+ }
+
+ if (!wpa_s->mscs_setup_done &&
+ wpa_s->robust_av.request_type != SCS_REQ_ADD) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "MSCS: Failed to send MSCS Request: request type invalid");
+ return -1;
+ }
+
+ buf_len = 3 + /* Action frame header */
+ 3 + /* MSCS descriptor IE header */
+ 1 + /* Request type */
+ 2 + /* User priority control */
+ 4 + /* Stream timeout */
+ 3 + /* TCLAS Mask IE header */
+ wpa_s->robust_av.frame_classifier_len;
+
+ buf = wpabuf_alloc(buf_len);
+ if (!buf) {
+ wpa_printf(MSG_ERROR, "Failed to allocate MSCS req");
+ return -1;
+ }
+
+ wpabuf_put_u8(buf, WLAN_ACTION_ROBUST_AV_STREAMING);
+ wpabuf_put_u8(buf, ROBUST_AV_MSCS_REQ);
+ wpa_s->robust_av.dialog_token++;
+ wpabuf_put_u8(buf, wpa_s->robust_av.dialog_token);
+
+ /* MSCS descriptor element */
+ wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, buf);
+
+ wpa_hexdump_buf(MSG_MSGDUMP, "MSCS Request", wpabuf_head(buf));
+ ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0);
+ if (ret < 0)
+ wpa_dbg(wpa_s, MSG_INFO, "MSCS: Failed to send MSCS Request");
+
+ wpabuf_free(buf);
+ return ret;
+}
+
+
+void wpas_handle_robust_av_recv_action(struct wpa_supplicant *wpa_s,
+ const u8 *src, const u8 *buf, size_t len)
+{
+ u8 dialog_token;
+ u16 status_code;
+
+ if (len < 3)
+ return;
+
+ dialog_token = *buf++;
+ if (dialog_token != wpa_s->robust_av.dialog_token) {
+ wpa_printf(MSG_INFO,
+ "MSCS: Drop received frame due to dialog token mismatch: received:%u expected:%u",
+ dialog_token, wpa_s->robust_av.dialog_token);
+ return;
+ }
+
+ status_code = *buf;
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_MSCS_RESULT "bssid=" MACSTR
+ " status_code=%u", MAC2STR(src), status_code);
+ wpa_s->mscs_setup_done = status_code == WLAN_STATUS_SUCCESS;
+}
+
+
+void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const u8 *ies, size_t ies_len)
+{
+ const u8 *mscs_desc_ie, *mscs_status;
+ u16 status;
+
+ /* Process optional MSCS Status subelement when MSCS IE is in
+ * (Re)Association Response frame */
+ if (!ies || ies_len == 0 || !wpa_s->robust_av.valid_config)
+ return;
+
+ mscs_desc_ie = get_ie_ext(ies, ies_len, WLAN_EID_EXT_MSCS_DESCRIPTOR);
+ if (!mscs_desc_ie || mscs_desc_ie[1] < 1)
+ return;
+
+ mscs_status = get_ie(mscs_desc_ie, mscs_desc_ie[1],
+ MCSC_SUBELEM_STATUS);
+ if (!mscs_status || mscs_status[1] < 2)
+ return;
+
+ status = WPA_GET_LE16(mscs_status + 2);
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_MSCS_RESULT "bssid=" MACSTR
+ " status_code=%u", MAC2STR(bssid), status);
+ wpa_s->mscs_setup_done = status == WLAN_STATUS_SUCCESS;
+}
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index b475730..7415eae 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -2187,6 +2187,60 @@ void scan_snr(struct wpa_scan_res *res)
}
+/* Minimum SNR required to achieve a certain bitrate. */
+struct minsnr_bitrate_entry {
+ int minsnr;
+ unsigned int bitrate; /* in Mbps */
+};
+
+/* VHT needs to be enabled in order to achieve MCS8 and MCS9 rates. */
+static const int vht_mcs = 8;
+
+static const struct minsnr_bitrate_entry vht20_table[] = {
+ { 0, 0 },
+ { 2, 6500 }, /* HT20 MCS0 */
+ { 5, 13000 }, /* HT20 MCS1 */
+ { 9, 19500 }, /* HT20 MCS2 */
+ { 11, 26000 }, /* HT20 MCS3 */
+ { 15, 39000 }, /* HT20 MCS4 */
+ { 18, 52000 }, /* HT20 MCS5 */
+ { 20, 58500 }, /* HT20 MCS6 */
+ { 25, 65000 }, /* HT20 MCS7 */
+ { 29, 78000 }, /* VHT20 MCS8 */
+ { -1, 78000 } /* SNR > 29 */
+};
+
+static const struct minsnr_bitrate_entry vht40_table[] = {
+ { 0, 0 },
+ { 5, 13500 }, /* HT40 MCS0 */
+ { 8, 27000 }, /* HT40 MCS1 */
+ { 12, 40500 }, /* HT40 MCS2 */
+ { 14, 54000 }, /* HT40 MCS3 */
+ { 18, 81000 }, /* HT40 MCS4 */
+ { 21, 108000 }, /* HT40 MCS5 */
+ { 23, 121500 }, /* HT40 MCS6 */
+ { 28, 135000 }, /* HT40 MCS7 */
+ { 32, 162000 }, /* VHT40 MCS8 */
+ { 34, 180000 }, /* VHT40 MCS9 */
+ { -1, 180000 } /* SNR > 34 */
+};
+
+static const struct minsnr_bitrate_entry vht80_table[] = {
+ { 0, 0 },
+ { 8, 29300 }, /* VHT80 MCS0 */
+ { 11, 58500 }, /* VHT80 MCS1 */
+ { 15, 87800 }, /* VHT80 MCS2 */
+ { 17, 117000 }, /* VHT80 MCS3 */
+ { 21, 175500 }, /* VHT80 MCS4 */
+ { 24, 234000 }, /* VHT80 MCS5 */
+ { 26, 263300 }, /* VHT80 MCS6 */
+ { 31, 292500 }, /* VHT80 MCS7 */
+ { 35, 351000 }, /* VHT80 MCS8 */
+ { 37, 390000 }, /* VHT80 MCS9 */
+ { -1, 390000 } /* SNR > 37 */
+};
+
+
static unsigned int interpolate_rate(int snr, int snr0, int snr1,
int rate0, int rate1)
{
@@ -2194,68 +2248,42 @@ static unsigned int interpolate_rate(int snr, int snr0, int snr1,
}
-#define INTERPOLATE_RATE(snr0, snr1, rate0, rate1) \
- if (snr < (snr1)) \
- return interpolate_rate(snr, (snr0), (snr1), (rate0), (rate1))
+static unsigned int max_rate(const struct minsnr_bitrate_entry table[],
+ int snr, bool vht)
+{
+ const struct minsnr_bitrate_entry *prev, *entry = table;
+
+ while ((entry->minsnr != -1) &&
+ (snr >= entry->minsnr) &&
+ (vht || entry - table <= vht_mcs))
+ entry++;
+ if (entry == table)
+ return entry->bitrate;
+ prev = entry - 1;
+ if (entry->minsnr == -1 || (!vht && entry - table > vht_mcs))
+ return prev->bitrate;
+ return interpolate_rate(snr, prev->minsnr, entry->minsnr, prev->bitrate,
+ entry->bitrate);
+}
+
-static unsigned int max_ht20_rate(int snr, int vht)
+static unsigned int max_ht20_rate(int snr, bool vht)
{
- if (snr < 0)
- return 0;
- INTERPOLATE_RATE(0, 2, 0, 6500); /* HT20 MCS0 */
- INTERPOLATE_RATE(2, 5, 6500, 13000); /* HT20 MCS1 */
- INTERPOLATE_RATE(5, 9, 13000, 19500); /* HT20 MCS2 */
- INTERPOLATE_RATE(9, 11, 19500, 26000); /* HT20 MCS3 */
- INTERPOLATE_RATE(11, 15, 26000, 39000); /* HT20 MCS4 */
- INTERPOLATE_RATE(15, 18, 39000, 52000); /* HT20 MCS5 */
- INTERPOLATE_RATE(18, 20, 52000, 58500); /* HT20 MCS6 */
- INTERPOLATE_RATE(20, 25, 58500, 65000); /* HT20 MCS7 */
- if (!vht)
- return 65000;
- INTERPOLATE_RATE(25, 29, 65000, 78000); /* VHT20 MCS8 */
- return 78000;
+ return max_rate(vht20_table, snr, vht);
}
-static unsigned int max_ht40_rate(int snr, int vht)
+static unsigned int max_ht40_rate(int snr, bool vht)
{
- if (snr < 0)
- return 0;
- INTERPOLATE_RATE(0, 5, 0, 13500); /* HT40 MCS0 */
- INTERPOLATE_RATE(5, 8, 13500, 27000); /* HT40 MCS1 */
- INTERPOLATE_RATE(8, 12, 27000, 40500); /* HT40 MCS2 */
- INTERPOLATE_RATE(12, 14, 40500, 54000); /* HT40 MCS3 */
- INTERPOLATE_RATE(14, 18, 54000, 81000); /* HT40 MCS4 */
- INTERPOLATE_RATE(18, 21, 81000, 108000); /* HT40 MCS5 */
- INTERPOLATE_RATE(21, 23, 108000, 121500); /* HT40 MCS6 */
- INTERPOLATE_RATE(23, 28, 121500, 135000); /* HT40 MCS7 */
- if (!vht)
- return 135000;
- INTERPOLATE_RATE(28, 32, 135000, 162000); /* VHT40 MCS8 */
- INTERPOLATE_RATE(32, 34, 162000, 180000); /* VHT40 MCS9 */
- return 180000;
+ return max_rate(vht40_table, snr, vht);
}
static unsigned int max_vht80_rate(int snr)
{
- if (snr < 0)
- return 0;
- INTERPOLATE_RATE(0, 8, 0, 29300); /* VHT80 MCS0 */
- INTERPOLATE_RATE(8, 11, 29300, 58500); /* VHT80 MCS1 */
- INTERPOLATE_RATE(11, 15, 58500, 87800); /* VHT80 MCS2 */
- INTERPOLATE_RATE(15, 17, 87800, 117000); /* VHT80 MCS3 */
- INTERPOLATE_RATE(17, 21, 117000, 175500); /* VHT80 MCS4 */
- INTERPOLATE_RATE(21, 24, 175500, 234000); /* VHT80 MCS5 */
- INTERPOLATE_RATE(24, 26, 234000, 263300); /* VHT80 MCS6 */
- INTERPOLATE_RATE(26, 31, 263300, 292500); /* VHT80 MCS7 */
- INTERPOLATE_RATE(31, 35, 292500, 351000); /* VHT80 MCS8 */
- INTERPOLATE_RATE(35, 37, 351000, 390000); /* VHT80 MCS9 */
- return 390000;
+ return max_rate(vht80_table, snr, 1);
}
-#undef INTERPOLATE_RATE
-
unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
const u8 *ies, size_t ies_len, int rate,
@@ -2309,7 +2337,7 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
if (capab == CAPAB_HT || capab == CAPAB_HT40 || capab == CAPAB_VHT) {
ie = get_ie(ies, ies_len, WLAN_EID_HT_CAP);
if (ie) {
- tmp = max_ht20_rate(snr, 0);
+ tmp = max_ht20_rate(snr, false);
if (tmp > est)
est = tmp;
}
@@ -2319,7 +2347,7 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION);
if (ie && ie[1] >= 2 &&
(ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
- tmp = max_ht40_rate(snr, 0);
+ tmp = max_ht40_rate(snr, false);
if (tmp > est)
est = tmp;
}
@@ -2329,7 +2357,7 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
/* Use +1 to assume VHT is always faster than HT */
ie = get_ie(ies, ies_len, WLAN_EID_VHT_CAP);
if (ie) {
- tmp = max_ht20_rate(snr, 1) + 1;
+ tmp = max_ht20_rate(snr, true) + 1;
if (tmp > est)
est = tmp;
@@ -2337,7 +2365,7 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
if (ie && ie[1] >= 2 &&
(ie[3] &
HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
- tmp = max_ht40_rate(snr, 1) + 1;
+ tmp = max_ht40_rate(snr, true) + 1;
if (tmp > est)
est = tmp;
}
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 3ad0065..592c742 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -128,8 +128,8 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
os_memcmp(bssid, wpa_s->sme.sae.tmp->bssid, ETH_ALEN) == 0) {
wpa_printf(MSG_DEBUG,
"SAE: Reuse previously generated PWE on a retry with the same AP");
- use_pt = wpa_s->sme.sae.tmp->h2e;
- use_pk = wpa_s->sme.sae.tmp->pk;
+ use_pt = wpa_s->sme.sae.h2e;
+ use_pk = wpa_s->sme.sae.pk;
goto reuse_data;
}
if (sme_set_sae_group(wpa_s) < 0) {
@@ -150,10 +150,20 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
use_pt = 1;
#ifdef CONFIG_SAE_PK
if ((rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)) &&
- ssid->sae_password && sae_pk_valid_password(ssid->sae_password)) {
+ ssid->sae_pk != SAE_PK_MODE_DISABLED &&
+ ((ssid->sae_password &&
+ sae_pk_valid_password(ssid->sae_password)) ||
+ (!ssid->sae_password && ssid->passphrase &&
+ sae_pk_valid_password(ssid->passphrase)))) {
use_pt = 1;
use_pk = true;
}
+
+ if (ssid->sae_pk == SAE_PK_MODE_ONLY && !use_pk) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Cannot use PK with the selected AP");
+ return NULL;
+ }
#endif /* CONFIG_SAE_PK */
if (use_pt || wpa_s->conf->sae_pwe == 1 || wpa_s->conf->sae_pwe == 2) {
@@ -184,7 +194,7 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
if (wpa_s->sme.sae.tmp) {
os_memcpy(wpa_s->sme.sae.tmp->bssid, bssid, ETH_ALEN);
if (use_pt && use_pk)
- wpa_s->sme.sae.tmp->pk = 1;
+ wpa_s->sme.sae.pk = 1;
#ifdef CONFIG_SAE_PK
os_memcpy(wpa_s->sme.sae.tmp->own_addr, wpa_s->own_addr,
ETH_ALEN);
@@ -1260,8 +1270,7 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
wpabuf_free(wpa_s->sme.sae_token);
token_pos = data + sizeof(le16);
token_len = len - sizeof(le16);
- if (wpa_s->sme.sae.tmp)
- h2e = wpa_s->sme.sae.tmp->h2e;
+ h2e = wpa_s->sme.sae.h2e;
if (h2e) {
if (token_len < 3) {
wpa_dbg(wpa_s, MSG_DEBUG,
@@ -1342,20 +1351,18 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
"SAE: Ignore commit message while waiting for confirm");
return 0;
}
- if (wpa_s->sme.sae.tmp && wpa_s->sme.sae.tmp->h2e &&
- status_code == WLAN_STATUS_SUCCESS) {
+ if (wpa_s->sme.sae.h2e && status_code == WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_DEBUG,
"SAE: Unexpected use of status code 0 in SAE commit when H2E was expected");
return -1;
}
- if (wpa_s->sme.sae.tmp &&
- (!wpa_s->sme.sae.tmp->h2e || wpa_s->sme.sae.tmp->pk) &&
+ if ((!wpa_s->sme.sae.h2e || wpa_s->sme.sae.pk) &&
status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) {
wpa_printf(MSG_DEBUG,
"SAE: Unexpected use of status code for H2E in SAE commit when H2E was not expected");
return -1;
}
- if (wpa_s->sme.sae.tmp && !wpa_s->sme.sae.tmp->pk &&
+ if (!wpa_s->sme.sae.pk &&
status_code == WLAN_STATUS_SAE_PK) {
wpa_printf(MSG_DEBUG,
"SAE: Unexpected use of status code for PK in SAE commit when PK was not expected");
@@ -1873,6 +1880,43 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
pfs_fail:
#endif /* CONFIG_DPP2 */
+ wpa_s->mscs_setup_done = false;
+ if (wpa_s->current_bss && wpa_s->robust_av.valid_config) {
+ struct wpabuf *mscs_ie;
+ size_t mscs_ie_len, buf_len, *wpa_ie_len, max_ie_len;
+
+ if (!wpa_bss_ext_capab(wpa_s->current_bss, WLAN_EXT_CAPAB_MSCS))
+ goto mscs_fail;
+
+ buf_len = 3 + /* MSCS descriptor IE header */
+ 1 + /* Request type */
+ 2 + /* User priority control */
+ 4 + /* Stream timeout */
+ 3 + /* TCLAS Mask IE header */
+ wpa_s->robust_av.frame_classifier_len;
+ mscs_ie = wpabuf_alloc(buf_len);
+ if (!mscs_ie) {
+ wpa_printf(MSG_INFO,
+ "MSCS: Failed to allocate MSCS IE");
+ goto mscs_fail;
+ }
+
+ wpa_ie_len = &wpa_s->sme.assoc_req_ie_len;
+ max_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
+ wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, mscs_ie);
+ if ((*wpa_ie_len + wpabuf_len(mscs_ie)) <= max_ie_len) {
+ wpa_hexdump_buf(MSG_MSGDUMP, "MSCS IE",
+ wpabuf_head(mscs_ie));
+ mscs_ie_len = wpabuf_len(mscs_ie);
+ os_memcpy(wpa_s->sme.assoc_req_ie + *wpa_ie_len,
+ wpabuf_head(mscs_ie), mscs_ie_len);
+ *wpa_ie_len += mscs_ie_len;
+ }
+
+ wpabuf_free(mscs_ie);
+ }
+mscs_fail:
+
if (ssid && ssid->multi_ap_backhaul_sta) {
size_t multi_ap_ie_len;
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 411ce88..d0c9f0f 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -121,6 +121,15 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
os_free(wnmtfs_ie);
return -1;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->oci_freq_override_wnm_sleep) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %d MHz",
+ ci.frequency,
+ wpa_s->oci_freq_override_wnm_sleep);
+ ci.frequency = wpa_s->oci_freq_override_wnm_sleep;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
oci_ie_len = OCV_OCI_EXTENDED_LEN;
oci_ie = os_zalloc(oci_ie_len);
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 6a2d2c3..f5b02f6 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -3059,6 +3059,78 @@ static int wpa_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc,
#endif /* CONFIG_DPP */
+static int wpa_ctrl_command_bss(struct wpa_ctrl *ctrl, const char *cmd)
+{
+ char buf[512], *pos, *bssid, *freq, *level, *flags, *ssid;
+ size_t len;
+ int ret, id = -1;
+
+ if (!ctrl_conn)
+ return -1;
+ len = sizeof(buf) - 1;
+ ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
+ wpa_cli_msg_cb);
+ if (ret == -2) {
+ printf("'%s' command timed out.\n", cmd);
+ return -2;
+ } else if (ret < 0) {
+ printf("'%s' command failed.\n", cmd);
+ return -1;
+ }
+
+ buf[len] = '\0';
+ if (os_memcmp(buf, "FAIL", 4) == 0)
+ return -1;
+
+ pos = buf;
+ while (*pos != '\0') {
+ if (str_starts(pos, "id="))
+ id = atoi(pos + 3);
+ if (str_starts(pos, "bssid="))
+ bssid = pos + 6;
+ if (str_starts(pos, "freq="))
+ freq = pos + 5;
+ if (str_starts(pos, "level="))
+ level = pos + 6;
+ if (str_starts(pos, "flags="))
+ flags = pos + 6;
+ if (str_starts(pos, "ssid="))
+ ssid = pos + 5;
+
+ while (*pos != '\0' && *pos != '\n')
+ pos++;
+ *pos++ = '\0';
+ }
+ if (id != -1)
+ printf("%s\t%s\t%s\t%s\t%s\n", bssid, freq, level, flags, ssid);
+ return id;
+}
+
+
+static int wpa_cli_cmd_all_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ char cmd[64];
+ int id = -1;
+ unsigned int mask;
+
+ printf("bssid / frequency / signal level / flags / ssid\n");
+
+ mask = WPA_BSS_MASK_ID | WPA_BSS_MASK_BSSID | WPA_BSS_MASK_FREQ |
+ WPA_BSS_MASK_LEVEL | WPA_BSS_MASK_FLAGS | WPA_BSS_MASK_SSID;
+ do {
+ if (id < 0)
+ os_snprintf(cmd, sizeof(cmd), "BSS FIRST MASK=0x%x",
+ mask);
+ else
+ os_snprintf(cmd, sizeof(cmd), "BSS NEXT-%d MASK=0x%x",
+ id, mask);
+ id = wpa_ctrl_command_bss(ctrl, cmd);
+ } while (id >= 0);
+
+ return 0;
+}
+
+
enum wpa_cli_cmd_flags {
cli_cmd_flag_none = 0x00,
cli_cmd_flag_sensitive = 0x01
@@ -3718,6 +3790,8 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
cli_cmd_flag_none,
"*|<id> = remove DPP pkex information" },
#endif /* CONFIG_DPP */
+ { "all_bss", wpa_cli_cmd_all_bss, NULL, cli_cmd_flag_none,
+ "= list all BSS entries (scan results)" },
{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
};
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index f5a4c36..3d2c0a9 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1639,11 +1639,26 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
if (ssid->sae_password_id && sae_pwe != 3)
sae_pwe = 1;
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, sae_pwe);
+#ifdef CONFIG_SAE_PK
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PK,
+ wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ ssid->sae_pk != SAE_PK_MODE_DISABLED &&
+ ((ssid->sae_password &&
+ sae_pk_valid_password(ssid->sae_password)) ||
+ (!ssid->sae_password && ssid->passphrase &&
+ sae_pk_valid_password(ssid->passphrase))));
+#endif /* CONFIG_SAE_PK */
#ifdef CONFIG_TESTING_OPTIONS
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_FT_RSNXE_USED,
wpa_s->ft_rsnxe_used);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_EAPOL,
wpa_s->oci_freq_override_eapol);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_EAPOL_G2,
+ wpa_s->oci_freq_override_eapol_g2);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FT_ASSOC,
+ wpa_s->oci_freq_override_ft_assoc);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FILS_ASSOC,
+ wpa_s->oci_freq_override_fils_assoc);
#endif /* CONFIG_TESTING_OPTIONS */
/* Extended Key ID is only supported in infrastructure BSS so far */
@@ -1884,6 +1899,9 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
*pos |= 0x01;
#endif /* CONFIG_FILS */
break;
+ case 10: /* Bits 80-87 */
+ *pos |= 0x20; /* Bit 85 - Mirrored SCS */
+ break;
}
}
@@ -1891,7 +1909,7 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen)
{
u8 *pos = buf;
- u8 len = 10, i;
+ u8 len = 11, i;
if (len < wpa_s->extended_capa_len)
len = wpa_s->extended_capa_len;
@@ -2745,9 +2763,9 @@ static u8 * wpas_populate_assoc_ies(
#ifdef CONFIG_MBO
const u8 *mbo_ie;
#endif
-#ifdef CONFIG_SAE
- int sae_pmksa_cached = 0;
-#endif /* CONFIG_SAE */
+#if defined(CONFIG_SAE) || defined(CONFIG_FILS)
+ int pmksa_cached = 0;
+#endif /* CONFIG_SAE || CONFIG_FILS */
#ifdef CONFIG_FILS
const u8 *realm, *username, *rrk;
size_t realm_len, username_len, rrk_len;
@@ -2787,9 +2805,9 @@ static u8 * wpas_populate_assoc_ies(
ssid, try_opportunistic,
cache_id, 0) == 0) {
eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
-#ifdef CONFIG_SAE
- sae_pmksa_cached = 1;
-#endif /* CONFIG_SAE */
+#if defined(CONFIG_SAE) || defined(CONFIG_FILS)
+ pmksa_cached = 1;
+#endif /* CONFIG_SAE || CONFIG_FILS */
}
wpa_ie_len = max_wpa_ie_len;
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
@@ -2888,6 +2906,10 @@ static u8 * wpas_populate_assoc_ies(
if (mask)
*mask |= WPA_DRV_UPDATE_FILS_ERP_INFO;
+ } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD) &&
+ ssid->eap.erp && wpa_key_mgmt_fils(wpa_s->key_mgmt) &&
+ pmksa_cached) {
+ algs = WPA_AUTH_ALG_FILS;
}
#endif /* CONFIG_FILS */
#endif /* IEEE8021X_EAPOL */
@@ -2904,7 +2926,7 @@ static u8 * wpas_populate_assoc_ies(
}
#ifdef CONFIG_SAE
- if (sae_pmksa_cached && algs == WPA_AUTH_ALG_SAE) {
+ if (pmksa_cached && algs == WPA_AUTH_ALG_SAE) {
wpa_dbg(wpa_s, MSG_DEBUG,
"SAE: Use WPA_AUTH_ALG_OPEN for PMKSA caching attempt");
algs = WPA_AUTH_ALG_OPEN;
@@ -3170,6 +3192,40 @@ pfs_fail:
wpa_ie_len += wpa_s->rsnxe_len;
}
+ if (bss && wpa_s->robust_av.valid_config) {
+ struct wpabuf *mscs_ie;
+ size_t mscs_ie_len, buf_len;
+
+ if (!wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_MSCS))
+ goto mscs_fail;
+
+ buf_len = 3 + /* MSCS descriptor IE header */
+ 1 + /* Request type */
+ 2 + /* User priority control */
+ 4 + /* Stream timeout */
+ 3 + /* TCLAS Mask IE header */
+ wpa_s->robust_av.frame_classifier_len;
+ mscs_ie = wpabuf_alloc(buf_len);
+ if (!mscs_ie) {
+ wpa_printf(MSG_INFO,
+ "MSCS: Failed to allocate MSCS IE");
+ goto mscs_fail;
+ }
+
+ wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, mscs_ie);
+ if ((wpa_ie_len + wpabuf_len(mscs_ie)) <= max_wpa_ie_len) {
+ wpa_hexdump_buf(MSG_MSGDUMP, "MSCS IE",
+ wpabuf_head(mscs_ie));
+ mscs_ie_len = wpabuf_len(mscs_ie);
+ os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(mscs_ie),
+ mscs_ie_len);
+ wpa_ie_len += mscs_ie_len;
+ }
+
+ wpabuf_free(mscs_ie);
+ }
+mscs_fail:
+
if (ssid->multi_ap_backhaul_sta) {
size_t multi_ap_ie_len;
@@ -3484,6 +3540,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
wpa_s->rsnxe_len = 0;
+ wpa_s->mscs_setup_done = false;
wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, &params, NULL);
if (!wpa_ie) {
@@ -7918,7 +7975,7 @@ static int wpa_set_driver_tmp_disallow_list(struct wpa_supplicant *wpa_s)
ETH_ALEN);
num_bssid++;
}
- ret = wpa_drv_set_bssid_blacklist(wpa_s, num_bssid, bssids);
+ ret = wpa_drv_set_bssid_tmp_disallow(wpa_s, num_bssid, bssids);
os_free(bssids);
return ret;
}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 3b90567..1250834 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -1472,6 +1472,58 @@ fast_reauth=1
# 2: do not allow PFS to be used
#dpp_pfs=0
+# Whether Beacon protection is enabled
+# This depends on management frame protection (ieee80211w) being enabled.
+#beacon_prot=0
+
+# OWE DH Group
+# 0: use default (19) first and then try all supported groups one by one if AP
+# rejects the selected group
+# 1-65535: DH Group to use for OWE
+# Groups 19 (NIST P-256), 20 (NIST P-384), and 21 (NIST P-521) are
+# currently supported.
+#owe_group=0
+
+# OWE-only mode (disable transition mode)
+# 0: enable transition mode (allow connection to either OWE or open BSS)
+# 1 = disable transition mode (allow connection only with OWE)
+#owe_only=0
+
+# OWE PTK derivation workaround
+# Initial OWE implementation used SHA256 when deriving the PTK for all
+# OWE groups. This was supposed to change to SHA384 for group 20 and
+# SHA512 for group 21. This parameter can be used to enable older
+# behavior mainly for testing purposes. There is no impact to group 19
+# behavior, but if enabled, this will make group 20 and 21 cases use
+# SHA256-based PTK derivation which will not work with the updated
+# OWE implementation on the AP side.
+#owe_ptk_workaround=0
+
+# 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)
+
+# SAE-PK mode
+# 0: automatic SAE/SAE-PK selection based on password; enable
+# transition mode (allow SAE authentication without SAE-PK)
+# 1: SAE-PK only (disable transition mode; allow SAE authentication
+# only with SAE-PK)
+# 2: disable SAE-PK (allow SAE authentication only without SAE-PK)
+#sae_pk=0
+
# MAC address policy
# 0 = use permanent MAC address
# 1 = use random MAC address for each ESS connection
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 28867f0..31a9b74 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -491,6 +491,17 @@ struct driver_signal_override {
int scan_level;
};
+struct robust_av_data {
+ u8 dialog_token;
+ enum scs_request_type request_type;
+ u8 up_bitmap;
+ u8 up_limit;
+ u32 stream_timeout;
+ u8 frame_classifier[48];
+ size_t frame_classifier_len;
+ bool valid_config;
+};
+
/**
* struct wpa_supplicant - Internal data for wpa_supplicant interface
*
@@ -1152,6 +1163,10 @@ struct wpa_supplicant {
unsigned int oci_freq_override_eapol;
unsigned int oci_freq_override_saquery_req;
unsigned int oci_freq_override_saquery_resp;
+ unsigned int oci_freq_override_eapol_g2;
+ unsigned int oci_freq_override_ft_assoc;
+ unsigned int oci_freq_override_fils_assoc;
+ unsigned int oci_freq_override_wnm_sleep;
#endif /* CONFIG_TESTING_OPTIONS */
struct wmm_ac_assoc_data *wmm_ac_assoc_info;
@@ -1277,10 +1292,10 @@ struct wpa_supplicant {
unsigned int dpp_resp_retry_time;
u8 dpp_last_ssid[SSID_MAX_LEN];
size_t dpp_last_ssid_len;
+ bool dpp_conf_backup_received;
#ifdef CONFIG_DPP2
struct dpp_pfs *dpp_pfs;
int dpp_pfs_fallback;
- struct wpabuf *dpp_reconfig_announcement;
struct wpabuf *dpp_presence_announcement;
struct dpp_bootstrap_info *dpp_chirp_bi;
int dpp_chirp_freq;
@@ -1291,6 +1306,7 @@ struct wpa_supplicant {
int dpp_chirp_listen;
struct wpa_ssid *dpp_reconfig_ssid;
int dpp_reconfig_ssid_id;
+ struct dpp_reconfig_id *dpp_reconfig_id;
#endif /* CONFIG_DPP2 */
#ifdef CONFIG_TESTING_OPTIONS
char *dpp_config_obj_override;
@@ -1310,6 +1326,8 @@ struct wpa_supplicant {
unsigned int multi_ap_ie:1;
unsigned int multi_ap_backhaul:1;
unsigned int multi_ap_fronthaul:1;
+ struct robust_av_data robust_av;
+ bool mscs_setup_done;
};
@@ -1523,6 +1541,9 @@ struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
int wpas_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s,
struct channel_list_changed *info);
+int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *current_bss,
+ struct wpa_bss *seleceted);
/* eap_register.c */
int eap_register_methods(void);
@@ -1615,4 +1636,13 @@ int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s);
void wpas_clear_driver_signal_override(struct wpa_supplicant *wpa_s);
+int wpas_send_mscs_req(struct wpa_supplicant *wpa_s);
+void wpas_populate_mscs_descriptor_ie(struct robust_av_data *robust_av,
+ struct wpabuf *buf);
+void wpas_handle_robust_av_recv_action(struct wpa_supplicant *wpa_s,
+ const u8 *src, const u8 *buf,
+ size_t len);
+void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const u8 *ies, size_t ies_len);
+
#endif /* WPA_SUPPLICANT_I_H */
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 6bd271e..a9a66ba 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -575,7 +575,8 @@ static int wpa_supplicant_add_pmkid(void *_wpa_s, void *network_ctx,
const u8 *bssid, const u8 *pmkid,
const u8 *fils_cache_id,
const u8 *pmk, size_t pmk_len,
- u32 pmk_lifetime, u8 pmk_reauth_threshold)
+ u32 pmk_lifetime, u8 pmk_reauth_threshold,
+ int akmp)
{
struct wpa_supplicant *wpa_s = _wpa_s;
struct wpa_ssid *ssid;
@@ -583,9 +584,22 @@ static int wpa_supplicant_add_pmkid(void *_wpa_s, void *network_ctx,
os_memset(&params, 0, sizeof(params));
ssid = wpas_get_network_ctx(wpa_s, network_ctx);
- if (ssid)
+ if (ssid) {
wpa_msg(wpa_s, MSG_INFO, PMKSA_CACHE_ADDED MACSTR " %d",
MAC2STR(bssid), ssid->id);
+ if ((akmp == WPA_KEY_MGMT_FT_IEEE8021X ||
+ akmp == WPA_KEY_MGMT_FT_IEEE8021X_SHA384) &&
+ !ssid->ft_eap_pmksa_caching) {
+ /* Since we will not be using PMKSA caching for FT-EAP
+ * within wpa_supplicant to avoid known interop issues
+ * with APs, do not add this PMKID to the driver either
+ * so that we won't be hitting those interop issues
+ * with driver-based RSNE generation. */
+ wpa_printf(MSG_DEBUG,
+ "FT: Do not add PMKID entry to the driver since FT-EAP PMKSA caching is not enabled in configuration");
+ return 0;
+ }
+ }
if (ssid && fils_cache_id) {
params.ssid = ssid->ssid;
params.ssid_len = ssid->ssid_len;
@@ -1268,6 +1282,7 @@ static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap)
if (!ssid)
return;
+#ifdef CONFIG_SAE
if ((bitmap & TRANSITION_DISABLE_WPA3_PERSONAL) &&
wpa_key_mgmt_sae(wpa_s->key_mgmt) &&
(ssid->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE)) &&
@@ -1279,6 +1294,24 @@ static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap)
changed = 1;
}
+ if ((bitmap & TRANSITION_DISABLE_SAE_PK) &&
+ wpa_key_mgmt_sae(wpa_s->key_mgmt) &&
+#ifdef CONFIG_SME
+ wpa_s->sme.sae.state == SAE_ACCEPTED &&
+ wpa_s->sme.sae.pk &&
+#endif /* CONFIG_SME */
+ (ssid->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE)) &&
+ (ssid->sae_pk != SAE_PK_MODE_ONLY ||
+ ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED ||
+ (ssid->group_cipher & WPA_CIPHER_TKIP))) {
+ wpa_printf(MSG_DEBUG,
+ "SAE-PK: SAE authentication without PK disabled based on AP notification");
+ disable_wpa_wpa2(ssid);
+ ssid->sae_pk = SAE_PK_MODE_ONLY;
+ changed = 1;
+ }
+#endif /* CONFIG_SAE */
+
if ((bitmap & TRANSITION_DISABLE_WPA3_ENTERPRISE) &&
wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
(ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X |