Merge "wifi: Create 1.3::IfaceParams to support dual bands (AP+AP Part 1)"
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 58b0d16..3590b09 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -261,6 +261,10 @@
ifdef CONFIG_SAE
L_CFLAGS += -DCONFIG_SAE
OBJS += src/common/sae.c
+ifdef CONFIG_SAE_PK
+L_CFLAGS += -DCONFIG_SAE_PK
+OBJS += src/common/sae_pk.c
+endif
NEED_ECC=y
NEED_DH_GROUPS=y
NEED_HMAC_SHA256_KDF=y
@@ -425,7 +429,7 @@
ifdef CONFIG_EAP_SIM_COMMON
OBJS += src/eap_common/eap_sim_common.c
# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be
-# replaced with another file implementating the interface specified in
+# replaced with another file implementing the interface specified in
# eap_sim_db.h.
OBJS += src/eap_server/eap_sim_db.c
NEED_FIPS186_2_PRF=y
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index 6c4410e..34a8a08 100644
--- a/hostapd/ChangeLog
+++ b/hostapd/ChangeLog
@@ -362,7 +362,7 @@
* RADIUS server functionality
- add minimal RADIUS accounting server support (hostapd-as-server);
this is mainly to enable testing coverage with hwsim scripts
- - allow authentication log to be written into SQLite databse
+ - allow authentication log to be written into SQLite database
- added option for TLS protocol testing of an EAP peer by simulating
various misbehaviors/known attacks
- MAC ACL support for testing purposes
@@ -668,7 +668,7 @@
* fixed HT Capabilities IE with nl80211 drivers
* moved generic AP functionality code into src/ap
* WPS: handle Selected Registrar as union of info from all Registrars
- * remove obsolte Prism54.org driver wrapper
+ * remove obsolete Prism54.org driver wrapper
* added internal debugging mechanism with backtrace support and memory
allocation/freeing validation, etc. tests (CONFIG_WPA_TRACE=y)
* EAP-FAST server: piggyback Phase 2 start with the end of Phase 1
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 95ef085..066bfae 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -1,10 +1,7 @@
-ifndef CC
-CC=gcc
-endif
+ALL=hostapd hostapd_cli
+CONFIG_FILE = .config
-ifndef CFLAGS
-CFLAGS = -MMD -O2 -Wall -g
-endif
+include ../src/build.rules
ifdef LIBS
# If LIBS is set with some global build system defaults, clone those for
@@ -19,6 +16,9 @@
ifndef LIBS_n
LIBS_n := $(LIBS)
endif
+ifndef LIBS_s
+LIBS_s := $(LIBS)
+endif
endif
CFLAGS += $(EXTRA_CFLAGS)
@@ -27,8 +27,6 @@
export BINDIR ?= /usr/local/bin/
--include .config
-
ifndef CONFIG_NO_GITVER
# Add VERSION_STR postfix for builds from a git repository
ifeq ($(wildcard ../.git),../.git)
@@ -122,6 +120,7 @@
LIBS_c += -lbfd -ldl -liberty -lz
LIBS_h += -lbfd -ldl -liberty -lz
LIBS_n += -lbfd -ldl -liberty -lz
+LIBS_s += -lbfd -ldl -liberty -lz
endif
endif
@@ -294,6 +293,10 @@
ifdef CONFIG_SAE
CFLAGS += -DCONFIG_SAE
OBJS += ../src/common/sae.o
+ifdef CONFIG_SAE_PK
+CFLAGS += -DCONFIG_SAE_PK
+OBJS += ../src/common/sae_pk.o
+endif
NEED_ECC=y
NEED_DH_GROUPS=y
NEED_HMAC_SHA256_KDF=y
@@ -445,7 +448,7 @@
ifdef CONFIG_EAP_SIM_COMMON
OBJS += ../src/eap_common/eap_sim_common.o
# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be
-# replaced with another file implementating the interface specified in
+# replaced with another file implementing the interface specified in
# eap_sim_db.h.
OBJS += ../src/eap_server/eap_sim_db.o
NEED_FIPS186_2_PRF=y
@@ -704,6 +707,7 @@
endif
OBJS += ../src/crypto/crypto_openssl.o
HOBJS += ../src/crypto/crypto_openssl.o
+SOBJS += ../src/crypto/crypto_openssl.o
ifdef NEED_FIPS186_2_PRF
OBJS += ../src/crypto/fips_prf_openssl.o
endif
@@ -711,9 +715,11 @@
LIBS += -lcrypto
LIBS_h += -lcrypto
LIBS_n += -lcrypto
+LIBS_s += -lcrypto
ifdef CONFIG_TLS_ADD_DL
LIBS += -ldl
LIBS_h += -ldl
+LIBS_s += -ldl
endif
ifndef CONFIG_TLS_DEFAULT_CIPHERS
CONFIG_TLS_DEFAULT_CIPHERS = "DEFAULT:!EXP:!LOW"
@@ -1257,60 +1263,25 @@
CFLAGS += -DCONFIG_NO_TKIP
endif
-ALL=hostapd hostapd_cli
-
-all: verify_config $(ALL)
-
-Q=@
-E=echo
-ifeq ($(V), 1)
-Q=
-E=true
-endif
-ifeq ($(QUIET), 1)
-Q=@
-E=true
-endif
-
-ifdef CONFIG_CODE_COVERAGE
-%.o: %.c
- @$(E) " CC " $<
- $(Q)cd $(dir $@); $(CC) -c -o $(notdir $@) $(CFLAGS) $(notdir $<)
-else
-%.o: %.c
- $(Q)$(CC) -c -o $@ $(CFLAGS) $<
- @$(E) " CC " $<
-endif
-
-verify_config:
- @if [ ! -r .config ]; then \
- echo 'Building hostapd requires a configuration file'; \
- echo '(.config). See README for more instructions. You can'; \
- echo 'run "cp defconfig .config" to create an example'; \
- echo 'configuration.'; \
- exit 1; \
- fi
-
$(DESTDIR)$(BINDIR)/%: %
install -D $(<) $(@)
install: $(addprefix $(DESTDIR)$(BINDIR)/,$(ALL))
-../src/drivers/build.hostapd:
- @if [ -f ../src/drivers/build.wpa_supplicant ]; then \
- $(MAKE) -C ../src/drivers clean; \
- fi
- @touch ../src/drivers/build.hostapd
+_OBJS_VAR := OBJS
+include ../src/objs.mk
-BCHECK=../src/drivers/build.hostapd
-
-hostapd: $(BCHECK) $(OBJS)
+hostapd: $(OBJS)
$(Q)$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS)
@$(E) " LD " $@
ifdef CONFIG_WPA_TRACE
OBJS_c += ../src/utils/trace.o
endif
+
+_OBJS_VAR := OBJS_c
+include ../src/objs.mk
+
hostapd_cli: $(OBJS_c)
$(Q)$(CC) $(LDFLAGS) -o hostapd_cli $(OBJS_c) $(LIBS_c)
@$(E) " LD " $@
@@ -1345,6 +1316,35 @@
HOBJS += ../src/crypto/crypto_linux.o
endif
+SOBJS += sae_pk_gen.o
+SOBJS += ../src/utils/common.o
+SOBJS += ../src/utils/os_$(CONFIG_OS).o
+SOBJS += ../src/utils/base64.o
+SOBJS += ../src/utils/wpa_debug.o
+SOBJS += ../src/utils/wpabuf.o
+ifdef CONFIG_WPA_TRACE
+SOBJS += ../src/utils/trace.o
+endif
+SOBJS += ../src/common/ieee802_11_common.o
+SOBJS += ../src/common/sae.o
+SOBJS += ../src/common/sae_pk.o
+SOBJS += ../src/common/dragonfly.o
+SOBJS += $(AESOBJS)
+SOBJS += ../src/crypto/sha256-prf.o
+SOBJS += ../src/crypto/sha384-prf.o
+SOBJS += ../src/crypto/sha512-prf.o
+SOBJS += ../src/crypto/dh_groups.o
+SOBJS += ../src/crypto/sha256-kdf.o
+SOBJS += ../src/crypto/sha384-kdf.o
+SOBJS += ../src/crypto/sha512-kdf.o
+
+_OBJS_VAR := NOBJS
+include ../src/objs.mk
+_OBJS_VAR := HOBJS
+include ../src/objs.mk
+_OBJS_VAR := SOBJS
+include ../src/objs.mk
+
nt_password_hash: $(NOBJS)
$(Q)$(CC) $(LDFLAGS) -o nt_password_hash $(NOBJS) $(LIBS_n)
@$(E) " LD " $@
@@ -1353,15 +1353,17 @@
$(Q)$(CC) $(LDFLAGS) -o hlr_auc_gw $(HOBJS) $(LIBS_h)
@$(E) " LD " $@
+sae_pk_gen: $(SOBJS)
+ $(Q)$(CC) $(LDFLAGS) -o sae_pk_gen $(SOBJS) $(LIBS_s)
+ @$(E) " LD " $@
+
+.PHONY: lcov-html
lcov-html:
- lcov -c -d .. > lcov.info
+ lcov -c -d $(BUILDDIR) > lcov.info
genhtml lcov.info --output-directory lcov-html
-clean:
- $(MAKE) -C ../src clean
- rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw
- rm -f *.d *.gcno *.gcda *.gcov
+clean: common-clean
+ rm -f core *~ nt_password_hash hlr_auc_gw
+ rm -f sae_pk_gen
rm -f lcov.info
rm -rf lcov-html
-
--include $(OBJS:%.o=%.d)
diff --git a/hostapd/android.config b/hostapd/android.config
index be56ad5..f791daa 100644
--- a/hostapd/android.config
+++ b/hostapd/android.config
@@ -196,7 +196,7 @@
#CONFIG_FST=y
# Multiband Operation support
-# These extentions facilitate efficient use of multiple frequency bands
+# These extensions facilitate efficient use of multiple frequency bands
# available to the AP and the devices that may associate with it.
#CONFIG_MBO=y
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index cc1855d..ce32f3c 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -14,6 +14,7 @@
#include "utils/common.h"
#include "utils/uuid.h"
#include "common/ieee802_11_defs.h"
+#include "common/sae.h"
#include "crypto/sha256.h"
#include "crypto/tls.h"
#include "drivers/driver.h"
@@ -340,7 +341,7 @@
struct hostapd_radius_attr *attr, *a;
attr = hostapd_parse_radius_attr(buf + 19);
if (attr == NULL) {
- wpa_printf(MSG_ERROR, "Invalid radius_auth_req_attr: %s",
+ wpa_printf(MSG_ERROR, "Invalid radius_accept_attr: %s",
buf + 19);
user = NULL; /* already in the BSS list */
goto failed;
@@ -942,104 +943,6 @@
}
-/* 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)
@@ -2290,6 +2193,35 @@
pw->vlan_id = atoi(pos2);
}
+#ifdef CONFIG_SAE_PK
+ pos2 = os_strstr(pos, "|pk=");
+ if (pos2) {
+ const char *epos;
+ char *tmp;
+
+ if (!end)
+ end = pos2;
+ pos2 += 4;
+ epos = os_strchr(pos2, '|');
+ if (epos) {
+ tmp = os_malloc(epos - pos2 + 1);
+ if (!tmp)
+ goto fail;
+ os_memcpy(tmp, pos2, epos - pos2);
+ tmp[epos - pos2] = '\0';
+ } else {
+ tmp = os_strdup(pos2);
+ if (!tmp)
+ goto fail;
+ }
+
+ pw->pk = sae_parse_pk(tmp);
+ str_clear_free(tmp);
+ if (!pw->pk)
+ goto fail;
+ }
+#endif /* CONFIG_SAE_PK */
+
pos2 = os_strstr(pos, "|id=");
if (pos2) {
if (!end)
@@ -2312,6 +2244,18 @@
pw->password[end - val] = '\0';
}
+#ifdef CONFIG_SAE_PK
+ if (pw->pk &&
+#ifdef CONFIG_TESTING_OPTIONS
+ !bss->sae_pk_password_check_skip &&
+#endif /* CONFIG_TESTING_OPTIONS */
+ !sae_pk_valid_password(pw->password)) {
+ wpa_printf(MSG_INFO,
+ "Invalid SAE password for a SAE-PK sae_password entry");
+ goto fail;
+ }
+#endif /* CONFIG_SAE_PK */
+
pw->next = bss->sae_passwords;
bss->sae_passwords = pw;
@@ -2319,6 +2263,9 @@
fail:
str_clear_free(pw->password);
os_free(pw->identifier);
+#ifdef CONFIG_SAE_PK
+ sae_deinit_pk(pw->pk);
+#endif /* CONFIG_SAE_PK */
os_free(pw);
return -1;
}
@@ -2612,7 +2559,7 @@
} 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);
@@ -3383,7 +3330,7 @@
} 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;
@@ -4190,6 +4137,12 @@
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_pk_password_check_skip") == 0) {
+ bss->sae_pk_password_check_skip = 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);
@@ -4217,6 +4170,20 @@
bss->skip_prune_assoc = atoi(pos);
} else if (os_strcmp(buf, "ft_rsnxe_used") == 0) {
bss->ft_rsnxe_used = atoi(pos);
+ } else if (os_strcmp(buf, "oci_freq_override_eapol_m3") == 0) {
+ bss->oci_freq_override_eapol_m3 = atoi(pos);
+ } else if (os_strcmp(buf, "oci_freq_override_eapol_g1") == 0) {
+ bss->oci_freq_override_eapol_g1 = atoi(pos);
+ } else if (os_strcmp(buf, "oci_freq_override_saquery_req") == 0) {
+ bss->oci_freq_override_saquery_req = atoi(pos);
+ } else if (os_strcmp(buf, "oci_freq_override_saquery_resp") == 0) {
+ bss->oci_freq_override_saquery_resp = atoi(pos);
+ } else if (os_strcmp(buf, "oci_freq_override_ft_assoc") == 0) {
+ bss->oci_freq_override_ft_assoc = atoi(pos);
+ } else if (os_strcmp(buf, "oci_freq_override_fils_assoc") == 0) {
+ bss->oci_freq_override_fils_assoc = atoi(pos);
+ } else if (os_strcmp(buf, "oci_freq_override_wnm_sleep") == 0) {
+ bss->oci_freq_override_wnm_sleep = atoi(pos);
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_SAE
} else if (os_strcmp(buf, "sae_password") == 0) {
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index edc69f4..30fa47f 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,12 +1479,31 @@
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
if (os_strcmp(cmd, "ft_rsnxe_used") == 0)
wpa_auth_set_ft_rsnxe_used(hapd->wpa_auth,
hapd->conf->ft_rsnxe_used);
+ else if (os_strcmp(cmd, "oci_freq_override_eapol_m3") == 0)
+ wpa_auth_set_ocv_override_freq(
+ hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_EAPOL_M3,
+ atoi(value));
+ else if (os_strcmp(cmd, "oci_freq_override_eapol_g1") == 0)
+ wpa_auth_set_ocv_override_freq(
+ hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_EAPOL_G1,
+ atoi(value));
+ else if (os_strcmp(cmd, "oci_freq_override_ft_assoc") == 0)
+ wpa_auth_set_ocv_override_freq(
+ hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_FT_ASSOC,
+ atoi(value));
+ else if (os_strcmp(cmd, "oci_freq_override_fils_assoc") == 0)
+ wpa_auth_set_ocv_override_freq(
+ hapd->wpa_auth,
+ WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC, atoi(value));
#endif /* CONFIG_TESTING_OPTIONS */
}
@@ -1902,7 +1922,7 @@
if (ip.ip_hl != 5 || ip.ip_v != 4 ||
ntohs(ip.ip_len) > HWSIM_IP_LEN) {
wpa_printf(MSG_DEBUG,
- "test data: RX - ignore unexpect IP header");
+ "test data: RX - ignore unexpected IP header");
return;
}
@@ -2437,6 +2457,19 @@
}
+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)
{
@@ -2452,13 +2485,13 @@
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);
@@ -3735,6 +3768,14 @@
if (hostapd_dpp_pkex_remove(hapd, buf + 16) < 0)
reply_len = -1;
#ifdef CONFIG_DPP2
+ } else if (os_strncmp(buf, "DPP_CONTROLLER_START ", 21) == 0) {
+ if (hostapd_dpp_controller_start(hapd, buf + 20) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "DPP_CONTROLLER_START") == 0) {
+ if (hostapd_dpp_controller_start(hapd, NULL) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "DPP_CONTROLLER_STOP") == 0) {
+ dpp_controller_stop(hapd->iface->interfaces->dpp);
} else if (os_strncmp(buf, "DPP_CHIRP ", 10) == 0) {
if (hostapd_dpp_chirp(hapd, buf + 9) < 0)
reply_len = -1;
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 2341765..11eed99 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -351,7 +351,7 @@
#CONFIG_ACS=y
# Multiband Operation support
-# These extentions facilitate efficient use of multiple frequency bands
+# These extensions facilitate efficient use of multiple frequency bands
# available to the AP and the devices that may associate with it.
#CONFIG_MBO=y
diff --git a/hostapd/hidl/1.3/hostapd.cpp b/hostapd/hidl/1.3/hostapd.cpp
index 6bbf3d9..6450a9f 100644
--- a/hostapd/hidl/1.3/hostapd.cpp
+++ b/hostapd/hidl/1.3/hostapd.cpp
@@ -406,7 +406,7 @@
if (((band & IHostapd::BandMask::BAND_5_GHZ) != 0)
|| ((band & IHostapd::BandMask::BAND_6_GHZ) != 0)) {
hw_mode_as_string = "hw_mode=any";
- if (iface_params.V1_1.V1_0.channelParams.enableAcs) {
+ if (iface_params.V1_1.V1_0.hwModeParams.enable80211AC) {
ht_cap_vht_oper_chwidth_as_string =
"ht_capab=[HT40+]\n"
"vht_oper_chwidth=1";
@@ -418,7 +418,7 @@
if (((band & IHostapd::BandMask::BAND_5_GHZ) != 0)
|| ((band & IHostapd::BandMask::BAND_6_GHZ) != 0)) {
hw_mode_as_string = "hw_mode=a";
- if (iface_params.V1_1.V1_0.channelParams.enableAcs) {
+ if (iface_params.V1_1.V1_0.hwModeParams.enable80211AC) {
ht_cap_vht_oper_chwidth_as_string =
"ht_capab=[HT40+]\n"
"vht_oper_chwidth=1";
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 9fae06d..bf89fbc 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1202,7 +1202,7 @@
# should be unique across all issuing servers. In theory, this is a variable
# length field, but due to some existing implementations requiring A-ID to be
# 16 octets in length, it is strongly recommended to use that length for the
-# field to provid interoperability with deployed peer implementations. This
+# field to provide interoperability with deployed peer implementations. This
# field is configured in hex format.
#eap_fast_a_id=101112131415161718191a1b1c1d1e1f
@@ -1229,6 +1229,8 @@
# 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
@@ -1730,6 +1732,19 @@
# Enabling this automatically also enables ieee80211w, if not yet enabled.
# 0 = disabled (default)
# 1 = enabled
+# 2 = enabled in workaround mode - Allow STA that claims OCV capability to
+# connect even if the STA doesn't send OCI or negotiate PMF. This
+# workaround is to improve interoperability with legacy STAs which are
+# wrongly copying reserved bits of RSN capabilities from the AP's
+# RSNE into (Re)Association Request frames. When this configuration is
+# enabled, the AP considers STA is OCV capable only when the STA indicates
+# MFP capability in (Re)Association Request frames and sends OCI in
+# EAPOL-Key msg 2/4/FT Reassociation Request frame/FILS (Re)Association
+# Request frame; otherwise, the AP disables OCV for the current connection
+# with the STA. Enabling this workaround mode reduced OCV protection to
+# some extend since it allows misbehavior to go through. As such, this
+# should be enabled only if interoperability with misbehaving STAs is
+# needed.
#ocv=1
# disable_pmksa_caching: Disable PMKSA caching
@@ -1761,7 +1776,7 @@
# be followed by optional peer MAC address (dot11RSNAConfigPasswordPeerMac) and
# by optional password identifier (dot11RSNAConfigPasswordIdentifier). In
# addition, an optional VLAN ID specification can be used to bind the station
-# to the specified VLAN whenver the specific SAE password entry is used.
+# to the specified VLAN whenever the specific SAE password entry is used.
#
# If the peer MAC address is not included or is set to the wildcard address
# (ff:ff:ff:ff:ff:ff), the entry is available for any station to use. If a
@@ -1776,7 +1791,8 @@
# special meaning of removing all previously added entries.
#
# sae_password uses the following encoding:
-#<password/credential>[|mac=<peer mac>][|vlanid=<VLAN ID>][|id=<identifier>]
+#<password/credential>[|mac=<peer mac>][|vlanid=<VLAN ID>]
+#[|pk=<m:ECPrivateKey-base64>][|id=<identifier>]
# Examples:
#sae_password=secret
#sae_password=really secret|mac=ff:ff:ff:ff:ff:ff
@@ -1965,7 +1981,7 @@
# 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
@@ -2021,7 +2037,7 @@
#ft_psk_generate_local=0
##### Neighbor table ##########################################################
-# Maximum number of entries kept in AP table (either for neigbor table or for
+# Maximum number of entries kept in AP table (either for neighbor table or for
# detecting Overlapping Legacy BSS Condition). The oldest entry will be
# removed when adding a new entry that would make the list grow over this
# limit. Note! WFA certification for IEEE 802.11g requires that OLBC is
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 440664e..ad43981 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -975,7 +975,7 @@
dir = opendir(ctrl_iface_dir);
if (dir == NULL) {
printf("Control interface directory '%s' could not be "
- "openned.\n", ctrl_iface_dir);
+ "opened.\n", ctrl_iface_dir);
return;
}
@@ -1402,6 +1402,13 @@
}
+static int hostapd_cli_cmd_dpp_bootstrap_set(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_SET", 1, argc, argv);
+}
+
+
static int hostapd_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -1464,6 +1471,23 @@
return hostapd_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv);
}
+
+#ifdef CONFIG_DPP2
+
+static int hostapd_cli_cmd_dpp_chirp(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_CHIRP", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_dpp_stop_chirp(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DPP_STOP_CHIRP");
+}
+
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
@@ -1650,6 +1674,8 @@
"<id> = get DPP bootstrap URI" },
{ "dpp_bootstrap_info", hostapd_cli_cmd_dpp_bootstrap_info, NULL,
"<id> = show DPP bootstrap information" },
+ { "dpp_bootstrap_set", hostapd_cli_cmd_dpp_bootstrap_set, NULL,
+ "<id> [conf=..] [ssid=<SSID>] [ssid_charset=#] [psk=<PSK>] [pass=<passphrase>] [configurator=<id>] [conn_status=#] [akm_use_selector=<0|1>] [group_id=..] [expiry=#] [csrattrs=..] = set DPP configurator parameters" },
{ "dpp_auth_init", hostapd_cli_cmd_dpp_auth_init, NULL,
"peer=<id> [own=<id>] = initiate DPP bootstrapping" },
{ "dpp_listen", hostapd_cli_cmd_dpp_listen, NULL,
@@ -1670,6 +1696,12 @@
"add PKEX code" },
{ "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL,
"*|<id> = remove DPP pkex information" },
+#ifdef CONFIG_DPP2
+ { "dpp_chirp", hostapd_cli_cmd_dpp_chirp, NULL,
+ "own=<BI ID> iter=<count> = start DPP chirp" },
+ { "dpp_stop_chirp", hostapd_cli_cmd_dpp_stop_chirp, NULL,
+ "= stop DPP chirp" },
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
{ "accept_acl", hostapd_cli_cmd_accept_macacl, NULL,
"=Add/Delete/Show/Clear accept MAC ACL" },
diff --git a/hostapd/main.c b/hostapd/main.c
index cdcb692..346df48 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -677,7 +677,6 @@
#ifdef CONFIG_DPP
os_memset(&dpp_conf, 0, sizeof(dpp_conf));
dpp_conf.cb_ctx = &interfaces;
- /* TODO: dpp_conf.msg_ctx? */
#ifdef CONFIG_DPP2
dpp_conf.remove_bi = hostapd_dpp_remove_bi;
#endif /* CONFIG_DPP2 */
diff --git a/hostapd/sae_pk_gen.c b/hostapd/sae_pk_gen.c
new file mode 100644
index 0000000..c31eff7
--- /dev/null
+++ b/hostapd/sae_pk_gen.c
@@ -0,0 +1,196 @@
+/*
+ * SAE-PK password/modifier generator
+ * 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 "utils/base64.h"
+#include "crypto/crypto.h"
+#include "common/sae.h"
+
+
+int main(int argc, char *argv[])
+{
+ char *der = NULL;
+ size_t der_len;
+ struct crypto_ec_key *key = NULL;
+ struct wpabuf *pub = NULL;
+ u8 *data = NULL, *m;
+ size_t data_len;
+ char *b64 = NULL, *pw = NULL, *pos, *src;
+ int sec, j;
+ int ret = -1;
+ 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)
+ goto fail;
+
+ if (argc != 4) {
+ fprintf(stderr,
+ "usage: sae_pk_gen <DER ECPrivateKey file> <Sec:3|5> <SSID>\n");
+ goto fail;
+ }
+
+ sec = atoi(argv[2]);
+ 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;
+
+ der = os_readfile(argv[1], &der_len);
+ if (!der) {
+ fprintf(stderr, "Could not read %s: %s\n",
+ argv[1], strerror(errno));
+ goto fail;
+ }
+
+ key = crypto_ec_key_parse_priv((u8 *) der, der_len);
+ if (!key) {
+ fprintf(stderr, "Could not parse ECPrivateKey\n");
+ goto fail;
+ }
+
+ pub = crypto_ec_key_get_subject_public_key(key);
+ if (!pub) {
+ fprintf(stderr, "Failed to build SubjectPublicKey\n");
+ goto fail;
+ }
+
+ group = crypto_ec_key_group(key);
+ switch (group) {
+ case 19:
+ hash_len = 32;
+ break;
+ case 20:
+ hash_len = 48;
+ break;
+ case 21:
+ hash_len = 64;
+ break;
+ default:
+ fprintf(stderr, "Unsupported private key group\n");
+ goto fail;
+ }
+
+ data_len = os_strlen(argv[3]) + SAE_PK_M_LEN + wpabuf_len(pub);
+ data = os_malloc(data_len);
+ if (!data) {
+ fprintf(stderr, "No memory for data buffer\n");
+ goto fail;
+ }
+ os_memcpy(data, argv[3], os_strlen(argv[3]));
+ m = data + os_strlen(argv[3]);
+ if (os_get_random(m, SAE_PK_M_LEN) < 0) {
+ fprintf(stderr, "Could not generate random Modifier M\n");
+ goto fail;
+ }
+ os_memcpy(m + SAE_PK_M_LEN, wpabuf_head(pub), wpabuf_len(pub));
+
+ fprintf(stderr, "Searching for a suitable Modifier M value\n");
+ for (i = 0;; i++) {
+ if (sae_hash(hash_len, data, data_len, hash) < 0) {
+ fprintf(stderr, "Hash failed\n");
+ goto fail;
+ }
+ if (hash[0] == 0 && hash[1] == 0) {
+ if ((hash[2] & 0xf0) == 0)
+ fprintf(stderr, "\r%3.2f%%",
+ 100.0 * (double) i / (double) expected);
+ for (j = 2; j < sec; j++) {
+ if (hash[j])
+ break;
+ }
+ if (j == sec)
+ break;
+ }
+ inc_byte_array(m, SAE_PK_M_LEN);
+ }
+
+ 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);
+ if (!b64)
+ goto fail;
+ src = pos = b64;
+ while (*src) {
+ if (*src != '\n')
+ *pos++ = *src;
+ src++;
+ }
+ *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("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:
+ os_free(der);
+ wpabuf_free(pub);
+ crypto_ec_key_deinit(key);
+ os_free(data);
+ os_free(b64);
+ os_free(pw);
+
+ os_program_deinit();
+
+ return ret;
+}
diff --git a/hs20/client/Makefile b/hs20/client/Makefile
index cc2af03..4dcfe2d 100644
--- a/hs20/client/Makefile
+++ b/hs20/client/Makefile
@@ -1,28 +1,6 @@
-all: hs20-osu-client
+ALL=hs20-osu-client
-ifndef CC
-CC=gcc
-endif
-
-ifndef LDO
-LDO=$(CC)
-endif
-
-ifeq ($(QUIET), 1)
-Q=@
-E=true
-else
-Q=@
-E=echo
-ifeq ($(V), 1)
-Q=
-E=true
-endif
-endif
-
-ifndef CFLAGS
-CFLAGS = -MMD -O2 -Wall -g
-endif
+include ../../src/build.rules
CFLAGS += -I../../src/utils
CFLAGS += -I../../src/common
@@ -93,23 +71,11 @@
OBJS += ../../src/crypto/tls_openssl_ocsp.o
LIBS += -lssl -lcrypto
+_OBJS_VAR := OBJS
+include ../../src/objs.mk
hs20-osu-client: $(OBJS)
$(Q)$(LDO) $(LDFLAGS) -o hs20-osu-client $(OBJS) $(LIBS)
@$(E) " LD " $@
-%.o: %.c
- $(Q)$(CC) -c -o $@ $(CFLAGS) $<
- @$(E) " CC " $<
-
-clean:
- rm -f core *~ *.o *.d hs20-osu-client
- rm -f ../../src/utils/*.o
- rm -f ../../src/utils/*.d
- rm -f ../../src/common/*.o
- rm -f ../../src/common/*.d
- rm -f ../../src/crypto/*.o
- rm -f ../../src/crypto/*.d
- rm -f ../../src/wps/*.o
- rm -f ../../src/wps/*.d
-
--include $(OBJS:%.o=%.d)
+clean: common-clean
+ rm -f core *~
diff --git a/hs20/server/.gitignore b/hs20/server/.gitignore
new file mode 100644
index 0000000..fecb096
--- /dev/null
+++ b/hs20/server/.gitignore
@@ -0,0 +1 @@
+hs20_spp_server
diff --git a/hs20/server/Makefile b/hs20/server/Makefile
index 9b73727..0cab6d6 100644
--- a/hs20/server/Makefile
+++ b/hs20/server/Makefile
@@ -1,16 +1,6 @@
-all: hs20_spp_server
+ALL=hs20_spp_server
-ifndef CC
-CC=gcc
-endif
-
-ifndef LDO
-LDO=$(CC)
-endif
-
-ifndef CFLAGS
-CFLAGS = -MMD -O2 -Wall -g
-endif
+include ../../src/build.rules
CFLAGS += -I../../src
CFLAGS += -I../../src/utils
@@ -43,14 +33,10 @@
LIBS += $(shell xml2-config --libs)
OBJS += ../../src/utils/xml_libxml2.o
+_OBJS_VAR := OBJS
+include ../../src/objs.mk
hs20_spp_server: $(OBJS)
$(LDO) $(LDFLAGS) -o hs20_spp_server $(OBJS) $(LIBS)
-clean:
- rm -f core *~ *.o *.d hs20_spp_server
- rm -f ../../src/utils/*.o
- rm -f ../../src/utils/*.d
- rm -f ../../src/crypto/*.o
- rm -f ../../src/crypto/*.d
-
--include $(OBJS:%.o=%.d)
+clean: common-clean
+ rm -f core *~
diff --git a/src/Makefile b/src/Makefile
index c9e84c1..6eb7f2a 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -5,8 +5,8 @@
for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d; done
clean:
- for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d clean; done
- rm -f *~
+ $(Q)for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d clean; done
+ $(Q)rm -f *~
install:
for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d install; done
diff --git a/src/ap/Makefile b/src/ap/Makefile
index 54e48a0..a1e9b7c 100644
--- a/src/ap/Makefile
+++ b/src/ap/Makefile
@@ -1,13 +1,3 @@
-all: libap.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libap.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
CFLAGS += -DHOSTAPD
CFLAGS += -DNEED_AP_MLME
CFLAGS += -DCONFIG_ETH_P_OUI
@@ -67,7 +57,4 @@
wps_hostapd.o \
x_snoop.o
-libap.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 35a32a1..04535a1 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -160,6 +160,10 @@
/* Default to strict CRL checking. */
bss->check_crl_strict = 1;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ bss->sae_commit_status = -1;
+#endif /* CONFIG_TESTING_OPTIONS */
}
@@ -461,7 +465,8 @@
struct hostapd_ssid *ssid = &conf->ssid;
struct sae_password_entry *pw;
- if ((conf->sae_pwe == 0 && !hostapd_sae_pw_id_in_use(conf)) ||
+ if ((conf->sae_pwe == 0 && !hostapd_sae_pw_id_in_use(conf) &&
+ !hostapd_sae_pk_in_use(conf)) ||
conf->sae_pwe == 3 ||
!wpa_key_mgmt_sae(conf->wpa_key_mgmt))
return 0; /* PT not needed */
@@ -711,6 +716,9 @@
#ifdef CONFIG_SAE
sae_deinit_pt(tmp->pt);
#endif /* CONFIG_SAE */
+#ifdef CONFIG_SAE_PK
+ sae_deinit_pk(tmp->pk);
+#endif /* CONFIG_SAE_PK */
os_free(tmp);
}
}
@@ -1111,6 +1119,37 @@
}
+#ifdef CONFIG_SAE_PK
+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 &&
+#ifdef CONFIG_TESTING_OPTIONS
+ !bss->sae_pk_password_check_skip &&
+#endif /* CONFIG_TESTING_OPTIONS */
+ sae_pk_valid_password(bss->ssid.wpa_passphrase))
+ res = true;
+
+ for (pw = bss->sae_passwords; pw; pw = pw->next) {
+ if (!pw->pk &&
+#ifdef CONFIG_TESTING_OPTIONS
+ !bss->sae_pk_password_check_skip &&
+#endif /* CONFIG_TESTING_OPTIONS */
+ 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 res;
+}
+#endif /* CONFIG_SAE_PK */
+
+
static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
struct hostapd_config *conf,
int full_config)
@@ -1294,6 +1333,15 @@
}
#endif /* CONFIG_OCV */
+#ifdef CONFIG_SAE_PK
+ if (full_config && hostapd_sae_pk_in_use(bss) &&
+ hostapd_sae_pk_password_without_pk(bss)) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: SAE password uses SAE-PK style, but does not have PK configured");
+ return -1;
+ }
+#endif /* CONFIG_SAE_PK */
+
return 0;
}
@@ -1473,3 +1521,38 @@
return 2;
return with_id;
}
+
+
+bool hostapd_sae_pk_in_use(struct hostapd_bss_config *conf)
+{
+#ifdef CONFIG_SAE_PK
+ struct sae_password_entry *pw;
+
+ for (pw = conf->sae_passwords; pw; pw = pw->next) {
+ if (pw->pk)
+ return true;
+ }
+#endif /* CONFIG_SAE_PK */
+
+ return false;
+}
+
+
+#ifdef CONFIG_SAE_PK
+bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf)
+{
+ bool with_pk = false;
+ struct sae_password_entry *pw;
+
+ if (conf->ssid.wpa_passphrase)
+ return false;
+
+ for (pw = conf->sae_passwords; pw; pw = pw->next) {
+ if (!pw->pk)
+ return false;
+ with_pk = true;
+ }
+
+ return with_pk;
+}
+#endif /* CONFIG_SAE_PK */
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index cffa636..bada04c 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -197,15 +197,6 @@
#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 {
@@ -261,6 +252,7 @@
u8 peer_addr[ETH_ALEN];
int vlan_id;
struct sae_pt *pt;
+ struct sae_pk *pk;
};
struct dpp_controller_conf {
@@ -677,6 +669,9 @@
u8 bss_load_test_set;
struct wpabuf *own_ie_override;
int sae_reflection_attack;
+ int sae_commit_status;
+ int sae_pk_omit;
+ int sae_pk_password_check_skip;
struct wpabuf *sae_commit_override;
struct wpabuf *rsne_override_eapol;
struct wpabuf *rsnxe_override_eapol;
@@ -687,6 +682,13 @@
int no_beacon_rsnxe;
int skip_prune_assoc;
int ft_rsnxe_used;
+ unsigned int oci_freq_override_eapol_m3;
+ unsigned int oci_freq_override_eapol_g1;
+ unsigned int oci_freq_override_saquery_req;
+ unsigned int oci_freq_override_saquery_resp;
+ 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 */
#define MESH_ENABLED BIT(0)
@@ -1140,6 +1142,8 @@
void hostapd_set_security_params(struct hostapd_bss_config *bss,
int full_config);
int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf);
+bool hostapd_sae_pk_in_use(struct hostapd_bss_config *conf);
+bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf);
int hostapd_setup_sae_pt(struct hostapd_bss_config *conf);
#endif /* HOSTAPD_CONFIG_H */
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 @@
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 @@
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/dfs.c b/src/ap/dfs.c
index 3c078b9..f04a00a 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -955,10 +955,13 @@
if (*skip_radar) {
*skip_radar = 0;
} else {
- if (iface->conf->vht_oper_chwidth == CHANWIDTH_USE_HT)
+ int oper_chwidth;
+
+ oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
+ if (oper_chwidth == CHANWIDTH_USE_HT)
break;
*skip_radar = 1;
- iface->conf->vht_oper_chwidth--;
+ hostapd_set_oper_chwidth(iface->conf, oper_chwidth - 1);
}
}
@@ -1028,7 +1031,7 @@
unsigned int i;
int err = 1;
struct hostapd_hw_modes *cmode = iface->current_mode;
- u8 current_vht_oper_chwidth = iface->conf->vht_oper_chwidth;
+ u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
__func__, iface->cac_started ? "yes" : "no",
@@ -1089,8 +1092,8 @@
"freq=%d chan=%d sec_chan=%d", channel->freq,
channel->chan, secondary_channel);
- new_vht_oper_chwidth = iface->conf->vht_oper_chwidth;
- iface->conf->vht_oper_chwidth = current_vht_oper_chwidth;
+ new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
+ hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth);
/* Setup CSA request */
os_memset(&csa_settings, 0, sizeof(csa_settings));
@@ -1130,7 +1133,7 @@
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
iface->conf->secondary_channel = secondary_channel;
- iface->conf->vht_oper_chwidth = new_vht_oper_chwidth;
+ hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth);
hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
oper_centr_freq_seg0_idx);
hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index 178fd12..6772a87 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -29,6 +29,9 @@
#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 };
@@ -63,6 +66,10 @@
wpabuf_len(hapd->dpp_auth->resp_msg));
}
+#ifdef CONFIG_DPP2
+ dpp_controller_new_qr_code(hapd->iface->interfaces->dpp, bi);
+#endif /* CONFIG_DPP2 */
+
return bi->id;
}
@@ -486,12 +493,35 @@
}
+#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 +534,25 @@
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 +590,7 @@
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 +604,32 @@
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;
@@ -1173,6 +1228,9 @@
r_bootstrap, r_bootstrap_len);
peer_bi = dpp_bootstrap_find_chirp(hapd->iface->interfaces->dpp,
r_bootstrap);
+ dpp_notify_chirp_received(hapd->msg_ctx,
+ peer_bi ? (int) peer_bi->id : -1,
+ src, freq, r_bootstrap);
if (!peer_bi) {
if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
src, hdr, buf, len, freq, NULL,
@@ -1194,8 +1252,8 @@
0);
if (!auth)
return;
- hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
- if (dpp_set_configurator(hapd->dpp_auth,
+ hostapd_dpp_set_testing_options(hapd, auth);
+ if (dpp_set_configurator(auth,
hapd->dpp_configurator_params) < 0) {
dpp_auth_deinit(auth);
return;
@@ -1235,11 +1293,12 @@
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 +1330,22 @@
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);
@@ -2156,6 +2229,45 @@
#ifdef CONFIG_DPP2
+int hostapd_dpp_controller_start(struct hostapd_data *hapd, const char *cmd)
+{
+ struct dpp_controller_config config;
+ const char *pos;
+
+ os_memset(&config, 0, sizeof(config));
+ config.allowed_roles = DPP_CAPAB_ENROLLEE | DPP_CAPAB_CONFIGURATOR;
+ config.netrole = DPP_NETROLE_AP;
+ config.msg_ctx = hapd->msg_ctx;
+ config.cb_ctx = hapd;
+ config.process_conf_obj = hostapd_dpp_process_conf_obj;
+ if (cmd) {
+ pos = os_strstr(cmd, " tcp_port=");
+ if (pos) {
+ pos += 10;
+ config.tcp_port = atoi(pos);
+ }
+
+ pos = os_strstr(cmd, " role=");
+ if (pos) {
+ pos += 6;
+ if (os_strncmp(pos, "configurator", 12) == 0)
+ config.allowed_roles = DPP_CAPAB_CONFIGURATOR;
+ else if (os_strncmp(pos, "enrollee", 8) == 0)
+ config.allowed_roles = DPP_CAPAB_ENROLLEE;
+ else if (os_strncmp(pos, "either", 6) == 0)
+ config.allowed_roles = DPP_CAPAB_CONFIGURATOR |
+ DPP_CAPAB_ENROLLEE;
+ else
+ return -1;
+ }
+
+ config.qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
+ }
+ config.configurator_params = hapd->dpp_configurator_params;
+ return dpp_controller_start(hapd->iface->interfaces->dpp, &config);
+}
+
+
static void hostapd_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx);
static void hostapd_dpp_chirp_timeout(void *eloop_ctx, void *timeout_ctx)
diff --git a/src/ap/dpp_hostapd.h b/src/ap/dpp_hostapd.h
index 7e74185..264d3e4 100644
--- a/src/ap/dpp_hostapd.h
+++ b/src/ap/dpp_hostapd.h
@@ -41,6 +41,7 @@
void hostapd_dpp_init_global(struct hapd_interfaces *ifaces);
void hostapd_dpp_deinit_global(struct hapd_interfaces *ifaces);
+int hostapd_dpp_controller_start(struct hostapd_data *hapd, const char *cmd);
int hostapd_dpp_chirp(struct hostapd_data *hapd, const char *cmd);
void hostapd_dpp_chirp_stop(struct hostapd_data *hapd);
void hostapd_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi);
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 524a151..9af5445 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -105,6 +105,32 @@
#endif /* CONFIG_FILS */
+static bool check_sa_query_need(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ if ((sta->flags &
+ (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
+ (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED))
+ return false;
+
+ if (!sta->sa_query_timed_out && sta->sa_query_count > 0)
+ ap_check_sa_query_timeout(hapd, sta);
+
+ if (!sta->sa_query_timed_out && (sta->auth_alg != WLAN_AUTH_FT)) {
+ /*
+ * STA has already been associated with MFP and SA Query timeout
+ * has not been reached. Reject the association attempt
+ * temporarily and start SA Query, if one is not pending.
+ */
+ if (sta->sa_query_count == 0)
+ ap_sta_start_sa_query(hapd, sta);
+
+ return true;
+ }
+
+ return false;
+}
+
+
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
const u8 *req_ies, size_t req_ies_len, int reassoc)
{
@@ -293,6 +319,17 @@
os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
struct wpabuf *wps;
+ if (check_sa_query_need(hapd, sta)) {
+ status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
+
+ p = hostapd_eid_assoc_comeback_time(hapd, sta,
+ p);
+
+ hostapd_sta_assoc(hapd, addr, reassoc, status,
+ buf, p - buf);
+ return 0;
+ }
+
sta->flags |= WLAN_STA_WPS;
wps = ieee802_11_vendor_ie_concat(ie, ielen,
WPS_IE_VENDOR_TYPE);
@@ -388,25 +425,7 @@
goto fail;
}
- if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
- (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
- !sta->sa_query_timed_out &&
- sta->sa_query_count > 0)
- ap_check_sa_query_timeout(hapd, sta);
- if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
- (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
- !sta->sa_query_timed_out &&
- (sta->auth_alg != WLAN_AUTH_FT)) {
- /*
- * STA has already been associated with MFP and SA
- * Query timeout has not been reached. Reject the
- * association attempt temporarily and start SA Query,
- * if one is not pending.
- */
-
- if (sta->sa_query_count == 0)
- ap_sta_start_sa_query(hapd, sta);
-
+ if (check_sa_query_need(hapd, sta)) {
status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
@@ -439,7 +458,7 @@
#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
@@ -844,8 +863,6 @@
int offset, int width, int cf1, int cf2,
int finished)
{
- /* TODO: If OCV is enabled deauth STAs that don't perform a SA Query */
-
#ifdef NEED_AP_MLME
int channel, chwidth, is_dfs;
u8 seg0_idx = 0, seg1_idx = 0;
@@ -895,9 +912,18 @@
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:
@@ -958,6 +984,29 @@
for (i = 0; i < hapd->iface->num_bss; i++)
hostapd_neighbor_set_own_report(hapd->iface->bss[i]);
+
+#ifdef CONFIG_OCV
+ if (hapd->conf->ocv) {
+ struct sta_info *sta;
+ bool check_sa_query = false;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (wpa_auth_uses_ocv(sta->wpa_sm) &&
+ !(sta->flags & WLAN_STA_WNM_SLEEP_MODE)) {
+ sta->post_csa_sa_query = 1;
+ check_sa_query = true;
+ }
+ }
+
+ if (check_sa_query) {
+ wpa_printf(MSG_DEBUG,
+ "OCV: Check post-CSA SA Query initiation in 15 seconds");
+ eloop_register_timeout(15, 0,
+ hostapd_ocv_check_csa_sa_query,
+ hapd, NULL);
+ }
+ }
+#endif /* CONFIG_OCV */
#endif /* NEED_AP_MLME */
}
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index 9567e20..90f1577 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -1555,11 +1555,14 @@
di->prot = prot;
di->sd_resp = buf;
di->sd_resp_pos = 0;
+ di->dpp = 1;
tx_buf = gas_build_initial_resp(
dialog_token, WLAN_STATUS_SUCCESS,
- comeback_delay, 10);
- if (tx_buf)
+ comeback_delay, 10 + 2);
+ if (tx_buf) {
gas_serv_write_dpp_adv_proto(tx_buf);
+ wpabuf_put_le16(tx_buf, 0);
+ }
}
} else {
wpa_printf(MSG_DEBUG,
@@ -1782,9 +1785,10 @@
tx_buf = gas_build_comeback_resp(dialog_token,
WLAN_STATUS_SUCCESS,
dialog->sd_frag_id, more, 0,
- 10 + frag_len);
+ 10 + 2 + frag_len);
if (tx_buf) {
gas_serv_write_dpp_adv_proto(tx_buf);
+ wpabuf_put_le16(tx_buf, frag_len);
wpabuf_put_buf(tx_buf, buf);
}
} else
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index f9af038..b37f49f 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -439,6 +439,10 @@
hostapd_clean_rrm(hapd);
fils_hlp_deinit(hapd);
+#ifdef CONFIG_OCV
+ eloop_cancel_timeout(hostapd_ocv_check_csa_sa_query, hapd, NULL);
+#endif /* CONFIG_OCV */
+
#ifdef CONFIG_SAE
{
struct hostapd_sae_commit_queue *q;
@@ -1911,6 +1915,13 @@
if (!bss->conf->owe_transition_ifname[0])
continue;
+ if (bss->iface->state != HAPD_IFACE_ENABLED) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: Interface %s state %s - defer beacon update",
+ bss->conf->iface,
+ hostapd_state_text(bss->iface->state));
+ continue;
+ }
res = hostapd_owe_trans_get_info(bss);
if (res == 0)
continue;
@@ -3151,6 +3162,7 @@
hostapd_prune_associations(hapd, sta->addr);
ap_sta_clear_disconnect_timeouts(hapd, sta);
+ sta->post_csa_sa_query = 0;
#ifdef CONFIG_P2P
if (sta->p2p_ie == NULL && !sta->no_p2p_set) {
@@ -3662,3 +3674,25 @@
#endif /* CONFIG_NO_RADIUS */
}
}
+
+
+#ifdef CONFIG_OCV
+void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct sta_info *sta;
+
+ wpa_printf(MSG_DEBUG, "OCV: Post-CSA SA Query initiation check");
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!sta->post_csa_sa_query)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "OCV: OCVC STA " MACSTR
+ " did not start SA Query after CSA - disconnect",
+ MAC2STR(sta->addr));
+ ap_sta_disconnect(hapd, sta, sta->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ }
+}
+#endif /* CONFIG_OCV */
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index a616136..9d3c85d 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -633,6 +633,7 @@
void hostapd_cleanup_cs_params(struct hostapd_data *hapd);
void hostapd_periodic_iface(struct hostapd_iface *iface);
int hostapd_owe_trans_get_info(struct hostapd_data *hapd);
+void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx);
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 565e9af..a872893 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -24,6 +24,7 @@
#include "common/dpp.h"
#include "common/ocv.h"
#include "common/wpa_common.h"
+#include "common/wpa_ctrl.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "p2p/p2p.h"
@@ -385,7 +386,8 @@
auth_alg == WLAN_AUTH_SAE) {
if (auth_transaction == 1 && sta &&
(resp == WLAN_STATUS_SUCCESS ||
- resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT)) {
+ resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ resp == WLAN_STATUS_SAE_PK)) {
wpa_printf(MSG_DEBUG,
"TESTING: Postpone SAE Commit transmission until Confirm is ready");
os_free(sta->sae_postponed_commit);
@@ -477,17 +479,23 @@
const char *rx_id = NULL;
int use_pt = 0;
struct sae_pt *pt = NULL;
+ const struct sae_pk *pk = NULL;
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);
+#endif /* CONFIG_SAE_PK */
}
if (rx_id && hapd->conf->sae_pwe != 3)
use_pt = 1;
else if (status_code == WLAN_STATUS_SUCCESS)
use_pt = 0;
- else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)
+ else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK)
use_pt = 1;
for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
@@ -501,6 +509,8 @@
continue;
password = pw->password;
pt = pw->pt;
+ if (!(hapd->conf->mesh & MESH_ENABLED))
+ pk = pw->pk;
break;
}
if (!password) {
@@ -514,7 +524,7 @@
if (update && use_pt &&
sae_prepare_commit_pt(sta->sae, pt, hapd->own_addr, sta->addr,
- NULL) < 0)
+ NULL, pk) < 0)
return NULL;
if (update && !use_pt &&
@@ -557,7 +567,17 @@
if (buf == NULL)
return NULL;
- sae_write_confirm(sta->sae, buf);
+#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;
+ }
return buf;
}
@@ -577,8 +597,21 @@
if (data == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- status = (sta->sae->tmp && sta->sae->tmp->h2e) ?
- WLAN_STATUS_SAE_HASH_TO_ELEMENT : WLAN_STATUS_SUCCESS;
+ if (sta->sae->tmp && sta->sae->pk)
+ status = WLAN_STATUS_SAE_PK;
+ 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),
@@ -899,9 +932,14 @@
switch (sta->sae->state) {
case SAE_NOTHING:
if (auth_transaction == 1) {
- if (sta->sae->tmp)
- sta->sae->tmp->h2e = status_code ==
- WLAN_STATUS_SAE_HASH_TO_ELEMENT;
+ if (sta->sae->tmp) {
+ sta->sae->h2e =
+ (status_code ==
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK);
+ sta->sae->pk =
+ status_code == WLAN_STATUS_SAE_PK;
+ }
ret = auth_sae_send_commit(hapd, sta, bssid,
!allow_reuse, status_code);
if (ret)
@@ -1117,14 +1155,20 @@
sae_pwe = 1;
else if (id_in_use == 1 && sae_pwe == 0)
sae_pwe = 2;
+#ifdef CONFIG_SAE_PK
+ if (sae_pwe == 0 && hostapd_sae_pk_in_use(hapd->conf))
+ sae_pwe = 2;
+#endif /* CONFIG_SAE_PK */
return ((sae_pwe == 0 || sae_pwe == 3) &&
status_code == WLAN_STATUS_SUCCESS) ||
(sae_pwe == 1 &&
- status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) ||
+ (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK)) ||
(sae_pwe == 2 &&
(status_code == WLAN_STATUS_SUCCESS ||
- status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT));
+ status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK));
}
@@ -1147,11 +1191,15 @@
static int check_sae_rejected_groups(struct hostapd_data *hapd,
- const struct wpabuf *groups)
+ struct sae_data *sae)
{
+ const struct wpabuf *groups;
size_t i, count;
const u8 *pos;
+ if (!sae->tmp)
+ return 0;
+ groups = sae->tmp->peer_rejected_groups;
if (!groups)
return 0;
@@ -1193,6 +1241,7 @@
wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack");
pos = mgmt->u.auth.variable;
end = ((const u8 *) mgmt) + len;
+ resp = status_code;
send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
auth_transaction, resp, pos, end - pos,
"auth-sae-reflection-attack");
@@ -1338,7 +1387,8 @@
((const u8 *) mgmt) + len -
mgmt->u.auth.variable, &token,
&token_len, groups, status_code ==
- WLAN_STATUS_SAE_HASH_TO_ELEMENT);
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK);
if (resp == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message from " MACSTR " due to reflection attack",
@@ -1368,9 +1418,7 @@
if (resp != WLAN_STATUS_SUCCESS)
goto reply;
- if (sta->sae->tmp &&
- check_sae_rejected_groups(
- hapd, sta->sae->tmp->peer_rejected_groups)) {
+ if (check_sae_rejected_groups(hapd, sta->sae)) {
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto reply;
}
@@ -1382,8 +1430,9 @@
"SAE: Request anti-clogging token from "
MACSTR, MAC2STR(sta->addr));
if (sta->sae->tmp)
- h2e = sta->sae->tmp->h2e;
- if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)
+ h2e = sta->sae->h2e;
+ if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK)
h2e = 1;
data = auth_build_token_req(hapd, sta->sae->group,
sta->addr, h2e);
@@ -3104,6 +3153,34 @@
#endif /* CONFIG_OWE */
+static bool check_sa_query(struct hostapd_data *hapd, struct sta_info *sta,
+ int reassoc)
+{
+ if ((sta->flags &
+ (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
+ (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED))
+ return false;
+
+ if (!sta->sa_query_timed_out && sta->sa_query_count > 0)
+ ap_check_sa_query_timeout(hapd, sta);
+
+ if (!sta->sa_query_timed_out &&
+ (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
+ /*
+ * STA has already been associated with MFP and SA Query timeout
+ * has not been reached. Reject the association attempt
+ * temporarily and start SA Query, if one is not pending.
+ */
+ if (sta->sa_query_count == 0)
+ ap_sta_start_sa_query(hapd, sta);
+
+ return true;
+ }
+
+ return false;
+}
+
+
static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ies, size_t ies_len, int reassoc)
{
@@ -3182,6 +3259,13 @@
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)
@@ -3220,6 +3304,8 @@
if (hapd->conf->wps_state && elems.wps_ie) {
wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
"Request - assume WPS is used");
+ if (check_sa_query(hapd, sta, reassoc))
+ return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
sta->flags |= WLAN_STA_WPS;
wpabuf_free(sta->wps_ie);
sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
@@ -3273,27 +3359,9 @@
resp = wpa_res_to_status_code(res);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
- if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
- (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
- !sta->sa_query_timed_out &&
- sta->sa_query_count > 0)
- ap_check_sa_query_timeout(hapd, sta);
- if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
- (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
- !sta->sa_query_timed_out &&
- (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
- /*
- * STA has already been associated with MFP and SA
- * Query timeout has not been reached. Reject the
- * association attempt temporarily and start SA Query,
- * if one is not pending.
- */
- if (sta->sa_query_count == 0)
- ap_sta_start_sa_query(hapd, sta);
-
+ if (check_sa_query(hapd, sta, reassoc))
return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
- }
if (wpa_auth_uses_mfp(sta->wpa_sm))
sta->flags |= WLAN_STA_MFP;
@@ -3346,7 +3414,7 @@
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
@@ -3494,6 +3562,7 @@
struct wpa_channel_info ci;
int tx_chanwidth;
int tx_seg1_idx;
+ enum oci_verify_result res;
if (hostapd_drv_channel_info(hapd, &ci) != 0) {
wpa_printf(MSG_WARNING,
@@ -3507,9 +3576,20 @@
&tx_seg1_idx) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
- tx_chanwidth, tx_seg1_idx) != 0) {
- wpa_printf(MSG_WARNING, "FILS: %s", ocv_errorstr);
+ res = ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx);
+ if (wpa_auth_uses_ocv(sta->wpa_sm) == 2 &&
+ res == OCI_NOT_FOUND) {
+ /* Work around misbehaving STAs */
+ wpa_printf(MSG_INFO,
+ "FILS: Disable OCV with a STA that does not send OCI");
+ wpa_auth_set_ocv(sta->wpa_sm, 0);
+ } else if (res != OCI_SUCCESS) {
+ wpa_printf(MSG_WARNING, "FILS: OCV failed: %s",
+ ocv_errorstr);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, OCV_FAILURE "addr="
+ MACSTR " frame=fils-reassoc-req error=%s",
+ MAC2STR(sta->addr), ocv_errorstr);
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
}
@@ -3831,7 +3911,8 @@
#ifdef CONFIG_OWE
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
- wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE) {
+ wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
+ !wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
struct wpabuf *pub;
pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
@@ -4085,7 +4166,7 @@
{
u16 capab_info, listen_interval, seq_ctrl, fc;
int resp = WLAN_STATUS_SUCCESS;
- u16 reply_res;
+ u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
const u8 *pos;
int left, i;
struct sta_info *sta;
@@ -4465,7 +4546,7 @@
os_free(tmp);
/*
- * Remove the station in case tranmission of a success response fails
+ * Remove the station in case transmission of a success response fails
* (the STA was added associated to the driver) or if the station was
* previously added unassociated.
*/
@@ -5511,4 +5592,57 @@
}
+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_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_shared.c b/src/ap/ieee802_11_shared.c
index 74a837f..17003d5 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/ocv.h"
+#include "common/wpa_ctrl.h"
#include "hostapd.h"
#include "sta_info.h"
#include "ap_config.h"
@@ -72,6 +73,16 @@
"Failed to get channel info for OCI element in SA Query Request");
return;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->oci_freq_override_saquery_req) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI frequency %d -> %u MHz",
+ ci.frequency,
+ hapd->conf->oci_freq_override_saquery_req);
+ ci.frequency =
+ hapd->conf->oci_freq_override_saquery_req;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
oci_ie_len = OCV_OCI_EXTENDED_LEN;
oci_ie = os_zalloc(oci_ie_len);
@@ -151,6 +162,16 @@
"Failed to get channel info for OCI element in SA Query Response");
return;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->oci_freq_override_saquery_resp) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI frequency %d -> %u MHz",
+ ci.frequency,
+ hapd->conf->oci_freq_override_saquery_resp);
+ ci.frequency =
+ hapd->conf->oci_freq_override_saquery_resp;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
oci_ie_len = OCV_OCI_EXTENDED_LEN;
oci_ie = os_zalloc(oci_ie_len);
@@ -254,14 +275,21 @@
return;
if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
- tx_chanwidth, tx_seg1_idx) != 0) {
- wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
+ tx_chanwidth, tx_seg1_idx) !=
+ OCI_SUCCESS) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, OCV_FAILURE "addr="
+ MACSTR " frame=saquery%s error=%s",
+ MAC2STR(sa),
+ action_type == WLAN_SA_QUERY_REQUEST ?
+ "req" : "resp", ocv_errorstr);
return;
}
}
#endif /* CONFIG_OCV */
if (action_type == WLAN_SA_QUERY_REQUEST) {
+ if (sta)
+ sta->post_csa_sa_query = 0;
ieee802_11_send_sa_query_resp(hapd, sa, trans_id);
return;
}
@@ -400,6 +428,14 @@
if (hapd->conf->beacon_prot)
*pos |= 0x10; /* Bit 84 - Beacon Protection Enabled */
break;
+ case 11: /* Bits 88-95 */
+#ifdef CONFIG_SAE_PK
+ if (hapd->conf->wpa &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+ hostapd_sae_pk_exclusively(hapd->conf))
+ *pos |= 0x01; /* Bit 88 - SAE PK Exclusively */
+#endif /* CONFIG_SAE_PK */
+ break;
}
}
@@ -460,6 +496,12 @@
#endif /* CONFIG_SAE */
if (len < 11 && hapd->conf->beacon_prot)
len = 11;
+#ifdef CONFIG_SAE_PK
+ if (len < 12 && hapd->conf->wpa &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+ hostapd_sae_pk_exclusively(hapd->conf))
+ len = 12;
+#endif /* CONFIG_SAE_PK */
if (len < hapd->iface->extended_capa_len)
len = hapd->iface->extended_capa_len;
if (len == 0)
@@ -1054,11 +1096,16 @@
u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
{
u8 *pos = eid;
+ bool sae_pk = false;
+
+#ifdef CONFIG_SAE_PK
+ sae_pk = hostapd_sae_pk_in_use(hapd->conf);
+#endif /* CONFIG_SAE_PK */
if (!(hapd->conf->wpa & WPA_PROTO_RSN) ||
!wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) ||
(hapd->conf->sae_pwe != 1 && hapd->conf->sae_pwe != 2 &&
- !hostapd_sae_pw_id_in_use(hapd->conf)) ||
+ !hostapd_sae_pw_id_in_use(hapd->conf) && !sae_pk) ||
hapd->conf->sae_pwe == 3 ||
len < 3)
return pos;
@@ -1067,7 +1114,12 @@
*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 (sae_pk)
+ *pos |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+#endif /* CONFIG_SAE_PK */
+ pos++;
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 @@
}
-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 *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/sta_info.h b/src/ap/sta_info.h
index 940d315..ef48561 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -122,6 +122,7 @@
unsigned int hs20_t_c_filtering:1;
unsigned int ft_over_ds:1;
unsigned int external_dh_updated:1;
+ unsigned int post_csa_sa_query:1;
u16 auth_alg;
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index 67281b3..be81797 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -103,6 +103,15 @@
os_free(wnmtfs_ie);
return -1;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->oci_freq_override_wnm_sleep) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI frequency %d -> %u MHz",
+ ci.frequency,
+ hapd->conf->oci_freq_override_wnm_sleep);
+ ci.frequency = hapd->conf->oci_freq_override_wnm_sleep;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
oci_ie_len = OCV_OCI_EXTENDED_LEN;
oci_ie = os_zalloc(oci_ie_len);
@@ -317,8 +326,9 @@
if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_msg(hapd, MSG_WARNING, "WNM: %s", ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(hapd, MSG_WARNING, "WNM: OCV failed: %s",
+ ocv_errorstr);
return;
}
}
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 019e535..9d74bfc 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -15,6 +15,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ocv.h"
#include "common/dpp.h"
+#include "common/wpa_ctrl.h"
#include "crypto/aes.h"
#include "crypto/aes_wrap.h"
#include "crypto/aes_siv.h"
@@ -2322,7 +2323,6 @@
struct wpa_auth_config *conf = &wpa_auth->conf;
u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
- size_t pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
if (wpa_derive_pmk_r0(fils_ft, fils_ft_len,
conf->ssid, conf->ssid_len,
@@ -2333,10 +2333,6 @@
use_sha384) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FILS+FT: PMK-R0",
- pmk_r0, pmk_r0_len);
- wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR0Name",
- pmk_r0_name, WPA_PMK_NAME_LEN);
wpa_ft_store_pmk_fils(sm, pmk_r0, pmk_r0_name);
forced_memzero(fils_ft, sizeof(fils_ft));
@@ -2776,6 +2772,15 @@
wpabuf_clear_free(plain);
return NULL;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conf->oci_freq_override_fils_assoc) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI frequency %d -> %u MHz",
+ ci.frequency,
+ conf->oci_freq_override_fils_assoc);
+ ci.frequency = conf->oci_freq_override_fils_assoc;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
pos = wpabuf_put(plain, OCV_OCI_EXTENDED_LEN);
if (ocv_insert_extended_oci(&ci, pos) < 0) {
@@ -3032,6 +3037,7 @@
struct wpa_channel_info ci;
int tx_chanwidth;
int tx_seg1_idx;
+ enum oci_verify_result res;
if (wpa_channel_info(wpa_auth, &ci) != 0) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -3045,10 +3051,21 @@
&tx_seg1_idx) < 0)
return;
- if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
- tx_chanwidth, tx_seg1_idx) != 0) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- ocv_errorstr);
+ res = ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx);
+ if (wpa_auth_uses_ocv(sm) == 2 && res == OCI_NOT_FOUND) {
+ /* Work around misbehaving STAs */
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "Disable OCV with a STA that does not send OCI");
+ wpa_auth_set_ocv(sm, 0);
+ } else if (res != OCI_SUCCESS) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "OCV failed: %s", ocv_errorstr);
+ if (wpa_auth->conf.msg_ctx)
+ wpa_msg(wpa_auth->conf.msg_ctx, MSG_INFO,
+ OCV_FAILURE "addr=" MACSTR
+ " frame=eapol-key-m2 error=%s",
+ MAC2STR(sm->addr), ocv_errorstr);
return;
}
}
@@ -3211,6 +3228,14 @@
else
os_memcpy(bigtk.pn, rsc, sizeof(bigtk.pn));
os_memcpy(bigtk.bigtk, gsm->BIGTK[gsm->GN_bigtk - 6], len);
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random BIGTK to each OSEN STA to prevent use
+ * of BIGTK in the BSS.
+ */
+ if (random_get_bytes(bigtk.bigtk, len) < 0)
+ return pos;
+ }
pos = wpa_add_kde(pos, RSN_KEY_DATA_BIGTK,
(const u8 *) &bigtk, WPA_BIGTK_KDE_PREFIX_LEN + len,
NULL, 0);
@@ -3228,7 +3253,9 @@
return 0;
}
-static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos)
+
+static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos,
+ unsigned int freq)
{
#ifdef CONFIG_OCV
struct wpa_channel_info ci;
@@ -3241,6 +3268,14 @@
"Failed to get channel info for OCI element");
return -1;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (freq) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %u MHz",
+ ci.frequency, freq);
+ ci.frequency = freq;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
return ocv_insert_oci_kde(&ci, argpos);
#else /* CONFIG_OCV */
@@ -3457,7 +3492,7 @@
gtk, gtk_len);
}
pos = ieee80211w_kde_add(sm, pos);
- if (ocv_oci_add(sm, &pos) < 0)
+ if (ocv_oci_add(sm, &pos, conf->oci_freq_override_eapol_m3) < 0)
goto done;
#ifdef CONFIG_IEEE80211R_AP
@@ -3807,7 +3842,8 @@
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gsm->GTK_len);
pos = ieee80211w_kde_add(sm, pos);
- if (ocv_oci_add(sm, &pos) < 0) {
+ if (ocv_oci_add(sm, &pos,
+ conf->oci_freq_override_eapol_g1) < 0) {
os_free(kde_buf);
return;
}
@@ -3873,7 +3909,7 @@
if (wpa_channel_info(wpa_auth, &ci) != 0) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "Failed to get channel info to validate received OCI in EAPOL-Key group 1/2");
+ "Failed to get channel info to validate received OCI in EAPOL-Key group 2/2");
return;
}
@@ -3884,9 +3920,15 @@
return;
if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
- tx_chanwidth, tx_seg1_idx) != 0) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- ocv_errorstr);
+ tx_chanwidth, tx_seg1_idx) !=
+ OCI_SUCCESS) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "OCV failed: %s", ocv_errorstr);
+ if (wpa_auth->conf.msg_ctx)
+ wpa_msg(wpa_auth->conf.msg_ctx, MSG_INFO,
+ OCV_FAILURE "addr=" MACSTR
+ " frame=eapol-key-g2 error=%s",
+ MAC2STR(sm->addr), ocv_errorstr);
return;
}
}
@@ -4072,6 +4114,7 @@
int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
{
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
u8 *start = pos;
@@ -4090,6 +4133,14 @@
return 0;
pos += 8;
os_memcpy(pos, gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random GTK to each STA to prevent use
+ * of GTK in the BSS.
+ */
+ if (random_get_bytes(pos, gsm->GTK_len) < 0)
+ return 0;
+ }
pos += gsm->GTK_len;
wpa_printf(MSG_DEBUG, "WNM: GTK Key ID %u in WNM-Sleep Mode exit",
@@ -4103,6 +4154,7 @@
int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
{
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
u8 *start = pos;
size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
@@ -4120,6 +4172,14 @@
pos += 6;
os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], len);
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random IGTK to each STA to prevent use
+ * of IGTK in the BSS.
+ */
+ if (random_get_bytes(pos, len) < 0)
+ return 0;
+ }
pos += len;
wpa_printf(MSG_DEBUG, "WNM: IGTK Key ID %u in WNM-Sleep Mode exit",
@@ -4150,6 +4210,14 @@
pos += 6;
os_memcpy(pos, gsm->BIGTK[gsm->GN_bigtk - 6], len);
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random BIGTK to each STA to prevent use
+ * of BIGTK in the BSS.
+ */
+ if (random_get_bytes(pos, len) < 0)
+ return 0;
+ }
pos += len;
wpa_printf(MSG_DEBUG, "WNM: BIGTK Key ID %u in WNM-Sleep Mode exit",
@@ -5228,6 +5296,14 @@
#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,
@@ -5259,6 +5335,7 @@
u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos;
u8 *opos;
size_t gtk_len, kde_len;
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
int wpa_ie_len, secure, gtkidx, encr = 0;
@@ -5369,7 +5446,7 @@
opos += 2 + RSN_SELECTOR_LEN + 2;
os_memset(opos, 0, 6); /* clear PN */
}
- if (ocv_oci_add(sm, &pos) < 0) {
+ if (ocv_oci_add(sm, &pos, conf->oci_freq_override_eapol_m3) < 0) {
os_free(kde);
return -1;
}
@@ -5377,9 +5454,7 @@
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
int res;
- struct wpa_auth_config *conf;
- conf = &sm->wpa_auth->conf;
if (sm->assoc_resp_ftie &&
kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) {
os_memcpy(pos, sm->assoc_resp_ftie,
@@ -5436,6 +5511,7 @@
void *ctx1, void *ctx2)
{
u8 rsc[WPA_KEY_RSC_LEN];
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
const u8 *kde;
u8 *kde_buf = NULL, *pos, hdr[2];
@@ -5470,7 +5546,8 @@
opos += 2 + RSN_SELECTOR_LEN + 2;
os_memset(opos, 0, 6); /* clear PN */
}
- if (ocv_oci_add(sm, &pos) < 0) {
+ if (ocv_oci_add(sm, &pos,
+ conf->oci_freq_override_eapol_g1) < 0) {
os_free(kde_buf);
return -1;
}
@@ -5512,4 +5589,27 @@
wpa_auth->conf.ft_rsnxe_used = val;
}
+
+void wpa_auth_set_ocv_override_freq(struct wpa_authenticator *wpa_auth,
+ enum wpa_auth_ocv_override_frame frame,
+ unsigned int freq)
+{
+ if (!wpa_auth)
+ return;
+ switch (frame) {
+ case WPA_AUTH_OCV_OVERRIDE_EAPOL_M3:
+ wpa_auth->conf.oci_freq_override_eapol_m3 = freq;
+ break;
+ case WPA_AUTH_OCV_OVERRIDE_EAPOL_G1:
+ wpa_auth->conf.oci_freq_override_eapol_g1 = freq;
+ break;
+ case WPA_AUTH_OCV_OVERRIDE_FT_ASSOC:
+ wpa_auth->conf.oci_freq_override_ft_assoc = freq;
+ break;
+ case WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC:
+ wpa_auth->conf.oci_freq_override_fils_assoc = freq;
+ break;
+ }
+}
+
#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 1ea067b..5f9df9c 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -168,6 +168,7 @@
struct wpa_auth_config {
+ void *msg_ctx;
int wpa;
int extended_key_id;
int wpa_key_mgmt;
@@ -240,6 +241,10 @@
unsigned int igtk_rsc_override_set:1;
int ft_rsnxe_used;
#endif /* CONFIG_TESTING_OPTIONS */
+ unsigned int oci_freq_override_eapol_m3;
+ unsigned int oci_freq_override_eapol_g1;
+ unsigned int oci_freq_override_ft_assoc;
+ unsigned int oci_freq_override_fils_assoc;
#ifdef CONFIG_P2P
u8 ip_addr_go[4];
u8 ip_addr_mask[4];
@@ -251,6 +256,7 @@
u8 fils_cache_id[FILS_CACHE_ID_LEN];
#endif /* CONFIG_FILS */
int sae_pwe;
+ bool sae_pk;
int owe_ptk_workaround;
u8 transition_disable;
#ifdef CONFIG_DPP2
@@ -511,6 +517,8 @@
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),
@@ -525,4 +533,14 @@
void wpa_auth_set_ptk_rekey_timer(struct wpa_state_machine *sm);
void wpa_auth_set_ft_rsnxe_used(struct wpa_authenticator *wpa_auth, int val);
+enum wpa_auth_ocv_override_frame {
+ WPA_AUTH_OCV_OVERRIDE_EAPOL_M3,
+ WPA_AUTH_OCV_OVERRIDE_EAPOL_G1,
+ WPA_AUTH_OCV_OVERRIDE_FT_ASSOC,
+ WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC,
+};
+void wpa_auth_set_ocv_override_freq(struct wpa_authenticator *wpa_auth,
+ enum wpa_auth_ocv_override_frame frame,
+ unsigned int freq);
+
#endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 5af65aa..5aa363e 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -14,6 +14,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/ocv.h"
+#include "common/wpa_ctrl.h"
#include "drivers/driver.h"
#include "crypto/aes.h"
#include "crypto/aes_siv.h"
@@ -1897,7 +1898,7 @@
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) {
@@ -1985,7 +1986,7 @@
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;
}
@@ -2128,8 +2129,6 @@
pmk_r0, pmk_r0_name,
wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, pmk_r0_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_len,
pmk_r0_name,
@@ -2140,9 +2139,6 @@
if (wpa_derive_pmk_r1(pmk_r0, pmk_r0_len, pmk_r0_name, r1kh, sm->addr,
pmk_r1, sm->pmk_r1_name) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r1_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
- WPA_PMK_NAME_LEN);
if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, pmk_r1_len,
sm->pmk_r1_name, sm->pairwise, &vlan,
@@ -2167,11 +2163,12 @@
static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
{
u8 *subelem;
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
size_t subelem_len, pad_len;
const u8 *key;
size_t key_len;
- u8 keybuf[32];
+ u8 keybuf[WPA_GTK_MAX_LEN];
const u8 *kek;
size_t kek_len;
@@ -2198,12 +2195,30 @@
pad_len += 8;
if (pad_len && key_len < sizeof(keybuf)) {
os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
+ if (conf->disable_gtk ||
+ sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random GTK to each STA to prevent use
+ * of GTK in the BSS.
+ */
+ if (random_get_bytes(keybuf, key_len) < 0)
+ return NULL;
+ }
os_memset(keybuf + key_len, 0, pad_len);
keybuf[key_len] = 0xdd;
key_len += pad_len;
key = keybuf;
- } else
+ } else if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random GTK to each STA to prevent use of GTK
+ * in the BSS.
+ */
+ if (random_get_bytes(keybuf, key_len) < 0)
+ return NULL;
+ key = keybuf;
+ } else {
key = gsm->GTK[gsm->GN - 1];
+ }
/*
* Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
@@ -2237,11 +2252,13 @@
static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
{
u8 *subelem, *pos;
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
size_t subelem_len;
- const u8 *kek;
+ const u8 *kek, *igtk;
size_t kek_len;
size_t igtk_len;
+ u8 dummy_igtk[WPA_IGTK_MAX_LEN];
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
kek = sm->PTK.kek2;
@@ -2268,8 +2285,19 @@
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
pos += 6;
*pos++ = igtk_len;
- if (aes_wrap(kek, kek_len, igtk_len / 8,
- gsm->IGTK[gsm->GN_igtk - 4], pos)) {
+ igtk = gsm->IGTK[gsm->GN_igtk - 4];
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random IGTK to each STA to prevent use of
+ * IGTK in the BSS.
+ */
+ if (random_get_bytes(dummy_igtk, igtk_len / 8) < 0) {
+ os_free(subelem);
+ return NULL;
+ }
+ igtk = dummy_igtk;
+ }
+ if (aes_wrap(kek, kek_len, igtk_len / 8, igtk, pos)) {
wpa_printf(MSG_DEBUG,
"FT: IGTK subelem encryption failed: kek_len=%d",
(int) kek_len);
@@ -2287,9 +2315,10 @@
u8 *subelem, *pos;
struct wpa_group *gsm = sm->group;
size_t subelem_len;
- const u8 *kek;
+ const u8 *kek, *bigtk;
size_t kek_len;
size_t bigtk_len;
+ u8 dummy_bigtk[WPA_IGTK_MAX_LEN];
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
kek = sm->PTK.kek2;
@@ -2316,8 +2345,19 @@
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos);
pos += 6;
*pos++ = bigtk_len;
- if (aes_wrap(kek, kek_len, bigtk_len / 8,
- gsm->IGTK[gsm->GN_bigtk - 6], pos)) {
+ bigtk = gsm->IGTK[gsm->GN_bigtk - 6];
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random BIGTK to each OSEN STA to prevent use
+ * of BIGTK in the BSS.
+ */
+ if (random_get_bytes(dummy_bigtk, bigtk_len / 8) < 0) {
+ os_free(subelem);
+ return NULL;
+ }
+ bigtk = dummy_bigtk;
+ }
+ if (aes_wrap(kek, kek_len, bigtk_len / 8, bigtk, pos)) {
wpa_printf(MSG_DEBUG,
"FT: BIGTK subelem encryption failed: kek_len=%d",
(int) kek_len);
@@ -2621,6 +2661,15 @@
os_free(subelem);
return NULL;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conf->oci_freq_override_ft_assoc) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI frequency %d -> %u MHz",
+ ci.frequency,
+ conf->oci_freq_override_ft_assoc);
+ ci.frequency = conf->oci_freq_override_ft_assoc;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
subelem_len += 2 + OCV_OCI_LEN;
nbuf = os_realloc(subelem, subelem_len);
@@ -2961,8 +3010,6 @@
conf->r1_key_holder,
sm->addr, out_pmk_r1, pmk_r1_name) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", out_pmk_r1, r0->pmk_r0_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
os_get_reltime(&now);
if (r0->expiration)
@@ -3091,8 +3138,6 @@
sm->wpa_auth->conf.r1_key_holder, sm->addr,
pmk_r1_name, use_sha384) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- wpa_hexdump(MSG_DEBUG, "FT: Derived requested PMKR1Name",
- pmk_r1_name, WPA_PMK_NAME_LEN);
if (conf->ft_psk_generate_local &&
wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
@@ -3460,6 +3505,7 @@
struct wpa_channel_info ci;
int tx_chanwidth;
int tx_seg1_idx;
+ enum oci_verify_result res;
if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
wpa_printf(MSG_WARNING,
@@ -3473,10 +3519,21 @@
&tx_seg1_idx) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- if (ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
- tx_chanwidth, tx_seg1_idx) != 0) {
- wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ res = ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx);
+ if (wpa_auth_uses_ocv(sm) == 2 && res == OCI_NOT_FOUND) {
+ /* Work around misbehaving STAs */
+ wpa_printf(MSG_INFO,
+ "Disable OCV with a STA that does not send OCI");
+ wpa_auth_set_ocv(sm, 0);
+ } else if (res != OCI_SUCCESS) {
+ wpa_printf(MSG_WARNING, "OCV failed: %s", ocv_errorstr);
+ if (sm->wpa_auth->conf.msg_ctx)
+ wpa_msg(sm->wpa_auth->conf.msg_ctx, MSG_INFO,
+ OCV_FAILURE "addr=" MACSTR
+ " frame=ft-reassoc-req error=%s",
+ MAC2STR(sm->addr), ocv_errorstr);
+ return WLAN_STATUS_INVALID_FTIE;
}
}
#endif /* CONFIG_OCV */
@@ -3699,14 +3756,11 @@
{ .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
};
+ wpa_printf(MSG_DEBUG, "FT: Derive PMK-R1 for peer AP");
if (wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_len,
pmk_r0->pmk_r0_name, r1kh_id,
s1kh_id, pmk_r1, pmk_r1_name) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 (for peer AP)",
- pmk_r1, pmk_r1_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name (for peer AP)",
- pmk_r1_name, WPA_PMK_NAME_LEN);
WPA_PUT_LE16(f_pairwise, pmk_r0->pairwise);
os_get_reltime(&now);
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 05d87ac..c01654f 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -175,6 +175,11 @@
wconf->igtk_rsc_override_set = 1;
}
wconf->ft_rsnxe_used = conf->ft_rsnxe_used;
+ wconf->oci_freq_override_eapol_m3 = conf->oci_freq_override_eapol_m3;
+ wconf->oci_freq_override_eapol_g1 = conf->oci_freq_override_eapol_g1;
+ wconf->oci_freq_override_ft_assoc = conf->oci_freq_override_ft_assoc;
+ wconf->oci_freq_override_fils_assoc =
+ conf->oci_freq_override_fils_assoc;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_P2P
os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4);
@@ -193,6 +198,9 @@
wconf->sae_pwe = 1;
else if (sae_pw_id == 1 && wconf->sae_pwe == 0)
wconf->sae_pwe = 2;
+#ifdef CONFIG_SAE_PK
+ wconf->sae_pk = hostapd_sae_pk_in_use(conf);
+#endif /* CONFIG_SAE_PK */
#ifdef CONFIG_OWE
wconf->owe_ptk_workaround = conf->owe_ptk_workaround;
#endif /* CONFIG_OWE */
@@ -1451,6 +1459,7 @@
size_t wpa_ie_len;
hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &_conf);
+ _conf.msg_ctx = hapd->msg_ctx;
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
_conf.tx_status = 1;
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index ba08ac2..a6dc1a5 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -95,8 +95,9 @@
#endif /* CONFIG_IEEE80211R_AP */
unsigned int is_wnmsleep:1;
unsigned int pmkid_set:1;
+
#ifdef CONFIG_OCV
- unsigned int ocv_enabled:1;
+ int ocv_enabled;
#endif /* CONFIG_OCV */
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 8dfd657..3704fc0 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -378,7 +378,7 @@
{
u8 *pos = buf;
- if (conf->sae_pwe != 1 && conf->sae_pwe != 2)
+ if (conf->sae_pwe != 1 && conf->sae_pwe != 2 && !conf->sae_pk)
return 0; /* no supported extended RSN capabilities */
if (len < 3)
@@ -388,7 +388,12 @@
*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 (conf->sae_pk)
+ *pos |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+#endif /* CONFIG_SAE_PK */
+ pos++;
return pos - buf;
}
@@ -803,14 +808,26 @@
#endif /* CONFIG_SAE */
#ifdef CONFIG_OCV
- if ((data.capabilities & WPA_CAPABILITY_OCVC) &&
+ if (wpa_auth->conf.ocv && (data.capabilities & WPA_CAPABILITY_OCVC) &&
!(data.capabilities & WPA_CAPABILITY_MFPC)) {
- wpa_printf(MSG_DEBUG,
- "Management frame protection required with OCV, but client did not enable it");
- return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+ /* Some legacy MFP incapable STAs wrongly copy OCVC bit from
+ * AP RSN capabilities. To improve interoperability with such
+ * legacy STAs allow connection without enabling OCV when the
+ * workaround mode (ocv=2) is enabled.
+ */
+ if (wpa_auth->conf.ocv == 2) {
+ wpa_printf(MSG_DEBUG,
+ "Allow connecting MFP incapable and OCV capable STA without enabling OCV");
+ wpa_auth_set_ocv(sm, 0);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "Management frame protection required with OCV, but client did not enable it");
+ return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+ }
+ } else {
+ wpa_auth_set_ocv(sm, (data.capabilities & WPA_CAPABILITY_OCVC) ?
+ wpa_auth->conf.ocv : 0);
}
- wpa_auth_set_ocv(sm, wpa_auth->conf.ocv &&
- (data.capabilities & WPA_CAPABILITY_OCVC));
#endif /* CONFIG_OCV */
if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION ||
diff --git a/src/build.rules b/src/build.rules
new file mode 100644
index 0000000..acda884
--- /dev/null
+++ b/src/build.rules
@@ -0,0 +1,109 @@
+.PHONY: all
+all: _all
+
+# disable built-in rules
+.SUFFIXES:
+
+# setup some variables
+ROOTDIR := $(dir $(lastword $(MAKEFILE_LIST)))
+ROOTDIR := $(dir $(ROOTDIR:%../src/=%))../
+BUILDDIR ?= $(abspath $(ROOTDIR)build)
+BUILDDIR := $(BUILDDIR:%/=%)
+ABSROOT := $(abspath $(ROOTDIR))
+ifeq ($(origin OUT),command line)
+_PROJ := $(OUT:%/=%)
+_PROJ := $(_PROJ:$(BUILDDIR)/%=%)
+else
+_PROJ := $(abspath $(dir $(firstword $(MAKEFILE_LIST))))
+_PROJ := $(_PROJ:$(ABSROOT)/%=%)
+endif
+
+ifndef CC
+CC=gcc
+endif
+
+ifndef RANLIB
+RANLIB=ranlib
+endif
+
+ifndef LDO
+LDO=$(CC)
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+ifneq ($(CONFIG_FILE),)
+-include $(CONFIG_FILE)
+
+# export for sub-makefiles
+export CONFIG_CODE_COVERAGE
+
+.PHONY: verify_config
+verify_config:
+ @if [ ! -r $(CONFIG_FILE) ]; then \
+ echo 'Building $(firstword $(ALL)) requires a configuration file'; \
+ echo '(.config). See README for more instructions. You can'; \
+ echo 'run "cp defconfig .config" to create an example'; \
+ echo 'configuration.'; \
+ exit 1; \
+ fi
+VERIFY := verify_config
+else
+VERIFY :=
+endif
+
+# default target
+.PHONY: _all
+_all: $(VERIFY) $(ALL) $(EXTRA_TARGETS)
+
+# continue setup
+COVSUFFIX := $(if $(CONFIG_CODE_COVERAGE),-cov,)
+PROJ := $(_PROJ)$(COVSUFFIX)
+
+Q=@
+E=echo
+ifeq ($(V), 1)
+Q=
+E=true
+endif
+ifeq ($(QUIET), 1)
+Q=@
+E=true
+endif
+
+ifeq ($(Q),@)
+MAKEFLAGS += --no-print-directory
+endif
+
+_DIRS := $(BUILDDIR)/$(PROJ)
+.PHONY: _make_dirs
+_make_dirs:
+ @mkdir -p $(_DIRS)
+
+$(BUILDDIR)/$(PROJ)/src/%.o: $(ROOTDIR)src/%.c $(CONFIG_FILE) | _make_dirs
+ $(Q)$(CC) -c -o $@ $(CFLAGS) $<
+ @$(E) " CC " $<
+$(BUILDDIR)/$(PROJ)/%.o: %.c $(CONFIG_FILE) | _make_dirs
+ $(Q)$(CC) -c -o $@ $(CFLAGS) $<
+ @$(E) " CC " $<
+# for the fuzzing tests
+$(BUILDDIR)/$(PROJ)/wpa_supplicant/%.o: $(ROOTDIR)wpa_supplicant/%.c $(CONFIG_FILE) | _make_dirs
+ $(Q)$(CC) -c -o $@ $(CFLAGS) $<
+ @$(E) " CC " $<
+
+# libraries - they know how to build themselves
+# (lib_phony so we recurse all the time)
+.PHONY: lib_phony
+lib_phony:
+# nothing
+
+$(BUILDDIR)/$(PROJ)/%.a: $(CONFIG_FILE) lib_phony
+ $(Q)$(MAKE) -C $(ROOTDIR)$(dir $(@:$(BUILDDIR)/$(PROJ)/%=%)) OUT=$(abspath $(dir $@))/
+
+BUILDOBJ = $(patsubst %,$(BUILDDIR)/$(PROJ)/%,$(patsubst $(ROOTDIR)%,%,$(1)))
+
+.PHONY: common-clean
+common-clean:
+ $(Q)rm -rf $(ALL) $(BUILDDIR)/$(PROJ)
diff --git a/src/common/Makefile b/src/common/Makefile
index ccb280e..59ba6c5 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -1,13 +1,3 @@
-all: libcommon.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libcommon.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
CFLAGS += -DCONFIG_IEEE80211R
CFLAGS += -DCONFIG_HS20
CFLAGS += -DCONFIG_SAE
@@ -21,7 +11,4 @@
sae.o \
wpa_common.o
-libcommon.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/common/brcm_vendor.h b/src/common/brcm_vendor.h
index cb5b348..b1bf397 100644
--- a/src/common/brcm_vendor.h
+++ b/src/common/brcm_vendor.h
@@ -27,6 +27,7 @@
*/
enum brcm_nl80211_vendor_subcmds {
BRCM_VENDOR_SUBCMD_UNSPEC = 0,
+ BRCM_VENDOR_SUBCMD_SET_MAC = 6,
BRCM_VENDOR_SCMD_ACS = 9,
BRCM_VENDOR_SCMD_MAX = 10
};
@@ -61,5 +62,12 @@
BRCM_VENDOR_ATTR_ACS_LAST
};
+
+enum brcm_wlan_vendor_attr {
+ BRCM_ATTR_DRIVER_CMD = 0,
+ BRCM_ATTR_DRIVER_MAC_ADDR = 3,
+ BRCM_ATTR_DRIVER_AFTER_LAST = 5,
+ BRCM_ATTR_DRIVER_MAX = BRCM_ATTR_DRIVER_AFTER_LAST - 1,
+};
#endif /* BRCM_VENDOR_H */
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
index a58bf66..00308d4 100644
--- a/src/common/common_module_tests.c
+++ b/src/common/common_module_tests.c
@@ -548,6 +548,95 @@
}
+static int sae_pk_tests(void)
+{
+#ifdef CONFIG_SAE_PK
+ const char *invalid[] = { "a2bc-de3f-ghim-", "a2bcde3fghim", "", NULL };
+ struct {
+ const char *pw;
+ const u8 *val;
+ } valid[] = {
+ { "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;
+ bool failed;
+
+ for (i = 0; invalid[i]; i++) {
+ if (sae_pk_valid_password(invalid[i])) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Invalid password '%s' not recognized",
+ invalid[i]);
+ return -1;
+ }
+ }
+
+ failed = false;
+ for (i = 0; valid[i].pw; i++) {
+ u8 *res;
+ size_t res_len;
+ char *b32;
+ const char *pw = valid[i].pw;
+ const u8 *val = valid[i].val;
+ size_t pw_len = os_strlen(pw);
+ size_t bits = (pw_len - pw_len / 5) * 5;
+ size_t bytes = (bits + 7) / 8;
+
+ if (!sae_pk_valid_password(pw)) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Valid password '%s' not recognized",
+ pw);
+ failed = true;
+ continue;
+ }
+
+ res = sae_pk_base32_decode(pw, pw_len, &res_len);
+ if (!res) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Failed to decode password '%s'",
+ valid[i].pw);
+ failed = true;
+ continue;
+ }
+ if (res_len != bytes || os_memcmp(val, res, res_len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Mismatch for decoded password '%s'",
+ valid[i].pw);
+ wpa_hexdump(MSG_INFO, "SAE-PK: Decoded value",
+ res, res_len);
+ wpa_hexdump(MSG_INFO, "SAE-PK: Expected value",
+ val, bytes);
+ failed = true;
+ }
+ os_free(res);
+
+ b32 = sae_pk_base32_encode(val, bits - 5);
+ if (!b32) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Failed to encode password '%s'",
+ pw);
+ failed = true;
+ continue;
+ }
+ if (os_strcmp(b32, pw) != 0) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Mismatch for password '%s'", pw);
+ wpa_printf(MSG_INFO, "SAE-PK: Encoded value: '%s'",
+ b32);
+ failed = true;
+ }
+ os_free(b32);
+ }
+
+ return failed ? -1 : 0;
+#else /* CONFIG_SAE_PK */
+ return 0;
+#endif /* CONFIG_SAE_PK */
+}
+
+
int common_module_tests(void)
{
int ret = 0;
@@ -557,6 +646,7 @@
if (ieee802_11_parse_tests() < 0 ||
gas_tests() < 0 ||
sae_tests() < 0 ||
+ sae_pk_tests() < 0 ||
rsn_ie_parse_tests() < 0)
ret = -1;
diff --git a/src/common/dpp.c b/src/common/dpp.c
index d09f0d1..67b8f07 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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,28 @@
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);
+ wpabuf_free(conf->pp_key);
}
#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 +1530,15 @@
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 +1554,30 @@
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, "\"");
@@ -1504,6 +1587,16 @@
wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
goto fail;
}
+#ifdef CONFIG_DPP2
+ if (auth->peer_version >= 2 && auth->conf->pp_key) {
+ json_value_sep(buf);
+ if (dpp_build_jwk(buf, "ppKey", auth->conf->pp_key, NULL,
+ curve) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to build ppKey JWK");
+ goto fail;
+ }
+ }
+#endif /* CONFIG_DPP2 */
json_end_object(buf);
json_end_object(buf);
@@ -1554,7 +1647,7 @@
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 +1680,28 @@
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 +1711,33 @@
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 +1751,9 @@
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 +1816,21 @@
}
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 +1901,7 @@
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 +2010,7 @@
dpp_auth_fail(auth, "Unsupported netRole");
goto fail;
}
+ auth->e_netrole = netrole;
token = json_get_member(root, "mudurl");
if (token && token->type == JSON_STRING) {
@@ -1930,9 +2062,56 @@
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;
@@ -2255,6 +2434,20 @@
}
+static void dpp_copy_ppkey(struct dpp_config_obj *conf, EVP_PKEY *ppkey)
+{
+ unsigned char *der = NULL;
+ int der_len;
+
+ der_len = i2d_PUBKEY(ppkey, &der);
+ if (der_len <= 0)
+ return;
+ wpabuf_free(conf->pp_key);
+ conf->pp_key = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
+}
+
+
static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
struct dpp_config_obj *conf)
{
@@ -2290,10 +2483,10 @@
struct json_token *cred)
{
struct dpp_signed_connector_info info;
- struct json_token *token, *csign;
+ struct json_token *token, *csign, *ppkey;
int ret = -1;
- EVP_PKEY *csign_pub = NULL;
- const struct dpp_curve_params *key_curve = NULL;
+ EVP_PKEY *csign_pub = NULL, *pp_pub = NULL;
+ const struct dpp_curve_params *key_curve = NULL, *pp_curve = NULL;
const char *signed_connector;
os_memset(&info, 0, sizeof(info));
@@ -2320,6 +2513,21 @@
}
dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
+ ppkey = json_get_member(cred, "ppKey");
+ if (ppkey && ppkey->type == JSON_OBJECT) {
+ pp_pub = dpp_parse_jwk(ppkey, &pp_curve);
+ if (!pp_pub) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to parse ppKey JWK");
+ goto fail;
+ }
+ dpp_debug_print_key("DPP: Received ppKey", pp_pub);
+ if (key_curve != pp_curve) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: C-sign-key and ppKey do not use the same curve");
+ goto fail;
+ }
+ }
+
token = json_get_member(cred, "signedConnector");
if (!token || token->type != JSON_STRING) {
wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
@@ -2350,17 +2558,72 @@
conf->connector = os_strdup(signed_connector);
dpp_copy_csign(conf, csign_pub);
+ if (pp_pub)
+ dpp_copy_ppkey(conf, pp_pub);
if (dpp_akm_dpp(conf->akm) || auth->peer_version >= 2)
dpp_copy_netaccesskey(auth, conf);
ret = 0;
fail:
EVP_PKEY_free(csign_pub);
+ EVP_PKEY_free(pp_pub);
os_free(info.payload);
return ret;
}
+#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) {
@@ -2376,6 +2639,8 @@
return "dpp+sae";
case DPP_AKM_PSK_SAE_DPP:
return "dpp+psk+sae";
+ case DPP_AKM_DOT1X:
+ return "dot1x";
default:
return "??";
}
@@ -2397,6 +2662,8 @@
return "506F9A02+000FAC08";
case DPP_AKM_PSK_SAE_DPP:
return "506F9A02+000FAC08+000FAC02+000FAC06";
+ case DPP_AKM_DOT1X:
+ return "000FAC01+000FAC05";
default:
return "??";
}
@@ -2406,7 +2673,7 @@
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;
@@ -2420,6 +2687,8 @@
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) {
@@ -2433,6 +2702,10 @@
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;
@@ -2451,6 +2724,8 @@
return DPP_AKM_SAE;
if (psk)
return DPP_AKM_PSK;
+ if (dot1x)
+ return DPP_AKM_DOT1X;
return DPP_AKM_UNKNOWN;
}
@@ -2568,6 +2843,12 @@
(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);
@@ -2584,6 +2865,20 @@
}
+#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)
{
@@ -2661,6 +2956,28 @@
}
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;
@@ -3086,6 +3403,7 @@
os_free(conf->kid);
os_free(conf->connector);
EVP_PKEY_free(conf->connector_key);
+ EVP_PKEY_free(conf->pp_key);
os_free(conf);
}
@@ -3144,9 +3462,9 @@
}
-struct dpp_configurator *
+static struct dpp_configurator *
dpp_keygen_configurator(const char *curve, const u8 *privkey,
- size_t privkey_len)
+ size_t privkey_len, const u8 *pp_key, size_t pp_key_len)
{
struct dpp_configurator *conf;
@@ -3166,7 +3484,12 @@
privkey_len);
else
conf->csign = dpp_gen_keypair(conf->curve);
- if (!conf->csign)
+ if (pp_key)
+ conf->pp_key = dpp_set_keypair(&conf->curve, pp_key,
+ pp_key_len);
+ else
+ conf->pp_key = dpp_gen_keypair(conf->curve);
+ if (!conf->csign || !conf->pp_key)
goto fail;
conf->own = 1;
@@ -3207,7 +3530,7 @@
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;
@@ -3762,11 +4085,11 @@
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];
@@ -3853,14 +4176,15 @@
int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
{
char *curve = NULL;
- char *key = NULL;
- u8 *privkey = NULL;
- size_t privkey_len = 0;
+ char *key = NULL, *ppkey = NULL;
+ u8 *privkey = NULL, *pp_key = NULL;
+ size_t privkey_len = 0, pp_key_len = 0;
int ret = -1;
struct dpp_configurator *conf = NULL;
curve = get_param(cmd, " curve=");
key = get_param(cmd, " key=");
+ ppkey = get_param(cmd, " ppkey=");
if (key) {
privkey_len = os_strlen(key) / 2;
@@ -3870,7 +4194,16 @@
goto fail;
}
- conf = dpp_keygen_configurator(curve, privkey, privkey_len);
+ if (ppkey) {
+ pp_key_len = os_strlen(key) / 2;
+ pp_key = os_malloc(pp_key_len);
+ if (!pp_key ||
+ hexstr2bin(ppkey, pp_key, pp_key_len) < 0)
+ goto fail;
+ }
+
+ conf = dpp_keygen_configurator(curve, privkey, privkey_len,
+ pp_key, pp_key_len);
if (!conf)
goto fail;
@@ -3881,7 +4214,9 @@
fail:
os_free(curve);
str_clear_free(key);
+ str_clear_free(ppkey);
bin_clear_free(privkey, privkey_len);
+ bin_clear_free(pp_key, pp_key_len);
dpp_configurator_free(conf);
return ret;
}
@@ -3945,12 +4280,12 @@
struct dpp_asymmetric_key *key)
{
struct dpp_configurator *conf;
- const EC_KEY *eckey;
- const EC_GROUP *group;
+ const EC_KEY *eckey, *eckey_pp;
+ const EC_GROUP *group, *group_pp;
int nid;
const struct dpp_curve_params *curve;
- if (!key->csign)
+ if (!key->csign || !key->pp_key)
return -1;
eckey = EVP_PKEY_get0_EC_KEY(key->csign);
if (!eckey)
@@ -3964,6 +4299,18 @@
wpa_printf(MSG_INFO, "DPP: Unsupported group in c-sign-key");
return -1;
}
+ eckey_pp = EVP_PKEY_get0_EC_KEY(key->pp_key);
+ if (!eckey_pp)
+ return -1;
+ group_pp = EC_KEY_get0_group(eckey_pp);
+ if (!group_pp)
+ return -1;
+ if (EC_GROUP_get_curve_name(group) !=
+ EC_GROUP_get_curve_name(group_pp)) {
+ wpa_printf(MSG_INFO,
+ "DPP: Mismatch in c-sign-key and ppKey groups");
+ return -1;
+ }
conf = os_zalloc(sizeof(*conf));
if (!conf)
@@ -3971,6 +4318,8 @@
conf->curve = curve;
conf->csign = key->csign;
key->csign = NULL;
+ conf->pp_key = key->pp_key;
+ key->pp_key = NULL;
conf->own = 1;
if (dpp_configurator_gen_kid(conf) < 0) {
dpp_configurator_free(conf);
@@ -4009,10 +4358,8 @@
dpp = os_zalloc(sizeof(*dpp));
if (!dpp)
return NULL;
- dpp->msg_ctx = config->msg_ctx;
#ifdef CONFIG_DPP2
dpp->cb_ctx = config->cb_ctx;
- dpp->process_conf_obj = config->process_conf_obj;
dpp->remove_bi = config->remove_bi;
#endif /* CONFIG_DPP2 */
@@ -4050,6 +4397,7 @@
#ifdef CONFIG_DPP2
+
struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi)
{
struct wpabuf *msg;
@@ -4066,4 +4414,17 @@
"DPP: Presence Announcement frame attributes", msg);
return msg;
}
+
+
+void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
+ unsigned int freq, const u8 *hash)
+{
+ char hex[SHA256_MAC_LEN * 2 + 1];
+
+ wpa_snprintf_hex(hex, sizeof(hex), hash, SHA256_MAC_LEN);
+ wpa_msg(msg_ctx, MSG_INFO,
+ DPP_EVENT_CHIRP_RX "id=%d src=" MACSTR " freq=%u hash=%s",
+ id, MAC2STR(src), freq, hex);
+}
+
#endif /* CONFIG_DPP2 */
diff --git a/src/common/dpp.h b/src/common/dpp.h
index d77762e..99a1ca7 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -21,6 +21,7 @@
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,9 @@
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,
+ DPP_ATTR_CONFIGURATOR_NONCE = 0x1022,
};
enum dpp_status_error {
@@ -120,6 +124,7 @@
#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 +154,7 @@
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 +202,7 @@
DPP_AKM_PSK_SAE,
DPP_AKM_SAE_DPP,
DPP_AKM_PSK_SAE_DPP,
+ DPP_AKM_DOT1X,
};
enum dpp_netrole {
@@ -221,11 +228,14 @@
char *passphrase;
u8 psk[32];
int psk_set;
+
+ char *csrattrs;
};
struct dpp_asymmetric_key {
struct dpp_asymmetric_key *next;
EVP_PKEY *csign;
+ EVP_PKEY *pp_key;
char *config_template;
char *connector_template;
};
@@ -241,18 +251,22 @@
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 c_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;
@@ -293,6 +307,7 @@
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;
@@ -309,6 +324,11 @@
int psk_set;
enum dpp_akm akm;
struct wpabuf *c_sign_key;
+ struct wpabuf *certbag;
+ struct wpabuf *certs;
+ struct wpabuf *cacert;
+ char *server_name;
+ struct wpabuf *pp_key;
} conf_obj[DPP_MAX_CONF_OBJ];
unsigned int num_conf_obj;
struct dpp_asymmetric_key *conf_key_pkg;
@@ -319,6 +339,16 @@
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;
@@ -339,6 +369,7 @@
const struct dpp_curve_params *curve;
char *connector; /* own Connector for reconfiguration */
EVP_PKEY *connector_key;
+ EVP_PKEY *pp_key;
};
struct dpp_introduction {
@@ -351,6 +382,7 @@
const struct hostapd_ip_addr *ipaddr;
const u8 *pkhash;
+ void *msg_ctx;
void *cb_ctx;
void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg,
size_t len);
@@ -362,6 +394,11 @@
const char *configurator_params;
int tcp_port;
u8 allowed_roles;
+ int qr_mutual;
+ enum dpp_netrole netrole;
+ void *msg_ctx;
+ void *cb_ctx;
+ int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
};
#ifdef CONFIG_TESTING_OPTIONS
@@ -519,6 +556,10 @@
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,
@@ -548,9 +589,6 @@
int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
size_t buflen);
void dpp_configurator_free(struct dpp_configurator *conf);
-struct dpp_configurator *
-dpp_keygen_configurator(const char *curve, const u8 *privkey,
- size_t privkey_len);
int dpp_configurator_own_config(struct dpp_authentication *auth,
const char *curve, int ap);
enum dpp_status_error
@@ -595,6 +633,11 @@
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,
@@ -634,14 +677,23 @@
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);
+void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
+ unsigned int freq, const u8 *hash);
struct dpp_global_config {
- void *msg_ctx;
void *cb_ctx;
- int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
};
@@ -652,10 +704,15 @@
/* 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,
@@ -669,5 +726,12 @@
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,
+ const u8 *pp_key,
+ size_t pp_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_backup.c b/src/common/dpp_backup.c
index c675c42..3b81f09 100644
--- a/src/common/dpp_backup.c
+++ b/src/common/dpp_backup.c
@@ -40,6 +40,7 @@
struct dpp_asymmetric_key *next = key->next;
EVP_PKEY_free(key->csign);
+ EVP_PKEY_free(key->pp_key);
str_clear_free(key->config_template);
str_clear_free(key->connector_template);
os_free(key);
@@ -48,35 +49,62 @@
}
-static struct wpabuf * dpp_build_conf_params(void)
+static struct wpabuf * dpp_build_conf_params(struct dpp_configurator *conf)
{
- struct wpabuf *buf;
+ struct wpabuf *buf, *priv_key = NULL;
size_t len;
/* TODO: proper template values */
const char *conf_template = "{\"wi-fi_tech\":\"infra\",\"discovery\":{\"ssid\":\"test\"},\"cred\":{\"akm\":\"dpp\"}}";
const char *connector_template = NULL;
+ EC_KEY *eckey;
+ unsigned char *der = NULL;
+ int der_len;
+
+ if (!conf->pp_key)
+ return NULL;
+ eckey = EVP_PKEY_get0_EC_KEY(conf->pp_key);
+ if (!eckey)
+ return NULL;
+
+ EC_KEY_set_enc_flags(eckey, EC_PKEY_NO_PUBKEY);
+ der_len = i2d_ECPrivateKey(eckey, &der);
+ if (der_len > 0)
+ priv_key = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
+ if (!priv_key)
+ goto fail;
len = 100 + os_strlen(conf_template);
if (connector_template)
len += os_strlen(connector_template);
+ if (priv_key)
+ len += wpabuf_len(priv_key);
buf = wpabuf_alloc(len);
if (!buf)
- return NULL;
+ goto fail;
/*
* DPPConfigurationParameters ::= SEQUENCE {
+ * privacyProtectionKey PrivateKey,
* configurationTemplate UTF8String,
* connectorTemplate UTF8String OPTIONAL}
*/
+ /* PrivateKey ::= OCTET STRING */
+ asn1_put_octet_string(buf, priv_key);
+
asn1_put_utf8string(buf, conf_template);
if (connector_template)
asn1_put_utf8string(buf, connector_template);
+ wpabuf_clear_free(priv_key);
return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+fail:
+ wpabuf_clear_free(priv_key);
+ return NULL;
}
-static struct wpabuf * dpp_build_attribute(void)
+static struct wpabuf * dpp_build_attribute(struct dpp_configurator *conf)
{
struct wpabuf *conf_params, *attr;
@@ -88,7 +116,7 @@
* type OBJECT IDENTIFIER,
* values SET SIZE(1..MAX) OF Type
*/
- conf_params = dpp_build_conf_params();
+ conf_params = dpp_build_conf_params(conf);
conf_params = asn1_encaps(conf_params, ASN1_CLASS_UNIVERSAL,
ASN1_TAG_SET);
if (!conf_params)
@@ -167,7 +195,7 @@
alg = dpp_build_key_alg(auth->conf->curve);
/* Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } */
- attr = dpp_build_attribute();
+ attr = dpp_build_attribute(auth->conf);
attr = asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SET);
if (!priv_key || !attr || !alg)
goto fail;
@@ -189,7 +217,7 @@
if (!key)
goto fail;
- asn1_put_integer(key, 1); /* version = v2(1) */
+ asn1_put_integer(key, 0); /* version = v1(0) */
/* PrivateKeyAlgorithmIdentifier */
wpabuf_put_buf(key, alg);
@@ -275,18 +303,21 @@
struct wpabuf *pwri = NULL, *enc_key = NULL, *key_der_alg = NULL,
*key_enc_alg = NULL, *salt;
u8 kek[DPP_MAX_HASH_LEN];
- const u8 *key;
+ u8 key[DPP_MAX_HASH_LEN];
size_t key_len;
+ int res;
salt = wpabuf_alloc(64);
if (!salt || os_get_random(wpabuf_put(salt, 64), 64) < 0)
goto fail;
wpa_hexdump_buf(MSG_DEBUG, "DPP: PBKDF2 salt", salt);
- /* TODO: For initial testing, use ke as the key. Replace this with a
- * new key once that has been defined. */
- key = auth->ke;
key_len = auth->curve->hash_len;
+ /* password = HKDF-Expand(bk, "Enveloped Data Password", length) */
+ res = dpp_hkdf_expand(key_len, auth->bk, key_len,
+ "Enveloped Data Password", key, key_len);
+ if (res < 0)
+ goto fail;
wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
if (dpp_pbkdf2(hash_len, key, key_len, wpabuf_head(salt), 64, 1000,
@@ -905,7 +936,7 @@
/* Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2) */
if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
goto fail;
- if (val != 1) {
+ if (val != 0 && val != 1) {
wpa_printf(MSG_DEBUG,
"DPP: Unsupported DPPAsymmetricKeyPackage version %d",
val);
@@ -1056,6 +1087,7 @@
/*
* DPPConfigurationParameters ::= SEQUENCE {
+ * privacyProtectionKey PrivateKey,
* configurationTemplate UTF8String,
* connectorTemplate UTF8String OPTIONAL}
*/
@@ -1072,6 +1104,37 @@
end = pos;
pos = hdr.payload;
+ /*
+ * PrivateKey ::= OCTET STRING
+ * (Contains DER encoding of ECPrivateKey)
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected OCTETSTRING (PrivateKey) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "DPP: privacyProtectionKey",
+ hdr.payload, hdr.length);
+ pos = hdr.payload + hdr.length;
+ eckey = d2i_ECPrivateKey(NULL, &hdr.payload, hdr.length);
+ if (!eckey) {
+ wpa_printf(MSG_INFO,
+ "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ key->pp_key = EVP_PKEY_new();
+ if (!key->pp_key || EVP_PKEY_assign_EC_KEY(key->pp_key, eckey) != 1) {
+ EC_KEY_free(eckey);
+ goto fail;
+ }
+ if (wpa_debug_show_keys)
+ dpp_debug_print_key("DPP: Received privacyProtectionKey",
+ key->pp_key);
+
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_UTF8STRING) {
@@ -1151,7 +1214,7 @@
int dpp_conf_resp_env_data(struct dpp_authentication *auth,
const u8 *env_data, size_t env_data_len)
{
- const u8 *key;
+ u8 key[DPP_MAX_HASH_LEN];
size_t key_len;
u8 kek[DPP_MAX_HASH_LEN];
u8 cont_encr_key[DPP_MAX_HASH_LEN];
@@ -1167,10 +1230,12 @@
if (dpp_parse_enveloped_data(env_data, env_data_len, &data) < 0)
return -1;
- /* TODO: For initial testing, use ke as the key. Replace this with a
- * new key once that has been defined. */
- key = auth->ke;
key_len = auth->curve->hash_len;
+ /* password = HKDF-Expand(bk, "Enveloped Data Password", length) */
+ res = dpp_hkdf_expand(key_len, auth->bk, key_len,
+ "Enveloped Data Password", key, key_len);
+ if (res < 0)
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
if (dpp_pbkdf2(data.prf_hash_len, key, key_len, data.salt, 64, 1000,
diff --git a/src/common/dpp_crypto.c b/src/common/dpp_crypto.c
index 8bf2a74..7c48015 100644
--- a/src/common/dpp_crypto.c
+++ b/src/common/dpp_crypto.c
@@ -12,12 +12,14 @@
#include <openssl/err.h>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
+#include <openssl/pem.h>
#include "utils/common.h"
#include "utils/base64.h"
#include "utils/json.h"
#include "common/ieee802_11_defs.h"
#include "crypto/crypto.h"
+#include "crypto/random.h"
#include "crypto/sha384.h"
#include "crypto/sha512.h"
#include "dpp.h"
@@ -129,6 +131,18 @@
}
+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)
{
@@ -855,7 +869,7 @@
"DPP: bk = HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x])",
auth->bk, hash_len);
- /* ke = HKDF-Expand(bkK, "DPP Key", length) */
+ /* ke = HKDF-Expand(bk, "DPP Key", length) */
res = dpp_hkdf_expand(hash_len, auth->bk, hash_len, info_ke, auth->ke,
hash_len);
if (res < 0)
@@ -2256,6 +2270,7 @@
u8 prk[DPP_MAX_HASH_LEN];
const struct dpp_curve_params *curve;
int res = -1;
+ u8 nonces[2 * DPP_MAX_NONCE_LEN];
own_key = dpp_set_keypair(&auth->curve, net_access_key,
net_access_key_len);
@@ -2271,7 +2286,7 @@
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;
}
@@ -2280,6 +2295,13 @@
if (!auth->own_protocol_key)
goto fail;
+ if (random_get_bytes(auth->e_nonce, auth->curve->nonce_len)) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "DPP: E-nonce",
+ auth->e_nonce, auth->curve->nonce_len);
+
/* M = { cR + pR } * CI */
cR = EVP_PKEY_get0_EC_KEY(own_key);
pR = EVP_PKEY_get0_EC_KEY(auth->own_protocol_key);
@@ -2312,10 +2334,12 @@
goto fail;
wpa_hexdump_key(MSG_DEBUG, "DPP: M.x", Mx, curve->prime_len);
- /* ke = HKDF(I-nonce, "dpp reconfig key", M.x) */
+ /* ke = HKDF(C-nonce | E-nonce, "dpp reconfig key", M.x) */
- /* HKDF-Extract(I-nonce, M.x) */
- if (dpp_hmac(curve->hash_len, auth->i_nonce, curve->nonce_len,
+ /* HKDF-Extract(C-nonce | E-nonce, M.x) */
+ os_memcpy(nonces, auth->c_nonce, curve->nonce_len);
+ os_memcpy(&nonces[curve->nonce_len], auth->e_nonce, curve->nonce_len);
+ if (dpp_hmac(curve->hash_len, nonces, 2 * curve->nonce_len,
Mx, curve->prime_len, prk) < 0)
goto fail;
wpa_hexdump_key(MSG_DEBUG, "DPP: PRK", prk, curve->hash_len);
@@ -2325,7 +2349,7 @@
"dpp reconfig key", auth->ke, curve->hash_len) < 0)
goto fail;
wpa_hexdump_key(MSG_DEBUG,
- "DPP: ke = HKDF(I-nonce, \"dpp reconfig key\", M.x)",
+ "DPP: ke = HKDF(C-nonce | E-nonce, \"dpp reconfig key\", M.x)",
auth->ke, curve->hash_len);
res = 0;
@@ -2362,6 +2386,7 @@
u8 prk[DPP_MAX_HASH_LEN];
int res = -1;
const struct dpp_curve_params *curve;
+ u8 nonces[2 * DPP_MAX_NONCE_LEN];
pr = dpp_set_pubkey_point(auth->conf->connector_key,
r_proto, r_proto_len);
@@ -2380,7 +2405,7 @@
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;
}
@@ -2407,10 +2432,12 @@
wpa_hexdump_key(MSG_DEBUG, "DPP: M.x", Mx, curve->prime_len);
- /* ke = HKDF(I-nonce, "dpp reconfig key", M.x) */
+ /* ke = HKDF(C-nonce | E-nonce, "dpp reconfig key", M.x) */
- /* HKDF-Extract(I-nonce, M.x) */
- if (dpp_hmac(curve->hash_len, auth->i_nonce, curve->nonce_len,
+ /* HKDF-Extract(C-nonce | E-nonce, M.x) */
+ os_memcpy(nonces, auth->c_nonce, curve->nonce_len);
+ os_memcpy(&nonces[curve->nonce_len], auth->e_nonce, curve->nonce_len);
+ if (dpp_hmac(curve->hash_len, nonces, 2 * curve->nonce_len,
Mx, curve->prime_len, prk) < 0)
goto fail;
wpa_hexdump_key(MSG_DEBUG, "DPP: PRK", prk, curve->hash_len);
@@ -2420,7 +2447,7 @@
"dpp reconfig key", auth->ke, curve->hash_len) < 0)
goto fail;
wpa_hexdump_key(MSG_DEBUG,
- "DPP: ke = HKDF(I-nonce, \"dpp reconfig key\", M.x)",
+ "DPP: ke = HKDF(C-nonce | E-nonce, \"dpp reconfig key\", M.x)",
auth->ke, curve->hash_len);
res = 0;
@@ -2664,6 +2691,520 @@
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 u8 *pp_key,
+ size_t pp_key_len)
+{
+ const unsigned char *p;
+ EVP_PKEY *csign = NULL, *ppkey = 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;
+
+ if (!pp_key)
+ goto fail;
+ p = pp_key;
+ ppkey = d2i_PUBKEY(NULL, &p, pp_key_len);
+ if (!ppkey)
+ 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;
+ id->pp_key = ppkey;
+ ppkey = NULL;
+fail:
+ EC_POINT_free(e_id);
+ EVP_PKEY_free(csign);
+ EVP_PKEY_free(ppkey);
+ 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 *pp;
+ const EC_POINT *pp_point;
+
+ pp = EVP_PKEY_get0_EC_KEY(id->pp_key);
+ if (!pp)
+ goto fail;
+ pp_point = EC_KEY_get0_public_key(pp);
+ 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 * P_pk */
+ if (!pp_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, pp_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);
+ EVP_PKEY_free(id->pp_key);
+ os_free(id);
+ }
+}
+
+
+EC_POINT * dpp_decrypt_e_id(EVP_PKEY *ppkey, EVP_PKEY *a_nonce,
+ EVP_PKEY *e_prime_id)
+{
+ const EC_KEY *pp_ec, *a_nonce_ec, *e_prime_id_ec;
+ const BIGNUM *pp_bn;
+ const EC_GROUP *group;
+ EC_POINT *e_id = NULL;
+ const EC_POINT *a_nonce_point, *e_prime_id_point;
+ BN_CTX *ctx = NULL;
+
+ if (!ppkey)
+ return NULL;
+
+ /* E-id = E'-id - s_C * A-NONCE */
+ pp_ec = EVP_PKEY_get0_EC_KEY(ppkey);
+ a_nonce_ec = EVP_PKEY_get0_EC_KEY(a_nonce);
+ e_prime_id_ec = EVP_PKEY_get0_EC_KEY(e_prime_id);
+ if (!pp_ec || !a_nonce_ec || !e_prime_id_ec)
+ return NULL;
+ pp_bn = EC_KEY_get0_private_key(pp_ec);
+ group = EC_KEY_get0_group(pp_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 (!pp_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, pp_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..af12467 100644
--- a/src/common/dpp_i.h
+++ b/src/common/dpp_i.h
@@ -73,6 +73,7 @@
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,22 @@
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 *ppkey, 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 */
+ EVP_PKEY *pp_key;
+};
+
/* 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..c4a0273 100644
--- a/src/common/dpp_reconfig.c
+++ b/src/common/dpp_reconfig.c
@@ -34,9 +34,12 @@
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 @@
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;
}
@@ -108,10 +158,10 @@
wpabuf_put_le16(msg, os_strlen(auth->conf->connector));
wpabuf_put_str(msg, auth->conf->connector);
- /* I-nonce */
- wpabuf_put_le16(msg, DPP_ATTR_I_NONCE);
+ /* C-nonce */
+ wpabuf_put_le16(msg, DPP_ATTR_CONFIGURATOR_NONCE);
wpabuf_put_le16(msg, auth->curve->nonce_len);
- wpabuf_put_data(msg, auth->i_nonce, auth->curve->nonce_len);
+ wpabuf_put_data(msg, auth->c_nonce, auth->curve->nonce_len);
wpa_hexdump_buf(MSG_DEBUG,
"DPP: Reconfig Authentication Request frame attributes",
@@ -121,7 +171,9 @@
}
-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 @@
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 @@
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 @@
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->pp_key, 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,16 +287,16 @@
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)) {
- wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce");
+ if (random_get_bytes(auth->c_nonce, auth->curve->nonce_len)) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to generate C-nonce");
goto fail;
}
@@ -224,21 +325,16 @@
int res = -1;
/* Build DPP Reconfig Authentication Response frame attributes */
- clear_len = 2 * (4 + auth->curve->nonce_len) +
+ clear_len = 4 + auth->curve->nonce_len +
4 + wpabuf_len(conn_status);
clear = wpabuf_alloc(clear_len);
if (!clear)
goto fail;
- /* I-nonce (wrapped) */
- wpabuf_put_le16(clear, DPP_ATTR_I_NONCE);
+ /* C-nonce (wrapped) */
+ wpabuf_put_le16(clear, DPP_ATTR_CONFIGURATOR_NONCE);
wpabuf_put_le16(clear, auth->curve->nonce_len);
- wpabuf_put_data(clear, auth->i_nonce, auth->curve->nonce_len);
-
- /* R-nonce (wrapped) */
- wpabuf_put_le16(clear, DPP_ATTR_R_NONCE);
- wpabuf_put_le16(clear, auth->curve->nonce_len);
- wpabuf_put_data(clear, auth->r_nonce, auth->curve->nonce_len);
+ wpabuf_put_data(clear, auth->c_nonce, auth->curve->nonce_len);
/* Connection Status (wrapped) */
wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
@@ -251,6 +347,7 @@
attr_len = 4 + 1 + 4 + 1 +
4 + os_strlen(own_connector) +
+ 4 + auth->curve->nonce_len +
4 + wpabuf_len(pr) +
4 + wpabuf_len(clear) + AES_BLOCK_SIZE;
msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_RESP, attr_len);
@@ -274,6 +371,11 @@
wpabuf_put_le16(msg, os_strlen(own_connector));
wpabuf_put_str(msg, own_connector);
+ /* E-nonce */
+ wpabuf_put_le16(msg, DPP_ATTR_ENROLLEE_NONCE);
+ wpabuf_put_le16(msg, auth->curve->nonce_len);
+ wpabuf_put_data(msg, auth->e_nonce, auth->curve->nonce_len);
+
/* Responder Protocol Key (Pr) */
wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
wpabuf_put_le16(msg, wpabuf_len(pr));
@@ -291,7 +393,7 @@
len[1] = attr_end - attr_start;
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
- /* Wrapped Data: {I-nonce, R-nonce, Connection Status}ke */
+ /* Wrapped Data: {C-nonce, E-nonce, Connection Status}ke */
wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
@@ -329,8 +431,8 @@
const u8 *attr_start, size_t attr_len)
{
struct dpp_authentication *auth = NULL;
- const u8 *trans_id, *version, *i_connector, *i_nonce;
- u16 trans_id_len, version_len, i_connector_len, i_nonce_len;
+ const u8 *trans_id, *version, *i_connector, *c_nonce;
+ u16 trans_id_len, version_len, i_connector_len, c_nonce_len;
struct dpp_signed_connector_info info;
enum dpp_status_error res;
struct json_token *root = NULL, *own_root = NULL, *token;
@@ -364,14 +466,14 @@
wpa_hexdump_ascii(MSG_DEBUG, "DPP: I-Connector",
i_connector, i_connector_len);
- i_nonce = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_NONCE,
- &i_nonce_len);
- if (!i_nonce || i_nonce_len > DPP_MAX_NONCE_LEN) {
+ c_nonce = dpp_get_attr(attr_start, attr_len,
+ DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len);
+ if (!c_nonce || c_nonce_len > DPP_MAX_NONCE_LEN) {
wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid I-Nonce attribute");
+ "DPP: Missing or invalid C-nonce attribute");
goto fail;
}
- wpa_hexdump(MSG_DEBUG, "DPP: I-Nonce", i_nonce, i_nonce_len);
+ wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len);
res = dpp_check_signed_connector(&info, csign_key, csign_key_len,
i_connector, i_connector_len);
@@ -418,26 +520,19 @@
wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
auth->peer_version);
- os_memcpy(auth->i_nonce, i_nonce, i_nonce_len);
+ os_memcpy(auth->c_nonce, c_nonce, c_nonce_len);
if (dpp_reconfig_derive_ke_responder(auth, net_access_key,
net_access_key_len, token) < 0)
goto fail;
- if (i_nonce_len != auth->curve->nonce_len) {
+ if (c_nonce_len != auth->curve->nonce_len) {
wpa_printf(MSG_DEBUG,
- "DPP: Unexpected I-nonce length %u (curve nonce len %zu)",
- i_nonce_len, auth->curve->nonce_len);
+ "DPP: Unexpected C-nonce length %u (curve nonce len %zu)",
+ c_nonce_len, auth->curve->nonce_len);
goto fail;
}
- if (random_get_bytes(auth->r_nonce, auth->curve->nonce_len)) {
- wpa_printf(MSG_ERROR, "DPP: Failed to generate R-nonce");
- goto fail;
- }
- wpa_hexdump_key(MSG_DEBUG, "DPP: R-nonce",
- auth->r_nonce, auth->curve->nonce_len);
-
/* Build Connection Status object */
/* TODO: Get appropriate result value */
/* TODO: ssid64 and channelList */
@@ -462,40 +557,19 @@
}
-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;
@@ -510,27 +584,33 @@
wpabuf_put_le16(clear, 1);
wpabuf_put_u8(clear, auth->peer_version);
- /* I-nonce (wrapped) */
- wpabuf_put_le16(clear, DPP_ATTR_I_NONCE);
+ /* C-nonce (wrapped) */
+ wpabuf_put_le16(clear, DPP_ATTR_CONFIGURATOR_NONCE);
wpabuf_put_le16(clear, auth->curve->nonce_len);
- wpabuf_put_data(clear, auth->i_nonce, auth->curve->nonce_len);
+ wpabuf_put_data(clear, auth->c_nonce, auth->curve->nonce_len);
- /* R-nonce (wrapped) */
- wpabuf_put_le16(clear, DPP_ATTR_R_NONCE);
+ /* E-nonce (wrapped) */
+ wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
wpabuf_put_le16(clear, auth->curve->nonce_len);
- wpabuf_put_data(clear, auth->r_nonce, auth->curve->nonce_len);
+ wpabuf_put_data(clear, auth->e_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 +639,6 @@
msg);
out:
- wpabuf_free(reconfig_flags);
wpabuf_free(clear);
return msg;
fail:
@@ -574,9 +653,9 @@
const u8 *attr_start, size_t attr_len)
{
const u8 *trans_id, *version, *r_connector, *r_proto, *wrapped_data,
- *i_nonce, *r_nonce, *conn_status;
+ *c_nonce, *e_nonce, *conn_status;
u16 trans_id_len, version_len, r_connector_len, r_proto_len,
- wrapped_data_len, i_nonce_len, r_nonce_len, conn_status_len;
+ wrapped_data_len, c_nonce_len, e_nonce_len, conn_status_len;
struct wpabuf *conf = NULL;
char *signed_connector = NULL;
struct dpp_signed_connector_info info;
@@ -634,6 +713,15 @@
wpa_hexdump_ascii(MSG_DEBUG, "DPP: R-Connector",
r_connector, r_connector_len);
+ e_nonce = dpp_get_attr(attr_start, attr_len,
+ DPP_ATTR_ENROLLEE_NONCE, &e_nonce_len);
+ if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
+ dpp_auth_fail(auth, "Missing or invalid E-nonce");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", e_nonce, e_nonce_len);
+ os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
+
r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
&r_proto_len);
if (!r_proto) {
@@ -702,23 +790,14 @@
goto fail;
}
- i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
- &i_nonce_len);
- if (!i_nonce || i_nonce_len != auth->curve->nonce_len ||
- os_memcmp(i_nonce, auth->i_nonce, i_nonce_len) != 0) {
- dpp_auth_fail(auth, "Missing or invalid I-nonce");
+ c_nonce = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len);
+ if (!c_nonce || c_nonce_len != auth->curve->nonce_len ||
+ os_memcmp(c_nonce, auth->c_nonce, c_nonce_len) != 0) {
+ dpp_auth_fail(auth, "Missing or invalid C-nonce");
goto fail;
}
- wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
-
- r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
- &r_nonce_len);
- if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
- dpp_auth_fail(auth, "Missing or invalid R-nonce");
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len);
- os_memcpy(auth->r_nonce, r_nonce, r_nonce_len);
+ wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len);
conn_status = dpp_get_attr(unwrapped, unwrapped_len,
DPP_ATTR_CONN_STATUS, &conn_status_len);
@@ -758,16 +837,16 @@
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;
- u16 trans_id_len, version_len, wrapped_data_len, i_nonce_len,
- r_nonce_len, reconfig_flags_len;
+ const u8 *trans_id, *version, *wrapped_data, *c_nonce, *e_nonce,
+ *reconfig_flags, *status;
+ u16 trans_id_len, version_len, wrapped_data_len, c_nonce_len,
+ e_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 +860,26 @@
}
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",
@@ -825,55 +919,38 @@
goto fail;
}
- i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
- &i_nonce_len);
- if (!i_nonce || i_nonce_len != auth->curve->nonce_len ||
- os_memcmp(i_nonce, auth->i_nonce, i_nonce_len) != 0) {
- dpp_auth_fail(auth, "Missing or invalid I-nonce");
+ c_nonce = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len);
+ if (!c_nonce || c_nonce_len != auth->curve->nonce_len ||
+ os_memcmp(c_nonce, auth->c_nonce, c_nonce_len) != 0) {
+ dpp_auth_fail(auth, "Missing or invalid C-nonce");
goto fail;
}
- wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
+ wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len);
- r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
- &r_nonce_len);
- if (!r_nonce || r_nonce_len != auth->curve->nonce_len ||
- os_memcmp(r_nonce, auth->r_nonce, r_nonce_len) != 0) {
- dpp_auth_fail(auth, "Missing or invalid R-nonce");
+ e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_ENROLLEE_NONCE, &e_nonce_len);
+ if (!e_nonce || e_nonce_len != auth->curve->nonce_len ||
+ os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
+ dpp_auth_fail(auth, "Missing or invalid E-nonce");
goto fail;
}
- wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len);
+ wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", e_nonce, e_nonce_len);
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..7e330d6 100644
--- a/src/common/dpp_tcp.c
+++ b/src/common/dpp_tcp.c
@@ -25,6 +25,9 @@
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 @@
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 */
@@ -46,6 +53,7 @@
struct dpp_global *global;
u8 pkhash[SHA256_MAC_LEN];
struct hostapd_ip_addr ipaddr;
+ void *msg_ctx;
void *cb_ctx;
void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg,
size_t len);
@@ -62,12 +70,18 @@
int sock;
struct dl_list conn; /* struct dpp_connection */
char *configurator_params;
+ enum dpp_netrole netrole;
+ void *msg_ctx;
+ void *cb_ctx;
+ int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
};
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 +95,12 @@
}
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);
}
@@ -110,6 +127,7 @@
ctrl->global = dpp;
os_memcpy(&ctrl->ipaddr, config->ipaddr, sizeof(*config->ipaddr));
os_memcpy(ctrl->pkhash, config->pkhash, SHA256_MAC_LEN);
+ ctrl->msg_ctx = config->msg_ctx;
ctrl->cb_ctx = config->cb_ctx;
ctrl->tx = config->tx;
ctrl->gas_resp_tx = config->gas_resp_tx;
@@ -139,7 +157,12 @@
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 +171,7 @@
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 +262,11 @@
{
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 +287,7 @@
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 +377,8 @@
conn->global = ctrl->global;
conn->relay = ctrl;
+ conn->msg_ctx = ctrl->msg_ctx;
+ conn->cb_ctx = ctrl->global->cb_ctx;
os_memcpy(conn->mac_addr, src, ETH_ALEN);
conn->freq = freq;
@@ -608,8 +631,7 @@
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 +667,7 @@
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 +714,7 @@
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 +726,7 @@
{
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 +738,6 @@
"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 +783,7 @@
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 +813,7 @@
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 +826,7 @@
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 +845,12 @@
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 +863,7 @@
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 +876,21 @@
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 +997,91 @@
}
+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 +1099,7 @@
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 +1124,76 @@
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 +1212,18 @@
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 +1246,40 @@
}
+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 +1295,10 @@
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 +1323,20 @@
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 +1460,15 @@
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,7 +1505,11 @@
conn->global = ctrl->global;
conn->ctrl = ctrl;
+ conn->msg_ctx = ctrl->msg_ctx;
+ conn->cb_ctx = ctrl->cb_ctx;
+ conn->process_conf_obj = ctrl->process_conf_obj;
conn->sock = fd;
+ conn->netrole = ctrl->netrole;
if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
@@ -1327,7 +1534,10 @@
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 +1559,11 @@
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 +1633,11 @@
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->netrole = config->netrole;
+ ctrl->msg_ctx = config->msg_ctx;
+ ctrl->cb_ctx = config->cb_ctx;
+ ctrl->process_conf_obj = config->process_conf_obj;
ctrl->sock = socket(AF_INET, SOCK_STREAM, 0);
if (ctrl->sock < 0)
@@ -1474,6 +1693,69 @@
}
+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..c000aeb 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 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 @@
u8 dst[ETH_ALEN];
u8 dialog_token;
struct gas_server_handler *handler;
+ u16 comeback_delay;
};
struct gas_server {
@@ -61,7 +64,8 @@
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,29 @@
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)
- return;
-
- response = os_zalloc(sizeof(*response));
- if (!response) {
- wpabuf_free(query_resp);
+ if (comeback_delay == 0 && !query_resp) {
+ gas_server_free_response(response);
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 +138,12 @@
/* 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 +170,7 @@
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 +216,15 @@
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 +232,22 @@
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 +261,31 @@
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 +322,11 @@
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 +405,19 @@
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 +468,27 @@
}
+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 +535,9 @@
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 @@
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 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..511e68f 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -415,7 +415,7 @@
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;
@@ -540,13 +540,20 @@
if (center_segment1 ||
(center_segment0 != 0 &&
5000 + center_segment0 * 5 != data->center_freq1 &&
- 2407 + center_segment0 * 5 != data->center_freq1))
+ 2407 + center_segment0 * 5 != data->center_freq1)) {
+ wpa_printf(MSG_ERROR,
+ "20/40 MHz: center segment 0 (=%d) and center freq 1 (=%d) not in sync",
+ center_segment0, data->center_freq1);
return -1;
+ }
break;
case CHANWIDTH_80P80MHZ:
if (center_segment1 == center_segment0 + 4 ||
- center_segment1 == center_segment0 - 4)
+ center_segment1 == center_segment0 - 4) {
+ wpa_printf(MSG_ERROR,
+ "80+80 MHz: center segment 1 only 20 MHz apart");
return -1;
+ }
data->center_freq2 = 5000 + center_segment1 * 5;
/* fall through */
case CHANWIDTH_80MHZ:
@@ -555,8 +562,11 @@
center_segment1) ||
(oper_chwidth == CHANWIDTH_80P80MHZ &&
!center_segment1) ||
- !sec_channel_offset)
+ !sec_channel_offset) {
+ wpa_printf(MSG_ERROR,
+ "80/80+80 MHz: center segment 1 wrong or no second channel offset");
return -1;
+ }
if (!center_segment0) {
if (channel <= 48)
center_segment0 = 42;
@@ -582,16 +592,25 @@
center_segment0 == channel - 2 ||
center_segment0 == channel - 6)
data->center_freq1 = 5000 + center_segment0 * 5;
- else
+ else {
+ wpa_printf(MSG_ERROR,
+ "Wrong coupling between HT and VHT/HE channel setting");
return -1;
+ }
}
break;
case CHANWIDTH_160MHZ:
data->bandwidth = 160;
- if (center_segment1)
+ if (center_segment1) {
+ wpa_printf(MSG_ERROR,
+ "160 MHz: center segment 1 should not be set");
return -1;
- if (!sec_channel_offset)
+ }
+ if (!sec_channel_offset) {
+ wpa_printf(MSG_ERROR,
+ "160 MHz: second channel offset not set");
return -1;
+ }
/*
* Note: HT/VHT config and params are coupled. Check if
* HT40 channel band is in VHT160 channel band configuration.
@@ -605,8 +624,11 @@
center_segment0 == channel - 10 ||
center_segment0 == channel - 14)
data->center_freq1 = 5000 + center_segment0 * 5;
- else
+ else {
+ wpa_printf(MSG_ERROR,
+ "160 MHz: HT40 channel band is not in 160 MHz band");
return -1;
+ }
break;
}
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 6859787..72d7dda 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -136,6 +136,10 @@
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 "
@@ -769,6 +773,98 @@
}
+/* 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;
@@ -1683,7 +1779,9 @@
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)
}
return "UNKNOWN";
#undef S2S
@@ -1781,7 +1879,6 @@
*/
{ HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, P2P_SUPP },
- { HOSTAPD_MODE_IEEE80211A, 130, 36, 161, 4, BW80P80, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, P2P_SUPP },
/*
@@ -1793,6 +1890,12 @@
{ HOSTAPD_MODE_IEEE80211AD, 181, 9, 13, 1, BW4320, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211AD, 182, 17, 20, 1, BW6480, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211AD, 183, 25, 27, 1, BW8640, P2P_SUPP },
+
+ /* Keep the operating class 130 as the last entry as a workaround for
+ * the OneHundredAndThirty Delimiter value used in the Supported
+ * Operating Classes element to indicate the end of the Operating
+ * Classes field. */
+ { HOSTAPD_MODE_IEEE80211A, 130, 36, 161, 4, BW80P80, P2P_SUPP },
{ -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP }
};
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 55f7aa6..98a55ec 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -114,6 +114,7 @@
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 @@
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 @@
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 65cc4df..de41d7f 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -204,7 +204,9 @@
#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
/* Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45) */
#define WLAN_REASON_UNSPECIFIED 1
@@ -476,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
@@ -560,11 +564,14 @@
#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 */
/* bits 0-3: Field length (n-1) */
#define WLAN_RSNX_CAPAB_PROTECTED_TWT 4
#define WLAN_RSNX_CAPAB_SAE_H2E 5
+#define WLAN_RSNX_CAPAB_SAE_PK 6
/* Action frame categories (IEEE Std 802.11-2016, 9.4.1.11, Table 9-76) */
#define WLAN_ACTION_SPECTRUM_MGMT 0
@@ -1325,6 +1332,8 @@
#define MULTI_AP_OUI_TYPE 0x1B
#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)
@@ -2178,23 +2187,30 @@
/* 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
@@ -2355,4 +2371,25 @@
/* 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/ocv.c b/src/common/ocv.c
index 06badfb..4bc2749 100644
--- a/src/common/ocv.c
+++ b/src/common/ocv.c
@@ -95,23 +95,24 @@
}
-int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
- struct wpa_channel_info *ci, int tx_chanwidth,
- int tx_seg1_idx)
+enum oci_verify_result
+ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
+ struct wpa_channel_info *ci, int tx_chanwidth,
+ int tx_seg1_idx)
{
struct oci_info oci;
if (!oci_ie) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
- "OCV failed: did not receive mandatory OCI");
- return -1;
+ "did not receive mandatory OCI");
+ return OCI_NOT_FOUND;
}
if (oci_ie_len != 3) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
- "OCV failed: received OCI of unexpected length (%d)",
+ "received OCI of unexpected length (%d)",
(int) oci_ie_len);
- return -1;
+ return OCI_INVALID_LENGTH;
}
os_memset(&oci, 0, sizeof(oci));
@@ -120,25 +121,25 @@
oci.seg1_idx = oci_ie[2];
if (ocv_derive_all_parameters(&oci) != 0) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
- "OCV failed: unable to interpret received OCI");
- return -1;
+ "unable to interpret received OCI");
+ return OCI_PARSE_ERROR;
}
/* Primary frequency used to send frames to STA must match the STA's */
if ((int) ci->frequency != oci.freq) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
- "OCV failed: primary channel mismatch in received OCI (we use %d but receiver is using %d)",
+ "primary channel mismatch in received OCI (we use %d but receiver is using %d)",
ci->frequency, oci.freq);
- return -1;
+ return OCI_PRIMARY_FREQ_MISMATCH;
}
/* We shouldn't transmit with a higher bandwidth than the STA supports
*/
if (tx_chanwidth > oci.chanwidth) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
- "OCV failed: channel bandwidth mismatch in received OCI (we use %d but receiver only supports %d)",
+ "channel bandwidth mismatch in received OCI (we use %d but receiver only supports %d)",
tx_chanwidth, oci.chanwidth);
- return -1;
+ return OCI_CHANNEL_WIDTH_MISMATCH;
}
/*
@@ -150,9 +151,9 @@
if (tx_chanwidth == 40 && ci->frequency < 2500 &&
ci->sec_channel != oci.sec_channel) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
- "OCV failed: secondary channel mismatch in received OCI (we use %d but receiver is using %d)",
+ "secondary channel mismatch in received OCI (we use %d but receiver is using %d)",
ci->sec_channel, oci.sec_channel);
- return -1;
+ return OCI_SECONDARY_FREQ_MISMATCH;
}
/*
@@ -163,10 +164,10 @@
ci->chanwidth == CHAN_WIDTH_80P80) &&
tx_seg1_idx != oci.seg1_idx) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
- "OCV failed: frequency segment 1 mismatch in received OCI (we use %d but receiver is using %d)",
+ "frequency segment 1 mismatch in received OCI (we use %d but receiver is using %d)",
tx_seg1_idx, oci.seg1_idx);
- return -1;
+ return OCI_SEG_1_INDEX_MISMATCH;
}
- return 0;
+ return OCI_SUCCESS;
}
diff --git a/src/common/ocv.h b/src/common/ocv.h
index 6379d9d..7fa4522 100644
--- a/src/common/ocv.h
+++ b/src/common/ocv.h
@@ -27,14 +27,21 @@
#define OCV_OCI_EXTENDED_LEN (3 + OCV_OCI_LEN)
#define OCV_OCI_KDE_LEN (2 + RSN_SELECTOR_LEN + OCV_OCI_LEN)
+enum oci_verify_result {
+ OCI_SUCCESS, OCI_NOT_FOUND, OCI_INVALID_LENGTH, OCI_PARSE_ERROR,
+ OCI_PRIMARY_FREQ_MISMATCH, OCI_CHANNEL_WIDTH_MISMATCH,
+ OCI_SECONDARY_FREQ_MISMATCH, OCI_SEG_1_INDEX_MISMATCH
+};
+
extern char ocv_errorstr[256];
int ocv_derive_all_parameters(struct oci_info *oci);
int ocv_insert_oci(struct wpa_channel_info *ci, u8 **argpos);
int ocv_insert_oci_kde(struct wpa_channel_info *ci, u8 **argpos);
int ocv_insert_extended_oci(struct wpa_channel_info *ci, u8 *pos);
-int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
- struct wpa_channel_info *ci, int tx_chanwidth,
- int tx_seg1_idx);
+enum oci_verify_result
+ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
+ struct wpa_channel_info *ci, int tx_chanwidth,
+ int tx_seg1_idx);
#endif /* OCV_H */
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index e599b8d..eb6a2c1 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 @@
* 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
@@ -646,6 +662,44 @@
* code immediately prior to triggering cfg80211_disconnected(). The
* attributes used with this event are defined in enum
* qca_wlan_vendor_attr_driver_disconnect_reason.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_CONFIG_TSPEC: This vendor subcommand is used to
+ * add/delete TSPEC for each AC. One command is for one specific AC only.
+ * 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.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_WIFI_FW_STATS: This vendor subcommand is used by
+ * the driver to send opaque data from the firmware to userspace. The
+ * driver sends an event to userspace whenever such data is received from
+ * the firmware.
+ *
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA is used as the attribute to
+ * send this opaque data for this event.
+ *
+ * The format of the opaque data is specific to the particular firmware
+ * version and there is no guarantee of the format remaining same.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_MBSSID_TX_VDEV_STATUS: This acts as an event.
+ * The host driver selects Tx VDEV, and notifies user. The attributes
+ * used with this event are defined in enum
+ * qca_wlan_vendor_attr_mbssid_tx_vdev_status.
+ *
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -825,6 +879,13 @@
QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS_EVENT = 187,
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,
+ QCA_NL80211_VENDOR_SUBCMD_WIFI_FW_STATS = 195,
+ QCA_NL80211_VENDOR_SUBCMD_MBSSID_TX_VDEV_STATUS = 196,
};
enum qca_wlan_vendor_attr {
@@ -855,7 +916,11 @@
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,
@@ -1018,6 +1083,15 @@
*/
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,
@@ -1565,9 +1639,10 @@
};
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),
};
/**
@@ -1695,6 +1770,8 @@
* (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,
@@ -1703,6 +1780,7 @@
QCA_VENDOR_ELEM_RAPS = 3,
QCA_VENDOR_ELEM_MU_EDCA_PARAMS = 4,
QCA_VENDOR_ELEM_BSS_COLOR_CHANGE = 5,
+ QCA_VENDOR_ELEM_ALLPLAY = 6,
};
/**
@@ -2120,6 +2198,141 @@
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_ROAM_REASON = 61,
+ /* 32-bit unsigned value to configure different PHY modes to the
+ * driver/firmware. The possible values are defined in
+ * enum qca_wlan_vendor_phy_mode. The configuration will be reset to
+ * default value, i.e., QCA_WLAN_VENDOR_PHY_MODE_AUTO upon restarting
+ * the driver.
+ */
+ 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.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MSDU_AGGREGATION = 65,
+
+ /* 8-bit unsigned value to configure the maximum number of subframes of
+ * RX MSDU for aggregation. Possible values are 0-31. When set to 0,
+ * it is decided by the hardware.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MSDU_AGGREGATION = 66,
+
+ /* 8-bit unsigned value. This attribute is used to dynamically
+ * enable/disable the LDPC capability of the device. When configured in
+ * the disconnected state, the updated configuration will be considered
+ * for the immediately following connection attempt. If this
+ * configuration is modified while the device is in the connected state,
+ * the LDPC TX will be updated with this configuration immediately,
+ * while the LDPC RX configuration update will take place starting from
+ * the subsequent association attempt.
+ * 1-Enable, 0-Disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LDPC = 67,
+
+ /* 8-bit unsigned value. This attribute is used to dynamically
+ * enable/disable the TX STBC capability of the device. When configured
+ * in the disconnected state, the updated configuration will be
+ * considered for the immediately following connection attempt. If the
+ * connection is formed with TX STBC enabled and if this configuration
+ * is disabled during that association, the TX will be impacted
+ * immediately. Further connection attempts will disable TX STBC.
+ * However, enabling the TX STBC for a connected session with disabled
+ * capability is not allowed and will fail.
+ * 1-Enable, 0-Disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TX_STBC = 68,
+
+ /* 8-bit unsigned value. This attribute is used to dynamically
+ * enable/disable the RX STBC capability of the device. When configured
+ * in the disconnected state, the updated configuration will be
+ * considered for the immediately following connection attempt. If the
+ * configuration is modified in the connected state, there will be no
+ * impact for the current association, but further connection attempts
+ * will use the updated configuration.
+ * 1-Enable, 0-Disable.
+ */
+ 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,
+
+ /* 8-bit unsigned value to configure ANI setting type.
+ * See &enum qca_wlan_ani_setting for possible values.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANI_SETTING = 75,
+ /* 32-bit signed value to configure ANI level. This is used when
+ * ANI settings type is &QCA_WLAN_ANI_SETTING_FIXED.
+ * The set and get of ANI level with &QCA_WLAN_ANI_SETTING_AUTO
+ * is invalid, the driver will return a failure.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANI_LEVEL = 76,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
@@ -2135,6 +2348,16 @@
QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_REPORT_FAIL
/**
+ * enum qca_wlan_ani_setting - ANI setting type
+ * @QCA_WLAN_ANI_SETTING_AUTO: Automatically determine ANI level
+ * @QCA_WLAN_ANI_SETTING_FIXED: Fix ANI level to the dBm parameter
+ */
+enum qca_wlan_ani_setting {
+ QCA_WLAN_ANI_SETTING_AUTO = 0,
+ QCA_WLAN_ANI_SETTING_FIXED = 1,
+};
+
+/**
* enum qca_wlan_vendor_attr_sap_config - Parameters for AP configuration
*
* @QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL: Optional (u8)
@@ -2189,19 +2412,54 @@
/**
* enum qca_wlan_gpio_attr - Parameters for GPIO configuration
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND: Required (u32)
+ * value to specify the GPIO command. Please refer to enum qca_gpio_cmd_type
+ * for the available values.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM: Required (u32)
+ * value to specify the GPIO number.
+ * This is required, when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND is
+ * %QCA_WLAN_VENDOR_GPIO_CONFIG or %QCA_WLAN_VENDOR_GPIO_OUTPUT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_VALUE: Required (u32)
+ * value to specify the GPIO output level. Please refer to enum qca_gpio_value
+ * for the available values.
+ * This is required, when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND is
+ * %QCA_WLAN_VENDOR_GPIO_OUTPUT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PULL_TYPE: Required (u32)
+ * value to specify the GPIO pull type. Please refer to enum qca_gpio_pull_type
+ * for the available values.
+ * This is required, when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND is
+ * %QCA_WLAN_VENDOR_GPIO_CONFIG.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTR_MODE: Required (u32)
+ * value to specify the GPIO interrupt mode. Please refer to enum
+ * qca_gpio_interrupt_mode for the available values.
+ * This is required, when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND is
+ * %QCA_WLAN_VENDOR_GPIO_CONFIG.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_DIR: Required (u32)
+ * value to specify the GPIO direction. Please refer to enum qca_gpio_direction
+ * for the available values.
+ * This is required, when %QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND is
+ * %QCA_WLAN_VENDOR_GPIO_CONFIG.
*/
enum qca_wlan_gpio_attr {
QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INVALID = 0,
/* Unsigned 32-bit attribute for GPIO command */
- QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND,
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND = 1,
/* Unsigned 32-bit attribute for GPIO PIN number to configure */
- QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM,
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM = 2,
/* Unsigned 32-bit attribute for GPIO value to configure */
- QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_VALUE,
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_VALUE = 3,
/* Unsigned 32-bit attribute for GPIO pull type */
- QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PULL_TYPE,
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PULL_TYPE = 4,
/* Unsigned 32-bit attribute for GPIO interrupt mode */
- QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTR_MODE,
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTR_MODE = 5,
+ /* Unsigned 32-bit attribute for GPIO direction to configure */
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_DIR = 6,
/* keep last */
QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_LAST,
@@ -2210,6 +2468,73 @@
};
/**
+ * enum gpio_cmd_type - GPIO configuration command type
+ * @QCA_WLAN_VENDOR_GPIO_CONFIG: Set GPIO configuration info
+ * @QCA_WLAN_VENDOR_GPIO_OUTPUT: Set GPIO output level
+ */
+enum qca_gpio_cmd_type {
+ QCA_WLAN_VENDOR_GPIO_CONFIG = 0,
+ QCA_WLAN_VENDOR_GPIO_OUTPUT = 1,
+};
+
+/**
+ * enum qca_gpio_pull_type - GPIO pull type
+ * @QCA_WLAN_GPIO_PULL_NONE: Set GPIO pull type to none
+ * @QCA_WLAN_GPIO_PULL_UP: Set GPIO pull up
+ * @QCA_WLAN_GPIO_PULL_DOWN: Set GPIO pull down
+ */
+enum qca_gpio_pull_type {
+ QCA_WLAN_GPIO_PULL_NONE = 0,
+ QCA_WLAN_GPIO_PULL_UP = 1,
+ QCA_WLAN_GPIO_PULL_DOWN = 2,
+ QCA_WLAN_GPIO_PULL_MAX,
+};
+
+/**
+ * enum qca_gpio_direction - GPIO direction
+ * @QCA_WLAN_GPIO_INPUT: Set GPIO as input mode
+ * @QCA_WLAN_GPIO_OUTPUT: Set GPIO as output mode
+ * @QCA_WLAN_GPIO_VALUE_MAX: Invalid value
+ */
+enum qca_gpio_direction {
+ QCA_WLAN_GPIO_INPUT = 0,
+ QCA_WLAN_GPIO_OUTPUT = 1,
+ QCA_WLAN_GPIO_DIR_MAX,
+};
+
+/**
+ * enum qca_gpio_value - GPIO Value
+ * @QCA_WLAN_GPIO_LEVEL_LOW: set gpio output level to low
+ * @QCA_WLAN_GPIO_LEVEL_HIGH: set gpio output level to high
+ * @QCA_WLAN_GPIO_LEVEL_MAX: Invalid value
+ */
+enum qca_gpio_value {
+ QCA_WLAN_GPIO_LEVEL_LOW = 0,
+ QCA_WLAN_GPIO_LEVEL_HIGH = 1,
+ QCA_WLAN_GPIO_LEVEL_MAX,
+};
+
+/**
+ * enum gpio_interrupt_mode - GPIO interrupt mode
+ * @QCA_WLAN_GPIO_INTMODE_DISABLE: Disable interrupt trigger
+ * @QCA_WLAN_GPIO_INTMODE_RISING_EDGE: Interrupt with GPIO rising edge trigger
+ * @QCA_WLAN_GPIO_INTMODE_FALLING_EDGE: Interrupt with GPIO falling edge trigger
+ * @QCA_WLAN_GPIO_INTMODE_BOTH_EDGE: Interrupt with GPIO both edge trigger
+ * @QCA_WLAN_GPIO_INTMODE_LEVEL_LOW: Interrupt with GPIO level low trigger
+ * @QCA_WLAN_GPIO_INTMODE_LEVEL_HIGH: Interrupt with GPIO level high trigger
+ * @QCA_WLAN_GPIO_INTMODE_MAX: Invalid value
+ */
+enum qca_gpio_interrupt_mode {
+ QCA_WLAN_GPIO_INTMODE_DISABLE = 0,
+ QCA_WLAN_GPIO_INTMODE_RISING_EDGE = 1,
+ QCA_WLAN_GPIO_INTMODE_FALLING_EDGE = 2,
+ QCA_WLAN_GPIO_INTMODE_BOTH_EDGE = 3,
+ QCA_WLAN_GPIO_INTMODE_LEVEL_LOW = 4,
+ QCA_WLAN_GPIO_INTMODE_LEVEL_HIGH = 5,
+ QCA_WLAN_GPIO_INTMODE_MAX,
+};
+
+/**
* qca_wlan_set_qdepth_thresh_attr - Parameters for setting
* MSDUQ depth threshold per peer per tid in the target
*
@@ -3297,7 +3622,7 @@
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,
@@ -3359,6 +3684,17 @@
*/
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 =
@@ -3706,6 +4042,30 @@
QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_SCHEME_AFTER_LAST - 1,
};
+/**
+ * enum qca_roam_scan_scheme: Scan scheme
+ *
+ * @QCA_ROAM_SCAN_SCHEME_NO_SCAN: No frequencies specified to scan.
+ * Indicates the driver to not scan on a Roam Trigger scenario, but
+ * disconnect. E.g., on a BTM request from the AP the driver/firmware shall
+ * disconnect from the current connected AP by notifying a failure
+ * code in the BTM response.
+ *
+ * @QCA_ROAM_SCAN_SCHEME_PARTIAL_SCAN: Indicates the driver/firmware to
+ * trigger partial frequency scans. These frequencies are the ones learned
+ * or maintained by the driver based on the probability of finding the
+ * BSSIDs in the ESS for which the roaming is triggered.
+ *
+ * @QCA_ROAM_SCAN_SCHEME_FULL_SCAN: Indicates the driver/firmware to
+ * trigger the scan on all the valid frequencies to find better
+ * candidates to roam.
+ */
+enum qca_roam_scan_scheme {
+ QCA_ROAM_SCAN_SCHEME_NO_SCAN = 0,
+ QCA_ROAM_SCAN_SCHEME_PARTIAL_SCAN = 1,
+ QCA_ROAM_SCAN_SCHEME_FULL_SCAN = 2,
+};
+
/*
* enum qca_vendor_roam_triggers: Bitmap of roaming triggers
*
@@ -3726,6 +4086,18 @@
* when BTM Request frame is received from the connected AP.
* @QCA_ROAM_TRIGGER_REASON_BSS_LOAD: Set if the roam has to be triggered
* when the channel utilization is goes above the configured threshold.
+ * @QCA_ROAM_TRIGGER_REASON_USER_TRIGGER: Set if the roam has to be triggered
+ * based on the request from the user (space).
+ * @QCA_ROAM_TRIGGER_REASON_DEAUTH: Set if the roam has to be triggered when
+ * device receives Deauthentication/Disassociation frame from connected AP.
+ * @QCA_ROAM_TRIGGER_REASON_IDLE: Set if the roam has to be triggered when the
+ * device is in idle state (no TX/RX) and suspend mode, if the current RSSI
+ * is determined to be a poor one.
+ * @QCA_ROAM_TRIGGER_REASON_TX_FAILURES: Set if the roam has to be triggered
+ * based on continuous TX Data frame failures to the connected AP.
+ * @QCA_ROAM_TRIGGER_REASON_EXTERNAL_SCAN: Set if the roam has to be triggered
+ * based on the scan results obtained from an external scan (not triggered
+ * to aim roaming).
*
* Set the corresponding roam trigger reason bit to consider it for roam
* trigger.
@@ -3741,6 +4113,11 @@
QCA_ROAM_TRIGGER_REASON_DENSE = 1 << 5,
QCA_ROAM_TRIGGER_REASON_BTM = 1 << 6,
QCA_ROAM_TRIGGER_REASON_BSS_LOAD = 1 << 7,
+ QCA_ROAM_TRIGGER_REASON_USER_TRIGGER = 1 << 8,
+ QCA_ROAM_TRIGGER_REASON_DEAUTH = 1 << 9,
+ QCA_ROAM_TRIGGER_REASON_IDLE = 1 << 10,
+ QCA_ROAM_TRIGGER_REASON_TX_FAILURES = 1 << 11,
+ QCA_ROAM_TRIGGER_REASON_EXTERNAL_SCAN = 1 << 12,
};
/**
@@ -3897,6 +4274,40 @@
*
* Clears the selection criteria configured in the driver when specified
* with clear command.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME: Unsigned 32-bit value.
+ * Represents value of the scan frequency scheme from enum
+ * qca_roam_scan_scheme.
+ * It's an optional attribute. If this attribute is not configured, the
+ * driver shall proceed with default behavior.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_CONNECTED_RSSI_THRESHOLD: Signed 32-bit value in dBm,
+ * signifying the RSSI threshold of the current connected AP, indicating
+ * the driver to trigger roam only when the current connected AP's RSSI
+ * is less than this threshold.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD: Signed 32-bit value in dBm,
+ * signifying the RSSI threshold of the candidate AP, indicating
+ * the driver to trigger roam only to the candidate AP with RSSI
+ * better than this threshold.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_USER_REASON: Unsigned 32-bit value. Represents the
+ * user defined reason code to be sent to the AP in response to AP's
+ * request to trigger the roam if the roaming cannot be triggered.
+ * Applies to all the scenarios of AP assisted roaming (e.g., BTM).
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME_TRIGGERS: Unsigned 32-bit value.
+ * Carries a bitmap of the roam triggers specified in
+ * enum qca_vendor_roam_triggers.
+ * Represents the roam triggers for which the specific scan scheme from
+ * enum qca_roam_scan_scheme has to be applied.
+ * It's an optional attribute. If this attribute is not configured, but
+ * QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME is specified, the scan scheme
+ * specified through QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME is applicable for
+ * all the roams.
+ * If both QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME and
+ * QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME_TRIGGERS are not specified, the
+ * driver shall proceed with the default behavior.
*/
enum qca_vendor_attr_roam_control {
QCA_ATTR_ROAM_CONTROL_ENABLE = 1,
@@ -3907,6 +4318,11 @@
QCA_ATTR_ROAM_CONTROL_FULL_SCAN_PERIOD = 6,
QCA_ATTR_ROAM_CONTROL_TRIGGERS = 7,
QCA_ATTR_ROAM_CONTROL_SELECTION_CRITERIA = 8,
+ QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME = 9,
+ QCA_ATTR_ROAM_CONTROL_CONNECTED_RSSI_THRESHOLD = 10,
+ QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD = 11,
+ QCA_ATTR_ROAM_CONTROL_USER_REASON = 12,
+ QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME_TRIGGERS = 13,
/* keep last */
QCA_ATTR_ROAM_CONTROL_AFTER_LAST,
@@ -3926,7 +4342,7 @@
* 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
@@ -3993,17 +4409,18 @@
* 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
@@ -4038,11 +4455,11 @@
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,
@@ -4078,9 +4495,9 @@
* 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
@@ -4742,9 +5159,9 @@
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,
};
@@ -6471,8 +6888,9 @@
/**
* enum qca_wlan_vendor_thermal_level - Defines various thermal levels
- * configured by userspace to the driver/firmware. The values will be
- * encapsulated in QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL attribute.
+ * configured by userspace to the driver/firmware.
+ * The values can be encapsulated in QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL or
+ * QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_LEVEL attribute.
* The driver/firmware takes actions requested by userspace such as throttling
* wifi TX etc. in order to mitigate high temperature.
*
@@ -6506,8 +6924,9 @@
*/
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE = 1,
/* Userspace uses this attribute to configure thermal level to the
- * driver/firmware. Used in request, u32 attribute, possible values
- * are defined in enum qca_wlan_vendor_thermal_level.
+ * driver/firmware, or get thermal level from the driver/firmware.
+ * Used in request or response, u32 attribute,
+ * possible values are defined in enum qca_wlan_vendor_thermal_level.
*/
QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL = 2,
/* Userspace uses this attribute to configure the time in which the
@@ -6545,6 +6964,9 @@
* resume action.
* @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL: Configure thermal level to
* the driver/firmware.
+ * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_LEVEL: Request to get the current
+ * thermal level from the driver/firmware. The driver should respond with a
+ * thermal level defined in enum qca_wlan_vendor_thermal_level.
*/
enum qca_wlan_vendor_attr_thermal_cmd_type {
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_PARAMS,
@@ -6552,6 +6974,7 @@
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SUSPEND,
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_RESUME,
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_LEVEL,
};
/**
@@ -6634,6 +7057,11 @@
* NLA_FLAG attribute.
*/
QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_RESUME_COMPLETE,
+ /* Thermal level from the driver.
+ * u32 attribute. Possible values are defined in
+ * enum qca_wlan_vendor_thermal_level.
+ */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_LEVEL = 3,
/* keep last */
QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_AFTER_LAST,
@@ -6847,6 +7275,72 @@
QCA_WLAN_VENDOR_ATTR_HE_OMI_AFTER_LAST - 1,
};
+ /**
+ * enum qca_wlan_vendor_phy_mode - Different PHY modes
+ * These values are used with %QCA_WLAN_VENDOR_ATTR_CONFIG_PHY_MODE.
+ *
+ * @QCA_WLAN_VENDOR_PHY_MODE_AUTO: autoselect
+ * @QCA_WLAN_VENDOR_PHY_MODE_2G_AUTO: 2.4 GHz 802.11b/g/n/ax autoselect
+ * @QCA_WLAN_VENDOR_PHY_MODE_5G_AUTO: 5 GHz 802.11a/n/ac/ax autoselect
+ * @QCA_WLAN_VENDOR_PHY_MODE_11A: 5 GHz, OFDM
+ * @QCA_WLAN_VENDOR_PHY_MODE_11B: 2.4 GHz, CCK
+ * @QCA_WLAN_VENDOR_PHY_MODE_11G: 2.4 GHz, OFDM
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AGN: Support 802.11n in both 2.4 GHz and 5 GHz
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NG_HT20: 2.4 GHz, HT20
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40PLUS: 2.4 GHz, HT40 (ext ch +1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40MINUS: 2.4 GHz, HT40 (ext ch -1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40: 2.4 GHz, Auto HT40
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NA_HT20: 5 GHz, HT20
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40PLUS: 5 GHz, HT40 (ext ch +1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40MINUS: 5 GHz, HT40 (ext ch -1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40: 5 GHz, Auto HT40
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT20: 5 GHz, VHT20
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40PLUS: 5 GHz, VHT40 (Ext ch +1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40MINUS: 5 GHz VHT40 (Ext ch -1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40: 5 GHz, VHT40
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80: 5 GHz, VHT80
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80P80: 5 GHz, VHT80+80
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT160: 5 GHz, VHT160
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AX_HE20: HE20
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40: HE40
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40PLUS: HE40 (ext ch +1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40MINUS: HE40 (ext ch -1)
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80: HE80
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80P80: HE 80P80
+ * @QCA_WLAN_VENDOR_PHY_MODE_11AX_HE160: HE160
+ */
+enum qca_wlan_vendor_phy_mode {
+ QCA_WLAN_VENDOR_PHY_MODE_AUTO = 0,
+ QCA_WLAN_VENDOR_PHY_MODE_2G_AUTO = 1,
+ QCA_WLAN_VENDOR_PHY_MODE_5G_AUTO = 2,
+ QCA_WLAN_VENDOR_PHY_MODE_11A = 3,
+ QCA_WLAN_VENDOR_PHY_MODE_11B = 4,
+ QCA_WLAN_VENDOR_PHY_MODE_11G = 5,
+ QCA_WLAN_VENDOR_PHY_MODE_11AGN = 6,
+ QCA_WLAN_VENDOR_PHY_MODE_11NG_HT20 = 7,
+ QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40PLUS = 8,
+ QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40MINUS = 9,
+ QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40 = 10,
+ QCA_WLAN_VENDOR_PHY_MODE_11NA_HT20 = 11,
+ QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40PLUS = 12,
+ QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40MINUS = 13,
+ QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40 = 14,
+ QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT20 = 15,
+ QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40PLUS = 16,
+ QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40MINUS = 17,
+ QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40 = 18,
+ QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80 = 19,
+ QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80P80 = 20,
+ QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT160 = 21,
+ QCA_WLAN_VENDOR_PHY_MODE_11AX_HE20 = 22,
+ QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40 = 23,
+ QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40PLUS = 24,
+ QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40MINUS = 25,
+ QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80 = 26,
+ QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80P80 = 27,
+ QCA_WLAN_VENDOR_PHY_MODE_11AX_HE160 = 28,
+};
+
/* Attributes for data used by
* QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION
*/
@@ -7130,6 +7624,67 @@
*/
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_TWT_REQ_SUPPORT = 37,
+ /* 8-bit unsigned value to configure protection for Management
+ * frames when PMF is enabled for the association.
+ * This attribute is used to configure the testbed device.
+ * 0-use the correct key, 1-use an incorrect key, 2-disable protection.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_PMF_PROTECTION = 38,
+
+ /* Flag attribute to inject Disassociation frame to the connected AP.
+ * This attribute is used to configure the testbed device.
+ */
+ 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,
+
+ /* 8-bit unsigned value to configure the driver/firmware to start or
+ * stop transmitting FILS discovery frames.
+ * 0 - Stop transmitting FILS discovery frames
+ * 1 - Start transmitting FILS discovery frames
+ * This attribute is used to configure the testbed device.
+ * This attribute can be configured only in AP mode and the
+ * configuration is valid until AP restart.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_FILS_DISCOVERY_FRAMES_TX = 44,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX =
@@ -7137,6 +7692,63 @@
};
/**
+ * 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
@@ -7287,7 +7899,8 @@
* 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
@@ -7297,10 +7910,13 @@
* 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.
@@ -7308,40 +7924,113 @@
* 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,
@@ -7356,6 +8045,14 @@
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 =
@@ -7363,24 +8060,83 @@
};
/**
- * 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
+ * @QCA_WLAN_VENDOR_TWT_STATUS_ALREADY_SUSPENDED: TWT session already in
+ * suspend state
+ */
+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,
+ QCA_WLAN_VENDOR_TWT_STATUS_ALREADY_SUSPENDED = 13,
+};
+
+/**
+ * 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,
@@ -7389,6 +8145,28 @@
};
/**
+ * 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
@@ -8321,10 +9099,14 @@
* enum qca_wlan_vendor_attr_oem_data_params - Used by the vendor command/event
* QCA_NL80211_VENDOR_SUBCMD_OEM_DATA.
*
- * @QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA: The binary blob for the vendor
- * command/event QCA_NL80211_VENDOR_SUBCMD_OEM_DATA are carried through this
- * attribute.
- * NLA_BINARY attribute, the max size is 1024 bytes.
+ * @QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA: This NLA_BINARY attribute is
+ * used to set/query the data to/from the firmware. On query, the same
+ * attribute is used to carry the respective data in the reply sent by the
+ * driver to userspace. The request to set/query the data and the format of the
+ * respective data from the firmware are embedded in the attribute. The
+ * maximum size of the attribute payload is 1024 bytes.
+ * Userspace has to set the QCA_WLAN_VENDOR_ATTR_OEM_DATA_RESPONSE_EXPECTED
+ * attribute when the data is queried from the firmware.
*
* @QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO: The binary blob will be routed
* based on this field. This optional attribute is included to specify whether
@@ -8333,11 +9115,16 @@
* command/event.
* This u8 attribute is used to carry information for the device type using
* values defined by enum qca_vendor_oem_device_type.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OEM_DATA_RESPONSE_EXPECTED: This NLA_FLAG attribute
+ * is set when the userspace queries data from the firmware. This attribute
+ * should not be set when userspace sets the OEM data to the firmware.
*/
enum qca_wlan_vendor_attr_oem_data_params {
QCA_WLAN_VENDOR_ATTR_OEM_DATA_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA = 1,
QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO = 2,
+ QCA_WLAN_VENDOR_ATTR_OEM_DATA_RESPONSE_EXPECTED = 3,
/* keep last */
QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_AFTER_LAST,
@@ -8671,6 +9458,36 @@
* 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.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_CONNECT_FAIL_REASON_CODE: u32, used in
+ * STA mode only. The driver uses this attribute to populate the connection
+ * failure reason codes and the values are defined in
+ * enum qca_sta_connect_fail_reason_codes. Userspace applications can send
+ * QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO vendor command after receiving
+ * a connection failure indication from the driver. The driver shall not
+ * include this attribute in response to the
+ * QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO command if there is no connection
+ * failure observed in the last attempted connection.
*/
enum qca_wlan_vendor_attr_get_sta_info {
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_INVALID = 0,
@@ -8712,6 +9529,11 @@
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,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_CONNECT_FAIL_REASON_CODE = 43,
/* keep last */
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_AFTER_LAST,
@@ -8841,4 +9663,352 @@
QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_AFTER_LAST - 1,
};
+/**
+ * enum qca_wlan_tspec_operation - Operation of the config TSPEC request
+ *
+ * Values for %QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_OPERATION.
+ */
+enum qca_wlan_tspec_operation {
+ QCA_WLAN_TSPEC_ADD = 0,
+ QCA_WLAN_TSPEC_DEL = 1,
+ QCA_WLAN_TSPEC_GET = 2,
+};
+
+/**
+ * enum qca_wlan_tspec_direction - Direction in TSPEC
+ * As what is defined in IEEE Std 802.11-2016, Table 9-139.
+ *
+ * Values for %QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_DIRECTION.
+ */
+enum qca_wlan_tspec_direction {
+ QCA_WLAN_TSPEC_DIRECTION_UPLINK = 0,
+ QCA_WLAN_TSPEC_DIRECTION_DOWNLINK = 1,
+ QCA_WLAN_TSPEC_DIRECTION_DIRECT = 2,
+ QCA_WLAN_TSPEC_DIRECTION_BOTH = 3,
+};
+
+/**
+ * enum qca_wlan_tspec_ack_policy - MAC acknowledgement policy in TSPEC
+ * As what is defined in IEEE Std 802.11-2016, Table 9-141.
+ *
+ * Values for %QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_ACK_POLICY.
+ */
+enum qca_wlan_tspec_ack_policy {
+ QCA_WLAN_TSPEC_NORMAL_ACK = 0,
+ QCA_WLAN_TSPEC_NO_ACK = 1,
+ /* Reserved */
+ QCA_WLAN_TSPEC_BLOCK_ACK = 3,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_config_tspec - Defines attributes
+ * used by %QCA_NL80211_VENDOR_SUBCMD_CONFIG_TSPEC vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_OPERATION:
+ * u8 attribute. Specify the TSPEC operation of this request. Possible values
+ * are defined in enum qca_wlan_tspec_operation.
+ * Mandatory attribute for all kinds of config TSPEC requests.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_TSID:
+ * u8 attribute. TS ID. Possible values are 0-7.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD, QCA_WLAN_TSPEC_DEL,
+ * QCA_WLAN_TSPEC_GET. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_DIRECTION:
+ * u8 attribute. Direction of data carried by the TS. Possible values are
+ * defined in enum qca_wlan_tspec_direction.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_APSD:
+ * Flag attribute. Indicate whether APSD is enabled for the traffic associated
+ * with the TS. set - enabled, not set - disabled.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_USER_PRIORITY:
+ * u8 attribute. User priority to be used for the transport of MSDUs/A-MSDUs
+ * belonging to this TS. Possible values are 0-7.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. An optional attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_ACK_POLICY:
+ * u8 attribute. Indicate whether MAC acknowledgements are required for
+ * MPDUs/A-MSDUs belonging to this TS and the form of those acknowledgements.
+ * Possible values are defined in enum qca_wlan_tspec_ack_policy.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_NOMINAL_MSDU_SIZE:
+ * u16 attribute. Specify the nominal size in bytes of MSDUs/A-MSDUs
+ * belonging to this TS.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAXIMUM_MSDU_SIZE:
+ * u16 attribute. Specify the maximum size in bytes of MSDUs/A-MSDUs
+ * belonging to this TS.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MIN_SERVICE_INTERVAL:
+ * u32 attribute. Specify the minimum interval in microseconds between the
+ * start of two successive SPs.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX_SERVICE_INTERVAL:
+ * u32 attribute. Specify the maximum interval in microseconds between the
+ * start of two successive SPs.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_INACTIVITY_INTERVAL:
+ * u32 attribute. Specify the minimum interval in microseconds that can elapse
+ * without arrival or transfer of an MPDU belonging to the TS before this TS
+ * is deleted by the MAC entity at the HC.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_SUSPENSION_INTERVAL:
+ * u32 attribute. Specify the minimum interval in microseconds that can elapse
+ * without arrival or transfer of an MSDU belonging to the TS before the
+ * generation of successive QoS(+)CF-Poll is stopped for this TS. A value of
+ * 0xFFFFFFFF disables the suspension interval. The value of the suspension
+ * interval is always less than or equal to the inactivity interval.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MINIMUM_DATA_RATE:
+ * u32 attribute. Indicate the lowest data rate in bps specified at the MAC
+ * SAP for transport of MSDUs or A-MSDUs belonging to this TS within the
+ * bounds of this TSPEC.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. An optional attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MEAN_DATA_RATE:
+ * u32 attribute. Indicate the average data rate in bps specified at the MAC
+ * SAP for transport of MSDUs or A-MSDUs belonging to this TS within the
+ * bounds of this TSPEC.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. An optional attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_PEAK_DATA_RATE:
+ * u32 attribute. Indicate the maximum allowable data rate in bps specified at
+ * the MAC SAP for transport of MSDUs or A-MSDUs belonging to this TS within
+ * the bounds of this TSPEC.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. An optional attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_BURST_SIZE:
+ * u32 attribute. Specify the maximum burst size in bytes of the MSDUs/A-MSDUs
+ * belonging to this TS that arrive at the MAC SAP at the peak data rate. A
+ * value of 0 indicates that there are no bursts.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. An optional attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MINIMUM_PHY_RATE:
+ * u32 attribute. Indicate the minimum PHY rate in bps for transport of
+ * MSDUs/A-MSDUs belonging to this TS within the bounds of this TSPEC.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. An optional attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_SURPLUS_BANDWIDTH_ALLOWANCE:
+ * u16 attribute. Specify the excess allocation of time (and bandwidth) over
+ * and above the stated application rates required to transport an MSDU/A-MSDU
+ * belonging to the TS in this TSPEC.
+ * Applicable for operation: QCA_WLAN_TSPEC_ADD. A mandatory attribute.
+ */
+enum qca_wlan_vendor_attr_config_tspec {
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_OPERATION = 1,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_TSID = 2,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_DIRECTION = 3,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_APSD = 4,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_USER_PRIORITY = 5,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_ACK_POLICY = 6,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_NOMINAL_MSDU_SIZE = 7,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAXIMUM_MSDU_SIZE = 8,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MIN_SERVICE_INTERVAL = 9,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX_SERVICE_INTERVAL = 10,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_INACTIVITY_INTERVAL = 11,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_SUSPENSION_INTERVAL = 12,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MINIMUM_DATA_RATE = 13,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MEAN_DATA_RATE = 14,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_PEAK_DATA_RATE = 15,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_BURST_SIZE = 16,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MINIMUM_PHY_RATE = 17,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_SURPLUS_BANDWIDTH_ALLOWANCE = 18,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX =
+ 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,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_mbssid_tx_vdev_status - Defines attributes
+ * used by QCA_NL80211_VENDOR_SUBCMD_MBSSID_TX_VDEV_STATUS vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_STATUS_VAL:
+ * u8 attribute. Notify the TX VDEV status. Possible values 0, 1
+ * belonging to MBSSID/EMA_AP configuration. 0 means Non-Tx VDEV,
+ * 1 means Tx VDEV. Mandatory attribute for all MBSSID VDEV status events.
+ */
+enum qca_wlan_vendor_attr_mbssid_tx_vdev_status {
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_STATUS_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_STATUS_VAL = 1,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_STATUS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_STATUS_MAX =
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_STATUS_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_sta_connect_fail_reason_codes - Defines values carried
+ * by QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_CONNECT_FAIL_REASON_CODE vendor
+ * attribute.
+ * @QCA_STA_CONNECT_FAIL_REASON_NO_BSS_FOUND: No Probe Response frame received
+ * for unicast Probe Request frame.
+ * @QCA_STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL: STA failed to send auth request.
+ * @QCA_STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED: AP didn't send ACK for
+ * auth request.
+ * @QCA_STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED: Auth response is not
+ * received from AP.
+ * @QCA_STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL: STA failed to send
+ * Association Request frame.
+ * @QCA_STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED: AP didn't send ACK for
+ * Association Request frame.
+ * @QCA_STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED: Association Response
+ * frame is not received from AP.
+ */
+enum qca_sta_connect_fail_reason_codes {
+ QCA_STA_CONNECT_FAIL_REASON_NO_BSS_FOUND = 1,
+ QCA_STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL = 2,
+ QCA_STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED = 3,
+ QCA_STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED = 4,
+ QCA_STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL = 5,
+ QCA_STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED = 6,
+ QCA_STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED = 7,
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index 1b4ec6d..057e1ce 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -713,6 +713,8 @@
goto fail;
const_time_select_bin(m_is_zero, bin1, bin2, prime_len, bin);
x1 = crypto_bignum_init_set(bin, prime_len);
+ if (!x1)
+ goto fail;
debug_print_bignum("SSWU: x1 = CSEL(l, x1a, x1b)", x1, prime_len);
/* gx1 = x1^3 + a * x1 + b */
@@ -753,6 +755,8 @@
goto fail;
const_time_select_bin(is_qr, bin1, bin2, prime_len, bin);
v = crypto_bignum_init_set(bin, prime_len);
+ if (!v)
+ goto fail;
debug_print_bignum("SSWU: v = CSEL(l, gx1, gx2)", v, prime_len);
/* x = CSEL(l, x1, x2) */
@@ -1052,10 +1056,17 @@
wpa_printf(MSG_DEBUG, "SAE: Derive PT - group %d", group);
+ if (ssid_len > 32)
+ return NULL;
+
pt = os_zalloc(sizeof(*pt));
if (!pt)
return NULL;
+#ifdef CONFIG_SAE_PK
+ os_memcpy(pt->ssid, ssid, ssid_len);
+ pt->ssid_len = ssid_len;
+#endif /* CONFIG_SAE_PK */
pt->group = group;
pt->ec = crypto_ec_init(group);
if (pt->ec) {
@@ -1354,14 +1365,15 @@
identifier) < 0))
return -1;
- sae->tmp->h2e = 0;
+ sae->h2e = 0;
+ sae->pk = 0;
return sae_derive_commit(sae);
}
int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
const u8 *addr1, const u8 *addr2,
- int *rejected_groups)
+ int *rejected_groups, const struct sae_pk *pk)
{
if (!sae->tmp)
return -1;
@@ -1377,6 +1389,11 @@
return -1;
}
+#ifdef CONFIG_SAE_PK
+ os_memcpy(sae->tmp->ssid, pt->ssid, pt->ssid_len);
+ sae->tmp->ssid_len = pt->ssid_len;
+ sae->tmp->ap_pk = pk;
+#endif /* CONFIG_SAE_PK */
sae->tmp->own_addr_higher = os_memcmp(addr1, addr2, ETH_ALEN) > 0;
wpabuf_free(sae->tmp->own_rejected_groups);
sae->tmp->own_rejected_groups = NULL;
@@ -1409,7 +1426,7 @@
return -1;
}
- sae->tmp->h2e = 1;
+ sae->h2e = 1;
return sae_derive_commit(sae);
}
@@ -1515,7 +1532,7 @@
const u8 *salt;
struct wpabuf *rejected_groups = NULL;
u8 keyseed[SAE_MAX_HASH_LEN];
- u8 keys[SAE_MAX_HASH_LEN + SAE_PMK_LEN];
+ u8 keys[2 * SAE_MAX_HASH_LEN + SAE_PMK_LEN];
struct crypto_bignum *tmp;
int ret = -1;
size_t hash_len, salt_len, prime_len = sae->tmp->prime_len;
@@ -1530,15 +1547,18 @@
* KCK || PMK = KDF-Hash-Length(keyseed, "SAE KCK and PMK",
* (commit-scalar + peer-commit-scalar) modulo r)
* PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128)
+ *
+ * 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;
@@ -1589,15 +1609,32 @@
* 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_kdf_hash(hash_len, keyseed, "SAE KCK and PMK",
+ 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->pk &&
+ sae_kdf_hash(hash_len, keyseed, "SAE-PK keys",
+ val, sae->tmp->order_len,
+ keys, 2 * hash_len + SAE_PMK_LEN) < 0)
+ goto fail;
+#endif /* CONFIG_SAE_PK */
forced_memzero(keyseed, sizeof(keyseed));
os_memcpy(sae->tmp->kck, keys, hash_len);
sae->tmp->kck_len = hash_len;
os_memcpy(sae->pmk, keys + hash_len, SAE_PMK_LEN);
os_memcpy(sae->pmkid, val, SAE_PMKID_LEN);
+#ifdef CONFIG_SAE_PK
+ if (sae->pk) {
+ os_memcpy(sae->tmp->kek, keys + hash_len + SAE_PMK_LEN,
+ hash_len);
+ sae->tmp->kek_len = hash_len;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: KEK for SAE-PK",
+ sae->tmp->kek, sae->tmp->kek_len);
+ }
+#endif /* CONFIG_SAE_PK */
forced_memzero(keys, sizeof(keys));
wpa_hexdump_key(MSG_DEBUG, "SAE: KCK",
sae->tmp->kck, sae->tmp->kck_len);
@@ -1632,7 +1669,7 @@
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));
@@ -1673,7 +1710,7 @@
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);
@@ -1683,7 +1720,7 @@
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);
@@ -2189,13 +2226,14 @@
}
-void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
+int sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
{
const u8 *sc;
size_t hash_len;
+ int res;
if (sae->tmp == NULL)
- return;
+ return -1;
hash_len = sae->tmp->kck_len;
@@ -2206,17 +2244,26 @@
sae->send_confirm++;
if (sae->tmp->ec)
- sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
- sae->tmp->own_commit_element_ecc,
- sae->peer_commit_scalar,
- sae->tmp->peer_commit_element_ecc,
- wpabuf_put(buf, hash_len));
+ res = sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
+ sae->tmp->own_commit_element_ecc,
+ sae->peer_commit_scalar,
+ sae->tmp->peer_commit_element_ecc,
+ wpabuf_put(buf, hash_len));
else
- sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
- sae->tmp->own_commit_element_ffc,
- sae->peer_commit_scalar,
- sae->tmp->peer_commit_element_ffc,
- wpabuf_put(buf, hash_len));
+ res = sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
+ sae->tmp->own_commit_element_ffc,
+ sae->peer_commit_scalar,
+ sae->tmp->peer_commit_element_ffc,
+ wpabuf_put(buf, hash_len));
+ if (res)
+ return res;
+
+#ifdef CONFIG_SAE_PK
+ if (sae_write_confirm_pk(sae, buf) < 0)
+ return -1;
+#endif /* CONFIG_SAE_PK */
+
+ return 0;
}
@@ -2270,6 +2317,12 @@
return -1;
}
+#ifdef CONFIG_SAE_PK
+ if (sae_check_confirm_pk(sae, data + 2 + hash_len,
+ len - 2 - hash_len) < 0)
+ return -1;
+#endif /* CONFIG_SAE_PK */
+
return 0;
}
diff --git a/src/common/sae.h b/src/common/sae.h
index 7966d70..2243c0f 100644
--- a/src/common/sae.h
+++ b/src/common/sae.h
@@ -16,11 +16,27 @@
#define SAE_MAX_ECC_PRIME_LEN 66
#define SAE_MAX_HASH_LEN 64
#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN + 255)
+#ifdef CONFIG_SAE_PK
+#define SAE_CONFIRM_MAX_LEN ((2 + SAE_MAX_HASH_LEN) + 1500)
+#else /* CONFIG_SAE_PK */
#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_HASH_LEN)
+#endif /* CONFIG_SAE_PK */
+#define SAE_PK_M_LEN 16
/* Special value returned by sae_parse_commit() */
#define SAE_SILENTLY_DISCARD 65535
+struct sae_pk {
+ struct wpabuf *m;
+ 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 */
+};
+
+
struct sae_temporary_data {
u8 kck[SAE_MAX_HASH_LEN];
size_t kck_len;
@@ -46,8 +62,25 @@
u8 bssid[ETH_ALEN];
struct wpabuf *own_rejected_groups;
struct wpabuf *peer_rejected_groups;
- unsigned int h2e:1;
unsigned int own_addr_higher:1;
+
+#ifdef CONFIG_SAE_PK
+ u8 kek[SAE_MAX_HASH_LEN];
+ size_t kek_len;
+ const struct sae_pk *ap_pk;
+ u8 own_addr[ETH_ALEN];
+ u8 peer_addr[ETH_ALEN];
+ 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;
+#ifdef CONFIG_TESTING_OPTIONS
+ bool omit_pk_elem;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_SAE_PK */
};
struct sae_pt {
@@ -58,6 +91,10 @@
const struct dh_group *dh;
struct crypto_bignum *ffc_pt;
+#ifdef CONFIG_SAE_PK
+ u8 ssid[32];
+ size_t ssid_len;
+#endif /* CONFIG_SAE_PK */
};
enum sae_state {
@@ -74,6 +111,8 @@
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;
};
@@ -86,17 +125,19 @@
const char *identifier, struct sae_data *sae);
int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
const u8 *addr1, const u8 *addr2,
- int *rejected_groups);
+ int *rejected_groups, const struct sae_pk *pk);
int sae_process_commit(struct sae_data *sae);
int sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
const struct wpabuf *token, const char *identifier);
u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
const u8 **token, size_t *token_len, int *allowed_groups,
int h2e);
-void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf);
+int sae_write_confirm(struct sae_data *sae, struct wpabuf *buf);
int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len);
u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group);
const char * sae_state_txt(enum sae_state state);
+size_t sae_ecc_prime_len_2_hash_len(size_t prime_len);
+size_t sae_ffc_prime_len_2_hash_len(size_t prime_len);
struct sae_pt * sae_derive_pt(int *groups, const u8 *ssid, size_t ssid_len,
const u8 *password, size_t password_len,
const char *identifier);
@@ -108,4 +149,24 @@
const u8 *addr1, const u8 *addr2);
void sae_deinit_pt(struct sae_pt *pt);
+/* sae_pk.c */
+#ifdef CONFIG_SAE_PK
+bool sae_pk_valid_password(const char *pw);
+#else /* CONFIG_SAE_PK */
+static inline bool sae_pk_valid_password(const char *pw)
+{
+ return false;
+}
+#endif /* CONFIG_SAE_PK */
+char * sae_pk_base32_encode(const u8 *src, size_t len_bits);
+u8 * sae_pk_base32_decode(const char *src, size_t len, size_t *out_len);
+int sae_pk_set_password(struct sae_data *sae, const char *password);
+void sae_deinit_pk(struct sae_pk *pk);
+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
new file mode 100644
index 0000000..df79e5f
--- /dev/null
+++ b/src/common/sae_pk.c
@@ -0,0 +1,884 @@
+/*
+ * SAE-PK
+ * 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 <stdint.h>
+
+#include "utils/common.h"
+#include "utils/base64.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "crypto/crypto.h"
+#include "crypto/aes.h"
+#include "crypto/aes_siv.h"
+#include "sae.h"
+
+
+/* RFC 4648 base 32 alphabet with lowercase characters */
+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];
+
+ 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] != '-') {
+ wpa_printf(MSG_DEBUG,
+ "SAE-PK: Not a valid password (separator)");
+ return false;
+ }
+ continue;
+ }
+ if (dtable[(u8) pw[pos]] == 0x80) {
+ wpa_printf(MSG_DEBUG,
+ "SAE-PK: Not a valid password (character)");
+ return false;
+ }
+ }
+
+ /* 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;
+ }
+
+ /* 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;
+}
+
+
+static char * add_char(const char *start, char *pos, u8 idx, size_t *bits)
+{
+ if (*bits == 0)
+ return pos;
+ if (*bits > 5)
+ *bits -= 5;
+ else
+ *bits = 0;
+
+ if ((pos - start) % 5 == 4)
+ *pos++ = '-';
+ *pos++ = sae_pk_base32_table[idx];
+ return pos;
+}
+
+
+/* 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;
+ size_t olen, extra_pad, i;
+ u64 block = 0;
+ u8 val;
+ size_t len = (len_bits + 7) / 8;
+ size_t left = len_bits;
+ int j;
+
+ if (len == 0 || len >= SIZE_MAX / 8)
+ return NULL;
+ olen = len * 8 / 5 + 1;
+ olen += olen / 4; /* hyphen separators */
+ pos = out = os_zalloc(olen + 2); /* include room for ChkSum and nul */
+ if (!out)
+ return NULL;
+
+ extra_pad = (5 - len % 5) % 5;
+ for (i = 0; i < len + extra_pad; i++) {
+ val = i < len ? src[i] : 0;
+ block <<= 8;
+ block |= val;
+ if (i % 5 == 4) {
+ for (j = 7; j >= 0; j--)
+ pos = add_char(out, pos,
+ (block >> j * 5) & 0x1f, &left);
+ block = 0;
+ }
+ }
+
+ *pos = d_check_char(out, os_strlen(out));
+
+ return out;
+}
+
+
+u8 * sae_pk_base32_decode(const char *src, size_t len, size_t *out_len)
+{
+ u8 dtable[256], *out, *pos, tmp;
+ u64 block = 0;
+ size_t i, count, olen;
+ int pad = 0;
+ size_t extra_pad;
+
+ os_memset(dtable, 0x80, 256);
+ for (i = 0; sae_pk_base32_table[i]; i++)
+ dtable[(u8) sae_pk_base32_table[i]] = i;
+ dtable['='] = 0;
+
+ count = 0;
+ for (i = 0; i < len; i++) {
+ if (dtable[(u8) src[i]] != 0x80)
+ count++;
+ }
+
+ if (count == 0)
+ return NULL;
+ extra_pad = (8 - count % 8) % 8;
+
+ olen = (count + extra_pad) / 8 * 5;
+ pos = out = os_malloc(olen);
+ if (!out)
+ return NULL;
+
+ count = 0;
+ for (i = 0; i < len + extra_pad; i++) {
+ u8 val;
+
+ if (i >= len)
+ val = '=';
+ else
+ val = src[i];
+ tmp = dtable[val];
+ if (tmp == 0x80)
+ continue;
+
+ if (val == '=')
+ pad++;
+ block <<= 5;
+ block |= tmp;
+ count++;
+ if (count == 8) {
+ *pos++ = (block >> 32) & 0xff;
+ *pos++ = (block >> 24) & 0xff;
+ *pos++ = (block >> 16) & 0xff;
+ *pos++ = (block >> 8) & 0xff;
+ *pos++ = block & 0xff;
+ count = 0;
+ block = 0;
+ if (pad) {
+ /* Leave in all the available bits with zero
+ * padding to full octets from right. */
+ pos -= pad * 5 / 8;
+ break;
+ }
+ }
+ }
+
+ *out_len = pos - out;
+ return out;
+}
+
+
+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, 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 (len < 1 || !sae_pk_valid_password(password))
+ return -1;
+
+ 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;
+ 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;
+}
+
+
+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);
+ }
+}
+
+
+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, b_len;
+
+ /* <m-as-hexdump>:<base64-encoded-DER-encoded-key> */
+
+ pos = os_strchr(val, ':');
+ if (!pos || (pos - val) & 0x01)
+ return NULL;
+ len = (pos - val) / 2;
+ if (len != SAE_PK_M_LEN) {
+ wpa_printf(MSG_INFO, "SAE: Unexpected Modifier M length %zu",
+ len);
+ return NULL;
+ }
+
+ pk = os_zalloc(sizeof(*pk));
+ if (!pk)
+ return NULL;
+ pk->m = wpabuf_alloc(len);
+ if (!pk->m || hexstr2bin(val, wpabuf_put(pk->m, len), len)) {
+ wpa_printf(MSG_INFO, "SAE: Failed to parse m");
+ goto fail;
+ }
+
+ pos++;
+ 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;
+ }
+
+ pk->key = crypto_ec_key_parse_priv(der, der_len);
+ bin_clear_free(der, der_len);
+ if (!pk->key)
+ goto fail;
+ pk->group = crypto_ec_key_group(pk->key);
+ pk->pubkey = crypto_ec_key_get_subject_public_key(pk->key);
+ 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);
+ return NULL;
+}
+
+
+int sae_hash(size_t hash_len, const u8 *data, size_t len, u8 *hash)
+{
+ if (hash_len == 32)
+ return sha256_vector(1, &data, &len, hash);
+#ifdef CONFIG_SHA384
+ if (hash_len == 48)
+ return sha384_vector(1, &data, &len, hash);
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+ if (hash_len == 64)
+ return sha512_vector(1, &data, &len, hash);
+#endif /* CONFIG_SHA512 */
+ return -1;
+}
+
+
+static int sae_pk_hash_sig_data(struct sae_data *sae, size_t hash_len,
+ bool ap, const u8 *m, size_t m_len,
+ const u8 *pubkey, size_t pubkey_len, u8 *hash)
+{
+ struct sae_temporary_data *tmp = sae->tmp;
+ struct wpabuf *sig_data;
+ u8 *pos;
+ int ret = -1;
+
+ /* Signed data for KeyAuth: eleAP || eleSTA || scaAP || scaSTA ||
+ * M || K_AP || AP-BSSID || STA-MAC */
+ sig_data = wpabuf_alloc(tmp->prime_len * 6 + m_len + pubkey_len +
+ 2 * ETH_ALEN);
+ if (!sig_data)
+ goto fail;
+ pos = wpabuf_put(sig_data, 2 * tmp->prime_len);
+ if (crypto_ec_point_to_bin(tmp->ec, ap ? tmp->own_commit_element_ecc :
+ tmp->peer_commit_element_ecc,
+ pos, pos + tmp->prime_len) < 0)
+ goto fail;
+ pos = wpabuf_put(sig_data, 2 * tmp->prime_len);
+ if (crypto_ec_point_to_bin(tmp->ec, ap ? tmp->peer_commit_element_ecc :
+ tmp->own_commit_element_ecc,
+ pos, pos + tmp->prime_len) < 0)
+ goto fail;
+ if (crypto_bignum_to_bin(ap ? tmp->own_commit_scalar :
+ sae->peer_commit_scalar,
+ wpabuf_put(sig_data, tmp->prime_len),
+ tmp->prime_len, tmp->prime_len) < 0 ||
+ crypto_bignum_to_bin(ap ? sae->peer_commit_scalar :
+ tmp->own_commit_scalar,
+ wpabuf_put(sig_data, tmp->prime_len),
+ tmp->prime_len, tmp->prime_len) < 0)
+ goto fail;
+ wpabuf_put_data(sig_data, m, m_len);
+ wpabuf_put_data(sig_data, pubkey, pubkey_len);
+ wpabuf_put_data(sig_data, ap ? tmp->own_addr : tmp->peer_addr,
+ ETH_ALEN);
+ wpabuf_put_data(sig_data, ap ? tmp->peer_addr : tmp->own_addr,
+ ETH_ALEN);
+ wpa_hexdump_buf_key(MSG_DEBUG, "SAE-PK: Data to be signed for KeyAuth",
+ sig_data);
+ if (sae_hash(hash_len, wpabuf_head(sig_data), wpabuf_len(sig_data),
+ hash) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: hash(data to be signed)",
+ hash, hash_len);
+ ret = 0;
+fail:
+ wpabuf_free(sig_data);
+ return ret;
+}
+
+
+int sae_write_confirm_pk(struct sae_data *sae, struct wpabuf *buf)
+{
+ struct sae_temporary_data *tmp = sae->tmp;
+ 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 (!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 writing confirm");
+ return -1;
+ }
+
+ if (!tmp->ec) {
+ /* Only ECC groups are supported for SAE-PK in the current
+ * implementation. */
+ wpa_printf(MSG_INFO,
+ "SAE-PK: SAE commit did not use an ECC group");
+ return -1;
+ }
+
+ 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(key, hash, hash_len);
+ if (!sig)
+ goto fail;
+ wpa_hexdump_buf(MSG_DEBUG, "SAE-PK: KeyAuth = Sig_AP()", sig);
+
+ /* TODO: fragmentation if any of the elements needs it for a group
+ * using sufficiently large primes (none of the currently supported
+ * ones do) */
+
+ encr_mod_len = wpabuf_len(pk->m) + AES_BLOCK_SIZE;
+ 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;
+ }
+
+ /* FILS Public Key element */
+ 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(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(buf, sig);
+
+ /* SAE-PK element */
+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(buf, 4 + encr_mod_len);
+ wpabuf_put_be32(buf, SAE_PK_IE_VENDOR_TYPE);
+ /* 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(sig);
+ return ret;
+
+}
+
+
+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, int group)
+{
+ struct sae_temporary_data *tmp = sae->tmp;
+ u8 *hash_data, *pos;
+ size_t hash_len, hash_data_len;
+ u8 hash[SAE_MAX_HASH_LEN];
+ int res;
+
+ 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 + 19*Lambda/4 - 5)
+ */
+
+ 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)
+ return false;
+ pos = hash_data;
+ os_memcpy(pos, tmp->ssid, tmp->ssid_len);
+ pos += tmp->ssid_len;
+ os_memcpy(pos, m, m_len);
+ pos += m_len;
+ os_memcpy(pos, k_ap, k_ap_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "SAE-PK: SSID || M || K_AP",
+ hash_data, hash_data_len);
+ res = sae_hash(hash_len, hash_data, hash_data_len, hash);
+ bin_clear_free(hash_data, hash_data_len);
+ if (res < 0)
+ return false;
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: Hash(SSID || M || K_AP)",
+ hash, hash_len);
+
+ if (tmp->fingerprint_bits > hash_len * 8) {
+ wpa_printf(MSG_INFO,
+ "SAE-PK: Not enough hash output bits for the fingerprint");
+ return false;
+ }
+ if (tmp->fingerprint_bits % 8) {
+ size_t extra;
+
+ /* Zero out the extra bits in the last octet */
+ extra = 8 - tmp->fingerprint_bits % 8;
+ pos = &hash[tmp->fingerprint_bits / 8];
+ *pos = (*pos >> extra) << extra;
+ }
+ 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;
+ }
+
+ wpa_printf(MSG_DEBUG, "SAE-PK: Valid K_AP fingerprint");
+ return true;
+}
+
+
+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 *k_ap;
+ u8 m[SAE_PK_M_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 (!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 checking confirm");
+ return -1;
+ }
+
+ if (!tmp->ec) {
+ /* Only ECC groups are supported for SAE-PK in the current
+ * implementation. */
+ wpa_printf(MSG_INFO,
+ "SAE-PK: SAE commit did not use an ECC group");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: Received confirm IEs", ies, ies_len);
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_INFO, "SAE-PK: Failed to parse confirm IEs");
+ return -1;
+ }
+ if (!elems.fils_pk || !elems.fils_key_confirm || !elems.sae_pk) {
+ wpa_printf(MSG_INFO,
+ "SAE-PK: Not all mandatory IEs included in confirm");
+ return -1;
+ }
+
+ /* TODO: Fragment reassembly */
+
+ if (elems.sae_pk_len < SAE_PK_M_LEN + AES_BLOCK_SIZE) {
+ wpa_printf(MSG_INFO,
+ "SAE-PK: No room for EncryptedModifier in SAE-PK element");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "SAE-PK: EncryptedModifier",
+ elems.sae_pk, SAE_PK_M_LEN + AES_BLOCK_SIZE);
+
+ if (aes_siv_decrypt(tmp->kek, tmp->kek_len,
+ 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");
+ return -1;
+ }
+ 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 */
+
+ key = crypto_ec_key_parse_pub(k_ap, k_ap_len);
+ if (!key) {
+ wpa_printf(MSG_INFO, "SAE-PK: Failed to parse K_AP");
+ return -1;
+ }
+
+ group = crypto_ec_key_group(key);
+ 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",
+ elems.fils_key_confirm, elems.fils_key_confirm_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);
+ return -1;
+ }
+
+ res = crypto_ec_key_verify_signature(key, hash, hash_len,
+ elems.fils_key_confirm,
+ elems.fils_key_confirm_len);
+ crypto_ec_key_deinit(key);
+
+ if (res != 1) {
+ wpa_printf(MSG_INFO,
+ "SAE-PK: Invalid or incorrect signature in KeyAuth");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "SAE-PK: Valid KeyAuth signature received");
+
+ /* TODO: Store validated public key into network profile */
+
+ return 0;
+}
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 1e7498a..82a5a17 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -1633,7 +1633,8 @@
if (!use_sha384 && sha256_vector(2, addr, len, hash) < 0)
return -1;
os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
- os_memset(r0_key_data, 0, sizeof(r0_key_data));
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
+ forced_memzero(r0_key_data, sizeof(r0_key_data));
return 0;
}
@@ -1670,6 +1671,7 @@
if (!use_sha384 && sha256_vector(4, addr, len, hash) < 0)
return -1;
os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
return 0;
}
@@ -1839,7 +1841,7 @@
wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len);
wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
- os_memset(tmp, 0, sizeof(tmp));
+ forced_memzero(tmp, sizeof(tmp));
return 0;
}
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 354de28..acc2d6c 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -97,6 +97,10 @@
"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 @@
#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 */
@@ -178,7 +184,11 @@
#define DPP_EVENT_CONFOBJ_PSK "DPP-CONFOBJ-PSK "
#define DPP_EVENT_CONNECTOR "DPP-CONNECTOR "
#define DPP_EVENT_C_SIGN_KEY "DPP-C-SIGN-KEY "
+#define DPP_EVENT_PP_KEY "DPP-PP-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 +202,8 @@
#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 "
+#define DPP_EVENT_CHIRP_RX "DPP-CHIRP-RX "
/* MESH events */
#define MESH_GROUP_STARTED "MESH-GROUP-STARTED "
@@ -388,6 +400,10 @@
/* Transition mode disabled indication - followed by bitmap */
#define TRANSITION_DISABLE "TRANSITION-DISABLE "
+/* OCV validation failure; parameters: addr=<src addr>
+ * frame=<saqueryreq/saqueryresp> error=<error string> */
+#define OCV_FAILURE "OCV-FAILURE "
+
#ifndef BIT
#define BIT(x) (1U << (x))
#endif
diff --git a/src/crypto/Makefile b/src/crypto/Makefile
index c40e955..ce09970 100644
--- a/src/crypto/Makefile
+++ b/src/crypto/Makefile
@@ -1,14 +1,3 @@
-all: libcrypto.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libcrypto.a
-
-install:
- @echo Nothing to be made.
-
-
-include ../lib.rules
-
CFLAGS += -DCONFIG_CRYPTO_INTERNAL
CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
@@ -68,8 +57,4 @@
LIB_OBJS += random.o
endif
-
-libcrypto.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index de2b077..7d2ebd6 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -918,4 +918,16 @@
void crypto_ecdh_deinit(struct crypto_ecdh *ecdh);
size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh);
+struct crypto_ec_key;
+
+struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len);
+struct crypto_ec_key * crypto_ec_key_parse_pub(const u8 *der, size_t der_len);
+void crypto_ec_key_deinit(struct crypto_ec_key *key);
+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);
+int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data,
+ size_t len, const u8 *sig, size_t sig_len);
+int crypto_ec_key_group(struct crypto_ec_key *key);
+
#endif /* CRYPTO_H */
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_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 @@
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 47b6ebb..72f93c1 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -21,6 +21,7 @@
#endif /* CONFIG_OPENSSL_CMAC */
#ifdef CONFIG_ECC
#include <openssl/ec.h>
+#include <openssl/x509.h>
#endif /* CONFIG_ECC */
#include "common.h"
@@ -79,6 +80,14 @@
bin_clear_free(ctx, sizeof(*ctx));
}
+
+static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
+{
+ if (pkey->type != EVP_PKEY_EC)
+ return NULL;
+ return pkey->pkey.ec;
+}
+
#endif /* OpenSSL version < 1.1.0 */
static BIGNUM * get_group5_prime(void)
@@ -2174,4 +2183,164 @@
return crypto_ec_prime_len(ecdh->ec);
}
+
+struct crypto_ec_key {
+ EVP_PKEY *pkey;
+ EC_KEY *eckey;
+};
+
+
+struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len)
+{
+ struct crypto_ec_key *key;
+
+ key = os_zalloc(sizeof(*key));
+ if (!key)
+ return NULL;
+
+ key->eckey = d2i_ECPrivateKey(NULL, &der, der_len);
+ if (!key->eckey) {
+ wpa_printf(MSG_INFO, "OpenSSL: d2i_ECPrivateKey() failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ EC_KEY_set_conv_form(key->eckey, POINT_CONVERSION_COMPRESSED);
+
+ key->pkey = EVP_PKEY_new();
+ if (!key->pkey || EVP_PKEY_assign_EC_KEY(key->pkey, key->eckey) != 1) {
+ EC_KEY_free(key->eckey);
+ key->eckey = NULL;
+ goto fail;
+ }
+
+ return key;
+fail:
+ crypto_ec_key_deinit(key);
+ return NULL;
+}
+
+
+struct crypto_ec_key * crypto_ec_key_parse_pub(const u8 *der, size_t der_len)
+{
+ struct crypto_ec_key *key;
+
+ key = os_zalloc(sizeof(*key));
+ if (!key)
+ return NULL;
+
+ key->pkey = d2i_PUBKEY(NULL, &der, der_len);
+ if (!key->pkey) {
+ wpa_printf(MSG_INFO, "OpenSSL: d2i_PUBKEY() failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ key->eckey = EVP_PKEY_get0_EC_KEY(key->pkey);
+ if (!key->eckey)
+ goto fail;
+ return key;
+fail:
+ crypto_ec_key_deinit(key);
+ return NULL;
+}
+
+
+void crypto_ec_key_deinit(struct crypto_ec_key *key)
+{
+ if (key) {
+ EVP_PKEY_free(key->pkey);
+ os_free(key);
+ }
+}
+
+
+struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key)
+{
+ unsigned char *der = NULL;
+ int der_len;
+ struct wpabuf *buf;
+
+ der_len = i2d_PUBKEY(key->pkey, &der);
+ if (der_len <= 0) {
+ wpa_printf(MSG_INFO, "OpenSSL: i2d_PUBKEY() failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return NULL;
+ }
+
+ buf = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
+ return buf;
+}
+
+
+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;
+ size_t sig_len;
+
+ sig_len = EVP_PKEY_size(key->pkey);
+ sig_der = wpabuf_alloc(sig_len);
+ if (!sig_der)
+ return NULL;
+
+ 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);
+ sig_der = NULL;
+ } else {
+ wpabuf_put(sig_der, sig_len);
+ }
+
+ EVP_PKEY_CTX_free(pkctx);
+ return sig_der;
+}
+
+
+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;
+
+ 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 */
+ return -1;
+}
+
+
+int crypto_ec_key_group(struct crypto_ec_key *key)
+{
+ const EC_GROUP *group;
+ int nid;
+
+ group = EC_KEY_get0_group(key->eckey);
+ if (!group)
+ return -1;
+ nid = EC_GROUP_get_curve_name(group);
+ switch (nid) {
+ case NID_X9_62_prime256v1:
+ return 19;
+ case NID_secp384r1:
+ return 20;
+ case NID_secp521r1:
+ return 21;
+ }
+ return -1;
+}
+
#endif /* CONFIG_ECC */
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 @@
*/
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 7ee371a..a789455 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -279,6 +279,7 @@
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];
@@ -1643,6 +1644,7 @@
os_free(conn->domain_match);
os_free(conn->check_cert_subject);
os_free(conn->session_ticket);
+ os_free(conn->peer_subject);
os_free(conn);
}
@@ -2597,6 +2599,11 @@
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;
}
@@ -3006,16 +3013,12 @@
/* Explicit request to enable TLS versions even if needing to
* override systemwide policies. */
- if (flags & TLS_CONN_ENABLE_TLSv1_0) {
+ if (flags & TLS_CONN_ENABLE_TLSv1_0)
version = TLS1_VERSION;
- } else if (flags & TLS_CONN_ENABLE_TLSv1_1) {
- if (!(flags & TLS_CONN_DISABLE_TLSv1_0))
- version = TLS1_1_VERSION;
- } else if (flags & TLS_CONN_ENABLE_TLSv1_2) {
- if (!(flags & (TLS_CONN_DISABLE_TLSv1_0 |
- TLS_CONN_DISABLE_TLSv1_1)))
- version = TLS1_2_VERSION;
- }
+ else if (flags & TLS_CONN_ENABLE_TLSv1_1)
+ version = TLS1_1_VERSION;
+ else if (flags & TLS_CONN_ENABLE_TLSv1_2)
+ version = TLS1_2_VERSION;
if (!version) {
wpa_printf(MSG_DEBUG,
"OpenSSL: Invalid TLS version configuration");
@@ -3029,6 +3032,18 @@
}
}
#endif /* >= 1.1.0 */
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
+ !defined(LIBRESSL_VERSION_NUMBER) && \
+ !defined(OPENSSL_IS_BORINGSSL)
+ if ((flags & (TLS_CONN_ENABLE_TLSv1_0 | TLS_CONN_ENABLE_TLSv1_1)) &&
+ SSL_get_security_level(ssl) >= 2) {
+ /*
+ * Need to drop to security level 1 to allow TLS versions older
+ * than 1.2 to be used when explicitly enabled in configuration.
+ */
+ SSL_set_security_level(conn->ssl, 1);
+ }
+#endif
#ifdef CONFIG_SUITEB
#ifdef OPENSSL_IS_BORINGSSL
@@ -3198,7 +3213,11 @@
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 |
@@ -3259,8 +3278,36 @@
"OK");
return 0;
} else if (client_cert_blob) {
+#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20901000L
tls_show_errors(MSG_DEBUG, __func__,
"SSL_use_certificate_ASN1 failed");
+#else
+ 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;
+#endif
}
if (client_cert == NULL)
@@ -3767,6 +3814,17 @@
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) {
@@ -5667,3 +5725,19 @@
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/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c
index 11e6582..b8a7665 100644
--- a/src/crypto/tls_wolfssl.c
+++ b/src/crypto/tls_wolfssl.c
@@ -19,6 +19,7 @@
#include <wolfssl/ssl.h>
#include <wolfssl/error-ssl.h>
#include <wolfssl/wolfcrypt/asn.h>
+#include <wolfssl/openssl/x509v3.h>
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
#define HAVE_AESGCM
@@ -576,7 +577,7 @@
static int tls_match_alt_subject_component(WOLFSSL_X509 *cert, int type,
const char *value, size_t len)
{
- WOLFSSL_ASN1_OBJECT *gen;
+ WOLFSSL_GENERAL_NAME *gen;
void *ext;
int found = 0;
int i;
@@ -585,14 +586,15 @@
for (i = 0; ext && i < wolfSSL_sk_num(ext); i++) {
gen = wolfSSL_sk_value(ext, i);
- if (gen->type != type)
+ if (!gen || gen->type != type)
continue;
- if (os_strlen((char *) gen->obj) == len &&
- os_memcmp(value, gen->obj, len) == 0)
+ if ((size_t) wolfSSL_ASN1_STRING_length(gen->d.ia5) == len &&
+ os_memcmp(value, wolfSSL_ASN1_STRING_data(gen->d.ia5),
+ len) == 0)
found++;
}
- wolfSSL_sk_ASN1_OBJECT_free(ext);
+ wolfSSL_sk_GENERAL_NAME_free(ext);
return found;
}
@@ -676,7 +678,7 @@
static int tls_match_suffix_helper(WOLFSSL_X509 *cert, const char *match,
size_t match_len, int full)
{
- WOLFSSL_ASN1_OBJECT *gen;
+ WOLFSSL_GENERAL_NAME *gen;
void *ext;
int i;
int j;
@@ -690,21 +692,23 @@
for (j = 0; ext && j < wolfSSL_sk_num(ext); j++) {
gen = wolfSSL_sk_value(ext, j);
- if (gen->type != ASN_DNS_TYPE)
+ if (!gen || gen->type != ASN_DNS_TYPE)
continue;
dns_name++;
wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName",
- gen->obj, os_strlen((char *)gen->obj));
- if (domain_suffix_match((const char *) gen->obj,
- os_strlen((char *) gen->obj), match,
- match_len, full) == 1) {
+ wolfSSL_ASN1_STRING_data(gen->d.ia5),
+ wolfSSL_ASN1_STRING_length(gen->d.ia5));
+ if (domain_suffix_match(
+ (const char *) wolfSSL_ASN1_STRING_data(gen->d.ia5),
+ wolfSSL_ASN1_STRING_length(gen->d.ia5), match,
+ match_len, full) == 1) {
wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
full ? "Match" : "Suffix match");
wolfSSL_sk_ASN1_OBJECT_free(ext);
return 1;
}
}
- wolfSSL_sk_ASN1_OBJECT_free(ext);
+ wolfSSL_sk_GENERAL_NAME_free(ext);
if (dns_name) {
wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
@@ -858,7 +862,7 @@
struct tls_context *context = conn->context;
char *alt_subject[TLS_MAX_ALT_SUBJECT];
int alt, num_alt_subject = 0;
- WOLFSSL_ASN1_OBJECT *gen;
+ WOLFSSL_GENERAL_NAME *gen;
void *ext;
int i;
#ifdef CONFIG_SHA256
@@ -899,12 +903,14 @@
if (num_alt_subject == TLS_MAX_ALT_SUBJECT)
break;
gen = wolfSSL_sk_value((void *) ext, i);
- if (gen->type != GEN_EMAIL &&
- gen->type != GEN_DNS &&
- gen->type != GEN_URI)
+ if (!gen ||
+ (gen->type != GEN_EMAIL &&
+ gen->type != GEN_DNS &&
+ gen->type != GEN_URI))
continue;
- pos = os_malloc(10 + os_strlen((char *) gen->obj) + 1);
+ pos = os_malloc(10 + wolfSSL_ASN1_STRING_length(gen->d.ia5) +
+ 1);
if (!pos)
break;
alt_subject[num_alt_subject++] = pos;
@@ -924,11 +930,12 @@
break;
}
- os_memcpy(pos, gen->obj, os_strlen((char *)gen->obj));
- pos += os_strlen((char *)gen->obj);
+ os_memcpy(pos, wolfSSL_ASN1_STRING_data(gen->d.ia5),
+ wolfSSL_ASN1_STRING_length(gen->d.ia5));
+ pos += wolfSSL_ASN1_STRING_length(gen->d.ia5);
*pos = '\0';
}
- wolfSSL_sk_ASN1_OBJECT_free(ext);
+ wolfSSL_sk_GENERAL_NAME_free(ext);
for (alt = 0; alt < num_alt_subject; alt++)
ev.peer_cert.altsubject[alt] = alt_subject[alt];
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 350c1cb..e8defab 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -197,6 +197,7 @@
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)
@@ -1930,6 +1931,8 @@
/** 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) \
@@ -4384,13 +4387,13 @@
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_bsd.c b/src/drivers/driver_bsd.c
index 5adee13..a29d2c8 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -137,7 +137,9 @@
ireq->i_data = arg;
if (ioctl(drv->global->sock, SIOCG80211, ireq) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCG80211, op=%u, "
+ int level = drv->if_removed ? MSG_DEBUG : MSG_ERROR;
+
+ wpa_printf(level, "ioctl[SIOCG80211, op=%u, "
"arg_len=%u]: %s", op, arg_len, strerror(errno));
return -1;
}
@@ -1468,6 +1470,9 @@
drv->global = priv;
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ /* Set the interface as removed until proven to work. */
+ drv->if_removed = 1;
+
if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) {
wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s",
__func__, strerror(errno));
@@ -1495,6 +1500,9 @@
if (bsd_get_iface_flags(drv) < 0)
goto fail;
+ /* Proven to work, lets go! */
+ drv->if_removed = 0;
+
drv->opmode = get80211opmode(drv);
dl_list_add(&drv->global->ifaces, &drv->list);
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 @@
#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_macsec_linux.c b/src/drivers/driver_macsec_linux.c
index 36a0757..3dba13c 100644
--- a/src/drivers/driver_macsec_linux.c
+++ b/src/drivers/driver_macsec_linux.c
@@ -712,6 +712,9 @@
if (!msg)
return ret;
+ if (nla_put_rxsc_config(msg, mka_sci_u64(&sa->sc->sci)))
+ goto nla_put_failure;
+
nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
if (!nest)
goto nla_put_failure;
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 5a760ff..4295f0c 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -280,6 +280,43 @@
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;
@@ -354,7 +391,9 @@
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;
@@ -392,7 +431,15 @@
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,
@@ -432,10 +479,13 @@
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);
}
@@ -449,7 +499,10 @@
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.
*
@@ -471,7 +524,8 @@
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);
}
@@ -539,7 +593,8 @@
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;
@@ -656,7 +711,8 @@
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;
}
@@ -673,7 +729,8 @@
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;
}
@@ -689,7 +746,8 @@
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);
}
@@ -709,7 +767,8 @@
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)",
@@ -1409,7 +1468,7 @@
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) {
@@ -1443,7 +1502,7 @@
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) {
@@ -1546,7 +1605,7 @@
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);
}
@@ -1603,7 +1662,8 @@
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);
}
@@ -1667,7 +1727,7 @@
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);
}
@@ -1716,7 +1776,7 @@
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;
}
@@ -1752,7 +1812,8 @@
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;
@@ -2117,6 +2178,11 @@
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;
@@ -2127,17 +2193,20 @@
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);
@@ -2193,7 +2262,8 @@
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)",
@@ -2378,7 +2448,8 @@
ret = -1;
/* Radio Measurement - Radio Measurement Request */
- if (nl80211_register_action_frame(bss, (u8 *) "\x05\x00", 2) < 0)
+ if (!drv->no_rrm &&
+ nl80211_register_action_frame(bss, (u8 *) "\x05\x00", 2) < 0)
ret = -1;
/* Radio Measurement - Link Measurement Request */
@@ -2386,6 +2457,10 @@
(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;
@@ -2432,7 +2507,8 @@
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)",
@@ -2586,7 +2662,7 @@
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,
@@ -2601,7 +2677,7 @@
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",
@@ -2672,7 +2748,8 @@
}
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));
@@ -2797,7 +2874,7 @@
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);
}
@@ -3121,7 +3198,7 @@
" %d VHT: %d BW: %d\n",
params->hw_mode, params->ht_enabled, params->ht40_enabled,
params->vht_enabled, params->ch_width);
- 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: Failed to invoke vendor"
" driver ACS function: %s\n",
@@ -3151,7 +3228,7 @@
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)",
@@ -3191,7 +3268,7 @@
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));
@@ -3357,7 +3434,8 @@
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)
@@ -3419,7 +3497,7 @@
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",
@@ -3543,9 +3621,10 @@
}
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)",
@@ -3793,7 +3872,7 @@
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,
@@ -4071,7 +4150,7 @@
return -ENOBUFS;
}
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
@@ -4115,7 +4194,7 @@
}
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));
@@ -4167,7 +4246,7 @@
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)",
@@ -4292,7 +4371,7 @@
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:
@@ -4581,7 +4660,7 @@
#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));
@@ -4750,7 +4829,7 @@
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;
@@ -5028,7 +5107,7 @@
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 "
@@ -5100,7 +5179,7 @@
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));
@@ -5131,7 +5210,7 @@
}
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);
}
@@ -5211,7 +5290,7 @@
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:
@@ -5366,8 +5445,10 @@
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,
@@ -5386,11 +5467,22 @@
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;
}
@@ -5542,7 +5634,7 @@
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;
@@ -5564,7 +5656,7 @@
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;
@@ -5610,7 +5702,7 @@
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));
@@ -5744,7 +5836,7 @@
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)",
@@ -6146,7 +6238,7 @@
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 "
@@ -6262,7 +6354,7 @@
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,
@@ -6293,7 +6385,7 @@
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;
@@ -6554,7 +6646,7 @@
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)",
@@ -6619,7 +6711,7 @@
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);
}
@@ -6642,7 +6734,7 @@
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: "
@@ -6670,7 +6762,7 @@
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 "
@@ -6692,7 +6784,7 @@
* 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));
@@ -6901,7 +6993,8 @@
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);
}
@@ -6958,7 +7051,7 @@
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);
@@ -6984,14 +7077,14 @@
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)",
@@ -7596,8 +7689,10 @@
drv->global->if_add_wdevid = p2pdev_info.wdev_id;
drv->global->if_add_wdevid_set = p2pdev_info.wdev_id_set;
- if (!is_zero_ether_addr(p2pdev_info.macaddr))
+ if (!is_zero_ether_addr(p2pdev_info.macaddr)) {
os_memcpy(if_addr, p2pdev_info.macaddr, ETH_ALEN);
+ os_memcpy(drv->global->p2p_perm_addr, p2pdev_info.macaddr, ETH_ALEN);
+ }
wpa_printf(MSG_DEBUG, "nl80211: New P2P Device interface %s (0x%llx) created",
ifname,
(long long unsigned int) p2pdev_info.wdev_id);
@@ -7838,7 +7933,7 @@
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 "
@@ -7945,7 +8040,7 @@
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));
@@ -7993,7 +8088,7 @@
}
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",
@@ -8033,7 +8128,7 @@
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: "
@@ -8130,7 +8225,7 @@
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));
@@ -8227,7 +8322,7 @@
}
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);
}
@@ -8265,7 +8360,7 @@
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);
}
@@ -8328,15 +8423,34 @@
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;
+ if (os_strstr(param, "no_rrm=1")) {
+ drv->no_rrm = 1;
+
+ if (!bss->in_deinit && !is_ap_interface(drv->nlmode) &&
+ !is_mesh_interface(drv->nlmode)) {
+ nl80211_mgmt_unsubscribe(bss, "no_rrm=1");
+ if (nl80211_mgmt_subscribe_non_ap(bss) < 0)
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to re-register Action frame processing - ignore for now");
+ }
+ }
+
return 0;
}
@@ -8451,7 +8565,7 @@
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);
}
@@ -8516,7 +8630,7 @@
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);
}
@@ -8681,7 +8795,7 @@
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)
@@ -8721,7 +8835,7 @@
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");
@@ -8788,7 +8902,7 @@
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)",
@@ -8814,7 +8928,7 @@
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)",
@@ -8874,7 +8988,7 @@
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: "
@@ -8921,7 +9035,7 @@
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);
@@ -8971,7 +9085,7 @@
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));
@@ -9005,7 +9119,7 @@
return ret;
}
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
@@ -9031,7 +9145,7 @@
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 */
@@ -9174,7 +9288,7 @@
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));
@@ -9202,7 +9316,7 @@
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)",
@@ -9407,7 +9521,7 @@
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);
@@ -9558,7 +9672,7 @@
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));
@@ -9599,7 +9713,7 @@
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));
@@ -9626,7 +9740,7 @@
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));
@@ -9711,7 +9825,8 @@
* 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);
@@ -9726,7 +9841,8 @@
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);
@@ -9755,7 +9871,7 @@
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");
@@ -9790,7 +9906,8 @@
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;
@@ -9837,7 +9954,7 @@
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");
@@ -9876,7 +9993,7 @@
}
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);
}
@@ -9904,15 +10021,15 @@
}
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;
@@ -9920,7 +10037,8 @@
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)
@@ -9960,7 +10078,7 @@
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);
@@ -9998,7 +10116,7 @@
}
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 */
@@ -10009,10 +10127,45 @@
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int new_addr = addr != NULL;
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+ struct nl_msg *msg;
+ struct nlattr *params;
+ int ret;
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
+ wpa_printf(MSG_DEBUG, "Enter: %s", __FUNCTION__);
if (TEST_FAIL())
return -1;
+ if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) {
+#ifdef CONFIG_DRIVER_NL80211_BRCM
+ if (!addr ) {
+ addr = drv->global->p2p_perm_addr;
+ }
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ BRCM_VENDOR_SUBCMD_SET_MAC) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put(msg, BRCM_ATTR_DRIVER_MAC_ADDR, ETH_ALEN, addr)) {
+ wpa_printf(MSG_ERROR, "failed to put p2p randmac");
+ nl80211_nlmsg_clear(msg);
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+ nla_nest_end(msg, params);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_ERROR, "nl80211: p2p set macaddr failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ }
+ memcpy(bss->addr, addr, ETH_ALEN);
+ return ret;
+#else
+ return -ENOTSUP;
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
+ }
if (!addr)
addr = drv->perm_addr;
@@ -10022,27 +10175,26 @@
if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, addr) < 0)
{
wpa_printf(MSG_DEBUG,
- "nl80211: failed to set_mac_addr for %s to " MACSTR,
- bss->ifname, MAC2STR(addr));
+ "nl80211: failed to set_mac_addr for %s to " MACSTR,
+ bss->ifname, MAC2STR(addr));
if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
- 1) < 0) {
+ 1) < 0) {
wpa_printf(MSG_DEBUG,
- "nl80211: Could not restore interface UP after failed set_mac_addr");
+ "nl80211: Could not restore interface UP after failed set_mac_addr");
}
return -1;
}
wpa_printf(MSG_DEBUG, "nl80211: set_mac_addr for %s to " MACSTR,
- bss->ifname, MAC2STR(addr));
+ bss->ifname, MAC2STR(addr));
drv->addr_changed = new_addr;
os_memcpy(bss->addr, addr, ETH_ALEN);
if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1) < 0)
{
wpa_printf(MSG_DEBUG,
- "nl80211: Could not restore interface UP after set_mac_addr");
+ "nl80211: Could not restore interface UP after set_mac_addr");
}
-
return 0;
}
@@ -10167,7 +10319,7 @@
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)",
@@ -10225,7 +10377,7 @@
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));
@@ -10259,7 +10411,7 @@
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)",
@@ -10671,7 +10823,7 @@
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",
@@ -10718,7 +10870,7 @@
}
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",
@@ -10851,7 +11003,8 @@
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, ¶m);
+ ret = send_and_recv_msgs(drv, msg, preferred_freq_info_handler, ¶m,
+ NULL, NULL);
if (ret) {
wpa_printf(MSG_ERROR,
"%s: err in send_and_recv_msgs", __func__);
@@ -10903,7 +11056,7 @@
}
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",
@@ -10959,7 +11112,7 @@
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,
@@ -10994,7 +11147,7 @@
return -1;
}
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
@@ -11033,7 +11186,7 @@
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,
@@ -11226,7 +11379,7 @@
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,
@@ -11279,7 +11432,7 @@
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,
@@ -11482,7 +11635,7 @@
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,
@@ -11525,7 +11678,7 @@
(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,
@@ -11565,7 +11718,7 @@
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 &&
@@ -11731,7 +11884,7 @@
.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 895f9d7..0db7d55 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -33,8 +33,8 @@
struct nl_sock *nl;
int nl80211_id;
int ioctl_sock; /* socket for ioctl() use */
-
struct nl_sock *nl_event;
+ u8 p2p_perm_addr[ETH_ALEN];
};
struct nl80211_wiphy_data {
@@ -173,6 +173,7 @@
unsigned int add_sta_node_vendor_cmd_avail:1;
unsigned int control_port_ap:1;
unsigned int multicast_registrations:1;
+ unsigned int no_rrm:1;
u64 vendor_scan_cookie;
u64 remain_on_chan_cookie;
@@ -180,6 +181,7 @@
#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;
@@ -230,7 +232,9 @@
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 435df11..416531f 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -51,7 +51,8 @@
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;
@@ -621,6 +622,10 @@
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))
@@ -1068,7 +1073,7 @@
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)
@@ -1174,7 +1179,8 @@
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;
}
@@ -1261,7 +1267,8 @@
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;
@@ -1806,6 +1813,13 @@
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);
+ }
}
@@ -1948,7 +1962,10 @@
for (m = 0; m < *num_modes; m++) {
if (!modes[m].num_channels)
continue;
- if (modes[m].channels[0].freq < 4000) {
+ if (modes[m].channels[0].freq < 2000) {
+ modes[m].num_channels = 0;
+ continue;
+ } else if (modes[m].channels[0].freq < 4000) {
modes[m].mode = HOSTAPD_MODE_IEEE80211B;
for (i = 0; i < modes[m].num_rates; i++) {
if (modes[m].rates[i] > 200) {
@@ -2336,7 +2353,8 @@
}
}
- return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
+ return send_and_recv_msgs(drv, msg, nl80211_get_reg, results,
+ NULL, NULL);
}
@@ -2425,7 +2443,8 @@
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 0454d29..680d426 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -22,6 +22,12 @@
#include "common/brcm_vendor.h"
#endif /* CONFIG_DRIVER_NL80211_BRCM */
+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;
@@ -140,6 +146,8 @@
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";
}
@@ -700,6 +708,16 @@
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;
@@ -2653,6 +2671,29 @@
}
+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)
{
@@ -2871,6 +2912,15 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
#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 @@
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 @@
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 @@
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 @@
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 5e500d7..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 @@
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 @@
* 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 @@
* 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 @@
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 @@
* 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 @@
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 @@
* (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 @@
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 @@
* @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 @@
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 @@
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 @@
* (%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 attribute, 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 @@
* &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 @@
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 @@
#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 @@
* @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 @@
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 @@
* @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 @@
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 @@
* @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 @@
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_common/Makefile b/src/eap_common/Makefile
index f00b438..fd058a0 100644
--- a/src/eap_common/Makefile
+++ b/src/eap_common/Makefile
@@ -1,13 +1,3 @@
-all: libeap_common.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libeap_common.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
LIB_OBJS= \
chap.o \
eap_common.o \
@@ -25,7 +15,4 @@
eap_wsc_common.o \
ikev2_common.o
-libeap_common.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/eap_peer/.gitignore b/src/eap_peer/.gitignore
new file mode 100644
index 0000000..140f8cf
--- /dev/null
+++ b/src/eap_peer/.gitignore
@@ -0,0 +1 @@
+*.so
diff --git a/src/eap_peer/Makefile b/src/eap_peer/Makefile
index 6531ccd..bdbead6 100644
--- a/src/eap_peer/Makefile
+++ b/src/eap_peer/Makefile
@@ -1,23 +1,13 @@
-all: libeap_peer.a
-
-clean:
- rm -f *~ *.o *.so *.d *.gcno *.gcda *.gcov libeap_peer.a
-
-install:
- if ls *.so >/dev/null 2>&1; then \
- install -d $(DESTDIR)$(LIBDIR)/wpa_supplicant && \
- cp *.so $(DESTDIR)$(LIBDIR)/wpa_supplicant \
- ; fi
-
-include ../lib.rules
-
CFLAGS += -DIEEE8021X_EAPOL
LIB_OBJS= \
eap.o \
eap_methods.o
-libeap_peer.a: $(LIB_OBJS)
- $(AR) crT $@ $?
+include ../lib.rules
--include $(OBJS:%.o=%.d)
+install:
+ if ls *.so >/dev/null 2>&1; then \
+ install -d $(DESTDIR)$(LIBDIR)/wpa_supplicant && \
+ cp *.so $(DESTDIR)$(LIBDIR)/wpa_supplicant \
+ ; fi
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index eaa1ad7..0986627 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -520,6 +520,12 @@
wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)", id);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START);
+ if (identity) {
+ wpa_hexdump_ascii(MSG_DEBUG, " AT_IDENTITY",
+ identity, identity_len);
+ eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
+ identity, identity_len);
+ }
if (!data->reauth) {
wpa_hexdump(MSG_DEBUG, " AT_NONCE_MT",
data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
@@ -531,13 +537,6 @@
data->selected_version, NULL, 0);
}
- if (identity) {
- wpa_hexdump_ascii(MSG_DEBUG, " AT_IDENTITY",
- identity, identity_len);
- eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
- identity, identity_len);
- }
-
resp = eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0);
if (resp)
eap_sim_state(data, START_DONE);
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 @@
"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/Makefile b/src/eap_server/Makefile
index 1172b72..cc9b76d 100644
--- a/src/eap_server/Makefile
+++ b/src/eap_server/Makefile
@@ -1,13 +1,3 @@
-all: libeap_server.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libeap_server.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
CFLAGS += -DCONFIG_HS20
LIB_OBJS= \
@@ -15,7 +5,4 @@
eap_server_identity.o \
eap_server_methods.o
-libeap_server.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
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 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 @@
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 @@
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 @@
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/eapol_auth/Makefile b/src/eapol_auth/Makefile
index 7b927a1..c82042f 100644
--- a/src/eapol_auth/Makefile
+++ b/src/eapol_auth/Makefile
@@ -1,16 +1,2 @@
-all: libeapol_auth.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libeapol_auth.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
LIB_OBJS = eapol_auth_sm.o eapol_auth_dump.o
-
-libeapol_auth.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/eapol_supp/Makefile b/src/eapol_supp/Makefile
index 80db9d4..67a1185 100644
--- a/src/eapol_supp/Makefile
+++ b/src/eapol_supp/Makefile
@@ -1,18 +1,5 @@
-all: libeapol_supp.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libeapol_supp.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
CFLAGS += -DIEEE8021X_EAPOL
LIB_OBJS = eapol_supp_sm.o
-libeapol_supp.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/l2_packet/Makefile b/src/l2_packet/Makefile
index 47925b7..c616626 100644
--- a/src/l2_packet/Makefile
+++ b/src/l2_packet/Makefile
@@ -1,16 +1,3 @@
-all: libl2_packet.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libl2_packet.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
LIB_OBJS = l2_packet_linux.o
-libl2_packet.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/lib.rules b/src/lib.rules
index a463154..947617b 100644
--- a/src/lib.rules
+++ b/src/lib.rules
@@ -1,10 +1,8 @@
-ifndef CC
-CC=gcc
-endif
-
-ifndef CFLAGS
-CFLAGS = -MMD -O2 -Wall -g
-endif
+_LIBMK := $(lastword $(wordlist 1,$(shell expr $(words $(MAKEFILE_LIST)) - 1),$(MAKEFILE_LIST)))
+_LIBNAME := $(notdir $(patsubst %/,%,$(dir $(abspath $(_LIBMK)))))
+ALL := $(OUT)lib$(_LIBNAME).a
+LIB_RULES := $(lastword $(MAKEFILE_LIST))
+include $(dir $(LIB_RULES))build.rules
ifdef TEST_FUZZ
CFLAGS += -DCONFIG_NO_RANDOM_POOL
@@ -14,18 +12,18 @@
CFLAGS += $(FUZZ_CFLAGS)
CFLAGS += -I.. -I../utils
+_OBJS_VAR := LIB_OBJS
+include ../objs.mk
-Q=@
-E=echo
-ifeq ($(V), 1)
-Q=
-E=true
-endif
-ifeq ($(QUIET), 1)
-Q=@
-E=true
-endif
+$(ALL): $(LIB_OBJS)
+ @$(E) " AR $(notdir $@)"
+ $(Q)$(AR) crT $@ $?
-%.o: %.c
- $(Q)$(CC) -c -o $@ $(CFLAGS) $<
- @$(E) " CC " $<
+install-default:
+ @echo Nothing to be made.
+
+%: %-default
+ @true
+
+clean: common-clean
+ $(Q)rm -f *~ *.o *.d *.gcno *.gcda *.gcov $(ALL)
diff --git a/src/objs.mk b/src/objs.mk
new file mode 100644
index 0000000..a3040b2
--- /dev/null
+++ b/src/objs.mk
@@ -0,0 +1,3 @@
+$(_OBJS_VAR) := $(call BUILDOBJ,$($(_OBJS_VAR)))
+-include $(filter-out %.a,$($(_OBJS_VAR):%.o=%.d))
+_DIRS += $(dir $($(_OBJS_VAR)))
diff --git a/src/p2p/Makefile b/src/p2p/Makefile
index 5587fcf..4d16180 100644
--- a/src/p2p/Makefile
+++ b/src/p2p/Makefile
@@ -1,13 +1,3 @@
-all: libp2p.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libp2p.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
CFLAGS += -DCONFIG_WIFI_DISPLAY
CFLAGS += -DCONFIG_WPS_NFC
@@ -23,7 +13,4 @@
p2p_sd.o \
p2p_utils.o
-libp2p.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 9c73885..6ddfb1e 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -3979,6 +3979,7 @@
}
p2p_dbg(p2p, "Go to Listen state while waiting for the peer to become ready for GO Negotiation");
+ p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT);
p2p_listen_in_find(p2p, 0);
}
diff --git a/src/radius/Makefile b/src/radius/Makefile
index 3ad4751..8cfb33d 100644
--- a/src/radius/Makefile
+++ b/src/radius/Makefile
@@ -1,14 +1,3 @@
-all: libradius.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libradius.a
-
-install:
- @echo Nothing to be made.
-
-
-include ../lib.rules
-
CFLAGS += -DCONFIG_IPV6
LIB_OBJS= \
@@ -17,7 +6,4 @@
radius_das.o \
radius_server.o
-libradius.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/rsn_supp/Makefile b/src/rsn_supp/Makefile
index eea0efb..d14d736 100644
--- a/src/rsn_supp/Makefile
+++ b/src/rsn_supp/Makefile
@@ -1,13 +1,3 @@
-all: librsn_supp.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov librsn_supp.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
CFLAGS += -DCONFIG_IEEE80211R
CFLAGS += -DCONFIG_TDLS
CFLAGS += -DCONFIG_WNM
@@ -21,7 +11,4 @@
wpa.o \
wpa_ie.o
-librsn_supp.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index e46c89a..b124dd9 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -272,7 +272,8 @@
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;
}
@@ -488,6 +489,9 @@
{
if (sm == NULL)
return;
+ if (sm->cur_pmksa)
+ wpa_printf(MSG_DEBUG,
+ "RSN: Clear current PMKSA entry selection");
sm->cur_pmksa = NULL;
}
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 @@
* 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/tdls.c b/src/rsn_supp/tdls.c
index 7b47e3a..eff8cd8 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -2807,6 +2807,11 @@
if (sm == NULL)
return -1;
+ if (sm->l2_tdls) {
+ l2_packet_deinit(sm->l2_tdls);
+ sm->l2_tdls = NULL;
+ }
+
sm->l2_tdls = l2_packet_init(sm->bridge_ifname ? sm->bridge_ifname :
sm->ifname,
sm->own_addr,
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index b9b1f0f..6c6de80 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -22,6 +22,7 @@
#include "common/ieee802_11_common.h"
#include "common/ocv.h"
#include "common/dpp.h"
+#include "common/wpa_ctrl.h"
#include "eap_common/eap_defs.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "drivers/driver.h"
@@ -756,6 +757,14 @@
"Failed to get channel info for OCI element in EAPOL-Key 2/4");
goto failed;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->oci_freq_override_eapol) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %d MHz",
+ ci.frequency, sm->oci_freq_override_eapol);
+ ci.frequency = sm->oci_freq_override_eapol;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
if (ocv_insert_oci_kde(&ci, &pos) < 0)
goto failed;
@@ -1708,9 +1717,10 @@
if (ocv_verify_tx_params(ie.oci, ie.oci_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "%s",
- ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, OCV_FAILURE
+ "addr=" MACSTR " frame=eapol-key-m3 error=%s",
+ MAC2STR(sm->bssid), ocv_errorstr);
return;
}
}
@@ -1855,9 +1865,10 @@
if (ocv_verify_tx_params(ie.oci, ie.oci_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "%s",
- ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, OCV_FAILURE
+ "addr=" MACSTR " frame=eapol-key-g1 error=%s",
+ MAC2STR(sm->bssid), ocv_errorstr);
return -1;
}
}
@@ -2028,6 +2039,15 @@
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) {
@@ -2431,13 +2451,16 @@
u8 *tmp = NULL;
int ret = -1;
u8 *mic, *key_data;
- size_t mic_len, keyhdrlen;
+ size_t mic_len, keyhdrlen, pmk_len;
#ifdef CONFIG_IEEE80211R
sm->ft_completed = 0;
#endif /* CONFIG_IEEE80211R */
- mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len);
+ pmk_len = sm->pmk_len;
+ if (!pmk_len && sm->cur_pmksa)
+ pmk_len = sm->cur_pmksa->pmk_len;
+ mic_len = wpa_mic_len(sm->key_mgmt, pmk_len);
keyhdrlen = sizeof(*key) + mic_len + 2;
if (len < sizeof(*hdr) + keyhdrlen) {
@@ -3278,6 +3301,9 @@
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;
@@ -3291,6 +3317,18 @@
case WPA_PARAM_FT_RSNXE_USED:
sm->ft_rsnxe_used = value;
break;
+ 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:
@@ -4430,10 +4468,6 @@
return -1;
}
sm->pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
- wpa_hexdump_key(MSG_DEBUG, "FILS+FT: PMK-R0",
- sm->pmk_r0, sm->pmk_r0_len);
- wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR0Name",
- sm->pmk_r0_name, WPA_PMK_NAME_LEN);
wpa_printf(MSG_DEBUG, "FILS+FT: R1KH-ID: " MACSTR,
MAC2STR(sm->r1kh_id));
pos = wpabuf_put(buf, WPA_PMK_NAME_LEN);
@@ -4442,8 +4476,6 @@
wpa_printf(MSG_WARNING, "FILS+FT: Could not derive PMKR1Name");
return -1;
}
- wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR1Name", sm->pmk_r1_name,
- WPA_PMK_NAME_LEN);
os_memcpy(pos, sm->pmk_r1_name, WPA_PMK_NAME_LEN);
if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
@@ -4554,6 +4586,15 @@
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) {
@@ -4758,8 +4799,10 @@
if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_printf(MSG_WARNING, "FILS: %s", ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, OCV_FAILURE
+ "addr=" MACSTR " frame=fils-assoc error=%s",
+ MAC2STR(sm->bssid), ocv_errorstr);
goto fail;
}
}
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index dfc156b..2142772 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -43,7 +43,7 @@
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,11 +103,16 @@
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 3e51cf2..bf73376 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -15,6 +15,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/ocv.h"
+#include "common/wpa_ctrl.h"
#include "drivers/driver.h"
#include "wpa.h"
#include "wpa_i.h"
@@ -50,17 +51,11 @@
sm->r0kh_id, sm->r0kh_id_len, sm->own_addr,
sm->pmk_r0, sm->pmk_r0_name, use_sha384) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", sm->pmk_r0, sm->pmk_r0_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name",
- sm->pmk_r0_name, WPA_PMK_NAME_LEN);
sm->pmk_r1_len = sm->pmk_r0_len;
if (wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_len, sm->pmk_r0_name,
sm->r1kh_id, sm->own_addr, sm->pmk_r1,
sm->pmk_r1_name) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, sm->pmk_r1_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
- WPA_PMK_NAME_LEN);
return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce, anonce,
sm->own_addr, sm->bssid, sm->pmk_r1_name, ptk,
ptk_name, sm->key_mgmt, sm->pairwise_cipher);
@@ -358,6 +353,14 @@
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;
@@ -641,9 +644,6 @@
sm->pmk_r1_name) < 0)
return -1;
sm->pmk_r1_len = sm->pmk_r0_len;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, sm->pmk_r1_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name",
- sm->pmk_r1_name, WPA_PMK_NAME_LEN);
bssid = target_ap;
if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce,
@@ -1167,8 +1167,10 @@
if (ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, OCV_FAILURE
+ "addr=" MACSTR " frame=ft-assoc error=%s",
+ MAC2STR(sm->bssid), ocv_errorstr);
return -1;
}
}
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index f7d9f62..96b07fc 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -95,6 +95,7 @@
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;
@@ -154,6 +155,10 @@
#ifdef CONFIG_TESTING_OPTIONS
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
@@ -267,12 +272,12 @@
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 @@
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 @@
*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/tls/Makefile b/src/tls/Makefile
index 52a890a..c84fbe8 100644
--- a/src/tls/Makefile
+++ b/src/tls/Makefile
@@ -1,14 +1,3 @@
-all: libtls.a
-
-clean:
- rm -f *~ *.o *.d libtls.a
-
-install:
- @echo Nothing to be made.
-
-
-include ../lib.rules
-
CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
CFLAGS += -DCONFIG_CRYPTO_INTERNAL
CFLAGS += -DCONFIG_TLSV11
@@ -33,8 +22,4 @@
tlsv1_server_write.o \
x509v3.o
-
-libtls.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/utils/Makefile b/src/utils/Makefile
index 1ee2bee..e8ad997 100644
--- a/src/utils/Makefile
+++ b/src/utils/Makefile
@@ -1,14 +1,3 @@
-all: libutils.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libutils.a
-
-install:
- @echo Nothing to be made.
-
-
-include ../lib.rules
-
#CFLAGS += -DWPA_TRACE
CFLAGS += -DCONFIG_IPV6
CFLAGS += -DCONFIG_DEBUG_FILE
@@ -37,7 +26,4 @@
#LIB_OBJS += pcsc_funcs.o
-libutils.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
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 @@
"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 @@
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 @@
*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 @@
*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 @@
*/
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_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_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 @@
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 @@
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/utils/wpabuf.h b/src/utils/wpabuf.h
index 01da41b..b2a54b2 100644
--- a/src/utils/wpabuf.h
+++ b/src/utils/wpabuf.h
@@ -71,6 +71,21 @@
}
/**
+ * wpabuf_cmp - Check if two buffers contain the same data
+ * @a: wpabuf buffer
+ * @b: wpabuf buffer
+ * Returns: 0 if the two buffers contain the same data and non-zero otherwise
+ */
+static inline int wpabuf_cmp(const struct wpabuf *a, const struct wpabuf *b)
+{
+ if (!a && !b)
+ return 0;
+ if (a && b && wpabuf_size(a) == wpabuf_size(b))
+ return os_memcmp(a->buf, b->buf, wpabuf_size(a));
+ return -1;
+}
+
+/**
* wpabuf_head - Get pointer to the head of the buffer data
* @buf: wpabuf buffer
* Returns: Pointer to the head of the buffer data
diff --git a/src/wps/Makefile b/src/wps/Makefile
index 4806fe8..cddc686 100644
--- a/src/wps/Makefile
+++ b/src/wps/Makefile
@@ -1,13 +1,3 @@
-all: libwps.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libwps.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
CFLAGS += -DCONFIG_P2P
CFLAGS += -DCONFIG_WPS_OOB
CFLAGS += -DCONFIG_WPS_NFC
@@ -35,7 +25,4 @@
wps_upnp_ssdp.o \
wps_upnp_web.o
-libwps.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
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 @@
"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 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 @@
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 @@
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 @@
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 @@
}
-#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 @@
}
return 0;
}
-#endif /* __FreeBSD__ */
+#endif /* __FreeBSD__ || __APPLE__ */
/**
@@ -890,11 +911,12 @@
* @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 @@
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 @@
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 @@
/* 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 @@
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 @@
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 @@
buf = event_build_message(e);
if (buf == NULL) {
- event_retry(e, 0);
+ event_addr_failure(e);
return -1;
}
@@ -301,7 +302,7 @@
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 @@
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 @@
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/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 5cc9c65..3a99bb6 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -128,6 +128,7 @@
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
@@ -265,6 +266,10 @@
ifdef CONFIG_SAE
L_CFLAGS += -DCONFIG_SAE
OBJS += src/common/sae.c
+ifdef CONFIG_SAE_PK
+L_CFLAGS += -DCONFIG_SAE_PK
+OBJS += src/common/sae_pk.c
+endif
NEED_ECC=y
NEED_DH_GROUPS=y
NEED_HMAC_SHA256_KDF=y
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index b35d11e..08522de 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -1,11 +1,24 @@
-ifndef CC
-CC=gcc
+BINALL=wpa_supplicant wpa_cli
+
+ifndef CONFIG_NO_WPA_PASSPHRASE
+BINALL += wpa_passphrase
endif
-ifndef CFLAGS
-CFLAGS = -MMD -O2 -Wall -g
+ALL = $(BINALL)
+ALL += systemd/wpa_supplicant.service
+ALL += systemd/wpa_supplicant@.service
+ALL += systemd/wpa_supplicant-nl80211@.service
+ALL += systemd/wpa_supplicant-wired@.service
+ALL += dbus/fi.w1.wpa_supplicant1.service
+ifdef CONFIG_BUILD_WPA_CLIENT_SO
+ALL += libwpa_client.so
endif
+EXTRA_TARGETS=dynamic_eap_methods
+
+CONFIG_FILE=.config
+include ../src/build.rules
+
ifdef LIBS
# If LIBS is set with some global build system defaults, clone those for
# LIBS_c and LIBS_p to cover wpa_passphrase and wpa_cli as well.
@@ -26,8 +39,6 @@
CFLAGS += -I$(abspath ../src)
CFLAGS += -I$(abspath ../src/utils)
--include .config
-
ifndef CONFIG_NO_GITVER
# Add VERSION_STR postfix for builds from a git repository
ifeq ($(wildcard ../.git),../.git)
@@ -44,34 +55,6 @@
CONFIG_TDLS_TESTING=y
endif
-BINALL=wpa_supplicant wpa_cli
-
-ifndef CONFIG_NO_WPA_PASSPHRASE
-BINALL += wpa_passphrase
-endif
-
-ALL = $(BINALL)
-ALL += systemd/wpa_supplicant.service
-ALL += systemd/wpa_supplicant@.service
-ALL += systemd/wpa_supplicant-nl80211@.service
-ALL += systemd/wpa_supplicant-wired@.service
-ALL += dbus/fi.w1.wpa_supplicant1.service
-ifdef CONFIG_BUILD_WPA_CLIENT_SO
-ALL += libwpa_client.so
-endif
-
-
-all: verify_config $(ALL) dynamic_eap_methods
-
-verify_config:
- @if [ ! -r .config ]; then \
- echo 'Building wpa_supplicant requires a configuration file'; \
- echo '(.config). See README for more instructions. You can'; \
- echo 'run "cp defconfig .config" to create an example'; \
- echo 'configuration.'; \
- exit 1; \
- fi
-
mkconfig:
@if [ -f .config ]; then \
echo '.config exists - did not replace it'; \
@@ -107,6 +90,7 @@
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
@@ -267,6 +251,10 @@
ifdef CONFIG_SAE
CFLAGS += -DCONFIG_SAE
OBJS += ../src/common/sae.o
+ifdef CONFIG_SAE_PK
+CFLAGS += -DCONFIG_SAE_PK
+OBJS += ../src/common/sae_pk.o
+endif
NEED_ECC=y
NEED_DH_GROUPS=y
NEED_HMAC_SHA256_KDF=y
@@ -1866,53 +1854,40 @@
CFLAGS += -DCONFIG_NO_TKIP
endif
-ifndef LDO
-LDO=$(CC)
-endif
-
-Q=@
-E=echo
-ifeq ($(V), 1)
-Q=
-E=true
-endif
-ifeq ($(QUIET), 1)
-Q=@
-E=true
-endif
-
dynamic_eap_methods: $(EAPDYN)
-../src/drivers/build.wpa_supplicant:
- @if [ -f ../src/drivers/build.hostapd ]; then \
- $(MAKE) -C ../src/drivers clean; \
- fi
- @touch ../src/drivers/build.wpa_supplicant
-
-BCHECK=../src/drivers/build.wpa_supplicant
-
+_OBJS_VAR := OBJS_priv
+include ../src/objs.mk
wpa_priv: $(BCHECK) $(OBJS_priv)
$(Q)$(LDO) $(LDFLAGS) -o wpa_priv $(OBJS_priv) $(LIBS)
@$(E) " LD " $@
-$(OBJS_c) $(OBJS_t) $(OBJS_t2) $(OBJS) $(BCHECK) $(EXTRA_progs): .config
-
+_OBJS_VAR := OBJS
+include ../src/objs.mk
wpa_supplicant: $(BCHECK) $(OBJS) $(EXTRA_progs)
$(Q)$(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS)
@$(E) " LD " $@
+_OBJS_VAR := OBJS_t
+include ../src/objs.mk
eapol_test: $(OBJS_t)
$(Q)$(LDO) $(LDFLAGS) -o eapol_test $(OBJS_t) $(LIBS)
@$(E) " LD " $@
+_OBJS_VAR := OBJS_t2
+include ../src/objs.mk
preauth_test: $(OBJS_t2)
$(Q)$(LDO) $(LDFLAGS) -o preauth_test $(OBJS_t2) $(LIBS)
@$(E) " LD " $@
+_OBJS_VAR := OBJS_p
+include ../src/objs.mk
wpa_passphrase: $(OBJS_p)
$(Q)$(LDO) $(LDFLAGS) -o wpa_passphrase $(OBJS_p) $(LIBS_p) $(LIBS)
@$(E) " LD " $@
+_OBJS_VAR := OBJS_c
+include ../src/objs.mk
wpa_cli: $(OBJS_c)
$(Q)$(LDO) $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c)
@$(E) " LD " $@
@@ -1926,6 +1901,8 @@
LIBCTRLSO += ../src/utils/common.c
LIBCTRLSO += ../src/utils/wpa_debug.c
+_OBJS_VAR := LIBCTRL
+include ../src/objs.mk
libwpa_client.a: $(LIBCTRL)
$(Q)rm -f $@
$(Q)$(AR) crs $@ $?
@@ -1935,14 +1912,19 @@
@$(E) " CC $@ ($^)"
$(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -fPIC $^
-libwpa_test1: libwpa_test.o libwpa_client.a
- $(Q)$(LDO) $(LDFLAGS) -o libwpa_test1 libwpa_test.o libwpa_client.a $(LIBS_c)
+OBJS_wpatest := libwpa_test.o
+_OBJS_VAR := OBJS_wpatest
+include ../src/objs.mk
+libwpa_test1: $(OBJS_wpatest) libwpa_client.a
+ $(Q)$(LDO) $(LDFLAGS) -o libwpa_test1 $(OBJS_wpatest) libwpa_client.a $(LIBS_c)
@$(E) " LD " $@
-libwpa_test2: libwpa_test.o libwpa_client.so
- $(Q)$(LDO) $(LDFLAGS) -o libwpa_test2 libwpa_test.o -L. -lwpa_client $(LIBS_c)
+libwpa_test2: $(OBJS_wpatest) libwpa_client.so
+ $(Q)$(LDO) $(LDFLAGS) -o libwpa_test2 $(OBJS_wpatest) -L. -lwpa_client $(LIBS_c)
@$(E) " LD " $@
+_OBJS_VAR := OBJS_nfc
+include ../src/objs.mk
nfc_pw_token: $(OBJS_nfc)
$(Q)$(LDO) $(LDFLAGS) -o nfc_pw_token $(OBJS_nfc) $(LIBS)
@$(E) " LD " $@
@@ -1979,16 +1961,6 @@
$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $< \
-D$(*F:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init
-ifdef CONFIG_CODE_COVERAGE
-%.o: %.c
- @$(E) " CC " $<
- $(Q)cd $(dir $@); $(CC) -c -o $(notdir $@) $(CFLAGS) $(notdir $<)
-else
-%.o: %.c
- $(Q)$(CC) -c -o $@ $(CFLAGS) $<
- @$(E) " CC " $<
-endif
-
%.service: %.service.in
$(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
@$(E) " sed" $<
@@ -2030,15 +2002,16 @@
fips:
$(MAKE) CC=$(FIPSLD) FIPSLD_CC="$(CC)"
-lcov-html: wpa_supplicant.gcda
- lcov -c -d .. > lcov.info
+.PHONY: lcov-html
+lcov-html: $(call BUILDOBJ,wpa_supplicant.gcda)
+ lcov -c -d $(BUILDDIR) > lcov.info
genhtml lcov.info --output-directory lcov-html
-clean:
+clean: common-clean
$(MAKE) -C ../src clean
$(MAKE) -C dbus clean
rm -f core *~ *.o *.d *.gcno *.gcda *.gcov
- rm -f eap_*.so $(ALL) $(WINALL) eapol_test preauth_test
+ rm -f eap_*.so $(WINALL) eapol_test preauth_test
rm -f wpa_priv
rm -f nfc_pw_token
rm -f lcov.info
@@ -2046,5 +2019,3 @@
rm -f libwpa_client.a
rm -f libwpa_client.so
rm -f libwpa_test1 libwpa_test2
-
--include $(OBJS:%.o=%.d)
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 6241682..a4892e7 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -53,30 +53,37 @@
u8 center_chan = 0;
u8 channel = conf->channel;
#endif /* CONFIG_P2P */
+ u8 freq_seg_idx;
if (!conf->secondary_channel)
goto no_vht;
/* Use the maximum oper channel width if it's given. */
if (ssid->max_oper_chwidth)
- conf->vht_oper_chwidth = ssid->max_oper_chwidth;
+ hostapd_set_oper_chwidth(conf, ssid->max_oper_chwidth);
- ieee80211_freq_to_chan(ssid->vht_center_freq2,
- &conf->vht_oper_centr_freq_seg1_idx);
+ if (hostapd_get_oper_chwidth(conf) == CHANWIDTH_80P80MHZ) {
+ ieee80211_freq_to_chan(ssid->vht_center_freq2,
+ &freq_seg_idx);
+ hostapd_set_oper_centr_freq_seg1_idx(conf, freq_seg_idx);
+ }
if (!ssid->p2p_group) {
- if (!ssid->vht_center_freq1 ||
- conf->vht_oper_chwidth == CHANWIDTH_USE_HT)
+ if (!ssid->vht_center_freq1)
goto no_vht;
ieee80211_freq_to_chan(ssid->vht_center_freq1,
- &conf->vht_oper_centr_freq_seg0_idx);
- wpa_printf(MSG_DEBUG, "VHT seg0 index %d for AP",
- conf->vht_oper_centr_freq_seg0_idx);
+ &freq_seg_idx);
+ hostapd_set_oper_centr_freq_seg0_idx(conf, freq_seg_idx);
+
+ wpa_printf(MSG_DEBUG,
+ "VHT seg0 index %d and seg1 index %d for AP",
+ hostapd_get_oper_centr_freq_seg0_idx(conf),
+ hostapd_get_oper_centr_freq_seg1_idx(conf));
return;
}
#ifdef CONFIG_P2P
- switch (conf->vht_oper_chwidth) {
+ switch (hostapd_get_oper_chwidth(conf)) {
case CHANWIDTH_80MHZ:
case CHANWIDTH_80P80MHZ:
center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel);
@@ -96,14 +103,14 @@
* try oper_cwidth 160 MHz first then VHT 80 MHz, if 160 MHz is
* not supported.
*/
- conf->vht_oper_chwidth = CHANWIDTH_160MHZ;
+ hostapd_set_oper_chwidth(conf, CHANWIDTH_160MHZ);
center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel);
if (center_chan) {
wpa_printf(MSG_DEBUG,
"VHT center channel %u for auto-selected 160 MHz bandwidth",
center_chan);
} else {
- conf->vht_oper_chwidth = CHANWIDTH_80MHZ;
+ hostapd_set_oper_chwidth(conf, CHANWIDTH_80MHZ);
center_chan = wpas_p2p_get_vht80_center(wpa_s, mode,
channel);
wpa_printf(MSG_DEBUG,
@@ -115,9 +122,9 @@
if (!center_chan)
goto no_vht;
- conf->vht_oper_centr_freq_seg0_idx = center_chan;
+ hostapd_set_oper_centr_freq_seg0_idx(conf, center_chan);
wpa_printf(MSG_DEBUG, "VHT seg0 index %d for P2P GO",
- conf->vht_oper_centr_freq_seg0_idx);
+ hostapd_get_oper_centr_freq_seg0_idx(conf));
return;
#endif /* CONFIG_P2P */
@@ -125,9 +132,27 @@
wpa_printf(MSG_DEBUG,
"No VHT higher bandwidth support for the selected channel %d",
conf->channel);
- conf->vht_oper_centr_freq_seg0_idx =
- conf->channel + conf->secondary_channel * 2;
- conf->vht_oper_chwidth = CHANWIDTH_USE_HT;
+ hostapd_set_oper_centr_freq_seg0_idx(
+ conf, conf->channel + conf->secondary_channel * 2);
+ hostapd_set_oper_chwidth(conf, CHANWIDTH_USE_HT);
+}
+
+
+static struct hostapd_hw_modes *
+wpa_supplicant_find_hw_mode(struct wpa_supplicant *wpa_s,
+ enum hostapd_hw_mode hw_mode)
+{
+ struct hostapd_hw_modes *mode = NULL;
+ int i;
+
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ if (wpa_s->hw.modes[i].mode == hw_mode) {
+ mode = &wpa_s->hw.modes[i];
+ break;
+ }
+ }
+
+ return mode;
}
@@ -144,9 +169,6 @@
return -1;
}
- /* TODO: enable HT40 if driver supports it;
- * drop to 11b if driver does not support 11g */
-
/*
* Enable HT20 if the driver supports it, by setting conf->ieee80211n
* and a mask of allowed capabilities within conf->ht_capab.
@@ -155,17 +177,28 @@
*/
if (wpa_s->hw.modes) {
struct hostapd_hw_modes *mode = NULL;
- int i, no_ht = 0;
+ int no_ht = 0;
wpa_printf(MSG_DEBUG,
"Determining HT/VHT options based on driver capabilities (freq=%u chan=%u)",
ssid->frequency, conf->channel);
- for (i = 0; i < wpa_s->hw.num_modes; i++) {
- if (wpa_s->hw.modes[i].mode == conf->hw_mode) {
- mode = &wpa_s->hw.modes[i];
- break;
- }
+ mode = wpa_supplicant_find_hw_mode(wpa_s, conf->hw_mode);
+
+ /* May drop to IEEE 802.11b if the driver does not support IEEE
+ * 802.11g */
+ if (!mode && conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
+ wpa_printf(MSG_INFO,
+ "Try downgrade to IEEE 802.11b as 802.11g is not supported by the current hardware");
+ mode = wpa_supplicant_find_hw_mode(wpa_s,
+ conf->hw_mode);
+ }
+
+ if (!mode) {
+ wpa_printf(MSG_ERROR,
+ "No match between requested and supported hw modes found");
+ return -1;
}
#ifdef CONFIG_HT_OVERRIDES
@@ -190,6 +223,14 @@
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET),
ssid->ht40);
conf->ieee80211n = 1;
+
+ if (ssid->ht40 &&
+ (mode->ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ conf->secondary_channel = ssid->ht40;
+ else
+ conf->secondary_channel = 0;
+
#ifdef CONFIG_P2P
if (ssid->p2p_group &&
conf->hw_mode == HOSTAPD_MODE_IEEE80211A &&
@@ -231,16 +272,19 @@
HT_CAP_INFO_TX_STBC |
HT_CAP_INFO_MAX_AMSDU_SIZE);
+ /* check this before VHT, because setting oper chan
+ * width and friends is the same call for HE and VHT
+ * and checks if conf->ieee8021ax == 1 */
+ if (mode->he_capab[wpas_mode_to_ieee80211_mode(
+ ssid->mode)].he_supported &&
+ ssid->he)
+ conf->ieee80211ax = 1;
+
if (mode->vht_capab && ssid->vht) {
conf->ieee80211ac = 1;
conf->vht_capab |= mode->vht_capab;
wpas_conf_ap_vht(wpa_s, ssid, conf, mode);
}
-
- if (mode->he_capab[wpas_mode_to_ieee80211_mode(
- ssid->mode)].he_supported &&
- ssid->he)
- conf->ieee80211ax = 1;
}
}
@@ -858,6 +902,9 @@
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;
@@ -1415,10 +1462,17 @@
struct csa_settings *settings)
{
#ifdef NEED_AP_MLME
- if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ struct hostapd_iface *iface = NULL;
+
+ if (wpa_s->ap_iface)
+ iface = wpa_s->ap_iface;
+ else if (wpa_s->ifmsh)
+ iface = wpa_s->ifmsh;
+
+ if (!iface || !iface->bss[0])
return -1;
- return hostapd_switch_channel(wpa_s->ap_iface->bss[0], settings);
+ return hostapd_switch_channel(iface->bss[0], settings);
#else /* NEED_AP_MLME */
return -1;
#endif /* NEED_AP_MLME */
diff --git a/wpa_supplicant/blacklist.c b/wpa_supplicant/blacklist.c
index e53dc38..2f32644 100644
--- a/wpa_supplicant/blacklist.c
+++ b/wpa_supplicant/blacklist.c
@@ -26,6 +26,15 @@
if (wpa_s == NULL || bssid == NULL)
return NULL;
+ if (wpa_s->current_ssid &&
+ wpa_s->current_ssid->was_recently_reconfigured) {
+ wpa_blacklist_clear(wpa_s);
+ wpa_s->current_ssid->was_recently_reconfigured = false;
+ return NULL;
+ }
+
+ wpa_blacklist_update(wpa_s);
+
e = wpa_s->blacklist;
while (e) {
if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0)
@@ -56,16 +65,29 @@
int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
struct wpa_blacklist *e;
+ struct os_reltime now;
if (wpa_s == NULL || bssid == NULL)
return -1;
e = wpa_blacklist_get(wpa_s, bssid);
+ os_get_reltime(&now);
if (e) {
+ e->blacklist_start = now;
e->count++;
- wpa_printf(MSG_DEBUG, "BSSID " MACSTR " blacklist count "
- "incremented to %d",
- MAC2STR(bssid), e->count);
+ if (e->count > 5)
+ e->timeout_secs = 1800;
+ else if (e->count == 5)
+ e->timeout_secs = 600;
+ else if (e->count == 4)
+ e->timeout_secs = 120;
+ else if (e->count == 3)
+ e->timeout_secs = 60;
+ else
+ e->timeout_secs = 10;
+ wpa_printf(MSG_INFO, "BSSID " MACSTR
+ " blacklist count incremented to %d, blacklisting for %d seconds",
+ MAC2STR(bssid), e->count, e->timeout_secs);
return e->count;
}
@@ -74,10 +96,13 @@
return -1;
os_memcpy(e->bssid, bssid, ETH_ALEN);
e->count = 1;
+ e->timeout_secs = 10;
+ e->blacklist_start = now;
e->next = wpa_s->blacklist;
wpa_s->blacklist = e;
- wpa_printf(MSG_DEBUG, "Added BSSID " MACSTR " into blacklist",
- MAC2STR(bssid));
+ wpa_printf(MSG_DEBUG, "Added BSSID " MACSTR
+ " into blacklist, blacklisting for %d seconds",
+ MAC2STR(bssid), e->timeout_secs);
return e->count;
}
@@ -117,25 +142,80 @@
/**
+ * wpa_blacklist_is_blacklisted - Check the blacklist status of a BSS
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID to be checked
+ * Returns: count if BSS is currently considered to be blacklisted, 0 otherwise
+ */
+int wpa_blacklist_is_blacklisted(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ struct wpa_blacklist *e;
+ struct os_reltime now;
+
+ e = wpa_blacklist_get(wpa_s, bssid);
+ if (!e)
+ return 0;
+ os_get_reltime(&now);
+ if (os_reltime_expired(&now, &e->blacklist_start, e->timeout_secs))
+ return 0;
+ return e->count;
+}
+
+
+/**
* wpa_blacklist_clear - Clear the blacklist of all entries
* @wpa_s: Pointer to wpa_supplicant data
*/
void wpa_blacklist_clear(struct wpa_supplicant *wpa_s)
{
struct wpa_blacklist *e, *prev;
- int max_count = 0;
e = wpa_s->blacklist;
wpa_s->blacklist = NULL;
while (e) {
- if (e->count > max_count)
- max_count = e->count;
prev = e;
e = e->next;
wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from "
"blacklist (clear)", MAC2STR(prev->bssid));
os_free(prev);
}
+}
- wpa_s->extra_blacklist_count += max_count;
+
+/**
+ * wpa_blacklist_update - Update the entries in the blacklist,
+ * deleting entries that have been expired for over an hour.
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
+void wpa_blacklist_update(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_blacklist *e, *prev = NULL;
+ struct os_reltime now;
+
+ if (!wpa_s)
+ return;
+
+ e = wpa_s->blacklist;
+ os_get_reltime(&now);
+ while (e) {
+ if (os_reltime_expired(&now, &e->blacklist_start,
+ e->timeout_secs + 3600)) {
+ struct wpa_blacklist *to_delete = e;
+
+ if (prev) {
+ prev->next = e->next;
+ e = prev->next;
+ } else {
+ wpa_s->blacklist = e->next;
+ e = wpa_s->blacklist;
+ }
+ wpa_printf(MSG_INFO, "Removed BSSID " MACSTR
+ " from blacklist (expired)",
+ MAC2STR(to_delete->bssid));
+ os_free(to_delete);
+ } else {
+ prev = e;
+ e = e->next;
+ }
+ }
}
diff --git a/wpa_supplicant/blacklist.h b/wpa_supplicant/blacklist.h
index ae06986..a1c60d5 100644
--- a/wpa_supplicant/blacklist.h
+++ b/wpa_supplicant/blacklist.h
@@ -13,12 +13,21 @@
struct wpa_blacklist *next;
u8 bssid[ETH_ALEN];
int count;
+ /* Time of most recent blacklist event. */
+ struct os_reltime blacklist_start;
+ /*
+ * Number of seconds after blacklist_start that the entry will be
+ * considered blacklisted.
+ */
+ int timeout_secs;
};
struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
const u8 *bssid);
int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid);
int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpa_blacklist_is_blacklisted(struct wpa_supplicant *wpa_s, const u8 *bssid);
void wpa_blacklist_clear(struct wpa_supplicant *wpa_s);
+void wpa_blacklist_update(struct wpa_supplicant *wpa_s);
#endif /* BLACKLIST_H */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index e1d9824..8a8765b 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2573,6 +2573,7 @@
{ STR_LEN(dpp_netaccesskey) },
{ INT(dpp_netaccesskey_expiry) },
{ STR_LEN(dpp_csign) },
+ { STR_LEN(dpp_pp_key) },
{ INT_RANGE(dpp_pfs, 0, 2) },
#endif /* CONFIG_DPP */
{ INT_RANGE(owe_group, 0, 65535) },
@@ -2582,6 +2583,7 @@
{ 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
@@ -2775,6 +2777,7 @@
os_free(ssid->dpp_connector);
bin_clear_free(ssid->dpp_netaccesskey, ssid->dpp_netaccesskey_len);
os_free(ssid->dpp_csign);
+ os_free(ssid->dpp_pp_key);
while ((psk = dl_list_first(&ssid->psk_list, struct psk_list_entry,
list))) {
dl_list_del(&psk->list);
@@ -3035,6 +3038,8 @@
ssid->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS;
ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
ssid->ht = 1;
+ ssid->vht = 1;
+ ssid->he = 1;
#ifdef IEEE8021X_EAPOL
ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;
ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
@@ -3141,6 +3146,7 @@
}
ret = -1;
}
+ ssid->was_recently_reconfigured = true;
return ret;
}
@@ -4254,6 +4260,8 @@
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 =
@@ -4261,9 +4269,20 @@
const struct hostapd_wmm_ac_params ac_be =
{ aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
- { aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
+ { aCWmin - 1, aCWmin, 2, 3008 / 32, 0 };
const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
- { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
+ { aCWmin - 2, aCWmin - 1, 2, 1504 / 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 +4312,10 @@
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;
@@ -4342,13 +4365,31 @@
#endif /* CONFIG_NO_STDOUT_DEBUG */
+/**
+ * Structure for global configuration parsing. This data is used to implement a
+ * generic parser for the global interface configuration. The table of variables
+ * is defined below in this file (global_fields[]).
+ */
struct global_parse_data {
+ /* Configuration variable name */
char *name;
+
+ /* Parser function for this variable. The parser functions return 0 or 1
+ * to indicate success. Value 0 indicates that the parameter value may
+ * have changed while value 1 means that the value did not change.
+ * Error cases (failure to parse the string) are indicated by returning
+ * -1. */
int (*parser)(const struct global_parse_data *data,
struct wpa_config *config, int line, const char *value);
+
+ /* Getter function to print the variable in text format to buf. */
int (*get)(const char *name, struct wpa_config *config, long offset,
char *buf, size_t buflen, int pretty_print);
+
+ /* Variable specific parameters for the parser. */
void *param1, *param2, *param3;
+
+ /* Indicates which configuration variable has changed. */
unsigned int changed_flag;
};
@@ -4359,6 +4400,7 @@
{
int val, *dst;
char *end;
+ bool same;
dst = (int *) (((u8 *) config) + (long) data->param1);
val = strtol(pos, &end, 0);
@@ -4367,6 +4409,7 @@
line, pos);
return -1;
}
+ same = *dst == val;
*dst = val;
wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
@@ -4387,7 +4430,7 @@
return -1;
}
- return 0;
+ return same;
}
@@ -4395,7 +4438,7 @@
struct wpa_config *config, int line,
const char *pos)
{
- size_t len;
+ size_t len, prev_len;
char **dst, *tmp;
len = os_strlen(pos);
@@ -4419,11 +4462,22 @@
return -1;
}
+ dst = (char **) (((u8 *) config) + (long) data->param1);
+ if (*dst)
+ prev_len = os_strlen(*dst);
+ else
+ prev_len = 0;
+
+ /* No change to the previously configured value */
+ if ((!(*dst) && !pos) ||
+ (*dst && pos && prev_len == len &&
+ os_memcmp(*dst, pos, len) == 0))
+ return 1;
+
tmp = os_strdup(pos);
if (tmp == NULL)
return -1;
- dst = (char **) (((u8 *) config) + (long) data->param1);
os_free(*dst);
*dst = tmp;
wpa_printf(MSG_DEBUG, "%s='%s'", data->name, *dst);
@@ -4464,6 +4518,10 @@
return -1;
dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1);
+ if (wpabuf_cmp(*dst, tmp) == 0) {
+ wpabuf_free(tmp);
+ return 1;
+ }
wpabuf_free(*dst);
*dst = tmp;
wpa_printf(MSG_DEBUG, "%s", data->name);
@@ -4505,6 +4563,8 @@
return -1;
dst = (u32 *) (((u8 *) config) + (long) data->param1);
+ if (os_memcmp(dst, &addr.u.v4.s_addr, 4) == 0)
+ return 1;
os_memcpy(dst, &addr.u.v4.s_addr, 4);
wpa_printf(MSG_DEBUG, "%s = 0x%x", data->name,
WPA_GET_BE32((u8 *) dst));
@@ -4522,6 +4582,8 @@
wpa_printf(MSG_DEBUG, "Invalid country set");
return -1;
}
+ if (pos[0] == config->country[0] && pos[1] == config->country[1])
+ return 1;
config->country[0] = pos[0];
config->country[1] = pos[1];
wpa_printf(MSG_DEBUG, "country='%c%c'",
@@ -4905,7 +4967,7 @@
{ INT_RANGE(eapol_version, 1, 2), 0 },
#endif /* CONFIG_MACSEC */
{ INT(ap_scan), 0 },
- { FUNC(bgscan), 0 },
+ { FUNC(bgscan), CFG_CHANGED_BGSCAN },
#ifdef CONFIG_MESH
{ INT(user_mpm), 0 },
{ INT_RANGE(max_peer_links, 0, 255), 0 },
@@ -4979,6 +5041,7 @@
{ INT(p2p_device_random_mac_addr), 0 },
{ FUNC(p2p_device_persistent_mac_addr), 0 },
{ INT(p2p_interface_random_mac_addr), 0 },
+ { INT(p2p_6ghz_disable), 0 },
#endif /* CONFIG_P2P */
{ FUNC(country), CFG_CHANGED_COUNTRY },
{ INT(bss_max_count), 0 },
@@ -5140,6 +5203,19 @@
}
+/**
+ * wpa_config_process_global - Set a variable in global configuration
+ * @config: Pointer to global configuration data
+ * @pos: Name and value in the format "{name}={value}"
+ * @line: Line number in configuration file or 0 if not used
+ * Returns: 0 on success with a possible change in value, 1 on success with no
+ * change to previously configured value, or -1 on failure
+ *
+ * This function can be used to set global configuration variables based on
+ * both the configuration file and management interface input. The value
+ * parameter must be in the same format as the text-based configuration file is
+ * using. For example, strings are using double quotation marks.
+ */
int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
{
size_t i;
@@ -5152,11 +5228,14 @@
pos[flen] != '=')
continue;
- if (field->parser(field, config, line, pos + flen + 1)) {
+ ret = field->parser(field, config, line, pos + flen + 1);
+ if (ret < 0) {
wpa_printf(MSG_ERROR, "Line %d: failed to "
"parse '%s'.", line, pos);
ret = -1;
}
+ if (ret == 1)
+ break;
if (field->changed_flag == CFG_CHANGED_NFC_PASSWORD_TOKEN)
config->wps_nfc_pw_from_config = 1;
config->changed_parameters |= field->changed_flag;
@@ -5164,6 +5243,26 @@
}
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 0ca27cb..0b9e3db 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -376,6 +376,7 @@
#define CFG_CHANGED_SCHED_SCAN_PLANS BIT(17)
#define CFG_CHANGED_WOWLAN_TRIGGERS BIT(18)
#define CFG_CHANGED_DISABLE_BTM BIT(19)
+#define CFG_CHANGED_BGSCAN BIT(20)
/**
* struct wpa_config - wpa_supplicant configuration data
@@ -779,6 +780,8 @@
int p2p_ignore_shared_freq;
int p2p_optimize_listen_chan;
+ int p2p_6ghz_disable;
+
struct wpabuf *wps_vendor_ext_m1;
#define MAX_WPS_VENDOR_EXT 10
@@ -974,7 +977,7 @@
int go_venue_type;
/**
- * hessid - Homogenous ESS identifier
+ * hessid - Homogeneous ESS identifier
*
* If this is set (any octet is non-zero), scans will be used to
* request response only from BSSes belonging to the specified
@@ -1058,6 +1061,7 @@
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 52e1372..74f91d3 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -876,9 +876,10 @@
write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1);
INT(disabled);
INT(mixed_cell);
- INT(vht);
+ INT_DEF(vht, 1);
INT_DEF(ht, 1);
INT(ht40);
+ INT_DEF(he, 1);
INT_DEF(max_oper_chwidth, DEFAULT_MAX_OPER_CHWIDTH);
INT(vht_center_freq1);
INT(vht_center_freq2);
@@ -928,6 +929,7 @@
STR(dpp_netaccesskey);
INT(dpp_netaccesskey_expiry);
STR(dpp_csign);
+ STR(dpp_pp_key);
INT(dpp_pfs);
#endif /* CONFIG_DPP */
INT(owe_group);
@@ -937,6 +939,7 @@
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);
@@ -1332,6 +1335,10 @@
if (config->p2p_go_freq_change_policy != DEFAULT_P2P_GO_FREQ_MOVE)
fprintf(f, "p2p_go_freq_change_policy=%u\n",
config->p2p_go_freq_change_policy);
+
+ if (config->p2p_6ghz_disable)
+ fprintf(f, "p2p_6ghz_disable=%d\n", config->p2p_6ghz_disable);
+
if (WPA_GET_BE32(config->ip_addr_go))
fprintf(f, "ip_addr_go=%u.%u.%u.%u\n",
config->ip_addr_go[0], config->ip_addr_go[1],
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 6737223..ecf258c 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -61,6 +61,12 @@
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
*
@@ -1017,6 +1023,16 @@
size_t dpp_csign_len;
/**
+ * dpp_pp_key - ppKey (Configurator privacy protection public key)
+ */
+ u8 *dpp_pp_key;
+
+ /**
+ * dpp_pp_key_len - ppKey length in octets
+ */
+ size_t dpp_pp_key_len;
+
+ /**
* dpp_pfs - DPP PFS
* 0: allow PFS to be used or not used
* 1: require PFS to be used (note: not compatible with DPP R1)
@@ -1120,6 +1136,25 @@
* 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;
+
+ /**
+ * was_recently_reconfigured - Whether this SSID config has been changed
+ * recently
+ *
+ * This is an internally used variable, i.e., not used in external
+ * configuration.
+ */
+ bool was_recently_reconfigured;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index f2d4d01..f5c6587 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -751,6 +751,26 @@
}
} else if (os_strcasecmp(cmd, "ft_rsnxe_used") == 0) {
wpa_s->ft_rsnxe_used = atoi(value);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_eapol") == 0) {
+ wpa_s->oci_freq_override_eapol = atoi(value);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_saquery_req") == 0) {
+ 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)
@@ -878,6 +898,8 @@
ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
if (ret == 0)
wpa_supplicant_update_config(wpa_s);
+ else if (ret == 1)
+ ret = 0;
}
return ret;
@@ -2277,8 +2299,12 @@
!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;
@@ -2934,7 +2960,7 @@
{
char *pos, *end;
int ret;
- const u8 *ie, *ie2, *osen_ie, *p2p, *mesh, *owe;
+ const u8 *ie, *ie2, *osen_ie, *p2p, *mesh, *owe, *rsnxe;
mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
@@ -2961,6 +2987,21 @@
pos = wpa_supplicant_ie_txt(pos, end, mesh ? "RSN" : "WPA2",
ie2, 2 + ie2[1]);
}
+ rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ if (rsnxe && rsnxe[1] >= 1) {
+ if (rsnxe[2] & BIT(WLAN_RSNX_CAPAB_SAE_H2E)) {
+ ret = os_snprintf(pos, end - pos, "[SAE-H2E]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ if (rsnxe[2] & BIT(WLAN_RSNX_CAPAB_SAE_PK)) {
+ ret = os_snprintf(pos, end - pos, "[SAE-PK]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ }
osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
if (osen_ie)
pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
@@ -3439,38 +3480,12 @@
struct wpa_supplicant *wpa_s, char *cmd)
{
int id;
- struct wpa_ssid *ssid;
int result;
/* cmd: "<network id>" or "all" */
if (os_strcmp(cmd, "all") == 0) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
- if (wpa_s->sched_scanning)
- wpa_supplicant_cancel_sched_scan(wpa_s);
-
- eapol_sm_invalidate_cached_session(wpa_s->eapol);
- if (wpa_s->current_ssid) {
-#ifdef CONFIG_SME
- wpa_s->sme.prev_bssid_set = 0;
-#endif /* CONFIG_SME */
- wpa_sm_set_config(wpa_s->wpa, NULL);
- eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
- if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
- wpa_s->own_disconnect_req = 1;
- wpa_supplicant_deauthenticate(
- wpa_s, WLAN_REASON_DEAUTH_LEAVING);
- }
- ssid = wpa_s->conf->ssid;
- while (ssid) {
- struct wpa_ssid *remove_ssid = ssid;
- id = ssid->id;
- ssid = ssid->next;
- if (wpa_s->last_ssid == remove_ssid)
- wpa_s->last_ssid = NULL;
- wpas_notify_network_removed(wpa_s, remove_ssid);
- wpa_config_remove_network(wpa_s->conf, id);
- }
- return 0;
+ return wpa_supplicant_remove_all_networks(wpa_s);
}
id = atoi(cmd);
@@ -3506,6 +3521,20 @@
if (ret == 1)
return 0; /* No change to the previously configured value */
+#ifdef CONFIG_BGSCAN
+ if (os_strcmp(name, "bgscan") == 0) {
+ /*
+ * Reset the bgscan parameters for the current network and
+ * return. There's no need to flush caches for bgscan parameter
+ * changes.
+ */
+ if (wpa_s->current_ssid == ssid &&
+ wpa_s->wpa_state == WPA_COMPLETED)
+ wpa_supplicant_reset_bgscan(wpa_s);
+ return 0;
+ }
+#endif /* CONFIG_BGSCAN */
+
if (os_strcmp(name, "bssid") != 0 &&
os_strcmp(name, "bssid_hint") != 0 &&
os_strcmp(name, "priority") != 0) {
@@ -4771,6 +4800,20 @@
}
#endif /* CONFIG_DPP */
+#ifdef CONFIG_SAE
+ if (os_strcmp(field, "sae") == 0 &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
+#ifdef CONFIG_SAE_PK
+ res = os_snprintf(buf, buflen, "H2E PK");
+#else /* CONFIG_SAE_PK */
+ res = os_snprintf(buf, buflen, "H2E");
+#endif /* CONFIG_SAE_PK */
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+#endif /* CONFIG_SAE */
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
field);
@@ -4891,7 +4934,7 @@
size_t i;
int ret;
char *pos, *end;
- const u8 *ie, *ie2, *osen_ie, *mesh, *owe;
+ const u8 *ie, *ie2, *osen_ie, *mesh, *owe, *rsnxe;
pos = buf;
end = buf + buflen;
@@ -5011,6 +5054,21 @@
pos = wpa_supplicant_ie_txt(pos, end,
mesh ? "RSN" : "WPA2", ie2,
2 + ie2[1]);
+ rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ if (rsnxe && rsnxe[1] >= 1) {
+ if (rsnxe[2] & BIT(WLAN_RSNX_CAPAB_SAE_H2E)) {
+ ret = os_snprintf(pos, end - pos, "[SAE-H2E]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ if (rsnxe[2] & BIT(WLAN_RSNX_CAPAB_SAE_PK)) {
+ ret = os_snprintf(pos, end - pos, "[SAE-PK]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ }
osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
if (osen_ie)
pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
@@ -7398,7 +7456,7 @@
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];
@@ -7412,6 +7470,15 @@
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
@@ -7446,7 +7513,7 @@
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);
}
@@ -8325,9 +8392,10 @@
wpa_s->set_sta_uapsd = 0;
wpa_s->sta_uapsd = 0;
+ wpa_s->consecutive_conn_failures = 0;
+
wpa_drv_radio_disable(wpa_s, 0);
wpa_blacklist_clear(wpa_s);
- wpa_s->extra_blacklist_count = 0;
wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all");
wpa_config_flush_blobs(wpa_s->conf);
@@ -8381,6 +8449,13 @@
wpabuf_free(wpa_s->rsnxe_override_eapol);
wpa_s->rsnxe_override_eapol = NULL;
wpas_clear_driver_signal_override(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;
@@ -8399,6 +8474,7 @@
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)) {
@@ -8424,6 +8500,8 @@
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));
}
@@ -9264,7 +9342,7 @@
if (ip.ip_hl != 5 || ip.ip_v != 4 || ntohs(ip.ip_len) > HWSIM_IP_LEN) {
wpa_printf(MSG_DEBUG,
- "test data: RX - ignore unexpect IP header");
+ "test data: RX - ignore unexpected IP header");
return;
}
@@ -10258,6 +10336,76 @@
}
+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)
{
@@ -11142,13 +11290,16 @@
} 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/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 793a881..6dcd948 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -3212,6 +3212,14 @@
END_ARGS
}
},
+ { "Roam", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_roam,
+ {
+ { "addr", "s", ARG_IN },
+ END_ARGS
+ }
+ },
+
#ifndef CONFIG_NO_CONFIG_BLOBS
{ "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
(WPADBusMethodHandler) wpas_dbus_handler_add_blob,
@@ -3613,7 +3621,7 @@
},
{ "BridgeIfname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
wpas_dbus_getter_bridge_ifname,
- NULL,
+ wpas_dbus_setter_bridge_ifname,
NULL
},
{ "ConfigFile", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index d1f9607..86f8560 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -139,6 +139,7 @@
"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
"bssid", "scan_freq", "freq_list", "scan_ssid", "bssid_hint",
"bssid_blacklist", "bssid_whitelist", "group_mgmt",
+ "ignore_broadcast_ssid",
#ifdef CONFIG_MESH
"mesh_basic_rates",
#endif /* CONFIG_MESH */
@@ -229,8 +230,6 @@
} else if (entry.type == DBUS_TYPE_STRING) {
if (should_quote_opt(entry.key)) {
size = os_strlen(entry.str_value);
- if (size == 0)
- goto error;
size += 3;
value = os_zalloc(size);
@@ -267,8 +266,28 @@
} else
goto error;
- if (wpa_config_set(ssid, entry.key, value, 0) < 0)
+ ret = wpa_config_set(ssid, entry.key, value, 0);
+ if (ret < 0)
goto error;
+ if (ret == 1)
+ goto skip_update;
+
+#ifdef CONFIG_BGSCAN
+ if (os_strcmp(entry.key, "bgscan") == 0) {
+ /*
+ * Reset the bgscan parameters for the current network
+ * and continue. There's no need to flush caches for
+ * bgscan parameter changes.
+ */
+ if (wpa_s->current_ssid == ssid &&
+ wpa_s->wpa_state == WPA_COMPLETED)
+ wpa_supplicant_reset_bgscan(wpa_s);
+ os_free(value);
+ value = NULL;
+ wpa_dbus_dict_entry_clear(&entry);
+ continue;
+ }
+#endif /* CONFIG_BGSCAN */
if (os_strcmp(entry.key, "bssid") != 0 &&
os_strcmp(entry.key, "priority") != 0)
@@ -290,6 +309,7 @@
else if (os_strcmp(entry.key, "priority") == 0)
wpa_config_update_prio_list(wpa_s->conf);
+ skip_update:
os_free(value);
value = NULL;
wpa_dbus_dict_entry_clear(&entry);
@@ -1797,25 +1817,6 @@
}
-static void remove_network(void *arg, struct wpa_ssid *ssid)
-{
- struct wpa_supplicant *wpa_s = arg;
-
- wpas_notify_network_removed(wpa_s, ssid);
-
- if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
- wpa_printf(MSG_ERROR,
- "%s[dbus]: error occurred when removing network %d",
- __func__, ssid->id);
- return;
- }
-
- if (ssid == wpa_s->current_ssid)
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
-}
-
-
/**
* wpas_dbus_handler_remove_all_networks - Remove all configured networks
* @message: Pointer to incoming dbus message
@@ -1827,11 +1828,8 @@
DBusMessage * wpas_dbus_handler_remove_all_networks(
DBusMessage *message, struct wpa_supplicant *wpa_s)
{
- if (wpa_s->sched_scanning)
- wpa_supplicant_cancel_sched_scan(wpa_s);
-
/* NB: could check for failure and return an error */
- wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s);
+ wpa_supplicant_remove_all_networks(wpa_s);
return NULL;
}
@@ -1956,6 +1954,55 @@
}
+/**
+ * wpas_dbus_handler_roam - Initiate a roam to another BSS within the ESS
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "Roam" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_roam(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_NO_SCAN_PROCESSING
+ return wpas_dbus_error_unknown_error(message,
+ "scan processing not included");
+#else /* CONFIG_NO_SCAN_PROCESSING */
+ u8 bssid[ETH_ALEN];
+ struct wpa_bss *bss;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ char *addr;
+
+ if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_INVALID))
+ return wpas_dbus_error_invalid_args(message, NULL);
+
+ if (hwaddr_aton(addr, bssid))
+ return wpas_dbus_error_invalid_args(
+ message, "Invalid hardware address format");
+
+ wpa_printf(MSG_DEBUG, "dbus: Roam " MACSTR, MAC2STR(bssid));
+
+ if (!ssid)
+ return dbus_message_new_error(
+ message, WPAS_DBUS_ERROR_NOT_CONNECTED,
+ "This interface is not connected");
+
+ bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
+ if (!bss) {
+ wpa_printf(MSG_DEBUG, "dbus: Roam: Target BSS not found");
+ return wpas_dbus_error_invalid_args(
+ message, "Target BSS not found");
+ }
+
+ wpa_s->reassociate = 1;
+ wpa_supplicant_connect(wpa_s, bss, ssid);
+
+ return NULL;
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+}
+
#ifndef CONFIG_NO_CONFIG_BLOBS
/**
@@ -3634,6 +3681,43 @@
}
+dbus_bool_t wpas_dbus_setter_bridge_ifname(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ const char *bridge_ifname = NULL;
+ const char *msg;
+ int r;
+
+ if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+ &bridge_ifname))
+ return FALSE;
+
+ r = wpa_supplicant_update_bridge_ifname(wpa_s, bridge_ifname);
+ if (r != 0) {
+ switch (r) {
+ case -EINVAL:
+ msg = "invalid interface name";
+ break;
+ case -EBUSY:
+ msg = "interface is busy";
+ break;
+ case -EIO:
+ msg = "socket error";
+ break;
+ default:
+ msg = "unknown error";
+ break;
+ }
+ dbus_set_error_const(error, DBUS_ERROR_FAILED, msg);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
/**
* wpas_dbus_getter_config_file - Get interface configuration file path
* @iter: Pointer to incoming dbus message iter
@@ -3941,14 +4025,15 @@
return FALSE;
}
- if (wpa_config_process_global(wpa_s->conf, buf, -1)) {
+ ret = wpa_config_process_global(wpa_s->conf, buf, -1);
+ if (ret < 0) {
dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
"Failed to set interface property %s",
property_desc->dbus_property);
return FALSE;
+ } else if (ret == 0) {
+ wpa_supplicant_update_config(wpa_s);
}
-
- wpa_supplicant_update_config(wpa_s);
return TRUE;
}
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index afa26ef..c36383f 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -117,6 +117,9 @@
DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_roam(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
struct wpa_supplicant *wpa_s);
@@ -167,6 +170,7 @@
DECLARE_ACCESSOR(wpas_dbus_getter_ifname);
DECLARE_ACCESSOR(wpas_dbus_getter_driver);
DECLARE_ACCESSOR(wpas_dbus_getter_bridge_ifname);
+DECLARE_ACCESSOR(wpas_dbus_setter_bridge_ifname);
DECLARE_ACCESSOR(wpas_dbus_getter_config_file);
DECLARE_ACCESSOR(wpas_dbus_getter_current_bss);
DECLARE_ACCESSOR(wpas_dbus_getter_current_network);
diff --git a/wpa_supplicant/doc/docbook/.gitignore b/wpa_supplicant/doc/docbook/.gitignore
index 8c3945c..dac35c5 100644
--- a/wpa_supplicant/doc/docbook/.gitignore
+++ b/wpa_supplicant/doc/docbook/.gitignore
@@ -1,5 +1,6 @@
manpage.links
manpage.refs
+manpage.log
*.8
*.5
*.html
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index 8c2e302..2d0c636 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"
@@ -49,6 +50,9 @@
#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 };
@@ -89,6 +93,10 @@
500, wpas_dpp_tx_status, 0);
}
+#ifdef CONFIG_DPP2
+ dpp_controller_new_qr_code(wpa_s->dpp, bi);
+#endif /* CONFIG_DPP2 */
+
return bi->id;
}
@@ -832,7 +840,9 @@
#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;
@@ -1185,6 +1195,15 @@
ssid->dpp_csign_len = wpabuf_len(conf->c_sign_key);
}
+ if (conf->pp_key) {
+ ssid->dpp_pp_key = os_malloc(wpabuf_len(conf->pp_key));
+ if (!ssid->dpp_pp_key)
+ goto fail;
+ os_memcpy(ssid->dpp_pp_key, wpabuf_head(conf->pp_key),
+ wpabuf_len(conf->pp_key));
+ ssid->dpp_pp_key_len = wpabuf_len(conf->pp_key);
+ }
+
if (auth->net_access_key) {
ssid->dpp_netaccesskey =
os_malloc(wpabuf_len(auth->net_access_key));
@@ -1220,6 +1239,102 @@
}
}
+#if defined(CONFIG_DPP2) && defined(IEEE8021X_EAPOL)
+ 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 && IEEE8021X_EAPOL */
+
os_memcpy(wpa_s->dpp_last_ssid, conf->ssid, conf->ssid_len);
wpa_s->dpp_last_ssid_len = conf->ssid_len;
@@ -1329,6 +1444,20 @@
os_free(hex);
}
}
+ if (conf->pp_key) {
+ char *hex;
+ size_t hexlen;
+
+ hexlen = 2 * wpabuf_len(conf->pp_key) + 1;
+ hex = os_malloc(hexlen);
+ if (hex) {
+ wpa_snprintf_hex(hex, hexlen,
+ wpabuf_head(conf->pp_key),
+ wpabuf_len(conf->pp_key));
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PP_KEY "%s", hex);
+ os_free(hex);
+ }
+ }
if (auth->net_access_key) {
char *hex;
size_t hexlen;
@@ -1351,6 +1480,32 @@
}
}
+#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);
}
@@ -1366,6 +1521,7 @@
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);
@@ -1381,6 +1537,31 @@
}
+#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,
@@ -1425,11 +1606,20 @@
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]);
@@ -1475,6 +1665,9 @@
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:
@@ -1828,6 +2021,8 @@
wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
r_bootstrap, r_bootstrap_len);
peer_bi = dpp_bootstrap_find_chirp(wpa_s->dpp, r_bootstrap);
+ dpp_notify_chirp_received(wpa_s, peer_bi ? (int) peer_bi->id : -1, src,
+ freq, r_bootstrap);
if (!peer_bi) {
wpa_printf(MSG_DEBUG,
"DPP: No matching bootstrapping information found");
@@ -1879,11 +2074,12 @@
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;
@@ -1913,7 +2109,21 @@
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);
@@ -1963,17 +2173,29 @@
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,
@@ -2667,8 +2889,8 @@
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;
@@ -2699,6 +2921,16 @@
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);
wpas_notify_dpp_configuration_failure(wpa_s);
@@ -2726,6 +2958,14 @@
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);
@@ -3087,10 +3327,8 @@
return -1;
os_memset(&config, 0, sizeof(config));
- config.msg_ctx = wpa_s;
config.cb_ctx = wpa_s;
#ifdef CONFIG_DPP2
- config.process_conf_obj = wpas_dpp_process_conf_obj;
config.remove_bi = wpas_dpp_remove_bi;
#endif /* CONFIG_DPP2 */
wpa_s->dpp = dpp_global_init(&config);
@@ -3111,7 +3349,6 @@
#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);
@@ -3123,9 +3360,12 @@
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);
@@ -3134,6 +3374,7 @@
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);
}
@@ -3146,6 +3387,10 @@
os_memset(&config, 0, sizeof(config));
config.allowed_roles = DPP_CAPAB_ENROLLEE | DPP_CAPAB_CONFIGURATOR;
+ config.netrole = DPP_NETROLE_STA;
+ config.msg_ctx = wpa_s;
+ config.cb_ctx = wpa_s;
+ config.process_conf_obj = wpas_dpp_process_conf_obj;
if (cmd) {
pos = os_strstr(cmd, " tcp_port=");
if (pos) {
@@ -3166,6 +3411,8 @@
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);
@@ -3208,13 +3455,26 @@
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;
@@ -3228,6 +3488,8 @@
wpabuf_head(msg), wpabuf_len(msg),
2000, wpas_dpp_chirp_tx_status, 0) < 0)
wpas_dpp_chirp_stop(wpa_s);
+
+ wpabuf_free(announce);
}
@@ -3239,8 +3501,9 @@
struct hostapd_hw_modes *mode;
int c;
struct wpa_bss *bss;
+ bool chan6;
- if (!bi && !wpa_s->dpp_reconfig_announcement)
+ if (!bi && !wpa_s->dpp_reconfig_ssid)
return;
wpa_s->dpp_chirp_scan_done = 1;
@@ -3256,7 +3519,22 @@
}
/* Preferred chirping channels */
- int_array_add_unique(&wpa_s->dpp_chirp_freqs, 2437);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ HOSTAPD_MODE_IEEE80211G, 0);
+ chan6 = mode == NULL;
+ if (mode) {
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+
+ if ((chan->flag & HOSTAPD_CHAN_DISABLED) ||
+ chan->freq != 2437)
+ continue;
+ chan6 = true;
+ break;
+ }
+ }
+ if (chan6)
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs, 2437);
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
HOSTAPD_MODE_IEEE80211A, 0);
@@ -3428,15 +3706,13 @@
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;
@@ -3452,23 +3728,55 @@
}
-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)
- return -1;
+ 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,
+ ssid->dpp_pp_key,
+ ssid->dpp_pp_key_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;
@@ -3476,4 +3784,111 @@
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 @@
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 @@
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 6b33ee3..fd4511d 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -356,6 +356,9 @@
int pmksa_set = -1;
size_t i;
+ /* Start with assumption of no PMKSA cache entry match */
+ pmksa_cache_clear_current(wpa_s->wpa);
+
if (wpa_sm_parse_own_wpa_ie(wpa_s->wpa, &ie) < 0 ||
ie.pmkid == NULL)
return;
@@ -1080,32 +1083,407 @@
}
+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, int blacklist_count,
+ 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) {
+ int count;
+ 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;
+
+ count = wpa_blacklist_is_blacklisted(wpa_s, bss->bssid);
+ if (wpa_scan_res_ok(wpa_s, ssid, match_ssid, match_ssid_len,
+ bss, count, 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, int blacklist_count,
+ 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) && blacklist_count) {
+ 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;
+ int blacklist_count;
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;
@@ -1125,8 +1503,8 @@
osen ? " osen=1" : "");
}
- e = wpa_blacklist_get(wpa_s, bss->bssid);
- if (e) {
+ blacklist_count = wpa_blacklist_is_blacklisted(wpa_s, bss->bssid);
+ if (blacklist_count) {
int limit = 1;
if (wpa_supplicant_enabled_networks(wpa_s) == 1) {
/*
@@ -1139,11 +1517,11 @@
*/
limit = 0;
}
- if (e->count > limit) {
+ if (blacklist_count > limit) {
if (debug_print) {
wpa_dbg(wpa_s, MSG_DEBUG,
" skip - blacklisted (count=%d limit=%d)",
- e->count, limit);
+ blacklist_count, limit);
}
return NULL;
}
@@ -1177,299 +1555,10 @@
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, blacklist_count, debug_print))
+ return ssid;
}
/* No matching configuration found */
@@ -1769,52 +1858,19 @@
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 */
+ int ret = 0;
- 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
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",
@@ -1933,13 +1989,64 @@
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 */
@@ -2571,11 +2678,11 @@
{
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);
@@ -2718,7 +2825,7 @@
#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)) {
@@ -2753,7 +2860,7 @@
#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,
@@ -2813,7 +2920,7 @@
/* 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,
@@ -2831,6 +2938,11 @@
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;
@@ -4164,6 +4276,13 @@
}
#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)
@@ -4402,7 +4521,9 @@
* WLAN_STATUS_AKMP_NOT_VALID is addressed in the same manner as an
* interoperability workaround with older hostapd implementation. */
if (DPP_VERSION > 1 && wpa_s->current_ssid &&
- wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_DPP &&
+ (wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_DPP ||
+ ((wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
+ wpa_s->key_mgmt == WPA_KEY_MGMT_DPP)) &&
wpa_s->current_ssid->dpp_pfs == 0 &&
(data->assoc_reject.status_code ==
WLAN_STATUS_ASSOC_DENIED_UNSPEC ||
@@ -4865,7 +4986,9 @@
}
#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;
@@ -5376,8 +5499,6 @@
return;
wpa_s = wpa_supplicant_add_iface(ctx, wpa_i, NULL);
os_free(wpa_i);
- if (wpa_s)
- wpa_s->matched = 1;
}
#endif /* CONFIG_MATCH_IFACE */
diff --git a/wpa_supplicant/examples/dpp-nfc.py b/wpa_supplicant/examples/dpp-nfc.py
index 1883545..8e865f3 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 @@
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 @@
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 @@
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 @@
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 @@
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,43 @@
raise Exception("Failed to generate bootstrapping info")
return int(res)
-def wpas_get_nfc_uri(start_listen=True, pick_channel=False):
+def dpp_start_listen(wpas, 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"
+ global netrole
+ if netrole:
+ cmd += " netrole=" + netrole
+ summary(cmd)
+ res = wpas.request(cmd)
+ if "OK" not in res:
+ summary("Failed to start DPP listen", color=C_RED)
+ return False
+ return True
+
+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 +236,18 @@
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")
+ if not dpp_start_listen(wpas, listen_freq):
+ raise Exception("Failed to start listen operation on %d MHz" % listen_freq)
return res
def wpas_report_handover_req(uri):
@@ -219,82 +266,180 @@
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 +448,19 @@
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 +480,7 @@
# 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 +490,23 @@
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 +515,67 @@
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 +584,33 @@
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 +628,73 @@
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 not dpp_start_listen(wpas, freq):
+ break
carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
summary("Own DPP carrier record: " + str(carrier))
@@ -492,11 +704,26 @@
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 +780,25 @@
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 +809,7 @@
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 +818,7 @@
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 +827,7 @@
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 +841,7 @@
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 +859,24 @@
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 +884,18 @@
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 +905,7 @@
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 +916,73 @@
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 +1026,53 @@
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 +1108,22 @@
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 +1133,14 @@
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 +1162,18 @@
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 @@
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/hidl/1.4/hidl.cpp b/wpa_supplicant/hidl/1.4/hidl.cpp
index c664e15..0145576 100644
--- a/wpa_supplicant/hidl/1.4/hidl.cpp
+++ b/wpa_supplicant/hidl/1.4/hidl.cpp
@@ -250,13 +250,13 @@
void wpas_hidl_notify_hs20_rx_deauth_imminent_notice(
struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url)
{
- if (!wpa_s || !wpa_s->global->hidl || !url)
+ if (!wpa_s || !wpa_s->global->hidl)
return;
wpa_printf(
MSG_DEBUG,
"Notifying HS20 deauth imminent notice rx to hidl control: %s",
- url);
+ url ? url : "<no URL>");
HidlManager *hidl_manager = HidlManager::getInstance();
if (!hidl_manager)
@@ -266,6 +266,23 @@
wpa_s, code, reauth_delay, url);
}
+void wpas_hidl_notify_hs20_rx_terms_and_conditions_acceptance(
+ struct wpa_supplicant *wpa_s, const char *url)
+{
+ if (!wpa_s || !wpa_s->global->hidl || !url)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "Notifying HS20 terms and conditions acceptance rx to hidl control: %s",
+ url);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyHs20RxTermsAndConditionsAcceptance(wpa_s, url);
+}
+
void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s)
{
if (!wpa_s)
@@ -876,3 +893,17 @@
hidl_manager->notifyBssTmStatus(wpa_s);
}
+
+void wpas_hidl_notify_transition_disable(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ u8 bitmap)
+{
+ if (!wpa_s || !ssid)
+ return;
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyTransitionDisable(wpa_s, ssid, bitmap);
+}
diff --git a/wpa_supplicant/hidl/1.4/hidl.h b/wpa_supplicant/hidl/1.4/hidl.h
index bf03bf9..671dd41 100644
--- a/wpa_supplicant/hidl/1.4/hidl.h
+++ b/wpa_supplicant/hidl/1.4/hidl.h
@@ -49,6 +49,8 @@
void wpas_hidl_notify_hs20_rx_deauth_imminent_notice(
struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay,
const char *url);
+ void wpas_hidl_notify_hs20_rx_terms_and_conditions_acceptance(
+ struct wpa_supplicant *wpa_s, const char *url);
void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s,
const u8 *bssid, u8 timed_out);
@@ -121,6 +123,8 @@
void wpas_hidl_notify_pmk_cache_added(
struct wpa_supplicant *wpas, struct rsn_pmksa_cache_entry *pmksa_entry);
void wpas_hidl_notify_bss_tm_status(struct wpa_supplicant *wpa_s);
+ void wpas_hidl_notify_transition_disable(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, u8 bitmap);
#else // CONFIG_CTRL_IFACE_HIDL
static inline int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s)
{
@@ -164,6 +168,9 @@
static void wpas_hidl_notify_hs20_rx_deauth_imminent_notice(
struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url)
{}
+void wpas_hidl_notify_hs20_rx_terms_and_conditions_acceptance(
+ struct wpa_supplicant *wpa_s, const char *url)
+{}
static void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s) {}
static void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s,
const u8 *bssid, u8 timed_out) {}
@@ -263,6 +270,10 @@
{}
void wpas_hidl_notify_bss_tm_status(struct wpa_supplicant *wpa_s)
{}
+static void wpas_hidl_notify_transition_disable(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ u8 bitmap)
+{}
#endif // CONFIG_CTRL_IFACE_HIDL
#ifdef _cplusplus
diff --git a/wpa_supplicant/hidl/1.4/hidl_manager.cpp b/wpa_supplicant/hidl/1.4/hidl_manager.cpp
index b44f0fd..d7136a6 100644
--- a/wpa_supplicant/hidl/1.4/hidl_manager.cpp
+++ b/wpa_supplicant/hidl/1.4/hidl_manager.cpp
@@ -323,6 +323,38 @@
}
}
+template <class CallbackTypeBase, class CallbackTypeDerived>
+void callWithEachNetworkCallbackDerived(
+ const std::string &ifname, int network_id,
+ const std::function<
+ android::hardware::Return<void>(android::sp<CallbackTypeDerived>)> &method,
+ const std::map<
+ const std::string, std::vector<android::sp<CallbackTypeBase>>>
+ &callbacks_map)
+{
+ if (ifname.empty())
+ return;
+
+ // Generate the key to be used to lookup the network.
+ const std::string network_key =
+ getNetworkObjectMapKey(ifname, network_id);
+ auto network_callback_map_iter = callbacks_map.find(network_key);
+ if (network_callback_map_iter == callbacks_map.end())
+ return;
+ const auto &network_callback_list = network_callback_map_iter->second;
+ for (const auto &callback : network_callback_list) {
+ android::sp<CallbackTypeDerived> callback_derived =
+ CallbackTypeDerived::castFrom(callback);
+ if (callback_derived == nullptr)
+ continue;
+ if (!method(callback_derived).isOk()) {
+ wpa_printf(
+ MSG_ERROR,
+ "Failed to invoke HIDL network callback");
+ }
+ }
+}
+
int parseGsmAuthNetworkRequest(
const std::string ¶ms_str,
std::vector<hidl_array<uint8_t, kGsmRandLenBytes>> *out_rands)
@@ -888,18 +920,18 @@
}
/**
- * Notify all listeners about the reception of HS20 immient deauth
+ * Notify all listeners about the reception of HS20 imminent deauth
* notification from the server.
*
* @param wpa_s |wpa_supplicant| struct corresponding to the interface.
* @param code Deauth reason code sent from server.
* @param reauth_delay Reauthentication delay in seconds sent from server.
- * @param url URL of the server.
+ * @param url URL of the server containing the reason text.
*/
void HidlManager::notifyHs20RxDeauthImminentNotice(
struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url)
{
- if (!wpa_s || !url)
+ if (!wpa_s)
return;
if (sta_iface_object_map_.find(wpa_s->ifname) ==
@@ -914,6 +946,30 @@
}
/**
+ * Notify all listeners about the reception of HS20 terms and conditions
+ * acceptance notification from the server.
+ *
+ * @param wpa_s |wpa_supplicant| struct corresponding to the interface.
+ * @param url URL of the T&C server.
+ */
+void HidlManager::notifyHs20RxTermsAndConditionsAcceptance(
+ struct wpa_supplicant *wpa_s, const char *url)
+{
+ if (!wpa_s || !url)
+ return;
+
+ if (sta_iface_object_map_.find(wpa_s->ifname)
+ == sta_iface_object_map_.end())
+ return;
+
+ callWithEachStaIfaceCallback_1_4(wpa_s->ifname,
+ std::bind(
+ &V1_4::ISupplicantStaIfaceCallback
+ ::onHs20TermsAndConditionsAcceptanceRequestedNotification,
+ std::placeholders::_1, wpa_s->bssid, url));
+}
+
+/**
* Notify all listeners about the reason code for disconnection from the
* currently connected network.
*
@@ -1737,6 +1793,56 @@
#endif
}
+uint32_t setTransitionDisableFlagsMask(u8 bitmap)
+{
+ uint32_t flags = 0;
+
+ if (bitmap & TRANSITION_DISABLE_WPA3_PERSONAL) {
+ flags |= V1_4::ISupplicantStaNetworkCallback::
+ TransitionDisableIndication::
+ USE_WPA3_PERSONAL;
+ bitmap &= ~TRANSITION_DISABLE_WPA3_PERSONAL;
+ }
+ if (bitmap & TRANSITION_DISABLE_SAE_PK) {
+ flags |= V1_4::ISupplicantStaNetworkCallback::
+ TransitionDisableIndication::
+ USE_SAE_PK;
+ bitmap &= ~TRANSITION_DISABLE_SAE_PK;
+ }
+ if (bitmap & TRANSITION_DISABLE_WPA3_ENTERPRISE) {
+ flags |= V1_4::ISupplicantStaNetworkCallback::
+ TransitionDisableIndication::
+ USE_WPA3_ENTERPRISE;
+ bitmap &= ~TRANSITION_DISABLE_WPA3_ENTERPRISE;
+ }
+ if (bitmap & TRANSITION_DISABLE_ENHANCED_OPEN) {
+ flags |= V1_4::ISupplicantStaNetworkCallback::
+ TransitionDisableIndication::
+ USE_ENHANCED_OPEN;
+ bitmap &= ~TRANSITION_DISABLE_ENHANCED_OPEN;
+ }
+
+ if (bitmap != 0) {
+ wpa_printf(MSG_WARNING, "Unhandled transition disable bit: 0x%x", bitmap);
+ }
+
+ return flags;
+}
+
+void HidlManager::notifyTransitionDisable(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid, u8 bitmap)
+{
+ uint32_t flag = setTransitionDisableFlagsMask(bitmap);
+ const std::function<
+ Return<void>(android::sp<V1_4::ISupplicantStaNetworkCallback>)>
+ func = std::bind(
+ &V1_4::ISupplicantStaNetworkCallback::onTransitionDisable,
+ std::placeholders::_1, flag);
+
+ callWithEachStaNetworkCallbackDerived(wpa_s->ifname, ssid->id, func);
+}
+
+
/**
* Retrieve the |ISupplicantP2pIface| hidl object reference using the provided
* ifname.
@@ -2123,6 +2229,23 @@
/**
* Helper function to invoke the provided callback method on all the
+ * registered V1.4 interface callback hidl objects for the specified
+ * |ifname|.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param method Pointer to the required hidl method from
+ * |V1_4::ISupplicantIfaceCallback|.
+ */
+void HidlManager::callWithEachStaIfaceCallback_1_4(
+ const std::string &ifname,
+ const std::function<
+ Return<void>(android::sp<V1_4::ISupplicantStaIfaceCallback>)> &method)
+{
+ callWithEachIfaceCallbackDerived(ifname, method, sta_iface_callbacks_map_);
+}
+
+/**
+ * Helper function to invoke the provided callback method on all the
* registered derived interface callback hidl objects for the specified
* |ifname|.
*
@@ -2193,6 +2316,24 @@
callWithEachNetworkCallback(
ifname, network_id, method, sta_network_callbacks_map_);
}
+
+/**
+ * Helper function to invoke the provided callback method on all the
+ * registered derived interface callback hidl objects for the specified
+ * |ifname|.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param method Pointer to the required hidl method from
+ * derived |V1_x::ISupplicantIfaceCallback|.
+ */
+template <class CallbackTypeDerived>
+void HidlManager::callWithEachStaNetworkCallbackDerived(
+ const std::string &ifname, int network_id,
+ const std::function<
+ Return<void>(android::sp<CallbackTypeDerived>)> &method)
+{
+ callWithEachNetworkCallbackDerived(ifname, network_id, method, sta_network_callbacks_map_);
+}
} // namespace implementation
} // namespace V1_4
} // namespace supplicant
diff --git a/wpa_supplicant/hidl/1.4/hidl_manager.h b/wpa_supplicant/hidl/1.4/hidl_manager.h
index 496ceae..e3d6312 100644
--- a/wpa_supplicant/hidl/1.4/hidl_manager.h
+++ b/wpa_supplicant/hidl/1.4/hidl_manager.h
@@ -18,6 +18,7 @@
#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetworkCallback.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetworkCallback.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicantStaNetworkCallback.h>
#include "p2p_iface.h"
#include "p2p_network.h"
@@ -101,7 +102,9 @@
struct wpa_supplicant *wpa_s, const char *url, u8 osu_method);
void notifyHs20RxDeauthImminentNotice(
struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay,
- const char *url);
+ const char *url);
+ void notifyHs20RxTermsAndConditionsAcceptance(
+ struct wpa_supplicant *wpa_s, const char *url);
void notifyDisconnectReason(struct wpa_supplicant *wpa_s);
void notifyAssocReject(struct wpa_supplicant *wpa_s,
const u8 *bssid, u8 timed_out);
@@ -166,6 +169,9 @@
void notifyPmkCacheAdded(struct wpa_supplicant *wpa_s,
struct rsn_pmksa_cache_entry *pmksa_entry);
void notifyBssTmStatus(struct wpa_supplicant *wpa_s);
+ void notifyTransitionDisable(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ u8 bitmap);
// Methods called from hidl objects.
void notifyExtRadioWorkStart(struct wpa_supplicant *wpa_s, uint32_t id);
@@ -245,6 +251,10 @@
const std::string &ifname,
const std::function<android::hardware::Return<void>(
android::sp<V1_3::ISupplicantStaIfaceCallback>)> &method);
+ void callWithEachStaIfaceCallback_1_4(
+ const std::string &ifname,
+ const std::function<android::hardware::Return<void>(
+ android::sp<V1_4::ISupplicantStaIfaceCallback>)> &method);
template <class CallbackTypeDerived>
void callWithEachStaIfaceCallbackDerived(
const std::string &ifname,
@@ -258,6 +268,11 @@
const std::string &ifname, int network_id,
const std::function<android::hardware::Return<void>(
android::sp<ISupplicantStaNetworkCallback>)> &method);
+ template <class CallbackTypeDerived>
+ void callWithEachStaNetworkCallbackDerived(
+ const std::string &ifname, int network_id,
+ const std::function<
+ Return<void>(android::sp<CallbackTypeDerived>)> &method);
// Singleton instance of this class.
static HidlManager *instance_;
diff --git a/wpa_supplicant/hidl/1.4/hidl_return_util.h b/wpa_supplicant/hidl/1.4/hidl_return_util.h
index d285164..217f215 100644
--- a/wpa_supplicant/hidl/1.4/hidl_return_util.h
+++ b/wpa_supplicant/hidl/1.4/hidl_return_util.h
@@ -17,7 +17,6 @@
namespace V1_4 {
namespace implementation {
namespace hidl_return_util {
-using V1_0::SupplicantStatusCode;
/**
* These utility functions are used to invoke a method on the provided
@@ -30,10 +29,11 @@
* provided error status and default values.
*/
// Use for HIDL methods which return only an instance of SupplicantStatus.
-template <typename ObjT, typename WorkFuncT, typename... Args>
+template <typename ObjT, typename SupplicantStatusCodeT, typename WorkFuncT,
+ typename SupplicantStatusT, typename... Args>
Return<void> validateAndCall(
- ObjT* obj, SupplicantStatusCode status_code_if_invalid, WorkFuncT&& work,
- const std::function<void(const SupplicantStatus&)>& hidl_cb, Args&&... args)
+ ObjT* obj, SupplicantStatusCodeT status_code_if_invalid, WorkFuncT&& work,
+ const std::function<void(const SupplicantStatusT&)>& hidl_cb, Args&&... args)
{
if (obj->isValid()) {
hidl_cb((obj->*work)(std::forward<Args>(args)...));
@@ -45,16 +45,17 @@
// Use for HIDL methods which return instance of SupplicantStatus and a single
// return value.
-template <typename ObjT, typename WorkFuncT, typename ReturnT, typename... Args>
+template <typename ObjT, typename SupplicantStatusCodeT, typename WorkFuncT,
+ typename SupplicantStatusT, typename ReturnT, typename... Args>
Return<void> validateAndCall(
- ObjT* obj, SupplicantStatusCode status_code_if_invalid, WorkFuncT&& work,
- const std::function<void(const SupplicantStatus&, ReturnT)>& hidl_cb,
+ ObjT* obj, SupplicantStatusCodeT status_code_if_invalid, WorkFuncT&& work,
+ const std::function<void(const SupplicantStatusT&, ReturnT)>& hidl_cb,
Args&&... args)
{
if (obj->isValid()) {
const auto& ret_pair =
(obj->*work)(std::forward<Args>(args)...);
- const SupplicantStatus& status = std::get<0>(ret_pair);
+ const SupplicantStatusT& status = std::get<0>(ret_pair);
const auto& ret_value = std::get<1>(ret_pair);
hidl_cb(status, ret_value);
} else {
@@ -68,18 +69,18 @@
// Use for HIDL methods which return instance of SupplicantStatus and 2 return
// values.
template <
- typename ObjT, typename WorkFuncT, typename ReturnT1, typename ReturnT2,
- typename... Args>
+ typename ObjT, typename SupplicantStatusCodeT, typename WorkFuncT,
+ typename SupplicantStatusT, typename ReturnT1, typename ReturnT2, typename... Args>
Return<void> validateAndCall(
- ObjT* obj, SupplicantStatusCode status_code_if_invalid, WorkFuncT&& work,
- const std::function<void(const SupplicantStatus&, ReturnT1, ReturnT2)>&
+ ObjT* obj, SupplicantStatusCodeT status_code_if_invalid, WorkFuncT&& work,
+ const std::function<void(const SupplicantStatusT&, ReturnT1, ReturnT2)>&
hidl_cb,
Args&&... args)
{
if (obj->isValid()) {
const auto& ret_tuple =
(obj->*work)(std::forward<Args>(args)...);
- const SupplicantStatus& status = std::get<0>(ret_tuple);
+ const SupplicantStatusT& status = std::get<0>(ret_tuple);
const auto& ret_value1 = std::get<1>(ret_tuple);
const auto& ret_value2 = std::get<2>(ret_tuple);
hidl_cb(status, ret_value1, ret_value2);
diff --git a/wpa_supplicant/hidl/1.4/iface_config_utils.cpp b/wpa_supplicant/hidl/1.4/iface_config_utils.cpp
index b10523a..9af3ea9 100644
--- a/wpa_supplicant/hidl/1.4/iface_config_utils.cpp
+++ b/wpa_supplicant/hidl/1.4/iface_config_utils.cpp
@@ -84,6 +84,8 @@
namespace V1_4 {
namespace implementation {
namespace iface_config_utils {
+using V1_0::SupplicantStatusCode;
+
SupplicantStatus setWpsDeviceName(
struct wpa_supplicant* wpa_s, const std::string& name)
{
diff --git a/wpa_supplicant/hidl/1.4/p2p_iface.cpp b/wpa_supplicant/hidl/1.4/p2p_iface.cpp
index d3d374e..7baffa2 100644
--- a/wpa_supplicant/hidl/1.4/p2p_iface.cpp
+++ b/wpa_supplicant/hidl/1.4/p2p_iface.cpp
@@ -884,14 +884,14 @@
Return<void> P2pIface::setEdmg(bool enable, setEdmg_cb _hidl_cb)
{
return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ this, V1_4::SupplicantStatusCode::FAILURE_NETWORK_INVALID,
&P2pIface::setEdmgInternal, _hidl_cb, enable);
}
Return<void> P2pIface::getEdmg(getEdmg_cb _hidl_cb)
{
return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ this, V1_4::SupplicantStatusCode::FAILURE_NETWORK_INVALID,
&P2pIface::getEdmgInternal, _hidl_cb);
}
@@ -1796,14 +1796,6 @@
bool currentEnabledState = !!wpa_s->conf->p2p_device_random_mac_addr;
u8 *addr = NULL;
- // A dedicated p2p device is not managed by supplicant,
- // supplicant could not change its MAC address.
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) {
- wpa_printf(MSG_ERROR,
- "Dedicated P2P device don't support MAC randomization");
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, "NotSupported"};
- }
-
// The same state, no change is needed.
if (currentEnabledState == enable) {
wpa_printf(MSG_DEBUG, "The random MAC is %s already.",
@@ -1847,19 +1839,19 @@
return {SupplicantStatusCode::SUCCESS, ""};
}
-SupplicantStatus P2pIface::setEdmgInternal(bool enable)
+V1_4::SupplicantStatus P2pIface::setEdmgInternal(bool enable)
{
struct wpa_supplicant* wpa_s = retrieveIfacePtr();
wpa_printf(MSG_DEBUG, "set p2p_go_edmg to %d", enable);
wpa_s->conf->p2p_go_edmg = enable ? 1 : 0;
wpa_s->p2p_go_edmg = enable ? 1 : 0;
- return {SupplicantStatusCode::SUCCESS, ""};
+ return {V1_4::SupplicantStatusCode::SUCCESS, ""};
}
-std::pair<SupplicantStatus, bool> P2pIface::getEdmgInternal()
+std::pair<V1_4::SupplicantStatus, bool> P2pIface::getEdmgInternal()
{
struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- return {{SupplicantStatusCode::SUCCESS, ""},
+ return {{V1_4::SupplicantStatusCode::SUCCESS, ""},
(wpa_s->p2p_go_edmg == 1)};
}
diff --git a/wpa_supplicant/hidl/1.4/p2p_iface.h b/wpa_supplicant/hidl/1.4/p2p_iface.h
index 4d07051..1694efe 100644
--- a/wpa_supplicant/hidl/1.4/p2p_iface.h
+++ b/wpa_supplicant/hidl/1.4/p2p_iface.h
@@ -30,6 +30,8 @@
#include "config.h"
}
+#define P2P_MGMT_DEVICE_PREFIX "p2p-dev-"
+
namespace android {
namespace hardware {
namespace wifi {
@@ -307,8 +309,8 @@
bool persistent, uint32_t freq, const std::array<uint8_t, 6>& peer_address,
bool joinExistingGroup);
SupplicantStatus setMacRandomizationInternal(bool enable);
- SupplicantStatus setEdmgInternal(bool enable);
- std::pair<SupplicantStatus, bool> getEdmgInternal();
+ V1_4::SupplicantStatus setEdmgInternal(bool enable);
+ std::pair<V1_4::SupplicantStatus, bool> getEdmgInternal();
struct wpa_supplicant* retrieveIfacePtr();
struct wpa_supplicant* retrieveGroupIfacePtr(
diff --git a/wpa_supplicant/hidl/1.4/sta_iface.cpp b/wpa_supplicant/hidl/1.4/sta_iface.cpp
index 7f476b1..40ec870 100644
--- a/wpa_supplicant/hidl/1.4/sta_iface.cpp
+++ b/wpa_supplicant/hidl/1.4/sta_iface.cpp
@@ -228,6 +228,7 @@
namespace implementation {
using hidl_return_util::validateAndCall;
using V1_0::ISupplicantStaIfaceCallback;
+using V1_0::SupplicantStatusCode;
StaIface::StaIface(struct wpa_global *wpa_global, const char ifname[])
: wpa_global_(wpa_global), ifname_(ifname), is_valid_(true)
@@ -338,6 +339,16 @@
&StaIface::registerCallbackInternal, _hidl_cb, callback_1_3);
}
+Return<void> StaIface::registerCallback_1_4(
+ const sp<V1_4::ISupplicantStaIfaceCallback> &callback,
+ registerCallback_1_4_cb _hidl_cb)
+{
+ sp<V1_4::ISupplicantStaIfaceCallback> callback_1_4 = callback;
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::registerCallbackInternal_1_4, _hidl_cb, callback_1_4);
+}
+
Return<void> StaIface::reassociate(reassociate_cb _hidl_cb)
{
return validateAndCall(
@@ -770,7 +781,7 @@
getConnectionCapabilities_1_4_cb _hidl_cb)
{
return validateAndCall(
- this, SupplicantStatusCode::FAILURE_UNKNOWN,
+ this, V1_4::SupplicantStatusCode::FAILURE_UNKNOWN,
&StaIface::getConnectionCapabilitiesInternal_1_4, _hidl_cb);
}
@@ -821,12 +832,18 @@
SupplicantStatus StaIface::registerCallbackInternal(
const sp<ISupplicantStaIfaceCallback> &callback)
{
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"};
+}
+
+V1_4::SupplicantStatus StaIface::registerCallbackInternal_1_4(
+ const sp<V1_4::ISupplicantStaIfaceCallback> &callback)
+{
HidlManager *hidl_manager = HidlManager::getInstance();
if (!hidl_manager ||
hidl_manager->addStaIfaceCallbackHidlObject(ifname_, callback)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ return {V1_4::SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
- return {SupplicantStatusCode::SUCCESS, ""};
+ return {V1_4::SupplicantStatusCode::SUCCESS, ""};
}
SupplicantStatus StaIface::reassociateInternal()
@@ -952,9 +969,10 @@
static_cast<std::underlying_type<
ISupplicantStaIface::Hs20AnqpSubtypes>::type>(type));
}
+
if (anqp_send_req(
- wpa_s, mac_address.data(), info_elems_buf, num_info_elems,
- sub_types_bitmask, false)) {
+ wpa_s, mac_address.data(), 0, info_elems_buf, num_info_elems,
+ sub_types_bitmask, 0)) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -1437,7 +1455,7 @@
return {{SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"}, capa};
}
-std::pair<SupplicantStatus, ConnectionCapabilities>
+std::pair<V1_4::SupplicantStatus, ConnectionCapabilities>
StaIface::getConnectionCapabilitiesInternal_1_4()
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
@@ -1489,7 +1507,7 @@
capa.V1_3.maxNumberRxSpatialStreams = 1;
capa.legacyMode = LegacyMode::UNKNOWN;
}
- return {{SupplicantStatusCode::SUCCESS, ""}, capa};
+ return {{V1_4::SupplicantStatusCode::SUCCESS, ""}, capa};
}
std::pair<SupplicantStatus, uint32_t>
diff --git a/wpa_supplicant/hidl/1.4/sta_iface.h b/wpa_supplicant/hidl/1.4/sta_iface.h
index 1b8584d..b6590d3 100644
--- a/wpa_supplicant/hidl/1.4/sta_iface.h
+++ b/wpa_supplicant/hidl/1.4/sta_iface.h
@@ -16,7 +16,7 @@
#include <android-base/macros.h>
#include <android/hardware/wifi/supplicant/1.4/ISupplicantStaIface.h>
-#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIfaceCallback.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicantStaIfaceCallback.h>
#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
extern "C"
@@ -90,6 +90,9 @@
Return<void> registerCallback_1_3(
const sp<V1_3::ISupplicantStaIfaceCallback>& callback,
registerCallback_cb _hidl_cb) override;
+ Return<void> registerCallback_1_4(
+ const sp<V1_4::ISupplicantStaIfaceCallback> &callback,
+ registerCallback_1_4_cb _hidl_cb) override;
Return<void> reassociate(reassociate_cb _hidl_cb) override;
Return<void> reconnect(reconnect_cb _hidl_cb) override;
Return<void> disconnect(disconnect_cb _hidl_cb) override;
@@ -217,6 +220,8 @@
const sp<V1_0::ISupplicantStaIfaceCallback>& callback);
SupplicantStatus registerCallbackInternal_1_1(
const sp<V1_1::ISupplicantStaIfaceCallback>& callback);
+ V1_4::SupplicantStatus registerCallbackInternal_1_4(
+ const sp<V1_4::ISupplicantStaIfaceCallback>& callback);
SupplicantStatus reassociateInternal();
SupplicantStatus reconnectInternal();
SupplicantStatus disconnectInternal();
@@ -285,7 +290,7 @@
uint32_t own_bootstrap_id);
SupplicantStatus stopDppInitiatorInternal();
std::pair<SupplicantStatus, V1_3::ConnectionCapabilities> getConnectionCapabilitiesInternal();
- std::pair<SupplicantStatus, V1_4::ConnectionCapabilities>
+ std::pair<V1_4::SupplicantStatus, V1_4::ConnectionCapabilities>
getConnectionCapabilitiesInternal_1_4();
std::pair<SupplicantStatus, uint32_t> getWpaDriverCapabilitiesInternal();
SupplicantStatus setMboCellularDataStatusInternal(bool available);
diff --git a/wpa_supplicant/hidl/1.4/sta_network.cpp b/wpa_supplicant/hidl/1.4/sta_network.cpp
index a87c9eb..d62fdae 100644
--- a/wpa_supplicant/hidl/1.4/sta_network.cpp
+++ b/wpa_supplicant/hidl/1.4/sta_network.cpp
@@ -96,6 +96,9 @@
constexpr char kNetworkEapSimUmtsAutsResponse[] = "UMTS-AUTS";
constexpr char kNetworkEapSimGsmAuthFailure[] = "GSM-FAIL";
constexpr char kNetworkEapSimUmtsAuthFailure[] = "UMTS-FAIL";
+/* These constants refer definitions in wpa_supplicant/config.h */
+constexpr int SAE_PWE_H2E_ONLY_MODE = 1;
+constexpr int SAE_PWE_HP_H2E_BOTH = 2;
#ifdef CONFIG_WAPI_INTERFACE
std::string dummyWapiCertSuite;
@@ -110,6 +113,7 @@
namespace V1_4 {
namespace implementation {
using hidl_return_util::validateAndCall;
+using V1_0::SupplicantStatus;
using V1_0::SupplicantStatusCode;
StaNetwork::StaNetwork(
@@ -156,6 +160,15 @@
&StaNetwork::registerCallbackInternal, _hidl_cb, callback);
}
+Return<void> StaNetwork::registerCallback_1_4(
+ const sp<V1_4::ISupplicantStaNetworkCallback> &callback,
+ registerCallback_1_4_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::registerCallback_1_4Internal, _hidl_cb, callback);
+}
+
Return<void> StaNetwork::setSsid(
const hidl_vec<uint8_t> &ssid, setSsid_cb _hidl_cb)
{
@@ -415,7 +428,7 @@
Return<void> StaNetwork::setEdmg(bool enable, setEdmg_cb _hidl_cb)
{
return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ this, V1_4::SupplicantStatusCode::FAILURE_NETWORK_INVALID,
&StaNetwork::setEdmgInternal, _hidl_cb, enable);
}
@@ -650,7 +663,7 @@
Return<void> StaNetwork::getEdmg(getEdmg_cb _hidl_cb)
{
return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ this, V1_4::SupplicantStatusCode::FAILURE_NETWORK_INVALID,
&StaNetwork::getEdmgInternal, _hidl_cb);
}
@@ -949,14 +962,14 @@
uint32_t group_cipher_mask, setGroupCipher_1_4_cb _hidl_cb)
{
return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ this, V1_4::SupplicantStatusCode::FAILURE_NETWORK_INVALID,
&StaNetwork::setGroupCipher_1_4Internal, _hidl_cb, group_cipher_mask);
}
Return<void> StaNetwork::getGroupCipher_1_4(getGroupCipher_1_4_cb _hidl_cb)
{
return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ this, V1_4::SupplicantStatusCode::FAILURE_NETWORK_INVALID,
&StaNetwork::getGroupCipher_1_4Internal, _hidl_cb);
}
@@ -964,7 +977,7 @@
uint32_t pairwise_cipher_mask, setPairwiseCipher_1_4_cb _hidl_cb)
{
return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ this, V1_4::SupplicantStatusCode::FAILURE_NETWORK_INVALID,
&StaNetwork::setPairwiseCipher_1_4Internal, _hidl_cb,
pairwise_cipher_mask);
}
@@ -973,10 +986,17 @@
getPairwiseCipher_1_4_cb _hidl_cb)
{
return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ this, V1_4::SupplicantStatusCode::FAILURE_NETWORK_INVALID,
&StaNetwork::getPairwiseCipher_1_4Internal, _hidl_cb);
}
+Return<void> StaNetwork::enableSaeH2eOnlyMode(bool enable, enableSaeH2eOnlyMode_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, V1_4::SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::enableSaeH2eOnlyModeInternal, _hidl_cb, enable);
+}
+
std::pair<SupplicantStatus, uint32_t> StaNetwork::getIdInternal()
{
return {{SupplicantStatusCode::SUCCESS, ""}, network_id_};
@@ -995,12 +1015,18 @@
SupplicantStatus StaNetwork::registerCallbackInternal(
const sp<ISupplicantStaNetworkCallback> &callback)
{
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"};
+}
+
+V1_4::SupplicantStatus StaNetwork::registerCallback_1_4Internal(
+ const sp<V1_4::ISupplicantStaNetworkCallback> &callback)
+{
HidlManager *hidl_manager = HidlManager::getInstance();
if (!hidl_manager || hidl_manager->addStaNetworkCallbackHidlObject(
ifname_, network_id_, callback)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ return {V1_4::SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
- return {SupplicantStatusCode::SUCCESS, ""};
+ return {V1_4::SupplicantStatusCode::SUCCESS, ""};
}
SupplicantStatus StaNetwork::setSsidInternal(const std::vector<uint8_t> &ssid)
@@ -1077,12 +1103,12 @@
return {SupplicantStatusCode::SUCCESS, ""};
}
-SupplicantStatus StaNetwork::setEdmgInternal(bool enable)
+V1_4::SupplicantStatus StaNetwork::setEdmgInternal(bool enable)
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
wpa_ssid->enable_edmg = enable ? 1 : 0;
resetInternalStateAfterParamsUpdate();
- return {SupplicantStatusCode::SUCCESS, ""};
+ return {V1_4::SupplicantStatusCode::SUCCESS, ""};
}
SupplicantStatus StaNetwork::setGroupCipherInternal(uint32_t group_cipher_mask)
@@ -1851,10 +1877,10 @@
return {{SupplicantStatusCode::SUCCESS, ""}, {wpa_ssid->id_str}};
}
-std::pair<SupplicantStatus, bool> StaNetwork::getEdmgInternal()
+std::pair<V1_4::SupplicantStatus, bool> StaNetwork::getEdmgInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""},
+ return {{V1_4::SupplicantStatusCode::SUCCESS, ""},
(wpa_ssid->enable_edmg == 1)};
}
@@ -2295,43 +2321,43 @@
return {{SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"}, 0};
}
-SupplicantStatus StaNetwork::setGroupCipher_1_4Internal(uint32_t group_cipher_mask)
+V1_4::SupplicantStatus StaNetwork::setGroupCipher_1_4Internal(uint32_t group_cipher_mask)
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (group_cipher_mask & ~kAllowedGroupCipherMask) {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ return {V1_4::SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
}
wpa_ssid->group_cipher = group_cipher_mask;
wpa_printf(MSG_MSGDUMP, "group_cipher: 0x%x", wpa_ssid->group_cipher);
resetInternalStateAfterParamsUpdate();
- return {SupplicantStatusCode::SUCCESS, ""};
+ return {V1_4::SupplicantStatusCode::SUCCESS, ""};
}
-std::pair<SupplicantStatus, uint32_t> StaNetwork::getGroupCipher_1_4Internal()
+std::pair<V1_4::SupplicantStatus, uint32_t> StaNetwork::getGroupCipher_1_4Internal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""},
+ return {{V1_4::SupplicantStatusCode::SUCCESS, ""},
wpa_ssid->group_cipher & kAllowedGroupCipherMask};
}
-SupplicantStatus StaNetwork::setPairwiseCipher_1_4Internal(
+V1_4::SupplicantStatus StaNetwork::setPairwiseCipher_1_4Internal(
uint32_t pairwise_cipher_mask)
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (pairwise_cipher_mask & ~kAllowedPairwisewCipherMask) {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ return {V1_4::SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
}
wpa_ssid->pairwise_cipher = pairwise_cipher_mask;
wpa_printf(
MSG_MSGDUMP, "pairwise_cipher: 0x%x", wpa_ssid->pairwise_cipher);
resetInternalStateAfterParamsUpdate();
- return {SupplicantStatusCode::SUCCESS, ""};
+ return {V1_4::SupplicantStatusCode::SUCCESS, ""};
}
-std::pair<SupplicantStatus, uint32_t> StaNetwork::getPairwiseCipher_1_4Internal()
+std::pair<V1_4::SupplicantStatus, uint32_t> StaNetwork::getPairwiseCipher_1_4Internal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""},
+ return {{V1_4::SupplicantStatusCode::SUCCESS, ""},
wpa_ssid->pairwise_cipher & kAllowedPairwisewCipherMask};
}
@@ -2582,6 +2608,14 @@
#endif /* CONFIG_FILS */
}
+V1_4::SupplicantStatus StaNetwork::enableSaeH2eOnlyModeInternal(bool enable)
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ wpa_s->conf->sae_pwe = enable ? SAE_PWE_H2E_ONLY_MODE : SAE_PWE_HP_H2E_BOTH;
+ resetInternalStateAfterParamsUpdate();
+ return {V1_4::SupplicantStatusCode::SUCCESS, ""};
+}
+
} // namespace implementation
} // namespace V1_4
} // namespace supplicant
diff --git a/wpa_supplicant/hidl/1.4/sta_network.h b/wpa_supplicant/hidl/1.4/sta_network.h
index 83b47d0..b00f8e5 100644
--- a/wpa_supplicant/hidl/1.4/sta_network.h
+++ b/wpa_supplicant/hidl/1.4/sta_network.h
@@ -62,6 +62,9 @@
Return<void> registerCallback(
const sp<ISupplicantStaNetworkCallback>& callback,
registerCallback_cb _hidl_cb) override;
+ Return<void> registerCallback_1_4(
+ const sp<V1_4::ISupplicantStaNetworkCallback>& callback,
+ registerCallback_1_4_cb _hidl_cb) override;
Return<void> setSsid(
const hidl_vec<uint8_t>& ssid, setSsid_cb _hidl_cb) override;
Return<void> setBssid(
@@ -268,6 +271,7 @@
setGroupCipher_1_4_cb _hidl_cb) override;
Return<void> getGroupCipher_1_4(
getGroupCipher_1_4_cb _hidl_cb) override;
+ Return<void> enableSaeH2eOnlyMode(bool enable, enableSaeH2eOnlyMode_cb _hidl_cb) override;
private:
// Corresponding worker functions for the HIDL methods.
@@ -276,6 +280,8 @@
std::pair<SupplicantStatus, IfaceType> getTypeInternal();
SupplicantStatus registerCallbackInternal(
const sp<ISupplicantStaNetworkCallback>& callback);
+ V1_4::SupplicantStatus registerCallback_1_4Internal(
+ const sp<V1_4::ISupplicantStaNetworkCallback>& callback);
SupplicantStatus setSsidInternal(const std::vector<uint8_t>& ssid);
SupplicantStatus setBssidInternal(const std::array<uint8_t, 6>& bssid);
SupplicantStatus setScanSsidInternal(bool enable);
@@ -317,7 +323,7 @@
SupplicantStatus setProactiveKeyCachingInternal(bool enable);
SupplicantStatus setIdStrInternal(const std::string& id_str);
SupplicantStatus setUpdateIdentifierInternal(uint32_t id);
- SupplicantStatus setEdmgInternal(bool enable);
+ V1_4::SupplicantStatus setEdmgInternal(bool enable);
std::pair<SupplicantStatus, std::vector<uint8_t>> getSsidInternal();
std::pair<SupplicantStatus, std::array<uint8_t, 6>> getBssidInternal();
std::pair<SupplicantStatus, bool> getScanSsidInternal();
@@ -358,7 +364,7 @@
std::pair<SupplicantStatus, std::string> getIdStrInternal();
std::pair<SupplicantStatus, std::vector<uint8_t>>
getWpsNfcConfigurationTokenInternal();
- std::pair<SupplicantStatus, bool> getEdmgInternal();
+ std::pair<V1_4::SupplicantStatus, bool> getEdmgInternal();
SupplicantStatus enableInternal(bool no_connect);
SupplicantStatus disableInternal();
SupplicantStatus selectInternal();
@@ -402,11 +408,12 @@
uint32_t pairwise_cipher_mask);
SupplicantStatus setWapiPskInternal(const std::vector<uint8_t>& psk);
std::pair<SupplicantStatus, std::vector<uint8_t>> getWapiPskInternal();
- std::pair<SupplicantStatus, uint32_t> getGroupCipher_1_4Internal();
- SupplicantStatus setGroupCipher_1_4Internal(uint32_t group_cipher_mask);
- std::pair<SupplicantStatus, uint32_t> getPairwiseCipher_1_4Internal();
- SupplicantStatus setPairwiseCipher_1_4Internal(
+ std::pair<V1_4::SupplicantStatus, uint32_t> getGroupCipher_1_4Internal();
+ V1_4::SupplicantStatus setGroupCipher_1_4Internal(uint32_t group_cipher_mask);
+ std::pair<V1_4::SupplicantStatus, uint32_t> getPairwiseCipher_1_4Internal();
+ V1_4::SupplicantStatus setPairwiseCipher_1_4Internal(
uint32_t pairwise_cipher_mask);
+ V1_4::SupplicantStatus enableSaeH2eOnlyModeInternal(bool enable);
struct wpa_ssid* retrieveNetworkPtr();
struct wpa_supplicant* retrieveIfacePtr();
diff --git a/wpa_supplicant/hidl/1.4/supplicant.cpp b/wpa_supplicant/hidl/1.4/supplicant.cpp
index 5fea68d..6f4cde6 100644
--- a/wpa_supplicant/hidl/1.4/supplicant.cpp
+++ b/wpa_supplicant/hidl/1.4/supplicant.cpp
@@ -10,6 +10,7 @@
#include "hidl_manager.h"
#include "hidl_return_util.h"
#include "supplicant.h"
+#include "p2p_iface.h"
#include <android-base/file.h>
#include <fcntl.h>
@@ -254,6 +255,39 @@
}
std::pair<SupplicantStatus, sp<ISupplicantIface>>
+Supplicant::addP2pDevInterface(struct wpa_interface iface_params)
+{
+ char primary_ifname[IFNAMSIZ];
+ u32 primary_ifname_len =
+ strlen(iface_params.ifname) - strlen(P2P_MGMT_DEVICE_PREFIX);
+
+ if(primary_ifname_len > IFNAMSIZ) {
+ wpa_printf(MSG_DEBUG, "%s, Invalid primary iface name ", __FUNCTION__);
+ return {{SupplicantStatusCode::FAILURE_ARGS_INVALID, ""}, {}};
+ }
+
+ strncpy(primary_ifname, iface_params.ifname +
+ strlen(P2P_MGMT_DEVICE_PREFIX), primary_ifname_len);
+ wpa_printf(MSG_DEBUG, "%s, Initialize p2p-dev-wlan0 iface with"
+ "primary_iface = %s", __FUNCTION__, primary_ifname);
+ struct wpa_supplicant* wpa_s =
+ wpa_supplicant_get_iface(wpa_global_, primary_ifname);
+ if (!wpa_s) {
+ wpa_printf(MSG_DEBUG, "%s,NULL wpa_s for wlan0", __FUNCTION__);
+ return {{SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""},
+ nullptr};
+ }
+ if (wpas_p2p_add_p2pdev_interface(
+ wpa_s, wpa_s->global->params.conf_p2p_dev) < 0) {
+ wpa_printf(MSG_INFO,
+ "Failed to enable P2P Device");
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN,
+ "Enable P2P Device failed"}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS,""}, {}};
+}
+
+std::pair<SupplicantStatus, sp<ISupplicantIface>>
Supplicant::addInterfaceInternal(const IfaceInfo& iface_info)
{
android::sp<ISupplicantIface> iface;
@@ -305,10 +339,19 @@
}
}
iface_params.ifname = iface_info.name.c_str();
- struct wpa_supplicant* wpa_s =
- wpa_supplicant_add_iface(wpa_global_, &iface_params, NULL);
- if (!wpa_s) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ if (strncmp(iface_params.ifname, P2P_MGMT_DEVICE_PREFIX,
+ strlen(P2P_MGMT_DEVICE_PREFIX)) == 0) {
+ std::tie(status, iface) = addP2pDevInterface(iface_params);
+ if (status.code != SupplicantStatusCode::SUCCESS) {
+ return {{status.code,
+ status.debugMessage.c_str()}, iface};
+ }
+ } else {
+ struct wpa_supplicant* wpa_s =
+ wpa_supplicant_add_iface(wpa_global_, &iface_params, NULL);
+ if (!wpa_s) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
}
// The supplicant core creates a corresponding hidl object via
// HidlManager when |wpa_supplicant_add_iface| is called.
diff --git a/wpa_supplicant/hidl/1.4/supplicant.h b/wpa_supplicant/hidl/1.4/supplicant.h
index 8fd2033..2944c50 100644
--- a/wpa_supplicant/hidl/1.4/supplicant.h
+++ b/wpa_supplicant/hidl/1.4/supplicant.h
@@ -81,6 +81,8 @@
SupplicantStatus setDebugParamsInternal(
ISupplicant::DebugLevel level, bool show_timestamp, bool show_keys);
SupplicantStatus setConcurrencyPriorityInternal(IfaceType type);
+ std::pair<SupplicantStatus, sp<ISupplicantIface>> addP2pDevInterface(
+ struct wpa_interface iface_params);
// Raw pointer to the global structure maintained by the core.
struct wpa_global* wpa_global_;
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index ce5608e..907803b 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -1335,6 +1335,7 @@
}
wpa_msg(wpa_s, MSG_INFO, HS20_T_C_ACCEPTANCE "%s", url);
+ wpas_notify_hs20_rx_terms_and_conditions_acceptance(wpa_s, url);
}
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index b60f80d..c799b5a 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -959,7 +959,9 @@
"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 @@
}
-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 @@
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.c b/wpa_supplicant/mesh.c
index c085466..558d87a 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -333,30 +333,6 @@
frequency);
goto out_free;
}
- if (ssid->ht40)
- conf->secondary_channel = ssid->ht40;
- if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A && ssid->vht) {
- if (ssid->max_oper_chwidth != DEFAULT_MAX_OPER_CHWIDTH)
- conf->vht_oper_chwidth = ssid->max_oper_chwidth;
- switch (conf->vht_oper_chwidth) {
- case CHANWIDTH_80MHZ:
- case CHANWIDTH_80P80MHZ:
- ieee80211_freq_to_chan(
- frequency,
- &conf->vht_oper_centr_freq_seg0_idx);
- conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
- break;
- case CHANWIDTH_160MHZ:
- ieee80211_freq_to_chan(
- frequency,
- &conf->vht_oper_centr_freq_seg0_idx);
- conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
- conf->vht_oper_centr_freq_seg0_idx += 40 / 5;
- break;
- }
- ieee80211_freq_to_chan(ssid->vht_center_freq2,
- &conf->vht_oper_centr_freq_seg1_idx);
- }
if (ssid->mesh_basic_rates == NULL) {
/*
@@ -387,6 +363,31 @@
conf->basic_rates[rate_len] = -1;
}
+ /* While it can enhance performance to switch the primary channel, which
+ * is also the secondary channel of another network at the same time),
+ * to the other primary channel, problems exist with this in mesh
+ * networks.
+ *
+ * Example with problems:
+ * - 3 mesh nodes M1-M3, freq (5200, 5180)
+ * - other node O1, e.g. AP mode, freq (5180, 5200),
+ * Locations: O1 M1 M2 M3
+ *
+ * M3 can only send frames to M1 over M2, no direct connection is
+ * possible
+ * Start O1, M1 and M3 first, M1 or O1 will switch channels to align
+ * with* each other. M3 does not swap, because M1 or O1 cannot be
+ * reached. M2 is started afterwards and can either connect to M3 or M1
+ * because of this primary secondary channel switch.
+ *
+ * Solutions: (1) central coordination -> not always possible
+ * (2) disable pri/sec channel switch in mesh networks
+ *
+ * In AP mode, when all nodes can work independently, this poses of
+ * course no problem, therefore disable it only in mesh mode. */
+ conf->no_pri_sec_switch = 1;
+ wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
+
if (wpa_drv_init_mesh(wpa_s)) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh in driver");
return -1;
@@ -398,8 +399,6 @@
return -1;
}
- wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
-
return 0;
out_free:
wpa_supplicant_mesh_deinit(wpa_s);
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 12aafcb..b6a5e88 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -533,11 +533,14 @@
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,
MAC2STR(sta->addr));
eloop_cancel_timeout(plink_timer, wpa_s, sta);
+ eloop_cancel_timeout(mesh_auth_timer, wpa_s, sta);
return 0;
}
@@ -1290,8 +1293,8 @@
if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
tx_chanwidth, tx_seg1_idx) !=
- 0) {
- wpa_printf(MSG_WARNING, "MPM: %s",
+ OCI_SUCCESS) {
+ wpa_printf(MSG_WARNING, "MPM: OCV failed: %s",
ocv_errorstr);
return;
}
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index f19bfbf..834c7a1 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -195,7 +195,8 @@
wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX IGTK",
rsn->igtk, rsn->igtk_len);
wpa_drv_set_key(rsn->wpa_s,
- wpa_cipher_to_alg(rsn->mgmt_group_cipher), NULL,
+ wpa_cipher_to_alg(rsn->mgmt_group_cipher),
+ broadcast_ether_addr,
rsn->igtk_key_id, 1,
seq, sizeof(seq), rsn->igtk, rsn->igtk_len,
KEY_FLAG_GROUP_TX_DEFAULT);
@@ -204,7 +205,8 @@
/* group privacy / data frames */
wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX MGTK",
rsn->mgtk, rsn->mgtk_len);
- wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher), NULL,
+ wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher),
+ broadcast_ether_addr,
rsn->mgtk_key_id, 1, seq, sizeof(seq),
rsn->mgtk, rsn->mgtk_len, KEY_FLAG_GROUP_TX_DEFAULT);
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 16e747f..ac40074 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -1007,14 +1007,23 @@
const char *url)
{
#ifdef CONFIG_HS20
- if (!wpa_s || !url)
+ if (!wpa_s)
return;
wpas_hidl_notify_hs20_rx_deauth_imminent_notice(wpa_s, code, reauth_delay,
- url);
+ url);
#endif /* CONFIG_HS20 */
}
+void wpas_notify_hs20_rx_terms_and_conditions_acceptance(
+ struct wpa_supplicant *wpa_s, const char *url) {
+#ifdef CONFIG_HS20
+ if (!wpa_s || !url)
+ return;
+
+ wpas_hidl_notify_hs20_rx_terms_and_conditions_acceptance(wpa_s, url);
+#endif /* CONFIG_HS20 */
+}
#ifdef CONFIG_MESH
@@ -1208,3 +1217,16 @@
wpas_hidl_notify_pmk_cache_added(wpa_s, entry);
}
+
+void wpas_notify_transition_disable(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ u8 bitmap)
+{
+ if (!wpa_s)
+ return;
+
+ if (!ssid)
+ return;
+
+ wpas_hidl_notify_transition_disable(wpa_s, ssid, bitmap);
+}
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 0e7991b..d75bc77 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -175,6 +175,8 @@
void wpas_notify_hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s,
u8 code, u16 reauth_delay,
const char *url);
+void wpas_notify_hs20_rx_terms_and_conditions_acceptance(
+ struct wpa_supplicant *wpa_s, const char *url);
void wpas_notify_dpp_config_received(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpas_notify_dpp_config_sent(struct wpa_supplicant *wpa_s);
@@ -194,5 +196,8 @@
void wpas_notify_dpp_config_rejected(struct wpa_supplicant *wpa_s);
void wpas_notify_pmk_cache_added(struct wpa_supplicant *wpa_s,
struct rsn_pmksa_cache_entry *entry);
+void wpas_notify_transition_disable(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ u8 bitmap);
#endif /* NOTIFY_H */
diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c
index bd97fee..91e15e7 100644
--- a/wpa_supplicant/op_classes.c
+++ b/wpa_supplicant/op_classes.c
@@ -412,9 +412,13 @@
}
*ie_len = wpabuf_len(buf) - 2;
- if (*ie_len < 2 || wpabuf_len(buf) > len) {
+ if (*ie_len < 2) {
+ wpa_printf(MSG_DEBUG,
+ "No supported operating classes IE to add");
+ res = 0;
+ } else if (wpabuf_len(buf) > len) {
wpa_printf(MSG_ERROR,
- "Failed to add supported operating classes IE");
+ "Supported operating classes IE exceeds maximum buffer length");
res = 0;
} else {
os_memcpy(pos, wpabuf_head(buf), wpabuf_len(buf));
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index eb7c392..dc5c16d 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -291,6 +291,41 @@
}
+static int wpas_p2p_add_scan_freq_list(struct wpa_supplicant *wpa_s,
+ enum hostapd_hw_mode band,
+ struct wpa_driver_scan_params *params)
+{
+ struct hostapd_hw_modes *mode;
+ int num_chans = 0;
+ int *freqs, i;
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band, 0);
+ if (!mode)
+ return -1;
+
+ if (params->freqs) {
+ while (params->freqs[num_chans])
+ num_chans++;
+ }
+
+ freqs = os_realloc(params->freqs,
+ (num_chans + mode->num_channels + 1) * sizeof(int));
+ if (!freqs)
+ return -1;
+
+ params->freqs = freqs;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+ params->freqs[num_chans++] = mode->channels[i].freq;
+ }
+ params->freqs[num_chans] = 0;
+
+ return 0;
+}
+
+
static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
{
struct wpa_supplicant *wpa_s = work->wpa_s;
@@ -312,6 +347,15 @@
"Request driver to clear scan cache due to local BSS flush");
params->only_new_results = 1;
}
+
+ if (wpa_s->conf->p2p_6ghz_disable && !params->freqs) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: 6 GHz disabled - update the scan frequency list");
+ wpas_p2p_add_scan_freq_list(wpa_s, HOSTAPD_MODE_IEEE80211G,
+ params);
+ wpas_p2p_add_scan_freq_list(wpa_s, HOSTAPD_MODE_IEEE80211A,
+ params);
+ }
ret = wpa_drv_scan(wpa_s, params);
if (ret == 0)
wpa_s->curr_scan_cookie = params->scan_cookie;
@@ -522,7 +566,7 @@
/*
* The calling wpa_s instance is going to be removed. Do that
* from an eloop callback to keep the instance available until
- * the caller has returned. This my be needed, e.g., to provide
+ * the caller has returned. This may be needed, e.g., to provide
* control interface responses on the per-interface socket.
*/
if (eloop_register_timeout(0, 0, run_wpas_p2p_disconnect,
@@ -3736,7 +3780,9 @@
u8 ch;
struct p2p_reg_class *reg = NULL, *cli_reg = NULL;
- if (o->p2p == NO_P2P_SUPP)
+ if (o->p2p == NO_P2P_SUPP ||
+ (is_6ghz_op_class(o->op_class) &&
+ wpa_s->conf->p2p_6ghz_disable))
continue;
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode,
@@ -3747,6 +3793,13 @@
wpa_s->global->p2p_24ghz_social_channels = 1;
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
enum chan_allowed res;
+
+ /* Check for non-continuous jump in channel index
+ * incrementation */
+ if ((o->op_class == 128 || o->op_class == 130) &&
+ ch < 149 && ch + o->inc > 149)
+ ch = 149;
+
res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
if (res == ALLOWED) {
if (reg == NULL) {
@@ -3807,7 +3860,9 @@
const struct oper_class_map *o = &global_op_class[op];
u8 ch;
- if (o->p2p == NO_P2P_SUPP)
+ if (o->p2p == NO_P2P_SUPP ||
+ (is_6ghz_op_class(o->op_class) &&
+ wpa_s->conf->p2p_6ghz_disable))
continue;
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
@@ -3939,6 +3994,10 @@
wpa_s->ifname);
if (os_snprintf_error(sizeof(ifname), ret))
return -1;
+ /* Cut length at the maximum size. Note that we don't need to ensure
+ * collision free names here as the created interface is not a netdev.
+ */
+ ifname[IFNAMSIZ - 1] = '\0';
force_name[0] = '\0';
wpa_s->pending_interface_type = WPA_IF_P2P_DEVICE;
ret = wpa_drv_if_add(wpa_s, WPA_IF_P2P_DEVICE, ifname, NULL, NULL,
@@ -4777,6 +4836,7 @@
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
wpas_p2p_remove_pending_group_interface(wpa_s);
eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_p2p_reconsider_moving_go, wpa_s, NULL);
wpas_p2p_listen_work_done(wpa_s);
if (wpa_s->p2p_send_action_work) {
os_free(wpa_s->p2p_send_action_work->ctx);
@@ -5284,6 +5344,13 @@
if (freq > 0) {
freqs[0] = freq;
params.freqs = freqs;
+ } else if (wpa_s->conf->p2p_6ghz_disable) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: 6 GHz disabled - update the scan frequency list");
+ wpas_p2p_add_scan_freq_list(wpa_s, HOSTAPD_MODE_IEEE80211G,
+ ¶ms);
+ wpas_p2p_add_scan_freq_list(wpa_s, HOSTAPD_MODE_IEEE80211A,
+ ¶ms);
}
ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
@@ -5314,6 +5381,8 @@
* the new scan results become available.
*/
ret = wpa_drv_scan(wpa_s, ¶ms);
+ if (wpa_s->conf->p2p_6ghz_disable && params.freqs != freqs)
+ os_free(params.freqs);
if (!ret) {
os_get_reltime(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
@@ -5654,6 +5723,9 @@
return -1;
}
+ if (is_6ghz_freq(freq) && wpa_s->conf->p2p_6ghz_disable)
+ return -2;
+
os_free(wpa_s->global->add_psk);
wpa_s->global->add_psk = NULL;
@@ -5880,6 +5952,8 @@
if (os_strcmp(ifname, "*") == 0) {
struct wpa_supplicant *prev;
+ bool calling_wpa_s_group_removed = false;
+
wpa_s = global->ifaces;
while (wpa_s) {
prev = wpa_s;
@@ -5887,9 +5961,23 @@
if (prev->p2p_group_interface !=
NOT_P2P_GROUP_INTERFACE ||
(prev->current_ssid &&
- prev->current_ssid->p2p_group))
+ prev->current_ssid->p2p_group)) {
wpas_p2p_disconnect_safely(prev, calling_wpa_s);
+ if (prev == calling_wpa_s)
+ calling_wpa_s_group_removed = true;
+ }
}
+
+ if (!calling_wpa_s_group_removed &&
+ (calling_wpa_s->p2p_group_interface !=
+ NOT_P2P_GROUP_INTERFACE ||
+ (calling_wpa_s->current_ssid &&
+ calling_wpa_s->current_ssid->p2p_group))) {
+ wpa_printf(MSG_DEBUG, "Remove calling_wpa_s P2P group");
+ wpas_p2p_disconnect_safely(calling_wpa_s,
+ calling_wpa_s);
+ }
+
return 0;
}
@@ -9406,6 +9494,8 @@
{
struct p2p_go_neg_results params;
struct wpa_ssid *current_ssid = wpa_s->current_ssid;
+ void (*ap_configured_cb)(void *ctx, void *data);
+ void *ap_configured_cb_ctx, *ap_configured_cb_data;
wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_REMOVE_AND_REFORM_GROUP);
@@ -9415,12 +9505,13 @@
/* Stop the AP functionality */
/* TODO: Should do this in a way that does not indicated to possible
* P2P Clients in the group that the group is terminated. */
- /* If this action occurs before a group is started, the callback should be
- * preserved, or GROUP-STARTED event would be lost. If this action occurs after
- * a group is started, these poiners are all NULL and harmless. */
- void (*ap_configured_cb)(void *ctx, void *data) = wpa_s->ap_configured_cb;
- void *ap_configured_cb_ctx = wpa_s->ap_configured_cb_ctx;;
- void *ap_configured_cb_data = wpa_s->ap_configured_cb_data;
+ /* If this action occurs before a group is started, the callback should
+ * be preserved, or GROUP-STARTED event would be lost. If this action
+ * occurs after a group is started, these pointers are all NULL and
+ * harmless. */
+ ap_configured_cb = wpa_s->ap_configured_cb;
+ ap_configured_cb_ctx = wpa_s->ap_configured_cb_ctx;
+ ap_configured_cb_data = wpa_s->ap_configured_cb_data;
wpa_supplicant_ap_deinit(wpa_s);
/* Reselect the GO frequency */
@@ -9444,9 +9535,11 @@
return;
}
+ /* Restore preserved callback parameters */
wpa_s->ap_configured_cb = ap_configured_cb;
wpa_s->ap_configured_cb_ctx = ap_configured_cb_ctx;
wpa_s->ap_configured_cb_data = ap_configured_cb_data;
+
/* Update the frequency */
current_ssid->frequency = params.freq;
wpa_s->connect_without_scan = current_ssid;
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 @@
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..1280f5d
--- /dev/null
+++ b/wpa_supplicant/robust_av.c
@@ -0,0 +1,160 @@
+/*
+ * 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", 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] <= 8)
+ return;
+
+ /* Subelements start after (ie_id(1) + ie_len(1) + ext_id(1) +
+ * request type(1) + upc(2) + stream timeout(4) =) 10.
+ */
+ mscs_status = get_ie(&mscs_desc_ie[10], mscs_desc_ie[1] - 8,
+ 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..b9e4162 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -237,6 +237,10 @@
if (wpa_s->disconnected)
retry = 0;
+ /* do not retry if operation is not supported */
+ if (ret == -EOPNOTSUPP)
+ retry = 0;
+
wpa_supplicant_notify_scanning(wpa_s, 0);
wpas_notify_scan_done(wpa_s, 0);
if (wpa_s->wpa_state == WPA_SCANNING)
@@ -2187,6 +2191,60 @@
}
+/* 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 +2252,42 @@
}
-#define INTERPOLATE_RATE(snr0, snr1, rate0, rate1) \
- if (snr < (snr1)) \
- return interpolate_rate(snr, (snr0), (snr1), (rate0), (rate1))
-
-static unsigned int max_ht20_rate(int snr, int vht)
+static unsigned int max_rate(const struct minsnr_bitrate_entry table[],
+ 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;
+ 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_ht40_rate(int snr, int vht)
+static unsigned int max_ht20_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(vht20_table, snr, vht);
+}
+
+
+static unsigned int max_ht40_rate(int snr, bool vht)
+{
+ 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 +2341,7 @@
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 +2351,7 @@
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 +2361,7 @@
/* 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 +2369,7 @@
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 d06f6e2..7fec1cd 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -85,16 +85,21 @@
static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
const u8 *bssid, int external,
- int reuse, int *ret_use_pt)
+ int reuse, int *ret_use_pt,
+ bool *ret_use_pk)
{
struct wpabuf *buf;
size_t len;
const char *password;
struct wpa_bss *bss;
int use_pt = 0;
+ bool use_pk = false;
+ u8 rsnxe_capa = 0;
if (ret_use_pt)
*ret_use_pt = 0;
+ if (ret_use_pk)
+ *ret_use_pk = false;
#ifdef CONFIG_TESTING_OPTIONS
if (wpa_s->sae_commit_override) {
@@ -123,7 +128,8 @@
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_pt = wpa_s->sme.sae.h2e;
+ use_pk = wpa_s->sme.sae.pk;
goto reuse_data;
}
if (sme_set_sae_group(wpa_s) < 0) {
@@ -131,19 +137,37 @@
return NULL;
}
+ bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
+ if (bss) {
+ const u8 *rsnxe;
+
+ rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ if (rsnxe && rsnxe[1] >= 1)
+ rsnxe_capa = rsnxe[2];
+ }
+
if (ssid->sae_password_id && wpa_s->conf->sae_pwe != 3)
use_pt = 1;
+#ifdef CONFIG_SAE_PK
+ if ((rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)) &&
+ 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) {
- bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
- if (bss) {
- const u8 *rsnxe;
-
- rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
- if (rsnxe && rsnxe[1] >= 1)
- use_pt = !!(rsnxe[2] &
- BIT(WLAN_RSNX_CAPAB_SAE_H2E));
- }
+ use_pt = !!(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_H2E));
if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) &&
wpa_s->conf->sae_pwe != 3 &&
@@ -157,7 +181,7 @@
if (use_pt &&
sae_prepare_commit_pt(&wpa_s->sme.sae, ssid->pt,
wpa_s->own_addr, bssid,
- wpa_s->sme.sae_rejected_groups) < 0)
+ wpa_s->sme.sae_rejected_groups, NULL) < 0)
return NULL;
if (!use_pt &&
sae_prepare_commit(wpa_s->own_addr, bssid,
@@ -167,8 +191,17 @@
wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
return NULL;
}
- if (wpa_s->sme.sae.tmp)
+ 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.pk = 1;
+#ifdef CONFIG_SAE_PK
+ os_memcpy(wpa_s->sme.sae.tmp->own_addr, wpa_s->own_addr,
+ ETH_ALEN);
+ os_memcpy(wpa_s->sme.sae.tmp->peer_addr, bssid, ETH_ALEN);
+ sae_pk_set_password(&wpa_s->sme.sae, password);
+#endif /* CONFIG_SAE_PK */
+ }
reuse_data:
len = wpa_s->sme.sae_token ? 3 + wpabuf_len(wpa_s->sme.sae_token) : 0;
@@ -179,8 +212,12 @@
return NULL;
if (!external) {
wpabuf_put_le16(buf, 1); /* Transaction seq# */
- wpabuf_put_le16(buf, use_pt ? WLAN_STATUS_SAE_HASH_TO_ELEMENT :
- WLAN_STATUS_SUCCESS);
+ if (use_pk)
+ wpabuf_put_le16(buf, WLAN_STATUS_SAE_PK);
+ else if (use_pt)
+ wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT);
+ else
+ wpabuf_put_le16(buf,WLAN_STATUS_SUCCESS);
}
if (sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token,
ssid->sae_password_id) < 0) {
@@ -189,6 +226,8 @@
}
if (ret_use_pt)
*ret_use_pt = use_pt;
+ if (ret_use_pk)
+ *ret_use_pk = use_pk;
return buf;
}
@@ -716,7 +755,8 @@
if (start)
resp = sme_auth_build_sae_commit(wpa_s, ssid,
bss->bssid, 0,
- start == 2, NULL);
+ start == 2, NULL,
+ NULL);
else
resp = sme_auth_build_sae_confirm(wpa_s, 0);
if (resp == NULL) {
@@ -1008,8 +1048,11 @@
{
struct wpabuf *resp, *buf;
int use_pt;
+ bool use_pk;
+ u16 status;
- resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0, &use_pt);
+ resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0, &use_pt,
+ &use_pk);
if (!resp) {
wpa_printf(MSG_DEBUG, "SAE: Failed to build SAE commit");
return -1;
@@ -1023,10 +1066,14 @@
}
wpa_s->sme.seq_num++;
+ if (use_pk)
+ status = WLAN_STATUS_SAE_PK;
+ else if (use_pt)
+ status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
+ else
+ status = WLAN_STATUS_SUCCESS;
sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
- bssid, 1, wpa_s->sme.seq_num,
- use_pt ? WLAN_STATUS_SAE_HASH_TO_ELEMENT :
- WLAN_STATUS_SUCCESS);
+ bssid, 1, wpa_s->sme.seq_num, status);
wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0);
wpabuf_free(resp);
wpabuf_free(buf);
@@ -1223,8 +1270,7 @@
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,
@@ -1287,7 +1333,8 @@
}
if (status_code != WLAN_STATUS_SUCCESS &&
- status_code != WLAN_STATUS_SAE_HASH_TO_ELEMENT)
+ status_code != WLAN_STATUS_SAE_HASH_TO_ELEMENT &&
+ status_code != WLAN_STATUS_SAE_PK)
return -1;
if (auth_transaction == 1) {
@@ -1304,24 +1351,30 @@
"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 &&
+ 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.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");
+ return -1;
+ }
if (groups && groups[0] <= 0)
groups = NULL;
res = sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL,
groups, status_code ==
- WLAN_STATUS_SAE_HASH_TO_ELEMENT);
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK);
if (res == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message due to reflection attack");
@@ -1827,6 +1880,42 @@
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", 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;
@@ -2573,6 +2662,16 @@
return;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->oci_freq_override_saquery_req) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override SA Query Request OCI frequency %d -> %d MHz",
+ ci.frequency,
+ wpa_s->oci_freq_override_saquery_req);
+ ci.frequency = wpa_s->oci_freq_override_saquery_req;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
if (ocv_insert_extended_oci(&ci, req + req_len) < 0)
return;
@@ -2727,6 +2826,16 @@
return;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->oci_freq_override_saquery_resp) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override SA Query Response OCI frequency %d -> %d MHz",
+ ci.frequency,
+ wpa_s->oci_freq_override_saquery_resp);
+ ci.frequency = wpa_s->oci_freq_override_saquery_resp;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
if (ocv_insert_extended_oci(&ci, resp + resp_len) < 0)
return;
@@ -2806,8 +2915,11 @@
if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(wpa_s, MSG_INFO, OCV_FAILURE "addr=" MACSTR
+ " frame=saquery%s error=%s",
+ MAC2STR(sa), data[0] == WLAN_SA_QUERY_REQUEST ?
+ "req" : "resp", ocv_errorstr);
return;
}
}
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 2e09102..c706a4e 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -121,6 +121,15 @@
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);
@@ -374,8 +383,9 @@
if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_msg(wpa_s, MSG_WARNING, "WNM: %s", ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(wpa_s, MSG_WARNING, "WNM: OCV failed: %s",
+ ocv_errorstr);
return;
}
}
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 6a2d2c3..51c9642 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -2994,6 +2994,13 @@
}
+static int wpa_cli_cmd_dpp_bootstrap_set(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_SET", 1, argc, argv);
+}
+
+
static int wpa_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -3056,9 +3063,98 @@
return wpa_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv);
}
+
+#ifdef CONFIG_DPP2
+
+static int wpa_cli_cmd_dpp_chirp(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_CHIRP", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_dpp_stop_chirp(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DPP_STOP_CHIRP");
+}
+
+#endif /* CONFIG_DPP2 */
#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
@@ -3692,6 +3788,9 @@
{ "dpp_bootstrap_info", wpa_cli_cmd_dpp_bootstrap_info, NULL,
cli_cmd_flag_none,
"<id> = show DPP bootstrap information" },
+ { "dpp_bootstrap_set", wpa_cli_cmd_dpp_bootstrap_set, NULL,
+ cli_cmd_flag_none,
+ "<id> [conf=..] [ssid=<SSID>] [ssid_charset=#] [psk=<PSK>] [pass=<passphrase>] [configurator=<id>] [conn_status=#] [akm_use_selector=<0|1>] [group_id=..] [expiry=#] [csrattrs=..] = set DPP configurator parameters" },
{ "dpp_auth_init", wpa_cli_cmd_dpp_auth_init, NULL, cli_cmd_flag_none,
"peer=<id> [own=<id>] = initiate DPP bootstrapping" },
{ "dpp_listen", wpa_cli_cmd_dpp_listen, NULL, cli_cmd_flag_none,
@@ -3717,7 +3816,17 @@
{ "dpp_pkex_remove", wpa_cli_cmd_dpp_pkex_remove, NULL,
cli_cmd_flag_none,
"*|<id> = remove DPP pkex information" },
+#ifdef CONFIG_DPP2
+ { "dpp_chirp", wpa_cli_cmd_dpp_chirp, NULL,
+ cli_cmd_flag_none,
+ "own=<BI ID> iter=<count> = start DPP chirp" },
+ { "dpp_stop_chirp", wpa_cli_cmd_dpp_stop_chirp, NULL,
+ cli_cmd_flag_none,
+ "= stop DPP chirp" },
+#endif /* CONFIG_DPP2 */
#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_gui-qt4/icons/.gitignore b/wpa_supplicant/wpa_gui-qt4/icons/.gitignore
new file mode 100644
index 0000000..8d772cc
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/icons/.gitignore
@@ -0,0 +1,2 @@
+hicolor
+pixmaps
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index a01a4e5..67fb426 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -804,7 +804,22 @@
#ifdef CONFIG_BGSCAN
-static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
+static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->bgscan_ssid) {
+ bgscan_deinit(wpa_s);
+ wpa_s->bgscan_ssid = NULL;
+ }
+}
+
+
+/**
+ * wpa_supplicant_reset_bgscan - Reset the bgscan for the current SSID.
+ * @wpa_s: Pointer to the wpa_supplicant data
+ *
+ * Stop, start, or reconfigure the scan parameters depending on the method.
+ */
+void wpa_supplicant_reset_bgscan(struct wpa_supplicant *wpa_s)
{
const char *name;
@@ -812,12 +827,12 @@
name = wpa_s->current_ssid->bgscan;
else
name = wpa_s->conf->bgscan;
- if (name == NULL || name[0] == '\0')
+ if (!name || name[0] == '\0') {
+ wpa_supplicant_stop_bgscan(wpa_s);
return;
+ }
if (wpas_driver_bss_selection(wpa_s))
return;
- if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
- return;
#ifdef CONFIG_P2P
if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
return;
@@ -847,15 +862,6 @@
wpa_s->bgscan_ssid = NULL;
}
-
-static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
-{
- if (wpa_s->bgscan_ssid != NULL) {
- bgscan_deinit(wpa_s);
- wpa_s->bgscan_ssid = NULL;
- }
-}
-
#endif /* CONFIG_BGSCAN */
@@ -979,8 +985,7 @@
fils_hlp_sent ? " FILS_HLP_SENT" : "");
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
wpas_clear_temp_disabled(wpa_s, ssid, 1);
- wpa_blacklist_clear(wpa_s);
- wpa_s->extra_blacklist_count = 0;
+ wpa_s->consecutive_conn_failures = 0;
wpa_s->new_connection = 0;
wpa_drv_set_operstate(wpa_s, 1);
#ifndef IEEE8021X_EAPOL
@@ -1012,8 +1017,8 @@
wpa_s->wpa_state = state;
#ifdef CONFIG_BGSCAN
- if (state == WPA_COMPLETED)
- wpa_supplicant_start_bgscan(wpa_s);
+ if (state == WPA_COMPLETED && wpa_s->current_ssid != wpa_s->bgscan_ssid)
+ wpa_supplicant_reset_bgscan(wpa_s);
else if (state < WPA_ASSOCIATED)
wpa_supplicant_stop_bgscan(wpa_s);
#endif /* CONFIG_BGSCAN */
@@ -1185,6 +1190,7 @@
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
+ wpa_blacklist_clear(wpa_s);
wpa_dbg(wpa_s, MSG_DEBUG, "Reconfiguration completed");
return 0;
}
@@ -1640,9 +1646,26 @@
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 */
@@ -1883,6 +1906,9 @@
*pos |= 0x01;
#endif /* CONFIG_FILS */
break;
+ case 10: /* Bits 80-87 */
+ *pos |= 0x20; /* Bit 85 - Mirrored SCS */
+ break;
}
}
@@ -1890,7 +1916,7 @@
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;
@@ -2060,7 +2086,9 @@
if (!password)
password = ssid->passphrase;
- if ((conf->sae_pwe == 0 && !ssid->sae_password_id) || !password ||
+ if (!password ||
+ (conf->sae_pwe == 0 && !ssid->sae_password_id &&
+ !sae_pk_valid_password(password)) ||
conf->sae_pwe == 3) {
/* PT derivation not needed */
sae_deinit_pt(ssid->pt);
@@ -3171,6 +3199,39 @@
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", 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;
@@ -3485,6 +3546,7 @@
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, ¶ms, NULL);
if (!wpa_ie) {
@@ -4062,6 +4124,52 @@
/**
+ * wpa_supplicant_remove_all_networks - Remove all configured networks
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: 0 on success (errors are currently ignored)
+ *
+ * This function performs the following operations:
+ * 1. Remove all networks.
+ * 2. Send network removal notifications.
+ * 3. Update internal state machines.
+ * 4. Stop any running sched scans.
+ */
+int wpa_supplicant_remove_all_networks(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid;
+
+ if (wpa_s->sched_scanning)
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+
+ eapol_sm_invalidate_cached_session(wpa_s->eapol);
+ if (wpa_s->current_ssid) {
+#ifdef CONFIG_SME
+ wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+ wpa_sm_set_config(wpa_s->wpa, NULL);
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+ wpa_s->own_disconnect_req = 1;
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ }
+ ssid = wpa_s->conf->ssid;
+ while (ssid) {
+ struct wpa_ssid *remove_ssid = ssid;
+ int id;
+
+ id = ssid->id;
+ ssid = ssid->next;
+ if (wpa_s->last_ssid == remove_ssid)
+ wpa_s->last_ssid = NULL;
+ wpas_notify_network_removed(wpa_s, remove_ssid);
+ wpa_config_remove_network(wpa_s->conf, id);
+ }
+ return 0;
+}
+
+
+/**
* wpa_supplicant_enable_network - Mark a configured network as enabled
* @wpa_s: wpa_supplicant structure for a network interface
* @ssid: wpa_ssid structure for a configured network or %NULL
@@ -4851,6 +4959,65 @@
}
+int wpa_supplicant_update_bridge_ifname(struct wpa_supplicant *wpa_s,
+ const char *bridge_ifname)
+{
+ if (wpa_s->wpa_state > WPA_SCANNING)
+ return -EBUSY;
+
+ if (bridge_ifname &&
+ os_strlen(bridge_ifname) >= sizeof(wpa_s->bridge_ifname))
+ return -EINVAL;
+
+ if (!bridge_ifname)
+ bridge_ifname = "";
+
+ if (os_strcmp(wpa_s->bridge_ifname, bridge_ifname) == 0)
+ return 0;
+
+ if (wpa_s->l2_br) {
+ l2_packet_deinit(wpa_s->l2_br);
+ wpa_s->l2_br = NULL;
+ }
+
+ os_strlcpy(wpa_s->bridge_ifname, bridge_ifname,
+ sizeof(wpa_s->bridge_ifname));
+
+ if (wpa_s->bridge_ifname[0]) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Receiving packets from bridge interface '%s'",
+ wpa_s->bridge_ifname);
+ wpa_s->l2_br = l2_packet_init_bridge(
+ wpa_s->bridge_ifname, wpa_s->ifname, wpa_s->own_addr,
+ ETH_P_EAPOL, wpa_supplicant_rx_eapol_bridge, wpa_s, 1);
+ if (!wpa_s->l2_br) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Failed to open l2_packet connection for the bridge interface '%s'",
+ wpa_s->bridge_ifname);
+ goto fail;
+ }
+ }
+
+#ifdef CONFIG_TDLS
+ if (!wpa_s->p2p_mgmt && wpa_tdls_init(wpa_s->wpa))
+ goto fail;
+#endif /* CONFIG_TDLS */
+
+ return 0;
+fail:
+ wpa_s->bridge_ifname[0] = 0;
+ if (wpa_s->l2_br) {
+ l2_packet_deinit(wpa_s->l2_br);
+ wpa_s->l2_br = NULL;
+ }
+#ifdef CONFIG_TDLS
+ if (!wpa_s->p2p_mgmt)
+ wpa_tdls_init(wpa_s->wpa);
+#endif /* CONFIG_TDLS */
+ return -EIO;
+}
+
+
/**
* wpa_supplicant_driver_init - Initialize driver interface parameters
* @wpa_s: Pointer to wpa_supplicant data
@@ -6034,6 +6201,8 @@
wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
if (wpa_s->drv_priv == NULL) {
const char *pos;
+ int level = MSG_ERROR;
+
pos = driver ? os_strchr(driver, ',') : NULL;
if (pos) {
wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
@@ -6041,8 +6210,12 @@
driver = pos + 1;
goto next_driver;
}
- wpa_msg(wpa_s, MSG_ERROR, "Failed to initialize driver "
- "interface");
+
+#ifdef CONFIG_MATCH_IFACE
+ if (wpa_s->matched == WPA_IFACE_MATCHED_NULL)
+ level = MSG_DEBUG;
+#endif /* CONFIG_MATCH_IFACE */
+ wpa_msg(wpa_s, level, "Failed to initialize driver interface");
return -1;
}
if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
@@ -6187,6 +6360,9 @@
return -1;
}
os_strlcpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname));
+#ifdef CONFIG_MATCH_IFACE
+ wpa_s->matched = iface->matched;
+#endif /* CONFIG_MATCH_IFACE */
if (iface->bridge_ifname) {
if (os_strlen(iface->bridge_ifname) >=
@@ -6578,6 +6754,10 @@
if (!iface)
return NULL;
*iface = *miface;
+ if (!miface->ifname)
+ iface->matched = WPA_IFACE_MATCHED_NULL;
+ else
+ iface->matched = WPA_IFACE_MATCHED;
iface->ifname = ifname;
return iface;
}
@@ -6612,8 +6792,6 @@
if (iface) {
wpa_s = wpa_supplicant_add_iface(global, iface, NULL);
os_free(iface);
- if (wpa_s)
- wpa_s->matched = 1;
}
}
@@ -7143,6 +7321,18 @@
if (wpa_s->conf->changed_parameters & CFG_CHANGED_DISABLE_BTM)
wpa_supplicant_set_default_scan_ies(wpa_s);
+#ifdef CONFIG_BGSCAN
+ /*
+ * We default to global bgscan parameters only when per-network bgscan
+ * parameters aren't set. Only bother resetting bgscan parameters if
+ * this is the case.
+ */
+ if ((wpa_s->conf->changed_parameters & CFG_CHANGED_BGSCAN) &&
+ wpa_s->current_ssid && !wpa_s->current_ssid->bgscan &&
+ wpa_s->wpa_state == WPA_COMPLETED)
+ wpa_supplicant_reset_bgscan(wpa_s);
+#endif /* CONFIG_BGSCAN */
+
#ifdef CONFIG_WPS
wpas_wps_update_config(wpa_s);
#endif /* CONFIG_WPS */
@@ -7183,7 +7373,7 @@
continue;
if (bss->ssid_len == cbss->ssid_len &&
os_memcmp(bss->ssid, cbss->ssid, bss->ssid_len) == 0 &&
- wpa_blacklist_get(wpa_s, bss->bssid) == NULL) {
+ !wpa_blacklist_is_blacklisted(wpa_s, bss->bssid)) {
add_freq(freqs, &num_freqs, bss->freq);
if (num_freqs == max_freqs)
break;
@@ -7237,10 +7427,6 @@
/*
* Add the failed BSSID into the blacklist and speed up next scan
* attempt if there could be other APs that could accept association.
- * The current blacklist count indicates how many times we have tried
- * connecting to this AP and multiple attempts mean that other APs are
- * either not available or has already been tried, so that we can start
- * increasing the delay here to avoid constant scanning.
*/
count = wpa_blacklist_add(wpa_s, bssid);
if (count == 1 && wpa_s->current_bss) {
@@ -7265,19 +7451,19 @@
}
}
- /*
- * Add previous failure count in case the temporary blacklist was
- * cleared due to no other BSSes being available.
- */
- count += wpa_s->extra_blacklist_count;
+ wpa_s->consecutive_conn_failures++;
- if (count > 3 && wpa_s->current_ssid) {
+ if (wpa_s->consecutive_conn_failures > 3 && wpa_s->current_ssid) {
wpa_printf(MSG_DEBUG, "Continuous association failures - "
"consider temporary network disabling");
wpas_auth_failed(wpa_s, "CONN_FAILED");
}
-
- switch (count) {
+ /*
+ * Multiple consecutive connection failures mean that other APs are
+ * either not available or have already been tried, so we can start
+ * increasing the delay here to avoid constant scanning.
+ */
+ switch (wpa_s->consecutive_conn_failures) {
case 1:
timeout = 100;
break;
@@ -7295,8 +7481,9 @@
break;
}
- wpa_dbg(wpa_s, MSG_DEBUG, "Blacklist count %d --> request scan in %d "
- "ms", count, timeout);
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Consecutive connection failures: %d --> request scan in %d ms",
+ wpa_s->consecutive_conn_failures, timeout);
/*
* TODO: if more than one possible AP is available in scan results,
@@ -7695,7 +7882,6 @@
wpa_s->normal_scans = 0;
wpa_s->scan_req = NORMAL_SCAN_REQ;
wpa_supplicant_reinit_autoscan(wpa_s);
- wpa_s->extra_blacklist_count = 0;
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
wpa_s->last_owe_group = 0;
@@ -7961,7 +8147,7 @@
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..c10dd73 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -843,6 +843,16 @@
# bssid: BSSID (optional); if set, this network block is used only when
# associating with the AP using the configured BSSID
#
+# ignore_broadcast_ssid: SSID broadcast behavior
+# Send empty SSID in beacons and ignore probe request frames that do not
+# specify full SSID, i.e., require stations to know SSID.
+# default: disabled (0)
+# 1 = send empty (length=0) SSID in beacon and ignore probe request for
+# broadcast SSID
+# 2 = clear SSID (ASCII 0), but keep the original length (this may be required
+# with some clients that do not support empty SSID) and ignore probe
+# requests for broadcast SSID
+#
# priority: priority group (integer)
# By default, all networks will get same priority group (0). If some of the
# networks are more desirable, this field can be used to change the order in
@@ -1472,6 +1482,58 @@
# 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 7c792b3..3fcd95a 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -121,6 +121,18 @@
* interface that is not a network interface.
*/
int p2p_mgmt;
+
+#ifdef CONFIG_MATCH_IFACE
+ /**
+ * matched - Interface was matched rather than specified
+ *
+ */
+ enum {
+ WPA_IFACE_NOT_MATCHED,
+ WPA_IFACE_MATCHED_NULL,
+ WPA_IFACE_MATCHED
+ } matched;
+#endif /* CONFIG_MATCH_IFACE */
};
/**
@@ -491,6 +503,17 @@
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
*
@@ -643,17 +666,8 @@
struct wpa_blacklist *blacklist;
- /**
- * extra_blacklist_count - Sum of blacklist counts after last connection
- *
- * This variable is used to maintain a count of temporary blacklisting
- * failures (maximum number for any BSS) over blacklist clear
- * operations. This is needed for figuring out whether there has been
- * failures prior to the last blacklist clear operation which happens
- * whenever no other not-blacklisted BSS candidates are available. This
- * gets cleared whenever a connection has been established successfully.
- */
- int extra_blacklist_count;
+ /* Number of connection failures since last successful connection */
+ unsigned int consecutive_conn_failures;
/**
* scan_req - Type of the scan request
@@ -1157,6 +1171,13 @@
struct wpabuf *rsnxe_override_assoc;
struct wpabuf *rsnxe_override_eapol;
struct dl_list drv_signal_override;
+ 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;
@@ -1282,10 +1303,10 @@
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;
@@ -1296,6 +1317,7 @@
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;
@@ -1315,6 +1337,8 @@
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;
};
@@ -1338,6 +1362,8 @@
const char * wpa_supplicant_state_txt(enum wpa_states state);
int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s);
int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_update_bridge_ifname(struct wpa_supplicant *wpa_s,
+ const char *bridge_ifname);
int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid,
u8 *wpa_ie, size_t *wpa_ie_len);
@@ -1363,6 +1389,7 @@
struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s);
int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id);
+int wpa_supplicant_remove_all_networks(struct wpa_supplicant *wpa_s);
void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
@@ -1450,6 +1477,7 @@
void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s);
void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s);
void wpas_clear_disabled_interface(void *eloop_ctx, void *timeout_ctx);
+void wpa_supplicant_reset_bgscan(struct wpa_supplicant *wpa_s);
/* MBO functions */
@@ -1542,6 +1570,9 @@
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);
@@ -1633,4 +1664,13 @@
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/wpa_supplicant_template.conf b/wpa_supplicant/wpa_supplicant_template.conf
index fce7e5e..7a558f3 100644
--- a/wpa_supplicant/wpa_supplicant_template.conf
+++ b/wpa_supplicant/wpa_supplicant_template.conf
@@ -6,3 +6,4 @@
pmf=1
p2p_add_cli_chan=1
oce=1
+sae_pwe=2
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 6bd271e..4462afc 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -575,7 +575,8 @@
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 @@
os_memset(¶ms, 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 @@
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 @@
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 |
@@ -1298,6 +1331,8 @@
changed = 1;
}
+ wpas_notify_transition_disable(wpa_s, ssid, bitmap);
+
if (!changed)
return;
diff --git a/wpa_supplicant/wpas_module_tests.c b/wpa_supplicant/wpas_module_tests.c
index 4e37591..1c136f7 100644
--- a/wpa_supplicant/wpas_module_tests.c
+++ b/wpa_supplicant/wpas_module_tests.c
@@ -59,6 +59,23 @@
wpa_blacklist_add(&wpa_s, (u8 *) "333333") < 0)
goto fail;
+ wpa_blacklist_clear(&wpa_s);
+
+ if (wpa_blacklist_add(&wpa_s, (u8 *) "111111") < 0 ||
+ wpa_blacklist_add(&wpa_s, (u8 *) "222222") < 0 ||
+ wpa_blacklist_add(&wpa_s, (u8 *) "333333") < 0 ||
+ wpa_blacklist_add(&wpa_s, (u8 *) "444444") < 0 ||
+ !wpa_blacklist_is_blacklisted(&wpa_s, (u8 *) "111111") ||
+ wpa_blacklist_del(&wpa_s, (u8 *) "111111") < 0 ||
+ wpa_blacklist_is_blacklisted(&wpa_s, (u8 *) "111111") ||
+ wpa_blacklist_add(&wpa_s, (u8 *) "111111") < 0)
+ goto fail;
+
+ wpa_blacklist_update(&wpa_s);
+
+ if (!wpa_blacklist_is_blacklisted(&wpa_s, (u8 *) "111111"))
+ goto fail;
+
ret = 0;
fail:
wpa_blacklist_clear(&wpa_s);
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 9f68b22..47d85dc 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -720,7 +720,7 @@
wpas_notify_wps_event_success(wpa_s);
if (wpa_s->current_ssid)
wpas_clear_temp_disabled(wpa_s, wpa_s->current_ssid, 1);
- wpa_s->extra_blacklist_count = 0;
+ wpa_s->consecutive_conn_failures = 0;
/*
* Enable the networks disabled during wpas_wps_reassoc after 10