[automerger skipped] DO NOT MERGE - Merge pie-platform-release (PPRL.190505.001) into master. am: 53bcaedcae -s ours
am: 4752eb7847 -s ours
am skip reason: subject contains skip directive
Change-Id: I285eb5c3ade683e10a4a2c511c187f09327f8c2f
diff --git a/.gitignore b/.gitignore
index 1d45c0a..e2ef98e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,5 @@
*.patch
+hostapd/.cproject
+hostapd/.project
+wpa_supplicant/.cproject
+wpa_supplicant/.project
diff --git a/CONTRIBUTIONS b/CONTRIBUTIONS
index 1dc7547..c81ad64 100644
--- a/CONTRIBUTIONS
+++ b/CONTRIBUTIONS
@@ -140,7 +140,7 @@
Modified BSD license (no advertisement clause):
-Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/COPYING b/COPYING
index 945bdc0..5d0115c 100644
--- a/COPYING
+++ b/COPYING
@@ -1,7 +1,7 @@
wpa_supplicant and hostapd
--------------------------
-Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
diff --git a/README b/README
index 43b684c..a9f8069 100644
--- a/README
+++ b/README
@@ -1,7 +1,7 @@
wpa_supplicant and hostapd
--------------------------
-Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
These programs are licensed under the BSD license (the one with
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 0224db1..df3542a 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -246,6 +246,12 @@
NEED_SHA384=y
endif
+ifdef CONFIG_OCV
+L_CFLAGS += -DCONFIG_OCV
+OBJS += src/common/ocv.c
+CONFIG_IEEE80211W=y
+endif
+
ifdef CONFIG_IEEE80211W
L_CFLAGS += -DCONFIG_IEEE80211W
NEED_SHA256=y
@@ -466,6 +472,7 @@
L_CFLAGS += -DEAP_SERVER_PWD
OBJS += src/eap_server/eap_server_pwd.c src/eap_common/eap_pwd_common.c
NEED_SHA256=y
+NEED_ECC=y
endif
ifdef CONFIG_EAP_EKE
@@ -558,6 +565,9 @@
NEED_JSON=y
NEED_GAS=y
NEED_BASE64=y
+ifdef CONFIG_DPP2
+L_CFLAGS += -DCONFIG_DPP2
+endif
endif
ifdef CONFIG_EAP_IKEV2
@@ -649,22 +659,33 @@
endif
ifeq ($(CONFIG_TLS), gnutls)
+ifndef CONFIG_CRYPTO
+# default to libgcrypt
+CONFIG_CRYPTO=gnutls
+endif
ifdef TLS_FUNCS
OBJS += src/crypto/tls_gnutls.c
LIBS += -lgnutls -lgpg-error
endif
-OBJS += src/crypto/crypto_gnutls.c
-HOBJS += src/crypto/crypto_gnutls.c
+OBJS += src/crypto/crypto_$(CONFIG_CRYPTO).c
+HOBJS += src/crypto/crypto_$(CONFIG_CRYPTO).c
ifdef NEED_FIPS186_2_PRF
OBJS += src/crypto/fips_prf_internal.c
OBJS += src/crypto/sha1-internal.c
endif
+ifeq ($(CONFIG_CRYPTO), gnutls)
LIBS += -lgcrypt
LIBS_h += -lgcrypt
-CONFIG_INTERNAL_SHA256=y
CONFIG_INTERNAL_RC4=y
CONFIG_INTERNAL_DH_GROUP5=y
endif
+ifeq ($(CONFIG_CRYPTO), nettle)
+LIBS += -lnettle -lgmp
+LIBS_p += -lnettle -lgmp
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+endif
ifeq ($(CONFIG_TLS), internal)
ifndef CONFIG_CRYPTO
@@ -820,8 +841,10 @@
SHA1OBJS =
ifdef NEED_SHA1
ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
SHA1OBJS += src/crypto/sha1.c
endif
+endif
SHA1OBJS += src/crypto/sha1-prf.c
ifdef CONFIG_INTERNAL_SHA1
SHA1OBJS += src/crypto/sha1-internal.c
@@ -845,8 +868,10 @@
endif
ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
OBJS += src/crypto/md5.c
endif
+endif
ifdef NEED_MD5
ifdef CONFIG_INTERNAL_MD5
@@ -882,8 +907,10 @@
ifdef NEED_SHA256
L_CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
OBJS += src/crypto/sha256.c
endif
+endif
OBJS += src/crypto/sha256-prf.c
ifdef CONFIG_INTERNAL_SHA256
OBJS += src/crypto/sha256-internal.c
@@ -904,17 +931,21 @@
ifdef NEED_SHA384
L_CFLAGS += -DCONFIG_SHA384
ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
OBJS += src/crypto/sha384.c
endif
+endif
OBJS += src/crypto/sha384-prf.c
endif
ifdef NEED_SHA512
L_CFLAGS += -DCONFIG_SHA512
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
OBJS += src/crypto/sha512.c
endif
endif
+endif
OBJS += src/crypto/sha512-prf.c
endif
@@ -1113,6 +1144,7 @@
endif
ifeq ($(HOSTAPD_USE_HIDL), y)
LOCAL_SHARED_LIBRARIES += android.hardware.wifi.hostapd@1.0
+LOCAL_SHARED_LIBRARIES += android.hardware.wifi.hostapd@1.1
LOCAL_SHARED_LIBRARIES += libbase libhidlbase libhidltransport libhwbinder libutils
LOCAL_STATIC_LIBRARIES += libhostapd_hidl
endif
@@ -1155,12 +1187,13 @@
LOCAL_CPPFLAGS := $(L_CPPFLAGS)
LOCAL_CFLAGS := $(L_CFLAGS)
LOCAL_C_INCLUDES := $(INCLUDES)
-HIDL_INTERFACE_VERSION = 1.0
+HIDL_INTERFACE_VERSION = 1.1
LOCAL_SRC_FILES := \
hidl/$(HIDL_INTERFACE_VERSION)/hidl.cpp \
hidl/$(HIDL_INTERFACE_VERSION)/hostapd.cpp
LOCAL_SHARED_LIBRARIES := \
android.hardware.wifi.hostapd@1.0 \
+ android.hardware.wifi.hostapd@1.1 \
libbase \
libhidlbase \
libhidltransport \
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index d2b669b..f1366b4 100644
--- a/hostapd/ChangeLog
+++ b/hostapd/ChangeLog
@@ -1,5 +1,60 @@
ChangeLog for hostapd
+2018-12-02 - v2.7
+ * fixed WPA packet number reuse with replayed messages and key
+ reinstallation
+ [http://w1.fi/security/2017-1/] (CVE-2017-13082)
+ * added support for FILS (IEEE 802.11ai) shared key authentication
+ * added support for OWE (Opportunistic Wireless Encryption, RFC 8110;
+ and transition mode defined by WFA)
+ * added support for DPP (Wi-Fi Device Provisioning Protocol)
+ * FT:
+ - added local generation of PMK-R0/PMK-R1 for FT-PSK
+ (ft_psk_generate_local=1)
+ - replaced inter-AP protocol with a cleaner design that is more
+ easily extensible; this breaks backward compatibility and requires
+ all APs in the ESS to be updated at the same time to maintain FT
+ functionality
+ - added support for wildcard R0KH/R1KH
+ - replaced r0_key_lifetime (minutes) parameter with
+ ft_r0_key_lifetime (seconds)
+ - fixed wpa_psk_file use for FT-PSK
+ - fixed FT-SAE PMKID matching
+ - added expiration to PMK-R0 and PMK-R1 cache
+ - added IEEE VLAN support (including tagged VLANs)
+ - added support for SHA384 based AKM
+ * SAE
+ - fixed some PMKSA caching cases with SAE
+ - added support for configuring SAE password separately of the
+ WPA2 PSK/passphrase
+ - added option to require MFP for SAE associations
+ (sae_require_pmf=1)
+ - fixed PTK and EAPOL-Key integrity and key-wrap algorithm selection
+ for SAE;
+ note: this is not backwards compatible, i.e., both the AP and
+ station side implementations will need to be update at the same
+ time to maintain interoperability
+ - added support for Password Identifier
+ * hostapd_cli: added support for command history and completion
+ * added support for requesting beacon report
+ * large number of other fixes, cleanup, and extensions
+ * added option to configure EAPOL-Key retry limits
+ (wpa_group_update_count and wpa_pairwise_update_count)
+ * removed all PeerKey functionality
+ * fixed nl80211 AP mode configuration regression with Linux 4.15 and
+ newer
+ * added support for using wolfSSL cryptographic library
+ * fixed some 20/40 MHz coexistence cases where the BSS could drop to
+ 20 MHz even when 40 MHz would be allowed
+ * Hotspot 2.0
+ - added support for setting Venue URL ANQP-element (venue_url)
+ - added support for advertising Hotspot 2.0 operator icons
+ - added support for Roaming Consortium Selection element
+ - added support for Terms and Conditions
+ - added support for OSEN connection in a shared RSN BSS
+ * added support for using OpenSSL 1.1.1
+ * added EAP-pwd server support for salted passwords
+
2016-10-02 - v2.6
* fixed EAP-pwd last fragment validation
[http://w1.fi/security/2015-7/] (CVE-2015-5314)
diff --git a/hostapd/Makefile b/hostapd/Makefile
index eb35672..6e263c5 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -278,6 +278,12 @@
NEED_SHA384=y
endif
+ifdef CONFIG_OCV
+CFLAGS += -DCONFIG_OCV
+OBJS += ../src/common/ocv.o
+CONFIG_IEEE80211W=y
+endif
+
ifdef CONFIG_IEEE80211W
CFLAGS += -DCONFIG_IEEE80211W
NEED_SHA256=y
@@ -489,6 +495,7 @@
CFLAGS += -DEAP_SERVER_PWD
OBJS += ../src/eap_server/eap_server_pwd.o ../src/eap_common/eap_pwd_common.o
NEED_SHA256=y
+NEED_ECC=y
endif
ifdef CONFIG_EAP_EKE
@@ -581,6 +588,9 @@
NEED_JSON=y
NEED_GAS=y
NEED_BASE64=y
+ifdef CONFIG_DPP2
+CFLAGS += -DCONFIG_DPP2
+endif
endif
ifdef CONFIG_EAP_IKEV2
@@ -650,7 +660,29 @@
NEED_SHA256=y
endif
+ifeq ($(CONFIG_TLS), wolfssl)
+CONFIG_CRYPTO=wolfssl
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_wolfssl.o
+LIBS += -lwolfssl -lm
+endif
+OBJS += ../src/crypto/crypto_wolfssl.o
+HOBJS += ../src/crypto/crypto_wolfssl.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_wolfssl.o
+endif
+NEED_SHA256=y
+NEED_TLS_PRF_SHA256=y
+LIBS += -lwolfssl -lm
+LIBS_h += -lwolfssl -lm
+ifdef CONFIG_TLS_ADD_DL
+LIBS += -ldl
+LIBS_h += -ldl
+endif
+endif
+
ifeq ($(CONFIG_TLS), openssl)
+CONFIG_CRYPTO=openssl
ifdef TLS_FUNCS
OBJS += ../src/crypto/tls_openssl.o
OBJS += ../src/crypto/tls_openssl_ocsp.o
@@ -665,6 +697,7 @@
NEED_TLS_PRF_SHA256=y
LIBS += -lcrypto
LIBS_h += -lcrypto
+LIBS_n += -lcrypto
ifdef CONFIG_TLS_ADD_DL
LIBS += -ldl
LIBS_h += -ldl
@@ -676,22 +709,34 @@
endif
ifeq ($(CONFIG_TLS), gnutls)
+ifndef CONFIG_CRYPTO
+# default to libgcrypt
+CONFIG_CRYPTO=gnutls
+endif
ifdef TLS_FUNCS
OBJS += ../src/crypto/tls_gnutls.o
LIBS += -lgnutls -lgpg-error
endif
-OBJS += ../src/crypto/crypto_gnutls.o
-HOBJS += ../src/crypto/crypto_gnutls.o
+OBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
+HOBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
ifdef NEED_FIPS186_2_PRF
OBJS += ../src/crypto/fips_prf_internal.o
SHA1OBJS += ../src/crypto/sha1-internal.o
endif
+ifeq ($(CONFIG_CRYPTO), gnutls)
LIBS += -lgcrypt
LIBS_h += -lgcrypt
-CONFIG_INTERNAL_SHA256=y
+LIBS_n += -lgcrypt
CONFIG_INTERNAL_RC4=y
CONFIG_INTERNAL_DH_GROUP5=y
endif
+ifeq ($(CONFIG_CRYPTO), nettle)
+LIBS += -lnettle -lgmp
+LIBS_p += -lnettle -lgmp
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+endif
ifeq ($(CONFIG_TLS), internal)
ifndef CONFIG_CRYPTO
@@ -843,8 +888,10 @@
endif
ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), wolfssl)
AESOBJS += ../src/crypto/aes-wrap.o
endif
+endif
ifdef NEED_AES_EAX
AESOBJS += ../src/crypto/aes-eax.o
NEED_AES_CTR=y
@@ -863,25 +910,31 @@
endif
ifdef NEED_AES_OMAC1
ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
AESOBJS += ../src/crypto/aes-omac1.o
endif
endif
+endif
ifdef NEED_AES_UNWRAP
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
NEED_AES_DEC=y
AESOBJS += ../src/crypto/aes-unwrap.o
endif
endif
endif
+endif
ifdef NEED_AES_CBC
NEED_AES_DEC=y
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
AESOBJS += ../src/crypto/aes-cbc.o
endif
endif
endif
+endif
ifdef NEED_AES_DEC
ifdef CONFIG_INTERNAL_AES
AESOBJS += ../src/crypto/aes-internal-dec.o
@@ -894,9 +947,13 @@
ifdef NEED_SHA1
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
SHA1OBJS += ../src/crypto/sha1.o
endif
endif
+endif
+endif
SHA1OBJS += ../src/crypto/sha1-prf.o
ifdef CONFIG_INTERNAL_SHA1
SHA1OBJS += ../src/crypto/sha1-internal.o
@@ -905,8 +962,10 @@
endif
endif
ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), wolfssl)
SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
endif
+endif
ifdef NEED_T_PRF
SHA1OBJS += ../src/crypto/sha1-tprf.o
endif
@@ -921,9 +980,13 @@
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
OBJS += ../src/crypto/md5.o
endif
endif
+endif
+endif
ifdef NEED_MD5
ifdef CONFIG_INTERNAL_MD5
@@ -939,6 +1002,7 @@
endif
ifdef NEED_DES
+CFLAGS += -DCONFIG_DES
ifdef CONFIG_INTERNAL_DES
OBJS += ../src/crypto/des-internal.o
endif
@@ -960,9 +1024,13 @@
CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
OBJS += ../src/crypto/sha256.o
endif
endif
+endif
+endif
OBJS += ../src/crypto/sha256-prf.o
ifdef CONFIG_INTERNAL_SHA256
OBJS += ../src/crypto/sha256-internal.o
@@ -984,18 +1052,26 @@
CFLAGS += -DCONFIG_SHA384
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
OBJS += ../src/crypto/sha384.o
endif
endif
+endif
+endif
OBJS += ../src/crypto/sha384-prf.o
endif
ifdef NEED_SHA512
CFLAGS += -DCONFIG_SHA512
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
OBJS += ../src/crypto/sha512.o
endif
endif
+endif
+endif
OBJS += ../src/crypto/sha512-prf.o
endif
@@ -1028,16 +1104,21 @@
ifdef CONFIG_NO_RANDOM_POOL
CFLAGS += -DCONFIG_NO_RANDOM_POOL
else
+ifdef CONFIG_GETRANDOM
+CFLAGS += -DCONFIG_GETRANDOM
+endif
OBJS += ../src/crypto/random.o
HOBJS += ../src/crypto/random.o
HOBJS += ../src/utils/eloop.o
HOBJS += $(SHA1OBJS)
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
HOBJS += ../src/crypto/md5.o
endif
endif
endif
+endif
ifdef CONFIG_RADIUS_SERVER
CFLAGS += -DRADIUS_SERVER
@@ -1228,16 +1309,14 @@
ifdef CONFIG_INTERNAL_MD5
NOBJS += ../src/crypto/md5-internal.o
endif
-NOBJS += ../src/crypto/crypto_openssl.o ../src/utils/os_$(CONFIG_OS).o
+NOBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
+NOBJS += ../src/utils/os_$(CONFIG_OS).o
NOBJS += ../src/utils/wpa_debug.o
NOBJS += ../src/utils/wpabuf.o
ifdef CONFIG_WPA_TRACE
NOBJS += ../src/utils/trace.o
LIBS_n += -lbfd
endif
-ifdef TLS_FUNCS
-LIBS_n += -lcrypto
-endif
HOBJS += hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/utils/wpabuf.o ../src/crypto/milenage.o
HOBJS += ../src/crypto/aes-encblock.o
diff --git a/hostapd/README b/hostapd/README
index 298391b..1f30d7e 100644
--- a/hostapd/README
+++ b/hostapd/README
@@ -2,7 +2,7 @@
Authenticator and RADIUS authentication server
================================================================
-Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
This program is licensed under the BSD license (the one with
diff --git a/hostapd/README-MULTI-AP b/hostapd/README-MULTI-AP
new file mode 100644
index 0000000..ccee69e
--- /dev/null
+++ b/hostapd/README-MULTI-AP
@@ -0,0 +1,160 @@
+hostapd, wpa_supplicant and the Multi-AP Specification
+======================================================
+
+This document describes how hostapd and wpa_supplicant can be configured to
+support the Multi-AP Specification.
+
+Introduction to Multi-AP
+------------------------
+
+The Wi-Fi Alliance Multi-AP Specification is the technical specification for
+Wi-Fi CERTIFIED EasyMesh(TM) [1], the Wi-Fi Alliance® certification program for
+Multi-AP. It defines control protocols between Wi-Fi® access points (APs) to
+join them into a network with centralized control and operation. It is targeted
+only at routers (repeaters, gateways, ...), not at clients. Clients are not
+involved at all in the protocols.
+
+Most of the Multi-AP specification falls outside of the scope of
+hostapd/wpa_supplicant. hostapd/wpa_supplicant is only involved for the items
+summarized below. The rest of the protocol must be implemented by a separate
+daemon, e.g., prplMesh [2]. That daemon also needs to communicate with hostapd,
+e.g., to get a list of associated clients, but this can be done using the normal
+hostapd interfaces.
+
+hostapd/wpa_supplicant needs to be configured specifically to support:
+- the WPS onboarding process;
+- configuring backhaul links.
+
+The text below refers to "Multi-AP Specification v1.0" [3].
+
+
+Fronthaul and backhaul links
+----------------------------
+
+In a Multi-AP network, the central controller can configure the BSSs on the
+devices that are joined into the network. These are called fronthaul BSSs.
+From the point of view of hostapd, there is nothing special about these
+fronthaul BSSs.
+
+In addition to fronthaul BSSs, the controller can also configure backhaul
+links. A backhaul link is a link between two access point devices, giving
+internet access to access point devices that don't have a wired link. The
+Multi-AP specification doesn't dictate this, but typically the backhaul link
+will be bridged into a LAN together with (one of) the fronthaul BSS(s) and the
+wired Ethernet ports.
+
+A backhaul link must be treated specially by hostapd and wpa_supplicant. One
+side of the backhaul link is configured through the Multi-AP protocol as the
+"backhaul STA", i.e., the client side of the link. A backhaul STA is like any
+station and is handled appropriately by wpa_supplicant, but two additional
+features are required. It must send an additional information element in each
+(Re)Association Request frame ([3], section 5.2, paragraph 4). In addition, it
+must use 4-address mode for all frames sent over this link ([3], section 14).
+Therefore, wpa_supplicant must be configured explicitly as the backhaul STA
+role, by setting 'multi_ap_backhaul_sta=1' in the network configuration block
+or when configuring the network profile through the control interface. When
+'multi_ap_backhaul_sta=1', wpa_supplicant includes the Multi-AP IE in
+(Re)Association Request frame and verifies that it is included in the
+(Re)Association Response frame. If it is not, association fails. If it is,
+wpa_supplicant sets 4-address mode for this interface through a driver
+callback.
+
+The AP side of the backhaul link is called a "backhaul BSS". Such a BSS must
+be handled specially by hostapd, because it must add an additional information
+element in each (Re)Association Response frame, but only to stations that have
+identified themselves as backhaul stations ([3], section 5.2, paragraph 5-6).
+This is important because it is possible to use the same BSS and SSID for
+fronthaul and backhaul at the same time. The additional information element must
+only be used for frames sent to a backhaul STA, not to a normal STA. Also,
+frames sent to a backhaul STA must use 4-address mode, while frames sent to a
+normal STA (fronthaul, when it's a fronthaul and backhaul BSS) must use
+3-address mode.
+
+A BSS is configured in Multi-AP mode in hostapd by setting the 'multi_ap'
+configuration option to 1 (backhaul BSS), 2 (fronthaul BSS), or 3
+(simultaneous backhaul and fronthaul BSS). If this option is set, hostapd
+parses the Multi-AP information element in the Association Request frame. If the
+station is a backhaul STA and the BSS is configured as a backhaul BSS,
+hostapd sets up 4-address mode. Since there may be multiple stations connected
+simultaneously, and each of them has a different RA (receiver address), a VLAN
+is created for each backhaul STA and it is automatically added to a bridge.
+This is the same behavior as for WDS, and the relevant option ('bridge' or
+'wds_bridge') applies here as well.
+
+If 'multi_ap' is 1 (backhaul BSS only), any station that tries to associate
+without the Multi-AP information element will be denied.
+
+If 'multi_ap' is 2 (fronthaul BSS only), any station that tries to associate
+with the Multi-AP information element will be denied. That is also the only
+difference with 'multi_ap' set to 0: in the latter case, the Multi-AP
+information element is simply ignored.
+
+In summary, this is the end-to-end behavior for a backhaul BSS (i.e.,
+multi_ap_backhaul_sta=1 in wpa_supplicant on STA, and multi_ap=1 or 3 in
+hostapd on AP). Note that point 1 means that hostapd must not be configured
+with WPS support on the backhaul BSS (multi_ap=1). hostapd does not check for
+that.
+
+1. Backhaul BSS beacons do not advertise WPS support (other than that, nothing
+ Multi-AP specific).
+2. STA sends Authentication frame (nothing Multi-AP specific).
+3. AP sends Authentication frame (nothing Multi-AP specific).
+4. STA sends Association Request frame with Multi-AP IE.
+5. AP sends Association Response frame with Multi-AP IE.
+6. STA and AP both use 4-address mode for Data frames.
+
+
+WPS support
+-----------
+
+WPS requires more special handling. WPS must only be advertised on fronthaul
+BSSs, not on backhaul BSSs, so WPS should not be enabled on a backhaul-only
+BSS in hostapd.conf. The WPS configuration purely works on the fronthaul BSS.
+When a WPS M1 message has an additional subelement that indicates a request for
+a Multi-AP backhaul link, hostapd must not respond with the normal fronthaul
+BSS credentials; instead, it should respond with the (potentially different)
+backhaul BSS credentials.
+
+To support this, hostapd has the 'multi_ap_backhaul_ssid',
+'multi_ap_backhaul_wpa_psk' and 'multi_ap_backhaul_wpa_passphrase' options.
+When these are set on an BSS with WPS, they are used instead of the normal
+credentials when hostapd receives a WPS M1 message with the Multi-AP IE. Only
+WPA2-Personal is supported in the Multi-AP specification, so there is no need
+to specify authentication or encryption options. For the backhaul credentials,
+per-device PSK is not supported.
+
+If the BSS is a simultaneous backhaul and fronthaul BSS, there is no need to
+specify the backhaul credentials, since the backhaul and fronthaul credentials
+are identical.
+
+To enable the Multi-AP backhaul STA feature when it performs WPS, a new
+parameter has been introduced to the WPS_PBC control interface call. When this
+"multi_ap=1" option is set, it adds the Multi-AP backhaul subelement to the
+Association Request frame and the M1 message. It then configures the new network
+profile with 'multi_ap_backhaul_sta=1'. Note that this means that if the AP does
+not follow the Multi-AP specification, wpa_supplicant will fail to associate.
+
+In summary, this is the end-to-end behavior for WPS of a backhaul link (i.e.,
+multi_ap=1 option is given in the wps_pbc call on the STA side, and multi_ap=2
+and multi_ap_backhaul_ssid and either multi_ap_backhaul_wpa_psk or
+multi_ap_backhaul_wpa_passphrase are set to the credentials of a backhaul BSS
+in hostapd on Registrar AP).
+
+1. Fronthaul BSS Beacon frames advertise WPS support (nothing Multi-AP
+ specific).
+2. Enrollee sends Authentication frame (nothing Multi-AP specific).
+3. AP sends Authentication frame (nothing Multi-AP specific).
+4. Enrollee sends Association Request frame with Multi-AP IE.
+5. AP sends Association Response frame with Multi-AP IE.
+6. Enrollee sends M1 with additional Multi-AP subelement.
+7. AP sends M8 with backhaul instead of fronthaul credentials.
+8. Enrollee sends Deauthentication frame.
+
+
+References
+----------
+
+[1] https://www.wi-fi.org/discover-wi-fi/wi-fi-easymesh
+[2] https://github.com/prplfoundation/prplMesh
+[3] https://www.wi-fi.org/file/multi-ap-specification-v10
+ (requires registration)
diff --git a/hostapd/android.config b/hostapd/android.config
index 5a24438..4502a60 100644
--- a/hostapd/android.config
+++ b/hostapd/android.config
@@ -50,6 +50,9 @@
# Driver support is also needed for IEEE 802.11w.
CONFIG_IEEE80211W=y
+# Support Operating Channel Validation
+#CONFIG_OCV=y
+
# Integrated EAP server
#CONFIG_EAP=y
@@ -220,3 +223,9 @@
# Enable support of Automatic Channel Selection
CONFIG_ACS=y
+
+# Easy Connect (Device Provisioning Protocol - DPP)
+CONFIG_DPP=y
+
+# WPA3-Personal (SAE)
+CONFIG_SAE=y
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index e2a470c..42f3b40 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -1,6 +1,6 @@
/*
* hostapd / Configuration file parser
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -37,7 +37,7 @@
const char *fname)
{
FILE *f;
- char buf[128], *pos, *pos2;
+ char buf[128], *pos, *pos2, *pos3;
int line = 0, vlan_id;
struct hostapd_vlan *vlan;
@@ -82,7 +82,10 @@
pos2 = pos;
while (*pos2 != ' ' && *pos2 != '\t' && *pos2 != '\0')
pos2++;
- *pos2 = '\0';
+
+ if (*pos2 != '\0')
+ *(pos2++) = '\0';
+
if (*pos == '\0' || os_strlen(pos) > IFNAMSIZ) {
wpa_printf(MSG_ERROR, "Invalid VLAN ifname at line %d "
"in '%s'", line, fname);
@@ -90,6 +93,13 @@
return -1;
}
+ while (*pos2 == ' ' || *pos2 == '\t')
+ pos2++;
+ pos3 = pos2;
+ while (*pos3 != ' ' && *pos3 != '\t' && *pos3 != '\0')
+ pos3++;
+ *pos3 = '\0';
+
vlan = os_zalloc(sizeof(*vlan));
if (vlan == NULL) {
wpa_printf(MSG_ERROR, "Out of memory while reading "
@@ -102,6 +112,7 @@
vlan->vlan_desc.untagged = vlan_id;
vlan->vlan_desc.notempty = !!vlan_id;
os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname));
+ os_strlcpy(vlan->bridge, pos2, sizeof(vlan->bridge));
vlan->next = bss->vlan;
bss->vlan = vlan;
}
@@ -113,7 +124,7 @@
#endif /* CONFIG_NO_VLAN */
-static int hostapd_acl_comp(const void *a, const void *b)
+int hostapd_acl_comp(const void *a, const void *b)
{
const struct mac_acl_entry *aa = a;
const struct mac_acl_entry *bb = b;
@@ -121,6 +132,44 @@
}
+int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
+ int vlan_id, const u8 *addr)
+{
+ struct mac_acl_entry *newacl;
+
+ newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
+ if (!newacl) {
+ wpa_printf(MSG_ERROR, "MAC list reallocation failed");
+ return -1;
+ }
+
+ *acl = newacl;
+ os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
+ os_memset(&(*acl)[*num].vlan_id, 0, sizeof((*acl)[*num].vlan_id));
+ (*acl)[*num].vlan_id.untagged = vlan_id;
+ (*acl)[*num].vlan_id.notempty = !!vlan_id;
+ (*num)++;
+
+ return 0;
+}
+
+
+void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
+ const u8 *addr)
+{
+ int i = 0;
+
+ while (i < *num) {
+ if (os_memcmp((*acl)[i].addr, addr, ETH_ALEN) == 0) {
+ os_remove_in_array(*acl, *num, sizeof(**acl), i);
+ (*num)--;
+ } else {
+ i++;
+ }
+ }
+}
+
+
static int hostapd_config_read_maclist(const char *fname,
struct mac_acl_entry **acl, int *num)
{
@@ -128,7 +177,6 @@
char buf[128], *pos;
int line = 0;
u8 addr[ETH_ALEN];
- struct mac_acl_entry *newacl;
int vlan_id;
f = fopen(fname, "r");
@@ -138,7 +186,7 @@
}
while (fgets(buf, sizeof(buf), f)) {
- int i, rem = 0;
+ int rem = 0;
line++;
@@ -168,16 +216,7 @@
}
if (rem) {
- i = 0;
- while (i < *num) {
- if (os_memcmp((*acl)[i].addr, addr, ETH_ALEN) ==
- 0) {
- os_remove_in_array(*acl, *num,
- sizeof(**acl), i);
- (*num)--;
- } else
- i++;
- }
+ hostapd_remove_acl_mac(acl, num, addr);
continue;
}
vlan_id = 0;
@@ -189,20 +228,10 @@
if (*pos != '\0')
vlan_id = atoi(pos);
- newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
- if (newacl == NULL) {
- wpa_printf(MSG_ERROR, "MAC list reallocation failed");
+ if (hostapd_add_acl_maclist(acl, num, vlan_id, addr) < 0) {
fclose(f);
return -1;
}
-
- *acl = newacl;
- os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
- os_memset(&(*acl)[*num].vlan_id, 0,
- sizeof((*acl)[*num].vlan_id));
- (*acl)[*num].vlan_id.untagged = vlan_id;
- (*acl)[*num].vlan_id.notempty = !!vlan_id;
- (*num)++;
}
fclose(f);
@@ -215,6 +244,62 @@
#ifdef EAP_SERVER
+
+static int hostapd_config_eap_user_salted(struct hostapd_eap_user *user,
+ const char *hash, size_t len,
+ char **pos, int line,
+ const char *fname)
+{
+ char *pos2 = *pos;
+
+ while (*pos2 != '\0' && *pos2 != ' ' && *pos2 != '\t' && *pos2 != '#')
+ pos2++;
+
+ if (pos2 - *pos < (int) (2 * (len + 1))) { /* at least 1 byte of salt */
+ wpa_printf(MSG_ERROR,
+ "Invalid salted %s hash on line %d in '%s'",
+ hash, line, fname);
+ return -1;
+ }
+
+ user->password = os_malloc(len);
+ if (!user->password) {
+ wpa_printf(MSG_ERROR,
+ "Failed to allocate memory for salted %s hash",
+ hash);
+ return -1;
+ }
+
+ if (hexstr2bin(*pos, user->password, len) < 0) {
+ wpa_printf(MSG_ERROR,
+ "Invalid salted password on line %d in '%s'",
+ line, fname);
+ return -1;
+ }
+ user->password_len = len;
+ *pos += 2 * len;
+
+ user->salt_len = (pos2 - *pos) / 2;
+ user->salt = os_malloc(user->salt_len);
+ if (!user->salt) {
+ wpa_printf(MSG_ERROR,
+ "Failed to allocate memory for salted %s hash",
+ hash);
+ return -1;
+ }
+
+ if (hexstr2bin(*pos, user->salt, user->salt_len) < 0) {
+ wpa_printf(MSG_ERROR,
+ "Invalid salt for password on line %d in '%s'",
+ line, fname);
+ return -1;
+ }
+
+ *pos = pos2;
+ return 0;
+}
+
+
static int hostapd_config_read_eap_user(const char *fname,
struct hostapd_bss_config *conf)
{
@@ -466,6 +551,24 @@
user->password_len = 16;
user->password_hash = 1;
pos = pos2;
+ } else if (os_strncmp(pos, "ssha1:", 6) == 0) {
+ pos += 6;
+ if (hostapd_config_eap_user_salted(user, "sha1", 20,
+ &pos,
+ line, fname) < 0)
+ goto failed;
+ } else if (os_strncmp(pos, "ssha256:", 8) == 0) {
+ pos += 8;
+ if (hostapd_config_eap_user_salted(user, "sha256", 32,
+ &pos,
+ line, fname) < 0)
+ goto failed;
+ } else if (os_strncmp(pos, "ssha512:", 8) == 0) {
+ pos += 8;
+ if (hostapd_config_eap_user_salted(user, "sha512", 64,
+ &pos,
+ line, fname) < 0)
+ goto failed;
} else {
pos2 = pos;
while (*pos2 != '\0' && *pos2 != ' ' &&
@@ -525,6 +628,7 @@
return ret;
}
+
#endif /* EAP_SERVER */
@@ -679,6 +783,10 @@
val |= WPA_KEY_MGMT_FT_PSK;
else if (os_strcmp(start, "FT-EAP") == 0)
val |= WPA_KEY_MGMT_FT_IEEE8021X;
+#ifdef CONFIG_SHA384
+ else if (os_strcmp(start, "FT-EAP-SHA384") == 0)
+ val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
@@ -720,6 +828,10 @@
else if (os_strcmp(start, "DPP") == 0)
val |= WPA_KEY_MGMT_DPP;
#endif /* CONFIG_DPP */
+#ifdef CONFIG_HS20
+ else if (os_strcmp(start, "OSEN") == 0)
+ val |= WPA_KEY_MGMT_OSEN;
+#endif /* CONFIG_HS20 */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
@@ -1136,6 +1248,8 @@
conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
conf->ht40_plus_minus_allowed = 1;
}
+ if (!os_strstr(capab, "[HT40+]") && !os_strstr(capab, "[HT40-]"))
+ conf->secondary_channel = 0;
if (os_strstr(capab, "[SMPS-STATIC]")) {
conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
conf->ht_capab |= HT_CAP_INFO_SMPS_STATIC;
@@ -1265,6 +1379,30 @@
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+
+static u8 find_bit_offset(u8 val)
+{
+ u8 res = 0;
+
+ for (; val; val >>= 1) {
+ if (val & 1)
+ break;
+ res++;
+ }
+
+ return res;
+}
+
+
+static u8 set_he_cap(int val, u8 mask)
+{
+ return (u8) (mask & (val << find_bit_offset(mask)));
+}
+
+#endif /* CONFIG_IEEE80211AX */
+
+
#ifdef CONFIG_INTERWORKING
static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
int line)
@@ -1358,6 +1496,44 @@
}
+static int parse_venue_url(struct hostapd_bss_config *bss, char *pos,
+ int line)
+{
+ char *sep;
+ size_t nlen;
+ struct hostapd_venue_url *url;
+ int ret = -1;
+
+ sep = os_strchr(pos, ':');
+ if (!sep)
+ goto fail;
+ *sep++ = '\0';
+
+ nlen = os_strlen(sep);
+ if (nlen > 254)
+ goto fail;
+
+ url = os_realloc_array(bss->venue_url, bss->venue_url_count + 1,
+ sizeof(struct hostapd_venue_url));
+ if (!url)
+ goto fail;
+
+ bss->venue_url = url;
+ url = &bss->venue_url[bss->venue_url_count++];
+
+ url->venue_number = atoi(pos);
+ url->url_len = nlen;
+ os_memcpy(url->url, sep, nlen);
+
+ ret = 0;
+fail:
+ if (ret)
+ wpa_printf(MSG_ERROR, "Line %d: Invalid venue_url '%s'",
+ line, pos);
+ return ret;
+}
+
+
static int parse_3gpp_cell_net(struct hostapd_bss_config *bss, char *buf,
int line)
{
@@ -1908,6 +2084,24 @@
}
+static int hs20_parse_osu_nai2(struct hostapd_bss_config *bss,
+ char *pos, int line)
+{
+ if (bss->last_osu == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line);
+ return -1;
+ }
+
+ os_free(bss->last_osu->osu_nai2);
+ bss->last_osu->osu_nai2 = os_strdup(pos);
+ if (bss->last_osu->osu_nai2 == NULL)
+ return -1;
+ bss->hs20_osu_providers_nai_count++;
+
+ return 0;
+}
+
+
static int hs20_parse_osu_method_list(struct hostapd_bss_config *bss, char *pos,
int line)
{
@@ -1967,6 +2161,25 @@
return 0;
}
+
+static int hs20_parse_operator_icon(struct hostapd_bss_config *bss, char *pos,
+ int line)
+{
+ char **n;
+
+ n = os_realloc_array(bss->hs20_operator_icon,
+ bss->hs20_operator_icon_count + 1, sizeof(char *));
+ if (!n)
+ return -1;
+ bss->hs20_operator_icon = n;
+ bss->hs20_operator_icon[bss->hs20_operator_icon_count] = os_strdup(pos);
+ if (!bss->hs20_operator_icon[bss->hs20_operator_icon_count])
+ return -1;
+ bss->hs20_operator_icon_count++;
+
+ return 0;
+}
+
#endif /* CONFIG_HS20 */
@@ -2065,16 +2278,31 @@
{
unsigned int flags = 0;
+ /* Disable TLS v1.3 by default for now to avoid interoperability issue.
+ * This can be enabled by default once the implementation has been fully
+ * completed and tested with other implementations. */
+ flags |= TLS_CONN_DISABLE_TLSv1_3;
+
if (os_strstr(val, "[ALLOW-SIGN-RSA-MD5]"))
flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5;
if (os_strstr(val, "[DISABLE-TIME-CHECKS]"))
flags |= TLS_CONN_DISABLE_TIME_CHECKS;
if (os_strstr(val, "[DISABLE-TLSv1.0]"))
flags |= TLS_CONN_DISABLE_TLSv1_0;
+ if (os_strstr(val, "[ENABLE-TLSv1.0]"))
+ flags |= TLS_CONN_ENABLE_TLSv1_0;
if (os_strstr(val, "[DISABLE-TLSv1.1]"))
flags |= TLS_CONN_DISABLE_TLSv1_1;
+ if (os_strstr(val, "[ENABLE-TLSv1.1]"))
+ flags |= TLS_CONN_ENABLE_TLSv1_1;
if (os_strstr(val, "[DISABLE-TLSv1.2]"))
flags |= TLS_CONN_DISABLE_TLSv1_2;
+ if (os_strstr(val, "[ENABLE-TLSv1.2]"))
+ flags |= TLS_CONN_ENABLE_TLSv1_2;
+ if (os_strstr(val, "[DISABLE-TLSv1.3]"))
+ flags |= TLS_CONN_DISABLE_TLSv1_3;
+ if (os_strstr(val, "[ENABLE-TLSv1.3]"))
+ flags &= ~TLS_CONN_DISABLE_TLSv1_3;
if (os_strstr(val, "[SUITEB]"))
flags |= TLS_CONN_SUITEB;
if (os_strstr(val, "[SUITEB-NO-ECDH]"))
@@ -2085,6 +2313,69 @@
#endif /* EAP_SERVER */
+#ifdef CONFIG_SAE
+static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
+{
+ struct sae_password_entry *pw;
+ const char *pos = val, *pos2, *end = NULL;
+
+ pw = os_zalloc(sizeof(*pw));
+ if (!pw)
+ return -1;
+ os_memset(pw->peer_addr, 0xff, ETH_ALEN); /* default to wildcard */
+
+ pos2 = os_strstr(pos, "|mac=");
+ if (pos2) {
+ end = pos2;
+ pos2 += 5;
+ if (hwaddr_aton(pos2, pw->peer_addr) < 0)
+ goto fail;
+ pos = pos2 + ETH_ALEN * 3 - 1;
+ }
+
+ pos2 = os_strstr(pos, "|vlanid=");
+ if (pos2) {
+ if (!end)
+ end = pos2;
+ pos2 += 8;
+ pw->vlan_id = atoi(pos2);
+ }
+
+ pos2 = os_strstr(pos, "|id=");
+ if (pos2) {
+ if (!end)
+ end = pos2;
+ pos2 += 4;
+ pw->identifier = os_strdup(pos2);
+ if (!pw->identifier)
+ goto fail;
+ }
+
+ if (!end) {
+ pw->password = os_strdup(val);
+ if (!pw->password)
+ goto fail;
+ } else {
+ pw->password = os_malloc(end - val + 1);
+ if (!pw->password)
+ goto fail;
+ os_memcpy(pw->password, val, end - val);
+ pw->password[end - val] = '\0';
+ }
+
+ pw->next = bss->sae_passwords;
+ bss->sae_passwords = pw;
+
+ return 0;
+fail:
+ str_clear_free(pw->password);
+ os_free(pw->identifier);
+ os_free(pw);
+ return -1;
+}
+#endif /* CONFIG_SAE */
+
+
static int hostapd_config_fill(struct hostapd_config *conf,
struct hostapd_bss_config *bss,
const char *buf, char *pos, int line)
@@ -2234,8 +2525,22 @@
} else if (os_strcmp(buf, "private_key_passwd") == 0) {
os_free(bss->private_key_passwd);
bss->private_key_passwd = os_strdup(pos);
+ } else if (os_strcmp(buf, "check_cert_subject") == 0) {
+ if (!pos[0]) {
+ wpa_printf(MSG_ERROR, "Line %d: unknown check_cert_subject '%s'",
+ line, pos);
+ return 1;
+ }
+ os_free(bss->check_cert_subject);
+ bss->check_cert_subject = os_strdup(pos);
+ if (!bss->check_cert_subject)
+ return 1;
} else if (os_strcmp(buf, "check_crl") == 0) {
bss->check_crl = atoi(pos);
+ } else if (os_strcmp(buf, "check_crl_strict") == 0) {
+ bss->check_crl_strict = atoi(pos);
+ } else if (os_strcmp(buf, "crl_reload_interval") == 0) {
+ bss->crl_reload_interval = atoi(pos);
} else if (os_strcmp(buf, "tls_session_lifetime") == 0) {
bss->tls_session_lifetime = atoi(pos);
} else if (os_strcmp(buf, "tls_flags") == 0) {
@@ -2252,6 +2557,9 @@
} else if (os_strcmp(buf, "openssl_ciphers") == 0) {
os_free(bss->openssl_ciphers);
bss->openssl_ciphers = os_strdup(pos);
+ } else if (os_strcmp(buf, "openssl_ecdh_curves") == 0) {
+ os_free(bss->openssl_ecdh_curves);
+ bss->openssl_ecdh_curves = os_strdup(pos);
} else if (os_strcmp(buf, "fragment_size") == 0) {
bss->fragment_size = atoi(pos);
#ifdef EAP_SERVER_FAST
@@ -2314,8 +2622,10 @@
} else if (os_strcmp(buf, "pwd_group") == 0) {
bss->pwd_group = atoi(pos);
#endif /* EAP_SERVER_PWD */
+#ifdef CONFIG_ERP
} else if (os_strcmp(buf, "eap_server_erp") == 0) {
bss->eap_server_erp = atoi(pos);
+#endif /* CONFIG_ERP */
#endif /* EAP_SERVER */
} else if (os_strcmp(buf, "eap_message") == 0) {
char *term;
@@ -2643,6 +2953,20 @@
line, pos);
return 1;
}
+ } else if (os_strcmp(buf, "group_cipher") == 0) {
+ bss->group_cipher = hostapd_config_parse_cipher(line, pos);
+ if (bss->group_cipher == -1 || bss->group_cipher == 0)
+ return 1;
+ if (bss->group_cipher != WPA_CIPHER_TKIP &&
+ bss->group_cipher != WPA_CIPHER_CCMP &&
+ bss->group_cipher != WPA_CIPHER_GCMP &&
+ bss->group_cipher != WPA_CIPHER_GCMP_256 &&
+ bss->group_cipher != WPA_CIPHER_CCMP_256) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: unsupported group cipher suite '%s'",
+ line, pos);
+ return 1;
+ }
#ifdef CONFIG_RSN_PREAUTH
} else if (os_strcmp(buf, "rsn_preauth") == 0) {
bss->rsn_preauth = atoi(pos);
@@ -2672,7 +2996,12 @@
return 1;
}
} else if (os_strcmp(buf, "r0_key_lifetime") == 0) {
+ /* DEPRECATED: Use ft_r0_key_lifetime instead. */
+ bss->r0_key_lifetime = atoi(pos) * 60;
+ } else if (os_strcmp(buf, "ft_r0_key_lifetime") == 0) {
bss->r0_key_lifetime = atoi(pos);
+ } else if (os_strcmp(buf, "r1_max_key_lifetime") == 0) {
+ bss->r1_max_key_lifetime = atoi(pos);
} else if (os_strcmp(buf, "reassociation_deadline") == 0) {
bss->reassociation_deadline = atoi(pos);
} else if (os_strcmp(buf, "rkh_pos_timeout") == 0) {
@@ -2807,9 +3136,10 @@
* cause problems with the current implementation.
* Since it is unlikely that this small numbers are
* useful in real life scenarios, do not allow beacon
- * period to be set below 15 TU. */
- if (val < 15 || val > 65535) {
- wpa_printf(MSG_ERROR, "Line %d: invalid beacon_int %d (expected 15..65535)",
+ * period to be set below 10 TU. */
+ if (val < 10 || val > 65535) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid beacon_int %d (expected 10..65535)",
line, val);
return 1;
}
@@ -2840,14 +3170,25 @@
}
bss->dtim_period = val;
} else if (os_strcmp(buf, "bss_load_update_period") == 0) {
- bss->bss_load_update_period = atoi(pos);
- if (bss->bss_load_update_period < 0 ||
- bss->bss_load_update_period > 100) {
+ int val = atoi(pos);
+
+ if (val < 0 || val > 100) {
wpa_printf(MSG_ERROR,
"Line %d: invalid bss_load_update_period %d",
- line, bss->bss_load_update_period);
+ line, val);
return 1;
}
+ bss->bss_load_update_period = val;
+ } else if (os_strcmp(buf, "chan_util_avg_period") == 0) {
+ int val = atoi(pos);
+
+ if (val < 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid chan_util_avg_period",
+ line);
+ return 1;
+ }
+ bss->chan_util_avg_period = val;
} else if (os_strcmp(buf, "rts_threshold") == 0) {
conf->rts_threshold = atoi(pos);
if (conf->rts_threshold < -1 || conf->rts_threshold > 65535) {
@@ -2874,7 +3215,7 @@
line, val);
return 1;
}
- conf->send_probe_response = val;
+ bss->send_probe_response = val;
} else if (os_strcmp(buf, "supported_rates") == 0) {
if (hostapd_parse_intlist(&conf->supported_rates, pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid rate list",
@@ -3042,6 +3383,12 @@
return 1;
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ } else if (os_strcmp(buf, "ocv") == 0) {
+ bss->ocv = atoi(pos);
+ if (bss->ocv && !bss->ieee80211w)
+ bss->ieee80211w = 1;
+#endif /* CONFIG_OCV */
#ifdef CONFIG_IEEE80211N
} else if (os_strcmp(buf, "ieee80211n") == 0) {
conf->ieee80211n = atoi(pos);
@@ -3095,6 +3442,90 @@
conf->he_op.he_twt_required = atoi(pos);
} else if (os_strcmp(buf, "he_rts_threshold") == 0) {
conf->he_op.he_rts_threshold = atoi(pos);
+ } else if (os_strcmp(buf, "he_mu_edca_qos_info_param_count") == 0) {
+ conf->he_mu_edca.he_qos_info |=
+ set_he_cap(atoi(pos), HE_QOS_INFO_EDCA_PARAM_SET_COUNT);
+ } else if (os_strcmp(buf, "he_mu_edca_qos_info_q_ack") == 0) {
+ conf->he_mu_edca.he_qos_info |=
+ set_he_cap(atoi(pos), HE_QOS_INFO_Q_ACK);
+ } else if (os_strcmp(buf, "he_mu_edca_qos_info_queue_request") == 0) {
+ conf->he_mu_edca.he_qos_info |=
+ set_he_cap(atoi(pos), HE_QOS_INFO_QUEUE_REQUEST);
+ } else if (os_strcmp(buf, "he_mu_edca_qos_info_txop_request") == 0) {
+ conf->he_mu_edca.he_qos_info |=
+ set_he_cap(atoi(pos), HE_QOS_INFO_TXOP_REQUEST);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_be_aifsn") == 0) {
+ conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_be_acm") == 0) {
+ conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_be_aci") == 0) {
+ conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_be_ecwmin") == 0) {
+ conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_be_ecwmax") == 0) {
+ conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_be_timer") == 0) {
+ conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_TIMER_IDX] =
+ atoi(pos) & 0xff;
+ } else if (os_strcmp(buf, "he_mu_edca_ac_bk_aifsn") == 0) {
+ conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_bk_acm") == 0) {
+ conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_bk_aci") == 0) {
+ conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_bk_ecwmin") == 0) {
+ conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_bk_ecwmax") == 0) {
+ conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_bk_timer") == 0) {
+ conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_TIMER_IDX] =
+ atoi(pos) & 0xff;
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vi_aifsn") == 0) {
+ conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vi_acm") == 0) {
+ conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vi_aci") == 0) {
+ conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vi_ecwmin") == 0) {
+ conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vi_ecwmax") == 0) {
+ conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vi_timer") == 0) {
+ conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_TIMER_IDX] =
+ atoi(pos) & 0xff;
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vo_aifsn") == 0) {
+ conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vo_acm") == 0) {
+ conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vo_aci") == 0) {
+ conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vo_ecwmin") == 0) {
+ conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vo_ecwmax") == 0) {
+ conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vo_timer") == 0) {
+ conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_TIMER_IDX] =
+ atoi(pos) & 0xff;
#endif /* CONFIG_IEEE80211AX */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
@@ -3192,6 +3623,8 @@
}
} else if (os_strcmp(buf, "wps_cred_processing") == 0) {
bss->wps_cred_processing = atoi(pos);
+ } else if (os_strcmp(buf, "wps_cred_add_sae") == 0) {
+ bss->wps_cred_add_sae = atoi(pos);
} else if (os_strcmp(buf, "ap_settings") == 0) {
os_free(bss->ap_settings);
bss->ap_settings =
@@ -3201,6 +3634,56 @@
line, pos);
return 1;
}
+ } else if (os_strcmp(buf, "multi_ap_backhaul_ssid") == 0) {
+ size_t slen;
+ char *str = wpa_config_parse_string(pos, &slen);
+
+ if (!str || slen < 1 || slen > SSID_MAX_LEN) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
+ line, pos);
+ os_free(str);
+ return 1;
+ }
+ os_memcpy(bss->multi_ap_backhaul_ssid.ssid, str, slen);
+ bss->multi_ap_backhaul_ssid.ssid_len = slen;
+ bss->multi_ap_backhaul_ssid.ssid_set = 1;
+ os_free(str);
+ } else if (os_strcmp(buf, "multi_ap_backhaul_wpa_passphrase") == 0) {
+ int len = os_strlen(pos);
+
+ if (len < 8 || len > 63) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid WPA passphrase length %d (expected 8..63)",
+ line, len);
+ return 1;
+ }
+ os_free(bss->multi_ap_backhaul_ssid.wpa_passphrase);
+ bss->multi_ap_backhaul_ssid.wpa_passphrase = os_strdup(pos);
+ if (bss->multi_ap_backhaul_ssid.wpa_passphrase) {
+ hostapd_config_clear_wpa_psk(
+ &bss->multi_ap_backhaul_ssid.wpa_psk);
+ bss->multi_ap_backhaul_ssid.wpa_passphrase_set = 1;
+ }
+ } else if (os_strcmp(buf, "multi_ap_backhaul_wpa_psk") == 0) {
+ hostapd_config_clear_wpa_psk(
+ &bss->multi_ap_backhaul_ssid.wpa_psk);
+ bss->multi_ap_backhaul_ssid.wpa_psk =
+ os_zalloc(sizeof(struct hostapd_wpa_psk));
+ if (!bss->multi_ap_backhaul_ssid.wpa_psk)
+ return 1;
+ if (hexstr2bin(pos, bss->multi_ap_backhaul_ssid.wpa_psk->psk,
+ PMK_LEN) ||
+ pos[PMK_LEN * 2] != '\0') {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
+ line, pos);
+ hostapd_config_clear_wpa_psk(
+ &bss->multi_ap_backhaul_ssid.wpa_psk);
+ return 1;
+ }
+ bss->multi_ap_backhaul_ssid.wpa_psk->group = 1;
+ os_free(bss->multi_ap_backhaul_ssid.wpa_passphrase);
+ bss->multi_ap_backhaul_ssid.wpa_passphrase = NULL;
+ bss->multi_ap_backhaul_ssid.wpa_psk_set = 1;
} else if (os_strcmp(buf, "upnp_iface") == 0) {
os_free(bss->upnp_iface);
bss->upnp_iface = os_strdup(pos);
@@ -3293,6 +3776,8 @@
#ifdef CONFIG_WNM_AP
} else if (os_strcmp(buf, "wnm_sleep_mode") == 0) {
bss->wnm_sleep_mode = atoi(pos);
+ } else if (os_strcmp(buf, "wnm_sleep_mode_no_keys") == 0) {
+ bss->wnm_sleep_mode_no_keys = atoi(pos);
} else if (os_strcmp(buf, "bss_transition") == 0) {
bss->bss_transition = atoi(pos);
#endif /* CONFIG_WNM_AP */
@@ -3333,6 +3818,9 @@
} else if (os_strcmp(buf, "venue_name") == 0) {
if (parse_venue_name(bss, pos, line) < 0)
return 1;
+ } else if (os_strcmp(buf, "venue_url") == 0) {
+ if (parse_venue_url(bss, pos, line) < 0)
+ return 1;
} else if (os_strcmp(buf, "network_auth_type") == 0) {
u8 auth_type;
u16 redirect_url_len;
@@ -3438,6 +3926,16 @@
#ifdef CONFIG_HS20
} else if (os_strcmp(buf, "hs20") == 0) {
bss->hs20 = atoi(pos);
+ } else if (os_strcmp(buf, "hs20_release") == 0) {
+ int val = atoi(pos);
+
+ if (val < 1 || val > (HS20_VERSION >> 4) + 1) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Unsupported hs20_release: %s",
+ line, pos);
+ return 1;
+ }
+ bss->hs20_release = val;
} else if (os_strcmp(buf, "disable_dgaf") == 0) {
bss->disable_dgaf = atoi(pos);
} else if (os_strcmp(buf, "na_mcast_to_ucast") == 0) {
@@ -3500,6 +3998,9 @@
} else if (os_strcmp(buf, "osu_nai") == 0) {
if (hs20_parse_osu_nai(bss, pos, line) < 0)
return 1;
+ } else if (os_strcmp(buf, "osu_nai2") == 0) {
+ if (hs20_parse_osu_nai2(bss, pos, line) < 0)
+ return 1;
} else if (os_strcmp(buf, "osu_method_list") == 0) {
if (hs20_parse_osu_method_list(bss, pos, line) < 0)
return 1;
@@ -3509,11 +4010,25 @@
} else if (os_strcmp(buf, "osu_service_desc") == 0) {
if (hs20_parse_osu_service_desc(bss, pos, line) < 0)
return 1;
+ } else if (os_strcmp(buf, "operator_icon") == 0) {
+ if (hs20_parse_operator_icon(bss, pos, line) < 0)
+ return 1;
} else if (os_strcmp(buf, "subscr_remediation_url") == 0) {
os_free(bss->subscr_remediation_url);
bss->subscr_remediation_url = os_strdup(pos);
} else if (os_strcmp(buf, "subscr_remediation_method") == 0) {
bss->subscr_remediation_method = atoi(pos);
+ } else if (os_strcmp(buf, "hs20_t_c_filename") == 0) {
+ os_free(bss->t_c_filename);
+ bss->t_c_filename = os_strdup(pos);
+ } else if (os_strcmp(buf, "hs20_t_c_timestamp") == 0) {
+ bss->t_c_timestamp = strtol(pos, NULL, 0);
+ } else if (os_strcmp(buf, "hs20_t_c_server_url") == 0) {
+ os_free(bss->t_c_server_url);
+ bss->t_c_server_url = os_strdup(pos);
+ } else if (os_strcmp(buf, "hs20_sim_provisioning_url") == 0) {
+ os_free(bss->hs20_sim_provisioning_url);
+ bss->hs20_sim_provisioning_url = os_strdup(pos);
#endif /* CONFIG_HS20 */
#ifdef CONFIG_MBO
} else if (os_strcmp(buf, "mbo") == 0) {
@@ -3595,10 +4110,15 @@
} else if (os_strcmp(buf, "sae_commit_override") == 0) {
wpabuf_free(bss->sae_commit_override);
bss->sae_commit_override = wpabuf_parse_bin(pos);
- } else if (os_strcmp(buf, "sae_password") == 0) {
- os_free(bss->sae_password);
- bss->sae_password = os_strdup(pos);
#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_SAE
+ } else if (os_strcmp(buf, "sae_password") == 0) {
+ if (parse_sae_password(bss, pos) < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid sae_password",
+ line);
+ return 1;
+ }
+#endif /* CONFIG_SAE */
} else if (os_strcmp(buf, "vendor_elements") == 0) {
if (parse_wpabuf_hex(line, buf, &bss->vendor_elements, pos))
return 1;
@@ -3607,6 +4127,8 @@
return 1;
} else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) {
bss->sae_anti_clogging_threshold = atoi(pos);
+ } else if (os_strcmp(buf, "sae_sync") == 0) {
+ bss->sae_sync = atoi(pos);
} else if (os_strcmp(buf, "sae_groups") == 0) {
if (hostapd_parse_intlist(&bss->sae_groups, pos)) {
wpa_printf(MSG_ERROR,
@@ -3614,6 +4136,8 @@
line, pos);
return 1;
}
+ } else if (os_strcmp(buf, "sae_require_mfp") == 0) {
+ bss->sae_require_mfp = atoi(pos);
} else if (os_strcmp(buf, "local_pwr_constraint") == 0) {
int val = atoi(pos);
if (val < 0 || val > 255) {
@@ -3806,7 +4330,25 @@
line, pos);
return 1;
}
+ } else if (os_strcmp(buf, "coloc_intf_reporting") == 0) {
+ bss->coloc_intf_reporting = atoi(pos);
#endif /* CONFIG_OWE */
+ } else if (os_strcmp(buf, "multi_ap") == 0) {
+ int val = atoi(pos);
+
+ if (val < 0 || val > 3) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid multi_ap '%s'",
+ line, buf);
+ return -1;
+ }
+
+ bss->multi_ap = val;
+ } else if (os_strcmp(buf, "rssi_reject_assoc_rssi") == 0) {
+ conf->rssi_reject_assoc_rssi = atoi(pos);
+ } else if (os_strcmp(buf, "rssi_reject_assoc_timeout") == 0) {
+ conf->rssi_reject_assoc_timeout = atoi(pos);
+ } else if (os_strcmp(buf, "pbss") == 0) {
+ bss->pbss = atoi(pos);
} else {
wpa_printf(MSG_ERROR,
"Line %d: unknown configuration item '%s'",
diff --git a/hostapd/config_file.h b/hostapd/config_file.h
index c98bdb6..9830f5a 100644
--- a/hostapd/config_file.h
+++ b/hostapd/config_file.h
@@ -13,5 +13,10 @@
int hostapd_set_iface(struct hostapd_config *conf,
struct hostapd_bss_config *bss, const char *field,
char *value);
+int hostapd_acl_comp(const void *a, const void *b);
+int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
+ int vlan_id, const u8 *addr);
+void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
+ const u8 *addr);
#endif /* CONFIG_FILE_H */
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index b3ef8d3..e4b16e6 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -1,6 +1,6 @@
/*
* hostapd / UNIX domain socket -based control interface
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -29,6 +29,10 @@
#include "common/version.h"
#include "common/ieee802_11_defs.h"
#include "common/ctrl_iface_common.h"
+#ifdef CONFIG_DPP
+#include "common/dpp.h"
+#endif /* CONFIG_DPP */
+#include "common/wpa_ctrl.h"
#include "crypto/tls.h"
#include "drivers/driver.h"
#include "eapol_auth/eapol_auth_sm.h"
@@ -77,9 +81,9 @@
static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
struct sockaddr_storage *from,
- socklen_t fromlen)
+ socklen_t fromlen, const char *input)
{
- return ctrl_iface_attach(&hapd->ctrl_dst, from, fromlen);
+ return ctrl_iface_attach(&hapd->ctrl_dst, from, fromlen, input);
}
@@ -879,7 +883,7 @@
/* TODO: TSF configurable/learnable */
bss_term_dur[0] = 4; /* Subelement ID */
bss_term_dur[1] = 10; /* Length */
- os_memset(bss_term_dur, 2, 8);
+ os_memset(&bss_term_dur[2], 0, 8);
end = os_strchr(pos, ',');
if (end == NULL) {
wpa_printf(MSG_DEBUG, "Invalid bss_term data");
@@ -988,6 +992,42 @@
return ret;
}
+
+static int hostapd_ctrl_iface_coloc_intf_req(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
+ const char *pos;
+ unsigned int auto_report, timeout;
+
+ if (hwaddr_aton(cmd, addr)) {
+ wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
+ return -1;
+ }
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for Collocated Interference Request",
+ MAC2STR(addr));
+ return -1;
+ }
+
+ pos = cmd + 17;
+ if (*pos != ' ')
+ return -1;
+ pos++;
+ auto_report = atoi(pos);
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ return -1;
+ pos++;
+ timeout = atoi(pos);
+
+ return wnm_send_coloc_intf_req(hapd, sta, auto_report, timeout);
+}
+
#endif /* CONFIG_WNM_AP */
@@ -1027,6 +1067,14 @@
return pos - buf;
pos += ret;
}
+#ifdef CONFIG_SHA384
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+ ret = os_snprintf(pos, end - pos, "FT-EAP-SHA384 ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SHA384 */
#ifdef CONFIG_SAE
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
ret = os_snprintf(pos, end - pos, "FT-SAE ");
@@ -1246,6 +1294,42 @@
}
+static void hostapd_disassoc_accept_mac(struct hostapd_data *hapd)
+{
+ struct sta_info *sta;
+ struct vlan_description vlan_id;
+
+ if (hapd->conf->macaddr_acl != DENY_UNLESS_ACCEPTED)
+ return;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!hostapd_maclist_found(hapd->conf->accept_mac,
+ hapd->conf->num_accept_mac,
+ sta->addr, &vlan_id) ||
+ (vlan_id.notempty &&
+ vlan_compare(&vlan_id, sta->vlan_desc)))
+ ap_sta_disconnect(hapd, sta, sta->addr,
+ WLAN_REASON_UNSPECIFIED);
+ }
+}
+
+
+static void hostapd_disassoc_deny_mac(struct hostapd_data *hapd)
+{
+ struct sta_info *sta;
+ struct vlan_description vlan_id;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (hostapd_maclist_found(hapd->conf->deny_mac,
+ hapd->conf->num_deny_mac, sta->addr,
+ &vlan_id) &&
+ (!vlan_id.notempty ||
+ !vlan_compare(&vlan_id, sta->vlan_desc)))
+ ap_sta_disconnect(hapd, sta, sta->addr,
+ WLAN_REASON_UNSPECIFIED);
+ }
+}
+
static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
{
char *value;
@@ -1301,6 +1385,8 @@
} else if (os_strcasecmp(cmd,
"dpp_ignore_netaccesskey_mismatch") == 0) {
hapd->dpp_ignore_netaccesskey_mismatch = atoi(value);
+ } else if (os_strcasecmp(cmd, "dpp_test") == 0) {
+ dpp_test = atoi(value);
#endif /* CONFIG_DPP */
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_MBO
@@ -1328,38 +1414,20 @@
hapd->dpp_configurator_params = os_strdup(value);
#endif /* CONFIG_DPP */
} else {
- struct sta_info *sta;
- struct vlan_description vlan_id;
-
ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
if (ret)
return ret;
if (os_strcasecmp(cmd, "deny_mac_file") == 0) {
- for (sta = hapd->sta_list; sta; sta = sta->next) {
- if (hostapd_maclist_found(
- hapd->conf->deny_mac,
- hapd->conf->num_deny_mac, sta->addr,
- &vlan_id) &&
- (!vlan_id.notempty ||
- !vlan_compare(&vlan_id, sta->vlan_desc)))
- ap_sta_disconnect(
- hapd, sta, sta->addr,
- WLAN_REASON_UNSPECIFIED);
- }
- } else if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED &&
- os_strcasecmp(cmd, "accept_mac_file") == 0) {
- for (sta = hapd->sta_list; sta; sta = sta->next) {
- if (!hostapd_maclist_found(
- hapd->conf->accept_mac,
- hapd->conf->num_accept_mac,
- sta->addr, &vlan_id) ||
- (vlan_id.notempty &&
- vlan_compare(&vlan_id, sta->vlan_desc)))
- ap_sta_disconnect(
- hapd, sta, sta->addr,
- WLAN_REASON_UNSPECIFIED);
- }
+ hostapd_disassoc_deny_mac(hapd);
+ } else if (os_strcasecmp(cmd, "accept_mac_file") == 0) {
+ hostapd_disassoc_accept_mac(hapd);
+ } else if (os_strncmp(cmd, "wme_ac_", 7) == 0 ||
+ os_strncmp(cmd, "wmm_ac_", 7) == 0) {
+ hapd->parameter_set_count++;
+ if (ieee802_11_update_beacons(hapd->iface))
+ wpa_printf(MSG_DEBUG,
+ "Failed to update beacons with WMM parameters");
}
}
@@ -1420,6 +1488,63 @@
}
+static int
+hostapd_ctrl_iface_kick_mismatch_psk_sta_iter(struct hostapd_data *hapd,
+ struct sta_info *sta, void *ctx)
+{
+ struct hostapd_wpa_psk *psk;
+ const u8 *pmk;
+ int pmk_len;
+ int pmk_match;
+ int sta_match;
+ int bss_match;
+ int reason;
+
+ pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
+
+ for (psk = hapd->conf->ssid.wpa_psk; pmk && psk; psk = psk->next) {
+ pmk_match = PMK_LEN == pmk_len &&
+ os_memcmp(psk->psk, pmk, pmk_len) == 0;
+ sta_match = psk->group == 0 &&
+ os_memcmp(sta->addr, psk->addr, ETH_ALEN) == 0;
+ bss_match = psk->group == 1;
+
+ if (pmk_match && (sta_match || bss_match))
+ return 0;
+ }
+
+ wpa_printf(MSG_INFO, "STA " MACSTR
+ " PSK/passphrase no longer valid - disconnect",
+ MAC2STR(sta->addr));
+ reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
+ hostapd_drv_sta_deauth(hapd, sta->addr, reason);
+ ap_sta_deauthenticate(hapd, sta, reason);
+
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_reload_wpa_psk(struct hostapd_data *hapd)
+{
+ struct hostapd_bss_config *conf = hapd->conf;
+ int err;
+
+ hostapd_config_clear_wpa_psk(&conf->ssid.wpa_psk);
+
+ err = hostapd_setup_wpa_psk(conf);
+ if (err < 0) {
+ wpa_printf(MSG_ERROR, "Reloading WPA-PSK passwords failed: %d",
+ err);
+ return -1;
+ }
+
+ ap_for_each_sta(hapd, hostapd_ctrl_iface_kick_mismatch_psk_sta_iter,
+ NULL);
+
+ return 0;
+}
+
+
#ifdef CONFIG_TESTING_OPTIONS
static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd)
@@ -2066,7 +2191,7 @@
if (!pos)
return -1;
pos++;
- if (hexstr2bin(pos, seq, sizeof(6)) < 0)
+ if (hexstr2bin(pos, seq, sizeof(seq)) < 0)
return -1;
pos += 2 * 6;
if (*pos != ' ')
@@ -2204,6 +2329,11 @@
return ret;
for (i = 0; i < iface->num_bss; i++) {
+
+ /* Save CHAN_SWITCH VHT config */
+ hostapd_chan_switch_vht_config(
+ iface->bss[i], settings.freq_params.vht_enabled);
+
ret = hostapd_switch_channel(iface->bss[i], &settings);
if (ret) {
/* FIX: What do we do if CSA fails in the middle of
@@ -2679,6 +2809,108 @@
}
+static int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
+ const char *txtaddr)
+{
+ u8 addr[ETH_ALEN];
+ struct vlan_description vlan_id;
+
+ if (!(*num))
+ return 0;
+
+ if (hwaddr_aton(txtaddr, addr))
+ return -1;
+
+ if (hostapd_maclist_found(*acl, *num, addr, &vlan_id))
+ hostapd_remove_acl_mac(acl, num, addr);
+
+ return 0;
+}
+
+
+static void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl,
+ int *num)
+{
+ while (*num)
+ hostapd_remove_acl_mac(acl, num, (*acl)[0].addr);
+}
+
+
+static int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num,
+ char *buf, size_t buflen)
+{
+ int i = 0, len = 0, ret = 0;
+
+ if (!acl)
+ return 0;
+
+ while (i < num) {
+ ret = os_snprintf(buf + len, buflen - len,
+ MACSTR " VLAN_ID=%d\n",
+ MAC2STR(acl[i].addr),
+ acl[i].vlan_id.untagged);
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ i++;
+ len += ret;
+ }
+ return len;
+}
+
+
+static int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ struct vlan_description vlan_id;
+ int ret = 0, vlanid = 0;
+ const char *pos;
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ pos = os_strstr(cmd, "VLAN_ID=");
+ if (pos)
+ vlanid = atoi(pos + 8);
+
+ if (!hostapd_maclist_found(*acl, *num, addr, &vlan_id)) {
+ ret = hostapd_add_acl_maclist(acl, num, vlanid, addr);
+ if (ret != -1 && *acl)
+ qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
+ }
+
+ return ret < 0 ? -1 : 0;
+}
+
+
+static int hostapd_ctrl_iface_get_capability(struct hostapd_data *hapd,
+ const char *field, char *buf,
+ size_t buflen)
+{
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s'", field);
+
+#ifdef CONFIG_DPP
+ if (os_strcmp(field, "dpp") == 0) {
+ int res;
+
+#ifdef CONFIG_DPP2
+ res = os_snprintf(buf, buflen, "DPP=2");
+#else /* CONFIG_DPP2 */
+ res = os_snprintf(buf, buflen, "DPP=1");
+#endif /* CONFIG_DPP2 */
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+#endif /* CONFIG_DPP */
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
+ field);
+
+ return -1;
+}
+
+
static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
char *buf, char *reply,
int reply_size,
@@ -2696,6 +2928,8 @@
} else if (os_strncmp(buf, "RELOG", 5) == 0) {
if (wpa_debug_reopen_file() < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "NOTE ", 5) == 0) {
+ wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
} else if (os_strcmp(buf, "STATUS") == 0) {
reply_len = hostapd_ctrl_iface_status(hapd, reply,
reply_size);
@@ -2743,7 +2977,10 @@
reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
reply_size);
} else if (os_strcmp(buf, "ATTACH") == 0) {
- if (hostapd_ctrl_iface_attach(hapd, from, fromlen))
+ if (hostapd_ctrl_iface_attach(hapd, from, fromlen, NULL))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "ATTACH ", 7) == 0) {
+ if (hostapd_ctrl_iface_attach(hapd, from, fromlen, buf + 7))
reply_len = -1;
} else if (os_strcmp(buf, "DETACH") == 0) {
if (hostapd_ctrl_iface_detach(hapd, from, fromlen))
@@ -2845,6 +3082,9 @@
} else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) {
if (hostapd_ctrl_iface_bss_tm_req(hapd, buf + 11))
reply_len = -1;
+ } else if (os_strncmp(buf, "COLOC_INTF_REQ ", 15) == 0) {
+ if (hostapd_ctrl_iface_coloc_intf_req(hapd, buf + 15))
+ reply_len = -1;
#endif /* CONFIG_WNM_AP */
} else if (os_strcmp(buf, "GET_CONFIG") == 0) {
reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
@@ -2858,6 +3098,9 @@
} else if (os_strncmp(buf, "ENABLE", 6) == 0) {
if (hostapd_ctrl_iface_enable(hapd->iface))
reply_len = -1;
+ } else if (os_strcmp(buf, "RELOAD_WPA_PSK") == 0) {
+ if (hostapd_ctrl_iface_reload_wpa_psk(hapd))
+ reply_len = -1;
} else if (os_strncmp(buf, "RELOAD", 6) == 0) {
if (hostapd_ctrl_iface_reload(hapd->iface))
reply_len = -1;
@@ -2919,6 +3162,9 @@
} else if (os_strncmp(buf, "RESEND_GROUP_M1 ", 16) == 0) {
if (hostapd_ctrl_resend_group_m1(hapd, buf + 16) < 0)
reply_len = -1;
+ } else if (os_strcmp(buf, "REKEY_GTK") == 0) {
+ if (wpa_auth_rekey_gtk(hapd->wpa_auth) < 0)
+ reply_len = -1;
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
@@ -2973,6 +3219,46 @@
reply_size);
} else if (os_strcmp(buf, "TERMINATE") == 0) {
eloop_terminate();
+ } else if (os_strncmp(buf, "ACCEPT_ACL ", 11) == 0) {
+ if (os_strncmp(buf + 11, "ADD_MAC ", 8) == 0) {
+ if (!hostapd_ctrl_iface_acl_add_mac(
+ &hapd->conf->accept_mac,
+ &hapd->conf->num_accept_mac, buf + 19))
+ hostapd_disassoc_accept_mac(hapd);
+ else
+ reply_len = -1;
+ } else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) {
+ hostapd_ctrl_iface_acl_del_mac(
+ &hapd->conf->accept_mac,
+ &hapd->conf->num_accept_mac, buf + 19);
+ } else if (os_strcmp(buf + 11, "SHOW") == 0) {
+ reply_len = hostapd_ctrl_iface_acl_show_mac(
+ hapd->conf->accept_mac,
+ hapd->conf->num_accept_mac, reply, reply_size);
+ } else if (os_strcmp(buf + 11, "CLEAR") == 0) {
+ hostapd_ctrl_iface_acl_clear_list(
+ &hapd->conf->accept_mac,
+ &hapd->conf->num_accept_mac);
+ }
+ } else if (os_strncmp(buf, "DENY_ACL ", 9) == 0) {
+ if (os_strncmp(buf + 9, "ADD_MAC ", 8) == 0) {
+ if (!hostapd_ctrl_iface_acl_add_mac(
+ &hapd->conf->deny_mac,
+ &hapd->conf->num_deny_mac, buf + 17))
+ hostapd_disassoc_deny_mac(hapd);
+ } else if (os_strncmp(buf + 9, "DEL_MAC ", 8) == 0) {
+ hostapd_ctrl_iface_acl_del_mac(
+ &hapd->conf->deny_mac,
+ &hapd->conf->num_deny_mac, buf + 17);
+ } else if (os_strcmp(buf + 9, "SHOW") == 0) {
+ reply_len = hostapd_ctrl_iface_acl_show_mac(
+ hapd->conf->deny_mac,
+ hapd->conf->num_deny_mac, reply, reply_size);
+ } else if (os_strcmp(buf + 9, "CLEAR") == 0) {
+ hostapd_ctrl_iface_acl_clear_list(
+ &hapd->conf->deny_mac,
+ &hapd->conf->num_deny_mac);
+ }
#ifdef CONFIG_DPP
} else if (os_strncmp(buf, "DPP_QR_CODE ", 12) == 0) {
res = hostapd_dpp_qr_code(hapd, buf + 12);
@@ -2984,7 +3270,7 @@
reply_len = -1;
}
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) {
- res = hostapd_dpp_bootstrap_gen(hapd, buf + 18);
+ res = dpp_bootstrap_gen(hapd->iface->interfaces->dpp, buf + 18);
if (res < 0) {
reply_len = -1;
} else {
@@ -2993,12 +3279,14 @@
reply_len = -1;
}
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_REMOVE ", 21) == 0) {
- if (hostapd_dpp_bootstrap_remove(hapd, buf + 21) < 0)
+ if (dpp_bootstrap_remove(hapd->iface->interfaces->dpp,
+ buf + 21) < 0)
reply_len = -1;
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_GET_URI ", 22) == 0) {
const char *uri;
- uri = hostapd_dpp_bootstrap_get_uri(hapd, atoi(buf + 22));
+ uri = dpp_bootstrap_get_uri(hapd->iface->interfaces->dpp,
+ atoi(buf + 22));
if (!uri) {
reply_len = -1;
} else {
@@ -3007,13 +3295,21 @@
reply_len = -1;
}
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_INFO ", 19) == 0) {
- reply_len = hostapd_dpp_bootstrap_info(hapd, atoi(buf + 19),
- reply, reply_size);
+ reply_len = dpp_bootstrap_info(hapd->iface->interfaces->dpp,
+ atoi(buf + 19),
+ reply, reply_size);
} else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
if (hostapd_dpp_auth_init(hapd, buf + 13) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "DPP_LISTEN ", 11) == 0) {
+ if (hostapd_dpp_listen(hapd, buf + 11) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "DPP_STOP_LISTEN") == 0) {
+ hostapd_dpp_stop(hapd);
+ hostapd_dpp_listen_stop(hapd);
} else if (os_strncmp(buf, "DPP_CONFIGURATOR_ADD", 20) == 0) {
- res = hostapd_dpp_configurator_add(hapd, buf + 20);
+ res = dpp_configurator_add(hapd->iface->interfaces->dpp,
+ buf + 20);
if (res < 0) {
reply_len = -1;
} else {
@@ -3022,8 +3318,17 @@
reply_len = -1;
}
} else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) {
- if (hostapd_dpp_configurator_remove(hapd, buf + 24) < 0)
+ if (dpp_configurator_remove(hapd->iface->interfaces->dpp,
+ buf + 24) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SIGN ", 22) == 0) {
+ if (hostapd_dpp_configurator_sign(hapd, buf + 21) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DPP_CONFIGURATOR_GET_KEY ", 25) == 0) {
+ reply_len = dpp_configurator_get_key_id(
+ hapd->iface->interfaces->dpp,
+ atoi(buf + 25),
+ reply, reply_size);
} else if (os_strncmp(buf, "DPP_PKEX_ADD ", 13) == 0) {
res = hostapd_dpp_pkex_add(hapd, buf + 12);
if (res < 0) {
@@ -3037,6 +3342,14 @@
if (hostapd_dpp_pkex_remove(hapd, buf + 16) < 0)
reply_len = -1;
#endif /* CONFIG_DPP */
+#ifdef RADIUS_SERVER
+ } else if (os_strncmp(buf, "DAC_REQUEST ", 12) == 0) {
+ if (radius_server_dac_request(hapd->radius_srv, buf + 12) < 0)
+ reply_len = -1;
+#endif /* RADIUS_SERVER */
+ } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
+ reply_len = hostapd_ctrl_iface_get_capability(
+ hapd, buf + 15, reply, reply_size);
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
@@ -3290,18 +3603,18 @@
}
if (hapd->conf->ctrl_interface_gid_set &&
- chown(hapd->conf->ctrl_interface, -1,
- hapd->conf->ctrl_interface_gid) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
+ lchown(hapd->conf->ctrl_interface, -1,
+ hapd->conf->ctrl_interface_gid) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
strerror(errno));
return -1;
}
if (!hapd->conf->ctrl_interface_gid_set &&
hapd->iface->interfaces->ctrl_iface_group &&
- chown(hapd->conf->ctrl_interface, -1,
- hapd->iface->interfaces->ctrl_iface_group) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
+ lchown(hapd->conf->ctrl_interface, -1,
+ hapd->iface->interfaces->ctrl_iface_group) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
strerror(errno));
return -1;
}
@@ -3374,16 +3687,16 @@
}
if (hapd->conf->ctrl_interface_gid_set &&
- chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s",
+ lchown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface/ifname]: %s",
strerror(errno));
goto fail;
}
if (!hapd->conf->ctrl_interface_gid_set &&
hapd->iface->interfaces->ctrl_iface_group &&
- chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s",
+ lchown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface/ifname]: %s",
strerror(errno));
goto fail;
}
@@ -3487,9 +3800,10 @@
static int hostapd_global_ctrl_iface_attach(struct hapd_interfaces *interfaces,
struct sockaddr_storage *from,
- socklen_t fromlen)
+ socklen_t fromlen, char *input)
{
- return ctrl_iface_attach(&interfaces->global_ctrl_dst, from, fromlen);
+ return ctrl_iface_attach(&interfaces->global_ctrl_dst, from, fromlen,
+ input);
}
@@ -3508,6 +3822,16 @@
wps_testing_dummy_cred = 0;
wps_corrupt_pkhash = 0;
#endif /* CONFIG_WPS_TESTING */
+
+#ifdef CONFIG_TESTING_OPTIONS
+#ifdef CONFIG_DPP
+ dpp_test = DPP_TEST_DISABLED;
+#endif /* CONFIG_DPP */
+#endif /* CONFIG_TESTING_OPTIONS */
+
+#ifdef CONFIG_DPP
+ dpp_global_clear(interfaces->dpp);
+#endif /* CONFIG_DPP */
}
@@ -3859,7 +4183,11 @@
reply_len = -1;
} else if (os_strcmp(buf, "ATTACH") == 0) {
if (hostapd_global_ctrl_iface_attach(interfaces, &from,
- fromlen))
+ fromlen, NULL))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "ATTACH ", 7) == 0) {
+ if (hostapd_global_ctrl_iface_attach(interfaces, &from,
+ fromlen, buf + 7))
reply_len = -1;
} else if (os_strcmp(buf, "DETACH") == 0) {
if (hostapd_global_ctrl_iface_detach(interfaces, &from,
@@ -4042,9 +4370,9 @@
goto fail;
}
} else if (interface->ctrl_iface_group &&
- chown(interface->global_iface_path, -1,
- interface->ctrl_iface_group) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
+ lchown(interface->global_iface_path, -1,
+ interface->ctrl_iface_group) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
strerror(errno));
goto fail;
}
@@ -4101,8 +4429,8 @@
}
if (interface->ctrl_iface_group &&
- chown(fname, -1, interface->ctrl_iface_group) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
+ lchown(fname, -1, interface->ctrl_iface_group) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
strerror(errno));
goto fail;
}
@@ -4175,6 +4503,18 @@
}
+static int hostapd_ctrl_check_event_enabled(struct wpa_ctrl_dst *dst,
+ const char *buf)
+{
+ /* Enable Probe Request events based on explicit request.
+ * Other events are enabled by default.
+ */
+ if (str_starts(buf, RX_PROBE_REQUEST))
+ return !!(dst->events & WPA_EVENT_RX_PROBE_REQUEST);
+ return 1;
+}
+
+
static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
enum wpa_msg_type type,
const char *buf, size_t len)
@@ -4209,7 +4549,8 @@
idx = 0;
dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
- if (level >= dst->debug_level) {
+ if ((level >= dst->debug_level) &&
+ hostapd_ctrl_check_event_enabled(dst, buf)) {
sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor send",
&dst->addr, dst->addrlen);
msg.msg_name = &dst->addr;
diff --git a/hostapd/defconfig b/hostapd/defconfig
index c67c662..ea5e2c9 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -31,7 +31,7 @@
#CONFIG_LIBNL20=y
# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
-#CONFIG_LIBNL32=y
+CONFIG_LIBNL32=y
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
@@ -53,6 +53,9 @@
# IEEE 802.11w (management frame protection)
CONFIG_IEEE80211W=y
+# Support Operating Channel Validation
+#CONFIG_OCV=y
+
# Integrated EAP server
CONFIG_EAP=y
@@ -249,6 +252,11 @@
# requirements described above.
#CONFIG_NO_RANDOM_POOL=y
+# Should we attempt to use the getrandom(2) call that provides more reliable
+# yet secure randomness source than /dev/random on Linux 3.17 and newer.
+# Requires glibc 2.25 to build, falls back to /dev/random if unavailable.
+#CONFIG_GETRANDOM=y
+
# Should we use poll instead of select? Select is used by default.
#CONFIG_ELOOP_POLL=y
@@ -356,8 +364,6 @@
#CONFIG_TAXONOMY=y
# Fast Initial Link Setup (FILS) (IEEE 802.11ai)
-# Note: This is an experimental and not yet complete implementation. This
-# should not be enabled for production use.
#CONFIG_FILS=y
# FILS shared key authentication with PFS
#CONFIG_FILS_SK_PFS=y
diff --git a/hostapd/hidl/1.0/hidl.cpp b/hostapd/hidl/1.1/hidl.cpp
similarity index 93%
rename from hostapd/hidl/1.0/hidl.cpp
rename to hostapd/hidl/1.1/hidl.cpp
index a0dc50e..2051e7b 100644
--- a/hostapd/hidl/1.0/hidl.cpp
+++ b/hostapd/hidl/1.1/hidl.cpp
@@ -22,8 +22,8 @@
using android::hardware::configureRpcThreadpool;
using android::hardware::IPCThreadState;
-using android::hardware::wifi::hostapd::V1_0::IHostapd;
-using android::hardware::wifi::hostapd::V1_0::implementation::Hostapd;
+using android::hardware::wifi::hostapd::V1_1::IHostapd;
+using android::hardware::wifi::hostapd::V1_1::implementation::Hostapd;
// This file is a bridge between the hostapd code written in 'C' and the HIDL
// interface in C++. So, using "C" style static globals here!
diff --git a/hostapd/hidl/1.0/hidl.h b/hostapd/hidl/1.1/hidl.h
similarity index 100%
rename from hostapd/hidl/1.0/hidl.h
rename to hostapd/hidl/1.1/hidl.h
diff --git a/hostapd/hidl/1.0/hidl_return_util.h b/hostapd/hidl/1.1/hidl_return_util.h
similarity index 96%
rename from hostapd/hidl/1.0/hidl_return_util.h
rename to hostapd/hidl/1.1/hidl_return_util.h
index 1625dc2..d914ee2 100644
--- a/hostapd/hidl/1.0/hidl_return_util.h
+++ b/hostapd/hidl/1.1/hidl_return_util.h
@@ -16,7 +16,7 @@
namespace hardware {
namespace wifi {
namespace hostapd {
-namespace V1_0 {
+namespace V1_1 {
namespace implementation {
namespace hidl_return_util {
@@ -36,7 +36,7 @@
} // namespace hidl_return_util
} // namespace implementation
-} // namespace V1_0
+} // namespace V1_1
} // namespace hostapd
} // namespace wifi
} // namespace hardware
diff --git a/hostapd/hidl/1.0/hostapd.cpp b/hostapd/hidl/1.1/hostapd.cpp
similarity index 67%
rename from hostapd/hidl/1.0/hostapd.cpp
rename to hostapd/hidl/1.1/hostapd.cpp
index 3cd78b3..0298537 100644
--- a/hostapd/hidl/1.0/hostapd.cpp
+++ b/hostapd/hidl/1.1/hostapd.cpp
@@ -33,7 +33,7 @@
using android::base::RemoveFileIfExists;
using android::base::StringPrintf;
using android::base::WriteStringToFile;
-using android::hardware::wifi::hostapd::V1_0::IHostapd;
+using android::hardware::wifi::hostapd::V1_1::IHostapd;
std::string WriteHostapdConfig(
const std::string& interface_name, const std::string& config)
@@ -126,26 +126,38 @@
}
std::string channel_config_as_string;
- if (iface_params.channelParams.enableAcs) {
+ if (iface_params.V1_0.channelParams.enableAcs) {
+ std::string chanlist_as_string;
+ for (const auto &range :
+ iface_params.channelParams.acsChannelRanges) {
+ if (range.start != range.end) {
+ chanlist_as_string +=
+ StringPrintf("%d-%d ", range.start, range.end);
+ } else {
+ chanlist_as_string += StringPrintf("%d ", range.start);
+ }
+ }
channel_config_as_string = StringPrintf(
"channel=0\n"
- "acs_exclude_dfs=%d",
- iface_params.channelParams.acsShouldExcludeDfs);
+ "acs_exclude_dfs=%d\n"
+ "chanlist=%s",
+ iface_params.V1_0.channelParams.acsShouldExcludeDfs,
+ chanlist_as_string.c_str());
} else {
channel_config_as_string = StringPrintf(
- "channel=%d", iface_params.channelParams.channel);
+ "channel=%d", iface_params.V1_0.channelParams.channel);
}
// Hw Mode String
std::string hw_mode_as_string;
std::string ht_cap_vht_oper_chwidth_as_string;
- switch (iface_params.channelParams.band) {
+ switch (iface_params.V1_0.channelParams.band) {
case IHostapd::Band::BAND_2_4_GHZ:
hw_mode_as_string = "hw_mode=g";
break;
case IHostapd::Band::BAND_5_GHZ:
hw_mode_as_string = "hw_mode=a";
- if (iface_params.channelParams.enableAcs) {
+ if (iface_params.V1_0.channelParams.enableAcs) {
ht_cap_vht_oper_chwidth_as_string =
"ht_capab=[HT40+]\n"
"vht_oper_chwidth=1";
@@ -153,7 +165,7 @@
break;
case IHostapd::Band::BAND_ANY:
hw_mode_as_string = "hw_mode=any";
- if (iface_params.channelParams.enableAcs) {
+ if (iface_params.V1_0.channelParams.enableAcs) {
ht_cap_vht_oper_chwidth_as_string =
"ht_capab=[HT40+]\n"
"vht_oper_chwidth=1";
@@ -180,32 +192,61 @@
"ignore_broadcast_ssid=%d\n"
"wowlan_triggers=any\n"
"%s\n",
- iface_params.ifaceName.c_str(), ssid_as_string.c_str(),
+ iface_params.V1_0.ifaceName.c_str(), ssid_as_string.c_str(),
channel_config_as_string.c_str(),
- iface_params.hwModeParams.enable80211N ? 1 : 0,
- iface_params.hwModeParams.enable80211AC ? 1 : 0,
+ iface_params.V1_0.hwModeParams.enable80211N ? 1 : 0,
+ iface_params.V1_0.hwModeParams.enable80211AC ? 1 : 0,
hw_mode_as_string.c_str(), ht_cap_vht_oper_chwidth_as_string.c_str(),
nw_params.isHidden ? 1 : 0, encryption_config_as_string.c_str());
}
+
+// hostapd core functions accept "C" style function pointers, so use global
+// functions to pass to the hostapd core function and store the corresponding
+// std::function methods to be invoked.
+//
+// NOTE: Using the pattern from the vendor HAL (wifi_legacy_hal.cpp).
+//
+// Callback to be invoked once setup is complete
+std::function<void(struct hostapd_data*)> on_setup_complete_internal_callback;
+void onAsyncSetupCompleteCb(void* ctx)
+{
+ struct hostapd_data* iface_hapd = (struct hostapd_data*)ctx;
+ if (on_setup_complete_internal_callback) {
+ on_setup_complete_internal_callback(iface_hapd);
+ // Invalidate this callback since we don't want this firing
+ // again.
+ on_setup_complete_internal_callback = nullptr;
+ }
+}
} // namespace
namespace android {
namespace hardware {
namespace wifi {
namespace hostapd {
-namespace V1_0 {
+namespace V1_1 {
namespace implementation {
using hidl_return_util::call;
+using namespace android::hardware::wifi::hostapd::V1_0;
Hostapd::Hostapd(struct hapd_interfaces* interfaces) : interfaces_(interfaces)
{}
Return<void> Hostapd::addAccessPoint(
+ const V1_0::IHostapd::IfaceParams& iface_params,
+ const NetworkParams& nw_params, addAccessPoint_cb _hidl_cb)
+{
+ return call(
+ this, &Hostapd::addAccessPointInternal, _hidl_cb, iface_params,
+ nw_params);
+}
+
+Return<void> Hostapd::addAccessPoint_1_1(
const IfaceParams& iface_params, const NetworkParams& nw_params,
addAccessPoint_cb _hidl_cb)
{
return call(
- this, &Hostapd::addAccessPointInternal, _hidl_cb, iface_params,
+ this, &Hostapd::addAccessPointInternal_1_1, _hidl_cb, iface_params,
nw_params);
}
@@ -216,19 +257,34 @@
this, &Hostapd::removeAccessPointInternal, _hidl_cb, iface_name);
}
-Return<void> Hostapd::terminate() {
+Return<void> Hostapd::terminate()
+{
wpa_printf(MSG_INFO, "Terminating...");
eloop_terminate();
return Void();
}
+Return<void> Hostapd::registerCallback(
+ const sp<IHostapdCallback>& callback, registerCallback_cb _hidl_cb)
+{
+ return call(
+ this, &Hostapd::registerCallbackInternal, _hidl_cb, callback);
+}
+
HostapdStatus Hostapd::addAccessPointInternal(
+ const V1_0::IHostapd::IfaceParams& iface_params,
+ const NetworkParams& nw_params)
+{
+ return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
+}
+
+HostapdStatus Hostapd::addAccessPointInternal_1_1(
const IfaceParams& iface_params, const NetworkParams& nw_params)
{
- if (hostapd_get_iface(interfaces_, iface_params.ifaceName.c_str())) {
+ if (hostapd_get_iface(interfaces_, iface_params.V1_0.ifaceName.c_str())) {
wpa_printf(
MSG_ERROR, "Interface %s already present",
- iface_params.ifaceName.c_str());
+ iface_params.V1_0.ifaceName.c_str());
return {HostapdStatusCode::FAILURE_IFACE_EXISTS, ""};
}
const auto conf_params = CreateHostapdConfig(iface_params, nw_params);
@@ -237,13 +293,13 @@
return {HostapdStatusCode::FAILURE_ARGS_INVALID, ""};
}
const auto conf_file_path =
- WriteHostapdConfig(iface_params.ifaceName, conf_params);
+ WriteHostapdConfig(iface_params.V1_0.ifaceName, conf_params);
if (conf_file_path.empty()) {
wpa_printf(MSG_ERROR, "Failed to write config file");
return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
}
std::string add_iface_param_str = StringPrintf(
- "%s config=%s", iface_params.ifaceName.c_str(),
+ "%s config=%s", iface_params.V1_0.ifaceName.c_str(),
conf_file_path.c_str());
std::vector<char> add_iface_param_vec(
add_iface_param_str.begin(), add_iface_param_str.end() + 1);
@@ -254,12 +310,29 @@
return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
}
struct hostapd_data* iface_hapd =
- hostapd_get_iface(interfaces_, iface_params.ifaceName.c_str());
+ hostapd_get_iface(interfaces_, iface_params.V1_0.ifaceName.c_str());
WPA_ASSERT(iface_hapd != nullptr && iface_hapd->iface != nullptr);
+ // Register the setup complete callbacks
+ on_setup_complete_internal_callback =
+ [this](struct hostapd_data* iface_hapd) {
+ wpa_printf(
+ MSG_DEBUG, "AP interface setup completed - state %s",
+ hostapd_state_text(iface_hapd->iface->state));
+ if (iface_hapd->iface->state == HAPD_IFACE_DISABLED) {
+ // Invoke the failure callback on all registered
+ // clients.
+ for (const auto& callback : callbacks_) {
+ callback->onFailure(
+ iface_hapd->conf->iface);
+ }
+ }
+ };
+ iface_hapd->setup_complete_cb = onAsyncSetupCompleteCb;
+ iface_hapd->setup_complete_cb_ctx = iface_hapd;
if (hostapd_enable_iface(iface_hapd->iface) < 0) {
wpa_printf(
MSG_ERROR, "Enabling interface %s failed",
- iface_params.ifaceName.c_str());
+ iface_params.V1_0.ifaceName.c_str());
return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
}
return {HostapdStatusCode::SUCCESS, ""};
@@ -278,8 +351,16 @@
}
return {HostapdStatusCode::SUCCESS, ""};
}
+
+HostapdStatus Hostapd::registerCallbackInternal(
+ const sp<IHostapdCallback>& callback)
+{
+ callbacks_.push_back(callback);
+ return {HostapdStatusCode::SUCCESS, ""};
+}
+
} // namespace implementation
-} // namespace V1_0
+} // namespace V1_1
} // namespace hostapd
} // namespace wifi
} // namespace hardware
diff --git a/hostapd/hidl/1.0/hostapd.h b/hostapd/hidl/1.1/hostapd.h
similarity index 64%
rename from hostapd/hidl/1.0/hostapd.h
rename to hostapd/hidl/1.1/hostapd.h
index 7985fd9..e2b4ba8 100644
--- a/hostapd/hidl/1.0/hostapd.h
+++ b/hostapd/hidl/1.1/hostapd.h
@@ -14,7 +14,8 @@
#include <android-base/macros.h>
-#include <android/hardware/wifi/hostapd/1.0/IHostapd.h>
+#include <android/hardware/wifi/hostapd/1.1/IHostapd.h>
+#include <android/hardware/wifi/hostapd/1.1/IHostapdCallback.h>
extern "C"
{
@@ -28,15 +29,16 @@
namespace hardware {
namespace wifi {
namespace hostapd {
-namespace V1_0 {
+namespace V1_1 {
namespace implementation {
+using namespace android::hardware::wifi::hostapd::V1_0;
/**
* Implementation of the hostapd hidl object. This hidl
* object is used core for global control operations on
* hostapd.
*/
-class Hostapd : public V1_0::IHostapd
+class Hostapd : public V1_1::IHostapd
{
public:
Hostapd(hapd_interfaces* interfaces);
@@ -44,26 +46,39 @@
// Hidl methods exposed.
Return<void> addAccessPoint(
+ const V1_0::IHostapd::IfaceParams& iface_params,
+ const NetworkParams& nw_params, addAccessPoint_cb _hidl_cb) override;
+ Return<void> addAccessPoint_1_1(
const IfaceParams& iface_params, const NetworkParams& nw_params,
addAccessPoint_cb _hidl_cb) override;
Return<void> removeAccessPoint(
const hidl_string& iface_name,
removeAccessPoint_cb _hidl_cb) override;
Return<void> terminate() override;
+ Return<void> registerCallback(
+ const sp<IHostapdCallback>& callback,
+ registerCallback_cb _hidl_cb) override;
private:
// Corresponding worker functions for the HIDL methods.
HostapdStatus addAccessPointInternal(
- const IfaceParams& iface_params, const NetworkParams& nw_params);
+ const V1_0::IHostapd::IfaceParams& iface_params,
+ const NetworkParams& nw_params);
+ HostapdStatus addAccessPointInternal_1_1(
+ const IfaceParams& IfaceParams, const NetworkParams& nw_params);
HostapdStatus removeAccessPointInternal(const std::string& iface_name);
+ HostapdStatus registerCallbackInternal(
+ const sp<IHostapdCallback>& callback);
// Raw pointer to the global structure maintained by the core.
struct hapd_interfaces* interfaces_;
+ // Callbacks registered.
+ std::vector<sp<IHostapdCallback>> callbacks_;
DISALLOW_COPY_AND_ASSIGN(Hostapd);
};
} // namespace implementation
-} // namespace V1_0
+} // namespace V1_1
} // namespace hostapd
} // namespace wifi
} // namespace hardware
diff --git a/hostapd/hostapd.android.rc b/hostapd/hostapd.android.rc
index 37a95c2..c8792d6 100644
--- a/hostapd/hostapd.android.rc
+++ b/hostapd/hostapd.android.rc
@@ -13,6 +13,7 @@
service hostapd /vendor/bin/hw/hostapd
interface android.hardware.wifi.hostapd@1.0::IHostapd default
+ interface android.hardware.wifi.hostapd@1.1::IHostapd default
class main
capabilities NET_ADMIN NET_RAW
user wifi
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index f558855..f8caa56 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -438,6 +438,13 @@
wmm_ac_vo_acm=0
# Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102
+# Enable Multi-AP functionality
+# 0 = disabled (default)
+# 1 = AP support backhaul BSS
+# 2 = AP support fronthaul BSS
+# 3 = AP supports both backhaul BSS and fronthaul BSS
+#multi_ap=0
+
# Static WEP key configuration
#
# The key number to use when transmitting.
@@ -511,6 +518,12 @@
# Beacon and Probe Response frames.
#bss_load_update_period=50
+# Channel utilization averaging period (in BUs)
+# This field is used to enable and configure channel utilization average
+# calculation with bss_load_update_period. This should be in multiples of
+# bss_load_update_period for more accurate calculation.
+#chan_util_avg_period=600
+
# Fixed BSS Load value for testing purposes
# This field can be used to configure hostapd to add a fixed BSS Load element
# into Beacon and Probe Response frames for testing purposes. The format is
@@ -788,6 +801,30 @@
# unsigned integer = duration in units of 16 us
#he_rts_threshold=0
+#he_mu_edca_qos_info_param_count
+#he_mu_edca_qos_info_q_ack
+#he_mu_edca_qos_info_queue_request=1
+#he_mu_edca_qos_info_txop_request
+#he_mu_edca_ac_be_aifsn=0
+#he_mu_edca_ac_be_ecwmin=15
+#he_mu_edca_ac_be_ecwmax=15
+#he_mu_edca_ac_be_timer=255
+#he_mu_edca_ac_bk_aifsn=0
+#he_mu_edca_ac_bk_aci=1
+#he_mu_edca_ac_bk_ecwmin=15
+#he_mu_edca_ac_bk_ecwmax=15
+#he_mu_edca_ac_bk_timer=255
+#he_mu_edca_ac_vi_ecwmin=15
+#he_mu_edca_ac_vi_ecwmax=15
+#he_mu_edca_ac_vi_aifsn=0
+#he_mu_edca_ac_vi_aci=2
+#he_mu_edca_ac_vi_timer=255
+#he_mu_edca_ac_vo_aifsn=0
+#he_mu_edca_ac_vo_aci=3
+#he_mu_edca_ac_vo_ecwmin=15
+#he_mu_edca_ac_vo_ecwmax=15
+#he_mu_edca_ac_vo_timer=255
+
##### IEEE 802.1X-2004 related configuration ##################################
# Require IEEE 802.1X authorization
@@ -885,18 +922,83 @@
# valid CRL signed by the CA is required to be included in the ca_cert file.
# This can be done by using PEM format for CA certificate and CRL and
# concatenating these into one file. Whenever CRL changes, hostapd needs to be
-# restarted to take the new CRL into use.
+# restarted to take the new CRL into use. Alternatively, crl_reload_interval can
+# be used to configure periodic updating of the loaded CRL information.
# 0 = do not verify CRLs (default)
# 1 = check the CRL of the user certificate
# 2 = check all CRLs in the certificate path
#check_crl=1
+# Specify whether to ignore certificate CRL validity time mismatches with
+# errors X509_V_ERR_CERT_HAS_EXPIRED and X509_V_ERR_CERT_NOT_YET_VALID.
+#
+# 0 = ignore errors
+# 1 = do not ignore errors (default)
+#check_crl_strict=1
+
+# CRL reload interval in seconds
+# This can be used to reload ca_cert file and the included CRL on every new TLS
+# session if difference between last reload and the current reload time in
+# seconds is greater than crl_reload_interval.
+# Note: If interval time is very short, CPU overhead may be negatively affected
+# and it is advised to not go below 300 seconds.
+# This is applicable only with check_crl values 1 and 2.
+# 0 = do not reload CRLs (default)
+# crl_reload_interval = 300
+
+# If check_cert_subject is set, the value of every field will be checked
+# against the DN of the subject in the client certificate. If the values do
+# not match, the certificate verification will fail, rejecting the user.
+# This option allows hostapd to match every individual field in the right order
+# against the DN of the subject in the client certificate.
+#
+# For example, check_cert_subject=C=US/O=XX/OU=ABC/OU=XYZ/CN=1234 will check
+# every individual DN field of the subject in the client certificate. If OU=XYZ
+# comes first in terms of the order in the client certificate (DN field of
+# client certificate C=US/O=XX/OU=XYZ/OU=ABC/CN=1234), hostapd will reject the
+# client because the order of 'OU' is not matching the specified string in
+# check_cert_subject.
+#
+# This option also allows '*' as a wildcard. This option has some limitation.
+# It can only be used as per the following example.
+#
+# For example, check_cert_subject=C=US/O=XX/OU=Production* and we have two
+# clients and DN of the subject in the first client certificate is
+# (C=US/O=XX/OU=Production Unit) and DN of the subject in the second client is
+# (C=US/O=XX/OU=Production Factory). In this case, hostapd will allow both
+# clients because the value of 'OU' field in both client certificates matches
+# 'OU' value in 'check_cert_subject' up to 'wildcard'.
+#
+# * (Allow all clients, e.g., check_cert_subject=*)
+#check_cert_subject=string
+
# TLS Session Lifetime in seconds
# This can be used to allow TLS sessions to be cached and resumed with an
# abbreviated handshake when using EAP-TLS/TTLS/PEAP.
# (default: 0 = session caching and resumption disabled)
#tls_session_lifetime=3600
+# TLS flags
+# [ALLOW-SIGN-RSA-MD5] = allow MD5-based certificate signatures (depending on
+# the TLS library, these may be disabled by default to enforce stronger
+# security)
+# [DISABLE-TIME-CHECKS] = ignore certificate validity time (this requests
+# the TLS library to accept certificates even if they are not currently
+# valid, i.e., have expired or have not yet become valid; this should be
+# used only for testing purposes)
+# [DISABLE-TLSv1.0] = disable use of TLSv1.0
+# [ENABLE-TLSv1.0] = explicitly enable use of TLSv1.0 (this allows
+# systemwide TLS policies to be overridden)
+# [DISABLE-TLSv1.1] = disable use of TLSv1.1
+# [ENABLE-TLSv1.1] = explicitly enable use of TLSv1.1 (this allows
+# systemwide TLS policies to be overridden)
+# [DISABLE-TLSv1.2] = disable use of TLSv1.2
+# [ENABLE-TLSv1.2] = explicitly enable use of TLSv1.2 (this allows
+# systemwide TLS policies to be overridden)
+# [DISABLE-TLSv1.3] = disable use of TLSv1.3
+# [ENABLE-TLSv1.3] = enable TLSv1.3 (experimental - disabled by default)
+#tls_flags=[flag1][flag2]...
+
# Cached OCSP stapling response (DER encoded)
# If set, this file is sent as a certificate status response by the EAP server
# if the EAP peer requests certificate status in the ClientHello message.
@@ -938,6 +1040,19 @@
# use OpenSSL.
#openssl_ciphers=DEFAULT:!EXP:!LOW
+# OpenSSL ECDH curves
+#
+# This is an OpenSSL specific configuration option for configuring the ECDH
+# curves for EAP-TLS/TTLS/PEAP/FAST server. If not set, automatic curve
+# selection is enabled. If set to an empty string, ECDH curve configuration is
+# not done (the exact library behavior depends on the library version).
+# Otherwise, this is a colon separated list of the supported curves (e.g.,
+# P-521:P-384:P-256). This is applicable only if hostapd is built to use
+# OpenSSL. This must not be used for Suite B cases since the same OpenSSL
+# parameter is set differently in those cases and this might conflict with that
+# design.
+#openssl_ecdh_curves=P-521:P-384:P-256
+
# Fragment size for EAP methods
#fragment_size=1400
@@ -1098,8 +1213,10 @@
# Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value
# VLANID as a string). Optionally, the local MAC ACL list (accept_mac_file) can
# be used to set static client MAC address to VLAN ID mapping.
-# 0 = disabled (default)
-# 1 = option; use default interface if RADIUS server does not include VLAN ID
+# Dynamic VLAN mode is also used with VLAN ID assignment based on WPA/WPA2
+# passphrase from wpa_psk_file or vlan_id parameter from sae_password.
+# 0 = disabled (default); only VLAN IDs from accept_mac_file will be used
+# 1 = optional; use default interface if RADIUS server does not include VLAN ID
# 2 = required; reject authentication if RADIUS server does not include VLAN ID
#dynamic_vlan=0
@@ -1122,6 +1239,7 @@
# white space (space or tab).
# If no entries are provided by this file, the station is statically mapped
# to <bss-iface>.<vlan-id> interfaces.
+# Each line can optionally also contain the name of a bridge to add the VLAN to
#vlan_file=/etc/hostapd.vlan
# Interface where 802.1q tagged packets should appear when a RADIUS server is
@@ -1185,6 +1303,8 @@
#radius_das_port=3799
#
# DAS client (the host that can send Disconnect/CoA requests) and shared secret
+# Format: <IP address> <shared secret>
+# IP address 0.0.0.0 can be used to allow requests from any address.
#radius_das_client=192.168.1.123 shared secret here
#
# DAS Event-Timestamp time window in seconds
@@ -1231,7 +1351,10 @@
# and/or WPA2 (full IEEE 802.11i/RSN):
# bit0 = WPA
# bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled)
-#wpa=1
+# Note that WPA3 is also configured with bit1 since it uses RSN just like WPA2.
+# In other words, for WPA3, wpa=2 is used the configuration (and
+# wpa_key_mgmt=SAE for WPA3-Personal instead of wpa_key_mgmt=WPA-PSK).
+#wpa=2
# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
@@ -1260,27 +1383,53 @@
# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
# added to enable SHA256-based stronger algorithms.
+# WPA-PSK = WPA-Personal / WPA2-Personal
+# WPA-PSK-SHA256 = WPA2-Personal using SHA256
+# WPA-EAP = WPA-Enterprise / WPA2-Enterprise
+# WPA-EAP-SHA256 = WPA2-Enterprise using SHA256
+# SAE = SAE (WPA3-Personal)
+# WPA-EAP-SUITE-B-192 = WPA3-Enterprise with 192-bit security/CNSA suite
+# FT-PSK = FT with passphrase/PSK
+# FT-EAP = FT with EAP
+# FT-EAP-SHA384 = FT with EAP using SHA384
+# FT-SAE = FT with SAE
# FILS-SHA256 = Fast Initial Link Setup with SHA256
# FILS-SHA384 = Fast Initial Link Setup with SHA384
# FT-FILS-SHA256 = FT and Fast Initial Link Setup with SHA256
# FT-FILS-SHA384 = FT and Fast Initial Link Setup with SHA384
+# OWE = Opportunistic Wireless Encryption (a.k.a. Enhanced Open)
+# DPP = Device Provisioning Protocol
+# OSEN = Hotspot 2.0 online signup with encryption
# (dot11RSNAConfigAuthenticationSuitesTable)
#wpa_key_mgmt=WPA-PSK WPA-EAP
# Set of accepted cipher suites (encryption algorithms) for pairwise keys
# (unicast packets). This is a space separated list of algorithms:
-# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
-# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
+# CCMP = AES in Counter mode with CBC-MAC (CCMP-128)
+# TKIP = Temporal Key Integrity Protocol
+# CCMP-256 = AES in Counter mode with CBC-MAC with 256-bit key
+# GCMP = Galois/counter mode protocol (GCMP-128)
+# GCMP-256 = Galois/counter mode protocol with 256-bit key
# Group cipher suite (encryption algorithm for broadcast and multicast frames)
# is automatically selected based on this configuration. If only CCMP is
# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
-# TKIP will be used as the group cipher.
+# TKIP will be used as the group cipher. The optional group_cipher parameter can
+# be used to override this automatic selection.
+#
# (dot11RSNAConfigPairwiseCiphersTable)
# Pairwise cipher for WPA (v1) (default: TKIP)
#wpa_pairwise=TKIP CCMP
# Pairwise cipher for RSN/WPA2 (default: use wpa_pairwise value)
#rsn_pairwise=CCMP
+# Optional override for automatic group cipher selection
+# This can be used to select a specific group cipher regardless of which
+# pairwise ciphers were enabled for WPA and RSN. It should be noted that
+# overriding the group cipher with an unexpected value can result in
+# interoperability issues and in general, this parameter is mainly used for
+# testing purposes.
+#group_cipher=CCMP
+
# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
# seconds. (dot11RSNAConfigGroupRekeyTime)
# This defaults to 86400 seconds (once per day) when using CCMP/GCMP as the
@@ -1381,6 +1530,13 @@
# dot11AssociationSAQueryRetryTimeout, 1...4294967295
#assoc_sa_query_retry_timeout=201
+# ocv: Operating Channel Validation
+# This is a countermeasure against multi-channel man-in-the-middle attacks.
+# Enabling this automatically also enables ieee80211w, if not yet enabled.
+# 0 = disabled (default)
+# 1 = enabled
+#ocv=1
+
# disable_pmksa_caching: Disable PMKSA caching
# This parameter can be used to disable caching of PMKSA created through EAP
# authentication. RSN preauthentication may still end up using PMKSA caching if
@@ -1397,27 +1553,71 @@
#okc=1
# SAE password
-# This parameter can be used to set a password for SAE. By default, the
+# This parameter can be used to set passwords for SAE. By default, the
# wpa_passphrase value is used if this separate parameter is not used, but
# wpa_passphrase follows the WPA-PSK constraints (8..63 characters) even though
# SAE passwords do not have such constraints. If the BSS enabled both SAE and
-# WPA-PSK and both values are set, SAE uses the sae_password value and WPA-PSK
+# WPA-PSK and both values are set, SAE uses the sae_password values and WPA-PSK
# uses the wpa_passphrase value.
+#
+# Each sae_password entry is added to a list of available passwords. This
+# corresponds to the dot11RSNAConfigPasswordValueEntry. sae_password value
+# starts with the password (dot11RSNAConfigPasswordCredential). That value can
+# 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.
+#
+# 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
+# specific peer MAC address is included, only a station with that MAC address
+# is allowed to use the entry.
+#
+# If the password identifier (with non-zero length) is included, the entry is
+# limited to be used only with that specified identifier.
+
+# The last matching (based on peer MAC address and identifier) entry is used to
+# select which password to use. Setting sae_password to an empty string has a
+# special meaning of removing all previously added entries.
+#
+# sae_password uses the following encoding:
+#<password/credential>[|mac=<peer mac>][|vlanid=<VLAN ID>][|id=<identifier>]
+# Examples:
#sae_password=secret
+#sae_password=really secret|mac=ff:ff:ff:ff:ff:ff
+#sae_password=example secret|mac=02:03:04:05:06:07|id=pw identifier
+#sae_password=example secret|vlanid=3|id=pw identifier
# SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold)
# This parameter defines how many open SAE instances can be in progress at the
# same time before the anti-clogging mechanism is taken into use.
#sae_anti_clogging_threshold=5
+# Maximum number of SAE synchronization errors (dot11RSNASAESync)
+# The offending SAe peer will be disconnected if more than this many
+# synchronization errors happen.
+#sae_sync=5
+
# Enabled SAE finite cyclic groups
# SAE implementation are required to support group 19 (ECC group defined over a
-# 256-bit prime order field). All groups that are supported by the
-# implementation are enabled by default. This configuration parameter can be
-# used to specify a limited set of allowed groups. The group values are listed
-# in the IANA registry:
+# 256-bit prime order field). This configuration parameter can be used to
+# specify a set of allowed groups. If not included, only the mandatory group 19
+# is enabled.
+# The group values are listed in the IANA registry:
# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
-#sae_groups=19 20 21 25 26
+# Note that groups 1, 2, 5, 22, 23, and 24 should not be used in production
+# purposes due limited security (see RFC 8247). Groups that are not as strong as
+# group 19 (ECC, NIST P-256) are unlikely to be useful for production use cases
+# since all implementations are required to support group 19.
+#sae_groups=19 20 21
+
+# Require MFP for all associations using SAE
+# This parameter can be used to enforce negotiation of MFP for all associations
+# that negotiate use of SAE. This is used in cases where SAE-capable devices are
+# known to be MFP-capable and the BSS is configured with optional MFP
+# (ieee80211w=1) for legacy support. The non-SAE stations can connect without
+# MFP while SAE stations are required to negotiate MFP if sae_require_mfp=1.
+#sae_require_mfp=0
# FILS Cache Identifier (16-bit value in hexdump format)
#fils_cache_id=0011
@@ -1492,9 +1692,16 @@
# 1 to 48 octet identifier.
# This is configured with nas_identifier (see RADIUS client section above).
-# Default lifetime of the PMK-RO in minutes; range 1..65535
+# Default lifetime of the PMK-R0 in seconds; range 60..4294967295
+# (default: 14 days / 1209600 seconds; 0 = disable timeout)
# (dot11FTR0KeyLifetime)
-#r0_key_lifetime=10000
+#ft_r0_key_lifetime=1209600
+
+# Maximum lifetime for PMK-R1; applied only if not zero
+# PMK-R1 is removed at latest after this limit.
+# Removing any PMK-R1 for expiry can be disabled by setting this to -1.
+# (default: 0)
+#r1_max_key_lifetime=0
# PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID)
# 6-octet identifier as a hex string.
@@ -1761,6 +1968,14 @@
# the configuration appropriately in this case.
#wps_cred_processing=0
+# Whether to enable SAE (WPA3-Personal transition mode) automatically for
+# WPA2-PSK credentials received using WPS.
+# 0 = only add the explicitly listed WPA2-PSK configuration (default)
+# 1 = add both the WPA2-PSK and SAE configuration and enable PMF so that the
+# AP gets configured in WPA3-Personal transition mode (supports both
+# WPA2-Personal (PSK) and WPA3-Personal (SAE) clients).
+#wps_cred_add_sae=0
+
# AP Settings Attributes for M7
# By default, hostapd generates the AP Settings Attributes for M7 based on the
# current configuration. It is possible to override this by providing a file
@@ -1769,6 +1984,15 @@
# attribute.
#ap_settings=hostapd.ap_settings
+# Multi-AP backhaul BSS config
+# Used in WPS when multi_ap=2 or 3. Defines "backhaul BSS" credentials.
+# These are passed in WPS M8 instead of the normal (fronthaul) credentials
+# if the Enrollee has the Multi-AP subelement set. Backhaul SSID is formatted
+# like ssid2. The key is set like wpa_psk or wpa_passphrase.
+#multi_ap_backhaul_ssid="backhaul"
+#multi_ap_backhaul_wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+#multi_ap_backhaul_wpa_passphrase=secret passphrase
+
# WPS UPnP interface
# If set, support for external Registrars is enabled.
#upnp_iface=br0
@@ -1841,6 +2065,18 @@
# 1 = enabled (allow stations to use WNM-Sleep Mode)
#wnm_sleep_mode=1
+# WNM-Sleep Mode GTK/IGTK workaround
+# Normally, WNM-Sleep Mode exit with management frame protection negotiated
+# would result in the current GTK/IGTK getting added into the WNM-Sleep Mode
+# Response frame. Some station implementations may have a vulnerability that
+# results in GTK/IGTK reinstallation based on this frame being replayed. This
+# configuration parameter can be used to disable that behavior and use EAPOL-Key
+# frames for GTK/IGTK update instead. This would likely be only used with
+# wpa_disable_eapol_key_retries=1 that enables a workaround for similar issues
+# with EAPOL-Key. This is related to station side vulnerabilities CVE-2017-13087
+# and CVE-2017-13088. To enable this AP-side workaround, set the parameter to 1.
+#wnm_sleep_mode_no_keys=0
+
# BSS Transition Management
# 0 = disabled (default)
# 1 = enabled
@@ -1928,6 +2164,15 @@
# (double quoted string, printf-escaped string)
#venue_name=P"eng:Example\nvenue"
+# Venue URL information
+# This parameter can be used to configure one or more Venue URL Duples to
+# provide additional information corresponding to Venue Name information.
+# Each entry has a Venue Number value separated by colon from the Venue URL
+# string. Venue Number indicates the corresponding venue_name entry (1 = 1st
+# venue_name, 2 = 2nd venue_name, and so on; 0 = no matching venue_name)
+#venue_url=1:http://www.example.com/info-eng
+#venue_url=2:http://www.example.com/info-fin
+
# Network Authentication Type
# This parameter indicates what type of network authentication is used in the
# network.
@@ -2098,7 +2343,27 @@
# channels 36-48):
#hs20_operating_class=5173
-# OSU icons
+# Terms and Conditions information
+#
+# hs20_t_c_filename contains the Terms and Conditions filename that the AP
+# indicates in RADIUS Access-Request messages.
+#hs20_t_c_filename=terms-and-conditions
+#
+# hs20_t_c_timestamp contains the Terms and Conditions timestamp that the AP
+# indicates in RADIUS Access-Request messages. Usually, this contains the number
+# of seconds since January 1, 1970 00:00 UTC showing the time when the file was
+# last modified.
+#hs20_t_c_timestamp=1234567
+#
+# hs20_t_c_server_url contains a template for the Terms and Conditions server
+# URL. This template is used to generate the URL for a STA that needs to
+# acknowledge Terms and Conditions. Unlike the other hs20_t_c_* parameters, this
+# parameter is used on the authentication server, not the AP.
+# Macros:
+# @1@ = MAC address of the STA (colon separated hex octets)
+#hs20_t_c_server_url=https://example.com/t_and_c?addr=@1@&ap=123
+
+# OSU and Operator icons
# <Icon Width>:<Icon Height>:<Language code>:<Icon Type>:<Name>:<file path>
#hs20_icon=32:32:eng:image/png:icon32:/tmp/icon32.png
#hs20_icon=64:64:eng:image/png:icon64:/tmp/icon64.png
@@ -2110,12 +2375,15 @@
# OSU Providers
# One or more sets of following parameter. Each OSU provider is started by the
# mandatory osu_server_uri item. The other parameters add information for the
-# last added OSU provider.
+# last added OSU provider. osu_nai specifies the OSU_NAI value for OSEN
+# authentication when using a standalone OSU BSS. osu_nai2 specifies the OSU_NAI
+# value for OSEN authentication when using a shared BSS (Single SSID) for OSU.
#
#osu_server_uri=https://example.com/osu/
#osu_friendly_name=eng:Example operator
#osu_friendly_name=fin:Esimerkkipalveluntarjoaja
#osu_nai=anonymous@example.com
+#osu_nai2=anonymous@example.com
#osu_method_list=1 0
#osu_icon=icon32
#osu_icon=icon64
@@ -2124,6 +2392,13 @@
#
#osu_server_uri=...
+# Operator Icons
+# Operator icons are specified using references to the hs20_icon entries
+# (Name subfield). This information, if present, is advertsised in the
+# Operator Icon Metadata ANQO-element.
+#operator_icon=icon32
+#operator_icon=icon64
+
##### Multiband Operation (MBO) ###############################################
#
# MBO enabled
@@ -2146,6 +2421,21 @@
# Default is 0 = OCE disabled
#oce=0
+# RSSI-based assocition rejection
+#
+# Reject STA association if RSSI is below given threshold (in dBm)
+# Allowed range: -60 to -90 dBm; default = 0 (rejection disabled)
+# Note: This rejection happens based on a signal strength detected while
+# receiving a single frame and as such, there is significant risk of the value
+# not being accurate and this resulting in valid stations being rejected. As
+# such, this functionality is not recommended to be used for purposes other than
+# testing.
+#rssi_reject_assoc_rssi=-75
+#
+# Association retry delay in seconds allowed by the STA if RSSI has not met the
+# threshold (range: 0..255, default=30).
+#rssi_reject_assoc_timeout=30
+
##### Fast Session Transfer (FST) support #####################################
#
# The options in this section are only available when the build configuration
diff --git a/hostapd/hostapd.eap_user_sqlite b/hostapd/hostapd.eap_user_sqlite
index 826db34..411b9ea 100644
--- a/hostapd/hostapd.eap_user_sqlite
+++ b/hostapd/hostapd.eap_user_sqlite
@@ -3,7 +3,8 @@
methods TEXT,
password TEXT,
remediation TEXT,
- phase2 INTEGER
+ phase2 INTEGER,
+ t_c_timestamp INTEGER
);
CREATE TABLE wildcards(
@@ -24,3 +25,18 @@
username TEXT,
note TEXT
);
+
+CREATE TABLE pending_tc(
+ mac_addr TEXT PRIMARY KEY,
+ identity TEXT
+);
+
+CREATE TABLE current_sessions(
+ mac_addr TEXT PRIMARY KEY,
+ identity TEXT,
+ start_time TEXT,
+ nas TEXT,
+ hs20_t_c_filtering BOOLEAN,
+ waiting_coa_ack BOOLEAN,
+ coa_ack_received BOOLEAN
+);
diff --git a/hostapd/hostapd.wpa_psk b/hostapd/hostapd.wpa_psk
index 0a9499a..166e59e 100644
--- a/hostapd/hostapd.wpa_psk
+++ b/hostapd/hostapd.wpa_psk
@@ -3,7 +3,13 @@
# Special MAC address 00:00:00:00:00:00 can be used to configure PSKs that
# anyone can use. PSK can be configured as an ASCII passphrase of 8..63
# characters or as a 256-bit hex PSK (64 hex digits).
+# An optional key identifier can be added by prefixing the line with
+# keyid=<keyid_string>
+# An optional VLAN ID can be specified by prefixing the line with
+# vlanid=<VLAN ID>.
00:00:00:00:00:00 secret passphrase
00:11:22:33:44:55 another passphrase
00:22:33:44:55:66 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+keyid=example_id 00:11:22:33:44:77 passphrase with keyid
+vlanid=3 00:00:00:00:00:00 passphrase with vlanid
00:00:00:00:00:00 another passphrase for all STAs
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 5b0882a..23c592a 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1,6 +1,6 @@
/*
* hostapd - command line interface for hostapd daemon
- * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -21,7 +21,7 @@
static const char *const hostapd_cli_version =
"hostapd_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi> and contributors";
static struct wpa_ctrl *ctrl_conn;
static int hostapd_cli_quit = 0;
@@ -1408,6 +1408,20 @@
}
+static int hostapd_cli_cmd_dpp_listen(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_LISTEN", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_dpp_stop_listen(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DPP_STOP_LISTEN");
+}
+
+
static int hostapd_cli_cmd_dpp_configurator_add(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -1422,6 +1436,20 @@
}
+static int hostapd_cli_cmd_dpp_configurator_get_key(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_GET_KEY", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_dpp_configurator_sign(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_SIGN", 1, argc, argv);
+}
+
+
static int hostapd_cli_cmd_dpp_pkex_add(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -1438,6 +1466,41 @@
#endif /* CONFIG_DPP */
+static int hostapd_cli_cmd_accept_macacl(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "ACCEPT_ACL", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_deny_macacl(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DENY_ACL", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_poll_sta(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "POLL_STA", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_req_beacon(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "REQ_BEACON", 2, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_reload_wpa_psk(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "RELOAD_WPA_PSK");
+}
+
+
struct hostapd_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
@@ -1586,16 +1649,35 @@
"<id> = show DPP bootstrap information" },
{ "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,
+ "<freq in MHz> = start DPP listen" },
+ { "dpp_stop_listen", hostapd_cli_cmd_dpp_stop_listen, NULL,
+ "= stop DPP listen" },
{ "dpp_configurator_add", hostapd_cli_cmd_dpp_configurator_add, NULL,
"[curve=..] [key=..] = add DPP configurator" },
{ "dpp_configurator_remove", hostapd_cli_cmd_dpp_configurator_remove,
NULL,
"*|<id> = remove DPP configurator" },
+ { "dpp_configurator_get_key", hostapd_cli_cmd_dpp_configurator_get_key,
+ NULL,
+ "<id> = Get DPP configurator's private key" },
+ { "dpp_configurator_sign", hostapd_cli_cmd_dpp_configurator_sign, NULL,
+ "conf=<role> configurator=<id> = generate self DPP configuration" },
{ "dpp_pkex_add", hostapd_cli_cmd_dpp_pkex_add, NULL,
"add PKEX code" },
{ "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL,
"*|<id> = remove DPP pkex information" },
#endif /* CONFIG_DPP */
+ { "accept_acl", hostapd_cli_cmd_accept_macacl, NULL,
+ "=Add/Delete/Show/Clear accept MAC ACL" },
+ { "deny_acl", hostapd_cli_cmd_deny_macacl, NULL,
+ "=Add/Delete/Show/Clear deny MAC ACL" },
+ { "poll_sta", hostapd_cli_cmd_poll_sta, hostapd_complete_stations,
+ "<addr> = poll a STA to check connectivity with a QoS null frame" },
+ { "req_beacon", hostapd_cli_cmd_req_beacon, NULL,
+ "<addr> [req_mode=] <measurement request hexdump> = send a Beacon report request to a station" },
+ { "reload_wpa_psk", hostapd_cli_cmd_reload_wpa_psk, NULL,
+ "= reload wpa_psk_file only" },
{ NULL, NULL, NULL, NULL }
};
diff --git a/hostapd/main.c b/hostapd/main.c
index 6c0490f..b9df584 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -1,6 +1,6 @@
/*
* hostapd / main()
- * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -18,12 +18,14 @@
#include "crypto/random.h"
#include "crypto/tls.h"
#include "common/version.h"
+#include "common/dpp.h"
#include "drivers/driver.h"
#include "eap_server/eap.h"
#include "eap_server/tncs.h"
#include "ap/hostapd.h"
#include "ap/ap_config.h"
#include "ap/ap_drv_ops.h"
+#include "ap/dpp_hostapd.h"
#include "fst/fst.h"
#include "config_file.h"
#include "eap_register.h"
@@ -254,7 +256,7 @@
*
* This function is used to parse configuration file for a full interface (one
* or more BSSes sharing the same radio) and allocate memory for the BSS
- * interfaces. No actiual driver operations are started.
+ * interfaces. No actual driver operations are started.
*/
static struct hostapd_iface *
hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name,
@@ -457,7 +459,7 @@
"hostapd v" VERSION_STR "\n"
"User space daemon for IEEE 802.11 AP management,\n"
"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
- "Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> "
+ "Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> "
"and contributors\n");
}
@@ -671,6 +673,11 @@
#ifdef CONFIG_ETH_P_OUI
dl_list_init(&interfaces.eth_p_oui);
#endif /* CONFIG_ETH_P_OUI */
+#ifdef CONFIG_DPP
+ interfaces.dpp = dpp_global_init();
+ if (!interfaces.dpp)
+ return -1;
+#endif /* CONFIG_DPP */
for (;;) {
c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:");
@@ -873,27 +880,8 @@
*/
interfaces.terminate_on_error = interfaces.count;
for (i = 0; i < interfaces.count; i++) {
- if (hostapd_driver_init(interfaces.iface[i]))
- goto out;
-#ifdef CONFIG_MBO
- for (j = 0; j < interfaces.iface[i]->num_bss; j++) {
- struct hostapd_data *hapd = interfaces.iface[i]->bss[j];
-
- if (hapd && (hapd->conf->oce & OCE_STA_CFON) &&
- (interfaces.iface[i]->drv_flags &
- WPA_DRIVER_FLAGS_OCE_STA_CFON))
- hapd->enable_oce = OCE_STA_CFON;
-
- if (hapd && (hapd->conf->oce & OCE_AP) &&
- (interfaces.iface[i]->drv_flags &
- WPA_DRIVER_FLAGS_OCE_STA_CFON)) {
- /* TODO: Need to add OCE-AP support */
- wpa_printf(MSG_ERROR,
- "OCE-AP feature is not yet supported");
- }
- }
-#endif /* CONFIG_MBO */
- if (hostapd_setup_interface(interfaces.iface[i]))
+ if (hostapd_driver_init(interfaces.iface[i]) ||
+ hostapd_setup_interface(interfaces.iface[i]))
goto out;
}
@@ -928,6 +916,10 @@
}
os_free(interfaces.iface);
+#ifdef CONFIG_DPP
+ dpp_global_deinit(interfaces.dpp);
+#endif /* CONFIG_DPP */
+
if (interfaces.eloop_initialized)
eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
hostapd_global_deinit(pid_file, interfaces.eloop_initialized);
diff --git a/hostapd/wps-ap-nfc.py b/hostapd/wps-ap-nfc.py
index 2fc3012..258d841 100755
--- a/hostapd/wps-ap-nfc.py
+++ b/hostapd/wps-ap-nfc.py
@@ -26,7 +26,7 @@
success_file = None
def summary(txt):
- print txt
+ print(txt)
if summary_file:
with open(summary_file, 'a') as f:
f.write(txt + "\n")
@@ -42,19 +42,19 @@
if os.path.isdir(wpas_ctrl):
try:
ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
- except OSError, error:
- print "Could not find hostapd: ", error
+ except OSError as error:
+ print("Could not find hostapd: ", error)
return None
if len(ifaces) < 1:
- print "No hostapd control interface found"
+ print("No hostapd control interface found")
return None
for ctrl in ifaces:
try:
wpas = wpaspy.Ctrl(ctrl)
return wpas
- except Exception, e:
+ except Exception as e:
pass
return None
@@ -133,23 +133,23 @@
def process_request(self, request):
summary("HandoverServer - request received")
try:
- print "Parsed handover request: " + request.pretty()
- except Exception, e:
- print e
- print str(request).encode("hex")
+ print("Parsed handover request: " + request.pretty())
+ except Exception as e:
+ print(e)
+ print(str(request).encode("hex"))
sel = nfc.ndef.HandoverSelectMessage(version="1.2")
for carrier in request.carriers:
- print "Remote carrier type: " + carrier.type
+ print("Remote carrier type: " + carrier.type)
if carrier.type == "application/vnd.wfa.wsc":
summary("WPS carrier type match - add WPS carrier record")
data = wpas_get_handover_sel()
if data is None:
summary("Could not get handover select carrier record from hostapd")
continue
- print "Handover select carrier record from hostapd:"
- print data.encode("hex")
+ print("Handover select carrier record from hostapd:")
+ print(data.encode("hex"))
if "OK" in wpas_report_handover(carrier.record, data):
success_report("Handover reported successfully")
else:
@@ -158,12 +158,12 @@
message = nfc.ndef.Message(data);
sel.add_carrier(message[0], "active", message[1:])
- print "Handover select:"
+ print("Handover select:")
try:
- print sel.pretty()
- except Exception, e:
- print e
- print str(sel).encode("hex")
+ print(sel.pretty())
+ except Exception as e:
+ print(e)
+ print(str(sel).encode("hex"))
summary("Sending handover select")
self.success = True
@@ -174,7 +174,7 @@
success = False
if len(tag.ndef.message):
for record in tag.ndef.message:
- print "record type " + record.type
+ print("record type " + record.type)
if record.type == "application/vnd.wfa.wsc":
summary("WPS tag - send to hostapd")
success = wpas_tag_read(tag.ndef.message)
@@ -193,7 +193,7 @@
global write_data
tag.ndef.message = str(write_data)
success_report("Tag write succeeded")
- print "Done - remove tag"
+ print("Done - remove tag")
global only_one
if only_one:
global continue_loop
@@ -211,7 +211,7 @@
summary("Could not get WPS config token from hostapd")
return
- print "Touch an NFC tag"
+ print("Touch an NFC tag")
clf.connect(rdwr={'on-connect': rdwr_connected_write})
@@ -224,7 +224,7 @@
summary("Could not get WPS password token from hostapd")
return
- print "Touch an NFC tag"
+ print("Touch an NFC tag")
clf.connect(rdwr={'on-connect': rdwr_connected_write})
@@ -233,11 +233,11 @@
summary("Tag connected: " + str(tag))
if tag.ndef:
- print "NDEF tag: " + tag.type
+ print("NDEF tag: " + tag.type)
try:
- print tag.ndef.message.pretty()
- except Exception, e:
- print e
+ print(tag.ndef.message.pretty())
+ except Exception as e:
+ print(e)
success = wps_tag_read(tag)
if only_one and success:
global continue_loop
@@ -250,13 +250,13 @@
def llcp_startup(clf, llc):
- print "Start LLCP server"
+ print("Start LLCP server")
global srv
srv = HandoverServer(llc)
return llc
def llcp_connected(llc):
- print "P2P LLCP connected"
+ print("P2P LLCP connected")
global wait_connection
wait_connection = False
global srv
@@ -304,7 +304,7 @@
try:
if not clf.open("usb"):
- print "Could not open connection with an NFC device"
+ print("Could not open connection with an NFC device")
raise SystemExit
if args.command == "write-config":
@@ -317,15 +317,15 @@
global continue_loop
while continue_loop:
- print "Waiting for a tag or peer to be touched"
+ print("Waiting for a tag or peer to be touched")
wait_connection = True
try:
if not clf.connect(rdwr={'on-connect': rdwr_connected},
llcp={'on-startup': llcp_startup,
'on-connect': llcp_connected}):
break
- except Exception, e:
- print "clf.connect failed"
+ except Exception as e:
+ print("clf.connect failed")
global srv
if only_one and srv and srv.success:
diff --git a/hs20/client/.gitignore b/hs20/client/.gitignore
new file mode 100644
index 0000000..d2fd60f
--- /dev/null
+++ b/hs20/client/.gitignore
@@ -0,0 +1 @@
+hs20-osu-client
diff --git a/hs20/client/Makefile b/hs20/client/Makefile
index fc9b619..67f6f55 100644
--- a/hs20/client/Makefile
+++ b/hs20/client/Makefile
@@ -8,12 +8,17 @@
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
diff --git a/hs20/client/est.c b/hs20/client/est.c
index 9f1519b..db65334 100644
--- a/hs20/client/est.c
+++ b/hs20/client/est.c
@@ -16,6 +16,7 @@
#include <openssl/asn1t.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
+#include <openssl/opensslv.h>
#ifdef OPENSSL_IS_BORINGSSL
#include <openssl/buf.h>
#endif /* OPENSSL_IS_BORINGSSL */
@@ -219,6 +220,10 @@
} d;
} AttrOrOID;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
+DEFINE_STACK_OF(AttrOrOID)
+#endif
+
typedef struct {
int type;
STACK_OF(AttrOrOID) *attrs;
@@ -352,9 +357,17 @@
}
}
#else /* OPENSSL_IS_BORINGSSL */
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
+ num = sk_AttrOrOID_num(csrattrs->attrs);
+#else
num = SKM_sk_num(AttrOrOID, csrattrs->attrs);
+#endif
for (i = 0; i < num; i++) {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
+ AttrOrOID *ao = sk_AttrOrOID_value(csrattrs->attrs, i);
+#else
AttrOrOID *ao = SKM_sk_value(AttrOrOID, csrattrs->attrs, i);
+#endif
switch (ao->type) {
case 0:
add_csrattrs_oid(ctx, ao->d.oid, exts);
@@ -666,7 +679,6 @@
char *buf, *resp, *req, *req2;
size_t buflen, resp_len, len, pkcs7_len;
unsigned char *pkcs7;
- FILE *f;
char client_cert_buf[200];
char client_key_buf[200];
const char *client_cert = NULL, *client_key = NULL;
@@ -721,11 +733,6 @@
return -1;
}
wpa_printf(MSG_DEBUG, "EST simpleenroll response: %s", resp);
- f = fopen("Cert/est-resp.raw", "w");
- if (f) {
- fwrite(resp, resp_len, 1, f);
- fclose(f);
- }
pkcs7 = base64_decode((unsigned char *) resp, resp_len, &pkcs7_len);
if (pkcs7 == NULL) {
diff --git a/hs20/client/oma_dm_client.c b/hs20/client/oma_dm_client.c
index 5854b72..d75c845 100644
--- a/hs20/client/oma_dm_client.c
+++ b/hs20/client/oma_dm_client.c
@@ -111,6 +111,12 @@
xml_node_t *syncml, *synchdr;
xml_namespace_t *ns;
+ if (!ctx->devid) {
+ wpa_printf(MSG_ERROR,
+ "DevId from devinfo.xml is not available - cannot use OMA DM");
+ return NULL;
+ }
+
syncml = xml_node_create_root(ctx->xml, "SYNCML:SYNCML1.2", NULL, &ns,
"SyncML");
diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c
index d73feb1..1f594ce 100644
--- a/hs20/client/osu_client.c
+++ b/hs20/client/osu_client.c
@@ -105,6 +105,35 @@
}
+static int android_update_permission(const char *path, mode_t mode)
+{
+#ifdef ANDROID
+ /* we need to change file/folder permission for Android */
+
+ if (!path) {
+ wpa_printf(MSG_ERROR, "file path null");
+ return -1;
+ }
+
+ /* Allow processes running with Group ID as AID_WIFI,
+ * to read files from SP, SP/<fqdn>, Cert and osu-info directories */
+ if (lchown(path, -1, AID_WIFI)) {
+ wpa_printf(MSG_INFO, "CTRL: Could not lchown directory: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ if (chmod(path, mode) < 0) {
+ wpa_printf(MSG_INFO, "CTRL: Could not chmod directory: %s",
+ strerror(errno));
+ return -1;
+ }
+#endif /* ANDROID */
+
+ return 0;
+}
+
+
int osu_get_certificate(struct hs20_osu_client *ctx, xml_node_t *getcert)
{
xml_node_t *node;
@@ -169,6 +198,8 @@
}
mkdir("Cert", S_IRWXU);
+ android_update_permission("Cert", S_IRWXU | S_IRWXG);
+
if (est_load_cacerts(ctx, url) < 0 ||
est_build_csr(ctx, url) < 0 ||
est_simple_enroll(ctx, url, user, pw) < 0)
@@ -262,7 +293,6 @@
unlink("Cert/est-req.b64");
unlink("Cert/est-req.pem");
- unlink("Cert/est-resp.raw");
rmdir("Cert");
return 0;
@@ -406,7 +436,7 @@
if (node == NULL) {
wpa_printf(MSG_INFO, "No Policy/PolicyUpdate/TrustRoot/CertURL found from PPS");
xml_node_free(ctx->xml, pps);
- return -1;
+ return -2;
}
ret = download_cert(ctx, node, ca_fname);
@@ -433,7 +463,7 @@
if (node == NULL) {
wpa_printf(MSG_INFO, "No AAAServerTrustRoot/CertURL found from PPS");
xml_node_free(ctx->xml, pps);
- return -1;
+ return -2;
}
aaa = xml_node_first_child(ctx->xml, node);
@@ -455,7 +485,7 @@
{
char *dir, *pos;
char fname[300];
- int ret;
+ int ret, ret1;
dir = os_strdup(pps_fname);
if (dir == NULL)
@@ -470,9 +500,13 @@
snprintf(fname, sizeof(fname), "%s/ca.pem", dir);
ret = cmd_dl_osu_ca(ctx, pps_fname, fname);
snprintf(fname, sizeof(fname), "%s/polupd-ca.pem", dir);
- cmd_dl_polupd_ca(ctx, pps_fname, fname);
+ ret1 = cmd_dl_polupd_ca(ctx, pps_fname, fname);
+ if (ret == 0 && ret1 == -1)
+ ret = -1;
snprintf(fname, sizeof(fname), "%s/aaa-ca.pem", dir);
- cmd_dl_aaa_ca(ctx, pps_fname, fname);
+ ret1 = cmd_dl_aaa_ca(ctx, pps_fname, fname);
+ if (ret == 0 && ret1 == -1)
+ ret = -1;
os_free(dir);
@@ -578,20 +612,8 @@
}
}
-#ifdef ANDROID
- /* Allow processes running with Group ID as AID_WIFI,
- * to read files from SP/<fqdn> directory */
- if (chown(fname, -1, AID_WIFI)) {
- wpa_printf(MSG_INFO, "CTRL: Could not chown directory: %s",
- strerror(errno));
- /* Try to continue anyway */
- }
- if (chmod(fname, S_IRWXU | S_IRGRP | S_IXGRP) < 0) {
- wpa_printf(MSG_INFO, "CTRL: Could not chmod directory: %s",
- strerror(errno));
- /* Try to continue anyway */
- }
-#endif /* ANDROID */
+ android_update_permission("SP", S_IRWXU | S_IRWXG);
+ android_update_permission(fname, S_IRWXU | S_IRWXG);
snprintf(fname, fname_len, "SP/%s/pps.xml", fqdn);
@@ -1213,8 +1235,7 @@
homeoi) < 0)
wpa_printf(MSG_INFO, "Failed to set cred required_roaming_consortium");
} else {
- if (set_cred_quoted(ctx->ifname, id, "roaming_consortium",
- homeoi) < 0)
+ if (set_cred(ctx->ifname, id, "roaming_consortium", homeoi) < 0)
wpa_printf(MSG_INFO, "Failed to set cred roaming_consortium");
}
@@ -1289,7 +1310,9 @@
if (str == NULL)
return;
wpa_printf(MSG_INFO, "- HomeSP/RoamingConsortiumOI = %s", str);
- /* TODO: Set to wpa_supplicant */
+ if (set_cred_quoted(ctx->ifname, id, "roaming_consortiums",
+ str) < 0)
+ wpa_printf(MSG_INFO, "Failed to set cred roaming_consortiums");
xml_node_get_text_free(ctx->xml, str);
}
@@ -1442,10 +1465,92 @@
}
+static void set_pps_cred_eap_method_eap_type(struct hs20_osu_client *ctx,
+ int id, xml_node_t *node)
+{
+ char *str = xml_node_get_text(ctx->xml, node);
+ int type;
+ const char *eap_method = NULL;
+
+ if (!str)
+ return;
+ wpa_printf(MSG_INFO,
+ "- Credential/UsernamePassword/EAPMethod/EAPType = %s", str);
+ type = atoi(str);
+ switch (type) {
+ case EAP_TYPE_TLS:
+ eap_method = "TLS";
+ break;
+ case EAP_TYPE_TTLS:
+ eap_method = "TTLS";
+ break;
+ case EAP_TYPE_PEAP:
+ eap_method = "PEAP";
+ break;
+ case EAP_TYPE_PWD:
+ eap_method = "PWD";
+ break;
+ }
+ xml_node_get_text_free(ctx->xml, str);
+ if (!eap_method) {
+ wpa_printf(MSG_INFO, "Unknown EAPType value");
+ return;
+ }
+
+ if (set_cred(ctx->ifname, id, "eap", eap_method) < 0)
+ wpa_printf(MSG_INFO, "Failed to set cred eap");
+}
+
+
+static void set_pps_cred_eap_method_inner_method(struct hs20_osu_client *ctx,
+ int id, xml_node_t *node)
+{
+ char *str = xml_node_get_text(ctx->xml, node);
+ const char *phase2 = NULL;
+
+ if (!str)
+ return;
+ wpa_printf(MSG_INFO,
+ "- Credential/UsernamePassword/EAPMethod/InnerMethod = %s",
+ str);
+ if (os_strcmp(str, "PAP") == 0)
+ phase2 = "auth=PAP";
+ else if (os_strcmp(str, "CHAP") == 0)
+ phase2 = "auth=CHAP";
+ else if (os_strcmp(str, "MS-CHAP") == 0)
+ phase2 = "auth=MSCHAP";
+ else if (os_strcmp(str, "MS-CHAP-V2") == 0)
+ phase2 = "auth=MSCHAPV2";
+ xml_node_get_text_free(ctx->xml, str);
+ if (!phase2) {
+ wpa_printf(MSG_INFO, "Unknown InnerMethod value");
+ return;
+ }
+
+ if (set_cred_quoted(ctx->ifname, id, "phase2", phase2) < 0)
+ wpa_printf(MSG_INFO, "Failed to set cred phase2");
+}
+
+
static void set_pps_cred_eap_method(struct hs20_osu_client *ctx, int id,
xml_node_t *node)
{
- wpa_printf(MSG_INFO, "- Credential/UsernamePassword/EAPMethod - TODO");
+ xml_node_t *child;
+ const char *name;
+
+ wpa_printf(MSG_INFO, "- Credential/UsernamePassword/EAPMethod");
+
+ xml_node_for_each_child(ctx->xml, child, node) {
+ xml_node_for_each_check(ctx->xml, child);
+ name = xml_node_get_localname(ctx->xml, child);
+ if (os_strcasecmp(name, "EAPType") == 0)
+ set_pps_cred_eap_method_eap_type(ctx, id, child);
+ else if (os_strcasecmp(name, "InnerMethod") == 0)
+ set_pps_cred_eap_method_inner_method(ctx, id, child);
+ else
+ wpa_printf(MSG_INFO, "Unknown Credential/UsernamePassword/EAPMethod node '%s'",
+ name);
+ }
}
@@ -1884,7 +1989,9 @@
char url[256];
unsigned int methods;
char osu_ssid[33];
+ char osu_ssid2[33];
char osu_nai[256];
+ char osu_nai2[256];
struct osu_lang_text friendly_name[MAX_OSU_VALS];
size_t friendly_name_count;
struct osu_lang_text serv_desc[MAX_OSU_VALS];
@@ -1943,12 +2050,24 @@
continue;
}
+ if (strncmp(buf, "osu_ssid2=", 10) == 0) {
+ snprintf(last->osu_ssid2, sizeof(last->osu_ssid2),
+ "%s", buf + 10);
+ continue;
+ }
+
if (os_strncmp(buf, "osu_nai=", 8) == 0) {
os_snprintf(last->osu_nai, sizeof(last->osu_nai),
"%s", buf + 8);
continue;
}
+ if (os_strncmp(buf, "osu_nai2=", 9) == 0) {
+ os_snprintf(last->osu_nai2, sizeof(last->osu_nai2),
+ "%s", buf + 9);
+ continue;
+ }
+
if (strncmp(buf, "friendly_name=", 14) == 0) {
struct osu_lang_text *txt;
if (last->friendly_name_count == MAX_OSU_VALS)
@@ -2024,9 +2143,9 @@
static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
- const char *ssid, const char *url,
+ const char *ssid, const char *ssid2, const char *url,
unsigned int methods, int no_prod_assoc,
- const char *osu_nai)
+ const char *osu_nai, const char *osu_nai2)
{
int id;
const char *ifname = ctx->ifname;
@@ -2034,26 +2153,54 @@
struct wpa_ctrl *mon;
int res;
+ if (ssid2 && ssid2[0] == '\0')
+ ssid2 = NULL;
+
+ if (ctx->osu_ssid) {
+ if (os_strcmp(ssid, ctx->osu_ssid) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "Enforced OSU SSID matches ANQP info");
+ ssid2 = NULL;
+ } else if (ssid2 && os_strcmp(ssid2, ctx->osu_ssid) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "Enforced OSU SSID matches RSN[OSEN] info");
+ ssid = ssid2;
+ } else {
+ wpa_printf(MSG_INFO, "Enforced OSU SSID did not match");
+ write_summary(ctx, "Enforced OSU SSID did not match");
+ return -1;
+ }
+ }
+
id = add_network(ifname);
if (id < 0)
return -1;
if (set_network_quoted(ifname, id, "ssid", ssid) < 0)
return -1;
+ if (ssid2)
+ osu_nai = osu_nai2;
if (osu_nai && os_strlen(osu_nai) > 0) {
char dir[255], fname[300];
if (getcwd(dir, sizeof(dir)) == NULL)
return -1;
os_snprintf(fname, sizeof(fname), "%s/osu-ca.pem", dir);
+ if (ssid2 && set_network_quoted(ifname, id, "ssid", ssid2) < 0)
+ return -1;
+
if (set_network(ifname, id, "proto", "OSEN") < 0 ||
set_network(ifname, id, "key_mgmt", "OSEN") < 0 ||
set_network(ifname, id, "pairwise", "CCMP") < 0 ||
- set_network(ifname, id, "group", "GTK_NOT_USED") < 0 ||
+ set_network(ifname, id, "group", "GTK_NOT_USED CCMP") < 0 ||
set_network(ifname, id, "eap", "WFA-UNAUTH-TLS") < 0 ||
set_network(ifname, id, "ocsp", "2") < 0 ||
set_network_quoted(ifname, id, "identity", osu_nai) < 0 ||
set_network_quoted(ifname, id, "ca_cert", fname) < 0)
return -1;
+ } else if (ssid2) {
+ wpa_printf(MSG_INFO, "No OSU_NAI set for RSN[OSEN]");
+ write_summary(ctx, "No OSU_NAI set for RSN[OSEN]");
+ return -1;
} else {
if (set_network(ifname, id, "key_mgmt", "NONE") < 0)
return -1;
@@ -2229,8 +2376,12 @@
fprintf(f, "</table></a><br><small>BSSID: %s<br>\n"
"SSID: %s<br>\n",
last->bssid, last->osu_ssid);
+ if (last->osu_ssid2[0])
+ fprintf(f, "SSID2: %s<br>\n", last->osu_ssid2);
if (last->osu_nai[0])
fprintf(f, "NAI: %s<br>\n", last->osu_nai);
+ if (last->osu_nai2[0])
+ fprintf(f, "NAI2: %s<br>\n", last->osu_nai2);
fprintf(f, "URL: %s<br>\n"
"methods:%s%s<br>\n"
"</small></p>\n",
@@ -2257,6 +2408,8 @@
ret = 0;
wpa_printf(MSG_INFO, "BSSID: %s", last->bssid);
wpa_printf(MSG_INFO, "SSID: %s", last->osu_ssid);
+ if (last->osu_ssid2[0])
+ wpa_printf(MSG_INFO, "SSID2: %s", last->osu_ssid2);
wpa_printf(MSG_INFO, "URL: %s", last->url);
write_summary(ctx, "Selected OSU provider id=%d BSSID=%s SSID=%s URL=%s",
ret, last->bssid, last->osu_ssid, last->url);
@@ -2311,10 +2464,13 @@
"No supported OSU provisioning method");
ret = -1;
}
- } else if (connect)
+ } else if (connect) {
ret = osu_connect(ctx, last->bssid, last->osu_ssid,
+ last->osu_ssid2,
last->url, last->methods,
- no_prod_assoc, last->osu_nai);
+ no_prod_assoc, last->osu_nai,
+ last->osu_nai2);
+ }
} else
ret = -1;
@@ -2346,15 +2502,7 @@
return -1;
}
-#ifdef ANDROID
- /* Allow processes running with Group ID as AID_WIFI
- * to read/write files from osu-info directory
- */
- if (chown(fname, -1, AID_WIFI)) {
- wpa_printf(MSG_INFO, "Could not chown osu-info directory: %s",
- strerror(errno));
- }
-#endif /* ANDROID */
+ android_update_permission(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
snprintf(buf, sizeof(buf), "SET osu_dir %s", fname);
if (wpa_command(ifname, buf) < 0) {
@@ -2920,24 +3068,17 @@
return -1;
devinfo = node_from_file(ctx->xml, "devinfo.xml");
- if (!devinfo) {
- wpa_printf(MSG_ERROR, "devinfo.xml not found");
- return -1;
- }
+ if (devinfo) {
+ devid = get_node(ctx->xml, devinfo, "DevId");
+ if (devid) {
+ char *tmp = xml_node_get_text(ctx->xml, devid);
- devid = get_node(ctx->xml, devinfo, "DevId");
- if (devid) {
- char *tmp = xml_node_get_text(ctx->xml, devid);
- if (tmp) {
- ctx->devid = os_strdup(tmp);
- xml_node_get_text_free(ctx->xml, tmp);
+ if (tmp) {
+ ctx->devid = os_strdup(tmp);
+ xml_node_get_text_free(ctx->xml, tmp);
+ }
}
- }
- xml_node_free(ctx->xml, devinfo);
-
- if (ctx->devid == NULL) {
- wpa_printf(MSG_ERROR, "Could not fetch DevId from devinfo.xml");
- return -1;
+ xml_node_free(ctx->xml, devinfo);
}
ctx->http = http_init_ctx(ctx, ctx->xml);
@@ -3040,7 +3181,7 @@
return -1;
for (;;) {
- c = getopt(argc, argv, "df:hKNO:qr:s:S:tw:x:");
+ c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tw:x:");
if (c < 0)
break;
switch (c) {
@@ -3057,6 +3198,9 @@
case 'N':
no_prod_assoc = 1;
break;
+ case 'o':
+ ctx.osu_ssid = optarg;
+ break;
case 'O':
friendly_name = optarg;
break;
diff --git a/hs20/client/osu_client.h b/hs20/client/osu_client.h
index 9a7059e..5c8e6d0 100644
--- a/hs20/client/osu_client.h
+++ b/hs20/client/osu_client.h
@@ -47,6 +47,7 @@
int client_cert_present;
char **server_dnsname;
size_t server_dnsname_count;
+ const char *osu_ssid; /* Enforced OSU_SSID for testing purposes */
#define WORKAROUND_OCSP_OPTIONAL 0x00000001
unsigned long int workarounds;
};
diff --git a/hs20/server/Makefile b/hs20/server/Makefile
index 248ed5c..9b73727 100644
--- a/hs20/server/Makefile
+++ b/hs20/server/Makefile
@@ -21,6 +21,16 @@
# Using glibc < 2.17 requires -lrt for clock_gettime()
LIBS += -lrt
+ifndef CONFIG_NO_GITVER
+# Add VERSION_STR postfix for builds from a git repository
+ifeq ($(wildcard ../../.git),../../.git)
+GITVER := $(shell git describe --dirty=+)
+ifneq ($(GITVER),)
+CFLAGS += -DGIT_VERSION_STR_POSTFIX=\"-$(GITVER)\"
+endif
+endif
+endif
+
OBJS=spp_server.o
OBJS += hs20_spp_server.o
OBJS += ../../src/utils/xml-utils.o
diff --git a/hs20/server/hs20-osu-server.txt b/hs20/server/hs20-osu-server.txt
index 20774a6..22478ad 100644
--- a/hs20/server/hs20-osu-server.txt
+++ b/hs20/server/hs20-osu-server.txt
@@ -2,7 +2,7 @@
======================
The information in this document is based on the assumption that Ubuntu
-12.04 server (64-bit) distribution is used and the web server is
+16.04 server (64-bit) distribution is used and the web server is
Apache2. Neither of these are requirements for the installation, but if
other combinations are used, the package names and configuration
parameters may need to be adjusted.
@@ -12,16 +12,11 @@
secure to be installed in a publicly available Internet server without
considerable amount of modification and review for security issues.
-NOTE: While this describes use on Ubuntu 12.04, the version of Apache2
-included in that distribution is not new enough to support all OSU
-server validation steps. In other words, it may be most adapt the steps
-described here to Ubuntu 13.10.
-
Build dependencies
------------------
-Ubuntu 12.04 server
+Ubuntu 16.04 server
- default installation
- upgraded to latest package versions
sudo apt-get update
@@ -30,7 +25,7 @@
Packages needed for running the service:
sudo apt-get install sqlite3
sudo apt-get install apache2
- sudo apt-get install php5-sqlite libapache2-mod-php5
+ sudo apt-get install php-sqlite3 php-xml libapache2-mod-php
Additional packages needed for building the components:
sudo apt-get install build-essential
@@ -100,6 +95,12 @@
# the examples as-is for initial testing).
cp -r www /home/user/hs20-server
+# Create /home/user/hs20-server/terms-and-conditions file (HTML segment to be
+# inserted within the BODY section of the page).
+cat > /home/user/hs20-server/terms-and-conditions <<EOF
+<P>Terms and conditions..</P>
+EOF
+
# Build local keys and certs
cd ca
# Display help options.
@@ -226,14 +227,18 @@
<Directory "/home/user/hs20-server/www/">
Options Indexes MultiViews FollowSymLinks
AllowOverride None
- Order allow,deny
- Allow from all
+ Require all granted
+ SSLOptions +StdEnvVars
</Directory>
Update SSL configuration to use the OSU server certificate/key.
They keys and certs are called 'server.key' and 'server.pem' from
ca/setup.sh.
+To support subscription remediation using client certificates, set
+"SSLVerifyClient optional" and configure the trust root CA(s) for the
+client certificates with SSLCACertificateFile.
+
Enable default-ssl site and restart Apache2:
sudo a2ensite default-ssl
sudo a2enmod ssl
diff --git a/hs20/server/hs20_spp_server.c b/hs20/server/hs20_spp_server.c
index 591f66b..6c74f54 100644
--- a/hs20/server/hs20_spp_server.c
+++ b/hs20/server/hs20_spp_server.c
@@ -11,6 +11,7 @@
#include <sqlite3.h>
#include "common.h"
+#include "common/version.h"
#include "xml-utils.h"
#include "spp_server.h"
@@ -70,6 +71,10 @@
ctx->addr = getenv("HS20ADDR");
if (ctx->addr)
debug_print(ctx, 1, "Connection from %s", ctx->addr);
+ ctx->test = getenv("HS20TEST");
+ if (ctx->test)
+ debug_print(ctx, 1, "Requested test functionality: %s",
+ ctx->test);
user = getenv("HS20USER");
if (user && strlen(user) == 0)
@@ -85,6 +90,18 @@
return -1;
}
+ ctx->imsi = getenv("HS20IMSI");
+ if (ctx->imsi)
+ debug_print(ctx, 1, "IMSI %s", ctx->imsi);
+
+ ctx->eap_method = getenv("HS20EAPMETHOD");
+ if (ctx->eap_method)
+ debug_print(ctx, 1, "EAP method %s", ctx->eap_method);
+
+ ctx->id_hash = getenv("HS20IDHASH");
+ if (ctx->id_hash)
+ debug_print(ctx, 1, "ID-HASH %s", ctx->id_hash);
+
soap = xml_node_from_buf(ctx->xml, post);
if (soap == NULL) {
debug_print(ctx, 1, "Could not parse SOAP data");
@@ -142,7 +159,7 @@
os_memset(&ctx, 0, sizeof(ctx));
for (;;) {
- int c = getopt(argc, argv, "f:r:");
+ int c = getopt(argc, argv, "f:r:v");
if (c < 0)
break;
switch (c) {
@@ -158,6 +175,9 @@
case 'r':
ctx.root_dir = optarg;
break;
+ case 'v':
+ printf("hs20_spp_server v" VERSION_STR "\n");
+ return 0;
default:
usage();
return -1;
diff --git a/hs20/server/spp_server.c b/hs20/server/spp_server.c
index 51c1d96..4bef0ff 100644
--- a/hs20/server/spp_server.c
+++ b/hs20/server/spp_server.c
@@ -41,6 +41,8 @@
POLICY_REMEDIATION,
POLICY_UPDATE,
FREE_REMEDIATION,
+ CLEAR_REMEDIATION,
+ CERT_REENROLL,
};
@@ -51,25 +53,37 @@
const char *field);
static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user,
const char *realm, int use_dmacc);
+static xml_node_t * spp_exec_get_certificate(struct hs20_svc *ctx,
+ const char *session_id,
+ const char *user,
+ const char *realm,
+ int add_est_user);
static int db_add_session(struct hs20_svc *ctx,
const char *user, const char *realm,
const char *sessionid, const char *pw,
const char *redirect_uri,
- enum hs20_session_operation operation)
+ enum hs20_session_operation operation,
+ const u8 *mac_addr)
{
char *sql;
int ret = 0;
+ char addr[20];
+ if (mac_addr)
+ snprintf(addr, sizeof(addr), MACSTR, MAC2STR(mac_addr));
+ else
+ addr[0] = '\0';
sql = sqlite3_mprintf("INSERT INTO sessions(timestamp,id,user,realm,"
- "operation,password,redirect_uri) "
+ "operation,password,redirect_uri,mac_addr,test) "
"VALUES "
"(strftime('%%Y-%%m-%%d %%H:%%M:%%f','now'),"
- "%Q,%Q,%Q,%d,%Q,%Q)",
+ "%Q,%Q,%Q,%d,%Q,%Q,%Q,%Q)",
sessionid, user ? user : "", realm ? realm : "",
operation, pw ? pw : "",
- redirect_uri ? redirect_uri : "");
+ redirect_uri ? redirect_uri : "",
+ addr, ctx->test);
if (sql == NULL)
return -1;
debug_print(ctx, 1, "DB: %s", sql);
@@ -197,6 +211,61 @@
}
+static void db_add_session_dmacc(struct hs20_svc *ctx, const char *sessionid,
+ const char *username, const char *password)
+{
+ char *sql;
+
+ sql = sqlite3_mprintf("UPDATE sessions SET osu_user=%Q, osu_password=%Q WHERE id=%Q",
+ username, password, sessionid);
+ if (!sql)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to add session DMAcc: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void db_add_session_eap_method(struct hs20_svc *ctx,
+ const char *sessionid,
+ const char *method)
+{
+ char *sql;
+
+ sql = sqlite3_mprintf("UPDATE sessions SET eap_method=%Q WHERE id=%Q",
+ method, sessionid);
+ if (!sql)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to add session EAP method: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
+static void db_add_session_id_hash(struct hs20_svc *ctx, const char *sessionid,
+ const char *id_hash)
+{
+ char *sql;
+
+ sql = sqlite3_mprintf("UPDATE sessions SET mobile_identifier_hash=%Q WHERE id=%Q",
+ id_hash, sessionid);
+ if (!sql)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to add session ID hash: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
static void db_remove_session(struct hs20_svc *ctx,
const char *user, const char *realm,
const char *sessionid)
@@ -283,8 +352,7 @@
char *sql;
if (user == NULL || realm == NULL || name == NULL)
return;
- sql = sqlite3_mprintf("UPDATE users SET %s=%Q "
- "WHERE identity=%Q AND realm=%Q AND phase2=1",
+ sql = sqlite3_mprintf("UPDATE users SET %s=%Q WHERE identity=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
name, str, user, realm);
if (sql == NULL)
return;
@@ -329,6 +397,29 @@
}
+static void add_text_node_conf_corrupt(struct hs20_svc *ctx, const char *realm,
+ xml_node_t *parent, const char *name,
+ const char *field)
+{
+ char *val;
+
+ val = db_get_osu_config_val(ctx, realm, field);
+ if (val) {
+ size_t len;
+
+ len = os_strlen(val);
+ if (len > 0) {
+ if (val[len - 1] == '0')
+ val[len - 1] = '1';
+ else
+ val[len - 1] = '0';
+ }
+ }
+ xml_node_create_text(ctx->xml, parent, NULL, name, val ? val : "");
+ os_free(val);
+}
+
+
static int new_password(char *buf, int buflen)
{
int i;
@@ -383,8 +474,7 @@
char *cmd;
struct get_db_field_data data;
- cmd = sqlite3_mprintf("SELECT %s FROM users WHERE "
- "%s=%Q AND realm=%Q AND phase2=1",
+ cmd = sqlite3_mprintf("SELECT %s FROM users WHERE %s=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
field, dmacc ? "osu_user" : "identity",
user, realm);
if (cmd == NULL)
@@ -413,8 +503,7 @@
char *cmd;
int ret;
- cmd = sqlite3_mprintf("UPDATE users SET %s=%Q WHERE "
- "%s=%Q AND realm=%Q AND phase2=1",
+ cmd = sqlite3_mprintf("UPDATE users SET %s=%Q WHERE %s=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
field, val, dmacc ? "osu_user" : "identity", user,
realm);
if (cmd == NULL)
@@ -494,6 +583,27 @@
}
+static int clear_remediation(struct hs20_svc *ctx, const char *user,
+ const char *realm, int dmacc)
+{
+ char *cmd;
+
+ cmd = sqlite3_mprintf("UPDATE users SET remediation='' WHERE %s=%Q",
+ dmacc ? "osu_user" : "identity",
+ user);
+ if (cmd == NULL)
+ return -1;
+ debug_print(ctx, 1, "DB: %s", cmd);
+ if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1, "Failed to update database for user '%s'",
+ user);
+ }
+ sqlite3_free(cmd);
+
+ return 0;
+}
+
+
static int add_eap_ttls(struct hs20_svc *ctx, xml_node_t *parent)
{
xml_node_t *node;
@@ -515,6 +625,7 @@
{
xml_node_t *node;
char *b64;
+ size_t len;
node = xml_node_create(ctx->xml, parent, NULL, "UsernamePassword");
if (node == NULL)
@@ -525,6 +636,9 @@
b64 = (char *) base64_encode((unsigned char *) pw, strlen(pw), NULL);
if (b64 == NULL)
return NULL;
+ len = os_strlen(b64);
+ if (len > 0 && b64[len - 1] == '\n')
+ b64[len - 1] = '\0';
add_text_node(ctx, node, "Password", b64);
free(b64);
@@ -533,7 +647,8 @@
static int add_username_password(struct hs20_svc *ctx, xml_node_t *cred,
- const char *user, const char *pw)
+ const char *user, const char *pw,
+ int machine_managed)
{
xml_node_t *node;
@@ -541,7 +656,8 @@
if (node == NULL)
return -1;
- add_text_node(ctx, node, "MachineManaged", "TRUE");
+ add_text_node(ctx, node, "MachineManaged",
+ machine_managed ? "TRUE" : "FALSE");
add_text_node(ctx, node, "SoftTokenApp", "");
add_eap_ttls(ctx, node);
@@ -566,7 +682,7 @@
static xml_node_t * build_credential_pw(struct hs20_svc *ctx,
const char *user, const char *realm,
- const char *pw)
+ const char *pw, int machine_managed)
{
xml_node_t *cred;
@@ -576,7 +692,7 @@
return NULL;
}
add_creation_date(ctx, cred);
- if (add_username_password(ctx, cred, user, pw) < 0) {
+ if (add_username_password(ctx, cred, user, pw, machine_managed) < 0) {
xml_node_free(ctx->xml, cred);
return NULL;
}
@@ -593,7 +709,7 @@
if (new_password(new_pw, new_pw_len) < 0)
return NULL;
debug_print(ctx, 1, "Update password to '%s'", new_pw);
- return build_credential_pw(ctx, user, realm, new_pw);
+ return build_credential_pw(ctx, user, realm, new_pw, 1);
}
@@ -674,6 +790,45 @@
}
+static xml_node_t * read_subrem_file(struct hs20_svc *ctx,
+ const char *subrem_id,
+ char *uri, size_t uri_size)
+{
+ char fname[200];
+ char *buf, *buf2, *pos;
+ size_t len;
+ xml_node_t *node;
+
+ os_snprintf(fname, sizeof(fname), "%s/spp/subrem/%s",
+ ctx->root_dir, subrem_id);
+ debug_print(ctx, 1, "Use subrem file %s", fname);
+
+ buf = os_readfile(fname, &len);
+ if (!buf)
+ return NULL;
+ buf2 = os_realloc(buf, len + 1);
+ if (!buf2) {
+ os_free(buf);
+ return NULL;
+ }
+ buf = buf2;
+ buf[len] = '\0';
+
+ pos = os_strchr(buf, '\n');
+ if (!pos) {
+ os_free(buf);
+ return NULL;
+ }
+ *pos++ = '\0';
+ os_strlcpy(uri, buf, uri_size);
+
+ node = xml_node_from_buf(ctx->xml, pos);
+ os_free(buf);
+
+ return node;
+}
+
+
static xml_node_t * build_sub_rem_resp(struct hs20_svc *ctx,
const char *user, const char *realm,
const char *session_id,
@@ -683,33 +838,74 @@
xml_node_t *spp_node, *cred;
char buf[400];
char new_pw[33];
- char *real_user = NULL;
char *status;
char *cert;
- if (dmacc) {
- real_user = db_get_val(ctx, user, realm, "identity", dmacc);
- if (real_user == NULL) {
- debug_print(ctx, 1, "Could not find user identity for "
- "dmacc user '%s'", user);
+ cert = db_get_val(ctx, user, realm, "cert", dmacc);
+ if (cert && cert[0] == '\0') {
+ os_free(cert);
+ cert = NULL;
+ }
+ if (cert) {
+ char *subrem;
+
+ /* No change needed in PPS MO unless specifically asked to */
+ cred = NULL;
+ buf[0] = '\0';
+
+ subrem = db_get_val(ctx, user, realm, "subrem", dmacc);
+ if (subrem && subrem[0]) {
+ cred = read_subrem_file(ctx, subrem, buf, sizeof(buf));
+ if (!cred) {
+ debug_print(ctx, 1,
+ "Could not create updateNode from subrem file");
+ os_free(subrem);
+ os_free(cert);
+ return NULL;
+ }
+ }
+ os_free(subrem);
+ } else {
+ char *real_user = NULL;
+ char *pw;
+
+ if (dmacc) {
+ real_user = db_get_val(ctx, user, realm, "identity",
+ dmacc);
+ if (!real_user) {
+ debug_print(ctx, 1,
+ "Could not find user identity for dmacc user '%s'",
+ user);
+ return NULL;
+ }
+ }
+
+ pw = db_get_session_val(ctx, user, realm, session_id,
+ "password");
+ if (pw && pw[0]) {
+ debug_print(ctx, 1, "New password from the user: '%s'",
+ pw);
+ snprintf(new_pw, sizeof(new_pw), "%s", pw);
+ free(pw);
+ cred = build_credential_pw(ctx,
+ real_user ? real_user : user,
+ realm, new_pw, 0);
+ } else {
+ cred = build_credential(ctx,
+ real_user ? real_user : user,
+ realm, new_pw, sizeof(new_pw));
+ }
+
+ free(real_user);
+ if (!cred) {
+ debug_print(ctx, 1, "Could not build credential");
+ os_free(cert);
return NULL;
}
- }
- cert = db_get_val(ctx, user, realm, "cert", dmacc);
- if (cert && cert[0] == '\0')
- cert = NULL;
- if (cert) {
- cred = build_credential_cert(ctx, real_user ? real_user : user,
- realm, cert);
- } else {
- cred = build_credential(ctx, real_user ? real_user : user,
- realm, new_pw, sizeof(new_pw));
- }
- free(real_user);
- if (!cred) {
- debug_print(ctx, 1, "Could not build credential");
- return NULL;
+ snprintf(buf, sizeof(buf),
+ "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
+ realm);
}
status = "Remediation complete, request sppUpdateResponse";
@@ -717,16 +913,15 @@
NULL);
if (spp_node == NULL) {
debug_print(ctx, 1, "Could not build sppPostDevDataResponse");
+ os_free(cert);
return NULL;
}
- snprintf(buf, sizeof(buf),
- "./Wi-Fi/%s/PerProviderSubscription/Credential1/Credential",
- realm);
-
- if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
+ if ((cred && add_update_node(ctx, spp_node, ns, buf, cred) < 0) ||
+ (!cred && !xml_node_create(ctx->xml, spp_node, ns, "noMOUpdate"))) {
debug_print(ctx, 1, "Could not add update node");
xml_node_free(ctx->xml, spp_node);
+ os_free(cert);
return NULL;
}
@@ -736,14 +931,16 @@
xml_node_free(ctx->xml, cred);
if (cert) {
- debug_print(ctx, 1, "Certificate credential - no need for DB "
- "password update on success notification");
+ debug_print(ctx, 1, "Request DB remediation clearing on success notification (certificate credential)");
+ db_add_session(ctx, user, realm, session_id, NULL, NULL,
+ CLEAR_REMEDIATION, NULL);
} else {
debug_print(ctx, 1, "Request DB password update on success "
"notification");
db_add_session(ctx, user, realm, session_id, new_pw, NULL,
- UPDATE_PASSWORD);
+ UPDATE_PASSWORD, NULL);
}
+ os_free(cert);
return spp_node;
}
@@ -758,6 +955,17 @@
}
+static xml_node_t * cert_reenroll(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm,
+ const char *session_id)
+{
+ db_add_session(ctx, user, realm, session_id, NULL, NULL,
+ CERT_REENROLL, NULL);
+ return spp_exec_get_certificate(ctx, session_id, user, realm, 0);
+}
+
+
static xml_node_t * policy_remediation(struct hs20_svc *ctx,
const char *user, const char *realm,
const char *session_id, int dmacc)
@@ -771,7 +979,7 @@
"requires policy remediation", NULL);
db_add_session(ctx, user, realm, session_id, NULL, NULL,
- POLICY_REMEDIATION);
+ POLICY_REMEDIATION, NULL);
policy = build_policy(ctx, user, realm, dmacc);
if (!policy) {
@@ -787,7 +995,7 @@
return NULL;
snprintf(buf, sizeof(buf),
- "./Wi-Fi/%s/PerProviderSubscription/Credential1/Policy",
+ "./Wi-Fi/%s/PerProviderSubscription/Cred01/Policy",
realm);
if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) {
@@ -844,7 +1052,7 @@
return NULL;
db_add_session(ctx, user, realm, session_id, NULL, redirect_uri,
- USER_REMEDIATION);
+ USER_REMEDIATION, NULL);
snprintf(uri, sizeof(uri), "%s%s", val, session_id);
os_free(val);
@@ -866,7 +1074,7 @@
return NULL;
db_add_session(ctx, user, realm, session_id, NULL, redirect_uri,
- FREE_REMEDIATION);
+ FREE_REMEDIATION, NULL);
snprintf(uri, sizeof(uri), "%s%s", val, session_id);
os_free(val);
@@ -940,19 +1148,53 @@
redirect_uri);
else if (type && strcmp(type, "policy") == 0)
ret = policy_remediation(ctx, user, realm, session_id, dmacc);
- else
+ else if (type && strcmp(type, "machine") == 0)
ret = machine_remediation(ctx, user, realm, session_id, dmacc);
+ else if (type && strcmp(type, "reenroll") == 0)
+ ret = cert_reenroll(ctx, user, realm, session_id);
+ else
+ ret = no_sub_rem(ctx, user, realm, session_id);
free(type);
return ret;
}
+static xml_node_t * read_policy_file(struct hs20_svc *ctx,
+ const char *policy_id)
+{
+ char fname[200];
+
+ snprintf(fname, sizeof(fname), "%s/spp/policy/%s.xml",
+ ctx->root_dir, policy_id);
+ debug_print(ctx, 1, "Use policy file %s", fname);
+
+ return node_from_file(ctx->xml, fname);
+}
+
+
+static void update_policy_update_uri(struct hs20_svc *ctx, const char *realm,
+ xml_node_t *policy)
+{
+ xml_node_t *node;
+ char *url;
+
+ node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate/URI");
+ if (!node)
+ return;
+
+ url = db_get_osu_config_val(ctx, realm, "policy_url");
+ if (!url)
+ return;
+ xml_node_set_text(ctx->xml, node, url);
+ free(url);
+}
+
+
static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user,
const char *realm, int use_dmacc)
{
char *policy_id;
- char fname[200];
xml_node_t *policy, *node;
policy_id = db_get_val(ctx, user, realm, "policy", use_dmacc);
@@ -962,27 +1204,12 @@
if (policy_id == NULL)
return NULL;
}
-
- snprintf(fname, sizeof(fname), "%s/spp/policy/%s.xml",
- ctx->root_dir, policy_id);
+ policy = read_policy_file(ctx, policy_id);
free(policy_id);
- debug_print(ctx, 1, "Use policy file %s", fname);
-
- policy = node_from_file(ctx->xml, fname);
if (policy == NULL)
return NULL;
- node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate/URI");
- if (node) {
- char *url;
- url = db_get_osu_config_val(ctx, realm, "policy_url");
- if (url == NULL) {
- xml_node_free(ctx->xml, policy);
- return NULL;
- }
- xml_node_set_text(ctx->xml, node, url);
- free(url);
- }
+ update_policy_update_uri(ctx, realm, policy);
node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate");
if (node && use_dmacc) {
@@ -1033,7 +1260,8 @@
"No update available at this time", NULL);
}
- db_add_session(ctx, user, realm, session_id, NULL, NULL, POLICY_UPDATE);
+ db_add_session(ctx, user, realm, session_id, NULL, NULL, POLICY_UPDATE,
+ NULL);
status = "Update complete, request sppUpdateResponse";
spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
@@ -1042,7 +1270,7 @@
return NULL;
snprintf(buf, sizeof(buf),
- "./Wi-Fi/%s/PerProviderSubscription/Credential1/Policy",
+ "./Wi-Fi/%s/PerProviderSubscription/Cred01/Policy",
realm);
if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) {
@@ -1146,14 +1374,15 @@
static xml_node_t * hs20_subscription_registration(struct hs20_svc *ctx,
const char *realm,
const char *session_id,
- const char *redirect_uri)
+ const char *redirect_uri,
+ const u8 *mac_addr)
{
xml_namespace_t *ns;
xml_node_t *spp_node, *exec_node;
char uri[300], *val;
if (db_add_session(ctx, NULL, realm, session_id, NULL, redirect_uri,
- SUBSCRIPTION_REGISTRATION) < 0)
+ SUBSCRIPTION_REGISTRATION, mac_addr) < 0)
return NULL;
val = db_get_osu_config_val(ctx, realm, "signup_url");
if (val == NULL)
@@ -1213,38 +1442,90 @@
static xml_node_t * build_pps(struct hs20_svc *ctx,
const char *user, const char *realm,
const char *pw, const char *cert,
- int machine_managed)
+ int machine_managed, const char *test,
+ const char *imsi, const char *dmacc_username,
+ const char *dmacc_password,
+ xml_node_t *policy_node)
{
- xml_node_t *pps, *c, *trust, *aaa, *aaa1, *upd, *homesp;
+ xml_node_t *pps, *c, *trust, *aaa, *aaa1, *upd, *homesp, *p;
xml_node_t *cred, *eap, *userpw;
pps = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
"PerProviderSubscription");
- if (pps == NULL)
+ if (!pps) {
+ xml_node_free(ctx->xml, policy_node);
return NULL;
+ }
add_text_node(ctx, pps, "UpdateIdentifier", "1");
- c = xml_node_create(ctx->xml, pps, NULL, "Credential1");
+ c = xml_node_create(ctx->xml, pps, NULL, "Cred01");
add_text_node(ctx, c, "CredentialPriority", "1");
+ if (imsi)
+ goto skip_aaa_trust_root;
aaa = xml_node_create(ctx->xml, c, NULL, "AAAServerTrustRoot");
aaa1 = xml_node_create(ctx->xml, aaa, NULL, "AAA1");
add_text_node_conf(ctx, realm, aaa1, "CertURL",
"aaa_trust_root_cert_url");
- add_text_node_conf(ctx, realm, aaa1, "CertSHA256Fingerprint",
- "aaa_trust_root_cert_fingerprint");
+ if (test && os_strcmp(test, "corrupt_aaa_hash") == 0) {
+ debug_print(ctx, 1,
+ "TEST: Corrupt PPS/Cred*/AAAServerTrustRoot/Root*/CertSHA256FingerPrint");
+ add_text_node_conf_corrupt(ctx, realm, aaa1,
+ "CertSHA256Fingerprint",
+ "aaa_trust_root_cert_fingerprint");
+ } else {
+ add_text_node_conf(ctx, realm, aaa1, "CertSHA256Fingerprint",
+ "aaa_trust_root_cert_fingerprint");
+ }
+
+ if (test && os_strcmp(test, "corrupt_polupd_hash") == 0) {
+ debug_print(ctx, 1,
+ "TEST: Corrupt PPS/Cred*/Policy/PolicyUpdate/Trustroot/CertSHA256FingerPrint");
+ p = xml_node_create(ctx->xml, c, NULL, "Policy");
+ upd = xml_node_create(ctx->xml, p, NULL, "PolicyUpdate");
+ add_text_node(ctx, upd, "UpdateInterval", "30");
+ add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated");
+ add_text_node(ctx, upd, "Restriction", "Unrestricted");
+ add_text_node_conf(ctx, realm, upd, "URI", "policy_url");
+ trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot");
+ add_text_node_conf(ctx, realm, trust, "CertURL",
+ "policy_trust_root_cert_url");
+ add_text_node_conf_corrupt(ctx, realm, trust,
+ "CertSHA256Fingerprint",
+ "policy_trust_root_cert_fingerprint");
+ }
+skip_aaa_trust_root:
upd = xml_node_create(ctx->xml, c, NULL, "SubscriptionUpdate");
add_text_node(ctx, upd, "UpdateInterval", "4294967295");
- add_text_node(ctx, upd, "UpdateMethod", "ClientInitiated");
+ add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated");
add_text_node(ctx, upd, "Restriction", "HomeSP");
add_text_node_conf(ctx, realm, upd, "URI", "spp_http_auth_url");
trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot");
add_text_node_conf(ctx, realm, trust, "CertURL", "trust_root_cert_url");
- add_text_node_conf(ctx, realm, trust, "CertSHA256Fingerprint",
- "trust_root_cert_fingerprint");
+ if (test && os_strcmp(test, "corrupt_subrem_hash") == 0) {
+ debug_print(ctx, 1,
+ "TEST: Corrupt PPS/Cred*/SubscriptionUpdate/Trustroot/CertSHA256FingerPrint");
+ add_text_node_conf_corrupt(ctx, realm, trust,
+ "CertSHA256Fingerprint",
+ "trust_root_cert_fingerprint");
+ } else {
+ add_text_node_conf(ctx, realm, trust, "CertSHA256Fingerprint",
+ "trust_root_cert_fingerprint");
+ }
+
+ if (dmacc_username &&
+ !build_username_password(ctx, upd, dmacc_username,
+ dmacc_password)) {
+ xml_node_free(ctx->xml, pps);
+ xml_node_free(ctx->xml, policy_node);
+ return NULL;
+ }
+
+ if (policy_node)
+ xml_node_add_child(ctx->xml, c, policy_node);
homesp = xml_node_create(ctx->xml, c, NULL, "HomeSP");
add_text_node_conf(ctx, realm, homesp, "FriendlyName", "friendly_name");
@@ -1254,7 +1535,19 @@
cred = xml_node_create(ctx->xml, c, NULL, "Credential");
add_creation_date(ctx, cred);
- if (cert) {
+ if (imsi) {
+ xml_node_t *sim;
+ const char *type = "18"; /* default to EAP-SIM */
+
+ sim = xml_node_create(ctx->xml, cred, NULL, "SIM");
+ add_text_node(ctx, sim, "IMSI", imsi);
+ if (ctx->eap_method && os_strcmp(ctx->eap_method, "AKA") == 0)
+ type = "23";
+ else if (ctx->eap_method &&
+ os_strcmp(ctx->eap_method, "AKA'") == 0)
+ type = "50";
+ add_text_node(ctx, sim, "EAPType", type);
+ } else if (cert) {
xml_node_t *dc;
dc = xml_node_create(ctx->xml, cred, NULL,
"DigitalCertificate");
@@ -1277,7 +1570,8 @@
static xml_node_t * spp_exec_get_certificate(struct hs20_svc *ctx,
const char *session_id,
const char *user,
- const char *realm)
+ const char *realm,
+ int add_est_user)
{
xml_namespace_t *ns;
xml_node_t *spp_node, *enroll, *exec_node;
@@ -1285,7 +1579,7 @@
char password[11];
char *b64;
- if (new_password(password, sizeof(password)) < 0)
+ if (add_est_user && new_password(password, sizeof(password)) < 0)
return NULL;
spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
@@ -1302,6 +1596,10 @@
xml_node_create_text(ctx->xml, enroll, ns, "enrollmentServerURI",
val ? val : "");
os_free(val);
+
+ if (!add_est_user)
+ return spp_node;
+
xml_node_create_text(ctx->xml, enroll, ns, "estUserID", user);
b64 = (char *) base64_encode((unsigned char *) password,
@@ -1328,7 +1626,7 @@
xml_node_t *pps, *tnds;
char buf[400];
char *str;
- char *user, *realm, *pw, *type, *mm;
+ char *user, *realm, *pw, *type, *mm, *test;
const char *status;
int cert = 0;
int machine_managed = 0;
@@ -1361,7 +1659,7 @@
xml_node_t *ret;
hs20_eventlog(ctx, user, realm, session_id,
"request client certificate enrollment", NULL);
- ret = spp_exec_get_certificate(ctx, session_id, user, realm);
+ ret = spp_exec_get_certificate(ctx, session_id, user, realm, 1);
free(user);
free(realm);
free(pw);
@@ -1387,9 +1685,15 @@
return NULL;
fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
+ test = db_get_session_val(ctx, NULL, NULL, session_id, "test");
+ if (test)
+ debug_print(ctx, 1, "TEST: Requested special behavior: %s",
+ test);
pps = build_pps(ctx, user, realm, pw,
- fingerprint ? fingerprint : NULL, machine_managed);
+ fingerprint ? fingerprint : NULL, machine_managed,
+ test, NULL, NULL, NULL, NULL);
free(fingerprint);
+ free(test);
if (!pps) {
xml_node_free(ctx->xml, spp_node);
free(user);
@@ -1460,7 +1764,7 @@
return NULL;
}
- cred = build_credential_pw(ctx, free_account, realm, pw);
+ cred = build_credential_pw(ctx, free_account, realm, pw, 1);
free(free_account);
free(pw);
if (!cred) {
@@ -1475,7 +1779,7 @@
return NULL;
snprintf(buf, sizeof(buf),
- "./Wi-Fi/%s/PerProviderSubscription/Credential1/Credential",
+ "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
realm);
if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
@@ -1528,6 +1832,72 @@
}
+static xml_node_t * hs20_cert_reenroll_complete(struct hs20_svc *ctx,
+ const char *session_id)
+{
+ char *user, *realm, *cert;
+ char *status;
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *cred;
+ char buf[400];
+
+ user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
+ realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
+ cert = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
+ if (!user || !realm || !cert) {
+ debug_print(ctx, 1,
+ "Could not find session info from DB for certificate reenrollment");
+ free(user);
+ free(realm);
+ free(cert);
+ return NULL;
+ }
+
+ cred = build_credential_cert(ctx, user, realm, cert);
+ if (!cred) {
+ debug_print(ctx, 1, "Could not build credential");
+ free(user);
+ free(realm);
+ free(cert);
+ return NULL;
+ }
+
+ status = "Remediation complete, request sppUpdateResponse";
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
+ NULL);
+ if (spp_node == NULL) {
+ debug_print(ctx, 1, "Could not build sppPostDevDataResponse");
+ free(user);
+ free(realm);
+ free(cert);
+ xml_node_free(ctx->xml, cred);
+ return NULL;
+ }
+
+ snprintf(buf, sizeof(buf),
+ "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
+ realm);
+
+ if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
+ debug_print(ctx, 1, "Could not add update node");
+ xml_node_free(ctx->xml, spp_node);
+ free(user);
+ free(realm);
+ free(cert);
+ return NULL;
+ }
+
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "certificate reenrollment", cred);
+ xml_node_free(ctx->xml, cred);
+
+ free(user);
+ free(realm);
+ free(cert);
+ return spp_node;
+}
+
+
static xml_node_t * hs20_cert_enroll_completed(struct hs20_svc *ctx,
const char *user,
const char *realm, int dmacc,
@@ -1536,7 +1906,7 @@
char *val;
enum hs20_session_operation oper;
- val = db_get_session_val(ctx, user, realm, session_id, "operation");
+ val = db_get_session_val(ctx, NULL, NULL, session_id, "operation");
if (val == NULL) {
debug_print(ctx, 1, "No session %s found to continue",
session_id);
@@ -1547,6 +1917,8 @@
if (oper == SUBSCRIPTION_REGISTRATION)
return hs20_user_input_registration(ctx, session_id, 1);
+ if (oper == CERT_REENROLL)
+ return hs20_cert_reenroll_complete(ctx, session_id);
debug_print(ctx, 1, "User session %s not in state for certificate "
"enrollment completion", session_id);
@@ -1594,6 +1966,103 @@
}
+static xml_node_t * hs20_sim_provisioning(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm, int dmacc,
+ const char *session_id)
+{
+ xml_namespace_t *ns;
+ xml_node_t *spp_node, *node = NULL;
+ xml_node_t *pps, *tnds;
+ char buf[400];
+ char *str;
+ const char *status;
+ char dmacc_username[32];
+ char dmacc_password[32];
+ char *policy;
+ xml_node_t *policy_node = NULL;
+
+ if (!ctx->imsi) {
+ debug_print(ctx, 1, "IMSI not available for SIM provisioning");
+ return NULL;
+ }
+
+ if (new_password(dmacc_username, sizeof(dmacc_username)) < 0 ||
+ new_password(dmacc_password, sizeof(dmacc_password)) < 0) {
+ debug_print(ctx, 1,
+ "Failed to generate DMAcc username/password");
+ return NULL;
+ }
+
+ status = "Provisioning complete, request sppUpdateResponse";
+ spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
+ NULL);
+ if (!spp_node)
+ return NULL;
+
+ policy = db_get_osu_config_val(ctx, realm, "sim_policy");
+ if (policy) {
+ policy_node = read_policy_file(ctx, policy);
+ os_free(policy);
+ if (!policy_node) {
+ xml_node_free(ctx->xml, spp_node);
+ return NULL;
+ }
+ update_policy_update_uri(ctx, realm, policy_node);
+ node = get_node_uri(ctx->xml, policy_node,
+ "Policy/PolicyUpdate");
+ if (node)
+ build_username_password(ctx, node, dmacc_username,
+ dmacc_password);
+ }
+
+ pps = build_pps(ctx, NULL, realm, NULL, NULL, 0, NULL, ctx->imsi,
+ dmacc_username, dmacc_password, policy_node);
+ if (!pps) {
+ xml_node_free(ctx->xml, spp_node);
+ return NULL;
+ }
+
+ debug_print(ctx, 1,
+ "Request DB subscription registration on success notification");
+ if (!user || !user[0])
+ user = ctx->imsi;
+ db_add_session(ctx, user, realm, session_id, NULL, NULL,
+ SUBSCRIPTION_REGISTRATION, NULL);
+ db_add_session_dmacc(ctx, session_id, dmacc_username, dmacc_password);
+ if (ctx->eap_method)
+ db_add_session_eap_method(ctx, session_id, ctx->eap_method);
+ if (ctx->id_hash)
+ db_add_session_id_hash(ctx, session_id, ctx->id_hash);
+ db_add_session_pps(ctx, user, realm, session_id, pps);
+
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "new subscription", pps);
+
+ tnds = mo_to_tnds(ctx->xml, pps, 0, URN_HS20_PPS, NULL);
+ xml_node_free(ctx->xml, pps);
+ if (!tnds) {
+ xml_node_free(ctx->xml, spp_node);
+ return NULL;
+ }
+
+ str = xml_node_to_str(ctx->xml, tnds);
+ xml_node_free(ctx->xml, tnds);
+ if (!str) {
+ xml_node_free(ctx->xml, spp_node);
+ return NULL;
+ }
+
+ node = xml_node_create_text(ctx->xml, spp_node, ns, "addMO", str);
+ free(str);
+ snprintf(buf, sizeof(buf), "./Wi-Fi/%s/PerProviderSubscription", realm);
+ xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", buf);
+ xml_node_add_attr(ctx->xml, node, ns, "moURN", URN_HS20_PPS);
+
+ return spp_node;
+}
+
+
static xml_node_t * hs20_spp_post_dev_data(struct hs20_svc *ctx,
xml_node_t *node,
const char *user,
@@ -1606,11 +2075,12 @@
char *req_reason_buf = NULL;
char str[200];
xml_node_t *ret = NULL, *devinfo = NULL, *devdetail = NULL;
- xml_node_t *mo;
+ xml_node_t *mo, *macaddr;
char *version;
int valid;
char *supp, *pos;
char *err;
+ u8 wifi_mac_addr[ETH_ALEN];
version = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
"sppVersion");
@@ -1716,6 +2186,29 @@
goto out;
}
os_free(err);
+
+ os_memset(wifi_mac_addr, 0, ETH_ALEN);
+ macaddr = get_node(ctx->xml, devdetail,
+ "Ext/org.wi-fi/Wi-Fi/Wi-FiMACAddress");
+ if (macaddr) {
+ char *addr, buf[50];
+
+ addr = xml_node_get_text(ctx->xml, macaddr);
+ if (addr && hwaddr_compact_aton(addr, wifi_mac_addr) == 0) {
+ snprintf(buf, sizeof(buf), "DevDetail MAC address: "
+ MACSTR, MAC2STR(wifi_mac_addr));
+ hs20_eventlog(ctx, user, realm, session_id, buf, NULL);
+ xml_node_get_text_free(ctx->xml, addr);
+ } else {
+ hs20_eventlog(ctx, user, realm, session_id,
+ "Could not extract MAC address from DevDetail",
+ NULL);
+ }
+ } else {
+ hs20_eventlog(ctx, user, realm, session_id,
+ "No MAC address in DevDetail", NULL);
+ }
+
if (user)
db_update_mo(ctx, user, realm, "devdetail", devdetail);
@@ -1762,7 +2255,7 @@
else
oper = NO_OPERATION;
if (db_add_session(ctx, user, realm, session_id, NULL,
- NULL, oper) < 0)
+ NULL, oper, NULL) < 0)
goto out;
ret = spp_exec_upload_mo(ctx, session_id,
@@ -1799,7 +2292,8 @@
if (strcasecmp(req_reason, "Subscription registration") == 0) {
ret = hs20_subscription_registration(ctx, realm, session_id,
- redirect_uri);
+ redirect_uri,
+ wifi_mac_addr);
hs20_eventlog_node(ctx, user, realm, session_id,
"subscription registration response",
ret);
@@ -1849,6 +2343,15 @@
goto out;
}
+ if (strcasecmp(req_reason, "Subscription provisioning") == 0) {
+ ret = hs20_sim_provisioning(ctx, user, realm, dmacc,
+ session_id);
+ hs20_eventlog_node(ctx, user, realm, session_id,
+ "subscription provisioning response",
+ ret);
+ goto out;
+ }
+
debug_print(ctx, 1, "Unsupported requestReason '%s' user '%s'",
req_reason, user);
out:
@@ -1891,6 +2394,8 @@
static int add_subscription(struct hs20_svc *ctx, const char *session_id)
{
char *user, *realm, *pw, *pw_mm, *pps, *str;
+ char *osu_user, *osu_password, *eap_method;
+ char *policy = NULL;
char *sql;
int ret = -1;
char *free_account;
@@ -1898,6 +2403,7 @@
char *type;
int cert = 0;
char *cert_pem, *fingerprint;
+ const char *method;
user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
@@ -1911,6 +2417,11 @@
if (type && strcmp(type, "cert") == 0)
cert = 1;
free(type);
+ osu_user = db_get_session_val(ctx, NULL, NULL, session_id, "osu_user");
+ osu_password = db_get_session_val(ctx, NULL, NULL, session_id,
+ "osu_password");
+ eap_method = db_get_session_val(ctx, NULL, NULL, session_id,
+ "eap_method");
if (!user || !realm || !pw) {
debug_print(ctx, 1, "Could not find session info from DB for "
@@ -1922,6 +2433,8 @@
free_acc = free_account && strcmp(free_account, user) == 0;
free(free_account);
+ policy = db_get_osu_config_val(ctx, realm, "sim_policy");
+
debug_print(ctx, 1,
"New subscription: user='%s' realm='%s' free_acc=%d",
user, realm, free_acc);
@@ -1948,13 +2461,23 @@
goto out;
}
- sql = sqlite3_mprintf("INSERT INTO users(identity,realm,phase2,"
- "methods,cert,cert_pem,machine_managed) VALUES "
- "(%Q,%Q,1,%Q,%Q,%Q,%d)",
- user, realm, cert ? "TLS" : "TTLS-MSCHAPV2",
+ str = db_get_session_val(ctx, NULL, NULL, session_id, "mac_addr");
+
+ if (eap_method && eap_method[0])
+ method = eap_method;
+ else
+ method = cert ? "TLS" : "TTLS-MSCHAPV2";
+ sql = sqlite3_mprintf("INSERT INTO users(identity,realm,phase2,methods,cert,cert_pem,machine_managed,mac_addr,osu_user,osu_password,policy) VALUES (%Q,%Q,%d,%Q,%Q,%Q,%d,%Q,%Q,%Q,%Q)",
+ user, realm, cert ? 0 : 1,
+ method,
fingerprint ? fingerprint : "",
cert_pem ? cert_pem : "",
- pw_mm && atoi(pw_mm) ? 1 : 0);
+ pw_mm && atoi(pw_mm) ? 1 : 0,
+ str ? str : "",
+ osu_user ? osu_user : "",
+ osu_password ? osu_password : "",
+ policy ? policy : "");
+ free(str);
if (sql == NULL)
goto out;
debug_print(ctx, 1, "DB: %s", sql);
@@ -1971,8 +2494,7 @@
else
ret = update_password(ctx, user, realm, pw, 0);
if (ret < 0) {
- sql = sqlite3_mprintf("DELETE FROM users WHERE identity=%Q AND "
- "realm=%Q AND phase2=1",
+ sql = sqlite3_mprintf("DELETE FROM users WHERE identity=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
user, realm);
if (sql) {
debug_print(ctx, 1, "DB: %s", sql);
@@ -1996,6 +2518,50 @@
free(str);
}
+ if (cert && user) {
+ const char *serialnum;
+
+ str = db_get_session_val(ctx, NULL, NULL, session_id,
+ "mac_addr");
+
+ if (os_strncmp(user, "cert-", 5) == 0)
+ serialnum = user + 5;
+ else
+ serialnum = "";
+ sql = sqlite3_mprintf("INSERT OR REPLACE INTO cert_enroll (mac_addr,user,realm,serialnum) VALUES(%Q,%Q,%Q,%Q)",
+ str ? str : "", user, realm ? realm : "",
+ serialnum);
+ free(str);
+ if (sql) {
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) !=
+ SQLITE_OK) {
+ debug_print(ctx, 1,
+ "Failed to add cert_enroll entry into sqlite database: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+ }
+ }
+
+ str = db_get_session_val(ctx, NULL, NULL, session_id,
+ "mobile_identifier_hash");
+ if (str) {
+ sql = sqlite3_mprintf("DELETE FROM sim_provisioning WHERE mobile_identifier_hash=%Q",
+ str);
+ if (sql) {
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) !=
+ SQLITE_OK) {
+ debug_print(ctx, 1,
+ "Failed to delete pending sim_provisioning entry: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+ }
+ os_free(str);
+ }
+
if (ret == 0) {
hs20_eventlog(ctx, user, realm, session_id,
"completed subscription registration", NULL);
@@ -2009,6 +2575,10 @@
free(pps);
free(cert_pem);
free(fingerprint);
+ free(osu_user);
+ free(osu_password);
+ free(eap_method);
+ os_free(policy);
return ret;
}
@@ -2035,11 +2605,11 @@
debug_print(ctx, 1, "sppUpdateResponse: sppStatus: %s sessionID: %s",
status, session_id);
- val = db_get_session_val(ctx, user, realm, session_id, "operation");
+ val = db_get_session_val(ctx, NULL, NULL, session_id, "operation");
if (!val) {
debug_print(ctx, 1,
- "No session active for user: %s sessionID: %s",
- user, session_id);
+ "No session active for sessionID: %s",
+ session_id);
oper = NO_OPERATION;
} else
oper = atoi(val);
@@ -2096,6 +2666,29 @@
session_id, "Updated user password "
"in database", NULL);
}
+ if (oper == CLEAR_REMEDIATION) {
+ debug_print(ctx, 1,
+ "Clear remediation requirement for user '%s' in DB",
+ user);
+ if (clear_remediation(ctx, user, realm, dmacc) < 0) {
+ debug_print(ctx, 1,
+ "Failed to clear remediation requirement for user '%s' in DB",
+ user);
+ ret = build_spp_exchange_complete(
+ ctx, session_id, "Error occurred",
+ "Other");
+ hs20_eventlog_node(ctx, user, realm,
+ session_id,
+ "Failed to update database",
+ ret);
+ db_remove_session(ctx, user, realm, session_id);
+ return ret;
+ }
+ hs20_eventlog(ctx, user, realm,
+ session_id,
+ "Cleared remediation requirement in database",
+ NULL);
+ }
if (oper == SUBSCRIPTION_REGISTRATION) {
if (add_subscription(ctx, session_id) < 0) {
debug_print(ctx, 1, "Failed to add "
@@ -2119,12 +2712,63 @@
"", dmacc);
free(val);
}
+ if (oper == POLICY_UPDATE)
+ db_update_val(ctx, user, realm, "polupd_done", "1",
+ dmacc);
+ if (oper == CERT_REENROLL) {
+ char *new_user;
+ char event[200];
+
+ new_user = db_get_session_val(ctx, NULL, NULL,
+ session_id, "user");
+ if (!new_user) {
+ debug_print(ctx, 1,
+ "Failed to find new user name (cert-serialnum)");
+ ret = build_spp_exchange_complete(
+ ctx, session_id, "Error occurred",
+ "Other");
+ hs20_eventlog_node(ctx, user, realm,
+ session_id,
+ "Failed to find new user name (cert reenroll)",
+ ret);
+ db_remove_session(ctx, NULL, NULL, session_id);
+ return ret;
+ }
+
+ debug_print(ctx, 1,
+ "Update certificate user entry to use the new serial number (old=%s new=%s)",
+ user, new_user);
+ os_snprintf(event, sizeof(event), "renamed user to: %s",
+ new_user);
+ hs20_eventlog(ctx, user, realm, session_id, event,
+ NULL);
+
+ if (db_update_val(ctx, user, realm, "identity",
+ new_user, 0) < 0 ||
+ db_update_val(ctx, new_user, realm, "remediation",
+ "", 0) < 0) {
+ debug_print(ctx, 1,
+ "Failed to update user name (cert-serialnum)");
+ ret = build_spp_exchange_complete(
+ ctx, session_id, "Error occurred",
+ "Other");
+ hs20_eventlog_node(ctx, user, realm,
+ session_id,
+ "Failed to update user name (cert reenroll)",
+ ret);
+ db_remove_session(ctx, NULL, NULL, session_id);
+ os_free(new_user);
+ return ret;
+ }
+
+ os_free(new_user);
+ }
ret = build_spp_exchange_complete(
ctx, session_id,
"Exchange complete, release TLS connection", NULL);
hs20_eventlog_node(ctx, user, realm, session_id,
"Exchange completed", ret);
- db_remove_session(ctx, user, realm, session_id);
+ db_remove_session(ctx, NULL, NULL, session_id);
return ret;
}
diff --git a/hs20/server/spp_server.h b/hs20/server/spp_server.h
index 7b27be3..421974c 100644
--- a/hs20/server/spp_server.h
+++ b/hs20/server/spp_server.h
@@ -16,6 +16,10 @@
FILE *debug_log;
sqlite3 *db;
const char *addr;
+ const char *test;
+ const char *imsi;
+ const char *eap_method;
+ const char *id_hash;
};
diff --git a/hs20/server/sql.txt b/hs20/server/sql.txt
index 6609538..2cc6ede 100644
--- a/hs20/server/sql.txt
+++ b/hs20/server/sql.txt
@@ -22,7 +22,13 @@
devinfo TEXT,
devdetail TEXT,
cert TEXT,
- cert_pem TEXT
+ cert_pem TEXT,
+ mac_addr TEXT,
+ osu_user TEXT,
+ osu_password TEXT,
+ eap_method TEXT,
+ mobile_identifier_hash TEXT,
+ test TEXT
);
CREATE index sessions_id_index ON sessions(id);
@@ -50,10 +56,53 @@
osu_password TEXT,
shared INTEGER,
cert TEXT,
- cert_pem TEXT
+ cert_pem TEXT,
+ t_c_timestamp INTEGER,
+ mac_addr TEXT,
+ last_msk TEXT,
+ polupd_done TEXT,
+ subrem TEXT
);
CREATE TABLE wildcards(
identity TEXT PRIMARY KEY,
methods TEXT
);
+
+CREATE TABLE authlog(
+ timestamp TEXT,
+ session TEXT,
+ nas_ip TEXT,
+ username TEXT,
+ note TEXT
+);
+
+CREATE TABLE pending_tc(
+ mac_addr TEXT PRIMARY KEY,
+ identity TEXT
+);
+
+CREATE TABLE current_sessions(
+ mac_addr TEXT PRIMARY KEY,
+ identity TEXT,
+ start_time TEXT,
+ nas TEXT,
+ hs20_t_c_filtering BOOLEAN,
+ waiting_coa_ack BOOLEAN,
+ coa_ack_received BOOLEAN
+);
+
+CREATE TABLE cert_enroll(
+ mac_addr TEXT PRIMARY KEY,
+ user TEXT,
+ realm TEXT,
+ serialnum TEXT
+);
+
+CREATE TABLE sim_provisioning(
+ mobile_identifier_hash TEXT PRIMARY KEY,
+ imsi TEXT,
+ mac_addr TEXT,
+ eap_method TEXT,
+ timestamp TEXT
+);
diff --git a/hs20/server/www/config.php b/hs20/server/www/config.php
index e3af435..4272b10 100644
--- a/hs20/server/www/config.php
+++ b/hs20/server/www/config.php
@@ -1,4 +1,7 @@
<?php
$osu_root = "/home/user/hs20-server";
$osu_db = "sqlite:$osu_root/AS/DB/eap_user.db";
+$t_c_file = "$osu_root/terms-and-conditions";
+$t_c_timestamp = 123456789;
+$hostapd_ctrl = "udg:///home/user/hs20-server/AS/ctrl/as"
?>
diff --git a/hs20/server/www/est.php b/hs20/server/www/est.php
index a45648b..b7fb260 100644
--- a/hs20/server/www/est.php
+++ b/hs20/server/www/est.php
@@ -2,7 +2,7 @@
require('config.php');
-$params = split("/", $_SERVER["PATH_INFO"], 3);
+$params = explode("/", $_SERVER["PATH_INFO"], 3);
$realm = $params[1];
$cmd = $params[2];
$method = $_SERVER["REQUEST_METHOD"];
@@ -10,6 +10,12 @@
unset($user);
unset($rowid);
+$db = new PDO($osu_db);
+if (!$db) {
+ error_log("EST: Could not access database");
+ die("Could not access database");
+}
+
if (!empty($_SERVER['PHP_AUTH_DIGEST'])) {
$needed = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1,
'uri'=>1, 'response'=>1);
@@ -31,12 +37,6 @@
die('Authentication failed');
}
- $db = new PDO($osu_db);
- if (!$db) {
- error_log("EST: Could not access database");
- die("Could not access database");
- }
-
$sql = "SELECT rowid,password,operation FROM sessions " .
"WHERE user='$user' AND realm='$realm'";
$q = $db->query($sql);
@@ -70,6 +70,29 @@
error_log("EST: Incorrect authentication response for user=$user realm=$realm");
die('Authentication failed');
}
+} else if (isset($_SERVER["SSL_CLIENT_VERIFY"]) &&
+ $_SERVER["SSL_CLIENT_VERIFY"] == "SUCCESS" &&
+ isset($_SERVER["SSL_CLIENT_M_SERIAL"])) {
+ $user = "cert-" . $_SERVER["SSL_CLIENT_M_SERIAL"];
+ $sql = "SELECT rowid,password,operation FROM sessions " .
+ "WHERE user='$user' AND realm='$realm'";
+ $q = $db->query($sql);
+ if (!$q) {
+ error_log("EST: Session not found for user=$user realm=$realm");
+ die("Session not found");
+ }
+ $row = $q->fetch();
+ if (!$row) {
+ error_log("EST: Session fetch failed for user=$user realm=$realm");
+ die('Session not found');
+ }
+ $rowid = $row['rowid'];
+
+ $oper = $row['operation'];
+ if ($oper != '10') {
+ error_log("EST: Unexpected operation $oper for user=$user realm=$realm");
+ die("Session not found");
+ }
}
@@ -92,14 +115,24 @@
header("Content-Type: application/csrattrs");
readfile("$osu_root/est/est-attrs.b64");
error_log("EST: csrattrs");
-} else if ($method == "POST" && $cmd == "simpleenroll") {
- if (!isset($user) || strlen($user) == 0) {
+} else if ($method == "POST" &&
+ ($cmd == "simpleenroll" || $cmd == "simplereenroll")) {
+ $reenroll = $cmd == "simplereenroll";
+ if (!$reenroll && (!isset($user) || strlen($user) == 0)) {
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate: Digest realm="'.$realm.
'",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
error_log("EST: simpleenroll - require authentication");
die('Authentication required');
}
+ if ($reenroll &&
+ (!isset($user) ||
+ !isset($_SERVER["SSL_CLIENT_VERIFY"]) ||
+ $_SERVER["SSL_CLIENT_VERIFY"] != "SUCCESS")) {
+ header('HTTP/1.1 403 Forbidden');
+ error_log("EST: simplereenroll - require certificate authentication");
+ die('Authentication required');
+ }
if (!isset($_SERVER["CONTENT_TYPE"])) {
error_log("EST: simpleenroll without Content-Type");
die("Missing Content-Type");
@@ -167,6 +200,7 @@
}
$der = file_get_contents($cert_der);
$fingerprint = hash("sha256", $der);
+ error_log("EST: sha256(DER cert): $fingerprint");
$pkcs7 = "$cadir/tmp/est-client.pkcs7";
if (file_exists($pkcs7))
diff --git a/hs20/server/www/remediation-pw.php b/hs20/server/www/remediation-pw.php
new file mode 100644
index 0000000..76fdccb
--- /dev/null
+++ b/hs20/server/www/remediation-pw.php
@@ -0,0 +1,41 @@
+<?php
+
+require('config.php');
+
+$db = new PDO($osu_db);
+if (!$db) {
+ die($sqliteerror);
+}
+
+if (isset($_POST["id"]))
+ $id = preg_replace("/[^a-fA-F0-9]/", "", $_POST["id"]);
+else
+ die("Missing session id");
+
+$pw = $_POST["password"];
+if (strlen($id) < 32 || !isset($pw)) {
+ die("Invalid POST data");
+}
+
+$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
+if ($row == false) {
+ die("Session not found");
+}
+$user = $row['user'];
+$realm = $row['realm'];
+
+$uri = $row['redirect_uri'];
+$rowid = $row['rowid'];
+
+if (!$db->exec("UPDATE sessions SET password='$pw' WHERE rowid=$rowid")) {
+ die("Failed to update session database");
+}
+
+$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
+ "VALUES ('$user', '$realm', '$id', " .
+ "strftime('%Y-%m-%d %H:%M:%f','now'), " .
+ "'completed user input response for subscription remediation')");
+
+header("Location: $uri", true, 302);
+
+?>
diff --git a/hs20/server/www/remediation.php b/hs20/server/www/remediation.php
index 392a7bd..3628065 100644
--- a/hs20/server/www/remediation.php
+++ b/hs20/server/www/remediation.php
@@ -6,13 +6,50 @@
<?php
-echo "SessionID: " . $_GET["session_id"] . "<br>\n";
+require('config.php');
-echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user subscription remediation</a><br>\n";
+$db = new PDO($osu_db);
+if (!$db) {
+ die($sqliteerror);
+}
+
+if (isset($_GET["session_id"]))
+ $id = preg_replace("/[^a-fA-F0-9]/", "", $_GET["session_id"]);
+else
+ $id = 0;
+echo "SessionID: " . $id . "<br>\n";
+
+$row = $db->query("SELECT * FROM sessions WHERE id='$id'")->fetch();
+if ($row == false) {
+ die("Session not found");
+}
+
+$username = $row['user'];
+echo "User: " . $username . "@" . $row['realm'] . "<br>\n";
+
+$user = $db->query("SELECT machine_managed,methods FROM users WHERE identity='$username'")->fetch();
+if ($user == false) {
+ die("User not found");
+}
+
+echo "<hr><br>\n";
+
+$cert = $user['methods'] == "TLS" || strncmp($username, "cert-", 5) == 0;
+
+if ($cert) {
+ echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user subscription remediation</a><br>\n";
+} else if ($user['machine_managed'] == "1") {
+ echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user subscription remediation</a><br>\n";
+ echo "This will provide a new machine-generated password.<br>\n";
+} else {
+ echo "<form action=\"remediation-pw.php\" method=\"POST\">\n";
+ echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n";
+ echo "New password: <input type=\"password\" name=\"password\"><br>\n";
+ echo "<input type=\"submit\" value=\"Change password\">\n";
+ echo "</form>\n";
+}
?>
-This will provide a new machine-generated password.
-
</body>
</html>
diff --git a/hs20/server/www/signup.php b/hs20/server/www/signup.php
index aeb2f68..80a9d40 100644
--- a/hs20/server/www/signup.php
+++ b/hs20/server/www/signup.php
@@ -15,19 +15,30 @@
die($sqliteerror);
}
-$row = $db->query("SELECT realm FROM sessions WHERE id='$id'")->fetch();
+$row = $db->query("SELECT realm,test FROM sessions WHERE id='$id'")->fetch();
if ($row == false) {
die("Session not found for id: $id");
}
$realm = $row['realm'];
+$test = $row['test'];
+
+if (strlen($test) > 0) {
+ echo "<p style=\"color:#FF0000\">Special test functionality: $test</red></big></p>\n";
+}
echo "<h3>Sign up for a subscription - $realm</h3>\n";
+echo "<p>This page can be used to select between three different types of subscriptions for testing purposes.</p>\n";
+
+echo "<h4>Option 1 - shared free access credential</h4>\n";
+
$row = $db->query("SELECT value FROM osu_config WHERE realm='$realm' AND field='free_account'")->fetch();
if ($row && strlen($row['value']) > 0) {
echo "<p><a href=\"free.php?session_id=$id\">Sign up for free access</a></p>\n";
}
+echo "<h4>Option 2 - username/password credential</h4>\n";
+
echo "<form action=\"add-mo.php\" method=\"POST\">\n";
echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n";
?>
@@ -39,6 +50,8 @@
</form>
<?php
+echo "<h4>Option 3 - client certificate credential</h4>\n";
+
echo "<p><a href=\"cert-enroll.php?id=$id\">Enroll a client certificate</a></p>\n"
?>
diff --git a/hs20/server/www/spp.php b/hs20/server/www/spp.php
index 002d028..c56d3d6 100644
--- a/hs20/server/www/spp.php
+++ b/hs20/server/www/spp.php
@@ -20,6 +20,11 @@
die("Realm not specified");
}
+if (isset($_GET["test"]))
+ $test = PREG_REPLACE("/[^0-9a-zA-Z\_\-]/i", '', $_GET["test"]);
+else
+ $test = "";
+
unset($user);
putenv("HS20CERT");
@@ -80,6 +85,40 @@
isset($_SERVER["SSL_CLIENT_M_SERIAL"])) {
$user = "cert-" . $_SERVER["SSL_CLIENT_M_SERIAL"];
putenv("HS20CERT=yes");
+} else if (isset($_GET["hotspot2dot0-mobile-identifier-hash"])) {
+ $id_hash = $_GET["hotspot2dot0-mobile-identifier-hash"];
+ $id_hash = PREG_REPLACE("/[^0-9a-h]/i", '', $id_hash);
+
+ $db = new PDO($osu_db);
+ if (!$db) {
+ error_log("spp.php - Could not access database");
+ die("Could not access database");
+ }
+
+ $row = $db->query("SELECT * FROM sim_provisioning " .
+ "WHERE mobile_identifier_hash='$id_hash'")->fetch();
+ if (!$row) {
+ error_log("spp.php - SIM provisioning failed - mobile_identifier_hash not found");
+ die('SIM provisioning failed - mobile_identifier_hash not found');
+ }
+
+ $imsi = $row['imsi'];
+ $mac_addr = $row['mac_addr'];
+ $eap_method = $row['eap_method'];
+
+ $row = $db->query("SELECT COUNT(*) FROM osu_config " .
+ "WHERE realm='$realm'")->fetch();
+ if (!$row || intval($row[0]) < 1) {
+ error_log("spp.php - SIM provisioning failed - realm $realm not found");
+ die('SIM provisioning failed');
+ }
+
+ error_log("spp.php - SIM provisioning for IMSI $imsi");
+ putenv("HS20SIMPROV=yes");
+ putenv("HS20IMSI=$imsi");
+ putenv("HS20MACADDR=$mac_addr");
+ putenv("HS20EAPMETHOD=$eap_method");
+ putenv("HS20IDHASH=$id_hash");
} else if (!isset($_SERVER["PATH_INFO"]) ||
$_SERVER["PATH_INFO"] != "/signup") {
header('HTTP/1.1 401 Unauthorized');
@@ -100,6 +139,7 @@
putenv("HS20POST=$postdata");
$addr = $_SERVER["REMOTE_ADDR"];
putenv("HS20ADDR=$addr");
+putenv("HS20TEST=$test");
$last = exec("$osu_root/spp/hs20_spp_server -r$osu_root -f/tmp/hs20_spp_server.log", $output, $ret);
diff --git a/hs20/server/www/terms.php b/hs20/server/www/terms.php
new file mode 100644
index 0000000..acba23e
--- /dev/null
+++ b/hs20/server/www/terms.php
@@ -0,0 +1,87 @@
+<?php
+
+require('config.php');
+
+function print_header()
+{
+ echo "<html>\n";
+ echo "<head><title>HS 2.0 Terms and Conditions</title></head>\n";
+ echo "<body>\n";
+}
+
+$db = new PDO($osu_db);
+if (!$db) {
+ die($sqliteerror);
+}
+
+if (!isset($_GET["addr"])) {
+ die("Missing addr parameter");
+}
+$addr = $_GET["addr"];
+
+$accept = isset($_GET["accept"]) && $_GET["accept"] == "yes";
+
+$res = $db->prepare("SELECT identity FROM pending_tc WHERE mac_addr=?");
+$res->execute(array($addr));
+$row = $res->fetch();
+if (!$row) {
+ die("No pending session for the specified MAC address");
+}
+$identity = $row[0];
+
+if (!$accept) {
+ print_header();
+
+ echo "<p>Accept the following terms and conditions by clicking here: <a href=\"terms.php?addr=$addr&accept=yes\">Accept</a></p>\n<hr>\n";
+ readfile($t_c_file);
+} else {
+ $res = $db->prepare("UPDATE users SET t_c_timestamp=? WHERE identity=?");
+ if (!$res->execute(array($t_c_timestamp, $identity))) {
+ die("Failed to update user account.");
+ }
+
+ $res = $db->prepare("DELETE FROM pending_tc WHERE mac_addr=?");
+ $res->execute(array($addr));
+
+ $fp = fsockopen($hostapd_ctrl);
+ if (!$fp) {
+ die("Could not connect to hostapd(AS)");
+ }
+
+ fwrite($fp, "DAC_REQUEST coa $addr t_c_clear");
+ fclose($fp);
+
+ $waiting = true;
+ $ack = false;
+ for ($i = 1; $i <= 10; $i++) {
+ $res = $db->prepare("SELECT waiting_coa_ack,coa_ack_received FROM current_sessions WHERE mac_addr=?");
+ $res->execute(array($addr));
+ $row = $res->fetch();
+ if (!$row) {
+ die("No current session for the specified MAC address");
+ }
+ if (strlen($row[0]) > 0)
+ $waiting = $row[0] == 1;
+ if (strlen($row[1]) > 0)
+ $ack = $row[1] == 1;
+ $res->closeCursor();
+ if (!$waiting)
+ break;
+ sleep(1);
+ }
+ if ($ack) {
+ header('X-WFA-Hotspot20-Filtering: removed');
+ print_header();
+ echo "<p>Terms and conditions were accepted.</p>\n";
+
+ echo "<P>Filtering disabled.</P>\n";
+ } else {
+ print_header();
+ echo "<P>Failed to disable filtering.</P>\n";
+ }
+}
+
+?>
+
+</body>
+</html>
diff --git a/hs20/server/www/users.php b/hs20/server/www/users.php
index c340a33..2bd5552 100644
--- a/hs20/server/www/users.php
+++ b/hs20/server/www/users.php
@@ -69,6 +69,9 @@
if ($cmd == 'subrem-add-machine' && $id > 0) {
$db->exec("UPDATE users SET remediation='machine' WHERE rowid=$id");
}
+if ($cmd == 'subrem-add-reenroll' && $id > 0) {
+ $db->exec("UPDATE users SET remediation='reenroll' WHERE rowid=$id");
+}
if ($cmd == 'subrem-add-policy' && $id > 0) {
$db->exec("UPDATE users SET remediation='policy' WHERE rowid=$id");
}
@@ -107,6 +110,10 @@
$db->exec("UPDATE users SET osu_user='$osu_user', osu_password='$osu_password' WHERE rowid=$id");
}
+if ($cmd == 'clear-t-c' && $id > 0) {
+ $db->exec("UPDATE users SET t_c_timestamp=NULL WHERE rowid=$id");
+}
+
$dump = 0;
if ($id > 0) {
@@ -168,6 +175,10 @@
$row['rowid'] . "\">add:user</a>]";
echo " [<a href=\"users.php?cmd=subrem-add-machine&id=" .
$row['rowid'] . "\">add:machine</a>]";
+ if ($row['methods'] == 'TLS') {
+ echo " [<a href=\"users.php?cmd=subrem-add-reenroll&id=" .
+ $row['rowid'] . "\">add:reenroll</a>]";
+ }
echo " [<a href=\"users.php?cmd=subrem-add-policy&id=" .
$row['rowid'] . "\">add:policy</a>]";
echo " [<a href=\"users.php?cmd=subrem-add-free&id=" .
@@ -181,12 +192,18 @@
} else if ($rem == "free") {
echo "Free [<a href=\"users.php?cmd=subrem-clear&id=" .
$row['rowid'] . "\">clear</a>]";
+} else if ($rem == "reenroll") {
+ echo "Reenroll [<a href=\"users.php?cmd=subrem-clear&id=" .
+ $row['rowid'] . "\">clear</a>]";
} else {
echo "Machine [<a href=\"users.php?cmd=subrem-clear&id=" .
$row['rowid'] . "\">clear</a>]";
}
echo "<br>\n";
+if (strncmp($row['identity'], "cert-", 5) != 0)
+ echo "Machine managed: " . ($row['machine_managed'] == "1" ? "TRUE" : "FALSE") . "<br>\n";
+
echo "<form>Policy: <select name=\"policy\" " .
"onChange=\"window.location='users.php?cmd=policy&id=" .
$row['rowid'] . "&policy=' + this.value;\">\n";
@@ -234,6 +251,13 @@
echo "<input type=\"submit\" value=\"Set OSU credentials\">\n";
echo "</form>\n";
+if (strlen($row['t_c_timestamp']) > 0) {
+ echo "<br>\n";
+ echo "<a href=\"users.php?cmd=clear-t-c&id=" .
+ $row['rowid'] .
+ "\">Clear Terms and Conditions acceptance</a><br>\n";
+}
+
echo "<hr>\n";
$user = $row['identity'];
@@ -302,10 +326,10 @@
echo "[<a href=\"users.php?cmd=eventlog&limit=50\">Eventlog</a>] ";
echo "<br>\n";
-echo "<table border=1>\n";
-echo "<tr><th>User<th>Realm<th>Remediation<th>Policy<th>Account type<th>Phase 2 method(s)<th>DevId\n";
+echo "<table border=1 cellspacing=0 cellpadding=0>\n";
+echo "<tr><th>User<th>Realm<th><small>Remediation</small><th>Policy<th><small>Account type</small><th><small>Phase 2 method(s)</small><th>DevId<th>MAC Address<th>T&C\n";
-$res = $db->query('SELECT rowid,* FROM users WHERE phase2=1');
+$res = $db->query('SELECT rowid,* FROM users WHERE (phase2=1 OR methods=\'TLS\') ORDER BY identity');
foreach ($res as $row) {
echo "<tr><td><a href=\"users.php?id=" . $row['rowid'] . "\"> " .
$row['identity'] . " </a>";
@@ -313,13 +337,15 @@
$rem = $row['remediation'];
echo "<td>";
if ($rem == "") {
- echo "Not required";
+ echo "-";
} else if ($rem == "user") {
echo "User";
} else if ($rem == "policy") {
echo "Policy";
} else if ($rem == "free") {
echo "Free";
+ } else if ($rem == "reenroll") {
+ echo "Reenroll";
} else {
echo "Machine";
}
@@ -328,16 +354,18 @@
echo "<td>shared";
else
echo "<td>default";
- echo "<td>" . $row['methods'];
+ echo "<td><small>" . $row['methods'] . "</small>";
echo "<td>";
$xml = xml_parser_create();
xml_parse_into_struct($xml, $row['devinfo'], $devinfo);
foreach($devinfo as $k) {
if ($k['tag'] == 'DEVID') {
- echo $k['value'];
+ echo "<small>" . $k['value'] . "</small>";
break;
}
}
+ echo "<td><small>" . $row['mac_addr'] . "</small>";
+ echo "<td><small>" . $row['t_c_timestamp'] . "</small>";
echo "\n";
}
echo "</table>\n";
diff --git a/src/ap/Makefile b/src/ap/Makefile
index b8c167c..9b07ee1 100644
--- a/src/ap/Makefile
+++ b/src/ap/Makefile
@@ -10,6 +10,7 @@
CFLAGS += -DHOSTAPD
CFLAGS += -DNEED_AP_MLME
+CFLAGS += -DCONFIG_ETH_P_OUI
CFLAGS += -DCONFIG_HS20
CFLAGS += -DCONFIG_INTERWORKING
CFLAGS += -DCONFIG_IEEE80211R
@@ -34,6 +35,7 @@
dhcp_snoop.o \
drv_callbacks.o \
eap_user_db.o \
+ eth_p_oui.o \
gas_serv.o \
hostapd.o \
hs20.o \
diff --git a/src/ap/acs.c b/src/ap/acs.c
index aa59058..3b45075 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -13,6 +13,7 @@
#include "utils/common.h"
#include "utils/list.h"
#include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
#include "common/wpa_ctrl.h"
#include "drivers/driver.h"
#include "hostapd.h"
@@ -314,7 +315,7 @@
/* TODO: figure out the best multiplier for noise floor base */
factor = pow(10, survey->nf / 5.0L) +
- (busy / total) *
+ (total ? (busy / total) : 0) *
pow(2, pow(10, (long double) survey->nf / 10.0L) -
pow(10, (long double) min_nf / 10.0L));
@@ -362,7 +363,7 @@
}
-static int acs_usable_ht40_chan(struct hostapd_channel_data *chan)
+static int acs_usable_ht40_chan(const struct hostapd_channel_data *chan)
{
const int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149,
157, 184, 192 };
@@ -376,7 +377,7 @@
}
-static int acs_usable_vht80_chan(struct hostapd_channel_data *chan)
+static int acs_usable_vht80_chan(const struct hostapd_channel_data *chan)
{
const int allowed[] = { 36, 52, 100, 116, 132, 149 };
unsigned int i;
@@ -389,6 +390,19 @@
}
+static int acs_usable_vht160_chan(const struct hostapd_channel_data *chan)
+{
+ const int allowed[] = { 36, 100 };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(allowed); i++)
+ if (chan->chan == allowed[i])
+ return 1;
+
+ return 0;
+}
+
+
static int acs_survey_is_sufficient(struct freq_survey *survey)
{
if (!(survey->filled & SURVEY_HAS_NF)) {
@@ -565,6 +579,7 @@
long double factor, ideal_factor = 0;
int i, j;
int n_chans = 1;
+ u32 bw;
unsigned int k;
/* TODO: HT40- support */
@@ -579,16 +594,23 @@
iface->conf->secondary_channel)
n_chans = 2;
- if (iface->conf->ieee80211ac &&
- iface->conf->vht_oper_chwidth == 1)
- n_chans = 4;
+ if (iface->conf->ieee80211ac) {
+ switch (iface->conf->vht_oper_chwidth) {
+ case VHT_CHANWIDTH_80MHZ:
+ n_chans = 4;
+ break;
+ case VHT_CHANWIDTH_160MHZ:
+ n_chans = 8;
+ break;
+ }
+ }
- /* TODO: VHT80+80, VHT160. Update acs_adjust_vht_center_freq() too. */
+ bw = num_chan_to_bw(n_chans);
- wpa_printf(MSG_DEBUG, "ACS: Survey analysis for selected bandwidth %d MHz",
- n_chans == 1 ? 20 :
- n_chans == 2 ? 40 :
- 80);
+ /* TODO: VHT80+80. Update acs_adjust_vht_center_freq() too. */
+
+ wpa_printf(MSG_DEBUG,
+ "ACS: Survey analysis for selected bandwidth %d MHz", bw);
for (i = 0; i < iface->current_mode->num_channels; i++) {
double total_weight;
@@ -596,12 +618,23 @@
chan = &iface->current_mode->channels[i];
- if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ /* Since in the current ACS implementation the first channel is
+ * always a primary channel, skip channels not available as
+ * primary until more sophisticated channel selection is
+ * implemented. */
+ if (!chan_pri_allowed(chan))
continue;
if (!is_in_chanlist(iface, chan))
continue;
+ if (!chan_bw_allowed(chan, bw, 1, 1)) {
+ wpa_printf(MSG_DEBUG,
+ "ACS: Channel %d: BW %u is not supported",
+ chan->chan, bw);
+ continue;
+ }
+
/* HT40 on 5 GHz has a limited set of primary channels as per
* 11n Annex J */
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
@@ -614,12 +647,24 @@
}
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
- iface->conf->ieee80211ac &&
- iface->conf->vht_oper_chwidth == 1 &&
- !acs_usable_vht80_chan(chan)) {
- wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for VHT80",
- chan->chan);
- continue;
+ iface->conf->ieee80211ac) {
+ if (iface->conf->vht_oper_chwidth ==
+ VHT_CHANWIDTH_80MHZ &&
+ !acs_usable_vht80_chan(chan)) {
+ wpa_printf(MSG_DEBUG,
+ "ACS: Channel %d: not allowed as primary channel for VHT80",
+ chan->chan);
+ continue;
+ }
+
+ if (iface->conf->vht_oper_chwidth ==
+ VHT_CHANWIDTH_160MHZ &&
+ !acs_usable_vht160_chan(chan)) {
+ wpa_printf(MSG_DEBUG,
+ "ACS: Channel %d: not allowed as primary channel for VHT160",
+ chan->chan);
+ continue;
+ }
}
factor = 0;
@@ -632,6 +677,13 @@
if (!adj_chan)
break;
+ if (!chan_bw_allowed(adj_chan, bw, 1, 0)) {
+ wpa_printf(MSG_DEBUG,
+ "ACS: PRI Channel %d: secondary channel %d BW %u is not supported",
+ chan->chan, adj_chan->chan, bw);
+ break;
+ }
+
if (acs_usable_chan(adj_chan)) {
factor += adj_chan->interference_factor;
total_weight += 1;
@@ -744,10 +796,14 @@
case VHT_CHANWIDTH_80MHZ:
offset = 6;
break;
+ case VHT_CHANWIDTH_160MHZ:
+ offset = 14;
+ break;
default:
/* TODO: How can this be calculated? Adjust
* acs_find_ideal_chan() */
- wpa_printf(MSG_INFO, "ACS: Only VHT20/40/80 is supported now");
+ wpa_printf(MSG_INFO,
+ "ACS: Only VHT20/40/80/160 is supported now");
return;
}
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 07310f9..e640e99 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -10,6 +10,7 @@
#include "utils/common.h"
#include "crypto/sha1.h"
+#include "crypto/tls.h"
#include "radius/radius_client.h"
#include "common/ieee802_11_defs.h"
#include "common/eapol_common.h"
@@ -103,11 +104,13 @@
bss->rkh_neg_timeout = 60;
bss->rkh_pull_timeout = 1000;
bss->rkh_pull_retries = 4;
+ bss->r0_key_lifetime = 1209600;
#endif /* CONFIG_IEEE80211R_AP */
bss->radius_das_time_window = 300;
bss->sae_anti_clogging_threshold = 5;
+ bss->sae_sync = 5;
bss->gas_frag_limit = 1400;
@@ -123,6 +126,20 @@
#ifdef CONFIG_MBO
bss->mbo_cell_data_conn_pref = -1;
#endif /* CONFIG_MBO */
+
+ /* Disable TLS v1.3 by default for now to avoid interoperability issue.
+ * This can be enabled by default once the implementation has been fully
+ * completed and tested with other implementations. */
+ bss->tls_flags = TLS_CONN_DISABLE_TLSv1_3;
+
+ bss->send_probe_response = 1;
+
+#ifdef CONFIG_HS20
+ bss->hs20_release = (HS20_VERSION >> 4) + 1;
+#endif /* CONFIG_HS20 */
+
+ /* Default to strict CRL checking. */
+ bss->check_crl_strict = 1;
}
@@ -183,9 +200,8 @@
conf->num_bss = 1;
conf->beacon_int = 100;
- conf->rts_threshold = -1; /* use driver default: 2347 */
- conf->fragm_threshold = -1; /* user driver default: 2346 */
- conf->send_probe_response = 1;
+ conf->rts_threshold = -2; /* use driver default: 2347 */
+ conf->fragm_threshold = -2; /* user driver default: 2346 */
/* Set to invalid value means do not add Power Constraint IE */
conf->local_pwr_constraint = -1;
@@ -225,6 +241,9 @@
* environments for the current frequency band in the country. */
conf->country[2] = ' ';
+ conf->rssi_reject_assoc_rssi = 0;
+ conf->rssi_reject_assoc_timeout = 30;
+
return conf;
}
@@ -240,6 +259,12 @@
{
FILE *f;
char buf[128], *pos;
+ const char *keyid;
+ char *context;
+ char *context2;
+ char *token;
+ char *name;
+ char *value;
int line = 0, ret = 0, len, ok;
u8 addr[ETH_ALEN];
struct hostapd_wpa_psk *psk;
@@ -254,6 +279,8 @@
}
while (fgets(buf, sizeof(buf), f)) {
+ int vlan_id = 0;
+
line++;
if (buf[0] == '#')
@@ -269,9 +296,39 @@
if (buf[0] == '\0')
continue;
- if (hwaddr_aton(buf, addr)) {
+ context = NULL;
+ keyid = NULL;
+ while ((token = str_token(buf, " ", &context))) {
+ if (!os_strchr(token, '='))
+ break;
+ context2 = NULL;
+ name = str_token(token, "=", &context2);
+ if (!name)
+ break;
+ value = str_token(token, "", &context2);
+ if (!value)
+ value = "";
+ if (!os_strcmp(name, "keyid")) {
+ keyid = value;
+ } else if (!os_strcmp(name, "vlanid")) {
+ vlan_id = atoi(value);
+ } else {
+ wpa_printf(MSG_ERROR,
+ "Unrecognized '%s=%s' on line %d in '%s'",
+ name, value, line, fname);
+ ret = -1;
+ break;
+ }
+ }
+
+ if (ret == -1)
+ break;
+
+ if (!token)
+ token = "";
+ if (hwaddr_aton(token, addr)) {
wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on "
- "line %d in '%s'", buf, line, fname);
+ "line %d in '%s'", token, line, fname);
ret = -1;
break;
}
@@ -282,20 +339,20 @@
ret = -1;
break;
}
+ psk->vlan_id = vlan_id;
if (is_zero_ether_addr(addr))
psk->group = 1;
else
os_memcpy(psk->addr, addr, ETH_ALEN);
- pos = buf + 17;
- if (*pos == '\0') {
+ pos = str_token(buf, "", &context);
+ if (!pos) {
wpa_printf(MSG_ERROR, "No PSK on line %d in '%s'",
line, fname);
os_free(psk);
ret = -1;
break;
}
- pos++;
ok = 0;
len = os_strlen(pos);
@@ -314,6 +371,18 @@
break;
}
+ if (keyid) {
+ len = os_strlcpy(psk->keyid, keyid, sizeof(psk->keyid));
+ if ((size_t) len >= sizeof(psk->keyid)) {
+ wpa_printf(MSG_ERROR,
+ "PSK keyid too long on line %d in '%s'",
+ line, fname);
+ os_free(psk);
+ ret = -1;
+ break;
+ }
+ }
+
psk->next = ssid->wpa_psk;
ssid->wpa_psk = psk;
}
@@ -407,6 +476,7 @@
hostapd_config_free_radius_attr(user->accept_attr);
os_free(user->identity);
bin_clear_free(user->password, user->password_len);
+ bin_clear_free(user->salt, user->salt_len);
os_free(user);
}
@@ -473,6 +543,22 @@
}
+static void hostapd_config_free_sae_passwords(struct hostapd_bss_config *conf)
+{
+ struct sae_password_entry *pw, *tmp;
+
+ pw = conf->sae_passwords;
+ conf->sae_passwords = NULL;
+ while (pw) {
+ tmp = pw;
+ pw = pw->next;
+ str_clear_free(tmp->password);
+ os_free(tmp->identifier);
+ os_free(tmp);
+ }
+}
+
+
void hostapd_config_free_bss(struct hostapd_bss_config *conf)
{
if (conf == NULL)
@@ -509,10 +595,12 @@
os_free(conf->server_cert);
os_free(conf->private_key);
os_free(conf->private_key_passwd);
+ os_free(conf->check_cert_subject);
os_free(conf->ocsp_stapling_response);
os_free(conf->ocsp_stapling_response_multi);
os_free(conf->dh_file);
os_free(conf->openssl_ciphers);
+ os_free(conf->openssl_ecdh_curves);
os_free(conf->pac_opaque_encr_key);
os_free(conf->eap_fast_a_id);
os_free(conf->eap_fast_a_id_info);
@@ -557,6 +645,8 @@
os_free(conf->ap_pin);
os_free(conf->extra_cred);
os_free(conf->ap_settings);
+ hostapd_config_clear_wpa_psk(&conf->multi_ap_backhaul_ssid.wpa_psk);
+ str_clear_free(conf->multi_ap_backhaul_ssid.wpa_passphrase);
os_free(conf->upnp_iface);
os_free(conf->friendly_name);
os_free(conf->manufacturer_url);
@@ -576,6 +666,7 @@
os_free(conf->roaming_consortium);
os_free(conf->venue_name);
+ os_free(conf->venue_url);
os_free(conf->nai_realm_data);
os_free(conf->network_auth_type);
os_free(conf->anqp_3gpp_cell_net);
@@ -605,11 +696,22 @@
os_free(p->icons[j]);
os_free(p->icons);
os_free(p->osu_nai);
+ os_free(p->osu_nai2);
os_free(p->service_desc);
}
os_free(conf->hs20_osu_providers);
}
+ if (conf->hs20_operator_icon) {
+ size_t i;
+
+ for (i = 0; i < conf->hs20_operator_icon_count; i++)
+ os_free(conf->hs20_operator_icon[i]);
+ os_free(conf->hs20_operator_icon);
+ }
os_free(conf->subscr_remediation_url);
+ os_free(conf->hs20_sim_provisioning_url);
+ os_free(conf->t_c_filename);
+ os_free(conf->t_c_server_url);
#endif /* CONFIG_HS20 */
wpabuf_free(conf->vendor_elements);
@@ -640,7 +742,7 @@
wpabuf_free(conf->dpp_csign);
#endif /* CONFIG_DPP */
- os_free(conf->sae_password);
+ hostapd_config_free_sae_passwords(conf);
os_free(conf);
}
@@ -766,11 +868,14 @@
const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
const u8 *addr, const u8 *p2p_dev_addr,
- const u8 *prev_psk)
+ const u8 *prev_psk, int *vlan_id)
{
struct hostapd_wpa_psk *psk;
int next_ok = prev_psk == NULL;
+ if (vlan_id)
+ *vlan_id = 0;
+
if (p2p_dev_addr && !is_zero_ether_addr(p2p_dev_addr)) {
wpa_printf(MSG_DEBUG, "Searching a PSK for " MACSTR
" p2p_dev_addr=" MACSTR " prev_psk=%p",
@@ -788,8 +893,11 @@
(addr && os_memcmp(psk->addr, addr, ETH_ALEN) == 0) ||
(!addr && p2p_dev_addr &&
os_memcmp(psk->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) ==
- 0)))
+ 0))) {
+ if (vlan_id)
+ *vlan_id = psk->vlan_id;
return psk->psk;
+ }
if (psk->psk == prev_psk)
next_ok = 1;
@@ -936,7 +1044,9 @@
if (full_config && bss->wps_state && bss->wpa &&
(!(bss->wpa & 2) ||
- !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) {
+ !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
+ WPA_CIPHER_CCMP_256 |
+ WPA_CIPHER_GCMP_256)))) {
wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
"WPA2/CCMP/GCMP forced WPS to be disabled");
bss->wps_state = 0;
@@ -965,6 +1075,15 @@
}
#endif /* CONFIG_MBO */
+#ifdef CONFIG_OCV
+ if (full_config && bss->ieee80211w == NO_MGMT_FRAME_PROTECTION &&
+ bss->ocv) {
+ wpa_printf(MSG_ERROR,
+ "OCV: PMF needs to be enabled whenever using OCV");
+ return -1;
+ }
+#endif /* CONFIG_OCV */
+
return 0;
}
@@ -1046,8 +1165,12 @@
if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
bss->rsn_pairwise = bss->wpa_pairwise;
- bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
- bss->rsn_pairwise);
+ if (bss->group_cipher)
+ bss->wpa_group = bss->group_cipher;
+ else
+ bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa,
+ bss->wpa_pairwise,
+ bss->rsn_pairwise);
if (!bss->wpa_group_rekey_set)
bss->wpa_group_rekey = bss->wpa_group == WPA_CIPHER_TKIP ?
600 : 86400;
@@ -1104,3 +1227,26 @@
}
}
}
+
+
+int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf)
+{
+ int with_id = 0, without_id = 0;
+ struct sae_password_entry *pw;
+
+ if (conf->ssid.wpa_passphrase)
+ without_id = 1;
+
+ for (pw = conf->sae_passwords; pw; pw = pw->next) {
+ if (pw->identifier)
+ with_id = 1;
+ else
+ without_id = 1;
+ if (with_id && without_id)
+ break;
+ }
+
+ if (with_id && !without_id)
+ return 2;
+ return with_id;
+}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 89bf289..509677a 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -42,6 +42,7 @@
#define MESH_CONF_SEC_AMPE BIT(2)
unsigned int security;
enum mfp_options ieee80211w;
+ int ocv;
unsigned int pairwise_cipher;
unsigned int group_cipher;
unsigned int mgmt_group_cipher;
@@ -122,6 +123,7 @@
int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
struct vlan_description vlan_desc;
char ifname[IFNAMSIZ + 1];
+ char bridge[IFNAMSIZ + 1];
int configured;
int dynamic_vlan;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
@@ -132,6 +134,7 @@
};
#define PMK_LEN 32
+#define KEYID_LEN 32
#define MIN_PASSPHRASE_LEN 8
#define MAX_PASSPHRASE_LEN 63
struct hostapd_sta_wpa_psk_short {
@@ -145,9 +148,11 @@
struct hostapd_wpa_psk {
struct hostapd_wpa_psk *next;
int group;
+ char keyid[KEYID_LEN];
u8 psk[PMK_LEN];
u8 addr[ETH_ALEN];
u8 p2p_dev_addr[ETH_ALEN];
+ int vlan_id;
};
struct hostapd_eap_user {
@@ -160,6 +165,8 @@
} methods[EAP_MAX_METHODS];
u8 *password;
size_t password_len;
+ u8 *salt;
+ size_t salt_len; /* non-zero when password is salted */
int phase2;
int force_version;
unsigned int wildcard_prefix:1;
@@ -169,6 +176,7 @@
unsigned int macacl:1;
int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
struct hostapd_radius_attr *accept_attr;
+ u32 t_c_timestamp;
};
struct hostapd_radius_attr {
@@ -201,6 +209,12 @@
u8 name[252];
};
+struct hostapd_venue_url {
+ u8 venue_number;
+ u8 url_len;
+ u8 url[254];
+};
+
#define MAX_NAI_REALMS 10
#define MAX_NAI_REALMLEN 255
#define MAX_NAI_EAP_METHODS 5
@@ -230,6 +244,13 @@
char realm[];
};
+struct sae_password_entry {
+ struct sae_password_entry *next;
+ char *password;
+ char *identifier;
+ u8 peer_addr[ETH_ALEN];
+ int vlan_id;
+};
/**
* struct hostapd_bss_config - Per-BSS configuration
@@ -248,7 +269,8 @@
int max_num_sta; /* maximum number of STAs in station table */
int dtim_period;
- int bss_load_update_period;
+ unsigned int bss_load_update_period;
+ unsigned int chan_util_avg_period;
int ieee802_1x; /* use IEEE 802.1X */
int eapol_version;
@@ -319,12 +341,16 @@
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
int assoc_sa_query_retry_timeout;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ int ocv; /* Operating Channel Validation */
+#endif /* CONFIG_OCV */
enum {
PSK_RADIUS_IGNORED = 0,
PSK_RADIUS_ACCEPTED = 1,
PSK_RADIUS_REQUIRED = 2
} wpa_psk_radius;
int wpa_pairwise;
+ int group_cipher; /* wpa_group value override from configuation */
int wpa_group;
int wpa_group_rekey;
int wpa_group_rekey_set;
@@ -342,7 +368,7 @@
/* IEEE 802.11r - Fast BSS Transition */
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
u8 r1_key_holder[FT_R1KH_ID_LEN];
- u32 r0_key_lifetime;
+ u32 r0_key_lifetime; /* PMK-R0 lifetime seconds */
int rkh_pos_timeout;
int rkh_neg_timeout;
int rkh_pull_timeout; /* ms */
@@ -353,6 +379,7 @@
int pmk_r1_push;
int ft_over_ds;
int ft_psk_generate_local;
+ int r1_max_key_lifetime;
#endif /* CONFIG_IEEE80211R_AP */
char *ctrl_interface; /* directory for UNIX domain sockets */
@@ -365,13 +392,17 @@
char *server_cert;
char *private_key;
char *private_key_passwd;
+ char *check_cert_subject;
int check_crl;
+ int check_crl_strict;
+ unsigned int crl_reload_interval;
unsigned int tls_session_lifetime;
unsigned int tls_flags;
char *ocsp_stapling_response;
char *ocsp_stapling_response_multi;
char *dh_file;
char *openssl_ciphers;
+ char *openssl_ecdh_curves;
u8 *pac_opaque_encr_key;
u8 *eap_fast_a_id;
size_t eap_fast_a_id_len;
@@ -434,9 +465,11 @@
u8 *extra_cred;
size_t extra_cred_len;
int wps_cred_processing;
+ int wps_cred_add_sae;
int force_per_enrollee_psk;
u8 *ap_settings;
size_t ap_settings_len;
+ struct hostapd_ssid multi_ap_backhaul_ssid;
char *upnp_iface;
char *friendly_name;
char *manufacturer_url;
@@ -479,6 +512,7 @@
int time_advertisement;
char *time_zone;
int wnm_sleep_mode;
+ int wnm_sleep_mode_no_keys;
int bss_transition;
/* IEEE 802.11u - Interworking */
@@ -501,6 +535,10 @@
unsigned int venue_name_count;
struct hostapd_lang_string *venue_name;
+ /* Venue URL duples */
+ unsigned int venue_url_count;
+ struct hostapd_venue_url *venue_url;
+
/* IEEE 802.11u - Network Authentication Type */
u8 *network_auth_type;
size_t network_auth_type_len;
@@ -534,6 +572,7 @@
int na_mcast_to_ucast;
#ifdef CONFIG_HS20
int hs20;
+ int hs20_release;
int disable_dgaf;
u16 anqp_domain_id;
unsigned int hs20_oper_friendly_name_count;
@@ -562,13 +601,21 @@
char **icons;
size_t icons_count;
char *osu_nai;
+ char *osu_nai2;
unsigned int service_desc_count;
struct hostapd_lang_string *service_desc;
} *hs20_osu_providers, *last_osu;
size_t hs20_osu_providers_count;
+ size_t hs20_osu_providers_nai_count;
+ char **hs20_operator_icon;
+ size_t hs20_operator_icon_count;
unsigned int hs20_deauth_req_timeout;
char *subscr_remediation_url;
u8 subscr_remediation_method;
+ char *hs20_sim_provisioning_url;
+ char *t_c_filename;
+ u32 t_c_timestamp;
+ char *t_c_server_url;
#endif /* CONFIG_HS20 */
u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
@@ -581,8 +628,10 @@
struct wpabuf *assocresp_elements;
unsigned int sae_anti_clogging_threshold;
+ unsigned int sae_sync;
+ int sae_require_mfp;
int *sae_groups;
- char *sae_password;
+ struct sae_password_entry *sae_passwords;
char *wowlan_triggers; /* Wake-on-WLAN triggers */
@@ -652,6 +701,14 @@
char owe_transition_ifname[IFNAMSIZ + 1];
int *owe_groups;
#endif /* CONFIG_OWE */
+
+ int coloc_intf_reporting;
+
+ u8 send_probe_response;
+
+#define BACKHAUL_BSS 1
+#define FRONTHAUL_BSS 2
+ int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */
};
/**
@@ -683,7 +740,6 @@
u16 beacon_int;
int rts_threshold;
int fragm_threshold;
- u8 send_probe_response;
u8 channel;
u8 acs;
struct wpa_freq_range_list acs_ch_list;
@@ -795,7 +851,16 @@
#ifdef CONFIG_IEEE80211AX
struct he_phy_capabilities_info he_phy_capab;
struct he_operation he_op;
+ struct ieee80211_he_mu_edca_parameter_set he_mu_edca;
#endif /* CONFIG_IEEE80211AX */
+
+ /* VHT enable/disable config from CHAN_SWITCH */
+#define CH_SWITCH_VHT_ENABLED BIT(0)
+#define CH_SWITCH_VHT_DISABLED BIT(1)
+ unsigned int ch_switch_vht_config;
+
+ int rssi_reject_assoc_rssi;
+ int rssi_reject_assoc_timeout;
};
@@ -812,7 +877,7 @@
int hostapd_rate_found(int *list, int rate);
const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
const u8 *addr, const u8 *p2p_dev_addr,
- const u8 *prev_psk);
+ const u8 *prev_psk, int *vlan_id);
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
int hostapd_vlan_valid(struct hostapd_vlan *vlan,
struct vlan_description *vlan_desc);
@@ -823,5 +888,6 @@
int hostapd_config_check(struct hostapd_config *conf, int full_config);
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);
#endif /* HOSTAPD_CONFIG_H */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 8f4d839..067cf86 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -176,7 +176,8 @@
#endif /* CONFIG_HS20 */
#ifdef CONFIG_MBO
- if (hapd->conf->mbo_enabled || hapd->enable_oce) {
+ if (hapd->conf->mbo_enabled ||
+ OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd)) {
pos = hostapd_eid_mbo(hapd, buf, sizeof(buf));
if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
add_buf_data(&proberesp, buf, pos - buf) < 0 ||
@@ -185,6 +186,13 @@
}
#endif /* CONFIG_MBO */
+#ifdef CONFIG_OWE
+ pos = hostapd_eid_owe_trans(hapd, buf, sizeof(buf));
+ if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
+ add_buf_data(&proberesp, buf, pos - buf) < 0)
+ goto fail;
+#endif /* CONFIG_OWE */
+
add_buf(&beacon, hapd->conf->vendor_elements);
add_buf(&proberesp, hapd->conf->vendor_elements);
add_buf(&assocresp, hapd->conf->assocresp_elements);
@@ -736,6 +744,15 @@
sta = ap_get_sta(hapd, dst);
if (!sta || !(sta->flags & WLAN_STA_ASSOC))
bssid = wildcard_bssid;
+ } else if (is_broadcast_ether_addr(dst) &&
+ len > 0 && data[0] == WLAN_ACTION_PUBLIC) {
+ /*
+ * The only current use case of Public Action frames with
+ * broadcast destination address is DPP PKEX. That case is
+ * directing all devices and not just the STAs within the BSS,
+ * so have to use the wildcard BSSID value.
+ */
+ bssid = wildcard_bssid;
}
return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
hapd->own_addr, bssid, data, len, 0);
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index bf8169d..de40171 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -103,6 +103,14 @@
unsigned int freq,
unsigned int wait, const u8 *dst,
const u8 *data, size_t len);
+static inline void
+hostapd_drv_send_action_cancel_wait(struct hostapd_data *hapd)
+{
+ if (!hapd->driver || !hapd->driver->send_action_cancel_wait ||
+ !hapd->drv_priv)
+ return;
+ hapd->driver->send_action_cancel_wait(hapd->drv_priv);
+}
int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
u16 auth_alg);
int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
@@ -348,4 +356,22 @@
return hapd->driver->stop_ap(hapd->drv_priv);
}
+static inline int hostapd_drv_channel_info(struct hostapd_data *hapd,
+ struct wpa_channel_info *ci)
+{
+ if (!hapd->driver || !hapd->driver->channel_info)
+ return -1;
+ return hapd->driver->channel_info(hapd->drv_priv, ci);
+}
+
+static inline int
+hostapd_drv_send_external_auth_status(struct hostapd_data *hapd,
+ struct external_auth *params)
+{
+ if (!hapd->driver || !hapd->drv_priv ||
+ !hapd->driver->send_external_auth_status)
+ return -1;
+ return hapd->driver->send_external_auth_status(hapd->drv_priv, params);
+}
+
#endif /* AP_DRV_OPS */
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index a20f49f..eced6c7 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -77,12 +77,20 @@
goto out;
user->password_len = eap_user->password_len;
user->password_hash = eap_user->password_hash;
+ if (eap_user->salt && eap_user->salt_len) {
+ user->salt = os_memdup(eap_user->salt,
+ eap_user->salt_len);
+ if (!user->salt)
+ goto out;
+ user->salt_len = eap_user->salt_len;
+ }
}
user->force_version = eap_user->force_version;
user->macacl = eap_user->macacl;
user->ttls_auth = eap_user->ttls_auth;
user->remediation = eap_user->remediation;
user->accept_attr = eap_user->accept_attr;
+ user->t_c_timestamp = eap_user->t_c_timestamp;
rv = 0;
out:
@@ -128,6 +136,8 @@
#ifdef CONFIG_HS20
srv.subscr_remediation_url = conf->subscr_remediation_url;
srv.subscr_remediation_method = conf->subscr_remediation_method;
+ srv.hs20_sim_provisioning_url = conf->hs20_sim_provisioning_url;
+ srv.t_c_server_url = conf->t_c_server_url;
#endif /* CONFIG_HS20 */
srv.erp = conf->eap_server_erp;
srv.erp_domain = conf->erp_domain;
@@ -146,6 +156,40 @@
#endif /* RADIUS_SERVER */
+#ifdef EAP_TLS_FUNCS
+static void authsrv_tls_event(void *ctx, enum tls_event ev,
+ union tls_event_data *data)
+{
+ switch (ev) {
+ case TLS_CERT_CHAIN_SUCCESS:
+ wpa_printf(MSG_DEBUG, "authsrv: remote certificate verification success");
+ break;
+ case TLS_CERT_CHAIN_FAILURE:
+ wpa_printf(MSG_INFO, "authsrv: certificate chain failure: reason=%d depth=%d subject='%s' err='%s'",
+ data->cert_fail.reason,
+ data->cert_fail.depth,
+ data->cert_fail.subject,
+ data->cert_fail.reason_txt);
+ break;
+ case TLS_PEER_CERTIFICATE:
+ wpa_printf(MSG_DEBUG, "authsrv: peer certificate: depth=%d serial_num=%s subject=%s",
+ data->peer_cert.depth,
+ data->peer_cert.serial_num ? data->peer_cert.serial_num : "N/A",
+ data->peer_cert.subject);
+ break;
+ case TLS_ALERT:
+ if (data->alert.is_local)
+ wpa_printf(MSG_DEBUG, "authsrv: local TLS alert: %s",
+ data->alert.description);
+ else
+ wpa_printf(MSG_DEBUG, "authsrv: remote TLS alert: %s",
+ data->alert.description);
+ break;
+ }
+}
+#endif /* EAP_TLS_FUNCS */
+
+
int authsrv_init(struct hostapd_data *hapd)
{
#ifdef EAP_TLS_FUNCS
@@ -157,7 +201,19 @@
os_memset(&conf, 0, sizeof(conf));
conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
+ if (hapd->conf->crl_reload_interval > 0 &&
+ hapd->conf->check_crl <= 0) {
+ wpa_printf(MSG_INFO,
+ "Cannot enable CRL reload functionality - it depends on check_crl being set");
+ } else if (hapd->conf->crl_reload_interval > 0) {
+ conf.crl_reload_interval =
+ hapd->conf->crl_reload_interval;
+ wpa_printf(MSG_INFO,
+ "Enabled CRL reload functionality");
+ }
conf.tls_flags = hapd->conf->tls_flags;
+ conf.event_cb = authsrv_tls_event;
+ conf.cb_ctx = hapd;
hapd->ssl_ctx = tls_init(&conf);
if (hapd->ssl_ctx == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize TLS");
@@ -172,10 +228,12 @@
params.private_key_passwd = hapd->conf->private_key_passwd;
params.dh_file = hapd->conf->dh_file;
params.openssl_ciphers = hapd->conf->openssl_ciphers;
+ params.openssl_ecdh_curves = hapd->conf->openssl_ecdh_curves;
params.ocsp_stapling_response =
hapd->conf->ocsp_stapling_response;
params.ocsp_stapling_response_multi =
hapd->conf->ocsp_stapling_response_multi;
+ params.check_cert_subject = hapd->conf->check_cert_subject;
if (tls_global_set_params(hapd->ssl_ctx, ¶ms)) {
wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
@@ -184,7 +242,8 @@
}
if (tls_global_set_verify(hapd->ssl_ctx,
- hapd->conf->check_crl)) {
+ hapd->conf->check_crl,
+ hapd->conf->check_crl_strict)) {
wpa_printf(MSG_ERROR, "Failed to enable check_crl");
authsrv_deinit(hapd);
return -1;
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 3ea28a7..3e62991 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -16,6 +16,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/hw_features_common.h"
+#include "common/wpa_ctrl.h"
#include "wps/wps_defs.h"
#include "p2p/p2p.h"
#include "hostapd.h"
@@ -30,6 +31,7 @@
#include "hs20.h"
#include "dfs.h"
#include "taxonomy.h"
+#include "ieee802_11_auth.h"
#ifdef NEED_AP_MLME
@@ -363,67 +365,6 @@
}
-#ifdef CONFIG_OWE
-static int hostapd_eid_owe_trans_enabled(struct hostapd_data *hapd)
-{
- return hapd->conf->owe_transition_ssid_len > 0 &&
- !is_zero_ether_addr(hapd->conf->owe_transition_bssid);
-}
-#endif /* CONFIG_OWE */
-
-
-static size_t hostapd_eid_owe_trans_len(struct hostapd_data *hapd)
-{
-#ifdef CONFIG_OWE
- if (!hostapd_eid_owe_trans_enabled(hapd))
- return 0;
- return 6 + ETH_ALEN + 1 + hapd->conf->owe_transition_ssid_len;
-#else /* CONFIG_OWE */
- return 0;
-#endif /* CONFIG_OWE */
-}
-
-
-static u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid,
- size_t len)
-{
-#ifdef CONFIG_OWE
- u8 *pos = eid;
- size_t elen;
-
- if (hapd->conf->owe_transition_ifname[0] &&
- !hostapd_eid_owe_trans_enabled(hapd))
- hostapd_owe_trans_get_info(hapd);
-
- if (!hostapd_eid_owe_trans_enabled(hapd))
- return pos;
-
- elen = hostapd_eid_owe_trans_len(hapd);
- if (len < elen) {
- wpa_printf(MSG_DEBUG,
- "OWE: Not enough room in the buffer for OWE IE");
- return pos;
- }
-
- *pos++ = WLAN_EID_VENDOR_SPECIFIC;
- *pos++ = elen - 2;
- WPA_PUT_BE24(pos, OUI_WFA);
- pos += 3;
- *pos++ = OWE_OUI_TYPE;
- os_memcpy(pos, hapd->conf->owe_transition_bssid, ETH_ALEN);
- pos += ETH_ALEN;
- *pos++ = hapd->conf->owe_transition_ssid_len;
- os_memcpy(pos, hapd->conf->owe_transition_ssid,
- hapd->conf->owe_transition_ssid_len);
- pos += hapd->conf->owe_transition_ssid_len;
-
- return pos;
-#else /* CONFIG_OWE */
- return eid;
-#endif /* CONFIG_OWE */
-}
-
-
static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
const struct ieee80211_mgmt *req,
int is_p2p, size_t *resp_len)
@@ -456,7 +397,8 @@
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) {
buflen += 3 + sizeof(struct ieee80211_he_capabilities) +
- 3 + sizeof(struct ieee80211_he_operation);
+ 3 + sizeof(struct ieee80211_he_operation) +
+ 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set);
}
#endif /* CONFIG_IEEE80211AX */
@@ -512,8 +454,9 @@
/* Extended supported rates */
pos = hostapd_eid_ext_supp_rates(hapd, pos);
- /* RSN, MDIE, WPA */
- pos = hostapd_eid_wpa(hapd, pos, epos - pos);
+ /* RSN, MDIE */
+ if (hapd->conf->wpa != WPA_PROTO_WPA)
+ pos = hostapd_eid_wpa(hapd, pos, epos - pos);
pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
@@ -568,6 +511,7 @@
if (hapd->iconf->ieee80211ax) {
pos = hostapd_eid_he_capab(hapd, pos);
pos = hostapd_eid_he_operation(hapd, pos);
+ pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
}
#endif /* CONFIG_IEEE80211AX */
@@ -576,6 +520,10 @@
pos = hostapd_eid_vendor_vht(hapd, pos);
#endif /* CONFIG_IEEE80211AC */
+ /* WPA */
+ if (hapd->conf->wpa == WPA_PROTO_WPA)
+ pos = hostapd_eid_wpa(hapd, pos, epos - pos);
+
/* Wi-Fi Alliance WMM */
pos = hostapd_eid_wmm(hapd, pos);
@@ -791,6 +739,11 @@
int ret;
u16 csa_offs[2];
size_t csa_offs_len;
+ u32 session_timeout, acct_interim_interval;
+ struct vlan_description vlan_id;
+ struct hostapd_sta_wpa_psk_short *psk = NULL;
+ char *identity = NULL;
+ char *radius_cui = NULL;
if (len < IEEE80211_HDRLEN)
return;
@@ -799,13 +752,24 @@
sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
ie_len = len - IEEE80211_HDRLEN;
+ ret = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
+ &session_timeout,
+ &acct_interim_interval, &vlan_id,
+ &psk, &identity, &radius_cui, 1);
+ if (ret == HOSTAPD_ACL_REJECT) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "Ignore Probe Request frame from " MACSTR
+ " due to ACL reject ", MAC2STR(mgmt->sa));
+ return;
+ }
+
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
mgmt->sa, mgmt->da, mgmt->bssid,
ie, ie_len, ssi_signal) > 0)
return;
- if (!hapd->iconf->send_probe_response)
+ if (!hapd->conf->send_probe_response)
return;
if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) {
@@ -993,6 +957,9 @@
}
#endif /* CONFIG_TESTING_OPTIONS */
+ wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, RX_PROBE_REQUEST "sa=" MACSTR
+ " signal=%d", MAC2STR(mgmt->sa), ssi_signal);
+
resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL,
&resp_len);
if (resp == NULL)
@@ -1120,7 +1087,8 @@
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) {
tail_len += 3 + sizeof(struct ieee80211_he_capabilities) +
- 3 + sizeof(struct ieee80211_he_operation);
+ 3 + sizeof(struct ieee80211_he_operation) +
+ 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set);
}
#endif /* CONFIG_IEEE80211AX */
@@ -1192,9 +1160,11 @@
/* Extended supported rates */
tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
- /* RSN, MDIE, WPA */
- tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
- tailpos);
+ /* RSN, MDIE */
+ if (hapd->conf->wpa != WPA_PROTO_WPA)
+ tailpos = hostapd_eid_wpa(hapd, tailpos,
+ tail + BEACON_TAIL_BUF_SIZE -
+ tailpos);
tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE -
@@ -1255,6 +1225,7 @@
if (hapd->iconf->ieee80211ax) {
tailpos = hostapd_eid_he_capab(hapd, tailpos);
tailpos = hostapd_eid_he_operation(hapd, tailpos);
+ tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
}
#endif /* CONFIG_IEEE80211AX */
@@ -1263,6 +1234,12 @@
tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
#endif /* CONFIG_IEEE80211AC */
+ /* WPA */
+ if (hapd->conf->wpa == WPA_PROTO_WPA)
+ tailpos = hostapd_eid_wpa(hapd, tailpos,
+ tail + BEACON_TAIL_BUF_SIZE -
+ tailpos);
+
/* Wi-Fi Alliance WMM */
tailpos = hostapd_eid_wmm(hapd, tailpos);
@@ -1384,6 +1361,18 @@
#endif /* CONFIG_HS20 */
params->multicast_to_unicast = hapd->conf->multicast_to_unicast;
params->pbss = hapd->conf->pbss;
+
+ if (hapd->conf->ftm_responder) {
+ if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_FTM_RESPONDER) {
+ params->ftm_responder = 1;
+ params->lci = hapd->iface->conf->lci;
+ params->civic = hapd->iface->conf->civic;
+ } else {
+ wpa_printf(MSG_WARNING,
+ "Not configuring FTM responder as the driver doesn't advertise support for it");
+ }
+ }
+
return 0;
}
diff --git a/src/ap/bss_load.c b/src/ap/bss_load.c
index fb63942..725d3cd 100644
--- a/src/ap/bss_load.c
+++ b/src/ap/bss_load.c
@@ -16,11 +16,35 @@
#include "beacon.h"
+static int get_bss_load_update_timeout(struct hostapd_data *hapd,
+ unsigned int *sec, unsigned int *usec)
+{
+ unsigned int update_period = hapd->conf->bss_load_update_period;
+ unsigned int beacon_int = hapd->iconf->beacon_int;
+ unsigned int update_timeout;
+
+ if (!update_period || !beacon_int) {
+ wpa_printf(MSG_ERROR,
+ "BSS Load: Invalid BSS load update configuration (period=%u beacon_int=%u)",
+ update_period, beacon_int);
+ return -1;
+ }
+
+ update_timeout = update_period * beacon_int;
+
+ *sec = ((update_timeout / 1000) * 1024) / 1000;
+ *usec = (update_timeout % 1000) * 1024;
+
+ return 0;
+}
+
+
static void update_channel_utilization(void *eloop_data, void *user_data)
{
struct hostapd_data *hapd = eloop_data;
unsigned int sec, usec;
int err;
+ struct hostapd_iface *iface = hapd->iface;
if (!(hapd->beacon_set_done && hapd->started))
return;
@@ -33,8 +57,24 @@
ieee802_11_set_beacon(hapd);
- sec = ((hapd->bss_load_update_timeout / 1000) * 1024) / 1000;
- usec = (hapd->bss_load_update_timeout % 1000) * 1024;
+ if (get_bss_load_update_timeout(hapd, &sec, &usec) < 0)
+ return;
+
+ if (hapd->conf->chan_util_avg_period) {
+ iface->chan_util_samples_sum += iface->channel_utilization;
+ iface->chan_util_num_sample_periods +=
+ hapd->conf->bss_load_update_period;
+ if (iface->chan_util_num_sample_periods >=
+ hapd->conf->chan_util_avg_period) {
+ iface->chan_util_average =
+ iface->chan_util_samples_sum /
+ (iface->chan_util_num_sample_periods /
+ hapd->conf->bss_load_update_period);
+ iface->chan_util_samples_sum = 0;
+ iface->chan_util_num_sample_periods = 0;
+ }
+ }
+
eloop_register_timeout(sec, usec, update_channel_utilization, hapd,
NULL);
}
@@ -42,17 +82,11 @@
int bss_load_update_init(struct hostapd_data *hapd)
{
- struct hostapd_bss_config *conf = hapd->conf;
- struct hostapd_config *iconf = hapd->iconf;
unsigned int sec, usec;
- if (!conf->bss_load_update_period || !iconf->beacon_int)
+ if (get_bss_load_update_timeout(hapd, &sec, &usec) < 0)
return -1;
- hapd->bss_load_update_timeout = conf->bss_load_update_period *
- iconf->beacon_int;
- sec = ((hapd->bss_load_update_timeout / 1000) * 1024) / 1000;
- usec = (hapd->bss_load_update_timeout % 1000) * 1024;
eloop_register_timeout(sec, usec, update_channel_utilization, hapd,
NULL);
return 0;
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 1a2b4e5..c693715 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -1,6 +1,6 @@
/*
* Control interface for shared AP commands
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -26,6 +26,30 @@
#include "taxonomy.h"
+static size_t hostapd_write_ht_mcs_bitmask(char *buf, size_t buflen,
+ size_t curr_len, const u8 *mcs_set)
+{
+ int ret;
+ size_t len = curr_len;
+
+ ret = os_snprintf(buf + len, buflen - len,
+ "ht_mcs_bitmask=");
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+
+ /* 77 first bits (+ 3 reserved bits) */
+ len += wpa_snprintf_hex(buf + len, buflen - len, mcs_set, 10);
+
+ ret = os_snprintf(buf + len, buflen - len, "\n");
+ if (os_snprintf_error(buflen - len, ret))
+ return curr_len;
+ len += ret;
+
+ return len;
+}
+
+
static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
struct sta_info *sta,
char *buf, size_t buflen)
@@ -111,6 +135,31 @@
if (!os_snprintf_error(buflen - len, ret))
len += ret;
+ if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "rx_vht_mcs_map=%04x\n"
+ "tx_vht_mcs_map=%04x\n",
+ le_to_host16(sta->vht_capabilities->
+ vht_supported_mcs_set.rx_map),
+ le_to_host16(sta->vht_capabilities->
+ vht_supported_mcs_set.tx_map));
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+ }
+
+ if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
+ len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
+ sta->ht_capabilities->
+ supported_mcs_set);
+ }
+
+ if (data.flags & STA_DRV_DATA_LAST_ACK_RSSI) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "last_ack_signal=%d\n", data.last_ack_rssi);
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+ }
+
return len;
}
@@ -158,6 +207,7 @@
char *buf, size_t buflen)
{
int len, res, ret, i;
+ const char *keyid;
if (!sta)
return 0;
@@ -245,6 +295,60 @@
len += os_snprintf(buf + len, buflen - len, "\n");
}
+ if (sta->power_capab) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "min_txpower=%d\n"
+ "max_txpower=%d\n",
+ sta->min_tx_power, sta->max_tx_power);
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+ }
+
+#ifdef CONFIG_IEEE80211AC
+ if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
+ res = os_snprintf(buf + len, buflen - len,
+ "vht_caps_info=0x%08x\n",
+ le_to_host32(sta->vht_capabilities->
+ vht_capabilities_info));
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+ }
+#endif /* CONFIG_IEEE80211AC */
+
+#ifdef CONFIG_IEEE80211N
+ if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
+ res = os_snprintf(buf + len, buflen - len,
+ "ht_caps_info=0x%04x\n",
+ le_to_host16(sta->ht_capabilities->
+ ht_capabilities_info));
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+ }
+#endif /* CONFIG_IEEE80211N */
+
+ if (sta->ext_capability &&
+ buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) {
+ len += os_snprintf(buf + len, buflen - len, "ext_capab=");
+ len += wpa_snprintf_hex(buf + len, buflen - len,
+ sta->ext_capability + 1,
+ sta->ext_capability[0]);
+ len += os_snprintf(buf + len, buflen - len, "\n");
+ }
+
+ if (sta->flags & WLAN_STA_WDS && sta->ifname_wds) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "wds_sta_ifname=%s\n", sta->ifname_wds);
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+ }
+
+ keyid = ap_sta_wpa_get_keyid(hapd, sta);
+ if (keyid) {
+ ret = os_snprintf(buf + len, buflen - len, "keyid=%s\n", keyid);
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+ }
+
return len;
}
@@ -347,11 +451,11 @@
if (stype == WLAN_FC_STYPE_DEAUTH) {
mgmt->u.deauth.reason_code =
host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
- pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
+ pos = mgmt->u.deauth.variable;
} else {
mgmt->u.disassoc.reason_code =
host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
- pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
+ pos = mgmt->u.disassoc.variable;
}
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
@@ -546,7 +650,8 @@
size_t buflen)
{
struct hostapd_iface *iface = hapd->iface;
- int len = 0, ret;
+ struct hostapd_hw_modes *mode = iface->current_mode;
+ int len = 0, ret, j;
size_t i;
ret = os_snprintf(buf + len, buflen - len,
@@ -606,13 +711,17 @@
"channel=%u\n"
"secondary_channel=%d\n"
"ieee80211n=%d\n"
- "ieee80211ac=%d\n",
+ "ieee80211ac=%d\n"
+ "beacon_int=%u\n"
+ "dtim_period=%d\n",
iface->conf->channel,
iface->conf->ieee80211n && !hapd->conf->disable_11n ?
iface->conf->secondary_channel : 0,
iface->conf->ieee80211n && !hapd->conf->disable_11n,
iface->conf->ieee80211ac &&
- !hapd->conf->disable_11ac);
+ !hapd->conf->disable_11ac,
+ iface->conf->beacon_int,
+ hapd->conf->dtim_period);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -620,15 +729,76 @@
ret = os_snprintf(buf + len, buflen - len,
"vht_oper_chwidth=%d\n"
"vht_oper_centr_freq_seg0_idx=%d\n"
- "vht_oper_centr_freq_seg1_idx=%d\n",
+ "vht_oper_centr_freq_seg1_idx=%d\n"
+ "vht_caps_info=%08x\n",
iface->conf->vht_oper_chwidth,
iface->conf->vht_oper_centr_freq_seg0_idx,
- iface->conf->vht_oper_centr_freq_seg1_idx);
+ iface->conf->vht_oper_centr_freq_seg1_idx,
+ iface->conf->vht_capab);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
+ if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac && mode) {
+ u16 rxmap = WPA_GET_LE16(&mode->vht_mcs_set[0]);
+ u16 txmap = WPA_GET_LE16(&mode->vht_mcs_set[4]);
+
+ ret = os_snprintf(buf + len, buflen - len,
+ "rx_vht_mcs_map=%04x\n"
+ "tx_vht_mcs_map=%04x\n",
+ rxmap, txmap);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+
+ if (iface->conf->ieee80211n && !hapd->conf->disable_11n) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "ht_caps_info=%04x\n",
+ hapd->iconf->ht_capab);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+
+ if (iface->conf->ieee80211n && !hapd->conf->disable_11n && mode) {
+ len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
+ mode->mcs_set);
+ }
+
+ if (iface->current_rates && iface->num_rates) {
+ ret = os_snprintf(buf + len, buflen - len, "supported_rates=");
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+
+ for (j = 0; j < iface->num_rates; j++) {
+ ret = os_snprintf(buf + len, buflen - len, "%s%02x",
+ j > 0 ? " " : "",
+ iface->current_rates[j].rate / 5);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+ ret = os_snprintf(buf + len, buflen - len, "\n");
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+
+ for (j = 0; mode && j < mode->num_channels; j++) {
+ if (mode->channels[j].freq == iface->freq) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "max_txpower=%u\n",
+ mode->channels[j].max_tx_power);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ break;
+ }
+ }
+
for (i = 0; i < iface->num_bss; i++) {
struct hostapd_data *bss = iface->bss[i];
ret = os_snprintf(buf + len, buflen - len,
@@ -647,6 +817,15 @@
len += ret;
}
+ if (hapd->conf->chan_util_avg_period) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "chan_util_avg=%u\n",
+ iface->chan_util_average);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+
return len;
}
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 5a0d781..79cd00f 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -142,18 +142,30 @@
{
struct hostapd_channel_data *first_chan, *chan;
int i;
+ u32 bw = num_chan_to_bw(num_chans);
if (first_chan_idx + num_chans > mode->num_channels)
return 0;
first_chan = &mode->channels[first_chan_idx];
+ /* hostapd DFS implementation assumes the first channel as primary.
+ * If it's not allowed to use the first channel as primary, decline the
+ * whole channel range. */
+ if (!chan_pri_allowed(first_chan))
+ return 0;
+
for (i = 0; i < num_chans; i++) {
chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
first_chan_idx);
if (!chan)
return 0;
+ /* HT 40 MHz secondary channel availability checked only for
+ * primary channel */
+ if (!chan_bw_allowed(chan, bw, 1, !i))
+ return 0;
+
if (!dfs_channel_available(chan, skip_radar))
return 0;
}
@@ -197,7 +209,8 @@
/* Skip HT40/VHT incompatible channels */
if (iface->conf->ieee80211n &&
iface->conf->secondary_channel &&
- !dfs_is_chan_allowed(chan, n_chans))
+ (!dfs_is_chan_allowed(chan, n_chans) ||
+ !(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)))
continue;
/* Skip incompatible chandefs */
@@ -1111,7 +1124,8 @@
return 1;
}
- if (ieee80211_is_dfs(iface->freq)) {
+ if (ieee80211_is_dfs(iface->freq, iface->hw_features,
+ iface->num_hw_features)) {
wpa_printf(MSG_DEBUG, "%s: freq %d MHz requires DFS",
__func__, iface->freq);
return 0;
diff --git a/src/ap/dhcp_snoop.c b/src/ap/dhcp_snoop.c
index 6d8c2f4..ed37fc8 100644
--- a/src/ap/dhcp_snoop.c
+++ b/src/ap/dhcp_snoop.c
@@ -88,6 +88,15 @@
}
}
+ if (hapd->conf->disable_dgaf && is_broadcast_ether_addr(buf)) {
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!(sta->flags & WLAN_STA_AUTHORIZED))
+ continue;
+ x_snoop_mcast_to_ucast_convert_send(hapd, sta,
+ (u8 *) buf, len);
+ }
+ }
+
if (msgtype == DHCPACK) {
if (b->your_ip == 0)
return;
@@ -124,15 +133,6 @@
}
sta->ipaddr = b->your_ip;
}
-
- if (hapd->conf->disable_dgaf && is_broadcast_ether_addr(buf)) {
- for (sta = hapd->sta_list; sta; sta = sta->next) {
- if (!(sta->flags & WLAN_STA_AUTHORIZED))
- continue;
- x_snoop_mcast_to_ucast_convert_send(hapd, sta,
- (u8 *) buf, len);
- }
- }
}
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index aae2910..75edbc9 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -20,39 +20,14 @@
#include "dpp_hostapd.h"
+static void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx);
static void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator);
+static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
+static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd);
static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-static struct dpp_configurator *
-hostapd_dpp_configurator_get_id(struct hostapd_data *hapd, unsigned int id)
-{
- struct dpp_configurator *conf;
-
- dl_list_for_each(conf, &hapd->dpp_configurator,
- struct dpp_configurator, list) {
- if (conf->id == id)
- return conf;
- }
- return NULL;
-}
-
-
-static unsigned int hapd_dpp_next_id(struct hostapd_data *hapd)
-{
- struct dpp_bootstrap_info *bi;
- unsigned int max_id = 0;
-
- dl_list_for_each(bi, &hapd->dpp_bootstrap, struct dpp_bootstrap_info,
- list) {
- if (bi->id > max_id)
- max_id = bi->id;
- }
- return max_id + 1;
-}
-
-
/**
* hostapd_dpp_qr_code - Parse and add DPP bootstrapping info from a QR Code
* @hapd: Pointer to hostapd_data
@@ -64,17 +39,18 @@
struct dpp_bootstrap_info *bi;
struct dpp_authentication *auth = hapd->dpp_auth;
- bi = dpp_parse_qr_code(cmd);
+ bi = dpp_add_qr_code(hapd->iface->interfaces->dpp, cmd);
if (!bi)
return -1;
- bi->id = hapd_dpp_next_id(hapd);
- dl_list_add(&hapd->dpp_bootstrap, &bi->list);
-
if (auth && auth->response_pending &&
dpp_notify_new_qr_code(auth, bi) == 1) {
wpa_printf(MSG_DEBUG,
"DPP: Sending out pending authentication response");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d",
+ MAC2STR(auth->peer_mac_addr), auth->curr_freq,
+ DPP_PA_AUTHENTICATION_RESP);
hostapd_drv_send_action(hapd, auth->curr_freq, 0,
auth->peer_mac_addr,
wpabuf_head(hapd->dpp_auth->resp_msg),
@@ -85,200 +61,72 @@
}
-static char * get_param(const char *cmd, const char *param)
+static void hostapd_dpp_auth_resp_retry_timeout(void *eloop_ctx,
+ void *timeout_ctx)
{
- const char *pos, *end;
- char *val;
- size_t len;
+ struct hostapd_data *hapd = eloop_ctx;
+ struct dpp_authentication *auth = hapd->dpp_auth;
- pos = os_strstr(cmd, param);
- if (!pos)
- return NULL;
+ if (!auth || !auth->resp_msg)
+ return;
- pos += os_strlen(param);
- end = os_strchr(pos, ' ');
- if (end)
- len = end - pos;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Retry Authentication Response after timeout");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d",
+ MAC2STR(auth->peer_mac_addr), auth->curr_freq,
+ DPP_PA_AUTHENTICATION_RESP);
+ hostapd_drv_send_action(hapd, auth->curr_freq, 500, auth->peer_mac_addr,
+ wpabuf_head(auth->resp_msg),
+ wpabuf_len(auth->resp_msg));
+}
+
+
+static void hostapd_dpp_auth_resp_retry(struct hostapd_data *hapd)
+{
+ struct dpp_authentication *auth = hapd->dpp_auth;
+ unsigned int wait_time, max_tries;
+
+ if (!auth || !auth->resp_msg)
+ return;
+
+ if (hapd->dpp_resp_max_tries)
+ max_tries = hapd->dpp_resp_max_tries;
else
- len = os_strlen(pos);
- val = os_malloc(len + 1);
- if (!val)
- return NULL;
- os_memcpy(val, pos, len);
- val[len] = '\0';
- return val;
-}
+ max_tries = 5;
+ auth->auth_resp_tries++;
+ if (auth->auth_resp_tries >= max_tries) {
+ wpa_printf(MSG_INFO,
+ "DPP: No confirm received from initiator - stopping exchange");
+ hostapd_drv_send_action_cancel_wait(hapd);
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ return;
+ }
-
-int hostapd_dpp_bootstrap_gen(struct hostapd_data *hapd, const char *cmd)
-{
- char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL;
- char *key = NULL;
- u8 *privkey = NULL;
- size_t privkey_len = 0;
- size_t len;
- int ret = -1;
- struct dpp_bootstrap_info *bi;
-
- bi = os_zalloc(sizeof(*bi));
- if (!bi)
- goto fail;
-
- if (os_strstr(cmd, "type=qrcode"))
- bi->type = DPP_BOOTSTRAP_QR_CODE;
- else if (os_strstr(cmd, "type=pkex"))
- bi->type = DPP_BOOTSTRAP_PKEX;
+ if (hapd->dpp_resp_retry_time)
+ wait_time = hapd->dpp_resp_retry_time;
else
- goto fail;
-
- chan = get_param(cmd, " chan=");
- mac = get_param(cmd, " mac=");
- info = get_param(cmd, " info=");
- curve = get_param(cmd, " curve=");
- key = get_param(cmd, " key=");
-
- if (key) {
- privkey_len = os_strlen(key) / 2;
- privkey = os_malloc(privkey_len);
- if (!privkey ||
- hexstr2bin(key, privkey, privkey_len) < 0)
- goto fail;
- }
-
- pk = dpp_keygen(bi, curve, privkey, privkey_len);
- if (!pk)
- goto fail;
-
- len = 4; /* "DPP:" */
- if (chan) {
- if (dpp_parse_uri_chan_list(bi, chan) < 0)
- goto fail;
- len += 3 + os_strlen(chan); /* C:...; */
- }
- if (mac) {
- if (dpp_parse_uri_mac(bi, mac) < 0)
- goto fail;
- len += 3 + os_strlen(mac); /* M:...; */
- }
- if (info) {
- if (dpp_parse_uri_info(bi, info) < 0)
- goto fail;
- len += 3 + os_strlen(info); /* I:...; */
- }
- len += 4 + os_strlen(pk);
- bi->uri = os_malloc(len + 1);
- if (!bi->uri)
- goto fail;
- os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
- chan ? "C:" : "", chan ? chan : "", chan ? ";" : "",
- mac ? "M:" : "", mac ? mac : "", mac ? ";" : "",
- info ? "I:" : "", info ? info : "", info ? ";" : "",
- pk);
- bi->id = hapd_dpp_next_id(hapd);
- dl_list_add(&hapd->dpp_bootstrap, &bi->list);
- ret = bi->id;
- bi = NULL;
-fail:
- os_free(curve);
- os_free(pk);
- os_free(chan);
- os_free(mac);
- os_free(info);
- str_clear_free(key);
- bin_clear_free(privkey, privkey_len);
- dpp_bootstrap_info_free(bi);
- return ret;
-}
-
-
-static struct dpp_bootstrap_info *
-dpp_bootstrap_get_id(struct hostapd_data *hapd, unsigned int id)
-{
- struct dpp_bootstrap_info *bi;
-
- dl_list_for_each(bi, &hapd->dpp_bootstrap, struct dpp_bootstrap_info,
- list) {
- if (bi->id == id)
- return bi;
- }
- return NULL;
-}
-
-
-static int dpp_bootstrap_del(struct hostapd_data *hapd, unsigned int id)
-{
- struct dpp_bootstrap_info *bi, *tmp;
- int found = 0;
-
- dl_list_for_each_safe(bi, tmp, &hapd->dpp_bootstrap,
- struct dpp_bootstrap_info, list) {
- if (id && bi->id != id)
- continue;
- found = 1;
- dl_list_del(&bi->list);
- dpp_bootstrap_info_free(bi);
- }
-
- if (id == 0)
- return 0; /* flush succeeds regardless of entries found */
- return found ? 0 : -1;
-}
-
-
-int hostapd_dpp_bootstrap_remove(struct hostapd_data *hapd, const char *id)
-{
- unsigned int id_val;
-
- if (os_strcmp(id, "*") == 0) {
- id_val = 0;
- } else {
- id_val = atoi(id);
- if (id_val == 0)
- return -1;
- }
-
- return dpp_bootstrap_del(hapd, id_val);
-}
-
-
-const char * hostapd_dpp_bootstrap_get_uri(struct hostapd_data *hapd,
- unsigned int id)
-{
- struct dpp_bootstrap_info *bi;
-
- bi = dpp_bootstrap_get_id(hapd, id);
- if (!bi)
- return NULL;
- return bi->uri;
-}
-
-
-int hostapd_dpp_bootstrap_info(struct hostapd_data *hapd, int id,
- char *reply, int reply_size)
-{
- struct dpp_bootstrap_info *bi;
-
- bi = dpp_bootstrap_get_id(hapd, id);
- if (!bi)
- return -1;
- return os_snprintf(reply, reply_size, "type=%s\n"
- "mac_addr=" MACSTR "\n"
- "info=%s\n"
- "num_freq=%u\n"
- "curve=%s\n",
- dpp_bootstrap_type_txt(bi->type),
- MAC2STR(bi->mac_addr),
- bi->info ? bi->info : "",
- bi->num_freq,
- bi->curve->name);
+ wait_time = 1000;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Schedule retransmission of Authentication Response frame in %u ms",
+ wait_time);
+ eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
+ eloop_register_timeout(wait_time / 1000,
+ (wait_time % 1000) * 1000,
+ hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
}
void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
const u8 *data, size_t data_len, int ok)
{
+ struct dpp_authentication *auth = hapd->dpp_auth;
+
wpa_printf(MSG_DEBUG, "DPP: TX status: dst=" MACSTR " ok=%d",
MAC2STR(dst), ok);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
+ " result=%s", MAC2STR(dst), ok ? "SUCCESS" : "FAILED");
if (!hapd->dpp_auth) {
wpa_printf(MSG_DEBUG,
@@ -286,9 +134,25 @@
return;
}
+#ifdef CONFIG_DPP2
+ if (auth->connect_on_tx_status) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Complete exchange on configuration result");
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ return;
+ }
+#endif /* CONFIG_DPP2 */
+
if (hapd->dpp_auth->remove_on_tx_status) {
wpa_printf(MSG_DEBUG,
"DPP: Terminate authentication exchange due to an earlier error");
+ eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
+ hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
+ NULL);
+ hostapd_drv_send_action_cancel_wait(hapd);
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
return;
@@ -296,6 +160,120 @@
if (hapd->dpp_auth_ok_on_ack)
hostapd_dpp_auth_success(hapd, 1);
+
+ if (!is_broadcast_ether_addr(dst) && !ok) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unicast DPP Action frame was not ACKed");
+ if (auth->waiting_auth_resp) {
+ /* In case of DPP Authentication Request frame, move to
+ * the next channel immediately. */
+ hostapd_drv_send_action_cancel_wait(hapd);
+ hostapd_dpp_auth_init_next(hapd);
+ return;
+ }
+ if (auth->waiting_auth_conf) {
+ hostapd_dpp_auth_resp_retry(hapd);
+ return;
+ }
+ }
+
+ if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp && ok) {
+ /* Allow timeout handling to stop iteration if no response is
+ * received from a peer that has ACKed a request. */
+ auth->auth_req_ack = 1;
+ }
+
+ if (!hapd->dpp_auth_ok_on_ack && hapd->dpp_auth->neg_freq > 0 &&
+ hapd->dpp_auth->curr_freq != hapd->dpp_auth->neg_freq) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Move from curr_freq %u MHz to neg_freq %u MHz for response",
+ hapd->dpp_auth->curr_freq,
+ hapd->dpp_auth->neg_freq);
+ hostapd_drv_send_action_cancel_wait(hapd);
+
+ if (hapd->dpp_auth->neg_freq !=
+ (unsigned int) hapd->iface->freq && hapd->iface->freq > 0) {
+ /* TODO: Listen operation on non-operating channel */
+ wpa_printf(MSG_INFO,
+ "DPP: Listen operation on non-operating channel (%d MHz) is not yet supported (operating channel: %d MHz)",
+ hapd->dpp_auth->neg_freq, hapd->iface->freq);
+ }
+ }
+
+ if (hapd->dpp_auth_ok_on_ack)
+ hapd->dpp_auth_ok_on_ack = 0;
+}
+
+
+static void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct dpp_authentication *auth = hapd->dpp_auth;
+ unsigned int freq;
+ struct os_reltime now, diff;
+ unsigned int wait_time, diff_ms;
+
+ if (!auth || !auth->waiting_auth_resp)
+ return;
+
+ wait_time = hapd->dpp_resp_wait_time ?
+ hapd->dpp_resp_wait_time : 2000;
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &hapd->dpp_last_init, &diff);
+ diff_ms = diff.sec * 1000 + diff.usec / 1000;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Reply wait timeout - wait_time=%u diff_ms=%u",
+ wait_time, diff_ms);
+
+ if (auth->auth_req_ack && diff_ms >= wait_time) {
+ /* Peer ACK'ed Authentication Request frame, but did not reply
+ * with Authentication Response frame within two seconds. */
+ wpa_printf(MSG_INFO,
+ "DPP: No response received from responder - stopping initiation attempt");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED);
+ hostapd_drv_send_action_cancel_wait(hapd);
+ hostapd_dpp_listen_stop(hapd);
+ dpp_auth_deinit(auth);
+ hapd->dpp_auth = NULL;
+ return;
+ }
+
+ if (diff_ms >= wait_time) {
+ /* Authentication Request frame was not ACK'ed and no reply
+ * was receiving within two seconds. */
+ wpa_printf(MSG_DEBUG,
+ "DPP: Continue Initiator channel iteration");
+ hostapd_drv_send_action_cancel_wait(hapd);
+ hostapd_dpp_listen_stop(hapd);
+ hostapd_dpp_auth_init_next(hapd);
+ return;
+ }
+
+ /* Driver did not support 2000 ms long wait_time with TX command, so
+ * schedule listen operation to continue waiting for the response.
+ *
+ * DPP listen operations continue until stopped, so simply schedule a
+ * new call to this function at the point when the two second reply
+ * wait has expired. */
+ wait_time -= diff_ms;
+
+ freq = auth->curr_freq;
+ if (auth->neg_freq > 0)
+ freq = auth->neg_freq;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Continue reply wait on channel %u MHz for %u ms",
+ freq, wait_time);
+ hapd->dpp_in_response_listen = 1;
+
+ if (freq != (unsigned int) hapd->iface->freq && hapd->iface->freq > 0) {
+ /* TODO: Listen operation on non-operating channel */
+ wpa_printf(MSG_INFO,
+ "DPP: Listen operation on non-operating channel (%d MHz) is not yet supported (operating channel: %d MHz)",
+ freq, hapd->iface->freq);
+ }
+
+ eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
+ hostapd_dpp_reply_wait_timeout, hapd, NULL);
}
@@ -317,132 +295,101 @@
}
-static void hostapd_dpp_set_configurator(struct hostapd_data *hapd,
- struct dpp_authentication *auth,
- const char *cmd)
+static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx)
{
- const char *pos, *end;
- struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
- struct dpp_configurator *conf = NULL;
- u8 ssid[32] = { "test" };
- size_t ssid_len = 4;
- char pass[64] = { };
- size_t pass_len = 0;
- u8 psk[PMK_LEN];
- int psk_set = 0;
+ struct hostapd_data *hapd = eloop_ctx;
- if (!cmd)
+ if (!hapd->dpp_auth)
return;
+ wpa_printf(MSG_DEBUG, "DPP: Retry initiation after timeout");
+ hostapd_dpp_auth_init_next(hapd);
+}
- wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
- pos = os_strstr(cmd, " ssid=");
- if (pos) {
- pos += 6;
- end = os_strchr(pos, ' ');
- ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
- ssid_len /= 2;
- if (ssid_len > sizeof(ssid) ||
- hexstr2bin(pos, ssid, ssid_len) < 0)
- goto fail;
- }
- pos = os_strstr(cmd, " pass=");
- if (pos) {
- pos += 6;
- end = os_strchr(pos, ' ');
- pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
- pass_len /= 2;
- if (pass_len > sizeof(pass) - 1 || pass_len < 8 ||
- hexstr2bin(pos, (u8 *) pass, pass_len) < 0)
- goto fail;
- }
+static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd)
+{
+ struct dpp_authentication *auth = hapd->dpp_auth;
+ const u8 *dst;
+ unsigned int wait_time, max_wait_time, freq, max_tries, used;
+ struct os_reltime now, diff;
- pos = os_strstr(cmd, " psk=");
- if (pos) {
- pos += 5;
- if (hexstr2bin(pos, psk, PMK_LEN) < 0)
- goto fail;
- psk_set = 1;
- }
+ if (!auth)
+ return -1;
- if (os_strstr(cmd, " conf=sta-")) {
- conf_sta = os_zalloc(sizeof(struct dpp_configuration));
- if (!conf_sta)
- goto fail;
- os_memcpy(conf_sta->ssid, ssid, ssid_len);
- conf_sta->ssid_len = ssid_len;
- if (os_strstr(cmd, " conf=sta-psk")) {
- conf_sta->dpp = 0;
- if (psk_set) {
- os_memcpy(conf_sta->psk, psk, PMK_LEN);
- } else {
- conf_sta->passphrase = os_strdup(pass);
- if (!conf_sta->passphrase)
- goto fail;
- }
- } else if (os_strstr(cmd, " conf=sta-dpp")) {
- conf_sta->dpp = 1;
- } else {
- goto fail;
- }
- }
+ if (auth->freq_idx == 0)
+ os_get_reltime(&hapd->dpp_init_iter_start);
- if (os_strstr(cmd, " conf=ap-")) {
- conf_ap = os_zalloc(sizeof(struct dpp_configuration));
- if (!conf_ap)
- goto fail;
- os_memcpy(conf_ap->ssid, ssid, ssid_len);
- conf_ap->ssid_len = ssid_len;
- if (os_strstr(cmd, " conf=ap-psk")) {
- conf_ap->dpp = 0;
- if (psk_set) {
- os_memcpy(conf_ap->psk, psk, PMK_LEN);
- } else {
- conf_ap->passphrase = os_strdup(pass);
- if (!conf_ap->passphrase)
- goto fail;
- }
- } else if (os_strstr(cmd, " conf=ap-dpp")) {
- conf_ap->dpp = 1;
- } else {
- goto fail;
- }
- }
-
- pos = os_strstr(cmd, " expiry=");
- if (pos) {
- long int val;
-
- pos += 8;
- val = strtol(pos, NULL, 0);
- if (val <= 0)
- goto fail;
- if (conf_sta)
- conf_sta->netaccesskey_expiry = val;
- if (conf_ap)
- conf_ap->netaccesskey_expiry = val;
- }
-
- pos = os_strstr(cmd, " configurator=");
- if (pos) {
- auth->configurator = 1;
- pos += 14;
- conf = hostapd_dpp_configurator_get_id(hapd, atoi(pos));
- if (!conf) {
+ if (auth->freq_idx >= auth->num_freq) {
+ auth->num_freq_iters++;
+ if (hapd->dpp_init_max_tries)
+ max_tries = hapd->dpp_init_max_tries;
+ else
+ max_tries = 5;
+ if (auth->num_freq_iters >= max_tries || auth->auth_req_ack) {
wpa_printf(MSG_INFO,
- "DPP: Could not find the specified configurator");
- goto fail;
+ "DPP: No response received from responder - stopping initiation attempt");
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ DPP_EVENT_AUTH_INIT_FAILED);
+ eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
+ hapd, NULL);
+ hostapd_drv_send_action_cancel_wait(hapd);
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ return -1;
}
+ auth->freq_idx = 0;
+ eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
+ if (hapd->dpp_init_retry_time)
+ wait_time = hapd->dpp_init_retry_time;
+ else
+ wait_time = 10000;
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &hapd->dpp_init_iter_start, &diff);
+ used = diff.sec * 1000 + diff.usec / 1000;
+ if (used > wait_time)
+ wait_time = 0;
+ else
+ wait_time -= used;
+ wpa_printf(MSG_DEBUG, "DPP: Next init attempt in %u ms",
+ wait_time);
+ eloop_register_timeout(wait_time / 1000,
+ (wait_time % 1000) * 1000,
+ hostapd_dpp_init_timeout, hapd,
+ NULL);
+ return 0;
}
- auth->conf_sta = conf_sta;
- auth->conf_ap = conf_ap;
- auth->conf = conf;
- return;
+ freq = auth->freq[auth->freq_idx++];
+ auth->curr_freq = freq;
-fail:
- wpa_printf(MSG_DEBUG, "DPP: Failed to set configurator parameters");
- dpp_configuration_free(conf_sta);
- dpp_configuration_free(conf_ap);
+ if (is_zero_ether_addr(auth->peer_bi->mac_addr))
+ dst = broadcast;
+ else
+ dst = auth->peer_bi->mac_addr;
+ hapd->dpp_auth_ok_on_ack = 0;
+ eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
+ wait_time = 2000; /* TODO: hapd->max_remain_on_chan; */
+ max_wait_time = hapd->dpp_resp_wait_time ?
+ hapd->dpp_resp_wait_time : 2000;
+ if (wait_time > max_wait_time)
+ wait_time = max_wait_time;
+ wait_time += 10; /* give the driver some extra time to complete */
+ eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
+ hostapd_dpp_reply_wait_timeout, hapd, NULL);
+ wait_time -= 10;
+ if (auth->neg_freq > 0 && freq != auth->neg_freq) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Initiate on %u MHz and move to neg_freq %u MHz for response",
+ freq, auth->neg_freq);
+ }
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d",
+ MAC2STR(dst), freq, DPP_PA_AUTHENTICATION_REQ);
+ auth->auth_req_ack = 0;
+ os_get_reltime(&hapd->dpp_last_init);
+ return hostapd_drv_send_action(hapd, freq, wait_time,
+ dst,
+ wpabuf_head(hapd->dpp_auth->req_msg),
+ wpabuf_len(hapd->dpp_auth->req_msg));
}
@@ -450,16 +397,14 @@
{
const char *pos;
struct dpp_bootstrap_info *peer_bi, *own_bi = NULL;
- const u8 *dst;
- int res;
- int configurator = 1;
- struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
+ u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
+ unsigned int neg_freq = 0;
pos = os_strstr(cmd, " peer=");
if (!pos)
return -1;
pos += 6;
- peer_bi = dpp_bootstrap_get_id(hapd, atoi(pos));
+ peer_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
if (!peer_bi) {
wpa_printf(MSG_INFO,
"DPP: Could not find bootstrapping info for the identified peer");
@@ -469,7 +414,8 @@
pos = os_strstr(cmd, " own=");
if (pos) {
pos += 5;
- own_bi = dpp_bootstrap_get_id(hapd, atoi(pos));
+ own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp,
+ atoi(pos));
if (!own_bi) {
wpa_printf(MSG_INFO,
"DPP: Could not find bootstrapping info for the identified local entry");
@@ -488,77 +434,110 @@
if (pos) {
pos += 6;
if (os_strncmp(pos, "configurator", 12) == 0)
- configurator = 1;
+ allowed_roles = DPP_CAPAB_CONFIGURATOR;
else if (os_strncmp(pos, "enrollee", 8) == 0)
- configurator = 0;
+ allowed_roles = DPP_CAPAB_ENROLLEE;
+ else if (os_strncmp(pos, "either", 6) == 0)
+ allowed_roles = DPP_CAPAB_CONFIGURATOR |
+ DPP_CAPAB_ENROLLEE;
else
goto fail;
}
- if (hapd->dpp_auth)
+ pos = os_strstr(cmd, " neg_freq=");
+ if (pos)
+ neg_freq = atoi(pos + 10);
+
+ if (hapd->dpp_auth) {
+ eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
+ hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
+ NULL);
+ hostapd_drv_send_action_cancel_wait(hapd);
dpp_auth_deinit(hapd->dpp_auth);
- hapd->dpp_auth = dpp_auth_init(hapd, peer_bi, own_bi, configurator);
+ }
+
+ hapd->dpp_auth = dpp_auth_init(hapd->msg_ctx, peer_bi, own_bi,
+ allowed_roles, neg_freq,
+ hapd->iface->hw_features,
+ hapd->iface->num_hw_features);
if (!hapd->dpp_auth)
goto fail;
hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
- hostapd_dpp_set_configurator(hapd, hapd->dpp_auth, cmd);
+ if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
+ hapd->dpp_auth, cmd) < 0) {
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ goto fail;
+ }
- /* TODO: Support iteration over all frequencies and filtering of
- * frequencies based on locally enabled channels that allow initiation
- * of transmission. */
- if (peer_bi->num_freq > 0)
- hapd->dpp_auth->curr_freq = peer_bi->freq[0];
- else
- hapd->dpp_auth->curr_freq = 2412;
+ hapd->dpp_auth->neg_freq = neg_freq;
- if (is_zero_ether_addr(peer_bi->mac_addr)) {
- dst = broadcast;
- } else {
- dst = peer_bi->mac_addr;
+ if (!is_zero_ether_addr(peer_bi->mac_addr))
os_memcpy(hapd->dpp_auth->peer_mac_addr, peer_bi->mac_addr,
ETH_ALEN);
- }
- hapd->dpp_auth_ok_on_ack = 0;
- res = hostapd_drv_send_action(hapd, hapd->dpp_auth->curr_freq, 0,
- dst, wpabuf_head(hapd->dpp_auth->req_msg),
- wpabuf_len(hapd->dpp_auth->req_msg));
-
- return res;
+ return hostapd_dpp_auth_init_next(hapd);
fail:
- dpp_configuration_free(conf_sta);
- dpp_configuration_free(conf_ap);
return -1;
}
+int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd)
+{
+ int freq;
+
+ freq = atoi(cmd);
+ if (freq <= 0)
+ return -1;
+
+ if (os_strstr(cmd, " role=configurator"))
+ hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR;
+ else if (os_strstr(cmd, " role=enrollee"))
+ hapd->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
+ else
+ hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR |
+ DPP_CAPAB_ENROLLEE;
+ hapd->dpp_qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
+
+ if (freq != hapd->iface->freq && hapd->iface->freq > 0) {
+ /* TODO: Listen operation on non-operating channel */
+ wpa_printf(MSG_INFO,
+ "DPP: Listen operation on non-operating channel (%d MHz) is not yet supported (operating channel: %d MHz)",
+ freq, hapd->iface->freq);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void hostapd_dpp_listen_stop(struct hostapd_data *hapd)
+{
+ /* TODO: Stop listen operation on non-operating channel */
+}
+
+
static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
const u8 *hdr, const u8 *buf, size_t len,
unsigned int freq)
{
- const u8 *r_bootstrap, *i_bootstrap, *wrapped_data;
- u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len;
- struct dpp_bootstrap_info *bi, *own_bi = NULL, *peer_bi = NULL;
+ const u8 *r_bootstrap, *i_bootstrap;
+ u16 r_bootstrap_len, i_bootstrap_len;
+ struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
+
+ if (!hapd->iface->interfaces->dpp)
+ return;
wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
MAC2STR(src));
- wrapped_data = dpp_get_attr(buf, len, DPP_ATTR_WRAPPED_DATA,
- &wrapped_data_len);
- if (!wrapped_data) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing required Wrapped data attribute");
- return;
- }
- wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped data",
- wrapped_data, wrapped_data_len);
-
r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
&r_bootstrap_len);
- if (!r_bootstrap || r_bootstrap > wrapped_data ||
- r_bootstrap_len != SHA256_MAC_LEN) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Responder Bootstrapping Key Hash attribute");
return;
}
wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
@@ -566,10 +545,9 @@
i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
&i_bootstrap_len);
- if (!i_bootstrap || i_bootstrap > wrapped_data ||
- i_bootstrap_len != SHA256_MAC_LEN) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid required Initiator Bootstrapping Key Hash attribute");
+ if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
return;
}
wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
@@ -577,103 +555,54 @@
/* Try to find own and peer bootstrapping key matches based on the
* received hash values */
- dl_list_for_each(bi, &hapd->dpp_bootstrap, struct dpp_bootstrap_info,
- list) {
- if (!own_bi && bi->own &&
- os_memcmp(bi->pubkey_hash, r_bootstrap,
- SHA256_MAC_LEN) == 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Found matching own bootstrapping information");
- own_bi = bi;
- }
-
- if (!peer_bi && !bi->own &&
- os_memcmp(bi->pubkey_hash, i_bootstrap,
- SHA256_MAC_LEN) == 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Found matching peer bootstrapping information");
- peer_bi = bi;
- }
-
- if (own_bi && peer_bi)
- break;
- }
-
+ dpp_bootstrap_find_pair(hapd->iface->interfaces->dpp, i_bootstrap,
+ r_bootstrap, &own_bi, &peer_bi);
if (!own_bi) {
- wpa_printf(MSG_DEBUG,
- "DPP: No matching own bootstrapping key found - ignore message");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "No matching own bootstrapping key found - ignore message");
return;
}
if (hapd->dpp_auth) {
- wpa_printf(MSG_DEBUG,
- "DPP: Already in DPP authentication exchange - ignore new one");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Already in DPP authentication exchange - ignore new one");
return;
}
hapd->dpp_auth_ok_on_ack = 0;
hapd->dpp_auth = dpp_auth_req_rx(hapd->msg_ctx, hapd->dpp_allowed_roles,
hapd->dpp_qr_mutual,
- peer_bi, own_bi, freq, hdr, buf,
- wrapped_data, wrapped_data_len);
+ peer_bi, own_bi, freq, hdr, buf, len);
if (!hapd->dpp_auth) {
wpa_printf(MSG_DEBUG, "DPP: No response generated");
return;
}
hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
- hostapd_dpp_set_configurator(hapd, hapd->dpp_auth,
- hapd->dpp_configurator_params);
+ if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
+ hapd->dpp_auth,
+ hapd->dpp_configurator_params) < 0) {
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ return;
+ }
os_memcpy(hapd->dpp_auth->peer_mac_addr, src, ETH_ALEN);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d",
+ MAC2STR(src), hapd->dpp_auth->curr_freq,
+ DPP_PA_AUTHENTICATION_RESP);
hostapd_drv_send_action(hapd, hapd->dpp_auth->curr_freq, 0,
src, wpabuf_head(hapd->dpp_auth->resp_msg),
wpabuf_len(hapd->dpp_auth->resp_msg));
}
-static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
- enum gas_query_ap_result result,
- const struct wpabuf *adv_proto,
- const struct wpabuf *resp, u16 status_code)
+static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
+ struct dpp_authentication *auth)
{
- struct hostapd_data *hapd = ctx;
- const u8 *pos;
- struct dpp_authentication *auth = hapd->dpp_auth;
-
- if (!auth || !auth->auth_success) {
- wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
- return;
- }
- if (!resp || status_code != WLAN_STATUS_SUCCESS) {
- wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed");
- goto fail;
- }
-
- wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response adv_proto",
- adv_proto);
- wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response (GAS response)",
- resp);
-
- if (wpabuf_len(adv_proto) != 10 ||
- !(pos = wpabuf_head(adv_proto)) ||
- pos[0] != WLAN_EID_ADV_PROTO ||
- pos[1] != 8 ||
- pos[3] != WLAN_EID_VENDOR_SPECIFIC ||
- pos[4] != 5 ||
- WPA_GET_BE24(&pos[5]) != OUI_WFA ||
- pos[8] != 0x1a ||
- pos[9] != 1) {
- wpa_printf(MSG_DEBUG,
- "DPP: Not a DPP Advertisement Protocol ID");
- goto fail;
- }
-
- if (dpp_conf_resp_rx(auth, resp) < 0) {
- wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
- goto fail;
- }
-
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_AKM "%s",
+ dpp_akm_str(auth->akm));
if (auth->ssid_len)
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
wpa_ssid_txt(auth->ssid, auth->ssid_len));
@@ -736,12 +665,88 @@
os_free(hex);
}
}
- dpp_auth_deinit(hapd->dpp_auth);
- hapd->dpp_auth = NULL;
- return;
+}
+
+static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
+ enum gas_query_ap_result result,
+ const struct wpabuf *adv_proto,
+ const struct wpabuf *resp, u16 status_code)
+{
+ struct hostapd_data *hapd = ctx;
+ const u8 *pos;
+ struct dpp_authentication *auth = hapd->dpp_auth;
+ enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
+
+ if (!auth || !auth->auth_success) {
+ wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
+ return;
+ }
+ if (!resp || status_code != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed");
+ goto fail;
+ }
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response adv_proto",
+ adv_proto);
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response (GAS response)",
+ resp);
+
+ if (wpabuf_len(adv_proto) != 10 ||
+ !(pos = wpabuf_head(adv_proto)) ||
+ pos[0] != WLAN_EID_ADV_PROTO ||
+ pos[1] != 8 ||
+ pos[3] != WLAN_EID_VENDOR_SPECIFIC ||
+ pos[4] != 5 ||
+ WPA_GET_BE24(&pos[5]) != OUI_WFA ||
+ pos[8] != 0x1a ||
+ pos[9] != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not a DPP Advertisement Protocol ID");
+ goto fail;
+ }
+
+ if (dpp_conf_resp_rx(auth, resp) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
+ goto fail;
+ }
+
+ hostapd_dpp_handle_config_obj(hapd, auth);
+ status = DPP_STATUS_OK;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_REJECT_CONFIG) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - Reject Config Object");
+ status = DPP_STATUS_CONFIG_REJECTED;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
fail:
- wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ if (status != DPP_STATUS_OK)
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
+#ifdef CONFIG_DPP2
+ if (auth->peer_version >= 2 &&
+ auth->conf_resp_status == DPP_STATUS_OK) {
+ struct wpabuf *msg;
+
+ wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
+ msg = dpp_build_conf_result(auth, status);
+ if (!msg)
+ goto fail2;
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(addr), auth->curr_freq,
+ DPP_PA_CONFIGURATION_RESULT);
+ hostapd_drv_send_action(hapd, auth->curr_freq, 0,
+ addr, wpabuf_head(msg),
+ wpabuf_len(msg));
+ wpabuf_free(msg);
+
+ /* This exchange will be terminated in the TX status handler */
+ auth->connect_on_tx_status = 1;
+ return;
+ }
+fail2:
+#endif /* CONFIG_DPP2 */
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
}
@@ -750,7 +755,7 @@
static void hostapd_dpp_start_gas_client(struct hostapd_data *hapd)
{
struct dpp_authentication *auth = hapd->dpp_auth;
- struct wpabuf *buf, *conf_req;
+ struct wpabuf *buf;
char json[100];
int res;
int netrole_ap = 1;
@@ -762,34 +767,13 @@
netrole_ap ? "ap" : "sta");
wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
- conf_req = dpp_build_conf_req(auth, json);
- if (!conf_req) {
+ buf = dpp_build_conf_req(auth, json);
+ if (!buf) {
wpa_printf(MSG_DEBUG,
"DPP: No configuration request data available");
return;
}
- buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req));
- if (!buf) {
- wpabuf_free(conf_req);
- return;
- }
-
- /* Advertisement Protocol IE */
- wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
- wpabuf_put_u8(buf, 8); /* Length */
- wpabuf_put_u8(buf, 0x7f);
- wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
- wpabuf_put_u8(buf, 5);
- wpabuf_put_be24(buf, OUI_WFA);
- wpabuf_put_u8(buf, DPP_OUI_TYPE);
- wpabuf_put_u8(buf, 0x01);
-
- /* GAS Query */
- wpabuf_put_le16(buf, wpabuf_len(conf_req));
- wpabuf_put_buf(buf, conf_req);
- wpabuf_free(conf_req);
-
wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR " (freq %u MHz)",
MAC2STR(auth->peer_mac_addr), auth->curr_freq);
@@ -811,6 +795,17 @@
wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d",
initiator);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at Authentication Confirm");
+ if (hapd->dpp_auth->configurator) {
+ /* Prevent GAS response */
+ hapd->dpp_auth->auth_success = 0;
+ }
+ return;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
if (!hapd->dpp_auth->configurator)
hostapd_dpp_start_gas_client(hapd);
@@ -818,7 +813,8 @@
static void hostapd_dpp_rx_auth_resp(struct hostapd_data *hapd, const u8 *src,
- const u8 *hdr, const u8 *buf, size_t len)
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
{
struct dpp_authentication *auth = hapd->dpp_auth;
struct wpabuf *msg;
@@ -839,6 +835,15 @@
return;
}
+ eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
+
+ if (auth->curr_freq != freq && auth->neg_freq == freq) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Responder accepted request for different negotiation channel");
+ auth->curr_freq = freq;
+ }
+
+ eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
msg = dpp_auth_resp_rx(auth, hdr, buf, len);
if (!msg) {
if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
@@ -850,6 +855,9 @@
}
os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d", MAC2STR(src), auth->curr_freq,
+ DPP_PA_AUTHENTICATION_CONF);
hostapd_drv_send_action(hapd, auth->curr_freq, 0, src,
wpabuf_head(msg), wpabuf_len(msg));
wpabuf_free(msg);
@@ -886,6 +894,155 @@
}
+#ifdef CONFIG_DPP2
+
+static void hostapd_dpp_config_result_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct dpp_authentication *auth = hapd->dpp_auth;
+
+ if (!auth || !auth->waiting_conf_result)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Timeout while waiting for Configuration Result");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ dpp_auth_deinit(auth);
+ hapd->dpp_auth = NULL;
+}
+
+
+static void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len)
+{
+ struct dpp_authentication *auth = hapd->dpp_auth;
+ enum dpp_status_error status;
+
+ wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR,
+ MAC2STR(src));
+
+ if (!auth || !auth->waiting_conf_result) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for result - drop");
+ return;
+ }
+
+ if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
+ MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
+ return;
+ }
+
+ status = dpp_conf_result_rx(auth, hdr, buf, len);
+
+ hostapd_drv_send_action_cancel_wait(hapd);
+ hostapd_dpp_listen_stop(hapd);
+ if (status == DPP_STATUS_OK)
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
+ else
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ dpp_auth_deinit(auth);
+ hapd->dpp_auth = NULL;
+ eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
+ NULL);
+}
+
+#endif /* CONFIG_DPP2 */
+
+
+static void hostapd_dpp_send_peer_disc_resp(struct hostapd_data *hapd,
+ const u8 *src, unsigned int freq,
+ u8 trans_id,
+ enum dpp_status_error status)
+{
+ struct wpabuf *msg;
+
+ msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_RESP,
+ 5 + 5 + 4 + os_strlen(hapd->conf->dpp_connector));
+ if (!msg)
+ return;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Transaction ID");
+ goto skip_trans_id;
+ }
+ if (dpp_test == DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Transaction ID");
+ trans_id ^= 0x01;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Transaction ID */
+ wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, trans_id);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_trans_id:
+ if (dpp_test == DPP_TEST_NO_STATUS_PEER_DISC_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
+ goto skip_status;
+ }
+ if (dpp_test == DPP_TEST_INVALID_STATUS_PEER_DISC_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
+ status = 254;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* DPP Status */
+ wpabuf_put_le16(msg, DPP_ATTR_STATUS);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, status);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_status:
+ if (dpp_test == DPP_TEST_NO_CONNECTOR_PEER_DISC_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Connector");
+ goto skip_connector;
+ }
+ if (status == DPP_STATUS_OK &&
+ dpp_test == DPP_TEST_INVALID_CONNECTOR_PEER_DISC_RESP) {
+ char *connector;
+
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Connector");
+ connector = dpp_corrupt_connector_signature(
+ hapd->conf->dpp_connector);
+ if (!connector) {
+ wpabuf_free(msg);
+ return;
+ }
+ wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
+ wpabuf_put_le16(msg, os_strlen(connector));
+ wpabuf_put_str(msg, connector);
+ os_free(connector);
+ goto skip_connector;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* DPP Connector */
+ if (status == DPP_STATUS_OK) {
+ wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
+ wpabuf_put_le16(msg, os_strlen(hapd->conf->dpp_connector));
+ wpabuf_put_str(msg, hapd->conf->dpp_connector);
+ }
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_connector:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_printf(MSG_DEBUG, "DPP: Send Peer Discovery Response to " MACSTR
+ " status=%d", MAC2STR(src), status);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d status=%d", MAC2STR(src), freq,
+ DPP_PA_PEER_DISCOVERY_RESP, status);
+ hostapd_drv_send_action(hapd, freq, 0, src,
+ wpabuf_head(msg), wpabuf_len(msg));
+ wpabuf_free(msg);
+}
+
+
static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
const u8 *src,
const u8 *buf, size_t len,
@@ -897,7 +1054,7 @@
struct dpp_introduction intro;
os_time_t expire;
int expiration;
- struct wpabuf *msg;
+ enum dpp_status_error res;
wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Request from " MACSTR,
MAC2STR(src));
@@ -917,7 +1074,7 @@
os_get_time(&now);
if (hapd->conf->dpp_netaccesskey_expiry &&
- hapd->conf->dpp_netaccesskey_expiry < now.sec) {
+ (os_time_t) hapd->conf->dpp_netaccesskey_expiry < now.sec) {
wpa_printf(MSG_INFO, "DPP: Own netAccessKey expired");
return;
}
@@ -937,18 +1094,28 @@
return;
}
- if (dpp_peer_intro(&intro, hapd->conf->dpp_connector,
- wpabuf_head(hapd->conf->dpp_netaccesskey),
- wpabuf_len(hapd->conf->dpp_netaccesskey),
- wpabuf_head(hapd->conf->dpp_csign),
- wpabuf_len(hapd->conf->dpp_csign),
- connector, connector_len, &expire) < 0) {
+ res = dpp_peer_intro(&intro, hapd->conf->dpp_connector,
+ wpabuf_head(hapd->conf->dpp_netaccesskey),
+ wpabuf_len(hapd->conf->dpp_netaccesskey),
+ wpabuf_head(hapd->conf->dpp_csign),
+ wpabuf_len(hapd->conf->dpp_csign),
+ connector, connector_len, &expire);
+ if (res == 255) {
wpa_printf(MSG_INFO,
- "DPP: Network Introduction protocol resulted in failure");
+ "DPP: Network Introduction protocol resulted in internal failure (peer "
+ MACSTR ")", MAC2STR(src));
+ return;
+ }
+ if (res != DPP_STATUS_OK) {
+ wpa_printf(MSG_INFO,
+ "DPP: Network Introduction protocol resulted in failure (peer "
+ MACSTR " status %d)", MAC2STR(src), res);
+ hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0],
+ res);
return;
}
- if (!expire || hapd->conf->dpp_netaccesskey_expiry < expire)
+ if (!expire || (os_time_t) hapd->conf->dpp_netaccesskey_expiry < expire)
expire = hapd->conf->dpp_netaccesskey_expiry;
if (expire)
expiration = expire - now.sec;
@@ -962,26 +1129,8 @@
return;
}
- msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_RESP,
- 5 + 4 + os_strlen(hapd->conf->dpp_connector));
- if (!msg)
- return;
-
- /* Transaction ID */
- wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
- wpabuf_put_le16(msg, 1);
- wpabuf_put_u8(msg, trans_id[0]);
-
- /* DPP Connector */
- wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
- wpabuf_put_le16(msg, os_strlen(hapd->conf->dpp_connector));
- wpabuf_put_str(msg, hapd->conf->dpp_connector);
-
- wpa_printf(MSG_DEBUG, "DPP: Send Peer Discovery Response to " MACSTR,
- MAC2STR(src));
- hostapd_drv_send_action(hapd, freq, 0, src,
- wpabuf_head(msg), wpabuf_len(msg));
- wpabuf_free(msg);
+ hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0],
+ DPP_STATUS_OK);
}
@@ -1011,7 +1160,8 @@
return;
}
- hapd->dpp_pkex = dpp_pkex_rx_exchange_req(hapd->dpp_pkex_bi,
+ hapd->dpp_pkex = dpp_pkex_rx_exchange_req(hapd->msg_ctx,
+ hapd->dpp_pkex_bi,
hapd->own_addr, src,
hapd->dpp_pkex_identifier,
hapd->dpp_pkex_code,
@@ -1023,8 +1173,19 @@
}
msg = hapd->dpp_pkex->exchange_resp;
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d", MAC2STR(src), freq,
+ DPP_PA_PKEX_EXCHANGE_RESP);
hostapd_drv_send_action(hapd, freq, 0, src,
wpabuf_head(msg), wpabuf_len(msg));
+ if (hapd->dpp_pkex->failed) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Terminate PKEX exchange due to an earlier error");
+ if (hapd->dpp_pkex->t > hapd->dpp_pkex->own_bi->pkex_t)
+ hapd->dpp_pkex->own_bi->pkex_t = hapd->dpp_pkex->t;
+ dpp_pkex_free(hapd->dpp_pkex);
+ hapd->dpp_pkex = NULL;
+ }
}
@@ -1046,8 +1207,7 @@
return;
}
- os_memcpy(hapd->dpp_pkex->peer_mac, src, ETH_ALEN);
- msg = dpp_pkex_rx_exchange_resp(hapd->dpp_pkex, buf, len);
+ msg = dpp_pkex_rx_exchange_resp(hapd->dpp_pkex, src, buf, len);
if (!msg) {
wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
return;
@@ -1056,6 +1216,9 @@
wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Request to " MACSTR,
MAC2STR(src));
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d", MAC2STR(src), freq,
+ DPP_PA_PKEX_COMMIT_REVEAL_REQ);
hostapd_drv_send_action(hapd, freq, 0, src,
wpabuf_head(msg), wpabuf_len(msg));
wpabuf_free(msg);
@@ -1082,34 +1245,31 @@
msg = dpp_pkex_rx_commit_reveal_req(pkex, hdr, buf, len);
if (!msg) {
wpa_printf(MSG_DEBUG, "DPP: Failed to process the request");
+ if (hapd->dpp_pkex->failed) {
+ wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange");
+ if (hapd->dpp_pkex->t > hapd->dpp_pkex->own_bi->pkex_t)
+ hapd->dpp_pkex->own_bi->pkex_t =
+ hapd->dpp_pkex->t;
+ dpp_pkex_free(hapd->dpp_pkex);
+ hapd->dpp_pkex = NULL;
+ }
return;
}
wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Response to "
MACSTR, MAC2STR(src));
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d", MAC2STR(src), freq,
+ DPP_PA_PKEX_COMMIT_REVEAL_RESP);
hostapd_drv_send_action(hapd, freq, 0, src,
wpabuf_head(msg), wpabuf_len(msg));
wpabuf_free(msg);
- bi = os_zalloc(sizeof(*bi));
+ bi = dpp_pkex_finish(hapd->iface->interfaces->dpp, pkex, src, freq);
if (!bi)
return;
- bi->id = hapd_dpp_next_id(hapd);
- bi->type = DPP_BOOTSTRAP_PKEX;
- os_memcpy(bi->mac_addr, src, ETH_ALEN);
- bi->num_freq = 1;
- bi->freq[0] = freq;
- bi->curve = pkex->own_bi->curve;
- bi->pubkey = pkex->peer_bootstrap_key;
- pkex->peer_bootstrap_key = NULL;
- dpp_pkex_free(pkex);
hapd->dpp_pkex = NULL;
- if (dpp_bootstrap_key_hash(bi) < 0) {
- dpp_bootstrap_info_free(bi);
- return;
- }
- dl_list_add(&hapd->dpp_bootstrap, &bi->list);
}
@@ -1119,7 +1279,7 @@
unsigned int freq)
{
int res;
- struct dpp_bootstrap_info *bi, *own_bi;
+ struct dpp_bootstrap_info *bi;
struct dpp_pkex *pkex = hapd->dpp_pkex;
char cmd[500];
@@ -1137,26 +1297,10 @@
return;
}
- own_bi = pkex->own_bi;
-
- bi = os_zalloc(sizeof(*bi));
+ bi = dpp_pkex_finish(hapd->iface->interfaces->dpp, pkex, src, freq);
if (!bi)
return;
- bi->id = hapd_dpp_next_id(hapd);
- bi->type = DPP_BOOTSTRAP_PKEX;
- os_memcpy(bi->mac_addr, src, ETH_ALEN);
- bi->num_freq = 1;
- bi->freq[0] = freq;
- bi->curve = own_bi->curve;
- bi->pubkey = pkex->peer_bootstrap_key;
- pkex->peer_bootstrap_key = NULL;
- dpp_pkex_free(pkex);
hapd->dpp_pkex = NULL;
- if (dpp_bootstrap_key_hash(bi) < 0) {
- dpp_bootstrap_info_free(bi);
- return;
- }
- dl_list_add(&hapd->dpp_bootstrap, &bi->list);
os_snprintf(cmd, sizeof(cmd), " peer=%u %s",
bi->id,
@@ -1178,6 +1322,7 @@
u8 crypto_suite;
enum dpp_public_action_frame_type type;
const u8 *hdr;
+ unsigned int pkex_t;
if (len < DPP_HDR_LEN)
return;
@@ -1197,18 +1342,27 @@
if (crypto_suite != 1) {
wpa_printf(MSG_DEBUG, "DPP: Unsupported crypto suite %u",
crypto_suite);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
+ " freq=%u type=%d ignore=unsupported-crypto-suite",
+ MAC2STR(src), freq, type);
return;
}
wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes", buf, len);
- if (dpp_check_attrs(buf, len) < 0)
+ if (dpp_check_attrs(buf, len) < 0) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
+ " freq=%u type=%d ignore=invalid-attributes",
+ MAC2STR(src), freq, type);
return;
+ }
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
+ " freq=%u type=%d", MAC2STR(src), freq, type);
switch (type) {
case DPP_PA_AUTHENTICATION_REQ:
hostapd_dpp_rx_auth_req(hapd, src, hdr, buf, len, freq);
break;
case DPP_PA_AUTHENTICATION_RESP:
- hostapd_dpp_rx_auth_resp(hapd, src, hdr, buf, len);
+ hostapd_dpp_rx_auth_resp(hapd, src, hdr, buf, len, freq);
break;
case DPP_PA_AUTHENTICATION_CONF:
hostapd_dpp_rx_auth_conf(hapd, src, hdr, buf, len);
@@ -1230,11 +1384,27 @@
hostapd_dpp_rx_pkex_commit_reveal_resp(hapd, src, hdr, buf, len,
freq);
break;
+#ifdef CONFIG_DPP2
+ case DPP_PA_CONFIGURATION_RESULT:
+ hostapd_dpp_rx_conf_result(hapd, src, hdr, buf, len);
+ break;
+#endif /* CONFIG_DPP2 */
default:
wpa_printf(MSG_DEBUG,
"DPP: Ignored unsupported frame subtype %d", type);
break;
}
+
+ if (hapd->dpp_pkex)
+ pkex_t = hapd->dpp_pkex->t;
+ else if (hapd->dpp_pkex_bi)
+ pkex_t = hapd->dpp_pkex_bi->pkex_t;
+ else
+ pkex_t = 0;
+ if (pkex_t >= PKEX_COUNTER_T_LIMIT) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PKEX_T_LIMIT "id=0");
+ hostapd_dpp_pkex_remove(hapd, "*");
+ }
}
@@ -1254,6 +1424,8 @@
wpa_hexdump(MSG_DEBUG,
"DPP: Received Configuration Request (GAS Query Request)",
query, query_len);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_REQ_RX "src=" MACSTR,
+ MAC2STR(sa));
resp = dpp_conf_req_rx(auth, query, query_len);
if (!resp)
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
@@ -1261,93 +1433,67 @@
}
-static unsigned int hostapd_dpp_next_configurator_id(struct hostapd_data *hapd)
+void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok)
{
- struct dpp_configurator *conf;
- unsigned int max_id = 0;
+ struct dpp_authentication *auth = hapd->dpp_auth;
- dl_list_for_each(conf, &hapd->dpp_configurator,
- struct dpp_configurator, list) {
- if (conf->id > max_id)
- max_id = conf->id;
+ if (!auth)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
+ ok);
+ eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
+#ifdef CONFIG_DPP2
+ if (ok && auth->peer_version >= 2 &&
+ auth->conf_resp_status == DPP_STATUS_OK) {
+ wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
+ auth->waiting_conf_result = 1;
+ eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout,
+ hapd, NULL);
+ eloop_register_timeout(2, 0,
+ hostapd_dpp_config_result_wait_timeout,
+ hapd, NULL);
+ return;
}
- return max_id + 1;
+#endif /* CONFIG_DPP2 */
+ hostapd_drv_send_action_cancel_wait(hapd);
+
+ if (ok)
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
+ else
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
}
-int hostapd_dpp_configurator_add(struct hostapd_data *hapd, const char *cmd)
+int hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd)
{
- char *curve = NULL;
- char *key = NULL;
- u8 *privkey = NULL;
- size_t privkey_len = 0;
+ struct dpp_authentication *auth;
int ret = -1;
- struct dpp_configurator *conf = NULL;
+ char *curve = NULL;
+
+ auth = os_zalloc(sizeof(*auth));
+ if (!auth)
+ return -1;
curve = get_param(cmd, " curve=");
- key = get_param(cmd, " key=");
-
- if (key) {
- privkey_len = os_strlen(key) / 2;
- privkey = os_malloc(privkey_len);
- if (!privkey ||
- hexstr2bin(key, privkey, privkey_len) < 0)
- goto fail;
+ hostapd_dpp_set_testing_options(hapd, auth);
+ if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
+ auth, cmd) == 0 &&
+ dpp_configurator_own_config(auth, curve, 1) == 0) {
+ hostapd_dpp_handle_config_obj(hapd, auth);
+ ret = 0;
}
- conf = dpp_keygen_configurator(curve, privkey, privkey_len);
- if (!conf)
- goto fail;
-
- conf->id = hostapd_dpp_next_configurator_id(hapd);
- dl_list_add(&hapd->dpp_configurator, &conf->list);
- ret = conf->id;
- conf = NULL;
-fail:
+ dpp_auth_deinit(auth);
os_free(curve);
- str_clear_free(key);
- bin_clear_free(privkey, privkey_len);
- dpp_configurator_free(conf);
+
return ret;
}
-static int dpp_configurator_del(struct hostapd_data *hapd, unsigned int id)
-{
- struct dpp_configurator *conf, *tmp;
- int found = 0;
-
- dl_list_for_each_safe(conf, tmp, &hapd->dpp_configurator,
- struct dpp_configurator, list) {
- if (id && conf->id != id)
- continue;
- found = 1;
- dl_list_del(&conf->list);
- dpp_configurator_free(conf);
- }
-
- if (id == 0)
- return 0; /* flush succeeds regardless of entries found */
- return found ? 0 : -1;
-}
-
-
-int hostapd_dpp_configurator_remove(struct hostapd_data *hapd, const char *id)
-{
- unsigned int id_val;
-
- if (os_strcmp(id, "*") == 0) {
- id_val = 0;
- } else {
- id_val = atoi(id);
- if (id_val == 0)
- return -1;
- }
-
- return dpp_configurator_del(hapd, id_val);
-}
-
-
int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
{
struct dpp_bootstrap_info *own_bi;
@@ -1357,7 +1503,7 @@
if (!pos)
return -1;
pos += 5;
- own_bi = dpp_bootstrap_get_id(hapd, atoi(pos));
+ own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
if (!own_bi) {
wpa_printf(MSG_DEBUG,
"DPP: Identified bootstrap info not found");
@@ -1369,6 +1515,7 @@
return -1;
}
hapd->dpp_pkex_bi = own_bi;
+ own_bi->pkex_t = 0; /* clear pending errors on new code */
os_free(hapd->dpp_pkex_identifier);
hapd->dpp_pkex_identifier = NULL;
@@ -1398,7 +1545,8 @@
wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX");
dpp_pkex_free(hapd->dpp_pkex);
- hapd->dpp_pkex = dpp_pkex_init(own_bi, hapd->own_addr,
+ hapd->dpp_pkex = dpp_pkex_init(hapd->msg_ctx, own_bi,
+ hapd->own_addr,
hapd->dpp_pkex_identifier,
hapd->dpp_pkex_code);
if (!hapd->dpp_pkex)
@@ -1406,6 +1554,9 @@
msg = hapd->dpp_pkex->exchange_req;
/* TODO: Which channel to use? */
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d", MAC2STR(broadcast), 2437,
+ DPP_PA_PKEX_EXCHANGE_REQ);
hostapd_drv_send_action(hapd, 2437, 0, broadcast,
wpabuf_head(msg), wpabuf_len(msg));
}
@@ -1449,10 +1600,17 @@
}
+void hostapd_dpp_stop(struct hostapd_data *hapd)
+{
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ dpp_pkex_free(hapd->dpp_pkex);
+ hapd->dpp_pkex = NULL;
+}
+
+
int hostapd_dpp_init(struct hostapd_data *hapd)
{
- dl_list_init(&hapd->dpp_bootstrap);
- dl_list_init(&hapd->dpp_configurator);
hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE;
hapd->dpp_init_done = 1;
return 0;
@@ -1472,8 +1630,13 @@
#endif /* CONFIG_TESTING_OPTIONS */
if (!hapd->dpp_init_done)
return;
- dpp_bootstrap_del(hapd, 0);
- dpp_configurator_del(hapd, 0);
+ eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
+#ifdef CONFIG_DPP2
+ eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
+ NULL);
+#endif /* CONFIG_DPP2 */
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
hostapd_dpp_pkex_remove(hapd, "*");
diff --git a/src/ap/dpp_hostapd.h b/src/ap/dpp_hostapd.h
index d870b20..449ca16 100644
--- a/src/ap/dpp_hostapd.h
+++ b/src/ap/dpp_hostapd.h
@@ -10,13 +10,9 @@
#define DPP_HOSTAPD_H
int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd);
-int hostapd_dpp_bootstrap_gen(struct hostapd_data *hapd, const char *cmd);
-int hostapd_dpp_bootstrap_remove(struct hostapd_data *hapd, const char *id);
-const char * hostapd_dpp_bootstrap_get_uri(struct hostapd_data *hapd,
- unsigned int id);
-int hostapd_dpp_bootstrap_info(struct hostapd_data *hapd, int id,
- char *reply, int reply_size);
int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd);
+void hostapd_dpp_listen_stop(struct hostapd_data *hapd);
void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
const u8 *buf, size_t len, unsigned int freq);
void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
@@ -24,11 +20,18 @@
struct wpabuf *
hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
const u8 *query, size_t query_len);
+void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok);
int hostapd_dpp_configurator_add(struct hostapd_data *hapd, const char *cmd);
int hostapd_dpp_configurator_remove(struct hostapd_data *hapd, const char *id);
+int hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_configurator_get_key(struct hostapd_data *hapd, unsigned int id,
+ char *buf, size_t buflen);
int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd);
int hostapd_dpp_pkex_remove(struct hostapd_data *hapd, const char *id);
+void hostapd_dpp_stop(struct hostapd_data *hapd);
int hostapd_dpp_init(struct hostapd_data *hapd);
void hostapd_dpp_deinit(struct hostapd_data *hapd);
+void hostapd_dpp_init_global(struct hapd_interfaces *ifaces);
+void hostapd_dpp_deinit_global(struct hapd_interfaces *ifaces);
#endif /* DPP_HOSTAPD_H */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 648f20e..952a3d5 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -15,6 +15,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
+#include "common/dpp.h"
#include "crypto/random.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
@@ -38,6 +39,7 @@
#include "mbo_ap.h"
#include "dpp_hostapd.h"
#include "fils_hlp.h"
+#include "neighbor_db.h"
#ifdef CONFIG_FILS
@@ -109,10 +111,10 @@
struct ieee802_11_elems elems;
const u8 *ie;
size_t ielen;
-#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
+#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
u8 *p = buf;
-#endif /* CONFIG_IEEE80211R_AP || CONFIG_IEEE80211W || CONFIG_FILS */
+#endif /* CONFIG_IEEE80211R_AP || CONFIG_IEEE80211W || CONFIG_FILS || CONFIG_OWE */
u16 reason = WLAN_REASON_UNSPECIFIED;
u16 status = WLAN_STATUS_SUCCESS;
const u8 *p2p_dev_addr = NULL;
@@ -235,6 +237,14 @@
elems.hs20_len - 4);
} else
sta->hs20_ie = NULL;
+
+ wpabuf_free(sta->roaming_consortium);
+ if (elems.roaming_cons_sel)
+ sta->roaming_consortium = wpabuf_alloc_copy(
+ elems.roaming_cons_sel + 4,
+ elems.roaming_cons_sel_len - 4);
+ else
+ sta->roaming_consortium = NULL;
#endif /* CONFIG_HS20 */
#ifdef CONFIG_FST
@@ -262,7 +272,9 @@
#endif /* CONFIG_WPS */
wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
- return -1;
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ goto fail;
}
#ifdef CONFIG_WPS
if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
@@ -294,6 +306,7 @@
return -1;
}
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+ hapd->iface->freq,
ie, ielen,
elems.mdie, elems.mdie_len,
elems.owe_dh, elems.owe_dh_len);
@@ -317,8 +330,8 @@
reason = WLAN_REASON_INVALID_IE;
status = WLAN_STATUS_INVALID_IE;
} else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
- reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
- status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+ reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
+ status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
}
#endif /* CONFIG_IEEE80211W */
else {
@@ -328,10 +341,14 @@
goto fail;
}
#ifdef CONFIG_IEEE80211W
- if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+ 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_MFP) && !sta->sa_query_timed_out &&
+ 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
@@ -443,6 +460,10 @@
#ifdef CONFIG_IEEE80211R_AP
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
sta->auth_alg, req_ies, req_ies_len);
+ if (!p) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_FILS
@@ -520,7 +541,64 @@
}
#endif /* CONFIG_FILS */
-#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS)
+#ifdef CONFIG_OWE
+ if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
+ wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
+ elems.owe_dh) {
+ u8 *npos;
+
+ npos = owe_assoc_req_process(hapd, sta,
+ elems.owe_dh, elems.owe_dh_len,
+ p, sizeof(buf) - (p - buf),
+ &reason);
+ if (npos)
+ p = npos;
+ if (!npos &&
+ reason == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
+ status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
+ p - buf);
+ return 0;
+ }
+
+ if (!npos || reason != WLAN_STATUS_SUCCESS)
+ goto fail;
+ }
+#endif /* CONFIG_OWE */
+
+#ifdef CONFIG_DPP2
+ dpp_pfs_free(sta->dpp_pfs);
+ sta->dpp_pfs = NULL;
+
+ if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
+ hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
+ wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
+ elems.owe_dh) {
+ sta->dpp_pfs = dpp_pfs_init(
+ wpabuf_head(hapd->conf->dpp_netaccesskey),
+ wpabuf_len(hapd->conf->dpp_netaccesskey));
+ if (!sta->dpp_pfs) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not initialize PFS");
+ /* Try to continue without PFS */
+ goto pfs_fail;
+ }
+
+ if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh,
+ elems.owe_dh_len) < 0) {
+ dpp_pfs_free(sta->dpp_pfs);
+ sta->dpp_pfs = NULL;
+ reason = WLAN_REASON_UNSPECIFIED;
+ goto fail;
+ }
+ }
+
+ wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ?
+ sta->dpp_pfs->secret : NULL);
+ pfs_fail:
+#endif /* CONFIG_DPP2 */
+
+#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
if (sta->auth_alg == WLAN_AUTH_FT ||
@@ -615,7 +693,7 @@
{
struct sta_info *sta = ap_get_sta(hapd, addr);
- if (!sta || !hapd->conf->disassoc_low_ack)
+ if (!sta || !hapd->conf->disassoc_low_ack || sta->agreed_to_steer)
return;
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
@@ -626,18 +704,95 @@
}
+void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr,
+ enum smps_mode smps_mode,
+ enum chan_width chan_width, u8 rx_nss)
+{
+ struct sta_info *sta = ap_get_sta(hapd, addr);
+ const char *txt;
+
+ if (!sta)
+ return;
+
+ switch (smps_mode) {
+ case SMPS_AUTOMATIC:
+ txt = "automatic";
+ break;
+ case SMPS_OFF:
+ txt = "off";
+ break;
+ case SMPS_DYNAMIC:
+ txt = "dynamic";
+ break;
+ case SMPS_STATIC:
+ txt = "static";
+ break;
+ default:
+ txt = NULL;
+ break;
+ }
+ if (txt) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_SMPS_MODE_CHANGED
+ MACSTR " %s", MAC2STR(addr), txt);
+ }
+
+ switch (chan_width) {
+ case CHAN_WIDTH_20_NOHT:
+ txt = "20(no-HT)";
+ break;
+ case CHAN_WIDTH_20:
+ txt = "20";
+ break;
+ case CHAN_WIDTH_40:
+ txt = "40";
+ break;
+ case CHAN_WIDTH_80:
+ txt = "80";
+ break;
+ case CHAN_WIDTH_80P80:
+ txt = "80+80";
+ break;
+ case CHAN_WIDTH_160:
+ txt = "160";
+ break;
+ default:
+ txt = NULL;
+ break;
+ }
+ if (txt) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_MAX_BW_CHANGED
+ MACSTR " %s", MAC2STR(addr), txt);
+ }
+
+ if (rx_nss != 0xff) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_N_SS_CHANGED
+ MACSTR " %d", MAC2STR(addr), rx_nss);
+ }
+}
+
+
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset, int width, int cf1, int cf2)
{
+ /* 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;
+ size_t i;
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
- "driver had channel switch: freq=%d, ht=%d, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
- freq, ht, offset, width, channel_width_to_string(width),
- cf1, cf2);
+ "driver had channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
+ freq, ht, hapd->iconf->ch_switch_vht_config, offset,
+ width, channel_width_to_string(width), cf1, cf2);
+
+ if (!hapd->iface->current_mode) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_WARNING,
+ "ignore channel switch since the interface is not yet ready");
+ return;
+ }
hapd->iface->freq = freq;
@@ -682,14 +837,26 @@
hapd->iconf->channel = channel;
hapd->iconf->ieee80211n = ht;
- if (!ht)
+ if (!ht) {
hapd->iconf->ieee80211ac = 0;
+ } else if (hapd->iconf->ch_switch_vht_config) {
+ /* CHAN_SWITCH VHT config */
+ if (hapd->iconf->ch_switch_vht_config &
+ CH_SWITCH_VHT_ENABLED)
+ hapd->iconf->ieee80211ac = 1;
+ else if (hapd->iconf->ch_switch_vht_config &
+ CH_SWITCH_VHT_DISABLED)
+ hapd->iconf->ieee80211ac = 0;
+ }
+ hapd->iconf->ch_switch_vht_config = 0;
+
hapd->iconf->secondary_channel = offset;
hapd->iconf->vht_oper_chwidth = chwidth;
hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx;
hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx;
- is_dfs = ieee80211_is_dfs(freq);
+ is_dfs = ieee80211_is_dfs(freq, hapd->iface->hw_features,
+ hapd->iface->num_hw_features);
if (hapd->csa_in_progress &&
freq == hapd->cs_freq_params.freq) {
@@ -702,6 +869,9 @@
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
"freq=%d dfs=%d", freq, is_dfs);
}
+
+ for (i = 0; i < hapd->iface->num_bss; i++)
+ hostapd_neighbor_set_own_report(hapd->iface->bss[i]);
#endif /* NEED_AP_MLME */
}
@@ -943,6 +1113,7 @@
}
+#ifndef NEED_AP_MLME
static void hostapd_action_rx(struct hostapd_data *hapd,
struct rx_mgmt *drv_mgmt)
{
@@ -950,19 +1121,23 @@
struct sta_info *sta;
size_t plen __maybe_unused;
u16 fc;
+ u8 *action __maybe_unused;
- if (drv_mgmt->frame_len < 24 + 1)
+ if (drv_mgmt->frame_len < IEEE80211_HDRLEN + 2 + 1)
return;
- plen = drv_mgmt->frame_len - 24 - 1;
+ plen = drv_mgmt->frame_len - IEEE80211_HDRLEN;
mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame;
fc = le_to_host16(mgmt->frame_control);
if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
return; /* handled by the driver */
- wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d",
- mgmt->u.action.category, (int) plen);
+ action = (u8 *) &mgmt->u.action.u;
+ wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR
+ " da " MACSTR " plen %d",
+ mgmt->u.action.category, *action,
+ MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) plen);
sta = ap_get_sta(hapd, mgmt->sa);
if (sta == NULL) {
@@ -971,22 +1146,20 @@
}
#ifdef CONFIG_IEEE80211R_AP
if (mgmt->u.action.category == WLAN_ACTION_FT) {
- const u8 *payload = drv_mgmt->frame + 24 + 1;
-
- wpa_ft_action_rx(sta->wpa_sm, payload, plen);
+ wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action, plen);
+ return;
}
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
- if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY && plen >= 4) {
- ieee802_11_sa_query_action(
- hapd, mgmt->sa,
- mgmt->u.action.u.sa_query_resp.action,
- mgmt->u.action.u.sa_query_resp.trans_id);
+ if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY) {
+ ieee802_11_sa_query_action(hapd, mgmt, drv_mgmt->frame_len);
+ return;
}
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WNM_AP
if (mgmt->u.action.category == WLAN_ACTION_WNM) {
ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
+ return;
}
#endif /* CONFIG_WNM_AP */
#ifdef CONFIG_FST
@@ -996,7 +1169,7 @@
}
#endif /* CONFIG_FST */
#ifdef CONFIG_DPP
- if (plen >= 1 + 4 &&
+ if (plen >= 2 + 4 &&
mgmt->u.action.u.vs_public_action.action ==
WLAN_PA_VENDOR_SPECIFIC &&
WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
@@ -1013,6 +1186,7 @@
}
#endif /* CONFIG_DPP */
}
+#endif /* NEED_AP_MLME */
#ifdef NEED_AP_MLME
@@ -1095,6 +1269,7 @@
}
os_memset(&fi, 0, sizeof(fi));
+ fi.freq = rx_mgmt->freq;
fi.datarate = rx_mgmt->datarate;
fi.ssi_signal = rx_mgmt->ssi_signal;
@@ -1378,6 +1553,28 @@
#endif /* NEED_AP_MLME */
+static void hostapd_event_wds_sta_interface_status(struct hostapd_data *hapd,
+ int istatus,
+ const char *ifname,
+ const u8 *addr)
+{
+ struct sta_info *sta = ap_get_sta(hapd, addr);
+
+ if (sta) {
+ os_free(sta->ifname_wds);
+ if (istatus == INTERFACE_ADDED)
+ sta->ifname_wds = os_strdup(ifname);
+ else
+ sta->ifname_wds = NULL;
+ }
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO, "%sifname=%s sta_addr=" MACSTR,
+ istatus == INTERFACE_ADDED ?
+ WDS_STA_INTERFACE_ADDED : WDS_STA_INTERFACE_REMOVED,
+ ifname, MAC2STR(addr));
+}
+
+
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
@@ -1451,10 +1648,10 @@
if (!data->rx_mgmt.frame)
break;
#ifdef NEED_AP_MLME
- if (hostapd_mgmt_rx(hapd, &data->rx_mgmt) > 0)
- break;
-#endif /* NEED_AP_MLME */
+ hostapd_mgmt_rx(hapd, &data->rx_mgmt);
+#else /* NEED_AP_MLME */
hostapd_action_rx(hapd, &data->rx_mgmt);
+#endif /* NEED_AP_MLME */
break;
case EVENT_RX_PROBE_REQ:
if (data->rx_probe_req.sa == NULL ||
@@ -1570,9 +1767,17 @@
* Try to re-enable interface if the driver stopped it
* when the interface got disabled.
*/
- wpa_auth_reconfig_group_keys(hapd->wpa_auth);
+ if (hapd->wpa_auth)
+ wpa_auth_reconfig_group_keys(hapd->wpa_auth);
+ else
+ hostapd_reconfig_encryption(hapd);
hapd->reenable_beacon = 1;
ieee802_11_set_beacon(hapd);
+#ifdef NEED_AP_MLME
+ } else if (hapd->disabled && hapd->iface->cac_started) {
+ wpa_printf(MSG_DEBUG, "DFS: restarting pending CAC");
+ hostapd_handle_dfs(hapd->iface);
+#endif /* NEED_AP_MLME */
}
break;
case EVENT_INTERFACE_DISABLED:
@@ -1586,6 +1791,18 @@
&data->acs_selected_channels);
break;
#endif /* CONFIG_ACS */
+ case EVENT_STATION_OPMODE_CHANGED:
+ hostapd_event_sta_opmode_changed(hapd, data->sta_opmode.addr,
+ data->sta_opmode.smps_mode,
+ data->sta_opmode.chan_width,
+ data->sta_opmode.rx_nss);
+ break;
+ case EVENT_WDS_STA_INTERFACE_STATUS:
+ hostapd_event_wds_sta_interface_status(
+ hapd, data->wds_sta_interface.istatus,
+ data->wds_sta_interface.ifname,
+ data->wds_sta_interface.sta_addr);
+ break;
default:
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
break;
diff --git a/src/ap/eap_user_db.c b/src/ap/eap_user_db.c
index 082d0f5..a510ee3 100644
--- a/src/ap/eap_user_db.c
+++ b/src/ap/eap_user_db.c
@@ -91,6 +91,8 @@
set_user_methods(user, argv[i]);
} else if (os_strcmp(col[i], "remediation") == 0 && argv[i]) {
user->remediation = strlen(argv[i]) > 0;
+ } else if (os_strcmp(col[i], "t_c_timestamp") == 0 && argv[i]) {
+ user->t_c_timestamp = strtol(argv[i], NULL, 10);
}
}
@@ -137,6 +139,7 @@
struct hostapd_eap_user *user = NULL;
char id_str[256], cmd[300];
size_t i;
+ int res;
if (identity_len >= sizeof(id_str)) {
wpa_printf(MSG_DEBUG, "%s: identity len too big: %d >= %d",
@@ -172,6 +175,7 @@
if (hapd->tmp_eap_user.identity == NULL)
return NULL;
os_memcpy(hapd->tmp_eap_user.identity, identity, identity_len);
+ hapd->tmp_eap_user.identity_len = identity_len;
if (sqlite3_open(hapd->conf->eap_user_sqlite, &db)) {
wpa_printf(MSG_INFO, "DB: Failed to open database %s: %s",
@@ -180,9 +184,12 @@
return NULL;
}
- os_snprintf(cmd, sizeof(cmd),
- "SELECT * FROM users WHERE identity='%s' AND phase2=%d;",
- id_str, phase2);
+ res = os_snprintf(cmd, sizeof(cmd),
+ "SELECT * FROM users WHERE identity='%s' AND phase2=%d;",
+ id_str, phase2);
+ if (os_snprintf_error(sizeof(cmd), res))
+ goto fail;
+
wpa_printf(MSG_DEBUG, "DB: %s", cmd);
if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) !=
SQLITE_OK) {
@@ -212,6 +219,7 @@
}
}
+fail:
sqlite3_close(db);
return user;
diff --git a/src/ap/fils_hlp.c b/src/ap/fils_hlp.c
index 2a359ab..6da514a 100644
--- a/src/ap/fils_hlp.c
+++ b/src/ap/fils_hlp.c
@@ -580,6 +580,19 @@
u8 *tmp, *tmp_pos;
int ret = 0;
+ if (sta->fils_pending_assoc_req &&
+ eloop_is_timeout_registered(fils_hlp_timeout, hapd, sta)) {
+ /* Do not process FILS HLP request again if the station
+ * retransmits (Re)Association Request frame before the previous
+ * HLP response has either been received or timed out. */
+ wpa_printf(MSG_DEBUG,
+ "FILS: Do not relay another HLP request from "
+ MACSTR
+ " before processing of the already pending one has been completed",
+ MAC2STR(sta->addr));
+ return 1;
+ }
+
/* Old DHCPDISCOVER is not needed anymore, if it was still pending */
wpabuf_free(sta->hlp_dhcp_discover);
sta->hlp_dhcp_discover = NULL;
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index fadb740..a7df810 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -181,8 +181,12 @@
wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
if (hapd->conf->hs20_osu_providers_count)
wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_LIST);
+ if (hapd->conf->hs20_osu_providers_nai_count)
+ wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_NAI_LIST);
if (hapd->conf->hs20_icons_count)
wpabuf_put_u8(buf, HS20_STYPE_ICON_REQUEST);
+ if (hapd->conf->hs20_operator_icon_count)
+ wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_ICON_METADATA);
gas_anqp_set_element_len(buf, len);
}
#endif /* CONFIG_HS20 */
@@ -288,7 +292,7 @@
#endif /* CONFIG_FILS */
if (get_anqp_elem(hapd, ANQP_CAG))
wpabuf_put_le16(buf, ANQP_CAG);
- if (get_anqp_elem(hapd, ANQP_VENUE_URL))
+ if (hapd->conf->venue_url || get_anqp_elem(hapd, ANQP_VENUE_URL))
wpabuf_put_le16(buf, ANQP_VENUE_URL);
if (get_anqp_elem(hapd, ANQP_ADVICE_OF_CHARGE))
wpabuf_put_le16(buf, ANQP_ADVICE_OF_CHARGE);
@@ -328,6 +332,29 @@
}
+static void anqp_add_venue_url(struct hostapd_data *hapd, struct wpabuf *buf)
+{
+ if (anqp_add_override(hapd, buf, ANQP_VENUE_URL))
+ return;
+
+ if (hapd->conf->venue_url) {
+ u8 *len;
+ unsigned int i;
+
+ len = gas_anqp_add_element(buf, ANQP_VENUE_URL);
+ for (i = 0; i < hapd->conf->venue_url_count; i++) {
+ struct hostapd_venue_url *url;
+
+ url = &hapd->conf->venue_url[i];
+ wpabuf_put_u8(buf, 1 + url->url_len);
+ wpabuf_put_u8(buf, url->venue_number);
+ wpabuf_put_data(buf, url->url, url->url_len);
+ }
+ gas_anqp_set_element_len(buf, len);
+ }
+}
+
+
static void anqp_add_network_auth_type(struct hostapd_data *hapd,
struct wpabuf *buf)
{
@@ -680,6 +707,29 @@
}
+static void anqp_add_icon(struct wpabuf *buf, struct hostapd_bss_config *bss,
+ const char *name)
+{
+ size_t j;
+ struct hs20_icon *icon = NULL;
+
+ for (j = 0; j < bss->hs20_icons_count && !icon; j++) {
+ if (os_strcmp(name, bss->hs20_icons[j].name) == 0)
+ icon = &bss->hs20_icons[j];
+ }
+ if (!icon)
+ return; /* icon info not found */
+
+ wpabuf_put_le16(buf, icon->width);
+ wpabuf_put_le16(buf, icon->height);
+ wpabuf_put_data(buf, icon->language, 3);
+ wpabuf_put_u8(buf, os_strlen(icon->type));
+ wpabuf_put_str(buf, icon->type);
+ wpabuf_put_u8(buf, os_strlen(icon->name));
+ wpabuf_put_str(buf, icon->name);
+}
+
+
static void anqp_add_osu_provider(struct wpabuf *buf,
struct hostapd_bss_config *bss,
struct hs20_osu_provider *p)
@@ -714,26 +764,8 @@
/* Icons Available */
len2 = wpabuf_put(buf, 2);
- for (i = 0; i < p->icons_count; i++) {
- size_t j;
- struct hs20_icon *icon = NULL;
-
- for (j = 0; j < bss->hs20_icons_count && !icon; j++) {
- if (os_strcmp(p->icons[i], bss->hs20_icons[j].name) ==
- 0)
- icon = &bss->hs20_icons[j];
- }
- if (!icon)
- continue; /* icon info not found */
-
- wpabuf_put_le16(buf, icon->width);
- wpabuf_put_le16(buf, icon->height);
- wpabuf_put_data(buf, icon->language, 3);
- wpabuf_put_u8(buf, os_strlen(icon->type));
- wpabuf_put_str(buf, icon->type);
- wpabuf_put_u8(buf, os_strlen(icon->name));
- wpabuf_put_str(buf, icon->name);
- }
+ for (i = 0; i < p->icons_count; i++)
+ anqp_add_icon(buf, bss, p->icons[i]);
WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
/* OSU_NAI */
@@ -787,6 +819,40 @@
}
+static void anqp_add_osu_provider_nai(struct wpabuf *buf,
+ struct hs20_osu_provider *p)
+{
+ /* OSU_NAI for shared BSS (Single SSID) */
+ if (p->osu_nai2) {
+ wpabuf_put_u8(buf, os_strlen(p->osu_nai2));
+ wpabuf_put_str(buf, p->osu_nai2);
+ } else {
+ wpabuf_put_u8(buf, 0);
+ }
+}
+
+
+static void anqp_add_osu_providers_nai_list(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ if (hapd->conf->hs20_osu_providers_nai_count) {
+ size_t i;
+ u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+ wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_NAI_LIST);
+ wpabuf_put_u8(buf, 0); /* Reserved */
+
+ for (i = 0; i < hapd->conf->hs20_osu_providers_count; i++) {
+ anqp_add_osu_provider_nai(
+ buf, &hapd->conf->hs20_osu_providers[i]);
+ }
+
+ gas_anqp_set_element_len(buf, len);
+ }
+}
+
+
static void anqp_add_icon_binary_file(struct hostapd_data *hapd,
struct wpabuf *buf,
const u8 *name, size_t name_len)
@@ -842,6 +908,30 @@
gas_anqp_set_element_len(buf, len);
}
+
+static void anqp_add_operator_icon_metadata(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ struct hostapd_bss_config *bss = hapd->conf;
+ size_t i;
+ u8 *len;
+
+ if (!bss->hs20_operator_icon_count)
+ return;
+
+ len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+ wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_ICON_METADATA);
+ wpabuf_put_u8(buf, 0); /* Reserved */
+
+ for (i = 0; i < bss->hs20_operator_icon_count; i++)
+ anqp_add_icon(buf, bss, bss->hs20_operator_icon[i]);
+
+ gas_anqp_set_element_len(buf, len);
+}
+
#endif /* CONFIG_HS20 */
@@ -946,6 +1036,10 @@
continue;
}
#endif /* CONFIG_FILS */
+ if (extra_req[i] == ANQP_VENUE_URL) {
+ anqp_add_venue_url(hapd, buf);
+ continue;
+ }
anqp_add_elem(hapd, buf, extra_req[i]);
}
@@ -964,6 +1058,10 @@
anqp_add_osu_providers_list(hapd, buf);
if (request & ANQP_REQ_ICON_REQUEST)
anqp_add_icon_binary_file(hapd, buf, icon_name, icon_name_len);
+ if (request & ANQP_REQ_OPERATOR_ICON_METADATA)
+ anqp_add_operator_icon_metadata(hapd, buf);
+ if (request & ANQP_REQ_OSU_PROVIDERS_NAI_LIST)
+ anqp_add_osu_providers_nai_list(hapd, buf);
#endif /* CONFIG_HS20 */
#ifdef CONFIG_MBO
@@ -1082,7 +1180,10 @@
"ANQP: FILS Realm Information (local)");
} else
#endif /* CONFIG_FILS */
- if (!get_anqp_elem(hapd, info_id)) {
+ if (info_id == ANQP_VENUE_URL && hapd->conf->venue_url) {
+ wpa_printf(MSG_DEBUG,
+ "ANQP: Venue URL (local)");
+ } else if (!get_anqp_elem(hapd, info_id)) {
wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
info_id);
break;
@@ -1148,6 +1249,16 @@
set_anqp_req(ANQP_REQ_OSU_PROVIDERS_LIST, "OSU Providers list",
hapd->conf->hs20_osu_providers_count, qi);
break;
+ case HS20_STYPE_OPERATOR_ICON_METADATA:
+ set_anqp_req(ANQP_REQ_OPERATOR_ICON_METADATA,
+ "Operator Icon Metadata",
+ hapd->conf->hs20_operator_icon_count, qi);
+ break;
+ case HS20_STYPE_OSU_PROVIDERS_NAI_LIST:
+ set_anqp_req(ANQP_REQ_OSU_PROVIDERS_NAI_LIST,
+ "OSU Providers NAI List",
+ hapd->conf->hs20_osu_providers_nai_count, qi);
+ break;
default:
wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u",
subtype);
@@ -1460,7 +1571,7 @@
gas_serv_write_dpp_adv_proto(tx_buf);
wpabuf_put_le16(tx_buf, wpabuf_len(buf));
wpabuf_put_buf(tx_buf, buf);
- wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
+ hostapd_dpp_gas_status_handler(hapd, 1);
}
wpabuf_free(buf);
}
@@ -1702,7 +1813,7 @@
"SD response sent");
#ifdef CONFIG_DPP
if (dialog->dpp)
- wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
+ hostapd_dpp_gas_status_handler(hapd, 1);
#endif /* CONFIG_DPP */
gas_serv_dialog_clear(dialog);
gas_serv_free_dialogs(hapd, sa);
diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h
index 3a30298..2cf1817 100644
--- a/src/ap/gas_serv.h
+++ b/src/ap/gas_serv.h
@@ -60,6 +60,10 @@
(0x10000 << HS20_STYPE_OSU_PROVIDERS_LIST)
#define ANQP_REQ_ICON_REQUEST \
(0x10000 << HS20_STYPE_ICON_REQUEST)
+#define ANQP_REQ_OPERATOR_ICON_METADATA \
+ (0x10000 << HS20_STYPE_OPERATOR_ICON_METADATA)
+#define ANQP_REQ_OSU_PROVIDERS_NAI_LIST \
+ (0x10000 << HS20_STYPE_OSU_PROVIDERS_NAI_LIST)
/* The first MBO ANQP-element can be included in the optimized bitmap. */
#define ANQP_REQ_MBO_CELL_DATA_CONN_PREF \
(BIT(29) << MBO_ANQP_SUBTYPE_CELL_CONN_PREF)
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 12911df..0bd6892 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1,6 +1,6 @@
/*
* hostapd / Initialization and configuration
- * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -49,6 +49,7 @@
#include "rrm.h"
#include "fils_hlp.h"
#include "acs.h"
+#include "hs20.h"
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
@@ -56,6 +57,8 @@
static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
static int setup_interface2(struct hostapd_iface *iface);
static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
+static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
+ void *timeout_ctx);
int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
@@ -75,6 +78,16 @@
}
+void hostapd_reconfig_encryption(struct hostapd_data *hapd)
+{
+ if (hapd->wpa_auth)
+ return;
+
+ hostapd_set_privacy(hapd, 0);
+ hostapd_setup_encryption(hapd->conf->iface, hapd);
+}
+
+
static void hostapd_reload_bss(struct hostapd_data *hapd)
{
struct hostapd_ssid *ssid;
@@ -82,6 +95,9 @@
if (!hapd->started)
return;
+ if (hapd->conf->wmm_enabled < 0)
+ hapd->conf->wmm_enabled = hapd->iconf->ieee80211n;
+
#ifndef CONFIG_NO_RADIUS
radius_client_reconfig(hapd->radius, hapd->conf->radius);
#endif /* CONFIG_NO_RADIUS */
@@ -160,8 +176,27 @@
}
+static int hostapd_iface_conf_changed(struct hostapd_config *newconf,
+ struct hostapd_config *oldconf)
+{
+ size_t i;
+
+ if (newconf->num_bss != oldconf->num_bss)
+ return 1;
+
+ for (i = 0; i < newconf->num_bss; i++) {
+ if (os_strcmp(newconf->bss[i]->iface,
+ oldconf->bss[i]->iface) != 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
int hostapd_reload_config(struct hostapd_iface *iface)
{
+ struct hapd_interfaces *interfaces = iface->interfaces;
struct hostapd_data *hapd = iface->bss[0];
struct hostapd_config *newconf, *oldconf;
size_t j;
@@ -184,6 +219,35 @@
hostapd_clear_old(iface);
oldconf = hapd->iconf;
+ if (hostapd_iface_conf_changed(newconf, oldconf)) {
+ char *fname;
+ int res;
+
+ wpa_printf(MSG_DEBUG,
+ "Configuration changes include interface/BSS modification - force full disable+enable sequence");
+ fname = os_strdup(iface->config_fname);
+ if (!fname) {
+ hostapd_config_free(newconf);
+ return -1;
+ }
+ hostapd_remove_iface(interfaces, hapd->conf->iface);
+ iface = hostapd_init(interfaces, fname);
+ os_free(fname);
+ hostapd_config_free(newconf);
+ if (!iface) {
+ wpa_printf(MSG_ERROR,
+ "Failed to initialize interface on config reload");
+ return -1;
+ }
+ iface->interfaces = interfaces;
+ interfaces->iface[interfaces->count] = iface;
+ interfaces->count++;
+ res = hostapd_enable_iface(iface);
+ if (res < 0)
+ wpa_printf(MSG_ERROR,
+ "Failed to enable interface on config reload");
+ return res;
+ }
iface->conf = newconf;
for (j = 0; j < iface->num_bss; j++) {
@@ -284,10 +348,11 @@
if (!hapd->started) {
wpa_printf(MSG_ERROR, "%s: Interface %s wasn't started",
- __func__, hapd->conf->iface);
+ __func__, hapd->conf ? hapd->conf->iface : "N/A");
return;
}
hapd->started = 0;
+ hapd->beacon_set_done = 0;
wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
iapp_deinit(hapd->iapp);
@@ -353,6 +418,20 @@
hostapd_clean_rrm(hapd);
fils_hlp_deinit(hapd);
+
+#ifdef CONFIG_SAE
+ {
+ struct hostapd_sae_commit_queue *q;
+
+ while ((q = dl_list_first(&hapd->sae_commit_queue,
+ struct hostapd_sae_commit_queue,
+ list))) {
+ dl_list_del(&q->list);
+ os_free(q);
+ }
+ }
+ eloop_cancel_timeout(auth_sae_process_commit, hapd, NULL);
+#endif /* CONFIG_SAE */
}
@@ -367,7 +446,7 @@
static void hostapd_cleanup(struct hostapd_data *hapd)
{
wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s))", __func__, hapd,
- hapd->conf->iface);
+ hapd->conf ? hapd->conf->iface : "N/A");
if (hapd->iface->interfaces &&
hapd->iface->interfaces->ctrl_iface_deinit) {
wpa_msg(hapd->msg_ctx, MSG_INFO, WPA_EVENT_TERMINATING);
@@ -426,6 +505,8 @@
{
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+ eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface,
+ NULL);
hostapd_cleanup_iface_partial(iface);
hostapd_config_free(iface->conf);
@@ -440,7 +521,7 @@
static void hostapd_clear_wep(struct hostapd_data *hapd)
{
- if (hapd->drv_priv && !hapd->iface->driver_ap_teardown) {
+ if (hapd->drv_priv && !hapd->iface->driver_ap_teardown && hapd->conf) {
hostapd_set_privacy(hapd, 0);
hostapd_broadcast_wep_clear(hapd);
}
@@ -592,8 +673,10 @@
for (i = 5; i > 5 - j; i--)
mask[i] = 0;
j = bits % 8;
- while (j--)
+ while (j) {
+ j--;
mask[i] <<= 1;
+ }
skip_mask_ext:
wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)",
@@ -893,6 +976,48 @@
return RADIUS_DAS_SUCCESS;
}
+
+#ifdef CONFIG_HS20
+static enum radius_das_res
+hostapd_das_coa(void *ctx, struct radius_das_attrs *attr)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+ int multi;
+
+ if (hostapd_das_nas_mismatch(hapd, attr))
+ return RADIUS_DAS_NAS_MISMATCH;
+
+ sta = hostapd_das_find_sta(hapd, attr, &multi);
+ if (!sta) {
+ if (multi) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Multiple sessions match - not supported");
+ return RADIUS_DAS_MULTI_SESSION_MATCH;
+ }
+ wpa_printf(MSG_DEBUG, "RADIUS DAS: No matching session found");
+ return RADIUS_DAS_SESSION_NOT_FOUND;
+ }
+
+ wpa_printf(MSG_DEBUG, "RADIUS DAS: Found a matching session " MACSTR
+ " - CoA", MAC2STR(sta->addr));
+
+ if (attr->hs20_t_c_filtering) {
+ if (attr->hs20_t_c_filtering[0] & BIT(0)) {
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Unexpected Terms and Conditions filtering required in CoA-Request");
+ return RADIUS_DAS_COA_FAILED;
+ }
+
+ hs20_t_c_filtering(hapd, sta, 0);
+ }
+
+ return RADIUS_DAS_SUCCESS;
+}
+#else /* CONFIG_HS20 */
+#define hostapd_das_coa NULL
+#endif /* CONFIG_HS20 */
+
#endif /* CONFIG_NO_RADIUS */
@@ -1067,6 +1192,7 @@
conf->radius_das_require_message_authenticator;
das_conf.ctx = hapd;
das_conf.disconnect = hostapd_das_disconnect;
+ das_conf.coa = hostapd_das_coa;
hapd->radius_das = radius_das_init(&das_conf);
if (hapd->radius_das == NULL) {
wpa_printf(MSG_ERROR, "RADIUS DAS initialization "
@@ -1559,127 +1685,6 @@
#endif /* CONFIG_FST */
-
-#ifdef NEED_AP_MLME
-static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd,
- int ht, int vht)
-{
- if (!ht && !vht)
- return NR_CHAN_WIDTH_20;
- if (!hapd->iconf->secondary_channel)
- return NR_CHAN_WIDTH_20;
- if (!vht || hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_USE_HT)
- return NR_CHAN_WIDTH_40;
- if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
- return NR_CHAN_WIDTH_80;
- if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_160MHZ)
- return NR_CHAN_WIDTH_160;
- if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ)
- return NR_CHAN_WIDTH_80P80;
- return NR_CHAN_WIDTH_20;
-}
-#endif /* NEED_AP_MLME */
-
-
-static void hostapd_set_own_neighbor_report(struct hostapd_data *hapd)
-{
-#ifdef NEED_AP_MLME
- u16 capab = hostapd_own_capab_info(hapd);
- int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
- int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
- struct wpa_ssid_value ssid;
- u8 channel, op_class;
- u8 center_freq1_idx = 0, center_freq2_idx = 0;
- enum nr_chan_width width;
- u32 bssid_info;
- struct wpabuf *nr;
-
- if (!(hapd->conf->radio_measurements[0] &
- WLAN_RRM_CAPS_NEIGHBOR_REPORT))
- return;
-
- bssid_info = 3; /* AP is reachable */
- bssid_info |= NEI_REP_BSSID_INFO_SECURITY; /* "same as the AP" */
- bssid_info |= NEI_REP_BSSID_INFO_KEY_SCOPE; /* "same as the AP" */
-
- if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT)
- bssid_info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT;
-
- bssid_info |= NEI_REP_BSSID_INFO_RM; /* RRM is supported */
-
- if (hapd->conf->wmm_enabled) {
- bssid_info |= NEI_REP_BSSID_INFO_QOS;
-
- if (hapd->conf->wmm_uapsd &&
- (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
- bssid_info |= NEI_REP_BSSID_INFO_APSD;
- }
-
- if (ht) {
- bssid_info |= NEI_REP_BSSID_INFO_HT |
- NEI_REP_BSSID_INFO_DELAYED_BA;
-
- /* VHT bit added in IEEE P802.11-REVmc/D4.3 */
- if (vht)
- bssid_info |= NEI_REP_BSSID_INFO_VHT;
- }
-
- /* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
-
- if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
- hapd->iconf->secondary_channel,
- hapd->iconf->vht_oper_chwidth,
- &op_class, &channel) ==
- NUM_HOSTAPD_MODES)
- return;
- width = hostapd_get_nr_chan_width(hapd, ht, vht);
- if (vht) {
- center_freq1_idx = hapd->iconf->vht_oper_centr_freq_seg0_idx;
- if (width == NR_CHAN_WIDTH_80P80)
- center_freq2_idx =
- hapd->iconf->vht_oper_centr_freq_seg1_idx;
- } else if (ht) {
- ieee80211_freq_to_chan(hapd->iface->freq +
- 10 * hapd->iconf->secondary_channel,
- ¢er_freq1_idx);
- }
-
- ssid.ssid_len = hapd->conf->ssid.ssid_len;
- os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len);
-
- /*
- * Neighbor Report element size = BSSID + BSSID info + op_class + chan +
- * phy type + wide bandwidth channel subelement.
- */
- nr = wpabuf_alloc(ETH_ALEN + 4 + 1 + 1 + 1 + 5);
- if (!nr)
- return;
-
- wpabuf_put_data(nr, hapd->own_addr, ETH_ALEN);
- wpabuf_put_le32(nr, bssid_info);
- wpabuf_put_u8(nr, op_class);
- wpabuf_put_u8(nr, channel);
- wpabuf_put_u8(nr, ieee80211_get_phy_type(hapd->iface->freq, ht, vht));
-
- /*
- * Wide Bandwidth Channel subelement may be needed to allow the
- * receiving STA to send packets to the AP. See IEEE P802.11-REVmc/D5.0
- * Figure 9-301.
- */
- wpabuf_put_u8(nr, WNM_NEIGHBOR_WIDE_BW_CHAN);
- wpabuf_put_u8(nr, 3);
- wpabuf_put_u8(nr, width);
- wpabuf_put_u8(nr, center_freq1_idx);
- wpabuf_put_u8(nr, center_freq2_idx);
-
- hostapd_neighbor_set(hapd, hapd->own_addr, &ssid, nr, hapd->iconf->lci,
- hapd->iconf->civic, hapd->iconf->stationary_ap);
-
- wpabuf_free(nr);
-#endif /* NEED_AP_MLME */
-}
-
-
#ifdef CONFIG_OWE
static int hostapd_owe_iface_iter(struct hostapd_iface *iface, void *ctx)
@@ -1776,6 +1781,20 @@
}
+static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct hostapd_iface *iface = eloop_ctx;
+ struct hostapd_data *hapd;
+
+ if (iface->num_bss < 1 || !iface->bss || !iface->bss[0])
+ return;
+ hapd = iface->bss[0];
+ if (hapd->setup_complete_cb)
+ hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
+}
+
+
static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
int err)
{
@@ -1865,15 +1884,17 @@
}
}
- if (hapd->iconf->rts_threshold > -1 &&
- hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) {
+ if (hapd->iconf->rts_threshold >= -1 &&
+ hostapd_set_rts(hapd, hapd->iconf->rts_threshold) &&
+ hapd->iconf->rts_threshold >= -1) {
wpa_printf(MSG_ERROR, "Could not set RTS threshold for "
"kernel driver");
goto fail;
}
- if (hapd->iconf->fragm_threshold > -1 &&
- hostapd_set_frag(hapd, hapd->iconf->fragm_threshold)) {
+ if (hapd->iconf->fragm_threshold >= -1 &&
+ hostapd_set_frag(hapd, hapd->iconf->fragm_threshold) &&
+ hapd->iconf->fragm_threshold != -1) {
wpa_printf(MSG_ERROR, "Could not set fragmentation threshold "
"for kernel driver");
goto fail;
@@ -1886,11 +1907,14 @@
if (j)
os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
if (hostapd_setup_bss(hapd, j == 0)) {
- do {
+ for (;;) {
hapd = iface->bss[j];
hostapd_bss_deinit_no_free(hapd);
hostapd_free_hapd_data(hapd);
- } while (j-- > 0);
+ if (j == 0)
+ break;
+ j--;
+ }
goto fail;
}
if (is_zero_ether_addr(hapd->conf->bssid))
@@ -1962,7 +1986,7 @@
iface->interfaces->terminate_on_error--;
for (j = 0; j < iface->num_bss; j++)
- hostapd_set_own_neighbor_report(iface->bss[j]);
+ hostapd_neighbor_set_own_report(iface->bss[j]);
return 0;
@@ -1976,8 +2000,19 @@
iface->fst = NULL;
}
#endif /* CONFIG_FST */
- if (iface->interfaces && iface->interfaces->terminate_on_error)
+
+ if (iface->interfaces && iface->interfaces->terminate_on_error) {
eloop_terminate();
+ } else if (hapd->setup_complete_cb) {
+ /*
+ * Calling hapd->setup_complete_cb directly may cause iface
+ * deinitialization which may be accessed later by the caller.
+ */
+ eloop_register_timeout(0, 0,
+ hostapd_interface_setup_failure_handler,
+ iface, NULL);
+ }
+
return -1;
}
@@ -2132,6 +2167,9 @@
dl_list_init(&hapd->l2_queue);
dl_list_init(&hapd->l2_oui_queue);
#endif /* CONFIG_IEEE80211R_AP */
+#ifdef CONFIG_SAE
+ dl_list_init(&hapd->sae_commit_queue);
+#endif /* CONFIG_SAE */
return hapd;
}
@@ -2142,7 +2180,7 @@
if (!hapd)
return;
wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__,
- hapd->conf->iface);
+ hapd->conf ? hapd->conf->iface : "N/A");
hostapd_bss_deinit_no_free(hapd);
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
hostapd_cleanup(hapd);
@@ -2159,12 +2197,6 @@
hostapd_set_state(iface, HAPD_IFACE_DISABLED);
-#ifdef CONFIG_IEEE80211N
-#ifdef NEED_AP_MLME
- hostapd_stop_setup_timers(iface);
- eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
-#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211N */
eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
iface->wait_channel_update = 0;
@@ -2175,11 +2207,18 @@
}
#endif /* CONFIG_FST */
- for (j = iface->num_bss - 1; j >= 0; j--) {
+ for (j = (int) iface->num_bss - 1; j >= 0; j--) {
if (!iface->bss)
break;
hostapd_bss_deinit(iface->bss[j]);
}
+
+#ifdef CONFIG_IEEE80211N
+#ifdef NEED_AP_MLME
+ hostapd_stop_setup_timers(iface);
+ eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_IEEE80211N */
}
@@ -2447,8 +2486,12 @@
wpa_printf(MSG_DEBUG, "%s:bss[%d]->drv_priv=%p",
__func__, (int) j,
hapd_iface->bss[j]->drv_priv);
- if (hapd_iface->bss[j]->drv_priv == drv_priv)
+ if (hapd_iface->bss[j]->drv_priv == drv_priv) {
hapd_iface->bss[j]->drv_priv = NULL;
+ hapd_iface->extended_capa = NULL;
+ hapd_iface->extended_capa_mask = NULL;
+ hapd_iface->extended_capa_len = 0;
+ }
}
}
}
@@ -2533,6 +2576,11 @@
!!(hapd_iface->drv_flags &
WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
+#ifdef NEED_AP_MLME
+ for (j = 0; j < hapd_iface->num_bss; j++)
+ hostapd_cleanup_cs_params(hapd_iface->bss[j]);
+#endif /* NEED_AP_MLME */
+
/* same as hostapd_interface_deinit without deinitializing ctrl-iface */
for (j = 0; j < hapd_iface->num_bss; j++) {
struct hostapd_data *hapd = hapd_iface->bss[j];
@@ -2590,7 +2638,7 @@
if (conf == NULL) {
wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
"configuration", __func__);
- return NULL;
+ return NULL;
}
if (driver) {
@@ -3294,6 +3342,19 @@
}
+void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled)
+{
+ if (vht_enabled)
+ hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_ENABLED;
+ else
+ hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_DISABLED;
+
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "CHAN_SWITCH VHT CONFIG 0x%x",
+ hapd->iconf->ch_switch_vht_config);
+}
+
+
int hostapd_switch_channel(struct hostapd_data *hapd,
struct csa_settings *settings)
{
@@ -3328,7 +3389,6 @@
const struct hostapd_freq_params *freq_params)
{
int vht_seg0_idx = 0, vht_seg1_idx = 0, vht_bw = VHT_CHANWIDTH_USE_HT;
- unsigned int i;
wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes");
@@ -3370,10 +3430,8 @@
/*
* cs_params must not be cleared earlier because the freq_params
* argument may actually point to one of these.
+ * These params will be cleared during interface disable below.
*/
- for (i = 0; i < iface->num_bss; i++)
- hostapd_cleanup_cs_params(iface->bss[i]);
-
hostapd_disable_iface(iface);
hostapd_enable_iface(iface);
}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index d7c6720..607bb95 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -14,6 +14,13 @@
#include "ap_config.h"
#include "drivers/driver.h"
+#define OCE_STA_CFON_ENABLED(hapd) \
+ ((hapd->conf->oce & OCE_STA_CFON) && \
+ (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_OCE_STA_CFON))
+#define OCE_AP_ENABLED(hapd) \
+ ((hapd->conf->oce & OCE_AP) && \
+ (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_OCE_AP))
+
struct wpa_ctrl_dst;
struct radius_server_data;
struct upnp_wps_device_sm;
@@ -57,6 +64,10 @@
struct dl_list eth_p_oui; /* OUI Extended EtherType handlers */
#endif /* CONFIG_ETH_P_OUI */
int eloop_initialized;
+
+#ifdef CONFIG_DPP
+ struct dpp_global *dpp;
+#endif /* CONFIG_DPP */
};
enum hostapd_chan_status {
@@ -79,6 +90,7 @@
};
struct hostapd_frame_info {
+ unsigned int freq;
u32 channel;
u32 datarate;
int ssi_signal; /* dBm */
@@ -115,6 +127,13 @@
int stationary;
};
+struct hostapd_sae_commit_queue {
+ struct dl_list list;
+ int rssi;
+ size_t len;
+ u8 msg[];
+};
+
/**
* struct hostapd_data - hostapd per-BSS data structure
*/
@@ -257,9 +276,6 @@
unsigned int cs_c_off_ecsa_beacon;
unsigned int cs_c_off_ecsa_proberesp;
- /* BSS Load */
- unsigned int bss_load_update_timeout;
-
#ifdef CONFIG_P2P
struct p2p_data *p2p;
struct p2p_group *p2p_group;
@@ -296,7 +312,10 @@
/** Key used for generating SAE anti-clogging tokens */
u8 sae_token_key[8];
struct os_reltime last_sae_token_key_update;
+ u16 sae_token_idx;
+ u16 sae_pending_token_idx[256];
int dot11RSNASAERetransPeriod; /* msec */
+ struct dl_list sae_commit_queue; /* struct hostapd_sae_commit_queue */
#endif /* CONFIG_SAE */
#ifdef CONFIG_TESTING_OPTIONS
@@ -320,11 +339,6 @@
#ifdef CONFIG_MBO
unsigned int mbo_assoc_disallow;
- /**
- * enable_oce - Enable OCE if it is enabled by user and device also
- * supports OCE.
- */
- u8 enable_oce;
#endif /* CONFIG_MBO */
struct dl_list nr_db;
@@ -338,13 +352,12 @@
int dhcp_sock; /* UDP socket used with the DHCP server */
#ifdef CONFIG_DPP
- struct dl_list dpp_bootstrap; /* struct dpp_bootstrap_info */
- struct dl_list dpp_configurator; /* struct dpp_configurator */
int dpp_init_done;
struct dpp_authentication *dpp_auth;
u8 dpp_allowed_roles;
int dpp_qr_mutual;
int dpp_auth_ok_on_ack;
+ int dpp_in_response_listen;
struct gas_query_ap *gas;
struct dpp_pkex *dpp_pkex;
struct dpp_bootstrap_info *dpp_pkex_bi;
@@ -352,6 +365,13 @@
char *dpp_pkex_identifier;
char *dpp_pkex_auth_cmd;
char *dpp_configurator_params;
+ struct os_reltime dpp_last_init;
+ struct os_reltime dpp_init_iter_start;
+ unsigned int dpp_init_max_tries;
+ unsigned int dpp_init_retry_time;
+ unsigned int dpp_resp_wait_time;
+ unsigned int dpp_resp_max_tries;
+ unsigned int dpp_resp_retry_time;
#ifdef CONFIG_TESTING_OPTIONS
char *dpp_config_obj_override;
char *dpp_discovery_override;
@@ -497,6 +517,10 @@
u64 last_channel_time_busy;
u8 channel_utilization;
+ unsigned int chan_util_samples_sum;
+ unsigned int chan_util_num_sample_periods;
+ unsigned int chan_util_average;
+
/* eCSA IE will be added only if operating class is specified */
u8 cs_oper_class;
@@ -525,6 +549,7 @@
int (*cb)(struct hostapd_iface *iface,
void *ctx), void *ctx);
int hostapd_reload_config(struct hostapd_iface *iface);
+void hostapd_reconfig_encryption(struct hostapd_data *hapd);
struct hostapd_data *
hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
struct hostapd_config *conf,
@@ -551,6 +576,7 @@
void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
const char * hostapd_state_text(enum hostapd_iface_state s);
int hostapd_csa_in_progress(struct hostapd_iface *iface);
+void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled);
int hostapd_switch_channel(struct hostapd_data *hapd,
struct csa_settings *settings);
void
@@ -595,6 +621,9 @@
struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
const char *ifname);
+void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr,
+ enum smps_mode smps_mode,
+ enum chan_width chan_width, u8 rx_nss);
#ifdef CONFIG_FST
void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
diff --git a/src/ap/hs20.c b/src/ap/hs20.c
index d7909fa..532580e 100644
--- a/src/ap/hs20.c
+++ b/src/ap/hs20.c
@@ -11,9 +11,11 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
+#include "sta_info.h"
#include "hs20.h"
@@ -23,17 +25,20 @@
if (!hapd->conf->hs20)
return eid;
*eid++ = WLAN_EID_VENDOR_SPECIFIC;
- *eid++ = 7;
+ *eid++ = hapd->conf->hs20_release < 2 ? 5 : 7;
WPA_PUT_BE24(eid, OUI_WFA);
eid += 3;
*eid++ = HS20_INDICATION_OUI_TYPE;
- conf = HS20_VERSION; /* Release Number */
- conf |= HS20_ANQP_DOMAIN_ID_PRESENT;
+ conf = (hapd->conf->hs20_release - 1) << 4; /* Release Number */
+ if (hapd->conf->hs20_release >= 2)
+ conf |= HS20_ANQP_DOMAIN_ID_PRESENT;
if (hapd->conf->disable_dgaf)
conf |= HS20_DGAF_DISABLED;
*eid++ = conf;
- WPA_PUT_LE16(eid, hapd->conf->anqp_domain_id);
- eid += 2;
+ if (hapd->conf->hs20_release >= 2) {
+ WPA_PUT_LE16(eid, hapd->conf->anqp_domain_id);
+ eid += 2;
+ }
return eid;
}
@@ -82,6 +87,10 @@
capab |= WPA_CAPABILITY_MFPR;
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ if (hapd->conf->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
+#endif /* CONFIG_OCV */
WPA_PUT_LE16(eid, capab);
eid += 2;
@@ -175,3 +184,72 @@
return ret;
}
+
+
+int hs20_send_wnm_notification_t_c(struct hostapd_data *hapd,
+ const u8 *addr, const char *url)
+{
+ struct wpabuf *buf;
+ int ret;
+ size_t url_len;
+
+ if (!url) {
+ wpa_printf(MSG_INFO, "HS 2.0: No T&C Server URL available");
+ return -1;
+ }
+
+ url_len = os_strlen(url);
+ if (5 + url_len > 255) {
+ wpa_printf(MSG_INFO,
+ "HS 2.0: Too long T&C Server URL for WNM-Notification: '%s'",
+ url);
+ return -1;
+ }
+
+ buf = wpabuf_alloc(4 + 7 + url_len);
+ if (!buf)
+ return -1;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_WNM);
+ wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ);
+ wpabuf_put_u8(buf, 1); /* Dialog token */
+ wpabuf_put_u8(buf, 1); /* Type - 1 reserved for WFA */
+
+ /* Terms and Conditions Acceptance subelement */
+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(buf, 4 + 1 + url_len);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_WNM_T_C_ACCEPTANCE);
+ wpabuf_put_u8(buf, url_len);
+ wpabuf_put_str(buf, url);
+
+ ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+
+ wpabuf_free(buf);
+
+ return ret;
+}
+
+
+void hs20_t_c_filtering(struct hostapd_data *hapd, struct sta_info *sta,
+ int enabled)
+{
+ if (enabled) {
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Terms and Conditions filtering required for "
+ MACSTR, MAC2STR(sta->addr));
+ sta->hs20_t_c_filtering = 1;
+ /* TODO: Enable firewall filtering for the STA */
+ wpa_msg(hapd->msg_ctx, MSG_INFO, HS20_T_C_FILTERING_ADD MACSTR,
+ MAC2STR(sta->addr));
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Terms and Conditions filtering not required for "
+ MACSTR, MAC2STR(sta->addr));
+ sta->hs20_t_c_filtering = 0;
+ /* TODO: Disable firewall filtering for the STA */
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ HS20_T_C_FILTERING_REMOVE MACSTR, MAC2STR(sta->addr));
+ }
+}
diff --git a/src/ap/hs20.h b/src/ap/hs20.h
index 152439f..e99e26e 100644
--- a/src/ap/hs20.h
+++ b/src/ap/hs20.h
@@ -18,5 +18,9 @@
int hs20_send_wnm_notification_deauth_req(struct hostapd_data *hapd,
const u8 *addr,
const struct wpabuf *payload);
+int hs20_send_wnm_notification_t_c(struct hostapd_data *hapd,
+ const u8 *addr, const char *url);
+void hs20_t_c_filtering(struct hostapd_data *hapd, struct sta_info *sta,
+ int enabled);
#endif /* HS20_H */
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 84e74ee..8ac33bb 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -229,9 +229,6 @@
{
int pri_chan, sec_chan;
- if (!iface->conf->secondary_channel)
- return 1; /* HT40 not used */
-
pri_chan = iface->conf->channel;
sec_chan = pri_chan + iface->conf->secondary_channel * 4;
@@ -679,7 +676,8 @@
if (!ieee80211n_supported_ht_capab(iface))
return -1;
#ifdef CONFIG_IEEE80211AC
- if (!ieee80211ac_supported_vht_capab(iface))
+ if (iface->conf->ieee80211ac &&
+ !ieee80211ac_supported_vht_capab(iface))
return -1;
#endif /* CONFIG_IEEE80211AC */
ret = ieee80211n_check_40mhz(iface);
@@ -696,30 +694,25 @@
static int hostapd_is_usable_chan(struct hostapd_iface *iface,
int channel, int primary)
{
- int i;
struct hostapd_channel_data *chan;
if (!iface->current_mode)
return 0;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
- if (chan->chan != channel)
- continue;
+ chan = hw_get_channel_chan(iface->current_mode, channel, NULL);
+ if (!chan)
+ return 0;
- if (!(chan->flag & HOSTAPD_CHAN_DISABLED))
- return 1;
+ if ((primary && chan_pri_allowed(chan)) ||
+ (!primary && !(chan->flag & HOSTAPD_CHAN_DISABLED)))
+ return 1;
- wpa_printf(MSG_DEBUG,
- "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s",
- primary ? "" : "Configured HT40 secondary ",
- i, chan->chan, chan->flag,
- chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
- chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
- }
-
- wpa_printf(MSG_INFO, "Channel %d (%s) not allowed for AP mode",
- channel, primary ? "primary" : "secondary");
+ wpa_printf(MSG_INFO,
+ "Channel %d (%s) not allowed for AP mode, flags: 0x%x%s%s",
+ channel, primary ? "primary" : "secondary",
+ chan->flag,
+ chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
+ chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
return 0;
}
@@ -727,6 +720,12 @@
static int hostapd_is_usable_chans(struct hostapd_iface *iface)
{
int secondary_chan;
+ struct hostapd_channel_data *pri_chan;
+
+ pri_chan = hw_get_channel_chan(iface->current_mode,
+ iface->conf->channel, NULL);
+ if (!pri_chan)
+ return 0;
if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1))
return 0;
@@ -741,13 +740,15 @@
/* Both HT40+ and HT40- are set, pick a valid secondary channel */
secondary_chan = iface->conf->channel + 4;
- if (hostapd_is_usable_chan(iface, secondary_chan, 0)) {
+ if (hostapd_is_usable_chan(iface, secondary_chan, 0) &&
+ (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) {
iface->conf->secondary_channel = 1;
return 1;
}
secondary_chan = iface->conf->channel - 4;
- if (hostapd_is_usable_chan(iface, secondary_chan, 0)) {
+ if (hostapd_is_usable_chan(iface, secondary_chan, 0) &&
+ (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) {
iface->conf->secondary_channel = -1;
return 1;
}
@@ -935,11 +936,16 @@
int i, channel;
struct hostapd_hw_modes *mode;
- channel = hw_get_chan(hapd->iface->current_mode, freq);
- if (channel)
- return channel;
+ if (hapd->iface->current_mode) {
+ channel = hw_get_chan(hapd->iface->current_mode, freq);
+ if (channel)
+ return channel;
+ }
+
/* Check other available modes since the channel list for the current
* mode did not include the specified frequency. */
+ if (!hapd->iface->hw_features)
+ return 0;
for (i = 0; i < hapd->iface->num_hw_features; i++) {
mode = &hapd->iface->hw_features[i];
channel = hw_get_chan(mode, freq);
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 65c4d88..5cd2562 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -21,6 +21,8 @@
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "common/sae.h"
+#include "common/dpp.h"
+#include "common/ocv.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "p2p/p2p.h"
@@ -61,6 +63,25 @@
const u8 *msk, size_t msk_len,
int *is_pub);
#endif /* CONFIG_FILS */
+static void handle_auth(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ int rssi, int from_queue);
+
+
+u8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 multi_ap_val = 0;
+
+ if (!hapd->conf->multi_ap)
+ return eid;
+ if (hapd->conf->multi_ap & BACKHAUL_BSS)
+ multi_ap_val |= MULTI_AP_BACKHAUL_BSS;
+ if (hapd->conf->multi_ap & FRONTHAUL_BSS)
+ multi_ap_val |= MULTI_AP_FRONTHAUL_BSS;
+
+ return eid + add_multi_ap_ie(eid, 9, multi_ap_val);
+}
+
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
{
@@ -277,7 +298,7 @@
static int send_auth_reply(struct hostapd_data *hapd,
const u8 *dst, const u8 *bssid,
u16 auth_alg, u16 auth_transaction, u16 resp,
- const u8 *ies, size_t ies_len)
+ const u8 *ies, size_t ies_len, const char *dbg)
{
struct ieee80211_mgmt *reply;
u8 *buf;
@@ -304,9 +325,9 @@
os_memcpy(reply->u.auth.variable, ies, ies_len);
wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR
- " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu)",
+ " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)",
MAC2STR(dst), auth_alg, auth_transaction,
- resp, (unsigned long) ies_len);
+ resp, (unsigned long) ies_len, dbg);
if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
wpa_printf(MSG_INFO, "send_auth_reply: send failed");
else
@@ -328,7 +349,8 @@
int reply_res;
reply_res = send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT,
- auth_transaction, status, ies, ies_len);
+ auth_transaction, status, ies, ies_len,
+ "auth-ft-finish");
sta = ap_get_sta(hapd, dst);
if (sta == NULL)
@@ -354,16 +376,39 @@
#ifdef CONFIG_SAE
-#define dot11RSNASAESync 5 /* attempts */
+static void sae_set_state(struct sta_info *sta, enum sae_state state,
+ const char *reason)
+{
+ wpa_printf(MSG_DEBUG, "SAE: State %s -> %s for peer " MACSTR " (%s)",
+ sae_state_txt(sta->sae->state), sae_state_txt(state),
+ MAC2STR(sta->addr), reason);
+ sta->sae->state = state;
+}
static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
struct sta_info *sta, int update)
{
struct wpabuf *buf;
- const char *password;
+ const char *password = NULL;
+ struct sae_password_entry *pw;
+ const char *rx_id = NULL;
- password = hapd->conf->sae_password;
+ if (sta->sae->tmp)
+ rx_id = sta->sae->tmp->pw_id;
+
+ for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
+ if (!is_broadcast_ether_addr(pw->peer_addr) &&
+ os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0)
+ continue;
+ if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier))
+ continue;
+ if (rx_id && pw->identifier &&
+ os_strcmp(rx_id, pw->identifier) != 0)
+ continue;
+ password = pw->password;
+ break;
+ }
if (!password)
password = hapd->conf->ssid.wpa_passphrase;
if (!password) {
@@ -373,17 +418,27 @@
if (update &&
sae_prepare_commit(hapd->own_addr, sta->addr,
- (u8 *) password, os_strlen(password),
+ (u8 *) password, os_strlen(password), rx_id,
sta->sae) < 0) {
wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
return NULL;
}
- buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN);
+ if (pw && pw->vlan_id) {
+ if (!sta->sae->tmp) {
+ wpa_printf(MSG_INFO,
+ "SAE: No temporary data allocated - cannot store VLAN ID");
+ return NULL;
+ }
+ sta->sae->tmp->vlan_id = pw->vlan_id;
+ }
+
+ buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
+ (rx_id ? 3 + os_strlen(rx_id) : 0));
if (buf == NULL)
return NULL;
sae_write_commit(sta->sae, buf, sta->sae->tmp ?
- sta->sae->tmp->anti_clogging_token : NULL);
+ sta->sae->tmp->anti_clogging_token : NULL, rx_id);
return buf;
}
@@ -412,12 +467,14 @@
int reply_res;
data = auth_build_sae_commit(hapd, sta, update);
+ if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
+ return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
if (data == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 1,
WLAN_STATUS_SUCCESS, wpabuf_head(data),
- wpabuf_len(data));
+ wpabuf_len(data), "sae-send-commit");
wpabuf_free(data);
@@ -438,7 +495,7 @@
reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 2,
WLAN_STATUS_SUCCESS, wpabuf_head(data),
- wpabuf_len(data));
+ wpabuf_len(data), "sae-send-confirm");
wpabuf_free(data);
@@ -465,21 +522,57 @@
return 1;
}
+ /* In addition to already existing open SAE sessions, check whether
+ * there are enough pending commit messages in the processing queue to
+ * potentially result in too many open sessions. */
+ if (open + dl_list_len(&hapd->sae_commit_queue) >=
+ hapd->conf->sae_anti_clogging_threshold)
+ return 1;
+
return 0;
}
+static u8 sae_token_hash(struct hostapd_data *hapd, const u8 *addr)
+{
+ u8 hash[SHA256_MAC_LEN];
+
+ hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+ addr, ETH_ALEN, hash);
+ return hash[0];
+}
+
+
static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
const u8 *token, size_t token_len)
{
u8 mac[SHA256_MAC_LEN];
+ const u8 *addrs[2];
+ size_t len[2];
+ u16 token_idx;
+ u8 idx;
if (token_len != SHA256_MAC_LEN)
return -1;
- if (hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
- addr, ETH_ALEN, mac) < 0 ||
- os_memcmp_const(token, mac, SHA256_MAC_LEN) != 0)
+ idx = sae_token_hash(hapd, addr);
+ token_idx = hapd->sae_pending_token_idx[idx];
+ if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) {
+ wpa_printf(MSG_DEBUG, "SAE: Invalid anti-clogging token from "
+ MACSTR " - token_idx 0x%04x, expected 0x%04x",
+ MAC2STR(addr), WPA_GET_BE16(token), token_idx);
return -1;
+ }
+
+ addrs[0] = addr;
+ len[0] = ETH_ALEN;
+ addrs[1] = token;
+ len[1] = 2;
+ if (hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+ 2, addrs, len, mac) < 0 ||
+ os_memcmp_const(token + 2, &mac[2], SHA256_MAC_LEN - 2) != 0)
+ return -1;
+
+ hapd->sae_pending_token_idx[idx] = 0; /* invalidate used token */
return 0;
}
@@ -491,16 +584,25 @@
struct wpabuf *buf;
u8 *token;
struct os_reltime now;
+ u8 idx[2];
+ const u8 *addrs[2];
+ size_t len[2];
+ u8 p_idx;
+ u16 token_idx;
os_get_reltime(&now);
if (!os_reltime_initialized(&hapd->last_sae_token_key_update) ||
- os_reltime_expired(&now, &hapd->last_sae_token_key_update, 60)) {
+ os_reltime_expired(&now, &hapd->last_sae_token_key_update, 60) ||
+ hapd->sae_token_idx == 0xffff) {
if (random_get_bytes(hapd->sae_token_key,
sizeof(hapd->sae_token_key)) < 0)
return NULL;
wpa_hexdump(MSG_DEBUG, "SAE: Updated token key",
hapd->sae_token_key, sizeof(hapd->sae_token_key));
hapd->last_sae_token_key_update = now;
+ hapd->sae_token_idx = 0;
+ os_memset(hapd->sae_pending_token_idx, 0,
+ sizeof(hapd->sae_pending_token_idx));
}
buf = wpabuf_alloc(sizeof(le16) + SHA256_MAC_LEN);
@@ -509,18 +611,34 @@
wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
+ p_idx = sae_token_hash(hapd, addr);
+ token_idx = hapd->sae_pending_token_idx[p_idx];
+ if (!token_idx) {
+ hapd->sae_token_idx++;
+ token_idx = hapd->sae_token_idx;
+ hapd->sae_pending_token_idx[p_idx] = token_idx;
+ }
+ WPA_PUT_BE16(idx, token_idx);
token = wpabuf_put(buf, SHA256_MAC_LEN);
- hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
- addr, ETH_ALEN, token);
+ addrs[0] = addr;
+ len[0] = ETH_ALEN;
+ addrs[1] = idx;
+ len[1] = sizeof(idx);
+ if (hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+ 2, addrs, len, token) < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+ WPA_PUT_BE16(token, token_idx);
return buf;
}
-static int sae_check_big_sync(struct sta_info *sta)
+static int sae_check_big_sync(struct hostapd_data *hapd, struct sta_info *sta)
{
- if (sta->sae->sync > dot11RSNASAESync) {
- sta->sae->state = SAE_NOTHING;
+ if (sta->sae->sync > hapd->conf->sae_sync) {
+ sae_set_state(sta, SAE_NOTHING, "Sync > dot11RSNASAESync");
sta->sae->sync = 0;
return -1;
}
@@ -534,12 +652,13 @@
struct sta_info *sta = eloop_data;
int ret;
- if (sae_check_big_sync(sta))
+ if (sae_check_big_sync(hapd, sta))
return;
sta->sae->sync++;
wpa_printf(MSG_DEBUG, "SAE: Auth SAE retransmit timer for " MACSTR
- " (sync=%d state=%d)",
- MAC2STR(sta->addr), sta->sae->sync, sta->sae->state);
+ " (sync=%d state=%s)",
+ MAC2STR(sta->addr), sta->sae->sync,
+ sae_state_txt(sta->sae->state));
switch (sta->sae->state) {
case SAE_COMMITTED:
@@ -582,33 +701,85 @@
}
+static void sae_sme_send_external_auth_status(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 status)
+{
+ struct external_auth params;
+
+ os_memset(¶ms, 0, sizeof(params));
+ params.status = status;
+ params.bssid = sta->addr;
+ if (status == WLAN_STATUS_SUCCESS && sta->sae)
+ params.pmkid = sta->sae->pmkid;
+
+ hostapd_drv_send_external_auth_status(hapd, ¶ms);
+}
+
+
void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
{
+#ifndef CONFIG_NO_VLAN
+ struct vlan_description vlan_desc;
+
+ if (sta->sae->tmp && sta->sae->tmp->vlan_id > 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Assign STA " MACSTR
+ " to VLAN ID %d",
+ MAC2STR(sta->addr), sta->sae->tmp->vlan_id);
+
+ os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+ vlan_desc.notempty = 1;
+ vlan_desc.untagged = sta->sae->tmp->vlan_id;
+ if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
+ wpa_printf(MSG_INFO,
+ "Invalid VLAN ID %d in sae_password",
+ sta->sae->tmp->vlan_id);
+ return;
+ }
+
+ if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0 ||
+ ap_sta_bind_vlan(hapd, sta) < 0) {
+ wpa_printf(MSG_INFO,
+ "Failed to assign VLAN ID %d from sae_password to "
+ MACSTR, sta->sae->tmp->vlan_id,
+ MAC2STR(sta->addr));
+ return;
+ }
+ }
+#endif /* CONFIG_NO_VLAN */
+
sta->flags |= WLAN_STA_AUTH;
sta->auth_alg = WLAN_AUTH_SAE;
mlme_authenticate_indication(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
- sta->sae->state = SAE_ACCEPTED;
+ sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm");
wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
sta->sae->pmk, sta->sae->pmkid);
+ sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS);
}
static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *bssid, u8 auth_transaction)
+ const u8 *bssid, u8 auth_transaction, int allow_reuse,
+ int *sta_removed)
{
int ret;
+ *sta_removed = 0;
+
if (auth_transaction != 1 && auth_transaction != 2)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ wpa_printf(MSG_DEBUG, "SAE: Peer " MACSTR " state=%s auth_trans=%u",
+ MAC2STR(sta->addr), sae_state_txt(sta->sae->state),
+ auth_transaction);
switch (sta->sae->state) {
case SAE_NOTHING:
if (auth_transaction == 1) {
- ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+ ret = auth_sae_send_commit(hapd, sta, bssid,
+ !allow_reuse);
if (ret)
return ret;
- sta->sae->state = SAE_COMMITTED;
+ sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
if (sae_process_commit(sta->sae) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -630,7 +801,8 @@
ret = auth_sae_send_confirm(hapd, sta, bssid);
if (ret)
return ret;
- sta->sae->state = SAE_CONFIRMED;
+ sae_set_state(sta, SAE_CONFIRMED,
+ "Sent Confirm (mesh)");
} else {
/*
* For infrastructure BSS, send only the Commit
@@ -659,7 +831,7 @@
ret = auth_sae_send_confirm(hapd, sta, bssid);
if (ret)
return ret;
- sta->sae->state = SAE_CONFIRMED;
+ sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
sta->sae->sync = 0;
sae_set_retransmit_timer(hapd, sta);
} else if (hapd->conf->mesh & MESH_ENABLED) {
@@ -667,7 +839,7 @@
* In mesh case, follow SAE finite state machine and
* send Commit now, if sync count allows.
*/
- if (sae_check_big_sync(sta))
+ if (sae_check_big_sync(hapd, sta))
return WLAN_STATUS_SUCCESS;
sta->sae->sync++;
@@ -686,20 +858,21 @@
if (ret)
return ret;
- sta->sae->state = SAE_CONFIRMED;
+ sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
/*
* Since this was triggered on Confirm RX, run another
* step to get to Accepted without waiting for
* additional events.
*/
- return sae_sm_step(hapd, sta, bssid, auth_transaction);
+ return sae_sm_step(hapd, sta, bssid, auth_transaction,
+ 0, sta_removed);
}
break;
case SAE_CONFIRMED:
sae_clear_retransmit_timer(hapd, sta);
if (auth_transaction == 1) {
- if (sae_check_big_sync(sta))
+ if (sae_check_big_sync(hapd, sta))
return WLAN_STATUS_SUCCESS;
sta->sae->sync++;
@@ -716,18 +889,32 @@
sae_set_retransmit_timer(hapd, sta);
} else {
+ sta->sae->send_confirm = 0xffff;
sae_accept_sta(hapd, sta);
}
break;
case SAE_ACCEPTED:
- if (auth_transaction == 1) {
+ if (auth_transaction == 1 &&
+ (hapd->conf->mesh & MESH_ENABLED)) {
wpa_printf(MSG_DEBUG, "SAE: remove the STA (" MACSTR
") doing reauthentication",
MAC2STR(sta->addr));
- ap_free_sta(hapd, sta);
wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+ ap_free_sta(hapd, sta);
+ *sta_removed = 1;
+ } else if (auth_transaction == 1) {
+ wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
+ ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+ if (ret)
+ return ret;
+ sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
+
+ if (sae_process_commit(sta->sae) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ sta->sae->sync = 0;
+ sae_set_retransmit_timer(hapd, sta);
} else {
- if (sae_check_big_sync(sta))
+ if (sae_check_big_sync(hapd, sta))
return WLAN_STATUS_SUCCESS;
sta->sae->sync++;
@@ -750,18 +937,21 @@
{
struct sae_data *sae = sta->sae;
int i, *groups = hapd->conf->sae_groups;
+ int default_groups[] = { 19, 0 };
if (sae->state != SAE_COMMITTED)
return;
wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group);
- for (i = 0; groups && groups[i] > 0; i++) {
+ if (!groups)
+ groups = default_groups;
+ for (i = 0; groups[i] > 0; i++) {
if (sae->group == groups[i])
break;
}
- if (!groups || groups[i] <= 0) {
+ if (groups[i] <= 0) {
wpa_printf(MSG_DEBUG,
"SAE: Previously selected group not found from the current configuration");
return;
@@ -790,16 +980,22 @@
{
int resp = WLAN_STATUS_SUCCESS;
struct wpabuf *data = NULL;
+ int *groups = hapd->conf->sae_groups;
+ int default_groups[] = { 19, 0 };
+ const u8 *pos, *end;
+ int sta_removed = 0;
+
+ if (!groups)
+ groups = default_groups;
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->conf->sae_reflection_attack && auth_transaction == 1) {
- const u8 *pos, *end;
-
wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack");
pos = mgmt->u.auth.variable;
end = ((const u8 *) mgmt) + len;
send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
- auth_transaction, resp, pos, end - pos);
+ auth_transaction, resp, pos, end - pos,
+ "auth-sae-reflection-attack");
goto remove_sta;
}
@@ -808,7 +1004,8 @@
send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
auth_transaction, resp,
wpabuf_head(hapd->conf->sae_commit_override),
- wpabuf_len(hapd->conf->sae_commit_override));
+ wpabuf_len(hapd->conf->sae_commit_override),
+ "sae-commit-override");
goto remove_sta;
}
#endif /* CONFIG_TESTING_OPTIONS */
@@ -823,7 +1020,7 @@
resp = -1;
goto remove_sta;
}
- sta->sae->state = SAE_NOTHING;
+ sae_set_state(sta, SAE_NOTHING, "Init");
sta->sae->sync = 0;
}
@@ -835,8 +1032,10 @@
}
if (auth_transaction == 1) {
- const u8 *token = NULL, *pos, *end;
+ const u8 *token = NULL;
size_t token_len = 0;
+ int allow_reuse = 0;
+
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"start SAE authentication (RX commit, status=%u)",
@@ -853,8 +1052,7 @@
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto reply;
}
- resp = sae_group_allowed(sta->sae,
- hapd->conf->sae_groups,
+ resp = sae_group_allowed(sta->sae, groups,
WPA_GET_LE16(pos));
if (resp != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_ERROR,
@@ -886,7 +1084,8 @@
"SAE: Failed to send commit message");
goto remove_sta;
}
- sta->sae->state = SAE_COMMITTED;
+ sae_set_state(sta, SAE_COMMITTED,
+ "Sent Commit (anti-clogging token case in mesh)");
sta->sae->sync = 0;
sae_set_retransmit_timer(hapd, sta);
return;
@@ -905,16 +1104,54 @@
if (status_code != WLAN_STATUS_SUCCESS)
goto remove_sta;
+ if (!(hapd->conf->mesh & MESH_ENABLED) &&
+ sta->sae->state == SAE_COMMITTED) {
+ /* This is needed in the infrastructure BSS case to
+ * address a sequence where a STA entry may remain in
+ * hostapd across two attempts to do SAE authentication
+ * by the same STA. The second attempt may end up trying
+ * to use a different group and that would not be
+ * allowed if we remain in Committed state with the
+ * previously set parameters. */
+ pos = mgmt->u.auth.variable;
+ end = ((const u8 *) mgmt) + len;
+ if (end - pos >= (int) sizeof(le16) &&
+ sae_group_allowed(sta->sae, groups,
+ WPA_GET_LE16(pos)) ==
+ WLAN_STATUS_SUCCESS) {
+ /* Do not waste resources deriving the same PWE
+ * again since the same group is reused. */
+ sae_set_state(sta, SAE_NOTHING,
+ "Allow previous PWE to be reused");
+ allow_reuse = 1;
+ } else {
+ sae_set_state(sta, SAE_NOTHING,
+ "Clear existing state to allow restart");
+ sae_clear_data(sta->sae);
+ }
+ }
+
resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
((const u8 *) mgmt) + len -
mgmt->u.auth.variable, &token,
- &token_len, hapd->conf->sae_groups);
+ &token_len, groups);
if (resp == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message from " MACSTR " due to reflection attack",
MAC2STR(sta->addr));
goto remove_sta;
}
+
+ if (resp == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER
+ MACSTR, MAC2STR(sta->addr));
+ sae_clear_retransmit_timer(hapd, sta);
+ sae_set_state(sta, SAE_NOTHING,
+ "Unknown Password Identifier");
+ goto remove_sta;
+ }
+
if (token && check_sae_token(hapd, sta->addr, token, token_len)
< 0) {
wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
@@ -927,7 +1164,7 @@
if (resp != WLAN_STATUS_SUCCESS)
goto reply;
- if (!token && use_sae_anti_clogging(hapd)) {
+ if (!token && use_sae_anti_clogging(hapd) && !allow_reuse) {
wpa_printf(MSG_DEBUG,
"SAE: Request anti-clogging token from "
MACSTR, MAC2STR(sta->addr));
@@ -935,11 +1172,13 @@
sta->addr);
resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
if (hapd->conf->mesh & MESH_ENABLED)
- sta->sae->state = SAE_NOTHING;
+ sae_set_state(sta, SAE_NOTHING,
+ "Request anti-clogging token case in mesh");
goto reply;
}
- resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction);
+ resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
+ allow_reuse, &sta_removed);
} else if (auth_transaction == 2) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -949,14 +1188,39 @@
goto remove_sta;
if (sta->sae->state >= SAE_CONFIRMED ||
!(hapd->conf->mesh & MESH_ENABLED)) {
- if (sae_check_confirm(sta->sae, mgmt->u.auth.variable,
- ((u8 *) mgmt) + len -
- mgmt->u.auth.variable) < 0) {
+ const u8 *var;
+ size_t var_len;
+ u16 peer_send_confirm;
+
+ var = mgmt->u.auth.variable;
+ var_len = ((u8 *) mgmt) + len - mgmt->u.auth.variable;
+ if (var_len < 2) {
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto reply;
}
+
+ peer_send_confirm = WPA_GET_LE16(var);
+
+ if (sta->sae->state == SAE_ACCEPTED &&
+ (peer_send_confirm <= sta->sae->rc ||
+ peer_send_confirm == 0xffff)) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Silently ignore unexpected Confirm from peer "
+ MACSTR
+ " (peer-send-confirm=%u Rc=%u)",
+ MAC2STR(sta->addr),
+ peer_send_confirm, sta->sae->rc);
+ return;
+ }
+
+ if (sae_check_confirm(sta->sae, var, var_len) < 0) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto reply;
+ }
+ sta->sae->rc = peer_send_confirm;
}
- resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction);
+ resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction, 0,
+ &sta_removed);
} else {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -968,16 +1232,27 @@
}
reply:
- if (resp != WLAN_STATUS_SUCCESS) {
+ if (!sta_removed && resp != WLAN_STATUS_SUCCESS) {
+ pos = mgmt->u.auth.variable;
+ end = ((const u8 *) mgmt) + len;
+
+ /* Copy the Finite Cyclic Group field from the request if we
+ * rejected it as unsupported group. */
+ if (resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
+ !data && end - pos >= 2)
+ data = wpabuf_alloc_copy(pos, 2);
+
+ sae_sme_send_external_auth_status(hapd, sta, resp);
send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
auth_transaction, resp,
data ? wpabuf_head(data) : (u8 *) "",
- data ? wpabuf_len(data) : 0);
+ data ? wpabuf_len(data) : 0, "auth-sae");
}
remove_sta:
- if (sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
- status_code != WLAN_STATUS_SUCCESS)) {
+ if (!sta_removed && sta->added_unassoc &&
+ (resp != WLAN_STATUS_SUCCESS ||
+ status_code != WLAN_STATUS_SUCCESS)) {
hostapd_drv_sta_remove(hapd, sta->addr);
sta->added_unassoc = 0;
}
@@ -1009,13 +1284,112 @@
if (ret)
return -1;
- sta->sae->state = SAE_COMMITTED;
+ sae_set_state(sta, SAE_COMMITTED, "Init and sent commit");
sta->sae->sync = 0;
sae_set_retransmit_timer(hapd, sta);
return 0;
}
+
+void auth_sae_process_commit(void *eloop_ctx, void *user_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct hostapd_sae_commit_queue *q;
+ unsigned int queue_len;
+
+ q = dl_list_first(&hapd->sae_commit_queue,
+ struct hostapd_sae_commit_queue, list);
+ if (!q)
+ return;
+ wpa_printf(MSG_DEBUG,
+ "SAE: Process next available message from queue");
+ dl_list_del(&q->list);
+ handle_auth(hapd, (const struct ieee80211_mgmt *) q->msg, q->len,
+ q->rssi, 1);
+ os_free(q);
+
+ if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
+ return;
+ queue_len = dl_list_len(&hapd->sae_commit_queue);
+ eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
+ hapd, NULL);
+}
+
+
+static void auth_sae_queue(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ int rssi)
+{
+ struct hostapd_sae_commit_queue *q, *q2;
+ unsigned int queue_len;
+ const struct ieee80211_mgmt *mgmt2;
+
+ queue_len = dl_list_len(&hapd->sae_commit_queue);
+ if (queue_len >= 15) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: No more room in message queue - drop the new frame from "
+ MACSTR, MAC2STR(mgmt->sa));
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "SAE: Queue Authentication message from "
+ MACSTR " for processing (queue_len %u)", MAC2STR(mgmt->sa),
+ queue_len);
+ q = os_zalloc(sizeof(*q) + len);
+ if (!q)
+ return;
+ q->rssi = rssi;
+ q->len = len;
+ os_memcpy(q->msg, mgmt, len);
+
+ /* Check whether there is already a queued Authentication frame from the
+ * same station with the same transaction number and if so, replace that
+ * queue entry with the new one. This avoids issues with a peer that
+ * sends multiple times (e.g., due to frequent SAE retries). There is no
+ * point in us trying to process the old attempts after a new one has
+ * obsoleted them. */
+ dl_list_for_each(q2, &hapd->sae_commit_queue,
+ struct hostapd_sae_commit_queue, list) {
+ mgmt2 = (const struct ieee80211_mgmt *) q2->msg;
+ if (os_memcmp(mgmt->sa, mgmt2->sa, ETH_ALEN) == 0 &&
+ mgmt->u.auth.auth_transaction ==
+ mgmt2->u.auth.auth_transaction) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Replace queued message from same STA with same transaction number");
+ dl_list_add(&q2->list, &q->list);
+ dl_list_del(&q2->list);
+ os_free(q2);
+ goto queued;
+ }
+ }
+
+ /* No pending identical entry, so add to the end of the queue */
+ dl_list_add_tail(&hapd->sae_commit_queue, &q->list);
+
+queued:
+ if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL))
+ return;
+ eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit,
+ hapd, NULL);
+}
+
+
+static int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr)
+{
+ struct hostapd_sae_commit_queue *q;
+ const struct ieee80211_mgmt *mgmt;
+
+ dl_list_for_each(q, &hapd->sae_commit_queue,
+ struct hostapd_sae_commit_queue, list) {
+ mgmt = (const struct ieee80211_mgmt *) q->msg;
+ if (os_memcmp(addr, mgmt->sa, ETH_ALEN) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
#endif /* CONFIG_SAE */
@@ -1033,7 +1407,7 @@
if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
- return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
+ return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
#endif /* CONFIG_IEEE80211W */
if (res == WPA_INVALID_MDIE)
return WLAN_STATUS_INVALID_MDIE;
@@ -1175,6 +1549,7 @@
}
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+ hapd->iface->freq,
elems.rsn_ie - 2, elems.rsn_ie_len + 2,
elems.mdie, elems.mdie_len, NULL, 0);
resp = wpa_res_to_status_code(res);
@@ -1374,8 +1749,11 @@
if (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm))) {
/* FTE[R1KH-ID,R0KH-ID] when using FILS+FT */
int res;
+ int use_sha384 = wpa_key_mgmt_sha384(
+ wpa_auth_sta_key_mgmt(sta->wpa_sm));
- res = wpa_auth_write_fte(hapd->wpa_auth, wpabuf_put(data, 0),
+ res = wpa_auth_write_fte(hapd->wpa_auth, use_sha384,
+ wpabuf_put(data, 0),
wpabuf_tailroom(data));
if (res < 0) {
*resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -1430,15 +1808,25 @@
if (sta->fils_erp_pmkid_set) {
/* TODO: get PMKLifetime from WPA parameters */
unsigned int dot11RSNAConfigPMKLifetime = 43200;
+ int session_timeout;
+
+ session_timeout = dot11RSNAConfigPMKLifetime;
+ if (sta->session_timeout_set) {
+ struct os_reltime now, diff;
+
+ os_get_reltime(&now);
+ os_reltime_sub(&sta->session_timeout, &now,
+ &diff);
+ session_timeout = diff.sec;
+ }
sta->fils_erp_pmkid_set = 0;
- if (wpa_auth_pmksa_add2(
+ if (!hapd->conf->disable_pmksa_caching &&
+ wpa_auth_pmksa_add2(
hapd->wpa_auth, sta->addr,
pmk, pmk_len,
sta->fils_erp_pmkid,
- sta->session_timeout_set ?
- sta->session_timeout :
- dot11RSNAConfigPMKLifetime,
+ session_timeout,
wpa_auth_sta_key_mgmt(sta->wpa_sm)) < 0) {
wpa_printf(MSG_ERROR,
"FILS: Failed to add PMKSA cache entry based on ERP");
@@ -1496,7 +1884,7 @@
WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
send_auth_reply(hapd, sta->addr, hapd->own_addr, auth_alg, 2, resp,
data ? wpabuf_head(data) : (u8 *) "",
- data ? wpabuf_len(data) : 0);
+ data ? wpabuf_len(data) : 0, "auth-fils-finish");
wpabuf_free(data);
if (resp == WLAN_STATUS_SUCCESS) {
@@ -1538,25 +1926,28 @@
#endif /* CONFIG_FILS */
-static int
+int
ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
u32 *acct_interim_interval,
struct vlan_description *vlan_id,
struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui)
+ char **identity, char **radius_cui, int is_probe_req)
{
int res;
os_memset(vlan_id, 0, sizeof(*vlan_id));
res = hostapd_allowed_address(hapd, addr, msg, len,
session_timeout, acct_interim_interval,
- vlan_id, psk, identity, radius_cui);
+ vlan_id, psk, identity, radius_cui,
+ is_probe_req);
if (res == HOSTAPD_ACL_REJECT) {
- wpa_printf(MSG_INFO,
- "Station " MACSTR " not allowed to authenticate",
- MAC2STR(addr));
+ if (!is_probe_req)
+ wpa_printf(MSG_DEBUG,
+ "Station " MACSTR
+ " not allowed to authenticate",
+ MAC2STR(addr));
return HOSTAPD_ACL_REJECT;
}
@@ -1605,24 +1996,33 @@
sta->psk = NULL;
}
+ os_free(sta->identity);
sta->identity = *identity;
*identity = NULL;
+
+ os_free(sta->radius_cui);
sta->radius_cui = *radius_cui;
*radius_cui = NULL;
if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
sta->acct_interim_interval = acct_interim_interval;
- if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
+ if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT) {
+ sta->session_timeout_set = 1;
+ os_get_reltime(&sta->session_timeout);
+ sta->session_timeout.sec += session_timeout;
ap_sta_session_timeout(hapd, sta, session_timeout);
- else
+ } else {
+ sta->session_timeout_set = 0;
ap_sta_no_session_timeout(hapd, sta);
+ }
return 0;
}
static void handle_auth(struct hostapd_data *hapd,
- const struct ieee80211_mgmt *mgmt, size_t len)
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ int rssi, int from_queue)
{
u16 auth_alg, auth_transaction, status_code;
u16 resp = WLAN_STATUS_SUCCESS;
@@ -1669,11 +2069,12 @@
wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
"auth_transaction=%d status_code=%d wep=%d%s "
- "seq_ctrl=0x%x%s",
+ "seq_ctrl=0x%x%s%s",
MAC2STR(mgmt->sa), auth_alg, auth_transaction,
status_code, !!(fc & WLAN_FC_ISWEP),
challenge ? " challenge" : "",
- seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
+ seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "",
+ from_queue ? " (from queue)" : "");
#ifdef CONFIG_NO_RC4
if (auth_alg == WLAN_AUTH_SHARED_KEY) {
@@ -1686,7 +2087,9 @@
#endif /* CONFIG_NO_RC4 */
if (hapd->tkip_countermeasures) {
- resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
+ wpa_printf(MSG_DEBUG,
+ "Ongoing TKIP countermeasures (Michael MIC failure) - reject authentication");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
@@ -1787,17 +2190,38 @@
res = ieee802_11_allowed_address(
hapd, mgmt->sa, (const u8 *) mgmt, len, &session_timeout,
- &acct_interim_interval, &vlan_id, &psk, &identity, &radius_cui);
+ &acct_interim_interval, &vlan_id, &psk, &identity, &radius_cui,
+ 0);
if (res == HOSTAPD_ACL_REJECT) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "Ignore Authentication frame from " MACSTR
+ " due to ACL reject", MAC2STR(mgmt->sa));
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
if (res == HOSTAPD_ACL_PENDING)
return;
+#ifdef CONFIG_SAE
+ if (auth_alg == WLAN_AUTH_SAE && !from_queue &&
+ (auth_transaction == 1 ||
+ (auth_transaction == 2 && auth_sae_queued_addr(hapd, mgmt->sa)))) {
+ /* Handle SAE Authentication commit message through a queue to
+ * provide more control for postponing the needed heavy
+ * processing under a possible DoS attack scenario. In addition,
+ * queue SAE Authentication confirm message if there happens to
+ * be a queued commit message from the same peer. This is needed
+ * to avoid reordering Authentication frames within the same
+ * SAE exchange. */
+ auth_sae_queue(hapd, mgmt, len, rssi);
+ return;
+ }
+#endif /* CONFIG_SAE */
+
sta = ap_get_sta(hapd, mgmt->sa);
if (sta) {
sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
+ sta->ft_over_ds = 0;
if ((fc & WLAN_FC_RETRY) &&
sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
sta->last_seq_ctrl == seq_ctrl &&
@@ -1839,17 +2263,22 @@
sta = ap_sta_add(hapd, mgmt->sa);
if (!sta) {
+ wpa_printf(MSG_DEBUG, "ap_sta_add() failed");
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
goto fail;
}
}
sta->last_seq_ctrl = seq_ctrl;
sta->last_subtype = WLAN_FC_STYPE_AUTH;
+#ifdef CONFIG_MBO
+ sta->auth_rssi = rssi;
+#endif /* CONFIG_MBO */
res = ieee802_11_set_radius_info(
hapd, sta, res, session_timeout, acct_interim_interval,
&vlan_id, &psk, &identity, &radius_cui);
if (res) {
+ wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed");
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
@@ -1887,6 +2316,7 @@
* updated. To handle this, station's added_unassoc flag is
* cleared once the station has completed association.
*/
+ ap_sta_set_authorized(hapd, sta, 0);
hostapd_drv_sta_remove(hapd, sta->addr);
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH |
WLAN_STA_AUTHORIZED);
@@ -1918,6 +2348,9 @@
case WLAN_AUTH_SHARED_KEY:
resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
fc & WLAN_FC_ISWEP);
+ if (resp != 0)
+ wpa_printf(MSG_DEBUG,
+ "auth_shared_key() failed: status=%d", resp);
sta->auth_alg = WLAN_AUTH_SHARED_KEY;
mlme_authenticate_indication(hapd, sta);
if (sta->challenge && auth_transaction == 1) {
@@ -1988,7 +2421,7 @@
reply_res = send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
auth_transaction + 1, resp, resp_ies,
- resp_ies_len);
+ resp_ies_len, "handle-auth");
if (sta && sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
reply_res != WLAN_STATUS_SUCCESS)) {
@@ -2077,6 +2510,59 @@
return WLAN_STATUS_SUCCESS;
}
+static u16 check_multi_ap(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *multi_ap_ie, size_t multi_ap_len)
+{
+ u8 multi_ap_value = 0;
+
+ sta->flags &= ~WLAN_STA_MULTI_AP;
+
+ if (!hapd->conf->multi_ap)
+ return WLAN_STATUS_SUCCESS;
+
+ if (multi_ap_ie) {
+ const u8 *multi_ap_subelem;
+
+ multi_ap_subelem = get_ie(multi_ap_ie + 4,
+ multi_ap_len - 4,
+ MULTI_AP_SUB_ELEM_TYPE);
+ if (multi_ap_subelem && multi_ap_subelem[1] == 1) {
+ multi_ap_value = multi_ap_subelem[2];
+ } else {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Multi-AP IE has missing or invalid Multi-AP subelement");
+ return WLAN_STATUS_INVALID_IE;
+ }
+ }
+
+ if (multi_ap_value && multi_ap_value != MULTI_AP_BACKHAUL_STA)
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Multi-AP IE with unexpected value 0x%02x",
+ multi_ap_value);
+
+ if (!(multi_ap_value & MULTI_AP_BACKHAUL_STA)) {
+ if (hapd->conf->multi_ap & FRONTHAUL_BSS)
+ return WLAN_STATUS_SUCCESS;
+
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Non-Multi-AP STA tries to associate with backhaul-only BSS");
+ return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+ }
+
+ if (!(hapd->conf->multi_ap & BACKHAUL_BSS))
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "Backhaul STA tries to associate with fronthaul-only BSS");
+
+ sta->flags |= WLAN_STA_MULTI_AP;
+ return WLAN_STATUS_SUCCESS;
+}
+
static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
struct ieee802_11_elems *elems)
@@ -2123,8 +2609,16 @@
}
#endif /* CONFIG_INTERWORKING */
- if (ext_capab_ie_len > 0)
+ if (ext_capab_ie_len > 0) {
sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2));
+ os_free(sta->ext_capability);
+ sta->ext_capability = os_malloc(1 + ext_capab_ie_len);
+ if (sta->ext_capability) {
+ sta->ext_capability[0] = ext_capab_ie_len;
+ os_memcpy(sta->ext_capability + 1, ext_capab_ie,
+ ext_capab_ie_len);
+ }
+ }
return WLAN_STATUS_SUCCESS;
}
@@ -2325,6 +2819,11 @@
resp = copy_supp_rates(hapd, sta, &elems);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
+
+ resp = check_multi_ap(hapd, sta, elems.multi_ap, elems.multi_ap_len);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+
#ifdef CONFIG_IEEE80211N
resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities);
if (resp != WLAN_STATUS_SUCCESS)
@@ -2344,6 +2843,10 @@
if (resp != WLAN_STATUS_SUCCESS)
return resp;
+ resp = copy_sta_vht_oper(hapd, sta, elems.vht_operation);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+
resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
@@ -2436,7 +2939,9 @@
"state machine");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
+ wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg);
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+ hapd->iface->freq,
wpa_ie, wpa_ie_len,
elems.mdie, elems.mdie_len,
elems.owe_dh, elems.owe_dh_len);
@@ -2444,10 +2949,14 @@
if (resp != WLAN_STATUS_SUCCESS)
return resp;
#ifdef CONFIG_IEEE80211W
- if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+ 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_MFP) && !sta->sa_query_timed_out &&
+ 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
@@ -2486,6 +2995,10 @@
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_SAE
+ if (wpa_auth_uses_sae(sta->wpa_sm) && sta->sae &&
+ sta->sae->state == SAE_ACCEPTED)
+ wpa_auth_add_sae_pmkid(sta->wpa_sm, sta->sae->pmkid);
+
if (wpa_auth_uses_sae(sta->wpa_sm) &&
sta->auth_alg == WLAN_AUTH_OPEN) {
struct rsn_pmksa_cache_entry *sa;
@@ -2520,6 +3033,37 @@
}
#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP2
+ dpp_pfs_free(sta->dpp_pfs);
+ sta->dpp_pfs = NULL;
+
+ if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
+ hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
+ wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
+ elems.owe_dh) {
+ sta->dpp_pfs = dpp_pfs_init(
+ wpabuf_head(hapd->conf->dpp_netaccesskey),
+ wpabuf_len(hapd->conf->dpp_netaccesskey));
+ if (!sta->dpp_pfs) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not initialize PFS");
+ /* Try to continue without PFS */
+ goto pfs_fail;
+ }
+
+ if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh,
+ elems.owe_dh_len) < 0) {
+ dpp_pfs_free(sta->dpp_pfs);
+ sta->dpp_pfs = NULL;
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ }
+
+ wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ?
+ sta->dpp_pfs->secret : NULL);
+ pfs_fail:
+#endif /* CONFIG_DPP2 */
+
#ifdef CONFIG_IEEE80211N
if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
@@ -2564,10 +3108,28 @@
#ifdef CONFIG_HS20
wpabuf_free(sta->hs20_ie);
if (elems.hs20 && elems.hs20_len > 4) {
+ int release;
+
sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
elems.hs20_len - 4);
- } else
+ release = ((elems.hs20[4] >> 4) & 0x0f) + 1;
+ if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm)) {
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: PMF not negotiated by release %d station "
+ MACSTR, release, MAC2STR(sta->addr));
+ return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
+ }
+ } else {
sta->hs20_ie = NULL;
+ }
+
+ wpabuf_free(sta->roaming_consortium);
+ if (elems.roaming_cons_sel)
+ sta->roaming_consortium = wpabuf_alloc_copy(
+ elems.roaming_cons_sel + 4,
+ elems.roaming_cons_sel_len - 4);
+ else
+ sta->roaming_consortium = NULL;
#endif /* CONFIG_HS20 */
#ifdef CONFIG_FST
@@ -2590,6 +3152,35 @@
}
#endif /* CONFIG_MBO */
+#if defined(CONFIG_FILS) && defined(CONFIG_OCV)
+ if (wpa_auth_uses_ocv(sta->wpa_sm) &&
+ (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sta->auth_alg == WLAN_AUTH_FILS_PK)) {
+ struct wpa_channel_info ci;
+ int tx_chanwidth;
+ int tx_seg1_idx;
+
+ if (hostapd_drv_channel_info(hapd, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info to validate received OCI in FILS (Re)Association Request frame");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ if (get_sta_tx_parameters(sta->wpa_sm,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx, &tx_chanwidth,
+ &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);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ }
+#endif /* CONFIG_FILS && CONFIG_OCV */
+
ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes,
elems.supp_op_classes_len);
@@ -2599,6 +3190,14 @@
os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled,
sizeof(sta->rrm_enabled_capa));
+ if (elems.power_capab) {
+ sta->min_tx_power = elems.power_capab[0];
+ sta->max_tx_power = elems.power_capab[1];
+ sta->power_capab = 1;
+ } else {
+ sta->power_capab = 0;
+ }
+
return WLAN_STATUS_SUCCESS;
}
@@ -2626,7 +3225,7 @@
static int add_associated_sta(struct hostapd_data *hapd,
- struct sta_info *sta)
+ struct sta_info *sta, int reassoc)
{
struct ieee80211_ht_capabilities ht_cap;
struct ieee80211_vht_capabilities vht_cap;
@@ -2642,14 +3241,36 @@
* Skip this if the STA has already completed FT reassociation and the
* TK has been configured since the TX/RX PN must not be reset to 0 for
* the same key.
+ *
+ * FT-over-the-DS has a special case where the STA entry (and as such,
+ * the TK) has not yet been configured to the driver depending on which
+ * driver interface is used. For that case, allow add-STA operation to
+ * be used (instead of set-STA). This is needed to allow mac80211-based
+ * drivers to accept the STA parameter configuration. Since this is
+ * after a new FT-over-DS exchange, a new TK has been derived, so key
+ * reinstallation is not a concern for this case.
*/
+ wpa_printf(MSG_DEBUG, "Add associated STA " MACSTR
+ " (added_unassoc=%d auth_alg=%u ft_over_ds=%u reassoc=%d authorized=%d ft_tk=%d fils_tk=%d)",
+ MAC2STR(sta->addr), sta->added_unassoc, sta->auth_alg,
+ sta->ft_over_ds, reassoc,
+ !!(sta->flags & WLAN_STA_AUTHORIZED),
+ wpa_auth_sta_ft_tk_already_set(sta->wpa_sm),
+ wpa_auth_sta_fils_tk_already_set(sta->wpa_sm));
+
if (!sta->added_unassoc &&
(!(sta->flags & WLAN_STA_AUTHORIZED) ||
+ (reassoc && sta->ft_over_ds && sta->auth_alg == WLAN_AUTH_FT) ||
(!wpa_auth_sta_ft_tk_already_set(sta->wpa_sm) &&
!wpa_auth_sta_fils_tk_already_set(sta->wpa_sm)))) {
hostapd_drv_sta_remove(hapd, sta->addr);
wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED);
set = 0;
+
+ /* Do not allow the FT-over-DS exception to be used more than
+ * once per authentication exchange to guarantee a new TK is
+ * used here */
+ sta->ft_over_ds = 0;
}
#ifdef CONFIG_IEEE80211N
@@ -2695,7 +3316,7 @@
static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *addr, u16 status_code, int reassoc,
- const u8 *ies, size_t ies_len)
+ const u8 *ies, size_t ies_len, int rssi)
{
int send_len;
u8 *buf;
@@ -2713,6 +3334,10 @@
if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
buflen += 150;
#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP2
+ if (sta && sta->dpp_pfs)
+ buflen += 5 + sta->dpp_pfs->curve->prime_len;
+#endif /* CONFIG_DPP2 */
buf = os_zalloc(buflen);
if (!buf) {
res = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -2740,6 +3365,16 @@
/* Extended supported rates */
p = hostapd_eid_ext_supp_rates(hapd, p);
+#ifdef CONFIG_MBO
+ if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
+ rssi != 0) {
+ int delta = hapd->iconf->rssi_reject_assoc_rssi - rssi;
+
+ p = hostapd_eid_mbo_rssi_assoc_rej(hapd, p, buf + buflen - p,
+ delta);
+ }
+#endif /* CONFIG_MBO */
+
#ifdef CONFIG_IEEE80211R_AP
if (sta && status_code == WLAN_STATUS_SUCCESS) {
/* IEEE 802.11r: Mobility Domain Information, Fast BSS
@@ -2747,11 +3382,18 @@
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
buf + buflen - p,
sta->auth_alg, ies, ies_len);
+ if (!p) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Failed to write AssocResp IEs");
+ res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto done;
+ }
}
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_OWE
- if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
+ if (sta && status_code == WLAN_STATUS_SUCCESS &&
+ (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
p = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, p,
buf + buflen - p,
ies, ies_len);
@@ -2803,6 +3445,39 @@
}
#endif /* CONFIG_FST */
+#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) {
+ struct wpabuf *pub;
+
+ pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
+ if (!pub) {
+ res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto done;
+ }
+ /* OWE Diffie-Hellman Parameter element */
+ *p++ = WLAN_EID_EXTENSION; /* Element ID */
+ *p++ = 1 + 2 + wpabuf_len(pub); /* Length */
+ *p++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension */
+ WPA_PUT_LE16(p, sta->owe_group);
+ p += 2;
+ os_memcpy(p, wpabuf_head(pub), wpabuf_len(pub));
+ p += wpabuf_len(pub);
+ wpabuf_free(pub);
+ }
+#endif /* CONFIG_OWE */
+
+#ifdef CONFIG_DPP2
+ if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
+ sta && sta->dpp_pfs && status_code == WLAN_STATUS_SUCCESS &&
+ wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP) {
+ os_memcpy(p, wpabuf_head(sta->dpp_pfs->ie),
+ wpabuf_len(sta->dpp_pfs->ie));
+ p += wpabuf_len(sta->dpp_pfs->ie);
+ }
+#endif /* CONFIG_DPP2 */
+
#ifdef CONFIG_IEEE80211AC
if (sta && hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
p = hostapd_eid_vendor_vht(hapd, p);
@@ -2824,6 +3499,9 @@
}
#endif /* CONFIG_WPS */
+ if (sta && (sta->flags & WLAN_STA_MULTI_AP))
+ p = hostapd_eid_multi_ap(hapd, p);
+
#ifdef CONFIG_P2P
if (sta && sta->p2p_ie && hapd->p2p_group) {
struct wpabuf *p2p_resp_ie;
@@ -2896,30 +3574,6 @@
}
#endif /* CONFIG_FILS */
-#ifdef CONFIG_OWE
- if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
- sta && sta->owe_ecdh &&
- wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE) {
- struct wpabuf *pub;
-
- pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
- if (!pub) {
- res = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto done;
- }
- /* OWE Diffie-Hellman Parameter element */
- *p++ = WLAN_EID_EXTENSION; /* Element ID */
- *p++ = 1 + 2 + wpabuf_len(pub); /* Length */
- *p++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension */
- WPA_PUT_LE16(p, sta->owe_group);
- p += 2;
- os_memcpy(p, wpabuf_head(pub), wpabuf_len(pub));
- p += wpabuf_len(pub);
- send_len += 3 + 2 + wpabuf_len(pub);
- wpabuf_free(pub);
- }
-#endif /* CONFIG_OWE */
-
if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) {
wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
strerror(errno));
@@ -2932,6 +3586,61 @@
}
+#ifdef CONFIG_OWE
+u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *owe_dh, u8 owe_dh_len,
+ u8 *owe_buf, size_t owe_buf_len, u16 *reason)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->own_ie_override) {
+ wpa_printf(MSG_DEBUG, "OWE: Using IE override");
+ *reason = WLAN_STATUS_SUCCESS;
+ return wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
+ owe_buf_len, NULL, 0);
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
+ wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
+ owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
+ owe_buf_len, NULL, 0);
+ *reason = WLAN_STATUS_SUCCESS;
+ return owe_buf;
+ }
+
+ *reason = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
+ if (*reason != WLAN_STATUS_SUCCESS)
+ return NULL;
+
+ owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
+ owe_buf_len, NULL, 0);
+
+ if (sta->owe_ecdh && owe_buf) {
+ struct wpabuf *pub;
+
+ pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
+ if (!pub) {
+ *reason = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ return owe_buf;
+ }
+
+ /* OWE Diffie-Hellman Parameter element */
+ *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
+ *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
+ *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
+ */
+ WPA_PUT_LE16(owe_buf, sta->owe_group);
+ owe_buf += 2;
+ os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
+ owe_buf += wpabuf_len(pub);
+ wpabuf_free(pub);
+ }
+
+ return owe_buf;
+}
+#endif /* CONFIG_OWE */
+
+
#ifdef CONFIG_FILS
void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta)
@@ -2946,7 +3655,7 @@
reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
sta->fils_pending_assoc_is_reassoc,
sta->fils_pending_assoc_req,
- sta->fils_pending_assoc_req_len);
+ sta->fils_pending_assoc_req_len, 0);
os_free(sta->fils_pending_assoc_req);
sta->fils_pending_assoc_req = NULL;
sta->fils_pending_assoc_req_len = 0;
@@ -2983,7 +3692,7 @@
static void handle_assoc(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
- int reassoc)
+ int reassoc, int rssi)
{
u16 capab_info, listen_interval, seq_ctrl, fc;
u16 resp = WLAN_STATUS_SUCCESS, reply_res;
@@ -3079,8 +3788,12 @@
acl_res = ieee802_11_allowed_address(
hapd, mgmt->sa, (const u8 *) mgmt, len,
&session_timeout, &acct_interim_interval,
- &vlan_id, &psk, &identity, &radius_cui);
+ &vlan_id, &psk, &identity, &radius_cui, 0);
if (acl_res == HOSTAPD_ACL_REJECT) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "Ignore Association Request frame from "
+ MACSTR " due to ACL reject",
+ MAC2STR(mgmt->sa));
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
@@ -3144,7 +3857,7 @@
WLAN_FC_STYPE_ASSOC_REQ;
if (hapd->tkip_countermeasures) {
- resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
@@ -3162,6 +3875,14 @@
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
goto fail;
}
+
+ if (hapd->iconf->rssi_reject_assoc_rssi && rssi &&
+ rssi < hapd->iconf->rssi_reject_assoc_rssi &&
+ (sta->auth_rssi == 0 ||
+ sta->auth_rssi < hapd->iconf->rssi_reject_assoc_rssi)) {
+ resp = WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS;
+ goto fail;
+ }
#endif /* CONFIG_MBO */
/*
@@ -3174,6 +3895,8 @@
if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
sta->auth_alg == WLAN_AUTH_FILS_PK) {
+ int res;
+
/* The end of the payload is encrypted. Need to decrypt it
* before parsing. */
@@ -3183,13 +3906,14 @@
goto fail;
}
- left = fils_decrypt_assoc(sta->wpa_sm, sta->fils_session, mgmt,
- len, tmp, left);
- if (left < 0) {
+ res = fils_decrypt_assoc(sta->wpa_sm, sta->fils_session, mgmt,
+ len, tmp, left);
+ if (res < 0) {
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
pos = tmp;
+ left = res;
}
#endif /* CONFIG_FILS */
@@ -3208,7 +3932,8 @@
sta->listen_interval = listen_interval;
- if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
sta->flags |= WLAN_STA_NONERP;
for (i = 0; i < sta->supported_rates_len; i++) {
if ((sta->supported_rates[i] & 0x7f) > 22) {
@@ -3227,7 +3952,8 @@
!sta->no_short_slot_time_set) {
sta->no_short_slot_time_set = 1;
hapd->iface->num_sta_no_short_slot_time++;
- if (hapd->iface->current_mode->mode ==
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode ==
HOSTAPD_MODE_IEEE80211G &&
hapd->iface->num_sta_no_short_slot_time == 1)
ieee802_11_set_beacons(hapd->iface);
@@ -3242,7 +3968,8 @@
!sta->no_short_preamble_set) {
sta->no_short_preamble_set = 1;
hapd->iface->num_sta_no_short_preamble++;
- if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
&& hapd->iface->num_sta_no_short_preamble == 1)
ieee802_11_set_beacons(hapd->iface);
}
@@ -3313,10 +4040,24 @@
* issues with processing other non-Data Class 3 frames during this
* window.
*/
- if (resp == WLAN_STATUS_SUCCESS && sta && add_associated_sta(hapd, sta))
+ if (resp == WLAN_STATUS_SUCCESS && sta &&
+ add_associated_sta(hapd, sta, reassoc))
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
#ifdef CONFIG_FILS
+ if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS &&
+ eloop_is_timeout_registered(fils_hlp_timeout, hapd, sta) &&
+ sta->fils_pending_assoc_req) {
+ /* Do not reschedule fils_hlp_timeout in case the station
+ * retransmits (Re)Association Request frame while waiting for
+ * the previously started FILS HLP wait, so that the timeout can
+ * be determined from the first pending attempt. */
+ wpa_printf(MSG_DEBUG,
+ "FILS: Continue waiting for HLP processing before sending (Re)Association Response frame to "
+ MACSTR, MAC2STR(sta->addr));
+ os_free(tmp);
+ return;
+ }
if (sta) {
eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
os_free(sta->fils_pending_assoc_req);
@@ -3341,7 +4082,7 @@
#endif /* CONFIG_FILS */
reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc, pos,
- left);
+ left, rssi);
os_free(tmp);
/*
@@ -3481,28 +4222,6 @@
#ifdef CONFIG_IEEE80211W
-
-static int hostapd_sa_query_action(struct hostapd_data *hapd,
- const struct ieee80211_mgmt *mgmt,
- size_t len)
-{
- const u8 *end;
-
- end = mgmt->u.action.u.sa_query_resp.trans_id +
- WLAN_SA_QUERY_TR_ID_LEN;
- if (((u8 *) mgmt) + len < end) {
- wpa_printf(MSG_DEBUG, "IEEE 802.11: Too short SA Query Action "
- "frame (len=%lu)", (unsigned long) len);
- return 0;
- }
-
- ieee802_11_sa_query_action(hapd, mgmt->sa,
- mgmt->u.action.u.sa_query_resp.action,
- mgmt->u.action.u.sa_query_resp.trans_id);
- return 1;
-}
-
-
static int robust_action_frame(u8 category)
{
return category != WLAN_ACTION_PUBLIC &&
@@ -3512,12 +4231,13 @@
static int handle_action(struct hostapd_data *hapd,
- const struct ieee80211_mgmt *mgmt, size_t len)
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ unsigned int freq)
{
struct sta_info *sta;
- sta = ap_get_sta(hapd, mgmt->sa);
+ u8 *action __maybe_unused;
- if (len < IEEE80211_HDRLEN + 1) {
+ if (len < IEEE80211_HDRLEN + 2 + 1) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"handle_action - too short payload (len=%lu)",
@@ -3525,6 +4245,14 @@
return 0;
}
+ action = (u8 *) &mgmt->u.action.u;
+ wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR
+ " da " MACSTR " len %d freq %u",
+ mgmt->u.action.category, *action,
+ MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) len, freq);
+
+ sta = ap_get_sta(hapd, mgmt->sa);
+
if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
(sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
@@ -3579,7 +4307,8 @@
return 1;
#ifdef CONFIG_IEEE80211W
case WLAN_ACTION_SA_QUERY:
- return hostapd_sa_query_action(hapd, mgmt, len);
+ ieee802_11_sa_query_action(hapd, mgmt, len);
+ return 1;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WNM_AP
case WLAN_ACTION_WNM:
@@ -3601,9 +4330,6 @@
if (len >= IEEE80211_HDRLEN + 2 &&
mgmt->u.action.u.public_action.action ==
WLAN_PA_20_40_BSS_COEX) {
- wpa_printf(MSG_DEBUG,
- "HT20/40 coex mgmt frame received from STA "
- MACSTR, MAC2STR(mgmt->sa));
hostapd_2040_coex_action(hapd, mgmt, len);
return 1;
}
@@ -3621,7 +4347,7 @@
pos = mgmt->u.action.u.vs_public_action.oui;
end = ((const u8 *) mgmt) + len;
hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos,
- hapd->iface->freq);
+ freq);
return 1;
}
if (len >= IEEE80211_HDRLEN + 2 &&
@@ -3720,10 +4446,17 @@
struct ieee80211_mgmt *mgmt;
u16 fc, stype;
int ret = 0;
+ unsigned int freq;
+ int ssi_signal = fi ? fi->ssi_signal : 0;
if (len < 24)
return 0;
+ if (fi && fi->freq)
+ freq = fi->freq;
+ else
+ freq = hapd->iface->freq;
+
mgmt = (struct ieee80211_mgmt *) buf;
fc = le_to_host16(mgmt->frame_control);
stype = WLAN_FC_GET_STYPE(fc);
@@ -3750,7 +4483,7 @@
if (stype == WLAN_FC_STYPE_PROBE_REQ) {
- handle_probe_req(hapd, mgmt, len, fi->ssi_signal);
+ handle_probe_req(hapd, mgmt, len, ssi_signal);
return 1;
}
@@ -3765,22 +4498,22 @@
}
if (hapd->iconf->track_sta_max_num)
- sta_track_add(hapd->iface, mgmt->sa, fi->ssi_signal);
+ sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
switch (stype) {
case WLAN_FC_STYPE_AUTH:
wpa_printf(MSG_DEBUG, "mgmt::auth");
- handle_auth(hapd, mgmt, len);
+ handle_auth(hapd, mgmt, len, ssi_signal, 0);
ret = 1;
break;
case WLAN_FC_STYPE_ASSOC_REQ:
wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
- handle_assoc(hapd, mgmt, len, 0);
+ handle_assoc(hapd, mgmt, len, 0, ssi_signal);
ret = 1;
break;
case WLAN_FC_STYPE_REASSOC_REQ:
wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
- handle_assoc(hapd, mgmt, len, 1);
+ handle_assoc(hapd, mgmt, len, 1, ssi_signal);
ret = 1;
break;
case WLAN_FC_STYPE_DISASSOC:
@@ -3795,7 +4528,7 @@
break;
case WLAN_FC_STYPE_ACTION:
wpa_printf(MSG_DEBUG, "mgmt::action");
- ret = handle_action(hapd, mgmt, len);
+ ret = handle_action(hapd, mgmt, len, freq);
break;
default:
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -3815,9 +4548,22 @@
u16 auth_alg, auth_transaction, status_code;
struct sta_info *sta;
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
+ wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
+ (unsigned long) len);
+
+ /*
+ * Initialize status_code here because we are not able to read
+ * it from the short payload.
+ */
+ status_code = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
sta = ap_get_sta(hapd, mgmt->da);
if (!sta) {
- wpa_printf(MSG_INFO, "handle_auth_cb: STA " MACSTR " not found",
+ wpa_printf(MSG_DEBUG, "handle_auth_cb: STA " MACSTR
+ " not found",
MAC2STR(mgmt->da));
return;
}
@@ -3833,12 +4579,6 @@
goto fail;
}
- if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
- wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
- (unsigned long) len);
- goto fail;
- }
-
if (status_code == WLAN_STATUS_SUCCESS &&
((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
(auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
@@ -3985,7 +4725,7 @@
sta->flags |= WLAN_STA_WDS;
}
- if (sta->flags & WLAN_STA_WDS) {
+ if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) {
int ret;
char ifname_wds[IFNAMSIZ + 1];
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 3b381b4..db7badc 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -16,6 +16,8 @@
struct ieee80211_ht_capabilities;
struct ieee80211_vht_capabilities;
struct ieee80211_mgmt;
+struct vlan_description;
+struct hostapd_sta_wpa_psk_short;
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
struct hostapd_frame_info *fi);
@@ -57,6 +59,7 @@
u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid);
int hostapd_ht_operation_update(struct hostapd_iface *iface);
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
@@ -78,6 +81,8 @@
void ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta);
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_capab);
+u16 copy_sta_vht_oper(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *vht_oper);
u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_opmode);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
@@ -89,8 +94,8 @@
u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
struct sta_info *sta, u8 *eid);
void ieee802_11_sa_query_action(struct hostapd_data *hapd,
- const u8 *sa, const u8 action_type,
- const u8 *trans_id);
+ const struct ieee80211_mgmt *mgmt,
+ size_t len);
u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid);
@@ -118,6 +123,9 @@
u8 hostapd_mbo_ie_len(struct hostapd_data *hapd);
+u8 * hostapd_eid_mbo_rssi_assoc_rej(struct hostapd_data *hapd, u8 *eid,
+ size_t len, int delta);
+
#else /* CONFIG_MBO */
static inline u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid,
@@ -142,6 +150,9 @@
struct sta_info *sta, int success,
struct wpabuf *erp_resp,
const u8 *msk, size_t msk_len);
+u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *owe_dh, u8 owe_dh_len,
+ u8 *owe_buf, size_t owe_buf_len, u16 *reason);
void fils_hlp_timeout(void *eloop_ctx, void *eloop_data);
void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta);
void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
@@ -151,4 +162,19 @@
struct sta_info *sta,
u16 resp, struct wpabuf *data, int pub));
+size_t hostapd_eid_owe_trans_len(struct hostapd_data *hapd);
+u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid, size_t len);
+int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *msg, size_t len, u32 *session_timeout,
+ u32 *acct_interim_interval,
+ struct vlan_description *vlan_id,
+ struct hostapd_sta_wpa_psk_short **psk,
+ char **identity, char **radius_cui,
+ int is_probe_req);
+
+int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
+ int ap_seg1_idx, int *bandwidth, int *seg1_idx);
+
+void auth_sae_process_commit(void *eloop_ctx, void *user_ctx);
+
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 3308398..931d4d0 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -244,6 +244,7 @@
* @psk: Linked list buffer for returning WPA PSK
* @identity: Buffer for returning identity (from RADIUS)
* @radius_cui: Buffer for returning CUI (from RADIUS)
+ * @is_probe_req: Whether this query for a Probe Request frame
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
*
* The caller is responsible for freeing the returned *identity and *radius_cui
@@ -254,7 +255,8 @@
u32 *acct_interim_interval,
struct vlan_description *vlan_id,
struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui)
+ char **identity, char **radius_cui,
+ int is_probe_req)
{
int res;
@@ -281,6 +283,15 @@
#else /* CONFIG_NO_RADIUS */
struct hostapd_acl_query_data *query;
+ if (is_probe_req) {
+ /* Skip RADIUS queries for Probe Request frames to avoid
+ * excessive load on the authentication server. */
+ return HOSTAPD_ACL_ACCEPT;
+ };
+
+ if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+ vlan_id = NULL;
+
/* Check whether ACL cache has an entry for this station */
res = hostapd_acl_cache_get(hapd, addr, session_timeout,
acct_interim_interval, vlan_id, psk,
@@ -508,7 +519,6 @@
struct hostapd_acl_query_data *query, *prev;
struct hostapd_cached_radius_acl *cache;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
- int *untagged, *tagged, *notempty;
query = hapd->acl_queries;
prev = NULL;
@@ -566,12 +576,10 @@
cache->acct_interim_interval = 0;
}
- notempty = &cache->vlan_id.notempty;
- untagged = &cache->vlan_id.untagged;
- tagged = cache->vlan_id.tagged;
- *notempty = !!radius_msg_get_vlanid(msg, untagged,
- MAX_NUM_TAGGED_VLAN,
- tagged);
+ if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED)
+ cache->vlan_id.notempty = !!radius_msg_get_vlanid(
+ msg, &cache->vlan_id.untagged,
+ MAX_NUM_TAGGED_VLAN, cache->vlan_id.tagged);
decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
msg, req, cache);
diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h
index 71f53b9..5aece51 100644
--- a/src/ap/ieee802_11_auth.h
+++ b/src/ap/ieee802_11_auth.h
@@ -23,7 +23,8 @@
u32 *acct_interim_interval,
struct vlan_description *vlan_id,
struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui);
+ char **identity, char **radius_cui,
+ int is_probe_req);
int hostapd_acl_init(struct hostapd_data *hapd);
void hostapd_acl_deinit(struct hostapd_data *hapd);
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index 1a8d469..0721358 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -86,3 +86,34 @@
return pos;
}
+
+
+u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid)
+{
+ struct ieee80211_he_mu_edca_parameter_set *edca;
+ u8 *pos;
+ size_t i;
+
+ pos = (u8 *) &hapd->iface->conf->he_mu_edca;
+ for (i = 0; i < sizeof(*edca); i++) {
+ if (pos[i])
+ break;
+ }
+ if (i == sizeof(*edca))
+ return eid; /* no MU EDCA Parameters configured */
+
+ pos = eid;
+ *pos++ = WLAN_EID_EXTENSION;
+ *pos++ = 1 + sizeof(*edca);
+ *pos++ = WLAN_EID_EXT_HE_MU_EDCA_PARAMS;
+
+ edca = (struct ieee80211_he_mu_edca_parameter_set *) pos;
+ os_memcpy(edca, &hapd->iface->conf->he_mu_edca, sizeof(*edca));
+
+ wpa_hexdump(MSG_DEBUG, "HE: MU EDCA Parameter Set element",
+ pos, sizeof(*edca));
+
+ pos += sizeof(*edca);
+
+ return pos;
+}
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 146e447..214855d 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -236,17 +236,29 @@
int i;
const u8 *start = (const u8 *) mgmt;
const u8 *data = start + IEEE80211_HDRLEN + 2;
+ struct sta_info *sta;
+
+ wpa_printf(MSG_DEBUG,
+ "HT: Received 20/40 BSS Coexistence Management frame from "
+ MACSTR, MAC2STR(mgmt->sa));
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "hostapd_public_action - action=%d",
mgmt->u.action.u.public_action.action);
- if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
+ wpa_printf(MSG_DEBUG,
+ "Ignore 20/40 BSS Coexistence Management frame since 40 MHz capability is not enabled");
return;
+ }
- if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie))
+ if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie)) {
+ wpa_printf(MSG_DEBUG,
+ "Ignore too short 20/40 BSS Coexistence Management frame");
return;
+ }
+ /* 20/40 BSS Coexistence element */
bc_ie = (struct ieee80211_2040_bss_coex_ie *) data;
if (bc_ie->element_id != WLAN_EID_20_40_BSS_COEXISTENCE ||
bc_ie->length < 1) {
@@ -254,13 +266,35 @@
bc_ie->element_id, bc_ie->length);
return;
}
- if (len < IEEE80211_HDRLEN + 2 + 2 + bc_ie->length)
+ if (len < IEEE80211_HDRLEN + 2 + 2 + bc_ie->length) {
+ wpa_printf(MSG_DEBUG,
+ "Truncated 20/40 BSS Coexistence element");
return;
+ }
data += 2 + bc_ie->length;
- wpa_printf(MSG_DEBUG, "20/40 BSS Coexistence Information field: 0x%x",
- bc_ie->coex_param);
+ wpa_printf(MSG_DEBUG,
+ "20/40 BSS Coexistence Information field: 0x%x (%s%s%s%s%s%s)",
+ bc_ie->coex_param,
+ (bc_ie->coex_param & BIT(0)) ? "[InfoReq]" : "",
+ (bc_ie->coex_param & BIT(1)) ? "[40MHzIntolerant]" : "",
+ (bc_ie->coex_param & BIT(2)) ? "[20MHzBSSWidthReq]" : "",
+ (bc_ie->coex_param & BIT(3)) ? "[OBSSScanExemptionReq]" : "",
+ (bc_ie->coex_param & BIT(4)) ?
+ "[OBSSScanExemptionGrant]" : "",
+ (bc_ie->coex_param & (BIT(5) | BIT(6) | BIT(7))) ?
+ "[Reserved]" : "");
+
if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ) {
+ /* Intra-BSS communication prohibiting 20/40 MHz BSS operation
+ */
+ sta = ap_get_sta(hapd, mgmt->sa);
+ if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
+ wpa_printf(MSG_DEBUG,
+ "Ignore intra-BSS 20/40 BSS Coexistence Management frame from not-associated STA");
+ return;
+ }
+
hostapd_logger(hapd, mgmt->sa,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -269,6 +303,8 @@
}
if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_40MHZ_INTOL) {
+ /* Inter-BSS communication prohibiting 20/40 MHz BSS operation
+ */
hostapd_logger(hapd, mgmt->sa,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -276,12 +312,16 @@
is_ht40_allowed = 0;
}
- if (start + len - data >= 3 &&
- data[0] == WLAN_EID_20_40_BSS_INTOLERANT && data[1] >= 1) {
+ /* 20/40 BSS Intolerant Channel Report element (zero or more times) */
+ while (start + len - data >= 3 &&
+ data[0] == WLAN_EID_20_40_BSS_INTOLERANT && data[1] >= 1) {
u8 ielen = data[1];
- if (ielen > start + len - data - 2)
+ if (ielen > start + len - data - 2) {
+ wpa_printf(MSG_DEBUG,
+ "Truncated 20/40 BSS Intolerant Channel Report element");
return;
+ }
ic_report = (struct ieee80211_2040_intol_chan_report *) data;
wpa_printf(MSG_DEBUG,
"20/40 BSS Intolerant Channel Report: Operating Class %u",
@@ -292,8 +332,10 @@
for (i = 0; i < ielen - 1; i++) {
u8 chan = ic_report->variable[i];
+ if (chan == iface->conf->channel)
+ continue; /* matching own primary channel */
if (is_40_allowed(iface, chan))
- continue;
+ continue; /* not within affected channels */
hostapd_logger(hapd, mgmt->sa,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -301,6 +343,8 @@
chan);
is_ht40_allowed = 0;
}
+
+ data += 2 + ielen;
}
wpa_printf(MSG_DEBUG, "is_ht40_allowed=%d num_sta_ht40_intolerant=%d",
is_ht40_allowed, iface->num_sta_ht40_intolerant);
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 902f64f..707381f 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -10,10 +10,12 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/ocv.h"
#include "hostapd.h"
#include "sta_info.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
+#include "wpa_auth.h"
#include "ieee802_11.h"
@@ -49,7 +51,12 @@
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
const u8 *addr, const u8 *trans_id)
{
- struct ieee80211_mgmt mgmt;
+#ifdef CONFIG_OCV
+ struct sta_info *sta;
+#endif /* CONFIG_OCV */
+ struct ieee80211_mgmt *mgmt;
+ u8 *oci_ie = NULL;
+ u8 oci_ie_len = 0;
u8 *end;
wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
@@ -57,19 +64,61 @@
wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
trans_id, WLAN_SA_QUERY_TR_ID_LEN);
- os_memset(&mgmt, 0, sizeof(mgmt));
- mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
- WLAN_FC_STYPE_ACTION);
- os_memcpy(mgmt.da, addr, ETH_ALEN);
- os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
- os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
- mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
- mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
- os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
+#ifdef CONFIG_OCV
+ sta = ap_get_sta(hapd, addr);
+ if (sta && wpa_auth_uses_ocv(sta->wpa_sm)) {
+ struct wpa_channel_info ci;
+
+ if (hostapd_drv_channel_info(hapd, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in SA Query Request");
+ return;
+ }
+
+ oci_ie_len = OCV_OCI_EXTENDED_LEN;
+ oci_ie = os_zalloc(oci_ie_len);
+ if (!oci_ie) {
+ wpa_printf(MSG_WARNING,
+ "Failed to allocate buffer for OCI element in SA Query Request");
+ return;
+ }
+
+ if (ocv_insert_extended_oci(&ci, oci_ie) < 0) {
+ os_free(oci_ie);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
+ mgmt = os_zalloc(sizeof(*mgmt) + oci_ie_len);
+ if (!mgmt) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to allocate buffer for SA Query Response frame");
+ os_free(oci_ie);
+ return;
+ }
+
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memcpy(mgmt->da, addr, ETH_ALEN);
+ os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+ mgmt->u.action.category = WLAN_ACTION_SA_QUERY;
+ mgmt->u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
+ os_memcpy(mgmt->u.action.u.sa_query_req.trans_id, trans_id,
WLAN_SA_QUERY_TR_ID_LEN);
- end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
- if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0)
+ end = mgmt->u.action.u.sa_query_req.variable;
+#ifdef CONFIG_OCV
+ if (oci_ie_len > 0) {
+ os_memcpy(end, oci_ie, oci_ie_len);
+ end += oci_ie_len;
+ }
+#endif /* CONFIG_OCV */
+ if (hostapd_drv_send_mlme(hapd, mgmt, end - (u8 *) mgmt, 0) < 0)
wpa_printf(MSG_INFO, "ieee802_11_send_sa_query_req: send failed");
+
+ os_free(mgmt);
+ os_free(oci_ie);
}
@@ -77,7 +126,9 @@
const u8 *sa, const u8 *trans_id)
{
struct sta_info *sta;
- struct ieee80211_mgmt resp;
+ struct ieee80211_mgmt *resp;
+ u8 *oci_ie = NULL;
+ u8 oci_ie_len = 0;
u8 *end;
wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
@@ -92,30 +143,123 @@
return;
}
+#ifdef CONFIG_OCV
+ if (wpa_auth_uses_ocv(sta->wpa_sm)) {
+ struct wpa_channel_info ci;
+
+ if (hostapd_drv_channel_info(hapd, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in SA Query Response");
+ return;
+ }
+
+ oci_ie_len = OCV_OCI_EXTENDED_LEN;
+ oci_ie = os_zalloc(oci_ie_len);
+ if (!oci_ie) {
+ wpa_printf(MSG_WARNING,
+ "Failed to allocate buffer for for OCI element in SA Query Response");
+ return;
+ }
+
+ if (ocv_insert_extended_oci(&ci, oci_ie) < 0) {
+ os_free(oci_ie);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
+ resp = os_zalloc(sizeof(*resp) + oci_ie_len);
+ if (!resp) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to allocate buffer for SA Query Response frame");
+ os_free(oci_ie);
+ return;
+ }
+
wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
MACSTR, MAC2STR(sa));
- os_memset(&resp, 0, sizeof(resp));
- resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
- WLAN_FC_STYPE_ACTION);
- os_memcpy(resp.da, sa, ETH_ALEN);
- os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN);
- os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN);
- resp.u.action.category = WLAN_ACTION_SA_QUERY;
- resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
- os_memcpy(resp.u.action.u.sa_query_req.trans_id, trans_id,
+ resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memcpy(resp->da, sa, ETH_ALEN);
+ os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
+ resp->u.action.category = WLAN_ACTION_SA_QUERY;
+ resp->u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
+ os_memcpy(resp->u.action.u.sa_query_req.trans_id, trans_id,
WLAN_SA_QUERY_TR_ID_LEN);
- end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
- if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp, 0) < 0)
+ end = resp->u.action.u.sa_query_req.variable;
+#ifdef CONFIG_OCV
+ if (oci_ie_len > 0) {
+ os_memcpy(end, oci_ie, oci_ie_len);
+ end += oci_ie_len;
+ }
+#endif /* CONFIG_OCV */
+ if (hostapd_drv_send_mlme(hapd, resp, end - (u8 *) resp, 0) < 0)
wpa_printf(MSG_INFO, "ieee80211_mgmt_sa_query_request: send failed");
+
+ os_free(resp);
+ os_free(oci_ie);
}
-void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa,
- const u8 action_type, const u8 *trans_id)
+void ieee802_11_sa_query_action(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len)
{
struct sta_info *sta;
int i;
+ const u8 *sa = mgmt->sa;
+ const u8 action_type = mgmt->u.action.u.sa_query_resp.action;
+ const u8 *trans_id = mgmt->u.action.u.sa_query_resp.trans_id;
+
+ if (((const u8 *) mgmt) + len <
+ mgmt->u.action.u.sa_query_resp.variable) {
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.11: Too short SA Query Action frame (len=%lu)",
+ (unsigned long) len);
+ return;
+ }
+
+ sta = ap_get_sta(hapd, sa);
+
+#ifdef CONFIG_OCV
+ if (sta && wpa_auth_uses_ocv(sta->wpa_sm)) {
+ struct ieee802_11_elems elems;
+ struct wpa_channel_info ci;
+ int tx_chanwidth;
+ int tx_seg1_idx;
+ size_t ies_len;
+ const u8 *ies;
+
+ ies = mgmt->u.action.u.sa_query_resp.variable;
+ ies_len = len - (ies - (u8 *) mgmt);
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) ==
+ ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "SA Query: Failed to parse elements");
+ return;
+ }
+
+ if (hostapd_drv_channel_info(hapd, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info to validate received OCI in SA Query Action frame");
+ return;
+ }
+
+ if (get_sta_tx_parameters(sta->wpa_sm,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx, &tx_chanwidth,
+ &tx_seg1_idx) < 0)
+ 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);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
if (action_type == WLAN_SA_QUERY_REQUEST) {
ieee802_11_send_sa_query_resp(hapd, sa, trans_id);
@@ -135,7 +279,6 @@
/* MLME-SAQuery.confirm */
- sta = ap_get_sta(hapd, sa);
if (sta == NULL || sta->sa_query_trans_id == NULL) {
wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
"pending SA Query request found");
@@ -178,6 +321,10 @@
case 1: /* Bits 8-15 */
if (hapd->conf->proxy_arp)
*pos |= 0x10; /* Bit 12 - Proxy ARP */
+ if (hapd->conf->coloc_intf_reporting) {
+ /* Bit 13 - Collocated Interference Reporting */
+ *pos |= 0x20;
+ }
break;
case 2: /* Bits 16-23 */
if (hapd->conf->wnm_sleep_mode)
@@ -225,6 +372,7 @@
*pos |= 0x40; /* Bit 70 - FTM responder */
if (hapd->conf->ftm_initiator)
*pos |= 0x80; /* Bit 71 - FTM initiator */
+ break;
case 9: /* Bits 72-79 */
#ifdef CONFIG_FILS
if ((hapd->conf->wpa & WPA_PROTO_RSN) &&
@@ -232,6 +380,21 @@
*pos |= 0x01;
#endif /* CONFIG_FILS */
break;
+ case 10: /* Bits 80-87 */
+#ifdef CONFIG_SAE
+ if (hapd->conf->wpa &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt)) {
+ int in_use = hostapd_sae_pw_id_in_use(hapd->conf);
+
+ if (in_use)
+ *pos |= 0x02; /* Bit 81 - SAE Password
+ * Identifiers In Use */
+ if (in_use == 2)
+ *pos |= 0x04; /* Bit 82 - SAE Password
+ * Identifiers Used Exclusively */
+ }
+#endif /* CONFIG_SAE */
+ break;
}
}
@@ -271,6 +434,12 @@
!wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) && len < 10)
len = 10;
#endif /* CONFIG_FILS */
+#ifdef CONFIG_SAE
+ if (len < 11 && hapd->conf->wpa &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+ hostapd_sae_pw_id_in_use(hapd->conf))
+ len = 11;
+#endif /* CONFIG_SAE */
if (len < hapd->iface->extended_capa_len)
len = hapd->iface->extended_capa_len;
if (len == 0)
@@ -445,7 +614,7 @@
{
size_t len;
- if (hapd->conf->time_advertisement != 2)
+ if (hapd->conf->time_advertisement != 2 || !hapd->conf->time_zone)
return eid;
len = os_strlen(hapd->conf->time_zone);
@@ -542,12 +711,29 @@
#ifdef CONFIG_MBO
+u8 * hostapd_eid_mbo_rssi_assoc_rej(struct hostapd_data *hapd, u8 *eid,
+ size_t len, int delta)
+{
+ u8 mbo[4];
+
+ mbo[0] = OCE_ATTR_ID_RSSI_BASED_ASSOC_REJECT;
+ mbo[1] = 2;
+ /* Delta RSSI */
+ mbo[2] = delta;
+ /* Retry delay */
+ mbo[3] = hapd->iconf->rssi_reject_assoc_timeout;
+
+ return eid + mbo_add_ie(eid, len, mbo, 4);
+}
+
+
u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len)
{
u8 mbo[9], *mbo_pos = mbo;
u8 *pos = eid;
- if (!hapd->conf->mbo_enabled && !hapd->enable_oce)
+ if (!hapd->conf->mbo_enabled &&
+ !OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd))
return eid;
if (hapd->conf->mbo_enabled) {
@@ -563,12 +749,11 @@
*mbo_pos++ = hapd->mbo_assoc_disallow;
}
- if (hapd->enable_oce & (OCE_AP | OCE_STA_CFON)) {
+ if (OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd)) {
u8 ctrl;
ctrl = OCE_RELEASE;
- if ((hapd->enable_oce & (OCE_AP | OCE_STA_CFON)) ==
- OCE_STA_CFON)
+ if (OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd))
ctrl |= OCE_IS_STA_CFON;
*mbo_pos++ = OCE_ATTR_ID_CAPA_IND;
@@ -586,7 +771,8 @@
{
u8 len;
- if (!hapd->conf->mbo_enabled && !hapd->enable_oce)
+ if (!hapd->conf->mbo_enabled &&
+ !OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd))
return 0;
/*
@@ -598,7 +784,7 @@
len += 3 + (hapd->mbo_assoc_disallow ? 3 : 0);
/* OCE capability indication attribute (3) */
- if (hapd->enable_oce & (OCE_AP | OCE_STA_CFON))
+ if (OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd))
len += 3;
return len;
@@ -607,6 +793,67 @@
#endif /* CONFIG_MBO */
+#ifdef CONFIG_OWE
+static int hostapd_eid_owe_trans_enabled(struct hostapd_data *hapd)
+{
+ return hapd->conf->owe_transition_ssid_len > 0 &&
+ !is_zero_ether_addr(hapd->conf->owe_transition_bssid);
+}
+#endif /* CONFIG_OWE */
+
+
+size_t hostapd_eid_owe_trans_len(struct hostapd_data *hapd)
+{
+#ifdef CONFIG_OWE
+ if (!hostapd_eid_owe_trans_enabled(hapd))
+ return 0;
+ return 6 + ETH_ALEN + 1 + hapd->conf->owe_transition_ssid_len;
+#else /* CONFIG_OWE */
+ return 0;
+#endif /* CONFIG_OWE */
+}
+
+
+u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid,
+ size_t len)
+{
+#ifdef CONFIG_OWE
+ u8 *pos = eid;
+ size_t elen;
+
+ if (hapd->conf->owe_transition_ifname[0] &&
+ !hostapd_eid_owe_trans_enabled(hapd))
+ hostapd_owe_trans_get_info(hapd);
+
+ if (!hostapd_eid_owe_trans_enabled(hapd))
+ return pos;
+
+ elen = hostapd_eid_owe_trans_len(hapd);
+ if (len < elen) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: Not enough room in the buffer for OWE IE");
+ return pos;
+ }
+
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = elen - 2;
+ WPA_PUT_BE24(pos, OUI_WFA);
+ pos += 3;
+ *pos++ = OWE_OUI_TYPE;
+ os_memcpy(pos, hapd->conf->owe_transition_bssid, ETH_ALEN);
+ pos += ETH_ALEN;
+ *pos++ = hapd->conf->owe_transition_ssid_len;
+ os_memcpy(pos, hapd->conf->owe_transition_ssid,
+ hapd->conf->owe_transition_ssid_len);
+ pos += hapd->conf->owe_transition_ssid_len;
+
+ return pos;
+#else /* CONFIG_OWE */
+ return eid;
+#endif /* CONFIG_OWE */
+}
+
+
void ap_copy_sta_supp_op_classes(struct sta_info *sta,
const u8 *supp_op_classes,
size_t supp_op_classes_len)
@@ -685,3 +932,71 @@
return pos;
}
+
+
+#ifdef CONFIG_OCV
+int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
+ int ap_seg1_idx, int *bandwidth, int *seg1_idx)
+{
+ int ht_40mhz = 0;
+ int vht_80p80 = 0;
+ int requested_bw;
+
+ if (sta->ht_capabilities)
+ ht_40mhz = !!(sta->ht_capabilities->ht_capabilities_info &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET);
+
+ if (sta->vht_operation) {
+ struct ieee80211_vht_operation *oper = sta->vht_operation;
+
+ /*
+ * If a VHT Operation element was present, use it to determine
+ * the supported channel bandwidth.
+ */
+ if (oper->vht_op_info_chwidth == 0) {
+ requested_bw = ht_40mhz ? 40 : 20;
+ } else if (oper->vht_op_info_chan_center_freq_seg1_idx == 0) {
+ requested_bw = 80;
+ } else {
+ int diff;
+
+ requested_bw = 160;
+ diff = abs((int)
+ oper->vht_op_info_chan_center_freq_seg0_idx -
+ (int)
+ oper->vht_op_info_chan_center_freq_seg1_idx);
+ vht_80p80 = oper->vht_op_info_chan_center_freq_seg1_idx
+ != 0 && diff > 16;
+ }
+ } else if (sta->vht_capabilities) {
+ struct ieee80211_vht_capabilities *capab;
+ int vht_chanwidth;
+
+ capab = sta->vht_capabilities;
+
+ /*
+ * If only the VHT Capabilities element is present (e.g., for
+ * normal clients), use it to determine the supported channel
+ * bandwidth.
+ */
+ vht_chanwidth = capab->vht_capabilities_info &
+ VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+ vht_80p80 = capab->vht_capabilities_info &
+ VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+
+ /* TODO: Also take into account Extended NSS BW Support field */
+ requested_bw = vht_chanwidth ? 160 : 80;
+ } else {
+ requested_bw = ht_40mhz ? 40 : 20;
+ }
+
+ *bandwidth = requested_bw < ap_max_chanwidth ?
+ requested_bw : ap_max_chanwidth;
+
+ *seg1_idx = 0;
+ if (ap_seg1_idx && vht_80p80)
+ *seg1_idx = ap_seg1_idx;
+
+ return 0;
+}
+#endif /* CONFIG_OCV */
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 8d06620..54ee080 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -357,6 +357,29 @@
}
+u16 copy_sta_vht_oper(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *vht_oper)
+{
+ if (!vht_oper) {
+ os_free(sta->vht_operation);
+ sta->vht_operation = NULL;
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ if (!sta->vht_operation) {
+ sta->vht_operation =
+ os_zalloc(sizeof(struct ieee80211_vht_operation));
+ if (!sta->vht_operation)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ os_memcpy(sta->vht_operation, vht_oper,
+ sizeof(struct ieee80211_vht_operation));
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ie, size_t len)
{
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 793d381..870329a 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -1,6 +1,6 @@
/*
* hostapd / IEEE 802.1X-2004 Authenticator
- * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -682,7 +682,8 @@
#ifdef CONFIG_HS20
if (hapd->conf->hs20) {
- u8 ver = 1; /* Release 2 */
+ u8 ver = hapd->conf->hs20_release - 1;
+
if (!radius_msg_add_wfa(
msg, RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION,
&ver, 1)) {
@@ -712,6 +713,41 @@
goto fail;
}
}
+
+ if (sta->roaming_consortium &&
+ !radius_msg_add_wfa(
+ msg, RADIUS_VENDOR_ATTR_WFA_HS20_ROAMING_CONSORTIUM,
+ wpabuf_head(sta->roaming_consortium),
+ wpabuf_len(sta->roaming_consortium))) {
+ wpa_printf(MSG_ERROR,
+ "Could not add HS 2.0 Roaming Consortium");
+ goto fail;
+ }
+
+ if (hapd->conf->t_c_filename) {
+ be32 timestamp;
+
+ if (!radius_msg_add_wfa(
+ msg,
+ RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILENAME,
+ (const u8 *) hapd->conf->t_c_filename,
+ os_strlen(hapd->conf->t_c_filename))) {
+ wpa_printf(MSG_ERROR,
+ "Could not add HS 2.0 T&C Filename");
+ goto fail;
+ }
+
+ timestamp = host_to_be32(hapd->conf->t_c_timestamp);
+ if (!radius_msg_add_wfa(
+ msg,
+ RADIUS_VENDOR_ATTR_WFA_HS20_TIMESTAMP,
+ (const u8 *) ×tamp,
+ sizeof(timestamp))) {
+ wpa_printf(MSG_ERROR,
+ "Could not add HS 2.0 Timestamp");
+ goto fail;
+ }
+ }
}
#endif /* CONFIG_HS20 */
@@ -1177,7 +1213,7 @@
sta->eapol_sm->portValid = TRUE;
if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap);
- /* TODO: get vlan_id from R0KH using RRB message */
+ ap_sta_bind_vlan(hapd, sta);
return;
}
#endif /* CONFIG_IEEE80211R_AP */
@@ -1587,6 +1623,33 @@
ap_sta_session_warning_timeout(hapd, sta, warning_time);
}
+
+static void ieee802_1x_hs20_t_c_filtering(struct hostapd_data *hapd,
+ struct sta_info *sta, u8 *pos,
+ size_t len)
+{
+ if (len < 4)
+ return; /* Malformed information */
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Terms and Conditions filtering %02x %02x %02x %02x",
+ pos[0], pos[1], pos[2], pos[3]);
+ hs20_t_c_filtering(hapd, sta, pos[0] & BIT(0));
+}
+
+
+static void ieee802_1x_hs20_t_c_url(struct hostapd_data *hapd,
+ struct sta_info *sta, u8 *pos, size_t len)
+{
+ os_free(sta->t_c_url);
+ sta->t_c_url = os_malloc(len + 1);
+ if (!sta->t_c_url)
+ return;
+ os_memcpy(sta->t_c_url, pos, len);
+ sta->t_c_url[len] = '\0';
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Terms and Conditions URL %s", sta->t_c_url);
+}
+
#endif /* CONFIG_HS20 */
@@ -1634,6 +1697,12 @@
ieee802_1x_hs20_session_info(hapd, sta, pos, sublen,
session_timeout);
break;
+ case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING:
+ ieee802_1x_hs20_t_c_filtering(hapd, sta, pos, sublen);
+ break;
+ case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_URL:
+ ieee802_1x_hs20_t_c_url(hapd, sta, pos, sublen);
+ break;
}
}
#endif /* CONFIG_HS20 */
@@ -1673,6 +1742,45 @@
}
+#ifndef CONFIG_NO_VLAN
+static int ieee802_1x_update_vlan(struct radius_msg *msg,
+ struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct vlan_description vlan_desc;
+
+ os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+ vlan_desc.notempty = !!radius_msg_get_vlanid(msg, &vlan_desc.untagged,
+ MAX_NUM_TAGGED_VLAN,
+ vlan_desc.tagged);
+
+ if (vlan_desc.notempty &&
+ !hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
+ sta->eapol_sm->authFail = TRUE;
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO,
+ "Invalid VLAN %d%s received from RADIUS server",
+ vlan_desc.untagged,
+ vlan_desc.tagged[0] ? "+" : "");
+ os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+ ap_sta_set_vlan(hapd, sta, &vlan_desc);
+ return -1;
+ }
+
+ if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
+ !vlan_desc.notempty) {
+ sta->eapol_sm->authFail = TRUE;
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_INFO,
+ "authentication server did not include required VLAN ID in Access-Accept");
+ return -1;
+ }
+
+ return ap_sta_set_vlan(hapd, sta, &vlan_desc);
+}
+#endif /* CONFIG_NO_VLAN */
+
+
/**
* ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server
* @msg: RADIUS response message
@@ -1691,15 +1799,10 @@
struct sta_info *sta;
u32 session_timeout = 0, termination_action, acct_interim_interval;
int session_timeout_set;
+ u32 reason_code;
struct eapol_state_machine *sm;
int override_eapReq = 0;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
- struct vlan_description vlan_desc;
-#ifndef CONFIG_NO_VLAN
- int *untagged, *tagged, *notempty;
-#endif /* CONFIG_NO_VLAN */
-
- os_memset(&vlan_desc, 0, sizeof(vlan_desc));
sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier);
if (sm == NULL) {
@@ -1764,66 +1867,34 @@
switch (hdr->code) {
case RADIUS_CODE_ACCESS_ACCEPT:
#ifndef CONFIG_NO_VLAN
- if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED) {
- notempty = &vlan_desc.notempty;
- untagged = &vlan_desc.untagged;
- tagged = vlan_desc.tagged;
- *notempty = !!radius_msg_get_vlanid(msg, untagged,
- MAX_NUM_TAGGED_VLAN,
- tagged);
- }
-
- if (vlan_desc.notempty &&
- !hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
- sta->eapol_sm->authFail = TRUE;
- hostapd_logger(hapd, sta->addr,
- HOSTAPD_MODULE_RADIUS,
- HOSTAPD_LEVEL_INFO,
- "Invalid VLAN %d%s received from RADIUS server",
- vlan_desc.untagged,
- vlan_desc.tagged[0] ? "+" : "");
- os_memset(&vlan_desc, 0, sizeof(vlan_desc));
- ap_sta_set_vlan(hapd, sta, &vlan_desc);
- break;
- }
-
- if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
- !vlan_desc.notempty) {
- sta->eapol_sm->authFail = TRUE;
- hostapd_logger(hapd, sta->addr,
- HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_INFO, "authentication "
- "server did not include required VLAN "
- "ID in Access-Accept");
- break;
- }
-#endif /* CONFIG_NO_VLAN */
-
- if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0)
+ if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED &&
+ ieee802_1x_update_vlan(msg, hapd, sta) < 0)
break;
-#ifndef CONFIG_NO_VLAN
if (sta->vlan_id > 0) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"VLAN ID %d", sta->vlan_id);
}
-#endif /* CONFIG_NO_VLAN */
if ((sta->flags & WLAN_STA_ASSOC) &&
ap_sta_bind_vlan(hapd, sta) < 0)
break;
+#endif /* CONFIG_NO_VLAN */
sta->session_timeout_set = !!session_timeout_set;
- sta->session_timeout = session_timeout;
+ os_get_reltime(&sta->session_timeout);
+ sta->session_timeout.sec += session_timeout;
/* RFC 3580, Ch. 3.17 */
if (session_timeout_set && termination_action ==
- RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) {
+ RADIUS_TERMINATION_ACTION_RADIUS_REQUEST)
sm->reAuthPeriod = session_timeout;
- } else if (session_timeout_set)
+ else if (session_timeout_set)
ap_sta_session_timeout(hapd, sta, session_timeout);
+ else
+ ap_sta_no_session_timeout(hapd, sta);
sm->eap_if->aaaSuccess = TRUE;
override_eapReq = 1;
@@ -1839,6 +1910,13 @@
case RADIUS_CODE_ACCESS_REJECT:
sm->eap_if->aaaFail = TRUE;
override_eapReq = 1;
+ if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE,
+ &reason_code) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS server indicated WLAN-Reason-Code %u in Access-Reject for "
+ MACSTR, reason_code, MAC2STR(sta->addr));
+ sta->disconnect_reason_code = reason_code;
+ }
break;
case RADIUS_CODE_ACCESS_CHALLENGE:
sm->eap_if->aaaEapReq = TRUE;
@@ -2081,6 +2159,13 @@
goto out;
user->password_len = eap_user->password_len;
user->password_hash = eap_user->password_hash;
+ if (eap_user->salt && eap_user->salt_len) {
+ user->salt = os_memdup(eap_user->salt,
+ eap_user->salt_len);
+ if (!user->salt)
+ goto out;
+ user->salt_len = eap_user->salt_len;
+ }
}
user->force_version = eap_user->force_version;
user->macacl = eap_user->macacl;
@@ -2509,6 +2594,7 @@
struct os_reltime diff;
const char *name1;
const char *name2;
+ char *identity_buf = NULL;
if (sm == NULL)
return 0;
@@ -2624,6 +2710,14 @@
/* dot1xAuthSessionStatsTable */
os_reltime_age(&sta->acct_session_start, &diff);
+ if (sm->eap && !sm->identity) {
+ const u8 *id;
+ size_t id_len;
+
+ id = eap_get_identity(sm->eap, &id_len);
+ if (id)
+ identity_buf = dup_binstr(id, id_len);
+ }
ret = os_snprintf(buf + len, buflen - len,
/* TODO: dot1xAuthSessionOctetsRx */
/* TODO: dot1xAuthSessionOctetsTx */
@@ -2639,7 +2733,9 @@
wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
1 : 2,
(unsigned int) diff.sec,
- sm->identity);
+ sm->identity ? (char *) sm->identity :
+ (identity_buf ? identity_buf : "N/A"));
+ os_free(identity_buf);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -2693,6 +2789,15 @@
hs20_send_wnm_notification_deauth_req(hapd, sta->addr,
sta->hs20_deauth_req);
}
+
+ if (sta->hs20_t_c_filtering) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to "
+ MACSTR " to indicate Terms and Conditions filtering",
+ MAC2STR(sta->addr));
+ hs20_send_wnm_notification_t_c(hapd, sta->addr, sta->t_c_url);
+ os_free(sta->t_c_url);
+ sta->t_c_url = NULL;
+ }
}
#endif /* CONFIG_HS20 */
@@ -2706,6 +2811,7 @@
/* TODO: get PMKLifetime from WPA parameters */
static const int dot11RSNAConfigPMKLifetime = 43200;
unsigned int session_timeout;
+ struct os_reltime now, remaining;
#ifdef CONFIG_HS20
if (remediation && !sta->remediation) {
@@ -2716,7 +2822,8 @@
sta->remediation_method = 1; /* SOAP-XML SPP */
}
- if (success && (sta->remediation || sta->hs20_deauth_req)) {
+ if (success && (sta->remediation || sta->hs20_deauth_req ||
+ sta->hs20_t_c_filtering)) {
wpa_printf(MSG_DEBUG, "HS 2.0: Schedule WNM-Notification to "
MACSTR " in 100 ms", MAC2STR(sta->addr));
eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta);
@@ -2726,10 +2833,13 @@
#endif /* CONFIG_HS20 */
key = ieee802_1x_get_key(sta->eapol_sm, &len);
- if (sta->session_timeout_set)
- session_timeout = sta->session_timeout;
- else
+ if (sta->session_timeout_set) {
+ os_get_reltime(&now);
+ os_reltime_sub(&sta->session_timeout, &now, &remaining);
+ session_timeout = (remaining.sec > 0) ? remaining.sec : 1;
+ } else {
session_timeout = dot11RSNAConfigPMKLifetime;
+ }
if (success && key && len >= PMK_LEN && !sta->remediation &&
!sta->hs20_deauth_requested &&
wpa_auth_pmksa_add(sta->wpa_sm, key, len, session_timeout,
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
index b8fd592..2b6f727 100644
--- a/src/ap/neighbor_db.c
+++ b/src/ap/neighbor_db.c
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "hostapd.h"
+#include "ieee802_11.h"
#include "neighbor_db.h"
@@ -123,7 +124,7 @@
}
-void hostpad_free_neighbor_db(struct hostapd_data *hapd)
+void hostapd_free_neighbor_db(struct hostapd_data *hapd)
{
struct hostapd_neighbor_entry *nr, *prev;
@@ -134,3 +135,123 @@
os_free(nr);
}
}
+
+
+#ifdef NEED_AP_MLME
+static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd,
+ int ht, int vht)
+{
+ if (!ht && !vht)
+ return NR_CHAN_WIDTH_20;
+ if (!hapd->iconf->secondary_channel)
+ return NR_CHAN_WIDTH_20;
+ if (!vht || hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_USE_HT)
+ return NR_CHAN_WIDTH_40;
+ if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
+ return NR_CHAN_WIDTH_80;
+ if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_160MHZ)
+ return NR_CHAN_WIDTH_160;
+ if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ)
+ return NR_CHAN_WIDTH_80P80;
+ return NR_CHAN_WIDTH_20;
+}
+#endif /* NEED_AP_MLME */
+
+
+void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
+{
+#ifdef NEED_AP_MLME
+ u16 capab = hostapd_own_capab_info(hapd);
+ int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
+ int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
+ struct wpa_ssid_value ssid;
+ u8 channel, op_class;
+ u8 center_freq1_idx = 0, center_freq2_idx = 0;
+ enum nr_chan_width width;
+ u32 bssid_info;
+ struct wpabuf *nr;
+
+ if (!(hapd->conf->radio_measurements[0] &
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT))
+ return;
+
+ bssid_info = 3; /* AP is reachable */
+ bssid_info |= NEI_REP_BSSID_INFO_SECURITY; /* "same as the AP" */
+ bssid_info |= NEI_REP_BSSID_INFO_KEY_SCOPE; /* "same as the AP" */
+
+ if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT)
+ bssid_info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT;
+
+ bssid_info |= NEI_REP_BSSID_INFO_RM; /* RRM is supported */
+
+ if (hapd->conf->wmm_enabled) {
+ bssid_info |= NEI_REP_BSSID_INFO_QOS;
+
+ if (hapd->conf->wmm_uapsd &&
+ (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
+ bssid_info |= NEI_REP_BSSID_INFO_APSD;
+ }
+
+ if (ht) {
+ bssid_info |= NEI_REP_BSSID_INFO_HT |
+ NEI_REP_BSSID_INFO_DELAYED_BA;
+
+ /* VHT bit added in IEEE P802.11-REVmc/D4.3 */
+ if (vht)
+ bssid_info |= NEI_REP_BSSID_INFO_VHT;
+ }
+
+ /* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
+
+ if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
+ hapd->iconf->secondary_channel,
+ hapd->iconf->vht_oper_chwidth,
+ &op_class, &channel) ==
+ NUM_HOSTAPD_MODES)
+ return;
+ width = hostapd_get_nr_chan_width(hapd, ht, vht);
+ if (vht) {
+ center_freq1_idx = hapd->iconf->vht_oper_centr_freq_seg0_idx;
+ if (width == NR_CHAN_WIDTH_80P80)
+ center_freq2_idx =
+ hapd->iconf->vht_oper_centr_freq_seg1_idx;
+ } else if (ht) {
+ ieee80211_freq_to_chan(hapd->iface->freq +
+ 10 * hapd->iconf->secondary_channel,
+ ¢er_freq1_idx);
+ }
+
+ ssid.ssid_len = hapd->conf->ssid.ssid_len;
+ os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len);
+
+ /*
+ * Neighbor Report element size = BSSID + BSSID info + op_class + chan +
+ * phy type + wide bandwidth channel subelement.
+ */
+ nr = wpabuf_alloc(ETH_ALEN + 4 + 1 + 1 + 1 + 5);
+ if (!nr)
+ return;
+
+ wpabuf_put_data(nr, hapd->own_addr, ETH_ALEN);
+ wpabuf_put_le32(nr, bssid_info);
+ wpabuf_put_u8(nr, op_class);
+ wpabuf_put_u8(nr, channel);
+ wpabuf_put_u8(nr, ieee80211_get_phy_type(hapd->iface->freq, ht, vht));
+
+ /*
+ * Wide Bandwidth Channel subelement may be needed to allow the
+ * receiving STA to send packets to the AP. See IEEE P802.11-REVmc/D5.0
+ * Figure 9-301.
+ */
+ wpabuf_put_u8(nr, WNM_NEIGHBOR_WIDE_BW_CHAN);
+ wpabuf_put_u8(nr, 3);
+ wpabuf_put_u8(nr, width);
+ wpabuf_put_u8(nr, center_freq1_idx);
+ wpabuf_put_u8(nr, center_freq2_idx);
+
+ hostapd_neighbor_set(hapd, hapd->own_addr, &ssid, nr, hapd->iconf->lci,
+ hapd->iconf->civic, hapd->iconf->stationary_ap);
+
+ wpabuf_free(nr);
+#endif /* NEED_AP_MLME */
+}
diff --git a/src/ap/neighbor_db.h b/src/ap/neighbor_db.h
index ba46d88..9c8f4f2 100644
--- a/src/ap/neighbor_db.h
+++ b/src/ap/neighbor_db.h
@@ -17,8 +17,9 @@
const struct wpa_ssid_value *ssid,
const struct wpabuf *nr, const struct wpabuf *lci,
const struct wpabuf *civic, int stationary);
+void hostapd_neighbor_set_own_report(struct hostapd_data *hapd);
int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
const struct wpa_ssid_value *ssid);
-void hostpad_free_neighbor_db(struct hostapd_data *hapd);
+void hostapd_free_neighbor_db(struct hostapd_data *hapd);
#endif /* NEIGHBOR_DB_H */
diff --git a/src/ap/rrm.c b/src/ap/rrm.c
index 56ed29c..f2d5cd1 100644
--- a/src/ap/rrm.c
+++ b/src/ap/rrm.c
@@ -558,7 +558,7 @@
void hostapd_clean_rrm(struct hostapd_data *hapd)
{
- hostpad_free_neighbor_db(hapd);
+ hostapd_free_neighbor_db(hapd);
eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL);
hapd->lci_req_active = 0;
eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index b1fde3c..71f9f21 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -13,6 +13,7 @@
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
#include "common/sae.h"
+#include "common/dpp.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "p2p/p2p.h"
@@ -166,7 +167,7 @@
/* just in case */
ap_sta_set_authorized(hapd, sta, 0);
- if (sta->flags & WLAN_STA_WDS)
+ if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP))
hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
if (sta->ipaddr)
@@ -197,7 +198,8 @@
if (sta->no_short_slot_time_set) {
sta->no_short_slot_time_set = 0;
hapd->iface->num_sta_no_short_slot_time--;
- if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
&& hapd->iface->num_sta_no_short_slot_time == 0)
set_beacon++;
}
@@ -205,7 +207,8 @@
if (sta->no_short_preamble_set) {
sta->no_short_preamble_set = 0;
hapd->iface->num_sta_no_short_preamble--;
- if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
&& hapd->iface->num_sta_no_short_preamble == 0)
set_beacon++;
}
@@ -319,16 +322,19 @@
wpabuf_free(sta->wps_ie);
wpabuf_free(sta->p2p_ie);
wpabuf_free(sta->hs20_ie);
+ wpabuf_free(sta->roaming_consortium);
#ifdef CONFIG_FST
wpabuf_free(sta->mb_ies);
#endif /* CONFIG_FST */
os_free(sta->ht_capabilities);
os_free(sta->vht_capabilities);
+ os_free(sta->vht_operation);
hostapd_free_psk_list(sta->psk);
os_free(sta->identity);
os_free(sta->radius_cui);
os_free(sta->remediation_url);
+ os_free(sta->t_c_url);
wpabuf_free(sta->hs20_deauth_req);
os_free(sta->hs20_session_info_url);
@@ -357,6 +363,19 @@
crypto_ecdh_deinit(sta->owe_ecdh);
#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP2
+ dpp_pfs_free(sta->dpp_pfs);
+ sta->dpp_pfs = NULL;
+#endif /* CONFIG_DPP2 */
+
+ os_free(sta->ext_capability);
+
+#ifdef CONFIG_WNM_AP
+ eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta);
+#endif /* CONFIG_WNM_AP */
+
+ os_free(sta->ifname_wds);
+
os_free(sta);
}
@@ -488,6 +507,13 @@
} else if (sta->timeout_next != STA_REMOVE) {
int deauth = sta->timeout_next == STA_DEAUTH;
+ if (!deauth && !(sta->flags & WLAN_STA_ASSOC)) {
+ /* Cannot disassociate not-associated STA, so move
+ * directly to deauthentication. */
+ sta->timeout_next = STA_DEAUTH;
+ deauth = 1;
+ }
+
wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
"Timeout, sending %s info to STA " MACSTR,
deauth ? "deauthentication" : "disassociation",
@@ -884,9 +910,6 @@
struct hostapd_vlan *vlan = NULL, *wildcard_vlan = NULL;
int old_vlan_id, vlan_id = 0, ret = 0;
- if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
- vlan_desc = NULL;
-
/* Check if there is something to do */
if (hapd->conf->ssid.per_sta_vif && !sta->vlan_id) {
/* This sta is lacking its own vif */
@@ -1153,6 +1176,32 @@
#endif /* CONFIG_IEEE80211W */
+const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct hostapd_wpa_psk *psk;
+ struct hostapd_ssid *ssid;
+ const u8 *pmk;
+ int pmk_len;
+
+ ssid = &hapd->conf->ssid;
+
+ pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
+ if (!pmk || pmk_len != PMK_LEN)
+ return NULL;
+
+ for (psk = ssid->wpa_psk; psk; psk = psk->next)
+ if (os_memcmp(pmk, psk->psk, PMK_LEN) == 0)
+ break;
+ if (!psk)
+ return NULL;
+ if (!psk || !psk->keyid[0])
+ return NULL;
+
+ return psk->keyid;
+}
+
+
void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
int authorized)
{
@@ -1191,7 +1240,11 @@
sta->addr, authorized, dev_addr);
if (authorized) {
+ const char *keyid;
+ char keyid_buf[100];
char ip_addr[100];
+
+ keyid_buf[0] = '\0';
ip_addr[0] = '\0';
#ifdef CONFIG_P2P
if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) {
@@ -1202,14 +1255,20 @@
}
#endif /* CONFIG_P2P */
- wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s",
- buf, ip_addr);
+ keyid = ap_sta_wpa_get_keyid(hapd, sta);
+ if (keyid) {
+ os_snprintf(keyid_buf, sizeof(keyid_buf),
+ " keyid=%s", keyid);
+ }
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s",
+ buf, ip_addr, keyid_buf);
if (hapd->msg_ctx_parent &&
hapd->msg_ctx_parent != hapd->msg_ctx)
wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
- AP_STA_CONNECTED "%s%s",
- buf, ip_addr);
+ AP_STA_CONNECTED "%s%s%s",
+ buf, ip_addr, keyid_buf);
} else {
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);
@@ -1342,7 +1401,7 @@
int res;
buf[0] = '\0';
- res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
(flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
(flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
(flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
@@ -1359,6 +1418,7 @@
(flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
(flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
(flags & WLAN_STA_GAS ? "[GAS]" : ""),
+ (flags & WLAN_STA_HT ? "[HT]" : ""),
(flags & WLAN_STA_VHT ? "[VHT]" : ""),
(flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
(flags & WLAN_STA_WNM_SLEEP_MODE ?
@@ -1374,13 +1434,16 @@
{
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
+ u16 reason;
wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
"IEEE 802.1X: Scheduled disconnection of " MACSTR
" after EAP-Failure", MAC2STR(sta->addr));
- ap_sta_disconnect(hapd, sta, sta->addr,
- WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
+ reason = sta->disconnect_reason_code;
+ if (!reason)
+ reason = WLAN_REASON_IEEE_802_1X_AUTH_FAILED;
+ ap_sta_disconnect(hapd, sta, sta->addr, reason);
if (sta->flags & WLAN_STA_WPS)
hostapd_wps_eap_completed(hapd);
}
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 3fb60f6..ece0c60 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -9,11 +9,7 @@
#ifndef STA_INFO_H
#define STA_INFO_H
-#ifdef CONFIG_MESH
-/* needed for mesh_plink_state enum */
#include "common/defs.h"
-#endif /* CONFIG_MESH */
-
#include "list.h"
#include "vlan.h"
#include "common/wpa_common.h"
@@ -40,6 +36,7 @@
#define WLAN_STA_VHT_OPMODE_ENABLED BIT(20)
#define WLAN_STA_VENDOR_VHT BIT(21)
#define WLAN_STA_PENDING_FILS_ERP BIT(22)
+#define WLAN_STA_MULTI_AP BIT(23)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -71,6 +68,7 @@
be32 ipaddr;
struct dl_list ip6addr; /* list head for struct ip6addr */
u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
+ u16 disconnect_reason_code; /* RADIUS server override */
u32 flags; /* Bitfield of WLAN_STA_* */
u16 capability;
u16 listen_interval; /* or beacon_int for APs */
@@ -117,6 +115,10 @@
unsigned int ecsa_supported:1;
unsigned int added_unassoc:1;
unsigned int pending_wds_enable:1;
+ unsigned int power_capab:1;
+ unsigned int agreed_to_steer:1;
+ unsigned int hs20_t_c_filtering:1;
+ unsigned int ft_over_ds:1;
u16 auth_alg;
@@ -162,6 +164,7 @@
struct ieee80211_ht_capabilities *ht_capabilities;
struct ieee80211_vht_capabilities *vht_capabilities;
+ struct ieee80211_vht_operation *vht_operation;
u8 vht_opmode;
#ifdef CONFIG_IEEE80211W
@@ -183,8 +186,11 @@
struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */
struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */
+ /* Hotspot 2.0 Roaming Consortium from (Re)Association Request */
+ struct wpabuf *roaming_consortium;
u8 remediation_method;
char *remediation_url; /* HS 2.0 Subscription Remediation Server URL */
+ char *t_c_url; /* HS 2.0 Terms and Conditions Server URL */
struct wpabuf *hs20_deauth_req;
char *hs20_session_info_url;
int hs20_disassoc_timer;
@@ -199,7 +205,8 @@
unsigned int mesh_sae_pmksa_caching:1;
#endif /* CONFIG_SAE */
- u32 session_timeout; /* valid only if session_timeout_set == 1 */
+ /* valid only if session_timeout_set == 1 */
+ struct os_reltime session_timeout;
/* Last Authentication/(Re)Association Request/Action frame sequence
* control */
@@ -211,6 +218,7 @@
u8 cell_capa; /* 0 = unknown (not an MBO STA); otherwise,
* enum mbo_cellular_capa values */
struct mbo_non_pref_chan_info *non_pref_chan;
+ int auth_rssi; /* Last Authentication frame RSSI */
#endif /* CONFIG_MBO */
u8 *supp_op_classes; /* Supported Operating Classes element, if
@@ -218,6 +226,9 @@
u8 rrm_enabled_capa[5];
+ s8 min_tx_power;
+ s8 max_tx_power;
+
#ifdef CONFIG_TAXONOMY
struct wpabuf *probe_ie_taxonomy;
struct wpabuf *assoc_ie_taxonomy;
@@ -251,6 +262,13 @@
u16 owe_group;
#endif /* CONFIG_OWE */
+ u8 *ext_capability;
+ char *ifname_wds; /* WDS ifname, if in use */
+
+#ifdef CONFIG_DPP2
+ struct dpp_pfs *dpp_pfs;
+#endif /* CONFIG_DPP2 */
+
#ifdef CONFIG_TESTING_OPTIONS
enum wpa_alg last_tk_alg;
int last_tk_key_idx;
@@ -310,6 +328,8 @@
void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
+const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
+ struct sta_info *sta);
void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *addr, u16 reason);
diff --git a/src/ap/tkip_countermeasures.c b/src/ap/tkip_countermeasures.c
index 4725e2b..557570c 100644
--- a/src/ap/tkip_countermeasures.c
+++ b/src/ap/tkip_countermeasures.c
@@ -71,6 +71,11 @@
struct os_reltime now;
int ret = 0;
+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Michael MIC failure detected in received frame%s",
+ local ? " (local)" : "");
+
if (addr && local) {
struct sta_info *sta = ap_get_sta(hapd, addr);
if (sta != NULL) {
diff --git a/src/ap/vlan_full.c b/src/ap/vlan_full.c
index aa42335..19aa3c6 100644
--- a/src/ap/vlan_full.c
+++ b/src/ap/vlan_full.c
@@ -16,6 +16,7 @@
#include "utils/common.h"
#include "drivers/priv_netlink.h"
+#include "drivers/linux_ioctl.h"
#include "common/linux_bridge.h"
#include "common/linux_vlan.h"
#include "utils/eloop.h"
@@ -143,6 +144,9 @@
return -1;
}
+ if (linux_br_del_if(fd, br_name, if_name) == 0)
+ goto done;
+
if_index = if_nametoindex(if_name);
if (if_index == 0) {
@@ -168,6 +172,7 @@
return -1;
}
+done:
close(fd);
return 0;
}
@@ -194,6 +199,14 @@
return -1;
}
+ if (linux_br_add_if(fd, br_name, if_name) == 0)
+ goto done;
+ if (errno == EBUSY) {
+ /* The interface is already added. */
+ close(fd);
+ return 1;
+ }
+
if_index = if_nametoindex(if_name);
if (if_index == 0) {
@@ -224,6 +237,7 @@
return -1;
}
+done:
close(fd);
return 0;
}
@@ -241,6 +255,9 @@
return -1;
}
+ if (linux_br_del(fd, br_name) == 0)
+ goto done;
+
arg[0] = BRCTL_DEL_BRIDGE;
arg[1] = (unsigned long) br_name;
@@ -252,6 +269,7 @@
return -1;
}
+done:
close(fd);
return 0;
}
@@ -277,11 +295,19 @@
return -1;
}
+ if (linux_br_add(fd, br_name) == 0)
+ goto done;
+ if (errno == EEXIST) {
+ /* The bridge is already added. */
+ close(fd);
+ return 1;
+ }
+
arg[0] = BRCTL_ADD_BRIDGE;
arg[1] = (unsigned long) br_name;
if (ioctl(fd, SIOCGIFBR, arg) < 0) {
- if (errno == EEXIST) {
+ if (errno == EEXIST) {
/* The bridge is already added. */
close(fd);
return 1;
@@ -294,6 +320,7 @@
}
}
+done:
/* Decrease forwarding delay to avoid EAPOL timeouts. */
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
@@ -363,12 +390,18 @@
{
char vlan_ifname[IFNAMSIZ];
int clean;
+ int ret;
if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
- os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
- tagged_interface, vid);
+ ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
+ tagged_interface, vid);
else
- os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d", vid);
+ ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d",
+ vid);
+ if (ret >= (int) sizeof(vlan_ifname))
+ wpa_printf(MSG_WARNING,
+ "VLAN: Interface name was truncated to %s",
+ vlan_ifname);
clean = 0;
ifconfig_up(tagged_interface);
@@ -384,19 +417,28 @@
}
-static void vlan_bridge_name(char *br_name, struct hostapd_data *hapd, int vid)
+static void vlan_bridge_name(char *br_name, struct hostapd_data *hapd,
+ struct hostapd_vlan *vlan, int vid)
{
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+ int ret;
- if (hapd->conf->vlan_bridge[0]) {
- os_snprintf(br_name, IFNAMSIZ, "%s%d",
- hapd->conf->vlan_bridge, vid);
+ if (vlan->bridge[0]) {
+ os_strlcpy(br_name, vlan->bridge, IFNAMSIZ);
+ ret = 0;
+ } else if (hapd->conf->vlan_bridge[0]) {
+ ret = os_snprintf(br_name, IFNAMSIZ, "%s%d",
+ hapd->conf->vlan_bridge, vid);
} else if (tagged_interface) {
- os_snprintf(br_name, IFNAMSIZ, "br%s.%d",
- tagged_interface, vid);
+ ret = os_snprintf(br_name, IFNAMSIZ, "br%s.%d",
+ tagged_interface, vid);
} else {
- os_snprintf(br_name, IFNAMSIZ, "brvlan%d", vid);
+ ret = os_snprintf(br_name, IFNAMSIZ, "brvlan%d", vid);
}
+ if (ret >= IFNAMSIZ)
+ wpa_printf(MSG_WARNING,
+ "VLAN: Interface name was truncated to %s",
+ br_name);
}
@@ -445,7 +487,7 @@
!br_addif(hapd->conf->bridge, ifname))
vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
} else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
- vlan_bridge_name(br_name, hapd, untagged);
+ vlan_bridge_name(br_name, hapd, vlan, untagged);
vlan_get_bridge(br_name, hapd, untagged);
@@ -458,7 +500,7 @@
tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
(i > 0 && tagged[i] == tagged[i - 1]))
continue;
- vlan_bridge_name(br_name, hapd, tagged[i]);
+ vlan_bridge_name(br_name, hapd, vlan, tagged[i]);
vlan_get_bridge(br_name, hapd, tagged[i]);
vlan_newlink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
ifname, br_name, tagged[i], hapd);
@@ -474,12 +516,19 @@
{
char vlan_ifname[IFNAMSIZ];
int clean;
+ int ret;
if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
- os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
- tagged_interface, vid);
+ ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
+ tagged_interface, vid);
else
- os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d", vid);
+ ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d",
+ vid);
+ if (ret >= (int) sizeof(vlan_ifname))
+ wpa_printf(MSG_WARNING,
+ "VLAN: Interface name was truncated to %s",
+ vlan_ifname);
+
clean = dyn_iface_put(hapd, vlan_ifname);
@@ -543,7 +592,7 @@
tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
(i > 0 && tagged[i] == tagged[i - 1]))
continue;
- vlan_bridge_name(br_name, hapd, tagged[i]);
+ vlan_bridge_name(br_name, hapd, vlan, tagged[i]);
vlan_dellink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
ifname, br_name, tagged[i], hapd);
vlan_put_bridge(br_name, hapd, tagged[i]);
@@ -555,7 +604,7 @@
(vlan->clean & DVLAN_CLEAN_WLAN_PORT))
br_delif(hapd->conf->bridge, ifname);
} else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
- vlan_bridge_name(br_name, hapd, untagged);
+ vlan_bridge_name(br_name, hapd, vlan, untagged);
if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
br_delif(br_name, vlan->ifname);
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index 31e4fc6..e293a00 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -138,6 +138,8 @@
!hapd->conf->vlan) {
/* dynamic vlans enabled but no (or empty) vlan_file given */
struct hostapd_vlan *vlan;
+ int ret;
+
vlan = os_zalloc(sizeof(*vlan));
if (vlan == NULL) {
wpa_printf(MSG_ERROR, "Out of memory while assigning "
@@ -146,8 +148,16 @@
}
vlan->vlan_id = VLAN_ID_WILDCARD;
- os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
- hapd->conf->iface);
+ ret = os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
+ hapd->conf->iface);
+ if (ret >= (int) sizeof(vlan->ifname)) {
+ wpa_printf(MSG_WARNING,
+ "VLAN: Interface name was truncated to %s",
+ vlan->ifname);
+ } else if (ret < 0) {
+ os_free(vlan);
+ return ret;
+ }
vlan->next = hapd->conf->vlan;
hapd->conf->vlan = vlan;
}
@@ -177,6 +187,7 @@
{
struct hostapd_vlan *n;
char ifname[IFNAMSIZ + 1], *pos;
+ int ret;
if (vlan == NULL || vlan->vlan_id != VLAN_ID_WILDCARD)
return NULL;
@@ -198,8 +209,13 @@
n->vlan_desc = *vlan_desc;
n->dynamic_vlan = 1;
- os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
- pos);
+ ret = os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s",
+ ifname, vlan_id, pos);
+ if (os_snprintf_error(sizeof(n->ifname), ret)) {
+ os_free(n);
+ return NULL;
+ }
+ os_strlcpy(n->bridge, vlan->bridge, sizeof(n->bridge));
n->next = hapd->conf->vlan;
hapd->conf->vlan = n;
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index adb66c1..27c69d3 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -12,6 +12,7 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
+#include "common/ocv.h"
#include "ap/hostapd.h"
#include "ap/sta_info.h"
#include "ap/ap_config.h"
@@ -54,8 +55,8 @@
size_t gtk_elem_len = 0;
size_t igtk_elem_len = 0;
struct wnm_sleep_element wnmsleep_ie;
- u8 *wnmtfs_ie;
- u8 wnmsleep_ie_len;
+ u8 *wnmtfs_ie, *oci_ie;
+ u8 wnmsleep_ie_len, oci_ie_len;
u16 wnmtfs_ie_len;
u8 *pos;
struct sta_info *sta;
@@ -88,10 +89,42 @@
wnmtfs_ie = NULL;
}
+ oci_ie = NULL;
+ oci_ie_len = 0;
+#ifdef CONFIG_OCV
+ if (action_type == WNM_SLEEP_MODE_EXIT &&
+ wpa_auth_uses_ocv(sta->wpa_sm)) {
+ struct wpa_channel_info ci;
+
+ if (hostapd_drv_channel_info(hapd, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in WNM-Sleep Mode frame");
+ os_free(wnmtfs_ie);
+ return -1;
+ }
+
+ oci_ie_len = OCV_OCI_EXTENDED_LEN;
+ oci_ie = os_zalloc(oci_ie_len);
+ if (!oci_ie) {
+ wpa_printf(MSG_WARNING,
+ "Failed to allocate buffer for OCI element in WNM-Sleep Mode frame");
+ os_free(wnmtfs_ie);
+ return -1;
+ }
+
+ if (ocv_insert_extended_oci(&ci, oci_ie) < 0) {
+ os_free(wnmtfs_ie);
+ os_free(oci_ie);
+ return -1;
+ }
+ }
+#endif /* CONFIG_OCV */
+
#define MAX_GTK_SUBELEM_LEN 45
#define MAX_IGTK_SUBELEM_LEN 26
mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len +
- MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN);
+ MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN +
+ oci_ie_len);
if (mgmt == NULL) {
wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
"WNM-Sleep Response action frame");
@@ -109,6 +142,7 @@
pos = (u8 *)mgmt->u.action.u.wnm_sleep_resp.variable;
/* add key data if MFP is enabled */
if (!wpa_auth_uses_mfp(sta->wpa_sm) ||
+ hapd->conf->wnm_sleep_mode_no_keys ||
action_type != WNM_SLEEP_MODE_EXIT) {
mgmt->u.action.u.wnm_sleep_resp.keydata_len = 0;
} else {
@@ -133,11 +167,18 @@
os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
/* copy TFS IE here */
pos += wnmsleep_ie_len;
- if (wnmtfs_ie)
+ if (wnmtfs_ie) {
os_memcpy(pos, wnmtfs_ie, wnmtfs_ie_len);
+ pos += wnmtfs_ie_len;
+ }
+#ifdef CONFIG_OCV
+ /* copy OCV OCI here */
+ if (oci_ie_len > 0)
+ os_memcpy(pos, oci_ie, oci_ie_len);
+#endif /* CONFIG_OCV */
len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len +
- igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len;
+ igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len;
/* In driver, response frame should be forced to sent when STA is in
* PS mode */
@@ -173,7 +214,8 @@
wpa_set_wnmsleep(sta->wpa_sm, 0);
hostapd_drv_wnm_oper(hapd, WNM_SLEEP_EXIT_CONFIRM,
addr, NULL, NULL);
- if (!wpa_auth_uses_mfp(sta->wpa_sm))
+ if (!wpa_auth_uses_mfp(sta->wpa_sm) ||
+ hapd->conf->wnm_sleep_mode_no_keys)
wpa_wnmsleep_rekey_gtk(sta->wpa_sm);
}
} else
@@ -183,6 +225,7 @@
#undef MAX_IGTK_SUBELEM_LEN
fail:
os_free(wnmtfs_ie);
+ os_free(oci_ie);
os_free(mgmt);
return res;
}
@@ -199,6 +242,18 @@
u8 *tfsreq_ie_start = NULL;
u8 *tfsreq_ie_end = NULL;
u16 tfsreq_ie_len = 0;
+#ifdef CONFIG_OCV
+ struct sta_info *sta;
+ const u8 *oci_ie = NULL;
+ u8 oci_ie_len = 0;
+#endif /* CONFIG_OCV */
+
+ if (!hapd->conf->wnm_sleep_mode) {
+ wpa_printf(MSG_DEBUG, "Ignore WNM-Sleep Mode Request from "
+ MACSTR " since WNM-Sleep Mode is disabled",
+ MAC2STR(addr));
+ return;
+ }
if (len < 1) {
wpa_printf(MSG_DEBUG,
@@ -219,6 +274,12 @@
if (!tfsreq_ie_start)
tfsreq_ie_start = (u8 *) pos;
tfsreq_ie_end = (u8 *) pos;
+#ifdef CONFIG_OCV
+ } else if (*pos == WLAN_EID_EXTENSION && ie_len >= 1 &&
+ pos[2] == WLAN_EID_EXT_OCV_OCI) {
+ oci_ie = pos + 3;
+ oci_ie_len = ie_len - 1;
+#endif /* CONFIG_OCV */
} else
wpa_printf(MSG_DEBUG, "WNM: EID %d not recognized",
*pos);
@@ -230,6 +291,27 @@
return;
}
+#ifdef CONFIG_OCV
+ sta = ap_get_sta(hapd, addr);
+ if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT &&
+ sta && wpa_auth_uses_ocv(sta->wpa_sm)) {
+ struct wpa_channel_info ci;
+
+ if (hostapd_drv_channel_info(hapd, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info to validate received OCI in WNM-Sleep Mode frame");
+ return;
+ }
+
+ 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);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER &&
tfsreq_ie_start && tfsreq_ie_end &&
tfsreq_ie_end - tfsreq_ie_start >= 0) {
@@ -302,6 +384,20 @@
{
u8 dialog_token, reason;
const u8 *pos, *end;
+ int enabled = hapd->conf->bss_transition;
+
+#ifdef CONFIG_MBO
+ if (hapd->conf->mbo_enabled)
+ enabled = 1;
+#endif /* CONFIG_MBO */
+ if (!enabled) {
+ wpa_printf(MSG_DEBUG,
+ "Ignore BSS Transition Management Query from "
+ MACSTR
+ " since BSS Transition Management is disabled",
+ MAC2STR(addr));
+ return;
+ }
if (len < 2) {
wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Query from "
@@ -325,12 +421,40 @@
}
+void ap_sta_reset_steer_flag_timer(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct sta_info *sta = timeout_ctx;
+
+ if (sta->agreed_to_steer) {
+ wpa_printf(MSG_DEBUG, "%s: Reset steering flag for STA " MACSTR,
+ hapd->conf->iface, MAC2STR(sta->addr));
+ sta->agreed_to_steer = 0;
+ }
+}
+
+
static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
const u8 *addr, const u8 *frm,
size_t len)
{
u8 dialog_token, status_code, bss_termination_delay;
const u8 *pos, *end;
+ int enabled = hapd->conf->bss_transition;
+ struct sta_info *sta;
+
+#ifdef CONFIG_MBO
+ if (hapd->conf->mbo_enabled)
+ enabled = 1;
+#endif /* CONFIG_MBO */
+ if (!enabled) {
+ wpa_printf(MSG_DEBUG,
+ "Ignore BSS Transition Management Response from "
+ MACSTR
+ " since BSS Transition Management is disabled",
+ MAC2STR(addr));
+ return;
+ }
if (len < 3) {
wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Response from "
@@ -349,11 +473,23 @@
"bss_termination_delay=%u", MAC2STR(addr), dialog_token,
status_code, bss_termination_delay);
+ sta = ap_get_sta(hapd, addr);
+ if (!sta) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for received BSS TM Response",
+ MAC2STR(addr));
+ return;
+ }
+
if (status_code == WNM_BSS_TM_ACCEPT) {
if (end - pos < ETH_ALEN) {
wpa_printf(MSG_DEBUG, "WNM: not enough room for Target BSSID field");
return;
}
+ sta->agreed_to_steer = 1;
+ eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta);
+ eloop_register_timeout(2, 0, ap_sta_reset_steer_flag_timer,
+ hapd, sta);
wpa_printf(MSG_DEBUG, "WNM: Target BSSID: " MACSTR,
MAC2STR(pos));
wpa_msg(hapd->msg_ctx, MSG_INFO, BSS_TM_RESP MACSTR
@@ -363,6 +499,7 @@
MAC2STR(pos));
pos += ETH_ALEN;
} else {
+ sta->agreed_to_steer = 0;
wpa_msg(hapd->msg_ctx, MSG_INFO, BSS_TM_RESP MACSTR
" status_code=%u bss_termination_delay=%u",
MAC2STR(addr), status_code, bss_termination_delay);
@@ -396,6 +533,48 @@
}
+static void ieee802_11_rx_wnm_coloc_intf_report(struct hostapd_data *hapd,
+ const u8 *addr, const u8 *buf,
+ size_t len)
+{
+ u8 dialog_token;
+ char *hex;
+ size_t hex_len;
+
+ if (!hapd->conf->coloc_intf_reporting) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Ignore unexpected Collocated Interference Report from "
+ MACSTR, MAC2STR(addr));
+ return;
+ }
+
+ if (len < 1) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Ignore too short Collocated Interference Report from "
+ MACSTR, MAC2STR(addr));
+ return;
+ }
+ dialog_token = *buf++;
+ len--;
+
+ wpa_printf(MSG_DEBUG,
+ "WNM: Received Collocated Interference Report frame from "
+ MACSTR " (dialog_token=%u)",
+ MAC2STR(addr), dialog_token);
+ wpa_hexdump(MSG_MSGDUMP, "WNM: Collocated Interference Report Elements",
+ buf, len);
+
+ hex_len = 2 * len + 1;
+ hex = os_malloc(hex_len);
+ if (!hex)
+ return;
+ wpa_snprintf_hex(hex, hex_len, buf, len);
+ wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, COLOC_INTF_REPORT MACSTR " %d %s",
+ MAC2STR(addr), dialog_token, hex);
+ os_free(hex);
+}
+
+
int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len)
{
@@ -426,6 +605,10 @@
ieee802_11_rx_wnm_notification_req(hapd, mgmt->sa, payload,
plen);
return 0;
+ case WNM_COLLOCATED_INTERFERENCE_REPORT:
+ ieee802_11_rx_wnm_coloc_intf_report(hapd, mgmt->sa, payload,
+ plen);
+ return 0;
}
wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR,
@@ -624,3 +807,40 @@
return 0;
}
+
+
+int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta,
+ unsigned int auto_report, unsigned int timeout)
+{
+ u8 buf[100], *pos;
+ struct ieee80211_mgmt *mgmt;
+ u8 dialog_token = 1;
+
+ if (auto_report > 3 || timeout > 63)
+ return -1;
+ os_memset(buf, 0, sizeof(buf));
+ mgmt = (struct ieee80211_mgmt *) buf;
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
+ os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+ mgmt->u.action.category = WLAN_ACTION_WNM;
+ mgmt->u.action.u.coloc_intf_req.action =
+ WNM_COLLOCATED_INTERFERENCE_REQ;
+ mgmt->u.action.u.coloc_intf_req.dialog_token = dialog_token;
+ mgmt->u.action.u.coloc_intf_req.req_info = auto_report | (timeout << 2);
+ pos = &mgmt->u.action.u.coloc_intf_req.req_info;
+ pos++;
+
+ wpa_printf(MSG_DEBUG, "WNM: Sending Collocated Interference Request to "
+ MACSTR " (dialog_token=%u auto_report=%u timeout=%u)",
+ MAC2STR(sta->addr), dialog_token, auto_report, timeout);
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Failed to send Collocated Interference Request frame");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/ap/wnm_ap.h b/src/ap/wnm_ap.h
index a44eadb..1806ba0 100644
--- a/src/ap/wnm_ap.h
+++ b/src/ap/wnm_ap.h
@@ -23,5 +23,8 @@
const u8 *bss_term_dur, const char *url,
const u8 *nei_rep, size_t nei_rep_len,
const u8 *mbo_attrs, size_t mbo_len);
+void ap_sta_reset_steer_flag_timer(void *eloop_ctx, void *timeout_ctx);
+int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta,
+ unsigned int auto_report, unsigned int timeout);
#endif /* WNM_AP_H */
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 8265fa1..e89a716 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 RSN / WPA Authenticator
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -13,14 +13,17 @@
#include "utils/state_machine.h"
#include "utils/bitfield.h"
#include "common/ieee802_11_defs.h"
+#include "common/ocv.h"
#include "crypto/aes.h"
#include "crypto/aes_wrap.h"
#include "crypto/aes_siv.h"
#include "crypto/crypto.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
+#include "crypto/sha384.h"
#include "crypto/random.h"
#include "eapol_auth/eapol_auth_sm.h"
+#include "drivers/driver.h"
#include "ap_config.h"
#include "ieee802_11.h"
#include "wpa_auth.h"
@@ -111,12 +114,13 @@
static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
const u8 *addr,
const u8 *p2p_dev_addr,
- const u8 *prev_psk, size_t *psk_len)
+ const u8 *prev_psk, size_t *psk_len,
+ int *vlan_id)
{
if (wpa_auth->cb->get_psk == NULL)
return NULL;
return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
- prev_psk, psk_len);
+ prev_psk, psk_len, vlan_id);
}
@@ -237,20 +241,23 @@
}
-static int wpa_use_aes_cmac(struct wpa_state_machine *sm)
+#ifdef CONFIG_OCV
+static int wpa_channel_info(struct wpa_authenticator *wpa_auth,
+ struct wpa_channel_info *ci)
{
- int ret = 0;
-#ifdef CONFIG_IEEE80211R_AP
- if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
- ret = 1;
-#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
- if (wpa_key_mgmt_sha256(sm->wpa_key_mgmt))
- ret = 1;
-#endif /* CONFIG_IEEE80211W */
- if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN)
- ret = 1;
- return ret;
+ if (!wpa_auth->cb->channel_info)
+ return -1;
+ return wpa_auth->cb->channel_info(wpa_auth->cb_ctx, ci);
+}
+#endif /* CONFIG_OCV */
+
+
+static int wpa_auth_update_vlan(struct wpa_authenticator *wpa_auth,
+ const u8 *addr, int vlan_id)
+{
+ if (!wpa_auth->cb->update_vlan)
+ return -1;
+ return wpa_auth->cb->update_vlan(wpa_auth->cb_ctx, addr, vlan_id);
}
@@ -348,6 +355,10 @@
wpa_get_ntp_timestamp(buf + ETH_ALEN);
ptr = (unsigned long) group;
os_memcpy(buf + ETH_ALEN + 8, &ptr, sizeof(ptr));
+#ifdef TEST_FUZZ
+ os_memset(buf + ETH_ALEN, 0xab, 8);
+ os_memset(buf + ETH_ALEN + 8, 0xcd, sizeof(ptr));
+#endif /* TEST_FUZZ */
if (random_get_bytes(rkey, sizeof(rkey)) < 0)
return -1;
@@ -685,7 +696,10 @@
os_free(sm->last_rx_eapol_key);
os_free(sm->wpa_ie);
wpa_group_put(sm->wpa_auth, sm->group);
- os_free(sm);
+#ifdef CONFIG_DPP2
+ wpabuf_clear_free(sm->dpp_z);
+#endif /* CONFIG_DPP2 */
+ bin_clear_free(sm, sizeof(*sm));
}
@@ -698,9 +712,10 @@
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"strict rekeying - force GTK rekey since STA "
"is leaving");
- eloop_cancel_timeout(wpa_rekey_gtk, sm->wpa_auth, NULL);
- eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->wpa_auth,
- NULL);
+ if (eloop_deplete_timeout(0, 500000, wpa_rekey_gtk,
+ sm->wpa_auth, NULL) == -1)
+ eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->wpa_auth,
+ NULL);
}
eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
@@ -850,15 +865,23 @@
int ok = 0;
const u8 *pmk = NULL;
size_t pmk_len;
+ int vlan_id = 0;
os_memset(&PTK, 0, sizeof(PTK));
for (;;) {
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
!wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
- sm->p2p_dev_addr, pmk, &pmk_len);
+ sm->p2p_dev_addr, pmk, &pmk_len,
+ &vlan_id);
if (pmk == NULL)
break;
+#ifdef CONFIG_IEEE80211R_AP
+ if (wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
+ os_memcpy(sm->xxkey, pmk, pmk_len);
+ sm->xxkey_len = pmk_len;
+ }
+#endif /* CONFIG_IEEE80211R_AP */
} else {
pmk = sm->PMK;
pmk_len = sm->pmk_len;
@@ -869,11 +892,16 @@
if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
data, data_len) == 0) {
+ if (sm->PMK != pmk) {
+ os_memcpy(sm->PMK, pmk, pmk_len);
+ sm->pmk_len = pmk_len;
+ }
ok = 1;
break;
}
- if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt))
+ if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
+ wpa_key_mgmt_sae(sm->wpa_key_mgmt))
break;
}
@@ -886,6 +914,11 @@
wpa_printf(MSG_DEBUG,
"WPA: Earlier SNonce resulted in matching MIC");
sm->alt_snonce_valid = 0;
+
+ if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
+ wpa_auth_update_vlan(sm->wpa_auth, sm->addr, vlan_id) < 0)
+ return -1;
+
os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN);
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
sm->PTK_valid = TRUE;
@@ -1001,10 +1034,8 @@
u16 ver = key_info & WPA_KEY_INFO_TYPE_MASK;
if (sm->pairwise == WPA_CIPHER_CCMP ||
sm->pairwise == WPA_CIPHER_GCMP) {
- if (wpa_use_aes_cmac(sm) &&
- sm->wpa_key_mgmt != WPA_KEY_MGMT_OSEN &&
- !wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) &&
- !wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
+ if (wpa_use_cmac(sm->wpa_key_mgmt) &&
+ !wpa_use_akm_defined(sm->wpa_key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
@@ -1014,11 +1045,8 @@
return;
}
- if (!wpa_use_aes_cmac(sm) &&
- !wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) &&
- !wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
- sm->wpa_key_mgmt != WPA_KEY_MGMT_OWE &&
- sm->wpa_key_mgmt != WPA_KEY_MGMT_DPP &&
+ if (!wpa_use_cmac(sm->wpa_key_mgmt) &&
+ !wpa_use_akm_defined(sm->wpa_key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
@@ -1028,10 +1056,7 @@
}
}
- if ((wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
- wpa_key_mgmt_fils(sm->wpa_key_mgmt) ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE) &&
+ if (wpa_use_akm_defined(sm->wpa_key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
"did not use EAPOL-Key descriptor version 0 as required for AKM-defined cases");
@@ -1218,6 +1243,11 @@
wpa_try_alt_snonce(sm, data, data_len))) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"received EAPOL-Key with invalid MIC");
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore Key MIC failure for fuzz testing");
+ goto continue_fuzz;
+#endif /* TEST_FUZZ */
return;
}
#ifdef CONFIG_FILS
@@ -1226,9 +1256,17 @@
&key_data_length) < 0) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"received EAPOL-Key with invalid MIC");
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore Key MIC failure for fuzz testing");
+ goto continue_fuzz;
+#endif /* TEST_FUZZ */
return;
}
#endif /* CONFIG_FILS */
+#ifdef TEST_FUZZ
+ continue_fuzz:
+#endif /* TEST_FUZZ */
sm->MICVerified = TRUE;
eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
sm->pending_1_of_4_timeout = 0;
@@ -1317,7 +1355,7 @@
static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr,
const u8 *gnonce, u8 *gtk, size_t gtk_len)
{
- u8 data[ETH_ALEN + WPA_NONCE_LEN + 8 + 16];
+ u8 data[ETH_ALEN + WPA_NONCE_LEN + 8 + WPA_GTK_MAX_LEN];
u8 *pos;
int ret = 0;
@@ -1328,21 +1366,33 @@
* is done only at the Authenticator and as such, does not need to be
* exactly same.
*/
+ os_memset(data, 0, sizeof(data));
os_memcpy(data, addr, ETH_ALEN);
os_memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN);
pos = data + ETH_ALEN + WPA_NONCE_LEN;
wpa_get_ntp_timestamp(pos);
+#ifdef TEST_FUZZ
+ os_memset(pos, 0xef, 8);
+#endif /* TEST_FUZZ */
pos += 8;
- if (random_get_bytes(pos, 16) < 0)
+ if (random_get_bytes(pos, gtk_len) < 0)
ret = -1;
-#ifdef CONFIG_IEEE80211W
- sha256_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len);
-#else /* CONFIG_IEEE80211W */
- if (sha1_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len)
- < 0)
+#ifdef CONFIG_SHA384
+ if (sha384_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data),
+ gtk, gtk_len) < 0)
ret = -1;
-#endif /* CONFIG_IEEE80211W */
+#else /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA256
+ if (sha256_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data),
+ gtk, gtk_len) < 0)
+ ret = -1;
+#else /* CONFIG_SHA256 */
+ if (sha1_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data),
+ gtk, gtk_len) < 0)
+ ret = -1;
+#endif /* CONFIG_SHA256 */
+#endif /* CONFIG_SHA384 */
return ret;
}
@@ -1383,13 +1433,9 @@
if (force_version)
version = force_version;
- else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
- wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
- wpa_key_mgmt_fils(sm->wpa_key_mgmt))
+ else if (wpa_use_akm_defined(sm->wpa_key_mgmt))
version = WPA_KEY_INFO_TYPE_AKM_DEFINED;
- else if (wpa_use_aes_cmac(sm))
+ else if (wpa_use_cmac(sm->wpa_key_mgmt))
version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
else if (sm->pairwise != WPA_CIPHER_TKIP)
version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
@@ -1411,10 +1457,7 @@
key_data_len = kde_len;
if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
- wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
+ wpa_use_aes_key_wrap(sm->wpa_key_mgmt) ||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) {
pad_len = key_data_len % 8;
if (pad_len)
@@ -1474,7 +1517,7 @@
os_memcpy(key_data, kde, kde_len);
WPA_PUT_BE16(key_mic + mic_len, kde_len);
#ifdef CONFIG_FILS
- } else if (!mic_len) {
+ } else if (!mic_len && kde) {
const u8 *aad[1];
size_t aad_len[1];
@@ -1513,10 +1556,7 @@
wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data",
buf, key_data_len);
if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
- wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
+ wpa_use_aes_key_wrap(sm->wpa_key_mgmt) ||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
wpa_printf(MSG_DEBUG,
"WPA: Encrypt Key Data using AES-WRAP (KEK length %u)",
@@ -1560,9 +1600,12 @@
return;
}
- wpa_eapol_key_mic(sm->PTK.kck, sm->PTK.kck_len,
- sm->wpa_key_mgmt, version,
- (u8 *) hdr, len, key_mic);
+ if (wpa_eapol_key_mic(sm->PTK.kck, sm->PTK.kck_len,
+ sm->wpa_key_mgmt, version,
+ (u8 *) hdr, len, key_mic) < 0) {
+ os_free(hdr);
+ return;
+ }
#ifdef CONFIG_TESTING_OPTIONS
if (!pairwise &&
wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 &&
@@ -1610,6 +1653,9 @@
timeout_ms = eapol_key_timeout_no_retrans;
if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC))
sm->pending_1_of_4_timeout = 1;
+#ifdef TEST_FUZZ
+ timeout_ms = 1;
+#endif /* TEST_FUZZ */
wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry "
"counter %u)", timeout_ms, ctr);
eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
@@ -1684,6 +1730,12 @@
case WPA_DEAUTH:
case WPA_DISASSOC:
sm->DeauthenticationRequest = TRUE;
+#ifdef CONFIG_IEEE80211R_AP
+ os_memset(sm->PMK, 0, sizeof(sm->PMK));
+ sm->pmk_len = 0;
+ os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
+ sm->xxkey_len = 0;
+#endif /* CONFIG_IEEE80211R_AP */
break;
case WPA_REAUTH:
case WPA_REAUTH_EAPOL:
@@ -1963,8 +2015,13 @@
sm->pmk_len = pmk_len;
#ifdef CONFIG_IEEE80211R_AP
if (len >= 2 * PMK_LEN) {
- os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN);
- sm->xxkey_len = PMK_LEN;
+ if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
+ os_memcpy(sm->xxkey, msk, SHA384_MAC_LEN);
+ sm->xxkey_len = SHA384_MAC_LEN;
+ } else {
+ os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN);
+ sm->xxkey_len = PMK_LEN;
+ }
}
#endif /* CONFIG_IEEE80211R_AP */
} else {
@@ -1995,7 +2052,7 @@
SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk);
psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL,
- &psk_len);
+ &psk_len, NULL);
if (psk) {
os_memcpy(sm->PMK, psk, psk_len);
sm->pmk_len = psk_len;
@@ -2009,6 +2066,10 @@
wpa_printf(MSG_DEBUG, "SAE: PMK from PMKSA cache");
os_memcpy(sm->PMK, sm->pmksa->pmk, sm->pmksa->pmk_len);
sm->pmk_len = sm->pmksa->pmk_len;
+#ifdef CONFIG_IEEE80211R_AP
+ os_memcpy(sm->xxkey, sm->pmksa->pmk, sm->pmksa->pmk_len);
+ sm->xxkey_len = sm->pmksa->pmk_len;
+#endif /* CONFIG_IEEE80211R_AP */
}
#endif /* CONFIG_SAE */
sm->req_replay_counter_used = 0;
@@ -2035,8 +2096,18 @@
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"sending 1/4 msg of 4-Way Handshake");
/*
- * TODO: Could add PMKID even with WPA2-PSK, but only if there is only
- * one possible PSK for this STA.
+ * For infrastructure BSS cases, it is better for the AP not to include
+ * the PMKID KDE in EAPOL-Key msg 1/4 since it could be used to initiate
+ * offline search for the passphrase/PSK without having to be able to
+ * capture a 4-way handshake from a STA that has access to the network.
+ *
+ * For IBSS cases, addition of PMKID KDE could be considered even with
+ * WPA2-PSK cases that use multiple PSKs, but only if there is a single
+ * possible PSK for this STA. However, this should not be done unless
+ * there is support for using that information on the supplicant side.
+ * The concern about exposing PMKID unnecessarily in infrastructure BSS
+ * cases would also apply here, but at least in the IBSS case, this
+ * would cover a potential real use case.
*/
if (sm->wpa == WPA_VERSION_WPA2 &&
(wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) ||
@@ -2049,11 +2120,31 @@
pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN;
RSN_SELECTOR_PUT(&pmkid[2], RSN_KEY_DATA_PMKID);
if (sm->pmksa) {
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: Message 1/4 PMKID from PMKSA entry",
+ sm->pmksa->pmkid, PMKID_LEN);
os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
sm->pmksa->pmkid, PMKID_LEN);
} else if (wpa_key_mgmt_suite_b(sm->wpa_key_mgmt)) {
/* No KCK available to derive PMKID */
+ wpa_printf(MSG_DEBUG,
+ "RSN: No KCK available to derive PMKID for message 1/4");
pmkid = NULL;
+#ifdef CONFIG_SAE
+ } else if (wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
+ if (sm->pmkid_set) {
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: Message 1/4 PMKID from SAE",
+ sm->pmkid, PMKID_LEN);
+ os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
+ sm->pmkid, PMKID_LEN);
+ } else {
+ /* No PMKID available */
+ wpa_printf(MSG_DEBUG,
+ "RSN: No SAE PMKID available for message 1/4");
+ pmkid = NULL;
+ }
+#endif /* CONFIG_SAE */
} else {
/*
* Calculate PMKID since no PMKSA cache entry was
@@ -2062,6 +2153,9 @@
rsn_pmkid(sm->PMK, sm->pmk_len, sm->wpa_auth->addr,
sm->addr, &pmkid[2 + RSN_SELECTOR_LEN],
sm->wpa_key_mgmt);
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: Message 1/4 PMKID derived from PMK",
+ &pmkid[2 + RSN_SELECTOR_LEN], PMKID_LEN);
}
}
wpa_send_eapol(sm->wpa_auth, sm,
@@ -2074,14 +2168,24 @@
const u8 *pmk, unsigned int pmk_len,
struct wpa_ptk *ptk)
{
+ const u8 *z = NULL;
+ size_t z_len = 0;
+
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
#endif /* CONFIG_IEEE80211R_AP */
+#ifdef CONFIG_DPP2
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && sm->dpp_z) {
+ z = wpabuf_head(sm->dpp_z);
+ z_len = wpabuf_len(sm->dpp_z);
+ }
+#endif /* CONFIG_DPP2 */
+
return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
- ptk, sm->wpa_key_mgmt, sm->pairwise);
+ ptk, sm->wpa_key_mgmt, sm->pairwise, z, z_len);
}
@@ -2112,22 +2216,35 @@
if (fils_ft_len) {
struct wpa_authenticator *wpa_auth = sm->wpa_auth;
struct wpa_auth_config *conf = &wpa_auth->conf;
- u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
+ 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,
conf->mobility_domain,
conf->r0_key_holder,
conf->r0_key_holder_len,
- sm->addr, pmk_r0, pmk_r0_name) < 0)
+ sm->addr, pmk_r0, pmk_r0_name,
+ use_sha384) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FILS+FT: PMK-R0", pmk_r0, PMK_LEN);
+ 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_r0(wpa_auth, sm->addr, pmk_r0, pmk_r0_name,
- sm->pairwise);
+ wpa_ft_store_pmk_fils(sm, pmk_r0, pmk_r0_name);
os_memset(fils_ft, 0, sizeof(fils_ft));
+
+ res = wpa_derive_pmk_r1_name(pmk_r0_name, conf->r1_key_holder,
+ sm->addr, sm->pmk_r1_name,
+ use_sha384);
+ os_memset(pmk_r0, 0, PMK_LEN_MAX);
+ if (res < 0)
+ return -1;
+ wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR1Name", sm->pmk_r1_name,
+ WPA_PMK_NAME_LEN);
+ sm->pmk_r1_name_valid = 1;
}
#endif /* CONFIG_IEEE80211R_AP */
@@ -2507,7 +2624,8 @@
/* GTK KDE */
gtk = gsm->GTK[gsm->GN - 1];
gtk_len = gsm->GTK_len;
- if (sm->wpa_auth->conf.disable_gtk) {
+ if (sm->wpa_auth->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.
@@ -2531,6 +2649,27 @@
wpabuf_put(plain, tmp2 - tmp);
*len = (u8 *) wpabuf_put(plain, 0) - len - 1;
+
+#ifdef CONFIG_OCV
+ if (wpa_auth_uses_ocv(sm)) {
+ struct wpa_channel_info ci;
+ u8 *pos;
+
+ if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "FILS: Failed to get channel info for OCI element");
+ wpabuf_free(plain);
+ return NULL;
+ }
+
+ pos = wpabuf_put(plain, OCV_OCI_EXTENDED_LEN);
+ if (ocv_insert_extended_oci(&ci, pos) < 0) {
+ wpabuf_free(plain);
+ return NULL;
+ }
+ }
+#endif /* CONFIG_OCV */
+
return plain;
}
@@ -2596,6 +2735,21 @@
#endif /* CONFIG_FILS */
+#ifdef CONFIG_OCV
+int get_sta_tx_parameters(struct wpa_state_machine *sm, int ap_max_chanwidth,
+ int ap_seg1_idx, int *bandwidth, int *seg1_idx)
+{
+ struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+
+ if (!wpa_auth->cb->get_sta_tx_params)
+ return -1;
+ return wpa_auth->cb->get_sta_tx_params(wpa_auth->cb_ctx, sm->addr,
+ ap_max_chanwidth, ap_seg1_idx,
+ bandwidth, seg1_idx);
+}
+#endif /* CONFIG_OCV */
+
+
SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
{
struct wpa_authenticator *wpa_auth = sm->wpa_auth;
@@ -2610,6 +2764,7 @@
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
struct wpa_eapol_ie_parse kde;
+ int vlan_id = 0;
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
sm->EAPOLKeyReceived = FALSE;
@@ -2625,10 +2780,17 @@
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
!wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
- sm->p2p_dev_addr, pmk, &pmk_len);
+ sm->p2p_dev_addr, pmk, &pmk_len,
+ &vlan_id);
if (pmk == NULL)
break;
psk_found = 1;
+#ifdef CONFIG_IEEE80211R_AP
+ if (wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
+ os_memcpy(sm->xxkey, pmk, pmk_len);
+ sm->xxkey_len = pmk_len;
+ }
+#endif /* CONFIG_IEEE80211R_AP */
} else {
pmk = sm->PMK;
pmk_len = sm->pmk_len;
@@ -2641,6 +2803,10 @@
wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
sm->last_rx_eapol_key,
sm->last_rx_eapol_key_len) == 0) {
+ if (sm->PMK != pmk) {
+ os_memcpy(sm->PMK, pmk, pmk_len);
+ sm->pmk_len = pmk_len;
+ }
ok = 1;
break;
}
@@ -2654,7 +2820,8 @@
}
#endif /* CONFIG_FILS */
- if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt))
+ if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
+ wpa_key_mgmt_sae(sm->wpa_key_mgmt))
break;
}
@@ -2711,6 +2878,32 @@
WLAN_REASON_PREV_AUTH_NOT_VALID);
return;
}
+#ifdef CONFIG_OCV
+ if (wpa_auth_uses_ocv(sm)) {
+ struct wpa_channel_info ci;
+ int tx_chanwidth;
+ int tx_seg1_idx;
+
+ 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 2/4");
+ return;
+ }
+
+ if (get_sta_tx_parameters(sm,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx, &tx_chanwidth,
+ &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);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
#ifdef CONFIG_IEEE80211R_AP
if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) {
wpa_sta_disconnect(wpa_auth, sm->addr,
@@ -2759,6 +2952,13 @@
}
#endif /* CONFIG_IEEE80211R_AP */
+ if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
+ wpa_auth_update_vlan(wpa_auth, sm->addr, vlan_id) < 0) {
+ wpa_sta_disconnect(wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ return;
+ }
+
sm->pending_1_of_4_timeout = 0;
eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
@@ -2816,7 +3016,8 @@
else
os_memcpy(igtk.pn, rsc, sizeof(igtk.pn));
os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], len);
- if (sm->wpa_auth->conf.disable_gtk) {
+ if (sm->wpa_auth->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.
@@ -2847,6 +3048,36 @@
#endif /* CONFIG_IEEE80211W */
+static int ocv_oci_len(struct wpa_state_machine *sm)
+{
+#ifdef CONFIG_OCV
+ if (wpa_auth_uses_ocv(sm))
+ return OCV_OCI_KDE_LEN;
+#endif /* CONFIG_OCV */
+ return 0;
+}
+
+static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos)
+{
+#ifdef CONFIG_OCV
+ struct wpa_channel_info ci;
+
+ if (!wpa_auth_uses_ocv(sm))
+ return 0;
+
+ if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element");
+ return -1;
+ }
+
+ return ocv_insert_oci_kde(&ci, argpos);
+#else /* CONFIG_OCV */
+ return 0;
+#endif /* CONFIG_OCV */
+}
+
+
SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
{
u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32];
@@ -2894,7 +3125,8 @@
secure = 1;
gtk = gsm->GTK[gsm->GN - 1];
gtk_len = gsm->GTK_len;
- if (sm->wpa_auth->conf.disable_gtk) {
+ if (sm->wpa_auth->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.
@@ -2929,7 +3161,7 @@
}
}
- kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
+ kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
if (gtk)
kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
#ifdef CONFIG_IEEE80211R_AP
@@ -2974,6 +3206,10 @@
gtk, gtk_len);
}
pos = ieee80211w_kde_add(sm, pos);
+ if (ocv_oci_add(sm, &pos) < 0) {
+ os_free(kde);
+ return;
+ }
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
@@ -2987,7 +3223,10 @@
2 + sm->assoc_resp_ftie[1]);
res = 2 + sm->assoc_resp_ftie[1];
} else {
- res = wpa_write_ftie(conf, conf->r0_key_holder,
+ int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
+
+ res = wpa_write_ftie(conf, use_sha384,
+ conf->r0_key_holder,
conf->r0_key_holder_len,
NULL, NULL, pos,
kde + kde_len - pos,
@@ -3012,7 +3251,7 @@
*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
*pos++ = 5;
*pos++ = WLAN_TIMEOUT_KEY_LIFETIME;
- WPA_PUT_LE32(pos, conf->r0_key_lifetime * 60);
+ WPA_PUT_LE32(pos, conf->r0_key_lifetime);
pos += 4;
}
#endif /* CONFIG_IEEE80211R_AP */
@@ -3159,7 +3398,7 @@
break;
case WPA_PTK_INITPSK:
if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr,
- NULL, NULL)) {
+ NULL, NULL, NULL)) {
SM_ENTER(WPA_PTK, PTKSTART);
#ifdef CONFIG_SAE
} else if (wpa_auth_uses_sae(sm) && sm->pmksa) {
@@ -3270,7 +3509,8 @@
"sending 1/2 msg of Group Key Handshake");
gtk = gsm->GTK[gsm->GN - 1];
- if (sm->wpa_auth->conf.disable_gtk) {
+ if (sm->wpa_auth->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.
@@ -3281,7 +3521,7 @@
}
if (sm->wpa == WPA_VERSION_WPA2) {
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
- ieee80211w_kde_len(sm);
+ ieee80211w_kde_len(sm) + ocv_oci_len(sm);
kde_buf = os_malloc(kde_len);
if (kde_buf == NULL)
return;
@@ -3292,6 +3532,10 @@
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) {
+ os_free(kde_buf);
+ return;
+ }
kde_len = pos - kde;
} else {
kde = gtk;
@@ -3312,8 +3556,67 @@
SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
{
+#ifdef CONFIG_OCV
+ struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+ const u8 *key_data, *mic;
+ struct ieee802_1x_hdr *hdr;
+ struct wpa_eapol_key *key;
+ struct wpa_eapol_ie_parse kde;
+ size_t mic_len;
+ u16 key_data_length;
+#endif /* CONFIG_OCV */
+
SM_ENTRY_MA(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group);
sm->EAPOLKeyReceived = FALSE;
+
+#ifdef CONFIG_OCV
+ mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
+
+ /*
+ * Note: last_rx_eapol_key length fields have already been validated in
+ * wpa_receive().
+ */
+ hdr = (struct ieee802_1x_hdr *) sm->last_rx_eapol_key;
+ key = (struct wpa_eapol_key *) (hdr + 1);
+ mic = (u8 *) (key + 1);
+ key_data = mic + mic_len + 2;
+ key_data_length = WPA_GET_BE16(mic + mic_len);
+ if (key_data_length > sm->last_rx_eapol_key_len - sizeof(*hdr) -
+ sizeof(*key) - mic_len - 2)
+ return;
+
+ if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received EAPOL-Key group msg 2/2 with invalid Key Data contents");
+ return;
+ }
+
+ if (wpa_auth_uses_ocv(sm)) {
+ struct wpa_channel_info ci;
+ int tx_chanwidth;
+ int tx_seg1_idx;
+
+ 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");
+ return;
+ }
+
+ if (get_sta_tx_parameters(sm,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx, &tx_chanwidth,
+ &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);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
if (sm->GUpdateStationKeys)
sm->group->GKeyDoneStations--;
sm->GUpdateStationKeys = FALSE;
@@ -3922,6 +4225,15 @@
}
+const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len)
+{
+ if (!sm)
+ return NULL;
+ *len = sm->pmk_len;
+ return sm->PMK;
+}
+
+
int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
{
if (sm == NULL)
@@ -4047,6 +4359,13 @@
}
+void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid)
+{
+ os_memcpy(sm->pmkid, pmkid, PMKID_LEN);
+ sm->pmkid_set = 1;
+}
+
+
int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *pmk, size_t pmk_len, const u8 *pmkid,
int session_timeout, int akmp)
@@ -4505,11 +4824,12 @@
#ifdef CONFIG_IEEE80211R_AP
-int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, u8 *buf, size_t len)
+int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, int use_sha384,
+ u8 *buf, size_t len)
{
struct wpa_auth_config *conf = &wpa_auth->conf;
- return wpa_write_ftie(conf, conf->r0_key_holder,
+ return wpa_write_ftie(conf, use_sha384, conf->r0_key_holder,
conf->r0_key_holder_len,
NULL, NULL, buf, len, NULL, 0);
}
@@ -4529,7 +4849,25 @@
#endif /* CONFIG_FILS */
-#if CONFIG_TESTING_OPTIONS
+void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg)
+{
+ if (sm)
+ sm->auth_alg = auth_alg;
+}
+
+
+#ifdef CONFIG_DPP2
+void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z)
+{
+ if (sm) {
+ wpabuf_clear_free(sm->dpp_z);
+ sm->dpp_z = z ? wpabuf_dup(z) : NULL;
+ }
+}
+#endif /* CONFIG_DPP2 */
+
+
+#ifdef CONFIG_TESTING_OPTIONS
int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
void (*cb)(void *ctx1, void *ctx2),
@@ -4557,7 +4895,10 @@
void (*cb)(void *ctx1, void *ctx2),
void *ctx1, void *ctx2)
{
- u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, *opos;
+ u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos;
+#ifdef CONFIG_IEEE80211W
+ u8 *opos;
+#endif /* CONFIG_IEEE80211W */
size_t gtk_len, kde_len;
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
@@ -4614,7 +4955,7 @@
}
}
- kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
+ kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
if (gtk)
kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
#ifdef CONFIG_IEEE80211R_AP
@@ -4654,12 +4995,19 @@
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gtk_len);
}
+#ifdef CONFIG_IEEE80211W
opos = pos;
pos = ieee80211w_kde_add(sm, pos);
- if (pos - opos >= WPA_IGTK_KDE_PREFIX_LEN) {
- opos += 2; /* skip keyid */
+ if (pos - opos >= 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN) {
+ /* skip KDE header and keyid */
+ opos += 2 + RSN_SELECTOR_LEN + 2;
os_memset(opos, 0, 6); /* clear PN */
}
+#endif /* CONFIG_IEEE80211W */
+ if (ocv_oci_add(sm, &pos) < 0) {
+ os_free(kde);
+ return -1;
+ }
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
@@ -4673,7 +5021,10 @@
2 + sm->assoc_resp_ftie[1]);
res = 2 + sm->assoc_resp_ftie[1];
} else {
- res = wpa_write_ftie(conf, conf->r0_key_holder,
+ int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
+
+ res = wpa_write_ftie(conf, use_sha384,
+ conf->r0_key_holder,
conf->r0_key_holder_len,
NULL, NULL, pos,
kde + kde_len - pos,
@@ -4698,7 +5049,7 @@
*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
*pos++ = 5;
*pos++ = WLAN_TIMEOUT_KEY_LIFETIME;
- WPA_PUT_LE32(pos, conf->r0_key_lifetime * 60);
+ WPA_PUT_LE32(pos, conf->r0_key_lifetime);
pos += 4;
}
#endif /* CONFIG_IEEE80211R_AP */
@@ -4722,7 +5073,10 @@
u8 rsc[WPA_KEY_RSC_LEN];
struct wpa_group *gsm = sm->group;
const u8 *kde;
- u8 *kde_buf = NULL, *pos, *opos, hdr[2];
+ u8 *kde_buf = NULL, *pos, hdr[2];
+#ifdef CONFIG_IEEE80211W
+ u8 *opos;
+#endif /* CONFIG_IEEE80211W */
size_t kde_len;
u8 *gtk;
@@ -4735,7 +5089,7 @@
gtk = gsm->GTK[gsm->GN - 1];
if (sm->wpa == WPA_VERSION_WPA2) {
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
- ieee80211w_kde_len(sm);
+ ieee80211w_kde_len(sm) + ocv_oci_len(sm);
kde_buf = os_malloc(kde_len);
if (kde_buf == NULL)
return -1;
@@ -4745,12 +5099,20 @@
hdr[1] = 0;
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gsm->GTK_len);
+#ifdef CONFIG_IEEE80211W
opos = pos;
pos = ieee80211w_kde_add(sm, pos);
- if (pos - opos >= WPA_IGTK_KDE_PREFIX_LEN) {
- opos += 2; /* skip keyid */
+ if (pos - opos >=
+ 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN) {
+ /* skip KDE header and keyid */
+ opos += 2 + RSN_SELECTOR_LEN + 2;
os_memset(opos, 0, 6); /* clear PN */
}
+#endif /* CONFIG_IEEE80211W */
+ if (ocv_oci_add(sm, &pos) < 0) {
+ os_free(kde_buf);
+ return -1;
+ }
kde_len = pos - kde;
} else {
kde = gtk;
@@ -4773,4 +5135,13 @@
return 0;
}
+
+int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth)
+{
+ if (!wpa_auth)
+ return -1;
+ eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
+ return eloop_register_timeout(0, 0, wpa_rekey_gtk, wpa_auth, NULL);
+}
+
#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 22f33dd..484e1e5 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -14,6 +14,8 @@
#include "common/wpa_common.h"
#include "common/ieee802_11_defs.h"
+struct vlan_description;
+
#define MAX_OWN_IE_OVERRIDE 256
#ifdef _MSC_VER
@@ -77,6 +79,14 @@
#define FT_RRB_PMK_R1 10 /* PMK_LEN */
#define FT_RRB_PAIRWISE 11 /* le16 */
+#define FT_RRB_EXPIRES_IN 12 /* le16 seconds */
+
+#define FT_RRB_VLAN_UNTAGGED 13 /* le16 */
+#define FT_RRB_VLAN_TAGGED 14 /* n times le16 */
+
+#define FT_RRB_IDENTITY 15
+#define FT_RRB_RADIUS_CUI 16
+#define FT_RRB_SESSION_TIMEOUT 17 /* le32 seconds */
struct ft_rrb_tlv {
le16 type;
@@ -92,6 +102,8 @@
/* session TLVs:
* required: PMK_R1, PMK_R1_NAME, PAIRWISE
+ * optional: VLAN_UNTAGGED, VLAN_TAGGED, EXPIRES_IN, IDENTITY, RADIUS_CUI,
+ * SESSION_TIMEOUT
*
* pull frame TLVs:
* auth:
@@ -133,6 +145,7 @@
struct rsn_pmksa_cache_entry;
struct eapol_state_machine;
struct ft_remote_seq;
+struct wpa_channel_info;
struct ft_remote_r0kh {
@@ -177,7 +190,11 @@
#ifdef CONFIG_IEEE80211W
enum mfp_options ieee80211w;
int group_mgmt_cipher;
+ int sae_require_mfp;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ int ocv; /* Operating Channel Validation */
+#endif /* CONFIG_OCV */
#ifdef CONFIG_IEEE80211R_AP
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
@@ -185,11 +202,12 @@
u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];
size_t r0_key_holder_len;
u8 r1_key_holder[FT_R1KH_ID_LEN];
- u32 r0_key_lifetime;
+ u32 r0_key_lifetime; /* PMK-R0 lifetime seconds */
int rkh_pos_timeout;
int rkh_neg_timeout;
int rkh_pull_timeout; /* ms */
int rkh_pull_retries;
+ int r1_max_key_lifetime;
u32 reassociation_deadline;
struct ft_remote_r0kh **r0kh_list;
struct ft_remote_r1kh **r1kh_list;
@@ -236,7 +254,8 @@
int value);
int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);
const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *p2p_dev_addr,
- const u8 *prev_psk, size_t *psk_len);
+ const u8 *prev_psk, size_t *psk_len,
+ int *vlan_id);
int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);
int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg,
const u8 *addr, int idx, u8 *key, size_t key_len);
@@ -251,8 +270,27 @@
size_t data_len);
int (*send_oui)(void *ctx, const u8 *dst, u8 oui_suffix, const u8 *data,
size_t data_len);
+ int (*channel_info)(void *ctx, struct wpa_channel_info *ci);
+ int (*update_vlan)(void *ctx, const u8 *addr, int vlan_id);
+ int (*get_sta_tx_params)(void *ctx, const u8 *addr,
+ int ap_max_chanwidth, int ap_seg1_idx,
+ int *bandwidth, int *seg1_idx);
#ifdef CONFIG_IEEE80211R_AP
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
+ int (*set_vlan)(void *ctx, const u8 *sta_addr,
+ struct vlan_description *vlan);
+ int (*get_vlan)(void *ctx, const u8 *sta_addr,
+ struct vlan_description *vlan);
+ int (*set_identity)(void *ctx, const u8 *sta_addr,
+ const u8 *identity, size_t identity_len);
+ size_t (*get_identity)(void *ctx, const u8 *sta_addr, const u8 **buf);
+ int (*set_radius_cui)(void *ctx, const u8 *sta_addr,
+ const u8 *radius_cui, size_t radius_cui_len);
+ size_t (*get_radius_cui)(void *ctx, const u8 *sta_addr, const u8 **buf);
+ void (*set_session_timeout)(void *ctx, const u8 *sta_addr,
+ int session_timeout);
+ int (*get_session_timeout)(void *ctx, const u8 *sta_addr);
+
int (*send_ft_action)(void *ctx, const u8 *dst,
const u8 *data, size_t data_len);
int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie,
@@ -280,7 +318,7 @@
};
int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm,
+ struct wpa_state_machine *sm, int freq,
const u8 *wpa_ie, size_t wpa_ie_len,
const u8 *mdie, size_t mdie_len,
const u8 *owe_dh, size_t owe_dh_len);
@@ -288,6 +326,8 @@
struct wpa_state_machine *sm,
const u8 *osen_ie, size_t osen_ie_len);
int wpa_auth_uses_mfp(struct wpa_state_machine *sm);
+void wpa_auth_set_ocv(struct wpa_state_machine *sm, int ocv);
+int wpa_auth_uses_ocv(struct wpa_state_machine *sm);
struct wpa_state_machine *
wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *p2p_dev_addr);
@@ -311,6 +351,7 @@
void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth);
int wpa_auth_pairwise_set(struct wpa_state_machine *sm);
int wpa_auth_get_pairwise(struct wpa_state_machine *sm);
+const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len);
int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm);
int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm);
int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm);
@@ -331,6 +372,7 @@
struct eapol_state_machine *eapol);
int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *pmk, const u8 *pmkid);
+void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid);
int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *pmk, size_t pmk_len, const u8 *pmkid,
int session_timeout, int akmp);
@@ -420,13 +462,19 @@
int wpa_fils_validate_key_confirm(struct wpa_state_machine *sm, const u8 *ies,
size_t ies_len);
-int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, u8 *buf, size_t len);
+int get_sta_tx_parameters(struct wpa_state_machine *sm, int ap_max_chanwidth,
+ int ap_seg1_idx, int *bandwidth, int *seg1_idx);
+
+int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, int use_sha384,
+ u8 *buf, size_t len);
void wpa_auth_get_fils_aead_params(struct wpa_state_machine *sm,
u8 *fils_anonce, u8 *fils_snonce,
u8 *fils_kek, size_t *fils_kek_len);
u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
u8 *pos, size_t max_len,
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);
int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
void (*cb)(void *ctx1, void *ctx2),
@@ -437,5 +485,6 @@
int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
void (*cb)(void *ctx1, void *ctx2),
void *ctx1, void *ctx2);
+int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth);
#endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 153752d..fdb7eba 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -1,6 +1,6 @@
/*
* hostapd - IEEE 802.11r - Fast BSS Transition
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -13,9 +13,12 @@
#include "utils/list.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/ocv.h"
+#include "drivers/driver.h"
#include "crypto/aes.h"
#include "crypto/aes_siv.h"
#include "crypto/aes_wrap.h"
+#include "crypto/sha384.h"
#include "crypto/random.h"
#include "ap_config.h"
#include "ieee802_11.h"
@@ -63,7 +66,7 @@
* Returns: 0 on success, -1 on error
*/
static int wpa_ft_rrb_decrypt(const u8 *key, const size_t key_len,
- const u8 *enc, const size_t enc_len,
+ const u8 *enc, size_t enc_len,
const u8 *auth, const size_t auth_len,
const u8 *src_addr, u8 type,
u8 **plain, size_t *plain_size)
@@ -71,7 +74,11 @@
const u8 *ad[3] = { src_addr, auth, &type };
size_t ad_len[3] = { ETH_ALEN, auth_len, sizeof(type) };
+ wpa_printf(MSG_DEBUG, "FT(RRB): src_addr=" MACSTR " type=%u",
+ MAC2STR(src_addr), type);
wpa_hexdump_key(MSG_DEBUG, "FT(RRB): decrypt using key", key, key_len);
+ wpa_hexdump(MSG_DEBUG, "FT(RRB): encrypted TLVs", enc, enc_len);
+ wpa_hexdump(MSG_DEBUG, "FT(RRB): authenticated TLVs", auth, auth_len);
if (!key) { /* skip decryption */
*plain = os_memdup(enc, enc_len);
@@ -94,8 +101,18 @@
goto err;
if (aes_siv_decrypt(key, key_len, enc, enc_len, 3, ad, ad_len,
- *plain) < 0)
- goto err;
+ *plain) < 0) {
+ if (enc_len < AES_BLOCK_SIZE + 2)
+ goto err;
+
+ /* Try to work around Ethernet devices that add extra
+ * two octet padding even if the frame is longer than
+ * the minimum Ethernet frame. */
+ enc_len -= 2;
+ if (aes_siv_decrypt(key, key_len, enc, enc_len, 3, ad, ad_len,
+ *plain) < 0)
+ goto err;
+ }
*plain_size = enc_len - AES_BLOCK_SIZE;
wpa_hexdump_key(MSG_DEBUG, "FT(RRB): decrypted TLVs",
@@ -192,6 +209,98 @@
}
+static int cmp_int(const void *a, const void *b)
+{
+ int x, y;
+
+ x = *((int *) a);
+ y = *((int *) b);
+ return x - y;
+}
+
+
+static int wpa_ft_rrb_get_tlv_vlan(const u8 *plain, const size_t plain_len,
+ struct vlan_description *vlan)
+{
+ struct ft_rrb_tlv *f;
+ size_t left;
+ size_t len;
+ int taggedidx;
+ int vlan_id;
+ int type;
+
+ left = plain_len;
+ taggedidx = 0;
+ os_memset(vlan, 0, sizeof(*vlan));
+
+ while (left >= sizeof(*f)) {
+ f = (struct ft_rrb_tlv *) plain;
+
+ left -= sizeof(*f);
+ plain += sizeof(*f);
+
+ len = le_to_host16(f->len);
+ type = le_to_host16(f->type);
+
+ if (left < len) {
+ wpa_printf(MSG_DEBUG, "FT: RRB message truncated");
+ return -1;
+ }
+
+ if (type != FT_RRB_VLAN_UNTAGGED && type != FT_RRB_VLAN_TAGGED)
+ goto skip;
+
+ if (type == FT_RRB_VLAN_UNTAGGED && len != sizeof(le16)) {
+ wpa_printf(MSG_DEBUG,
+ "FT: RRB VLAN_UNTAGGED invalid length");
+ return -1;
+ }
+
+ if (type == FT_RRB_VLAN_TAGGED && len % sizeof(le16) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "FT: RRB VLAN_TAGGED invalid length");
+ return -1;
+ }
+
+ while (len >= sizeof(le16)) {
+ vlan_id = WPA_GET_LE16(plain);
+ plain += sizeof(le16);
+ left -= sizeof(le16);
+ len -= sizeof(le16);
+
+ if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID) {
+ wpa_printf(MSG_DEBUG,
+ "FT: RRB VLAN ID invalid %d",
+ vlan_id);
+ continue;
+ }
+
+ if (type == FT_RRB_VLAN_UNTAGGED)
+ vlan->untagged = vlan_id;
+
+ if (type == FT_RRB_VLAN_TAGGED &&
+ taggedidx < MAX_NUM_TAGGED_VLAN) {
+ vlan->tagged[taggedidx] = vlan_id;
+ taggedidx++;
+ } else if (type == FT_RRB_VLAN_TAGGED) {
+ wpa_printf(MSG_DEBUG, "FT: RRB too many VLANs");
+ }
+ }
+
+ skip:
+ left -= len;
+ plain += len;
+ }
+
+ if (taggedidx)
+ qsort(vlan->tagged, taggedidx, sizeof(int), cmp_int);
+
+ vlan->notempty = vlan->untagged || vlan->tagged[0];
+
+ return 0;
+}
+
+
static size_t wpa_ft_tlv_len(const struct tlv_list *tlvs)
{
size_t tlv_len = 0;
@@ -233,6 +342,8 @@
if (tlv_len + tlvs[i].len > (size_t) (endpos - start))
return tlv_len;
+ if (tlvs[i].len == 0)
+ continue;
tlv_len += tlvs[i].len;
os_memcpy(pos, tlvs[i].data, tlvs[i].len);
pos = start + tlv_len;
@@ -242,8 +353,84 @@
}
+static size_t wpa_ft_vlan_len(const struct vlan_description *vlan)
+{
+ size_t tlv_len = 0;
+ int i;
+
+ if (!vlan || !vlan->notempty)
+ return 0;
+
+ if (vlan->untagged) {
+ tlv_len += sizeof(struct ft_rrb_tlv);
+ tlv_len += sizeof(le16);
+ }
+ if (vlan->tagged[0])
+ tlv_len += sizeof(struct ft_rrb_tlv);
+ for (i = 0; i < MAX_NUM_TAGGED_VLAN && vlan->tagged[i]; i++)
+ tlv_len += sizeof(le16);
+
+ return tlv_len;
+}
+
+
+static size_t wpa_ft_vlan_lin(const struct vlan_description *vlan,
+ u8 *start, u8 *endpos)
+{
+ size_t tlv_len;
+ int i, len;
+ struct ft_rrb_tlv *hdr;
+ u8 *pos = start;
+
+ if (!vlan || !vlan->notempty)
+ return 0;
+
+ tlv_len = 0;
+ if (vlan->untagged) {
+ tlv_len += sizeof(*hdr);
+ if (start + tlv_len > endpos)
+ return tlv_len;
+ hdr = (struct ft_rrb_tlv *) pos;
+ hdr->type = host_to_le16(FT_RRB_VLAN_UNTAGGED);
+ hdr->len = host_to_le16(sizeof(le16));
+ pos = start + tlv_len;
+
+ tlv_len += sizeof(le16);
+ if (start + tlv_len > endpos)
+ return tlv_len;
+ WPA_PUT_LE16(pos, vlan->untagged);
+ pos = start + tlv_len;
+ }
+
+ if (!vlan->tagged[0])
+ return tlv_len;
+
+ tlv_len += sizeof(*hdr);
+ if (start + tlv_len > endpos)
+ return tlv_len;
+ hdr = (struct ft_rrb_tlv *) pos;
+ hdr->type = host_to_le16(FT_RRB_VLAN_TAGGED);
+ len = 0; /* len is computed below */
+ pos = start + tlv_len;
+
+ for (i = 0; i < MAX_NUM_TAGGED_VLAN && vlan->tagged[i]; i++) {
+ tlv_len += sizeof(le16);
+ if (start + tlv_len > endpos)
+ break;
+ len += sizeof(le16);
+ WPA_PUT_LE16(pos, vlan->tagged[i]);
+ pos = start + tlv_len;
+ }
+
+ hdr->len = host_to_le16(len);
+
+ return tlv_len;
+}
+
+
static int wpa_ft_rrb_lin(const struct tlv_list *tlvs1,
const struct tlv_list *tlvs2,
+ const struct vlan_description *vlan,
u8 **plain, size_t *plain_len)
{
u8 *pos, *endpos;
@@ -251,6 +438,7 @@
tlv_len = wpa_ft_tlv_len(tlvs1);
tlv_len += wpa_ft_tlv_len(tlvs2);
+ tlv_len += wpa_ft_vlan_len(vlan);
*plain_len = tlv_len;
*plain = os_zalloc(tlv_len);
@@ -263,6 +451,7 @@
endpos = *plain + tlv_len;
pos += wpa_ft_tlv_lin(tlvs1, pos, endpos);
pos += wpa_ft_tlv_lin(tlvs2, pos, endpos);
+ pos += wpa_ft_vlan_lin(vlan, pos, endpos);
/* sanity check */
if (pos != endpos) {
@@ -288,9 +477,12 @@
const u8 *ad[3] = { src_addr, auth, &type };
size_t ad_len[3] = { ETH_ALEN, auth_len, sizeof(type) };
+ wpa_printf(MSG_DEBUG, "FT(RRB): src_addr=" MACSTR " type=%u",
+ MAC2STR(src_addr), type);
wpa_hexdump_key(MSG_DEBUG, "FT(RRB): plaintext message",
plain, plain_len);
wpa_hexdump_key(MSG_DEBUG, "FT(RRB): encrypt using key", key, key_len);
+ wpa_hexdump(MSG_DEBUG, "FT(RRB): authenticated TLVs", auth, auth_len);
if (!key) {
/* encryption not needed, return plaintext as packet */
@@ -300,6 +492,8 @@
wpa_printf(MSG_ERROR, "FT: Failed to encrypt RRB-OUI message");
return -1;
}
+ wpa_hexdump(MSG_DEBUG, "FT(RRB): encrypted TLVs",
+ enc, plain_len + AES_BLOCK_SIZE);
return 0;
}
@@ -324,22 +518,47 @@
const struct tlv_list *tlvs_enc0,
const struct tlv_list *tlvs_enc1,
const struct tlv_list *tlvs_auth,
+ const struct vlan_description *vlan,
const u8 *src_addr, u8 type,
u8 **packet, size_t *packet_len)
{
- u8 *plain = NULL, *auth = NULL, *pos;
+ u8 *plain = NULL, *auth = NULL, *pos, *tmp;
size_t plain_len = 0, auth_len = 0;
int ret = -1;
+ size_t pad_len = 0;
- if (wpa_ft_rrb_lin(tlvs_enc0, tlvs_enc1, &plain, &plain_len) < 0)
+ *packet = NULL;
+ if (wpa_ft_rrb_lin(tlvs_enc0, tlvs_enc1, vlan, &plain, &plain_len) < 0)
goto out;
- if (wpa_ft_rrb_lin(tlvs_auth, NULL, &auth, &auth_len) < 0)
+ if (wpa_ft_rrb_lin(tlvs_auth, NULL, NULL, &auth, &auth_len) < 0)
goto out;
*packet_len = sizeof(u16) + auth_len + plain_len;
if (key)
*packet_len += AES_BLOCK_SIZE;
+#define RRB_MIN_MSG_LEN 64
+ if (*packet_len < RRB_MIN_MSG_LEN) {
+ pad_len = RRB_MIN_MSG_LEN - *packet_len;
+ if (pad_len < sizeof(struct ft_rrb_tlv))
+ pad_len = sizeof(struct ft_rrb_tlv);
+ wpa_printf(MSG_DEBUG,
+ "FT: Pad message to minimum Ethernet frame length (%d --> %d)",
+ (int) *packet_len, (int) (*packet_len + pad_len));
+ *packet_len += pad_len;
+ tmp = os_realloc(auth, auth_len + pad_len);
+ if (!tmp)
+ goto out;
+ auth = tmp;
+ pos = auth + auth_len;
+ WPA_PUT_LE16(pos, FT_RRB_LAST_EMPTY);
+ pos += 2;
+ WPA_PUT_LE16(pos, pad_len - sizeof(struct ft_rrb_tlv));
+ pos += 2;
+ os_memset(pos, 0, pad_len - sizeof(struct ft_rrb_tlv));
+ auth_len += pad_len;
+
+ }
*packet = os_zalloc(*packet_len);
if (!*packet)
goto out;
@@ -352,6 +571,7 @@
if (wpa_ft_rrb_encrypt(key, key_len, plain, plain_len, auth,
auth_len, src_addr, type, pos) < 0)
goto out;
+ wpa_hexdump(MSG_MSGDUMP, "FT: RRB frame payload", *packet, *packet_len);
ret = 0;
@@ -419,8 +639,8 @@
{
if (!wpa_auth->cb->send_oui)
return -1;
- wpa_printf(MSG_DEBUG, "FT: RRB-OUI type %u send to " MACSTR,
- oui_suffix, MAC2STR(dst));
+ wpa_printf(MSG_DEBUG, "FT: RRB-OUI type %u send to " MACSTR " (len=%u)",
+ oui_suffix, MAC2STR(dst), (unsigned int) data_len);
return wpa_auth->cb->send_oui(wpa_auth->cb_ctx, dst, oui_suffix, data,
data_len);
}
@@ -443,7 +663,7 @@
if (wpa_auth->cb->get_psk == NULL)
return NULL;
return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
- prev_psk, NULL);
+ prev_psk, NULL, NULL);
}
@@ -456,6 +676,89 @@
}
+static int wpa_ft_set_vlan(struct wpa_authenticator *wpa_auth,
+ const u8 *sta_addr, struct vlan_description *vlan)
+{
+ if (!wpa_auth->cb->set_vlan)
+ return -1;
+ return wpa_auth->cb->set_vlan(wpa_auth->cb_ctx, sta_addr, vlan);
+}
+
+
+static int wpa_ft_get_vlan(struct wpa_authenticator *wpa_auth,
+ const u8 *sta_addr, struct vlan_description *vlan)
+{
+ if (!wpa_auth->cb->get_vlan)
+ return -1;
+ return wpa_auth->cb->get_vlan(wpa_auth->cb_ctx, sta_addr, vlan);
+}
+
+
+static int
+wpa_ft_set_identity(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
+ const u8 *identity, size_t identity_len)
+{
+ if (!wpa_auth->cb->set_identity)
+ return -1;
+ return wpa_auth->cb->set_identity(wpa_auth->cb_ctx, sta_addr, identity,
+ identity_len);
+}
+
+
+static size_t
+wpa_ft_get_identity(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
+ const u8 **buf)
+{
+ *buf = NULL;
+ if (!wpa_auth->cb->get_identity)
+ return 0;
+ return wpa_auth->cb->get_identity(wpa_auth->cb_ctx, sta_addr, buf);
+}
+
+
+static int
+wpa_ft_set_radius_cui(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
+ const u8 *radius_cui, size_t radius_cui_len)
+{
+ if (!wpa_auth->cb->set_radius_cui)
+ return -1;
+ return wpa_auth->cb->set_radius_cui(wpa_auth->cb_ctx, sta_addr,
+ radius_cui, radius_cui_len);
+}
+
+
+static size_t
+wpa_ft_get_radius_cui(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
+ const u8 **buf)
+{
+ *buf = NULL;
+ if (!wpa_auth->cb->get_radius_cui)
+ return 0;
+ return wpa_auth->cb->get_radius_cui(wpa_auth->cb_ctx, sta_addr, buf);
+}
+
+
+static void
+wpa_ft_set_session_timeout(struct wpa_authenticator *wpa_auth,
+ const u8 *sta_addr, int session_timeout)
+{
+ if (!wpa_auth->cb->set_session_timeout)
+ return;
+ wpa_auth->cb->set_session_timeout(wpa_auth->cb_ctx, sta_addr,
+ session_timeout);
+}
+
+
+static int
+wpa_ft_get_session_timeout(struct wpa_authenticator *wpa_auth,
+ const u8 *sta_addr)
+{
+ if (!wpa_auth->cb->get_session_timeout)
+ return 0;
+ return wpa_auth->cb->get_session_timeout(wpa_auth->cb_ctx, sta_addr);
+}
+
+
static int wpa_ft_add_tspec(struct wpa_authenticator *wpa_auth,
const u8 *sta_addr,
u8 *tspec_ie, size_t tspec_ielen)
@@ -469,6 +772,17 @@
}
+#ifdef CONFIG_OCV
+static int wpa_channel_info(struct wpa_authenticator *wpa_auth,
+ struct wpa_channel_info *ci)
+{
+ if (!wpa_auth->cb->channel_info)
+ return -1;
+ return wpa_auth->cb->channel_info(wpa_auth->cb_ctx, ci);
+}
+#endif /* CONFIG_OCV */
+
+
int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len)
{
u8 *pos = buf;
@@ -489,30 +803,44 @@
}
-int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
- size_t r0kh_id_len,
+int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
+ const u8 *r0kh_id, size_t r0kh_id_len,
const u8 *anonce, const u8 *snonce,
u8 *buf, size_t len, const u8 *subelem,
size_t subelem_len)
{
u8 *pos = buf, *ielen;
- struct rsn_ftie *hdr;
+ size_t hdrlen = use_sha384 ? sizeof(struct rsn_ftie_sha384) :
+ sizeof(struct rsn_ftie);
- if (len < 2 + sizeof(*hdr) + 2 + FT_R1KH_ID_LEN + 2 + r0kh_id_len +
+ if (len < 2 + hdrlen + 2 + FT_R1KH_ID_LEN + 2 + r0kh_id_len +
subelem_len)
return -1;
*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
ielen = pos++;
- hdr = (struct rsn_ftie *) pos;
- os_memset(hdr, 0, sizeof(*hdr));
- pos += sizeof(*hdr);
- WPA_PUT_LE16(hdr->mic_control, 0);
- if (anonce)
- os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
- if (snonce)
- os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN);
+ if (use_sha384) {
+ struct rsn_ftie_sha384 *hdr = (struct rsn_ftie_sha384 *) pos;
+
+ os_memset(hdr, 0, sizeof(*hdr));
+ pos += sizeof(*hdr);
+ WPA_PUT_LE16(hdr->mic_control, 0);
+ if (anonce)
+ os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
+ if (snonce)
+ os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN);
+ } else {
+ struct rsn_ftie *hdr = (struct rsn_ftie *) pos;
+
+ os_memset(hdr, 0, sizeof(*hdr));
+ pos += sizeof(*hdr);
+ WPA_PUT_LE16(hdr->mic_control, 0);
+ if (anonce)
+ os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
+ if (snonce)
+ os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN);
+ }
/* Optional Parameters */
*pos++ = FTIE_SUBELEM_R1KH_ID;
@@ -622,6 +950,8 @@
goto err;
}
+ wpa_printf(MSG_DEBUG, "FT: Send out sequence number request to " MACSTR,
+ MAC2STR(src_addr));
item = os_zalloc(sizeof(*item));
if (!item)
goto err;
@@ -656,7 +986,7 @@
seq_req_auth[0].data = item->nonce;
- if (wpa_ft_rrb_build(key, key_len, NULL, NULL, seq_req_auth,
+ if (wpa_ft_rrb_build(key, key_len, NULL, NULL, seq_req_auth, NULL,
wpa_auth->addr, FT_PACKET_R0KH_R1KH_SEQ_REQ,
&packet, &packet_len) < 0) {
item = NULL; /* some other seq resp might still accept this */
@@ -834,34 +1164,136 @@
struct wpa_ft_pmk_r0_sa {
- struct wpa_ft_pmk_r0_sa *next;
- u8 pmk_r0[PMK_LEN];
+ struct dl_list list;
+ u8 pmk_r0[PMK_LEN_MAX];
+ size_t pmk_r0_len;
u8 pmk_r0_name[WPA_PMK_NAME_LEN];
u8 spa[ETH_ALEN];
int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
- /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
+ struct vlan_description *vlan;
+ os_time_t expiration; /* 0 for no expiration */
+ u8 *identity;
+ size_t identity_len;
+ u8 *radius_cui;
+ size_t radius_cui_len;
+ os_time_t session_timeout; /* 0 for no expiration */
+ /* TODO: radius_class, EAP type */
int pmk_r1_pushed;
};
struct wpa_ft_pmk_r1_sa {
- struct wpa_ft_pmk_r1_sa *next;
- u8 pmk_r1[PMK_LEN];
+ struct dl_list list;
+ u8 pmk_r1[PMK_LEN_MAX];
+ size_t pmk_r1_len;
u8 pmk_r1_name[WPA_PMK_NAME_LEN];
u8 spa[ETH_ALEN];
int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
- /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
+ struct vlan_description *vlan;
+ u8 *identity;
+ size_t identity_len;
+ u8 *radius_cui;
+ size_t radius_cui_len;
+ os_time_t session_timeout; /* 0 for no expiration */
+ /* TODO: radius_class, EAP type */
};
struct wpa_ft_pmk_cache {
- struct wpa_ft_pmk_r0_sa *pmk_r0;
- struct wpa_ft_pmk_r1_sa *pmk_r1;
+ struct dl_list pmk_r0; /* struct wpa_ft_pmk_r0_sa */
+ struct dl_list pmk_r1; /* struct wpa_ft_pmk_r1_sa */
};
+
+static void wpa_ft_expire_pmk_r0(void *eloop_ctx, void *timeout_ctx);
+static void wpa_ft_expire_pmk_r1(void *eloop_ctx, void *timeout_ctx);
+
+
+static void wpa_ft_free_pmk_r0(struct wpa_ft_pmk_r0_sa *r0)
+{
+ if (!r0)
+ return;
+
+ dl_list_del(&r0->list);
+ eloop_cancel_timeout(wpa_ft_expire_pmk_r0, r0, NULL);
+
+ os_memset(r0->pmk_r0, 0, PMK_LEN_MAX);
+ os_free(r0->vlan);
+ os_free(r0->identity);
+ os_free(r0->radius_cui);
+ os_free(r0);
+}
+
+
+static void wpa_ft_expire_pmk_r0(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_ft_pmk_r0_sa *r0 = eloop_ctx;
+ struct os_reltime now;
+ int expires_in;
+ int session_timeout;
+
+ os_get_reltime(&now);
+
+ if (!r0)
+ return;
+
+ expires_in = r0->expiration - now.sec;
+ session_timeout = r0->session_timeout - now.sec;
+ /* conditions to remove from cache:
+ * a) r0->expiration is set and hit
+ * -or-
+ * b) r0->session_timeout is set and hit
+ */
+ if ((!r0->expiration || expires_in > 0) &&
+ (!r0->session_timeout || session_timeout > 0)) {
+ wpa_printf(MSG_ERROR,
+ "FT: %s() called for non-expired entry %p",
+ __func__, r0);
+ eloop_cancel_timeout(wpa_ft_expire_pmk_r0, r0, NULL);
+ if (r0->expiration && expires_in > 0)
+ eloop_register_timeout(expires_in + 1, 0,
+ wpa_ft_expire_pmk_r0, r0, NULL);
+ if (r0->session_timeout && session_timeout > 0)
+ eloop_register_timeout(session_timeout + 1, 0,
+ wpa_ft_expire_pmk_r0, r0, NULL);
+ return;
+ }
+
+ wpa_ft_free_pmk_r0(r0);
+}
+
+
+static void wpa_ft_free_pmk_r1(struct wpa_ft_pmk_r1_sa *r1)
+{
+ if (!r1)
+ return;
+
+ dl_list_del(&r1->list);
+ eloop_cancel_timeout(wpa_ft_expire_pmk_r1, r1, NULL);
+
+ os_memset(r1->pmk_r1, 0, PMK_LEN_MAX);
+ os_free(r1->vlan);
+ os_free(r1->identity);
+ os_free(r1->radius_cui);
+ os_free(r1);
+}
+
+
+static void wpa_ft_expire_pmk_r1(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_ft_pmk_r1_sa *r1 = eloop_ctx;
+
+ wpa_ft_free_pmk_r1(r1);
+}
+
+
struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void)
{
struct wpa_ft_pmk_cache *cache;
cache = os_zalloc(sizeof(*cache));
+ if (cache) {
+ dl_list_init(&cache->pmk_r0);
+ dl_list_init(&cache->pmk_r1);
+ }
return cache;
}
@@ -872,46 +1304,77 @@
struct wpa_ft_pmk_r0_sa *r0, *r0prev;
struct wpa_ft_pmk_r1_sa *r1, *r1prev;
- r0 = cache->pmk_r0;
- while (r0) {
- r0prev = r0;
- r0 = r0->next;
- os_memset(r0prev->pmk_r0, 0, PMK_LEN);
- os_free(r0prev);
- }
+ dl_list_for_each_safe(r0, r0prev, &cache->pmk_r0,
+ struct wpa_ft_pmk_r0_sa, list)
+ wpa_ft_free_pmk_r0(r0);
- r1 = cache->pmk_r1;
- while (r1) {
- r1prev = r1;
- r1 = r1->next;
- os_memset(r1prev->pmk_r1, 0, PMK_LEN);
- os_free(r1prev);
- }
+ dl_list_for_each_safe(r1, r1prev, &cache->pmk_r1,
+ struct wpa_ft_pmk_r1_sa, list)
+ wpa_ft_free_pmk_r1(r1);
os_free(cache);
}
-int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth,
- const u8 *spa, const u8 *pmk_r0,
- const u8 *pmk_r0_name, int pairwise)
+static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth,
+ const u8 *spa, const u8 *pmk_r0,
+ size_t pmk_r0_len,
+ const u8 *pmk_r0_name, int pairwise,
+ const struct vlan_description *vlan,
+ int expires_in, int session_timeout,
+ const u8 *identity, size_t identity_len,
+ const u8 *radius_cui, size_t radius_cui_len)
{
struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
struct wpa_ft_pmk_r0_sa *r0;
+ struct os_reltime now;
- /* TODO: add expiration and limit on number of entries in cache */
+ /* TODO: add limit on number of entries in cache */
+ os_get_reltime(&now);
r0 = os_zalloc(sizeof(*r0));
if (r0 == NULL)
return -1;
- os_memcpy(r0->pmk_r0, pmk_r0, PMK_LEN);
+ os_memcpy(r0->pmk_r0, pmk_r0, pmk_r0_len);
+ r0->pmk_r0_len = pmk_r0_len;
os_memcpy(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
os_memcpy(r0->spa, spa, ETH_ALEN);
r0->pairwise = pairwise;
+ if (expires_in > 0)
+ r0->expiration = now.sec + expires_in;
+ if (vlan && vlan->notempty) {
+ r0->vlan = os_zalloc(sizeof(*vlan));
+ if (!r0->vlan) {
+ bin_clear_free(r0, sizeof(*r0));
+ return -1;
+ }
+ *r0->vlan = *vlan;
+ }
+ if (identity) {
+ r0->identity = os_malloc(identity_len);
+ if (r0->identity) {
+ os_memcpy(r0->identity, identity, identity_len);
+ r0->identity_len = identity_len;
+ }
+ }
+ if (radius_cui) {
+ r0->radius_cui = os_malloc(radius_cui_len);
+ if (r0->radius_cui) {
+ os_memcpy(r0->radius_cui, radius_cui, radius_cui_len);
+ r0->radius_cui_len = radius_cui_len;
+ }
+ }
+ if (session_timeout > 0)
+ r0->session_timeout = now.sec + session_timeout;
- r0->next = cache->pmk_r0;
- cache->pmk_r0 = r0;
+ dl_list_add(&cache->pmk_r0, &r0->list);
+ if (expires_in > 0)
+ eloop_register_timeout(expires_in + 1, 0, wpa_ft_expire_pmk_r0,
+ r0, NULL);
+ if (session_timeout > 0)
+ eloop_register_timeout(session_timeout + 1, 0,
+ wpa_ft_expire_pmk_r0, r0, NULL);
return 0;
}
@@ -923,17 +1386,16 @@
{
struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
struct wpa_ft_pmk_r0_sa *r0;
+ struct os_reltime now;
- r0 = cache->pmk_r0;
- while (r0) {
+ os_get_reltime(&now);
+ dl_list_for_each(r0, &cache->pmk_r0, struct wpa_ft_pmk_r0_sa, list) {
if (os_memcmp(r0->spa, spa, ETH_ALEN) == 0 &&
os_memcmp_const(r0->pmk_r0_name, pmk_r0_name,
WPA_PMK_NAME_LEN) == 0) {
*r0_out = r0;
return 0;
}
-
- r0 = r0->next;
}
*r0_out = NULL;
@@ -943,24 +1405,66 @@
static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth,
const u8 *spa, const u8 *pmk_r1,
- const u8 *pmk_r1_name, int pairwise)
+ size_t pmk_r1_len,
+ const u8 *pmk_r1_name, int pairwise,
+ const struct vlan_description *vlan,
+ int expires_in, int session_timeout,
+ const u8 *identity, size_t identity_len,
+ const u8 *radius_cui, size_t radius_cui_len)
{
struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
+ int max_expires_in = wpa_auth->conf.r1_max_key_lifetime;
struct wpa_ft_pmk_r1_sa *r1;
+ struct os_reltime now;
- /* TODO: add expiration and limit on number of entries in cache */
+ /* TODO: limit on number of entries in cache */
+ os_get_reltime(&now);
+
+ if (max_expires_in && (max_expires_in < expires_in || expires_in == 0))
+ expires_in = max_expires_in;
r1 = os_zalloc(sizeof(*r1));
if (r1 == NULL)
return -1;
- os_memcpy(r1->pmk_r1, pmk_r1, PMK_LEN);
+ os_memcpy(r1->pmk_r1, pmk_r1, pmk_r1_len);
+ r1->pmk_r1_len = pmk_r1_len;
os_memcpy(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
os_memcpy(r1->spa, spa, ETH_ALEN);
r1->pairwise = pairwise;
+ if (vlan && vlan->notempty) {
+ r1->vlan = os_zalloc(sizeof(*vlan));
+ if (!r1->vlan) {
+ bin_clear_free(r1, sizeof(*r1));
+ return -1;
+ }
+ *r1->vlan = *vlan;
+ }
+ if (identity) {
+ r1->identity = os_malloc(identity_len);
+ if (r1->identity) {
+ os_memcpy(r1->identity, identity, identity_len);
+ r1->identity_len = identity_len;
+ }
+ }
+ if (radius_cui) {
+ r1->radius_cui = os_malloc(radius_cui_len);
+ if (r1->radius_cui) {
+ os_memcpy(r1->radius_cui, radius_cui, radius_cui_len);
+ r1->radius_cui_len = radius_cui_len;
+ }
+ }
+ if (session_timeout > 0)
+ r1->session_timeout = now.sec + session_timeout;
- r1->next = cache->pmk_r1;
- cache->pmk_r1 = r1;
+ dl_list_add(&cache->pmk_r1, &r1->list);
+
+ if (expires_in > 0)
+ eloop_register_timeout(expires_in + 1, 0, wpa_ft_expire_pmk_r1,
+ r1, NULL);
+ if (session_timeout > 0)
+ eloop_register_timeout(session_timeout + 1, 0,
+ wpa_ft_expire_pmk_r1, r1, NULL);
return 0;
}
@@ -968,23 +1472,47 @@
static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
const u8 *spa, const u8 *pmk_r1_name,
- u8 *pmk_r1, int *pairwise)
+ u8 *pmk_r1, size_t *pmk_r1_len, int *pairwise,
+ struct vlan_description *vlan,
+ const u8 **identity, size_t *identity_len,
+ const u8 **radius_cui, size_t *radius_cui_len,
+ int *session_timeout)
{
struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
struct wpa_ft_pmk_r1_sa *r1;
+ struct os_reltime now;
- r1 = cache->pmk_r1;
- while (r1) {
+ os_get_reltime(&now);
+
+ dl_list_for_each(r1, &cache->pmk_r1, struct wpa_ft_pmk_r1_sa, list) {
if (os_memcmp(r1->spa, spa, ETH_ALEN) == 0 &&
os_memcmp_const(r1->pmk_r1_name, pmk_r1_name,
WPA_PMK_NAME_LEN) == 0) {
- os_memcpy(pmk_r1, r1->pmk_r1, PMK_LEN);
+ os_memcpy(pmk_r1, r1->pmk_r1, r1->pmk_r1_len);
+ *pmk_r1_len = r1->pmk_r1_len;
if (pairwise)
*pairwise = r1->pairwise;
+ if (vlan && r1->vlan)
+ *vlan = *r1->vlan;
+ if (vlan && !r1->vlan)
+ os_memset(vlan, 0, sizeof(*vlan));
+ if (identity && identity_len) {
+ *identity = r1->identity;
+ *identity_len = r1->identity_len;
+ }
+ if (radius_cui && radius_cui_len) {
+ *radius_cui = r1->radius_cui;
+ *radius_cui_len = r1->radius_cui_len;
+ }
+ if (session_timeout && r1->session_timeout > now.sec)
+ *session_timeout = r1->session_timeout -
+ now.sec;
+ else if (session_timeout && r1->session_timeout)
+ *session_timeout = 1;
+ else if (session_timeout)
+ *session_timeout = 0;
return 0;
}
-
- r1 = r1->next;
}
return -1;
@@ -1459,6 +1987,11 @@
sm->r0kh_id, sm->r0kh_id_len);
return -1;
}
+ if (os_memcmp(r0kh->addr, sm->wpa_auth->addr, ETH_ALEN) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "FT: R0KH-ID points to self - no matching key available");
+ return -1;
+ }
key = r0kh->key;
key_len = sizeof(r0kh->key);
@@ -1486,7 +2019,7 @@
return -1;
}
- if (wpa_ft_rrb_build(key, key_len, req_enc, NULL, req_auth,
+ if (wpa_ft_rrb_build(key, key_len, req_enc, NULL, req_auth, NULL,
sm->wpa_auth->addr, FT_PACKET_R0KH_R1KH_PULL,
&packet, &packet_len) < 0)
return -1;
@@ -1512,11 +2045,43 @@
}
+int wpa_ft_store_pmk_fils(struct wpa_state_machine *sm,
+ const u8 *pmk_r0, const u8 *pmk_r0_name)
+{
+ int expires_in = sm->wpa_auth->conf.r0_key_lifetime;
+ struct vlan_description vlan;
+ const u8 *identity, *radius_cui;
+ size_t identity_len, radius_cui_len;
+ int session_timeout;
+ size_t pmk_r0_len = wpa_key_mgmt_sha384(sm->wpa_key_mgmt) ?
+ SHA384_MAC_LEN : PMK_LEN;
+
+ if (wpa_ft_get_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: vlan not available for STA " MACSTR,
+ MAC2STR(sm->addr));
+ return -1;
+ }
+
+ identity_len = wpa_ft_get_identity(sm->wpa_auth, sm->addr, &identity);
+ radius_cui_len = wpa_ft_get_radius_cui(sm->wpa_auth, sm->addr,
+ &radius_cui);
+ session_timeout = wpa_ft_get_session_timeout(sm->wpa_auth, sm->addr);
+
+ return wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_len,
+ pmk_r0_name, sm->pairwise, &vlan, expires_in,
+ session_timeout, identity, identity_len,
+ radius_cui, radius_cui_len);
+}
+
+
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
struct wpa_ptk *ptk)
{
- u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
- u8 pmk_r1[PMK_LEN];
+ u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
+ size_t pmk_r0_len = wpa_key_mgmt_sha384(sm->wpa_key_mgmt) ?
+ SHA384_MAC_LEN : PMK_LEN;
+ size_t pmk_r1_len = pmk_r0_len;
+ u8 pmk_r1[PMK_LEN_MAX];
u8 ptk_name[WPA_PMK_NAME_LEN];
const u8 *mdid = sm->wpa_auth->conf.mobility_domain;
const u8 *r0kh = sm->wpa_auth->conf.r0_key_holder;
@@ -1525,6 +2090,11 @@
const u8 *ssid = sm->wpa_auth->conf.ssid;
size_t ssid_len = sm->wpa_auth->conf.ssid_len;
int psk_local = sm->wpa_auth->conf.ft_psk_generate_local;
+ int expires_in = sm->wpa_auth->conf.r0_key_lifetime;
+ struct vlan_description vlan;
+ const u8 *identity, *radius_cui;
+ size_t identity_len, radius_cui_len;
+ int session_timeout;
if (sm->xxkey_len == 0) {
wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
@@ -1532,28 +2102,45 @@
return -1;
}
+ if (wpa_ft_get_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: vlan not available for STA " MACSTR,
+ MAC2STR(sm->addr));
+ return -1;
+ }
+
+ identity_len = wpa_ft_get_identity(sm->wpa_auth, sm->addr, &identity);
+ radius_cui_len = wpa_ft_get_radius_cui(sm->wpa_auth, sm->addr,
+ &radius_cui);
+ session_timeout = wpa_ft_get_session_timeout(sm->wpa_auth, sm->addr);
+
if (wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
r0kh, r0kh_len, sm->addr,
- pmk_r0, pmk_r0_name) < 0)
+ 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_LEN);
+ 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_name,
- sm->pairwise);
+ wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_len,
+ pmk_r0_name,
+ sm->pairwise, &vlan, expires_in,
+ session_timeout, identity, identity_len,
+ radius_cui, radius_cui_len);
- if (wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
+ 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_LEN);
+ 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,
- sm->pmk_r1_name, sm->pairwise);
+ wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, pmk_r1_len,
+ sm->pmk_r1_name, sm->pairwise, &vlan,
+ expires_in, session_timeout, identity,
+ identity_len, radius_cui, radius_cui_len);
- return wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
- sm->wpa_auth->addr, sm->pmk_r1_name,
+ return wpa_pmk_r1_to_ptk(pmk_r1, pmk_r1_len, sm->SNonce, sm->ANonce,
+ sm->addr, sm->wpa_auth->addr, sm->pmk_r1_name,
ptk, ptk_name, sm->wpa_key_mgmt, sm->pairwise);
}
@@ -1575,6 +2162,16 @@
const u8 *key;
size_t key_len;
u8 keybuf[32];
+ const u8 *kek;
+ size_t kek_len;
+
+ if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+ kek = sm->PTK.kek2;
+ kek_len = sm->PTK.kek2_len;
+ } else {
+ kek = sm->PTK.kek;
+ kek_len = sm->PTK.kek_len;
+ }
key_len = gsm->GTK_len;
if (key_len > sizeof(keybuf))
@@ -1613,8 +2210,10 @@
WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03);
subelem[4] = gsm->GTK_len;
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5);
- if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, key_len / 8, key,
- subelem + 13)) {
+ if (aes_wrap(kek, kek_len, key_len / 8, key, subelem + 13)) {
+ wpa_printf(MSG_DEBUG,
+ "FT: GTK subelem encryption failed: kek_len=%d",
+ (int) kek_len);
os_free(subelem);
return NULL;
}
@@ -1630,10 +2229,23 @@
u8 *subelem, *pos;
struct wpa_group *gsm = sm->group;
size_t subelem_len;
+ const u8 *kek;
+ size_t kek_len;
+ size_t igtk_len;
+
+ if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+ kek = sm->PTK.kek2;
+ kek_len = sm->PTK.kek2_len;
+ } else {
+ kek = sm->PTK.kek;
+ kek_len = sm->PTK.kek_len;
+ }
+
+ igtk_len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
/* Sub-elem ID[1] | Length[1] | KeyID[2] | IPN[6] | Key Length[1] |
* Key[16+8] */
- subelem_len = 1 + 1 + 2 + 6 + 1 + WPA_IGTK_LEN + 8;
+ subelem_len = 1 + 1 + 2 + 6 + 1 + igtk_len + 8;
subelem = os_zalloc(subelem_len);
if (subelem == NULL)
return NULL;
@@ -1645,9 +2257,12 @@
pos += 2;
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
pos += 6;
- *pos++ = WPA_IGTK_LEN;
- if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, WPA_IGTK_LEN / 8,
+ *pos++ = igtk_len;
+ if (aes_wrap(kek, kek_len, igtk_len / 8,
gsm->IGTK[gsm->GN_igtk - 4], pos)) {
+ wpa_printf(MSG_DEBUG,
+ "FT: IGTK subelem encryption failed: kek_len=%d",
+ (int) kek_len);
os_free(subelem);
return NULL;
}
@@ -1794,17 +2409,21 @@
const u8 *req_ies, size_t req_ies_len)
{
u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL;
+ u8 *fte_mic, *elem_count;
size_t mdie_len, ftie_len, rsnie_len = 0, r0kh_id_len, subelem_len = 0;
int res;
struct wpa_auth_config *conf;
- struct rsn_ftie *_ftie;
struct wpa_ft_ies parse;
u8 *ric_start;
u8 *anonce, *snonce;
+ const u8 *kck;
+ size_t kck_len;
+ int use_sha384;
if (sm == NULL)
return pos;
+ use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
conf = &sm->wpa_auth->conf;
if (!wpa_key_mgmt_ft(sm->wpa_key_mgmt))
@@ -1812,14 +2431,28 @@
end = pos + max_len;
- if (auth_alg == WLAN_AUTH_FT) {
+ if (auth_alg == WLAN_AUTH_FT ||
+ ((auth_alg == WLAN_AUTH_FILS_SK ||
+ auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ auth_alg == WLAN_AUTH_FILS_PK) &&
+ (sm->wpa_key_mgmt & (WPA_KEY_MGMT_FT_FILS_SHA256 |
+ WPA_KEY_MGMT_FT_FILS_SHA384)))) {
+ if (!sm->pmk_r1_name_valid) {
+ wpa_printf(MSG_ERROR,
+ "FT: PMKR1Name is not valid for Assoc Resp RSNE");
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name for Assoc Resp RSNE",
+ sm->pmk_r1_name, WPA_PMK_NAME_LEN);
/*
* RSN (only present if this is a Reassociation Response and
- * part of a fast BSS transition)
+ * part of a fast BSS transition; or if this is a
+ * (Re)Association Response frame during an FT initial mobility
+ * domain association using FILS)
*/
res = wpa_write_rsn_ie(conf, pos, end - pos, sm->pmk_r1_name);
if (res < 0)
- return pos;
+ return NULL;
rsnie = pos;
rsnie_len = res;
pos += res;
@@ -1828,7 +2461,7 @@
/* Mobility Domain Information */
res = wpa_write_mdie(conf, pos, end - pos);
if (res < 0)
- return pos;
+ return NULL;
mdie = pos;
mdie_len = res;
pos += res;
@@ -1836,6 +2469,11 @@
/* Fast BSS Transition Information */
if (auth_alg == WLAN_AUTH_FT) {
subelem = wpa_ft_gtk_subelem(sm, &subelem_len);
+ if (!subelem) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Failed to add GTK subelement");
+ return NULL;
+ }
r0kh_id = sm->r0kh_id;
r0kh_id_len = sm->r0kh_id_len;
anonce = sm->ANonce;
@@ -1847,14 +2485,16 @@
u8 *nbuf;
igtk = wpa_ft_igtk_subelem(sm, &igtk_len);
if (igtk == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Failed to add IGTK subelement");
os_free(subelem);
- return pos;
+ return NULL;
}
nbuf = os_realloc(subelem, subelem_len + igtk_len);
if (nbuf == NULL) {
os_free(subelem);
os_free(igtk);
- return pos;
+ return NULL;
}
subelem = nbuf;
os_memcpy(subelem + subelem_len, igtk, igtk_len);
@@ -1862,50 +2502,101 @@
os_free(igtk);
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ if (wpa_auth_uses_ocv(sm)) {
+ struct wpa_channel_info ci;
+ u8 *nbuf, *ocipos;
+
+ if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element");
+ os_free(subelem);
+ return NULL;
+ }
+
+ subelem_len += 2 + OCV_OCI_LEN;
+ nbuf = os_realloc(subelem, subelem_len);
+ if (!nbuf) {
+ os_free(subelem);
+ return NULL;
+ }
+ subelem = nbuf;
+
+ ocipos = subelem + subelem_len - 2 - OCV_OCI_LEN;
+ *ocipos++ = FTIE_SUBELEM_OCI;
+ *ocipos++ = OCV_OCI_LEN;
+ if (ocv_insert_oci(&ci, &ocipos) < 0) {
+ os_free(subelem);
+ return NULL;
+ }
+ }
+#endif /* CONFIG_OCV */
} else {
r0kh_id = conf->r0_key_holder;
r0kh_id_len = conf->r0_key_holder_len;
anonce = NULL;
snonce = NULL;
}
- res = wpa_write_ftie(conf, r0kh_id, r0kh_id_len, anonce, snonce, pos,
- end - pos, subelem, subelem_len);
+ res = wpa_write_ftie(conf, use_sha384, r0kh_id, r0kh_id_len,
+ anonce, snonce, pos, end - pos,
+ subelem, subelem_len);
os_free(subelem);
if (res < 0)
- return pos;
+ return NULL;
ftie = pos;
ftie_len = res;
pos += res;
- _ftie = (struct rsn_ftie *) (ftie + 2);
+ if (use_sha384) {
+ struct rsn_ftie_sha384 *_ftie =
+ (struct rsn_ftie_sha384 *) (ftie + 2);
+
+ fte_mic = _ftie->mic;
+ elem_count = &_ftie->mic_control[1];
+ } else {
+ struct rsn_ftie *_ftie = (struct rsn_ftie *) (ftie + 2);
+
+ fte_mic = _ftie->mic;
+ elem_count = &_ftie->mic_control[1];
+ }
if (auth_alg == WLAN_AUTH_FT)
- _ftie->mic_control[1] = 3; /* Information element count */
+ *elem_count = 3; /* Information element count */
ric_start = pos;
- if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse) == 0 && parse.ric) {
+ if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse, use_sha384) == 0
+ && parse.ric) {
pos = wpa_ft_process_ric(sm, pos, end, parse.ric,
parse.ric_len);
if (auth_alg == WLAN_AUTH_FT)
- _ftie->mic_control[1] +=
+ *elem_count +=
ieee802_11_ie_count(ric_start,
pos - ric_start);
}
if (ric_start == pos)
ric_start = NULL;
+ if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+ kck = sm->PTK.kck2;
+ kck_len = sm->PTK.kck2_len;
+ } else {
+ kck = sm->PTK.kck;
+ kck_len = sm->PTK.kck_len;
+ }
if (auth_alg == WLAN_AUTH_FT &&
- wpa_ft_mic(sm->PTK.kck, sm->PTK.kck_len, sm->addr,
- sm->wpa_auth->addr, 6,
+ wpa_ft_mic(kck, kck_len, sm->addr, sm->wpa_auth->addr, 6,
mdie, mdie_len, ftie, ftie_len,
rsnie, rsnie_len,
ric_start, ric_start ? pos - ric_start : 0,
- _ftie->mic) < 0)
+ fte_mic) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
+ return NULL;
+ }
os_free(sm->assoc_resp_ftie);
sm->assoc_resp_ftie = os_malloc(ftie_len);
- if (sm->assoc_resp_ftie)
- os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len);
+ if (!sm->assoc_resp_ftie)
+ return NULL;
+ os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len);
return pos;
}
@@ -1964,7 +2655,12 @@
/* Derive PMK-R1 from PSK, check all available PSK */
static int wpa_ft_psk_pmk_r1(struct wpa_state_machine *sm,
const u8 *req_pmk_r1_name,
- u8 *out_pmk_r1, int *out_pairwise)
+ u8 *out_pmk_r1, int *out_pairwise,
+ struct vlan_description *out_vlan,
+ const u8 **out_identity, size_t *out_identity_len,
+ const u8 **out_radius_cui,
+ size_t *out_radius_cui_len,
+ int *out_session_timeout)
{
const u8 *pmk = NULL;
u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
@@ -1988,9 +2684,9 @@
if (wpa_derive_pmk_r0(pmk, PMK_LEN, ssid, ssid_len, mdid, r0kh,
r0kh_len, sm->addr,
- pmk_r0, pmk_r0_name) < 0 ||
- wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
- pmk_r1, pmk_r1_name) < 0 ||
+ pmk_r0, pmk_r0_name, 0) < 0 ||
+ wpa_derive_pmk_r1(pmk_r0, PMK_LEN, pmk_r0_name, r1kh,
+ sm->addr, pmk_r1, pmk_r1_name) < 0 ||
os_memcmp_const(pmk_r1_name, req_pmk_r1_name,
WPA_PMK_NAME_LEN) != 0)
continue;
@@ -2001,6 +2697,30 @@
os_memcpy(out_pmk_r1, pmk_r1, PMK_LEN);
if (out_pairwise)
*out_pairwise = pairwise;
+ os_memcpy(sm->PMK, pmk, PMK_LEN);
+ sm->pmk_len = PMK_LEN;
+ if (out_vlan &&
+ wpa_ft_get_vlan(sm->wpa_auth, sm->addr, out_vlan) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: vlan not available for STA "
+ MACSTR, MAC2STR(sm->addr));
+ return -1;
+ }
+
+ if (out_identity && out_identity_len) {
+ *out_identity_len = wpa_ft_get_identity(
+ sm->wpa_auth, sm->addr, out_identity);
+ }
+
+ if (out_radius_cui && out_radius_cui_len) {
+ *out_radius_cui_len = wpa_ft_get_radius_cui(
+ sm->wpa_auth, sm->addr, out_radius_cui);
+ }
+
+ if (out_session_timeout) {
+ *out_session_timeout = wpa_ft_get_session_timeout(
+ sm->wpa_auth, sm->addr);
+ }
+
return 0;
}
@@ -2029,6 +2749,10 @@
}
if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
+#ifdef CONFIG_SHA384
+ else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+#endif /* CONFIG_SHA384 */
else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
#ifdef CONFIG_FILS
@@ -2050,20 +2774,99 @@
}
+static int wpa_ft_local_derive_pmk_r1(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm,
+ const u8 *r0kh_id, size_t r0kh_id_len,
+ const u8 *req_pmk_r0_name,
+ const u8 *req_pmk_r1_name,
+ u8 *out_pmk_r1, int *out_pairwise,
+ struct vlan_description *vlan,
+ const u8 **identity, size_t *identity_len,
+ const u8 **radius_cui,
+ size_t *radius_cui_len,
+ int *out_session_timeout)
+{
+ struct wpa_auth_config *conf = &wpa_auth->conf;
+ const struct wpa_ft_pmk_r0_sa *r0;
+ u8 pmk_r1_name[WPA_PMK_NAME_LEN];
+ int expires_in = 0;
+ int session_timeout = 0;
+ struct os_reltime now;
+
+ if (conf->r0_key_holder_len != r0kh_id_len ||
+ os_memcmp(conf->r0_key_holder, r0kh_id, conf->r0_key_holder_len) !=
+ 0)
+ return -1; /* not our R0KH-ID */
+
+ wpa_printf(MSG_DEBUG, "FT: STA R0KH-ID matching local configuration");
+ if (wpa_ft_fetch_pmk_r0(sm->wpa_auth, sm->addr, req_pmk_r0_name, &r0) <
+ 0)
+ return -1; /* no matching PMKR0Name in local cache */
+
+ wpa_printf(MSG_DEBUG, "FT: Requested PMKR0Name found in local cache");
+
+ if (wpa_derive_pmk_r1(r0->pmk_r0, r0->pmk_r0_len, r0->pmk_r0_name,
+ 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)
+ expires_in = r0->expiration - now.sec;
+
+ if (r0->session_timeout)
+ session_timeout = r0->session_timeout - now.sec;
+
+ wpa_ft_store_pmk_r1(wpa_auth, sm->addr, out_pmk_r1, r0->pmk_r0_len,
+ pmk_r1_name,
+ sm->pairwise, r0->vlan, expires_in, session_timeout,
+ r0->identity, r0->identity_len,
+ r0->radius_cui, r0->radius_cui_len);
+
+ *out_pairwise = sm->pairwise;
+ if (vlan) {
+ if (r0->vlan)
+ *vlan = *r0->vlan;
+ else
+ os_memset(vlan, 0, sizeof(*vlan));
+ }
+
+ if (identity && identity_len) {
+ *identity = r0->identity;
+ *identity_len = r0->identity_len;
+ }
+
+ if (radius_cui && radius_cui_len) {
+ *radius_cui = r0->radius_cui;
+ *radius_cui_len = r0->radius_cui_len;
+ }
+
+ *out_session_timeout = session_timeout;
+
+ return 0;
+}
+
+
static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
const u8 *ies, size_t ies_len,
u8 **resp_ies, size_t *resp_ies_len)
{
struct rsn_mdie *mdie;
- struct rsn_ftie *ftie;
- u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN];
+ u8 pmk_r1[PMK_LEN_MAX], pmk_r1_name[WPA_PMK_NAME_LEN];
u8 ptk_name[WPA_PMK_NAME_LEN];
struct wpa_auth_config *conf;
struct wpa_ft_ies parse;
size_t buflen;
int ret;
u8 *pos, *end;
- int pairwise;
+ int pairwise, session_timeout = 0;
+ struct vlan_description vlan;
+ const u8 *identity, *radius_cui;
+ size_t identity_len = 0, radius_cui_len = 0;
+ int use_sha384;
+ size_t pmk_r1_len;
*resp_ies = NULL;
*resp_ies_len = 0;
@@ -2074,10 +2877,12 @@
wpa_hexdump(MSG_DEBUG, "FT: Received authentication frame IEs",
ies, ies_len);
- if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+ if (wpa_ft_parse_ies(ies, ies_len, &parse, -1)) {
wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
+ use_sha384 = wpa_key_mgmt_sha384(parse.key_mgmt);
+ pmk_r1_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
mdie = (struct rsn_mdie *) parse.mdie;
if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
@@ -2088,13 +2893,27 @@
return WLAN_STATUS_INVALID_MDIE;
}
- ftie = (struct rsn_ftie *) parse.ftie;
- if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
- wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
- return WLAN_STATUS_INVALID_FTIE;
- }
+ if (use_sha384) {
+ struct rsn_ftie_sha384 *ftie;
- os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN);
+ ftie = (struct rsn_ftie_sha384 *) parse.ftie;
+ if (!ftie || parse.ftie_len < sizeof(*ftie)) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+ return WLAN_STATUS_INVALID_FTIE;
+ }
+
+ os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN);
+ } else {
+ struct rsn_ftie *ftie;
+
+ ftie = (struct rsn_ftie *) parse.ftie;
+ if (!ftie || parse.ftie_len < sizeof(*ftie)) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+ return WLAN_STATUS_INVALID_FTIE;
+ }
+
+ os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN);
+ }
if (parse.r0kh_id == NULL) {
wpa_printf(MSG_DEBUG, "FT: Invalid FTIE - no R0KH-ID");
@@ -2118,17 +2937,38 @@
parse.rsn_pmkid, WPA_PMK_NAME_LEN);
if (wpa_derive_pmk_r1_name(parse.rsn_pmkid,
sm->wpa_auth->conf.r1_key_holder, sm->addr,
- pmk_r1_name) < 0)
+ 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)) {
- if (wpa_ft_psk_pmk_r1(sm, pmk_r1_name, pmk_r1, &pairwise) < 0)
+ if (wpa_ft_psk_pmk_r1(sm, pmk_r1_name, pmk_r1, &pairwise,
+ &vlan, &identity, &identity_len,
+ &radius_cui, &radius_cui_len,
+ &session_timeout) < 0)
return WLAN_STATUS_INVALID_PMKID;
+ wpa_printf(MSG_DEBUG,
+ "FT: Generated PMK-R1 for FT-PSK locally");
} else if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name,
- pmk_r1, &pairwise) < 0) {
+ pmk_r1, &pmk_r1_len, &pairwise, &vlan,
+ &identity, &identity_len, &radius_cui,
+ &radius_cui_len, &session_timeout) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "FT: No PMK-R1 available in local cache for the requested PMKR1Name");
+ if (wpa_ft_local_derive_pmk_r1(sm->wpa_auth, sm,
+ parse.r0kh_id, parse.r0kh_id_len,
+ parse.rsn_pmkid,
+ pmk_r1_name, pmk_r1, &pairwise,
+ &vlan, &identity, &identity_len,
+ &radius_cui, &radius_cui_len,
+ &session_timeout) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Generated PMK-R1 based on local PMK-R0");
+ goto pmk_r1_derived;
+ }
+
if (wpa_ft_pull_pmk_r1(sm, ies, ies_len, parse.rsn_pmkid) < 0) {
wpa_printf(MSG_DEBUG,
"FT: Did not have matching PMK-R1 and either unknown or blocked R0KH-ID or NAK from R0KH");
@@ -2136,9 +2976,12 @@
}
return -1; /* Status pending */
+ } else {
+ wpa_printf(MSG_DEBUG, "FT: Found PMKR1Name from local cache");
}
- wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, PMK_LEN);
+pmk_r1_derived:
+ wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, pmk_r1_len);
sm->pmk_r1_name_valid = 1;
os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
@@ -2153,8 +2996,8 @@
wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
sm->ANonce, WPA_NONCE_LEN);
- if (wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
- sm->wpa_auth->addr, pmk_r1_name,
+ if (wpa_pmk_r1_to_ptk(pmk_r1, pmk_r1_len, sm->SNonce, sm->ANonce,
+ sm->addr, sm->wpa_auth->addr, pmk_r1_name,
&sm->PTK, ptk_name, sm->wpa_key_mgmt,
pairwise) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -2164,6 +3007,19 @@
sm->tk_already_set = FALSE;
wpa_ft_install_ptk(sm);
+ if (wpa_ft_set_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to configure VLAN");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ if (wpa_ft_set_identity(sm->wpa_auth, sm->addr,
+ identity, identity_len) < 0 ||
+ wpa_ft_set_radius_cui(sm->wpa_auth, sm->addr,
+ radius_cui, radius_cui_len) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to configure identity/CUI");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ wpa_ft_set_session_timeout(sm->wpa_auth, sm->addr, session_timeout);
+
buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
2 + FT_R1KH_ID_LEN + 200;
*resp_ies = os_zalloc(buflen);
@@ -2183,7 +3039,7 @@
goto fail;
pos += ret;
- ret = wpa_write_ftie(conf, parse.r0kh_id, parse.r0kh_id_len,
+ ret = wpa_write_ftie(conf, use_sha384, parse.r0kh_id, parse.r0kh_id_len,
sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0);
if (ret < 0)
goto fail;
@@ -2247,17 +3103,23 @@
{
struct wpa_ft_ies parse;
struct rsn_mdie *mdie;
- struct rsn_ftie *ftie;
u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
size_t mic_len = 16;
unsigned int count;
+ const u8 *kck;
+ size_t kck_len;
+ int use_sha384;
+ const u8 *anonce, *snonce, *fte_mic;
+ u8 fte_elem_count;
if (sm == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
+
wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len);
- if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+ if (wpa_ft_parse_ies(ies, ies_len, &parse, use_sha384) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
@@ -2288,25 +3150,47 @@
return WLAN_STATUS_INVALID_MDIE;
}
- ftie = (struct rsn_ftie *) parse.ftie;
- if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
- wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
- return WLAN_STATUS_INVALID_FTIE;
+ if (use_sha384) {
+ struct rsn_ftie_sha384 *ftie;
+
+ ftie = (struct rsn_ftie_sha384 *) parse.ftie;
+ if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+ return WLAN_STATUS_INVALID_FTIE;
+ }
+
+ anonce = ftie->anonce;
+ snonce = ftie->snonce;
+ fte_elem_count = ftie->mic_control[1];
+ fte_mic = ftie->mic;
+ } else {
+ struct rsn_ftie *ftie;
+
+ ftie = (struct rsn_ftie *) parse.ftie;
+ if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+ return WLAN_STATUS_INVALID_FTIE;
+ }
+
+ anonce = ftie->anonce;
+ snonce = ftie->snonce;
+ fte_elem_count = ftie->mic_control[1];
+ fte_mic = ftie->mic;
}
- if (os_memcmp(ftie->snonce, sm->SNonce, WPA_NONCE_LEN) != 0) {
+ if (os_memcmp(snonce, sm->SNonce, WPA_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
- ftie->snonce, WPA_NONCE_LEN);
+ snonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
sm->SNonce, WPA_NONCE_LEN);
return WLAN_STATUS_INVALID_FTIE;
}
- if (os_memcmp(ftie->anonce, sm->ANonce, WPA_NONCE_LEN) != 0) {
+ if (os_memcmp(anonce, sm->ANonce, WPA_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE");
wpa_hexdump(MSG_DEBUG, "FT: Received ANonce",
- ftie->anonce, WPA_NONCE_LEN);
+ anonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce",
sm->ANonce, WPA_NONCE_LEN);
return WLAN_STATUS_INVALID_FTIE;
@@ -2357,15 +3241,21 @@
count = 3;
if (parse.ric)
count += ieee802_11_ie_count(parse.ric, parse.ric_len);
- if (ftie->mic_control[1] != count) {
+ if (fte_elem_count != count) {
wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
"Control: received %u expected %u",
- ftie->mic_control[1], count);
+ fte_elem_count, count);
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- if (wpa_ft_mic(sm->PTK.kck, sm->PTK.kck_len, sm->addr,
- sm->wpa_auth->addr, 5,
+ if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+ kck = sm->PTK.kck2;
+ kck_len = sm->PTK.kck2_len;
+ } else {
+ kck = sm->PTK.kck;
+ kck_len = sm->PTK.kck_len;
+ }
+ if (wpa_ft_mic(kck, kck_len, sm->addr, sm->wpa_auth->addr, 5,
parse.mdie - 2, parse.mdie_len + 2,
parse.ftie - 2, parse.ftie_len + 2,
parse.rsn - 2, parse.rsn_len + 2,
@@ -2375,12 +3265,12 @@
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- if (os_memcmp_const(mic, ftie->mic, mic_len) != 0) {
+ if (os_memcmp_const(mic, fte_mic, mic_len) != 0) {
wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
wpa_printf(MSG_DEBUG, "FT: addr=" MACSTR " auth_addr=" MACSTR,
MAC2STR(sm->addr), MAC2STR(sm->wpa_auth->addr));
wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC",
- ftie->mic, mic_len);
+ fte_mic, mic_len);
wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, mic_len);
wpa_hexdump(MSG_MSGDUMP, "FT: MDIE",
parse.mdie - 2, parse.mdie_len + 2);
@@ -2391,6 +3281,32 @@
return WLAN_STATUS_INVALID_FTIE;
}
+#ifdef CONFIG_OCV
+ if (wpa_auth_uses_ocv(sm)) {
+ struct wpa_channel_info ci;
+ int tx_chanwidth;
+ int tx_seg1_idx;
+
+ if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info to validate received OCI in (Re)Assoc Request");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ if (get_sta_tx_parameters(sm,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx, &tx_chanwidth,
+ &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;
+ }
+ }
+#endif /* CONFIG_OCV */
+
return WLAN_STATUS_SUCCESS;
}
@@ -2579,33 +3495,65 @@
const u8 *src_addr, u8 type,
u8 **packet, size_t *packet_len)
{
- u8 pmk_r1[PMK_LEN];
+ u8 pmk_r1[PMK_LEN_MAX];
+ size_t pmk_r1_len = pmk_r0->pmk_r0_len;
u8 pmk_r1_name[WPA_PMK_NAME_LEN];
u8 f_pairwise[sizeof(le16)];
+ u8 f_expires_in[sizeof(le16)];
+ u8 f_session_timeout[sizeof(le32)];
+ int expires_in;
+ int session_timeout;
+ struct os_reltime now;
int ret;
struct tlv_list sess_tlv[] = {
- { .type = FT_RRB_PMK_R1, .len = sizeof(pmk_r1),
+ { .type = FT_RRB_PMK_R1, .len = pmk_r1_len,
.data = pmk_r1 },
{ .type = FT_RRB_PMK_R1_NAME, .len = sizeof(pmk_r1_name),
.data = pmk_r1_name },
{ .type = FT_RRB_PAIRWISE, .len = sizeof(f_pairwise),
.data = f_pairwise },
+ { .type = FT_RRB_EXPIRES_IN, .len = sizeof(f_expires_in),
+ .data = f_expires_in },
+ { .type = FT_RRB_IDENTITY, .len = pmk_r0->identity_len,
+ .data = pmk_r0->identity },
+ { .type = FT_RRB_RADIUS_CUI, .len = pmk_r0->radius_cui_len,
+ .data = pmk_r0->radius_cui },
+ { .type = FT_RRB_SESSION_TIMEOUT,
+ .len = sizeof(f_session_timeout),
+ .data = f_session_timeout },
{ .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
};
- if (!pmk_r0)
- return wpa_ft_rrb_build(key, key_len, tlvs, NULL, tlv_auth,
- src_addr, type, packet, packet_len);
-
- if (wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh_id,
+ 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", pmk_r1, PMK_LEN);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
+ 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);
+ if (pmk_r0->expiration > now.sec)
+ expires_in = pmk_r0->expiration - now.sec;
+ else if (pmk_r0->expiration)
+ expires_in = 1;
+ else
+ expires_in = 0;
+ WPA_PUT_LE16(f_expires_in, expires_in);
+
+ if (pmk_r0->session_timeout > now.sec)
+ session_timeout = pmk_r0->session_timeout - now.sec;
+ else if (pmk_r0->session_timeout)
+ session_timeout = 1;
+ else
+ session_timeout = 0;
+ WPA_PUT_LE32(f_session_timeout, session_timeout);
+
ret = wpa_ft_rrb_build(key, key_len, tlvs, sess_tlv, tlv_auth,
- src_addr, type, packet, packet_len);
+ pmk_r0->vlan, src_addr, type,
+ packet, packet_len);
os_memset(pmk_r1, 0, sizeof(pmk_r1));
@@ -2736,13 +3684,18 @@
resp_auth[4].len = 0;
resp_auth[4].data = NULL;
- if (wpa_ft_fetch_pmk_r0(wpa_auth, f_s1kh_id, f_pmk_r0_name, &r0) < 0)
+ if (wpa_ft_fetch_pmk_r0(wpa_auth, f_s1kh_id, f_pmk_r0_name, &r0) < 0) {
wpa_printf(MSG_DEBUG, "FT: No matching PMK-R0-Name found");
-
- ret = wpa_ft_rrb_build_r0(key, key_len, resp, r0, f_r1kh_id, f_s1kh_id,
- resp_auth, wpa_auth->addr,
- FT_PACKET_R0KH_R1KH_RESP,
- &packet, &packet_len);
+ ret = wpa_ft_rrb_build(key, key_len, resp, NULL, resp_auth,
+ NULL, wpa_auth->addr,
+ FT_PACKET_R0KH_R1KH_RESP,
+ &packet, &packet_len);
+ } else {
+ ret = wpa_ft_rrb_build_r0(key, key_len, resp, r0, f_r1kh_id,
+ f_s1kh_id, resp_auth, wpa_auth->addr,
+ FT_PACKET_R0KH_R1KH_RESP,
+ &packet, &packet_len);
+ }
if (!ret)
wpa_ft_rrb_oui_send(wpa_auth, src_addr,
@@ -2780,10 +3733,20 @@
int seq_ret;
const u8 *f_r1kh_id, *f_s1kh_id, *f_r0kh_id;
const u8 *f_pmk_r1_name, *f_pairwise, *f_pmk_r1;
+ const u8 *f_expires_in;
size_t f_r1kh_id_len, f_s1kh_id_len, f_r0kh_id_len;
+ const u8 *f_identity, *f_radius_cui;
+ const u8 *f_session_timeout;
size_t f_pmk_r1_name_len, f_pairwise_len, f_pmk_r1_len;
+ size_t f_expires_in_len;
+ size_t f_identity_len, f_radius_cui_len;
+ size_t f_session_timeout_len;
int pairwise;
int ret = -1;
+ int expires_in;
+ int session_timeout;
+ struct vlan_description vlan;
+ size_t pmk_r1_len;
RRB_GET_AUTH(FT_RRB_R0KH_ID, r0kh_id, msgtype, -1);
wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID", f_r0kh_id, f_r0kh_id_len);
@@ -2862,13 +3825,58 @@
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name",
f_pmk_r1_name, WPA_PMK_NAME_LEN);
- RRB_GET(FT_RRB_PMK_R1, pmk_r1, msgtype, PMK_LEN);
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f_pmk_r1, PMK_LEN);
+ pmk_r1_len = PMK_LEN;
+ if (wpa_ft_rrb_get_tlv(plain, plain_len, FT_RRB_PMK_R1, &f_pmk_r1_len,
+ &f_pmk_r1) == 0 &&
+ (f_pmk_r1_len == PMK_LEN || f_pmk_r1_len == SHA384_MAC_LEN))
+ pmk_r1_len = f_pmk_r1_len;
+ RRB_GET(FT_RRB_PMK_R1, pmk_r1, msgtype, pmk_r1_len);
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f_pmk_r1, pmk_r1_len);
pairwise = WPA_GET_LE16(f_pairwise);
- if (wpa_ft_store_pmk_r1(wpa_auth, f_s1kh_id, f_pmk_r1, f_pmk_r1_name,
- pairwise) < 0)
+ RRB_GET_OPTIONAL(FT_RRB_EXPIRES_IN, expires_in, msgtype,
+ sizeof(le16));
+ if (f_expires_in)
+ expires_in = WPA_GET_LE16(f_expires_in);
+ else
+ expires_in = 0;
+
+ wpa_printf(MSG_DEBUG, "FT: PMK-R1 %s - expires_in=%d", msgtype,
+ expires_in);
+
+ if (wpa_ft_rrb_get_tlv_vlan(plain, plain_len, &vlan) < 0) {
+ wpa_printf(MSG_DEBUG, "FT: Cannot parse vlan");
+ wpa_ft_rrb_dump(plain, plain_len);
+ goto out;
+ }
+
+ wpa_printf(MSG_DEBUG, "FT: vlan %d%s",
+ le_to_host16(vlan.untagged), vlan.tagged[0] ? "+" : "");
+
+ RRB_GET_OPTIONAL(FT_RRB_IDENTITY, identity, msgtype, -1);
+ if (f_identity)
+ wpa_hexdump_ascii(MSG_DEBUG, "FT: Identity", f_identity,
+ f_identity_len);
+
+ RRB_GET_OPTIONAL(FT_RRB_RADIUS_CUI, radius_cui, msgtype, -1);
+ if (f_radius_cui)
+ wpa_hexdump_ascii(MSG_DEBUG, "FT: CUI", f_radius_cui,
+ f_radius_cui_len);
+
+ RRB_GET_OPTIONAL(FT_RRB_SESSION_TIMEOUT, session_timeout, msgtype,
+ sizeof(le32));
+ if (f_session_timeout)
+ session_timeout = WPA_GET_LE32(f_session_timeout);
+ else
+ session_timeout = 0;
+ wpa_printf(MSG_DEBUG, "FT: session_timeout %d", session_timeout);
+
+ if (wpa_ft_store_pmk_r1(wpa_auth, f_s1kh_id, f_pmk_r1, pmk_r1_len,
+ f_pmk_r1_name,
+ pairwise, &vlan, expires_in, session_timeout,
+ f_identity, f_identity_len, f_radius_cui,
+ f_radius_cui_len) < 0)
goto out;
ret = 0;
@@ -3178,7 +4186,7 @@
seq_resp_auth[4].len = 0;
seq_resp_auth[4].data = NULL;
- if (wpa_ft_rrb_build(key, key_len, NULL, NULL, seq_resp_auth,
+ if (wpa_ft_rrb_build(key, key_len, NULL, NULL, seq_resp_auth, NULL,
wpa_auth->addr, FT_PACKET_R0KH_R1KH_SEQ_RESP,
&packet, &packet_len) < 0)
goto out;
@@ -3424,6 +4432,7 @@
wpa_printf(MSG_DEBUG, "FT: RRB-OUI received frame from remote AP "
MACSTR, MAC2STR(src_addr));
wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame - oui_suffix=%d", oui_suffix);
+ wpa_hexdump(MSG_MSGDUMP, "FT: RRB frame payload", data, data_len);
if (is_multicast_ether_addr(src_addr)) {
wpa_printf(MSG_DEBUG,
@@ -3452,8 +4461,10 @@
}
auth = data + sizeof(u16);
+ wpa_hexdump(MSG_MSGDUMP, "FT: Authenticated payload", auth, alen);
enc = data + sizeof(u16) + alen;
elen = data_len - sizeof(u16) - alen;
+ wpa_hexdump(MSG_MSGDUMP, "FT: Encrypted payload", enc, elen);
switch (oui_suffix) {
case FT_PACKET_R0KH_R1KH_PULL:
@@ -3527,7 +4538,8 @@
void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr)
{
- struct wpa_ft_pmk_r0_sa *r0;
+ struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
+ struct wpa_ft_pmk_r0_sa *r0, *r0found = NULL;
struct ft_remote_r1kh *r1kh;
if (!wpa_auth->conf.pmk_r1_push)
@@ -3535,13 +4547,14 @@
if (!wpa_auth->conf.r1kh_list)
return;
- r0 = wpa_auth->ft_pmk_cache->pmk_r0;
- while (r0) {
- if (os_memcmp(r0->spa, addr, ETH_ALEN) == 0)
+ dl_list_for_each(r0, &cache->pmk_r0, struct wpa_ft_pmk_r0_sa, list) {
+ if (os_memcmp(r0->spa, addr, ETH_ALEN) == 0) {
+ r0found = r0;
break;
- r0 = r0->next;
+ }
}
+ r0 = r0found;
if (r0 == NULL || r0->pmk_r1_pushed)
return;
r0->pmk_r1_pushed = 1;
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 98133a0..45172c6 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -27,6 +27,7 @@
#include "tkip_countermeasures.h"
#include "ap_drv_ops.h"
#include "ap_config.h"
+#include "ieee802_11.h"
#include "pmksa_cache_auth.h"
#include "wpa_auth.h"
#include "wpa_auth_glue.h"
@@ -55,10 +56,14 @@
wconf->wmm_enabled = conf->wmm_enabled;
wconf->wmm_uapsd = conf->wmm_uapsd;
wconf->disable_pmksa_caching = conf->disable_pmksa_caching;
+#ifdef CONFIG_OCV
+ wconf->ocv = conf->ocv;
+#endif /* CONFIG_OCV */
wconf->okc = conf->okc;
#ifdef CONFIG_IEEE80211W
wconf->ieee80211w = conf->ieee80211w;
wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
+ wconf->sae_require_mfp = conf->sae_require_mfp;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R_AP
wconf->ssid_len = conf->ssid.ssid_len;
@@ -75,6 +80,7 @@
}
os_memcpy(wconf->r1_key_holder, conf->r1_key_holder, FT_R1KH_ID_LEN);
wconf->r0_key_lifetime = conf->r0_key_lifetime;
+ wconf->r1_max_key_lifetime = conf->r1_max_key_lifetime;
wconf->reassociation_deadline = conf->reassociation_deadline;
wconf->rkh_pos_timeout = conf->rkh_pos_timeout;
wconf->rkh_neg_timeout = conf->rkh_neg_timeout;
@@ -240,12 +246,15 @@
static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
const u8 *p2p_dev_addr,
- const u8 *prev_psk, size_t *psk_len)
+ const u8 *prev_psk, size_t *psk_len,
+ int *vlan_id)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = ap_get_sta(hapd, addr);
const u8 *psk;
+ if (vlan_id)
+ *vlan_id = 0;
if (psk_len)
*psk_len = PMK_LEN;
@@ -281,7 +290,8 @@
}
#endif /* CONFIG_OWE */
- psk = hostapd_get_psk(hapd->conf, addr, p2p_dev_addr, prev_psk);
+ psk = hostapd_get_psk(hapd->conf, addr, p2p_dev_addr, prev_psk,
+ vlan_id);
/*
* This is about to iterate over all psks, prev_psk gives the last
* returned psk which should not be returned again.
@@ -289,6 +299,9 @@
*/
if (sta && sta->psk && !psk) {
struct hostapd_sta_wpa_psk_short *pos;
+
+ if (vlan_id)
+ *vlan_id = 0;
psk = sta->psk->psk;
for (pos = sta->psk; pos; pos = pos->next) {
if (pos->is_passphrase) {
@@ -364,10 +377,10 @@
sta->last_tk_len = key_len;
}
#ifdef CONFIG_IEEE80211W
- } else if (alg == WPA_CIPHER_AES_128_CMAC ||
- alg == WPA_CIPHER_BIP_GMAC_128 ||
- alg == WPA_CIPHER_BIP_GMAC_256 ||
- alg == WPA_CIPHER_BIP_CMAC_256) {
+ } else if (alg == WPA_ALG_IGTK ||
+ alg == WPA_ALG_BIP_GMAC_128 ||
+ alg == WPA_ALG_BIP_GMAC_256 ||
+ alg == WPA_ALG_BIP_CMAC_256) {
hapd->last_igtk_alg = alg;
hapd->last_igtk_key_idx = idx;
if (key)
@@ -774,6 +787,74 @@
}
+static int hostapd_channel_info(void *ctx, struct wpa_channel_info *ci)
+{
+ struct hostapd_data *hapd = ctx;
+
+ return hostapd_drv_channel_info(hapd, ci);
+}
+
+
+static int hostapd_wpa_auth_update_vlan(void *ctx, const u8 *addr, int vlan_id)
+{
+#ifndef CONFIG_NO_VLAN
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+ struct vlan_description vlan_desc;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta)
+ return -1;
+
+ os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+ vlan_desc.notempty = 1;
+ vlan_desc.untagged = vlan_id;
+ if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
+ wpa_printf(MSG_INFO, "Invalid VLAN ID %d in wpa_psk_file",
+ vlan_id);
+ return -1;
+ }
+
+ if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0) {
+ wpa_printf(MSG_INFO,
+ "Failed to assign VLAN ID %d from wpa_psk_file to "
+ MACSTR, vlan_id, MAC2STR(sta->addr));
+ return -1;
+ }
+
+ wpa_printf(MSG_INFO,
+ "Assigned VLAN ID %d from wpa_psk_file to " MACSTR,
+ vlan_id, MAC2STR(sta->addr));
+ if ((sta->flags & WLAN_STA_ASSOC) &&
+ ap_sta_bind_vlan(hapd, sta) < 0)
+ return -1;
+#endif /* CONFIG_NO_VLAN */
+
+ return 0;
+}
+
+
+#ifdef CONFIG_OCV
+static int hostapd_get_sta_tx_params(void *ctx, const u8 *addr,
+ int ap_max_chanwidth, int ap_seg1_idx,
+ int *bandwidth, int *seg1_idx)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta) {
+ hostapd_wpa_auth_logger(hapd, addr, LOGGER_INFO,
+ "Failed to get STA info to validate received OCI");
+ return -1;
+ }
+
+ return get_tx_parameters(sta, ap_max_chanwidth, ap_seg1_idx, bandwidth,
+ seg1_idx);
+}
+#endif /* CONFIG_OCV */
+
+
#ifdef CONFIG_IEEE80211R_AP
static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
@@ -812,12 +893,18 @@
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
+ wpa_printf(MSG_DEBUG, "Add station entry for " MACSTR
+ " based on WPA authenticator callback",
+ MAC2STR(sta_addr));
if (hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT) < 0)
return NULL;
sta = ap_sta_add(hapd, sta_addr);
if (sta == NULL)
return NULL;
+ if (hapd->driver && hapd->driver->add_sta_node)
+ sta->added_unassoc = 1;
+ sta->ft_over_ds = 1;
if (sta->wpa_sm) {
sta->auth_alg = WLAN_AUTH_FT;
return sta->wpa_sm;
@@ -834,6 +921,244 @@
}
+static int hostapd_wpa_auth_set_vlan(void *ctx, const u8 *sta_addr,
+ struct vlan_description *vlan)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, sta_addr);
+ if (!sta || !sta->wpa_sm)
+ return -1;
+
+ if (vlan->notempty &&
+ !hostapd_vlan_valid(hapd->conf->vlan, vlan)) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Invalid VLAN %d%s received from FT",
+ vlan->untagged, vlan->tagged[0] ? "+" : "");
+ return -1;
+ }
+
+ if (ap_sta_set_vlan(hapd, sta, vlan) < 0)
+ return -1;
+ /* Configure wpa_group for GTK but ignore error due to driver not
+ * knowing this STA. */
+ ap_sta_bind_vlan(hapd, sta);
+
+ if (sta->vlan_id)
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
+
+ return 0;
+}
+
+
+static int hostapd_wpa_auth_get_vlan(void *ctx, const u8 *sta_addr,
+ struct vlan_description *vlan)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, sta_addr);
+ if (!sta)
+ return -1;
+
+ if (sta->vlan_desc)
+ *vlan = *sta->vlan_desc;
+ else
+ os_memset(vlan, 0, sizeof(*vlan));
+
+ return 0;
+}
+
+
+static int
+hostapd_wpa_auth_set_identity(void *ctx, const u8 *sta_addr,
+ const u8 *identity, size_t identity_len)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, sta_addr);
+ if (!sta)
+ return -1;
+
+ os_free(sta->identity);
+ sta->identity = NULL;
+
+ if (sta->eapol_sm) {
+ os_free(sta->eapol_sm->identity);
+ sta->eapol_sm->identity = NULL;
+ sta->eapol_sm->identity_len = 0;
+ }
+
+ if (!identity_len)
+ return 0;
+
+ /* sta->identity is NULL terminated */
+ sta->identity = os_zalloc(identity_len + 1);
+ if (!sta->identity)
+ return -1;
+ os_memcpy(sta->identity, identity, identity_len);
+
+ if (sta->eapol_sm) {
+ sta->eapol_sm->identity = os_zalloc(identity_len);
+ if (!sta->eapol_sm->identity)
+ return -1;
+ os_memcpy(sta->eapol_sm->identity, identity, identity_len);
+ sta->eapol_sm->identity_len = identity_len;
+ }
+
+ return 0;
+}
+
+
+static size_t
+hostapd_wpa_auth_get_identity(void *ctx, const u8 *sta_addr, const u8 **buf)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+ size_t len;
+ char *identity;
+
+ sta = ap_get_sta(hapd, sta_addr);
+ if (!sta)
+ return 0;
+
+ *buf = ieee802_1x_get_identity(sta->eapol_sm, &len);
+ if (*buf && len)
+ return len;
+
+ if (!sta->identity) {
+ *buf = NULL;
+ return 0;
+ }
+
+ identity = sta->identity;
+ len = os_strlen(identity);
+ *buf = (u8 *) identity;
+
+ return len;
+}
+
+
+static int
+hostapd_wpa_auth_set_radius_cui(void *ctx, const u8 *sta_addr,
+ const u8 *radius_cui, size_t radius_cui_len)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, sta_addr);
+ if (!sta)
+ return -1;
+
+ os_free(sta->radius_cui);
+ sta->radius_cui = NULL;
+
+ if (sta->eapol_sm) {
+ wpabuf_free(sta->eapol_sm->radius_cui);
+ sta->eapol_sm->radius_cui = NULL;
+ }
+
+ if (!radius_cui)
+ return 0;
+
+ /* sta->radius_cui is NULL terminated */
+ sta->radius_cui = os_zalloc(radius_cui_len + 1);
+ if (!sta->radius_cui)
+ return -1;
+ os_memcpy(sta->radius_cui, radius_cui, radius_cui_len);
+
+ if (sta->eapol_sm) {
+ sta->eapol_sm->radius_cui = wpabuf_alloc_copy(radius_cui,
+ radius_cui_len);
+ if (!sta->eapol_sm->radius_cui)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static size_t
+hostapd_wpa_auth_get_radius_cui(void *ctx, const u8 *sta_addr, const u8 **buf)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+ struct wpabuf *b;
+ size_t len;
+ char *radius_cui;
+
+ sta = ap_get_sta(hapd, sta_addr);
+ if (!sta)
+ return 0;
+
+ b = ieee802_1x_get_radius_cui(sta->eapol_sm);
+ if (b) {
+ len = wpabuf_len(b);
+ *buf = wpabuf_head(b);
+ return len;
+ }
+
+ if (!sta->radius_cui) {
+ *buf = NULL;
+ return 0;
+ }
+
+ radius_cui = sta->radius_cui;
+ len = os_strlen(radius_cui);
+ *buf = (u8 *) radius_cui;
+
+ return len;
+}
+
+
+static void hostapd_wpa_auth_set_session_timeout(void *ctx, const u8 *sta_addr,
+ int session_timeout)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, sta_addr);
+ if (!sta)
+ return;
+
+ if (session_timeout) {
+ os_get_reltime(&sta->session_timeout);
+ sta->session_timeout.sec += session_timeout;
+ sta->session_timeout_set = 1;
+ ap_sta_session_timeout(hapd, sta, session_timeout);
+ } else {
+ sta->session_timeout_set = 0;
+ ap_sta_no_session_timeout(hapd, sta);
+ }
+}
+
+
+static int hostapd_wpa_auth_get_session_timeout(void *ctx, const u8 *sta_addr)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+ struct os_reltime now, remaining;
+
+ sta = ap_get_sta(hapd, sta_addr);
+ if (!sta || !sta->session_timeout_set)
+ return 0;
+
+ os_get_reltime(&now);
+ if (os_reltime_before(&sta->session_timeout, &now)) {
+ /* already expired, return >0 as timeout was set */
+ return 1;
+ }
+
+ os_reltime_sub(&sta->session_timeout, &now, &remaining);
+
+ return (remaining.sec > 0) ? remaining.sec : 1;
+}
+
+
static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
size_t len)
{
@@ -949,10 +1274,23 @@
.for_each_auth = hostapd_wpa_auth_for_each_auth,
.send_ether = hostapd_wpa_auth_send_ether,
.send_oui = hostapd_wpa_auth_send_oui,
+ .channel_info = hostapd_channel_info,
+ .update_vlan = hostapd_wpa_auth_update_vlan,
+#ifdef CONFIG_OCV
+ .get_sta_tx_params = hostapd_get_sta_tx_params,
+#endif /* CONFIG_OCV */
#ifdef CONFIG_IEEE80211R_AP
.send_ft_action = hostapd_wpa_auth_send_ft_action,
.add_sta = hostapd_wpa_auth_add_sta,
.add_tspec = hostapd_wpa_auth_add_tspec,
+ .set_vlan = hostapd_wpa_auth_set_vlan,
+ .get_vlan = hostapd_wpa_auth_get_vlan,
+ .set_identity = hostapd_wpa_auth_set_identity,
+ .get_identity = hostapd_wpa_auth_get_identity,
+ .set_radius_cui = hostapd_wpa_auth_set_radius_cui,
+ .get_radius_cui = hostapd_wpa_auth_get_radius_cui,
+ .set_session_timeout = hostapd_wpa_auth_set_session_timeout,
+ .get_session_timeout = hostapd_wpa_auth_get_session_timeout,
#endif /* CONFIG_IEEE80211R_AP */
};
const u8 *wpa_ie;
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index befa800..3dcf77a 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -22,6 +22,7 @@
u8 addr[ETH_ALEN];
u8 p2p_dev_addr[ETH_ALEN];
+ u16 auth_alg;
enum {
WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED,
@@ -58,6 +59,7 @@
u8 alt_replay_counter[WPA_REPLAY_COUNTER_LEN];
u8 PMK[PMK_LEN_MAX];
unsigned int pmk_len;
+ u8 pmkid[PMKID_LEN]; /* valid if pmkid_set == 1 */
struct wpa_ptk PTK;
Boolean PTK_valid;
Boolean pairwise_set;
@@ -90,6 +92,10 @@
unsigned int pmk_r1_name_valid:1;
#endif /* CONFIG_IEEE80211R_AP */
unsigned int is_wnmsleep:1;
+ unsigned int pmkid_set:1;
+#ifdef CONFIG_OCV
+ unsigned int ocv_enabled:1;
+#endif /* CONFIG_OCV */
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
int req_replay_counter_used;
@@ -110,7 +116,8 @@
u32 dot11RSNAStatsTKIPRemoteMICFailures;
#ifdef CONFIG_IEEE80211R_AP
- u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */
+ u8 xxkey[PMK_LEN_MAX]; /* PSK or the second 256 bits of MSK, or the
+ * first 384 bits of MSK */
size_t xxkey_len;
u8 pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name derived from FT Auth
* Request */
@@ -144,6 +151,10 @@
unsigned int fils_completed:1;
#endif /* CONFIG_FILS */
+#ifdef CONFIG_DPP2
+ struct wpabuf *dpp_z;
+#endif /* CONFIG_DPP2 */
+
#ifdef CONFIG_TESTING_OPTIONS
void (*eapol_status_cb)(void *ctx1, void *ctx2);
void *eapol_status_cb_ctx1;
@@ -274,8 +285,8 @@
#ifdef CONFIG_IEEE80211R_AP
int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len);
-int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
- size_t r0kh_id_len,
+int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
+ const u8 *r0kh_id, size_t r0kh_id_len,
const u8 *anonce, const u8 *snonce,
u8 *buf, size_t len, const u8 *subelem,
size_t subelem_len);
@@ -284,9 +295,8 @@
struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
void wpa_ft_install_ptk(struct wpa_state_machine *sm);
-int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth,
- const u8 *spa, const u8 *pmk_r0,
- const u8 *pmk_r0_name, int pairwise);
+int wpa_ft_store_pmk_fils(struct wpa_state_machine *sm, const u8 *pmk_r0,
+ const u8 *pmk_r0_name);
#endif /* CONFIG_IEEE80211R_AP */
#endif /* WPA_AUTH_I_H */
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 0196d00..8580a5a 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -1,6 +1,6 @@
/*
* hostapd - WPA/RSN IE and KDE definitions
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -170,6 +170,13 @@
pos += RSN_SELECTOR_LEN;
num_suites++;
}
+#ifdef CONFIG_SHA384
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+#endif /* CONFIG_SHA384 */
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
pos += RSN_SELECTOR_LEN;
@@ -248,6 +255,13 @@
num_suites++;
}
#endif /* CONFIG_DPP */
+#ifdef CONFIG_HS20
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_OSEN) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+#endif /* CONFIG_HS20 */
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
@@ -279,9 +293,13 @@
capab |= WPA_CAPABILITY_MFPR;
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ if (conf->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
+#endif /* CONFIG_OCV */
#ifdef CONFIG_RSN_TESTING
if (rsn_testing)
- capab |= BIT(8) | BIT(14) | BIT(15);
+ capab |= BIT(8) | BIT(15);
#endif /* CONFIG_RSN_TESTING */
WPA_PUT_LE16(pos, capab);
pos += 2;
@@ -400,6 +418,10 @@
capab |= WPA_CAPABILITY_MFPR;
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ if (conf->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
+#endif /* CONFIG_OCV */
WPA_PUT_LE16(eid, capab);
eid += 2;
@@ -508,7 +530,7 @@
int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm,
+ struct wpa_state_machine *sm, int freq,
const u8 *wpa_ie, size_t wpa_ie_len,
const u8 *mdie, size_t mdie_len,
const u8 *owe_dh, size_t owe_dh_len)
@@ -538,6 +560,23 @@
if (version == WPA_PROTO_RSN) {
res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data);
+ if (!data.has_pairwise)
+ data.pairwise_cipher = wpa_default_rsn_cipher(freq);
+ if (!data.has_group)
+ data.group_cipher = wpa_default_rsn_cipher(freq);
+
+ if (wpa_key_mgmt_ft(data.key_mgmt) && !mdie &&
+ !wpa_key_mgmt_only_ft(data.key_mgmt)) {
+ /* Workaround for some HP and Epson printers that seem
+ * to incorrectly copy the FT-PSK + WPA-PSK AKMs from AP
+ * advertised RSNE to Association Request frame. */
+ wpa_printf(MSG_DEBUG,
+ "RSN: FT set in RSNE AKM but MDE is missing from "
+ MACSTR
+ " - ignore FT AKM(s) because there's also a non-FT AKM",
+ MAC2STR(sm->addr));
+ data.key_mgmt &= ~WPA_KEY_MGMT_FT;
+ }
selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
if (0) {
@@ -559,6 +598,10 @@
selector = RSN_AUTH_KEY_MGMT_FILS_SHA256;
#endif /* CONFIG_FILS */
#ifdef CONFIG_IEEE80211R_AP
+#ifdef CONFIG_SHA384
+ else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
+ selector = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
+#endif /* CONFIG_SHA384 */
else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
selector = RSN_AUTH_KEY_MGMT_FT_802_1X;
else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
@@ -588,6 +631,10 @@
else if (data.key_mgmt & WPA_KEY_MGMT_DPP)
selector = RSN_AUTH_KEY_MGMT_DPP;
#endif /* CONFIG_DPP */
+#ifdef CONFIG_HS20
+ else if (data.key_mgmt & WPA_KEY_MGMT_OSEN)
+ selector = RSN_AUTH_KEY_MGMT_OSEN;
+#endif /* CONFIG_HS20 */
wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
@@ -661,6 +708,10 @@
sm->wpa_key_mgmt = WPA_KEY_MGMT_FILS_SHA256;
#endif /* CONFIG_FILS */
#ifdef CONFIG_IEEE80211R_AP
+#ifdef CONFIG_SHA384
+ else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+#endif /* CONFIG_SHA384 */
else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
@@ -688,6 +739,10 @@
else if (key_mgmt & WPA_KEY_MGMT_DPP)
sm->wpa_key_mgmt = WPA_KEY_MGMT_DPP;
#endif /* CONFIG_DPP */
+#ifdef CONFIG_HS20
+ else if (key_mgmt & WPA_KEY_MGMT_OSEN)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_OSEN;
+#endif /* CONFIG_HS20 */
else
sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
@@ -711,12 +766,6 @@
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
}
- if (ciphers & WPA_CIPHER_TKIP) {
- wpa_printf(MSG_DEBUG, "Management frame protection "
- "cannot use TKIP");
- return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
- }
-
if (data.mgmt_group_cipher != wpa_auth->conf.group_mgmt_cipher)
{
wpa_printf(MSG_DEBUG, "Unsupported management group "
@@ -725,11 +774,39 @@
}
}
+#ifdef CONFIG_SAE
+ if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_OPTIONAL &&
+ wpa_auth->conf.sae_require_mfp &&
+ wpa_key_mgmt_sae(sm->wpa_key_mgmt) &&
+ !(data.capabilities & WPA_CAPABILITY_MFPC)) {
+ wpa_printf(MSG_DEBUG,
+ "Management frame protection required with SAE, but client did not enable it");
+ return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+ }
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_OCV
+ if ((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;
+ }
+ 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 ||
!(data.capabilities & WPA_CAPABILITY_MFPC))
sm->mgmt_frame_prot = 0;
else
sm->mgmt_frame_prot = 1;
+
+ if (sm->mgmt_frame_prot && (ciphers & WPA_CIPHER_TKIP)) {
+ wpa_printf(MSG_DEBUG,
+ "Management frame protection cannot use TKIP");
+ return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+ }
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R_AP
@@ -758,6 +835,12 @@
"OWE: No Diffie-Hellman Parameter element");
return WPA_INVALID_AKMP;
}
+#ifdef CONFIG_DPP
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && owe_dh) {
+ /* Diffie-Hellman Parameter element can be used with DPP as
+ * well, so allow this to proceed. */
+ } else
+#endif /* CONFIG_DPP */
if (sm->wpa_key_mgmt != WPA_KEY_MGMT_OWE && owe_dh) {
wpa_printf(MSG_DEBUG,
"OWE: Unexpected Diffie-Hellman Parameter element with non-OWE AKM");
@@ -775,6 +858,21 @@
else
sm->wpa = WPA_VERSION_WPA;
+#if defined(CONFIG_IEEE80211R_AP) && defined(CONFIG_FILS)
+ if ((sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA256 ||
+ sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA384) &&
+ (sm->auth_alg == WLAN_AUTH_FILS_SK ||
+ sm->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sm->auth_alg == WLAN_AUTH_FILS_PK) &&
+ (data.num_pmkid != 1 || !data.pmkid || !sm->pmk_r1_name_valid ||
+ os_memcmp_const(data.pmkid, sm->pmk_r1_name,
+ WPA_PMK_NAME_LEN) != 0)) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "No PMKR1Name match for FILS+FT");
+ return WPA_INVALID_PMKID;
+ }
+#endif /* CONFIG_IEEE80211R_AP && CONFIG_FILS */
+
sm->pmksa = NULL;
for (i = 0; i < data.num_pmkid; i++) {
wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID",
@@ -817,6 +915,15 @@
os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN);
}
+#ifdef CONFIG_SAE
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE && data.num_pmkid &&
+ !sm->pmksa) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "No PMKSA cache entry found for SAE");
+ return WPA_INVALID_PMKID;
+ }
+#endif /* CONFIG_SAE */
+
#ifdef CONFIG_DPP
if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && !sm->pmksa) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
@@ -945,6 +1052,15 @@
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_OCV
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
+ ie->oci = pos + 2 + RSN_SELECTOR_LEN;
+ ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
+ return 0;
+ }
+#endif /* CONFIG_OCV */
+
return 0;
}
@@ -1012,14 +1128,48 @@
}
+#ifdef CONFIG_OCV
+
+void wpa_auth_set_ocv(struct wpa_state_machine *sm, int ocv)
+{
+ if (sm)
+ sm->ocv_enabled = ocv;
+}
+
+
+int wpa_auth_uses_ocv(struct wpa_state_machine *sm)
+{
+ return sm ? sm->ocv_enabled : 0;
+}
+
+#endif /* CONFIG_OCV */
+
+
#ifdef CONFIG_OWE
u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
u8 *pos, size_t max_len,
const u8 *req_ies, size_t req_ies_len)
{
int res;
+ struct wpa_auth_config *conf;
- res = wpa_write_rsn_ie(&sm->wpa_auth->conf, pos, max_len,
+ if (!sm)
+ return pos;
+ conf = &sm->wpa_auth->conf;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conf->own_ie_override_len) {
+ if (max_len < conf->own_ie_override_len)
+ return NULL;
+ wpa_hexdump(MSG_DEBUG, "WPA: Forced own IE(s) for testing",
+ conf->own_ie_override, conf->own_ie_override_len);
+ os_memcpy(pos, conf->own_ie_override,
+ conf->own_ie_override_len);
+ return pos + conf->own_ie_override_len;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ res = wpa_write_rsn_ie(conf, pos, max_len,
sm->pmksa ? sm->pmksa->pmkid : NULL);
if (res < 0)
return pos;
diff --git a/src/ap/wpa_auth_ie.h b/src/ap/wpa_auth_ie.h
index 73e4333..a38b206 100644
--- a/src/ap/wpa_auth_ie.h
+++ b/src/ap/wpa_auth_ie.h
@@ -33,6 +33,10 @@
const u8 *ip_addr_req;
const u8 *ip_addr_alloc;
#endif /* CONFIG_P2P */
+#ifdef CONFIG_OCV
+ const u8 *oci;
+ size_t oci_len;
+#endif /* CONFIG_OCV */
const u8 *osen;
size_t osen_len;
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 95b40da..6161cdb 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -354,6 +354,18 @@
bss->wpa_pairwise,
bss->rsn_pairwise);
+ if (hapd->conf->wps_cred_add_sae &&
+ (cred->auth_type & WPS_AUTH_WPA2PSK) &&
+ cred->key_len != 2 * PMK_LEN) {
+ bss->wpa_key_mgmt |= WPA_KEY_MGMT_SAE;
+#ifdef CONFIG_IEEE80211W
+ if (bss->ieee80211w == NO_MGMT_FRAME_PROTECTION)
+ bss->ieee80211w =
+ MGMT_FRAME_PROTECTION_OPTIONAL;
+ bss->sae_require_mfp = 1;
+#endif /* CONFIG_IEEE80211W */
+ }
+
if (cred->key_len >= 8 && cred->key_len < 64) {
os_free(bss->ssid.wpa_passphrase);
bss->ssid.wpa_passphrase = os_zalloc(cred->key_len + 1);
@@ -401,6 +413,7 @@
char buf[1024];
int multi_bss;
int wpa;
+ int pmf_changed = 0;
if (hapd->wps == NULL)
return 0;
@@ -520,6 +533,10 @@
if (wpa) {
char *prefix;
+#ifdef CONFIG_IEEE80211W
+ int sae = 0;
+#endif /* CONFIG_IEEE80211W */
+
fprintf(nconf, "wpa=%d\n", wpa);
fprintf(nconf, "wpa_key_mgmt=");
@@ -528,10 +545,30 @@
fprintf(nconf, "WPA-EAP");
prefix = " ";
}
- if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK))
+ if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) {
fprintf(nconf, "%sWPA-PSK", prefix);
+ prefix = " ";
+ }
+ if (hapd->conf->wps_cred_add_sae &&
+ (cred->auth_type & WPS_AUTH_WPA2PSK) &&
+ cred->key_len != 2 * PMK_LEN) {
+ fprintf(nconf, "%sSAE", prefix);
+#ifdef CONFIG_IEEE80211W
+ sae = 1;
+#endif /* CONFIG_IEEE80211W */
+ }
fprintf(nconf, "\n");
+#ifdef CONFIG_IEEE80211W
+ if (sae && hapd->conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
+ fprintf(nconf, "ieee80211w=%d\n",
+ MGMT_FRAME_PROTECTION_OPTIONAL);
+ pmf_changed = 1;
+ }
+ if (sae)
+ fprintf(nconf, "sae_require_mfp=1\n");
+#endif /* CONFIG_IEEE80211W */
+
fprintf(nconf, "wpa_pairwise=");
prefix = "";
if (cred->encr_type & WPS_ENCR_AES) {
@@ -585,6 +622,7 @@
str_starts(buf, "wep_default_key=") ||
str_starts(buf, "wep_key") ||
str_starts(buf, "wps_state=") ||
+ (pmf_changed && str_starts(buf, "ieee80211w=")) ||
str_starts(buf, "wpa=") ||
str_starts(buf, "wpa_psk=") ||
str_starts(buf, "wpa_pairwise=") ||
@@ -975,6 +1013,7 @@
{
struct wps_context *wps;
struct wps_registrar_config cfg;
+ u8 *multi_ap_netw_key = NULL;
if (conf->wps_state == 0) {
hostapd_wps_clear_ies(hapd, 0);
@@ -1064,7 +1103,9 @@
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
wps->auth_types |= WPS_AUTH_WPA2;
- if (conf->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) {
+ if (conf->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
+ WPA_CIPHER_CCMP_256 |
+ WPA_CIPHER_GCMP_256)) {
wps->encr_types |= WPS_ENCR_AES;
wps->encr_types_rsn |= WPS_ENCR_AES;
}
@@ -1131,6 +1172,31 @@
wps->encr_types_wpa = WPS_ENCR_AES | WPS_ENCR_TKIP;
}
+ if ((hapd->conf->multi_ap & FRONTHAUL_BSS) &&
+ hapd->conf->multi_ap_backhaul_ssid.ssid_len) {
+ cfg.multi_ap_backhaul_ssid_len =
+ hapd->conf->multi_ap_backhaul_ssid.ssid_len;
+ cfg.multi_ap_backhaul_ssid =
+ hapd->conf->multi_ap_backhaul_ssid.ssid;
+
+ if (conf->multi_ap_backhaul_ssid.wpa_passphrase) {
+ cfg.multi_ap_backhaul_network_key = (const u8 *)
+ conf->multi_ap_backhaul_ssid.wpa_passphrase;
+ cfg.multi_ap_backhaul_network_key_len =
+ os_strlen(conf->multi_ap_backhaul_ssid.wpa_passphrase);
+ } else if (conf->multi_ap_backhaul_ssid.wpa_psk) {
+ multi_ap_netw_key = os_malloc(2 * PMK_LEN + 1);
+ if (!multi_ap_netw_key)
+ goto fail;
+ wpa_snprintf_hex((char *) multi_ap_netw_key,
+ 2 * PMK_LEN + 1,
+ conf->multi_ap_backhaul_ssid.wpa_psk->psk,
+ PMK_LEN);
+ cfg.multi_ap_backhaul_network_key = multi_ap_netw_key;
+ cfg.multi_ap_backhaul_network_key_len = 2 * PMK_LEN;
+ }
+ }
+
wps->ap_settings = conf->ap_settings;
wps->ap_settings_len = conf->ap_settings_len;
@@ -1172,10 +1238,12 @@
hostapd_register_probereq_cb(hapd, hostapd_wps_probe_req_rx, hapd);
hapd->wps = wps;
+ bin_clear_free(multi_ap_netw_key, 2 * PMK_LEN);
return 0;
fail:
+ bin_clear_free(multi_ap_netw_key, 2 * PMK_LEN);
hostapd_free_wps(wps);
return -1;
}
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
index 0b596bb..30c5247 100644
--- a/src/common/common_module_tests.c
+++ b/src/common/common_module_tests.c
@@ -1,6 +1,6 @@
/*
* common module tests
- * Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2014-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,10 +10,12 @@
#include "utils/common.h"
#include "utils/module_tests.h"
+#include "crypto/crypto.h"
#include "ieee802_11_common.h"
#include "ieee802_11_defs.h"
#include "gas.h"
#include "wpa_common.h"
+#include "sae.h"
struct ieee802_11_parse_test_data {
@@ -248,6 +250,179 @@
}
+static int sae_tests(void)
+{
+#ifdef CONFIG_SAE
+ struct sae_data sae;
+ int ret = -1;
+ /* IEEE P802.11-REVmd/D2.1, Annex J.10 */
+ const u8 addr1[ETH_ALEN] = { 0x82, 0x7b, 0x91, 0x9d, 0xd4, 0xb9 };
+ const u8 addr2[ETH_ALEN] = { 0x1e, 0xec, 0x49, 0xea, 0x64, 0x88 };
+ const char *pw = "mekmitasdigoat";
+ const char *pwid = "psk4internet";
+ const u8 local_rand[] = {
+ 0xa9, 0x06, 0xf6, 0x1e, 0x4d, 0x3a, 0x5d, 0x4e,
+ 0xb2, 0x96, 0x5f, 0xf3, 0x4c, 0xf9, 0x17, 0xdd,
+ 0x04, 0x44, 0x45, 0xc8, 0x78, 0xc1, 0x7c, 0xa5,
+ 0xd5, 0xb9, 0x37, 0x86, 0xda, 0x9f, 0x83, 0xcf
+ };
+ const u8 local_mask[] = {
+ 0x42, 0x34, 0xb4, 0xfb, 0x17, 0xaa, 0x43, 0x5c,
+ 0x52, 0xfb, 0xfd, 0xeb, 0xe6, 0x40, 0x39, 0xb4,
+ 0x34, 0x78, 0x20, 0x0e, 0x54, 0xff, 0x7b, 0x6e,
+ 0x07, 0xb6, 0x9c, 0xad, 0x74, 0x15, 0x3c, 0x15
+ };
+ const u8 local_commit[] = {
+ 0x13, 0x00, 0xeb, 0x3b, 0xab, 0x19, 0x64, 0xe4,
+ 0xa0, 0xab, 0x05, 0x92, 0x5d, 0xdf, 0x33, 0x39,
+ 0x51, 0x91, 0x38, 0xbc, 0x65, 0xd6, 0xcd, 0xc0,
+ 0xf8, 0x13, 0xdd, 0x6f, 0xd4, 0x34, 0x4e, 0xb4,
+ 0xbf, 0xe4, 0x4b, 0x5c, 0x21, 0x59, 0x76, 0x58,
+ 0xf4, 0xe3, 0xed, 0xdf, 0xb4, 0xb9, 0x9f, 0x25,
+ 0xb4, 0xd6, 0x54, 0x0f, 0x32, 0xff, 0x1f, 0xd5,
+ 0xc5, 0x30, 0xc6, 0x0a, 0x79, 0x44, 0x48, 0x61,
+ 0x0b, 0xc6, 0xde, 0x3d, 0x92, 0xbd, 0xbb, 0xd4,
+ 0x7d, 0x93, 0x59, 0x80, 0xca, 0x6c, 0xf8, 0x98,
+ 0x8a, 0xb6, 0x63, 0x0b, 0xe6, 0x76, 0x4c, 0x88,
+ 0x5c, 0xeb, 0x97, 0x93, 0x97, 0x0f, 0x69, 0x52,
+ 0x17, 0xee, 0xff, 0x0d, 0x21, 0x70, 0x73, 0x6b,
+ 0x34, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
+ 0x74
+ };
+ const u8 peer_commit[] = {
+ 0x13, 0x00, 0x55, 0x64, 0xf0, 0x45, 0xb2, 0xea,
+ 0x1e, 0x56, 0x6c, 0xf1, 0xdd, 0x74, 0x1f, 0x70,
+ 0xd9, 0xbe, 0x35, 0xd2, 0xdf, 0x5b, 0x9a, 0x55,
+ 0x02, 0x94, 0x6e, 0xe0, 0x3c, 0xf8, 0xda, 0xe2,
+ 0x7e, 0x1e, 0x05, 0xb8, 0x43, 0x0e, 0xb7, 0xa9,
+ 0x9e, 0x24, 0x87, 0x7c, 0xe6, 0x9b, 0xaf, 0x3d,
+ 0xc5, 0x80, 0xe3, 0x09, 0x63, 0x3d, 0x6b, 0x38,
+ 0x5f, 0x83, 0xee, 0x1c, 0x3e, 0xc3, 0x59, 0x1f,
+ 0x1a, 0x53, 0x93, 0xc0, 0x6e, 0x80, 0x5d, 0xdc,
+ 0xeb, 0x2f, 0xde, 0x50, 0x93, 0x0d, 0xd7, 0xcf,
+ 0xeb, 0xb9, 0x87, 0xc6, 0xff, 0x96, 0x66, 0xaf,
+ 0x16, 0x4e, 0xb5, 0x18, 0x4d, 0x8e, 0x66, 0x62,
+ 0xed, 0x6a, 0xff, 0x0d, 0x21, 0x70, 0x73, 0x6b,
+ 0x34, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
+ 0x74
+ };
+ const u8 kck[] = {
+ 0x59, 0x9d, 0x6f, 0x1e, 0x27, 0x54, 0x8b, 0xe8,
+ 0x49, 0x9d, 0xce, 0xed, 0x2f, 0xec, 0xcf, 0x94,
+ 0x81, 0x8c, 0xe1, 0xc7, 0x9f, 0x1b, 0x4e, 0xb3,
+ 0xd6, 0xa5, 0x32, 0x28, 0xa0, 0x9b, 0xf3, 0xed
+ };
+ const u8 pmk[] = {
+ 0x7a, 0xea, 0xd8, 0x6f, 0xba, 0x4c, 0x32, 0x21,
+ 0xfc, 0x43, 0x7f, 0x5f, 0x14, 0xd7, 0x0d, 0x85,
+ 0x4e, 0xa5, 0xd5, 0xaa, 0xc1, 0x69, 0x01, 0x16,
+ 0x79, 0x30, 0x81, 0xed, 0xa4, 0xd5, 0x57, 0xc5
+ };
+ const u8 pmkid[] = {
+ 0x40, 0xa0, 0x9b, 0x60, 0x17, 0xce, 0xbf, 0x00,
+ 0x72, 0x84, 0x3b, 0x53, 0x52, 0xaa, 0x2b, 0x4f
+ };
+ const u8 local_confirm[] = {
+ 0x01, 0x00, 0x12, 0xd9, 0xd5, 0xc7, 0x8c, 0x50,
+ 0x05, 0x26, 0xd3, 0x6c, 0x41, 0xdb, 0xc5, 0x6a,
+ 0xed, 0xf2, 0x91, 0x4c, 0xed, 0xdd, 0xd7, 0xca,
+ 0xd4, 0xa5, 0x8c, 0x48, 0xf8, 0x3d, 0xbd, 0xe9,
+ 0xfc, 0x77
+ };
+ const u8 peer_confirm[] = {
+ 0x01, 0x00, 0x02, 0x87, 0x1c, 0xf9, 0x06, 0x89,
+ 0x8b, 0x80, 0x60, 0xec, 0x18, 0x41, 0x43, 0xbe,
+ 0x77, 0xb8, 0xc0, 0x8a, 0x80, 0x19, 0xb1, 0x3e,
+ 0xb6, 0xd0, 0xae, 0xf0, 0xd8, 0x38, 0x3d, 0xfa,
+ 0xc2, 0xfd
+ };
+ struct wpabuf *buf = NULL;
+ struct crypto_bignum *mask = NULL;
+
+ os_memset(&sae, 0, sizeof(sae));
+ buf = wpabuf_alloc(1000);
+ if (!buf ||
+ sae_set_group(&sae, 19) < 0 ||
+ sae_prepare_commit(addr1, addr2, (const u8 *) pw, os_strlen(pw),
+ pwid, &sae) < 0)
+ goto fail;
+
+ /* Override local values based on SAE test vector */
+ crypto_bignum_deinit(sae.tmp->sae_rand, 1);
+ sae.tmp->sae_rand = crypto_bignum_init_set(local_rand,
+ sizeof(local_rand));
+ mask = crypto_bignum_init_set(local_mask, sizeof(local_mask));
+ if (!sae.tmp->sae_rand || !mask)
+ goto fail;
+
+ if (crypto_bignum_add(sae.tmp->sae_rand, mask,
+ sae.tmp->own_commit_scalar) < 0 ||
+ crypto_bignum_mod(sae.tmp->own_commit_scalar, sae.tmp->order,
+ sae.tmp->own_commit_scalar) < 0 ||
+ crypto_ec_point_mul(sae.tmp->ec, sae.tmp->pwe_ecc, mask,
+ sae.tmp->own_commit_element_ecc) < 0 ||
+ crypto_ec_point_invert(sae.tmp->ec,
+ sae.tmp->own_commit_element_ecc) < 0)
+ goto fail;
+
+ /* Check that output matches the test vector */
+ sae_write_commit(&sae, buf, NULL, pwid);
+ wpa_hexdump_buf(MSG_DEBUG, "SAE: Commit message", buf);
+
+ if (wpabuf_len(buf) != sizeof(local_commit) ||
+ os_memcmp(wpabuf_head(buf), local_commit,
+ sizeof(local_commit)) != 0) {
+ wpa_printf(MSG_ERROR, "SAE: Mismatch in local commit");
+ goto fail;
+ }
+
+ if (sae_parse_commit(&sae, peer_commit, sizeof(peer_commit), NULL, NULL,
+ NULL) != 0 ||
+ sae_process_commit(&sae) < 0)
+ goto fail;
+
+ if (os_memcmp(kck, sae.tmp->kck, SAE_KCK_LEN) != 0) {
+ wpa_printf(MSG_ERROR, "SAE: Mismatch in KCK");
+ goto fail;
+ }
+
+ if (os_memcmp(pmk, sae.pmk, SAE_PMK_LEN) != 0) {
+ wpa_printf(MSG_ERROR, "SAE: Mismatch in PMK");
+ goto fail;
+ }
+
+ if (os_memcmp(pmkid, sae.pmkid, SAE_PMKID_LEN) != 0) {
+ wpa_printf(MSG_ERROR, "SAE: Mismatch in PMKID");
+ goto fail;
+ }
+
+ buf->used = 0;
+ sae.send_confirm = 1;
+ sae_write_confirm(&sae, buf);
+ wpa_hexdump_buf(MSG_DEBUG, "SAE: Confirm message", buf);
+
+ if (wpabuf_len(buf) != sizeof(local_confirm) ||
+ os_memcmp(wpabuf_head(buf), local_confirm,
+ sizeof(local_confirm)) != 0) {
+ wpa_printf(MSG_ERROR, "SAE: Mismatch in local confirm");
+ goto fail;
+ }
+
+ if (sae_check_confirm(&sae, peer_confirm, sizeof(peer_confirm)) < 0)
+ goto fail;
+
+ ret = 0;
+fail:
+ sae_clear_data(&sae);
+ wpabuf_free(buf);
+ crypto_bignum_deinit(mask, 1);
+ return ret;
+#else /* CONFIG_SAE */
+ return 0;
+#endif /* CONFIG_SAE */
+}
+
+
int common_module_tests(void)
{
int ret = 0;
@@ -256,6 +431,7 @@
if (ieee802_11_parse_tests() < 0 ||
gas_tests() < 0 ||
+ sae_tests() < 0 ||
rsn_ie_parse_tests() < 0)
ret = -1;
diff --git a/src/common/ctrl_iface_common.c b/src/common/ctrl_iface_common.c
index ebbe6ff..e26407d 100644
--- a/src/common/ctrl_iface_common.c
+++ b/src/common/ctrl_iface_common.c
@@ -113,17 +113,53 @@
}
+static int ctrl_set_events(struct wpa_ctrl_dst *dst, const char *input)
+{
+ const char *value;
+ int val;
+
+ if (!input)
+ return 0;
+
+ value = os_strchr(input, '=');
+ if (!value)
+ return -1;
+ value++;
+ val = atoi(value);
+ if (val < 0 || val > 1)
+ return -1;
+
+ if (str_starts(input, "probe_rx_events=")) {
+ if (val)
+ dst->events |= WPA_EVENT_RX_PROBE_REQUEST;
+ else
+ dst->events &= ~WPA_EVENT_RX_PROBE_REQUEST;
+ }
+
+ return 0;
+}
+
+
int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
- socklen_t fromlen)
+ socklen_t fromlen, const char *input)
{
struct wpa_ctrl_dst *dst;
+ /* Update event registration if already attached */
+ dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
+ if (!sockaddr_compare(from, fromlen,
+ &dst->addr, dst->addrlen))
+ return ctrl_set_events(dst, input);
+ }
+
+ /* New attachment */
dst = os_zalloc(sizeof(*dst));
if (dst == NULL)
return -1;
os_memcpy(&dst->addr, from, fromlen);
dst->addrlen = fromlen;
dst->debug_level = MSG_INFO;
+ ctrl_set_events(dst, input);
dl_list_add(ctrl_dst, &dst->list);
sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor attached", from, fromlen);
diff --git a/src/common/ctrl_iface_common.h b/src/common/ctrl_iface_common.h
index 0b6e3e7..85e258e 100644
--- a/src/common/ctrl_iface_common.h
+++ b/src/common/ctrl_iface_common.h
@@ -11,6 +11,9 @@
#include "utils/list.h"
+/* Events enable bits (wpa_ctrl_dst::events) */
+#define WPA_EVENT_RX_PROBE_REQUEST BIT(0)
+
/**
* struct wpa_ctrl_dst - Data structure of control interface monitors
*
@@ -23,13 +26,14 @@
socklen_t addrlen;
int debug_level;
int errors;
+ u32 events; /* WPA_EVENT_* bitmap */
};
void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock,
socklen_t socklen);
int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
- socklen_t fromlen);
+ socklen_t fromlen, const char *input);
int ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
socklen_t fromlen);
int ctrl_iface_level(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
diff --git a/src/common/defs.h b/src/common/defs.h
index 1de099f..4faf1c8 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Common definitions
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -57,11 +57,20 @@
#define WPA_KEY_MGMT_FT_FILS_SHA384 BIT(21)
#define WPA_KEY_MGMT_OWE BIT(22)
#define WPA_KEY_MGMT_DPP BIT(23)
+#define WPA_KEY_MGMT_FT_IEEE8021X_SHA384 BIT(24)
+
+#define WPA_KEY_MGMT_FT (WPA_KEY_MGMT_FT_PSK | \
+ WPA_KEY_MGMT_FT_IEEE8021X | \
+ WPA_KEY_MGMT_FT_IEEE8021X_SHA384 | \
+ WPA_KEY_MGMT_FT_SAE | \
+ WPA_KEY_MGMT_FT_FILS_SHA256 | \
+ WPA_KEY_MGMT_FT_FILS_SHA384)
static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
{
return !!(akm & (WPA_KEY_MGMT_IEEE8021X |
WPA_KEY_MGMT_FT_IEEE8021X |
+ WPA_KEY_MGMT_FT_IEEE8021X_SHA384 |
WPA_KEY_MGMT_CCKM |
WPA_KEY_MGMT_OSEN |
WPA_KEY_MGMT_IEEE8021X_SHA256 |
@@ -84,11 +93,14 @@
static inline int wpa_key_mgmt_ft(int akm)
{
- return !!(akm & (WPA_KEY_MGMT_FT_PSK |
- WPA_KEY_MGMT_FT_IEEE8021X |
- WPA_KEY_MGMT_FT_SAE |
- WPA_KEY_MGMT_FT_FILS_SHA256 |
- WPA_KEY_MGMT_FT_FILS_SHA384));
+ return !!(akm & WPA_KEY_MGMT_FT);
+}
+
+static inline int wpa_key_mgmt_only_ft(int akm)
+{
+ int ft = wpa_key_mgmt_ft(akm);
+ akm &= ~WPA_KEY_MGMT_FT;
+ return ft && !akm;
}
static inline int wpa_key_mgmt_ft_psk(int akm)
@@ -114,6 +126,8 @@
{
return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 |
WPA_KEY_MGMT_IEEE8021X_SHA256 |
+ WPA_KEY_MGMT_SAE |
+ WPA_KEY_MGMT_FT_SAE |
WPA_KEY_MGMT_OSEN |
WPA_KEY_MGMT_IEEE8021X_SUITE_B |
WPA_KEY_MGMT_FILS_SHA256 |
@@ -123,6 +137,7 @@
static inline int wpa_key_mgmt_sha384(int akm)
{
return !!(akm & (WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 |
+ WPA_KEY_MGMT_FT_IEEE8021X_SHA384 |
WPA_KEY_MGMT_FILS_SHA384 |
WPA_KEY_MGMT_FT_FILS_SHA384));
}
@@ -393,4 +408,15 @@
#define OCE_STA_CFON BIT(1)
#define OCE_AP BIT(2)
+/* enum chan_width - Channel width definitions */
+enum chan_width {
+ CHAN_WIDTH_20_NOHT,
+ CHAN_WIDTH_20,
+ CHAN_WIDTH_40,
+ CHAN_WIDTH_80,
+ CHAN_WIDTH_80P80,
+ CHAN_WIDTH_160,
+ CHAN_WIDTH_UNKNOWN
+};
+
#endif /* DEFS_H */
diff --git a/src/common/dpp.c b/src/common/dpp.c
index 5107950..49de476 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -1,6 +1,7 @@
/*
* DPP functionality shared between hostapd and wpa_supplicant
* Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2019, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,6 +10,8 @@
#include "utils/includes.h"
#include <openssl/opensslv.h>
#include <openssl/err.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
#include "utils/common.h"
#include "utils/base64.h"
@@ -16,16 +19,35 @@
#include "common/ieee802_11_common.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
+#include "common/gas.h"
#include "crypto/crypto.h"
#include "crypto/random.h"
#include "crypto/aes.h"
#include "crypto/aes_siv.h"
#include "crypto/sha384.h"
#include "crypto/sha512.h"
+#include "drivers/driver.h"
#include "dpp.h"
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#ifdef CONFIG_TESTING_OPTIONS
+enum dpp_test_behavior dpp_test = DPP_TEST_DISABLED;
+u8 dpp_pkex_own_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+u8 dpp_pkex_peer_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+u8 dpp_pkex_ephemeral_key_override[600];
+size_t dpp_pkex_ephemeral_key_override_len = 0;
+u8 dpp_protocol_key_override[600];
+size_t dpp_protocol_key_override_len = 0;
+u8 dpp_nonce_override[DPP_MAX_NONCE_LEN];
+size_t dpp_nonce_override_len = 0;
+
+static int dpp_test_gen_invalid_key(struct wpabuf *msg,
+ const struct dpp_curve_params *curve);
+#endif /* CONFIG_TESTING_OPTIONS */
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
/* Compatibility wrappers for older versions. */
static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
@@ -48,6 +70,11 @@
#endif
+struct dpp_global {
+ struct dl_list bootstrap; /* struct dpp_bootstrap_info */
+ struct dl_list configurator; /* struct dpp_configurator */
+};
+
static const struct dpp_curve_params dpp_curves[] = {
/* The mandatory to support and the default NIST P-256 curve needs to
* be the first entry on this list. */
@@ -83,10 +110,10 @@
0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
};
static const u8 pkex_resp_y_p256[32] = {
- 0x26, 0x04, 0x09, 0x45, 0x0a, 0x05, 0x20, 0xe7,
- 0xa7, 0x27, 0xc1, 0x36, 0x76, 0x85, 0xca, 0x3e,
- 0x42, 0x16, 0xf4, 0x89, 0x85, 0x34, 0x6e, 0xd5,
- 0x17, 0xde, 0xc0, 0xb8, 0xad, 0xfd, 0xb2, 0x98
+ 0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
+ 0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
+ 0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
+ 0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
};
/* NIST P-384 */
@@ -99,12 +126,12 @@
0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
};
static const u8 pkex_init_y_p384[48] = {
- 0x89, 0xd0, 0x97, 0x7b, 0x59, 0x4f, 0xa6, 0xd6,
- 0x7c, 0x5d, 0x93, 0x5b, 0x93, 0xc4, 0x07, 0xa9,
- 0x89, 0xee, 0xd5, 0xcd, 0x6f, 0x42, 0xf8, 0x38,
- 0xc8, 0xc6, 0x62, 0x24, 0x69, 0x0c, 0xd4, 0x48,
- 0xd8, 0x44, 0xd6, 0xc2, 0xe8, 0xcc, 0x62, 0x6b,
- 0x3c, 0x25, 0x53, 0xba, 0x4f, 0x71, 0xf8, 0xe7
+ 0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
+ 0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
+ 0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
+ 0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
+ 0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
+ 0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
};
static const u8 pkex_resp_x_p384[48] = {
0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
@@ -115,12 +142,12 @@
0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
};
static const u8 pkex_resp_y_p384[48] = {
- 0x54, 0x58, 0x20, 0xad, 0x55, 0x1d, 0xca, 0xf3,
- 0x1c, 0x8a, 0xcd, 0x19, 0x40, 0xf9, 0x37, 0x83,
- 0xc7, 0xd6, 0xb3, 0x13, 0x7d, 0x53, 0x28, 0x5c,
- 0xf6, 0x2d, 0xf1, 0xdd, 0xa5, 0x8b, 0xad, 0x5d,
- 0x81, 0xab, 0xb1, 0x00, 0x39, 0xd6, 0xcc, 0x9c,
- 0xea, 0x1e, 0x84, 0x1d, 0xbf, 0xe3, 0x35, 0xf9
+ 0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
+ 0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
+ 0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
+ 0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
+ 0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
+ 0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
};
/* NIST P-521 */
@@ -136,15 +163,15 @@
0x97, 0x76
};
static const u8 pkex_init_y_p521[66] = {
- 0x01, 0x4c, 0x71, 0xfd, 0x1b, 0xd5, 0x9c, 0xa6,
- 0xed, 0x39, 0xef, 0x45, 0xc5, 0x06, 0xfd, 0x66,
- 0xc0, 0xeb, 0x0f, 0xbf, 0x21, 0xa3, 0x36, 0x74,
- 0xfd, 0xaa, 0x05, 0x6e, 0x4e, 0x33, 0x95, 0x42,
- 0x1a, 0x9d, 0x3f, 0x3a, 0x1c, 0x5e, 0xa8, 0x60,
- 0xf7, 0xe5, 0x59, 0x1d, 0x07, 0xaa, 0x6f, 0x40,
- 0x0a, 0x59, 0x3c, 0x27, 0xad, 0xe0, 0x48, 0xfd,
- 0xd1, 0x83, 0x37, 0x4c, 0xdf, 0xe1, 0x86, 0x72,
- 0xfc, 0x57
+ 0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
+ 0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
+ 0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
+ 0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
+ 0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
+ 0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
+ 0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
+ 0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
+ 0x03, 0xa8
};
static const u8 pkex_resp_x_p521[66] = {
0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
@@ -158,15 +185,15 @@
0x84, 0xb4
};
static const u8 pkex_resp_y_p521[66] = {
- 0x01, 0xb9, 0x9c, 0xc6, 0x41, 0x32, 0x5b, 0xd2,
- 0x35, 0xd8, 0x8b, 0x2b, 0xe4, 0x6e, 0xcc, 0xdf,
- 0x7c, 0x38, 0xc4, 0x5b, 0xf6, 0x74, 0x71, 0x5c,
- 0x77, 0x16, 0x8a, 0x80, 0xa9, 0x84, 0xc7, 0x7b,
- 0x9d, 0xfd, 0x83, 0x6f, 0xae, 0xf8, 0x24, 0x16,
- 0x2f, 0x21, 0x25, 0x65, 0xa2, 0x1a, 0x6b, 0x2d,
- 0x30, 0x62, 0xb3, 0xcc, 0x6e, 0x59, 0x3c, 0x7f,
- 0x58, 0x91, 0x81, 0x72, 0x07, 0x8c, 0x91, 0xac,
- 0x31, 0x1e
+ 0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
+ 0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
+ 0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
+ 0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
+ 0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
+ 0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
+ 0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
+ 0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
+ 0xce, 0xe1
};
/* Brainpool P-256r1 */
@@ -177,10 +204,10 @@
0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
};
static const u8 pkex_init_y_bp_p256r1[32] = {
- 0x16, 0x30, 0x68, 0x32, 0x3b, 0xb0, 0x21, 0xee,
- 0xeb, 0xf7, 0xb6, 0x7c, 0xae, 0x52, 0x26, 0x42,
- 0x59, 0x28, 0x58, 0xb6, 0x14, 0x90, 0xed, 0x69,
- 0xd0, 0x67, 0xea, 0x25, 0x60, 0x0f, 0xa9, 0x6c
+ 0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
+ 0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
+ 0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
+ 0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
};
static const u8 pkex_resp_x_bp_p256r1[32] = {
0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
@@ -241,14 +268,14 @@
0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
};
static const u8 pkex_init_y_bp_p512r1[64] = {
- 0x5a, 0x28, 0x01, 0xbe, 0x96, 0x82, 0x4e, 0xf6,
- 0xfa, 0xed, 0x7d, 0xfd, 0x48, 0x8b, 0x48, 0x4e,
- 0xd1, 0x97, 0x87, 0xc4, 0x05, 0x5d, 0x15, 0x2a,
- 0xf4, 0x91, 0x4b, 0x75, 0x90, 0xd9, 0x34, 0x2c,
- 0x3c, 0x12, 0xf2, 0xf5, 0x25, 0x94, 0x24, 0x34,
- 0xa7, 0x6d, 0x66, 0xbc, 0x27, 0xa4, 0xa0, 0x8d,
- 0xd5, 0xe1, 0x54, 0xa3, 0x55, 0x26, 0xd4, 0x14,
- 0x17, 0x0f, 0xc1, 0xc7, 0x3d, 0x68, 0x7f, 0x5a
+ 0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
+ 0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
+ 0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
+ 0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
+ 0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
+ 0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
+ 0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
+ 0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
};
static const u8 pkex_resp_x_bp_p512r1[64] = {
0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
@@ -261,17 +288,50 @@
0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
};
static const u8 pkex_resp_y_bp_p512r1[64] = {
- 0x2a, 0xbe, 0x59, 0xe6, 0xc4, 0xb3, 0xd8, 0x09,
- 0x66, 0x89, 0x0a, 0x2d, 0x19, 0xf0, 0x9c, 0x9f,
- 0xb4, 0xab, 0x8f, 0x50, 0x68, 0x3c, 0x74, 0x64,
- 0x4e, 0x19, 0x55, 0x81, 0x9b, 0x48, 0x5c, 0xf4,
- 0x12, 0x8d, 0xb9, 0xd8, 0x02, 0x5b, 0xe1, 0x26,
- 0x7e, 0x19, 0x5c, 0xfd, 0x70, 0xf7, 0x4b, 0xdc,
- 0xb5, 0x5d, 0xc1, 0x7a, 0xe9, 0xd1, 0x05, 0x2e,
- 0xd1, 0xfd, 0x2f, 0xce, 0x63, 0x77, 0x48, 0x2c
+ 0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
+ 0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
+ 0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
+ 0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
+ 0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
+ 0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
+ 0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
+ 0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
};
+static void dpp_debug_print_point(const char *title, const EC_GROUP *group,
+ const EC_POINT *point)
+{
+ BIGNUM *x, *y;
+ BN_CTX *ctx;
+ char *x_str = NULL, *y_str = NULL;
+
+ if (!wpa_debug_show_keys)
+ return;
+
+ ctx = BN_CTX_new();
+ x = BN_new();
+ y = BN_new();
+ if (!ctx || !x || !y ||
+ EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx) != 1)
+ goto fail;
+
+ x_str = BN_bn2hex(x);
+ y_str = BN_bn2hex(y);
+ if (!x_str || !y_str)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "%s (%s,%s)", title, x_str, y_str);
+
+fail:
+ OPENSSL_free(x_str);
+ OPENSSL_free(y_str);
+ BN_free(x);
+ BN_free(y);
+ BN_CTX_free(ctx);
+}
+
+
static int dpp_hash_vector(const struct dpp_curve_params *curve,
size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac)
@@ -335,6 +395,20 @@
}
+static int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
+{
+ int num_bytes, offset;
+
+ num_bytes = BN_num_bytes(bn);
+ if ((size_t) num_bytes > len)
+ return -1;
+ offset = len - num_bytes;
+ os_memset(pos, 0, offset);
+ BN_bn2bin(bn, pos + offset);
+ return 0;
+}
+
+
static struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix)
{
int len, res;
@@ -418,6 +492,7 @@
wpa_printf(MSG_ERROR, "DPP: Invalid point");
goto fail;
}
+ dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group, point);
eckey = EC_KEY_new();
if (!eckey ||
@@ -479,6 +554,12 @@
}
+static void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
+{
+ wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
+}
+
+
struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
size_t len)
{
@@ -523,6 +604,7 @@
int dpp_check_attrs(const u8 *buf, size_t len)
{
const u8 *pos, *end;
+ int wrapped_data = 0;
pos = buf;
end = buf + len;
@@ -540,6 +622,13 @@
"DPP: Truncated message - not enough room for the attribute - dropped");
return -1;
}
+ if (wrapped_data) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: An unexpected attribute included after the Wrapped Data attribute");
+ return -1;
+ }
+ if (id == DPP_ATTR_WRAPPED_DATA)
+ wrapped_data = 1;
pos += alen;
}
@@ -731,7 +820,9 @@
const unsigned char *pk;
int ppklen;
X509_ALGOR *pa;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20800000L)
ASN1_OBJECT *pa_oid;
#else
const ASN1_OBJECT *pa_oid;
@@ -758,6 +849,7 @@
if (sha256_vector(1, (const u8 **) &data, &data_len,
bi->pubkey_hash) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
+ os_free(data);
return -1;
}
wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
@@ -939,6 +1031,8 @@
int res;
unsigned char *der = NULL;
int der_len;
+ const EC_GROUP *group;
+ const EC_POINT *point;
out = BIO_new(BIO_s_mem());
if (!out)
@@ -961,6 +1055,11 @@
if (!eckey)
return;
+ group = EC_KEY_get0_group(eckey);
+ point = EC_KEY_get0_public_key(eckey);
+ if (group && point)
+ dpp_debug_print_point(title, group, point);
+
der_len = i2d_ECPrivateKey(eckey, &der);
if (der_len > 0)
wpa_hexdump_key(MSG_DEBUG, "DPP: ECPrivateKey", der, der_len);
@@ -979,13 +1078,8 @@
static EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve)
{
-#ifdef OPENSSL_IS_BORINGSSL
EVP_PKEY_CTX *kctx = NULL;
- const EC_GROUP *group;
EC_KEY *ec_params;
-#else
- EVP_PKEY_CTX *pctx, *kctx = NULL;
-#endif
EVP_PKEY *params = NULL, *key = NULL;
int nid;
@@ -996,10 +1090,9 @@
wpa_printf(MSG_INFO, "DPP: Unsupported curve %s", curve->name);
return NULL;
}
-#ifdef OPENSSL_IS_BORINGSSL
- group = EC_GROUP_new_by_curve_name(nid);
- ec_params = EC_KEY_new();
- if (!ec_params || EC_KEY_set_group(ec_params, group) != 1) {
+
+ ec_params = EC_KEY_new_by_curve_name(nid);
+ if (!ec_params) {
wpa_printf(MSG_ERROR,
"DPP: Failed to generate EC_KEY parameters");
goto fail;
@@ -1011,20 +1104,6 @@
"DPP: Failed to generate EVP_PKEY parameters");
goto fail;
}
-#else
- pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
- if (!pctx ||
- EVP_PKEY_paramgen_init(pctx) != 1 ||
- EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) != 1 ||
- EVP_PKEY_CTX_set_ec_param_enc(pctx, OPENSSL_EC_NAMED_CURVE) != 1 ||
- EVP_PKEY_paramgen(pctx, ¶ms) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to generate EVP_PKEY parameters");
- EVP_PKEY_CTX_free(pctx);
- goto fail;
- }
- EVP_PKEY_CTX_free(pctx);
-#endif
kctx = EVP_PKEY_CTX_new(params, NULL);
if (!kctx ||
@@ -1121,34 +1200,111 @@
}
-int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
+typedef struct {
+ /* AlgorithmIdentifier ecPublicKey with optional parameters present
+ * as an OID identifying the curve */
+ X509_ALGOR *alg;
+ /* Compressed format public key per ANSI X9.63 */
+ ASN1_BIT_STRING *pub_key;
+} DPP_BOOTSTRAPPING_KEY;
+
+ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY) = {
+ ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, alg, X509_ALGOR),
+ ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, pub_key, ASN1_BIT_STRING)
+} ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY);
+
+IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY);
+
+
+static struct wpabuf * dpp_bootstrap_key_der(EVP_PKEY *key)
{
unsigned char *der = NULL;
int der_len;
EC_KEY *eckey;
- int res;
+ struct wpabuf *ret = NULL;
size_t len;
+ const EC_GROUP *group;
+ const EC_POINT *point;
+ BN_CTX *ctx;
+ DPP_BOOTSTRAPPING_KEY *bootstrap = NULL;
+ int nid;
- /* Need to get the compressed form of the public key through EC_KEY, so
- * cannot use the simpler i2d_PUBKEY() here. */
- eckey = EVP_PKEY_get1_EC_KEY(bi->pubkey);
- if (!eckey)
- return -1;
- EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED);
- der_len = i2d_EC_PUBKEY(eckey, &der);
- EC_KEY_free(eckey);
+ ctx = BN_CTX_new();
+ eckey = EVP_PKEY_get1_EC_KEY(key);
+ if (!ctx || !eckey)
+ goto fail;
+
+ group = EC_KEY_get0_group(eckey);
+ point = EC_KEY_get0_public_key(eckey);
+ if (!group || !point)
+ goto fail;
+ dpp_debug_print_point("DPP: bootstrap public key", group, point);
+ nid = EC_GROUP_get_curve_name(group);
+
+ bootstrap = DPP_BOOTSTRAPPING_KEY_new();
+ if (!bootstrap ||
+ X509_ALGOR_set0(bootstrap->alg, OBJ_nid2obj(EVP_PKEY_EC),
+ V_ASN1_OBJECT, (void *) OBJ_nid2obj(nid)) != 1)
+ goto fail;
+
+ len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
+ NULL, 0, ctx);
+ if (len == 0)
+ goto fail;
+
+ der = OPENSSL_malloc(len);
+ if (!der)
+ goto fail;
+ len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
+ der, len, ctx);
+
+ OPENSSL_free(bootstrap->pub_key->data);
+ bootstrap->pub_key->data = der;
+ der = NULL;
+ bootstrap->pub_key->length = len;
+ /* No unused bits */
+ bootstrap->pub_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
+ bootstrap->pub_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
+
+ der_len = i2d_DPP_BOOTSTRAPPING_KEY(bootstrap, &der);
if (der_len <= 0) {
wpa_printf(MSG_ERROR,
"DDP: Failed to build DER encoded public key");
- OPENSSL_free(der);
- return -1;
+ goto fail;
}
- len = der_len;
- res = sha256_vector(1, (const u8 **) &der, &len, bi->pubkey_hash);
+ ret = wpabuf_alloc_copy(der, der_len);
+fail:
+ DPP_BOOTSTRAPPING_KEY_free(bootstrap);
OPENSSL_free(der);
+ EC_KEY_free(eckey);
+ BN_CTX_free(ctx);
+ return ret;
+}
+
+
+int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
+{
+ struct wpabuf *der;
+ int res;
+ const u8 *addr[1];
+ size_t len[1];
+
+ der = dpp_bootstrap_key_der(bi->pubkey);
+ if (!der)
+ return -1;
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
+ der);
+
+ addr[0] = wpabuf_head(der);
+ len[0] = wpabuf_len(der);
+ res = sha256_vector(1, addr, len, bi->pubkey_hash);
if (res < 0)
wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
+ else
+ wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
+ SHA256_MAC_LEN);
+ wpabuf_free(der);
return res;
}
@@ -1159,9 +1315,9 @@
unsigned char *base64 = NULL;
char *pos, *end;
size_t len;
- unsigned char *der = NULL;
- int der_len;
- EC_KEY *eckey;
+ struct wpabuf *der = NULL;
+ const u8 *addr[1];
+ int res;
if (!curve) {
bi->curve = &dpp_curves[0];
@@ -1181,28 +1337,24 @@
goto fail;
bi->own = 1;
- /* Need to get the compressed form of the public key through EC_KEY, so
- * cannot use the simpler i2d_PUBKEY() here. */
- eckey = EVP_PKEY_get1_EC_KEY(bi->pubkey);
- if (!eckey)
+ der = dpp_bootstrap_key_der(bi->pubkey);
+ if (!der)
goto fail;
- EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED);
- der_len = i2d_EC_PUBKEY(eckey, &der);
- EC_KEY_free(eckey);
- if (der_len <= 0) {
- wpa_printf(MSG_ERROR,
- "DDP: Failed to build DER encoded public key");
- goto fail;
- }
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
+ der);
- len = der_len;
- if (sha256_vector(1, (const u8 **) &der, &len, bi->pubkey_hash) < 0) {
+ addr[0] = wpabuf_head(der);
+ len = wpabuf_len(der);
+ res = sha256_vector(1, addr, &len, bi->pubkey_hash);
+ if (res < 0) {
wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
goto fail;
}
+ wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
+ SHA256_MAC_LEN);
- base64 = base64_encode(der, der_len, &len);
- OPENSSL_free(der);
+ base64 = base64_encode(wpabuf_head(der), wpabuf_len(der), &len);
+ wpabuf_free(der);
der = NULL;
if (!base64)
goto fail;
@@ -1217,7 +1369,7 @@
return (char *) base64;
fail:
os_free(base64);
- OPENSSL_free(der);
+ wpabuf_free(der);
return NULL;
}
@@ -1291,6 +1443,12 @@
size_t len[3];
size_t num_elem = 0;
+ if (!auth->Mx_len || !auth->Nx_len) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Mx/Nx not available - cannot derive ke");
+ return -1;
+ }
+
/* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
/* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
@@ -1298,12 +1456,17 @@
os_memcpy(nonces, auth->i_nonce, nonce_len);
os_memcpy(&nonces[nonce_len], auth->r_nonce, nonce_len);
addr[num_elem] = auth->Mx;
- len[num_elem] = auth->secret_len;
+ len[num_elem] = auth->Mx_len;
num_elem++;
addr[num_elem] = auth->Nx;
- len[num_elem] = auth->secret_len;
+ len[num_elem] = auth->Nx_len;
num_elem++;
if (auth->peer_bi && auth->own_bi) {
+ if (!auth->Lx_len) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Lx not available - cannot derive ke");
+ return -1;
+ }
addr[num_elem] = auth->Lx;
len[num_elem] = auth->secret_len;
num_elem++;
@@ -1327,16 +1490,48 @@
}
-struct dpp_authentication * dpp_auth_init(void *msg_ctx,
- struct dpp_bootstrap_info *peer_bi,
- struct dpp_bootstrap_info *own_bi,
- int configurator)
+static void dpp_build_attr_status(struct wpabuf *msg,
+ enum dpp_status_error status)
{
- struct dpp_authentication *auth;
- size_t nonce_len;
- EVP_PKEY_CTX *ctx = NULL;
- size_t secret_len;
- struct wpabuf *msg, *pi = NULL;
+ wpa_printf(MSG_DEBUG, "DPP: Status %d", status);
+ wpabuf_put_le16(msg, DPP_ATTR_STATUS);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, status);
+}
+
+
+static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg,
+ const u8 *hash)
+{
+ if (hash) {
+ wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash");
+ wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
+ wpabuf_put_le16(msg, SHA256_MAC_LEN);
+ wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
+ }
+}
+
+
+static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf *msg,
+ const u8 *hash)
+{
+ if (hash) {
+ wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
+ wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
+ wpabuf_put_le16(msg, SHA256_MAC_LEN);
+ wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
+ }
+}
+
+
+static struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth,
+ const struct wpabuf *pi,
+ size_t nonce_len,
+ const u8 *r_pubkey_hash,
+ const u8 *i_pubkey_hash,
+ unsigned int neg_freq)
+{
+ struct wpabuf *msg;
u8 clear[4 + DPP_MAX_NONCE_LEN + 4 + 1];
u8 wrapped_data[4 + DPP_MAX_NONCE_LEN + 4 + 1 + AES_BLOCK_SIZE];
u8 *pos;
@@ -1344,24 +1539,613 @@
size_t len[2], siv_len, attr_len;
u8 *attr_start, *attr_end;
+ /* Build DPP Authentication Request frame attributes */
+ attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + (pi ? wpabuf_len(pi) : 0) +
+ 4 + sizeof(wrapped_data);
+ if (neg_freq > 0)
+ attr_len += 4 + 2;
+#ifdef CONFIG_DPP2
+ attr_len += 5;
+#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ)
+ attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+ msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len);
+ if (!msg)
+ return NULL;
+
+ attr_start = wpabuf_put(msg, 0);
+
+ /* Responder Bootstrapping Key Hash */
+ dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
+
+ /* Initiator Bootstrapping Key Hash */
+ dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
+
+ /* Initiator Protocol Key */
+ if (pi) {
+ wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY);
+ wpabuf_put_le16(msg, wpabuf_len(pi));
+ wpabuf_put_buf(msg, pi);
+ }
+
+ /* Channel */
+ if (neg_freq > 0) {
+ u8 op_class, channel;
+
+ if (ieee80211_freq_to_channel_ext(neg_freq, 0, 0, &op_class,
+ &channel) ==
+ NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_INFO,
+ "DPP: Unsupported negotiation frequency request: %d",
+ neg_freq);
+ wpabuf_free(msg);
+ return NULL;
+ }
+ wpabuf_put_le16(msg, DPP_ATTR_CHANNEL);
+ wpabuf_put_le16(msg, 2);
+ wpabuf_put_u8(msg, op_class);
+ wpabuf_put_u8(msg, channel);
+ }
+
+#ifdef CONFIG_DPP2
+ /* Protocol Version */
+ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, 2);
+#endif /* CONFIG_DPP2 */
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+ goto skip_wrapped_data;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Wrapped data ({I-nonce, I-capabilities}k1) */
+ pos = clear;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
+ goto skip_i_nonce;
+ }
+ if (dpp_test == DPP_TEST_INVALID_I_NONCE_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-nonce");
+ WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
+ pos += 2;
+ WPA_PUT_LE16(pos, nonce_len - 1);
+ pos += 2;
+ os_memcpy(pos, auth->i_nonce, nonce_len - 1);
+ pos += nonce_len - 1;
+ goto skip_i_nonce;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* I-nonce */
+ WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
+ pos += 2;
+ WPA_PUT_LE16(pos, nonce_len);
+ pos += 2;
+ os_memcpy(pos, auth->i_nonce, nonce_len);
+ pos += nonce_len;
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_i_nonce:
+ if (dpp_test == DPP_TEST_NO_I_CAPAB_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-capab");
+ goto skip_i_capab;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* I-capabilities */
+ WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES);
+ pos += 2;
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ auth->i_capab = auth->allowed_roles;
+ *pos++ = auth->i_capab;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_ZERO_I_CAPAB) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - zero I-capabilities");
+ pos[-1] = 0;
+ }
+skip_i_capab:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ attr_end = wpabuf_put(msg, 0);
+
+ /* OUI, OUI type, Crypto Suite, DPP frame type */
+ addr[0] = wpabuf_head_u8(msg) + 2;
+ len[0] = 3 + 1 + 1 + 1;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+
+ /* Attributes before Wrapped Data */
+ addr[1] = attr_start;
+ len[1] = attr_end - attr_start;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ siv_len = pos - clear;
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
+ if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
+ 2, addr, len, wrapped_data) < 0) {
+ wpabuf_free(msg);
+ return NULL;
+ }
+ siv_len += AES_BLOCK_SIZE;
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, siv_len);
+
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, siv_len);
+ wpabuf_put_data(msg, wrapped_data, siv_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+ }
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_hexdump_buf(MSG_DEBUG,
+ "DPP: Authentication Request frame attributes", msg);
+
+ return msg;
+}
+
+
+static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
+ enum dpp_status_error status,
+ const struct wpabuf *pr,
+ size_t nonce_len,
+ const u8 *r_pubkey_hash,
+ const u8 *i_pubkey_hash,
+ const u8 *r_nonce, const u8 *i_nonce,
+ const u8 *wrapped_r_auth,
+ size_t wrapped_r_auth_len,
+ const u8 *siv_key)
+{
+ struct wpabuf *msg;
+#define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
+ 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
+ u8 clear[DPP_AUTH_RESP_CLEAR_LEN];
+ u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN + AES_BLOCK_SIZE];
+ const u8 *addr[2];
+ size_t len[2], siv_len, attr_len;
+ u8 *attr_start, *attr_end, *pos;
+
+ auth->waiting_auth_conf = 1;
+ auth->auth_resp_tries = 0;
+
+ /* Build DPP Authentication Response frame attributes */
+ attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
+ 4 + (pr ? wpabuf_len(pr) : 0) + 4 + sizeof(wrapped_data);
+#ifdef CONFIG_DPP2
+ attr_len += 5;
+#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP)
+ attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+ msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
+ if (!msg)
+ return NULL;
+
+ attr_start = wpabuf_put(msg, 0);
+
+ /* DPP Status */
+ if (status != 255)
+ dpp_build_attr_status(msg, status);
+
+ /* Responder Bootstrapping Key Hash */
+ dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
+
+ /* Initiator Bootstrapping Key Hash (mutual authentication) */
+ dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
+
+ /* Responder Protocol Key */
+ if (pr) {
+ wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
+ wpabuf_put_le16(msg, wpabuf_len(pr));
+ wpabuf_put_buf(msg, pr);
+ }
+
+#ifdef CONFIG_DPP2
+ /* Protocol Version */
+ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, 2);
+#endif /* CONFIG_DPP2 */
+
+ attr_end = wpabuf_put(msg, 0);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+ goto skip_wrapped_data;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
+ pos = clear;
+
+ if (r_nonce) {
+ /* R-nonce */
+ WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE);
+ pos += 2;
+ WPA_PUT_LE16(pos, nonce_len);
+ pos += 2;
+ os_memcpy(pos, r_nonce, nonce_len);
+ pos += nonce_len;
+ }
+
+ if (i_nonce) {
+ /* I-nonce */
+ WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
+ pos += 2;
+ WPA_PUT_LE16(pos, nonce_len);
+ pos += 2;
+ os_memcpy(pos, i_nonce, nonce_len);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - I-nonce mismatch");
+ pos[nonce_len / 2] ^= 0x01;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ pos += nonce_len;
+ }
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_R_CAPAB_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-capab");
+ goto skip_r_capab;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* R-capabilities */
+ WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
+ pos += 2;
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
+ DPP_CAPAB_ENROLLEE;
+ *pos++ = auth->r_capab;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_ZERO_R_CAPAB) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - zero R-capabilities");
+ pos[-1] = 0;
+ } else if (dpp_test == DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - incompatible R-capabilities");
+ if ((auth->i_capab & DPP_CAPAB_ROLE_MASK) ==
+ (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE))
+ pos[-1] = 0;
+ else
+ pos[-1] = auth->configurator ? DPP_CAPAB_ENROLLEE :
+ DPP_CAPAB_CONFIGURATOR;
+ }
+skip_r_capab:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (wrapped_r_auth) {
+ /* {R-auth}ke */
+ WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA);
+ pos += 2;
+ WPA_PUT_LE16(pos, wrapped_r_auth_len);
+ pos += 2;
+ os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len);
+ pos += wrapped_r_auth_len;
+ }
+
+ /* OUI, OUI type, Crypto Suite, DPP frame type */
+ addr[0] = wpabuf_head_u8(msg) + 2;
+ len[0] = 3 + 1 + 1 + 1;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+
+ /* Attributes before Wrapped Data */
+ addr[1] = attr_start;
+ len[1] = attr_end - attr_start;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ siv_len = pos - clear;
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
+ if (aes_siv_encrypt(siv_key, auth->curve->hash_len, clear, siv_len,
+ 2, addr, len, wrapped_data) < 0) {
+ wpabuf_free(msg);
+ return NULL;
+ }
+ siv_len += AES_BLOCK_SIZE;
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped_data, siv_len);
+
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, siv_len);
+ wpabuf_put_data(msg, wrapped_data, siv_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+ }
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_hexdump_buf(MSG_DEBUG,
+ "DPP: Authentication Response frame attributes", msg);
+ return msg;
+}
+
+
+static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes,
+ u16 num_modes, unsigned int freq)
+{
+ u16 m;
+ int c, flag;
+
+ if (!own_modes || !num_modes)
+ return 1;
+
+ for (m = 0; m < num_modes; m++) {
+ for (c = 0; c < own_modes[m].num_channels; c++) {
+ if ((unsigned int) own_modes[m].channels[c].freq !=
+ freq)
+ continue;
+ flag = own_modes[m].channels[c].flag;
+ if (!(flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_NO_IR |
+ HOSTAPD_CHAN_RADAR)))
+ return 1;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Peer channel %u MHz not supported", freq);
+ return 0;
+}
+
+
+static int freq_included(const unsigned int freqs[], unsigned int num,
+ unsigned int freq)
+{
+ while (num > 0) {
+ if (freqs[--num] == freq)
+ return 1;
+ }
+ return 0;
+}
+
+
+static void freq_to_start(unsigned int freqs[], unsigned int num,
+ unsigned int freq)
+{
+ unsigned int i;
+
+ for (i = 0; i < num; i++) {
+ if (freqs[i] == freq)
+ break;
+ }
+ if (i == 0 || i >= num)
+ return;
+ os_memmove(&freqs[1], &freqs[0], i * sizeof(freqs[0]));
+ freqs[0] = freq;
+}
+
+
+static int dpp_channel_intersect(struct dpp_authentication *auth,
+ struct hostapd_hw_modes *own_modes,
+ u16 num_modes)
+{
+ struct dpp_bootstrap_info *peer_bi = auth->peer_bi;
+ unsigned int i, freq;
+
+ for (i = 0; i < peer_bi->num_freq; i++) {
+ freq = peer_bi->freq[i];
+ if (freq_included(auth->freq, auth->num_freq, freq))
+ continue;
+ if (dpp_channel_ok_init(own_modes, num_modes, freq))
+ auth->freq[auth->num_freq++] = freq;
+ }
+ if (!auth->num_freq) {
+ wpa_printf(MSG_INFO,
+ "DPP: No available channels for initiating DPP Authentication");
+ return -1;
+ }
+ auth->curr_freq = auth->freq[0];
+ return 0;
+}
+
+
+static int dpp_channel_local_list(struct dpp_authentication *auth,
+ struct hostapd_hw_modes *own_modes,
+ u16 num_modes)
+{
+ u16 m;
+ int c, flag;
+ unsigned int freq;
+
+ auth->num_freq = 0;
+
+ if (!own_modes || !num_modes) {
+ auth->freq[0] = 2412;
+ auth->freq[1] = 2437;
+ auth->freq[2] = 2462;
+ auth->num_freq = 3;
+ return 0;
+ }
+
+ for (m = 0; m < num_modes; m++) {
+ for (c = 0; c < own_modes[m].num_channels; c++) {
+ freq = own_modes[m].channels[c].freq;
+ flag = own_modes[m].channels[c].flag;
+ if (flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_NO_IR |
+ HOSTAPD_CHAN_RADAR))
+ continue;
+ if (freq_included(auth->freq, auth->num_freq, freq))
+ continue;
+ auth->freq[auth->num_freq++] = freq;
+ if (auth->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
+ m = num_modes;
+ break;
+ }
+ }
+ }
+
+ return auth->num_freq == 0 ? -1 : 0;
+}
+
+
+static int dpp_prepare_channel_list(struct dpp_authentication *auth,
+ struct hostapd_hw_modes *own_modes,
+ u16 num_modes)
+{
+ int res;
+ char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
+ unsigned int i;
+
+ if (auth->peer_bi->num_freq > 0)
+ res = dpp_channel_intersect(auth, own_modes, num_modes);
+ else
+ res = dpp_channel_local_list(auth, own_modes, num_modes);
+ if (res < 0)
+ return res;
+
+ /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
+ * likely channels first. */
+ freq_to_start(auth->freq, auth->num_freq, 2462);
+ freq_to_start(auth->freq, auth->num_freq, 2412);
+ freq_to_start(auth->freq, auth->num_freq, 2437);
+
+ auth->freq_idx = 0;
+ auth->curr_freq = auth->freq[0];
+
+ pos = freqs;
+ end = pos + sizeof(freqs);
+ for (i = 0; i < auth->num_freq; i++) {
+ res = os_snprintf(pos, end - pos, " %u", auth->freq[i]);
+ if (os_snprintf_error(end - pos, res))
+ break;
+ pos += res;
+ }
+ *pos = '\0';
+ wpa_printf(MSG_DEBUG, "DPP: Possible frequencies for initiating:%s",
+ freqs);
+
+ return 0;
+}
+
+
+static int dpp_autogen_bootstrap_key(struct dpp_authentication *auth)
+{
+ struct dpp_bootstrap_info *bi;
+ char *pk = NULL;
+ size_t len;
+
+ if (auth->own_bi)
+ return 0; /* already generated */
+
+ bi = os_zalloc(sizeof(*bi));
+ if (!bi)
+ return -1;
+ bi->type = DPP_BOOTSTRAP_QR_CODE;
+ pk = dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0);
+ if (!pk)
+ goto fail;
+
+ len = 4; /* "DPP:" */
+ len += 4 + os_strlen(pk);
+ bi->uri = os_malloc(len + 1);
+ if (!bi->uri)
+ goto fail;
+ os_snprintf(bi->uri, len + 1, "DPP:K:%s;;", pk);
+ wpa_printf(MSG_DEBUG,
+ "DPP: Auto-generated own bootstrapping key info: URI %s",
+ bi->uri);
+
+ auth->tmp_own_bi = auth->own_bi = bi;
+
+ os_free(pk);
+
+ return 0;
+fail:
+ os_free(pk);
+ dpp_bootstrap_info_free(bi);
+ return -1;
+}
+
+
+struct dpp_authentication * dpp_auth_init(void *msg_ctx,
+ struct dpp_bootstrap_info *peer_bi,
+ struct dpp_bootstrap_info *own_bi,
+ u8 dpp_allowed_roles,
+ unsigned int neg_freq,
+ struct hostapd_hw_modes *own_modes,
+ u16 num_modes)
+{
+ struct dpp_authentication *auth;
+ size_t nonce_len;
+ EVP_PKEY_CTX *ctx = NULL;
+ size_t secret_len;
+ struct wpabuf *pi = NULL;
+ const u8 *r_pubkey_hash, *i_pubkey_hash;
+#ifdef CONFIG_TESTING_OPTIONS
+ u8 test_hash[SHA256_MAC_LEN];
+#endif /* CONFIG_TESTING_OPTIONS */
+
auth = os_zalloc(sizeof(*auth));
if (!auth)
return NULL;
auth->msg_ctx = msg_ctx;
auth->initiator = 1;
- auth->configurator = configurator;
+ auth->waiting_auth_resp = 1;
+ auth->allowed_roles = dpp_allowed_roles;
+ auth->configurator = !!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR);
auth->peer_bi = peer_bi;
auth->own_bi = own_bi;
auth->curve = peer_bi->curve;
+ if (dpp_autogen_bootstrap_key(auth) < 0 ||
+ dpp_prepare_channel_list(auth, own_modes, num_modes) < 0)
+ goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_nonce_override_len > 0) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - override I-nonce");
+ nonce_len = dpp_nonce_override_len;
+ os_memcpy(auth->i_nonce, dpp_nonce_override, nonce_len);
+ } else {
+ nonce_len = auth->curve->nonce_len;
+ if (random_get_bytes(auth->i_nonce, nonce_len)) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to generate I-nonce");
+ goto fail;
+ }
+ }
+#else /* CONFIG_TESTING_OPTIONS */
nonce_len = auth->curve->nonce_len;
if (random_get_bytes(auth->i_nonce, nonce_len)) {
wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce");
goto fail;
}
+#endif /* CONFIG_TESTING_OPTIONS */
wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", auth->i_nonce, nonce_len);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_protocol_key_override_len) {
+ const struct dpp_curve_params *tmp_curve;
+
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - override protocol key");
+ auth->own_protocol_key = dpp_set_keypair(
+ &tmp_curve, dpp_protocol_key_override,
+ dpp_protocol_key_override_len);
+ } else {
+ auth->own_protocol_key = dpp_gen_keypair(auth->curve);
+ }
+#else /* CONFIG_TESTING_OPTIONS */
auth->own_protocol_key = dpp_gen_keypair(auth->curve);
+#endif /* CONFIG_TESTING_OPTIONS */
if (!auth->own_protocol_key)
goto fail;
@@ -1388,103 +2172,71 @@
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
auth->Mx, auth->secret_len);
+ auth->Mx_len = auth->secret_len;
if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
auth->curve->hash_len) < 0)
goto fail;
- /* Build DPP Authentication Request frame attributes */
- attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + wpabuf_len(pi) +
- 4 + sizeof(wrapped_data);
- msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len);
- if (!msg)
+ r_pubkey_hash = auth->peer_bi->pubkey_hash;
+ i_pubkey_hash = auth->own_bi->pubkey_hash;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
+ r_pubkey_hash = NULL;
+ } else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid R-Bootstrap Key Hash");
+ os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ r_pubkey_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
+ i_pubkey_hash = NULL;
+ } else if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid I-Bootstrap Key Hash");
+ os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ i_pubkey_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-Proto Key");
+ wpabuf_free(pi);
+ pi = NULL;
+ } else if (dpp_test == DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-Proto Key");
+ wpabuf_free(pi);
+ pi = wpabuf_alloc(2 * auth->curve->prime_len);
+ if (!pi || dpp_test_gen_invalid_key(pi, auth->curve) < 0)
+ goto fail;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash,
+ i_pubkey_hash, neg_freq);
+ if (!auth->req_msg)
goto fail;
- auth->req_msg = msg;
- attr_start = wpabuf_put(msg, 0);
-
- /* Responder Bootstrapping Key Hash */
- wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
- wpabuf_put_le16(msg, SHA256_MAC_LEN);
- wpabuf_put_data(msg, auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
-
- /* Initiator Bootstrapping Key Hash */
- wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
- wpabuf_put_le16(msg, SHA256_MAC_LEN);
- if (auth->own_bi)
- wpabuf_put_data(msg, auth->own_bi->pubkey_hash, SHA256_MAC_LEN);
- else
- os_memset(wpabuf_put(msg, SHA256_MAC_LEN), 0, SHA256_MAC_LEN);
-
- /* Initiator Protocol Key */
- wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY);
- wpabuf_put_le16(msg, wpabuf_len(pi));
- wpabuf_put_buf(msg, pi);
- wpabuf_free(pi);
- pi = NULL;
-
- /* Wrapped data ({I-nonce, I-capabilities}k1) */
- pos = clear;
- /* I-nonce */
- WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
- pos += 2;
- WPA_PUT_LE16(pos, nonce_len);
- pos += 2;
- os_memcpy(pos, auth->i_nonce, nonce_len);
- pos += nonce_len;
- /* I-capabilities */
- WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES);
- pos += 2;
- WPA_PUT_LE16(pos, 1);
- pos += 2;
- auth->i_capab = configurator ? DPP_CAPAB_CONFIGURATOR :
- DPP_CAPAB_ENROLLEE;
- *pos++ = auth->i_capab;
-
- attr_end = wpabuf_put(msg, 0);
-
- /* OUI, OUI type, Crypto Suite, DPP frame type */
- addr[0] = wpabuf_head_u8(msg) + 2;
- len[0] = 3 + 1 + 1 + 1;
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
-
- /* Attributes before Wrapped Data */
- addr[1] = attr_start;
- len[1] = attr_end - attr_start;
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
-
- siv_len = pos - clear;
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
- if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
- 2, addr, len, wrapped_data) < 0)
- goto fail;
- siv_len += AES_BLOCK_SIZE;
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
- wrapped_data, siv_len);
-
- wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
- wpabuf_put_le16(msg, siv_len);
- wpabuf_put_data(msg, wrapped_data, siv_len);
-
- wpa_hexdump_buf(MSG_DEBUG,
- "DPP: Authentication Request frame attributes", msg);
-
- return auth;
-fail:
+out:
wpabuf_free(pi);
EVP_PKEY_CTX_free(ctx);
+ return auth;
+fail:
dpp_auth_deinit(auth);
- return NULL;
+ auth = NULL;
+ goto out;
}
-struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
- const char *json)
+static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth,
+ const char *json)
{
size_t nonce_len;
size_t json_len, clear_len;
struct wpabuf *clear = NULL, *msg = NULL;
u8 *wrapped;
+ size_t attr_len;
wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
@@ -1500,20 +2252,55 @@
/* { E-nonce, configAttrib }ke */
clear_len = 4 + nonce_len + 4 + json_len;
clear = wpabuf_alloc(clear_len);
- msg = wpabuf_alloc(4 + clear_len + AES_BLOCK_SIZE);
+ attr_len = 4 + clear_len + AES_BLOCK_SIZE;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ)
+ attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+ msg = wpabuf_alloc(attr_len);
if (!clear || !msg)
goto fail;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
+ goto skip_e_nonce;
+ }
+ if (dpp_test == DPP_TEST_INVALID_E_NONCE_CONF_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid E-nonce");
+ wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
+ wpabuf_put_le16(clear, nonce_len - 1);
+ wpabuf_put_data(clear, auth->e_nonce, nonce_len - 1);
+ goto skip_e_nonce;
+ }
+ if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+ goto skip_wrapped_data;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
/* E-nonce */
wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
wpabuf_put_le16(clear, nonce_len);
wpabuf_put_data(clear, auth->e_nonce, nonce_len);
+#ifdef CONFIG_TESTING_OPTIONS
+skip_e_nonce:
+ if (dpp_test == DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no configAttrib");
+ goto skip_conf_attr_obj;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
/* configAttrib */
wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
wpabuf_put_le16(clear, json_len);
wpabuf_put_data(clear, json, json_len);
+#ifdef CONFIG_TESTING_OPTIONS
+skip_conf_attr_obj:
+#endif /* CONFIG_TESTING_OPTIONS */
+
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);
@@ -1527,6 +2314,14 @@
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+ }
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
wpa_hexdump_buf(MSG_DEBUG,
"DPP: Configuration Request frame attributes", msg);
wpabuf_free(clear);
@@ -1539,13 +2334,65 @@
}
+static void dpp_write_adv_proto(struct wpabuf *buf)
+{
+ /* Advertisement Protocol IE */
+ wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
+ wpabuf_put_u8(buf, 8); /* Length */
+ wpabuf_put_u8(buf, 0x7f);
+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(buf, 5);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, DPP_OUI_TYPE);
+ wpabuf_put_u8(buf, 0x01);
+}
+
+
+static void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query)
+{
+ /* GAS Query */
+ wpabuf_put_le16(buf, wpabuf_len(query));
+ wpabuf_put_buf(buf, query);
+}
+
+
+struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
+ const char *json)
+{
+ struct wpabuf *buf, *conf_req;
+
+ conf_req = dpp_build_conf_req_attr(auth, json);
+ if (!conf_req) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No configuration request data available");
+ return NULL;
+ }
+
+ buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req));
+ if (!buf) {
+ wpabuf_free(conf_req);
+ return NULL;
+ }
+
+ dpp_write_adv_proto(buf);
+ dpp_write_gas_query(buf, conf_req);
+ wpabuf_free(conf_req);
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: GAS Config Request", buf);
+
+ return buf;
+}
+
+
static void dpp_auth_success(struct dpp_authentication *auth)
{
wpa_printf(MSG_DEBUG,
"DPP: Authentication success - clear temporary keys");
os_memset(auth->Mx, 0, sizeof(auth->Mx));
+ auth->Mx_len = 0;
os_memset(auth->Nx, 0, sizeof(auth->Nx));
+ auth->Nx_len = 0;
os_memset(auth->Lx, 0, sizeof(auth->Lx));
+ auth->Lx_len = 0;
os_memset(auth->k1, 0, sizeof(auth->k1));
os_memset(auth->k2, 0, sizeof(auth->k2));
@@ -1725,7 +2572,6 @@
BIGNUM *lx, *sum, *q;
const BIGNUM *bR_bn, *pR_bn;
int ret = -1;
- int num_bytes, offset;
/* L = ((bR + pR) modulo q) * BI */
@@ -1765,17 +2611,10 @@
goto fail;
}
- num_bytes = BN_num_bytes(lx);
- if ((size_t) num_bytes > auth->secret_len)
+ if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
goto fail;
- if (auth->secret_len > (size_t) num_bytes)
- offset = auth->secret_len - num_bytes;
- else
- offset = 0;
-
- os_memset(auth->Lx, 0, offset);
- BN_bn2bin(lx, auth->Lx + offset);
wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
+ auth->Lx_len = auth->secret_len;
ret = 0;
fail:
EC_POINT_clear_free(l);
@@ -1800,7 +2639,6 @@
BIGNUM *lx;
const BIGNUM *bI_bn;
int ret = -1;
- int num_bytes, offset;
/* L = bI * (BR + PR) */
@@ -1835,20 +2673,14 @@
goto fail;
}
- num_bytes = BN_num_bytes(lx);
- if ((size_t) num_bytes > auth->secret_len)
+ if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
goto fail;
- if (auth->secret_len > (size_t) num_bytes)
- offset = auth->secret_len - num_bytes;
- else
- offset = 0;
-
- os_memset(auth->Lx, 0, offset);
- BN_bn2bin(lx, auth->Lx + offset);
wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
+ auth->Lx_len = auth->secret_len;
ret = 0;
fail:
EC_POINT_clear_free(l);
+ EC_POINT_clear_free(sum);
EC_KEY_free(bI);
EC_KEY_free(BR);
EC_KEY_free(PR);
@@ -1858,34 +2690,63 @@
}
-static int dpp_auth_build_resp(struct dpp_authentication *auth)
+static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
{
size_t nonce_len;
EVP_PKEY_CTX *ctx = NULL;
size_t secret_len;
struct wpabuf *msg, *pr = NULL;
u8 r_auth[4 + DPP_MAX_HASH_LEN];
- u8 wrapped_r_auth[4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE];
-#define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
- 4 + sizeof(wrapped_r_auth)
+ u8 wrapped_r_auth[4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE], *w_r_auth;
size_t wrapped_r_auth_len;
- u8 clear[DPP_AUTH_RESP_CLEAR_LEN];
- u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN + AES_BLOCK_SIZE];
- u8 *pos;
- const u8 *addr[2];
- size_t len[2], siv_len, attr_len;
- u8 *attr_start, *attr_end;
+ int ret = -1;
+ const u8 *r_pubkey_hash, *i_pubkey_hash, *r_nonce, *i_nonce;
+ enum dpp_status_error status = DPP_STATUS_OK;
+#ifdef CONFIG_TESTING_OPTIONS
+ u8 test_hash[SHA256_MAC_LEN];
+#endif /* CONFIG_TESTING_OPTIONS */
wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
+ if (!auth->own_bi)
+ return -1;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_nonce_override_len > 0) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - override R-nonce");
+ nonce_len = dpp_nonce_override_len;
+ os_memcpy(auth->r_nonce, dpp_nonce_override, nonce_len);
+ } else {
+ nonce_len = auth->curve->nonce_len;
+ if (random_get_bytes(auth->r_nonce, nonce_len)) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to generate R-nonce");
+ goto fail;
+ }
+ }
+#else /* CONFIG_TESTING_OPTIONS */
nonce_len = auth->curve->nonce_len;
if (random_get_bytes(auth->r_nonce, nonce_len)) {
wpa_printf(MSG_ERROR, "DPP: Failed to generate R-nonce");
goto fail;
}
+#endif /* CONFIG_TESTING_OPTIONS */
wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", auth->r_nonce, nonce_len);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_protocol_key_override_len) {
+ const struct dpp_curve_params *tmp_curve;
+
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - override protocol key");
+ auth->own_protocol_key = dpp_set_keypair(
+ &tmp_curve, dpp_protocol_key_override,
+ dpp_protocol_key_override_len);
+ } else {
+ auth->own_protocol_key = dpp_gen_keypair(auth->curve);
+ }
+#else /* CONFIG_TESTING_OPTIONS */
auth->own_protocol_key = dpp_gen_keypair(auth->curve);
+#endif /* CONFIG_TESTING_OPTIONS */
if (!auth->own_protocol_key)
goto fail;
@@ -1911,6 +2772,7 @@
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
auth->Nx, auth->secret_len);
+ auth->Nx_len = auth->secret_len;
if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
auth->curve->hash_len) < 0)
@@ -1928,215 +2790,163 @@
/* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
WPA_PUT_LE16(r_auth, DPP_ATTR_R_AUTH_TAG);
WPA_PUT_LE16(&r_auth[2], auth->curve->hash_len);
- if (dpp_gen_r_auth(auth, r_auth + 4) < 0 ||
- aes_siv_encrypt(auth->ke, auth->curve->hash_len,
+ if (dpp_gen_r_auth(auth, r_auth + 4) < 0)
+ goto fail;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - R-auth mismatch");
+ r_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
r_auth, 4 + auth->curve->hash_len,
0, NULL, NULL, wrapped_r_auth) < 0)
goto fail;
wrapped_r_auth_len = 4 + auth->curve->hash_len + AES_BLOCK_SIZE;
wpa_hexdump(MSG_DEBUG, "DPP: {R-auth}ke",
wrapped_r_auth, wrapped_r_auth_len);
+ w_r_auth = wrapped_r_auth;
- /* Build DPP Authentication Response frame attributes */
- attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
- 4 + wpabuf_len(pr) + 4 + sizeof(wrapped_data);
- msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
+ r_pubkey_hash = auth->own_bi->pubkey_hash;
+ if (auth->peer_bi)
+ i_pubkey_hash = auth->peer_bi->pubkey_hash;
+ else
+ i_pubkey_hash = NULL;
+
+ i_nonce = auth->i_nonce;
+ r_nonce = auth->r_nonce;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
+ r_pubkey_hash = NULL;
+ } else if (dpp_test ==
+ DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid R-Bootstrap Key Hash");
+ os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ r_pubkey_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
+ i_pubkey_hash = NULL;
+ } else if (dpp_test ==
+ DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid I-Bootstrap Key Hash");
+ if (i_pubkey_hash)
+ os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
+ else
+ os_memset(test_hash, 0, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ i_pubkey_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-Proto Key");
+ wpabuf_free(pr);
+ pr = NULL;
+ } else if (dpp_test == DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid R-Proto Key");
+ wpabuf_free(pr);
+ pr = wpabuf_alloc(2 * auth->curve->prime_len);
+ if (!pr || dpp_test_gen_invalid_key(pr, auth->curve) < 0)
+ goto fail;
+ } else if (dpp_test == DPP_TEST_NO_R_AUTH_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth");
+ w_r_auth = NULL;
+ wrapped_r_auth_len = 0;
+ } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
+ status = 255;
+ } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
+ status = 254;
+ } else if (dpp_test == DPP_TEST_NO_R_NONCE_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-nonce");
+ r_nonce = NULL;
+ } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
+ i_nonce = NULL;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ msg = dpp_auth_build_resp(auth, status, pr, nonce_len,
+ r_pubkey_hash, i_pubkey_hash,
+ r_nonce, i_nonce,
+ w_r_auth, wrapped_r_auth_len,
+ auth->k2);
if (!msg)
goto fail;
wpabuf_free(auth->resp_msg);
auth->resp_msg = msg;
-
- attr_start = wpabuf_put(msg, 0);
-
- /* DPP Status */
- wpabuf_put_le16(msg, DPP_ATTR_STATUS);
- wpabuf_put_le16(msg, 1);
- wpabuf_put_u8(msg, DPP_STATUS_OK);
-
- /* Responder Bootstrapping Key Hash */
- wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
- wpabuf_put_le16(msg, SHA256_MAC_LEN);
- wpabuf_put_data(msg, auth->own_bi->pubkey_hash, SHA256_MAC_LEN);
-
- if (auth->peer_bi) {
- /* Mutual authentication */
- /* Initiator Bootstrapping Key Hash */
- wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
- wpabuf_put_le16(msg, SHA256_MAC_LEN);
- wpabuf_put_data(msg, auth->peer_bi->pubkey_hash,
- SHA256_MAC_LEN);
- }
-
- /* Responder Protocol Key */
- wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
- wpabuf_put_le16(msg, wpabuf_len(pr));
- wpabuf_put_buf(msg, pr);
- wpabuf_free(pr);
- pr = NULL;
-
- attr_end = wpabuf_put(msg, 0);
-
- /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
- pos = clear;
- /* R-nonce */
- WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE);
- pos += 2;
- WPA_PUT_LE16(pos, nonce_len);
- pos += 2;
- os_memcpy(pos, auth->r_nonce, nonce_len);
- pos += nonce_len;
- /* I-nonce */
- WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
- pos += 2;
- WPA_PUT_LE16(pos, nonce_len);
- pos += 2;
- os_memcpy(pos, auth->i_nonce, nonce_len);
- pos += nonce_len;
- /* R-capabilities */
- WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
- pos += 2;
- WPA_PUT_LE16(pos, 1);
- pos += 2;
- auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
- DPP_CAPAB_ENROLLEE;
- *pos++ = auth->r_capab;
- /* {R-auth}ke */
- WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA);
- pos += 2;
- WPA_PUT_LE16(pos, wrapped_r_auth_len);
- pos += 2;
- os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len);
- pos += wrapped_r_auth_len;
-
- /* OUI, OUI type, Crypto Suite, DPP frame type */
- addr[0] = wpabuf_head_u8(msg) + 2;
- len[0] = 3 + 1 + 1 + 1;
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
-
- /* Attributes before Wrapped Data */
- addr[1] = attr_start;
- len[1] = attr_end - attr_start;
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
-
- siv_len = pos - clear;
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
- if (aes_siv_encrypt(auth->k2, auth->curve->hash_len, clear, siv_len,
- 2, addr, len, wrapped_data) < 0)
- goto fail;
- siv_len += AES_BLOCK_SIZE;
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
- wrapped_data, siv_len);
-
- wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
- wpabuf_put_le16(msg, siv_len);
- wpabuf_put_data(msg, wrapped_data, siv_len);
-
- wpa_hexdump_buf(MSG_DEBUG,
- "DPP: Authentication Response frame attributes", msg);
-
- return 0;
-
+ ret = 0;
fail:
wpabuf_free(pr);
- return -1;
+ return ret;
}
static int dpp_auth_build_resp_status(struct dpp_authentication *auth,
enum dpp_status_error status)
{
- size_t nonce_len;
struct wpabuf *msg;
-#define DPP_AUTH_RESP_CLEAR_LEN2 4 + DPP_MAX_NONCE_LEN + 4 + 1
- u8 clear[DPP_AUTH_RESP_CLEAR_LEN2];
- u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN2 + AES_BLOCK_SIZE];
- u8 *pos;
- const u8 *addr[2];
- size_t len[2], siv_len, attr_len;
- u8 *attr_start, *attr_end;
+ const u8 *r_pubkey_hash, *i_pubkey_hash, *i_nonce;
+#ifdef CONFIG_TESTING_OPTIONS
+ u8 test_hash[SHA256_MAC_LEN];
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (!auth->own_bi)
+ return -1;
wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
- /* Build DPP Authentication Response frame attributes */
- attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) + 4 + sizeof(wrapped_data);
- msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
+ r_pubkey_hash = auth->own_bi->pubkey_hash;
+ if (auth->peer_bi)
+ i_pubkey_hash = auth->peer_bi->pubkey_hash;
+ else
+ i_pubkey_hash = NULL;
+
+ i_nonce = auth->i_nonce;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
+ r_pubkey_hash = NULL;
+ } else if (dpp_test ==
+ DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid R-Bootstrap Key Hash");
+ os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ r_pubkey_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
+ i_pubkey_hash = NULL;
+ } else if (dpp_test ==
+ DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid I-Bootstrap Key Hash");
+ if (i_pubkey_hash)
+ os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
+ else
+ os_memset(test_hash, 0, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ i_pubkey_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
+ status = 255;
+ } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
+ i_nonce = NULL;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ msg = dpp_auth_build_resp(auth, status, NULL, auth->curve->nonce_len,
+ r_pubkey_hash, i_pubkey_hash,
+ NULL, i_nonce, NULL, 0, auth->k1);
if (!msg)
- goto fail;
+ return -1;
wpabuf_free(auth->resp_msg);
auth->resp_msg = msg;
-
- attr_start = wpabuf_put(msg, 0);
-
- /* DPP Status */
- wpabuf_put_le16(msg, DPP_ATTR_STATUS);
- wpabuf_put_le16(msg, 1);
- wpabuf_put_u8(msg, status);
-
- /* Responder Bootstrapping Key Hash */
- wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
- wpabuf_put_le16(msg, SHA256_MAC_LEN);
- wpabuf_put_data(msg, auth->own_bi->pubkey_hash, SHA256_MAC_LEN);
-
- if (auth->peer_bi) {
- /* Mutual authentication */
- /* Initiator Bootstrapping Key Hash */
- wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
- wpabuf_put_le16(msg, SHA256_MAC_LEN);
- wpabuf_put_data(msg, auth->peer_bi->pubkey_hash,
- SHA256_MAC_LEN);
- }
-
- attr_end = wpabuf_put(msg, 0);
-
- /* Wrapped data ({I-nonce, R-capabilities}k1) */
- pos = clear;
- /* I-nonce */
- nonce_len = auth->curve->nonce_len;
- WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
- pos += 2;
- WPA_PUT_LE16(pos, nonce_len);
- pos += 2;
- os_memcpy(pos, auth->i_nonce, nonce_len);
- pos += nonce_len;
- /* R-capabilities */
- WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
- pos += 2;
- WPA_PUT_LE16(pos, 1);
- pos += 2;
- auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
- DPP_CAPAB_ENROLLEE;
- *pos++ = auth->r_capab;
-
- /* OUI, OUI type, Crypto Suite, DPP frame type */
- addr[0] = wpabuf_head_u8(msg) + 2;
- len[0] = 3 + 1 + 1 + 1;
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
-
- /* Attributes before Wrapped Data */
- addr[1] = attr_start;
- len[1] = attr_end - attr_start;
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
-
- siv_len = pos - clear;
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
- if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
- 2, addr, len, wrapped_data) < 0)
- goto fail;
- siv_len += AES_BLOCK_SIZE;
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
- wrapped_data, siv_len);
-
- wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
- wpabuf_put_le16(msg, siv_len);
- wpabuf_put_data(msg, wrapped_data, siv_len);
-
- wpa_hexdump_buf(MSG_DEBUG,
- "DPP: Authentication Response frame attributes", msg);
-
return 0;
-
-fail:
- return -1;
}
@@ -2145,7 +2955,7 @@
struct dpp_bootstrap_info *peer_bi,
struct dpp_bootstrap_info *own_bi,
unsigned int freq, const u8 *hdr, const u8 *attr_start,
- const u8 *wrapped_data, u16 wrapped_data_len)
+ size_t attr_len)
{
EVP_PKEY *pi = NULL;
EVP_PKEY_CTX *ctx = NULL;
@@ -2154,14 +2964,33 @@
size_t len[2];
u8 *unwrapped = NULL;
size_t unwrapped_len = 0;
- const u8 *i_proto, *i_nonce, *i_capab, *i_bootstrap;
- u16 i_proto_len, i_nonce_len, i_capab_len, i_bootstrap_len;
+ const u8 *wrapped_data, *i_proto, *i_nonce, *i_capab, *i_bootstrap,
+ *channel;
+ u16 wrapped_data_len, i_proto_len, i_nonce_len, i_capab_len,
+ i_bootstrap_len, channel_len;
struct dpp_authentication *auth = NULL;
- size_t attr_len;
+#ifdef CONFIG_DPP2
+ const u8 *version;
+ u16 version_len;
+#endif /* CONFIG_DPP2 */
- if (wrapped_data_len < AES_BLOCK_SIZE)
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_AUTH_REQ) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at Authentication Request");
return NULL;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
+ &wrapped_data_len);
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Wrapped Data attribute");
+ return NULL;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
+ wrapped_data, wrapped_data_len);
attr_len = wrapped_data - 4 - attr_start;
auth = os_zalloc(sizeof(*auth));
@@ -2173,11 +3002,55 @@
auth->curve = own_bi->curve;
auth->curr_freq = freq;
+ auth->peer_version = 1; /* default to the first version */
+#ifdef CONFIG_DPP2
+ version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
+ &version_len);
+ if (version) {
+ if (version_len < 1 || version[0] == 0) {
+ dpp_auth_fail(auth,
+ "Invalid Protocol Version attribute");
+ goto fail;
+ }
+ auth->peer_version = version[0];
+ wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
+ auth->peer_version);
+ }
+#endif /* CONFIG_DPP2 */
+
+ channel = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CHANNEL,
+ &channel_len);
+ if (channel) {
+ int neg_freq;
+
+ if (channel_len < 2) {
+ dpp_auth_fail(auth, "Too short Channel attribute");
+ goto fail;
+ }
+
+ neg_freq = ieee80211_chan_to_freq(NULL, channel[0], channel[1]);
+ wpa_printf(MSG_DEBUG,
+ "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
+ channel[0], channel[1], neg_freq);
+ if (neg_freq < 0) {
+ dpp_auth_fail(auth,
+ "Unsupported Channel attribute value");
+ goto fail;
+ }
+
+ if (auth->curr_freq != (unsigned int) neg_freq) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Changing negotiation channel from %u MHz to %u MHz",
+ freq, neg_freq);
+ auth->curr_freq = neg_freq;
+ }
+ }
+
i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY,
&i_proto_len);
if (!i_proto) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing required Initiator Protocol Key attribute");
+ dpp_auth_fail(auth,
+ "Missing required Initiator Protocol Key attribute");
goto fail;
}
wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key",
@@ -2186,7 +3059,7 @@
/* M = bR * PI */
pi = dpp_set_pubkey_point(own_bi->pubkey, i_proto, i_proto_len);
if (!pi) {
- wpa_printf(MSG_DEBUG, "DPP: Invalid Initiator Protocol Key");
+ dpp_auth_fail(auth, "Invalid Initiator Protocol Key");
goto fail;
}
dpp_debug_print_key("Peer (Initiator) Protocol Key", pi);
@@ -2201,6 +3074,7 @@
wpa_printf(MSG_ERROR,
"DPP: Failed to derive ECDH shared secret: %s",
ERR_error_string(ERR_get_error(), NULL));
+ dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
goto fail;
}
auth->secret_len = secret_len;
@@ -2209,6 +3083,7 @@
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
auth->Mx, auth->secret_len);
+ auth->Mx_len = auth->secret_len;
if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
auth->curve->hash_len) < 0)
@@ -2229,22 +3104,21 @@
if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
wrapped_data, wrapped_data_len,
2, addr, len, unwrapped) < 0) {
- wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
unwrapped, unwrapped_len);
if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Invalid attribute in unwrapped data");
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
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) {
- wpa_printf(MSG_DEBUG, "DPP: Missing or invalid I-nonce");
+ dpp_auth_fail(auth, "Missing or invalid I-nonce");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
@@ -2254,7 +3128,7 @@
DPP_ATTR_I_CAPABILITIES,
&i_capab_len);
if (!i_capab || i_capab_len < 1) {
- wpa_printf(MSG_DEBUG, "DPP: Missing or invalid I-capabilities");
+ dpp_auth_fail(auth, "Missing or invalid I-capabilities");
goto fail;
}
auth->i_capab = i_capab[0];
@@ -2282,9 +3156,25 @@
wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
auth->configurator = 0;
break;
+ case DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE:
+ if (dpp_allowed_roles & DPP_CAPAB_ENROLLEE) {
+ wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
+ auth->configurator = 0;
+ } else if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR) {
+ wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
+ auth->configurator = 1;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Local policy does not allow Configurator/Enrollee role");
+ goto not_compatible;
+ }
+ break;
default:
wpa_printf(MSG_DEBUG, "DPP: Unexpected role in I-capabilities");
- goto not_compatible;
+ wpa_msg(auth->msg_ctx, MSG_INFO,
+ DPP_EVENT_FAIL "Invalid role in I-capabilities 0x%02x",
+ auth->i_capab & DPP_CAPAB_ROLE_MASK);
+ goto fail;
}
auth->peer_protocol_key = pi;
@@ -2314,7 +3204,7 @@
"%s", hex);
return auth;
}
- if (dpp_auth_build_resp(auth) < 0)
+ if (dpp_auth_build_resp_ok(auth) < 0)
goto fail;
return auth;
@@ -2355,52 +3245,107 @@
MACSTR, MAC2STR(auth->peer_mac_addr));
auth->peer_bi = peer_bi;
- if (dpp_auth_build_resp(auth) < 0)
+ if (dpp_auth_build_resp_ok(auth) < 0)
return -1;
return 1;
}
-static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth)
+static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth,
+ enum dpp_status_error status)
{
struct wpabuf *msg;
u8 i_auth[4 + DPP_MAX_HASH_LEN];
size_t i_auth_len;
+ u8 r_nonce[4 + DPP_MAX_NONCE_LEN];
+ size_t r_nonce_len;
const u8 *addr[2];
size_t len[2], attr_len;
u8 *wrapped_i_auth;
+ u8 *wrapped_r_nonce;
u8 *attr_start, *attr_end;
+ const u8 *r_pubkey_hash, *i_pubkey_hash;
+#ifdef CONFIG_TESTING_OPTIONS
+ u8 test_hash[SHA256_MAC_LEN];
+#endif /* CONFIG_TESTING_OPTIONS */
wpa_printf(MSG_DEBUG, "DPP: Build Authentication Confirmation");
i_auth_len = 4 + auth->curve->hash_len;
+ r_nonce_len = 4 + auth->curve->nonce_len;
/* Build DPP Authentication Confirmation frame attributes */
attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
- 4 + i_auth_len + AES_BLOCK_SIZE;
+ 4 + i_auth_len + r_nonce_len + AES_BLOCK_SIZE;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF)
+ attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF, attr_len);
if (!msg)
goto fail;
attr_start = wpabuf_put(msg, 0);
+ r_pubkey_hash = auth->peer_bi->pubkey_hash;
+ if (auth->own_bi)
+ i_pubkey_hash = auth->own_bi->pubkey_hash;
+ else
+ i_pubkey_hash = NULL;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_STATUS_AUTH_CONF) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
+ goto skip_status;
+ } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_CONF) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
+ status = 254;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
/* DPP Status */
- wpabuf_put_le16(msg, DPP_ATTR_STATUS);
- wpabuf_put_le16(msg, 1);
- wpabuf_put_u8(msg, DPP_STATUS_OK);
+ dpp_build_attr_status(msg, status);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_status:
+ if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
+ r_pubkey_hash = NULL;
+ } else if (dpp_test ==
+ DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid R-Bootstrap Key Hash");
+ os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ r_pubkey_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
+ i_pubkey_hash = NULL;
+ } else if (dpp_test ==
+ DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid I-Bootstrap Key Hash");
+ if (i_pubkey_hash)
+ os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
+ else
+ os_memset(test_hash, 0, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ i_pubkey_hash = test_hash;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
/* Responder Bootstrapping Key Hash */
- wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
- wpabuf_put_le16(msg, SHA256_MAC_LEN);
- wpabuf_put_data(msg, auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
+ dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
- if (auth->own_bi) {
- /* Mutual authentication */
- /* Initiator Bootstrapping Key Hash */
- wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
- wpabuf_put_le16(msg, SHA256_MAC_LEN);
- wpabuf_put_data(msg, auth->own_bi->pubkey_hash, SHA256_MAC_LEN);
- }
+ /* Initiator Bootstrapping Key Hash (mutual authentication) */
+ dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF)
+ goto skip_wrapped_data;
+ if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
+ i_auth_len = 0;
+#endif /* CONFIG_TESTING_OPTIONS */
attr_end = wpabuf_put(msg, 0);
@@ -2414,28 +3359,73 @@
len[1] = attr_end - attr_start;
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
- wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
- wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE);
- wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE);
- /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
- WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG);
- WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len);
- if (dpp_gen_i_auth(auth, i_auth + 4) < 0 ||
- aes_siv_encrypt(auth->ke, auth->curve->hash_len,
- i_auth, i_auth_len,
- 2, addr, len, wrapped_i_auth) < 0)
- goto fail;
- wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke",
- wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE);
+ if (status == DPP_STATUS_OK) {
+ /* I-auth wrapped with ke */
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE);
+ wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
+ goto skip_i_auth;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
+ * 1) */
+ WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG);
+ WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len);
+ if (dpp_gen_i_auth(auth, i_auth + 4) < 0)
+ goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - I-auth mismatch");
+ i_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
+ }
+skip_i_auth:
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
+ i_auth, i_auth_len,
+ 2, addr, len, wrapped_i_auth) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke",
+ wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE);
+ } else {
+ /* R-nonce wrapped with k2 */
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, r_nonce_len + AES_BLOCK_SIZE);
+ wrapped_r_nonce = wpabuf_put(msg, r_nonce_len + AES_BLOCK_SIZE);
+
+ WPA_PUT_LE16(r_nonce, DPP_ATTR_R_NONCE);
+ WPA_PUT_LE16(&r_nonce[2], auth->curve->nonce_len);
+ os_memcpy(r_nonce + 4, auth->r_nonce, auth->curve->nonce_len);
+
+ if (aes_siv_encrypt(auth->k2, auth->curve->hash_len,
+ r_nonce, r_nonce_len,
+ 2, addr, len, wrapped_r_nonce) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: {R-nonce}k2",
+ wrapped_r_nonce, r_nonce_len + AES_BLOCK_SIZE);
+ }
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+ }
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
wpa_hexdump_buf(MSG_DEBUG,
"DPP: Authentication Confirmation frame attributes",
msg);
- dpp_auth_success(auth);
+ if (status == DPP_STATUS_OK)
+ dpp_auth_success(auth);
return msg;
fail:
+ wpabuf_free(msg);
return NULL;
}
@@ -2463,6 +3453,7 @@
wpa_printf(MSG_DEBUG,
"DPP: Responder reported failure (status %d)",
status);
+ dpp_auth_fail(auth, "Responder reported failure");
return;
}
@@ -2481,27 +3472,26 @@
if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
wrapped_data, wrapped_data_len,
2, addr, len, unwrapped) < 0) {
- wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
unwrapped, unwrapped_len);
if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Invalid attribute in unwrapped data");
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
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) {
- wpa_printf(MSG_DEBUG, "DPP: Missing or invalid I-nonce");
+ dpp_auth_fail(auth, "Missing or invalid I-nonce");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
- wpa_printf(MSG_DEBUG, "DPP: I-nonce mismatch");
+ dpp_auth_fail(auth, "I-nonce mismatch");
goto fail;
}
@@ -2509,7 +3499,7 @@
DPP_ATTR_R_CAPABILITIES,
&r_capab_len);
if (!r_capab || r_capab_len < 1) {
- wpa_printf(MSG_DEBUG, "DPP: Missing or invalid R-capabilities");
+ dpp_auth_fail(auth, "Missing or invalid R-capabilities");
goto fail;
}
auth->r_capab = r_capab[0];
@@ -2518,9 +3508,20 @@
wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
"r-capab=0x%02x", auth->r_capab);
} else if (status == DPP_STATUS_RESPONSE_PENDING) {
- wpa_printf(MSG_DEBUG,
- "DPP: Continue waiting for full DPP Authentication Response");
- wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_RESPONSE_PENDING);
+ u8 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
+
+ if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
+ (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
+ wpa_msg(auth->msg_ctx, MSG_INFO,
+ DPP_EVENT_FAIL "Unexpected role in R-capabilities 0x%02x",
+ role);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Continue waiting for full DPP Authentication Response");
+ wpa_msg(auth->msg_ctx, MSG_INFO,
+ DPP_EVENT_RESPONSE_PENDING "%s",
+ auth->tmp_own_bi ? auth->tmp_own_bi->uri : "");
+ }
}
fail:
bin_clear_free(unwrapped, unwrapped_len);
@@ -2544,34 +3545,53 @@
r_proto_len, r_nonce_len, i_nonce_len, r_capab_len,
wrapped2_len, r_auth_len;
u8 r_auth2[DPP_MAX_HASH_LEN];
+ u8 role;
+#ifdef CONFIG_DPP2
+ const u8 *version;
+ u16 version_len;
+#endif /* CONFIG_DPP2 */
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_AUTH_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at Authentication Response");
+ return NULL;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (!auth->initiator || !auth->peer_bi) {
+ dpp_auth_fail(auth, "Unexpected Authentication Response");
+ return NULL;
+ }
+
+ auth->waiting_auth_resp = 0;
wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
&wrapped_data_len);
- if (!wrapped_data) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing required Wrapped data attribute");
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Wrapped Data attribute");
return NULL;
}
wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
wrapped_data, wrapped_data_len);
- if (wrapped_data_len < AES_BLOCK_SIZE)
- return NULL;
-
attr_len = wrapped_data - 4 - attr_start;
r_bootstrap = dpp_get_attr(attr_start, attr_len,
DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
&r_bootstrap_len);
if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ dpp_auth_fail(auth,
+ "Missing or invalid required Responder Bootstrapping Key Hash attribute");
return NULL;
}
wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
r_bootstrap, r_bootstrap_len);
if (os_memcmp(r_bootstrap, auth->peer_bi->pubkey_hash,
SHA256_MAC_LEN) != 0) {
+ dpp_auth_fail(auth,
+ "Unexpected Responder Bootstrapping Key Hash value");
wpa_hexdump(MSG_DEBUG,
"DPP: Expected Responder Bootstrapping Key Hash",
auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
@@ -2583,8 +3603,8 @@
&i_bootstrap_len);
if (i_bootstrap) {
if (i_bootstrap_len != SHA256_MAC_LEN) {
- wpa_printf(MSG_DEBUG,
- "DPP: Invalid Initiator Bootstrapping Key Hash attribute");
+ dpp_auth_fail(auth,
+ "Invalid Initiator Bootstrapping Key Hash attribute");
return NULL;
}
wpa_hexdump(MSG_MSGDUMP,
@@ -2593,17 +3613,38 @@
if (!auth->own_bi ||
os_memcmp(i_bootstrap, auth->own_bi->pubkey_hash,
SHA256_MAC_LEN) != 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Initiator Bootstrapping Key Hash attribute did not match");
+ dpp_auth_fail(auth,
+ "Initiator Bootstrapping Key Hash attribute did not match");
return NULL;
}
+ } else if (auth->own_bi && auth->own_bi->type == DPP_BOOTSTRAP_PKEX) {
+ /* PKEX bootstrapping mandates use of mutual authentication */
+ dpp_auth_fail(auth,
+ "Missing Initiator Bootstrapping Key Hash attribute");
+ return NULL;
}
+ auth->peer_version = 1; /* default to the first version */
+#ifdef CONFIG_DPP2
+ version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
+ &version_len);
+ if (version) {
+ if (version_len < 1 || version[0] == 0) {
+ dpp_auth_fail(auth,
+ "Invalid Protocol Version attribute");
+ return NULL;
+ }
+ auth->peer_version = version[0];
+ wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
+ auth->peer_version);
+ }
+#endif /* CONFIG_DPP2 */
+
status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
&status_len);
if (!status || status_len < 1) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid required DPP Status attribute");
+ dpp_auth_fail(auth,
+ "Missing or invalid required DPP Status attribute");
return NULL;
}
wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
@@ -2615,11 +3656,20 @@
return NULL;
}
+ if (!i_bootstrap && auth->own_bi) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Responder decided not to use mutual authentication");
+ auth->own_bi = NULL;
+ }
+
+ wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_DIRECTION "mutual=%d",
+ auth->own_bi != NULL);
+
r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
&r_proto_len);
if (!r_proto) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing required Responder Protocol Key attribute");
+ dpp_auth_fail(auth,
+ "Missing required Responder Protocol Key attribute");
return NULL;
}
wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key",
@@ -2628,7 +3678,7 @@
/* N = pI * PR */
pr = dpp_set_pubkey_point(auth->own_protocol_key, r_proto, r_proto_len);
if (!pr) {
- wpa_printf(MSG_DEBUG, "DPP: Invalid Responder Protocol Key");
+ dpp_auth_fail(auth, "Invalid Responder Protocol Key");
return NULL;
}
dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
@@ -2643,6 +3693,7 @@
wpa_printf(MSG_ERROR,
"DPP: Failed to derive ECDH shared secret: %s",
ERR_error_string(ERR_get_error(), NULL));
+ dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
goto fail;
}
EVP_PKEY_CTX_free(ctx);
@@ -2652,6 +3703,7 @@
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
auth->Nx, auth->secret_len);
+ auth->Nx_len = auth->secret_len;
if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
auth->curve->hash_len) < 0)
@@ -2672,22 +3724,21 @@
if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
wrapped_data, wrapped_data_len,
2, addr, len, unwrapped) < 0) {
- wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
unwrapped, unwrapped_len);
if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Invalid attribute in unwrapped data");
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
goto fail;
}
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) {
- wpa_printf(MSG_DEBUG, "DPP: Missing or invalid R-nonce");
+ dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len);
@@ -2696,49 +3747,67 @@
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) {
- wpa_printf(MSG_DEBUG, "DPP: Missing or invalid I-nonce");
+ dpp_auth_fail(auth, "Missing or invalid I-nonce");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
- wpa_printf(MSG_DEBUG, "DPP: I-nonce mismatch");
+ dpp_auth_fail(auth, "I-nonce mismatch");
goto fail;
}
- if (auth->own_bi && auth->peer_bi) {
+ if (auth->own_bi) {
/* Mutual authentication */
if (dpp_auth_derive_l_initiator(auth) < 0)
goto fail;
}
- if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
- goto fail;
-
r_capab = dpp_get_attr(unwrapped, unwrapped_len,
DPP_ATTR_R_CAPABILITIES,
&r_capab_len);
if (!r_capab || r_capab_len < 1) {
- wpa_printf(MSG_DEBUG, "DPP: Missing or invalid R-capabilities");
+ dpp_auth_fail(auth, "Missing or invalid R-capabilities");
goto fail;
}
auth->r_capab = r_capab[0];
wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
- if ((auth->configurator && (auth->r_capab & DPP_CAPAB_CONFIGURATOR)) ||
- (!auth->configurator && (auth->r_capab & DPP_CAPAB_ENROLLEE))) {
+ role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
+ if ((auth->allowed_roles ==
+ (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE)) &&
+ (role == DPP_CAPAB_CONFIGURATOR || role == DPP_CAPAB_ENROLLEE)) {
+ /* Peer selected its role, so move from "either role" to the
+ * role that is compatible with peer's selection. */
+ auth->configurator = role == DPP_CAPAB_ENROLLEE;
+ wpa_printf(MSG_DEBUG, "DPP: Acting as %s",
+ auth->configurator ? "Configurator" : "Enrollee");
+ } else if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
+ (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
wpa_printf(MSG_DEBUG, "DPP: Incompatible role selection");
- goto fail;
+ wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Unexpected role in R-capabilities 0x%02x",
+ role);
+ if (role != DPP_CAPAB_ENROLLEE &&
+ role != DPP_CAPAB_CONFIGURATOR)
+ goto fail;
+ bin_clear_free(unwrapped, unwrapped_len);
+ auth->remove_on_tx_status = 1;
+ return dpp_auth_build_conf(auth, DPP_STATUS_NOT_COMPATIBLE);
}
wrapped2 = dpp_get_attr(unwrapped, unwrapped_len,
DPP_ATTR_WRAPPED_DATA, &wrapped2_len);
if (!wrapped2 || wrapped2_len < AES_BLOCK_SIZE) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid Secondary Wrapped Data");
+ dpp_auth_fail(auth,
+ "Missing or invalid Secondary Wrapped Data");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
wrapped2, wrapped2_len);
+
+ if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
+ goto fail;
+
unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE;
unwrapped2 = os_malloc(unwrapped2_len);
if (!unwrapped2)
@@ -2746,23 +3815,23 @@
if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
wrapped2, wrapped2_len,
0, NULL, NULL, unwrapped2) < 0) {
- wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
unwrapped2, unwrapped2_len);
if (dpp_check_attrs(unwrapped2, unwrapped2_len) < 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Invalid attribute in secondary unwrapped data");
+ dpp_auth_fail(auth,
+ "Invalid attribute in secondary unwrapped data");
goto fail;
}
r_auth = dpp_get_attr(unwrapped2, unwrapped2_len, DPP_ATTR_R_AUTH_TAG,
&r_auth_len);
if (!r_auth || r_auth_len != auth->curve->hash_len) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid Responder Authenticating Tag");
+ dpp_auth_fail(auth,
+ "Missing or invalid Responder Authenticating Tag");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: Received Responder Authenticating Tag",
@@ -2773,15 +3842,27 @@
wpa_hexdump(MSG_DEBUG, "DPP: Calculated Responder Authenticating Tag",
r_auth2, r_auth_len);
if (os_memcmp(r_auth, r_auth2, r_auth_len) != 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Mismatching Responder Authenticating Tag");
- goto fail;
+ dpp_auth_fail(auth, "Mismatching Responder Authenticating Tag");
+ bin_clear_free(unwrapped, unwrapped_len);
+ bin_clear_free(unwrapped2, unwrapped2_len);
+ auth->remove_on_tx_status = 1;
+ return dpp_auth_build_conf(auth, DPP_STATUS_AUTH_FAILURE);
}
bin_clear_free(unwrapped, unwrapped_len);
bin_clear_free(unwrapped2, unwrapped2_len);
- return dpp_auth_build_conf(auth);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - Authentication Response in place of Confirm");
+ if (dpp_auth_build_resp_ok(auth) < 0)
+ return NULL;
+ return wpabuf_dup(auth->resp_msg);
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ return dpp_auth_build_conf(auth, DPP_STATUS_OK);
fail:
bin_clear_free(unwrapped, unwrapped_len);
@@ -2792,6 +3873,77 @@
}
+static int dpp_auth_conf_rx_failure(struct dpp_authentication *auth,
+ const u8 *hdr,
+ const u8 *attr_start, size_t attr_len,
+ const u8 *wrapped_data,
+ u16 wrapped_data_len,
+ enum dpp_status_error status)
+{
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+ const u8 *r_nonce;
+ u16 r_nonce_len;
+
+ /* Authentication Confirm failure cases are expected to include
+ * {R-nonce}k2 in the Wrapped Data attribute. */
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ addr[1] = attr_start;
+ 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",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped) {
+ dpp_auth_fail(auth, "Authentication failed");
+ goto fail;
+ }
+ if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ 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, "DPP: Missing or invalid R-nonce");
+ goto fail;
+ }
+ if (os_memcmp(r_nonce, auth->r_nonce, r_nonce_len) != 0) {
+ wpa_hexdump(MSG_DEBUG, "DPP: Received R-nonce",
+ r_nonce, r_nonce_len);
+ wpa_hexdump(MSG_DEBUG, "DPP: Expected R-nonce",
+ auth->r_nonce, r_nonce_len);
+ dpp_auth_fail(auth, "R-nonce mismatch");
+ goto fail;
+ }
+
+ if (status == DPP_STATUS_NOT_COMPATIBLE)
+ dpp_auth_fail(auth, "Peer reported incompatible R-capab role");
+ else if (status == DPP_STATUS_AUTH_FAILURE)
+ dpp_auth_fail(auth, "Peer reported authentication failure)");
+
+fail:
+ bin_clear_free(unwrapped, unwrapped_len);
+ return -1;
+}
+
+
int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
const u8 *attr_start, size_t attr_len)
{
@@ -2804,28 +3956,39 @@
size_t unwrapped_len = 0;
u8 i_auth2[DPP_MAX_HASH_LEN];
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at Authentication Confirm");
+ return -1;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (auth->initiator || !auth->own_bi) {
+ dpp_auth_fail(auth, "Unexpected Authentication Confirm");
+ return -1;
+ }
+
+ auth->waiting_auth_conf = 0;
+
wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
&wrapped_data_len);
- if (!wrapped_data) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing required Wrapped data attribute");
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Wrapped Data attribute");
return -1;
}
wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
wrapped_data, wrapped_data_len);
- if (wrapped_data_len < AES_BLOCK_SIZE)
- return -1;
-
attr_len = wrapped_data - 4 - attr_start;
r_bootstrap = dpp_get_attr(attr_start, attr_len,
DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
&r_bootstrap_len);
- if (!r_bootstrap || r_bootstrap > wrapped_data ||
- r_bootstrap_len != SHA256_MAC_LEN) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Responder Bootstrapping Key Hash attribute");
return -1;
}
wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
@@ -2835,6 +3998,8 @@
wpa_hexdump(MSG_DEBUG,
"DPP: Expected Responder Bootstrapping Key Hash",
auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
+ dpp_auth_fail(auth,
+ "Responder Bootstrapping Key Hash mismatch");
return -1;
}
@@ -2842,10 +4007,9 @@
DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
&i_bootstrap_len);
if (i_bootstrap) {
- if (i_bootstrap > wrapped_data ||
- i_bootstrap_len != SHA256_MAC_LEN) {
- wpa_printf(MSG_DEBUG,
- "DPP: Invalid Initiator Bootstrapping Key Hash attribute");
+ if (i_bootstrap_len != SHA256_MAC_LEN) {
+ dpp_auth_fail(auth,
+ "Invalid Initiator Bootstrapping Key Hash attribute");
return -1;
}
wpa_hexdump(MSG_MSGDUMP,
@@ -2854,22 +4018,34 @@
if (!auth->peer_bi ||
os_memcmp(i_bootstrap, auth->peer_bi->pubkey_hash,
SHA256_MAC_LEN) != 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Initiator Bootstrapping Key Hash attribute did not match");
+ dpp_auth_fail(auth,
+ "Initiator Bootstrapping Key Hash mismatch");
return -1;
}
+ } else if (auth->peer_bi) {
+ /* Mutual authentication and peer did not include its
+ * Bootstrapping Key Hash attribute. */
+ dpp_auth_fail(auth,
+ "Missing Initiator Bootstrapping Key Hash attribute");
+ return -1;
}
status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
&status_len);
if (!status || status_len < 1) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid required DPP Status attribute");
+ dpp_auth_fail(auth,
+ "Missing or invalid required DPP Status attribute");
return -1;
}
wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
+ if (status[0] == DPP_STATUS_NOT_COMPATIBLE ||
+ status[0] == DPP_STATUS_AUTH_FAILURE)
+ return dpp_auth_conf_rx_failure(auth, hdr, attr_start,
+ attr_len, wrapped_data,
+ wrapped_data_len, status[0]);
+
if (status[0] != DPP_STATUS_OK) {
- wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
+ dpp_auth_fail(auth, "Authentication failed");
return -1;
}
@@ -2888,23 +4064,22 @@
if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
wrapped_data, wrapped_data_len,
2, addr, len, unwrapped) < 0) {
- wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
unwrapped, unwrapped_len);
if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Invalid attribute in unwrapped data");
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
goto fail;
}
i_auth = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
&i_auth_len);
if (!i_auth || i_auth_len != auth->curve->hash_len) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid Initiator Authenticating Tag");
+ dpp_auth_fail(auth,
+ "Missing or invalid Initiator Authenticating Tag");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: Received Initiator Authenticating Tag",
@@ -2915,8 +4090,7 @@
wpa_hexdump(MSG_DEBUG, "DPP: Calculated Initiator Authenticating Tag",
i_auth2, i_auth_len);
if (os_memcmp(i_auth, i_auth2, i_auth_len) != 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Mismatching Initiator Authenticating Tag");
+ dpp_auth_fail(auth, "Mismatching Initiator Authenticating Tag");
goto fail;
}
@@ -2929,15 +4103,265 @@
}
+static int bin_str_eq(const char *val, size_t len, const char *cmp)
+{
+ return os_strlen(cmp) == len && os_memcmp(val, cmp, len) == 0;
+}
+
+
+struct dpp_configuration * dpp_configuration_alloc(const char *type)
+{
+ struct dpp_configuration *conf;
+ const char *end;
+ size_t len;
+
+ conf = os_zalloc(sizeof(*conf));
+ if (!conf)
+ goto fail;
+
+ end = os_strchr(type, ' ');
+ if (end)
+ len = end - type;
+ else
+ len = os_strlen(type);
+
+ if (bin_str_eq(type, len, "psk"))
+ conf->akm = DPP_AKM_PSK;
+ else if (bin_str_eq(type, len, "sae"))
+ conf->akm = DPP_AKM_SAE;
+ else if (bin_str_eq(type, len, "psk-sae") ||
+ bin_str_eq(type, len, "psk+sae"))
+ conf->akm = DPP_AKM_PSK_SAE;
+ else if (bin_str_eq(type, len, "sae-dpp") ||
+ bin_str_eq(type, len, "dpp+sae"))
+ conf->akm = DPP_AKM_SAE_DPP;
+ else if (bin_str_eq(type, len, "psk-sae-dpp") ||
+ bin_str_eq(type, len, "dpp+psk+sae"))
+ conf->akm = DPP_AKM_PSK_SAE_DPP;
+ else if (bin_str_eq(type, len, "dpp"))
+ conf->akm = DPP_AKM_DPP;
+ else
+ goto fail;
+
+ return conf;
+fail:
+ dpp_configuration_free(conf);
+ return NULL;
+}
+
+
+int dpp_akm_psk(enum dpp_akm akm)
+{
+ return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
+ akm == DPP_AKM_PSK_SAE_DPP;
+}
+
+
+int dpp_akm_sae(enum dpp_akm akm)
+{
+ return akm == DPP_AKM_SAE || akm == DPP_AKM_PSK_SAE ||
+ akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
+}
+
+
+int dpp_akm_legacy(enum dpp_akm akm)
+{
+ return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
+ akm == DPP_AKM_SAE;
+}
+
+
+int dpp_akm_dpp(enum dpp_akm akm)
+{
+ return akm == DPP_AKM_DPP || akm == DPP_AKM_SAE_DPP ||
+ akm == DPP_AKM_PSK_SAE_DPP;
+}
+
+
+int dpp_akm_ver2(enum dpp_akm akm)
+{
+ return akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
+}
+
+
+int dpp_configuration_valid(const struct dpp_configuration *conf)
+{
+ if (conf->ssid_len == 0)
+ return 0;
+ if (dpp_akm_psk(conf->akm) && !conf->passphrase && !conf->psk_set)
+ return 0;
+ if (dpp_akm_sae(conf->akm) && !conf->passphrase)
+ return 0;
+ return 1;
+}
+
+
void dpp_configuration_free(struct dpp_configuration *conf)
{
if (!conf)
return;
str_clear_free(conf->passphrase);
+ os_free(conf->group_id);
bin_clear_free(conf, sizeof(*conf));
}
+static int dpp_configuration_parse(struct dpp_authentication *auth,
+ const char *cmd)
+{
+ const char *pos, *end;
+ struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
+ struct dpp_configuration *conf = NULL;
+
+ pos = os_strstr(cmd, " conf=sta-");
+ if (pos) {
+ conf_sta = dpp_configuration_alloc(pos + 10);
+ if (!conf_sta)
+ goto fail;
+ conf = conf_sta;
+ }
+
+ pos = os_strstr(cmd, " conf=ap-");
+ if (pos) {
+ conf_ap = dpp_configuration_alloc(pos + 9);
+ if (!conf_ap)
+ goto fail;
+ conf = conf_ap;
+ }
+
+ if (!conf)
+ return 0;
+
+ pos = os_strstr(cmd, " ssid=");
+ if (pos) {
+ pos += 6;
+ end = os_strchr(pos, ' ');
+ conf->ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
+ conf->ssid_len /= 2;
+ if (conf->ssid_len > sizeof(conf->ssid) ||
+ hexstr2bin(pos, conf->ssid, conf->ssid_len) < 0)
+ goto fail;
+ } else {
+#ifdef CONFIG_TESTING_OPTIONS
+ /* use a default SSID for legacy testing reasons */
+ os_memcpy(conf->ssid, "test", 4);
+ conf->ssid_len = 4;
+#else /* CONFIG_TESTING_OPTIONS */
+ goto fail;
+#endif /* CONFIG_TESTING_OPTIONS */
+ }
+
+ pos = os_strstr(cmd, " pass=");
+ if (pos) {
+ size_t pass_len;
+
+ pos += 6;
+ end = os_strchr(pos, ' ');
+ pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
+ pass_len /= 2;
+ if (pass_len > 63 || pass_len < 8)
+ goto fail;
+ conf->passphrase = os_zalloc(pass_len + 1);
+ if (!conf->passphrase ||
+ hexstr2bin(pos, (u8 *) conf->passphrase, pass_len) < 0)
+ goto fail;
+ }
+
+ pos = os_strstr(cmd, " psk=");
+ if (pos) {
+ pos += 5;
+ if (hexstr2bin(pos, conf->psk, PMK_LEN) < 0)
+ goto fail;
+ conf->psk_set = 1;
+ }
+
+ pos = os_strstr(cmd, " group_id=");
+ if (pos) {
+ size_t group_id_len;
+
+ pos += 10;
+ end = os_strchr(pos, ' ');
+ group_id_len = end ? (size_t) (end - pos) : os_strlen(pos);
+ conf->group_id = os_malloc(group_id_len + 1);
+ if (!conf->group_id)
+ goto fail;
+ os_memcpy(conf->group_id, pos, group_id_len);
+ conf->group_id[group_id_len] = '\0';
+ }
+
+ pos = os_strstr(cmd, " expiry=");
+ if (pos) {
+ long int val;
+
+ pos += 8;
+ val = strtol(pos, NULL, 0);
+ if (val <= 0)
+ goto fail;
+ conf->netaccesskey_expiry = val;
+ }
+
+ if (!dpp_configuration_valid(conf))
+ goto fail;
+
+ auth->conf_sta = conf_sta;
+ auth->conf_ap = conf_ap;
+ return 0;
+
+fail:
+ dpp_configuration_free(conf_sta);
+ dpp_configuration_free(conf_ap);
+ return -1;
+}
+
+
+static struct dpp_configurator *
+dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
+{
+ struct dpp_configurator *conf;
+
+ if (!dpp)
+ return NULL;
+
+ dl_list_for_each(conf, &dpp->configurator,
+ struct dpp_configurator, list) {
+ if (conf->id == id)
+ return conf;
+ }
+ return NULL;
+}
+
+
+int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
+ struct dpp_authentication *auth,
+ const char *cmd)
+{
+ const char *pos;
+
+ if (!cmd)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
+
+ pos = os_strstr(cmd, " configurator=");
+ if (pos) {
+ pos += 14;
+ auth->conf = dpp_configurator_get_id(dpp, atoi(pos));
+ if (!auth->conf) {
+ wpa_printf(MSG_INFO,
+ "DPP: Could not find the specified configurator");
+ return -1;
+ }
+ }
+
+ if (dpp_configuration_parse(auth, cmd) < 0) {
+ wpa_msg(msg_ctx, MSG_INFO,
+ "DPP: Failed to set configurator parameters");
+ return -1;
+ }
+ return 0;
+}
+
+
void dpp_auth_deinit(struct dpp_authentication *auth)
{
if (!auth)
@@ -2952,6 +4376,7 @@
os_free(auth->connector);
wpabuf_free(auth->net_access_key);
wpabuf_free(auth->c_sign_key);
+ dpp_bootstrap_info_free(auth->tmp_own_bi);
#ifdef CONFIG_TESTING_OPTIONS
os_free(auth->config_obj_override);
os_free(auth->discovery_override);
@@ -2990,28 +4415,12 @@
json_escape_string(ssid, sizeof(ssid),
(const char *) conf->ssid, conf->ssid_len);
wpabuf_put_str(buf, ssid);
- wpabuf_put_str(buf, "\"");
- /* TODO: optional channel information */
- wpabuf_put_str(buf, "},");
+ wpabuf_put_str(buf, "\"},");
return buf;
}
-static int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
-{
- int num_bytes, offset;
-
- num_bytes = BN_num_bytes(bn);
- if ((size_t) num_bytes > len)
- return -1;
- offset = len - num_bytes;
- os_memset(pos, 0, offset);
- BN_bn2bin(bn, pos + offset);
- return 0;
-}
-
-
static int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key,
const char *kid, const struct dpp_curve_params *curve)
{
@@ -3052,6 +4461,31 @@
}
+static void dpp_build_legacy_cred_params(struct wpabuf *buf,
+ struct dpp_configuration *conf)
+{
+ if (conf->passphrase && os_strlen(conf->passphrase) < 64) {
+ char pass[63 * 6 + 1];
+
+ json_escape_string(pass, sizeof(pass), conf->passphrase,
+ os_strlen(conf->passphrase));
+ wpabuf_put_str(buf, "\"pass\":\"");
+ wpabuf_put_str(buf, pass);
+ wpabuf_put_str(buf, "\"");
+ os_memset(pass, 0, sizeof(pass));
+ } else if (conf->psk_set) {
+ char psk[2 * sizeof(conf->psk) + 1];
+
+ wpa_snprintf_hex(psk, sizeof(psk),
+ conf->psk, sizeof(conf->psk));
+ wpabuf_put_str(buf, "\"psk_hex\":\"");
+ wpabuf_put_str(buf, psk);
+ wpabuf_put_str(buf, "\"");
+ os_memset(psk, 0, sizeof(psk));
+ }
+}
+
+
static struct wpabuf *
dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
struct dpp_configuration *conf)
@@ -3072,6 +4506,8 @@
const EVP_MD *sign_md;
const BIGNUM *r, *s;
size_t extra_len = 1000;
+ int incl_legacy;
+ enum dpp_akm akm;
if (!auth->conf) {
wpa_printf(MSG_INFO,
@@ -3090,11 +4526,21 @@
goto fail;
}
+ akm = conf->akm;
+ if (dpp_akm_ver2(akm) && auth->peer_version < 2) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
+ akm = DPP_AKM_DPP;
+ }
+
#ifdef CONFIG_TESTING_OPTIONS
if (auth->groups_override)
extra_len += os_strlen(auth->groups_override);
#endif /* CONFIG_TESTING_OPTIONS */
+ if (conf->group_id)
+ extra_len += os_strlen(conf->group_id);
+
/* Connector (JSON dppCon object) */
dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3);
if (!dppcon)
@@ -3113,7 +4559,8 @@
goto skip_groups;
}
#endif /* CONFIG_TESTING_OPTIONS */
- wpabuf_put_str(dppcon, "{\"groups\":[{\"groupId\":\"*\",");
+ wpabuf_printf(dppcon, "{\"groups\":[{\"groupId\":\"%s\",",
+ conf->group_id ? conf->group_id : "*");
wpabuf_printf(dppcon, "\"netRole\":\"%s\"}],", ap ? "ap" : "sta");
#ifdef CONFIG_TESTING_OPTIONS
skip_groups:
@@ -3203,14 +4650,22 @@
if (!signed3)
goto fail;
+ incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm);
tailroom = 1000;
tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
tailroom += signed1_len + signed2_len + signed3_len;
+ if (incl_legacy)
+ tailroom += 1000;
buf = dpp_build_conf_start(auth, conf, tailroom);
if (!buf)
- return NULL;
+ goto fail;
- wpabuf_put_str(buf, "\"cred\":{\"akm\":\"dpp\",\"signedConnector\":\"");
+ wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(akm));
+ if (incl_legacy) {
+ dpp_build_legacy_cred_params(buf, conf);
+ wpabuf_put_str(buf, ",");
+ }
+ wpabuf_put_str(buf, "\"signedConnector\":\"");
wpabuf_put_str(buf, signed1);
wpabuf_put_u8(buf, '.');
wpabuf_put_str(buf, signed2);
@@ -3255,29 +4710,8 @@
if (!buf)
return NULL;
- wpabuf_put_str(buf, "\"cred\":{\"akm\":\"psk\",");
- if (conf->passphrase) {
- char pass[63 * 6 + 1];
-
- if (os_strlen(conf->passphrase) > 63) {
- wpabuf_free(buf);
- return NULL;
- }
-
- json_escape_string(pass, sizeof(pass), conf->passphrase,
- os_strlen(conf->passphrase));
- wpabuf_put_str(buf, "\"pass\":\"");
- wpabuf_put_str(buf, pass);
- wpabuf_put_str(buf, "\"");
- } else {
- char psk[2 * sizeof(conf->psk) + 1];
-
- wpa_snprintf_hex(psk, sizeof(psk),
- conf->psk, sizeof(conf->psk));
- wpabuf_put_str(buf, "\"psk_hex\":\"");
- wpabuf_put_str(buf, psk);
- wpabuf_put_str(buf, "\"");
- }
+ wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(conf->akm));
+ dpp_build_legacy_cred_params(buf, conf);
wpabuf_put_str(buf, "}}");
wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
@@ -3308,7 +4742,7 @@
return NULL;
}
- if (conf->dpp)
+ if (dpp_akm_dpp(conf->akm))
return dpp_build_conf_obj_dpp(auth, ap, conf);
return dpp_build_conf_obj_legacy(auth, ap, conf);
}
@@ -3319,7 +4753,7 @@
u16 e_nonce_len, int ap)
{
struct wpabuf *conf;
- size_t clear_len;
+ size_t clear_len, attr_len;
struct wpabuf *clear = NULL, *msg = NULL;
u8 *wrapped;
const u8 *addr[1];
@@ -3332,33 +4766,78 @@
wpabuf_head(conf), wpabuf_len(conf));
}
status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE;
+ auth->conf_resp_status = status;
/* { E-nonce, configurationObject}ke */
clear_len = 4 + e_nonce_len;
if (conf)
clear_len += 4 + wpabuf_len(conf);
clear = wpabuf_alloc(clear_len);
- msg = wpabuf_alloc(4 + 1 + 4 + clear_len + AES_BLOCK_SIZE);
+ attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
+ attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+ msg = wpabuf_alloc(attr_len);
if (!clear || !msg)
goto fail;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
+ goto skip_e_nonce;
+ }
+ if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
+ wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
+ wpabuf_put_le16(clear, e_nonce_len);
+ wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
+ wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
+ goto skip_e_nonce;
+ }
+ if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+ goto skip_wrapped_data;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
/* E-nonce */
wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
wpabuf_put_le16(clear, e_nonce_len);
wpabuf_put_data(clear, e_nonce, e_nonce_len);
+#ifdef CONFIG_TESTING_OPTIONS
+skip_e_nonce:
+ if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
+ goto skip_config_obj;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
if (conf) {
wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
wpabuf_put_le16(clear, wpabuf_len(conf));
wpabuf_put_buf(clear, conf);
- wpabuf_free(conf);
- conf = NULL;
}
+#ifdef CONFIG_TESTING_OPTIONS
+skip_config_obj:
+ if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - Status");
+ goto skip_status;
+ }
+ if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
+ status = 255;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
/* DPP Status */
- wpabuf_put_le16(msg, DPP_ATTR_STATUS);
- wpabuf_put_le16(msg, 1);
- wpabuf_put_u8(msg, status);
+ dpp_build_attr_status(msg, status);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_status:
+#endif /* CONFIG_TESTING_OPTIONS */
addr[0] = wpabuf_head(msg);
len[0] = wpabuf_len(msg);
@@ -3375,17 +4854,26 @@
goto fail;
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
- wpabuf_free(clear);
- clear = NULL;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+ }
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
wpa_hexdump_buf(MSG_DEBUG,
"DPP: Configuration Response attributes", msg);
- return msg;
-fail:
+out:
wpabuf_free(conf);
wpabuf_free(clear);
+
+ return msg;
+fail:
wpabuf_free(msg);
- return NULL;
+ msg = NULL;
+ goto out;
}
@@ -3401,17 +4889,24 @@
struct json_token *root = NULL, *token;
int ap;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at Config Request");
+ return NULL;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
if (dpp_check_attrs(attr_start, attr_len) < 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Invalid attribute in config request");
+ dpp_auth_fail(auth, "Invalid attribute in config request");
return NULL;
}
wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
&wrapped_data_len);
if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid required Wrapped data attribute");
+ dpp_auth_fail(auth,
+ "Missing or invalid required Wrapped Data attribute");
return NULL;
}
@@ -3424,15 +4919,14 @@
if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
wrapped_data, wrapped_data_len,
0, NULL, NULL, unwrapped) < 0) {
- wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
unwrapped, unwrapped_len);
if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Invalid attribute in unwrapped data");
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
goto fail;
}
@@ -3440,18 +4934,19 @@
DPP_ATTR_ENROLLEE_NONCE,
&e_nonce_len);
if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid Enrollee Nonce attribute");
+ dpp_auth_fail(auth,
+ "Missing or invalid Enrollee Nonce attribute");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
+ os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
config_attr = dpp_get_attr(unwrapped, unwrapped_len,
DPP_ATTR_CONFIG_ATTR_OBJ,
&config_attr_len);
if (!config_attr) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid Config Attributes attribute");
+ dpp_auth_fail(auth,
+ "Missing or invalid Config Attributes attribute");
goto fail;
}
wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
@@ -3459,32 +4954,33 @@
root = json_parse((const char *) config_attr, config_attr_len);
if (!root) {
- wpa_printf(MSG_DEBUG, "DPP: Could not parse Config Attributes");
+ dpp_auth_fail(auth, "Could not parse Config Attributes");
goto fail;
}
token = json_get_member(root, "name");
if (!token || token->type != JSON_STRING) {
- wpa_printf(MSG_DEBUG, "DPP: No Config Attributes - name");
+ dpp_auth_fail(auth, "No Config Attributes - name");
goto fail;
}
wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
token = json_get_member(root, "wi-fi_tech");
if (!token || token->type != JSON_STRING) {
- wpa_printf(MSG_DEBUG, "DPP: No Config Attributes - wi-fi_tech");
+ dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
goto fail;
}
wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
if (os_strcmp(token->string, "infra") != 0) {
wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
token->string);
+ dpp_auth_fail(auth, "Unsupported wi-fi_tech");
goto fail;
}
token = json_get_member(root, "netRole");
if (!token || token->type != JSON_STRING) {
- wpa_printf(MSG_DEBUG, "DPP: No Config Attributes - netRole");
+ dpp_auth_fail(auth, "No Config Attributes - netRole");
goto fail;
}
wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
@@ -3495,6 +4991,7 @@
} else {
wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
token->string);
+ dpp_auth_fail(auth, "Unsupported netRole");
goto fail;
}
@@ -3607,6 +5104,11 @@
os_strlcpy(auth->passphrase, pass->string,
sizeof(auth->passphrase));
} else if (psk_hex && psk_hex->type == JSON_STRING) {
+ if (dpp_akm_sae(auth->akm) && !dpp_akm_psk(auth->akm)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected psk_hex with akm=sae");
+ return -1;
+ }
if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
hexstr2bin(psk_hex->string, auth->psk, PMK_LEN) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
@@ -3620,6 +5122,11 @@
return -1;
}
+ if (dpp_akm_sae(auth->akm) && !auth->passphrase[0]) {
+ wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
+ return -1;
+ }
+
return 0;
}
@@ -3639,7 +5146,7 @@
goto fail;
}
if (os_strcmp(token->string, "EC") != 0) {
- wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s",
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'",
token->string);
goto fail;
}
@@ -3950,11 +5457,11 @@
size_t payload_len;
};
-static int
+static enum dpp_status_error
dpp_process_signed_connector(struct dpp_signed_connector_info *info,
EVP_PKEY *csign_pub, const char *connector)
{
- int ret = -1;
+ enum dpp_status_error ret = 255;
const char *pos, *end, *signed_start, *signed_end;
struct wpabuf *kid = NULL;
unsigned char *prot_hdr = NULL, *signature = NULL;
@@ -3988,6 +5495,7 @@
end = os_strchr(pos, '.');
if (!end) {
wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
+ ret = DPP_STATUS_INVALID_CONNECTOR;
goto fail;
}
prot_hdr = base64_url_decode((const unsigned char *) pos,
@@ -3995,18 +5503,22 @@
if (!prot_hdr) {
wpa_printf(MSG_DEBUG,
"DPP: Failed to base64url decode signedConnector JWS Protected Header");
+ ret = DPP_STATUS_INVALID_CONNECTOR;
goto fail;
}
wpa_hexdump_ascii(MSG_DEBUG,
"DPP: signedConnector - JWS Protected Header",
prot_hdr, prot_hdr_len);
kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md);
- if (!kid)
+ if (!kid) {
+ ret = DPP_STATUS_INVALID_CONNECTOR;
goto fail;
+ }
if (wpabuf_len(kid) != SHA256_MAC_LEN) {
wpa_printf(MSG_DEBUG,
"DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
(unsigned int) wpabuf_len(kid), SHA256_MAC_LEN);
+ ret = DPP_STATUS_INVALID_CONNECTOR;
goto fail;
}
@@ -4015,6 +5527,7 @@
if (!end) {
wpa_printf(MSG_DEBUG,
"DPP: Missing dot(2) in signedConnector");
+ ret = DPP_STATUS_INVALID_CONNECTOR;
goto fail;
}
signed_end = end - 1;
@@ -4023,6 +5536,7 @@
if (!info->payload) {
wpa_printf(MSG_DEBUG,
"DPP: Failed to base64url decode signedConnector JWS Payload");
+ ret = DPP_STATUS_INVALID_CONNECTOR;
goto fail;
}
wpa_hexdump_ascii(MSG_DEBUG,
@@ -4034,18 +5548,22 @@
if (!signature) {
wpa_printf(MSG_DEBUG,
"DPP: Failed to base64url decode signedConnector signature");
+ ret = DPP_STATUS_INVALID_CONNECTOR;
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
signature, signature_len);
- if (dpp_check_pubkey_match(csign_pub, kid) < 0)
+ if (dpp_check_pubkey_match(csign_pub, kid) < 0) {
+ ret = DPP_STATUS_NO_MATCH;
goto fail;
+ }
if (signature_len & 0x01) {
wpa_printf(MSG_DEBUG,
"DPP: Unexpected signedConnector signature length (%d)",
(int) signature_len);
+ ret = DPP_STATUS_INVALID_CONNECTOR;
goto fail;
}
@@ -4086,10 +5604,11 @@
wpa_printf(MSG_DEBUG,
"DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
res, ERR_error_string(ERR_get_error(), NULL));
+ ret = DPP_STATUS_INVALID_CONNECTOR;
goto fail;
}
- ret = 0;
+ ret = DPP_STATUS_OK;
fail:
EC_KEY_free(eckey);
EVP_MD_CTX_destroy(md_ctx);
@@ -4116,6 +5635,13 @@
os_memset(&info, 0, sizeof(info));
+ if (dpp_akm_psk(auth->akm) || dpp_akm_sae(auth->akm)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Legacy credential included in Connector credential");
+ if (dpp_parse_cred_legacy(auth, cred) < 0)
+ return -1;
+ }
+
wpa_printf(MSG_DEBUG, "DPP: Connector credential");
csign = json_get_member(cred, "csign");
@@ -4148,7 +5674,7 @@
}
if (dpp_process_signed_connector(&info, csign_pub,
- signed_connector) < 0)
+ signed_connector) != DPP_STATUS_OK)
goto fail;
if (dpp_parse_connector(auth, info.payload, info.payload_len) < 0) {
@@ -4170,6 +5696,45 @@
}
+const char * dpp_akm_str(enum dpp_akm akm)
+{
+ switch (akm) {
+ case DPP_AKM_DPP:
+ return "dpp";
+ case DPP_AKM_PSK:
+ return "psk";
+ case DPP_AKM_SAE:
+ return "sae";
+ case DPP_AKM_PSK_SAE:
+ return "psk+sae";
+ case DPP_AKM_SAE_DPP:
+ return "dpp+sae";
+ case DPP_AKM_PSK_SAE_DPP:
+ return "dpp+psk+sae";
+ default:
+ return "??";
+ }
+}
+
+
+static enum dpp_akm dpp_akm_from_str(const char *akm)
+{
+ if (os_strcmp(akm, "psk") == 0)
+ return DPP_AKM_PSK;
+ if (os_strcmp(akm, "sae") == 0)
+ return DPP_AKM_SAE;
+ if (os_strcmp(akm, "psk+sae") == 0)
+ return DPP_AKM_PSK_SAE;
+ if (os_strcmp(akm, "dpp") == 0)
+ return DPP_AKM_DPP;
+ if (os_strcmp(akm, "dpp+sae") == 0)
+ return DPP_AKM_SAE_DPP;
+ if (os_strcmp(akm, "dpp+psk+sae") == 0)
+ return DPP_AKM_PSK_SAE_DPP;
+ return DPP_AKM_UNKNOWN;
+}
+
+
static int dpp_parse_conf_obj(struct dpp_authentication *auth,
const u8 *conf_obj, u16 conf_obj_len)
{
@@ -4180,38 +5745,37 @@
if (!root)
return -1;
if (root->type != JSON_OBJECT) {
- wpa_printf(MSG_DEBUG, "DPP: JSON root is not an object");
+ dpp_auth_fail(auth, "JSON root is not an object");
goto fail;
}
token = json_get_member(root, "wi-fi_tech");
if (!token || token->type != JSON_STRING) {
- wpa_printf(MSG_DEBUG, "DPP: No wi-fi_tech string value found");
+ dpp_auth_fail(auth, "No wi-fi_tech string value found");
goto fail;
}
if (os_strcmp(token->string, "infra") != 0) {
wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
token->string);
+ dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
goto fail;
}
discovery = json_get_member(root, "discovery");
if (!discovery || discovery->type != JSON_OBJECT) {
- wpa_printf(MSG_DEBUG, "DPP: No discovery object in JSON");
+ dpp_auth_fail(auth, "No discovery object in JSON");
goto fail;
}
token = json_get_member(discovery, "ssid");
if (!token || token->type != JSON_STRING) {
- wpa_printf(MSG_DEBUG,
- "DPP: No discovery::ssid string value found");
+ dpp_auth_fail(auth, "No discovery::ssid string value found");
goto fail;
}
wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
token->string, os_strlen(token->string));
if (os_strlen(token->string) > SSID_MAX_LEN) {
- wpa_printf(MSG_DEBUG,
- "DPP: Too long discovery::ssid string value");
+ dpp_auth_fail(auth, "Too long discovery::ssid string value");
goto fail;
}
auth->ssid_len = os_strlen(token->string);
@@ -4219,25 +5783,27 @@
cred = json_get_member(root, "cred");
if (!cred || cred->type != JSON_OBJECT) {
- wpa_printf(MSG_DEBUG, "DPP: No cred object in JSON");
+ dpp_auth_fail(auth, "No cred object in JSON");
goto fail;
}
token = json_get_member(cred, "akm");
if (!token || token->type != JSON_STRING) {
- wpa_printf(MSG_DEBUG,
- "DPP: No cred::akm string value found");
+ dpp_auth_fail(auth, "No cred::akm string value found");
goto fail;
}
- if (os_strcmp(token->string, "psk") == 0) {
+ auth->akm = dpp_akm_from_str(token->string);
+
+ if (dpp_akm_legacy(auth->akm)) {
if (dpp_parse_cred_legacy(auth, cred) < 0)
goto fail;
- } else if (os_strcmp(token->string, "dpp") == 0) {
+ } else if (dpp_akm_dpp(auth->akm)) {
if (dpp_parse_cred_dpp(auth, cred) < 0)
goto fail;
} else {
wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
token->string);
+ dpp_auth_fail(auth, "Unsupported akm");
goto fail;
}
@@ -4260,9 +5826,10 @@
size_t unwrapped_len = 0;
int ret = -1;
+ auth->conf_resp_status = 255;
+
if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Invalid attribute in config response");
+ dpp_auth_fail(auth, "Invalid attribute in config response");
return -1;
}
@@ -4270,8 +5837,8 @@
DPP_ATTR_WRAPPED_DATA,
&wrapped_data_len);
if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid required Wrapped data attribute");
+ dpp_auth_fail(auth,
+ "Missing or invalid required Wrapped Data attribute");
return -1;
}
@@ -4289,15 +5856,14 @@
if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
wrapped_data, wrapped_data_len,
1, addr, len, unwrapped) < 0) {
- wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
unwrapped, unwrapped_len);
if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Invalid attribute in unwrapped data");
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
goto fail;
}
@@ -4305,34 +5871,35 @@
DPP_ATTR_ENROLLEE_NONCE,
&e_nonce_len);
if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid Enrollee Nonce attribute");
+ dpp_auth_fail(auth,
+ "Missing or invalid Enrollee Nonce attribute");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
- wpa_printf(MSG_DEBUG, "Enrollee Nonce mismatch");
+ dpp_auth_fail(auth, "Enrollee Nonce mismatch");
goto fail;
}
status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
DPP_ATTR_STATUS, &status_len);
if (!status || status_len < 1) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid required DPP Status attribute");
+ dpp_auth_fail(auth,
+ "Missing or invalid required DPP Status attribute");
goto fail;
}
+ auth->conf_resp_status = status[0];
wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
if (status[0] != DPP_STATUS_OK) {
- wpa_printf(MSG_DEBUG, "DPP: Configuration failed");
+ dpp_auth_fail(auth, "Configurator rejected configuration");
goto fail;
}
conf_obj = dpp_get_attr(unwrapped, unwrapped_len,
DPP_ATTR_CONFIG_OBJ, &conf_obj_len);
if (!conf_obj) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing required Configuration Object attribute");
+ dpp_auth_fail(auth,
+ "Missing required Configuration Object attribute");
goto fail;
}
wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
@@ -4348,6 +5915,146 @@
}
+#ifdef CONFIG_DPP2
+enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
+ const u8 *hdr,
+ const u8 *attr_start, size_t attr_len)
+{
+ const u8 *wrapped_data, *status, *e_nonce;
+ u16 wrapped_data_len, status_len, e_nonce_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *unwrapped = NULL;
+ size_t unwrapped_len = 0;
+ enum dpp_status_error ret = 256;
+
+ wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
+ &wrapped_data_len);
+ if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Wrapped Data attribute");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
+ wrapped_data, wrapped_data_len);
+
+ attr_len = wrapped_data - 4 - attr_start;
+
+ addr[0] = hdr;
+ len[0] = DPP_HDR_LEN;
+ addr[1] = attr_start;
+ 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",
+ wrapped_data, wrapped_data_len);
+ unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
+ unwrapped = os_malloc(unwrapped_len);
+ if (!unwrapped)
+ goto fail;
+ if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
+ wrapped_data, wrapped_data_len,
+ 2, addr, len, unwrapped) < 0) {
+ dpp_auth_fail(auth, "AES-SIV decryption failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
+ unwrapped, unwrapped_len);
+
+ if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
+ dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
+ goto fail;
+ }
+
+ 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) {
+ dpp_auth_fail(auth,
+ "Missing or invalid Enrollee Nonce attribute");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
+ if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
+ dpp_auth_fail(auth, "Enrollee Nonce mismatch");
+ wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
+ auth->e_nonce, e_nonce_len);
+ goto fail;
+ }
+
+ status = dpp_get_attr(unwrapped, unwrapped_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]);
+ ret = status[0];
+
+fail:
+ bin_clear_free(unwrapped, unwrapped_len);
+ return ret;
+}
+#endif /* CONFIG_DPP2 */
+
+
+struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
+ enum dpp_status_error status)
+{
+ struct wpabuf *msg, *clear;
+ size_t nonce_len, clear_len, attr_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *wrapped;
+
+ nonce_len = auth->curve->nonce_len;
+ clear_len = 5 + 4 + nonce_len;
+ attr_len = 4 + clear_len + AES_BLOCK_SIZE;
+ clear = wpabuf_alloc(clear_len);
+ msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
+ if (!clear || !msg)
+ return NULL;
+
+ /* DPP Status */
+ dpp_build_attr_status(clear, status);
+
+ /* E-nonce */
+ wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
+ wpabuf_put_le16(clear, nonce_len);
+ wpabuf_put_data(clear, auth->e_nonce, nonce_len);
+
+ /* OUI, OUI type, Crypto Suite, DPP frame type */
+ addr[0] = wpabuf_head_u8(msg) + 2;
+ len[0] = 3 + 1 + 1 + 1;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+
+ /* Attributes before Wrapped Data (none) */
+ addr[1] = wpabuf_put(msg, 0);
+ len[1] = 0;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ /* Wrapped Data */
+ 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);
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
+ if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
+ wpabuf_head(clear), wpabuf_len(clear),
+ 2, addr, len, wrapped) < 0)
+ goto fail;
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Result attributes", msg);
+ wpabuf_free(clear);
+ return msg;
+fail:
+ wpabuf_free(clear);
+ wpabuf_free(msg);
+ return NULL;
+}
+
+
void dpp_configurator_free(struct dpp_configurator *conf)
{
if (!conf)
@@ -4358,6 +6065,30 @@
}
+int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
+ size_t buflen)
+{
+ EC_KEY *eckey;
+ int key_len, ret = -1;
+ unsigned char *key = NULL;
+
+ if (!conf->csign)
+ return -1;
+
+ eckey = EVP_PKEY_get1_EC_KEY(conf->csign);
+ if (!eckey)
+ return -1;
+
+ key_len = i2d_ECPrivateKey(eckey, &key);
+ if (key_len > 0)
+ ret = wpa_snprintf_hex(buf, buflen, key, key_len);
+
+ EC_KEY_free(eckey);
+ OPENSSL_free(key);
+ return ret;
+}
+
+
struct dpp_configurator *
dpp_keygen_configurator(const char *curve, const u8 *privkey,
size_t privkey_len)
@@ -4379,6 +6110,7 @@
if (!conf->curve) {
wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
curve);
+ os_free(conf);
return NULL;
}
}
@@ -4421,7 +6153,7 @@
int dpp_configurator_own_config(struct dpp_authentication *auth,
- const char *curve)
+ const char *curve, int ap)
{
struct wpabuf *conf_obj;
int ret = -1;
@@ -4452,7 +6184,7 @@
auth->peer_protocol_key = auth->own_protocol_key;
dpp_copy_csign(auth, auth->conf->csign);
- conf_obj = dpp_build_conf_obj(auth, 0);
+ conf_obj = dpp_build_conf_obj(auth, ap);
if (!conf_obj)
goto fail;
ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
@@ -4615,15 +6347,16 @@
}
-int dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
- const u8 *net_access_key, size_t net_access_key_len,
- const u8 *csign_key, size_t csign_key_len,
- const u8 *peer_connector, size_t peer_connector_len,
- os_time_t *expiry)
+enum dpp_status_error
+dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
+ const u8 *net_access_key, size_t net_access_key_len,
+ const u8 *csign_key, size_t csign_key_len,
+ const u8 *peer_connector, size_t peer_connector_len,
+ os_time_t *expiry)
{
struct json_token *root = NULL, *netkey, *token;
struct json_token *own_root = NULL;
- int ret = -1;
+ enum dpp_status_error ret = 255, res;
EVP_PKEY *own_key = NULL, *peer_key = NULL;
struct wpabuf *own_key_pub = NULL;
const struct dpp_curve_params *curve, *own_curve;
@@ -4691,18 +6424,23 @@
os_memcpy(signed_connector, peer_connector, peer_connector_len);
signed_connector[peer_connector_len] = '\0';
- if (dpp_process_signed_connector(&info, csign, signed_connector) < 0)
+ res = dpp_process_signed_connector(&info, csign, signed_connector);
+ if (res != DPP_STATUS_OK) {
+ ret = res;
goto fail;
+ }
root = json_parse((const char *) info.payload, info.payload_len);
if (!root) {
wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
+ ret = DPP_STATUS_INVALID_CONNECTOR;
goto fail;
}
if (!dpp_connector_match_groups(own_root, root)) {
wpa_printf(MSG_DEBUG,
"DPP: Peer connector does not include compatible group netrole with own connector");
+ ret = DPP_STATUS_NO_MATCH;
goto fail;
}
@@ -4715,6 +6453,7 @@
if (dpp_key_expired(token->string, expiry)) {
wpa_printf(MSG_DEBUG,
"DPP: Connector (netAccessKey) has expired");
+ ret = DPP_STATUS_INVALID_CONNECTOR;
goto fail;
}
}
@@ -4722,18 +6461,22 @@
netkey = json_get_member(root, "netAccessKey");
if (!netkey || netkey->type != JSON_OBJECT) {
wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
+ ret = DPP_STATUS_INVALID_CONNECTOR;
goto fail;
}
peer_key = dpp_parse_jwk(netkey, &curve);
- if (!peer_key)
+ if (!peer_key) {
+ ret = DPP_STATUS_INVALID_CONNECTOR;
goto fail;
+ }
dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
if (own_curve != curve) {
wpa_printf(MSG_DEBUG,
"DPP: Mismatching netAccessKey curves (%s != %s)",
own_curve->name, curve->name);
+ ret = DPP_STATUS_INVALID_CONNECTOR;
goto fail;
}
@@ -4767,9 +6510,9 @@
goto fail;
}
- ret = 0;
+ ret = DPP_STATUS_OK;
fail:
- if (ret < 0)
+ if (ret != DPP_STATUS_OK)
os_memset(intro, 0, sizeof(*intro));
os_memset(Nx, 0, sizeof(Nx));
EVP_PKEY_CTX_free(ctx);
@@ -4893,9 +6636,10 @@
EC_POINT_mul(group2, Qi, NULL, Pi_point, hash_bn, bnctx) != 1)
goto fail;
if (EC_POINT_is_at_infinity(group, Qi)) {
- wpa_printf(MSG_INFO, "PDP: Qi is the point-at-infinity");
+ wpa_printf(MSG_INFO, "DPP: Qi is the point-at-infinity");
goto fail;
}
+ dpp_debug_print_point("DPP: Qi", group, Qi);
out:
EC_KEY_free(Pi_ec);
EVP_PKEY_free(Pi);
@@ -4973,6 +6717,11 @@
if (!hash_bn ||
EC_POINT_mul(group2, Qr, NULL, Pr_point, hash_bn, bnctx) != 1)
goto fail;
+ if (EC_POINT_is_at_infinity(group, Qr)) {
+ wpa_printf(MSG_INFO, "DPP: Qr is the point-at-infinity");
+ goto fail;
+ }
+ dpp_debug_print_point("DPP: Qr", group, Qr);
out:
EC_KEY_free(Pr_ec);
EVP_PKEY_free(Pr);
@@ -4987,6 +6736,72 @@
}
+#ifdef CONFIG_TESTING_OPTIONS
+static int dpp_test_gen_invalid_key(struct wpabuf *msg,
+ const struct dpp_curve_params *curve)
+{
+ BN_CTX *ctx;
+ BIGNUM *x, *y;
+ int ret = -1;
+ EC_GROUP *group;
+ EC_POINT *point;
+
+ group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
+ if (!group)
+ return -1;
+
+ ctx = BN_CTX_new();
+ point = EC_POINT_new(group);
+ x = BN_new();
+ y = BN_new();
+ if (!ctx || !point || !x || !y)
+ goto fail;
+
+ if (BN_rand(x, curve->prime_len * 8, 0, 0) != 1)
+ goto fail;
+
+ /* Generate a random y coordinate that results in a point that is not
+ * on the curve. */
+ for (;;) {
+ if (BN_rand(y, curve->prime_len * 8, 0, 0) != 1)
+ goto fail;
+
+ if (EC_POINT_set_affine_coordinates_GFp(group, point, x, y,
+ ctx) != 1) {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
+ /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
+ * return an error from EC_POINT_set_affine_coordinates_GFp()
+ * when the point is not on the curve. */
+ break;
+#else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
+ goto fail;
+#endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
+ }
+
+ if (!EC_POINT_is_on_curve(group, point, ctx))
+ break;
+ }
+
+ if (dpp_bn2bin_pad(x, wpabuf_put(msg, curve->prime_len),
+ curve->prime_len) < 0 ||
+ dpp_bn2bin_pad(y, wpabuf_put(msg, curve->prime_len),
+ curve->prime_len) < 0)
+ goto fail;
+
+ ret = 0;
+fail:
+ if (ret < 0)
+ wpa_printf(MSG_INFO, "DPP: Failed to generate invalid key");
+ BN_free(x);
+ BN_free(y);
+ EC_POINT_free(point);
+ BN_CTX_free(ctx);
+
+ return ret;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
{
EC_KEY *X_ec = NULL;
@@ -4999,7 +6814,6 @@
struct wpabuf *msg = NULL;
size_t attr_len;
const struct dpp_curve_params *curve = pkex->own_bi->curve;
- int num_bytes, offset;
wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request");
@@ -5013,7 +6827,21 @@
goto fail;
/* Generate a random ephemeral keypair x/X */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_pkex_ephemeral_key_override_len) {
+ const struct dpp_curve_params *tmp_curve;
+
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - override ephemeral key x/X");
+ pkex->x = dpp_set_keypair(&tmp_curve,
+ dpp_pkex_ephemeral_key_override,
+ dpp_pkex_ephemeral_key_override_len);
+ } else {
+ pkex->x = dpp_gen_keypair(curve);
+ }
+#else /* CONFIG_TESTING_OPTIONS */
pkex->x = dpp_gen_keypair(curve);
+#endif /* CONFIG_TESTING_OPTIONS */
if (!pkex->x)
goto fail;
@@ -5024,6 +6852,7 @@
X_point = EC_KEY_get0_public_key(X_ec);
if (!X_point)
goto fail;
+ dpp_debug_print_point("DPP: X", group, X_point);
M = EC_POINT_new(group);
Mx = BN_new();
My = BN_new();
@@ -5031,6 +6860,7 @@
EC_POINT_add(group, M, X_point, Qi, bnctx) != 1 ||
EC_POINT_get_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1)
goto fail;
+ dpp_debug_print_point("DPP: M", group, M);
/* Initiator -> Responder: group, [identifier,] M */
attr_len = 4 + 2;
@@ -5041,11 +6871,22 @@
if (!msg)
goto fail;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
+ goto skip_finite_cyclic_group;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
/* Finite Cyclic Group attribute */
wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
wpabuf_put_le16(msg, 2);
wpabuf_put_le16(msg, curve->ike_group);
+#ifdef CONFIG_TESTING_OPTIONS
+skip_finite_cyclic_group:
+#endif /* CONFIG_TESTING_OPTIONS */
+
/* Code Identifier attribute */
if (pkex->identifier) {
wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
@@ -5053,31 +6894,32 @@
wpabuf_put_str(msg, pkex->identifier);
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
+ goto out;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
/* M in Encrypted Key attribute */
wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
wpabuf_put_le16(msg, 2 * curve->prime_len);
- num_bytes = BN_num_bytes(Mx);
- if ((size_t) num_bytes > curve->prime_len)
- goto fail;
- if (curve->prime_len > (size_t) num_bytes)
- offset = curve->prime_len - num_bytes;
- else
- offset = 0;
- os_memset(wpabuf_put(msg, offset), 0, offset);
- BN_bn2bin(Mx, wpabuf_put(msg, num_bytes));
- os_memset(pkex->Mx, 0, offset);
- BN_bn2bin(Mx, pkex->Mx + offset);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
+ if (dpp_test_gen_invalid_key(msg, curve) < 0)
+ goto fail;
+ goto out;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
- num_bytes = BN_num_bytes(My);
- if ((size_t) num_bytes > curve->prime_len)
+ if (dpp_bn2bin_pad(Mx, wpabuf_put(msg, curve->prime_len),
+ curve->prime_len) < 0 ||
+ dpp_bn2bin_pad(Mx, pkex->Mx, curve->prime_len) < 0 ||
+ dpp_bn2bin_pad(My, wpabuf_put(msg, curve->prime_len),
+ curve->prime_len) < 0)
goto fail;
- if (curve->prime_len > (size_t) num_bytes)
- offset = curve->prime_len - num_bytes;
- else
- offset = 0;
- os_memset(wpabuf_put(msg, offset), 0, offset);
- BN_bn2bin(My, wpabuf_put(msg, num_bytes));
out:
wpabuf_free(M_buf);
@@ -5096,16 +6938,31 @@
}
-struct dpp_pkex * dpp_pkex_init(struct dpp_bootstrap_info *bi,
+static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
+{
+ wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
+}
+
+
+struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
const u8 *own_mac,
const char *identifier,
const char *code)
{
struct dpp_pkex *pkex;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
+ MAC2STR(dpp_pkex_own_mac_override));
+ own_mac = dpp_pkex_own_mac_override;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
pkex = os_zalloc(sizeof(*pkex));
if (!pkex)
return NULL;
+ pkex->msg_ctx = msg_ctx;
pkex->initiator = 1;
pkex->own_bi = bi;
os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
@@ -5127,158 +6984,42 @@
}
-struct dpp_pkex * dpp_pkex_rx_exchange_req(struct dpp_bootstrap_info *bi,
- const u8 *own_mac,
- const u8 *peer_mac,
- const char *identifier,
- const char *code,
- const u8 *buf, size_t len)
+static struct wpabuf *
+dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
+ enum dpp_status_error status,
+ const BIGNUM *Nx, const BIGNUM *Ny)
{
- const u8 *attr_group, *attr_id, *attr_key;
- u16 attr_group_len, attr_id_len, attr_key_len;
- const struct dpp_curve_params *curve = bi->curve;
- u16 ike_group;
- struct dpp_pkex *pkex = NULL;
- EC_POINT *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, *N = NULL;
- BN_CTX *bnctx = NULL;
- const EC_GROUP *group;
- BIGNUM *Mx = NULL, *My = NULL;
- EC_KEY *Y_ec = NULL, *X_ec = NULL;;
- const EC_POINT *Y_point;
- BIGNUM *Nx = NULL, *Ny = NULL;
struct wpabuf *msg = NULL;
size_t attr_len;
- int num_bytes, offset;
-
- attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
- &attr_id_len);
- if (!attr_id && identifier) {
- wpa_printf(MSG_DEBUG,
- "DPP: No PKEX code identifier received, but expected one");
- return NULL;
- }
- if (attr_id && identifier &&
- (os_strlen(identifier) != attr_id_len ||
- os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
- wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
- return NULL;
- }
-
- attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
- &attr_group_len);
- if (!attr_group || attr_group_len != 2) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid Finite Cyclic Group attribute");
- return NULL;
- }
- ike_group = WPA_GET_LE16(attr_group);
- if (ike_group != curve->ike_group) {
- wpa_printf(MSG_DEBUG,
- "DPP: Mismatching PKEX curve: peer=%u own=%u",
- ike_group, curve->ike_group);
- /* TODO: error response with suggested curve:
- * DPP Status, group */
- return NULL;
- }
-
- /* M in Encrypted Key attribute */
- attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
- &attr_key_len);
- if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
- attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
- wpa_printf(MSG_DEBUG, "DPP: Missing Encrypted Key attribute");
- return NULL;
- }
-
- /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
- bnctx = BN_CTX_new();
- if (!bnctx)
- goto fail;
- Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx,
- &group);
- if (!Qi)
- goto fail;
-
- /* X' = M - Qi */
- X = EC_POINT_new(group);
- M = EC_POINT_new(group);
- Mx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
- My = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
- if (!X || !M || !Mx || !My ||
- EC_POINT_set_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1 ||
- EC_POINT_is_at_infinity(group, M) ||
- !EC_POINT_is_on_curve(group, M, bnctx) ||
- EC_POINT_invert(group, Qi, bnctx) != 1 ||
- EC_POINT_add(group, X, M, Qi, bnctx) != 1 ||
- EC_POINT_is_at_infinity(group, X) ||
- !EC_POINT_is_on_curve(group, X, bnctx))
- goto fail;
-
- pkex = os_zalloc(sizeof(*pkex));
- if (!pkex)
- goto fail;
- pkex->own_bi = bi;
- os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
- os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
- if (identifier) {
- pkex->identifier = os_strdup(identifier);
- if (!pkex->identifier)
- goto fail;
- }
- pkex->code = os_strdup(code);
- if (!pkex->code)
- goto fail;
-
- os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
-
- X_ec = EC_KEY_new();
- if (!X_ec ||
- EC_KEY_set_group(X_ec, group) != 1 ||
- EC_KEY_set_public_key(X_ec, X) != 1)
- goto fail;
- pkex->x = EVP_PKEY_new();
- if (!pkex->x ||
- EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1)
- goto fail;
-
- /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
- Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL);
- if (!Qr)
- goto fail;
-
- /* Generate a random ephemeral keypair y/Y */
- pkex->y = dpp_gen_keypair(curve);
- if (!pkex->y)
- goto fail;
-
- /* N = Y + Qr */
- Y_ec = EVP_PKEY_get1_EC_KEY(pkex->y);
- if (!Y_ec)
- goto fail;
- Y_point = EC_KEY_get0_public_key(Y_ec);
- if (!Y_point)
- goto fail;
- N = EC_POINT_new(group);
- Nx = BN_new();
- Ny = BN_new();
- if (!N || !Nx || !Ny ||
- EC_POINT_add(group, N, Y_point, Qr, bnctx) != 1 ||
- EC_POINT_get_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1)
- goto fail;
+ const struct dpp_curve_params *curve = pkex->own_bi->curve;
/* Initiator -> Responder: DPP Status, [identifier,] N */
attr_len = 4 + 1;
- if (identifier)
- attr_len += 4 + os_strlen(identifier);
+ if (pkex->identifier)
+ attr_len += 4 + os_strlen(pkex->identifier);
attr_len += 4 + 2 * curve->prime_len;
msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len);
if (!msg)
goto fail;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
+ goto skip_status;
+ }
+
+ if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
+ status = 255;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
/* DPP Status */
- wpabuf_put_le16(msg, DPP_ATTR_STATUS);
- wpabuf_put_le16(msg, 1);
- wpabuf_put_u8(msg, DPP_STATUS_OK);
+ dpp_build_attr_status(msg, status);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_status:
+#endif /* CONFIG_TESTING_OPTIONS */
/* Code Identifier attribute */
if (pkex->identifier) {
@@ -5287,56 +7028,48 @@
wpabuf_put_str(msg, pkex->identifier);
}
+ if (status != DPP_STATUS_OK)
+ goto skip_encrypted_key;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
+ goto skip_encrypted_key;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
/* N in Encrypted Key attribute */
wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
wpabuf_put_le16(msg, 2 * curve->prime_len);
- num_bytes = BN_num_bytes(Nx);
- if ((size_t) num_bytes > curve->prime_len)
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
+ if (dpp_test_gen_invalid_key(msg, curve) < 0)
+ goto fail;
+ goto skip_encrypted_key;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (dpp_bn2bin_pad(Nx, wpabuf_put(msg, curve->prime_len),
+ curve->prime_len) < 0 ||
+ dpp_bn2bin_pad(Nx, pkex->Nx, curve->prime_len) < 0 ||
+ dpp_bn2bin_pad(Ny, wpabuf_put(msg, curve->prime_len),
+ curve->prime_len) < 0)
goto fail;
- if (curve->prime_len > (size_t) num_bytes)
- offset = curve->prime_len - num_bytes;
- else
- offset = 0;
- os_memset(wpabuf_put(msg, offset), 0, offset);
- BN_bn2bin(Nx, wpabuf_put(msg, num_bytes));
- os_memset(pkex->Nx, 0, offset);
- BN_bn2bin(Nx, pkex->Nx + offset);
- num_bytes = BN_num_bytes(Ny);
- if ((size_t) num_bytes > curve->prime_len)
- goto fail;
- if (curve->prime_len > (size_t) num_bytes)
- offset = curve->prime_len - num_bytes;
- else
- offset = 0;
- os_memset(wpabuf_put(msg, offset), 0, offset);
- BN_bn2bin(Ny, wpabuf_put(msg, num_bytes));
+skip_encrypted_key:
+ if (status == DPP_STATUS_BAD_GROUP) {
+ /* Finite Cyclic Group attribute */
+ wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
+ wpabuf_put_le16(msg, 2);
+ wpabuf_put_le16(msg, curve->ike_group);
+ }
- pkex->exchange_resp = msg;
- msg = NULL;
- pkex->exchange_done = 1;
-
-out:
- wpabuf_free(msg);
- BN_CTX_free(bnctx);
- EC_POINT_free(Qi);
- EC_POINT_free(Qr);
- BN_free(Mx);
- BN_free(My);
- BN_free(Nx);
- BN_free(Ny);
- EC_POINT_free(M);
- EC_POINT_free(N);
- EC_POINT_free(X);
- EC_KEY_free(X_ec);
- EC_KEY_free(Y_ec);
- return pkex;
+ return msg;
fail:
- wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing faileed");
- dpp_pkex_free(pkex);
- pkex = NULL;
- goto out;
+ wpabuf_free(msg);
+ return NULL;
}
@@ -5399,16 +7132,394 @@
}
-struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
- const u8 *buf, size_t buflen)
+static int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len,
+ const char *identifier)
{
- const u8 *attr_status, *attr_id, *attr_key;
- u16 attr_status_len, attr_id_len, attr_key_len;
- const EC_GROUP *group;
+ if (!attr_id && identifier) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No PKEX code identifier received, but expected one");
+ return 0;
+ }
+
+ if (attr_id && !identifier) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: PKEX code identifier received, but not expecting one");
+ return 0;
+ }
+
+ if (attr_id && identifier &&
+ (os_strlen(identifier) != attr_id_len ||
+ os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
+ wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
+ struct dpp_bootstrap_info *bi,
+ const u8 *own_mac,
+ const u8 *peer_mac,
+ const char *identifier,
+ const char *code,
+ const u8 *buf, size_t len)
+{
+ const u8 *attr_group, *attr_id, *attr_key;
+ u16 attr_group_len, attr_id_len, attr_key_len;
+ const struct dpp_curve_params *curve = bi->curve;
+ u16 ike_group;
+ struct dpp_pkex *pkex = NULL;
+ EC_POINT *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, *N = NULL;
BN_CTX *bnctx = NULL;
- size_t clear_len;
+ const EC_GROUP *group;
+ BIGNUM *Mx = NULL, *My = NULL;
+ EC_KEY *Y_ec = NULL, *X_ec = NULL;;
+ const EC_POINT *Y_point;
+ BIGNUM *Nx = NULL, *Ny = NULL;
+ u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
+ size_t Kx_len;
+ int res;
+ EVP_PKEY_CTX *ctx = NULL;
+
+ if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "PKEX counter t limit reached - ignore message");
+ return NULL;
+ }
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
+ MAC2STR(dpp_pkex_peer_mac_override));
+ peer_mac = dpp_pkex_peer_mac_override;
+ }
+ if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
+ MAC2STR(dpp_pkex_own_mac_override));
+ own_mac = dpp_pkex_own_mac_override;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ attr_id_len = 0;
+ attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
+ &attr_id_len);
+ if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier))
+ return NULL;
+
+ attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
+ &attr_group_len);
+ if (!attr_group || attr_group_len != 2) {
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid Finite Cyclic Group attribute");
+ return NULL;
+ }
+ ike_group = WPA_GET_LE16(attr_group);
+ if (ike_group != curve->ike_group) {
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Mismatching PKEX curve: peer=%u own=%u",
+ ike_group, curve->ike_group);
+ pkex = os_zalloc(sizeof(*pkex));
+ if (!pkex)
+ goto fail;
+ pkex->own_bi = bi;
+ pkex->failed = 1;
+ pkex->exchange_resp = dpp_pkex_build_exchange_resp(
+ pkex, DPP_STATUS_BAD_GROUP, NULL, NULL);
+ if (!pkex->exchange_resp)
+ goto fail;
+ return pkex;
+ }
+
+ /* M in Encrypted Key attribute */
+ attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
+ &attr_key_len);
+ if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
+ attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing Encrypted Key attribute");
+ return NULL;
+ }
+
+ /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
+ bnctx = BN_CTX_new();
+ if (!bnctx)
+ goto fail;
+ Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx,
+ &group);
+ if (!Qi)
+ goto fail;
+
+ /* X' = M - Qi */
+ X = EC_POINT_new(group);
+ M = EC_POINT_new(group);
+ Mx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
+ My = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
+ if (!X || !M || !Mx || !My ||
+ EC_POINT_set_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1 ||
+ EC_POINT_is_at_infinity(group, M) ||
+ !EC_POINT_is_on_curve(group, M, bnctx) ||
+ EC_POINT_invert(group, Qi, bnctx) != 1 ||
+ EC_POINT_add(group, X, M, Qi, bnctx) != 1 ||
+ EC_POINT_is_at_infinity(group, X) ||
+ !EC_POINT_is_on_curve(group, X, bnctx)) {
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Invalid Encrypted Key value");
+ bi->pkex_t++;
+ goto fail;
+ }
+ dpp_debug_print_point("DPP: M", group, M);
+ dpp_debug_print_point("DPP: X'", group, X);
+
+ pkex = os_zalloc(sizeof(*pkex));
+ if (!pkex)
+ goto fail;
+ pkex->t = bi->pkex_t;
+ pkex->msg_ctx = msg_ctx;
+ pkex->own_bi = bi;
+ os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
+ os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
+ if (identifier) {
+ pkex->identifier = os_strdup(identifier);
+ if (!pkex->identifier)
+ goto fail;
+ }
+ pkex->code = os_strdup(code);
+ if (!pkex->code)
+ goto fail;
+
+ os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
+
+ X_ec = EC_KEY_new();
+ if (!X_ec ||
+ EC_KEY_set_group(X_ec, group) != 1 ||
+ EC_KEY_set_public_key(X_ec, X) != 1)
+ goto fail;
+ pkex->x = EVP_PKEY_new();
+ if (!pkex->x ||
+ EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1)
+ goto fail;
+
+ /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
+ Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL);
+ if (!Qr)
+ goto fail;
+
+ /* Generate a random ephemeral keypair y/Y */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_pkex_ephemeral_key_override_len) {
+ const struct dpp_curve_params *tmp_curve;
+
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - override ephemeral key y/Y");
+ pkex->y = dpp_set_keypair(&tmp_curve,
+ dpp_pkex_ephemeral_key_override,
+ dpp_pkex_ephemeral_key_override_len);
+ } else {
+ pkex->y = dpp_gen_keypair(curve);
+ }
+#else /* CONFIG_TESTING_OPTIONS */
+ pkex->y = dpp_gen_keypair(curve);
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (!pkex->y)
+ goto fail;
+
+ /* N = Y + Qr */
+ Y_ec = EVP_PKEY_get1_EC_KEY(pkex->y);
+ if (!Y_ec)
+ goto fail;
+ Y_point = EC_KEY_get0_public_key(Y_ec);
+ if (!Y_point)
+ goto fail;
+ dpp_debug_print_point("DPP: Y", group, Y_point);
+ N = EC_POINT_new(group);
+ Nx = BN_new();
+ Ny = BN_new();
+ if (!N || !Nx || !Ny ||
+ EC_POINT_add(group, N, Y_point, Qr, bnctx) != 1 ||
+ EC_POINT_get_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1)
+ goto fail;
+ dpp_debug_print_point("DPP: N", group, N);
+
+ pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
+ Nx, Ny);
+ if (!pkex->exchange_resp)
+ goto fail;
+
+ /* K = y * X' */
+ ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
+ if (!ctx ||
+ EVP_PKEY_derive_init(ctx) != 1 ||
+ EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
+ EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
+ Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
+ EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to derive ECDH shared secret: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
+ Kx, Kx_len);
+
+ /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
+ */
+ res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac,
+ pkex->Mx, curve->prime_len,
+ pkex->Nx, curve->prime_len, pkex->code,
+ Kx, Kx_len, pkex->z, curve->hash_len);
+ os_memset(Kx, 0, Kx_len);
+ if (res < 0)
+ goto fail;
+
+ pkex->exchange_done = 1;
+
+out:
+ EVP_PKEY_CTX_free(ctx);
+ BN_CTX_free(bnctx);
+ EC_POINT_free(Qi);
+ EC_POINT_free(Qr);
+ BN_free(Mx);
+ BN_free(My);
+ BN_free(Nx);
+ BN_free(Ny);
+ EC_POINT_free(M);
+ EC_POINT_free(N);
+ EC_POINT_free(X);
+ EC_KEY_free(X_ec);
+ EC_KEY_free(Y_ec);
+ return pkex;
+fail:
+ wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
+ dpp_pkex_free(pkex);
+ pkex = NULL;
+ goto out;
+}
+
+
+static struct wpabuf *
+dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
+ const struct wpabuf *A_pub, const u8 *u)
+{
+ const struct dpp_curve_params *curve = pkex->own_bi->curve;
+ struct wpabuf *msg = NULL;
+ size_t clear_len, attr_len;
struct wpabuf *clear = NULL;
u8 *wrapped;
+ u8 octet;
+ const u8 *addr[2];
+ size_t len[2];
+
+ /* {A, u, [bootstrapping info]}z */
+ clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
+ clear = wpabuf_alloc(clear_len);
+ attr_len = 4 + clear_len + AES_BLOCK_SIZE;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ)
+ attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+ msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
+ if (!clear || !msg)
+ goto fail;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
+ goto skip_bootstrap_key;
+ }
+ if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
+ wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
+ wpabuf_put_le16(clear, 2 * curve->prime_len);
+ if (dpp_test_gen_invalid_key(clear, curve) < 0)
+ goto fail;
+ goto skip_bootstrap_key;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* A in Bootstrap Key attribute */
+ wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
+ wpabuf_put_le16(clear, wpabuf_len(A_pub));
+ wpabuf_put_buf(clear, A_pub);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_bootstrap_key:
+ if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag");
+ goto skip_i_auth_tag;
+ }
+ if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch");
+ wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
+ wpabuf_put_le16(clear, curve->hash_len);
+ wpabuf_put_data(clear, u, curve->hash_len - 1);
+ wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01);
+ goto skip_i_auth_tag;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* u in I-Auth tag attribute */
+ wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
+ wpabuf_put_le16(clear, curve->hash_len);
+ wpabuf_put_data(clear, u, curve->hash_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_i_auth_tag:
+ if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+ goto skip_wrapped_data;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ addr[0] = wpabuf_head_u8(msg) + 2;
+ len[0] = DPP_HDR_LEN;
+ octet = 0;
+ addr[1] = &octet;
+ len[1] = sizeof(octet);
+ 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]);
+
+ 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);
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
+ if (aes_siv_encrypt(pkex->z, curve->hash_len,
+ wpabuf_head(clear), wpabuf_len(clear),
+ 2, addr, len, wrapped) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
+ wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+ }
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+out:
+ wpabuf_free(clear);
+ return msg;
+
+fail:
+ wpabuf_free(msg);
+ msg = NULL;
+ goto out;
+}
+
+
+struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
+ const u8 *peer_mac,
+ const u8 *buf, size_t buflen)
+{
+ const u8 *attr_status, *attr_id, *attr_key, *attr_group;
+ u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
+ const EC_GROUP *group;
+ BN_CTX *bnctx = NULL;
struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
const struct dpp_curve_params *curve = pkex->own_bi->curve;
EC_POINT *Qr = NULL, *Y = NULL, *N = NULL;
@@ -5420,32 +7531,59 @@
const u8 *addr[4];
size_t len[4];
u8 u[DPP_MAX_HASH_LEN];
- u8 octet;
int res;
+ if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
+ return NULL;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at PKEX Exchange Response");
+ pkex->failed = 1;
+ return NULL;
+ }
+
+ if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
+ MAC2STR(dpp_pkex_peer_mac_override));
+ peer_mac = dpp_pkex_peer_mac_override;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
+
attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
&attr_status_len);
if (!attr_status || attr_status_len != 1) {
- wpa_printf(MSG_DEBUG, "DPP: No DPP Status attribute");
+ dpp_pkex_fail(pkex, "No DPP Status attribute");
return NULL;
}
wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
+
+ if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
+ attr_group = dpp_get_attr(buf, buflen,
+ DPP_ATTR_FINITE_CYCLIC_GROUP,
+ &attr_group_len);
+ if (attr_group && attr_group_len == 2) {
+ wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Peer indicated mismatching PKEX group - proposed %u",
+ WPA_GET_LE16(attr_group));
+ return NULL;
+ }
+ }
+
if (attr_status[0] != DPP_STATUS_OK) {
- wpa_printf(MSG_DEBUG, "DPP: PKEX failed");
+ dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
return NULL;
}
+ attr_id_len = 0;
attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
&attr_id_len);
- if (!attr_id && pkex->identifier) {
- wpa_printf(MSG_DEBUG,
- "DPP: No PKEX code identifier received, but expected one");
- return NULL;
- }
- if (attr_id && pkex->identifier &&
- (os_strlen(pkex->identifier) != attr_id_len ||
- os_memcmp(pkex->identifier, attr_id, attr_id_len) != 0)) {
- wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
+ if (!dpp_pkex_identifier_match(attr_id, attr_id_len,
+ pkex->identifier)) {
+ dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
return NULL;
}
@@ -5453,7 +7591,7 @@
attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
&attr_key_len);
if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
- wpa_printf(MSG_DEBUG, "DPP: Missing Encrypted Key attribute");
+ dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
return NULL;
}
@@ -5478,8 +7616,13 @@
EC_POINT_invert(group, Qr, bnctx) != 1 ||
EC_POINT_add(group, Y, N, Qr, bnctx) != 1 ||
EC_POINT_is_at_infinity(group, Y) ||
- !EC_POINT_is_on_curve(group, Y, bnctx))
+ !EC_POINT_is_on_curve(group, Y, bnctx)) {
+ dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
+ pkex->t++;
goto fail;
+ }
+ dpp_debug_print_point("DPP: N", group, N);
+ dpp_debug_print_point("DPP: Y'", group, Y);
pkex->exchange_done = 1;
@@ -5556,27 +7699,106 @@
if (res < 0)
goto fail;
- /* {A, u, [bootstrapping info]}z */
+ msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
+ if (!msg)
+ goto fail;
+
+out:
+ wpabuf_free(A_pub);
+ wpabuf_free(X_pub);
+ wpabuf_free(Y_pub);
+ EC_POINT_free(Qr);
+ EC_POINT_free(Y);
+ EC_POINT_free(N);
+ BN_free(Nx);
+ BN_free(Ny);
+ EC_KEY_free(Y_ec);
+ EVP_PKEY_CTX_free(ctx);
+ BN_CTX_free(bnctx);
+ return msg;
+fail:
+ wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
+ goto out;
+}
+
+
+static struct wpabuf *
+dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
+ const struct wpabuf *B_pub, const u8 *v)
+{
+ const struct dpp_curve_params *curve = pkex->own_bi->curve;
+ struct wpabuf *msg = NULL;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 octet;
+ u8 *wrapped;
+ struct wpabuf *clear = NULL;
+ size_t clear_len, attr_len;
+
+ /* {B, v [bootstrapping info]}z */
clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
clear = wpabuf_alloc(clear_len);
- msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ,
- 4 + clear_len + AES_BLOCK_SIZE);
+ attr_len = 4 + clear_len + AES_BLOCK_SIZE;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP)
+ attr_len += 5;
+#endif /* CONFIG_TESTING_OPTIONS */
+ msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
if (!clear || !msg)
goto fail;
- /* A in Bootstrap Key attribute */
- wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
- wpabuf_put_le16(clear, wpabuf_len(A_pub));
- wpabuf_put_buf(clear, A_pub);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
+ goto skip_bootstrap_key;
+ }
+ if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
+ wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
+ wpabuf_put_le16(clear, 2 * curve->prime_len);
+ if (dpp_test_gen_invalid_key(clear, curve) < 0)
+ goto fail;
+ goto skip_bootstrap_key;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
- /* u in I-Auth tag attribute */
- wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
+ /* B in Bootstrap Key attribute */
+ wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
+ wpabuf_put_le16(clear, wpabuf_len(B_pub));
+ wpabuf_put_buf(clear, B_pub);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_bootstrap_key:
+ if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag");
+ goto skip_r_auth_tag;
+ }
+ if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch");
+ wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
+ wpabuf_put_le16(clear, curve->hash_len);
+ wpabuf_put_data(clear, v, curve->hash_len - 1);
+ wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01);
+ goto skip_r_auth_tag;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* v in R-Auth tag attribute */
+ wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
wpabuf_put_le16(clear, curve->hash_len);
- wpabuf_put_data(clear, u, curve->hash_len);
+ wpabuf_put_data(clear, v, curve->hash_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_r_auth_tag:
+ if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
+ goto skip_wrapped_data;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
addr[0] = wpabuf_head_u8(msg) + 2;
len[0] = DPP_HDR_LEN;
- octet = 0;
+ octet = 1;
addr[1] = &octet;
len[1] = sizeof(octet);
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
@@ -5594,22 +7816,19 @@
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
+ dpp_build_attr_status(msg, DPP_STATUS_OK);
+ }
+skip_wrapped_data:
+#endif /* CONFIG_TESTING_OPTIONS */
+
out:
wpabuf_free(clear);
- wpabuf_free(A_pub);
- wpabuf_free(X_pub);
- wpabuf_free(Y_pub);
- EC_POINT_free(Qr);
- EC_POINT_free(Y);
- EC_POINT_free(N);
- BN_free(Nx);
- BN_free(Ny);
- EC_KEY_free(Y_ec);
- EVP_PKEY_CTX_free(ctx);
- BN_CTX_free(bnctx);
return msg;
+
fail:
- wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing faileed");
wpabuf_free(msg);
msg = NULL;
goto out;
@@ -5621,9 +7840,9 @@
const u8 *buf, size_t buflen)
{
const struct dpp_curve_params *curve = pkex->own_bi->curve;
- EVP_PKEY_CTX *ctx;
- size_t Jx_len, Kx_len, Lx_len;
- u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
+ EVP_PKEY_CTX *ctx = NULL;
+ size_t Jx_len, Lx_len;
+ u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
const u8 *wrapped_data, *b_key, *peer_u;
u16 wrapped_data_len, b_key_len, peer_u_len = 0;
@@ -5635,43 +7854,25 @@
struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
struct wpabuf *B_pub = NULL;
u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
- size_t clear_len;
- struct wpabuf *clear = NULL;
- u8 *wrapped;
- int res;
- /* K = y * X' */
- ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 ||
- Kx_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_REQ) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at PKEX CR Request");
+ pkex->failed = 1;
+ return NULL;
}
+#endif /* CONFIG_TESTING_OPTIONS */
- wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
- Kx, Kx_len);
-
- /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
- */
- res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac,
- pkex->Mx, curve->prime_len,
- pkex->Nx, curve->prime_len, pkex->code,
- Kx, Kx_len, pkex->z, curve->hash_len);
- os_memset(Kx, 0, Kx_len);
- if (res < 0)
+ if (!pkex->exchange_done || pkex->failed ||
+ pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
goto fail;
wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
&wrapped_data_len);
if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid required Wrapped data attribute");
+ dpp_pkex_fail(pkex,
+ "Missing or invalid required Wrapped Data attribute");
goto fail;
}
@@ -5693,34 +7894,36 @@
if (aes_siv_decrypt(pkex->z, curve->hash_len,
wrapped_data, wrapped_data_len,
2, addr, len, unwrapped) < 0) {
- wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
+ dpp_pkex_fail(pkex,
+ "AES-SIV decryption failed - possible PKEX code mismatch");
+ pkex->failed = 1;
+ pkex->t++;
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
unwrapped, unwrapped_len);
if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Invalid attribute in unwrapped data");
+ dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
goto fail;
}
b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
&b_key_len);
if (!b_key || b_key_len != 2 * curve->prime_len) {
- wpa_printf(MSG_DEBUG,
- "DPP: No valid peer bootstrapping key found");
+ dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
goto fail;
}
pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
b_key_len);
- if (!pkex->peer_bootstrap_key)
+ if (!pkex->peer_bootstrap_key) {
+ dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
goto fail;
+ }
dpp_debug_print_key("DPP: Peer bootstrap public key",
pkex->peer_bootstrap_key);
/* ECDH: J' = y * A' */
- EVP_PKEY_CTX_free(ctx);
ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
if (!ctx ||
EVP_PKEY_derive_init(ctx) != 1 ||
@@ -5758,10 +7961,11 @@
&peer_u_len);
if (!peer_u || peer_u_len != curve->hash_len ||
os_memcmp(peer_u, u, curve->hash_len) != 0) {
- wpa_printf(MSG_DEBUG, "DPP: No valid u (I-Auth tag) found");
+ dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
u, curve->hash_len);
wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
+ pkex->t++;
goto fail;
}
wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
@@ -5800,43 +8004,10 @@
goto fail;
wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
- /* {B, v [bootstrapping info]}z */
- clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
- clear = wpabuf_alloc(clear_len);
- msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP,
- 4 + clear_len + AES_BLOCK_SIZE);
- if (!clear || !msg)
+ msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
+ if (!msg)
goto fail;
- /* A in Bootstrap Key attribute */
- wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
- wpabuf_put_le16(clear, wpabuf_len(B_pub));
- wpabuf_put_buf(clear, B_pub);
-
- /* v in R-Auth tag attribute */
- wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
- wpabuf_put_le16(clear, curve->hash_len);
- wpabuf_put_data(clear, v, curve->hash_len);
-
- addr[0] = wpabuf_head_u8(msg) + 2;
- len[0] = DPP_HDR_LEN;
- octet = 1;
- addr[1] = &octet;
- len[1] = sizeof(octet);
- 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]);
-
- 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);
-
- wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
- if (aes_siv_encrypt(pkex->z, curve->hash_len,
- wpabuf_head(clear), wpabuf_len(clear),
- 2, addr, len, wrapped) < 0)
- goto fail;
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
- wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
out:
EVP_PKEY_CTX_free(ctx);
os_free(unwrapped);
@@ -5844,11 +8015,10 @@
wpabuf_free(B_pub);
wpabuf_free(X_pub);
wpabuf_free(Y_pub);
- wpabuf_free(clear);
return msg;
fail:
- wpabuf_free(msg);
- msg = NULL;
+ wpa_printf(MSG_DEBUG,
+ "DPP: PKEX Commit-Reveal Request processing failed");
goto out;
}
@@ -5871,11 +8041,24 @@
EVP_PKEY_CTX *ctx = NULL;
struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at PKEX CR Response");
+ pkex->failed = 1;
+ goto fail;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (!pkex->exchange_done || pkex->failed ||
+ pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
+ goto fail;
+
wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
&wrapped_data_len);
if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid required Wrapped data attribute");
+ dpp_pkex_fail(pkex,
+ "Missing or invalid required Wrapped Data attribute");
goto fail;
}
@@ -5897,29 +8080,31 @@
if (aes_siv_decrypt(pkex->z, curve->hash_len,
wrapped_data, wrapped_data_len,
2, addr, len, unwrapped) < 0) {
- wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
+ dpp_pkex_fail(pkex,
+ "AES-SIV decryption failed - possible PKEX code mismatch");
+ pkex->t++;
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
unwrapped, unwrapped_len);
if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Invalid attribute in unwrapped data");
+ dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
goto fail;
}
b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
&b_key_len);
if (!b_key || b_key_len != 2 * curve->prime_len) {
- wpa_printf(MSG_DEBUG,
- "DPP: No valid peer bootstrapping key found");
+ dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
goto fail;
}
pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
b_key_len);
- if (!pkex->peer_bootstrap_key)
+ if (!pkex->peer_bootstrap_key) {
+ dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
goto fail;
+ }
dpp_debug_print_key("DPP: Peer bootstrap public key",
pkex->peer_bootstrap_key);
@@ -5961,10 +8146,11 @@
&peer_v_len);
if (!peer_v || peer_v_len != curve->hash_len ||
os_memcmp(peer_v, v, curve->hash_len) != 0) {
- wpa_printf(MSG_DEBUG, "DPP: No valid v (R-Auth tag) found");
+ dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
v, curve->hash_len);
wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
+ pkex->t++;
goto fail;
}
wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
@@ -5996,3 +8182,540 @@
wpabuf_free(pkex->exchange_resp);
os_free(pkex);
}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+char * dpp_corrupt_connector_signature(const char *connector)
+{
+ char *tmp, *pos, *signed3 = NULL;
+ unsigned char *signature = NULL;
+ size_t signature_len = 0, signed3_len;
+
+ tmp = os_zalloc(os_strlen(connector) + 5);
+ if (!tmp)
+ goto fail;
+ os_memcpy(tmp, connector, os_strlen(connector));
+
+ pos = os_strchr(tmp, '.');
+ if (!pos)
+ goto fail;
+
+ pos = os_strchr(pos + 1, '.');
+ if (!pos)
+ goto fail;
+ pos++;
+
+ wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s",
+ pos);
+ signature = base64_url_decode((const unsigned char *) pos,
+ os_strlen(pos), &signature_len);
+ if (!signature || signature_len == 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature",
+ signature, signature_len);
+ signature[signature_len - 1] ^= 0x01;
+ wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature",
+ signature, signature_len);
+ signed3 = (char *) base64_url_encode(signature, signature_len,
+ &signed3_len, 0);
+ if (!signed3)
+ goto fail;
+ os_memcpy(pos, signed3, signed3_len);
+ pos[signed3_len] = '\0';
+ wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s",
+ pos);
+
+out:
+ os_free(signature);
+ os_free(signed3);
+ return tmp;
+fail:
+ os_free(tmp);
+ tmp = NULL;
+ goto out;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+#ifdef CONFIG_DPP2
+
+struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
+ size_t net_access_key_len)
+{
+ struct wpabuf *pub = NULL;
+ EVP_PKEY *own_key;
+ struct dpp_pfs *pfs;
+
+ pfs = os_zalloc(sizeof(*pfs));
+ if (!pfs)
+ return NULL;
+
+ own_key = dpp_set_keypair(&pfs->curve, net_access_key,
+ net_access_key_len);
+ if (!own_key) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
+ goto fail;
+ }
+ EVP_PKEY_free(own_key);
+
+ pfs->ecdh = crypto_ecdh_init(pfs->curve->ike_group);
+ if (!pfs->ecdh)
+ goto fail;
+
+ pub = crypto_ecdh_get_pubkey(pfs->ecdh, 0);
+ pub = wpabuf_zeropad(pub, pfs->curve->prime_len);
+ if (!pub)
+ goto fail;
+
+ pfs->ie = wpabuf_alloc(5 + wpabuf_len(pub));
+ if (!pfs->ie)
+ goto fail;
+ wpabuf_put_u8(pfs->ie, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(pfs->ie, 1 + 2 + wpabuf_len(pub));
+ wpabuf_put_u8(pfs->ie, WLAN_EID_EXT_OWE_DH_PARAM);
+ wpabuf_put_le16(pfs->ie, pfs->curve->ike_group);
+ wpabuf_put_buf(pfs->ie, pub);
+ wpabuf_free(pub);
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Diffie-Hellman Parameter element",
+ pfs->ie);
+
+ return pfs;
+fail:
+ wpabuf_free(pub);
+ dpp_pfs_free(pfs);
+ return NULL;
+}
+
+
+int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len)
+{
+ if (peer_ie_len < 2)
+ return -1;
+ if (WPA_GET_LE16(peer_ie) != pfs->curve->ike_group) {
+ wpa_printf(MSG_DEBUG, "DPP: Peer used different group for PFS");
+ return -1;
+ }
+
+ pfs->secret = crypto_ecdh_set_peerkey(pfs->ecdh, 0, peer_ie + 2,
+ peer_ie_len - 2);
+ pfs->secret = wpabuf_zeropad(pfs->secret, pfs->curve->prime_len);
+ if (!pfs->secret) {
+ wpa_printf(MSG_DEBUG, "DPP: Invalid peer DH public key");
+ return -1;
+ }
+ wpa_hexdump_buf_key(MSG_DEBUG, "DPP: DH shared secret", pfs->secret);
+ return 0;
+}
+
+
+void dpp_pfs_free(struct dpp_pfs *pfs)
+{
+ if (!pfs)
+ return;
+ crypto_ecdh_deinit(pfs->ecdh);
+ wpabuf_free(pfs->ie);
+ wpabuf_clear_free(pfs->secret);
+ os_free(pfs);
+}
+
+#endif /* CONFIG_DPP2 */
+
+
+static unsigned int dpp_next_id(struct dpp_global *dpp)
+{
+ struct dpp_bootstrap_info *bi;
+ unsigned int max_id = 0;
+
+ dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
+ if (bi->id > max_id)
+ max_id = bi->id;
+ }
+ return max_id + 1;
+}
+
+
+static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
+{
+ struct dpp_bootstrap_info *bi, *tmp;
+ int found = 0;
+
+ if (!dpp)
+ return -1;
+
+ dl_list_for_each_safe(bi, tmp, &dpp->bootstrap,
+ struct dpp_bootstrap_info, list) {
+ if (id && bi->id != id)
+ continue;
+ found = 1;
+ dl_list_del(&bi->list);
+ dpp_bootstrap_info_free(bi);
+ }
+
+ if (id == 0)
+ return 0; /* flush succeeds regardless of entries found */
+ return found ? 0 : -1;
+}
+
+
+struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
+ const char *uri)
+{
+ struct dpp_bootstrap_info *bi;
+
+ if (!dpp)
+ return NULL;
+
+ bi = dpp_parse_qr_code(uri);
+ if (!bi)
+ return NULL;
+
+ bi->id = dpp_next_id(dpp);
+ dl_list_add(&dpp->bootstrap, &bi->list);
+ return bi;
+}
+
+
+int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
+{
+ char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL;
+ char *key = NULL;
+ u8 *privkey = NULL;
+ size_t privkey_len = 0;
+ size_t len;
+ int ret = -1;
+ struct dpp_bootstrap_info *bi;
+
+ if (!dpp)
+ return -1;
+
+ bi = os_zalloc(sizeof(*bi));
+ if (!bi)
+ goto fail;
+
+ if (os_strstr(cmd, "type=qrcode"))
+ bi->type = DPP_BOOTSTRAP_QR_CODE;
+ else if (os_strstr(cmd, "type=pkex"))
+ bi->type = DPP_BOOTSTRAP_PKEX;
+ else
+ goto fail;
+
+ chan = get_param(cmd, " chan=");
+ mac = get_param(cmd, " mac=");
+ info = get_param(cmd, " info=");
+ curve = get_param(cmd, " curve=");
+ key = get_param(cmd, " key=");
+
+ if (key) {
+ privkey_len = os_strlen(key) / 2;
+ privkey = os_malloc(privkey_len);
+ if (!privkey ||
+ hexstr2bin(key, privkey, privkey_len) < 0)
+ goto fail;
+ }
+
+ pk = dpp_keygen(bi, curve, privkey, privkey_len);
+ if (!pk)
+ goto fail;
+
+ len = 4; /* "DPP:" */
+ if (chan) {
+ if (dpp_parse_uri_chan_list(bi, chan) < 0)
+ goto fail;
+ len += 3 + os_strlen(chan); /* C:...; */
+ }
+ if (mac) {
+ if (dpp_parse_uri_mac(bi, mac) < 0)
+ goto fail;
+ len += 3 + os_strlen(mac); /* M:...; */
+ }
+ if (info) {
+ if (dpp_parse_uri_info(bi, info) < 0)
+ goto fail;
+ len += 3 + os_strlen(info); /* I:...; */
+ }
+ len += 4 + os_strlen(pk);
+ bi->uri = os_malloc(len + 1);
+ if (!bi->uri)
+ goto fail;
+ os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
+ chan ? "C:" : "", chan ? chan : "", chan ? ";" : "",
+ mac ? "M:" : "", mac ? mac : "", mac ? ";" : "",
+ info ? "I:" : "", info ? info : "", info ? ";" : "",
+ pk);
+ bi->id = dpp_next_id(dpp);
+ dl_list_add(&dpp->bootstrap, &bi->list);
+ ret = bi->id;
+ bi = NULL;
+fail:
+ os_free(curve);
+ os_free(pk);
+ os_free(chan);
+ os_free(mac);
+ os_free(info);
+ str_clear_free(key);
+ bin_clear_free(privkey, privkey_len);
+ dpp_bootstrap_info_free(bi);
+ return ret;
+}
+
+
+struct dpp_bootstrap_info *
+dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id)
+{
+ struct dpp_bootstrap_info *bi;
+
+ if (!dpp)
+ return NULL;
+
+ dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
+ if (bi->id == id)
+ return bi;
+ }
+ return NULL;
+}
+
+
+int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id)
+{
+ unsigned int id_val;
+
+ if (os_strcmp(id, "*") == 0) {
+ id_val = 0;
+ } else {
+ id_val = atoi(id);
+ if (id_val == 0)
+ return -1;
+ }
+
+ return dpp_bootstrap_del(dpp, id_val);
+}
+
+
+struct dpp_bootstrap_info *
+dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
+ unsigned int freq)
+{
+ struct dpp_bootstrap_info *bi;
+
+ bi = os_zalloc(sizeof(*bi));
+ if (!bi)
+ return NULL;
+ bi->id = dpp_next_id(dpp);
+ bi->type = DPP_BOOTSTRAP_PKEX;
+ os_memcpy(bi->mac_addr, peer, ETH_ALEN);
+ bi->num_freq = 1;
+ bi->freq[0] = freq;
+ bi->curve = pkex->own_bi->curve;
+ bi->pubkey = pkex->peer_bootstrap_key;
+ pkex->peer_bootstrap_key = NULL;
+ if (dpp_bootstrap_key_hash(bi) < 0) {
+ dpp_bootstrap_info_free(bi);
+ return NULL;
+ }
+ dpp_pkex_free(pkex);
+ dl_list_add(&dpp->bootstrap, &bi->list);
+ return bi;
+}
+
+
+const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id)
+{
+ struct dpp_bootstrap_info *bi;
+
+ bi = dpp_bootstrap_get_id(dpp, id);
+ if (!bi)
+ return NULL;
+ return bi->uri;
+}
+
+
+int dpp_bootstrap_info(struct dpp_global *dpp, int id,
+ char *reply, int reply_size)
+{
+ struct dpp_bootstrap_info *bi;
+
+ bi = dpp_bootstrap_get_id(dpp, id);
+ if (!bi)
+ return -1;
+ return os_snprintf(reply, reply_size, "type=%s\n"
+ "mac_addr=" MACSTR "\n"
+ "info=%s\n"
+ "num_freq=%u\n"
+ "curve=%s\n",
+ dpp_bootstrap_type_txt(bi->type),
+ MAC2STR(bi->mac_addr),
+ bi->info ? bi->info : "",
+ bi->num_freq,
+ bi->curve->name);
+}
+
+
+void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
+ const u8 *r_bootstrap,
+ struct dpp_bootstrap_info **own_bi,
+ struct dpp_bootstrap_info **peer_bi)
+{
+ struct dpp_bootstrap_info *bi;
+
+ *own_bi = NULL;
+ *peer_bi = NULL;
+ if (!dpp)
+ return;
+
+ dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
+ if (!*own_bi && bi->own &&
+ os_memcmp(bi->pubkey_hash, r_bootstrap,
+ SHA256_MAC_LEN) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Found matching own bootstrapping information");
+ *own_bi = bi;
+ }
+
+ if (!*peer_bi && !bi->own &&
+ os_memcmp(bi->pubkey_hash, i_bootstrap,
+ SHA256_MAC_LEN) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Found matching peer bootstrapping information");
+ *peer_bi = bi;
+ }
+
+ if (*own_bi && *peer_bi)
+ break;
+ }
+
+}
+
+
+static unsigned int dpp_next_configurator_id(struct dpp_global *dpp)
+{
+ struct dpp_configurator *conf;
+ unsigned int max_id = 0;
+
+ dl_list_for_each(conf, &dpp->configurator, struct dpp_configurator,
+ list) {
+ if (conf->id > max_id)
+ max_id = conf->id;
+ }
+ return max_id + 1;
+}
+
+
+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;
+ int ret = -1;
+ struct dpp_configurator *conf = NULL;
+
+ curve = get_param(cmd, " curve=");
+ key = get_param(cmd, " key=");
+
+ if (key) {
+ privkey_len = os_strlen(key) / 2;
+ privkey = os_malloc(privkey_len);
+ if (!privkey ||
+ hexstr2bin(key, privkey, privkey_len) < 0)
+ goto fail;
+ }
+
+ conf = dpp_keygen_configurator(curve, privkey, privkey_len);
+ if (!conf)
+ goto fail;
+
+ conf->id = dpp_next_configurator_id(dpp);
+ dl_list_add(&dpp->configurator, &conf->list);
+ ret = conf->id;
+ conf = NULL;
+fail:
+ os_free(curve);
+ str_clear_free(key);
+ bin_clear_free(privkey, privkey_len);
+ dpp_configurator_free(conf);
+ return ret;
+}
+
+
+static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id)
+{
+ struct dpp_configurator *conf, *tmp;
+ int found = 0;
+
+ if (!dpp)
+ return -1;
+
+ dl_list_for_each_safe(conf, tmp, &dpp->configurator,
+ struct dpp_configurator, list) {
+ if (id && conf->id != id)
+ continue;
+ found = 1;
+ dl_list_del(&conf->list);
+ dpp_configurator_free(conf);
+ }
+
+ if (id == 0)
+ return 0; /* flush succeeds regardless of entries found */
+ return found ? 0 : -1;
+}
+
+
+int dpp_configurator_remove(struct dpp_global *dpp, const char *id)
+{
+ unsigned int id_val;
+
+ if (os_strcmp(id, "*") == 0) {
+ id_val = 0;
+ } else {
+ id_val = atoi(id);
+ if (id_val == 0)
+ return -1;
+ }
+
+ return dpp_configurator_del(dpp, id_val);
+}
+
+
+int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
+ char *buf, size_t buflen)
+{
+ struct dpp_configurator *conf;
+
+ conf = dpp_configurator_get_id(dpp, id);
+ if (!conf)
+ return -1;
+
+ return dpp_configurator_get_key(conf, buf, buflen);
+}
+
+
+struct dpp_global * dpp_global_init(void)
+{
+ struct dpp_global *dpp;
+
+ dpp = os_zalloc(sizeof(*dpp));
+ if (!dpp)
+ return NULL;
+
+ dl_list_init(&dpp->bootstrap);
+ dl_list_init(&dpp->configurator);
+
+ return dpp;
+}
+
+
+void dpp_global_clear(struct dpp_global *dpp)
+{
+ if (!dpp)
+ return;
+
+ dpp_bootstrap_del(dpp, 0);
+ dpp_configurator_del(dpp, 0);
+}
+
+
+void dpp_global_deinit(struct dpp_global *dpp)
+{
+ dpp_global_clear(dpp);
+ os_free(dpp);
+}
diff --git a/src/common/dpp.h b/src/common/dpp.h
index dfee499..5a6d8cc 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -1,6 +1,7 @@
/*
* DPP functionality shared between hostapd and wpa_supplicant
* Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2019, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,12 +10,16 @@
#ifndef DPP_H
#define DPP_H
+#ifdef CONFIG_DPP
#include <openssl/x509.h>
#include "utils/list.h"
#include "common/wpa_common.h"
#include "crypto/sha256.h"
+struct crypto_ecdh;
+struct dpp_global;
+
#define DPP_HDR_LEN (4 + 2) /* OUI, OUI Type, Crypto Suite, DPP frame type */
enum dpp_public_action_frame_type {
@@ -27,6 +32,7 @@
DPP_PA_PKEX_EXCHANGE_RESP = 8,
DPP_PA_PKEX_COMMIT_REVEAL_REQ = 9,
DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10,
+ DPP_PA_CONFIGURATION_RESULT = 11,
};
enum dpp_attribute_id {
@@ -52,6 +58,10 @@
DPP_ATTR_ENROLLEE_NONCE = 0x1014,
DPP_ATTR_CODE_IDENTIFIER = 0x1015,
DPP_ATTR_TRANSACTION_ID = 0x1016,
+ DPP_ATTR_BOOTSTRAP_INFO = 0x1017,
+ DPP_ATTR_CHANNEL = 0x1018,
+ DPP_ATTR_PROTOCOL_VERSION = 0x1019,
+ DPP_ATTR_ENVELOPED_DATA = 0x101A,
};
enum dpp_status_error {
@@ -62,6 +72,9 @@
DPP_STATUS_BAD_GROUP = 4,
DPP_STATUS_CONFIGURE_FAILURE = 5,
DPP_STATUS_RESPONSE_PENDING = 6,
+ DPP_STATUS_INVALID_CONNECTOR = 7,
+ DPP_STATUS_NO_MATCH = 8,
+ DPP_STATUS_CONFIG_REJECTED = 9,
};
#define DPP_CAPAB_ENROLLEE BIT(0)
@@ -102,11 +115,17 @@
EVP_PKEY *pubkey;
u8 pubkey_hash[SHA256_MAC_LEN];
const struct dpp_curve_params *curve;
+ unsigned int pkex_t; /* number of failures before dpp_pkex
+ * instantiation */
};
+#define PKEX_COUNTER_T_LIMIT 5
+
struct dpp_pkex {
+ void *msg_ctx;
unsigned int initiator:1;
unsigned int exchange_done:1;
+ unsigned int failed:1;
struct dpp_bootstrap_info *own_bi;
u8 own_mac[ETH_ALEN];
u8 peer_mac[ETH_ALEN];
@@ -120,31 +139,50 @@
EVP_PKEY *peer_bootstrap_key;
struct wpabuf *exchange_req;
struct wpabuf *exchange_resp;
+ unsigned int t; /* number of failures on code use */
+ unsigned int exch_req_wait_time;
+ unsigned int exch_req_tries;
+ unsigned int freq;
+};
+
+enum dpp_akm {
+ DPP_AKM_UNKNOWN,
+ DPP_AKM_DPP,
+ DPP_AKM_PSK,
+ DPP_AKM_SAE,
+ DPP_AKM_PSK_SAE,
+ DPP_AKM_SAE_DPP,
+ DPP_AKM_PSK_SAE_DPP,
};
struct dpp_configuration {
u8 ssid[32];
size_t ssid_len;
- int dpp; /* whether to use DPP or legacy configuration */
+ enum dpp_akm akm;
/* For DPP configuration (connector) */
os_time_t netaccesskey_expiry;
/* TODO: groups */
+ char *group_id;
/* For legacy configuration */
char *passphrase;
u8 psk[32];
+ int psk_set;
};
struct dpp_authentication {
void *msg_ctx;
+ u8 peer_version;
const struct dpp_curve_params *curve;
struct dpp_bootstrap_info *peer_bi;
struct dpp_bootstrap_info *own_bi;
+ struct dpp_bootstrap_info *tmp_own_bi;
u8 waiting_pubkey_hash[SHA256_MAC_LEN];
int response_pending;
enum dpp_status_error auth_resp_status;
+ enum dpp_status_error conf_resp_status;
u8 peer_mac_addr[ETH_ALEN];
u8 i_nonce[DPP_MAX_NONCE_LEN];
u8 r_nonce[DPP_MAX_NONCE_LEN];
@@ -155,19 +193,36 @@
EVP_PKEY *peer_protocol_key;
struct wpabuf *req_msg;
struct wpabuf *resp_msg;
+ /* Intersection of possible frequencies for initiating DPP
+ * Authentication exchange */
+ unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
+ unsigned int num_freq, freq_idx;
unsigned int curr_freq;
+ unsigned int neg_freq;
+ unsigned int num_freq_iters;
size_t secret_len;
u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
+ size_t Mx_len;
u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
+ size_t Nx_len;
u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
+ size_t Lx_len;
u8 k1[DPP_MAX_HASH_LEN];
u8 k2[DPP_MAX_HASH_LEN];
u8 ke[DPP_MAX_HASH_LEN];
int initiator;
+ int waiting_auth_resp;
+ int waiting_auth_conf;
+ int auth_req_ack;
+ unsigned int auth_resp_tries;
+ u8 allowed_roles;
int configurator;
int remove_on_tx_status;
+ int connect_on_tx_status;
+ int waiting_conf_result;
int auth_success;
struct wpabuf *conf_req;
+ const struct wpabuf *conf_resp; /* owned by GAS server */
struct dpp_configuration *conf_ap;
struct dpp_configuration *conf_sta;
struct dpp_configurator *conf;
@@ -177,6 +232,7 @@
char passphrase[64];
u8 psk[PMK_LEN];
int psk_set;
+ enum dpp_akm akm;
struct wpabuf *net_access_key;
os_time_t net_access_key_expiry;
struct wpabuf *c_sign_key;
@@ -203,6 +259,113 @@
size_t pmk_len;
};
+#ifdef CONFIG_TESTING_OPTIONS
+enum dpp_test_behavior {
+ DPP_TEST_DISABLED = 0,
+ DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ = 1,
+ DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP = 2,
+ DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF = 3,
+ DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ = 4,
+ DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP = 5,
+ DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ = 6,
+ DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP = 7,
+ DPP_TEST_ZERO_I_CAPAB = 8,
+ DPP_TEST_ZERO_R_CAPAB = 9,
+ DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ = 10,
+ DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ = 11,
+ DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ = 12,
+ DPP_TEST_NO_I_NONCE_AUTH_REQ = 13,
+ DPP_TEST_NO_I_CAPAB_AUTH_REQ = 14,
+ DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ = 15,
+ DPP_TEST_NO_STATUS_AUTH_RESP = 16,
+ DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP = 17,
+ DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP = 18,
+ DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP = 19,
+ DPP_TEST_NO_R_NONCE_AUTH_RESP = 20,
+ DPP_TEST_NO_I_NONCE_AUTH_RESP = 21,
+ DPP_TEST_NO_R_CAPAB_AUTH_RESP = 22,
+ DPP_TEST_NO_R_AUTH_AUTH_RESP = 23,
+ DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP = 24,
+ DPP_TEST_NO_STATUS_AUTH_CONF = 25,
+ DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF = 26,
+ DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF = 27,
+ DPP_TEST_NO_I_AUTH_AUTH_CONF = 28,
+ DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF = 29,
+ DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP = 30,
+ DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP = 31,
+ DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP = 32,
+ DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF = 33,
+ DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ = 34,
+ DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ = 35,
+ DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP = 36,
+ DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP = 37,
+ DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ = 38,
+ DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ = 39,
+ DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ = 40,
+ DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP = 41,
+ DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP = 42,
+ DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP = 43,
+ DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ = 44,
+ DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP = 45,
+ DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP = 46,
+ DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ = 47,
+ DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP = 48,
+ DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ = 49,
+ DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP = 50,
+ DPP_TEST_NO_E_NONCE_CONF_REQ = 51,
+ DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ = 52,
+ DPP_TEST_NO_WRAPPED_DATA_CONF_REQ = 53,
+ DPP_TEST_NO_E_NONCE_CONF_RESP = 54,
+ DPP_TEST_NO_CONFIG_OBJ_CONF_RESP = 55,
+ DPP_TEST_NO_STATUS_CONF_RESP = 56,
+ DPP_TEST_NO_WRAPPED_DATA_CONF_RESP = 57,
+ DPP_TEST_INVALID_STATUS_CONF_RESP = 58,
+ DPP_TEST_E_NONCE_MISMATCH_CONF_RESP = 59,
+ DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_REQ = 60,
+ DPP_TEST_NO_CONNECTOR_PEER_DISC_REQ = 61,
+ DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_RESP = 62,
+ DPP_TEST_NO_STATUS_PEER_DISC_RESP = 63,
+ DPP_TEST_NO_CONNECTOR_PEER_DISC_RESP = 64,
+ DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF = 65,
+ DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ = 66,
+ DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP = 67,
+ DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ = 68,
+ DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ = 69,
+ DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP = 70,
+ DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP = 71,
+ DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF = 72,
+ DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF = 73,
+ DPP_TEST_INVALID_STATUS_AUTH_RESP = 74,
+ DPP_TEST_INVALID_STATUS_AUTH_CONF = 75,
+ DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ = 76,
+ DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_RESP = 77,
+ DPP_TEST_INVALID_STATUS_PEER_DISC_RESP = 78,
+ DPP_TEST_INVALID_CONNECTOR_PEER_DISC_RESP = 79,
+ DPP_TEST_INVALID_CONNECTOR_PEER_DISC_REQ = 80,
+ DPP_TEST_INVALID_I_NONCE_AUTH_REQ = 81,
+ DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_REQ = 82,
+ DPP_TEST_INVALID_E_NONCE_CONF_REQ = 83,
+ DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP = 84,
+ DPP_TEST_STOP_AT_PKEX_CR_REQ = 85,
+ DPP_TEST_STOP_AT_PKEX_CR_RESP = 86,
+ DPP_TEST_STOP_AT_AUTH_REQ = 87,
+ DPP_TEST_STOP_AT_AUTH_RESP = 88,
+ DPP_TEST_STOP_AT_AUTH_CONF = 89,
+ DPP_TEST_STOP_AT_CONF_REQ = 90,
+ DPP_TEST_REJECT_CONFIG = 91,
+};
+
+extern enum dpp_test_behavior dpp_test;
+extern u8 dpp_pkex_own_mac_override[ETH_ALEN];
+extern u8 dpp_pkex_peer_mac_override[ETH_ALEN];
+extern u8 dpp_pkex_ephemeral_key_override[600];
+extern size_t dpp_pkex_ephemeral_key_override_len;
+extern u8 dpp_protocol_key_override[600];
+extern size_t dpp_protocol_key_override_len;
+extern u8 dpp_nonce_override[DPP_MAX_NONCE_LEN];
+extern size_t dpp_nonce_override_len;
+#endif /* CONFIG_TESTING_OPTIONS */
+
void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info);
const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type);
int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi);
@@ -213,16 +376,20 @@
struct dpp_bootstrap_info * dpp_parse_qr_code(const char *uri);
char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
const u8 *privkey, size_t privkey_len);
+struct hostapd_hw_modes;
struct dpp_authentication * dpp_auth_init(void *msg_ctx,
struct dpp_bootstrap_info *peer_bi,
struct dpp_bootstrap_info *own_bi,
- int configurator);
+ u8 dpp_allowed_roles,
+ unsigned int neg_freq,
+ struct hostapd_hw_modes *own_modes,
+ u16 num_modes);
struct dpp_authentication *
dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
struct dpp_bootstrap_info *peer_bi,
struct dpp_bootstrap_info *own_bi,
unsigned int freq, const u8 *hdr, const u8 *attr_start,
- const u8 *wrapped_data, u16 wrapped_data_len);
+ size_t attr_len);
struct wpabuf *
dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
const u8 *attr_start, size_t attr_len);
@@ -232,40 +399,61 @@
const u8 *attr_start, size_t attr_len);
int dpp_notify_new_qr_code(struct dpp_authentication *auth,
struct dpp_bootstrap_info *peer_bi);
+struct dpp_configuration * dpp_configuration_alloc(const char *type);
+int dpp_akm_psk(enum dpp_akm akm);
+int dpp_akm_sae(enum dpp_akm akm);
+int dpp_akm_legacy(enum dpp_akm akm);
+int dpp_akm_dpp(enum dpp_akm akm);
+int dpp_akm_ver2(enum dpp_akm akm);
+int dpp_configuration_valid(const struct dpp_configuration *conf);
void dpp_configuration_free(struct dpp_configuration *conf);
+int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
+ struct dpp_authentication *auth,
+ const char *cmd);
void dpp_auth_deinit(struct dpp_authentication *auth);
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,
const struct wpabuf *resp);
+enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
+ const u8 *hdr,
+ const u8 *attr_start, size_t attr_len);
+struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
+ enum dpp_status_error status);
struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
size_t len);
const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len);
int dpp_check_attrs(const u8 *buf, size_t len);
int dpp_key_expired(const char *timestamp, os_time_t *expiry);
+const char * dpp_akm_str(enum dpp_akm akm);
+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 dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
- const u8 *net_access_key, size_t net_access_key_len,
- const u8 *csign_key, size_t csign_key_len,
- const u8 *peer_connector, size_t peer_connector_len,
- os_time_t *expiry);
-struct dpp_pkex * dpp_pkex_init(struct dpp_bootstrap_info *bi,
+ const char *curve, int ap);
+enum dpp_status_error
+dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
+ const u8 *net_access_key, size_t net_access_key_len,
+ const u8 *csign_key, size_t csign_key_len,
+ const u8 *peer_connector, size_t peer_connector_len,
+ os_time_t *expiry);
+struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
const u8 *own_mac,
const char *identifier,
const char *code);
-struct dpp_pkex * dpp_pkex_rx_exchange_req(struct dpp_bootstrap_info *bi,
+struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
+ struct dpp_bootstrap_info *bi,
const u8 *own_mac,
const u8 *peer_mac,
const char *identifier,
const char *code,
const u8 *buf, size_t len);
struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
+ const u8 *peer_mac,
const u8 *buf, size_t len);
struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
const u8 *hdr,
@@ -274,4 +462,44 @@
const u8 *buf, size_t len);
void dpp_pkex_free(struct dpp_pkex *pkex);
+char * dpp_corrupt_connector_signature(const char *connector);
+
+
+struct dpp_pfs {
+ struct crypto_ecdh *ecdh;
+ const struct dpp_curve_params *curve;
+ struct wpabuf *ie;
+ struct wpabuf *secret;
+};
+
+struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
+ size_t net_access_key_len);
+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 dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
+ const char *uri);
+int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd);
+struct dpp_bootstrap_info *
+dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id);
+int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id);
+struct dpp_bootstrap_info *
+dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
+ unsigned int freq);
+const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id);
+int dpp_bootstrap_info(struct dpp_global *dpp, int id,
+ char *reply, int reply_size);
+void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
+ const u8 *r_bootstrap,
+ struct dpp_bootstrap_info **own_bi,
+ struct dpp_bootstrap_info **peer_bi);
+int dpp_configurator_add(struct dpp_global *dpp, const char *cmd);
+int dpp_configurator_remove(struct dpp_global *dpp, const char *id);
+int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
+ char *buf, size_t buflen);
+struct dpp_global * dpp_global_init(void);
+void dpp_global_clear(struct dpp_global *dpp);
+void dpp_global_deinit(struct dpp_global *dpp);
+
+#endif /* CONFIG_DPP */
#endif /* DPP_H */
diff --git a/src/common/gas_server.c b/src/common/gas_server.c
index b258675..ca46758 100644
--- a/src/common/gas_server.c
+++ b/src/common/gas_server.c
@@ -97,8 +97,10 @@
return;
response = os_zalloc(sizeof(*response));
- if (!response)
+ if (!response) {
+ wpabuf_free(query_resp);
return;
+ }
wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response);
response->freq = freq;
response->handler = handler;
@@ -119,6 +121,7 @@
handler->adv_proto_id_len +
resp_frag_len);
if (!resp) {
+ wpabuf_free(query_resp);
gas_server_free_response(response);
return;
}
@@ -257,6 +260,7 @@
handler->adv_proto_id_len +
resp_frag_len);
if (!resp) {
+ dl_list_del(&response->list);
gas_server_free_response(response);
return;
}
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index fdd5e73..49ed806 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -87,13 +87,29 @@
int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
int sec_chan)
{
- int ok, j, first;
+ int ok, first;
int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 140,
- 149, 157, 184, 192 };
+ 149, 157, 165, 184, 192 };
size_t k;
+ struct hostapd_channel_data *p_chan, *s_chan;
+ const int ht40_plus = pri_chan < sec_chan;
- if (pri_chan == sec_chan || !sec_chan)
- return 1; /* HT40 not used */
+ p_chan = hw_get_channel_chan(mode, pri_chan, NULL);
+ if (!p_chan)
+ return 0;
+
+ if (pri_chan == sec_chan || !sec_chan) {
+ if (chan_pri_allowed(p_chan))
+ return 1; /* HT40 not used */
+
+ wpa_printf(MSG_ERROR, "Channel %d is not allowed as primary",
+ pri_chan);
+ return 0;
+ }
+
+ s_chan = hw_get_channel_chan(mode, sec_chan, NULL);
+ if (!s_chan)
+ return 0;
wpa_printf(MSG_DEBUG,
"HT40: control channel: %d secondary channel: %d",
@@ -101,16 +117,9 @@
/* Verify that HT40 secondary channel is an allowed 20 MHz
* channel */
- ok = 0;
- for (j = 0; j < mode->num_channels; j++) {
- struct hostapd_channel_data *chan = &mode->channels[j];
- if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
- chan->chan == sec_chan) {
- ok = 1;
- break;
- }
- }
- if (!ok) {
+ if ((s_chan->flag & HOSTAPD_CHAN_DISABLED) ||
+ (ht40_plus && !(p_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) ||
+ (!ht40_plus && !(p_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M))) {
wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
sec_chan);
return 0;
@@ -553,3 +562,59 @@
}
#endif /* CONFIG_IEEE80211AC */
+
+
+u32 num_chan_to_bw(int num_chans)
+{
+ switch (num_chans) {
+ case 2:
+ case 4:
+ case 8:
+ return num_chans * 20;
+ default:
+ return 20;
+ }
+}
+
+
+/* check if BW is applicable for channel */
+int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw,
+ int ht40_plus, int pri)
+{
+ u32 bw_mask;
+
+ switch (bw) {
+ case 20:
+ bw_mask = HOSTAPD_CHAN_WIDTH_20;
+ break;
+ case 40:
+ /* HT 40 MHz support declared only for primary channel,
+ * just skip 40 MHz secondary checking */
+ if (pri && ht40_plus)
+ bw_mask = HOSTAPD_CHAN_WIDTH_40P;
+ else if (pri && !ht40_plus)
+ bw_mask = HOSTAPD_CHAN_WIDTH_40M;
+ else
+ bw_mask = 0;
+ break;
+ case 80:
+ bw_mask = HOSTAPD_CHAN_WIDTH_80;
+ break;
+ case 160:
+ bw_mask = HOSTAPD_CHAN_WIDTH_160;
+ break;
+ default:
+ bw_mask = 0;
+ break;
+ }
+
+ return (chan->allowed_bw & bw_mask) == bw_mask;
+}
+
+
+/* check if channel is allowed to be used as primary */
+int chan_pri_allowed(const struct hostapd_channel_data *chan)
+{
+ return !(chan->flag & HOSTAPD_CHAN_DISABLED) &&
+ (chan->allowed_bw & HOSTAPD_CHAN_WIDTH_20);
+}
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index 9cddbd5..eb1f1c5 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -39,4 +39,9 @@
int disabled);
int ieee80211ac_cap_check(u32 hw, u32 conf);
+u32 num_chan_to_bw(int num_chans);
+int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw,
+ int ht40_plus, int pri);
+int chan_pri_allowed(const struct hostapd_channel_data *chan);
+
#endif /* HW_FEATURES_COMMON_H */
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 120d4e8..f886551 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 Common routines
- * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,7 @@
#include "common.h"
#include "defs.h"
#include "wpa_common.h"
+#include "drivers/driver.h"
#include "qca-vendor.h"
#include "ieee802_11_defs.h"
#include "ieee802_11_common.h"
@@ -120,6 +121,15 @@
elems->mbo = pos;
elems->mbo_len = elen;
break;
+ case HS20_ROAMING_CONS_SEL_OUI_TYPE:
+ /* Hotspot 2.0 Roaming Consortium Selection */
+ elems->roaming_cons_sel = pos;
+ elems->roaming_cons_sel_len = elen;
+ break;
+ case MULTI_AP_OUI_TYPE:
+ elems->multi_ap = pos;
+ elems->multi_ap_len = elen;
+ break;
default:
wpa_printf(MSG_MSGDUMP, "Unknown WFA "
"information element ignored "
@@ -256,6 +266,18 @@
elems->owe_dh = pos;
elems->owe_dh_len = elen;
break;
+ case WLAN_EID_EXT_PASSWORD_IDENTIFIER:
+ elems->password_id = pos;
+ elems->password_id_len = elen;
+ break;
+ case WLAN_EID_EXT_HE_CAPABILITIES:
+ elems->he_capabilities = pos;
+ elems->he_capabilities_len = elen;
+ break;
+ case WLAN_EID_EXT_OCV_OCI:
+ elems->oci = pos;
+ elems->oci_len = elen;
+ break;
default:
if (show_errors) {
wpa_printf(MSG_MSGDUMP,
@@ -281,29 +303,17 @@
struct ieee802_11_elems *elems,
int show_errors)
{
- size_t left = len;
- const u8 *pos = start;
+ const struct element *elem;
int unknown = 0;
os_memset(elems, 0, sizeof(*elems));
- while (left >= 2) {
- u8 id, elen;
+ if (!start)
+ return ParseOK;
- id = *pos++;
- elen = *pos++;
- left -= 2;
-
- if (elen > left) {
- if (show_errors) {
- wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
- "parse failed (id=%d elen=%d "
- "left=%lu)",
- id, elen, (unsigned long) left);
- wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
- }
- return ParseFailed;
- }
+ for_each_element(elem, start, len) {
+ u8 id = elem->id, elen = elem->datalen;
+ const u8 *pos = elem->data;
switch (id) {
case WLAN_EID_SSID:
@@ -352,6 +362,10 @@
elems->rsn_ie_len = elen;
break;
case WLAN_EID_PWR_CAPABILITY:
+ if (elen < 2)
+ break;
+ elems->power_capab = pos;
+ elems->power_capab_len = elen;
break;
case WLAN_EID_SUPPORTED_CHANNELS:
elems->supp_channels = pos;
@@ -447,8 +461,7 @@
elems->mic = pos;
elems->mic_len = elen;
/* after mic everything is encrypted, so stop. */
- left = elen;
- break;
+ goto done;
case WLAN_EID_MULTI_BAND:
if (elems->mb_ies.nof_ies >= MAX_NOF_MB_IES_SUPPORTED) {
wpa_printf(MSG_MSGDUMP,
@@ -507,35 +520,33 @@
id, elen);
break;
}
-
- left -= elen;
- pos += elen;
}
- if (left)
+ if (!for_each_element_completed(elem, start, len)) {
+ if (show_errors) {
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.11 element parse failed @%d",
+ (int) (start + len - (const u8 *) elem));
+ wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
+ }
return ParseFailed;
+ }
+done:
return unknown ? ParseUnknown : ParseOK;
}
int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
{
+ const struct element *elem;
int count = 0;
- const u8 *pos, *end;
if (ies == NULL)
return 0;
- pos = ies;
- end = ies + ies_len;
-
- while (end - pos >= 2) {
- if (2 + pos[1] > end - pos)
- break;
+ for_each_element(elem, ies, ies_len)
count++;
- pos += 2 + pos[1];
- }
return count;
}
@@ -545,24 +556,17 @@
u32 oui_type)
{
struct wpabuf *buf;
- const u8 *end, *pos, *ie;
+ const struct element *elem, *found = NULL;
- pos = ies;
- end = ies + ies_len;
- ie = NULL;
-
- while (end - pos > 1) {
- if (2 + pos[1] > end - pos)
- return NULL;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- WPA_GET_BE32(&pos[2]) == oui_type) {
- ie = pos;
+ for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) {
+ if (elem->datalen >= 4 &&
+ WPA_GET_BE32(elem->data) == oui_type) {
+ found = elem;
break;
}
- pos += 2 + pos[1];
}
- if (ie == NULL)
+ if (!found)
return NULL; /* No specified vendor IE found */
buf = wpabuf_alloc(ies_len);
@@ -573,13 +577,9 @@
* There may be multiple vendor IEs in the message, so need to
* concatenate their data fields.
*/
- while (end - pos > 1) {
- if (2 + pos[1] > end - pos)
- break;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- WPA_GET_BE32(&pos[2]) == oui_type)
- wpabuf_put_data(buf, pos + 6, pos[1] - 4);
- pos += 2 + pos[1];
+ for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) {
+ if (elem->datalen >= 4 && WPA_GET_BE32(elem->data) == oui_type)
+ wpabuf_put_data(buf, elem->data + 4, elem->datalen - 4);
}
return buf;
@@ -619,6 +619,8 @@
return NULL;
return hdr->addr1;
case WLAN_FC_TYPE_MGMT:
+ if (len < 24)
+ return NULL;
return hdr->addr3;
default:
return NULL;
@@ -882,6 +884,41 @@
}
+int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth,
+ int sec_channel, u8 *op_class, u8 *channel)
+{
+ int vht = CHAN_WIDTH_UNKNOWN;
+
+ switch (chanwidth) {
+ case CHAN_WIDTH_UNKNOWN:
+ case CHAN_WIDTH_20_NOHT:
+ case CHAN_WIDTH_20:
+ case CHAN_WIDTH_40:
+ vht = VHT_CHANWIDTH_USE_HT;
+ break;
+ case CHAN_WIDTH_80:
+ vht = VHT_CHANWIDTH_80MHZ;
+ break;
+ case CHAN_WIDTH_80P80:
+ vht = VHT_CHANWIDTH_80P80MHZ;
+ break;
+ case CHAN_WIDTH_160:
+ vht = VHT_CHANWIDTH_160MHZ;
+ break;
+ }
+
+ if (ieee80211_freq_to_channel_ext(freq, sec_channel, vht, op_class,
+ channel) == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_WARNING,
+ "Cannot determine operating class and channel (freq=%u chanwidth=%d sec_channel=%d)",
+ freq, chanwidth, sec_channel);
+ return -1;
+ }
+
+ return 0;
+}
+
+
static const char *const us_op_class_cc[] = {
"US", "CA", NULL
};
@@ -1169,10 +1206,24 @@
}
-int ieee80211_is_dfs(int freq)
+int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes,
+ u16 num_modes)
{
- /* TODO: this could be more accurate to better cover all domains */
- return (freq >= 5260 && freq <= 5320) || (freq >= 5500 && freq <= 5700);
+ int i, j;
+
+ if (!modes || !num_modes)
+ return (freq >= 5260 && freq <= 5320) ||
+ (freq >= 5500 && freq <= 5700);
+
+ for (i = 0; i < num_modes; i++) {
+ for (j = 0; j < modes[i].num_channels; j++) {
+ if (modes[i].channels[j].freq == freq &&
+ (modes[i].channels[j].flag & HOSTAPD_CHAN_RADAR))
+ return 1;
+ }
+ }
+
+ return 0;
}
@@ -1269,27 +1320,27 @@
int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
size_t ies_len)
{
+ const struct element *elem;
+
os_memset(info, 0, sizeof(*info));
- while (ies_buf && ies_len >= 2 &&
- info->nof_ies < MAX_NOF_MB_IES_SUPPORTED) {
- size_t len = 2 + ies_buf[1];
+ if (!ies_buf)
+ return 0;
- if (len > ies_len) {
- wpa_hexdump(MSG_DEBUG, "Truncated IEs",
- ies_buf, ies_len);
- return -1;
- }
+ for_each_element_id(elem, WLAN_EID_MULTI_BAND, ies_buf, ies_len) {
+ if (info->nof_ies >= MAX_NOF_MB_IES_SUPPORTED)
+ return 0;
- if (ies_buf[0] == WLAN_EID_MULTI_BAND) {
- wpa_printf(MSG_DEBUG, "MB IE of %zu bytes found", len);
- info->ies[info->nof_ies].ie = ies_buf + 2;
- info->ies[info->nof_ies].ie_len = ies_buf[1];
- info->nof_ies++;
- }
+ wpa_printf(MSG_DEBUG, "MB IE of %u bytes found",
+ elem->datalen + 2);
+ info->ies[info->nof_ies].ie = elem->data;
+ info->ies[info->nof_ies].ie_len = elem->datalen;
+ info->nof_ies++;
+ }
- ies_len -= len;
- ies_buf += len;
+ if (!for_each_element_completed(elem, ies_buf, ies_len)) {
+ wpa_hexdump(MSG_DEBUG, "Truncated IEs", ies_buf, ies_len);
+ return -1;
}
return 0;
@@ -1412,22 +1463,13 @@
*/
const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
{
- const u8 *end;
+ const struct element *elem;
if (!ies)
return NULL;
- end = ies + len;
-
- while (end - ies > 1) {
- if (2 + ies[1] > end - ies)
- break;
-
- if (ies[0] == eid)
- return ies;
-
- ies += 2 + ies[1];
- }
+ for_each_element_id(elem, eid, ies, len)
+ return &elem->id;
return NULL;
}
@@ -1445,22 +1487,26 @@
*/
const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext)
{
- const u8 *end;
+ const struct element *elem;
if (!ies)
return NULL;
- end = ies + len;
+ for_each_element_extid(elem, ext, ies, len)
+ return &elem->id;
- while (end - ies > 1) {
- if (2 + ies[1] > end - ies)
- break;
+ return NULL;
+}
- if (ies[0] == WLAN_EID_EXTENSION && ies[1] >= 1 &&
- ies[2] == ext)
- return ies;
- ies += 2 + ies[1];
+const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type)
+{
+ const struct element *elem;
+
+ for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, len) {
+ if (elem->datalen >= 4 &&
+ vendor_type == WPA_GET_BE32(elem->data))
+ return &elem->id;
}
return NULL;
@@ -1491,6 +1537,26 @@
}
+size_t add_multi_ap_ie(u8 *buf, size_t len, u8 value)
+{
+ u8 *pos = buf;
+
+ if (len < 9)
+ return 0;
+
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 7; /* len */
+ WPA_PUT_BE24(pos, OUI_WFA);
+ pos += 3;
+ *pos++ = MULTI_AP_OUI_TYPE;
+ *pos++ = MULTI_AP_SUB_ELEM_TYPE;
+ *pos++ = 1; /* len */
+ *pos++ = value;
+
+ return pos - buf;
+}
+
+
static const struct country_op_class us_op_class[] = {
{ 1, 115 },
{ 2, 118 },
@@ -1636,6 +1702,27 @@
}
+int oper_class_bw_to_int(const struct oper_class_map *map)
+{
+ switch (map->bw) {
+ case BW20:
+ return 20;
+ case BW40PLUS:
+ case BW40MINUS:
+ return 40;
+ case BW80:
+ return 80;
+ case BW80P80:
+ case BW160:
+ return 160;
+ case BW2160:
+ return 2160;
+ default:
+ return 0;
+ }
+}
+
+
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
size_t nei_rep_len)
{
@@ -1736,3 +1823,11 @@
return nei_pos - nei_rep;
}
+
+
+int ieee802_11_ext_capab(const u8 *ie, unsigned int capab)
+{
+ if (!ie || ie[1] <= capab / 8)
+ return 0;
+ return !!(ie[2 + capab / 8] & BIT(capab % 8));
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 9276158..d41bd39 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 Common routines
- * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,15 @@
#define IEEE802_11_COMMON_H
#include "defs.h"
+#include "ieee802_11_defs.h"
+
+struct element {
+ u8 id;
+ u8 datalen;
+ u8 data[];
+} STRUCT_PACKED;
+
+struct hostapd_hw_modes;
#define MAX_NOF_MB_IES_SUPPORTED 5
@@ -79,6 +88,12 @@
const u8 *fils_pk;
const u8 *fils_nonce;
const u8 *owe_dh;
+ const u8 *power_capab;
+ const u8 *roaming_cons_sel;
+ const u8 *password_id;
+ const u8 *oci;
+ const u8 *multi_ap;
+ const u8 *he_capabilities;
u8 ssid_len;
u8 supp_rates_len;
@@ -122,6 +137,12 @@
u8 fils_wrapped_data_len;
u8 fils_pk_len;
u8 owe_dh_len;
+ u8 power_capab_len;
+ u8 roaming_cons_sel_len;
+ u8 password_id_len;
+ u8 oci_len;
+ u8 multi_ap_len;
+ u8 he_capabilities_len;
struct mb_ies_info mb_ies;
};
@@ -152,7 +173,10 @@
enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
int sec_channel, int vht,
u8 *op_class, u8 *channel);
-int ieee80211_is_dfs(int freq);
+int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth,
+ int sec_channel, u8 *op_class, u8 *channel);
+int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes,
+ u16 num_modes);
enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht);
int supp_rates_11b_only(struct ieee802_11_elems *elems);
@@ -177,9 +201,12 @@
const u8 * get_ie(const u8 *ies, size_t len, u8 eid);
const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext);
+const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type);
size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len);
+size_t add_multi_ap_ie(u8 *buf, size_t len, u8 value);
+
struct country_op_class {
u8 country_op_class;
u8 global_op_class;
@@ -188,8 +215,58 @@
u8 country_to_global_op_class(const char *country, u8 op_class);
const struct oper_class_map * get_oper_class(const char *country, u8 op_class);
+int oper_class_bw_to_int(const struct oper_class_map *map);
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
size_t nei_rep_len);
+int ieee802_11_ext_capab(const u8 *ie, unsigned int capab);
+
+/* element iteration helpers */
+#define for_each_element(_elem, _data, _datalen) \
+ for (_elem = (const struct element *) (_data); \
+ (const u8 *) (_data) + (_datalen) - (const u8 *) _elem >= \
+ (int) sizeof(*_elem) && \
+ (const u8 *) (_data) + (_datalen) - (const u8 *) _elem >= \
+ (int) sizeof(*_elem) + _elem->datalen; \
+ _elem = (const struct element *) (_elem->data + _elem->datalen))
+
+#define for_each_element_id(element, _id, data, datalen) \
+ for_each_element(element, data, datalen) \
+ if (element->id == (_id))
+
+#define for_each_element_extid(element, extid, _data, _datalen) \
+ for_each_element(element, _data, _datalen) \
+ if (element->id == WLAN_EID_EXTENSION && \
+ element->datalen > 0 && \
+ element->data[0] == (extid))
+
+#define for_each_subelement(sub, element) \
+ for_each_element(sub, (element)->data, (element)->datalen)
+
+#define for_each_subelement_id(sub, id, element) \
+ for_each_element_id(sub, id, (element)->data, (element)->datalen)
+
+#define for_each_subelement_extid(sub, extid, element) \
+ for_each_element_extid(sub, extid, (element)->data, (element)->datalen)
+
+/**
+ * for_each_element_completed - Determine if element parsing consumed all data
+ * @element: Element pointer after for_each_element() or friends
+ * @data: Same data pointer as passed to for_each_element() or friends
+ * @datalen: Same data length as passed to for_each_element() or friends
+ *
+ * This function returns 1 if all the data was parsed or considered
+ * while walking the elements. Only use this if your for_each_element()
+ * loop cannot be broken out of, otherwise it always returns 0.
+ *
+ * If some data was malformed, this returns %false since the last parsed
+ * element will not fill the whole remaining data.
+ */
+static inline int for_each_element_completed(const struct element *element,
+ const void *data, size_t datalen)
+{
+ return (const u8 *) element == (const u8 *) data + datalen;
+}
+
#endif /* IEEE802_11_COMMON_H */
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index b7fa563..adaa893 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 Frame type definitions
- * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
* Copyright (c) 2007-2008 Intel Corporation
*
* This software may be distributed under the terms of the BSD license.
@@ -203,6 +203,7 @@
#define WLAN_STATUS_AUTHORIZATION_DEENABLED 107
#define WLAN_STATUS_FILS_AUTHENTICATION_FAILURE 112
#define WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER 113
+#define WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER 123
/* Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45) */
#define WLAN_REASON_UNSPECIFIED 1
@@ -333,7 +334,7 @@
#define WLAN_EID_LOCATION_PARAMETERS 82
#define WLAN_EID_NONTRANSMITTED_BSSID_CAPA 83
#define WLAN_EID_SSID_LIST 84
-#define WLAN_EID_MLTIPLE_BSSID_INDEX 85
+#define WLAN_EID_MULTIPLE_BSSID_INDEX 85
#define WLAN_EID_FMS_DESCRIPTOR 86
#define WLAN_EID_FMS_REQUEST 87
#define WLAN_EID_FMS_RESPONSE 88
@@ -463,9 +464,92 @@
#define WLAN_EID_EXT_FILS_NONCE 13
#define WLAN_EID_EXT_FUTURE_CHANNEL_GUIDANCE 14
#define WLAN_EID_EXT_OWE_DH_PARAM 32
+#define WLAN_EID_EXT_PASSWORD_IDENTIFIER 33
#define WLAN_EID_EXT_HE_CAPABILITIES 35
#define WLAN_EID_EXT_HE_OPERATION 36
+#define WLAN_EID_EXT_HE_MU_EDCA_PARAMS 38
+#define WLAN_EID_EXT_OCV_OCI 54
+/* Extended Capabilities field */
+#define WLAN_EXT_CAPAB_20_40_COEX 0
+#define WLAN_EXT_CAPAB_GLK 1
+#define WLAN_EXT_CAPAB_EXT_CHAN_SWITCH 2
+#define WLAN_EXT_CAPAB_GLK_GCR 3
+#define WLAN_EXT_CAPAB_PSMP 4
+/* 5 - Reserved */
+#define WLAN_EXT_CAPAB_S_PSMP 6
+#define WLAN_EXT_CAPAB_EVENT 7
+#define WLAN_EXT_CAPAB_DIAGNOSTICS 8
+#define WLAN_EXT_CAPAB_MULTICAST_DIAGNOSTICS 9
+#define WLAN_EXT_CAPAB_LOCATION_TRACKING 10
+#define WLAN_EXT_CAPAB_FMS 11
+#define WLAN_EXT_CAPAB_PROXY_ARP 12
+#define WLAN_EXT_CAPAB_COLL_INTERF_REP 13
+#define WLAN_EXT_CAPAB_CIVIC_LOCATION 14
+#define WLAN_EXT_CAPAB_GEOSPATIAL_LOCATION 15
+#define WLAN_EXT_CAPAB_TFS 16
+#define WLAN_EXT_CAPAB_WNM_SLEEP_MODE 17
+#define WLAN_EXT_CAPAB_TIM_BROADCAST 18
+#define WLAN_EXT_CAPAB_BSS_TRANSITION 19
+#define WLAN_EXT_CAPAB_QOS_TRAFFIC 20
+#define WLAN_EXT_CAPAB_AC_STA_COUNT 21
+#define WLAN_EXT_CAPAB_MULTIPLE_BSSID 22
+#define WLAN_EXT_CAPAB_TIMING_MEASUREMENT 23
+#define WLAN_EXT_CAPAB_CHANNEL_USAGE 24
+#define WLAN_EXT_CAPAB_SSID_LIST 25
+#define WLAN_EXT_CAPAB_DMS 26
+#define WLAN_EXT_CAPAB_UTF_TSF_OFFSET 27
+#define WLAN_EXT_CAPAB_TPU_BUFFER_STA 28
+#define WLAN_EXT_CAPAB_TDLS_PEER_PSM 29
+#define WLAN_EXT_CAPAB_TDLS_CHANNEL_SWITCH 30
+#define WLAN_EXT_CAPAB_INTERWORKING 31
+#define WLAN_EXT_CAPAB_QOS_MAP 32
+#define WLAN_EXT_CAPAB_EBR 33
+#define WLAN_EXT_CAPAB_SSPN_INTERFACE 34
+/* 35 - Reserved */
+#define WLAN_EXT_CAPAB_MSGCF 36
+#define WLAN_EXT_CAPAB_TDLS 37
+#define WLAN_EXT_CAPAB_TDLS_PROHIBITED 38
+#define WLAN_EXT_CAPAB_TDLS_CHANNEL_SWITCH_PROHIBITED 39
+#define WLAN_EXT_CAPAB_REJECT_UNADMITTED_FRAME 40
+#define WLAN_EXT_CAPAB_
+/* 41-43 - Service Interval Granularity */
+#define WLAN_EXT_CAPAB_IDENTIFIER_LOCATION 44
+#define WLAN_EXT_CAPAB_U_APSD_COEX 45
+#define WLAN_EXT_CAPAB_WNM_NOTIFCATION 46
+#define WLAN_EXT_CAPAB_QAB 47
+#define WLAN_EXT_CAPAB_UTF_8_SSID 48
+#define WLAN_EXT_CAPAB_QMF 49
+#define WLAN_EXT_CAPAB_QMF_RECONFIG 50
+#define WLAN_EXT_CAPAB_ROBUST_AV_STREAMING 51
+#define WLAN_EXT_CAPAB_ADVANCED_GCR 52
+#define WLAN_EXT_CAPAB_MESH_GCR 53
+#define WLAN_EXT_CAPAB_SCS 54
+#define WLAN_EXT_CAPAB_QLOAD_REPORT 55
+#define WLAN_EXT_CAPAB_ALT_EDCA 56
+#define WLAN_EXT_CAPAB_UNPROT_TXOP_NEG 57
+#define WLAN_EXT_CAPAB_PROT_TXOP_NEG 58
+/* 59 - Reserved */
+#define WLAN_EXT_CAPAB_PROT_QLOAD_REPORT 60
+#define WLAN_EXT_CAPAB_TDLS_WIDER_BW 61
+#define WLAN_EXT_CAPAB_OPMODE_NOTIF 62
+#define WLAN_EXT_CAPAB_
+/* 63-64 - Max Number of MSDUs In A-MSDU */
+#define WLAN_EXT_CAPAB_CHANNEL_SCHEDULE_MGMT 65
+#define WLAN_EXT_CAPAB_GEODB_INBAND_ENABLING_SIGNAL 66
+#define WLAN_EXT_CAPAB_NETWORK_CHANNEL_CTRL 67
+#define WLAN_EXT_CAPAB_WHITE_SPACE_MAP 68
+#define WLAN_EXT_CAPAB_CHANNEL_AVAIL_QUERY 69
+#define WLAN_EXT_CAPAB_FTM_RESPONDER 70
+#define WLAN_EXT_CAPAB_FTM_INITIATOR 71
+#define WLAN_EXT_CAPAB_FILS 72
+#define WLAN_EXT_CAPAB_EXT_SPECTRUM_MGMT 73
+#define WLAN_EXT_CAPAB_FUTURE_CHANNEL_GUIDANCE 74
+#define WLAN_EXT_CAPAB_PAD 75
+/* 76-79 - Reserved */
+#define WLAN_EXT_CAPAB_COMPLETE_NON_TX_BSSID_PROFILE 80
+#define WLAN_EXT_CAPAB_SAE_PW_ID 81
+#define WLAN_EXT_CAPAB_SAE_PW_ID_EXCLUSIVELY 82
/* Action frame categories (IEEE Std 802.11-2016, 9.4.1.11, Table 9-76) */
#define WLAN_ACTION_SPECTRUM_MGMT 0
@@ -863,10 +947,12 @@
struct {
u8 action;
u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
+ u8 variable[]; /* OCI element */
} STRUCT_PACKED sa_query_req;
struct {
u8 action; /* */
u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
+ u8 variable[]; /* OCI element */
} STRUCT_PACKED sa_query_resp;
struct {
u8 action;
@@ -920,6 +1006,16 @@
u8 variable[];
} STRUCT_PACKED bss_tm_query;
struct {
+ u8 action; /* 11 */
+ u8 dialog_token;
+ u8 req_info;
+ } STRUCT_PACKED coloc_intf_req;
+ struct {
+ u8 action; /* 12 */
+ u8 dialog_token;
+ u8 variable[];
+ } STRUCT_PACKED coloc_intf_report;
+ struct {
u8 action; /* 15 */
u8 variable[];
} STRUCT_PACKED slf_prot_action;
@@ -1198,6 +1294,13 @@
#define MBO_OUI_TYPE 22
#define OWE_IE_VENDOR_TYPE 0x506f9a1c
#define OWE_OUI_TYPE 28
+#define MULTI_AP_OUI_TYPE 0x1B
+
+#define MULTI_AP_SUB_ELEM_TYPE 0x06
+#define MULTI_AP_TEAR_DOWN BIT(4)
+#define MULTI_AP_FRONTHAUL_BSS BIT(5)
+#define MULTI_AP_BACKHAUL_BSS BIT(6)
+#define MULTI_AP_BACKHAUL_STA BIT(7)
#define WMM_OUI_TYPE 2
#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
@@ -1317,6 +1420,7 @@
#define HS20_INDICATION_OUI_TYPE 16
#define HS20_ANQP_OUI_TYPE 17
#define HS20_OSEN_OUI_TYPE 18
+#define HS20_ROAMING_CONS_SEL_OUI_TYPE 29
#define HS20_STYPE_QUERY_LIST 1
#define HS20_STYPE_CAPABILITY_LIST 2
#define HS20_STYPE_OPERATOR_FRIENDLY_NAME 3
@@ -1327,15 +1431,22 @@
#define HS20_STYPE_OSU_PROVIDERS_LIST 8
#define HS20_STYPE_ICON_REQUEST 10
#define HS20_STYPE_ICON_BINARY_FILE 11
+#define HS20_STYPE_OPERATOR_ICON_METADATA 12
+#define HS20_STYPE_OSU_PROVIDERS_NAI_LIST 13
#define HS20_DGAF_DISABLED 0x01
#define HS20_PPS_MO_ID_PRESENT 0x02
#define HS20_ANQP_DOMAIN_ID_PRESENT 0x04
-#define HS20_VERSION 0x10 /* Release 2 */
+#ifndef HS20_VERSION
+#define HS20_VERSION 0x20 /* Release 3 */
+#endif /* HS20_VERSION */
/* WNM-Notification WFA vendors specific subtypes */
#define HS20_WNM_SUB_REM_NEEDED 0
#define HS20_WNM_DEAUTH_IMMINENT_NOTICE 1
+#define WFA_WNM_NOTIF_SUBELEM_NON_PREF_CHAN_REPORT 2
+#define WFA_WNM_NOTIF_SUBELEM_CELL_DATA_CAPA 3
+#define HS20_WNM_T_C_ACCEPTANCE 4
#define HS20_DEAUTH_REASON_CODE_BSS 0
#define HS20_DEAUTH_REASON_CODE_ESS 1
@@ -1424,12 +1535,6 @@
MBO_TRANSITION_REJECT_REASON_SERVICES = 6,
};
-/* MBO v0.0_r19, 4.4: WNM-Notification vendor subelements */
-enum wfa_wnm_notif_subelem_id {
- WFA_WNM_NOTIF_SUBELEM_NON_PREF_CHAN_REPORT = 2,
- WFA_WNM_NOTIF_SUBELEM_CELL_DATA_CAPA = 3,
-};
-
/* MBO v0.0_r27, 4.3: MBO ANQP-elements */
#define MBO_ANQP_OUI_TYPE 0x12
#define MBO_ANQP_SUBTYPE_QUERY_LIST 1
@@ -1823,11 +1928,14 @@
};
/* IEEE Std 802.11-2016, Table 9-88 - Beacon Request subelement IDs */
+/* IEEE P802.11-REVmd/D2.0, Table 9-106 - Optional subelement IDs for
+ * Beacon request */
#define WLAN_BEACON_REQUEST_SUBELEM_SSID 0
#define WLAN_BEACON_REQUEST_SUBELEM_INFO 1 /* Beacon Reporting */
#define WLAN_BEACON_REQUEST_SUBELEM_DETAIL 2 /* Reporting Detail */
#define WLAN_BEACON_REQUEST_SUBELEM_REQUEST 10
#define WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL 51 /* AP Channel Report */
+#define WLAN_BEACON_REQUEST_SUBELEM_LAST_INDICATION 164
#define WLAN_BEACON_REQUEST_SUBELEM_VENDOR 221
/*
@@ -1877,9 +1985,21 @@
} STRUCT_PACKED;
/* IEEE Std 802.11-2016, Table 9-112 - Beacon report Subelement IDs */
+/* IEEE P802.11-REVmd/D2.0, Table 9-130 - Optional subelement IDs for
+ * Beacon report */
#define WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY 1
+#define WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY_FRAGMENT_ID 2
+#define WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION 164
#define WLAN_BEACON_REPORT_SUBELEM_VENDOR 221
+/* IEEE P802.11-REVmd/D2.0, Table 9-232 - Data field format of the
+ * Reported Frame Body Fragment ID subelement */
+#define REPORTED_FRAME_BODY_SUBELEM_LEN 4
+#define REPORTED_FRAME_BODY_MORE_FRAGMENTS BIT(7)
+
+/* IEEE P802.11-REVmd/D2.0, 9.4.2.21.7 - Beacon report */
+#define BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN 3
+
/* IEEE Std 802.11ad-2012 - Multi-band element */
struct multi_band_ie {
u8 eid; /* WLAN_EID_MULTI_BAND */
@@ -1982,14 +2102,15 @@
};
struct ieee80211_he_capabilities {
- u8 he_mac_capab_info[5];
- u8 he_phy_capab_info[9];
+ u8 he_mac_capab_info[6];
+ u8 he_phy_capab_info[11];
u8 he_txrx_mcs_support[12]; /* TODO: 4, 8, or 12 octets */
/* PPE Thresholds (optional) */
} STRUCT_PACKED;
struct ieee80211_he_operation {
- u32 he_oper_params;
+ u32 he_oper_params; /* HE Operation Parameters[3] and
+ * BSS Color Information[1] */
u8 he_mcs_nss_set[2];
u8 vht_op_info_chwidth;
u8 vht_op_info_chan_center_freq_seg0_idx;
@@ -2006,28 +2127,55 @@
#define HE_PHYCAP_MU_BEAMFORMER_CAPAB ((u8) BIT(1))
/* HE Operation defines */
+/* HE Operation Parameters and BSS Color Information fields */
#define HE_OPERATION_BSS_COLOR_MASK ((u32) (BIT(0) | BIT(1) | \
BIT(2) | BIT(3) | \
BIT(4) | BIT(5)))
-#define HE_OPERATION_DFLT_PE_DURATION_MASK ((u32) (BIT(6) | BIT(7) | \
- BIT(8)))
-#define HE_OPERATION_DFLT_PE_DURATION_OFFSET 6
-#define HE_OPERATION_TWT_REQUIRED ((u32) BIT(9))
-#define HE_OPERATION_RTS_THRESHOLD_MASK ((u32) (BIT(10) | BIT(11) | \
- BIT(12) | BIT(13) | \
+#define HE_OPERATION_PARTIAL_BSS_COLOR ((u32) BIT(6))
+#define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(7))
+#define HE_OPERATION_DFLT_PE_DURATION_MASK ((u32) (BIT(8) | BIT(9) | \
+ BIT(10)))
+#define HE_OPERATION_DFLT_PE_DURATION_OFFSET 8
+#define HE_OPERATION_TWT_REQUIRED ((u32) BIT(11))
+#define HE_OPERATION_RTS_THRESHOLD_MASK ((u32) (BIT(12) | BIT(13) | \
BIT(14) | BIT(15) | \
BIT(16) | BIT(17) | \
- BIT(18) | BIT(19)))
-#define HE_OPERATION_RTS_THRESHOLD_OFFSET 10
-#define HE_OPERATION_PARTIAL_BSS_COLOR ((u32) BIT(20))
-#define HE_OPERATION_MAX_BSSID_INDICATOR_MASK ((u32) (BIT(21) | BIT(22) | \
- BIT(23) | BIT(24) | \
- BIT(25) | BIT(26) | \
- BIT(27) | BIT(28)))
-#define HE_OPERATION_MAX_BSSID_INDICATOR_OFFSET 21
-#define HE_OPERATION_TX_BSSID_INDICATOR ((u32) BIT(29))
-#define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(30))
-#define HE_OPERATION_BSS_DUAL_BEACON ((u32) BIT(31))
+ BIT(18) | BIT(19) | \
+ BIT(20) | BIT(21)))
+#define HE_OPERATION_RTS_THRESHOLD_OFFSET 12
+
+struct ieee80211_he_mu_edca_parameter_set {
+ u8 he_qos_info;
+ u8 he_mu_ac_be_param[3];
+ u8 he_mu_ac_bk_param[3];
+ u8 he_mu_ac_vi_param[3];
+ u8 he_mu_ac_vo_param[3];
+} STRUCT_PACKED;
+
+/* HE MU AC parameter record field format */
+/* ACI/AIFSN */
+#define HE_MU_AC_PARAM_ACI_IDX 0
+#define HE_MU_AC_PARAM_AIFSN ((u8) (BIT(0) | BIT(1) | BIT(2) | BIT(3)))
+#define HE_MU_AC_PARAM_ACM ((u8) BIT(4))
+#define HE_MU_AC_PARAM_ACI ((u8) (BIT(5) | BIT(6)))
+/* B7: Reserved */
+
+/* ECWmin/ECWmax */
+#define HE_MU_AC_PARAM_ECW_IDX 1
+#define HE_MU_AC_PARAM_ECWMIN ((u8) (BIT(0) | BIT(1) | BIT(2) | BIT(3)))
+#define HE_MU_AC_PARAM_ECWMAX ((u8) (BIT(4) | BIT(5) | BIT(6) | BIT(7)))
+
+/* MU EDCA Timer */
+#define HE_MU_AC_PARAM_TIMER_IDX 2
+
+/* HE QoS Info field */
+#define HE_QOS_INFO_EDCA_PARAM_SET_COUNT ((u8) (BIT(0) | BIT(1) | \
+ BIT(2) | BIT(3)))
+#define HE_QOS_INFO_Q_ACK ((u8) (BIT(4)))
+#define HE_QOS_INFO_QUEUE_REQUEST ((u8) (BIT(5)))
+#define HE_QOS_INFO_TXOP_REQUEST ((u8) (BIT(6)))
+/* B7: Reserved if sent by an AP; More Data Ack if sent by a non-AP STA */
+#define HE_QOS_INFO_MORE_DATA_ACK ((u8) (BIT(7)))
/* DPP Public Action frame identifiers - OUI_WFA */
#define DPP_OUI_TYPE 0x1A
diff --git a/src/common/ieee802_1x_defs.h b/src/common/ieee802_1x_defs.h
index 280c439..e7acff1 100644
--- a/src/common/ieee802_1x_defs.h
+++ b/src/common/ieee802_1x_defs.h
@@ -12,6 +12,8 @@
#define CS_ID_LEN 8
#define CS_ID_GCM_AES_128 0x0080020001000001ULL
#define CS_NAME_GCM_AES_128 "GCM-AES-128"
+#define CS_ID_GCM_AES_256 0x0080c20001000002ULL
+#define CS_NAME_GCM_AES_256 "GCM-AES-256"
enum macsec_policy {
/**
diff --git a/src/common/linux_bridge.h b/src/common/linux_bridge.h
index 7b76846..84386e6 100644
--- a/src/common/linux_bridge.h
+++ b/src/common/linux_bridge.h
@@ -9,6 +9,21 @@
#ifndef LINUX_BRIDGE_H
#define LINUX_BRIDGE_H
+/* This ioctl is defined in linux/sockios.h */
+
+#ifndef SIOCBRADDBR
+#define SIOCBRADDBR 0x89a0
+#endif
+#ifndef SIOCBRDELBR
+#define SIOCBRDELBR 0x89a1
+#endif
+#ifndef SIOCBRADDIF
+#define SIOCBRADDIF 0x89a2
+#endif
+#ifndef SIOCBRDELIF
+#define SIOCBRDELIF 0x89a3
+#endif
+
/* This interface is defined in linux/if_bridge.h */
#define BRCTL_GET_VERSION 0
diff --git a/src/common/ocv.c b/src/common/ocv.c
new file mode 100644
index 0000000..06badfb
--- /dev/null
+++ b/src/common/ocv.c
@@ -0,0 +1,172 @@
+/*
+ * Operating Channel Validation (OCV)
+ * Copyright (c) 2018, Mathy Vanhoef
+ *
+ * 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 "drivers/driver.h"
+#include "common/ieee802_11_common.h"
+#include "ocv.h"
+
+/**
+ * Caller of OCV functionality may use various debug output functions, so store
+ * the error here and let the caller use an appropriate debug output function.
+ */
+char ocv_errorstr[256];
+
+
+int ocv_derive_all_parameters(struct oci_info *oci)
+{
+ const struct oper_class_map *op_class_map;
+
+ oci->freq = ieee80211_chan_to_freq(NULL, oci->op_class, oci->channel);
+ if (oci->freq < 0) {
+ wpa_printf(MSG_INFO,
+ "Error interpreting OCI: unrecognized opclass/channel pair (%d/%d)",
+ oci->op_class, oci->channel);
+ return -1;
+ }
+
+ op_class_map = get_oper_class(NULL, oci->op_class);
+ if (!op_class_map) {
+ wpa_printf(MSG_INFO,
+ "Error interpreting OCI: Unrecognized opclass (%d)",
+ oci->op_class);
+ return -1;
+ }
+
+ oci->chanwidth = oper_class_bw_to_int(op_class_map);
+ oci->sec_channel = 0;
+ if (op_class_map->bw == BW40PLUS)
+ oci->sec_channel = 1;
+ else if (op_class_map->bw == BW40MINUS)
+ oci->sec_channel = -1;
+
+ return 0;
+}
+
+
+int ocv_insert_oci(struct wpa_channel_info *ci, u8 **argpos)
+{
+ u8 op_class, channel;
+ u8 *pos = *argpos;
+
+ if (ieee80211_chaninfo_to_channel(ci->frequency, ci->chanwidth,
+ ci->sec_channel,
+ &op_class, &channel) < 0) {
+ wpa_printf(MSG_WARNING,
+ "Cannot determine operating class and channel for OCI element");
+ return -1;
+ }
+
+ *pos++ = op_class;
+ *pos++ = channel;
+ *pos++ = ci->seg1_idx;
+
+ *argpos = pos;
+ return 0;
+}
+
+
+int ocv_insert_oci_kde(struct wpa_channel_info *ci, u8 **argpos)
+{
+ u8 *pos = *argpos;
+
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = RSN_SELECTOR_LEN + 3;
+ RSN_SELECTOR_PUT(pos, RSN_KEY_DATA_OCI);
+ pos += RSN_SELECTOR_LEN;
+
+ *argpos = pos;
+ return ocv_insert_oci(ci, argpos);
+}
+
+
+int ocv_insert_extended_oci(struct wpa_channel_info *ci, u8 *pos)
+{
+ *pos++ = WLAN_EID_EXTENSION;
+ *pos++ = 1 + OCV_OCI_LEN;
+ *pos++ = WLAN_EID_EXT_OCV_OCI;
+ return ocv_insert_oci(ci, &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)
+{
+ struct oci_info oci;
+
+ if (!oci_ie) {
+ os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+ "OCV failed: did not receive mandatory OCI");
+ return -1;
+ }
+
+ if (oci_ie_len != 3) {
+ os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+ "OCV failed: received OCI of unexpected length (%d)",
+ (int) oci_ie_len);
+ return -1;
+ }
+
+ os_memset(&oci, 0, sizeof(oci));
+ oci.op_class = oci_ie[0];
+ oci.channel = oci_ie[1];
+ 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;
+ }
+
+ /* 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)",
+ ci->frequency, oci.freq);
+ return -1;
+ }
+
+ /* 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)",
+ tx_chanwidth, oci.chanwidth);
+ return -1;
+ }
+
+ /*
+ * Secondary channel only needs be checked for 40 MHz in the 2.4 GHz
+ * band. In the 5 GHz band it's verified through the primary frequency.
+ * Note that the field ci->sec_channel is only filled in when we use
+ * 40 MHz.
+ */
+ 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)",
+ ci->sec_channel, oci.sec_channel);
+ return -1;
+ }
+
+ /*
+ * When using a 160 or 80+80 MHz channel to transmit, verify that we use
+ * the same segments as the receiver by comparing frequency segment 1.
+ */
+ if ((ci->chanwidth == CHAN_WIDTH_160 ||
+ 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)",
+ tx_seg1_idx, oci.seg1_idx);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/common/ocv.h b/src/common/ocv.h
new file mode 100644
index 0000000..6379d9d
--- /dev/null
+++ b/src/common/ocv.h
@@ -0,0 +1,40 @@
+/*
+ * Operating Channel Validation (OCV)
+ * Copyright (c) 2018, Mathy Vanhoef
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef OCV_H
+#define OCV_H
+
+struct wpa_channel_info;
+
+struct oci_info {
+ /* Values in the OCI element */
+ u8 op_class;
+ u8 channel;
+ u8 seg1_idx;
+
+ /* Derived values for easier verification */
+ int freq;
+ int sec_channel;
+ int chanwidth;
+};
+
+#define OCV_OCI_LEN 3
+#define OCV_OCI_EXTENDED_LEN (3 + OCV_OCI_LEN)
+#define OCV_OCI_KDE_LEN (2 + RSN_SELECTOR_LEN + OCV_OCI_LEN)
+
+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);
+
+#endif /* OCV_H */
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index b4f7d12..c34a3bc 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -1,6 +1,7 @@
/*
* Qualcomm Atheros OUI and vendor specific assignments
* Copyright (c) 2014-2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -41,15 +42,22 @@
*
* @QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: Recommendation of frequency
* ranges to avoid to reduce issues due to interference or internal
- * co-existence information in the driver. The event data structure is
- * defined in struct qca_avoid_freq_list.
+ * co-existence information in the driver. These frequencies aim to
+ * minimize the traffic but not to totally avoid the traffic. That said
+ * for a P2P use case, these frequencies are allowed for the P2P
+ * discovery/negotiation but avoid the group to get formed on these
+ * frequencies. The event data structure is defined in
+ * struct qca_avoid_freq_list.
*
* @QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY: Command to check driver support
* for DFS offloading.
*
* @QCA_NL80211_VENDOR_SUBCMD_NAN: NAN command/event which is used to pass
* NAN Request/Response and NAN Indication messages. These messages are
- * interpreted between the framework and the firmware component.
+ * interpreted between the framework and the firmware component. While
+ * sending the command from userspace to the driver, payload is not
+ * encapsulated inside any attribute. Attribute QCA_WLAN_VENDOR_ATTR_NAN
+ * is used when receiving vendor events in userspace from the driver.
*
* @QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY: Set key operation that can be
* used to configure PMK to the driver even when not connected. This can
@@ -90,6 +98,49 @@
* which supports DFS offloading, to indicate a radar pattern has been
* detected. The channel is now unusable.
*
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET: Get the feature bitmap
+ * based on enum wifi_logger_supported_features. Attributes defined in
+ * enum qca_wlan_vendor_attr_get_logger_features.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_RING_DATA: Get the ring data from a particular
+ * logger ring, QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID is passed as the
+ * attribute for this command. Attributes defined in
+ * enum qca_wlan_vendor_attr_wifi_logger_start.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES: Get the supported TDLS
+ * capabilities of the driver, parameters includes the attributes defined
+ * in enum qca_wlan_vendor_attr_tdls_get_capabilities.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_OFFLOADED_PACKETS: Vendor command used to offload
+ * sending of certain periodic IP packet to firmware, attributes defined in
+ * enum qca_wlan_vendor_attr_offloaded_packets.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI: Command used to configure RSSI
+ * monitoring, defines min and max RSSI which are configured for RSSI
+ * monitoring. Also used to notify the RSSI breach and provides the BSSID
+ * and RSSI value that was breached. Attributes defined in
+ * enum qca_wlan_vendor_attr_rssi_monitoring.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_NDP: Command used for performing various NAN
+ * Data Path (NDP) related operations, attributes defined in
+ * enum qca_wlan_vendor_attr_ndp_params.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_ND_OFFLOAD: Command used to enable/disable
+ * Neighbour Discovery offload, attributes defined in
+ * enum qca_wlan_vendor_attr_nd_offload.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_PACKET_FILTER: Used to set/get the various
+ * configuration parameter for BPF packet filter, attributes defined in
+ * enum qca_wlan_vendor_attr_packet_filter.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_BUS_SIZE: Gets the driver-firmware
+ * maximum supported size, attributes defined in
+ * enum qca_wlan_vendor_drv_info.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_WAKE_REASON_STATS: Command to get various
+ * data about wake reasons and datapath IP statistics, attributes defined
+ * in enum qca_wlan_vendor_attr_wake_stats.
+ *
* @QCA_NL80211_VENDOR_SUBCMD_OCB_SET_CONFIG: Command used to set configuration
* for IEEE 802.11 communicating outside the context of a basic service
* set, called OCB command. Uses the attributes defines in
@@ -111,6 +162,11 @@
* timer value. Uses the attributes defines in
* enum qca_wlan_vendor_attr_ocb_get_tsf_resp.
*
+ * @QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES: Command/event to update the
+ * link properties of the respective interface. As an event, is used
+ * 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_P2P_LISTEN_OFFLOAD_START: Command used to
* start the P2P Listen offload function in device and pass the listen
* channel, period, interval, count, device types, and vendor specific
@@ -338,6 +394,136 @@
* information indicating the reason that triggered this detection. The
* attributes for this command are defined in
* enum qca_wlan_vendor_attr_hang.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CONFIG: Get the current values
+ * of spectral parameters used. The spectral scan parameters are specified
+ * by enum qca_wlan_vendor_attr_spectral_scan.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_DIAG_STATS: Get the debug stats
+ * for spectral scan functionality. The debug stats are specified by
+ * enum qca_wlan_vendor_attr_spectral_diag_stats.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CAP_INFO: Get spectral
+ * scan system capabilities. The capabilities are specified
+ * by enum qca_wlan_vendor_attr_spectral_cap.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_STATUS: Get the current
+ * status of spectral scan. The status values are specified
+ * by enum qca_wlan_vendor_attr_spectral_scan_status.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_PEER_FLUSH_PENDING: Sub-command to flush
+ * peer pending packets. Specify the peer MAC address in
+ * QCA_WLAN_VENDOR_ATTR_PEER_ADDR and the access category of the packets
+ * in QCA_WLAN_VENDOR_ATTR_AC. The attributes are listed
+ * in enum qca_wlan_vendor_attr_flush_pending.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_RROP_INFO: Get vendor specific Representative
+ * RF Operating Parameter (RROP) information. The attributes for this
+ * information are defined in enum qca_wlan_vendor_attr_rrop_info. This is
+ * intended for use by external Auto Channel Selection applications.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS: Get the Specific Absorption Rate
+ * (SAR) power limits. This is a companion to the command
+ * @QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS and is used to retrieve the
+ * settings currently in use. The attributes returned by this command are
+ * defined by enum qca_vendor_attr_sar_limits.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO: Provides the current behavior of
+ * the WLAN hardware MAC. Also, provides the WLAN netdev interface
+ * information attached to the respective MAC.
+ * This works both as a query (user space asks the current mode) or event
+ * interface (driver advertising the current mode to the user space).
+ * Driver does not trigger this event for temporary hardware mode changes.
+ * Mode changes w.r.t Wi-Fi connection update (VIZ creation / deletion,
+ * channel change, etc.) are updated with this event. Attributes for this
+ * interface are defined in enum qca_wlan_vendor_attr_mac.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SET_QDEPTH_THRESH: Set MSDU queue depth threshold
+ * per peer per TID. Attributes for this command are define in
+ * enum qca_wlan_set_qdepth_thresh_attr.
+ * @QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD: Provides the thermal shutdown action
+ * guide for WLAN driver. Request to suspend of driver and FW if the
+ * temperature is higher than the suspend threshold; resume action is
+ * requested to driver if the temperature is lower than the resume
+ * threshold. In user poll mode, request temperature data by user. For test
+ * purpose, getting thermal shutdown configuration parameters is needed.
+ * Attributes for this interface are defined in
+ * enum qca_wlan_vendor_attr_thermal_cmd.
+ * @QCA_NL80211_VENDOR_SUBCMD_THERMAL_EVENT: Thermal events reported from
+ * driver. Thermal temperature and indication of resume completion are
+ * reported as thermal events. The attributes for this command are defined
+ * in enum qca_wlan_vendor_attr_thermal_event.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION: Sub command to set WiFi
+ * test configuration. Attributes for this command are defined in
+ * enum qca_wlan_vendor_attr_wifi_test_config.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER: This command is used to configure an
+ * RX filter to receive frames from stations that are active on the
+ * operating channel, but not associated with the local device (e.g., STAs
+ * associated with other APs). Filtering is done based on a list of BSSIDs
+ * and STA MAC addresses added by the user. This command is also used to
+ * fetch the statistics of unassociated stations. The attributes used with
+ * this command are defined in enum qca_wlan_vendor_attr_bss_filter.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_NAN_EXT: An extendable version of NAN vendor
+ * command. The earlier command for NAN, QCA_NL80211_VENDOR_SUBCMD_NAN,
+ * carried a payload which was a binary blob of data. The command was not
+ * extendable to send more information. The newer version carries the
+ * legacy blob encapsulated within an attribute and can be extended with
+ * additional vendor attributes that can enhance the NAN command interface.
+ * @QCA_NL80211_VENDOR_SUBCMD_ROAM_SCAN_EVENT: Event to indicate scan triggered
+ * or stopped within driver/firmware in order to initiate roaming. The
+ * attributes used with this event are defined in enum
+ * qca_wlan_vendor_attr_roam_scan. Some drivers may not send these events
+ * in few cases, e.g., if the host processor is sleeping when this event
+ * is generated in firmware.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG: This command is used to
+ * configure parameters per peer to capture Channel Frequency Response
+ * (CFR) and enable Periodic CFR capture. The attributes for this command
+ * are defined in enum qca_wlan_vendor_peer_cfr_capture_attr.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_THROUGHPUT_CHANGE_EVENT: Event to indicate changes
+ * in throughput dynamically. The driver estimates the throughput based on
+ * number of packets being transmitted/received per second and indicates
+ * the changes in throughput to user space. Userspace tools can use this
+ * information to configure kernel's TCP parameters in order to achieve
+ * peak throughput. Optionally, the driver will also send guidance on
+ * modifications to kernel's TCP parameters which can be referred by
+ * userspace tools. The attributes used with this event are defined in enum
+ * qca_wlan_vendor_attr_throughput_change.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_COEX_CONFIG: This command is used to set
+ * priorities among different types of traffic during coex scenarios.
+ * Current supported prioritization is among WLAN/BT/ZIGBEE with different
+ * profiles mentioned in enum qca_coex_config_profiles. The associated
+ * attributes used with this command are defined in enum
+ * qca_vendor_attr_coex_config.
+ *
+ * Based on the config provided, FW will boost the weight and prioritize
+ * the traffic for that subsystem (WLAN/BT/Zigbee).
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS: This command is used to query
+ * the supported AKM suite selectorss from the driver. It returns the list
+ * of supported AKMs in the attribute NL80211_ATTR_AKM_SUITES.
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_FW_STATE: This command is used to get firmware
+ * state from the driver. It returns the firmware state in the attribute
+ * QCA_WLAN_VENDOR_ATTR_FW_STATE.
+ * @QCA_NL80211_VENDOR_SUBCMD_PEER_STATS_CACHE_FLUSH: This vendor subcommand
+ * is used by the driver to flush per-peer cached statistics to user space
+ * application. This interface is used as an event from the driver to
+ * user space application. Attributes for this event are specified in
+ * enum qca_wlan_vendor_attr_peer_stats_cache_params.
+ * QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_DATA attribute is expected to be
+ * sent in the event.
+ * @QCA_NL80211_VENDOR_SUBCMD_MPTA_HELPER_CONFIG: This sub command is used to
+ * improve the success rate of Zigbee joining network.
+ * Due to PTA master limitation, Zigbee joining network success rate is
+ * low while WLAN is working. The WLAN driver needs to configure some
+ * parameters including Zigbee state and specific WLAN periods to enhance
+ * PTA master. All these parameters are delivered by the attributes
+ * defined in enum qca_mpta_helper_vendor_attr.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -405,7 +591,17 @@
/* Wi-Fi configuration subcommands */
QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION = 74,
QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION = 75,
- /* 76-90 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET = 76,
+ QCA_NL80211_VENDOR_SUBCMD_GET_RING_DATA = 77,
+ QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES = 78,
+ QCA_NL80211_VENDOR_SUBCMD_OFFLOADED_PACKETS = 79,
+ QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI = 80,
+ QCA_NL80211_VENDOR_SUBCMD_NDP = 81,
+ QCA_NL80211_VENDOR_SUBCMD_ND_OFFLOAD = 82,
+ QCA_NL80211_VENDOR_SUBCMD_PACKET_FILTER = 83,
+ QCA_NL80211_VENDOR_SUBCMD_GET_BUS_SIZE = 84,
+ QCA_NL80211_VENDOR_SUBCMD_GET_WAKE_REASON_STATS = 85,
+ /* 86-90 - reserved for QCA */
QCA_NL80211_VENDOR_SUBCMD_DATA_OFFLOAD = 91,
QCA_NL80211_VENDOR_SUBCMD_OCB_SET_CONFIG = 92,
QCA_NL80211_VENDOR_SUBCMD_OCB_SET_UTC_TIME = 93,
@@ -470,21 +666,50 @@
QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_STOP = 155,
QCA_NL80211_VENDOR_SUBCMD_ACTIVE_TOS = 156,
QCA_NL80211_VENDOR_SUBCMD_HANG = 157,
+ QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CONFIG = 158,
+ QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_DIAG_STATS = 159,
+ QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CAP_INFO = 160,
+ QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_STATUS = 161,
+ /* Flush peer pending data */
+ QCA_NL80211_VENDOR_SUBCMD_PEER_FLUSH_PENDING = 162,
+ QCA_NL80211_VENDOR_SUBCMD_GET_RROP_INFO = 163,
+ QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS = 164,
+ QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO = 165,
+ QCA_NL80211_VENDOR_SUBCMD_SET_QDEPTH_THRESH = 166,
+ /* Thermal shutdown commands to protect wifi chip */
+ QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD = 167,
+ QCA_NL80211_VENDOR_SUBCMD_THERMAL_EVENT = 168,
+ /* Wi-Fi test configuration subcommand */
+ QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION = 169,
+ /* Frame filter operations for other BSSs/unassociated STAs */
+ QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER = 170,
+ QCA_NL80211_VENDOR_SUBCMD_NAN_EXT = 171,
+ QCA_NL80211_VENDOR_SUBCMD_ROAM_SCAN_EVENT = 172,
+ QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG = 173,
+ QCA_NL80211_VENDOR_SUBCMD_THROUGHPUT_CHANGE_EVENT = 174,
+ QCA_NL80211_VENDOR_SUBCMD_COEX_CONFIG = 175,
+ QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS = 176,
+ QCA_NL80211_VENDOR_SUBCMD_GET_FW_STATE = 177,
+ QCA_NL80211_VENDOR_SUBCMD_PEER_STATS_CACHE_FLUSH = 178,
+ QCA_NL80211_VENDOR_SUBCMD_MPTA_HELPER_CONFIG = 179,
};
-
enum qca_wlan_vendor_attr {
QCA_WLAN_VENDOR_ATTR_INVALID = 0,
/* used by QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY */
QCA_WLAN_VENDOR_ATTR_DFS = 1,
- /* used by QCA_NL80211_VENDOR_SUBCMD_NAN */
+ /* Used only when driver sends vendor events to the userspace under the
+ * command QCA_NL80211_VENDOR_SUBCMD_NAN. Not used when userspace sends
+ * commands to the driver.
+ */
QCA_WLAN_VENDOR_ATTR_NAN = 2,
/* used by QCA_NL80211_VENDOR_SUBCMD_STATS_EXT */
QCA_WLAN_VENDOR_ATTR_STATS_EXT = 3,
/* used by QCA_NL80211_VENDOR_SUBCMD_STATS_EXT */
QCA_WLAN_VENDOR_ATTR_IFINDEX = 4,
/* used by QCA_NL80211_VENDOR_SUBCMD_ROAMING, u32 with values defined
- * by enum qca_roaming_policy. */
+ * by enum qca_roaming_policy.
+ */
QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY = 5,
QCA_WLAN_VENDOR_ATTR_MAC_ADDR = 6,
/* used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */
@@ -572,10 +797,12 @@
QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT = 25,
/* Used in QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI command
* to specify the chain number (unsigned 32 bit value) to inquire
- * the corresponding antenna RSSI value */
+ * the corresponding antenna RSSI value
+ */
QCA_WLAN_VENDOR_ATTR_CHAIN_INDEX = 26,
/* Used in QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI command
- * to report the specific antenna RSSI value (unsigned 32 bit value) */
+ * to report the specific antenna RSSI value (unsigned 32 bit value)
+ */
QCA_WLAN_VENDOR_ATTR_CHAIN_RSSI = 27,
/* Frequency in MHz, various uses. Unsigned 32 bit value */
QCA_WLAN_VENDOR_ATTR_FREQ = 28,
@@ -642,20 +869,75 @@
*/
QCA_WLAN_VENDOR_ATTR_BRP_ANT_NUM_LIMIT = 39,
/* Used in QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI command
- * to report the corresponding antenna index to the chain RSSI value */
+ * to report the corresponding antenna index to the chain RSSI value
+ */
QCA_WLAN_VENDOR_ATTR_ANTENNA_INFO = 40,
+ /* Used in QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI command to report
+ * the specific antenna EVM value (unsigned 32 bit value). With a
+ * determinate group of antennas, the driver specifies the EVM value
+ * for each antenna ID, and application extract them in user space.
+ */
+ QCA_WLAN_VENDOR_ATTR_CHAIN_EVM = 41,
+ /*
+ * Used in QCA_NL80211_VENDOR_SUBCMD_GET_FW_STATE command to report
+ * wlan firmware current state. FW state is an unsigned 8 bit value,
+ * one of the values in enum qca_wlan_vendor_attr_fw_state.
+ */
+ QCA_WLAN_VENDOR_ATTR_FW_STATE = 42,
/* keep last */
QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
};
-
enum qca_roaming_policy {
QCA_ROAMING_NOT_ALLOWED,
QCA_ROAMING_ALLOWED_WITHIN_ESS,
};
+/**
+ * enum qca_roam_reason - Represents the reason codes for roaming. Used by
+ * QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REASON.
+ *
+ * @QCA_ROAM_REASON_UNKNOWN: Any reason that do not classify under the below
+ * reasons.
+ *
+ * @QCA_ROAM_REASON_PER: Roam triggered when packet error rates (PER) breached
+ * the configured threshold.
+ *
+ * @QCA_ROAM_REASON_BEACON_MISS: Roam triggered due to the continuous configured
+ * beacon misses from the then connected AP.
+ *
+ * @QCA_ROAM_REASON_POOR_RSSI: Roam triggered due to the poor RSSI reported
+ * by the connected AP.
+ *
+ * @QCA_ROAM_REASON_BETTER_RSSI: Roam triggered for finding a BSS with a better
+ * RSSI than the connected BSS. Here the RSSI of the current BSS is not poor.
+ *
+ * @QCA_ROAM_REASON_CONGESTION: Roam triggered considering the connected channel
+ * or environment being very noisy or congested.
+ *
+ * @QCA_ROAM_REASON_EXPLICIT_REQUEST: Roam triggered due to an explicit request
+ * from the user (user space).
+ *
+ * @QCA_ROAM_REASON_BTM: Roam triggered due to BTM Request frame received from
+ * the connected AP.
+ *
+ * @QCA_ROAM_REASON_BSS_LOAD: Roam triggered due to the channel utilization
+ * breaching out the configured threshold.
+ */
+enum qca_roam_reason {
+ QCA_ROAM_REASON_UNKNOWN,
+ QCA_ROAM_REASON_PER,
+ QCA_ROAM_REASON_BEACON_MISS,
+ QCA_ROAM_REASON_POOR_RSSI,
+ QCA_ROAM_REASON_BETTER_RSSI,
+ QCA_ROAM_REASON_CONGESTION,
+ QCA_ROAM_REASON_USER_TRIGGER,
+ QCA_ROAM_REASON_BTM,
+ QCA_ROAM_REASON_BSS_LOAD,
+};
+
enum qca_wlan_vendor_attr_roam_auth {
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID,
@@ -698,6 +980,11 @@
* doing subsequent ERP based connections in the same realm.
*/
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_FILS_ERP_NEXT_SEQ_NUM = 13,
+ /* A 16-bit unsigned value representing the reasons for the roaming.
+ * Defined by enum qca_roam_reason.
+ */
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REASON = 14,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX =
@@ -778,7 +1065,7 @@
* @QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY: Device supports automatic
* band selection based on channel selection results.
* @QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS: Device supports
- * simultaneous off-channel operations.
+ * simultaneous off-channel operations.
* @QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD: Device supports P2P
* Listen offload; a mechanism where the station's firmware takes care of
* responding to incoming Probe Request frames received from other P2P
@@ -794,6 +1081,9 @@
* %QCA_WLAN_VENDOR_FEATURE_OCE_AP, the userspace shall assume that
* this Device may not support all OCE AP functionalities but can support
* only OCE STA-CFON functionalities.
+ * @QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY: Device supports self
+ * managed regulatory.
+ * @QCA_WLAN_VENDOR_FEATURE_TWT: Device supports TWT (Target Wake Time).
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
*/
enum qca_wlan_vendor_features {
@@ -804,6 +1094,8 @@
QCA_WLAN_VENDOR_FEATURE_OCE_STA = 4,
QCA_WLAN_VENDOR_FEATURE_OCE_AP = 5,
QCA_WLAN_VENDOR_FEATURE_OCE_STA_CFON = 6,
+ QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY = 7,
+ QCA_WLAN_VENDOR_FEATURE_TWT = 8,
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
@@ -947,6 +1239,12 @@
* from kernel space to user space.
*/
QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST,
+ /* An array of nested values as per enum qca_wlan_vendor_attr_pcl
+ * attribute. Each element contains frequency (MHz), weight, and flag
+ * bit mask indicating how the frequency should be used in P2P
+ * negotiation; sent from kernel space to user space.
+ */
+ QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_WEIGHED_PCL,
/* keep last */
QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX =
@@ -1127,16 +1425,16 @@
* @QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES: Nested array attribute of supported
* rates to be included
* @QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE: flag used to send probe requests
- * at non CCK rate in 2GHz band
+ * at non CCK rate in 2GHz band
* @QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS: Unsigned 32-bit scan flags
* @QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE: Unsigned 64-bit cookie provided by the
- * driver for the specific scan request
+ * driver for the specific scan request
* @QCA_WLAN_VENDOR_ATTR_SCAN_STATUS: Unsigned 8-bit status of the scan
- * request decoded as in enum scan_status
+ * request decoded as in enum scan_status
* @QCA_WLAN_VENDOR_ATTR_SCAN_MAC: 6-byte MAC address to use when randomisation
- * scan flag is set
+ * scan flag is set
* @QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK: 6-byte MAC address mask to be used with
- * randomisation
+ * randomisation
* @QCA_WLAN_VENDOR_ATTR_SCAN_BSSID: 6-byte MAC address representing the
* specific BSSID to scan for.
*/
@@ -1160,10 +1458,10 @@
/**
* enum scan_status - Specifies the valid values the vendor scan attribute
- * QCA_WLAN_VENDOR_ATTR_SCAN_STATUS can take
+ * QCA_WLAN_VENDOR_ATTR_SCAN_STATUS can take
*
* @VENDOR_SCAN_STATUS_NEW_RESULTS: implies the vendor scan is successful with
- * new scan results
+ * new scan results
* @VENDOR_SCAN_STATUS_ABORTED: implies the vendor scan was aborted in-between
*/
enum scan_status {
@@ -1210,7 +1508,8 @@
enum qca_vendor_attr_txpower_decr_db {
QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB_INVALID,
/* 8-bit unsigned value to indicate the reduction of TX power in dB for
- * a virtual interface. */
+ * a virtual interface.
+ */
QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB,
/* keep last */
QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB_AFTER_LAST,
@@ -1260,29 +1559,37 @@
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_AVOIDANCE_IND = 7,
/* 8-bit unsigned value to configure the maximum TX MPDU for
- * aggregation. */
+ * aggregation.
+ */
QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MPDU_AGGREGATION = 8,
/* 8-bit unsigned value to configure the maximum RX MPDU for
- * aggregation. */
+ * aggregation.
+ */
QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MPDU_AGGREGATION = 9,
/* 8-bit unsigned value to configure the Non aggregrate/11g sw
- * retry threshold (0 disable, 31 max). */
+ * retry threshold (0 disable, 31 max).
+ */
QCA_WLAN_VENDOR_ATTR_CONFIG_NON_AGG_RETRY = 10,
/* 8-bit unsigned value to configure the aggregrate sw
- * retry threshold (0 disable, 31 max). */
+ * retry threshold (0 disable, 31 max).
+ */
QCA_WLAN_VENDOR_ATTR_CONFIG_AGG_RETRY = 11,
/* 8-bit unsigned value to configure the MGMT frame
- * retry threshold (0 disable, 31 max). */
+ * retry threshold (0 disable, 31 max).
+ */
QCA_WLAN_VENDOR_ATTR_CONFIG_MGMT_RETRY = 12,
/* 8-bit unsigned value to configure the CTRL frame
- * retry threshold (0 disable, 31 max). */
+ * retry threshold (0 disable, 31 max).
+ */
QCA_WLAN_VENDOR_ATTR_CONFIG_CTRL_RETRY = 13,
/* 8-bit unsigned value to configure the propagation delay for
- * 2G/5G band (0~63, units in us) */
+ * 2G/5G band (0~63, units in us)
+ */
QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_DELAY = 14,
/* Unsigned 32-bit value to configure the number of unicast TX fail
* packet count. The peer is disconnected once this threshold is
- * reached. */
+ * reached.
+ */
QCA_WLAN_VENDOR_ATTR_CONFIG_TX_FAIL_COUNT = 15,
/* Attribute used to set scan default IEs to the driver.
*
@@ -1293,7 +1600,8 @@
* merged with the IEs received along with scan request coming to the
* driver. If a particular IE is present in the scan default IEs but not
* present in the scan request, then that IE should be added to the IEs
- * sent in the Probe Request frames for that scan request. */
+ * sent in the Probe Request frames for that scan request.
+ */
QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_DEFAULT_IES = 16,
/* Unsigned 32-bit attribute for generic commands */
QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_COMMAND = 17,
@@ -1302,41 +1610,50 @@
/* Unsigned 32-bit data attribute for generic command response */
QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA = 19,
/* Unsigned 32-bit length attribute for
- * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA */
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA
+ */
QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_LENGTH = 20,
/* Unsigned 32-bit flags attribute for
- * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA */
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA
+ */
QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_FLAGS = 21,
/* Unsigned 32-bit, defining the access policy.
* See enum qca_access_policy. Used with
- * QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST. */
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST.
+ */
QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY = 22,
/* Sets the list of full set of IEs for which a specific access policy
* has to be applied. Used along with
* QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY to control the access.
- * Zero length payload can be used to clear this access constraint. */
+ * Zero length payload can be used to clear this access constraint.
+ */
QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST = 23,
/* Unsigned 32-bit, specifies the interface index (netdev) for which the
* corresponding configurations are applied. If the interface index is
* not specified, the configurations are attributed to the respective
- * wiphy. */
+ * wiphy.
+ */
QCA_WLAN_VENDOR_ATTR_CONFIG_IFINDEX = 24,
/* 8-bit unsigned value to trigger QPower: 1-Enable, 0-Disable */
QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER = 25,
/* 8-bit unsigned value to configure the driver and below layers to
* ignore the assoc disallowed set by APs while connecting
- * 1-Ignore, 0-Don't ignore */
+ * 1-Ignore, 0-Don't ignore
+ */
QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED = 26,
/* 32-bit unsigned value to trigger antenna diversity features:
- * 1-Enable, 0-Disable */
+ * 1-Enable, 0-Disable
+ */
QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_ENA = 27,
/* 32-bit unsigned value to configure specific chain antenna */
QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_CHAIN = 28,
/* 32-bit unsigned value to trigger cycle selftest
- * 1-Enable, 0-Disable */
+ * 1-Enable, 0-Disable
+ */
QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST = 29,
/* 32-bit unsigned to configure the cycle time of selftest
- * the unit is micro-second */
+ * the unit is micro-second
+ */
QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST_INTVL = 30,
/* 32-bit unsigned value to set reorder timeout for AC_VO */
QCA_WLAN_VENDOR_ATTR_CONFIG_RX_REORDER_TIMEOUT_VOICE = 31,
@@ -1360,10 +1677,12 @@
* NL80211_CHAN_WIDTH_10 means 10 MHz. If set, the device work in 5 or
* 10 MHz channel width, the station will not connect to a BSS using 20
* MHz or higher bandwidth. Set to NL80211_CHAN_WIDTH_20_NOHT to
- * clear this constraint. */
+ * clear this constraint.
+ */
QCA_WLAN_VENDOR_ATTR_CONFIG_SUB20_CHAN_WIDTH = 39,
/* 32-bit unsigned value to configure the propagation absolute delay
- * for 2G/5G band (units in us) */
+ * for 2G/5G band (units in us)
+ */
QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_ABS_DELAY = 40,
/* 32-bit unsigned value to set probe period */
QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_PROBE_PERIOD = 41,
@@ -1431,7 +1750,7 @@
QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_ENABLE = 51,
/* 8-bit unsigned value to set the total beacon miss count
- * This paramater will set the total beacon miss count.
+ * This parameter will set the total beacon miss count.
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_TOTAL_BEACON_MISS_COUNT = 52,
@@ -1443,9 +1762,32 @@
/* 8-bit unsigned value to configure the driver and below layers to
* enable/disable all FILS features.
- * 0-enable, 1-disable */
+ * 0-enable, 1-disable
+ */
QCA_WLAN_VENDOR_ATTR_CONFIG_DISABLE_FILS = 54,
+ /* 16-bit unsigned value to configure the level of WLAN latency
+ * module. See enum qca_wlan_vendor_attr_config_latency_level.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL = 55,
+
+ /* 8-bit unsigned value indicating the driver to use the RSNE as-is from
+ * the connect interface. Exclusively used for the scenarios where the
+ * device is used as a test bed device with special functionality and
+ * not recommended for production. This helps driver to not validate the
+ * RSNE passed from user space and thus allow arbitrary IE data to be
+ * used for testing purposes.
+ * 1-enable, 0-disable.
+ * Applications set/reset this configuration. If not reset, this
+ * parameter remains in use until the driver is unloaded.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RSN_IE = 56,
+
+ /* 8-bit unsigned value to trigger green Tx power saving.
+ * 1-Enable, 0-Disable
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_GTX = 57,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
@@ -1478,7 +1820,8 @@
enum qca_wlan_vendor_attr_sap_conditional_chan_switch {
QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_INVALID = 0,
/* Priority based frequency list (an array of u32 values in host byte
- * order) */
+ * order)
+ */
QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST = 1,
/* Status of the conditional switch (u32).
* 0: Success, Non-zero: Failure
@@ -1513,6 +1856,36 @@
};
/**
+ * qca_wlan_set_qdepth_thresh_attr - Parameters for setting
+ * MSDUQ depth threshold per peer per tid in the target
+ *
+ * Associated Vendor Command:
+ * QCA_NL80211_VENDOR_SUBCMD_SET_QDEPTH_THRESH
+ */
+enum qca_wlan_set_qdepth_thresh_attr {
+ QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_INVALID = 0,
+ /* 6-byte MAC address */
+ QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_MAC_ADDR,
+ /* Unsigned 32-bit attribute for holding the TID */
+ QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_TID,
+ /* Unsigned 32-bit attribute for holding the update mask
+ * bit 0 - Update high priority msdu qdepth threshold
+ * bit 1 - Update low priority msdu qdepth threshold
+ * bit 2 - Update UDP msdu qdepth threshold
+ * bit 3 - Update Non UDP msdu qdepth threshold
+ * rest of bits are reserved
+ */
+ QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_UPDATE_MASK,
+ /* Unsigned 32-bit attribute for holding the threshold value */
+ QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_VALUE,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_LAST,
+ QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_MAX =
+ QCA_WLAN_VENDOR_ATTR_QDEPTH_THRESH_LAST - 1,
+};
+
+/**
* enum qca_wlan_vendor_attr_get_hw_capability - Wi-Fi hardware capability
*/
enum qca_wlan_vendor_attr_get_hw_capability {
@@ -1684,6 +2057,12 @@
* @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF: per antenna NF value
* @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_RSSI_BEACON: RSSI of beacon
* @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_SNR_BEACON: SNR of beacon
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_REPORT_TIME: u64
+ * Absolute timestamp from 1970/1/1, unit in ms. After receiving the
+ * message, user layer APP could call gettimeofday to get another
+ * timestamp and calculate transfer delay for the message.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MEASUREMENT_TIME: u32
+ * Real period for this measurement, unit in us.
*/
enum qca_wlan_vendor_attr_ll_stats_ext {
QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_INVALID = 0,
@@ -1777,6 +2156,9 @@
QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_RSSI_BEACON,
QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_SNR_BEACON,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_REPORT_TIME,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MEASUREMENT_TIME,
+
QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_LAST,
QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX =
QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_LAST - 1
@@ -1830,7 +2212,7 @@
* @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_INITIATOR: Set if driver
* can run FTM sessions. QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION
* will be supported if set.
-* @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_ASAP: Set if FTM responder
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_ASAP: Set if FTM responder
* supports immediate (ASAP) response.
* @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA: Set if driver supports standalone
* AOA measurement using QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS.
@@ -2147,6 +2529,18 @@
};
/**
+ * enum qca_wlan_vendor_attr_fw_state - State of firmware
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FW_STATE_ERROR: FW is in bad state
+ * @QCA_WLAN_VENDOR_ATTR_FW_STATE_ACTIVE: FW is active
+ */
+enum qca_wlan_vendor_attr_fw_state {
+ QCA_WLAN_VENDOR_ATTR_FW_STATE_ERROR,
+ QCA_WLAN_VENDOR_ATTR_FW_STATE_ACTIVE,
+ QCA_WLAN_VENDOR_ATTR_FW_STATE_MAX
+};
+
+/**
* BRP antenna limit mode
*
* @QCA_WLAN_VENDOR_ATTR_BRP_ANT_LIMIT_MODE_DISABLE: Disable BRP force
@@ -2393,13 +2787,13 @@
/* Unsigned int 8 bit value; 0:20 MHz, 1:40 MHz, 2:80 MHz, 3:160 MHz */
QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW = 40,
/* Unsigned int 8 bit value; OFDM/CCK rate code would be as per IEEE Std
- * in the units of 0.5 Mbps HT/VHT it would be MCS index */
+ * in the units of 0.5 Mbps HT/VHT it would be MCS index
+ */
QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX = 41,
/* Unsigned 32 bit value. Bit rate in units of 100 kbps */
QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE = 42,
-
/* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_STAT_* could be
* nested within the peer info stats.
*/
@@ -2558,14 +2952,18 @@
/* Unsigned 32 bit value */
QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_FAIL_CNT = 82,
+ /* Unsigned int 32 value.
+ * Pending MSDUs corresponding to respective AC.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_PENDING_MSDU = 83,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX =
QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST - 1,
};
-enum qca_wlan_vendor_attr_ll_stats_type
-{
+enum qca_wlan_vendor_attr_ll_stats_type {
QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_INVALID = 0,
QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_RADIO = 1,
QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_IFACE = 2,
@@ -2682,10 +3080,14 @@
* limit feature.
* @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER: Select the SAR power
* limits configured by %QCA_NL80211_VENDOR_SUBCMD_SET_SAR.
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0: Select the SAR power
+ * limits version 2.0 configured by %QCA_NL80211_VENDOR_SUBCMD_SET_SAR.
*
* This enumerates the valid set of values that may be supplied for
* attribute %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT in an instance of
- * the %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS vendor command.
+ * the %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS vendor command or in
+ * the response to an instance of the
+ * %QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS vendor command.
*/
enum qca_vendor_attr_sar_limits_selections {
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0 = 0,
@@ -2695,6 +3097,7 @@
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4 = 4,
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE = 5,
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER = 6,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0 = 7,
};
/**
@@ -2709,7 +3112,8 @@
* attribute %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION in an
* instance of attribute %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC in an
* instance of the %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS vendor
- * command.
+ * command or in the response to an instance of the
+ * %QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS vendor command.
*/
enum qca_vendor_attr_sar_limits_spec_modulations {
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_CCK = 0,
@@ -2740,7 +3144,12 @@
* %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN, and
* %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION and always
* contains as a payload the attribute
- * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT.
+ * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT,
+ * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX.
+ * Either %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT or
+ * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX is
+ * needed based upon the value of
+ * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE.
*
* @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND: Optional (u32) value to
* indicate for which band this specification applies. Valid
@@ -2765,8 +3174,16 @@
* @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT: Required (u32)
* value to specify the actual power limit value in units of 0.5
* dBm (i.e., a value of 11 represents 5.5 dBm).
+ * This is required, when %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT is
+ * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER.
*
- * These attributes are used with %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS.
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX: Required (u32)
+ * value to indicate SAR V2 indices (0 - 11) to select SAR V2 profiles.
+ * This is required, when %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT is
+ * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0.
+ *
+ * These attributes are used with %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS
+ * and %QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS.
*/
enum qca_vendor_attr_sar_limits {
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_INVALID = 0,
@@ -2777,6 +3194,7 @@
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN = 5,
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION = 6,
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT = 7,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX = 8,
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX =
@@ -2824,7 +3242,7 @@
/* Unsigned 32-bit value; used to indicate the size of memory
* dump to be allocated.
- */
+ */
QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_MEMDUMP_SIZE = 2,
/* keep last */
@@ -2866,6 +3284,8 @@
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 */
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_HINT = 21,
/* keep last */
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_AFTER_LAST,
@@ -3255,6 +3675,14 @@
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_BUCKETS_SCANNED = 45,
+ /* Unsigned 32-bit value; a GSCAN Capabilities attribute.
+ * This is used to limit the maximum number of BSSIDs while sending
+ * the vendor command QCA_NL80211_VENDOR_SUBCMD_ROAM with attributes
+ * QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID and
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_MAX_NUM_BLACKLISTED_BSSID = 46,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX =
@@ -3528,7 +3956,8 @@
/**
* qca_wlan_vendor_attr_pcl: Represents attributes for
* preferred channel list (PCL). These attributes are sent as part of
- * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PCL.
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PCL and
+ * QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST.
*/
enum qca_wlan_vendor_attr_pcl {
QCA_WLAN_VENDOR_ATTR_PCL_INVALID = 0,
@@ -3537,6 +3966,17 @@
QCA_WLAN_VENDOR_ATTR_PCL_CHANNEL = 1,
/* Channel weightage (u8) */
QCA_WLAN_VENDOR_ATTR_PCL_WEIGHT = 2,
+ /* Channel frequency (u32) in MHz */
+ QCA_WLAN_VENDOR_ATTR_PCL_FREQ = 3,
+ /* Channel flags (u32)
+ * bit 0 set: channel to be used for GO role,
+ * bit 1 set: channel to be used on CLI role,
+ * bit 2 set: channel must be considered for operating channel
+ * selection & peer chosen operating channel should be
+ * one of the channels with this flag set,
+ * bit 3 set: channel should be excluded in GO negotiation
+ */
+ QCA_WLAN_VENDOR_ATTR_PCL_FLAG = 4,
};
/**
@@ -3556,12 +3996,14 @@
/* Flag attribute to indicate if 11ac is offloaded to firmware */
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_IS_OFFLOAD_ENABLED = 3,
/* Flag attribute to indicate if driver provides additional channel
- * capability as part of scan operation */
+ * capability as part of scan operation
+ */
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_ADD_CHAN_STATS_SUPPORT = 4,
/* Flag attribute to indicate interface status is UP */
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_AP_UP = 5,
/* Operating mode (u8) of interface. Takes one of enum nl80211_iftype
- * values. */
+ * values.
+ */
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_SAP_MODE = 6,
/* Channel width (u8). It takes one of enum nl80211_chan_width values.
* This is the upper bound of channel width. ACS logic should try to get
@@ -3572,7 +4014,8 @@
/* This (u8) will hold values of one of enum nl80211_bands */
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_BAND = 8,
/* PHY/HW mode (u8). Takes one of enum qca_wlan_vendor_acs_hw_mode
- * values */
+ * values
+ */
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PHY_MODE = 9,
/* Array of (u32) supported frequency list among which ACS should choose
* best frequency.
@@ -3591,6 +4034,11 @@
* qca_wlan_vendor_attr_external_acs_policy.
*/
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_POLICY = 13,
+ /* Reference RF Operating Parameter (RROP) availability information
+ * (u16). It uses values defined in enum
+ * qca_wlan_vendor_attr_rropavail_info.
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_RROPAVAIL_INFO = 14,
/* keep last */
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_LAST,
@@ -3642,10 +4090,10 @@
/* Indicates if the reason for the failure is due to a protocol
* layer/module.
*/
- QCA_CHIP_POWER_SAVE_FAILURE_REASON_PROTOCOL = 0,
+ QCA_CHIP_POWER_SAVE_FAILURE_REASON_PROTOCOL = 0,
/* Indicates if the reason for the failure is due to a hardware issue.
*/
- QCA_CHIP_POWER_SAVE_FAILURE_REASON_HARDWARE = 1,
+ QCA_CHIP_POWER_SAVE_FAILURE_REASON_HARDWARE = 1,
};
/**
@@ -3654,17 +4102,70 @@
* information leading to the power save failure.
*/
enum qca_attr_chip_power_save_failure {
- QCA_ATTR_CHIP_POWER_SAVE_FAILURE_INVALID = 0,
- /* Reason to cause the power save failure.
+ QCA_ATTR_CHIP_POWER_SAVE_FAILURE_INVALID = 0,
+ /* Reason to cause the power save failure.
* These reasons are represented by
* enum qca_chip_power_save_failure_reason.
*/
- QCA_ATTR_CHIP_POWER_SAVE_FAILURE_REASON = 1,
+ QCA_ATTR_CHIP_POWER_SAVE_FAILURE_REASON = 1,
- /* keep last */
- QCA_ATTR_CHIP_POWER_SAVE_FAILURE_LAST,
- QCA_ATTR_CHIP_POWER_SAVE_FAILURE_MAX =
- QCA_ATTR_CHIP_POWER_SAVE_FAILURE_LAST - 1,
+ /* keep last */
+ QCA_ATTR_CHIP_POWER_SAVE_FAILURE_LAST,
+ QCA_ATTR_CHIP_POWER_SAVE_FAILURE_MAX =
+ QCA_ATTR_CHIP_POWER_SAVE_FAILURE_LAST - 1,
+};
+
+/**
+ * qca_wlan_vendor_nud_stats_data_pkt_flags: Flag representing the various
+ * data types for which the stats have to get collected.
+ */
+enum qca_wlan_vendor_nud_stats_data_pkt_flags {
+ QCA_WLAN_VENDOR_NUD_STATS_DATA_ARP = 1 << 0,
+ QCA_WLAN_VENDOR_NUD_STATS_DATA_DNS = 1 << 1,
+ QCA_WLAN_VENDOR_NUD_STATS_DATA_TCP_HANDSHAKE = 1 << 2,
+ QCA_WLAN_VENDOR_NUD_STATS_DATA_ICMPV4 = 1 << 3,
+ QCA_WLAN_VENDOR_NUD_STATS_DATA_ICMPV6 = 1 << 4,
+ /* Used by QCA_ATTR_NUD_STATS_PKT_TYPE only in nud stats get
+ * to represent the stats of respective data type.
+ */
+ QCA_WLAN_VENDOR_NUD_STATS_DATA_TCP_SYN = 1 << 5,
+ QCA_WLAN_VENDOR_NUD_STATS_DATA_TCP_SYN_ACK = 1 << 6,
+ QCA_WLAN_VENDOR_NUD_STATS_DATA_TCP_ACK = 1 << 7,
+};
+
+enum qca_wlan_vendor_nud_stats_set_data_pkt_info {
+ QCA_ATTR_NUD_STATS_DATA_PKT_INFO_INVALID = 0,
+ /* Represents the data packet type to be monitored (u32).
+ * Host driver tracks the stats corresponding to each data frame
+ * represented by these flags.
+ * These data packets are represented by
+ * enum qca_wlan_vendor_nud_stats_data_pkt_flags
+ */
+ QCA_ATTR_NUD_STATS_DATA_PKT_INFO_TYPE = 1,
+ /* Name corresponding to the DNS frame for which the respective DNS
+ * stats have to get monitored (string). Max string length 255.
+ */
+ QCA_ATTR_NUD_STATS_DATA_PKT_INFO_DNS_DOMAIN_NAME = 2,
+ /* source port on which the respective proto stats have to get
+ * collected (u32).
+ */
+ QCA_ATTR_NUD_STATS_DATA_PKT_INFO_SRC_PORT = 3,
+ /* destination port on which the respective proto stats have to get
+ * collected (u32).
+ */
+ QCA_ATTR_NUD_STATS_DATA_PKT_INFO_DEST_PORT = 4,
+ /* IPv4 address for which the destined data packets have to be
+ * monitored. (in network byte order), u32.
+ */
+ QCA_ATTR_NUD_STATS_DATA_PKT_INFO_DEST_IPV4 = 5,
+ /* IPv6 address for which the destined data packets have to be
+ * monitored. (in network byte order), 16 bytes array.
+ */
+ QCA_ATTR_NUD_STATS_DATA_PKT_INFO_DEST_IPV6 = 6,
+
+ QCA_ATTR_NUD_STATS_DATA_PKT_INFO_LAST,
+ QCA_ATTR_NUD_STATS_DATA_PKT_INFO_MAX =
+ QCA_ATTR_NUD_STATS_DATA_PKT_INFO_LAST - 1,
};
/**
@@ -3679,8 +4180,15 @@
* Start - If included, Stop - If not included
*/
QCA_ATTR_NUD_STATS_SET_START = 1,
- /* IPv4 address of the default gateway (in network byte order) */
+ /* IPv4 address of the default gateway (in network byte order), u32 */
QCA_ATTR_NUD_STATS_GW_IPV4 = 2,
+ /* Represents the list of data packet types to be monitored.
+ * Host driver tracks the stats corresponding to each data frame
+ * represented by these flags.
+ * These data packets are represented by
+ * enum qca_wlan_vendor_nud_stats_set_data_pkt_info
+ */
+ QCA_ATTR_NUD_STATS_SET_DATA_PKT_INFO = 3,
/* keep last */
QCA_ATTR_NUD_STATS_SET_LAST,
@@ -3688,6 +4196,58 @@
QCA_ATTR_NUD_STATS_SET_LAST - 1,
};
+enum qca_attr_nud_data_stats {
+ QCA_ATTR_NUD_DATA_STATS_INVALID = 0,
+ /* Data packet type for which the stats are collected (u32).
+ * Represented by enum qca_wlan_vendor_nud_stats_data_pkt_flags
+ */
+ QCA_ATTR_NUD_STATS_PKT_TYPE = 1,
+ /* Name corresponding to the DNS frame for which the respective DNS
+ * stats are monitored (string). Max string length 255.
+ */
+ QCA_ATTR_NUD_STATS_PKT_DNS_DOMAIN_NAME = 2,
+ /* source port on which the respective proto stats are collected (u32).
+ */
+ QCA_ATTR_NUD_STATS_PKT_SRC_PORT = 3,
+ /* destination port on which the respective proto stats are collected
+ * (u32).
+ */
+ QCA_ATTR_NUD_STATS_PKT_DEST_PORT = 4,
+ /* IPv4 address for which the destined data packets have to be
+ * monitored. (in network byte order), u32.
+ */
+ QCA_ATTR_NUD_STATS_PKT_DEST_IPV4 = 5,
+ /* IPv6 address for which the destined data packets have to be
+ * monitored. (in network byte order), 16 bytes array.
+ */
+ QCA_ATTR_NUD_STATS_PKT_DEST_IPV6 = 6,
+ /* Data packet Request count received from netdev (u32). */
+ QCA_ATTR_NUD_STATS_PKT_REQ_COUNT_FROM_NETDEV = 7,
+ /* Data packet Request count sent to lower MAC from upper MAC (u32). */
+ QCA_ATTR_NUD_STATS_PKT_REQ_COUNT_TO_LOWER_MAC = 8,
+ /* Data packet Request count received by lower MAC from upper MAC
+ * (u32)
+ */
+ QCA_ATTR_NUD_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC = 9,
+ /* Data packet Request count successfully transmitted by the device
+ * (u32)
+ */
+ QCA_ATTR_NUD_STATS_PKT_REQ_COUNT_TX_SUCCESS = 10,
+ /* Data packet Response count received by lower MAC (u32) */
+ QCA_ATTR_NUD_STATS_PKT_RSP_RX_COUNT_BY_LOWER_MAC = 11,
+ /* Data packet Response count received by upper MAC (u32) */
+ QCA_ATTR_NUD_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC = 12,
+ /* Data packet Response count delivered to netdev (u32) */
+ QCA_ATTR_NUD_STATS_PKT_RSP_COUNT_TO_NETDEV = 13,
+ /* Data Packet Response count that are dropped out of order (u32) */
+ QCA_ATTR_NUD_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP = 14,
+
+ /* keep last */
+ QCA_ATTR_NUD_DATA_STATS_LAST,
+ QCA_ATTR_NUD_DATA_STATS_MAX =
+ QCA_ATTR_NUD_DATA_STATS_LAST - 1,
+};
+
/**
* qca_attr_nud_stats_get: Attributes to vendor subcmd
* QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET. This carries the requisite
@@ -3695,21 +4255,21 @@
*/
enum qca_attr_nud_stats_get {
QCA_ATTR_NUD_STATS_GET_INVALID = 0,
- /* ARP Request count from netdev */
+ /* ARP Request count from netdev (u32) */
QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV = 1,
- /* ARP Request count sent to lower MAC from upper MAC */
+ /* ARP Request count sent to lower MAC from upper MAC (u32) */
QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC = 2,
- /* ARP Request count received by lower MAC from upper MAC */
+ /* ARP Request count received by lower MAC from upper MAC (u32) */
QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC = 3,
- /* ARP Request count successfully transmitted by the device */
+ /* ARP Request count successfully transmitted by the device (u32) */
QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS = 4,
- /* ARP Response count received by lower MAC */
+ /* ARP Response count received by lower MAC (u32) */
QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC = 5,
- /* ARP Response count received by upper MAC */
+ /* ARP Response count received by upper MAC (u32) */
QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC = 6,
- /* ARP Response count delivered to netdev */
+ /* ARP Response count delivered to netdev (u32) */
QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV = 7,
- /* ARP Response count delivered to netdev */
+ /* ARP Response count dropped due to out of order reception (u32) */
QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP = 8,
/* Flag indicating if the station's link to the AP is active.
* Active Link - If included, Inactive link - If not included
@@ -3719,6 +4279,11 @@
* Yes - If detected, No - If not detected.
*/
QCA_ATTR_NUD_STATS_IS_DAD = 10,
+ /* List of Data packet types for which the stats are requested.
+ * This list does not carry ARP stats as they are done by the
+ * above attributes. Represented by enum qca_attr_nud_data_stats.
+ */
+ QCA_ATTR_NUD_STATS_DATA_PKT_STATS = 11,
/* keep last */
QCA_ATTR_NUD_STATS_GET_LAST,
@@ -3784,7 +4349,8 @@
enum qca_wlan_vendor_attr_get_he_capabilities {
QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_INVALID = 0,
/* Whether HE capabilities is supported
- * (u8 attribute: 0 = not supported, 1 = supported) */
+ * (u8 attribute: 0 = not supported, 1 = supported)
+ */
QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED = 1,
/* HE PHY capabilities, array of 3 u32 values */
QCA_WLAN_VENDOR_ATTR_PHY_CAPAB = 2,
@@ -3895,12 +4461,159 @@
* specific scan to be stopped.
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COOKIE = 19,
+ /* Skip interval for FFT reports. u32 attribute */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_PERIOD = 20,
+ /* Set to report only one set of FFT results.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SHORT_REPORT = 21,
+ /* Debug level for spectral module in driver.
+ * 0 : Verbosity level 0
+ * 1 : Verbosity level 1
+ * 2 : Verbosity level 2
+ * 3 : Matched filterID display
+ * 4 : One time dump of FFT report
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DEBUG_LEVEL = 22,
+ /* Type of spectral scan request. u32 attribute.
+ * It uses values defined in enum
+ * qca_wlan_vendor_attr_spectral_scan_request_type.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE = 23,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX =
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_AFTER_LAST - 1,
};
+/**
+ * enum qca_wlan_vendor_attr_spectral_diag_stats - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_DIAG_STATS.
+ */
+enum qca_wlan_vendor_attr_spectral_diag_stats {
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_INVALID = 0,
+ /* Number of spectral TLV signature mismatches.
+ * u64 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_SIG_MISMATCH = 1,
+ /* Number of spectral phyerror events with insufficient length when
+ * parsing for secondary 80 search FFT report. u64 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_SEC80_SFFT_INSUFFLEN = 2,
+ /* Number of spectral phyerror events without secondary 80
+ * search FFT report. u64 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_NOSEC80_SFFT = 3,
+ /* Number of spectral phyerror events with vht operation segment 1 id
+ * mismatches in search fft report. u64 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_VHTSEG1ID_MISMATCH = 4,
+ /* Number of spectral phyerror events with vht operation segment 2 id
+ * mismatches in search fft report. u64 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_VHTSEG2ID_MISMATCH = 5,
+
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_MAX =
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_spectral_cap - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CAP_INFO.
+ */
+enum qca_wlan_vendor_attr_spectral_cap {
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_INVALID = 0,
+ /* Flag attribute to indicate phydiag capability */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_PHYDIAG = 1,
+ /* Flag attribute to indicate radar detection capability */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_RADAR = 2,
+ /* Flag attribute to indicate spectral capability */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_SPECTRAL = 3,
+ /* Flag attribute to indicate advanced spectral capability */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_ADVANCED_SPECTRAL = 4,
+ /* Spectral hardware generation. u32 attribute.
+ * It uses values defined in enum
+ * qca_wlan_vendor_spectral_scan_cap_hw_gen.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_HW_GEN = 5,
+ /* Spectral bin scaling formula ID. u16 attribute.
+ * It uses values defined in enum
+ * qca_wlan_vendor_spectral_scan_cap_formula_id.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_FORMULA_ID = 6,
+ /* Spectral bin scaling param - low level offset.
+ * s16 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_LOW_LEVEL_OFFSET = 7,
+ /* Spectral bin scaling param - high level offset.
+ * s16 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_HIGH_LEVEL_OFFSET = 8,
+ /* Spectral bin scaling param - RSSI threshold.
+ * s16 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_RSSI_THR = 9,
+ /* Spectral bin scaling param - default AGC max gain.
+ * u8 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_DEFAULT_AGC_MAX_GAIN = 10,
+
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_MAX =
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_spectral_scan_status - used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_STATUS.
+ */
+enum qca_wlan_vendor_attr_spectral_scan_status {
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_INVALID = 0,
+ /* Flag attribute to indicate whether spectral scan is enabled */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_IS_ENABLED = 1,
+ /* Flag attribute to indicate whether spectral scan is in progress*/
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_IS_ACTIVE = 2,
+
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_MAX =
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_AFTER_LAST - 1,
+};
+
+/**
+ * qca_wlan_vendor_attr_spectral_scan_request_type: Attribute values for
+ * QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE to the vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_START. This represents the
+ * spectral scan request types.
+ * @QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE_SCAN_AND_CONFIG: Request to
+ * set the spectral parameters and start scan.
+ * @QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE_SCAN: Request to
+ * only set the spectral parameters.
+ * @QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE_CONFIG: Request to
+ * only start the spectral scan.
+ */
+enum qca_wlan_vendor_attr_spectral_scan_request_type {
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE_SCAN_AND_CONFIG,
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE_SCAN,
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE_CONFIG,
+};
+
+/**
+ * qca_wlan_vendor_spectral_scan_cap_hw_gen: Attribute values for
+ * QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_HW_GEN to the vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CAP_INFO. This represents the
+ * spectral hardware generation.
+ * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_HW_GEN_1: generation 1
+ * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_HW_GEN_2: generation 2
+ * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_HW_GEN_3: generation 3
+ */
+enum qca_wlan_vendor_spectral_scan_cap_hw_gen {
+ QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_HW_GEN_1 = 0,
+ QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_HW_GEN_2 = 1,
+ QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_HW_GEN_3 = 2,
+};
+
enum qca_wlan_vendor_tos {
QCA_WLAN_VENDOR_TOS_BK = 0,
QCA_WLAN_VENDOR_TOS_BE = 1,
@@ -3969,4 +4682,2031 @@
QCA_WLAN_VENDOR_ATTR_HANG_AFTER_LAST - 1,
};
+/**
+ * enum qca_wlan_vendor_attr_flush_pending - Attributes for
+ * flushing pending traffic in firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_ADDR: Configure peer MAC address.
+ * @QCA_WLAN_VENDOR_ATTR_AC: Configure access category of the pending
+ * packets. It is u8 value with bit 0~3 represent AC_BE, AC_BK,
+ * AC_VI, AC_VO respectively. Set the corresponding bit to 1 to
+ * flush packets with access category.
+ */
+enum qca_wlan_vendor_attr_flush_pending {
+ QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_PEER_ADDR = 1,
+ QCA_WLAN_VENDOR_ATTR_AC = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_MAX =
+ QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_AFTER_LAST - 1,
+};
+
+/**
+ * qca_wlan_vendor_spectral_scan_cap_formula_id: Attribute values for
+ * QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_FORMULA_ID in the vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CAP_INFO. This represents the
+ * Spectral bin scaling formula ID.
+ * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_NO_SCALING: No scaling
+ * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_AGC_GAIN_RSSI_CORR_BASED: AGC gain
+ * and RSSI threshold based formula.
+ */
+enum qca_wlan_vendor_spectral_scan_cap_formula_id {
+ QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_NO_SCALING = 0,
+ QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_AGC_GAIN_RSSI_CORR_BASED = 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_rropavail_info - Specifies whether Representative
+ * RF Operating Parameter (RROP) information is available, and if so, at which
+ * point in the application-driver interaction sequence it can be retrieved by
+ * the application from the driver. This point may vary by architecture and
+ * other factors. This is a u16 value.
+ */
+enum qca_wlan_vendor_attr_rropavail_info {
+ /* RROP information is unavailable. */
+ QCA_WLAN_VENDOR_ATTR_RROPAVAIL_INFO_UNAVAILABLE,
+ /* RROP information is available and the application can retrieve the
+ * information after receiving an QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS
+ * event from the driver.
+ */
+ QCA_WLAN_VENDOR_ATTR_RROPAVAIL_INFO_EXTERNAL_ACS_START,
+ /* RROP information is available only after a vendor specific scan
+ * (requested using QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN) has
+ * successfully completed. The application can retrieve the information
+ * after receiving the QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE event from
+ * the driver.
+ */
+ QCA_WLAN_VENDOR_ATTR_RROPAVAIL_INFO_VSCAN_END,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_rrop_info - Specifies vendor specific
+ * Representative RF Operating Parameter (RROP) information. It is sent for the
+ * vendor command QCA_NL80211_VENDOR_SUBCMD_GET_RROP_INFO. This information is
+ * intended for use by external Auto Channel Selection applications. It provides
+ * guidance values for some RF parameters that are used by the system during
+ * operation. These values could vary by channel, band, radio, and so on.
+ */
+enum qca_wlan_vendor_attr_rrop_info {
+ QCA_WLAN_VENDOR_ATTR_RROP_INFO_INVALID = 0,
+
+ /* Representative Tx Power List (RTPL) which has an array of nested
+ * values as per attributes in enum qca_wlan_vendor_attr_rtplinst.
+ */
+ QCA_WLAN_VENDOR_ATTR_RROP_INFO_RTPL = 1,
+
+ QCA_WLAN_VENDOR_ATTR_RROP_INFO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_RROP_INFO_MAX =
+ QCA_WLAN_VENDOR_ATTR_RROP_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_rtplinst - Specifies attributes for individual list
+ * entry instances in the Representative Tx Power List (RTPL). It provides
+ * simplified power values intended for helping external Auto channel Selection
+ * applications compare potential Tx power performance between channels, other
+ * operating conditions remaining identical. These values are not necessarily
+ * the actual Tx power values that will be used by the system. They are also not
+ * necessarily the max or average values that will be used. Instead, they are
+ * relative, summarized keys for algorithmic use computed by the driver or
+ * underlying firmware considering a number of vendor specific factors.
+ */
+enum qca_wlan_vendor_attr_rtplinst {
+ QCA_WLAN_VENDOR_ATTR_RTPLINST_INVALID = 0,
+
+ /* Primary channel number (u8) */
+ QCA_WLAN_VENDOR_ATTR_RTPLINST_PRIMARY = 1,
+ /* Representative Tx power in dBm (s32) with emphasis on throughput. */
+ QCA_WLAN_VENDOR_ATTR_RTPLINST_TXPOWER_THROUGHPUT = 2,
+ /* Representative Tx power in dBm (s32) with emphasis on range. */
+ QCA_WLAN_VENDOR_ATTR_RTPLINST_TXPOWER_RANGE = 3,
+
+ QCA_WLAN_VENDOR_ATTR_RTPLINST_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_RTPLINST_MAX =
+ QCA_WLAN_VENDOR_ATTR_RTPLINST_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_config_latency_level - Level for
+ * wlan latency module.
+ *
+ * There will be various of Wi-Fi functionality like scan/roaming/adaptive
+ * power saving which would causing data exchange out of service, this
+ * would be a big impact on latency. For latency sensitive applications over
+ * Wi-Fi are intolerant to such operations and thus would configure them
+ * to meet their respective needs. It is well understood by such applications
+ * that altering the default behavior would degrade the Wi-Fi functionality
+ * w.r.t the above pointed WLAN operations.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_NORMAL:
+ * Default WLAN operation level which throughput orientated.
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_MODERATE:
+ * Use moderate level to improve latency by limit scan duration.
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_LOW:
+ * Use low latency level to benifit application like concurrent
+ * downloading or video streaming via constraint scan/adaptive PS.
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_ULTRALOW:
+ * Use ultra low latency level to benefit for gaming/voice
+ * application via constraint scan/roaming/adaptive PS.
+ */
+enum qca_wlan_vendor_attr_config_latency_level {
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_NORMAL = 1,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_MODERATE = 2,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_LOW = 3,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_ULTRALOW = 4,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_MAX =
+ QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_wlan_mac - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO.
+ */
+enum qca_wlan_vendor_attr_mac {
+ QCA_WLAN_VENDOR_ATTR_MAC_INVALID = 0,
+
+ /* MAC mode info list which has an array of nested values as
+ * per attributes in enum qca_wlan_vendor_attr_mac_mode_info.
+ */
+ QCA_WLAN_VENDOR_ATTR_MAC_INFO = 1,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_MAC_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_MAC_MAX =
+ QCA_WLAN_VENDOR_ATTR_MAC_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_mac_iface_info - Information of the connected
+ * Wi-Fi netdev interface on a respective MAC.
+ * Used by the attribute QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO.
+ */
+enum qca_wlan_vendor_attr_mac_iface_info {
+ QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_INVALID = 0,
+ /* Wi-Fi netdev's interface index (u32) */
+ QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_IFINDEX = 1,
+ /* Associated frequency in MHz of the connected Wi-Fi interface (u32) */
+ QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_FREQ = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_MAX =
+ QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_mac_info - Points to MAC the information.
+ * Used by the attribute QCA_WLAN_VENDOR_ATTR_MAC_INFO of the
+ * vendor command QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO.
+ */
+enum qca_wlan_vendor_attr_mac_info {
+ QCA_WLAN_VENDOR_ATTR_MAC_INFO_INVALID = 0,
+ /* Hardware MAC ID associated for the MAC (u32) */
+ QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAC_ID = 1,
+ /* Band supported by the MAC at a given point.
+ * This is a u32 bitmask of BIT(NL80211_BAND_*) as described in %enum
+ * nl80211_band.
+ */
+ QCA_WLAN_VENDOR_ATTR_MAC_INFO_BAND = 2,
+ /* Refers to list of WLAN netdev interfaces associated with this MAC.
+ * Represented by enum qca_wlan_vendor_attr_mac_iface_info.
+ */
+ QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO = 3,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_MAC_INFO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAX =
+ QCA_WLAN_VENDOR_ATTR_MAC_INFO_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_get_logger_features - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET.
+ */
+enum qca_wlan_vendor_attr_get_logger_features {
+ QCA_WLAN_VENDOR_ATTR_LOGGER_INVALID = 0,
+ /* Unsigned 32-bit enum value of wifi_logger_supported_features */
+ QCA_WLAN_VENDOR_ATTR_LOGGER_SUPPORTED = 1,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_LOGGER_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_LOGGER_MAX =
+ QCA_WLAN_VENDOR_ATTR_LOGGER_AFTER_LAST - 1,
+};
+
+/**
+ * enum wifi_logger_supported_features - Values for supported logger features
+ */
+enum wifi_logger_supported_features {
+ WIFI_LOGGER_MEMORY_DUMP_FEATURE = (1 << (0)),
+ WIFI_LOGGER_PER_PACKET_TX_RX_STATUS_FEATURE = (1 << (1)),
+ WIFI_LOGGER_CONNECT_EVENT_FEATURE = (1 << (2)),
+ WIFI_LOGGER_POWER_EVENT_FEATURE = (1 << (3)),
+ WIFI_LOGGER_WAKE_LOCK_FEATURE = (1 << (4)),
+ WIFI_LOGGER_VERBOSE_FEATURE = (1 << (5)),
+ WIFI_LOGGER_WATCHDOG_TIMER_FEATURE = (1 << (6)),
+ WIFI_LOGGER_DRIVER_DUMP_FEATURE = (1 << (7)),
+ WIFI_LOGGER_PACKET_FATE_FEATURE = (1 << (8)),
+};
+
+/**
+ * enum qca_wlan_tdls_caps_features_supported - Values for TDLS get
+ * capabilities features
+ */
+enum qca_wlan_tdls_caps_features_supported {
+ WIFI_TDLS_SUPPORT = (1 << (0)),
+ WIFI_TDLS_EXTERNAL_CONTROL_SUPPORT = (1 << (1)),
+ WIFI_TDLS_OFFCHANNEL_SUPPORT = (1 << (2))
+};
+
+/**
+ * enum qca_wlan_vendor_attr_tdls_get_capabilities - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES.
+ */
+enum qca_wlan_vendor_attr_tdls_get_capabilities {
+ QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_INVALID = 0,
+ /* Indicates the max concurrent sessions */
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX_CONC_SESSIONS,
+ /* Indicates the support for features */
+ /* Unsigned 32-bit bitmap qca_wlan_tdls_caps_features_supported
+ */
+ QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_FEATURES_SUPPORTED,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX =
+ QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_offloaded_packets_sending_control - Offload packets control
+ * command used as value for the attribute
+ * QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SENDING_CONTROL.
+ */
+enum qca_wlan_offloaded_packets_sending_control {
+ QCA_WLAN_OFFLOADED_PACKETS_SENDING_CONTROL_INVALID = 0,
+ QCA_WLAN_OFFLOADED_PACKETS_SENDING_START,
+ QCA_WLAN_OFFLOADED_PACKETS_SENDING_STOP
+};
+
+/**
+ * enum qca_wlan_vendor_attr_offloaded_packets - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_OFFLOADED_PACKETS.
+ */
+enum qca_wlan_vendor_attr_offloaded_packets {
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_INVALID = 0,
+ /* Takes valid value from the enum
+ * qca_wlan_offloaded_packets_sending_control
+ * Unsigned 32-bit value
+ */
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SENDING_CONTROL,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_REQUEST_ID,
+ /* array of u8 len: Max packet size */
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_IP_PACKET_DATA,
+ /* 6-byte MAC address used to represent source MAC address */
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SRC_MAC_ADDR,
+ /* 6-byte MAC address used to represent destination MAC address */
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_DST_MAC_ADDR,
+ /* Unsigned 32-bit value, in milli seconds */
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_PERIOD,
+ /* This optional unsigned 16-bit attribute is used for specifying
+ * ethernet protocol type. If not specified ethertype defaults to IPv4.
+ */
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_ETHER_PROTO_TYPE,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_MAX =
+ QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_rssi_monitoring_control - RSSI control commands used as values
+ * by the attribute QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL.
+ */
+enum qca_wlan_rssi_monitoring_control {
+ QCA_WLAN_RSSI_MONITORING_CONTROL_INVALID = 0,
+ QCA_WLAN_RSSI_MONITORING_START,
+ QCA_WLAN_RSSI_MONITORING_STOP,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_rssi_monitoring - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI.
+ */
+enum qca_wlan_vendor_attr_rssi_monitoring {
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_INVALID = 0,
+ /* Takes valid value from the enum
+ * qca_wlan_rssi_monitoring_control
+ * Unsigned 32-bit value enum qca_wlan_rssi_monitoring_control
+ */
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID,
+ /* Signed 8-bit value in dBm */
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI,
+ /* Signed 8-bit value in dBm */
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI,
+ /* attributes to be used/received in callback */
+ /* 6-byte MAC address used to represent current BSSID MAC address */
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID,
+ /* Signed 8-bit value indicating the current RSSI */
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX =
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ndp_params - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_NDP.
+ */
+enum qca_wlan_vendor_attr_ndp_params {
+ QCA_WLAN_VENDOR_ATTR_NDP_PARAM_INVALID = 0,
+ /* Unsigned 32-bit value
+ * enum of sub commands values in qca_wlan_ndp_sub_cmd
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD,
+ /* Unsigned 16-bit value */
+ QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID,
+ /* NL attributes for data used NDP SUB cmds */
+ /* Unsigned 32-bit value indicating a service info */
+ QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID,
+ /* Unsigned 32-bit value; channel frequency in MHz */
+ QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL,
+ /* Interface Discovery MAC address. An array of 6 Unsigned int8 */
+ QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR,
+ /* Interface name on which NDP is being created */
+ QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR,
+ /* Unsigned 32-bit value for security */
+ /* CONFIG_SECURITY is deprecated, use NCS_SK_TYPE/PMK/SCID instead */
+ QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_SECURITY,
+ /* Unsigned 32-bit value for QoS */
+ QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS,
+ /* Array of u8: len = QCA_WLAN_VENDOR_ATTR_NAN_DP_APP_INFO_LEN */
+ QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO,
+ /* Unsigned 32-bit value for NDP instance Id */
+ QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID,
+ /* Array of instance Ids */
+ QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY,
+ /* Unsigned 32-bit value for initiator/responder NDP response code
+ * accept/reject
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE,
+ /* NDI MAC address. An array of 6 Unsigned int8 */
+ QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR,
+ /* Unsigned 32-bit value errors types returned by driver
+ * The wifi_nan.h in AOSP project platform/hardware/libhardware_legacy
+ * NanStatusType includes these values.
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE,
+ /* Unsigned 32-bit value error values returned by driver
+ * The nan_i.h in AOSP project platform/hardware/qcom/wlan
+ * NanInternalStatusType includes these values.
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE,
+ /* Unsigned 32-bit value for Channel setup configuration
+ * The wifi_nan.h in AOSP project platform/hardware/libhardware_legacy
+ * NanDataPathChannelCfg includes these values.
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_CONFIG,
+ /* Unsigned 32-bit value for Cipher Suite Shared Key Type */
+ QCA_WLAN_VENDOR_ATTR_NDP_CSID,
+ /* Array of u8: len = NAN_PMK_INFO_LEN 32 bytes */
+ QCA_WLAN_VENDOR_ATTR_NDP_PMK,
+ /* Security Context Identifier that contains the PMKID
+ * Array of u8: len = NAN_SCID_BUF_LEN 1024 bytes
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_SCID,
+ /* Array of u8: len = NAN_SECURITY_MAX_PASSPHRASE_LEN 63 bytes */
+ QCA_WLAN_VENDOR_ATTR_NDP_PASSPHRASE,
+ /* Array of u8: len = NAN_MAX_SERVICE_NAME_LEN 255 bytes */
+ QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_NAME,
+ /* Unsigned 32-bit bitmap indicating schedule update
+ * BIT_0: NSS Update
+ * BIT_1: Channel list update
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_SCHEDULE_UPDATE_REASON,
+ /* Unsigned 32-bit value for NSS */
+ QCA_WLAN_VENDOR_ATTR_NDP_NSS,
+ /* Unsigned 32-bit value for NUMBER NDP CHANNEL */
+ QCA_WLAN_VENDOR_ATTR_NDP_NUM_CHANNELS,
+ /* Unsigned 32-bit value for CHANNEL BANDWIDTH
+ * 0:20 MHz, 1:40 MHz, 2:80 MHz, 3:160 MHz
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_WIDTH,
+ /* Array of channel/band width */
+ QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_INFO,
+ /* IPv6 address used by NDP (in network byte order), 16 bytes array.
+ * This attribute is used and optional for ndp request, ndp response,
+ * ndp indication, and ndp confirm.
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR = 27,
+ /* Unsigned 16-bit value indicating transport port used by NDP.
+ * This attribute is used and optional for ndp response, ndp indication,
+ * and ndp confirm.
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PORT = 28,
+ /* Unsigned 8-bit value indicating protocol used by NDP and assigned by
+ * the Internet Assigned Numbers Authority (IANA) as per:
+ * https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
+ * This attribute is used and optional for ndp response, ndp indication,
+ * and ndp confirm.
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PROTOCOL = 29,
+ /* Unsigned 8-bit value indicating if NDP remote peer supports NAN NDPE.
+ * 1:support 0:not support
+ */
+ QCA_WLAN_VENDOR_ATTR_PEER_NDPE_SUPPORT = 30,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX =
+ QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_AFTER_LAST - 1,
+};
+
+enum qca_wlan_ndp_sub_cmd {
+ QCA_WLAN_VENDOR_ATTR_NDP_INVALID = 0,
+ /* Command to create a NAN data path interface */
+ QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE = 1,
+ /* Command to delete a NAN data path interface */
+ QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE = 2,
+ /* Command to initiate a NAN data path session */
+ QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_REQUEST = 3,
+ /* Command to notify if the NAN data path session was sent */
+ QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_RESPONSE = 4,
+ /* Command to respond to NAN data path session */
+ QCA_WLAN_VENDOR_ATTR_NDP_RESPONDER_REQUEST = 5,
+ /* Command to notify on the responder about the response */
+ QCA_WLAN_VENDOR_ATTR_NDP_RESPONDER_RESPONSE = 6,
+ /* Command to initiate a NAN data path end */
+ QCA_WLAN_VENDOR_ATTR_NDP_END_REQUEST = 7,
+ /* Command to notify the if end request was sent */
+ QCA_WLAN_VENDOR_ATTR_NDP_END_RESPONSE = 8,
+ /* Command to notify the peer about the end request */
+ QCA_WLAN_VENDOR_ATTR_NDP_REQUEST_IND = 9,
+ /* Command to confirm the NAN data path session is complete */
+ QCA_WLAN_VENDOR_ATTR_NDP_CONFIRM_IND = 10,
+ /* Command to indicate the peer about the end request being received */
+ QCA_WLAN_VENDOR_ATTR_NDP_END_IND = 11,
+ /* Command to indicate the peer of schedule update */
+ QCA_WLAN_VENDOR_ATTR_NDP_SCHEDULE_UPDATE_IND = 12
+};
+
+/**
+ * enum qca_wlan_vendor_attr_nd_offload - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_ND_OFFLOAD.
+ */
+enum qca_wlan_vendor_attr_nd_offload {
+ QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_INVALID = 0,
+ /* Flag to set Neighbour Discovery offload */
+ QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_FLAG,
+ /* Keep last */
+ QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_MAX =
+ QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_AFTER_LAST - 1,
+};
+
+/**
+ * enum packet_filter_sub_cmd - Packet filter sub commands
+ */
+enum packet_filter_sub_cmd {
+ /**
+ * Write packet filter program and/or data. The driver/firmware should
+ * disable APF before writing into local buffer and re-enable APF after
+ * writing is done.
+ */
+ QCA_WLAN_SET_PACKET_FILTER = 1,
+ /* Get packet filter feature capabilities from driver */
+ QCA_WLAN_GET_PACKET_FILTER = 2,
+ /**
+ * Write packet filter program and/or data. User space will send the
+ * %QCA_WLAN_DISABLE_PACKET_FILTER command before issuing this command
+ * and will send the %QCA_WLAN_ENABLE_PACKET_FILTER afterwards. The key
+ * difference from that %QCA_WLAN_SET_PACKET_FILTER is the control over
+ * enable/disable is given to user space with this command. Also,
+ * user space sends the length of program portion in the buffer within
+ * %QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROG_LENGTH.
+ */
+ QCA_WLAN_WRITE_PACKET_FILTER = 3,
+ /* Read packet filter program and/or data */
+ QCA_WLAN_READ_PACKET_FILTER = 4,
+ /* Enable APF feature */
+ QCA_WLAN_ENABLE_PACKET_FILTER = 5,
+ /* Disable APF feature */
+ QCA_WLAN_DISABLE_PACKET_FILTER = 6,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_packet_filter - BPF control commands used by
+ * vendor QCA_NL80211_VENDOR_SUBCMD_PACKET_FILTER.
+ */
+enum qca_wlan_vendor_attr_packet_filter {
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_INVALID = 0,
+ /* Unsigned 32-bit enum passed using packet_filter_sub_cmd */
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SUB_CMD,
+ /* Unsigned 32-bit value indicating the packet filter version */
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_VERSION,
+ /* Unsigned 32-bit value indicating the packet filter id */
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_ID,
+ /**
+ * Unsigned 32-bit value indicating the packet filter size including
+ * program + data.
+ */
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SIZE,
+ /* Unsigned 32-bit value indicating the packet filter current offset */
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_CURRENT_OFFSET,
+ /* Program and/or data in bytes */
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROGRAM,
+ /* Unsigned 32-bit value of the length of the program section in packet
+ * filter buffer.
+ */
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROG_LENGTH = 7,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_MAX =
+ QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_drv_info - WLAN driver info used by vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_GET_BUS_SIZE.
+ */
+enum qca_wlan_vendor_drv_info {
+ QCA_WLAN_VENDOR_ATTR_DRV_INFO_INVALID = 0,
+ /* Maximum Message size info between firmware & HOST
+ * Unsigned 32-bit value
+ */
+ QCA_WLAN_VENDOR_ATTR_DRV_INFO_BUS_SIZE,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_DRV_INFO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_DRV_INFO_MAX =
+ QCA_WLAN_VENDOR_ATTR_DRV_INFO_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_wake_stats - Wake lock stats used by vendor
+ * command QCA_NL80211_VENDOR_SUBCMD_GET_WAKE_REASON_STATS.
+ */
+enum qca_wlan_vendor_attr_wake_stats {
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_INVALID = 0,
+ /* Unsigned 32-bit value indicating the total count of wake event */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_TOTAL_CMD_EVENT_WAKE,
+ /* Array of individual wake count, each index representing wake reason
+ */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_CMD_EVENT_WAKE_CNT_PTR,
+ /* Unsigned 32-bit value representing wake count array */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_CMD_EVENT_WAKE_CNT_SZ,
+ /* Unsigned 32-bit total wake count value of driver/fw */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_TOTAL_DRIVER_FW_LOCAL_WAKE,
+ /* Array of wake stats of driver/fw */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_DRIVER_FW_LOCAL_WAKE_CNT_PTR,
+ /* Unsigned 32-bit total wake count value of driver/fw */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_DRIVER_FW_LOCAL_WAKE_CNT_SZ,
+ /* Unsigned 32-bit total wake count value of packets received */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_TOTAL_RX_DATA_WAKE,
+ /* Unsigned 32-bit wake count value unicast packets received */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RX_UNICAST_CNT,
+ /* Unsigned 32-bit wake count value multicast packets received */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RX_MULTICAST_CNT,
+ /* Unsigned 32-bit wake count value broadcast packets received */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RX_BROADCAST_CNT,
+ /* Unsigned 32-bit wake count value of ICMP packets */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP_PKT,
+ /* Unsigned 32-bit wake count value of ICMP6 packets */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_PKT,
+ /* Unsigned 32-bit value ICMP6 router advertisement */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_RA,
+ /* Unsigned 32-bit value ICMP6 neighbor advertisement */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_NA,
+ /* Unsigned 32-bit value ICMP6 neighbor solicitation */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_NS,
+ /* Unsigned 32-bit wake count value of receive side ICMP4 multicast */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP4_RX_MULTICAST_CNT,
+ /* Unsigned 32-bit wake count value of receive side ICMP6 multicast */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_RX_MULTICAST_CNT,
+ /* Unsigned 32-bit wake count value of receive side multicast */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_OTHER_RX_MULTICAST_CNT,
+ /* Unsigned 32-bit wake count value of a given RSSI breach */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RSSI_BREACH_CNT,
+ /* Unsigned 32-bit wake count value of low RSSI */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_LOW_RSSI_CNT,
+ /* Unsigned 32-bit value GSCAN count */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_GSCAN_CNT,
+ /* Unsigned 32-bit value PNO complete count */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_PNO_COMPLETE_CNT,
+ /* Unsigned 32-bit value PNO match count */
+ QCA_WLAN_VENDOR_ATTR_WAKE_STATS_PNO_MATCH_CNT,
+ /* keep last */
+ QCA_WLAN_VENDOR_GET_WAKE_STATS_AFTER_LAST,
+ QCA_WLAN_VENDOR_GET_WAKE_STATS_MAX =
+ QCA_WLAN_VENDOR_GET_WAKE_STATS_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_thermal_cmd - Vendor subcmd attributes to set
+ * cmd value. Used for NL attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD sub command.
+ */
+enum qca_wlan_vendor_attr_thermal_cmd {
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_INVALID = 0,
+ /* The value of command, driver will implement different operations
+ * according to this value. It uses values defined in
+ * enum qca_wlan_vendor_attr_thermal_cmd_type.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE = 1,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_MAX =
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_AFTER_LAST - 1
+};
+
+/**
+ * qca_wlan_vendor_attr_thermal_cmd_type: Attribute values for
+ * QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE to the vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD. This represents the
+ * thermal command types sent to driver.
+ * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_PARAMS: Request to
+ * get thermal shutdown configuration parameters for display. Parameters
+ * responded from driver are defined in
+ * enum qca_wlan_vendor_attr_get_thermal_params_rsp.
+ * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_TEMPERATURE: Request to
+ * get temperature. Host should respond with a temperature data. It is defined
+ * in enum qca_wlan_vendor_attr_thermal_get_temperature.
+ * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SUSPEND: Request to execute thermal
+ * suspend action.
+ * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_RESUME: Request to execute thermal
+ * resume action.
+ */
+enum qca_wlan_vendor_attr_thermal_cmd_type {
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_PARAMS,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_TEMPERATURE,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SUSPEND,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_RESUME,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_thermal_get_temperature - vendor subcmd attributes
+ * to get chip temperature by user.
+ * enum values are used for NL attributes for data used by
+ * QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_TEMPERATURE command for data used
+ * by QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD sub command.
+ */
+enum qca_wlan_vendor_attr_thermal_get_temperature {
+ QCA_WLAN_VENDOR_ATTR_THERMAL_GET_TEMPERATURE_INVALID = 0,
+ /* Temperature value (degree Celsius) from driver.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_GET_TEMPERATURE_DATA,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_GET_TEMPERATURE_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_GET_TEMPERATURE_MAX =
+ QCA_WLAN_VENDOR_ATTR_THERMAL_GET_TEMPERATURE_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_get_thermal_params_rsp - vendor subcmd attributes
+ * to get configuration parameters of thermal shutdown feature. Enum values are
+ * used by QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_PARAMS command for data
+ * used by QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD sub command.
+ */
+enum qca_wlan_vendor_attr_get_thermal_params_rsp {
+ QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_INVALID = 0,
+ /* Indicate if the thermal shutdown feature is enabled.
+ * NLA_FLAG attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_SHUTDOWN_EN,
+ /* Indicate if the auto mode is enabled.
+ * Enable: Driver triggers the suspend/resume action.
+ * Disable: User space triggers the suspend/resume action.
+ * NLA_FLAG attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_SHUTDOWN_AUTO_EN,
+ /* Thermal resume threshold (degree Celsius). Issue the resume command
+ * if the temperature value is lower than this threshold.
+ * u16 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_RESUME_THRESH,
+ /* Thermal warning threshold (degree Celsius). FW reports temperature
+ * to driver if it's higher than this threshold.
+ * u16 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_WARNING_THRESH,
+ /* Thermal suspend threshold (degree Celsius). Issue the suspend command
+ * if the temperature value is higher than this threshold.
+ * u16 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_SUSPEND_THRESH,
+ /* FW reports temperature data periodically at this interval (ms).
+ * u16 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_SAMPLE_RATE,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_MAX =
+ QCA_WLAN_VENDOR_ATTR_GET_THERMAL_PARAMS_RSP_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_thermal_event - vendor subcmd attributes to
+ * report thermal events from driver to user space.
+ * enum values are used for NL attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_THERMAL_EVENT sub command.
+ */
+enum qca_wlan_vendor_attr_thermal_event {
+ QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_INVALID = 0,
+ /* Temperature value (degree Celsius) from driver.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_TEMPERATURE,
+ /* Indication of resume completion from power save mode.
+ * NLA_FLAG attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_RESUME_COMPLETE,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_MAX =
+ QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_AFTER_LAST - 1,
+};
+
+/**
+ * enum he_fragmentation_val - HE fragmentation support values
+ * Indicates level of dynamic fragmentation that is supported by
+ * a STA as a recipient.
+ * HE fragmentation values are defined in IEEE P802.11ax/D2.0, 9.4.2.237.2
+ * (HE MAC Capabilities Information field) and are used in HE Capabilities
+ * element to advertise the support. These values are validated in the driver
+ * to check the device capability and advertised in the HE Capabilities
+ * element. These values are used to configure testbed device to allow the
+ * advertised hardware capabilities to be downgraded for testing purposes.
+ *
+ * @HE_FRAG_DISABLE: no support for dynamic fragmentation
+ * @HE_FRAG_LEVEL1: support for dynamic fragments that are
+ * contained within an MPDU or S-MPDU, no support for dynamic fragments
+ * within an A-MPDU that is not an S-MPDU.
+ * @HE_FRAG_LEVEL2: support for dynamic fragments that are
+ * contained within an MPDU or S-MPDU and support for up to one dynamic
+ * fragment for each MSDU, each A-MSDU if supported by the recipient, and
+ * each MMPDU within an A-MPDU or multi-TID A-MPDU that is not an
+ * MPDU or S-MPDU.
+ * @HE_FRAG_LEVEL3: support for dynamic fragments that are
+ * contained within an MPDU or S-MPDU and support for multiple dynamic
+ * fragments for each MSDU and for each A-MSDU if supported by the
+ * recipient within an A-MPDU or multi-TID AMPDU and up to one dynamic
+ * fragment for each MMPDU in a multi-TID A-MPDU that is not an S-MPDU.
+ */
+enum he_fragmentation_val {
+ HE_FRAG_DISABLE,
+ HE_FRAG_LEVEL1,
+ HE_FRAG_LEVEL2,
+ HE_FRAG_LEVEL3,
+};
+
+/**
+ * enum he_mcs_config - HE MCS support configuration
+ *
+ * Configures the HE Tx/Rx MCS map in HE capability IE for given bandwidth.
+ * These values are used in driver to configure the HE MCS map to advertise
+ * Tx/Rx MCS map in HE capability and these values are applied for all the
+ * streams supported by the device. To configure MCS for different bandwidths,
+ * vendor command needs to be sent using this attribute with appropriate value.
+ * For example, to configure HE_80_MCS_0_7, send vendor command using HE MCS
+ * attribute with HE_80_MCS0_7. And to configure HE MCS for HE_160_MCS0_11
+ * send this command using HE MCS config attribute with value HE_160_MCS0_11.
+ * These values are used to configure testbed device to allow the advertised
+ * hardware capabilities to be downgraded for testing purposes. The enum values
+ * are defined such that BIT[1:0] indicates the MCS map value. Values 3,7 and
+ * 11 are not used as BIT[1:0] value is 3 which is used to disable MCS map.
+ * These values are validated in the driver before setting the MCS map and
+ * driver returns error if the input is other than these enum values.
+ *
+ * @HE_80_MCS0_7: support for HE 80/40/20 MHz MCS 0 to 7
+ * @HE_80_MCS0_9: support for HE 80/40/20 MHz MCS 0 to 9
+ * @HE_80_MCS0_11: support for HE 80/40/20 MHz MCS 0 to 11
+ * @HE_160_MCS0_7: support for HE 160 MHz MCS 0 to 7
+ * @HE_160_MCS0_9: support for HE 160 MHz MCS 0 to 9
+ * @HE_160_MCS0_11: support for HE 160 MHz MCS 0 to 11
+ * @HE_80P80_MCS0_7: support for HE 80p80 MHz MCS 0 to 7
+ * @HE_80P80_MCS0_9: support for HE 80p80 MHz MCS 0 to 9
+ * @HE_80P80_MCS0_11: support for HE 80p80 MHz MCS 0 to 11
+ */
+enum he_mcs_config {
+ HE_80_MCS0_7 = 0,
+ HE_80_MCS0_9 = 1,
+ HE_80_MCS0_11 = 2,
+ HE_160_MCS0_7 = 4,
+ HE_160_MCS0_9 = 5,
+ HE_160_MCS0_11 = 6,
+ HE_80P80_MCS0_7 = 8,
+ HE_80P80_MCS0_9 = 9,
+ HE_80P80_MCS0_11 = 10,
+};
+
+/**
+ * enum qca_wlan_ba_session_config - BA session configuration
+ *
+ * Indicates the configuration values for BA session configuration attribute.
+ *
+ * @QCA_WLAN_ADD_BA: Establish a new BA session with given configuration.
+ * @QCA_WLAN_DELETE_BA: Delete the existing BA session for given TID.
+ */
+enum qca_wlan_ba_session_config {
+ QCA_WLAN_ADD_BA = 1,
+ QCA_WLAN_DELETE_BA = 2,
+};
+
+/**
+ * enum qca_wlan_ac_type - Access category type
+ *
+ * Indicates the access category type value.
+ *
+ * @QCA_WLAN_AC_BE: BE access category
+ * @QCA_WLAN_AC_BK: BK access category
+ * @QCA_WLAN_AC_VI: VI access category
+ * @QCA_WLAN_AC_VO: VO access category
+ * @QCA_WLAN_AC_ALL: All ACs
+ */
+enum qca_wlan_ac_type {
+ QCA_WLAN_AC_BE = 0,
+ QCA_WLAN_AC_BK = 1,
+ QCA_WLAN_AC_VI = 2,
+ QCA_WLAN_AC_VO = 3,
+ QCA_WLAN_AC_ALL = 4,
+};
+
+/**
+ * enum qca_wlan_he_ltf_cfg - HE LTF configuration
+ *
+ * Indicates the HE LTF configuration value.
+ *
+ * @QCA_WLAN_HE_LTF_AUTO: HE-LTF is automatically set to the mandatory HE-LTF,
+ * based on the GI setting
+ * @QCA_WLAN_HE_LTF_1X: 1X HE LTF is 3.2us LTF
+ * @QCA_WLAN_HE_LTF_2X: 2X HE LTF is 6.4us LTF
+ * @QCA_WLAN_HE_LTF_4X: 4X HE LTF is 12.8us LTF
+ */
+enum qca_wlan_he_ltf_cfg {
+ QCA_WLAN_HE_LTF_AUTO = 0,
+ QCA_WLAN_HE_LTF_1X = 1,
+ QCA_WLAN_HE_LTF_2X = 2,
+ QCA_WLAN_HE_LTF_4X = 3,
+};
+
+/**
+ * enum qca_wlan_he_mac_padding_dur - HE trigger frame MAC padding duration
+ *
+ * Indicates the HE trigger frame MAC padding duration value.
+ *
+ * @QCA_WLAN_HE_NO_ADDITIONAL_PROCESS_TIME: no additional time required to
+ * process the trigger frame.
+ * @QCA_WLAN_HE_8US_OF_PROCESS_TIME: indicates the 8us of processing time for
+ * trigger frame.
+ * @QCA_WLAN_HE_16US_OF_PROCESS_TIME: indicates the 16us of processing time for
+ * trigger frame.
+ */
+enum qca_wlan_he_mac_padding_dur {
+ QCA_WLAN_HE_NO_ADDITIONAL_PROCESS_TIME = 0,
+ QCA_WLAN_HE_8US_OF_PROCESS_TIME = 1,
+ QCA_WLAN_HE_16US_OF_PROCESS_TIME = 2,
+};
+
+/**
+ * enum qca_wlan_he_om_ctrl_ch_bw - HE OM control field BW configuration
+ *
+ * Indicates the HE Operating mode control channel width setting value.
+ *
+ * @QCA_WLAN_HE_OM_CTRL_BW_20M: Primary 20 MHz
+ * @QCA_WLAN_HE_OM_CTRL_BW_40M: Primary 40 MHz
+ * @QCA_WLAN_HE_OM_CTRL_BW_80M: Primary 80 MHz
+ * @QCA_WLAN_HE_OM_CTRL_BW_160M: 160 MHz and 80+80 MHz
+ */
+enum qca_wlan_he_om_ctrl_ch_bw {
+ QCA_WLAN_HE_OM_CTRL_BW_20M = 0,
+ QCA_WLAN_HE_OM_CTRL_BW_40M = 1,
+ QCA_WLAN_HE_OM_CTRL_BW_80M = 2,
+ QCA_WLAN_HE_OM_CTRL_BW_160M = 3,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_he_omi_tx: Represents attributes for
+ * HE operating mode control transmit request. These attributes are
+ * sent as part of QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OMI_TX and
+ * QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_HE_OMI_RX_NSS: Mandatory 8-bit unsigned value
+ * indicates the maximum number of spatial streams, NSS, that the STA
+ * supports in reception for PPDU bandwidths less than or equal to 80 MHz
+ * and is set to NSS - 1.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_HE_OMI_CH_BW: Mandatory 8-bit unsigned value
+ * indicates the operating channel width supported by the STA for both
+ * reception and transmission. Uses enum qca_wlan_he_om_ctrl_ch_bw values.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DISABLE: Mandatory 8-bit unsigned value
+ * indicates the all trigger based UL MU operations by the STA.
+ * 0 - UL MU operations are enabled by the STA.
+ * 1 - All triggered UL MU transmissions are suspended by the STA.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_HE_OMI_TX_NSTS: Mandatory 8-bit unsigned value
+ * indicates the maximum number of space-time streams, NSTS, that
+ * the STA supports in transmission and is set to NSTS - 1.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DATA_DISABLE: 8-bit unsigned value
+ * combined with the UL MU Disable subfield and the recipient's setting
+ * of the OM Control UL MU Data Disable RX Support subfield in the HE MAC
+ * capabilities to determine which HE TB PPDUs are possible by the
+ * STA to transmit.
+ * 0 - UL MU data operations are enabled by the STA.
+ * 1 - Determine which HE TB PPDU types are allowed by the STA if UL MU disable
+ * bit is not set, else UL MU Tx is suspended.
+ *
+ */
+enum qca_wlan_vendor_attr_he_omi_tx {
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_RX_NSS = 1,
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_CH_BW = 2,
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DISABLE = 3,
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_TX_NSTS = 4,
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DATA_DISABLE = 5,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_MAX =
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_AFTER_LAST - 1,
+};
+
+/* Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION
+ */
+enum qca_wlan_vendor_attr_wifi_test_config {
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_INVALID = 0,
+ /* 8-bit unsigned value to configure the driver to enable/disable
+ * WMM feature. This attribute is used to configure testbed device.
+ * 1-enable, 0-disable
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_WMM_ENABLE = 1,
+
+ /* 8-bit unsigned value to configure the driver to accept/reject
+ * the addba request from peer. This attribute is used to configure
+ * the testbed device.
+ * 1-accept addba, 0-reject addba
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ACCEPT_ADDBA_REQ = 2,
+
+ /* 8-bit unsigned value to configure the driver to send or not to
+ * send the addba request to peer.
+ * This attribute is used to configure the testbed device.
+ * 1-send addba, 0-do not send addba
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_SEND_ADDBA_REQ = 3,
+
+ /* 8-bit unsigned value to indicate the HE fragmentation support.
+ * Uses enum he_fragmentation_val values.
+ * This attribute is used to configure the testbed device to
+ * allow the advertised hardware capabilities to be downgraded
+ * for testing purposes.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_FRAGMENTATION = 4,
+
+ /* 8-bit unsigned value to indicate the HE MCS support.
+ * Uses enum he_mcs_config values.
+ * This attribute is used to configure the testbed device to
+ * allow the advertised hardware capabilities to be downgraded
+ * for testing purposes.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MCS = 5,
+
+ /* 8-bit unsigned value to configure the driver to allow or not to
+ * allow the connection with WEP/TKIP in HT/VHT/HE modes.
+ * This attribute is used to configure the testbed device.
+ * 1-allow WEP/TKIP in HT/VHT/HE, 0-do not allow WEP/TKIP.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_WEP_TKIP_IN_HE = 6,
+
+ /* 8-bit unsigned value to configure the driver to add a
+ * new BA session or delete the existing BA session for
+ * given TID. ADDBA command uses the buffer size and TID
+ * configuration if user specifies the values else default
+ * value for buffer size is used for all TIDs if the TID
+ * also not specified. For DEL_BA command TID value is
+ * required to process the command.
+ * Uses enum qca_wlan_ba_session_config values.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ADD_DEL_BA_SESSION = 7,
+
+ /* 16-bit unsigned value to configure the buffer size in addba
+ * request and response frames.
+ * This attribute is used to configure the testbed device.
+ * The range of the value is 0 to 256.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ADDBA_BUFF_SIZE = 8,
+
+ /* 8-bit unsigned value to configure the buffer size in addba
+ * request and response frames.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BA_TID = 9,
+
+ /* 8-bit unsigned value to configure the no ack policy.
+ * To configure no ack policy, access category value is
+ * required to process the command.
+ * This attribute is used to configure the testbed device.
+ * 1 - enable no ack, 0 - disable no ack.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ENABLE_NO_ACK = 10,
+
+ /* 8-bit unsigned value to configure the AC for no ack policy
+ * This attribute is used to configure the testbed device.
+ * Uses the enum qca_wlan_ac_type values.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_NO_ACK_AC = 11,
+
+ /* 8-bit unsigned value to configure the HE LTF
+ * This attribute is used to configure the testbed device.
+ * Uses the enum qca_wlan_he_ltf_cfg values.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_LTF = 12,
+
+ /* 8-bit unsigned value to configure the tx beamformee.
+ * This attribute is used to configure the testbed device.
+ * 1-enable, 0-disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ENABLE_TX_BEAMFORMEE = 13,
+
+ /* 8-bit unsigned value to configure the tx beamformee number
+ * of space-time streams.
+ * This attribute is used to configure the testbed device.
+ * The range of the value is 0 to 8.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_TX_BEAMFORMEE_NSTS = 14,
+
+ /* 8-bit unsigned value to configure the MU EDCA params for given AC
+ * This attribute is used to configure the testbed device.
+ * Uses the enum qca_wlan_ac_type values.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MU_EDCA_AC = 15,
+
+ /* 8-bit unsigned value to configure the MU EDCA AIFSN for given AC
+ * To configure MU EDCA AIFSN value, MU EDCA access category value
+ * is required to process the command.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MU_EDCA_AIFSN = 16,
+
+ /* 8-bit unsigned value to configure the MU EDCA ECW min value for
+ * given AC.
+ * To configure MU EDCA ECW min value, MU EDCA access category value
+ * is required to process the command.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MU_EDCA_ECWMIN = 17,
+
+ /* 8-bit unsigned value to configure the MU EDCA ECW max value for
+ * given AC.
+ * To configure MU EDCA ECW max value, MU EDCA access category value
+ * is required to process the command.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MU_EDCA_ECWMAX = 18,
+
+ /* 8-bit unsigned value to configure the MU EDCA timer for given AC
+ * To configure MU EDCA timer value, MU EDCA access category value
+ * is required to process the command.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MU_EDCA_TIMER = 19,
+
+ /* 8-bit unsigned value to configure the HE trigger frame MAC padding
+ * duration.
+ * This attribute is used to configure the testbed device.
+ * Uses the enum qca_wlan_he_mac_padding_dur values.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MAC_PADDING_DUR = 20,
+
+ /* 8-bit unsigned value to override the MU EDCA params to defaults
+ * regardless of the AP beacon MU EDCA params. If it is enabled use
+ * the default values else use the MU EDCA params from AP beacon.
+ * This attribute is used to configure the testbed device.
+ * 1-enable, 0-disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OVERRIDE_MU_EDCA = 21,
+
+ /* 8-bit unsigned value to configure the support for receiving
+ * an MPDU that contains an operating mode control subfield.
+ * This attribute is used to configure the testbed device.
+ * 1-enable, 0-disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OM_CTRL_SUPP = 22,
+
+ /* Nested attribute values required to setup the TWT session.
+ * enum qca_wlan_vendor_attr_twt_setup provides the necessary
+ * information to set up the session. It contains broadcast flags,
+ * set_up flags, trigger value, flow type, flow ID, wake interval
+ * exponent, protection, target wake time, wake duration, wake interval
+ * mantissa. These nested attributes are used to setup a host triggered
+ * TWT session.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_SETUP = 23,
+
+ /* This nested attribute is used to terminate the current TWT session.
+ * It does not currently carry any attributes.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_TERMINATE = 24,
+
+ /* This nested attribute is used to suspend the current TWT session.
+ * It does not currently carry any attributes.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_SUSPEND = 25,
+
+ /* Nested attribute values to indicate the request for resume.
+ * This attribute is used to resume the TWT session.
+ * enum qca_wlan_vendor_attr_twt_resume provides the necessary
+ * parameters required to resume the TWT session.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_RESUME = 26,
+
+ /* 8-bit unsigned value to set the HE operating mode control
+ * (OM CTRL) Channel Width subfield.
+ * The Channel Width subfield indicates the operating channel width
+ * supported by the STA for both reception and transmission.
+ * Uses the enum qca_wlan_he_om_ctrl_ch_bw values.
+ * This setting is cleared with the
+ * QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_CLEAR_HE_OM_CTRL_CONFIG
+ * flag attribute to reset defaults.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OM_CTRL_BW = 27,
+
+ /* 8-bit unsigned value to configure the number of spatial
+ * streams in HE operating mode control field.
+ * This setting is cleared with the
+ * QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_CLEAR_HE_OM_CTRL_CONFIG
+ * flag attribute to reset defaults.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OM_CTRL_NSS = 28,
+
+ /* Flag attribute to configure the UL MU disable bit in
+ * HE operating mode control field.
+ * This setting is cleared with the
+ * QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_CLEAR_HE_OM_CTRL_CONFIG
+ * flag attribute to reset defaults.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OM_CTRL_UL_MU_DISABLE = 29,
+
+ /* Flag attribute to clear the previously set HE operating mode
+ * control field configuration.
+ * This attribute is used to configure the testbed device to reset
+ * defaults to clear any previously set HE operating mode control
+ * field configuration.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_CLEAR_HE_OM_CTRL_CONFIG = 30,
+
+ /* 8-bit unsigned value to configure HE single user PPDU
+ * transmission. By default this setting is disabled and it
+ * is disabled in the reset defaults of the device configuration.
+ * This attribute is used to configure the testbed device.
+ * 1-enable, 0-disable
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_TX_SUPPDU = 31,
+
+ /* 8-bit unsigned value to configure action frame transmission
+ * in HE trigger based PPDU transmission.
+ * By default this setting is disabled and it is disabled in
+ * the reset defaults of the device configuration.
+ * This attribute is used to configure the testbed device.
+ * 1-enable, 0-disable
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_ACTION_TX_TB_PPDU = 32,
+
+ /* Nested attribute to indicate HE operating mode control field
+ * transmission. It contains operating mode control field Nss,
+ * channel bandwidth, Tx Nsts and UL MU disable attributes.
+ * These nested attributes are used to send HE operating mode control
+ * with configured values.
+ * Uses the enum qca_wlan_vendor_attr_he_omi_tx attributes.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OMI_TX = 33,
+
+ /* 8-bit unsigned value to configure +HTC_HE support to indicate the
+ * support for the reception of a frame that carries an HE variant
+ * HT Control field.
+ * This attribute is used to configure the testbed device.
+ * 1-enable, 0-disable
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_HTC_HE_SUPP = 34,
+
+ /* 8-bit unsigned value to configure VHT support in 2.4G band.
+ * This attribute is used to configure the testbed device.
+ * 1-enable, 0-disable
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ENABLE_2G_VHT = 35,
+
+ /* 8-bit unsigned value to configure HE testbed defaults.
+ * This attribute is used to configure the testbed device.
+ * 1-set the device HE capabilities to testbed defaults.
+ * 0-reset the device HE capabilities to supported config.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_SET_HE_TESTBED_DEFAULTS = 36,
+
+ /* 8-bit unsigned value to configure TWT request support.
+ * This attribute is used to configure the testbed device.
+ * 1-enable, 0-disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_TWT_REQ_SUPPORT = 37,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX =
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_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
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR, filter type in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE, add/delete action in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION in the request. The user can get the
+ * statistics of an unassociated station by specifying the MAC address in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR, station type in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE, GET action in
+ * QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION in the request. The user also can get
+ * the statistics of all unassociated stations by specifying the Broadcast MAC
+ * address (ff:ff:ff:ff:ff:ff) in QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR with
+ * above procedure. In the response, driver shall specify statistics
+ * information nested in QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS.
+ */
+enum qca_wlan_vendor_attr_bss_filter {
+ QCA_WLAN_VENDOR_ATTR_BSS_FILTER_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAC_ADDR = 1,
+ /* Other BSS filter type, unsigned 8 bit value. One of the values
+ * in enum qca_wlan_vendor_bss_filter_type.
+ */
+ QCA_WLAN_VENDOR_ATTR_BSS_FILTER_TYPE = 2,
+ /* Other BSS filter action, unsigned 8 bit value. One of the values
+ * in enum qca_wlan_vendor_bss_filter_action.
+ */
+ QCA_WLAN_VENDOR_ATTR_BSS_FILTER_ACTION = 3,
+ /* Array of nested attributes where each entry is the statistics
+ * information of the specified station that belong to another BSS.
+ * Attributes for each entry are taken from enum
+ * qca_wlan_vendor_bss_filter_sta_stats.
+ * Other BSS station configured in
+ * QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER with filter type
+ * QCA_WLAN_VENDOR_BSS_FILTER_TYPE_STA.
+ * Statistics returned by QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER
+ * with filter action QCA_WLAN_VENDOR_BSS_FILTER_ACTION_GET.
+ */
+ QCA_WLAN_VENDOR_ATTR_BSS_FILTER_STA_STATS = 4,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_BSS_FILTER_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_BSS_FILTER_MAX =
+ QCA_WLAN_VENDOR_ATTR_BSS_FILTER_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_bss_filter_type - Type of
+ * filter used in other BSS filter operations. Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
+ *
+ * @QCA_WLAN_VENDOR_BSS_FILTER_TYPE_BSSID: BSSID filter
+ * @QCA_WLAN_VENDOR_BSS_FILTER_TYPE_STA: Station MAC address filter
+ */
+enum qca_wlan_vendor_bss_filter_type {
+ QCA_WLAN_VENDOR_BSS_FILTER_TYPE_BSSID,
+ QCA_WLAN_VENDOR_BSS_FILTER_TYPE_STA,
+};
+
+/**
+ * enum qca_wlan_vendor_bss_filter_action - Type of
+ * action in other BSS filter operations. Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
+ *
+ * @QCA_WLAN_VENDOR_BSS_FILTER_ACTION_ADD: Add filter
+ * @QCA_WLAN_VENDOR_BSS_FILTER_ACTION_DEL: Delete filter
+ * @QCA_WLAN_VENDOR_BSS_FILTER_ACTION_GET: Get the statistics
+ */
+enum qca_wlan_vendor_bss_filter_action {
+ QCA_WLAN_VENDOR_BSS_FILTER_ACTION_ADD,
+ QCA_WLAN_VENDOR_BSS_FILTER_ACTION_DEL,
+ QCA_WLAN_VENDOR_BSS_FILTER_ACTION_GET,
+};
+
+/**
+ * enum qca_wlan_vendor_bss_filter_sta_stats - Attributes for
+ * the statistics of a specific unassociated station belonging to another BSS.
+ * The statistics provides information of the unassociated station
+ * filtered by other BSS operation - such as MAC, signal value.
+ * Used by the vendor command QCA_NL80211_VENDOR_SUBCMD_BSS_FILTER.
+ *
+ * @QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_MAC: MAC address of the station.
+ * @QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_RSSI: Last received signal strength
+ * of the station. Unsigned 8 bit number containing RSSI.
+ * @QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_RSSI_TS: Time stamp of the host
+ * driver for the last received RSSI. Unsigned 64 bit number containing
+ * nanoseconds from the boottime.
+ */
+enum qca_wlan_vendor_bss_filter_sta_stats {
+ QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_INVALID = 0,
+ QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_MAC = 1,
+ QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_RSSI = 2,
+ QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_RSSI_TS = 3,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_AFTER_LAST,
+ QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_MAX =
+ QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_AFTER_LAST - 1
+};
+
+/* enum qca_wlan_nan_subcmd_type - Type of NAN command used by attribute
+ * QCA_WLAN_VENDOR_ATTR_NAN_SUBCMD_TYPE as a part of vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_NAN_EXT.
+ */
+enum qca_wlan_nan_ext_subcmd_type {
+ /* Subcmd of type NAN Enable Request */
+ QCA_WLAN_NAN_EXT_SUBCMD_TYPE_ENABLE_REQ = 1,
+ /* Subcmd of type NAN Disable Request */
+ QCA_WLAN_NAN_EXT_SUBCMD_TYPE_DISABLE_REQ = 2,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_nan_params - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_NAN_EXT.
+ */
+enum qca_wlan_vendor_attr_nan_params {
+ QCA_WLAN_VENDOR_ATTR_NAN_INVALID = 0,
+ /* Carries NAN command for firmware component. Every vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_NAN_EXT must contain this attribute with a
+ * payload containing the NAN command. NLA_BINARY attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA = 1,
+ /* Indicates the type of NAN command sent with
+ * QCA_NL80211_VENDOR_SUBCMD_NAN_EXT. enum qca_wlan_nan_ext_subcmd_type
+ * describes the possible range of values. This attribute is mandatory
+ * if the command being issued is either
+ * QCA_WLAN_NAN_EXT_SUBCMD_TYPE_ENABLE_REQ or
+ * QCA_WLAN_NAN_EXT_SUBCMD_TYPE_DISABLE_REQ. NLA_U32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_NAN_SUBCMD_TYPE = 2,
+ /* Frequency (in MHz) of primary NAN discovery social channel in 2.4 GHz
+ * band. This attribute is mandatory when command type is
+ * QCA_WLAN_NAN_EXT_SUBCMD_TYPE_ENABLE_REQ. NLA_U32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_NAN_DISC_24GHZ_BAND_FREQ = 3,
+ /* Frequency (in MHz) of secondary NAN discovery social channel in 5 GHz
+ * band. This attribute is optional and should be included when command
+ * type is QCA_WLAN_NAN_EXT_SUBCMD_TYPE_ENABLE_REQ and NAN discovery
+ * has to be started on 5GHz along with 2.4GHz. NLA_U32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_NAN_DISC_5GHZ_BAND_FREQ = 4,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_NAN_PARAMS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_NAN_PARAMS_MAX =
+ QCA_WLAN_VENDOR_ATTR_NAN_PARAMS_AFTER_LAST - 1
+};
+
+/**
+ * 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_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST: Flag attribute.
+ * Disable (flag attribute not present) - Individual TWT
+ * Enable (flag attribute present) - Broadcast TWT.
+ * Individual means the session is between the STA and the AP.
+ * This session is established using a separate negotiation between
+ * 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.
+ *
+ * @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
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER: Flag attribute
+ * Enable (flag attribute present) - TWT with trigger support.
+ * Disable (flag attribute not present) - TWT without trigger support.
+ * 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.
+ *
+ * @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.
+ *
+ * @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.
+ *
+ * @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.
+ *
+ * @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.
+ *
+ * @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.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION: Required (u32)
+ * This is the duration of the service period. The units are in TU.
+ *
+ * @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.
+ */
+enum qca_wlan_vendor_attr_twt_setup {
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST = 1,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE = 2,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER = 3,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE = 4,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID = 5,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP = 6,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION = 7,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME = 8,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION = 9,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA = 10,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX =
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_AFTER_LAST - 1,
+};
+
+/**
+ * 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_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_NEXT_TWT_SIZE: Required (u32)
+ * This attribute represents the next TWT subfield size.
+ */
+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,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_TWT_RESUME_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAX =
+ QCA_WLAN_VENDOR_ATTR_TWT_RESUME_AFTER_LAST - 1,
+};
+
+/**
+ * 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
+ * parameters but relying on AP to fill the parameters during the negotiation.
+ * @QCA_WLAN_VENDOR_TWT_SETUP_SUGGEST: STA will provide all the suggested
+ * values which the AP may accept or AP may provide alternative parameters
+ * which the STA may accept.
+ * @QCA_WLAN_VENDOR_TWT_SETUP_DEMAND: STA is not willing to accept any
+ * alternate parameters than the requested ones.
+ */
+enum qca_wlan_vendor_twt_setup_req_type {
+ QCA_WLAN_VENDOR_TWT_SETUP_REQUEST = 1,
+ QCA_WLAN_VENDOR_TWT_SETUP_SUGGEST = 2,
+ QCA_WLAN_VENDOR_TWT_SETUP_DEMAND = 3,
+};
+
+/**
+ * enum qca_wlan_roam_scan_event_type - Type of roam scan event
+ *
+ * Indicates the type of roam scan event sent by firmware/driver.
+ *
+ * @QCA_WLAN_ROAM_SCAN_TRIGGER_EVENT: Roam scan trigger event type.
+ * @QCA_WLAN_ROAM_SCAN_STOP_EVENT: Roam scan stopped event type.
+ */
+enum qca_wlan_roam_scan_event_type {
+ QCA_WLAN_ROAM_SCAN_TRIGGER_EVENT = 0,
+ QCA_WLAN_ROAM_SCAN_STOP_EVENT = 1,
+};
+
+/**
+ * enum qca_wlan_roam_scan_trigger_reason - Roam scan trigger reason
+ *
+ * Indicates the reason for triggering roam scan by firmware/driver.
+ *
+ * @QCA_WLAN_ROAM_SCAN_TRIGGER_REASON_LOW_RSSI: Due to low RSSI of current AP.
+ * @QCA_WLAN_ROAM_SCAN_TRIGGER_REASON_HIGH_PER: Due to high packet error rate.
+ */
+enum qca_wlan_roam_scan_trigger_reason {
+ QCA_WLAN_ROAM_SCAN_TRIGGER_REASON_LOW_RSSI = 0,
+ QCA_WLAN_ROAM_SCAN_TRIGGER_REASON_HIGH_PER = 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_roam_scan - Vendor subcmd attributes to report
+ * roam scan related details from driver/firmware to user space. enum values
+ * are used for NL attributes sent with
+ * %QCA_NL80211_VENDOR_SUBCMD_ROAM_SCAN_EVENT sub command.
+ */
+enum qca_wlan_vendor_attr_roam_scan {
+ QCA_WLAN_VENDOR_ATTR_ROAM_SCAN_INVALID = 0,
+ /* Encapsulates type of roam scan event being reported. enum
+ * qca_wlan_roam_scan_event_type describes the possible range of
+ * values. u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_ROAM_SCAN_EVENT_TYPE = 1,
+ /* Encapsulates reason for triggering roam scan. enum
+ * qca_wlan_roam_scan_trigger_reason describes the possible range of
+ * values. u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_ROAM_SCAN_TRIGGER_REASON = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_ROAM_SCAN_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ROAM_SCAN_MAX =
+ QCA_WLAN_VENDOR_ATTR_ROAM_SCAN_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_cfr_method - QCA vendor CFR methods used by
+ * attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD as part of vendor
+ * command QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG.
+ */
+enum qca_wlan_vendor_cfr_method {
+ /* CFR method using QOS Null frame */
+ QCA_WLAN_VENDOR_CFR_METHOD_QOS_NULL = 0,
+};
+
+/**
+ * enum qca_wlan_vendor_peer_cfr_capture_attr - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG to configure peer
+ * Channel Frequency Response capture parameters and enable periodic CFR
+ * capture.
+ */
+enum qca_wlan_vendor_peer_cfr_capture_attr {
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_INVALID = 0,
+ /* 6-byte MAC address of the peer.
+ * This attribute is mandatory.
+ */
+ QCA_WLAN_VENDOR_ATTR_CFR_PEER_MAC_ADDR = 1,
+ /* Enable peer CFR Capture, flag attribute.
+ * This attribute is mandatory to enable peer CFR capture.
+ * If this attribute is not present, peer CFR capture is disabled.
+ */
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE = 2,
+ /* BW of measurement, attribute uses the values in enum nl80211_chan_width
+ * Supported values: 20, 40, 80, 80+80, 160.
+ * Note that all targets may not support all bandwidths.
+ * u8 attribute. This attribute is mandatory if attribute
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
+ */
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_BANDWIDTH = 3,
+ /* Periodicity of CFR measurement in msec.
+ * Periodicity should be a multiple of Base timer.
+ * Current Base timer value supported is 10 msecs (default).
+ * 0 for one shot capture. u32 attribute.
+ * This attribute is mandatory if attribute
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
+ */
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_PERIODICITY = 4,
+ /* Method used to capture Channel Frequency Response.
+ * Attribute uses the values defined in enum qca_wlan_vendor_cfr_method.
+ * u8 attribute. This attribute is mandatory if attribute
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
+ */
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD = 5,
+ /* Enable periodic CFR capture, flag attribute.
+ * This attribute is mandatory to enable Periodic CFR capture.
+ * If this attribute is not present, periodic CFR capture is disabled.
+ */
+ QCA_WLAN_VENDOR_ATTR_PERIODIC_CFR_CAPTURE_ENABLE = 6,
+
+ /* Keep last */
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX =
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_throughput_level - Current throughput level
+ *
+ * Indicates the current level of throughput calculated by the driver. The
+ * driver may choose different thresholds to decide whether the throughput level
+ * is low or medium or high based on variety of parameters like physical link
+ * capacity of the current connection, the number of packets being dispatched
+ * per second, etc. The throughput level events might not be consistent with the
+ * actual current throughput value being observed.
+ *
+ * @QCA_WLAN_THROUGHPUT_LEVEL_LOW: Low level of throughput
+ * @QCA_WLAN_THROUGHPUT_LEVEL_MEDIUM: Medium level of throughput
+ * @QCA_WLAN_THROUGHPUT_LEVEL_HIGH: High level of throughput
+ */
+enum qca_wlan_throughput_level {
+ QCA_WLAN_THROUGHPUT_LEVEL_LOW = 0,
+ QCA_WLAN_THROUGHPUT_LEVEL_MEDIUM = 1,
+ QCA_WLAN_THROUGHPUT_LEVEL_HIGH = 2,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_throughput_change - Vendor subcmd attributes to
+ * report throughput changes from the driver to user space. enum values are used
+ * for netlink attributes sent with
+ * %QCA_NL80211_VENDOR_SUBCMD_THROUGHPUT_CHANGE_EVENT sub command.
+ */
+enum qca_wlan_vendor_attr_throughput_change {
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_INVALID = 0,
+ /* Indicates the direction of throughput in which the change is being
+ * reported. u8 attribute. Value is 0 for TX and 1 for RX.
+ */
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_DIRECTION = 1,
+ /* Indicates the newly observed throughput level. enum
+ * qca_wlan_throughput_level describes the possible range of values.
+ * u8 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_THROUGHPUT_LEVEL = 2,
+ /* Indicates the driver's guidance on the new value to be set to
+ * kernel's TCP parameter tcp_limit_output_bytes. u32 attribute. The
+ * driver may optionally include this attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_TCP_LIMIT_OUTPUT_BYTES = 3,
+ /* Indicates the driver's guidance on the new value to be set to
+ * kernel's TCP parameter tcp_adv_win_scale. s8 attribute. Possible
+ * values are from -31 to 31. The driver may optionally include this
+ * attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_TCP_ADV_WIN_SCALE = 4,
+ /* Indicates the driver's guidance on the new value to be set to
+ * kernel's TCP parameter tcp_delack_seg. u32 attribute. The driver may
+ * optionally include this attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_TCP_DELACK_SEG = 5,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_MAX =
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_coex_config_profiles - This enum defines different types of
+ * traffic streams that can be prioritized one over the other during coex
+ * scenarios.
+ * The types defined in this enum are categorized in the below manner.
+ * 0 - 31 values corresponds to WLAN
+ * 32 - 63 values corresponds to BT
+ * 64 - 95 values corresponds to Zigbee
+ * @QCA_WIFI_STA_DISCOVERY: Prioritize discovery frames for WLAN STA
+ * @QCA_WIFI_STA_CONNECTION: Prioritize connection frames for WLAN STA
+ * @QCA_WIFI_STA_CLASS_3_MGMT: Prioritize class 3 mgmt frames for WLAN STA
+ * @QCA_WIFI_STA_DATA : Prioritize data frames for WLAN STA
+ * @QCA_WIFI_STA_ALL: Priritize all frames for WLAN STA
+ * @QCA_WIFI_SAP_DISCOVERY: Prioritize discovery frames for WLAN SAP
+ * @QCA_WIFI_SAP_CONNECTION: Prioritize connection frames for WLAN SAP
+ * @QCA_WIFI_SAP_CLASS_3_MGMT: Prioritize class 3 mgmt frames for WLAN SAP
+ * @QCA_WIFI_SAP_DATA: Prioritize data frames for WLAN SAP
+ * @QCA_WIFI_SAP_ALL: Prioritize all frames for WLAN SAP
+ * @QCA_BT_A2DP: Prioritize BT A2DP
+ * @QCA_BT_BLE: Prioritize BT BLE
+ * @QCA_BT_SCO: Prioritize BT SCO
+ * @QCA_ZB_LOW: Prioritize Zigbee Low
+ * @QCA_ZB_HIGH: Prioritize Zigbee High
+ */
+enum qca_coex_config_profiles {
+ /* 0 - 31 corresponds to WLAN */
+ QCA_WIFI_STA_DISCOVERY = 0,
+ QCA_WIFI_STA_CONNECTION = 1,
+ QCA_WIFI_STA_CLASS_3_MGMT = 2,
+ QCA_WIFI_STA_DATA = 3,
+ QCA_WIFI_STA_ALL = 4,
+ QCA_WIFI_SAP_DISCOVERY = 5,
+ QCA_WIFI_SAP_CONNECTION = 6,
+ QCA_WIFI_SAP_CLASS_3_MGMT = 7,
+ QCA_WIFI_SAP_DATA = 8,
+ QCA_WIFI_SAP_ALL = 9,
+ QCA_WIFI_CASE_MAX = 31,
+ /* 32 - 63 corresponds to BT */
+ QCA_BT_A2DP = 32,
+ QCA_BT_BLE = 33,
+ QCA_BT_SCO = 34,
+ QCA_BT_CASE_MAX = 63,
+ /* 64 - 95 corresponds to Zigbee */
+ QCA_ZB_LOW = 64,
+ QCA_ZB_HIGH = 65,
+ QCA_ZB_CASE_MAX = 95,
+ /* 0xff is default value if the u8 profile value is not set. */
+ QCA_COEX_CONFIG_PROFILE_DEFAULT_VALUE = 255
+};
+
+/**
+ * enum qca_vendor_attr_coex_config_types - Coex configurations types.
+ * This enum defines the valid set of values of coex configuration types. These
+ * values may used by attribute
+ * %QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_CONFIG_TYPE.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_COEX_RESET: Reset all the
+ * weights to default values.
+ * @QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_COEX_START: Start to config
+ * weights with configurability value.
+ */
+enum qca_vendor_attr_coex_config_types {
+ QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_COEX_RESET = 1,
+ QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_COEX_START = 2,
+};
+
+/**
+ * enum qca_vendor_attr_coex_config - Specifies vendor coex config attributes
+ *
+ * @QCA_VENDOR_ATTR_COEX_CONFIG_PROFILES: This attribute contains variable
+ * length array of 8-bit values from enum qca_coex_config_profiles.
+ * FW will prioritize the profiles in the order given in the array encapsulated
+ * in this attribute.
+ * For example:
+ * -----------------------------------------------------------------------
+ * | 1 | 34 | 32 | 65 |
+ * -----------------------------------------------------------------------
+ * If the attribute contains the values defined in above array then it means
+ * 1) Wifi STA connection has priority over BT_SCO, BT_A2DP and ZIGBEE HIGH.
+ * 2) BT_SCO has priority over BT_A2DP.
+ * 3) BT_A2DP has priority over ZIGBEE HIGH.
+ * Profiles which are not listed in this array shall not be preferred over the
+ * profiles which are listed in the array as a part of this attribute.
+ */
+enum qca_vendor_attr_coex_config {
+ QCA_VENDOR_ATTR_COEX_CONFIG_INVALID = 0,
+ QCA_VENDOR_ATTR_COEX_CONFIG_PROFILES = 1,
+
+ /* Keep last */
+ QCA_VENDOR_ATTR_COEX_CONFIG_AFTER_LAST,
+ QCA_VENDOR_ATTR_COEX_CONFIG_MAX =
+ QCA_VENDOR_ATTR_COEX_CONFIG_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_vendor_attr_coex_config_three_way - Specifies vendor coex config
+ * attributes
+ * Attributes for data used by QCA_NL80211_VENDOR_SUBCMD_COEX_CONFIG
+ *
+ * QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_CONFIG_TYPE: u32 attribute.
+ * Indicate config type.
+ * The config types are 32-bit values from qca_vendor_attr_coex_config_types
+ *
+ * @QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_1: u32 attribute.
+ * Indicate the Priority 1 profiles.
+ * The profiles are 8-bit values from enum qca_coex_config_profiles.
+ * In same priority level, maximum to 4 profiles can be set here.
+ * @QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_2: u32 attribute.
+ * Indicate the Priority 2 profiles.
+ * The profiles are 8-bit values from enum qca_coex_config_profiles.
+ * In same priority level, maximum to 4 profiles can be set here.
+ * @QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_3: u32 attribute.
+ * Indicate the Priority 3 profiles.
+ * The profiles are 8-bit values from enum qca_coex_config_profiles.
+ * In same priority level, maximum to 4 profiles can be set here.
+ * @QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_4: u32 attribute.
+ * Indicate the Priority 4 profiles.
+ * The profiles are 8-bit values from enum qca_coex_config_profiles.
+ * In same priority level, maximum to 4 profiles can be set here.
+ * NOTE:
+ * Limitations for QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_x priority
+ * arrangement:
+ * 1: In the same u32 attribute (priority x), the profiles enum values own
+ * same priority level.
+ * 2: 0xff is default value if the u8 profile value is not set.
+ * 3: max to 4 rules/profiles in same priority level.
+ * 4: max to 4 priority level (priority 1 - priority 4)
+ * 5: one priority level only supports one scenario from WLAN/BT/ZB,
+ * hybrid rules not support.
+ * 6: if WMI_COEX_CONFIG_THREE_WAY_COEX_RESET called, priority x will
+ * remain blank to reset all parameters.
+ * For example:
+ *
+ * If the attributes as follow:
+ * priority 1:
+ * ------------------------------------
+ * | 0xff | 0 | 1 | 2 |
+ * ------------------------------------
+ * priority 2:
+ * -------------------------------------
+ * | 0xff | 0xff | 0xff | 32 |
+ * -------------------------------------
+ * priority 3:
+ * -------------------------------------
+ * | 0xff | 0xff | 0xff | 65 |
+ * -------------------------------------
+ * then it means:
+ * 1: WIFI_STA_DISCOVERY, WIFI_STA_CLASS_3_MGMT and WIFI_STA_CONNECTION
+ * owns same priority level.
+ * 2: WIFI_STA_DISCOVERY, WIFI_STA_CLASS_3_MGMT and WIFI_STA_CONNECTION
+ * has priority over BT_A2DP and ZB_HIGH.
+ * 3: BT_A2DP has priority over ZB_HIGH.
+ */
+
+enum qca_vendor_attr_coex_config_three_way {
+ QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_INVALID = 0,
+ QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_CONFIG_TYPE = 1,
+ QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_1 = 2,
+ QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_2 = 3,
+ QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_3 = 4,
+ QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_4 = 5,
+
+ /* Keep last */
+ QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_AFTER_LAST,
+ QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_MAX =
+ QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_link_properties - Represent the link properties.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_MAC_ADDR: MAC address of the peer
+ * (STA/AP) for the connected link.
+ * @QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_STA_FLAGS: Attribute containing a
+ * &struct nl80211_sta_flag_update for the respective connected link. MAC
+ * address of the peer represented by
+ * QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_MAC_ADDR.
+ */
+enum qca_wlan_vendor_attr_link_properties {
+ QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_INVALID = 0,
+ /* 1 - 3 are reserved */
+ QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_MAC_ADDR = 4,
+ QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_STA_FLAGS = 5,
+
+ /* Keep last */
+ QCA_VENDOR_ATTR_LINK_PROPERTIES_AFTER_LAST,
+ QCA_VENDOR_ATTR_LINK_PROPERTIES_MAX =
+ QCA_VENDOR_ATTR_LINK_PROPERTIES_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_vendor_attr_peer_stats_cache_type - Represents peer stats cache type
+ * This enum defines the valid set of values of peer stats cache types. These
+ * values are used by attribute
+ * %QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_TYPE.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_TX_RATE_STATS: Represents peer TX rate statistics
+ * @QCA_WLAN_VENDOR_ATTR_PEER_RX_RATE_STATS: Represents peer RX rate statistics
+ * @QCA_WLAN_VENDOR_ATTR_PEER_TX_SOJOURN_STATS: Represents peer TX sojourn
+ * statistics
+ */
+enum qca_vendor_attr_peer_stats_cache_type {
+ QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_TYPE_INVALID = 0,
+
+ QCA_WLAN_VENDOR_ATTR_PEER_TX_RATE_STATS,
+ QCA_WLAN_VENDOR_ATTR_PEER_RX_RATE_STATS,
+ QCA_WLAN_VENDOR_ATTR_PEER_TX_SOJOURN_STATS,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_peer_stats_cache_params - This enum defines
+ * attributes required for QCA_NL80211_VENDOR_SUBCMD_PEER_STATS_CACHE_FLUSH
+ * Information in these attributes is used to flush peer rate statistics from
+ * the driver to user application.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_TYPE: Unsigned 32-bit attribute
+ * Indicate peer statistics cache type.
+ * The statistics types are 32-bit values from
+ * enum qca_vendor_attr_peer_stats_cache_type.
+ * @QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PEER_MAC: Unsigned 8-bit array
+ * of size 6 octets, representing the peer MAC address.
+ * @QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_DATA: Opaque data attribute
+ * containing buffer of statistics to send to application layer entity.
+ * @QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PEER_COOKIE: Unsigned 64-bit attribute
+ * representing a cookie for peer unique session.
+ */
+enum qca_wlan_vendor_attr_peer_stats_cache_params {
+ QCA_WLAN_VENDOR_ATTR_PEER_STATS_INVALID = 0,
+
+ QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_TYPE = 1,
+ QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PEER_MAC = 2,
+ QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_DATA = 3,
+ QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PEER_COOKIE = 4,
+
+ /* Keep last */
+ QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_LAST,
+ QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_MAX =
+ QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_LAST - 1
+};
+
+/**
+ * enum qca_mpta_helper_attr_zigbee_state - Current Zigbee state
+ * This enum defines all the possible states of Zigbee, which can be
+ * delivered in the QCA_MPTA_HELPER_VENDOR_ATTR_ZIGBEE_STATE attribute.
+ *
+ * @ZIGBEE_IDLE: Zigbee in idle state
+ * @ZIGBEE_FORM_NETWORK: Zigbee forming network
+ * @ZIGBEE_WAIT_JOIN: Zigbee waiting for joining network
+ * @ZIGBEE_JOIN: Zigbee joining network
+ * @ZIGBEE_NETWORK_UP: Zigbee network is up
+ * @ZIGBEE_HMI: Zigbee in HMI mode
+ */
+enum qca_mpta_helper_attr_zigbee_state {
+ ZIGBEE_IDLE = 0,
+ ZIGBEE_FORM_NETWORK = 1,
+ ZIGBEE_WAIT_JOIN = 2,
+ ZIGBEE_JOIN = 3,
+ ZIGBEE_NETWORK_UP = 4,
+ ZIGBEE_HMI = 5,
+};
+
+/*
+ * enum qca_mpta_helper_vendor_attr - Attributes used in vendor sub-command
+ * QCA_NL80211_VENDOR_SUBCMD_MPTA_HELPER_CONFIG.
+ */
+enum qca_mpta_helper_vendor_attr {
+ QCA_MPTA_HELPER_VENDOR_ATTR_INVALID = 0,
+ /* Optional attribute used to update Zigbee state.
+ * enum qca_mpta_helper_attr_zigbee_state.
+ * NLA_U32 attribute.
+ */
+ QCA_MPTA_HELPER_VENDOR_ATTR_ZIGBEE_STATE = 1,
+ /* Optional attribute used to configure WLAN duration for Shape-OCS
+ * during interrupt.
+ * Set in pair with QCA_MPTA_HELPER_VENDOR_ATTR_INT_NON_WLAN_DURATION.
+ * Value range 0 ~ 300 (ms).
+ * NLA_U32 attribute.
+ */
+ QCA_MPTA_HELPER_VENDOR_ATTR_INT_WLAN_DURATION = 2,
+ /* Optional attribute used to configure non-WLAN duration for Shape-OCS
+ * during interrupt.
+ * Set in pair with QCA_MPTA_HELPER_VENDOR_ATTR_INT_WLAN_DURATION.
+ * Value range 0 ~ 300 (ms).
+ * NLA_U32 attribute.
+ */
+ QCA_MPTA_HELPER_VENDOR_ATTR_INT_NON_WLAN_DURATION = 3,
+ /* Optional attribute used to configure WLAN duration for Shape-OCS
+ * monitor period.
+ * Set in pair with QCA_MPTA_HELPER_VENDOR_ATTR_MON_NON_WLAN_DURATION.
+ * Value range 0 ~ 300 (ms)
+ * NLA_U32 attribute
+ */
+ QCA_MPTA_HELPER_VENDOR_ATTR_MON_WLAN_DURATION = 4,
+ /* Optional attribute used to configure non-WLAN duration for Shape-OCS
+ * monitor period.
+ * Set in pair with QCA_MPTA_HELPER_VENDOR_ATTR_MON_WLAN_DURATION.
+ * Value range 0 ~ 300 (ms)
+ * NLA_U32 attribute
+ */
+ QCA_MPTA_HELPER_VENDOR_ATTR_MON_NON_WLAN_DURATION = 5,
+ /* Optional attribute used to configure OCS interrupt duration.
+ * Set in pair with QCA_MPTA_HELPER_VENDOR_ATTR_MON_OCS_DURATION.
+ * Value range 1000 ~ 20000 (ms)
+ * NLA_U32 attribute
+ */
+ QCA_MPTA_HELPER_VENDOR_ATTR_INT_OCS_DURATION = 6,
+ /* Optional attribute used to configure OCS monitor duration.
+ * Set in pair with QCA_MPTA_HELPER_VENDOR_ATTR_INT_OCS_DURATION.
+ * Value range 1000 ~ 20000 (ms)
+ * NLA_U32 attribute
+ */
+ QCA_MPTA_HELPER_VENDOR_ATTR_MON_OCS_DURATION = 7,
+ /* Optional attribute used to notify WLAN firmware the current Zigbee
+ * channel.
+ * Value range 11 ~ 26
+ * NLA_U32 attribute
+ */
+ QCA_MPTA_HELPER_VENDOR_ATTR_ZIGBEE_CHAN = 8,
+ /* Optional attribute used to configure WLAN mute duration.
+ * Value range 0 ~ 400 (ms)
+ * NLA_U32 attribute
+ */
+ QCA_MPTA_HELPER_VENDOR_ATTR_WLAN_MUTE_DURATION = 9,
+
+ /* keep last */
+ QCA_MPTA_HELPER_VENDOR_ATTR_AFTER_LAST,
+ QCA_MPTA_HELPER_VENDOR_ATTR_MAX =
+ QCA_MPTA_HELPER_VENDOR_ATTR_AFTER_LAST - 1
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index 9f70f03..0d56e55 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
+#include "utils/const_time.h"
#include "crypto/crypto.h"
#include "crypto/sha256.h"
#include "crypto/random.h"
@@ -17,10 +18,33 @@
#include "sae.h"
+static int sae_suitable_group(int group)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+ /* Allow all groups for testing purposes in non-production builds. */
+ return 1;
+#else /* CONFIG_TESTING_OPTIONS */
+ /* Enforce REVmd rules on which SAE groups are suitable for production
+ * purposes: FFC groups whose prime is >= 3072 bits and ECC groups
+ * defined over a prime field whose prime is >= 256 bits. Furthermore,
+ * ECC groups defined over a characteristic 2 finite field and ECC
+ * groups with a co-factor greater than 1 are not suitable. */
+ return group == 19 || group == 20 || group == 21 ||
+ group == 28 || group == 29 || group == 30 ||
+ group == 15 || group == 16 || group == 17 || group == 18;
+#endif /* CONFIG_TESTING_OPTIONS */
+}
+
+
int sae_set_group(struct sae_data *sae, int group)
{
struct sae_temporary_data *tmp;
+ if (!sae_suitable_group(group)) {
+ wpa_printf(MSG_DEBUG, "SAE: Reject unsuitable group %d", group);
+ return -1;
+ }
+
sae_clear_data(sae);
tmp = sae->tmp = os_zalloc(sizeof(*tmp));
if (tmp == NULL)
@@ -29,6 +53,8 @@
/* First, check if this is an ECC group */
tmp->ec = crypto_ec_init(group);
if (tmp->ec) {
+ wpa_printf(MSG_DEBUG, "SAE: Selecting supported ECC group %d",
+ group);
sae->group = group;
tmp->prime_len = crypto_ec_prime_len(tmp->ec);
tmp->prime = crypto_ec_get_prime(tmp->ec);
@@ -39,6 +65,8 @@
/* Not an ECC group, check FFC */
tmp->dh = dh_groups_get(group);
if (tmp->dh) {
+ wpa_printf(MSG_DEBUG, "SAE: Selecting supported FFC group %d",
+ group);
sae->group = group;
tmp->prime_len = tmp->dh->prime_len;
if (tmp->prime_len > SAE_MAX_PRIME_LEN) {
@@ -66,6 +94,8 @@
}
/* Unsupported group */
+ wpa_printf(MSG_DEBUG,
+ "SAE: Group %d not supported by the crypto library", group);
return -1;
}
@@ -88,6 +118,7 @@
crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0);
crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0);
wpabuf_free(tmp->anti_clogging_token);
+ os_free(tmp->pw_id);
bin_clear_free(tmp, sizeof(*tmp));
sae->tmp = NULL;
}
@@ -201,12 +232,14 @@
static int is_quadratic_residue_blind(struct sae_data *sae,
const u8 *prime, size_t bits,
- const struct crypto_bignum *qr,
- const struct crypto_bignum *qnr,
+ const u8 *qr, const u8 *qnr,
const struct crypto_bignum *y_sqr)
{
- struct crypto_bignum *r, *num;
+ struct crypto_bignum *r, *num, *qr_or_qnr = NULL;
int r_odd, check, res = -1;
+ u8 qr_or_qnr_bin[SAE_MAX_ECC_PRIME_LEN];
+ size_t prime_len = sae->tmp->prime_len;
+ unsigned int mask;
/*
* Use the blinding technique to mask y_sqr while determining
@@ -217,7 +250,7 @@
* r = a random number between 1 and p-1, inclusive
* num = (v * r * r) modulo p
*/
- r = get_rand_1_to_p_1(prime, sae->tmp->prime_len, bits, &r_odd);
+ r = get_rand_1_to_p_1(prime, prime_len, bits, &r_odd);
if (!r)
return -1;
@@ -227,50 +260,51 @@
crypto_bignum_mulmod(num, r, sae->tmp->prime, num) < 0)
goto fail;
- if (r_odd) {
- /*
- * num = (num * qr) module p
- * LGR(num, p) = 1 ==> quadratic residue
- */
- if (crypto_bignum_mulmod(num, qr, sae->tmp->prime, num) < 0)
- goto fail;
- check = 1;
- } else {
- /*
- * num = (num * qnr) module p
- * LGR(num, p) = -1 ==> quadratic residue
- */
- if (crypto_bignum_mulmod(num, qnr, sae->tmp->prime, num) < 0)
- goto fail;
- check = -1;
- }
+ /*
+ * Need to minimize differences in handling different cases, so try to
+ * avoid branches and timing differences.
+ *
+ * If r_odd:
+ * num = (num * qr) module p
+ * LGR(num, p) = 1 ==> quadratic residue
+ * else:
+ * num = (num * qnr) module p
+ * LGR(num, p) = -1 ==> quadratic residue
+ */
+ mask = const_time_is_zero(r_odd);
+ const_time_select_bin(mask, qnr, qr, prime_len, qr_or_qnr_bin);
+ qr_or_qnr = crypto_bignum_init_set(qr_or_qnr_bin, prime_len);
+ if (!qr_or_qnr ||
+ crypto_bignum_mulmod(num, qr_or_qnr, sae->tmp->prime, num) < 0)
+ goto fail;
+ /* r_odd is 0 or 1; branchless version of check = r_odd ? 1 : -1, */
+ check = const_time_select_int(mask, -1, 1);
res = crypto_bignum_legendre(num, sae->tmp->prime);
if (res == -2) {
res = -1;
goto fail;
}
- res = res == check;
+ /* branchless version of res = res == check
+ * (res is -1, 0, or 1; check is -1 or 1) */
+ mask = const_time_eq(res, check);
+ res = const_time_select_int(mask, 1, 0);
fail:
crypto_bignum_deinit(num, 1);
crypto_bignum_deinit(r, 1);
+ crypto_bignum_deinit(qr_or_qnr, 1);
return res;
}
static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
- const u8 *prime,
- const struct crypto_bignum *qr,
- const struct crypto_bignum *qnr,
- struct crypto_bignum **ret_x_cand)
+ const u8 *prime, const u8 *qr, const u8 *qnr,
+ u8 *pwd_value)
{
- u8 pwd_value[SAE_MAX_ECC_PRIME_LEN];
struct crypto_bignum *y_sqr, *x_cand;
int res;
size_t bits;
- *ret_x_cand = NULL;
-
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
/* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
@@ -279,42 +313,38 @@
prime, sae->tmp->prime_len, pwd_value, bits) < 0)
return -1;
if (bits % 8)
- buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
+ buf_shift_right(pwd_value, sae->tmp->prime_len, 8 - bits % 8);
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
pwd_value, sae->tmp->prime_len);
- if (os_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0)
+ if (const_time_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0)
return 0;
x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
if (!x_cand)
return -1;
y_sqr = crypto_ec_point_compute_y_sqr(sae->tmp->ec, x_cand);
- if (!y_sqr) {
- crypto_bignum_deinit(x_cand, 1);
+ crypto_bignum_deinit(x_cand, 1);
+ if (!y_sqr)
return -1;
- }
res = is_quadratic_residue_blind(sae, prime, bits, qr, qnr, y_sqr);
crypto_bignum_deinit(y_sqr, 1);
- if (res <= 0) {
- crypto_bignum_deinit(x_cand, 1);
- return res;
- }
-
- *ret_x_cand = x_cand;
- return 1;
+ return res;
}
+/* Returns -1 on fatal failure, 0 if PWE cannot be derived from the provided
+ * pwd-seed, or 1 if a valid PWE was derived from pwd-seed. */
static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
struct crypto_bignum *pwe)
{
u8 pwd_value[SAE_MAX_PRIME_LEN];
size_t bits = sae->tmp->prime_len * 8;
u8 exp[1];
- struct crypto_bignum *a, *b;
- int res;
+ struct crypto_bignum *a, *b = NULL;
+ int res, is_val;
+ u8 pwd_value_valid;
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
@@ -326,16 +356,29 @@
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value,
sae->tmp->prime_len);
- if (os_memcmp(pwd_value, sae->tmp->dh->prime, sae->tmp->prime_len) >= 0)
- {
- wpa_printf(MSG_DEBUG, "SAE: pwd-value >= p");
- return 0;
- }
+ /* Check whether pwd-value < p */
+ res = const_time_memcmp(pwd_value, sae->tmp->dh->prime,
+ sae->tmp->prime_len);
+ /* pwd-value >= p is invalid, so res is < 0 for the valid cases and
+ * the negative sign can be used to fill the mask for constant time
+ * selection */
+ pwd_value_valid = const_time_fill_msb(res);
+
+ /* If pwd-value >= p, force pwd-value to be < p and perform the
+ * calculations anyway to hide timing difference. The derived PWE will
+ * be ignored in that case. */
+ pwd_value[0] = const_time_select_u8(pwd_value_valid, pwd_value[0], 0);
/* PWE = pwd-value^((p-1)/r) modulo p */
+ res = -1;
a = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
+ if (!a)
+ goto fail;
+ /* This is an optimization based on the used group that does not depend
+ * on the password in any way, so it is fine to use separate branches
+ * for this step without constant time operations. */
if (sae->tmp->dh->safe_prime) {
/*
* r = (p-1)/2 for the group used here, so this becomes:
@@ -349,33 +392,34 @@
b = crypto_bignum_init_set(exp, sizeof(exp));
if (b == NULL ||
crypto_bignum_sub(sae->tmp->prime, b, b) < 0 ||
- crypto_bignum_div(b, sae->tmp->order, b) < 0) {
- crypto_bignum_deinit(b, 0);
- b = NULL;
- }
+ crypto_bignum_div(b, sae->tmp->order, b) < 0)
+ goto fail;
}
- if (a == NULL || b == NULL)
- res = -1;
- else
- res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe);
+ if (!b)
+ goto fail;
- crypto_bignum_deinit(a, 0);
- crypto_bignum_deinit(b, 0);
+ res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe);
+ if (res < 0)
+ goto fail;
- if (res < 0) {
- wpa_printf(MSG_DEBUG, "SAE: Failed to calculate PWE");
- return -1;
- }
+ /* There were no fatal errors in calculations, so determine the return
+ * value using constant time operations. We get here for number of
+ * invalid cases which are cleared here after having performed all the
+ * computation. PWE is valid if pwd-value was less than prime and
+ * PWE > 1. Start with pwd-value check first and then use constant time
+ * operations to clear res to 0 if PWE is 0 or 1.
+ */
+ res = const_time_select_u8(pwd_value_valid, 1, 0);
+ is_val = crypto_bignum_is_zero(pwe);
+ res = const_time_select_u8(const_time_is_zero(is_val), res, 0);
+ is_val = crypto_bignum_is_one(pwe);
+ res = const_time_select_u8(const_time_is_zero(is_val), res, 0);
- /* if (PWE > 1) --> found */
- if (crypto_bignum_is_zero(pwe) || crypto_bignum_is_one(pwe)) {
- wpa_printf(MSG_DEBUG, "SAE: PWE <= 1");
- return 0;
- }
-
- wpa_printf(MSG_DEBUG, "SAE: PWE found");
- return 1;
+fail:
+ crypto_bignum_deinit(a, 1);
+ crypto_bignum_deinit(b, 1);
+ return res;
}
@@ -417,31 +461,39 @@
static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
const u8 *addr2, const u8 *password,
- size_t password_len)
+ size_t password_len, const char *identifier)
{
u8 counter, k = 40;
u8 addrs[2 * ETH_ALEN];
- const u8 *addr[2];
- size_t len[2];
- u8 dummy_password[32];
- size_t dummy_password_len;
+ const u8 *addr[3];
+ size_t len[3];
+ size_t num_elem;
+ u8 *dummy_password, *tmp_password;
int pwd_seed_odd = 0;
u8 prime[SAE_MAX_ECC_PRIME_LEN];
size_t prime_len;
- struct crypto_bignum *x = NULL, *qr, *qnr;
+ struct crypto_bignum *x = NULL, *qr = NULL, *qnr = NULL;
+ u8 x_bin[SAE_MAX_ECC_PRIME_LEN];
+ u8 x_cand_bin[SAE_MAX_ECC_PRIME_LEN];
+ u8 qr_bin[SAE_MAX_ECC_PRIME_LEN];
+ u8 qnr_bin[SAE_MAX_ECC_PRIME_LEN];
size_t bits;
- int res;
+ int res = -1;
+ u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
+ * mask */
- dummy_password_len = password_len;
- if (dummy_password_len > sizeof(dummy_password))
- dummy_password_len = sizeof(dummy_password);
- if (random_get_bytes(dummy_password, dummy_password_len) < 0)
- return -1;
+ os_memset(x_bin, 0, sizeof(x_bin));
+
+ dummy_password = os_malloc(password_len);
+ tmp_password = os_malloc(password_len);
+ if (!dummy_password || !tmp_password ||
+ random_get_bytes(dummy_password, password_len) < 0)
+ goto fail;
prime_len = sae->tmp->prime_len;
if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
prime_len) < 0)
- return -1;
+ goto fail;
bits = crypto_ec_prime_len_bits(sae->tmp->ec);
/*
@@ -449,33 +501,44 @@
* (qnr) modulo p for blinding purposes during the loop.
*/
if (get_random_qr_qnr(prime, prime_len, sae->tmp->prime, bits,
- &qr, &qnr) < 0)
- return -1;
+ &qr, &qnr) < 0 ||
+ crypto_bignum_to_bin(qr, qr_bin, sizeof(qr_bin), prime_len) < 0 ||
+ crypto_bignum_to_bin(qnr, qnr_bin, sizeof(qnr_bin), prime_len) < 0)
+ goto fail;
wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
password, password_len);
+ if (identifier)
+ wpa_printf(MSG_DEBUG, "SAE: password identifier: %s",
+ identifier);
/*
* H(salt, ikm) = HMAC-SHA256(salt, ikm)
- * base = password
+ * base = password [|| identifier]
* pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
* base || counter)
*/
sae_pwd_seed_key(addr1, addr2, addrs);
- addr[0] = password;
+ addr[0] = tmp_password;
len[0] = password_len;
- addr[1] = &counter;
- len[1] = sizeof(counter);
+ num_elem = 1;
+ if (identifier) {
+ addr[num_elem] = (const u8 *) identifier;
+ len[num_elem] = os_strlen(identifier);
+ num_elem++;
+ }
+ addr[num_elem] = &counter;
+ len[num_elem] = sizeof(counter);
+ num_elem++;
/*
* Continue for at least k iterations to protect against side-channel
* attacks that attempt to determine the number of iterations required
* in the loop.
*/
- for (counter = 1; counter <= k || !x; counter++) {
+ for (counter = 1; counter <= k || !found; counter++) {
u8 pwd_seed[SHA256_MAC_LEN];
- struct crypto_bignum *x_cand;
if (counter > 200) {
/* This should not happen in practice */
@@ -483,40 +546,49 @@
break;
}
- wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
- if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len,
- pwd_seed) < 0)
+ wpa_printf(MSG_DEBUG, "SAE: counter = %03u", counter);
+ const_time_select_bin(found, dummy_password, password,
+ password_len, tmp_password);
+ if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
+ addr, len, pwd_seed) < 0)
break;
res = sae_test_pwd_seed_ecc(sae, pwd_seed,
- prime, qr, qnr, &x_cand);
+ prime, qr_bin, qnr_bin, x_cand_bin);
+ const_time_select_bin(found, x_bin, x_cand_bin, prime_len,
+ x_bin);
+ pwd_seed_odd = const_time_select_u8(
+ found, pwd_seed_odd,
+ pwd_seed[SHA256_MAC_LEN - 1] & 0x01);
+ os_memset(pwd_seed, 0, sizeof(pwd_seed));
if (res < 0)
goto fail;
- if (res > 0 && !x) {
- wpa_printf(MSG_DEBUG,
- "SAE: Selected pwd-seed with counter %u",
- counter);
- x = x_cand;
- pwd_seed_odd = pwd_seed[SHA256_MAC_LEN - 1] & 0x01;
- os_memset(pwd_seed, 0, sizeof(pwd_seed));
+ /* Need to minimize differences in handling res == 0 and 1 here
+ * to avoid differences in timing and instruction cache access,
+ * so use const_time_select_*() to make local copies of the
+ * values based on whether this loop iteration was the one that
+ * found the pwd-seed/x. */
- /*
- * Use a dummy password for the following rounds, if
- * any.
- */
- addr[0] = dummy_password;
- len[0] = dummy_password_len;
- } else if (res > 0) {
- crypto_bignum_deinit(x_cand, 1);
- }
+ /* found is 0 or 0xff here and res is 0 or 1. Bitwise OR of them
+ * (with res converted to 0/0xff) handles this in constant time.
+ */
+ found |= res * 0xff;
+ wpa_printf(MSG_DEBUG, "SAE: pwd-seed result %d found=0x%02x",
+ res, found);
}
- if (!x) {
+ if (!found) {
wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE");
res = -1;
goto fail;
}
+ x = crypto_bignum_init_set(x_bin, prime_len);
+ if (!x) {
+ res = -1;
+ goto fail;
+ }
+
if (!sae->tmp->pwe_ecc)
sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec);
if (!sae->tmp->pwe_ecc)
@@ -525,7 +597,6 @@
res = crypto_ec_point_solve_y_coord(sae->tmp->ec,
sae->tmp->pwe_ecc, x,
pwd_seed_odd);
- crypto_bignum_deinit(x, 1);
if (res < 0) {
/*
* This should not happen since we already checked that there
@@ -537,26 +608,48 @@
fail:
crypto_bignum_deinit(qr, 0);
crypto_bignum_deinit(qnr, 0);
+ os_free(dummy_password);
+ bin_clear_free(tmp_password, password_len);
+ crypto_bignum_deinit(x, 1);
+ os_memset(x_bin, 0, sizeof(x_bin));
+ os_memset(x_cand_bin, 0, sizeof(x_cand_bin));
return res;
}
+static int sae_modp_group_require_masking(int group)
+{
+ /* Groups for which pwd-value is likely to be >= p frequently */
+ return group == 22 || group == 23 || group == 24;
+}
+
+
static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
const u8 *addr2, const u8 *password,
- size_t password_len)
+ size_t password_len, const char *identifier)
{
- u8 counter;
+ u8 counter, k, sel_counter = 0;
u8 addrs[2 * ETH_ALEN];
- const u8 *addr[2];
- size_t len[2];
- int found = 0;
+ const u8 *addr[3];
+ size_t len[3];
+ size_t num_elem;
+ u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
+ * mask */
+ u8 mask;
+ struct crypto_bignum *pwe;
+ size_t prime_len = sae->tmp->prime_len * 8;
+ u8 *pwe_buf;
- if (sae->tmp->pwe_ffc == NULL) {
- sae->tmp->pwe_ffc = crypto_bignum_init();
- if (sae->tmp->pwe_ffc == NULL)
- return -1;
- }
+ crypto_bignum_deinit(sae->tmp->pwe_ffc, 1);
+ sae->tmp->pwe_ffc = NULL;
+
+ /* Allocate a buffer to maintain selected and candidate PWE for constant
+ * time selection. */
+ pwe_buf = os_zalloc(prime_len * 2);
+ pwe = crypto_bignum_init();
+ if (!pwe_buf || !pwe)
+ goto fail;
wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
password, password_len);
@@ -564,16 +657,25 @@
/*
* H(salt, ikm) = HMAC-SHA256(salt, ikm)
* pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
- * password || counter)
+ * password [|| identifier] || counter)
*/
sae_pwd_seed_key(addr1, addr2, addrs);
addr[0] = password;
len[0] = password_len;
- addr[1] = &counter;
- len[1] = sizeof(counter);
+ num_elem = 1;
+ if (identifier) {
+ addr[num_elem] = (const u8 *) identifier;
+ len[num_elem] = os_strlen(identifier);
+ num_elem++;
+ }
+ addr[num_elem] = &counter;
+ len[num_elem] = sizeof(counter);
+ num_elem++;
- for (counter = 1; !found; counter++) {
+ k = sae_modp_group_require_masking(sae->group) ? 40 : 1;
+
+ for (counter = 1; counter <= k || !found; counter++) {
u8 pwd_seed[SHA256_MAC_LEN];
int res;
@@ -583,20 +685,37 @@
break;
}
- wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
- if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len,
- pwd_seed) < 0)
+ wpa_printf(MSG_DEBUG, "SAE: counter = %02u", counter);
+ if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
+ addr, len, pwd_seed) < 0)
break;
- res = sae_test_pwd_seed_ffc(sae, pwd_seed, sae->tmp->pwe_ffc);
+ res = sae_test_pwd_seed_ffc(sae, pwd_seed, pwe);
+ /* res is -1 for fatal failure, 0 if a valid PWE was not found,
+ * or 1 if a valid PWE was found. */
if (res < 0)
break;
- if (res > 0) {
- wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
- found = 1;
- }
+ /* Store the candidate PWE into the second half of pwe_buf and
+ * the selected PWE in the beginning of pwe_buf using constant
+ * time selection. */
+ if (crypto_bignum_to_bin(pwe, pwe_buf + prime_len, prime_len,
+ prime_len) < 0)
+ break;
+ const_time_select_bin(found, pwe_buf, pwe_buf + prime_len,
+ prime_len, pwe_buf);
+ sel_counter = const_time_select_u8(found, sel_counter, counter);
+ mask = const_time_eq_u8(res, 1);
+ found = const_time_select_u8(found, found, mask);
}
- return found ? 0 : -1;
+ if (!found)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "SAE: Use PWE from counter = %02u", sel_counter);
+ sae->tmp->pwe_ffc = crypto_bignum_init_set(pwe_buf, prime_len);
+fail:
+ crypto_bignum_deinit(pwe, 1);
+ bin_clear_free(pwe_buf, prime_len * 2);
+ return sae->tmp->pwe_ffc ? 0 : -1;
}
@@ -696,13 +815,15 @@
int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
const u8 *password, size_t password_len,
- struct sae_data *sae)
+ const char *identifier, struct sae_data *sae)
{
if (sae->tmp == NULL ||
(sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
- password_len) < 0) ||
+ password_len,
+ identifier) < 0) ||
(sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
- password_len) < 0) ||
+ password_len,
+ identifier) < 0) ||
sae_derive_commit(sae) < 0)
return -1;
return 0;
@@ -842,7 +963,7 @@
void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
- const struct wpabuf *token)
+ const struct wpabuf *token, const char *identifier)
{
u8 *pos;
@@ -876,6 +997,16 @@
wpa_hexdump(MSG_DEBUG, "SAE: own commit-element",
pos, sae->tmp->prime_len);
}
+
+ if (identifier) {
+ /* Password Identifier element */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + os_strlen(identifier));
+ wpabuf_put_u8(buf, WLAN_EID_EXT_PASSWORD_IDENTIFIER);
+ wpabuf_put_str(buf, identifier);
+ wpa_printf(MSG_DEBUG, "SAE: own Password Identifier: %s",
+ identifier);
+ }
}
@@ -921,25 +1052,70 @@
}
+static int sae_is_password_id_elem(const u8 *pos, const u8 *end)
+{
+ return end - pos >= 3 &&
+ pos[0] == WLAN_EID_EXTENSION &&
+ pos[1] >= 1 &&
+ end - pos - 2 >= pos[1] &&
+ pos[2] == WLAN_EID_EXT_PASSWORD_IDENTIFIER;
+}
+
+
static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
const u8 *end, const u8 **token,
size_t *token_len)
{
- if ((sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len < end - *pos) {
- size_t tlen = end - (*pos + (sae->tmp->ec ? 3 : 2) *
- sae->tmp->prime_len);
- wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
- if (token)
- *token = *pos;
- if (token_len)
- *token_len = tlen;
- *pos += tlen;
- } else {
- if (token)
- *token = NULL;
- if (token_len)
- *token_len = 0;
+ size_t scalar_elem_len, tlen;
+ const u8 *elem;
+
+ if (token)
+ *token = NULL;
+ if (token_len)
+ *token_len = 0;
+
+ scalar_elem_len = (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len;
+ if (scalar_elem_len >= (size_t) (end - *pos))
+ return; /* No extra data beyond peer scalar and element */
+
+ /* It is a bit difficult to parse this now that there is an
+ * optional variable length Anti-Clogging Token field and
+ * optional variable length Password Identifier element in the
+ * frame. We are sending out fixed length Anti-Clogging Token
+ * fields, so use that length as a requirement for the received
+ * token and check for the presence of possible Password
+ * Identifier element based on the element header information.
+ */
+ tlen = end - (*pos + scalar_elem_len);
+
+ if (tlen < SHA256_MAC_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Too short optional data (%u octets) to include our Anti-Clogging Token",
+ (unsigned int) tlen);
+ return;
}
+
+ elem = *pos + scalar_elem_len;
+ if (sae_is_password_id_elem(elem, end)) {
+ /* Password Identifier element takes out all available
+ * extra octets, so there can be no Anti-Clogging token in
+ * this frame. */
+ return;
+ }
+
+ elem += SHA256_MAC_LEN;
+ if (sae_is_password_id_elem(elem, end)) {
+ /* Password Identifier element is included in the end, so
+ * remove its length from the Anti-Clogging token field. */
+ tlen -= 2 + elem[1];
+ }
+
+ wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
+ if (token)
+ *token = *pos;
+ if (token_len)
+ *token_len = tlen;
+ *pos += tlen;
}
@@ -991,12 +1167,12 @@
}
-static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos,
+static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 **pos,
const u8 *end)
{
u8 prime[SAE_MAX_ECC_PRIME_LEN];
- if (2 * sae->tmp->prime_len > end - pos) {
+ if (2 * sae->tmp->prime_len > end - *pos) {
wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
"commit-element");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -1007,8 +1183,8 @@
return WLAN_STATUS_UNSPECIFIED_FAILURE;
/* element x and y coordinates < p */
- if (os_memcmp(pos, prime, sae->tmp->prime_len) >= 0 ||
- os_memcmp(pos + sae->tmp->prime_len, prime,
+ if (os_memcmp(*pos, prime, sae->tmp->prime_len) >= 0 ||
+ os_memcmp(*pos + sae->tmp->prime_len, prime,
sae->tmp->prime_len) >= 0) {
wpa_printf(MSG_DEBUG, "SAE: Invalid coordinates in peer "
"element");
@@ -1016,13 +1192,13 @@
}
wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(x)",
- pos, sae->tmp->prime_len);
+ *pos, sae->tmp->prime_len);
wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(y)",
- pos + sae->tmp->prime_len, sae->tmp->prime_len);
+ *pos + sae->tmp->prime_len, sae->tmp->prime_len);
crypto_ec_point_deinit(sae->tmp->peer_commit_element_ecc, 0);
sae->tmp->peer_commit_element_ecc =
- crypto_ec_point_from_bin(sae->tmp->ec, pos);
+ crypto_ec_point_from_bin(sae->tmp->ec, *pos);
if (sae->tmp->peer_commit_element_ecc == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -1032,27 +1208,29 @@
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
+ *pos += 2 * sae->tmp->prime_len;
+
return WLAN_STATUS_SUCCESS;
}
-static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos,
+static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 **pos,
const u8 *end)
{
struct crypto_bignum *res, *one;
const u8 one_bin[1] = { 0x01 };
- if (sae->tmp->prime_len > end - pos) {
+ if (sae->tmp->prime_len > end - *pos) {
wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
"commit-element");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", pos,
+ wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", *pos,
sae->tmp->prime_len);
crypto_bignum_deinit(sae->tmp->peer_commit_element_ffc, 0);
sae->tmp->peer_commit_element_ffc =
- crypto_bignum_init_set(pos, sae->tmp->prime_len);
+ crypto_bignum_init_set(*pos, sae->tmp->prime_len);
if (sae->tmp->peer_commit_element_ffc == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
/* 1 < element < p - 1 */
@@ -1080,11 +1258,13 @@
}
crypto_bignum_deinit(res, 0);
+ *pos += sae->tmp->prime_len;
+
return WLAN_STATUS_SUCCESS;
}
-static u16 sae_parse_commit_element(struct sae_data *sae, const u8 *pos,
+static u16 sae_parse_commit_element(struct sae_data *sae, const u8 **pos,
const u8 *end)
{
if (sae->tmp->dh)
@@ -1093,6 +1273,44 @@
}
+static int sae_parse_password_identifier(struct sae_data *sae,
+ const u8 *pos, const u8 *end)
+{
+ wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
+ pos, end - pos);
+ if (!sae_is_password_id_elem(pos, end)) {
+ if (sae->tmp->pw_id) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: No Password Identifier included, but expected one (%s)",
+ sae->tmp->pw_id);
+ return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
+ }
+ os_free(sae->tmp->pw_id);
+ sae->tmp->pw_id = NULL;
+ return WLAN_STATUS_SUCCESS; /* No Password Identifier */
+ }
+
+ if (sae->tmp->pw_id &&
+ (pos[1] - 1 != (int) os_strlen(sae->tmp->pw_id) ||
+ os_memcmp(sae->tmp->pw_id, pos + 3, pos[1] - 1) != 0)) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: The included Password Identifier does not match the expected one (%s)",
+ sae->tmp->pw_id);
+ return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
+ }
+
+ os_free(sae->tmp->pw_id);
+ sae->tmp->pw_id = os_malloc(pos[1]);
+ if (!sae->tmp->pw_id)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ os_memcpy(sae->tmp->pw_id, pos + 3, pos[1] - 1);
+ sae->tmp->pw_id[pos[1] - 1] = '\0';
+ wpa_hexdump_ascii(MSG_DEBUG, "SAE: Received Password Identifier",
+ sae->tmp->pw_id, pos[1] - 1);
+ return WLAN_STATUS_SUCCESS;
+}
+
+
u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
const u8 **token, size_t *token_len, int *allowed_groups)
{
@@ -1116,7 +1334,12 @@
return res;
/* commit-element */
- res = sae_parse_commit_element(sae, pos, end);
+ res = sae_parse_commit_element(sae, &pos, end);
+ if (res != WLAN_STATUS_SUCCESS)
+ return res;
+
+ /* Optional Password Identifier element */
+ res = sae_parse_password_identifier(sae, pos, end);
if (res != WLAN_STATUS_SUCCESS)
return res;
@@ -1235,7 +1458,8 @@
/* Send-Confirm */
sc = wpabuf_put(buf, 0);
wpabuf_put_le16(buf, sae->send_confirm);
- sae->send_confirm++;
+ if (sae->send_confirm < 0xffff)
+ sae->send_confirm++;
if (sae->tmp->ec)
sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
@@ -1263,23 +1487,31 @@
wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data));
- if (sae->tmp == NULL) {
+ if (!sae->tmp || !sae->peer_commit_scalar ||
+ !sae->tmp->own_commit_scalar) {
wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available");
return -1;
}
- if (sae->tmp->ec)
+ if (sae->tmp->ec) {
+ if (!sae->tmp->peer_commit_element_ecc ||
+ !sae->tmp->own_commit_element_ecc)
+ return -1;
sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
sae->tmp->peer_commit_element_ecc,
sae->tmp->own_commit_scalar,
sae->tmp->own_commit_element_ecc,
verifier);
- else
+ } else {
+ if (!sae->tmp->peer_commit_element_ffc ||
+ !sae->tmp->own_commit_element_ffc)
+ return -1;
sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar,
sae->tmp->peer_commit_element_ffc,
sae->tmp->own_commit_scalar,
sae->tmp->own_commit_element_ffc,
verifier);
+ }
if (os_memcmp_const(verifier, data + 2, SHA256_MAC_LEN) != 0) {
wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch");
@@ -1292,3 +1524,19 @@
return 0;
}
+
+
+const char * sae_state_txt(enum sae_state state)
+{
+ switch (state) {
+ case SAE_NOTHING:
+ return "Nothing";
+ case SAE_COMMITTED:
+ return "Committed";
+ case SAE_CONFIRMED:
+ return "Confirmed";
+ case SAE_ACCEPTED:
+ return "Accepted";
+ }
+ return "?";
+}
diff --git a/src/common/sae.h b/src/common/sae.h
index a4270bc..3eb6e32 100644
--- a/src/common/sae.h
+++ b/src/common/sae.h
@@ -39,16 +39,24 @@
struct crypto_bignum *prime_buf;
struct crypto_bignum *order_buf;
struct wpabuf *anti_clogging_token;
+ char *pw_id;
+ int vlan_id;
+ u8 bssid[ETH_ALEN];
+};
+
+enum sae_state {
+ SAE_NOTHING, SAE_COMMITTED, SAE_CONFIRMED, SAE_ACCEPTED
};
struct sae_data {
- enum { SAE_NOTHING, SAE_COMMITTED, SAE_CONFIRMED, SAE_ACCEPTED } state;
+ enum sae_state state;
u16 send_confirm;
u8 pmk[SAE_PMK_LEN];
u8 pmkid[SAE_PMKID_LEN];
struct crypto_bignum *peer_commit_scalar;
int group;
- int sync;
+ unsigned int sync; /* protocol instance variable: Sync */
+ u16 rc; /* protocol instance variable: Rc (received send-confirm) */
struct sae_temporary_data *tmp;
};
@@ -58,14 +66,15 @@
int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
const u8 *password, size_t password_len,
- struct sae_data *sae);
+ const char *identifier, struct sae_data *sae);
int sae_process_commit(struct sae_data *sae);
void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
- const struct wpabuf *token);
+ 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);
void 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);
#endif /* SAE_H */
diff --git a/src/common/version.h b/src/common/version.h
index 16c1004..eb4f313 100644
--- a/src/common/version.h
+++ b/src/common/version.h
@@ -9,6 +9,6 @@
#define GIT_VERSION_STR_POSTFIX ""
#endif /* GIT_VERSION_STR_POSTFIX */
-#define VERSION_STR "2.7-devel" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
+#define VERSION_STR "2.8-devel" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
#endif /* VERSION_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 4bab6b9..ed2d1c2 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -1,6 +1,6 @@
/*
* WPA/RSN - Shared functions for supplicant and authenticator
- * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -25,6 +25,7 @@
{
switch (akmp) {
case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
return 24;
case WPA_KEY_MGMT_FILS_SHA256:
case WPA_KEY_MGMT_FT_FILS_SHA256:
@@ -41,6 +42,21 @@
}
+#ifdef CONFIG_IEEE80211R
+static unsigned int wpa_kck2_len(int akmp)
+{
+ switch (akmp) {
+ case WPA_KEY_MGMT_FT_FILS_SHA256:
+ return 16;
+ case WPA_KEY_MGMT_FT_FILS_SHA384:
+ return 24;
+ default:
+ return 0;
+ }
+}
+#endif /* CONFIG_IEEE80211R */
+
+
static unsigned int wpa_kek_len(int akmp, size_t pmk_len)
{
switch (akmp) {
@@ -50,6 +66,7 @@
case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
case WPA_KEY_MGMT_FILS_SHA256:
case WPA_KEY_MGMT_FT_FILS_SHA256:
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
return 32;
case WPA_KEY_MGMT_DPP:
return pmk_len <= 32 ? 16 : 32;
@@ -61,10 +78,26 @@
}
+#ifdef CONFIG_IEEE80211R
+static unsigned int wpa_kek2_len(int akmp)
+{
+ switch (akmp) {
+ case WPA_KEY_MGMT_FT_FILS_SHA256:
+ return 16;
+ case WPA_KEY_MGMT_FT_FILS_SHA384:
+ return 32;
+ default:
+ return 0;
+ }
+}
+#endif /* CONFIG_IEEE80211R */
+
+
unsigned int wpa_mic_len(int akmp, size_t pmk_len)
{
switch (akmp) {
case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
return 24;
case WPA_KEY_MGMT_FILS_SHA256:
case WPA_KEY_MGMT_FILS_SHA384:
@@ -82,6 +115,61 @@
/**
+ * wpa_use_akm_defined - Is AKM-defined Key Descriptor Version used
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
+ * Returns: 1 if AKM-defined Key Descriptor Version is used; 0 otherwise
+ */
+int wpa_use_akm_defined(int akmp)
+{
+ return akmp == WPA_KEY_MGMT_OSEN ||
+ akmp == WPA_KEY_MGMT_OWE ||
+ akmp == WPA_KEY_MGMT_DPP ||
+ akmp == WPA_KEY_MGMT_FT_IEEE8021X_SHA384 ||
+ wpa_key_mgmt_sae(akmp) ||
+ wpa_key_mgmt_suite_b(akmp) ||
+ wpa_key_mgmt_fils(akmp);
+}
+
+
+/**
+ * wpa_use_cmac - Is CMAC integrity algorithm used for EAPOL-Key MIC
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
+ * Returns: 1 if CMAC is used; 0 otherwise
+ */
+int wpa_use_cmac(int akmp)
+{
+ return akmp == WPA_KEY_MGMT_OSEN ||
+ akmp == WPA_KEY_MGMT_OWE ||
+ akmp == WPA_KEY_MGMT_DPP ||
+ wpa_key_mgmt_ft(akmp) ||
+ wpa_key_mgmt_sha256(akmp) ||
+ wpa_key_mgmt_sae(akmp) ||
+ wpa_key_mgmt_suite_b(akmp);
+}
+
+
+/**
+ * wpa_use_aes_key_wrap - Is AES Keywrap algorithm used for EAPOL-Key Key Data
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
+ * Returns: 1 if AES Keywrap is used; 0 otherwise
+ *
+ * Note: AKM 00-0F-AC:1 and 00-0F-AC:2 have special rules for selecting whether
+ * to use AES Keywrap based on the negotiated pairwise cipher. This function
+ * does not cover those special cases.
+ */
+int wpa_use_aes_key_wrap(int akmp)
+{
+ return akmp == WPA_KEY_MGMT_OSEN ||
+ akmp == WPA_KEY_MGMT_OWE ||
+ akmp == WPA_KEY_MGMT_DPP ||
+ wpa_key_mgmt_ft(akmp) ||
+ wpa_key_mgmt_sha256(akmp) ||
+ wpa_key_mgmt_sae(akmp) ||
+ wpa_key_mgmt_suite_b(akmp);
+}
+
+
+/**
* wpa_eapol_key_mic - Calculate EAPOL-Key MIC
* @key: EAPOL-Key Key Confirmation Key (KCK)
* @key_len: KCK length in octets
@@ -131,6 +219,13 @@
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
case WPA_KEY_INFO_TYPE_AKM_DEFINED:
switch (akmp) {
+#ifdef CONFIG_SAE
+ case WPA_KEY_MGMT_SAE:
+ case WPA_KEY_MGMT_FT_SAE:
+ wpa_printf(MSG_DEBUG,
+ "WPA: EAPOL-Key MIC using AES-CMAC (AKM-defined - SAE)");
+ return omac1_aes_128(key, buf, len, mic);
+#endif /* CONFIG_SAE */
#ifdef CONFIG_HS20
case WPA_KEY_MGMT_OSEN:
wpa_printf(MSG_DEBUG,
@@ -201,6 +296,15 @@
os_memcpy(mic, hash, key_len);
break;
#endif /* CONFIG_DPP */
+#if defined(CONFIG_IEEE80211R) && defined(CONFIG_SHA384)
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+ wpa_printf(MSG_DEBUG,
+ "WPA: EAPOL-Key MIC using HMAC-SHA384 (AKM-defined - FT 802.1X SHA384)");
+ if (hmac_sha384(key, key_len, buf, len, hash))
+ return -1;
+ os_memcpy(mic, hash, 24);
+ break;
+#endif /* CONFIG_IEEE80211R && CONFIG_SHA384 */
default:
wpa_printf(MSG_DEBUG,
"WPA: EAPOL-Key MIC algorithm not known (AKM-defined - akmp=0x%x)",
@@ -236,22 +340,32 @@
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
* PTK = PRF-X(PMK, "Pairwise key expansion",
* Min(AA, SA) || Max(AA, SA) ||
- * Min(ANonce, SNonce) || Max(ANonce, SNonce))
+ * Min(ANonce, SNonce) || Max(ANonce, SNonce)
+ * [ || Z.x ])
+ *
+ * The optional Z.x component is used only with DPP and that part is not defined
+ * in IEEE 802.11.
*/
int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
const u8 *addr1, const u8 *addr2,
const u8 *nonce1, const u8 *nonce2,
- struct wpa_ptk *ptk, int akmp, int cipher)
+ struct wpa_ptk *ptk, int akmp, int cipher,
+ const u8 *z, size_t z_len)
{
- u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
+#define MAX_Z_LEN 66 /* with NIST P-521 */
+ u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN + MAX_Z_LEN];
+ size_t data_len = 2 * ETH_ALEN + 2 * WPA_NONCE_LEN;
u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
size_t ptk_len;
if (pmk_len == 0) {
- wpa_printf(MSG_ERROR, "WPA: No PMK set for PT derivation");
+ wpa_printf(MSG_ERROR, "WPA: No PMK set for PTK derivation");
return -1;
}
+ if (z_len > MAX_Z_LEN)
+ return -1;
+
if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
os_memcpy(data, addr1, ETH_ALEN);
os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
@@ -270,43 +384,54 @@
WPA_NONCE_LEN);
}
+ if (z && z_len) {
+ os_memcpy(data + 2 * ETH_ALEN + 2 * WPA_NONCE_LEN, z, z_len);
+ data_len += z_len;
+ }
+
ptk->kck_len = wpa_kck_len(akmp, pmk_len);
ptk->kek_len = wpa_kek_len(akmp, pmk_len);
ptk->tk_len = wpa_cipher_key_len(cipher);
+ if (ptk->tk_len == 0) {
+ wpa_printf(MSG_ERROR,
+ "WPA: Unsupported cipher (0x%x) used in PTK derivation",
+ cipher);
+ return -1;
+ }
ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
if (wpa_key_mgmt_sha384(akmp)) {
#if defined(CONFIG_SUITEB192) || defined(CONFIG_FILS)
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)");
- if (sha384_prf(pmk, pmk_len, label, data, sizeof(data),
+ if (sha384_prf(pmk, pmk_len, label, data, data_len,
tmp, ptk_len) < 0)
return -1;
#else /* CONFIG_SUITEB192 || CONFIG_FILS */
return -1;
#endif /* CONFIG_SUITEB192 || CONFIG_FILS */
} else if (wpa_key_mgmt_sha256(akmp) || akmp == WPA_KEY_MGMT_OWE) {
-#ifdef CONFIG_IEEE80211W
+#if defined(CONFIG_IEEE80211W) || defined(CONFIG_SAE) || defined(CONFIG_FILS)
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
- if (sha256_prf(pmk, pmk_len, label, data, sizeof(data),
+ if (sha256_prf(pmk, pmk_len, label, data, data_len,
tmp, ptk_len) < 0)
return -1;
-#else /* CONFIG_IEEE80211W */
+#else /* CONFIG_IEEE80211W or CONFIG_SAE or CONFIG_FILS */
return -1;
-#endif /* CONFIG_IEEE80211W */
+#endif /* CONFIG_IEEE80211W or CONFIG_SAE or CONFIG_FILS */
#ifdef CONFIG_DPP
} else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 32) {
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
- if (sha256_prf(pmk, pmk_len, label, data, sizeof(data),
+ if (sha256_prf(pmk, pmk_len, label, data, data_len,
tmp, ptk_len) < 0)
return -1;
} else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 48) {
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)");
- if (sha384_prf(pmk, pmk_len, label, data, sizeof(data),
+ if (sha384_prf(pmk, pmk_len, label, data, data_len,
tmp, ptk_len) < 0)
return -1;
} else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 64) {
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA512)");
- if (sha512_prf(pmk, pmk_len, label, data, sizeof(data),
+ if (sha512_prf(pmk, pmk_len, label, data, data_len,
tmp, ptk_len) < 0)
return -1;
} else if (akmp == WPA_KEY_MGMT_DPP) {
@@ -316,7 +441,7 @@
#endif /* CONFIG_DPP */
} else {
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA1)");
- if (sha1_prf(pmk, pmk_len, label, data, sizeof(data), tmp,
+ if (sha1_prf(pmk, pmk_len, label, data, data_len, tmp,
ptk_len) < 0)
return -1;
}
@@ -325,6 +450,8 @@
MAC2STR(addr1), MAC2STR(addr2));
wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN);
+ if (z && z_len)
+ wpa_hexdump_key(MSG_DEBUG, "WPA: Z.x", z, z_len);
wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", tmp, ptk_len);
@@ -337,7 +464,11 @@
os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len);
+ ptk->kek2_len = 0;
+ ptk->kck2_len = 0;
+
os_memset(tmp, 0, sizeof(tmp));
+ os_memset(data, 0, data_len);
return 0;
}
@@ -386,6 +517,8 @@
addr, len, pmk);
if (res == 0)
wpa_hexdump_key(MSG_DEBUG, "FILS: PMK", pmk, *pmk_len);
+ else
+ *pmk_len = 0;
return res;
}
@@ -515,6 +648,9 @@
fils_ft, *fils_ft_len);
}
+ ptk->kek2_len = 0;
+ ptk->kck2_len = 0;
+
os_memset(tmp, 0, sizeof(tmp));
ret = 0;
err:
@@ -625,14 +761,23 @@
const u8 *addr[9];
size_t len[9];
size_t i, num_elem = 0;
- u8 zero_mic[16];
+ u8 zero_mic[24];
+ size_t mic_len, fte_fixed_len;
- if (kck_len != 16) {
+ if (kck_len == 16) {
+ mic_len = 16;
+#ifdef CONFIG_SHA384
+ } else if (kck_len == 24) {
+ mic_len = 24;
+#endif /* CONFIG_SHA384 */
+ } else {
wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u",
(unsigned int) kck_len);
return -1;
}
+ fte_fixed_len = sizeof(struct rsn_ftie) - 16 + mic_len;
+
addr[num_elem] = sta_addr;
len[num_elem] = ETH_ALEN;
num_elem++;
@@ -656,7 +801,7 @@
num_elem++;
}
if (ftie) {
- if (ftie_len < 2 + sizeof(struct rsn_ftie))
+ if (ftie_len < 2 + fte_fixed_len)
return -1;
/* IE hdr and mic_control */
@@ -665,14 +810,14 @@
num_elem++;
/* MIC field with all zeros */
- os_memset(zero_mic, 0, sizeof(zero_mic));
+ os_memset(zero_mic, 0, mic_len);
addr[num_elem] = zero_mic;
- len[num_elem] = sizeof(zero_mic);
+ len[num_elem] = mic_len;
num_elem++;
/* Rest of FTIE */
- addr[num_elem] = ftie + 2 + 2 + 16;
- len[num_elem] = ftie_len - (2 + 2 + 16);
+ addr[num_elem] = ftie + 2 + 2 + mic_len;
+ len[num_elem] = ftie_len - (2 + 2 + mic_len);
num_elem++;
}
if (ric) {
@@ -683,7 +828,17 @@
for (i = 0; i < num_elem; i++)
wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", addr[i], len[i]);
- if (omac1_aes_128_vector(kck, num_elem, addr, len, mic))
+#ifdef CONFIG_SHA384
+ if (kck_len == 24) {
+ u8 hash[SHA384_MAC_LEN];
+
+ if (hmac_sha384_vector(kck, kck_len, num_elem, addr, len, hash))
+ return -1;
+ os_memcpy(mic, hash, 24);
+ }
+#endif /* CONFIG_SHA384 */
+ if (kck_len == 16 &&
+ omac1_aes_128_vector(kck, num_elem, addr, len, mic))
return -1;
return 0;
@@ -691,23 +846,27 @@
static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
- struct wpa_ft_ies *parse)
+ struct wpa_ft_ies *parse, int use_sha384)
{
const u8 *end, *pos;
parse->ftie = ie;
parse->ftie_len = ie_len;
- pos = ie + sizeof(struct rsn_ftie);
+ pos = ie + (use_sha384 ? sizeof(struct rsn_ftie_sha384) :
+ sizeof(struct rsn_ftie));
end = ie + ie_len;
+ wpa_hexdump(MSG_DEBUG, "FT: Parse FTE subelements", pos, end - pos);
while (end - pos >= 2) {
u8 id, len;
id = *pos++;
len = *pos++;
- if (len > end - pos)
+ if (len > end - pos) {
+ wpa_printf(MSG_DEBUG, "FT: Truncated subelement");
break;
+ }
switch (id) {
case FTIE_SUBELEM_R1KH_ID:
@@ -739,6 +898,15 @@
parse->igtk_len = len;
break;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ case FTIE_SUBELEM_OCI:
+ parse->oci = pos;
+ parse->oci_len = len;
+ break;
+#endif /* CONFIG_OCV */
+ default:
+ wpa_printf(MSG_DEBUG, "FT: Unknown subelem id %u", id);
+ break;
}
pos += len;
@@ -749,13 +917,19 @@
int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
- struct wpa_ft_ies *parse)
+ struct wpa_ft_ies *parse, int use_sha384)
{
const u8 *end, *pos;
struct wpa_ie_data data;
int ret;
const struct rsn_ftie *ftie;
int prot_ie_count = 0;
+ int update_use_sha384 = 0;
+
+ if (use_sha384 < 0) {
+ use_sha384 = 0;
+ update_use_sha384 = 1;
+ }
os_memset(parse, 0, sizeof(*parse));
if (ies == NULL)
@@ -773,6 +947,7 @@
switch (id) {
case WLAN_EID_RSN:
+ wpa_hexdump(MSG_DEBUG, "FT: RSNE", pos, len);
parse->rsn = pos;
parse->rsn_len = len;
ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
@@ -787,22 +962,63 @@
parse->rsn_pmkid = data.pmkid;
parse->key_mgmt = data.key_mgmt;
parse->pairwise_cipher = data.pairwise_cipher;
+ if (update_use_sha384) {
+ use_sha384 =
+ wpa_key_mgmt_sha384(parse->key_mgmt);
+ update_use_sha384 = 0;
+ }
break;
case WLAN_EID_MOBILITY_DOMAIN:
+ wpa_hexdump(MSG_DEBUG, "FT: MDE", pos, len);
if (len < sizeof(struct rsn_mdie))
return -1;
parse->mdie = pos;
parse->mdie_len = len;
break;
case WLAN_EID_FAST_BSS_TRANSITION:
+ wpa_hexdump(MSG_DEBUG, "FT: FTE", pos, len);
+ if (use_sha384) {
+ const struct rsn_ftie_sha384 *ftie_sha384;
+
+ if (len < sizeof(*ftie_sha384))
+ return -1;
+ ftie_sha384 =
+ (const struct rsn_ftie_sha384 *) pos;
+ wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control",
+ ftie_sha384->mic_control, 2);
+ wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
+ ftie_sha384->mic,
+ sizeof(ftie_sha384->mic));
+ wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
+ ftie_sha384->anonce,
+ WPA_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
+ ftie_sha384->snonce,
+ WPA_NONCE_LEN);
+ prot_ie_count = ftie_sha384->mic_control[1];
+ if (wpa_ft_parse_ftie(pos, len, parse, 1) < 0)
+ return -1;
+ break;
+ }
+
if (len < sizeof(*ftie))
return -1;
ftie = (const struct rsn_ftie *) pos;
+ wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control",
+ ftie->mic_control, 2);
+ wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
+ ftie->mic, sizeof(ftie->mic));
+ wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
+ ftie->anonce, WPA_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
+ ftie->snonce, WPA_NONCE_LEN);
prot_ie_count = ftie->mic_control[1];
- if (wpa_ft_parse_ftie(pos, len, parse) < 0)
+ if (wpa_ft_parse_ftie(pos, len, parse, 0) < 0)
return -1;
break;
case WLAN_EID_TIMEOUT_INTERVAL:
+ wpa_hexdump(MSG_DEBUG, "FT: Timeout Interval",
+ pos, len);
if (len != 5)
break;
parse->tie = pos;
@@ -904,6 +1120,10 @@
return WPA_KEY_MGMT_FT_IEEE8021X;
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
return WPA_KEY_MGMT_FT_PSK;
+#ifdef CONFIG_SHA384
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384)
+ return WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
@@ -1006,6 +1226,9 @@
pos = rsn_ie + 6;
left = rsn_ie_len - 6;
+ data->group_cipher = WPA_CIPHER_GTK_NOT_USED;
+ data->has_group = 1;
+ data->key_mgmt = WPA_KEY_MGMT_OSEN;
data->proto = WPA_PROTO_OSEN;
} else {
const struct rsn_ie_hdr *hdr;
@@ -1026,6 +1249,7 @@
if (left >= RSN_SELECTOR_LEN) {
data->group_cipher = rsn_selector_to_bitfield(pos);
+ data->has_group = 1;
if (!wpa_cipher_valid_group(data->group_cipher)) {
wpa_printf(MSG_DEBUG,
"%s: invalid group cipher 0x%x (%08x)",
@@ -1051,6 +1275,8 @@
"count %u left %u", __func__, count, left);
return -4;
}
+ if (count)
+ data->has_pairwise = 1;
for (i = 0; i < count; i++) {
data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
pos += RSN_SELECTOR_LEN;
@@ -1269,6 +1495,15 @@
}
+int wpa_default_rsn_cipher(int freq)
+{
+ if (freq > 56160)
+ return WPA_CIPHER_GCMP; /* DMG */
+
+ return WPA_CIPHER_CCMP;
+}
+
+
#ifdef CONFIG_IEEE80211R
/**
@@ -1279,24 +1514,36 @@
int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
const u8 *ssid, size_t ssid_len,
const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
- const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
+ const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name,
+ int use_sha384)
{
u8 buf[1 + SSID_MAX_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
FT_R0KH_ID_MAX_LEN + ETH_ALEN];
- u8 *pos, r0_key_data[48], hash[32];
+ u8 *pos, r0_key_data[64], hash[48];
const u8 *addr[2];
size_t len[2];
+ size_t q = use_sha384 ? 48 : 32;
+ size_t r0_key_data_len = q + 16;
/*
* R0-Key-Data = KDF-384(XXKey, "FT-R0",
* SSIDlength || SSID || MDID || R0KHlength ||
* R0KH-ID || S0KH-ID)
- * XXKey is either the second 256 bits of MSK or PSK.
- * PMK-R0 = L(R0-Key-Data, 0, 256)
- * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
+ * XXKey is either the second 256 bits of MSK or PSK; or the first
+ * 384 bits of MSK for FT-EAP-SHA384.
+ * PMK-R0 = L(R0-Key-Data, 0, Q)
+ * PMK-R0Name-Salt = L(R0-Key-Data, Q, 128)
+ * Q = 384 for FT-EAP-SHA384; otherwise, 256
*/
if (ssid_len > SSID_MAX_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
return -1;
+ wpa_printf(MSG_DEBUG, "FT: Derive PMK-R0 using KDF-%s",
+ use_sha384 ? "SHA384" : "SHA256");
+ wpa_hexdump_key(MSG_DEBUG, "FT: XXKey", xxkey, xxkey_len);
+ wpa_hexdump_ascii(MSG_DEBUG, "FT: SSID", ssid, ssid_len);
+ wpa_hexdump(MSG_DEBUG, "FT: MDID", mdid, MOBILITY_DOMAIN_ID_LEN);
+ wpa_hexdump_ascii(MSG_DEBUG, "FT: R0KH-ID", r0kh_id, r0kh_id_len);
+ wpa_printf(MSG_DEBUG, "FT: S0KH-ID: " MACSTR, MAC2STR(s0kh_id));
pos = buf;
*pos++ = ssid_len;
os_memcpy(pos, ssid, ssid_len);
@@ -1309,22 +1556,50 @@
os_memcpy(pos, s0kh_id, ETH_ALEN);
pos += ETH_ALEN;
- if (sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
- r0_key_data, sizeof(r0_key_data)) < 0)
- return -1;
- os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
+#ifdef CONFIG_SHA384
+ if (use_sha384) {
+ if (xxkey_len != SHA384_MAC_LEN) {
+ wpa_printf(MSG_ERROR,
+ "FT: Unexpected XXKey length %d (expected %d)",
+ (int) xxkey_len, SHA384_MAC_LEN);
+ return -1;
+ }
+ if (sha384_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
+ r0_key_data, r0_key_data_len) < 0)
+ return -1;
+ }
+#endif /* CONFIG_SHA384 */
+ if (!use_sha384) {
+ if (xxkey_len != PMK_LEN) {
+ wpa_printf(MSG_ERROR,
+ "FT: Unexpected XXKey length %d (expected %d)",
+ (int) xxkey_len, PMK_LEN);
+ return -1;
+ }
+ if (sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
+ r0_key_data, r0_key_data_len) < 0)
+ return -1;
+ }
+ os_memcpy(pmk_r0, r0_key_data, q);
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, q);
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0Name-Salt", &r0_key_data[q], 16);
/*
- * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt)
+ * PMKR0Name = Truncate-128(Hash("FT-R0N" || PMK-R0Name-Salt)
*/
addr[0] = (const u8 *) "FT-R0N";
len[0] = 6;
- addr[1] = r0_key_data + PMK_LEN;
+ addr[1] = &r0_key_data[q];
len[1] = 16;
- if (sha256_vector(2, addr, len, hash) < 0)
+#ifdef CONFIG_SHA384
+ if (use_sha384 && sha384_vector(2, addr, len, hash) < 0)
+ return -1;
+#endif /* CONFIG_SHA384 */
+ 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));
return 0;
}
@@ -1335,15 +1610,15 @@
* IEEE Std 802.11r-2008 - 8.5.1.5.4
*/
int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
- const u8 *s1kh_id, u8 *pmk_r1_name)
+ const u8 *s1kh_id, u8 *pmk_r1_name, int use_sha384)
{
- u8 hash[32];
+ u8 hash[48];
const u8 *addr[4];
size_t len[4];
/*
- * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name ||
- * R1KH-ID || S1KH-ID))
+ * PMKR1Name = Truncate-128(Hash("FT-R1N" || PMKR0Name ||
+ * R1KH-ID || S1KH-ID))
*/
addr[0] = (const u8 *) "FT-R1N";
len[0] = 6;
@@ -1354,7 +1629,11 @@
addr[3] = s1kh_id;
len[3] = ETH_ALEN;
- if (sha256_vector(4, addr, len, hash) < 0)
+#ifdef CONFIG_SHA384
+ if (use_sha384 && sha384_vector(4, addr, len, hash) < 0)
+ return -1;
+#endif /* CONFIG_SHA384 */
+ if (!use_sha384 && sha256_vector(4, addr, len, hash) < 0)
return -1;
os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
return 0;
@@ -1366,7 +1645,8 @@
*
* IEEE Std 802.11r-2008 - 8.5.1.5.4
*/
-int wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
+int wpa_derive_pmk_r1(const u8 *pmk_r0, size_t pmk_r0_len,
+ const u8 *pmk_r0_name,
const u8 *r1kh_id, const u8 *s1kh_id,
u8 *pmk_r1, u8 *pmk_r1_name)
{
@@ -1374,18 +1654,37 @@
u8 *pos;
/* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
+ wpa_printf(MSG_DEBUG, "FT: Derive PMK-R1 using KDF-%s",
+ pmk_r0_len == SHA384_MAC_LEN ? "SHA384" : "SHA256");
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, pmk_r0_len);
+ wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", r1kh_id, FT_R1KH_ID_LEN);
+ wpa_printf(MSG_DEBUG, "FT: S1KH-ID: " MACSTR, MAC2STR(s1kh_id));
pos = buf;
os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
pos += FT_R1KH_ID_LEN;
os_memcpy(pos, s1kh_id, ETH_ALEN);
pos += ETH_ALEN;
- if (sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf,
- pmk_r1, PMK_LEN) < 0)
+#ifdef CONFIG_SHA384
+ if (pmk_r0_len == SHA384_MAC_LEN &&
+ sha384_prf(pmk_r0, pmk_r0_len, "FT-R1",
+ buf, pos - buf, pmk_r1, pmk_r0_len) < 0)
return -1;
+#endif /* CONFIG_SHA384 */
+ if (pmk_r0_len == PMK_LEN &&
+ sha256_prf(pmk_r0, pmk_r0_len, "FT-R1",
+ buf, pos - buf, pmk_r1, pmk_r0_len) < 0)
+ return -1;
+ if (pmk_r0_len != SHA384_MAC_LEN && pmk_r0_len != PMK_LEN) {
+ wpa_printf(MSG_ERROR, "FT: Unexpected PMK-R0 length %d",
+ (int) pmk_r0_len);
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r0_len);
return wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id,
- pmk_r1_name);
+ pmk_r1_name,
+ pmk_r0_len == SHA384_MAC_LEN);
}
@@ -1394,7 +1693,8 @@
*
* IEEE Std 802.11r-2008 - 8.5.1.5.5
*/
-int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
+int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
+ const u8 *snonce, const u8 *anonce,
const u8 *sta_addr, const u8 *bssid,
const u8 *pmk_r1_name,
struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher)
@@ -1403,13 +1703,21 @@
u8 *pos, hash[32];
const u8 *addr[6];
size_t len[6];
- u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
- size_t ptk_len;
+ u8 tmp[2 * WPA_KCK_MAX_LEN + 2 * WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
+ size_t ptk_len, offset;
+ int use_sha384 = wpa_key_mgmt_sha384(akmp);
/*
* PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
* BSSID || STA-ADDR)
*/
+ wpa_printf(MSG_DEBUG, "FT: Derive PTK using KDF-%s",
+ use_sha384 ? "SHA384" : "SHA256");
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r1_len);
+ wpa_hexdump(MSG_DEBUG, "FT: SNonce", snonce, WPA_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: ANonce", anonce, WPA_NONCE_LEN);
+ wpa_printf(MSG_DEBUG, "FT: BSSID=" MACSTR " STA-ADDR=" MACSTR,
+ MAC2STR(bssid), MAC2STR(sta_addr));
pos = buf;
os_memcpy(pos, snonce, WPA_NONCE_LEN);
pos += WPA_NONCE_LEN;
@@ -1421,18 +1729,44 @@
pos += ETH_ALEN;
ptk->kck_len = wpa_kck_len(akmp, PMK_LEN);
+ ptk->kck2_len = wpa_kck2_len(akmp);
ptk->kek_len = wpa_kek_len(akmp, PMK_LEN);
+ ptk->kek2_len = wpa_kek2_len(akmp);
ptk->tk_len = wpa_cipher_key_len(cipher);
- ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
+ ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len +
+ ptk->kck2_len + ptk->kek2_len;
- if (sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf,
- tmp, ptk_len) < 0)
- return -1;
+#ifdef CONFIG_SHA384
+ if (use_sha384) {
+ if (pmk_r1_len != SHA384_MAC_LEN) {
+ wpa_printf(MSG_ERROR,
+ "FT: Unexpected PMK-R1 length %d (expected %d)",
+ (int) pmk_r1_len, SHA384_MAC_LEN);
+ return -1;
+ }
+ if (sha384_prf(pmk_r1, pmk_r1_len, "FT-PTK",
+ buf, pos - buf, tmp, ptk_len) < 0)
+ return -1;
+ }
+#endif /* CONFIG_SHA384 */
+ if (!use_sha384) {
+ if (pmk_r1_len != PMK_LEN) {
+ wpa_printf(MSG_ERROR,
+ "FT: Unexpected PMK-R1 length %d (expected %d)",
+ (int) pmk_r1_len, PMK_LEN);
+ return -1;
+ }
+ if (sha256_prf(pmk_r1, pmk_r1_len, "FT-PTK",
+ buf, pos - buf, tmp, ptk_len) < 0)
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "FT: PTK", tmp, ptk_len);
/*
* PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
* ANonce || BSSID || STA-ADDR))
*/
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
addr[0] = pmk_r1_name;
len[0] = WPA_PMK_NAME_LEN;
addr[1] = (const u8 *) "FT-PTKN";
@@ -1451,11 +1785,23 @@
os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
os_memcpy(ptk->kck, tmp, ptk->kck_len);
- os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
- os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
+ offset = ptk->kck_len;
+ os_memcpy(ptk->kek, tmp + offset, ptk->kek_len);
+ offset += ptk->kek_len;
+ os_memcpy(ptk->tk, tmp + offset, ptk->tk_len);
+ offset += ptk->tk_len;
+ os_memcpy(ptk->kck2, tmp + offset, ptk->kck2_len);
+ offset += ptk->kck2_len;
+ os_memcpy(ptk->kek2, tmp + offset, ptk->kek2_len);
wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len);
wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len);
+ if (ptk->kck2_len)
+ wpa_hexdump_key(MSG_DEBUG, "FT: KCK2",
+ ptk->kck2, ptk->kck2_len);
+ if (ptk->kek2_len)
+ wpa_hexdump_key(MSG_DEBUG, "FT: KEK2",
+ ptk->kek2, ptk->kek2_len);
wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len);
wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
@@ -1483,7 +1829,7 @@
* See rsn_pmkid_suite_b()
* AKM: 00-0F-AC:12
* See rsn_pmkid_suite_b_192()
- * AKM: 00-0F-AC:15, 00-0F-AC:17
+ * AKM: 00-0F-AC:13, 00-0F-AC:15, 00-0F-AC:17
* PMKID = Truncate-128(HMAC-SHA-384(PMK, "PMK Name" || AA || SPA))
* Otherwise:
* PMKID = Truncate-128(HMAC-SHA-1(PMK, "PMK Name" || AA || SPA))
@@ -1501,11 +1847,11 @@
addr[2] = spa;
if (0) {
-#ifdef CONFIG_FILS
+#if defined(CONFIG_FILS) || defined(CONFIG_SHA384)
} else if (wpa_key_mgmt_sha384(akmp)) {
wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-384");
hmac_sha384_vector(pmk, pmk_len, 3, addr, len, hash);
-#endif /* CONFIG_FILS */
+#endif /* CONFIG_FILS || CONFIG_SHA384 */
#if defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
} else if (wpa_key_mgmt_sha256(akmp)) {
wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-256");
@@ -1656,6 +2002,8 @@
#ifdef CONFIG_IEEE80211R
case WPA_KEY_MGMT_FT_IEEE8021X:
return "FT-EAP";
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+ return "FT-EAP-SHA384";
case WPA_KEY_MGMT_FT_PSK:
return "FT-PSK";
#endif /* CONFIG_IEEE80211R */
@@ -1697,6 +2045,8 @@
u32 wpa_akm_to_suite(int akm)
{
+ if (akm & WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
+ return RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
if (akm & WPA_KEY_MGMT_FT_IEEE8021X)
return RSN_AUTH_KEY_MGMT_FT_802_1X;
if (akm & WPA_KEY_MGMT_FT_PSK)
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 3b8c1fb..e83d688 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -1,6 +1,6 @@
/*
* WPA definitions shared between hostapd and wpa_supplicant
- * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -62,8 +62,7 @@
#define RSN_AUTH_KEY_MGMT_FT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192 RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
-#define RSN_AUTH_KEY_MGMT_FT_802_1X_SUITE_B_192 \
-RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
+#define RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384 RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
#define RSN_AUTH_KEY_MGMT_FILS_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 14)
#define RSN_AUTH_KEY_MGMT_FILS_SHA384 RSN_SELECTOR(0x00, 0x0f, 0xac, 15)
#define RSN_AUTH_KEY_MGMT_FT_FILS_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 16)
@@ -111,6 +110,7 @@
#define RSN_KEY_DATA_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 10)
#define RSN_KEY_DATA_MULTIBAND_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
#define RSN_KEY_DATA_MULTIBAND_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
+#define RSN_KEY_DATA_OCI RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
#define WFA_KEY_DATA_IP_ADDR_REQ RSN_SELECTOR(0x50, 0x6f, 0x9a, 4)
#define WFA_KEY_DATA_IP_ADDR_ALLOC RSN_SELECTOR(0x50, 0x6f, 0x9a, 5)
@@ -149,7 +149,8 @@
#define WPA_CAPABILITY_SPP_A_MSDU_REQUIRED BIT(11)
#define WPA_CAPABILITY_PBAC BIT(12)
#define WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST BIT(13)
-/* B14-B15: Reserved */
+#define WPA_CAPABILITY_OCVC BIT(14)
+/* B15: Reserved */
/* IEEE 802.11r */
@@ -210,9 +211,13 @@
u8 kck[WPA_KCK_MAX_LEN]; /* EAPOL-Key Key Confirmation Key (KCK) */
u8 kek[WPA_KEK_MAX_LEN]; /* EAPOL-Key Key Encryption Key (KEK) */
u8 tk[WPA_TK_MAX_LEN]; /* Temporal Key (TK) */
+ u8 kck2[WPA_KCK_MAX_LEN]; /* FT reasoc Key Confirmation Key (KCK2) */
+ u8 kek2[WPA_KEK_MAX_LEN]; /* FT reassoc Key Encryption Key (KEK2) */
size_t kck_len;
size_t kek_len;
size_t tk_len;
+ size_t kck2_len;
+ size_t kek2_len;
int installed; /* 1 if key has already been installed to driver */
};
@@ -311,10 +316,19 @@
/* followed by optional parameters */
} STRUCT_PACKED;
+struct rsn_ftie_sha384 {
+ u8 mic_control[2];
+ u8 mic[24];
+ u8 anonce[WPA_NONCE_LEN];
+ u8 snonce[WPA_NONCE_LEN];
+ /* followed by optional parameters */
+} STRUCT_PACKED;
+
#define FTIE_SUBELEM_R1KH_ID 1
#define FTIE_SUBELEM_GTK 2
#define FTIE_SUBELEM_R0KH_ID 3
#define FTIE_SUBELEM_IGTK 4
+#define FTIE_SUBELEM_OCI 5
struct rsn_rdie {
u8 id;
@@ -333,7 +347,8 @@
int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
const u8 *addr1, const u8 *addr2,
const u8 *nonce1, const u8 *nonce2,
- struct wpa_ptk *ptk, int akmp, int cipher);
+ struct wpa_ptk *ptk, int akmp, int cipher,
+ const u8 *z, size_t z_len);
int fils_rmsk_to_pmk(int akmp, const u8 *rmsk, size_t rmsk_len,
const u8 *snonce, const u8 *anonce, const u8 *dh_ss,
size_t dh_ss_len, u8 *pmk, size_t *pmk_len);
@@ -361,14 +376,16 @@
int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
const u8 *ssid, size_t ssid_len,
const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
- const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name);
+ const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name,
+ int use_sha384);
int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
- const u8 *s1kh_id, u8 *pmk_r1_name);
-int wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
+ const u8 *s1kh_id, u8 *pmk_r1_name, int use_sha384);
+int wpa_derive_pmk_r1(const u8 *pmk_r0, size_t pmk_r0_len,
+ const u8 *pmk_r0_name,
const u8 *r1kh_id, const u8 *s1kh_id,
u8 *pmk_r1, u8 *pmk_r1_name);
-int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
- const u8 *sta_addr, const u8 *bssid,
+int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len, const u8 *snonce,
+ const u8 *anonce, const u8 *sta_addr, const u8 *bssid,
const u8 *pmk_r1_name,
struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher);
#endif /* CONFIG_IEEE80211R */
@@ -376,7 +393,9 @@
struct wpa_ie_data {
int proto;
int pairwise_cipher;
+ int has_pairwise;
int group_cipher;
+ int has_group;
int key_mgmt;
int capabilities;
size_t num_pmkid;
@@ -389,6 +408,7 @@
struct wpa_ie_data *data);
int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
struct wpa_ie_data *data);
+int wpa_default_rsn_cipher(int freq);
void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
u8 *pmkid, int akmp);
@@ -438,13 +458,18 @@
size_t tie_len;
const u8 *igtk;
size_t igtk_len;
+#ifdef CONFIG_OCV
+ const u8 *oci;
+ size_t oci_len;
+#endif /* CONFIG_OCV */
const u8 *ric;
size_t ric_len;
int key_mgmt;
int pairwise_cipher;
};
-int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse);
+int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
+ int use_sha384);
int wpa_cipher_key_len(int cipher);
int wpa_cipher_rsc_len(int cipher);
@@ -461,6 +486,9 @@
int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim);
int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise);
unsigned int wpa_mic_len(int akmp, size_t pmk_len);
+int wpa_use_akm_defined(int akmp);
+int wpa_use_cmac(int akmp);
+int wpa_use_aes_key_wrap(int akmp);
int fils_domain_name_hash(const char *domain, u8 *hash);
#endif /* WPA_COMMON_H */
diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c
index a0fe822..944b6e3 100644
--- a/src/common/wpa_ctrl.c
+++ b/src/common/wpa_ctrl.c
@@ -159,8 +159,8 @@
}
#ifdef ANDROID
- chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
/* Set group even if we do not have privileges to change owner */
+ chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
grp_wifi = getgrnam("wifi");
gid_wifi = grp_wifi ? grp_wifi->gr_gid : 0;
pwd_system = getpwnam("system");
@@ -558,7 +558,8 @@
res = recv(ctrl->s, reply, *reply_len, 0);
if (res < 0)
return res;
- if (res > 0 && reply[0] == '<') {
+ if ((res > 0 && reply[0] == '<') ||
+ (res > 6 && strncmp(reply, "IFNAME=", 7) == 0)) {
/* This is an unsolicited message from
* wpa_supplicant, not the reply to the
* request. Use msg_cb to report this to the
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index c59bc60..f65077e 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -50,10 +50,19 @@
#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR "
/** EAP status */
#define WPA_EVENT_EAP_STATUS "CTRL-EVENT-EAP-STATUS "
+/** Retransmit the previous request packet */
+#define WPA_EVENT_EAP_RETRANSMIT "CTRL-EVENT-EAP-RETRANSMIT "
+#define WPA_EVENT_EAP_RETRANSMIT2 "CTRL-EVENT-EAP-RETRANSMIT2 "
/** EAP authentication completed successfully */
#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
+#define WPA_EVENT_EAP_SUCCESS2 "CTRL-EVENT-EAP-SUCCESS2 "
/** EAP authentication failed (EAP-Failure received) */
#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
+#define WPA_EVENT_EAP_FAILURE2 "CTRL-EVENT-EAP-FAILURE2 "
+/** EAP authentication failed due to no response received */
+#define WPA_EVENT_EAP_TIMEOUT_FAILURE "CTRL-EVENT-EAP-TIMEOUT-FAILURE "
+#define WPA_EVENT_EAP_TIMEOUT_FAILURE2 "CTRL-EVENT-EAP-TIMEOUT-FAILURE2 "
+#define WPA_EVENT_EAP_ERROR_CODE "EAP-ERROR-CODE "
/** Network block temporarily disabled (e.g., due to authentication failure) */
#define WPA_EVENT_TEMP_DISABLED "CTRL-EVENT-SSID-TEMP-DISABLED "
/** Temporarily disabled network block re-enabled */
@@ -80,6 +89,9 @@
#define WPA_EVENT_REGDOM_CHANGE "CTRL-EVENT-REGDOM-CHANGE "
/** Channel switch (followed by freq=<MHz> and other channel parameters) */
#define WPA_EVENT_CHANNEL_SWITCH "CTRL-EVENT-CHANNEL-SWITCH "
+/** SAE authentication failed due to unknown password identifier */
+#define WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER \
+ "CTRL-EVENT-SAE-UNKNOWN-PASSWORD-IDENTIFIER "
/** IP subnet status change notification
*
@@ -145,12 +157,15 @@
/* DPP events */
#define DPP_EVENT_AUTH_SUCCESS "DPP-AUTH-SUCCESS "
+#define DPP_EVENT_AUTH_INIT_FAILED "DPP-AUTH-INIT-FAILED "
#define DPP_EVENT_NOT_COMPATIBLE "DPP-NOT-COMPATIBLE "
#define DPP_EVENT_RESPONSE_PENDING "DPP-RESPONSE-PENDING "
#define DPP_EVENT_SCAN_PEER_QR_CODE "DPP-SCAN-PEER-QR-CODE "
+#define DPP_EVENT_AUTH_DIRECTION "DPP-AUTH-DIRECTION "
#define DPP_EVENT_CONF_RECEIVED "DPP-CONF-RECEIVED "
#define DPP_EVENT_CONF_SENT "DPP-CONF-SENT "
#define DPP_EVENT_CONF_FAILED "DPP-CONF-FAILED "
+#define DPP_EVENT_CONFOBJ_AKM "DPP-CONFOBJ-AKM "
#define DPP_EVENT_CONFOBJ_SSID "DPP-CONFOBJ-SSID "
#define DPP_EVENT_CONFOBJ_PASS "DPP-CONFOBJ-PASS "
#define DPP_EVENT_CONFOBJ_PSK "DPP-CONFOBJ-PSK "
@@ -159,6 +174,13 @@
#define DPP_EVENT_NET_ACCESS_KEY "DPP-NET-ACCESS-KEY "
#define DPP_EVENT_MISSING_CONNECTOR "DPP-MISSING-CONNECTOR "
#define DPP_EVENT_NETWORK_ID "DPP-NETWORK-ID "
+#define DPP_EVENT_RX "DPP-RX "
+#define DPP_EVENT_TX "DPP-TX "
+#define DPP_EVENT_TX_STATUS "DPP-TX-STATUS "
+#define DPP_EVENT_FAIL "DPP-FAIL "
+#define DPP_EVENT_PKEX_T_LIMIT "DPP-PKEX-T-LIMIT "
+#define DPP_EVENT_INTRO "DPP-INTRO "
+#define DPP_EVENT_CONF_REQ_RX "DPP-CONF-REQ-RX "
/* MESH events */
#define MESH_GROUP_STARTED "MESH-GROUP-STARTED "
@@ -253,8 +275,12 @@
#define RX_HS20_ICON "RX-HS20-ICON "
#define RX_MBO_ANQP "RX-MBO-ANQP "
+/* parameters: <Venue Number> <Venue URL> */
+#define RX_VENUE_URL "RX-VENUE-URL "
+
#define HS20_SUBSCRIPTION_REMEDIATION "HS20-SUBSCRIPTION-REMEDIATION "
#define HS20_DEAUTH_IMMINENT_NOTICE "HS20-DEAUTH-IMMINENT-NOTICE "
+#define HS20_T_C_ACCEPTANCE "HS20-T-C-ACCEPTANCE "
#define EXT_RADIO_WORK_START "EXT-RADIO-WORK-START "
#define EXT_RADIO_WORK_TIMEOUT "EXT-RADIO-WORK-TIMEOUT "
@@ -278,6 +304,9 @@
#define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA "
#define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA "
+#define HS20_T_C_FILTERING_ADD "HS20-T-C-FILTERING-ADD "
+#define HS20_T_C_FILTERING_REMOVE "HS20-T-C-FILTERING-REMOVE "
+
#define AP_EVENT_ENABLED "AP-ENABLED "
#define AP_EVENT_DISABLED "AP-DISABLED "
@@ -303,6 +332,13 @@
/* BSS Transition Management Response frame received */
#define BSS_TM_RESP "BSS-TM-RESP "
+/* Collocated Interference Request frame received;
+ * parameters: <dialog token> <automatic report enabled> <report timeout> */
+#define COLOC_INTF_REQ "COLOC-INTF-REQ "
+/* Collocated Interference Report frame received;
+ * parameters: <STA address> <dialog token> <hexdump of report elements> */
+#define COLOC_INTF_REPORT "COLOC-INTF-REPORT "
+
/* MBO IE with cellular data connection preference received */
#define MBO_CELL_PREFERENCE "MBO-CELL-PREFERENCE "
@@ -323,6 +359,19 @@
*/
#define FILS_HLP_RX "FILS-HLP-RX "
+/* Event to indicate Probe Request frame;
+ * parameters: sa=<STA MAC address> signal=<signal> */
+#define RX_PROBE_REQUEST "RX-PROBE-REQUEST "
+
+/* Event to indicate station's HT/VHT operation mode change information */
+#define STA_OPMODE_MAX_BW_CHANGED "STA-OPMODE-MAX-BW-CHANGED "
+#define STA_OPMODE_SMPS_MODE_CHANGED "STA-OPMODE-SMPS-MODE-CHANGED "
+#define STA_OPMODE_N_SS_CHANGED "STA-OPMODE-N_SS-CHANGED "
+
+/* New interface addition or removal for 4addr WDS SDA */
+#define WDS_STA_INTERFACE_ADDED "WDS-STA-INTERFACE-ADDED "
+#define WDS_STA_INTERFACE_REMOVED "WDS-STA-INTERFACE-REMOVED "
+
/* BSS command information masks */
#define WPA_BSS_MASK_ALL 0xFFFDFFFF
@@ -424,7 +473,7 @@
*
* This function is used to send commands to wpa_supplicant/hostapd. Received
* response will be written to reply and reply_len is set to the actual length
- * of the reply. This function will block for up to two seconds while waiting
+ * of the reply. This function will block for up to 10 seconds while waiting
* for the reply. If unsolicited messages are received, the blocking time may
* be longer.
*
diff --git a/src/crypto/Makefile b/src/crypto/Makefile
index ee93e41..ab108da 100644
--- a/src/crypto/Makefile
+++ b/src/crypto/Makefile
@@ -62,7 +62,9 @@
LIB_OBJS += crypto_internal-rsa.o
LIB_OBJS += tls_internal.o
LIB_OBJS += fips_prf_internal.o
+ifndef TEST_FUZZ
LIB_OBJS += random.o
+endif
libcrypto.a: $(LIB_OBJS)
diff --git a/src/crypto/aes-internal-enc.c b/src/crypto/aes-internal-enc.c
index 9fdb4f3..baeffca 100644
--- a/src/crypto/aes-internal-enc.c
+++ b/src/crypto/aes-internal-enc.c
@@ -99,6 +99,10 @@
{
u32 *rk;
int res;
+
+ if (TEST_FAIL())
+ return NULL;
+
rk = os_malloc(AES_PRIV_SIZE);
if (rk == NULL)
return NULL;
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index a723201..12109ce 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -417,6 +417,14 @@
struct crypto_public_key *key, const u8 *crypt, size_t crypt_len,
u8 *plain, size_t *plain_len);
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey);
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *order, size_t order_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len);
+
/**
* crypto_global_init - Initialize crypto wrapper
*
@@ -529,6 +537,14 @@
u8 *buf, size_t buflen, size_t padlen);
/**
+ * crypto_bignum_rand - Create a random number in range of modulus
+ * @r: Bignum; set to a random value
+ * @m: Bignum; modulus
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m);
+
+/**
* crypto_bignum_add - c = a + b
* @a: Bignum
* @b: Bignum
@@ -610,6 +626,16 @@
struct crypto_bignum *d);
/**
+ * crypto_bignum_rshift - r = a >> n
+ * @a: Bignum
+ * @n: Number of bits
+ * @r: Bignum; used to store the result of a >> n
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
+ struct crypto_bignum *r);
+
+/**
* crypto_bignum_cmp - Compare two bignums
* @a: Bignum
* @b: Bignum
@@ -640,6 +666,13 @@
int crypto_bignum_is_one(const struct crypto_bignum *a);
/**
+ * crypto_bignum_is_odd - Is the given bignum odd
+ * @a: Bignum
+ * Returns: 1 if @a is odd or 0 if not
+ */
+int crypto_bignum_is_odd(const struct crypto_bignum *a);
+
+/**
* crypto_bignum_legendre - Compute the Legendre symbol (a/p)
* @a: Bignum
* @p: Bignum
@@ -685,6 +718,13 @@
size_t crypto_ec_prime_len_bits(struct crypto_ec *e);
/**
+ * crypto_ec_order_len - Get length of the order in octets
+ * @e: EC context from crypto_ec_init()
+ * Returns: Length of the order defining the group
+ */
+size_t crypto_ec_order_len(struct crypto_ec *e);
+
+/**
* crypto_ec_get_prime - Get prime defining an EC group
* @e: EC context from crypto_ec_init()
* Returns: Prime (bignum) defining the group
@@ -721,6 +761,16 @@
void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear);
/**
+ * crypto_ec_point_x - Copies the x-ordinate point into big number
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point data
+ * @x: Big number to set to the copy of x-ordinate
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p,
+ struct crypto_bignum *x);
+
+/**
* crypto_ec_point_to_bin - Write EC point value as binary data
* @e: EC context from crypto_ec_init()
* @p: EC point data from crypto_ec_point_init()
@@ -749,7 +799,7 @@
const u8 *val);
/**
- * crypto_bignum_add - c = a + b
+ * crypto_ec_point_add - c = a + b
* @e: EC context from crypto_ec_init()
* @a: Bignum
* @b: Bignum
@@ -761,7 +811,7 @@
struct crypto_ec_point *c);
/**
- * crypto_bignum_mul - res = b * p
+ * crypto_ec_point_mul - res = b * p
* @e: EC context from crypto_ec_init()
* @p: EC point
* @b: Bignum
diff --git a/src/crypto/crypto_gnutls.c b/src/crypto/crypto_gnutls.c
index 31a580e..4ef1146 100644
--- a/src/crypto/crypto_gnutls.c
+++ b/src/crypto/crypto_gnutls.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / wrapper functions for libgcrypt
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,26 +10,41 @@
#include <gcrypt.h>
#include "common.h"
+#include "md5.h"
+#include "sha1.h"
+#include "sha256.h"
+#include "sha384.h"
+#include "sha512.h"
#include "crypto.h"
-int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+static int gnutls_digest_vector(int algo, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
{
gcry_md_hd_t hd;
unsigned char *p;
size_t i;
- if (gcry_md_open(&hd, GCRY_MD_MD4, 0) != GPG_ERR_NO_ERROR)
+ if (TEST_FAIL())
+ return -1;
+
+ if (gcry_md_open(&hd, algo, 0) != GPG_ERR_NO_ERROR)
return -1;
for (i = 0; i < num_elem; i++)
gcry_md_write(hd, addr[i], len[i]);
- p = gcry_md_read(hd, GCRY_MD_MD4);
+ p = gcry_md_read(hd, algo);
if (p)
- memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD4));
+ memcpy(mac, p, gcry_md_get_algo_dlen(algo));
gcry_md_close(hd);
return 0;
}
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_digest_vector(GCRY_MD_MD4, num_elem, addr, len, mac);
+}
+
+
int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
gcry_cipher_hd_t hd;
@@ -55,44 +70,155 @@
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
- gcry_md_hd_t hd;
- unsigned char *p;
- size_t i;
-
- if (gcry_md_open(&hd, GCRY_MD_MD5, 0) != GPG_ERR_NO_ERROR)
- return -1;
- for (i = 0; i < num_elem; i++)
- gcry_md_write(hd, addr[i], len[i]);
- p = gcry_md_read(hd, GCRY_MD_MD5);
- if (p)
- memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD5));
- gcry_md_close(hd);
- return 0;
+ return gnutls_digest_vector(GCRY_MD_MD5, num_elem, addr, len, mac);
}
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
+ return gnutls_digest_vector(GCRY_MD_SHA1, num_elem, addr, len, mac);
+}
+
+
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_digest_vector(GCRY_MD_SHA256, num_elem, addr, len, mac);
+}
+
+
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_digest_vector(GCRY_MD_SHA384, num_elem, addr, len, mac);
+}
+
+
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_digest_vector(GCRY_MD_SHA512, num_elem, addr, len, mac);
+}
+
+
+static int gnutls_hmac_vector(int algo, const u8 *key, size_t key_len,
+ size_t num_elem, const u8 *addr[],
+ const size_t *len, u8 *mac)
+{
gcry_md_hd_t hd;
unsigned char *p;
size_t i;
- if (gcry_md_open(&hd, GCRY_MD_SHA1, 0) != GPG_ERR_NO_ERROR)
+ if (TEST_FAIL())
return -1;
+
+ if (gcry_md_open(&hd, algo, GCRY_MD_FLAG_HMAC) != GPG_ERR_NO_ERROR)
+ return -1;
+ if (gcry_md_setkey(hd, key, key_len) != GPG_ERR_NO_ERROR) {
+ gcry_md_close(hd);
+ return -1;
+ }
for (i = 0; i < num_elem; i++)
gcry_md_write(hd, addr[i], len[i]);
- p = gcry_md_read(hd, GCRY_MD_SHA1);
+ p = gcry_md_read(hd, algo);
if (p)
- memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_SHA1));
+ memcpy(mac, p, gcry_md_get_algo_dlen(algo));
gcry_md_close(hd);
return 0;
}
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_hmac_vector(GCRY_MD_MD5, key, key_len, num_elem, addr,
+ len, mac);
+}
+
+
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_hmac_vector(GCRY_MD_SHA1, key, key_len, num_elem, addr,
+ len, mac);
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+#ifdef CONFIG_SHA256
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_hmac_vector(GCRY_MD_SHA256, key, key_len, num_elem, addr,
+ len, mac);
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA256 */
+
+
+#ifdef CONFIG_SHA384
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_hmac_vector(GCRY_MD_SHA384, key, key_len, num_elem, addr,
+ len, mac);
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA384 */
+
+
+#ifdef CONFIG_SHA512
+
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return gnutls_hmac_vector(GCRY_MD_SHA512, key, key_len, num_elem, addr,
+ len, mac);
+}
+
+
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA512 */
+
+
void * aes_encrypt_init(const u8 *key, size_t len)
{
gcry_cipher_hd_t hd;
+ if (TEST_FAIL())
+ return NULL;
+
if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
GPG_ERR_NO_ERROR) {
printf("cipher open failed\n");
@@ -127,6 +253,9 @@
{
gcry_cipher_hd_t hd;
+ if (TEST_FAIL())
+ return NULL;
+
if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
GPG_ERR_NO_ERROR)
return NULL;
@@ -154,6 +283,81 @@
}
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey)
+{
+ size_t pubkey_len, pad;
+
+ if (os_get_random(privkey, prime_len) < 0)
+ return -1;
+ if (os_memcmp(privkey, prime, prime_len) > 0) {
+ /* Make sure private value is smaller than prime */
+ privkey[0] = 0;
+ }
+
+ pubkey_len = prime_len;
+ if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
+ pubkey, &pubkey_len) < 0)
+ return -1;
+ if (pubkey_len < prime_len) {
+ pad = prime_len - pubkey_len;
+ os_memmove(pubkey + pad, pubkey, pubkey_len);
+ os_memset(pubkey, 0, pad);
+ }
+
+ return 0;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *order, size_t order_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len)
+{
+ gcry_mpi_t pub = NULL;
+ int res = -1;
+
+ if (pubkey_len > prime_len ||
+ (pubkey_len == prime_len &&
+ os_memcmp(pubkey, prime, prime_len) >= 0))
+ return -1;
+
+ if (gcry_mpi_scan(&pub, GCRYMPI_FMT_USG, pubkey, pubkey_len, NULL) !=
+ GPG_ERR_NO_ERROR ||
+ gcry_mpi_cmp_ui(pub, 1) <= 0)
+ goto fail;
+
+ if (order) {
+ gcry_mpi_t p = NULL, q = NULL, tmp;
+ int failed;
+
+ /* verify: pubkey^q == 1 mod p */
+ tmp = gcry_mpi_new(prime_len * 8);
+ failed = !tmp ||
+ gcry_mpi_scan(&p, GCRYMPI_FMT_USG, prime, prime_len,
+ NULL) != GPG_ERR_NO_ERROR ||
+ gcry_mpi_scan(&q, GCRYMPI_FMT_USG, order, order_len,
+ NULL) != GPG_ERR_NO_ERROR;
+ if (!failed) {
+ gcry_mpi_powm(tmp, pub, q, p);
+ failed = gcry_mpi_cmp_ui(tmp, 1) != 0;
+ }
+ gcry_mpi_release(p);
+ gcry_mpi_release(q);
+ gcry_mpi_release(tmp);
+ if (failed)
+ goto fail;
+ }
+
+ res = crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
+ prime, prime_len, secret, len);
+fail:
+ gcry_mpi_release(pub);
+ return res;
+}
+
+
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
diff --git a/src/crypto/crypto_internal-modexp.c b/src/crypto/crypto_internal-modexp.c
index 9dcabb9..6819f1a 100644
--- a/src/crypto/crypto_internal-modexp.c
+++ b/src/crypto/crypto_internal-modexp.c
@@ -13,6 +13,79 @@
#include "crypto.h"
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey)
+{
+ size_t pubkey_len, pad;
+
+ if (os_get_random(privkey, prime_len) < 0)
+ return -1;
+ if (os_memcmp(privkey, prime, prime_len) > 0) {
+ /* Make sure private value is smaller than prime */
+ privkey[0] = 0;
+ }
+
+ pubkey_len = prime_len;
+ if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
+ pubkey, &pubkey_len) < 0)
+ return -1;
+ if (pubkey_len < prime_len) {
+ pad = prime_len - pubkey_len;
+ os_memmove(pubkey + pad, pubkey, pubkey_len);
+ os_memset(pubkey, 0, pad);
+ }
+
+ return 0;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *order, size_t order_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len)
+{
+ struct bignum *pub;
+ int res = -1;
+
+ if (pubkey_len > prime_len ||
+ (pubkey_len == prime_len &&
+ os_memcmp(pubkey, prime, prime_len) >= 0))
+ return -1;
+
+ pub = bignum_init();
+ if (!pub || bignum_set_unsigned_bin(pub, pubkey, pubkey_len) < 0 ||
+ bignum_cmp_d(pub, 1) <= 0)
+ goto fail;
+
+ if (order) {
+ struct bignum *p, *q, *tmp;
+ int failed;
+
+ /* verify: pubkey^q == 1 mod p */
+ p = bignum_init();
+ q = bignum_init();
+ tmp = bignum_init();
+ failed = !p || !q || !tmp ||
+ bignum_set_unsigned_bin(p, prime, prime_len) < 0 ||
+ bignum_set_unsigned_bin(q, order, order_len) < 0 ||
+ bignum_exptmod(pub, q, p, tmp) < 0 ||
+ bignum_cmp_d(tmp, 1) != 0;
+ bignum_deinit(p);
+ bignum_deinit(q);
+ bignum_deinit(tmp);
+ if (failed)
+ goto fail;
+ }
+
+ res = crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
+ prime, prime_len, secret, len);
+fail:
+ bignum_deinit(pub);
+ return res;
+}
+
+
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
diff --git a/src/crypto/crypto_internal.c b/src/crypto/crypto_internal.c
index d391f48..aad40af 100644
--- a/src/crypto/crypto_internal.c
+++ b/src/crypto/crypto_internal.c
@@ -310,6 +310,9 @@
os_free(ctx);
+ if (TEST_FAIL())
+ return -1;
+
return 0;
}
diff --git a/src/crypto/crypto_libtomcrypt.c b/src/crypto/crypto_libtomcrypt.c
index b80ad57..ed30efa 100644
--- a/src/crypto/crypto_libtomcrypt.c
+++ b/src/crypto/crypto_libtomcrypt.c
@@ -278,6 +278,9 @@
os_free(ctx);
+ if (TEST_FAIL())
+ return -1;
+
return ret;
}
@@ -694,6 +697,44 @@
#ifdef CONFIG_MODEXP
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey)
+{
+ size_t pubkey_len, pad;
+
+ if (os_get_random(privkey, prime_len) < 0)
+ return -1;
+ if (os_memcmp(privkey, prime, prime_len) > 0) {
+ /* Make sure private value is smaller than prime */
+ privkey[0] = 0;
+ }
+
+ pubkey_len = prime_len;
+ if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
+ pubkey, &pubkey_len) < 0)
+ return -1;
+ if (pubkey_len < prime_len) {
+ pad = prime_len - pubkey_len;
+ os_memmove(pubkey + pad, pubkey, pubkey_len);
+ os_memset(pubkey, 0, pad);
+ }
+
+ return 0;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *order, size_t order_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len)
+{
+ /* TODO: check pubkey */
+ return crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
+ prime, prime_len, secret, len);
+}
+
+
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
diff --git a/src/crypto/crypto_linux.c b/src/crypto/crypto_linux.c
index 8099193..1724456 100644
--- a/src/crypto/crypto_linux.c
+++ b/src/crypto/crypto_linux.c
@@ -386,6 +386,9 @@
}
crypto_hash_deinit(ctx);
+
+ if (TEST_FAIL())
+ return -1;
return 0;
}
diff --git a/src/crypto/crypto_nettle.c b/src/crypto/crypto_nettle.c
new file mode 100644
index 0000000..f85d365
--- /dev/null
+++ b/src/crypto/crypto_nettle.c
@@ -0,0 +1,469 @@
+/*
+ * Wrapper functions for libnettle and libgmp
+ * Copyright (c) 2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <nettle/nettle-meta.h>
+#include <nettle/des.h>
+#undef des_encrypt
+#include <nettle/hmac.h>
+#include <nettle/aes.h>
+#undef aes_encrypt
+#undef aes_decrypt
+#include <nettle/arcfour.h>
+#include <nettle/bignum.h>
+
+#include "common.h"
+#include "md5.h"
+#include "sha1.h"
+#include "sha256.h"
+#include "sha384.h"
+#include "sha512.h"
+#include "crypto.h"
+
+
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+ struct des_ctx ctx;
+ u8 pkey[8], next, tmp;
+ int i;
+
+ /* Add parity bits to the key */
+ next = 0;
+ for (i = 0; i < 7; i++) {
+ tmp = key[i];
+ pkey[i] = (tmp >> i) | next | 1;
+ next = tmp << (7 - i);
+ }
+ pkey[i] = next | 1;
+
+ nettle_des_set_key(&ctx, pkey);
+ nettle_des_encrypt(&ctx, DES_BLOCK_SIZE, cypher, clear);
+ os_memset(&ctx, 0, sizeof(ctx));
+ return 0;
+}
+
+
+static int nettle_digest_vector(const struct nettle_hash *alg, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ void *ctx;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ctx = os_malloc(alg->context_size);
+ if (!ctx)
+ return -1;
+ alg->init(ctx);
+ for (i = 0; i < num_elem; i++)
+ alg->update(ctx, len[i], addr[i]);
+ alg->digest(ctx, alg->digest_size, mac);
+ bin_clear_free(ctx, alg->context_size);
+ return 0;
+}
+
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return nettle_digest_vector(&nettle_md4, num_elem, addr, len, mac);
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return nettle_digest_vector(&nettle_md5, num_elem, addr, len, mac);
+}
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return nettle_digest_vector(&nettle_sha1, num_elem, addr, len, mac);
+}
+
+
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return nettle_digest_vector(&nettle_sha256, num_elem, addr, len, mac);
+}
+
+
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return nettle_digest_vector(&nettle_sha384, num_elem, addr, len, mac);
+}
+
+
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return nettle_digest_vector(&nettle_sha512, num_elem, addr, len, mac);
+}
+
+
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ struct hmac_md5_ctx ctx;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ hmac_md5_set_key(&ctx, key_len, key);
+ for (i = 0; i < num_elem; i++)
+ hmac_md5_update(&ctx, len[i], addr[i]);
+ hmac_md5_digest(&ctx, MD5_DIGEST_SIZE, mac);
+ os_memset(&ctx, 0, sizeof(ctx));
+ return 0;
+}
+
+
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ struct hmac_sha1_ctx ctx;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ hmac_sha1_set_key(&ctx, key_len, key);
+ for (i = 0; i < num_elem; i++)
+ hmac_sha1_update(&ctx, len[i], addr[i]);
+ hmac_sha1_digest(&ctx, SHA1_DIGEST_SIZE, mac);
+ os_memset(&ctx, 0, sizeof(ctx));
+ return 0;
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+#ifdef CONFIG_SHA256
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ struct hmac_sha256_ctx ctx;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ hmac_sha256_set_key(&ctx, key_len, key);
+ for (i = 0; i < num_elem; i++)
+ hmac_sha256_update(&ctx, len[i], addr[i]);
+ hmac_sha256_digest(&ctx, SHA256_DIGEST_SIZE, mac);
+ os_memset(&ctx, 0, sizeof(ctx));
+ return 0;
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA256 */
+
+
+#ifdef CONFIG_SHA384
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ struct hmac_sha384_ctx ctx;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ hmac_sha384_set_key(&ctx, key_len, key);
+ for (i = 0; i < num_elem; i++)
+ hmac_sha384_update(&ctx, len[i], addr[i]);
+ hmac_sha384_digest(&ctx, SHA384_DIGEST_SIZE, mac);
+ os_memset(&ctx, 0, sizeof(ctx));
+ return 0;
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA384 */
+
+
+#ifdef CONFIG_SHA512
+
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ struct hmac_sha512_ctx ctx;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ hmac_sha512_set_key(&ctx, key_len, key);
+ for (i = 0; i < num_elem; i++)
+ hmac_sha512_update(&ctx, len[i], addr[i]);
+ hmac_sha512_digest(&ctx, SHA512_DIGEST_SIZE, mac);
+ os_memset(&ctx, 0, sizeof(ctx));
+ return 0;
+}
+
+
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA512 */
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+ struct aes_ctx *ctx;
+
+ if (TEST_FAIL())
+ return NULL;
+ ctx = os_malloc(sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+
+ nettle_aes_set_encrypt_key(ctx, len, key);
+
+ return ctx;
+}
+
+
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+ struct aes_ctx *actx = ctx;
+ nettle_aes_encrypt(actx, AES_BLOCK_SIZE, crypt, plain);
+ return 0;
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+ struct aes_ctx *actx = ctx;
+ bin_clear_free(actx, sizeof(*actx));
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+ struct aes_ctx *ctx;
+
+ if (TEST_FAIL())
+ return NULL;
+ ctx = os_malloc(sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+
+ nettle_aes_set_decrypt_key(ctx, len, key);
+
+ return ctx;
+}
+
+
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+ struct aes_ctx *actx = ctx;
+ nettle_aes_decrypt(actx, AES_BLOCK_SIZE, plain, crypt);
+ return 0;
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+ struct aes_ctx *actx = ctx;
+ bin_clear_free(actx, sizeof(*actx));
+}
+
+
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey)
+{
+ size_t pubkey_len, pad;
+
+ if (os_get_random(privkey, prime_len) < 0)
+ return -1;
+ if (os_memcmp(privkey, prime, prime_len) > 0) {
+ /* Make sure private value is smaller than prime */
+ privkey[0] = 0;
+ }
+
+ pubkey_len = prime_len;
+ if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
+ pubkey, &pubkey_len) < 0)
+ return -1;
+ if (pubkey_len < prime_len) {
+ pad = prime_len - pubkey_len;
+ os_memmove(pubkey + pad, pubkey, pubkey_len);
+ os_memset(pubkey, 0, pad);
+ }
+
+ return 0;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *order, size_t order_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len)
+{
+ mpz_t pub;
+ int res = -1;
+
+ if (pubkey_len > prime_len ||
+ (pubkey_len == prime_len &&
+ os_memcmp(pubkey, prime, prime_len) >= 0))
+ return -1;
+
+ mpz_init(pub);
+ mpz_import(pub, pubkey_len, 1, 1, 1, 0, pubkey);
+ if (mpz_cmp_d(pub, 1) <= 0)
+ goto fail;
+
+ if (order) {
+ mpz_t p, q, tmp;
+ int failed;
+
+ /* verify: pubkey^q == 1 mod p */
+ mpz_inits(p, q, tmp, NULL);
+ mpz_import(p, prime_len, 1, 1, 1, 0, prime);
+ mpz_import(q, order_len, 1, 1, 1, 0, order);
+ mpz_powm(tmp, pub, q, p);
+ failed = mpz_cmp_d(tmp, 1) != 0;
+ mpz_clears(p, q, tmp, NULL);
+ if (failed)
+ goto fail;
+ }
+
+ res = crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
+ prime, prime_len, secret, len);
+fail:
+ mpz_clear(pub);
+ return res;
+}
+
+
+int crypto_mod_exp(const u8 *base, size_t base_len,
+ const u8 *power, size_t power_len,
+ const u8 *modulus, size_t modulus_len,
+ u8 *result, size_t *result_len)
+{
+ mpz_t bn_base, bn_exp, bn_modulus, bn_result;
+ int ret = -1;
+ size_t len;
+
+ mpz_inits(bn_base, bn_exp, bn_modulus, bn_result, NULL);
+ mpz_import(bn_base, base_len, 1, 1, 1, 0, base);
+ mpz_import(bn_exp, power_len, 1, 1, 1, 0, power);
+ mpz_import(bn_modulus, modulus_len, 1, 1, 1, 0, modulus);
+
+ mpz_powm(bn_result, bn_base, bn_exp, bn_modulus);
+ len = mpz_sizeinbase(bn_result, 2);
+ len = (len + 7) / 8;
+ if (*result_len < len)
+ goto error;
+ mpz_export(result, result_len, 1, 1, 1, 0, bn_result);
+ ret = 0;
+
+error:
+ mpz_clears(bn_base, bn_exp, bn_modulus, bn_result, NULL);
+ return ret;
+}
+
+
+struct crypto_cipher {
+ enum crypto_cipher_alg alg;
+ union {
+ struct arcfour_ctx arcfour_ctx;
+ } u;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+ const u8 *iv, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_cipher *ctx;
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+
+ ctx->alg = alg;
+
+ switch (alg) {
+ case CRYPTO_CIPHER_ALG_RC4:
+ nettle_arcfour_set_key(&ctx->u.arcfour_ctx, key_len, key);
+ break;
+ default:
+ os_free(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+ u8 *crypt, size_t len)
+{
+ switch (ctx->alg) {
+ case CRYPTO_CIPHER_ALG_RC4:
+ nettle_arcfour_crypt(&ctx->u.arcfour_ctx, len, crypt, plain);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+ u8 *plain, size_t len)
+{
+ switch (ctx->alg) {
+ case CRYPTO_CIPHER_ALG_RC4:
+ nettle_arcfour_crypt(&ctx->u.arcfour_ctx, len, plain, crypt);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+ bin_clear_free(ctx, sizeof(*ctx));
+}
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 6bff202..1b0c1ec 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -24,16 +24,20 @@
#endif /* CONFIG_ECC */
#include "common.h"
+#include "utils/const_time.h"
#include "wpabuf.h"
#include "dh_group5.h"
#include "sha1.h"
#include "sha256.h"
#include "sha384.h"
+#include "sha512.h"
#include "md5.h"
#include "aes_wrap.h"
#include "crypto.h"
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
/* Compatibility wrappers for older versions. */
static HMAC_CTX * HMAC_CTX_new(void)
@@ -79,7 +83,9 @@
static BIGNUM * get_group5_prime(void)
{
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
+ !(defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
return BN_get_rfc3526_prime_1536(NULL);
#elif !defined(OPENSSL_IS_BORINGSSL)
return get_rfc3526_prime_1536(NULL);
@@ -106,6 +112,31 @@
#endif
}
+
+static BIGNUM * get_group5_order(void)
+{
+ static const unsigned char RFC3526_ORDER_1536[] = {
+ 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE4,0x87,0xED,0x51,
+ 0x10,0xB4,0x61,0x1A,0x62,0x63,0x31,0x45,0xC0,0x6E,0x0E,0x68,
+ 0x94,0x81,0x27,0x04,0x45,0x33,0xE6,0x3A,0x01,0x05,0xDF,0x53,
+ 0x1D,0x89,0xCD,0x91,0x28,0xA5,0x04,0x3C,0xC7,0x1A,0x02,0x6E,
+ 0xF7,0xCA,0x8C,0xD9,0xE6,0x9D,0x21,0x8D,0x98,0x15,0x85,0x36,
+ 0xF9,0x2F,0x8A,0x1B,0xA7,0xF0,0x9A,0xB6,0xB6,0xA8,0xE1,0x22,
+ 0xF2,0x42,0xDA,0xBB,0x31,0x2F,0x3F,0x63,0x7A,0x26,0x21,0x74,
+ 0xD3,0x1B,0xF6,0xB5,0x85,0xFF,0xAE,0x5B,0x7A,0x03,0x5B,0xF6,
+ 0xF7,0x1C,0x35,0xFD,0xAD,0x44,0xCF,0xD2,0xD7,0x4F,0x92,0x08,
+ 0xBE,0x25,0x8F,0xF3,0x24,0x94,0x33,0x28,0xF6,0x72,0x2D,0x9E,
+ 0xE1,0x00,0x3E,0x5C,0x50,0xB1,0xDF,0x82,0xCC,0x6D,0x24,0x1B,
+ 0x0E,0x2A,0xE9,0xCD,0x34,0x8B,0x1F,0xD4,0x7E,0x92,0x67,0xAF,
+ 0xC1,0xB2,0xAE,0x91,0xEE,0x51,0xD6,0xCB,0x0E,0x31,0x79,0xAB,
+ 0x10,0x42,0xA9,0x5D,0xCF,0x6A,0x94,0x83,0xB8,0x4B,0x4B,0x36,
+ 0xB3,0x86,0x1A,0xA7,0x25,0x5E,0x4C,0x02,0x78,0xBA,0x36,0x04,
+ 0x65,0x11,0xB9,0x93,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
+ };
+ return BN_bin2bn(RFC3526_ORDER_1536, sizeof(RFC3526_ORDER_1536), NULL);
+}
+
+
#ifdef OPENSSL_NO_SHA256
#define NO_SHA256_WRAPPER
#endif
@@ -270,10 +301,8 @@
switch (keylen) {
case 16:
return EVP_aes_128_ecb();
-#ifndef OPENSSL_IS_BORINGSSL
case 24:
return EVP_aes_192_ecb();
-#endif /* OPENSSL_IS_BORINGSSL */
case 32:
return EVP_aes_256_ecb();
}
@@ -291,8 +320,11 @@
return NULL;
type = aes_get_evp_cipher(len);
- if (type == NULL)
+ if (!type) {
+ wpa_printf(MSG_INFO, "%s: Unsupported len=%u",
+ __func__, (unsigned int) len);
return NULL;
+ }
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL)
@@ -345,8 +377,11 @@
return NULL;
type = aes_get_evp_cipher(len);
- if (type == NULL)
+ if (!type) {
+ wpa_printf(MSG_INFO, "%s: Unsupported len=%u",
+ __func__, (unsigned int) len);
return NULL;
+ }
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL)
@@ -482,6 +517,75 @@
}
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey)
+{
+ size_t pubkey_len, pad;
+
+ if (os_get_random(privkey, prime_len) < 0)
+ return -1;
+ if (os_memcmp(privkey, prime, prime_len) > 0) {
+ /* Make sure private value is smaller than prime */
+ privkey[0] = 0;
+ }
+
+ pubkey_len = prime_len;
+ if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
+ pubkey, &pubkey_len) < 0)
+ return -1;
+ if (pubkey_len < prime_len) {
+ pad = prime_len - pubkey_len;
+ os_memmove(pubkey + pad, pubkey, pubkey_len);
+ os_memset(pubkey, 0, pad);
+ }
+
+ return 0;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *order, size_t order_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len)
+{
+ BIGNUM *pub, *p;
+ int res = -1;
+
+ pub = BN_bin2bn(pubkey, pubkey_len, NULL);
+ p = BN_bin2bn(prime, prime_len, NULL);
+ if (!pub || !p || BN_is_zero(pub) || BN_is_one(pub) ||
+ BN_cmp(pub, p) >= 0)
+ goto fail;
+
+ if (order) {
+ BN_CTX *ctx;
+ BIGNUM *q, *tmp;
+ int failed;
+
+ /* verify: pubkey^q == 1 mod p */
+ q = BN_bin2bn(order, order_len, NULL);
+ ctx = BN_CTX_new();
+ tmp = BN_new();
+ failed = !q || !ctx || !tmp ||
+ !BN_mod_exp(tmp, pub, q, p, ctx) ||
+ !BN_is_one(tmp);
+ BN_clear(q);
+ BN_clear(tmp);
+ BN_CTX_free(ctx);
+ if (failed)
+ goto fail;
+ }
+
+ res = crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
+ prime, prime_len, secret, len);
+fail:
+ BN_clear(pub);
+ BN_clear(p);
+ return res;
+}
+
+
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
@@ -504,7 +608,8 @@
bn_result == NULL)
goto error;
- if (BN_mod_exp(bn_result, bn_base, bn_exp, bn_modulus, ctx) != 1)
+ if (BN_mod_exp_mont_consttime(bn_result, bn_base, bn_exp, bn_modulus,
+ ctx, NULL) != 1)
goto error;
*result_len = BN_bn2bin(bn_result, result);
@@ -641,7 +746,9 @@
void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
{
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
DH *dh;
struct wpabuf *pubkey = NULL, *privkey = NULL;
size_t publen, privlen;
@@ -662,6 +769,10 @@
if (dh->p == NULL)
goto err;
+ dh->q = get_group5_order();
+ if (!dh->q)
+ goto err;
+
if (DH_generate_key(dh) != 1)
goto err;
@@ -690,7 +801,7 @@
DH *dh;
struct wpabuf *pubkey = NULL, *privkey = NULL;
size_t publen, privlen;
- BIGNUM *p = NULL, *g;
+ BIGNUM *p, *g, *q;
const BIGNUM *priv_key = NULL, *pub_key = NULL;
*priv = NULL;
@@ -703,10 +814,12 @@
g = BN_new();
p = get_group5_prime();
- if (!g || BN_set_word(g, 2) != 1 || !p ||
- DH_set0_pqg(dh, p, NULL, g) != 1)
+ q = get_group5_order();
+ if (!g || BN_set_word(g, 2) != 1 || !p || !q ||
+ DH_set0_pqg(dh, p, q, g) != 1)
goto err;
p = NULL;
+ q = NULL;
g = NULL;
if (DH_generate_key(dh) != 1)
@@ -731,6 +844,7 @@
err:
BN_free(p);
+ BN_free(q);
BN_free(g);
wpabuf_clear_free(pubkey);
wpabuf_clear_free(privkey);
@@ -742,7 +856,9 @@
void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
{
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
DH *dh;
dh = DH_new();
@@ -938,6 +1054,9 @@
HMAC_CTX_free(ctx->ctx);
bin_clear_free(ctx, sizeof(*ctx));
+ if (TEST_FAIL())
+ return -1;
+
if (res == 1) {
*len = mdlen;
return 0;
@@ -1199,6 +1318,14 @@
}
+int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m)
+{
+ if (TEST_FAIL())
+ return -1;
+ return BN_rand_range((BIGNUM *) r, (const BIGNUM *) m) == 1 ? 0 : -1;
+}
+
+
int crypto_bignum_add(const struct crypto_bignum *a,
const struct crypto_bignum *b,
struct crypto_bignum *c)
@@ -1240,8 +1367,9 @@
bnctx = BN_CTX_new();
if (bnctx == NULL)
return -1;
- res = BN_mod_exp((BIGNUM *) d, (const BIGNUM *) a, (const BIGNUM *) b,
- (const BIGNUM *) c, bnctx);
+ res = BN_mod_exp_mont_consttime((BIGNUM *) d, (const BIGNUM *) a,
+ (const BIGNUM *) b, (const BIGNUM *) c,
+ bnctx, NULL);
BN_CTX_free(bnctx);
return res ? 0 : -1;
@@ -1260,6 +1388,11 @@
bnctx = BN_CTX_new();
if (bnctx == NULL)
return -1;
+#ifdef OPENSSL_IS_BORINGSSL
+ /* TODO: use BN_mod_inverse_blinded() ? */
+#else /* OPENSSL_IS_BORINGSSL */
+ BN_set_flags((BIGNUM *) a, BN_FLG_CONSTTIME);
+#endif /* OPENSSL_IS_BORINGSSL */
res = BN_mod_inverse((BIGNUM *) c, (const BIGNUM *) a,
(const BIGNUM *) b, bnctx);
BN_CTX_free(bnctx);
@@ -1293,6 +1426,9 @@
bnctx = BN_CTX_new();
if (bnctx == NULL)
return -1;
+#ifndef OPENSSL_IS_BORINGSSL
+ BN_set_flags((BIGNUM *) a, BN_FLG_CONSTTIME);
+#endif /* OPENSSL_IS_BORINGSSL */
res = BN_div((BIGNUM *) c, NULL, (const BIGNUM *) a,
(const BIGNUM *) b, bnctx);
BN_CTX_free(bnctx);
@@ -1324,6 +1460,15 @@
}
+int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
+ struct crypto_bignum *r)
+{
+ /* Note: BN_rshift() does not modify the first argument even though it
+ * has not been marked const. */
+ return BN_rshift((BIGNUM *) a, (BIGNUM *) r, n) == 1 ? 0 : -1;
+}
+
+
int crypto_bignum_cmp(const struct crypto_bignum *a,
const struct crypto_bignum *b)
{
@@ -1349,12 +1494,19 @@
}
+int crypto_bignum_is_odd(const struct crypto_bignum *a)
+{
+ return BN_is_odd((const BIGNUM *) a);
+}
+
+
int crypto_bignum_legendre(const struct crypto_bignum *a,
const struct crypto_bignum *p)
{
BN_CTX *bnctx;
BIGNUM *exp = NULL, *tmp = NULL;
int res = -2;
+ unsigned int mask;
if (TEST_FAIL())
return -2;
@@ -1369,16 +1521,17 @@
/* exp = (p-1) / 2 */
!BN_sub(exp, (const BIGNUM *) p, BN_value_one()) ||
!BN_rshift1(exp, exp) ||
- !BN_mod_exp(tmp, (const BIGNUM *) a, exp, (const BIGNUM *) p,
- bnctx))
+ !BN_mod_exp_mont_consttime(tmp, (const BIGNUM *) a, exp,
+ (const BIGNUM *) p, bnctx, NULL))
goto fail;
- if (BN_is_word(tmp, 1))
- res = 1;
- else if (BN_is_zero(tmp))
- res = 0;
- else
- res = -1;
+ /* Return 1 if tmp == 1, 0 if tmp == 0, or -1 otherwise. Need to use
+ * constant time selection to avoid branches here. */
+ res = -1;
+ mask = const_time_eq(BN_is_word(tmp, 1), 1);
+ res = const_time_select_int(mask, 1, res);
+ mask = const_time_eq(BN_is_zero(tmp), 1);
+ res = const_time_select_int(mask, 0, res);
fail:
BN_clear_free(tmp);
@@ -1505,6 +1658,12 @@
}
+size_t crypto_ec_order_len(struct crypto_ec *e)
+{
+ return BN_num_bytes(e->order);
+}
+
+
const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e)
{
return (const struct crypto_bignum *) e->prime;
@@ -1526,6 +1685,16 @@
}
+int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p,
+ struct crypto_bignum *x)
+{
+ return EC_POINT_get_affine_coordinates_GFp(e->group,
+ (const EC_POINT *) p,
+ (BIGNUM *) x, NULL,
+ e->bnctx) == 1 ? 0 : -1;
+}
+
+
int crypto_ec_point_to_bin(struct crypto_ec *e,
const struct crypto_ec_point *point, u8 *x, u8 *y)
{
@@ -1701,7 +1870,7 @@
{
struct crypto_ecdh *ecdh;
EVP_PKEY *params = NULL;
- EVP_PKEY_CTX *pctx = NULL;
+ EC_KEY *ec_params;
EVP_PKEY_CTX *kctx = NULL;
ecdh = os_zalloc(sizeof(*ecdh));
@@ -1712,27 +1881,17 @@
if (!ecdh->ec)
goto fail;
- pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
- if (!pctx)
- goto fail;
-
- if (EVP_PKEY_paramgen_init(pctx) != 1) {
+ ec_params = EC_KEY_new_by_curve_name(ecdh->ec->nid);
+ if (!ec_params) {
wpa_printf(MSG_ERROR,
- "OpenSSL: EVP_PKEY_paramgen_init failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ "OpenSSL: Failed to generate EC_KEY parameters");
goto fail;
}
-
- if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, ecdh->ec->nid) != 1) {
+ EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE);
+ params = EVP_PKEY_new();
+ if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) {
wpa_printf(MSG_ERROR,
- "OpenSSL: EVP_PKEY_CTX_set_ec_paramgen_curve_nid failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
-
- if (EVP_PKEY_paramgen(pctx, ¶ms) != 1) {
- wpa_printf(MSG_ERROR, "OpenSSL: EVP_PKEY_paramgen failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ "OpenSSL: Failed to generate EVP_PKEY parameters");
goto fail;
}
@@ -1755,7 +1914,6 @@
done:
EVP_PKEY_free(params);
- EVP_PKEY_CTX_free(pctx);
EVP_PKEY_CTX_free(kctx);
return ecdh;
diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c
new file mode 100644
index 0000000..976a008
--- /dev/null
+++ b/src/crypto/crypto_wolfssl.c
@@ -0,0 +1,1786 @@
+/*
+ * Wrapper functions for libwolfssl
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+
+/* wolfSSL headers */
+#include <wolfssl/options.h>
+#include <wolfssl/wolfcrypt/md4.h>
+#include <wolfssl/wolfcrypt/md5.h>
+#include <wolfssl/wolfcrypt/sha.h>
+#include <wolfssl/wolfcrypt/sha256.h>
+#include <wolfssl/wolfcrypt/sha512.h>
+#include <wolfssl/wolfcrypt/hmac.h>
+#include <wolfssl/wolfcrypt/pwdbased.h>
+#include <wolfssl/wolfcrypt/arc4.h>
+#include <wolfssl/wolfcrypt/des3.h>
+#include <wolfssl/wolfcrypt/aes.h>
+#include <wolfssl/wolfcrypt/dh.h>
+#include <wolfssl/wolfcrypt/cmac.h>
+#include <wolfssl/wolfcrypt/ecc.h>
+#include <wolfssl/openssl/bn.h>
+
+
+#ifndef CONFIG_FIPS
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ Md4 md4;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ wc_InitMd4(&md4);
+
+ for (i = 0; i < num_elem; i++)
+ wc_Md4Update(&md4, addr[i], len[i]);
+
+ wc_Md4Final(&md4, mac);
+
+ return 0;
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ wc_Md5 md5;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ wc_InitMd5(&md5);
+
+ for (i = 0; i < num_elem; i++)
+ wc_Md5Update(&md5, addr[i], len[i]);
+
+ wc_Md5Final(&md5, mac);
+
+ return 0;
+}
+
+#endif /* CONFIG_FIPS */
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ wc_Sha sha;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ wc_InitSha(&sha);
+
+ for (i = 0; i < num_elem; i++)
+ wc_ShaUpdate(&sha, addr[i], len[i]);
+
+ wc_ShaFinal(&sha, mac);
+
+ return 0;
+}
+
+
+#ifndef NO_SHA256_WRAPPER
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ wc_Sha256 sha256;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ wc_InitSha256(&sha256);
+
+ for (i = 0; i < num_elem; i++)
+ wc_Sha256Update(&sha256, addr[i], len[i]);
+
+ wc_Sha256Final(&sha256, mac);
+
+ return 0;
+}
+#endif /* NO_SHA256_WRAPPER */
+
+
+#ifdef CONFIG_SHA384
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ wc_Sha384 sha384;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ wc_InitSha384(&sha384);
+
+ for (i = 0; i < num_elem; i++)
+ wc_Sha384Update(&sha384, addr[i], len[i]);
+
+ wc_Sha384Final(&sha384, mac);
+
+ return 0;
+}
+#endif /* CONFIG_SHA384 */
+
+
+#ifdef CONFIG_SHA512
+int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ wc_Sha512 sha512;
+ size_t i;
+
+ if (TEST_FAIL())
+ return -1;
+
+ wc_InitSha512(&sha512);
+
+ for (i = 0; i < num_elem; i++)
+ wc_Sha512Update(&sha512, addr[i], len[i]);
+
+ wc_Sha512Final(&sha512, mac);
+
+ return 0;
+}
+#endif /* CONFIG_SHA512 */
+
+
+static int wolfssl_hmac_vector(int type, const u8 *key,
+ size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac,
+ unsigned int mdlen)
+{
+ Hmac hmac;
+ size_t i;
+
+ (void) mdlen;
+
+ if (TEST_FAIL())
+ return -1;
+
+ if (wc_HmacSetKey(&hmac, type, key, (word32) key_len) != 0)
+ return -1;
+ for (i = 0; i < num_elem; i++)
+ if (wc_HmacUpdate(&hmac, addr[i], len[i]) != 0)
+ return -1;
+ if (wc_HmacFinal(&hmac, mac) != 0)
+ return -1;
+ return 0;
+}
+
+
+#ifndef CONFIG_FIPS
+
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return wolfssl_hmac_vector(WC_MD5, key, key_len, num_elem, addr, len,
+ mac, 16);
+}
+
+
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_FIPS */
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return wolfssl_hmac_vector(WC_SHA, key, key_len, num_elem, addr, len,
+ mac, 20);
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+#ifdef CONFIG_SHA256
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return wolfssl_hmac_vector(WC_SHA256, key, key_len, num_elem, addr, len,
+ mac, 32);
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA256 */
+
+
+#ifdef CONFIG_SHA384
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return wolfssl_hmac_vector(WC_SHA384, key, key_len, num_elem, addr, len,
+ mac, 48);
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA384 */
+
+
+#ifdef CONFIG_SHA512
+
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return wolfssl_hmac_vector(WC_SHA512, key, key_len, num_elem, addr, len,
+ mac, 64);
+}
+
+
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA512 */
+
+
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
+ int iterations, u8 *buf, size_t buflen)
+{
+ if (wc_PBKDF2(buf, (const byte*)passphrase, os_strlen(passphrase), ssid,
+ ssid_len, iterations, buflen, WC_SHA) != 0)
+ return -1;
+ return 0;
+}
+
+
+#ifdef CONFIG_DES
+int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+ Des des;
+ u8 pkey[8], next, tmp;
+ int i;
+
+ /* Add parity bits to the key */
+ next = 0;
+ for (i = 0; i < 7; i++) {
+ tmp = key[i];
+ pkey[i] = (tmp >> i) | next | 1;
+ next = tmp << (7 - i);
+ }
+ pkey[i] = next | 1;
+
+ wc_Des_SetKey(&des, pkey, NULL, DES_ENCRYPTION);
+ wc_Des_EcbEncrypt(&des, cypher, clear, DES_BLOCK_SIZE);
+
+ return 0;
+}
+#endif /* CONFIG_DES */
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+ Aes *aes;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ aes = os_malloc(sizeof(Aes));
+ if (!aes)
+ return NULL;
+
+ if (wc_AesSetKey(aes, key, len, NULL, AES_ENCRYPTION) < 0) {
+ os_free(aes);
+ return NULL;
+ }
+
+ return aes;
+}
+
+
+int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+ wc_AesEncryptDirect(ctx, crypt, plain);
+ return 0;
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+ os_free(ctx);
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+ Aes *aes;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ aes = os_malloc(sizeof(Aes));
+ if (!aes)
+ return NULL;
+
+ if (wc_AesSetKey(aes, key, len, NULL, AES_DECRYPTION) < 0) {
+ os_free(aes);
+ return NULL;
+ }
+
+ return aes;
+}
+
+
+int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+ wc_AesDecryptDirect(ctx, plain, crypt);
+ return 0;
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+ os_free(ctx);
+}
+
+
+int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+ Aes aes;
+ int ret;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ret = wc_AesSetKey(&aes, key, 16, iv, AES_ENCRYPTION);
+ if (ret != 0)
+ return -1;
+
+ ret = wc_AesCbcEncrypt(&aes, data, data, data_len);
+ if (ret != 0)
+ return -1;
+ return 0;
+}
+
+
+int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+ Aes aes;
+ int ret;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ret = wc_AesSetKey(&aes, key, 16, iv, AES_DECRYPTION);
+ if (ret != 0)
+ return -1;
+
+ ret = wc_AesCbcDecrypt(&aes, data, data, data_len);
+ if (ret != 0)
+ return -1;
+ return 0;
+}
+
+
+int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
+{
+ int ret;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ret = wc_AesKeyWrap(kek, kek_len, plain, n * 8, cipher, (n + 1) * 8,
+ NULL);
+ return ret != (n + 1) * 8 ? -1 : 0;
+}
+
+
+int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
+ u8 *plain)
+{
+ int ret;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ret = wc_AesKeyUnWrap(kek, kek_len, cipher, (n + 1) * 8, plain, n * 8,
+ NULL);
+ return ret != n * 8 ? -1 : 0;
+}
+
+
+#ifndef CONFIG_NO_RC4
+int rc4_skip(const u8 *key, size_t keylen, size_t skip, u8 *data,
+ size_t data_len)
+{
+#ifndef NO_RC4
+ Arc4 arc4;
+ unsigned char skip_buf[16];
+
+ wc_Arc4SetKey(&arc4, key, keylen);
+
+ while (skip >= sizeof(skip_buf)) {
+ size_t len = skip;
+
+ if (len > sizeof(skip_buf))
+ len = sizeof(skip_buf);
+ wc_Arc4Process(&arc4, skip_buf, skip_buf, len);
+ skip -= len;
+ }
+
+ wc_Arc4Process(&arc4, data, data, data_len);
+
+ return 0;
+#else /* NO_RC4 */
+ return -1;
+#endif /* NO_RC4 */
+}
+#endif /* CONFIG_NO_RC4 */
+
+
+#if defined(EAP_IKEV2) || defined(EAP_IKEV2_DYNAMIC) \
+ || defined(EAP_SERVER_IKEV2)
+union wolfssl_cipher {
+ Aes aes;
+ Des3 des3;
+ Arc4 arc4;
+};
+
+struct crypto_cipher {
+ enum crypto_cipher_alg alg;
+ union wolfssl_cipher enc;
+ union wolfssl_cipher dec;
+};
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+ const u8 *iv, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_cipher *ctx;
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+
+ switch (alg) {
+#ifndef CONFIG_NO_RC4
+#ifndef NO_RC4
+ case CRYPTO_CIPHER_ALG_RC4:
+ wc_Arc4SetKey(&ctx->enc.arc4, key, key_len);
+ wc_Arc4SetKey(&ctx->dec.arc4, key, key_len);
+ break;
+#endif /* NO_RC4 */
+#endif /* CONFIG_NO_RC4 */
+#ifndef NO_AES
+ case CRYPTO_CIPHER_ALG_AES:
+ switch (key_len) {
+ case 16:
+ case 24:
+ case 32:
+ break;
+ default:
+ os_free(ctx);
+ return NULL;
+ }
+ if (wc_AesSetKey(&ctx->enc.aes, key, key_len, iv,
+ AES_ENCRYPTION) ||
+ wc_AesSetKey(&ctx->dec.aes, key, key_len, iv,
+ AES_DECRYPTION)) {
+ os_free(ctx);
+ return NULL;
+ }
+ break;
+#endif /* NO_AES */
+#ifndef NO_DES3
+ case CRYPTO_CIPHER_ALG_3DES:
+ if (key_len != DES3_KEYLEN ||
+ wc_Des3_SetKey(&ctx->enc.des3, key, iv, DES_ENCRYPTION) ||
+ wc_Des3_SetKey(&ctx->dec.des3, key, iv, DES_DECRYPTION)) {
+ os_free(ctx);
+ return NULL;
+ }
+ break;
+#endif /* NO_DES3 */
+ case CRYPTO_CIPHER_ALG_RC2:
+ case CRYPTO_CIPHER_ALG_DES:
+ default:
+ os_free(ctx);
+ return NULL;
+ }
+
+ ctx->alg = alg;
+
+ return ctx;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+ u8 *crypt, size_t len)
+{
+ switch (ctx->alg) {
+#ifndef CONFIG_NO_RC4
+#ifndef NO_RC4
+ case CRYPTO_CIPHER_ALG_RC4:
+ wc_Arc4Process(&ctx->enc.arc4, crypt, plain, len);
+ return 0;
+#endif /* NO_RC4 */
+#endif /* CONFIG_NO_RC4 */
+#ifndef NO_AES
+ case CRYPTO_CIPHER_ALG_AES:
+ if (wc_AesCbcEncrypt(&ctx->enc.aes, crypt, plain, len) != 0)
+ return -1;
+ return 0;
+#endif /* NO_AES */
+#ifndef NO_DES3
+ case CRYPTO_CIPHER_ALG_3DES:
+ if (wc_Des3_CbcEncrypt(&ctx->enc.des3, crypt, plain, len) != 0)
+ return -1;
+ return 0;
+#endif /* NO_DES3 */
+ default:
+ return -1;
+ }
+ return -1;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+ u8 *plain, size_t len)
+{
+ switch (ctx->alg) {
+#ifndef CONFIG_NO_RC4
+#ifndef NO_RC4
+ case CRYPTO_CIPHER_ALG_RC4:
+ wc_Arc4Process(&ctx->dec.arc4, plain, crypt, len);
+ return 0;
+#endif /* NO_RC4 */
+#endif /* CONFIG_NO_RC4 */
+#ifndef NO_AES
+ case CRYPTO_CIPHER_ALG_AES:
+ if (wc_AesCbcDecrypt(&ctx->dec.aes, plain, crypt, len) != 0)
+ return -1;
+ return 0;
+#endif /* NO_AES */
+#ifndef NO_DES3
+ case CRYPTO_CIPHER_ALG_3DES:
+ if (wc_Des3_CbcDecrypt(&ctx->dec.des3, plain, crypt, len) != 0)
+ return -1;
+ return 0;
+#endif /* NO_DES3 */
+ default:
+ return -1;
+ }
+ return -1;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+ os_free(ctx);
+}
+
+#endif
+
+
+#ifdef CONFIG_WPS_NFC
+
+static const unsigned char RFC3526_PRIME_1536[] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
+ 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
+ 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+ 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
+ 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+ 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
+ 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+ 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
+ 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
+ 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36,
+ 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
+ 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56,
+ 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
+ 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08,
+ 0xCA, 0x23, 0x73, 0x27, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+static const unsigned char RFC3526_GENERATOR_1536[] = {
+ 0x02
+};
+
+#define RFC3526_LEN sizeof(RFC3526_PRIME_1536)
+
+
+void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
+{
+ WC_RNG rng;
+ DhKey *ret = NULL;
+ DhKey *dh = NULL;
+ struct wpabuf *privkey = NULL;
+ struct wpabuf *pubkey = NULL;
+ word32 priv_sz, pub_sz;
+
+ *priv = NULL;
+ wpabuf_free(*publ);
+ *publ = NULL;
+
+ dh = XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ if (!dh)
+ return NULL;
+ wc_InitDhKey(dh);
+
+ if (wc_InitRng(&rng) != 0) {
+ XFREE(dh, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ return NULL;
+ }
+
+ privkey = wpabuf_alloc(RFC3526_LEN);
+ pubkey = wpabuf_alloc(RFC3526_LEN);
+ if (!privkey || !pubkey)
+ goto done;
+
+ if (wc_DhSetKey(dh, RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536),
+ RFC3526_GENERATOR_1536, sizeof(RFC3526_GENERATOR_1536))
+ != 0)
+ goto done;
+
+ if (wc_DhGenerateKeyPair(dh, &rng, wpabuf_mhead(privkey), &priv_sz,
+ wpabuf_mhead(pubkey), &pub_sz) != 0)
+ goto done;
+
+ wpabuf_put(privkey, priv_sz);
+ wpabuf_put(pubkey, pub_sz);
+
+ ret = dh;
+ *priv = privkey;
+ *publ = pubkey;
+ dh = NULL;
+ privkey = NULL;
+ pubkey = NULL;
+done:
+ wpabuf_clear_free(pubkey);
+ wpabuf_clear_free(privkey);
+ if (dh) {
+ wc_FreeDhKey(dh);
+ XFREE(dh, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ }
+ wc_FreeRng(&rng);
+ return ret;
+}
+
+
+void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
+{
+ DhKey *ret = NULL;
+ DhKey *dh;
+ byte *secret;
+ word32 secret_sz;
+
+ dh = XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ if (!dh)
+ return NULL;
+ wc_InitDhKey(dh);
+
+ secret = XMALLOC(RFC3526_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ if (!secret)
+ goto done;
+
+ if (wc_DhSetKey(dh, RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536),
+ RFC3526_GENERATOR_1536, sizeof(RFC3526_GENERATOR_1536))
+ != 0)
+ goto done;
+
+ if (wc_DhAgree(dh, secret, &secret_sz, wpabuf_head(priv),
+ wpabuf_len(priv), RFC3526_GENERATOR_1536,
+ sizeof(RFC3526_GENERATOR_1536)) != 0)
+ goto done;
+
+ if (secret_sz != wpabuf_len(publ) ||
+ os_memcmp(secret, wpabuf_head(publ), secret_sz) != 0)
+ goto done;
+
+ ret = dh;
+ dh = NULL;
+done:
+ if (dh) {
+ wc_FreeDhKey(dh);
+ XFREE(dh, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ }
+ XFREE(secret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ return ret;
+}
+
+
+struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
+ const struct wpabuf *own_private)
+{
+ struct wpabuf *ret = NULL;
+ struct wpabuf *secret;
+ word32 secret_sz;
+
+ secret = wpabuf_alloc(RFC3526_LEN);
+ if (!secret)
+ goto done;
+
+ if (wc_DhAgree(ctx, wpabuf_mhead(secret), &secret_sz,
+ wpabuf_head(own_private), wpabuf_len(own_private),
+ wpabuf_head(peer_public), wpabuf_len(peer_public)) != 0)
+ goto done;
+
+ wpabuf_put(secret, secret_sz);
+
+ ret = secret;
+ secret = NULL;
+done:
+ wpabuf_clear_free(secret);
+ return ret;
+}
+
+
+void dh5_free(void *ctx)
+{
+ if (!ctx)
+ return;
+
+ wc_FreeDhKey(ctx);
+ XFREE(ctx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+}
+
+#endif /* CONFIG_WPS_NFC */
+
+
+int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
+ u8 *pubkey)
+{
+ int ret = -1;
+ WC_RNG rng;
+ DhKey *dh = NULL;
+ word32 priv_sz, pub_sz;
+
+ if (TEST_FAIL())
+ return -1;
+
+ dh = os_malloc(sizeof(DhKey));
+ if (!dh)
+ return -1;
+ wc_InitDhKey(dh);
+
+ if (wc_InitRng(&rng) != 0) {
+ os_free(dh);
+ return -1;
+ }
+
+ if (wc_DhSetKey(dh, prime, prime_len, &generator, 1) != 0)
+ goto done;
+
+ if (wc_DhGenerateKeyPair(dh, &rng, privkey, &priv_sz, pubkey, &pub_sz)
+ != 0)
+ goto done;
+
+ if (priv_sz < prime_len) {
+ size_t pad_sz = prime_len - priv_sz;
+
+ os_memmove(privkey + pad_sz, privkey, priv_sz);
+ os_memset(privkey, 0, pad_sz);
+ }
+
+ if (pub_sz < prime_len) {
+ size_t pad_sz = prime_len - pub_sz;
+
+ os_memmove(pubkey + pad_sz, pubkey, pub_sz);
+ os_memset(pubkey, 0, pad_sz);
+ }
+ ret = 0;
+done:
+ wc_FreeDhKey(dh);
+ os_free(dh);
+ wc_FreeRng(&rng);
+ return ret;
+}
+
+
+int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
+ const u8 *order, size_t order_len,
+ const u8 *privkey, size_t privkey_len,
+ const u8 *pubkey, size_t pubkey_len,
+ u8 *secret, size_t *len)
+{
+ int ret = -1;
+ DhKey *dh;
+ word32 secret_sz;
+
+ dh = os_malloc(sizeof(DhKey));
+ if (!dh)
+ return -1;
+ wc_InitDhKey(dh);
+
+ if (wc_DhSetKey(dh, prime, prime_len, &generator, 1) != 0)
+ goto done;
+
+ if (wc_DhAgree(dh, secret, &secret_sz, privkey, privkey_len, pubkey,
+ pubkey_len) != 0)
+ goto done;
+
+ *len = secret_sz;
+ ret = 0;
+done:
+ wc_FreeDhKey(dh);
+ os_free(dh);
+ return ret;
+}
+
+
+#ifdef CONFIG_FIPS
+int crypto_get_random(void *buf, size_t len)
+{
+ int ret = 0;
+ WC_RNG rng;
+
+ if (wc_InitRng(&rng) != 0)
+ return -1;
+ if (wc_RNG_GenerateBlock(&rng, buf, len) != 0)
+ ret = -1;
+ wc_FreeRng(&rng);
+ return ret;
+}
+#endif /* CONFIG_FIPS */
+
+
+#if defined(EAP_PWD) || defined(EAP_SERVER_PWD)
+struct crypto_hash {
+ Hmac hmac;
+ int size;
+};
+
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_hash *ret = NULL;
+ struct crypto_hash *hash;
+ int type;
+
+ hash = os_zalloc(sizeof(*hash));
+ if (!hash)
+ goto done;
+
+ switch (alg) {
+#ifndef NO_MD5
+ case CRYPTO_HASH_ALG_HMAC_MD5:
+ hash->size = 16;
+ type = WC_MD5;
+ break;
+#endif /* NO_MD5 */
+#ifndef NO_SHA
+ case CRYPTO_HASH_ALG_HMAC_SHA1:
+ type = WC_SHA;
+ hash->size = 20;
+ break;
+#endif /* NO_SHA */
+#ifdef CONFIG_SHA256
+#ifndef NO_SHA256
+ case CRYPTO_HASH_ALG_HMAC_SHA256:
+ type = WC_SHA256;
+ hash->size = 32;
+ break;
+#endif /* NO_SHA256 */
+#endif /* CONFIG_SHA256 */
+ default:
+ goto done;
+ }
+
+ if (wc_HmacSetKey(&hash->hmac, type, key, key_len) != 0)
+ goto done;
+
+ ret = hash;
+ hash = NULL;
+done:
+ os_free(hash);
+ return ret;
+}
+
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+ if (!ctx)
+ return;
+ wc_HmacUpdate(&ctx->hmac, data, len);
+}
+
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+ int ret = 0;
+
+ if (!ctx)
+ return -2;
+
+ if (!mac || !len)
+ goto done;
+
+ if (wc_HmacFinal(&ctx->hmac, mac) != 0) {
+ ret = -1;
+ goto done;
+ }
+
+ *len = ctx->size;
+ ret = 0;
+done:
+ bin_clear_free(ctx, sizeof(*ctx));
+ if (TEST_FAIL())
+ return -1;
+ return ret;
+}
+
+#endif
+
+
+int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ Cmac cmac;
+ size_t i;
+ word32 sz;
+
+ if (TEST_FAIL())
+ return -1;
+
+ if (wc_InitCmac(&cmac, key, key_len, WC_CMAC_AES, NULL) != 0)
+ return -1;
+
+ for (i = 0; i < num_elem; i++)
+ if (wc_CmacUpdate(&cmac, addr[i], len[i]) != 0)
+ return -1;
+
+ sz = AES_BLOCK_SIZE;
+ if (wc_CmacFinal(&cmac, mac, &sz) != 0 || sz != AES_BLOCK_SIZE)
+ return -1;
+
+ return 0;
+}
+
+
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return omac1_aes_vector(key, 16, num_elem, addr, len, mac);
+}
+
+
+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
+}
+
+
+int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
+}
+
+
+struct crypto_bignum * crypto_bignum_init(void)
+{
+ mp_int *a;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ a = os_malloc(sizeof(*a));
+ if (!a || mp_init(a) != MP_OKAY) {
+ os_free(a);
+ a = NULL;
+ }
+
+ return (struct crypto_bignum *) a;
+}
+
+
+struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len)
+{
+ mp_int *a;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ a = (mp_int *) crypto_bignum_init();
+ if (!a)
+ return NULL;
+
+ if (mp_read_unsigned_bin(a, buf, len) != MP_OKAY) {
+ os_free(a);
+ a = NULL;
+ }
+
+ return (struct crypto_bignum *) a;
+}
+
+
+void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
+{
+ if (!n)
+ return;
+
+ if (clear)
+ mp_forcezero((mp_int *) n);
+ mp_clear((mp_int *) n);
+ os_free((mp_int *) n);
+}
+
+
+int crypto_bignum_to_bin(const struct crypto_bignum *a,
+ u8 *buf, size_t buflen, size_t padlen)
+{
+ int num_bytes, offset;
+
+ if (TEST_FAIL())
+ return -1;
+
+ if (padlen > buflen)
+ return -1;
+
+ num_bytes = (mp_count_bits((mp_int *) a) + 7) / 8;
+ if ((size_t) num_bytes > buflen)
+ return -1;
+ if (padlen > (size_t) num_bytes)
+ offset = padlen - num_bytes;
+ else
+ offset = 0;
+
+ os_memset(buf, 0, offset);
+ mp_to_unsigned_bin((mp_int *) a, buf + offset);
+
+ return num_bytes + offset;
+}
+
+
+int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m)
+{
+ int ret = 0;
+ WC_RNG rng;
+
+ if (TEST_FAIL())
+ return -1;
+ if (wc_InitRng(&rng) != 0)
+ return -1;
+ if (mp_rand_prime((mp_int *) r,
+ (mp_count_bits((mp_int *) m) + 7) / 8 * 2,
+ &rng, NULL) != 0)
+ ret = -1;
+ if (ret == 0 &&
+ mp_mod((mp_int *) r, (mp_int *) m, (mp_int *) r) != 0)
+ ret = -1;
+ wc_FreeRng(&rng);
+ return ret;
+}
+
+
+int crypto_bignum_add(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *r)
+{
+ return mp_add((mp_int *) a, (mp_int *) b,
+ (mp_int *) r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_mod(const struct crypto_bignum *a,
+ const struct crypto_bignum *m,
+ struct crypto_bignum *r)
+{
+ return mp_mod((mp_int *) a, (mp_int *) m,
+ (mp_int *) r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_exptmod(const struct crypto_bignum *b,
+ const struct crypto_bignum *e,
+ const struct crypto_bignum *m,
+ struct crypto_bignum *r)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_exptmod((mp_int *) b, (mp_int *) e, (mp_int *) m,
+ (mp_int *) r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_inverse(const struct crypto_bignum *a,
+ const struct crypto_bignum *m,
+ struct crypto_bignum *r)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_invmod((mp_int *) a, (mp_int *) m,
+ (mp_int *) r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_sub(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *r)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_add((mp_int *) a, (mp_int *) b,
+ (mp_int *) r) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_div(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *d)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_div((mp_int *) a, (mp_int *) b, (mp_int *) d,
+ NULL) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_mulmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *m,
+ struct crypto_bignum *d)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_mulmod((mp_int *) a, (mp_int *) b, (mp_int *) m,
+ (mp_int *) d) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
+ struct crypto_bignum *r)
+{
+ if (mp_copy((mp_int *) a, (mp_int *) r) != MP_OKAY)
+ return -1;
+ mp_rshb((mp_int *) r, n);
+ return 0;
+}
+
+
+int crypto_bignum_cmp(const struct crypto_bignum *a,
+ const struct crypto_bignum *b)
+{
+ return mp_cmp((mp_int *) a, (mp_int *) b);
+}
+
+
+int crypto_bignum_bits(const struct crypto_bignum *a)
+{
+ return mp_count_bits((mp_int *) a);
+}
+
+
+int crypto_bignum_is_zero(const struct crypto_bignum *a)
+{
+ return mp_iszero((mp_int *) a);
+}
+
+
+int crypto_bignum_is_one(const struct crypto_bignum *a)
+{
+ return mp_isone((const mp_int *) a);
+}
+
+int crypto_bignum_is_odd(const struct crypto_bignum *a)
+{
+ return mp_isodd((mp_int *) a);
+}
+
+
+int crypto_bignum_legendre(const struct crypto_bignum *a,
+ const struct crypto_bignum *p)
+{
+ mp_int t;
+ int ret;
+ int res = -2;
+
+ if (TEST_FAIL())
+ return -2;
+
+ if (mp_init(&t) != MP_OKAY)
+ return -2;
+
+ /* t = (p-1) / 2 */
+ ret = mp_sub_d((mp_int *) p, 1, &t);
+ if (ret == MP_OKAY)
+ mp_rshb(&t, 1);
+ if (ret == MP_OKAY)
+ ret = mp_exptmod((mp_int *) a, &t, (mp_int *) p, &t);
+ if (ret == MP_OKAY) {
+ if (mp_isone(&t))
+ res = 1;
+ else if (mp_iszero(&t))
+ res = 0;
+ else
+ res = -1;
+ }
+
+ mp_clear(&t);
+ return res;
+}
+
+
+#ifdef CONFIG_ECC
+
+int ecc_map(ecc_point *, mp_int *, mp_digit);
+int ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R,
+ mp_int *a, mp_int *modulus, mp_digit mp);
+
+struct crypto_ec {
+ ecc_key key;
+ mp_int a;
+ mp_int prime;
+ mp_int order;
+ mp_digit mont_b;
+ mp_int b;
+};
+
+
+struct crypto_ec * crypto_ec_init(int group)
+{
+ int built = 0;
+ struct crypto_ec *e;
+ int curve_id;
+
+ /* Map from IANA registry for IKE D-H groups to OpenSSL NID */
+ switch (group) {
+ case 19:
+ curve_id = ECC_SECP256R1;
+ break;
+ case 20:
+ curve_id = ECC_SECP384R1;
+ break;
+ case 21:
+ curve_id = ECC_SECP521R1;
+ break;
+ case 25:
+ curve_id = ECC_SECP192R1;
+ break;
+ case 26:
+ curve_id = ECC_SECP224R1;
+ break;
+#ifdef HAVE_ECC_BRAINPOOL
+ case 27:
+ curve_id = ECC_BRAINPOOLP224R1;
+ break;
+ case 28:
+ curve_id = ECC_BRAINPOOLP256R1;
+ break;
+ case 29:
+ curve_id = ECC_BRAINPOOLP384R1;
+ break;
+ case 30:
+ curve_id = ECC_BRAINPOOLP512R1;
+ break;
+#endif /* HAVE_ECC_BRAINPOOL */
+ default:
+ return NULL;
+ }
+
+ e = os_zalloc(sizeof(*e));
+ if (!e)
+ return NULL;
+
+ if (wc_ecc_init(&e->key) != 0 ||
+ wc_ecc_set_curve(&e->key, 0, curve_id) != 0 ||
+ mp_init(&e->a) != MP_OKAY ||
+ mp_init(&e->prime) != MP_OKAY ||
+ mp_init(&e->order) != MP_OKAY ||
+ mp_init(&e->b) != MP_OKAY ||
+ mp_read_radix(&e->a, e->key.dp->Af, 16) != MP_OKAY ||
+ mp_read_radix(&e->b, e->key.dp->Bf, 16) != MP_OKAY ||
+ mp_read_radix(&e->prime, e->key.dp->prime, 16) != MP_OKAY ||
+ mp_read_radix(&e->order, e->key.dp->order, 16) != MP_OKAY ||
+ mp_montgomery_setup(&e->prime, &e->mont_b) != MP_OKAY)
+ goto done;
+
+ built = 1;
+done:
+ if (!built) {
+ crypto_ec_deinit(e);
+ e = NULL;
+ }
+ return e;
+}
+
+
+void crypto_ec_deinit(struct crypto_ec* e)
+{
+ if (!e)
+ return;
+
+ mp_clear(&e->b);
+ mp_clear(&e->order);
+ mp_clear(&e->prime);
+ mp_clear(&e->a);
+ wc_ecc_free(&e->key);
+ os_free(e);
+}
+
+
+struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e)
+{
+ if (TEST_FAIL())
+ return NULL;
+ if (!e)
+ return NULL;
+ return (struct crypto_ec_point *) wc_ecc_new_point();
+}
+
+
+size_t crypto_ec_prime_len(struct crypto_ec *e)
+{
+ return (mp_count_bits(&e->prime) + 7) / 8;
+}
+
+
+size_t crypto_ec_prime_len_bits(struct crypto_ec *e)
+{
+ return mp_count_bits(&e->prime);
+}
+
+
+size_t crypto_ec_order_len(struct crypto_ec *e)
+{
+ return (mp_count_bits(&e->order) + 7) / 8;
+}
+
+
+const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) &e->prime;
+}
+
+
+const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) &e->order;
+}
+
+
+void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
+{
+ ecc_point *point = (ecc_point *) p;
+
+ if (!p)
+ return;
+
+ if (clear) {
+ mp_forcezero(point->x);
+ mp_forcezero(point->y);
+ mp_forcezero(point->z);
+ }
+ wc_ecc_del_point(point);
+}
+
+
+int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p,
+ struct crypto_bignum *x)
+{
+ return mp_copy(((ecc_point *) p)->x, (mp_int *) x) == MP_OKAY ? 0 : -1;
+}
+
+
+int crypto_ec_point_to_bin(struct crypto_ec *e,
+ const struct crypto_ec_point *point, u8 *x, u8 *y)
+{
+ ecc_point *p = (ecc_point *) point;
+
+ if (TEST_FAIL())
+ return -1;
+
+ if (!mp_isone(p->z)) {
+ if (ecc_map(p, &e->prime, e->mont_b) != MP_OKAY)
+ return -1;
+ }
+
+ if (x) {
+ if (crypto_bignum_to_bin((struct crypto_bignum *)p->x, x,
+ e->key.dp->size,
+ e->key.dp->size) <= 0)
+ return -1;
+ }
+
+ if (y) {
+ if (crypto_bignum_to_bin((struct crypto_bignum *) p->y, y,
+ e->key.dp->size,
+ e->key.dp->size) <= 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
+ const u8 *val)
+{
+ ecc_point *point = NULL;
+ int loaded = 0;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ point = wc_ecc_new_point();
+ if (!point)
+ goto done;
+
+ if (mp_read_unsigned_bin(point->x, val, e->key.dp->size) != MP_OKAY)
+ goto done;
+ val += e->key.dp->size;
+ if (mp_read_unsigned_bin(point->y, val, e->key.dp->size) != MP_OKAY)
+ goto done;
+ mp_set(point->z, 1);
+
+ loaded = 1;
+done:
+ if (!loaded) {
+ wc_ecc_del_point(point);
+ point = NULL;
+ }
+ return (struct crypto_ec_point *) point;
+}
+
+
+int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
+ const struct crypto_ec_point *b,
+ struct crypto_ec_point *c)
+{
+ mp_int mu;
+ ecc_point *ta = NULL, *tb = NULL;
+ ecc_point *pa = (ecc_point *) a, *pb = (ecc_point *) b;
+ mp_int *modulus = &e->prime;
+ int ret;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ret = mp_init(&mu);
+ if (ret != MP_OKAY)
+ return -1;
+
+ ret = mp_montgomery_calc_normalization(&mu, modulus);
+ if (ret != MP_OKAY) {
+ mp_clear(&mu);
+ return -1;
+ }
+
+ if (!mp_isone(&mu)) {
+ ta = wc_ecc_new_point();
+ if (!ta) {
+ mp_clear(&mu);
+ return -1;
+ }
+ tb = wc_ecc_new_point();
+ if (!tb) {
+ wc_ecc_del_point(ta);
+ mp_clear(&mu);
+ return -1;
+ }
+
+ if (mp_mulmod(pa->x, &mu, modulus, ta->x) != MP_OKAY ||
+ mp_mulmod(pa->y, &mu, modulus, ta->y) != MP_OKAY ||
+ mp_mulmod(pa->z, &mu, modulus, ta->z) != MP_OKAY ||
+ mp_mulmod(pb->x, &mu, modulus, tb->x) != MP_OKAY ||
+ mp_mulmod(pb->y, &mu, modulus, tb->y) != MP_OKAY ||
+ mp_mulmod(pb->z, &mu, modulus, tb->z) != MP_OKAY) {
+ ret = -1;
+ goto end;
+ }
+ pa = ta;
+ pb = tb;
+ }
+
+ ret = ecc_projective_add_point(pa, pb, (ecc_point *) c, &e->a,
+ &e->prime, e->mont_b);
+ if (ret != 0) {
+ ret = -1;
+ goto end;
+ }
+
+ if (ecc_map((ecc_point *) c, &e->prime, e->mont_b) != MP_OKAY)
+ ret = -1;
+ else
+ ret = 0;
+end:
+ wc_ecc_del_point(tb);
+ wc_ecc_del_point(ta);
+ mp_clear(&mu);
+ return ret;
+}
+
+
+int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
+ const struct crypto_bignum *b,
+ struct crypto_ec_point *res)
+{
+ int ret;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ret = wc_ecc_mulmod((mp_int *) b, (ecc_point *) p, (ecc_point *) res,
+ &e->a, &e->prime, 1);
+ return ret == 0 ? 0 : -1;
+}
+
+
+int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p)
+{
+ ecc_point *point = (ecc_point *) p;
+
+ if (TEST_FAIL())
+ return -1;
+
+ if (mp_sub(&e->prime, point->y, point->y) != MP_OKAY)
+ return -1;
+
+ return 0;
+}
+
+
+int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
+ struct crypto_ec_point *p,
+ const struct crypto_bignum *x, int y_bit)
+{
+ byte buf[1 + 2 * MAX_ECC_BYTES];
+ int ret;
+ int prime_len = crypto_ec_prime_len(e);
+
+ if (TEST_FAIL())
+ return -1;
+
+ buf[0] = y_bit ? ECC_POINT_COMP_ODD : ECC_POINT_COMP_EVEN;
+ ret = crypto_bignum_to_bin(x, buf + 1, prime_len, prime_len);
+ if (ret <= 0)
+ return -1;
+ ret = wc_ecc_import_point_der(buf, 1 + 2 * ret, e->key.idx,
+ (ecc_point *) p);
+ if (ret != 0)
+ return -1;
+
+ return 0;
+}
+
+
+struct crypto_bignum *
+crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
+ const struct crypto_bignum *x)
+{
+ mp_int *y2 = NULL;
+ mp_int t;
+ int calced = 0;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ if (mp_init(&t) != MP_OKAY)
+ return NULL;
+
+ y2 = (mp_int *) crypto_bignum_init();
+ if (!y2)
+ goto done;
+
+ if (mp_sqrmod((mp_int *) x, &e->prime, y2) != 0 ||
+ mp_mulmod((mp_int *) x, y2, &e->prime, y2) != 0 ||
+ mp_mulmod((mp_int *) x, &e->a, &e->prime, &t) != 0 ||
+ mp_addmod(y2, &t, &e->prime, y2) != 0 ||
+ mp_addmod(y2, &e->b, &e->prime, y2) != 0)
+ goto done;
+
+ calced = 1;
+done:
+ if (!calced) {
+ if (y2) {
+ mp_clear(y2);
+ os_free(y2);
+ }
+ mp_clear(&t);
+ }
+
+ return (struct crypto_bignum *) y2;
+}
+
+
+int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
+ const struct crypto_ec_point *p)
+{
+ return wc_ecc_point_is_at_infinity((ecc_point *) p);
+}
+
+
+int crypto_ec_point_is_on_curve(struct crypto_ec *e,
+ const struct crypto_ec_point *p)
+{
+ return wc_ecc_is_point((ecc_point *) p, &e->a, &e->b, &e->prime) ==
+ MP_OKAY;
+}
+
+
+int crypto_ec_point_cmp(const struct crypto_ec *e,
+ const struct crypto_ec_point *a,
+ const struct crypto_ec_point *b)
+{
+ return wc_ecc_cmp_point((ecc_point *) a, (ecc_point *) b);
+}
+
+
+struct crypto_ecdh {
+ struct crypto_ec *ec;
+};
+
+struct crypto_ecdh * crypto_ecdh_init(int group)
+{
+ struct crypto_ecdh *ecdh = NULL;
+ WC_RNG rng;
+ int ret;
+
+ if (wc_InitRng(&rng) != 0)
+ goto fail;
+
+ ecdh = os_zalloc(sizeof(*ecdh));
+ if (!ecdh)
+ goto fail;
+
+ ecdh->ec = crypto_ec_init(group);
+ if (!ecdh->ec)
+ goto fail;
+
+ ret = wc_ecc_make_key_ex(&rng, ecdh->ec->key.dp->size, &ecdh->ec->key,
+ ecdh->ec->key.dp->id);
+ if (ret < 0)
+ goto fail;
+
+done:
+ wc_FreeRng(&rng);
+
+ return ecdh;
+fail:
+ crypto_ecdh_deinit(ecdh);
+ ecdh = NULL;
+ goto done;
+}
+
+
+void crypto_ecdh_deinit(struct crypto_ecdh *ecdh)
+{
+ if (ecdh) {
+ crypto_ec_deinit(ecdh->ec);
+ os_free(ecdh);
+ }
+}
+
+
+struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y)
+{
+ struct wpabuf *buf = NULL;
+ int ret;
+ int len = ecdh->ec->key.dp->size;
+
+ buf = wpabuf_alloc(inc_y ? 2 * len : len);
+ if (!buf)
+ goto fail;
+
+ ret = crypto_bignum_to_bin((struct crypto_bignum *)
+ ecdh->ec->key.pubkey.x, wpabuf_put(buf, len),
+ len, len);
+ if (ret < 0)
+ goto fail;
+ if (inc_y) {
+ ret = crypto_bignum_to_bin((struct crypto_bignum *)
+ ecdh->ec->key.pubkey.y,
+ wpabuf_put(buf, len), len, len);
+ if (ret < 0)
+ goto fail;
+ }
+
+done:
+ return buf;
+fail:
+ wpabuf_free(buf);
+ buf = NULL;
+ goto done;
+}
+
+
+struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
+ const u8 *key, size_t len)
+{
+ int ret;
+ struct wpabuf *pubkey = NULL;
+ struct wpabuf *secret = NULL;
+ word32 key_len = ecdh->ec->key.dp->size;
+ ecc_point *point = NULL;
+ size_t need_key_len = inc_y ? 2 * key_len : key_len;
+
+ if (len < need_key_len)
+ goto fail;
+ pubkey = wpabuf_alloc(1 + 2 * key_len);
+ if (!pubkey)
+ goto fail;
+ wpabuf_put_u8(pubkey, inc_y ? ECC_POINT_UNCOMP : ECC_POINT_COMP_EVEN);
+ wpabuf_put_data(pubkey, key, need_key_len);
+
+ point = wc_ecc_new_point();
+ if (!point)
+ goto fail;
+
+ ret = wc_ecc_import_point_der(wpabuf_mhead(pubkey), 1 + 2 * key_len,
+ ecdh->ec->key.idx, point);
+ if (ret != MP_OKAY)
+ goto fail;
+
+ secret = wpabuf_alloc(key_len);
+ if (!secret)
+ goto fail;
+
+ ret = wc_ecc_shared_secret_ex(&ecdh->ec->key, point,
+ wpabuf_put(secret, key_len), &key_len);
+ if (ret != MP_OKAY)
+ goto fail;
+
+done:
+ wc_ecc_del_point(point);
+ wpabuf_free(pubkey);
+ return secret;
+fail:
+ wpabuf_free(secret);
+ secret = NULL;
+ goto done;
+}
+
+#endif /* CONFIG_ECC */
diff --git a/src/crypto/dh_groups.c b/src/crypto/dh_groups.c
index 7912361..5e421b2 100644
--- a/src/crypto/dh_groups.c
+++ b/src/crypto/dh_groups.c
@@ -1151,7 +1151,7 @@
{ id, dh_group ## id ## _generator, sizeof(dh_group ## id ## _generator), \
dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime), \
dh_group ## id ## _order, sizeof(dh_group ## id ## _order), safe }
-
+
static const struct dh_group dh_groups[] = {
DH_GROUP(5, 1),
@@ -1203,19 +1203,6 @@
if (*priv == NULL)
return NULL;
- if (random_get_bytes(wpabuf_put(*priv, dh->prime_len), dh->prime_len))
- {
- wpabuf_clear_free(*priv);
- *priv = NULL;
- return NULL;
- }
-
- if (os_memcmp(wpabuf_head(*priv), dh->prime, dh->prime_len) > 0) {
- /* Make sure private value is smaller than prime */
- *(wpabuf_mhead_u8(*priv)) = 0;
- }
- wpa_hexdump_buf_key(MSG_DEBUG, "DH: private value", *priv);
-
pv_len = dh->prime_len;
pv = wpabuf_alloc(pv_len);
if (pv == NULL) {
@@ -1223,17 +1210,17 @@
*priv = NULL;
return NULL;
}
- if (crypto_mod_exp(dh->generator, dh->generator_len,
- wpabuf_head(*priv), wpabuf_len(*priv),
- dh->prime, dh->prime_len, wpabuf_mhead(pv),
- &pv_len) < 0) {
+ if (crypto_dh_init(*dh->generator, dh->prime, dh->prime_len,
+ wpabuf_mhead(*priv), wpabuf_mhead(pv)) < 0) {
wpabuf_clear_free(pv);
- wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
+ wpa_printf(MSG_INFO, "DH: crypto_dh_init failed");
wpabuf_clear_free(*priv);
*priv = NULL;
return NULL;
}
- wpabuf_put(pv, pv_len);
+ wpabuf_put(*priv, dh->prime_len);
+ wpabuf_put(pv, dh->prime_len);
+ wpa_hexdump_buf_key(MSG_DEBUG, "DH: private value", *priv);
wpa_hexdump_buf(MSG_DEBUG, "DH: public value", pv);
return pv;
@@ -1261,12 +1248,15 @@
shared = wpabuf_alloc(shared_len);
if (shared == NULL)
return NULL;
- if (crypto_mod_exp(wpabuf_head(peer_public), wpabuf_len(peer_public),
- wpabuf_head(own_private), wpabuf_len(own_private),
- dh->prime, dh->prime_len,
- wpabuf_mhead(shared), &shared_len) < 0) {
+ if (crypto_dh_derive_secret(*dh->generator, dh->prime, dh->prime_len,
+ dh->order, dh->order_len,
+ wpabuf_head(own_private),
+ wpabuf_len(own_private),
+ wpabuf_head(peer_public),
+ wpabuf_len(peer_public),
+ wpabuf_mhead(shared), &shared_len) < 0) {
wpabuf_clear_free(shared);
- wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
+ wpa_printf(MSG_INFO, "DH: crypto_dh_derive_secret failed");
return NULL;
}
wpabuf_put(shared, shared_len);
diff --git a/src/crypto/fips_prf_wolfssl.c b/src/crypto/fips_prf_wolfssl.c
new file mode 100644
index 0000000..feb39db
--- /dev/null
+++ b/src/crypto/fips_prf_wolfssl.c
@@ -0,0 +1,87 @@
+/*
+ * FIPS 186-2 PRF for libcrypto
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <wolfssl/options.h>
+#include <wolfssl/wolfcrypt/sha.h>
+
+#include "common.h"
+#include "crypto.h"
+
+
+static void sha1_transform(u32 *state, const u8 data[64])
+{
+ wc_Sha sha;
+
+ os_memset(&sha, 0, sizeof(sha));
+ sha.digest[0] = state[0];
+ sha.digest[1] = state[1];
+ sha.digest[2] = state[2];
+ sha.digest[3] = state[3];
+ sha.digest[4] = state[4];
+ wc_ShaUpdate(&sha, data, 64);
+ state[0] = sha.digest[0];
+ state[1] = sha.digest[1];
+ state[2] = sha.digest[2];
+ state[3] = sha.digest[3];
+ state[4] = sha.digest[4];
+}
+
+
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
+{
+ u8 xkey[64];
+ u32 t[5], _t[5];
+ int i, j, m, k;
+ u8 *xpos = x;
+ u32 carry;
+
+ if (seed_len < sizeof(xkey))
+ os_memset(xkey + seed_len, 0, sizeof(xkey) - seed_len);
+ else
+ seed_len = sizeof(xkey);
+
+ /* FIPS 186-2 + change notice 1 */
+
+ os_memcpy(xkey, seed, seed_len);
+ t[0] = 0x67452301;
+ t[1] = 0xEFCDAB89;
+ t[2] = 0x98BADCFE;
+ t[3] = 0x10325476;
+ t[4] = 0xC3D2E1F0;
+
+ m = xlen / 40;
+ for (j = 0; j < m; j++) {
+ /* XSEED_j = 0 */
+ for (i = 0; i < 2; i++) {
+ /* XVAL = (XKEY + XSEED_j) mod 2^b */
+
+ /* w_i = G(t, XVAL) */
+ os_memcpy(_t, t, 20);
+ sha1_transform(_t, xkey);
+ WPA_PUT_BE32(xpos, _t[0]);
+ WPA_PUT_BE32(xpos + 4, _t[1]);
+ WPA_PUT_BE32(xpos + 8, _t[2]);
+ WPA_PUT_BE32(xpos + 12, _t[3]);
+ WPA_PUT_BE32(xpos + 16, _t[4]);
+
+ /* XKEY = (1 + XKEY + w_i) mod 2^b */
+ carry = 1;
+ for (k = 19; k >= 0; k--) {
+ carry += xkey[k] + xpos[k];
+ xkey[k] = carry & 0xff;
+ carry >>= 8;
+ }
+
+ xpos += 20;
+ }
+ /* x_j = w_0|w_1 */
+ }
+
+ return 0;
+}
diff --git a/src/crypto/md4-internal.c b/src/crypto/md4-internal.c
index d9c737a..cf408e8 100644
--- a/src/crypto/md4-internal.c
+++ b/src/crypto/md4-internal.c
@@ -85,7 +85,7 @@
(cp)[1] = (value) >> 8; \
(cp)[0] = (value); } while (0)
-static u8 PADDING[MD4_BLOCK_LENGTH] = {
+static const u8 PADDING[MD4_BLOCK_LENGTH] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
diff --git a/src/crypto/random.c b/src/crypto/random.c
index 9774a69..ca9c0c8 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -25,6 +25,9 @@
#include "utils/includes.h"
#ifdef __linux__
#include <fcntl.h>
+#ifdef CONFIG_GETRANDOM
+#include <sys/random.h>
+#endif /* CONFIG_GETRANDOM */
#endif /* __linux__ */
#include "utils/common.h"
@@ -54,7 +57,6 @@
static unsigned int own_pool_ready = 0;
#define RANDOM_ENTROPY_SIZE 20
static char *random_entropy_file = NULL;
-static int random_entropy_file_read = 0;
#define MIN_COLLECT_ENTROPY 1000
static unsigned int entropy = 0;
@@ -236,30 +238,52 @@
return 1; /* Already initialized - good to continue */
/*
- * Try to fetch some more data from the kernel high quality
- * /dev/random. There may not be enough data available at this point,
+ * Try to fetch some more data from the kernel high quality RNG.
+ * There may not be enough data available at this point,
* so use non-blocking read to avoid blocking the application
* completely.
*/
- fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
- if (fd < 0) {
- wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
- strerror(errno));
- return -1;
+
+#ifdef CONFIG_GETRANDOM
+ res = getrandom(dummy_key + dummy_key_avail,
+ sizeof(dummy_key) - dummy_key_avail, GRND_NONBLOCK);
+ if (res < 0) {
+ if (errno == ENOSYS) {
+ wpa_printf(MSG_DEBUG,
+ "random: getrandom() not supported, falling back to /dev/random");
+ } else {
+ wpa_printf(MSG_INFO,
+ "random: no data from getrandom(): %s",
+ strerror(errno));
+ res = 0;
+ }
+ }
+#else /* CONFIG_GETRANDOM */
+ res = -1;
+#endif /* CONFIG_GETRANDOM */
+ if (res < 0) {
+ fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+ wpa_printf(MSG_ERROR,
+ "random: Cannot open /dev/random: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ res = read(fd, dummy_key + dummy_key_avail,
+ sizeof(dummy_key) - dummy_key_avail);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR,
+ "random: Cannot read from /dev/random: %s",
+ strerror(errno));
+ res = 0;
+ }
+ close(fd);
}
- res = read(fd, dummy_key + dummy_key_avail,
- sizeof(dummy_key) - dummy_key_avail);
- if (res < 0) {
- wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: "
- "%s", strerror(errno));
- res = 0;
- }
- wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from "
- "/dev/random", (unsigned) res,
+ wpa_printf(MSG_DEBUG, "random: Got %u/%u random bytes", (unsigned) res,
(unsigned) (sizeof(dummy_key) - dummy_key_avail));
dummy_key_avail += res;
- close(fd);
if (dummy_key_avail == sizeof(dummy_key)) {
if (own_pool_ready < MIN_READY_MARK)
@@ -269,7 +293,7 @@
}
wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong "
- "random data available from /dev/random",
+ "random data available",
(unsigned) dummy_key_avail, (unsigned) sizeof(dummy_key));
if (own_pool_ready >= MIN_READY_MARK ||
@@ -364,7 +388,6 @@
own_pool_ready = (u8) buf[0];
random_add_randomness(buf + 1, RANDOM_ENTROPY_SIZE);
- random_entropy_file_read = 1;
os_free(buf);
wpa_printf(MSG_DEBUG, "random: Added entropy from %s "
"(own_pool_ready=%u)",
@@ -422,6 +445,19 @@
if (random_fd >= 0)
return;
+#ifdef CONFIG_GETRANDOM
+ {
+ u8 dummy;
+
+ if (getrandom(&dummy, 0, GRND_NONBLOCK) == 0 ||
+ errno != ENOSYS) {
+ wpa_printf(MSG_DEBUG,
+ "random: getrandom() support available");
+ return;
+ }
+ }
+#endif /* CONFIG_GETRANDOM */
+
random_fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
if (random_fd < 0) {
wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
diff --git a/src/crypto/sha1-tlsprf.c b/src/crypto/sha1-tlsprf.c
index f9bc0eb..a11649a 100644
--- a/src/crypto/sha1-tlsprf.c
+++ b/src/crypto/sha1-tlsprf.c
@@ -40,9 +40,6 @@
const unsigned char *SHA1_addr[3];
size_t SHA1_len[3];
- if (secret_len & 1)
- return -1;
-
MD5_addr[0] = A_MD5;
MD5_len[0] = MD5_MAC_LEN;
MD5_addr[1] = (unsigned char *) label;
diff --git a/src/crypto/sha512-internal.c b/src/crypto/sha512-internal.c
index 76c4fe7..c026394 100644
--- a/src/crypto/sha512-internal.c
+++ b/src/crypto/sha512-internal.c
@@ -109,9 +109,14 @@
/* compress 1024-bits */
static int sha512_compress(struct sha512_state *md, unsigned char *buf)
{
- u64 S[8], W[80], t0, t1;
+ u64 S[8], t0, t1;
+ u64 *W;
int i;
+ W = os_malloc(80 * sizeof(u64));
+ if (!W)
+ return -1;
+
/* copy state into S */
for (i = 0; i < 8; i++) {
S[i] = md->state[i];
@@ -146,6 +151,7 @@
md->state[i] = md->state[i] + S[i];
}
+ os_free(W);
return 0;
}
diff --git a/src/crypto/sha512.c b/src/crypto/sha512.c
new file mode 100644
index 0000000..66311c3
--- /dev/null
+++ b/src/crypto/sha512.c
@@ -0,0 +1,104 @@
+/*
+ * SHA-512 hash implementation and interface functions
+ * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha512.h"
+#include "crypto.h"
+
+
+/**
+ * hmac_sha512_vector - HMAC-SHA512 over data vector (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash (64 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */
+ unsigned char tk[64];
+ const u8 *_addr[6];
+ size_t _len[6], i;
+
+ if (num_elem > 5) {
+ /*
+ * Fixed limit on the number of fragments to avoid having to
+ * allocate memory (which could fail).
+ */
+ return -1;
+ }
+
+ /* if key is longer than 128 bytes reset it to key = SHA512(key) */
+ if (key_len > 128) {
+ if (sha512_vector(1, &key, &key_len, tk) < 0)
+ return -1;
+ key = tk;
+ key_len = 64;
+ }
+
+ /* the HMAC_SHA512 transform looks like:
+ *
+ * SHA512(K XOR opad, SHA512(K XOR ipad, text))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 128 times
+ * opad is the byte 0x5c repeated 128 times
+ * and text is the data being protected */
+
+ /* start out by storing key in ipad */
+ os_memset(k_pad, 0, sizeof(k_pad));
+ os_memcpy(k_pad, key, key_len);
+ /* XOR key with ipad values */
+ for (i = 0; i < 128; i++)
+ k_pad[i] ^= 0x36;
+
+ /* perform inner SHA512 */
+ _addr[0] = k_pad;
+ _len[0] = 128;
+ for (i = 0; i < num_elem; i++) {
+ _addr[i + 1] = addr[i];
+ _len[i + 1] = len[i];
+ }
+ if (sha512_vector(1 + num_elem, _addr, _len, mac) < 0)
+ return -1;
+
+ os_memset(k_pad, 0, sizeof(k_pad));
+ os_memcpy(k_pad, key, key_len);
+ /* XOR key with opad values */
+ for (i = 0; i < 128; i++)
+ k_pad[i] ^= 0x5c;
+
+ /* perform outer SHA512 */
+ _addr[0] = k_pad;
+ _len[0] = 128;
+ _addr[1] = mac;
+ _len[1] = SHA512_MAC_LEN;
+ return sha512_vector(2, _addr, _len, mac);
+}
+
+
+/**
+ * hmac_sha512 - HMAC-SHA512 over data buffer (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @data: Pointers to the data area
+ * @data_len: Length of the data area
+ * @mac: Buffer for the hash (64 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
+}
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index dc4117c..8bdb91f 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -42,6 +42,7 @@
TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9,
TLS_FAIL_DOMAIN_MISMATCH = 10,
TLS_FAIL_INSUFFICIENT_KEY_LEN = 11,
+ TLS_FAIL_DN_MISMATCH = 12,
};
@@ -64,6 +65,7 @@
size_t hash_len;
const char *altsubject[TLS_MAX_ALT_SUBJECT];
int num_altsubject;
+ const char *serial_num;
} peer_cert;
struct {
@@ -81,6 +83,7 @@
int cert_in_cb;
const char *openssl_ciphers;
unsigned int tls_session_lifetime;
+ unsigned int crl_reload_interval;
unsigned int tls_flags;
void (*event_cb)(void *ctx, enum tls_event ev,
@@ -101,6 +104,10 @@
#define TLS_CONN_REQUIRE_OCSP_ALL BIT(10)
#define TLS_CONN_SUITEB BIT(11)
#define TLS_CONN_SUITEB_NO_ECDH BIT(12)
+#define TLS_CONN_DISABLE_TLSv1_3 BIT(13)
+#define TLS_CONN_ENABLE_TLSv1_0 BIT(14)
+#define TLS_CONN_ENABLE_TLSv1_1 BIT(15)
+#define TLS_CONN_ENABLE_TLSv1_2 BIT(16)
/**
* struct tls_connection_params - Parameters for TLS connection
@@ -113,12 +120,19 @@
* %NULL to allow all subjects
* @altsubject_match: String to match in the alternative subject of the peer
* certificate or %NULL to allow all alternative subjects
- * @suffix_match: String to suffix match in the dNSName or CN of the peer
- * certificate or %NULL to allow all domain names. This may allow subdomains an
- * wildcard certificates. Each domain name label must have a full match.
+ * @suffix_match: Semicolon deliminated string of values to suffix match against
+ * the dNSName or CN of the peer certificate or %NULL to allow all domain names.
+ * This may allow subdomains and wildcard certificates. Each domain name label
+ * must have a full case-insensitive match.
* @domain_match: String to match in the dNSName or CN of the peer
* certificate or %NULL to allow all domain names. This requires a full,
* case-insensitive match.
+ *
+ * More than one match string can be provided by using semicolons to
+ * separate the strings (e.g., example.org;example.com). When multiple
+ * strings are specified, a match with any one of the values is
+ * considered a sufficient match for the certificate, i.e., the
+ * conditions are ORed together.
* @client_cert: File or reference name for client X.509 certificate in PEM or
* DER format
* @client_cert_blob: client_cert as inlined data or %NULL if not used
@@ -142,12 +156,15 @@
* @cert_id: the certificate's id when using engine
* @ca_cert_id: the CA certificate's id when using engine
* @openssl_ciphers: OpenSSL cipher configuration
+ * @openssl_ecdh_curves: OpenSSL ECDH curve configuration. %NULL for auto if
+ * supported, empty string to disable, or a colon-separated curve list.
* @flags: Parameter options (TLS_CONN_*)
* @ocsp_stapling_response: DER encoded file with cached OCSP stapling response
* or %NULL if OCSP is not enabled
* @ocsp_stapling_response_multi: DER encoded file with cached OCSP stapling
* response list (OCSPResponseList for ocsp_multi in RFC 6961) or %NULL if
* ocsp_multi is not enabled
+ * @check_cert_subject: Client certificate subject name matching string
*
* TLS connection parameters to be configured with tls_connection_set_params()
* and tls_global_set_params().
@@ -185,10 +202,12 @@
const char *cert_id;
const char *ca_cert_id;
const char *openssl_ciphers;
+ const char *openssl_ecdh_curves;
unsigned int flags;
const char *ocsp_stapling_response;
const char *ocsp_stapling_response_multi;
+ const char *check_cert_subject;
};
@@ -252,6 +271,18 @@
int tls_connection_established(void *tls_ctx, struct tls_connection *conn);
/**
+ * tls_connection_peer_serial_num - Fetch peer certificate serial number
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: Allocated string buffer containing the peer certificate serial
+ * number or %NULL on error.
+ *
+ * The caller is responsible for freeing the returned buffer with os_free().
+ */
+char * tls_connection_peer_serial_num(void *tls_ctx,
+ struct tls_connection *conn);
+
+/**
* tls_connection_shutdown - Shutdown TLS connection
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
@@ -307,9 +338,11 @@
* @tls_ctx: TLS context data from tls_init()
* @check_crl: 0 = do not verify CRLs, 1 = verify CRL for the user certificate,
* 2 = verify CRL for all certificates
+ * @strict: 0 = allow CRL time errors, 1 = do not allow CRL time errors
* Returns: 0 on success, -1 on failure
*/
-int __must_check tls_global_set_verify(void *tls_ctx, int check_crl);
+int __must_check tls_global_set_verify(void *tls_ctx, int check_crl,
+ int strict);
/**
* tls_connection_set_verify - Set certificate verification options
@@ -344,15 +377,21 @@
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @label: Label (e.g., description of the key) for PRF
+ * @context: Optional extra upper-layer context (max len 2^16)
+ * @context_len: The length of the context value
* @out: Buffer for output data from TLS-PRF
* @out_len: Length of the output buffer
* Returns: 0 on success, -1 on failure
*
- * Exports keying material using the mechanism described in RFC 5705.
+ * Exports keying material using the mechanism described in RFC 5705. If
+ * context is %NULL, context is not provided; otherwise, context is provided
+ * (including the case of empty context with context_len == 0).
*/
int __must_check tls_connection_export_key(void *tls_ctx,
struct tls_connection *conn,
const char *label,
+ const u8 *context,
+ size_t context_len,
u8 *out, size_t out_len);
/**
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index 8c76bfa..daa01d9 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -1,6 +1,6 @@
/*
* SSL/TLS interface functions for GnuTLS
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -295,6 +295,14 @@
}
+char * tls_connection_peer_serial_num(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ /* TODO */
+ return NULL;
+}
+
+
int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
{
struct tls_global *global = ssl_ctx;
@@ -346,6 +354,9 @@
const struct tls_connection_params *params)
{
int ret;
+ const char *err;
+ char prio_buf[100];
+ const char *prio = NULL;
if (conn == NULL || params == NULL)
return -1;
@@ -397,8 +408,62 @@
conn->flags = params->flags;
+ if (params->flags & (TLS_CONN_DISABLE_TLSv1_0 |
+ TLS_CONN_DISABLE_TLSv1_1 |
+ TLS_CONN_DISABLE_TLSv1_2)) {
+ os_snprintf(prio_buf, sizeof(prio_buf),
+ "NORMAL:-VERS-SSL3.0%s%s%s",
+ params->flags & TLS_CONN_DISABLE_TLSv1_0 ?
+ ":-VERS-TLS1.0" : "",
+ params->flags & TLS_CONN_DISABLE_TLSv1_1 ?
+ ":-VERS-TLS1.1" : "",
+ params->flags & TLS_CONN_DISABLE_TLSv1_2 ?
+ ":-VERS-TLS1.2" : "");
+ prio = prio_buf;
+ }
+
if (params->openssl_ciphers) {
- wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
+ if (os_strcmp(params->openssl_ciphers, "SUITEB128") == 0) {
+ prio = "SUITEB128";
+ } else if (os_strcmp(params->openssl_ciphers,
+ "SUITEB192") == 0) {
+ prio = "SUITEB192";
+ } else if ((params->flags & TLS_CONN_SUITEB) &&
+ os_strcmp(params->openssl_ciphers,
+ "ECDHE-RSA-AES256-GCM-SHA384") == 0) {
+ prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
+ } else if (os_strcmp(params->openssl_ciphers,
+ "ECDHE-RSA-AES256-GCM-SHA384") == 0) {
+ prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
+ } else if (os_strcmp(params->openssl_ciphers,
+ "DHE-RSA-AES256-GCM-SHA384") == 0) {
+ prio = "NONE:+VERS-TLS1.2:+AEAD:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
+ } else if (os_strcmp(params->openssl_ciphers,
+ "ECDHE-ECDSA-AES256-GCM-SHA384") == 0) {
+ prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
+ } else {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: openssl_ciphers not supported");
+ return -1;
+ }
+ } else if (params->flags & TLS_CONN_SUITEB) {
+ prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+ECDHE-RSA:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
+ }
+
+ if (prio) {
+ wpa_printf(MSG_DEBUG, "GnuTLS: Set priority string: %s", prio);
+ ret = gnutls_priority_set_direct(conn->session, prio, &err);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ "GnuTLS: Priority string failure at '%s'",
+ err);
+ return -1;
+ }
+ }
+
+ if (params->openssl_ecdh_curves) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: openssl_ecdh_curves not supported");
return -1;
}
@@ -425,6 +490,13 @@
gnutls_strerror(ret));
return -1;
}
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Successfully read CA cert '%s' in PEM format",
+ params->ca_cert);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Successfully read CA cert '%s' in DER format",
+ params->ca_cert);
}
} else if (params->ca_cert_blob) {
gnutls_datum_t ca;
@@ -472,6 +544,9 @@
}
if (params->client_cert && params->private_key) {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Try to parse client cert '%s' and key '%s' in DER format",
+ params->client_cert, params->private_key);
#if GNUTLS_VERSION_NUMBER >= 0x03010b
ret = gnutls_certificate_set_x509_key_file2(
conn->xcred, params->client_cert, params->private_key,
@@ -483,8 +558,9 @@
GNUTLS_X509_FMT_DER);
#endif
if (ret < 0) {
- wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
- "in DER format: %s", gnutls_strerror(ret));
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Failed to read client cert/key in DER format (%s) - try in PEM format",
+ gnutls_strerror(ret));
#if GNUTLS_VERSION_NUMBER >= 0x03010b
ret = gnutls_certificate_set_x509_key_file2(
conn->xcred, params->client_cert,
@@ -501,11 +577,19 @@
gnutls_strerror(ret));
return ret;
}
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Successfully read client cert/key in PEM format");
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Successfully read client cert/key in DER format");
}
} else if (params->private_key) {
int pkcs12_ok = 0;
#ifdef PKCS12_FUNCS
/* Try to load in PKCS#12 format */
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Try to parse client cert/key '%s'in PKCS#12 DER format",
+ params->private_key);
ret = gnutls_certificate_set_x509_simple_pkcs12_file(
conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
params->private_key_passwd);
@@ -655,6 +739,9 @@
struct tls_global *global = tls_ctx;
int ret;
+ if (params->check_cert_subject)
+ return -1; /* not yet supported */
+
/* Currently, global parameters are only set when running in server
* mode. */
global->server = 1;
@@ -764,7 +851,7 @@
}
-int tls_global_set_verify(void *ssl_ctx, int check_crl)
+int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
{
/* TODO */
return 0;
@@ -811,14 +898,23 @@
int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
- const char *label, u8 *out, size_t out_len)
+ const char *label, const u8 *context,
+ size_t context_len, u8 *out, size_t out_len)
{
if (conn == NULL || conn->session == NULL)
return -1;
+#if GNUTLS_VERSION_NUMBER >= 0x030404
+ return gnutls_prf_rfc5705(conn->session, os_strlen(label), label,
+ context_len, (const char *) context,
+ out_len, (char *) out);
+#else /* 3.4.4 */
+ if (context)
+ return -1;
return gnutls_prf(conn->session, os_strlen(label), label,
0 /* client_random first */, 0, NULL, out_len,
(char *) out);
+#endif /* 3.4.4 */
}
@@ -990,6 +1086,52 @@
}
+static int tls_match_suffix_helper(gnutls_x509_crt_t cert, const char *match,
+ int full)
+{
+ int res = -1;
+
+#if GNUTLS_VERSION_NUMBER >= 0x030300
+ if (full)
+ res = gnutls_x509_crt_check_hostname2(
+ cert, match,
+ GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS);
+#endif /* >= 3.3.0 */
+ if (res == -1)
+ res = gnutls_x509_crt_check_hostname(cert, match);
+
+ wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s --> res=%d",
+ full ? "": "suffix ", match, res);
+ return res;
+}
+
+
+static int tls_match_suffix(gnutls_x509_crt_t cert, const char *match,
+ int full)
+{
+ char *values, *token, *context = NULL;
+ int ret = 0;
+
+ if (!os_strchr(match, ';'))
+ return tls_match_suffix_helper(cert, match, full);
+
+ values = os_strdup(match);
+ if (!values)
+ return 0;
+
+ /* Process each match alternative separately until a match is found */
+ while ((token = str_token(values, ";", &context))) {
+ if (tls_match_suffix_helper(cert, token, full)) {
+ ret = 1;
+ break;
+ }
+ }
+
+ os_free(values);
+ return ret;
+}
+
+
static int tls_connection_verify_peer(gnutls_session_t session)
{
struct tls_connection *conn;
@@ -1185,8 +1327,7 @@
if (i == 0) {
if (conn->suffix_match &&
- !gnutls_x509_crt_check_hostname(
- cert, conn->suffix_match)) {
+ !tls_match_suffix(cert, conn->suffix_match, 0)) {
wpa_printf(MSG_WARNING,
"TLS: Domain suffix match '%s' not found",
conn->suffix_match);
@@ -1202,9 +1343,7 @@
#if GNUTLS_VERSION_NUMBER >= 0x030300
if (conn->domain_match &&
- !gnutls_x509_crt_check_hostname2(
- cert, conn->domain_match,
- GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS)) {
+ !tls_match_suffix(cert, conn->domain_match, 1)) {
wpa_printf(MSG_WARNING,
"TLS: Domain match '%s' not found",
conn->domain_match);
@@ -1333,6 +1472,7 @@
ret = gnutls_handshake(conn->session);
if (ret < 0) {
gnutls_alert_description_t alert;
+ union tls_event_data ev;
switch (ret) {
case GNUTLS_E_AGAIN:
@@ -1343,14 +1483,29 @@
conn->push_buf = wpabuf_alloc(0);
}
break;
+ case GNUTLS_E_DH_PRIME_UNACCEPTABLE:
+ wpa_printf(MSG_DEBUG, "GnuTLS: Unacceptable DH prime");
+ if (conn->global->event_cb) {
+ os_memset(&ev, 0, sizeof(ev));
+ ev.alert.is_local = 1;
+ ev.alert.type = "fatal";
+ ev.alert.description = "insufficient security";
+ conn->global->event_cb(conn->global->cb_ctx,
+ TLS_ALERT, &ev);
+ }
+ /*
+ * Could send a TLS Alert to the server, but for now,
+ * simply terminate handshake.
+ */
+ conn->failed++;
+ conn->write_alerts++;
+ break;
case GNUTLS_E_FATAL_ALERT_RECEIVED:
alert = gnutls_alert_get(conn->session);
wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
__func__, gnutls_alert_get_name(alert));
conn->read_alerts++;
if (conn->global->event_cb != NULL) {
- union tls_event_data ev;
-
os_memset(&ev, 0, sizeof(ev));
ev.alert.is_local = 0;
ev.alert.type = gnutls_alert_get_name(alert);
@@ -1501,16 +1656,53 @@
int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
- /* TODO */
- return -1;
+ gnutls_protocol_t ver;
+
+ ver = gnutls_protocol_get_version(conn->session);
+ if (ver == GNUTLS_TLS1_0)
+ os_strlcpy(buf, "TLSv1", buflen);
+ else if (ver == GNUTLS_TLS1_1)
+ os_strlcpy(buf, "TLSv1.1", buflen);
+ else if (ver == GNUTLS_TLS1_2)
+ os_strlcpy(buf, "TLSv1.2", buflen);
+ else
+ return -1;
+ return 0;
}
int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
- /* TODO */
- buf[0] = '\0';
+ gnutls_cipher_algorithm_t cipher;
+ gnutls_kx_algorithm_t kx;
+ gnutls_mac_algorithm_t mac;
+ const char *kx_str, *cipher_str, *mac_str;
+ int res;
+
+ cipher = gnutls_cipher_get(conn->session);
+ cipher_str = gnutls_cipher_get_name(cipher);
+ if (!cipher_str)
+ cipher_str = "";
+
+ kx = gnutls_kx_get(conn->session);
+ kx_str = gnutls_kx_get_name(kx);
+ if (!kx_str)
+ kx_str = "";
+
+ mac = gnutls_mac_get(conn->session);
+ mac_str = gnutls_mac_get_name(mac);
+ if (!mac_str)
+ mac_str = "";
+
+ if (kx == GNUTLS_KX_RSA)
+ res = os_snprintf(buf, buflen, "%s-%s", cipher_str, mac_str);
+ else
+ res = os_snprintf(buf, buflen, "%s-%s-%s",
+ kx_str, cipher_str, mac_str);
+ if (os_snprintf_error(buflen, res))
+ return -1;
+
return 0;
}
diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c
index c7cb5de..8095b43 100644
--- a/src/crypto/tls_internal.c
+++ b/src/crypto/tls_internal.c
@@ -1,6 +1,6 @@
/*
* TLS interface functions and an internal TLS implementation
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -177,6 +177,14 @@
}
+char * tls_connection_peer_serial_num(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ /* TODO */
+ return NULL;
+}
+
+
int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
{
#ifdef CONFIG_TLS_INTERNAL_CLIENT
@@ -240,6 +248,12 @@
return -1;
}
+ if (params->openssl_ecdh_curves) {
+ wpa_printf(MSG_INFO, "TLS: openssl_ecdh_curves not supported");
+ tlsv1_cred_free(cred);
+ return -1;
+ }
+
if (tlsv1_set_ca_cert(cred, params->ca_cert,
params->ca_cert_blob, params->ca_cert_blob_len,
params->ca_path)) {
@@ -295,6 +309,9 @@
struct tls_global *global = tls_ctx;
struct tlsv1_credentials *cred;
+ if (params->check_cert_subject)
+ return -1; /* not yet supported */
+
/* Currently, global parameters are only set when running in server
* mode. */
global->server = 1;
@@ -345,7 +362,7 @@
}
-int tls_global_set_verify(void *tls_ctx, int check_crl)
+int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
{
struct tls_global *global = tls_ctx;
global->check_crl = check_crl;
@@ -395,7 +412,8 @@
static int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
- const char *label, int server_random_first,
+ const char *label, const u8 *context,
+ size_t context_len, int server_random_first,
int skip_keyblock, u8 *out, size_t out_len)
{
int ret = -1, skip = 0;
@@ -414,15 +432,15 @@
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client) {
- ret = tlsv1_client_prf(conn->client, label,
- server_random_first,
+ ret = tlsv1_client_prf(conn->client, label, context,
+ context_len, server_random_first,
_out, skip + out_len);
}
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server) {
- ret = tlsv1_server_prf(conn->server, label,
- server_random_first,
+ ret = tlsv1_server_prf(conn->server, label, context,
+ context_len, server_random_first,
_out, skip + out_len);
}
#endif /* CONFIG_TLS_INTERNAL_SERVER */
@@ -435,17 +453,19 @@
int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
- const char *label, u8 *out, size_t out_len)
+ const char *label, const u8 *context,
+ size_t context_len, u8 *out, size_t out_len)
{
- return tls_connection_prf(tls_ctx, conn, label, 0, 0, out, out_len);
+ return tls_connection_prf(tls_ctx, conn, label, context, context_len,
+ 0, 0, out, out_len);
}
int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
u8 *out, size_t out_len)
{
- return tls_connection_prf(tls_ctx, conn, "key expansion", 1, 1, out,
- out_len);
+ return tls_connection_prf(tls_ctx, conn, "key expansion", NULL, 0,
+ 1, 1, out, out_len);
}
@@ -712,12 +732,20 @@
int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
{
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ return tlsv1_server_get_failed(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
return 0;
}
int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
{
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ return tlsv1_server_get_read_alerts(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
return 0;
}
@@ -725,6 +753,10 @@
int tls_connection_get_write_alerts(void *tls_ctx,
struct tls_connection *conn)
{
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ return tlsv1_server_get_write_alerts(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
return 0;
}
diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c
index dd5681e..6d6fb0c 100644
--- a/src/crypto/tls_none.c
+++ b/src/crypto/tls_none.c
@@ -45,6 +45,13 @@
}
+char * tls_connection_peer_serial_num(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ return NULL;
+}
+
+
int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
{
return -1;
@@ -65,7 +72,7 @@
}
-int tls_global_set_verify(void *tls_ctx, int check_crl)
+int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
{
return -1;
}
@@ -87,7 +94,8 @@
int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
- const char *label, u8 *out, size_t out_len)
+ const char *label, const u8 *context,
+ size_t context_len, u8 *out, size_t out_len)
{
return -1;
}
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 7243d9f..620254a 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -59,7 +59,8 @@
#endif /* SSL_set_tlsext_status_type */
#if (OPENSSL_VERSION_NUMBER < 0x10100000L || \
- defined(LIBRESSL_VERSION_NUMBER)) && \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)) && \
!defined(BORINGSSL_API_VERSION)
/*
* SSL_get_client_random() and SSL_get_server_random() were added in OpenSSL
@@ -103,13 +104,21 @@
#endif
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
#ifdef CONFIG_SUITEB
static int RSA_bits(const RSA *r)
{
return BN_num_bits(r->n);
}
#endif /* CONFIG_SUITEB */
+
+
+static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x)
+{
+ return ASN1_STRING_data((ASN1_STRING *) x);
+}
#endif
#ifdef ANDROID
@@ -219,10 +228,17 @@
struct tls_data {
SSL_CTX *ssl;
unsigned int tls_session_lifetime;
+ int check_crl;
+ int check_crl_strict;
+ char *ca_cert;
+ unsigned int crl_reload_interval;
+ struct os_reltime crl_last_reload;
+ char *check_cert_subject;
};
struct tls_connection {
struct tls_context *context;
+ struct tls_data *data;
SSL_CTX *ssl_ctx;
SSL *ssl;
BIO *ssl_in, *ssl_out;
@@ -231,6 +247,7 @@
EVP_PKEY *private_key; /* the private key if using engine */
#endif /* OPENSSL_NO_ENGINE */
char *subject_match, *altsubject_match, *suffix_match, *domain_match;
+ char *check_cert_subject;
int read_alerts, write_alerts, failed;
tls_session_ticket_cb session_ticket_cb;
@@ -245,6 +262,8 @@
unsigned int server_cert_only:1;
unsigned int invalid_hb_used:1;
unsigned int success_data:1;
+ unsigned int client_hello_generated:1;
+ unsigned int server:1;
u8 srv_cert_hash[32];
@@ -306,6 +325,36 @@
#endif /* CONFIG_NO_STDOUT_DEBUG */
+static X509_STORE * tls_crl_cert_reload(const char *ca_cert, int check_crl)
+{
+ int flags;
+ X509_STORE *store;
+
+ store = X509_STORE_new();
+ if (!store) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: %s - failed to allocate new certificate store",
+ __func__);
+ return NULL;
+ }
+
+ if (ca_cert && X509_STORE_load_locations(store, ca_cert, NULL) != 1) {
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed to load root certificates");
+ X509_STORE_free(store);
+ return NULL;
+ }
+
+ flags = check_crl ? X509_V_FLAG_CRL_CHECK : 0;
+ if (check_crl == 2)
+ flags |= X509_V_FLAG_CRL_CHECK_ALL;
+
+ X509_STORE_set_flags(store, flags);
+
+ return store;
+}
+
+
#ifdef CONFIG_NATIVE_WINDOWS
/* Windows CryptoAPI and access to certificate stores */
@@ -945,7 +994,9 @@
}
#endif /* OPENSSL_FIPS */
#endif /* CONFIG_FIPS */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
SSL_load_error_strings();
SSL_library_init();
#ifndef OPENSSL_NO_SHA256
@@ -992,8 +1043,10 @@
return NULL;
}
data->ssl = ssl;
- if (conf)
+ if (conf) {
data->tls_session_lifetime = conf->tls_session_lifetime;
+ data->crl_reload_interval = conf->crl_reload_interval;
+ }
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
@@ -1033,8 +1086,10 @@
#ifndef OPENSSL_NO_ENGINE
wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
ERR_load_ENGINE_strings();
ENGINE_load_dynamic();
+#endif /* OPENSSL_VERSION_NUMBER */
if (conf &&
(conf->opensc_engine_path || conf->pkcs11_engine_path ||
@@ -1073,11 +1128,14 @@
os_free(context);
if (data->tls_session_lifetime > 0)
SSL_CTX_flush_sessions(ssl, 0);
+ os_free(data->ca_cert);
SSL_CTX_free(ssl);
tls_openssl_ref_count--;
if (tls_openssl_ref_count == 0) {
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
#ifndef OPENSSL_NO_ENGINE
ENGINE_cleanup();
#endif /* OPENSSL_NO_ENGINE */
@@ -1092,6 +1150,7 @@
tls_global = NULL;
}
+ os_free(data->check_cert_subject);
os_free(data);
}
@@ -1304,8 +1363,16 @@
return "client hello";
case 2:
return "server hello";
+ case 3:
+ return "hello verify request";
case 4:
return "new session ticket";
+ case 5:
+ return "end of early data";
+ case 6:
+ return "hello retry request";
+ case 8:
+ return "encrypted extensions";
case 11:
return "certificate";
case 12:
@@ -1324,6 +1391,12 @@
return "certificate url";
case 22:
return "certificate status";
+ case 23:
+ return "supplemental data";
+ case 24:
+ return "key update";
+ case 254:
+ return "message hash";
default:
return "?";
}
@@ -1466,11 +1539,32 @@
SSL_CTX *ssl = data->ssl;
struct tls_connection *conn;
long options;
+ X509_STORE *new_cert_store;
+ struct os_reltime now;
struct tls_context *context = SSL_CTX_get_app_data(ssl);
+ /* Replace X509 store if it is time to update CRL. */
+ if (data->crl_reload_interval > 0 && os_get_reltime(&now) == 0 &&
+ os_reltime_expired(&now, &data->crl_last_reload,
+ data->crl_reload_interval)) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Flushing X509 store with ca_cert file");
+ new_cert_store = tls_crl_cert_reload(data->ca_cert,
+ data->check_crl);
+ if (!new_cert_store) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Error replacing X509 store with ca_cert file");
+ } else {
+ /* Replace old store */
+ SSL_CTX_set_cert_store(ssl, new_cert_store);
+ data->crl_last_reload = now;
+ }
+ }
+
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
+ conn->data = data;
conn->ssl_ctx = ssl;
conn->ssl = SSL_new(ssl);
if (conn->ssl == NULL) {
@@ -1534,6 +1628,7 @@
os_free(conn->altsubject_match);
os_free(conn->suffix_match);
os_free(conn->domain_match);
+ os_free(conn->check_cert_subject);
os_free(conn->session_ticket);
os_free(conn);
}
@@ -1545,6 +1640,31 @@
}
+char * tls_connection_peer_serial_num(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ ASN1_INTEGER *ser;
+ char *serial_num;
+ size_t len;
+
+ if (!conn->peer_cert)
+ return NULL;
+
+ ser = X509_get_serialNumber(conn->peer_cert);
+ if (!ser)
+ return NULL;
+
+ len = ASN1_STRING_length(ser) * 2 + 1;
+ serial_num = os_malloc(len);
+ if (!serial_num)
+ return NULL;
+ wpa_snprintf_hex_uppercase(serial_num, len,
+ ASN1_STRING_get0_data(ser),
+ ASN1_STRING_length(ser));
+ return serial_num;
+}
+
+
int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
@@ -1629,9 +1749,9 @@
#ifndef CONFIG_NATIVE_WINDOWS
static int domain_suffix_match(const u8 *val, size_t len, const char *match,
- int full)
+ size_t match_len, int full)
{
- size_t i, match_len;
+ size_t i;
/* Check for embedded nuls that could mess up suffix matching */
for (i = 0; i < len; i++) {
@@ -1641,7 +1761,6 @@
}
}
- match_len = os_strlen(match);
if (match_len > len || (full && match_len != len))
return 0;
@@ -1661,12 +1780,223 @@
#endif /* CONFIG_NATIVE_WINDOWS */
-static int tls_match_suffix(X509 *cert, const char *match, int full)
+struct tls_dn_field_order_cnt {
+ u8 cn;
+ u8 c;
+ u8 l;
+ u8 st;
+ u8 o;
+ u8 ou;
+ u8 email;
+};
+
+
+static int get_dn_field_index(const struct tls_dn_field_order_cnt *dn_cnt,
+ int nid)
{
-#ifdef CONFIG_NATIVE_WINDOWS
- /* wincrypt.h has conflicting X509_NAME definition */
- return -1;
-#else /* CONFIG_NATIVE_WINDOWS */
+ switch (nid) {
+ case NID_commonName:
+ return dn_cnt->cn;
+ case NID_countryName:
+ return dn_cnt->c;
+ case NID_localityName:
+ return dn_cnt->l;
+ case NID_stateOrProvinceName:
+ return dn_cnt->st;
+ case NID_organizationName:
+ return dn_cnt->o;
+ case NID_organizationalUnitName:
+ return dn_cnt->ou;
+ case NID_pkcs9_emailAddress:
+ return dn_cnt->email;
+ default:
+ wpa_printf(MSG_ERROR,
+ "TLS: Unknown NID '%d' in check_cert_subject",
+ nid);
+ return -1;
+ }
+}
+
+
+/**
+ * match_dn_field - Match configuration DN field against Certificate DN field
+ * @cert: Certificate
+ * @nid: NID of DN field
+ * @field: Field name
+ * @value DN field value which is passed from configuration
+ * e.g., if configuration have C=US and this argument will point to US.
+ * @dn_cnt: DN matching context
+ * Returns: 1 on success and 0 on failure
+ */
+static int match_dn_field(const X509 *cert, int nid, const char *field,
+ const char *value,
+ const struct tls_dn_field_order_cnt *dn_cnt)
+{
+ int i, ret = 0, len, config_dn_field_index, match_index = 0;
+ X509_NAME *name;
+
+ len = os_strlen(value);
+ name = X509_get_subject_name((X509 *) cert);
+
+ /* Assign incremented cnt for every field of DN to check DN field in
+ * right order */
+ config_dn_field_index = get_dn_field_index(dn_cnt, nid);
+ if (config_dn_field_index < 0)
+ return 0;
+
+ /* Fetch value based on NID */
+ for (i = -1; (i = X509_NAME_get_index_by_NID(name, nid, i)) > -1;) {
+ X509_NAME_ENTRY *e;
+ ASN1_STRING *cn;
+
+ e = X509_NAME_get_entry(name, i);
+ if (!e)
+ continue;
+
+ cn = X509_NAME_ENTRY_get_data(e);
+ if (!cn)
+ continue;
+
+ match_index++;
+
+ /* check for more than one DN field with same name */
+ if (match_index != config_dn_field_index)
+ continue;
+
+ /* Check wildcard at the right end side */
+ /* E.g., if OU=develop* mentioned in configuration, allow 'OU'
+ * of the subject in the client certificate to start with
+ * 'develop' */
+ if (len > 0 && value[len - 1] == '*') {
+ /* Compare actual certificate DN field value with
+ * configuration DN field value up to the specified
+ * length. */
+ ret = ASN1_STRING_length(cn) >= len - 1 &&
+ os_memcmp(ASN1_STRING_get0_data(cn), value,
+ len - 1) == 0;
+ } else {
+ /* Compare actual certificate DN field value with
+ * configuration DN field value */
+ ret = ASN1_STRING_length(cn) == len &&
+ os_memcmp(ASN1_STRING_get0_data(cn), value,
+ len) == 0;
+ }
+ if (!ret) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to match %s '%s' with certificate DN field value '%s'",
+ field, value, ASN1_STRING_get0_data(cn));
+ }
+ break;
+ }
+
+ return ret;
+}
+
+
+/**
+ * get_value_from_field - Get value from DN field
+ * @cert: Certificate
+ * @field_str: DN field string which is passed from configuration file (e.g.,
+ * C=US)
+ * @dn_cnt: DN matching context
+ * Returns: 1 on success and 0 on failure
+ */
+static int get_value_from_field(const X509 *cert, char *field_str,
+ struct tls_dn_field_order_cnt *dn_cnt)
+{
+ int nid;
+ char *context = NULL, *name, *value;
+
+ if (os_strcmp(field_str, "*") == 0)
+ return 1; /* wildcard matches everything */
+
+ name = str_token(field_str, "=", &context);
+ if (!name)
+ return 0;
+
+ /* Compare all configured DN fields and assign nid based on that to
+ * fetch correct value from certificate subject */
+ if (os_strcmp(name, "CN") == 0) {
+ nid = NID_commonName;
+ dn_cnt->cn++;
+ } else if(os_strcmp(name, "C") == 0) {
+ nid = NID_countryName;
+ dn_cnt->c++;
+ } else if (os_strcmp(name, "L") == 0) {
+ nid = NID_localityName;
+ dn_cnt->l++;
+ } else if (os_strcmp(name, "ST") == 0) {
+ nid = NID_stateOrProvinceName;
+ dn_cnt->st++;
+ } else if (os_strcmp(name, "O") == 0) {
+ nid = NID_organizationName;
+ dn_cnt->o++;
+ } else if (os_strcmp(name, "OU") == 0) {
+ nid = NID_organizationalUnitName;
+ dn_cnt->ou++;
+ } else if (os_strcmp(name, "emailAddress") == 0) {
+ nid = NID_pkcs9_emailAddress;
+ dn_cnt->email++;
+ } else {
+ wpa_printf(MSG_ERROR,
+ "TLS: Unknown field '%s' in check_cert_subject", name);
+ return 0;
+ }
+
+ value = str_token(field_str, "=", &context);
+ if (!value) {
+ wpa_printf(MSG_ERROR,
+ "TLS: Distinguished Name field '%s' value is not defined in check_cert_subject",
+ name);
+ return 0;
+ }
+
+ return match_dn_field(cert, nid, name, value, dn_cnt);
+}
+
+
+/**
+ * tls_match_dn_field - Match subject DN field with check_cert_subject
+ * @cert: Certificate
+ * @match: check_cert_subject string
+ * Returns: Return 1 on success and 0 on failure
+*/
+static int tls_match_dn_field(X509 *cert, const char *match)
+{
+ const char *token, *last = NULL;
+ char field[256];
+ struct tls_dn_field_order_cnt dn_cnt;
+
+ os_memset(&dn_cnt, 0, sizeof(dn_cnt));
+
+ /* Maximum length of each DN field is 255 characters */
+
+ /* Process each '/' delimited field */
+ while ((token = cstr_token(match, "/", &last))) {
+ if (last - token >= (int) sizeof(field)) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Too long DN matching field value in '%s'",
+ match);
+ return 0;
+ }
+ os_memcpy(field, token, last - token);
+ field[last - token] = '\0';
+
+ if (!get_value_from_field(cert, field, &dn_cnt)) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: No match for DN '%s'",
+ field);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+#ifndef CONFIG_NATIVE_WINDOWS
+static int tls_match_suffix_helper(X509 *cert, const char *match,
+ size_t match_len, int full)
+{
GENERAL_NAME *gen;
void *ext;
int i;
@@ -1688,8 +2018,8 @@
gen->d.dNSName->data,
gen->d.dNSName->length);
if (domain_suffix_match(gen->d.dNSName->data,
- gen->d.dNSName->length, match, full) ==
- 1) {
+ gen->d.dNSName->length,
+ match, match_len, full) == 1) {
wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
full ? "Match" : "Suffix match");
sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
@@ -1720,8 +2050,8 @@
continue;
wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
cn->data, cn->length);
- if (domain_suffix_match(cn->data, cn->length, match, full) == 1)
- {
+ if (domain_suffix_match(cn->data, cn->length,
+ match, match_len, full) == 1) {
wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
full ? "Match" : "Suffix match");
return 1;
@@ -1731,6 +2061,25 @@
wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found",
full ? "": "suffix ");
return 0;
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+static int tls_match_suffix(X509 *cert, const char *match, int full)
+{
+#ifdef CONFIG_NATIVE_WINDOWS
+ /* wincrypt.h has conflicting X509_NAME definition */
+ return -1;
+#else /* CONFIG_NATIVE_WINDOWS */
+ const char *token, *last = NULL;
+
+ /* Process each match alternative separately until a match is found */
+ while ((token = cstr_token(match, ";", &last))) {
+ if (tls_match_suffix_helper(cert, token, last - token, full))
+ return 1;
+ }
+
+ return 0;
#endif /* CONFIG_NATIVE_WINDOWS */
}
@@ -1833,6 +2182,8 @@
GENERAL_NAME *gen;
void *ext;
stack_index_t i;
+ ASN1_INTEGER *ser;
+ char serial_num[128];
#ifdef CONFIG_SHA256
u8 hash[32];
#endif /* CONFIG_SHA256 */
@@ -1861,6 +2212,14 @@
ev.peer_cert.depth = depth;
ev.peer_cert.subject = subject;
+ ser = X509_get_serialNumber(err_cert);
+ if (ser) {
+ wpa_snprintf_hex_uppercase(serial_num, sizeof(serial_num),
+ ASN1_STRING_get0_data(ser),
+ ASN1_STRING_length(ser));
+ ev.peer_cert.serial_num = serial_num;
+ }
+
ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL);
for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
char *pos;
@@ -1919,6 +2278,7 @@
struct tls_connection *conn;
struct tls_context *context;
char *match, *altmatch, *suffix_match, *domain_match;
+ const char *check_cert_subject;
const char *err_str;
err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
@@ -1959,6 +2319,13 @@
"time mismatch");
preverify_ok = 1;
}
+ if (!preverify_ok && !conn->data->check_crl_strict &&
+ (err == X509_V_ERR_CRL_HAS_EXPIRED ||
+ err == X509_V_ERR_CRL_NOT_YET_VALID)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Ignore certificate validity CRL time mismatch");
+ preverify_ok = 1;
+ }
err_str = X509_verify_cert_error_string(err);
@@ -2012,6 +2379,18 @@
"err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
preverify_ok, err, err_str,
conn->ca_cert_verify, depth, buf);
+ check_cert_subject = conn->check_cert_subject;
+ if (!check_cert_subject)
+ check_cert_subject = conn->data->check_cert_subject;
+ if (check_cert_subject) {
+ if (depth == 0 &&
+ !tls_match_dn_field(err_cert, check_cert_subject)) {
+ preverify_ok = 0;
+ openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "Distinguished Name",
+ TLS_FAIL_DN_MISMATCH);
+ }
+ }
if (depth == 0 && match && os_strstr(buf, match) == NULL) {
wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
"match with '%s'", buf, match);
@@ -2349,13 +2728,16 @@
SSL_CTX_set_client_CA_list(ssl_ctx,
SSL_load_client_CA_file(ca_cert));
#endif /* OPENSSL_NO_STDIO */
+
+ os_free(data->ca_cert);
+ data->ca_cert = os_strdup(ca_cert);
}
return 0;
}
-int tls_global_set_verify(void *ssl_ctx, int check_crl)
+int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
{
int flags;
@@ -2372,6 +2754,10 @@
if (check_crl == 2)
flags |= X509_V_FLAG_CRL_CHECK_ALL;
X509_STORE_set_flags(cs, flags);
+
+ data->check_crl = check_crl;
+ data->check_crl_strict = strict;
+ os_get_reltime(&data->crl_last_reload);
}
return 0;
}
@@ -2381,7 +2767,8 @@
const char *subject_match,
const char *altsubject_match,
const char *suffix_match,
- const char *domain_match)
+ const char *domain_match,
+ const char *check_cert_subject)
{
os_free(conn->subject_match);
conn->subject_match = NULL;
@@ -2415,6 +2802,14 @@
return -1;
}
+ os_free(conn->check_cert_subject);
+ conn->check_cert_subject = NULL;
+ if (check_cert_subject) {
+ conn->check_cert_subject = os_strdup(check_cert_subject);
+ if (!conn->check_cert_subject)
+ return -1;
+ }
+
return 0;
}
@@ -2451,7 +2846,8 @@
#endif /* CONFIG_SUITEB */
-static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags)
+static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags,
+ const char *openssl_ciphers)
{
SSL *ssl = conn->ssl;
@@ -2480,11 +2876,59 @@
else
SSL_clear_options(ssl, SSL_OP_NO_TLSv1_2);
#endif /* SSL_OP_NO_TLSv1_2 */
+#ifdef SSL_OP_NO_TLSv1_3
+ if (flags & TLS_CONN_DISABLE_TLSv1_3)
+ SSL_set_options(ssl, SSL_OP_NO_TLSv1_3);
+ else
+ SSL_clear_options(ssl, SSL_OP_NO_TLSv1_3);
+#endif /* SSL_OP_NO_TLSv1_3 */
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ if (flags & (TLS_CONN_ENABLE_TLSv1_0 |
+ TLS_CONN_ENABLE_TLSv1_1 |
+ TLS_CONN_ENABLE_TLSv1_2)) {
+ int version = 0;
+
+ /* Explicit request to enable TLS versions even if needing to
+ * override systemwide policies. */
+ 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;
+ }
+ if (!version) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Invalid TLS version configuration");
+ return -1;
+ }
+
+ if (SSL_set_min_proto_version(ssl, version) != 1) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Failed to set minimum TLS version");
+ return -1;
+ }
+ }
+#endif /* >= 1.1.0 */
+
#ifdef CONFIG_SUITEB
+#ifdef OPENSSL_IS_BORINGSSL
+ /* Start with defaults from BoringSSL */
+ SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, NULL, 0);
+#endif /* OPENSSL_IS_BORINGSSL */
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (flags & TLS_CONN_SUITEB_NO_ECDH) {
const char *ciphers = "DHE-RSA-AES256-GCM-SHA384";
+ if (openssl_ciphers) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Override ciphers for Suite B (no ECDH): %s",
+ openssl_ciphers);
+ ciphers = openssl_ciphers;
+ }
if (SSL_set_cipher_list(ssl, ciphers) != 1) {
wpa_printf(MSG_INFO,
"OpenSSL: Failed to set Suite B ciphers");
@@ -2494,14 +2938,21 @@
EC_KEY *ecdh;
const char *ciphers =
"ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384";
+ int nid[1] = { NID_secp384r1 };
+ if (openssl_ciphers) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Override ciphers for Suite B: %s",
+ openssl_ciphers);
+ ciphers = openssl_ciphers;
+ }
if (SSL_set_cipher_list(ssl, ciphers) != 1) {
wpa_printf(MSG_INFO,
"OpenSSL: Failed to set Suite B ciphers");
return -1;
}
- if (SSL_set1_curves_list(ssl, "P-384") != 1) {
+ if (SSL_set1_curves(ssl, nid, 1) != 1) {
wpa_printf(MSG_INFO,
"OpenSSL: Failed to set Suite B curves");
return -1;
@@ -2517,12 +2968,23 @@
EC_KEY_free(ecdh);
}
if (flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) {
+#ifdef OPENSSL_IS_BORINGSSL
+ uint16_t sigalgs[1] = { SSL_SIGN_RSA_PKCS1_SHA384 };
+
+ if (SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, sigalgs,
+ 1) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set Suite B sigalgs");
+ return -1;
+ }
+#else /* OPENSSL_IS_BORINGSSL */
/* ECDSA+SHA384 if need to add EC support here */
if (SSL_set1_sigalgs_list(ssl, "RSA+SHA384") != 1) {
wpa_printf(MSG_INFO,
"OpenSSL: Failed to set Suite B sigalgs");
return -1;
}
+#endif /* OPENSSL_IS_BORINGSSL */
SSL_set_options(ssl, SSL_OP_NO_TLSv1);
SSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
@@ -2535,6 +2997,41 @@
return -1;
}
#endif /* OPENSSL_VERSION_NUMBER */
+
+#ifdef OPENSSL_IS_BORINGSSL
+ if (openssl_ciphers && os_strcmp(openssl_ciphers, "SUITEB192") == 0) {
+ uint16_t sigalgs[1] = { SSL_SIGN_ECDSA_SECP384R1_SHA384 };
+ int nid[1] = { NID_secp384r1 };
+
+ if (SSL_set1_curves(ssl, nid, 1) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set Suite B curves");
+ return -1;
+ }
+
+ if (SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, sigalgs,
+ 1) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set Suite B sigalgs");
+ return -1;
+ }
+ }
+#else /* OPENSSL_IS_BORINGSSL */
+ if (!(flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) &&
+ openssl_ciphers && SSL_set_cipher_list(ssl, openssl_ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set openssl_ciphers '%s'",
+ openssl_ciphers);
+ return -1;
+ }
+#endif /* OPENSSL_IS_BORINGSSL */
+#else /* CONFIG_SUITEB */
+ if (openssl_ciphers && SSL_set_cipher_list(ssl, openssl_ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set openssl_ciphers '%s'",
+ openssl_ciphers);
+ return -1;
+ }
#endif /* CONFIG_SUITEB */
return 0;
@@ -2561,7 +3058,7 @@
SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
}
- if (tls_set_conn_flags(conn, flags) < 0)
+ if (tls_set_conn_flags(conn, flags, NULL) < 0)
return -1;
conn->flags = flags;
@@ -2656,6 +3153,15 @@
return 0;
}
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
+ !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL)
+ if (SSL_use_certificate_chain_file(conn->ssl, client_cert) == 1) {
+ ERR_clear_error();
+ wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_chain_file"
+ " --> OK");
+ return 0;
+ }
+#else
if (SSL_use_certificate_file(conn->ssl, client_cert,
SSL_FILETYPE_PEM) == 1) {
ERR_clear_error();
@@ -2663,6 +3169,7 @@
" --> OK");
return 0;
}
+#endif
tls_show_errors(MSG_DEBUG, __func__,
"SSL_use_certificate_file failed");
@@ -2702,16 +3209,6 @@
}
-static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
-{
- if (password == NULL) {
- return 0;
- }
- os_strlcpy(buf, (char *) password, size);
- return os_strlen(buf);
-}
-
-
#ifdef PKCS12_FUNCS
static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
const char *passwd)
@@ -3030,16 +3527,61 @@
}
-static void tls_clear_default_passwd_cb(SSL_CTX *ssl_ctx, SSL *ssl)
+#ifndef OPENSSL_NO_STDIO
+static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
{
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL)
- if (ssl) {
- SSL_set_default_passwd_cb(ssl, NULL);
- SSL_set_default_passwd_cb_userdata(ssl, NULL);
+ if (!password)
+ return 0;
+ os_strlcpy(buf, (const char *) password, size);
+ return os_strlen(buf);
+}
+#endif /* OPENSSL_NO_STDIO */
+
+
+static int tls_use_private_key_file(struct tls_data *data, SSL *ssl,
+ const char *private_key,
+ const char *private_key_passwd)
+{
+#ifndef OPENSSL_NO_STDIO
+ BIO *bio;
+ EVP_PKEY *pkey;
+ int ret;
+
+ /* First try ASN.1 (DER). */
+ bio = BIO_new_file(private_key, "r");
+ if (!bio)
+ return -1;
+ pkey = d2i_PrivateKey_bio(bio, NULL);
+ BIO_free(bio);
+
+ if (pkey) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s (DER) --> loaded", __func__);
+ } else {
+ /* Try PEM with the provided password. */
+ bio = BIO_new_file(private_key, "r");
+ if (!bio)
+ return -1;
+ pkey = PEM_read_bio_PrivateKey(bio, NULL, tls_passwd_cb,
+ (void *) private_key_passwd);
+ BIO_free(bio);
+ if (!pkey)
+ return -1;
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s (PEM) --> loaded", __func__);
+ /* Clear errors from the previous failed load. */
+ ERR_clear_error();
}
-#endif /* >= 1.1.0f && !LibreSSL && !BoringSSL */
- SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
- SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, NULL);
+
+ if (ssl)
+ ret = SSL_use_PrivateKey(ssl, pkey);
+ else
+ ret = SSL_CTX_use_PrivateKey(data->ssl, pkey);
+
+ EVP_PKEY_free(pkey);
+ return ret == 1 ? 0 : -1;
+#else /* OPENSSL_NO_STDIO */
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
+ return -1;
+#endif /* OPENSSL_NO_STDIO */
}
@@ -3050,32 +3592,11 @@
const u8 *private_key_blob,
size_t private_key_blob_len)
{
- SSL_CTX *ssl_ctx = data->ssl;
- char *passwd;
int ok;
if (private_key == NULL && private_key_blob == NULL)
return 0;
- if (private_key_passwd) {
- passwd = os_strdup(private_key_passwd);
- if (passwd == NULL)
- return -1;
- } else
- passwd = NULL;
-
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL)
- /*
- * In OpenSSL >= 1.1.0f SSL_use_PrivateKey_file() uses the callback
- * from the SSL object. See OpenSSL commit d61461a75253.
- */
- SSL_set_default_passwd_cb(conn->ssl, tls_passwd_cb);
- SSL_set_default_passwd_cb_userdata(conn->ssl, passwd);
-#endif /* >= 1.1.0f && !LibreSSL && !BoringSSL */
- /* Keep these for OpenSSL < 1.1.0f */
- SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
- SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
-
ok = 0;
while (private_key_blob) {
if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl,
@@ -3106,7 +3627,8 @@
}
if (tls_read_pkcs12_blob(data, conn->ssl, private_key_blob,
- private_key_blob_len, passwd) == 0) {
+ private_key_blob_len,
+ private_key_passwd) == 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> "
"OK");
ok = 1;
@@ -3117,29 +3639,14 @@
}
while (!ok && private_key) {
-#ifndef OPENSSL_NO_STDIO
- if (SSL_use_PrivateKey_file(conn->ssl, private_key,
- SSL_FILETYPE_ASN1) == 1) {
- wpa_printf(MSG_DEBUG, "OpenSSL: "
- "SSL_use_PrivateKey_File (DER) --> OK");
+ if (tls_use_private_key_file(data, conn->ssl, private_key,
+ private_key_passwd) == 0) {
ok = 1;
break;
}
- if (SSL_use_PrivateKey_file(conn->ssl, private_key,
- SSL_FILETYPE_PEM) == 1) {
- wpa_printf(MSG_DEBUG, "OpenSSL: "
- "SSL_use_PrivateKey_File (PEM) --> OK");
- ok = 1;
- break;
- }
-#else /* OPENSSL_NO_STDIO */
- wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
- __func__);
-#endif /* OPENSSL_NO_STDIO */
-
- if (tls_read_pkcs12(data, conn->ssl, private_key, passwd)
- == 0) {
+ if (tls_read_pkcs12(data, conn->ssl, private_key,
+ private_key_passwd) == 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file "
"--> OK");
ok = 1;
@@ -3159,13 +3666,9 @@
if (!ok) {
tls_show_errors(MSG_INFO, __func__,
"Failed to load private key");
- tls_clear_default_passwd_cb(ssl_ctx, conn->ssl);
- os_free(passwd);
return -1;
}
ERR_clear_error();
- tls_clear_default_passwd_cb(ssl_ctx, conn->ssl);
- os_free(passwd);
if (!SSL_check_private_key(conn->ssl)) {
tls_show_errors(MSG_INFO, __func__, "Private key failed "
@@ -3183,37 +3686,18 @@
const char *private_key_passwd)
{
SSL_CTX *ssl_ctx = data->ssl;
- char *passwd;
if (private_key == NULL)
return 0;
- if (private_key_passwd) {
- passwd = os_strdup(private_key_passwd);
- if (passwd == NULL)
- return -1;
- } else
- passwd = NULL;
-
- SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
- SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
- if (
-#ifndef OPENSSL_NO_STDIO
- SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
- SSL_FILETYPE_ASN1) != 1 &&
- SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
- SSL_FILETYPE_PEM) != 1 &&
-#endif /* OPENSSL_NO_STDIO */
- tls_read_pkcs12(data, NULL, private_key, passwd)) {
+ if (tls_use_private_key_file(data, NULL, private_key,
+ private_key_passwd) &&
+ tls_read_pkcs12(data, NULL, private_key, private_key_passwd)) {
tls_show_errors(MSG_INFO, __func__,
"Failed to load private key");
- tls_clear_default_passwd_cb(ssl_ctx, NULL);
- os_free(passwd);
ERR_clear_error();
return -1;
}
- tls_clear_default_passwd_cb(ssl_ctx, NULL);
- os_free(passwd);
ERR_clear_error();
if (!SSL_CTX_check_private_key(ssl_ctx)) {
@@ -3401,7 +3885,9 @@
#ifdef OPENSSL_NEED_EAP_FAST_PRF
static int openssl_get_keyblock_size(SSL *ssl)
{
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
const EVP_CIPHER *c;
const EVP_MD *h;
int md_size;
@@ -3457,11 +3943,13 @@
int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
- const char *label, u8 *out, size_t out_len)
+ const char *label, const u8 *context,
+ size_t context_len, u8 *out, size_t out_len)
{
if (!conn ||
SSL_export_keying_material(conn->ssl, out, out_len, label,
- os_strlen(label), NULL, 0, 0) != 1)
+ os_strlen(label), context, context_len,
+ context != NULL) != 1)
return -1;
return 0;
}
@@ -3548,8 +4036,7 @@
static struct wpabuf *
-openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data,
- int server)
+openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data)
{
int res;
struct wpabuf *out_data;
@@ -3567,7 +4054,7 @@
}
/* Initiate TLS handshake or continue the existing handshake */
- if (server)
+ if (conn->server)
res = SSL_accept(conn->ssl);
else
res = SSL_connect(conn->ssl);
@@ -3582,11 +4069,25 @@
else {
tls_show_errors(MSG_INFO, __func__, "SSL_connect");
conn->failed++;
+ if (!conn->server && !conn->client_hello_generated) {
+ /* The server would not understand TLS Alert
+ * before ClientHello, so simply terminate
+ * handshake on this type of error case caused
+ * by a likely internal error like no ciphers
+ * available. */
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not generate ClientHello");
+ conn->write_alerts++;
+ return NULL;
+ }
}
}
+ if (!conn->server && !conn->failed)
+ conn->client_hello_generated = 1;
+
#ifdef CONFIG_SUITEB
- if ((conn->flags & TLS_CONN_SUITEB) && !server &&
+ if ((conn->flags & TLS_CONN_SUITEB) && !conn->server &&
os_strncmp(SSL_get_cipher(conn->ssl), "DHE-", 4) == 0 &&
conn->server_dh_prime_len < 3072) {
struct tls_context *context = conn->context;
@@ -3689,14 +4190,14 @@
static struct wpabuf *
openssl_connection_handshake(struct tls_connection *conn,
const struct wpabuf *in_data,
- struct wpabuf **appl_data, int server)
+ struct wpabuf **appl_data)
{
struct wpabuf *out_data;
if (appl_data)
*appl_data = NULL;
- out_data = openssl_handshake(conn, in_data, server);
+ out_data = openssl_handshake(conn, in_data);
if (out_data == NULL)
return NULL;
if (conn->invalid_hb_used) {
@@ -3733,7 +4234,7 @@
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
- return openssl_connection_handshake(conn, in_data, appl_data, 0);
+ return openssl_connection_handshake(conn, in_data, appl_data);
}
@@ -3742,7 +4243,8 @@
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
- return openssl_connection_handshake(conn, in_data, appl_data, 1);
+ conn->server = 1;
+ return openssl_connection_handshake(conn, in_data, appl_data);
}
@@ -3837,7 +4339,7 @@
int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
{
- return conn ? SSL_cache_hit(conn->ssl) : 0;
+ return conn ? SSL_session_reused(conn->ssl) : 0;
}
@@ -4283,6 +4785,7 @@
const char *cert_id = params->cert_id;
const char *ca_cert_id = params->ca_cert_id;
const char *engine_id = params->engine ? params->engine_id : NULL;
+ const char *ciphers;
if (conn == NULL)
return -1;
@@ -4335,6 +4838,17 @@
}
}
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L
+#ifdef SSL_OP_NO_TLSv1_3
+ if (params->flags & TLS_CONN_EAP_FAST) {
+ /* Need to disable TLS v1.3 at least for now since OpenSSL 1.1.1
+ * refuses to start the handshake with the modified ciphersuite
+ * list (no TLS v1.3 ciphersuites included) for EAP-FAST. */
+ wpa_printf(MSG_DEBUG, "OpenSSL: Disable TLSv1.3 for EAP-FAST");
+ SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1_3);
+ }
+#endif /* SSL_OP_NO_TLSv1_3 */
+#endif
#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
while ((err = ERR_get_error())) {
@@ -4353,7 +4867,8 @@
params->subject_match,
params->altsubject_match,
params->suffix_match,
- params->domain_match))
+ params->domain_match,
+ params->check_cert_subject))
return -1;
if (engine_id && ca_cert_id) {
@@ -4393,15 +4908,60 @@
return -1;
}
- if (params->openssl_ciphers &&
- SSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) {
+ ciphers = params->openssl_ciphers;
+#ifdef CONFIG_SUITEB
+#ifdef OPENSSL_IS_BORINGSSL
+ if (ciphers && os_strcmp(ciphers, "SUITEB192") == 0) {
+ /* BoringSSL removed support for SUITEB192, so need to handle
+ * this with hardcoded ciphersuite and additional checks for
+ * other parameters. */
+ ciphers = "ECDHE-ECDSA-AES256-GCM-SHA384";
+ }
+#endif /* OPENSSL_IS_BORINGSSL */
+#endif /* CONFIG_SUITEB */
+ if (ciphers && SSL_set_cipher_list(conn->ssl, ciphers) != 1) {
wpa_printf(MSG_INFO,
"OpenSSL: Failed to set cipher string '%s'",
- params->openssl_ciphers);
+ ciphers);
return -1;
}
- if (tls_set_conn_flags(conn, params->flags) < 0)
+ if (!params->openssl_ecdh_curves) {
+#ifndef OPENSSL_IS_BORINGSSL
+#ifndef OPENSSL_NO_EC
+#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \
+ (OPENSSL_VERSION_NUMBER < 0x10100000L)
+ if (SSL_set_ecdh_auto(conn->ssl, 1) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set ECDH curves to auto");
+ return -1;
+ }
+#endif /* >= 1.0.2 && < 1.1.0 */
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_IS_BORINGSSL */
+ } else if (params->openssl_ecdh_curves[0]) {
+#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L)
+ wpa_printf(MSG_INFO,
+ "OpenSSL: ECDH configuration nnot supported");
+ return -1;
+#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */
+#ifndef OPENSSL_NO_EC
+ if (SSL_set1_curves_list(conn->ssl,
+ params->openssl_ecdh_curves) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set ECDH curves '%s'",
+ params->openssl_ecdh_curves);
+ return -1;
+ }
+#else /* OPENSSL_NO_EC */
+ wpa_printf(MSG_INFO, "OpenSSL: ECDH not supported");
+ return -1;
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_IS_BORINGSSL */
+ }
+
+ if (tls_set_conn_flags(conn, params->flags,
+ params->openssl_ciphers) < 0)
return -1;
#ifdef OPENSSL_IS_BORINGSSL
@@ -4449,6 +5009,15 @@
__func__, ERR_error_string(err, NULL));
}
+ os_free(data->check_cert_subject);
+ data->check_cert_subject = NULL;
+ if (params->check_cert_subject) {
+ data->check_cert_subject =
+ os_strdup(params->check_cert_subject);
+ if (!data->check_cert_subject)
+ return -1;
+ }
+
if (tls_global_ca_cert(data, params->ca_cert) ||
tls_global_client_cert(data, params->client_cert) ||
tls_global_private_key(data, params->private_key,
@@ -4466,6 +5035,44 @@
return -1;
}
+ if (!params->openssl_ecdh_curves) {
+#ifndef OPENSSL_IS_BORINGSSL
+#ifndef OPENSSL_NO_EC
+#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \
+ (OPENSSL_VERSION_NUMBER < 0x10100000L)
+ if (SSL_CTX_set_ecdh_auto(ssl_ctx, 1) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set ECDH curves to auto");
+ return -1;
+ }
+#endif /* >= 1.0.2 && < 1.1.0 */
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_IS_BORINGSSL */
+ } else if (params->openssl_ecdh_curves[0]) {
+#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L)
+ wpa_printf(MSG_INFO,
+ "OpenSSL: ECDH configuration nnot supported");
+ return -1;
+#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */
+#ifndef OPENSSL_NO_EC
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ SSL_CTX_set_ecdh_auto(ssl_ctx, 1);
+#endif
+ if (SSL_CTX_set1_curves_list(ssl_ctx,
+ params->openssl_ecdh_curves) !=
+ 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set ECDH curves '%s'",
+ params->openssl_ecdh_curves);
+ return -1;
+ }
+#else /* OPENSSL_NO_EC */
+ wpa_printf(MSG_INFO, "OpenSSL: ECDH not supported");
+ return -1;
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_IS_BORINGSSL */
+ }
+
#ifdef SSL_OP_NO_TICKET
if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
@@ -4506,7 +5113,9 @@
struct tls_connection *conn = arg;
int ret;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
if (conn == NULL || conn->session_ticket_cb == NULL)
return 0;
diff --git a/src/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c
new file mode 100644
index 0000000..e9cb425
--- /dev/null
+++ b/src/crypto/tls_wolfssl.c
@@ -0,0 +1,2201 @@
+/*
+ * SSL/TLS interface functions for wolfSSL TLS case
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "tls.h"
+
+/* wolfSSL includes */
+#include <wolfssl/options.h>
+#include <wolfssl/ssl.h>
+#include <wolfssl/error-ssl.h>
+#include <wolfssl/wolfcrypt/asn.h>
+
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+#define HAVE_AESGCM
+#include <wolfssl/wolfcrypt/aes.h>
+#endif
+
+#if !defined(CONFIG_FIPS) && \
+ (defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \
+ defined(EAP_SERVER_FAST))
+#define WOLFSSL_NEED_EAP_FAST_PRF
+#endif
+
+#define SECRET_LEN 48
+#define RAN_LEN 32
+#define SESSION_TICKET_LEN 256
+
+static int tls_ref_count = 0;
+
+static int tls_ex_idx_session = 0;
+
+
+/* tls input data for wolfSSL Read Callback */
+struct tls_in_data {
+ const struct wpabuf *in_data;
+ size_t consumed; /* how many bytes have we used already */
+};
+
+/* tls output data for wolfSSL Write Callback */
+struct tls_out_data {
+ struct wpabuf *out_data;
+};
+
+struct tls_context {
+ void (*event_cb)(void *ctx, enum tls_event ev,
+ union tls_event_data *data);
+ void *cb_ctx;
+ int cert_in_cb;
+ char *ocsp_stapling_response;
+};
+
+static struct tls_context *tls_global = NULL;
+
+/* wolfssl tls_connection */
+struct tls_connection {
+ struct tls_context *context;
+ WOLFSSL *ssl;
+ int read_alerts;
+ int write_alerts;
+ int failed;
+ struct tls_in_data input;
+ struct tls_out_data output;
+ char *subject_match;
+ char *alt_subject_match;
+ char *suffix_match;
+ char *domain_match;
+
+ u8 srv_cert_hash[32];
+
+ unsigned char client_random[RAN_LEN];
+ unsigned char server_random[RAN_LEN];
+ unsigned int flags;
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+ tls_session_ticket_cb session_ticket_cb;
+ void *session_ticket_cb_ctx;
+ byte session_ticket[SESSION_TICKET_LEN];
+#endif
+ unsigned int ca_cert_verify:1;
+ unsigned int cert_probe:1;
+ unsigned int server_cert_only:1;
+ unsigned int success_data:1;
+
+ WOLFSSL_X509 *peer_cert;
+ WOLFSSL_X509 *peer_issuer;
+ WOLFSSL_X509 *peer_issuer_issuer;
+};
+
+
+static struct tls_context * tls_context_new(const struct tls_config *conf)
+{
+ struct tls_context *context = os_zalloc(sizeof(*context));
+
+ if (!context)
+ return NULL;
+
+ if (conf) {
+ context->event_cb = conf->event_cb;
+ context->cb_ctx = conf->cb_ctx;
+ context->cert_in_cb = conf->cert_in_cb;
+ }
+
+ return context;
+}
+
+
+static void wolfssl_reset_in_data(struct tls_in_data *in,
+ const struct wpabuf *buf)
+{
+ /* old one not owned by us so don't free */
+ in->in_data = buf;
+ in->consumed = 0;
+}
+
+
+static void wolfssl_reset_out_data(struct tls_out_data *out)
+{
+ /* old one not owned by us so don't free */
+ out->out_data = wpabuf_alloc_copy("", 0);
+}
+
+
+/* wolfSSL I/O Receive CallBack */
+static int wolfssl_receive_cb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
+{
+ size_t get = sz;
+ struct tls_in_data *data = ctx;
+
+ if (!data)
+ return -1;
+
+ if (get > (wpabuf_len(data->in_data) - data->consumed))
+ get = wpabuf_len(data->in_data) - data->consumed;
+
+ os_memcpy(buf, wpabuf_head(data->in_data) + data->consumed, get);
+ data->consumed += get;
+
+ if (get == 0)
+ return -2; /* WANT_READ */
+
+ return (int) get;
+}
+
+
+/* wolfSSL I/O Send CallBack */
+static int wolfssl_send_cb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
+{
+ struct wpabuf *tmp;
+ struct tls_out_data *data = ctx;
+
+ if (!data)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "SSL: adding %d bytes", sz);
+
+ tmp = wpabuf_alloc_copy(buf, sz);
+ if (!tmp)
+ return -1;
+ data->out_data = wpabuf_concat(data->out_data, tmp);
+ if (!data->out_data)
+ return -1;
+
+ return sz;
+}
+
+
+static void remove_session_cb(WOLFSSL_CTX *ctx, WOLFSSL_SESSION *sess)
+{
+ struct wpabuf *buf;
+
+ buf = wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+ if (!buf)
+ return;
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Free application session data %p (sess %p)",
+ buf, sess);
+ wpabuf_free(buf);
+
+ wolfSSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
+}
+
+
+void * tls_init(const struct tls_config *conf)
+{
+ WOLFSSL_CTX *ssl_ctx;
+ struct tls_context *context;
+ const char *ciphers;
+
+#ifdef DEBUG_WOLFSSL
+ wolfSSL_Debugging_ON();
+#endif /* DEBUG_WOLFSSL */
+
+ context = tls_context_new(conf);
+ if (!context)
+ return NULL;
+
+ if (tls_ref_count == 0) {
+ tls_global = context;
+
+ if (wolfSSL_Init() < 0)
+ return NULL;
+ /* wolfSSL_Debugging_ON(); */
+ }
+
+ tls_ref_count++;
+
+ /* start as client */
+ ssl_ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
+ if (!ssl_ctx) {
+ tls_ref_count--;
+ if (context != tls_global)
+ os_free(context);
+ if (tls_ref_count == 0) {
+ os_free(tls_global);
+ tls_global = NULL;
+ }
+ }
+ wolfSSL_SetIORecv(ssl_ctx, wolfssl_receive_cb);
+ wolfSSL_SetIOSend(ssl_ctx, wolfssl_send_cb);
+ wolfSSL_CTX_set_ex_data(ssl_ctx, 0, context);
+
+ if (conf->tls_session_lifetime > 0) {
+ wolfSSL_CTX_set_quiet_shutdown(ssl_ctx, 1);
+ wolfSSL_CTX_set_session_cache_mode(ssl_ctx,
+ SSL_SESS_CACHE_SERVER);
+ wolfSSL_CTX_set_timeout(ssl_ctx, conf->tls_session_lifetime);
+ wolfSSL_CTX_sess_set_remove_cb(ssl_ctx, remove_session_cb);
+ } else {
+ wolfSSL_CTX_set_session_cache_mode(ssl_ctx,
+ SSL_SESS_CACHE_CLIENT);
+ }
+
+ if (conf && conf->openssl_ciphers)
+ ciphers = conf->openssl_ciphers;
+ else
+ ciphers = "ALL";
+ if (wolfSSL_CTX_set_cipher_list(ssl_ctx, ciphers) != 1) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: Failed to set cipher string '%s'",
+ ciphers);
+ tls_deinit(ssl_ctx);
+ return NULL;
+ }
+
+ return ssl_ctx;
+}
+
+
+void tls_deinit(void *ssl_ctx)
+{
+ struct tls_context *context = wolfSSL_CTX_get_ex_data(ssl_ctx, 0);
+
+ if (context != tls_global)
+ os_free(context);
+
+ wolfSSL_CTX_free((WOLFSSL_CTX *) ssl_ctx);
+
+ tls_ref_count--;
+ if (tls_ref_count == 0) {
+ wolfSSL_Cleanup();
+ os_free(tls_global);
+ tls_global = NULL;
+ }
+}
+
+
+int tls_get_errors(void *tls_ctx)
+{
+#ifdef DEBUG_WOLFSSL
+#if 0
+ unsigned long err;
+
+ err = wolfSSL_ERR_peek_last_error_line(NULL, NULL);
+ if (err != 0) {
+ wpa_printf(MSG_INFO, "TLS - SSL error: %s",
+ wolfSSL_ERR_error_string(err, NULL));
+ return 1;
+ }
+#endif
+#endif /* DEBUG_WOLFSSL */
+ return 0;
+}
+
+
+struct tls_connection * tls_connection_init(void *tls_ctx)
+{
+ WOLFSSL_CTX *ssl_ctx = tls_ctx;
+ struct tls_connection *conn;
+
+ wpa_printf(MSG_DEBUG, "SSL: connection init");
+
+ conn = os_zalloc(sizeof(*conn));
+ if (!conn)
+ return NULL;
+ conn->ssl = wolfSSL_new(ssl_ctx);
+ if (!conn->ssl) {
+ os_free(conn);
+ return NULL;
+ }
+
+ wolfSSL_SetIOReadCtx(conn->ssl, &conn->input);
+ wolfSSL_SetIOWriteCtx(conn->ssl, &conn->output);
+ wolfSSL_set_ex_data(conn->ssl, 0, conn);
+ conn->context = wolfSSL_CTX_get_ex_data(ssl_ctx, 0);
+
+ /* Need randoms post-hanshake for EAP-FAST, export key and deriving
+ * session ID in EAP methods. */
+ wolfSSL_KeepArrays(conn->ssl);
+ wolfSSL_KeepHandshakeResources(conn->ssl);
+ wolfSSL_UseClientSuites(conn->ssl);
+
+ return conn;
+}
+
+
+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
+{
+ if (!conn)
+ return;
+
+ wpa_printf(MSG_DEBUG, "SSL: connection deinit");
+
+ /* parts */
+ wolfSSL_free(conn->ssl);
+ os_free(conn->subject_match);
+ os_free(conn->alt_subject_match);
+ os_free(conn->suffix_match);
+ os_free(conn->domain_match);
+
+ /* self */
+ os_free(conn);
+}
+
+
+int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
+{
+ return conn ? wolfSSL_is_init_finished(conn->ssl) : 0;
+}
+
+
+char * tls_connection_peer_serial_num(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ /* TODO */
+ return NULL;
+}
+
+
+int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
+{
+ WOLFSSL_SESSION *session;
+
+ if (!conn)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "SSL: connection shutdown");
+
+ /* Set quiet as OpenSSL does */
+ wolfSSL_set_quiet_shutdown(conn->ssl, 1);
+ wolfSSL_shutdown(conn->ssl);
+
+ session = wolfSSL_get_session(conn->ssl);
+ if (wolfSSL_clear(conn->ssl) != 1)
+ return -1;
+ wolfSSL_set_session(conn->ssl, session);
+
+ return 0;
+}
+
+
+static int tls_connection_set_subject_match(struct tls_connection *conn,
+ const char *subject_match,
+ const char *alt_subject_match,
+ const char *suffix_match,
+ const char *domain_match)
+{
+ os_free(conn->subject_match);
+ conn->subject_match = NULL;
+ if (subject_match) {
+ conn->subject_match = os_strdup(subject_match);
+ if (!conn->subject_match)
+ return -1;
+ }
+
+ os_free(conn->alt_subject_match);
+ conn->alt_subject_match = NULL;
+ if (alt_subject_match) {
+ conn->alt_subject_match = os_strdup(alt_subject_match);
+ if (!conn->alt_subject_match)
+ return -1;
+ }
+
+ os_free(conn->suffix_match);
+ conn->suffix_match = NULL;
+ if (suffix_match) {
+ conn->suffix_match = os_strdup(suffix_match);
+ if (!conn->suffix_match)
+ return -1;
+ }
+
+ os_free(conn->domain_match);
+ conn->domain_match = NULL;
+ if (domain_match) {
+ conn->domain_match = os_strdup(domain_match);
+ if (!conn->domain_match)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int tls_connection_dh(struct tls_connection *conn, const char *dh_file,
+ const u8 *dh_blob, size_t blob_len)
+{
+ if (!dh_file && !dh_blob)
+ return 0;
+
+ wolfSSL_set_accept_state(conn->ssl);
+
+ if (dh_blob) {
+ if (wolfSSL_SetTmpDH_buffer(conn->ssl, dh_blob, blob_len,
+ SSL_FILETYPE_ASN1) < 0) {
+ wpa_printf(MSG_INFO, "SSL: use DH DER blob failed");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "SSL: use DH blob OK");
+ return 0;
+ }
+
+ if (dh_file) {
+ wpa_printf(MSG_INFO, "SSL: use DH PEM file: %s", dh_file);
+ if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file,
+ SSL_FILETYPE_PEM) < 0) {
+ wpa_printf(MSG_INFO, "SSL: use DH PEM file failed");
+ if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file,
+ SSL_FILETYPE_ASN1) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: use DH DER file failed");
+ return -1;
+ }
+ }
+ wpa_printf(MSG_DEBUG, "SSL: use DH file OK");
+ return 0;
+ }
+
+ return 0;
+}
+
+
+static int tls_connection_client_cert(struct tls_connection *conn,
+ const char *client_cert,
+ const u8 *client_cert_blob,
+ size_t blob_len)
+{
+ if (!client_cert && !client_cert_blob)
+ return 0;
+
+ if (client_cert_blob) {
+ if (wolfSSL_use_certificate_chain_buffer_format(
+ conn->ssl, client_cert_blob, blob_len,
+ SSL_FILETYPE_ASN1) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: use client cert DER blob failed");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "SSL: use client cert blob OK");
+ return 0;
+ }
+
+ if (client_cert) {
+ if (wolfSSL_use_certificate_chain_file(conn->ssl,
+ client_cert) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: use client cert PEM file failed");
+ if (wolfSSL_use_certificate_chain_file_format(
+ conn->ssl, client_cert,
+ SSL_FILETYPE_ASN1) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: use client cert DER file failed");
+ return -1;
+ }
+ }
+ wpa_printf(MSG_DEBUG, "SSL: use client cert file OK");
+ return 0;
+ }
+
+ return 0;
+}
+
+
+static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
+{
+ if (!password)
+ return 0;
+ os_strlcpy(buf, (char *) password, size);
+ return os_strlen(buf);
+}
+
+
+static int tls_connection_private_key(void *tls_ctx,
+ struct tls_connection *conn,
+ const char *private_key,
+ const char *private_key_passwd,
+ const u8 *private_key_blob,
+ size_t blob_len)
+{
+ WOLFSSL_CTX *ctx = tls_ctx;
+ char *passwd = NULL;
+ int ok = 0;
+
+ if (!private_key && !private_key_blob)
+ return 0;
+
+ if (private_key_passwd) {
+ passwd = os_strdup(private_key_passwd);
+ if (!passwd)
+ return -1;
+ }
+
+ wolfSSL_CTX_set_default_passwd_cb(ctx, tls_passwd_cb);
+ wolfSSL_CTX_set_default_passwd_cb_userdata(ctx, passwd);
+
+ if (private_key_blob) {
+ if (wolfSSL_use_PrivateKey_buffer(conn->ssl,
+ private_key_blob, blob_len,
+ SSL_FILETYPE_ASN1) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: use private DER blob failed");
+ } else {
+ wpa_printf(MSG_DEBUG, "SSL: use private key blob OK");
+ ok = 1;
+ }
+ }
+
+ if (!ok && private_key) {
+ if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
+ SSL_FILETYPE_PEM) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: use private key PEM file failed");
+ if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
+ SSL_FILETYPE_ASN1) < 0)
+ {
+ wpa_printf(MSG_INFO,
+ "SSL: use private key DER file failed");
+ } else {
+ ok = 1;
+ }
+ } else {
+ ok = 1;
+ }
+
+ if (ok)
+ wpa_printf(MSG_DEBUG, "SSL: use private key file OK");
+ }
+
+ wolfSSL_CTX_set_default_passwd_cb(ctx, NULL);
+ os_free(passwd);
+
+ if (!ok)
+ return -1;
+
+ return 0;
+}
+
+
+static int tls_match_alt_subject_component(WOLFSSL_X509 *cert, int type,
+ const char *value, size_t len)
+{
+ WOLFSSL_ASN1_OBJECT *gen;
+ void *ext;
+ int found = 0;
+ int i;
+
+ ext = wolfSSL_X509_get_ext_d2i(cert, ALT_NAMES_OID, NULL, NULL);
+
+ for (i = 0; ext && i < wolfSSL_sk_num(ext); i++) {
+ gen = wolfSSL_sk_value(ext, i);
+ if (gen->type != type)
+ continue;
+ if (os_strlen((char *) gen->obj) == len &&
+ os_memcmp(value, gen->obj, len) == 0)
+ found++;
+ }
+
+ wolfSSL_sk_ASN1_OBJECT_free(ext);
+
+ return found;
+}
+
+
+static int tls_match_alt_subject(WOLFSSL_X509 *cert, const char *match)
+{
+ int type;
+ const char *pos, *end;
+ size_t len;
+
+ pos = match;
+ do {
+ if (os_strncmp(pos, "EMAIL:", 6) == 0) {
+ type = GEN_EMAIL;
+ pos += 6;
+ } else if (os_strncmp(pos, "DNS:", 4) == 0) {
+ type = GEN_DNS;
+ pos += 4;
+ } else if (os_strncmp(pos, "URI:", 4) == 0) {
+ type = GEN_URI;
+ pos += 4;
+ } else {
+ wpa_printf(MSG_INFO,
+ "TLS: Invalid altSubjectName match '%s'",
+ pos);
+ return 0;
+ }
+ end = os_strchr(pos, ';');
+ while (end) {
+ if (os_strncmp(end + 1, "EMAIL:", 6) == 0 ||
+ os_strncmp(end + 1, "DNS:", 4) == 0 ||
+ os_strncmp(end + 1, "URI:", 4) == 0)
+ break;
+ end = os_strchr(end + 1, ';');
+ }
+ if (end)
+ len = end - pos;
+ else
+ len = os_strlen(pos);
+ if (tls_match_alt_subject_component(cert, type, pos, len) > 0)
+ return 1;
+ pos = end + 1;
+ } while (end);
+
+ return 0;
+}
+
+
+static int domain_suffix_match(const char *val, size_t len, const char *match,
+ size_t match_len, int full)
+{
+ size_t i;
+
+ /* Check for embedded nuls that could mess up suffix matching */
+ for (i = 0; i < len; i++) {
+ if (val[i] == '\0') {
+ wpa_printf(MSG_DEBUG,
+ "TLS: Embedded null in a string - reject");
+ return 0;
+ }
+ }
+
+ if (match_len > len || (full && match_len != len))
+ return 0;
+
+ if (os_strncasecmp(val + len - match_len, match, match_len) != 0)
+ return 0; /* no match */
+
+ if (match_len == len)
+ return 1; /* exact match */
+
+ if (val[len - match_len - 1] == '.')
+ return 1; /* full label match completes suffix match */
+
+ wpa_printf(MSG_DEBUG, "TLS: Reject due to incomplete label match");
+ return 0;
+}
+
+
+static int tls_match_suffix_helper(WOLFSSL_X509 *cert, const char *match,
+ size_t match_len, int full)
+{
+ WOLFSSL_ASN1_OBJECT *gen;
+ void *ext;
+ int i;
+ int j;
+ int dns_name = 0;
+ WOLFSSL_X509_NAME *name;
+
+ wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s",
+ full ? "" : "suffix ", match);
+
+ ext = wolfSSL_X509_get_ext_d2i(cert, ALT_NAMES_OID, NULL, NULL);
+
+ for (j = 0; ext && j < wolfSSL_sk_num(ext); j++) {
+ gen = wolfSSL_sk_value(ext, j);
+ if (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) {
+ 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);
+
+ if (dns_name) {
+ wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
+ return 0;
+ }
+
+ name = wolfSSL_X509_get_subject_name(cert);
+ i = -1;
+ for (;;) {
+ WOLFSSL_X509_NAME_ENTRY *e;
+ WOLFSSL_ASN1_STRING *cn;
+
+ i = wolfSSL_X509_NAME_get_index_by_NID(name, ASN_COMMON_NAME,
+ i);
+ if (i == -1)
+ break;
+ e = wolfSSL_X509_NAME_get_entry(name, i);
+ if (!e)
+ continue;
+ cn = wolfSSL_X509_NAME_ENTRY_get_data(e);
+ if (!cn)
+ continue;
+ wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
+ cn->data, cn->length);
+ if (domain_suffix_match(cn->data, cn->length,
+ match, match_len, full) == 1) {
+ wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
+ full ? "Match" : "Suffix match");
+ return 1;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found",
+ full ? "" : "suffix ");
+ return 0;
+}
+
+
+static int tls_match_suffix(WOLFSSL_X509 *cert, const char *match, int full)
+{
+ const char *token, *last = NULL;
+
+ /* Process each match alternative separately until a match is found */
+ while ((token = cstr_token(match, ";", &last))) {
+ if (tls_match_suffix_helper(cert, token, last - token, full))
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static enum tls_fail_reason wolfssl_tls_fail_reason(int err)
+{
+ switch (err) {
+ case X509_V_ERR_CERT_REVOKED:
+ return TLS_FAIL_REVOKED;
+ case ASN_BEFORE_DATE_E:
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ case X509_V_ERR_CRL_NOT_YET_VALID:
+ return TLS_FAIL_NOT_YET_VALID;
+ case ASN_AFTER_DATE_E:
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ case X509_V_ERR_CRL_HAS_EXPIRED:
+ return TLS_FAIL_EXPIRED;
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ case X509_V_ERR_UNABLE_TO_GET_CRL:
+ case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+ case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+ case X509_V_ERR_CERT_CHAIN_TOO_LONG:
+ case X509_V_ERR_PATH_LENGTH_EXCEEDED:
+ case X509_V_ERR_INVALID_CA:
+ return TLS_FAIL_UNTRUSTED;
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
+ case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
+ case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
+ case X509_V_ERR_CERT_UNTRUSTED:
+ case X509_V_ERR_CERT_REJECTED:
+ return TLS_FAIL_BAD_CERTIFICATE;
+ default:
+ return TLS_FAIL_UNSPECIFIED;
+ }
+}
+
+
+static const char * wolfssl_tls_err_string(int err, const char *err_str)
+{
+ switch (err) {
+ case ASN_BEFORE_DATE_E:
+ return "certificate is not yet valid";
+ case ASN_AFTER_DATE_E:
+ return "certificate has expired";
+ default:
+ return err_str;
+ }
+}
+
+
+static struct wpabuf * get_x509_cert(WOLFSSL_X509 *cert)
+{
+ struct wpabuf *buf = NULL;
+ const u8 *data;
+ int cert_len;
+
+ data = wolfSSL_X509_get_der(cert, &cert_len);
+ if (!data)
+ buf = wpabuf_alloc_copy(data, cert_len);
+
+ return buf;
+}
+
+
+static void wolfssl_tls_fail_event(struct tls_connection *conn,
+ WOLFSSL_X509 *err_cert, int err, int depth,
+ const char *subject, const char *err_str,
+ enum tls_fail_reason reason)
+{
+ union tls_event_data ev;
+ struct wpabuf *cert = NULL;
+ struct tls_context *context = conn->context;
+
+ if (!context->event_cb)
+ return;
+
+ cert = get_x509_cert(err_cert);
+ os_memset(&ev, 0, sizeof(ev));
+ ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ?
+ reason : wolfssl_tls_fail_reason(err);
+ ev.cert_fail.depth = depth;
+ ev.cert_fail.subject = subject;
+ ev.cert_fail.reason_txt = wolfssl_tls_err_string(err, err_str);
+ ev.cert_fail.cert = cert;
+ context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
+ wpabuf_free(cert);
+}
+
+
+static void wolfssl_tls_cert_event(struct tls_connection *conn,
+ WOLFSSL_X509 *err_cert, int depth,
+ const char *subject)
+{
+ struct wpabuf *cert = NULL;
+ union tls_event_data ev;
+ struct tls_context *context = conn->context;
+ char *alt_subject[TLS_MAX_ALT_SUBJECT];
+ int alt, num_alt_subject = 0;
+ WOLFSSL_ASN1_OBJECT *gen;
+ void *ext;
+ int i;
+#ifdef CONFIG_SHA256
+ u8 hash[32];
+#endif /* CONFIG_SHA256 */
+
+ if (!context->event_cb)
+ return;
+
+ os_memset(&ev, 0, sizeof(ev));
+ if (conn->cert_probe || (conn->flags & TLS_CONN_EXT_CERT_CHECK) ||
+ context->cert_in_cb) {
+ cert = get_x509_cert(err_cert);
+ ev.peer_cert.cert = cert;
+ }
+
+#ifdef CONFIG_SHA256
+ if (cert) {
+ const u8 *addr[1];
+ size_t len[1];
+
+ addr[0] = wpabuf_head(cert);
+ len[0] = wpabuf_len(cert);
+ if (sha256_vector(1, addr, len, hash) == 0) {
+ ev.peer_cert.hash = hash;
+ ev.peer_cert.hash_len = sizeof(hash);
+ }
+ }
+#endif /* CONFIG_SHA256 */
+
+ ev.peer_cert.depth = depth;
+ ev.peer_cert.subject = subject;
+
+ ext = wolfSSL_X509_get_ext_d2i(err_cert, ALT_NAMES_OID, NULL, NULL);
+ for (i = 0; ext && i < wolfSSL_sk_num(ext); i++) {
+ char *pos;
+
+ 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)
+ continue;
+
+ pos = os_malloc(10 + os_strlen((char *) gen->obj) + 1);
+ if (!pos)
+ break;
+ alt_subject[num_alt_subject++] = pos;
+
+ switch (gen->type) {
+ case GEN_EMAIL:
+ os_memcpy(pos, "EMAIL:", 6);
+ pos += 6;
+ break;
+ case GEN_DNS:
+ os_memcpy(pos, "DNS:", 4);
+ pos += 4;
+ break;
+ case GEN_URI:
+ os_memcpy(pos, "URI:", 4);
+ pos += 4;
+ break;
+ }
+
+ os_memcpy(pos, gen->obj, os_strlen((char *)gen->obj));
+ pos += os_strlen((char *)gen->obj);
+ *pos = '\0';
+ }
+ wolfSSL_sk_ASN1_OBJECT_free(ext);
+
+ for (alt = 0; alt < num_alt_subject; alt++)
+ ev.peer_cert.altsubject[alt] = alt_subject[alt];
+ ev.peer_cert.num_altsubject = num_alt_subject;
+
+ context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
+ wpabuf_free(cert);
+ for (alt = 0; alt < num_alt_subject; alt++)
+ os_free(alt_subject[alt]);
+}
+
+
+static int tls_verify_cb(int preverify_ok, WOLFSSL_X509_STORE_CTX *x509_ctx)
+{
+ char buf[256];
+ WOLFSSL_X509 *err_cert;
+ int err, depth;
+ WOLFSSL *ssl;
+ struct tls_connection *conn;
+ struct tls_context *context;
+ char *match, *altmatch, *suffix_match, *domain_match;
+ const char *err_str;
+
+ err_cert = wolfSSL_X509_STORE_CTX_get_current_cert(x509_ctx);
+ if (!err_cert) {
+ wpa_printf(MSG_DEBUG, "wolfSSL: No Cert");
+ return 0;
+ }
+
+ err = wolfSSL_X509_STORE_CTX_get_error(x509_ctx);
+ depth = wolfSSL_X509_STORE_CTX_get_error_depth(x509_ctx);
+ ssl = wolfSSL_X509_STORE_CTX_get_ex_data(
+ x509_ctx, wolfSSL_get_ex_data_X509_STORE_CTX_idx());
+ wolfSSL_X509_NAME_oneline(wolfSSL_X509_get_subject_name(err_cert), buf,
+ sizeof(buf));
+
+ conn = wolfSSL_get_ex_data(ssl, 0);
+ if (!conn) {
+ wpa_printf(MSG_DEBUG, "wolfSSL: No ex_data");
+ return 0;
+ }
+
+ if (depth == 0)
+ conn->peer_cert = err_cert;
+ else if (depth == 1)
+ conn->peer_issuer = err_cert;
+ else if (depth == 2)
+ conn->peer_issuer_issuer = err_cert;
+
+ context = conn->context;
+ match = conn->subject_match;
+ altmatch = conn->alt_subject_match;
+ suffix_match = conn->suffix_match;
+ domain_match = conn->domain_match;
+
+ if (!preverify_ok && !conn->ca_cert_verify)
+ preverify_ok = 1;
+ if (!preverify_ok && depth > 0 && conn->server_cert_only)
+ preverify_ok = 1;
+ if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) &&
+ (err == X509_V_ERR_CERT_HAS_EXPIRED ||
+ err == ASN_AFTER_DATE_E || err == ASN_BEFORE_DATE_E ||
+ err == X509_V_ERR_CERT_NOT_YET_VALID)) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Ignore certificate validity time mismatch");
+ preverify_ok = 1;
+ }
+
+ err_str = wolfSSL_X509_verify_cert_error_string(err);
+
+#ifdef CONFIG_SHA256
+ /*
+ * Do not require preverify_ok so we can explicity allow otherwise
+ * invalid pinned server certificates.
+ */
+ if (depth == 0 && conn->server_cert_only) {
+ struct wpabuf *cert;
+
+ cert = get_x509_cert(err_cert);
+ if (!cert) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Could not fetch server certificate data");
+ preverify_ok = 0;
+ } else {
+ u8 hash[32];
+ const u8 *addr[1];
+ size_t len[1];
+
+ addr[0] = wpabuf_head(cert);
+ len[0] = wpabuf_len(cert);
+ if (sha256_vector(1, addr, len, hash) < 0 ||
+ os_memcmp(conn->srv_cert_hash, hash, 32) != 0) {
+ err_str = "Server certificate mismatch";
+ err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
+ preverify_ok = 0;
+ } else if (!preverify_ok) {
+ /*
+ * Certificate matches pinned certificate, allow
+ * regardless of other problems.
+ */
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Ignore validation issues for a pinned server certificate");
+ preverify_ok = 1;
+ }
+ wpabuf_free(cert);
+ }
+ }
+#endif /* CONFIG_SHA256 */
+
+ if (!preverify_ok) {
+ wpa_printf(MSG_WARNING,
+ "TLS: Certificate verification failed, error %d (%s) depth %d for '%s'",
+ err, err_str, depth, buf);
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ err_str, TLS_FAIL_UNSPECIFIED);
+ return preverify_ok;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "TLS: %s - preverify_ok=%d err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
+ __func__, preverify_ok, err, err_str,
+ conn->ca_cert_verify, depth, buf);
+ if (depth == 0 && match && os_strstr(buf, match) == NULL) {
+ wpa_printf(MSG_WARNING,
+ "TLS: Subject '%s' did not match with '%s'",
+ buf, match);
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "Subject mismatch",
+ TLS_FAIL_SUBJECT_MISMATCH);
+ } else if (depth == 0 && altmatch &&
+ !tls_match_alt_subject(err_cert, altmatch)) {
+ wpa_printf(MSG_WARNING,
+ "TLS: altSubjectName match '%s' not found",
+ altmatch);
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "AltSubject mismatch",
+ TLS_FAIL_ALTSUBJECT_MISMATCH);
+ } else if (depth == 0 && suffix_match &&
+ !tls_match_suffix(err_cert, suffix_match, 0)) {
+ wpa_printf(MSG_WARNING,
+ "TLS: Domain suffix match '%s' not found",
+ suffix_match);
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "Domain suffix mismatch",
+ TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
+ } else if (depth == 0 && domain_match &&
+ !tls_match_suffix(err_cert, domain_match, 1)) {
+ wpa_printf(MSG_WARNING, "TLS: Domain match '%s' not found",
+ domain_match);
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "Domain mismatch",
+ TLS_FAIL_DOMAIN_MISMATCH);
+ } else {
+ wolfssl_tls_cert_event(conn, err_cert, depth, buf);
+ }
+
+ if (conn->cert_probe && preverify_ok && depth == 0) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Reject server certificate on probe-only run");
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "Server certificate chain probe",
+ TLS_FAIL_SERVER_CHAIN_PROBE);
+ }
+
+#ifdef HAVE_OCSP_WOLFSSL
+ if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) &&
+ preverify_ok) {
+ enum ocsp_result res;
+
+ res = check_ocsp_resp(conn->ssl_ctx, conn->ssl, err_cert,
+ conn->peer_issuer,
+ conn->peer_issuer_issuer);
+ if (res == OCSP_REVOKED) {
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "certificate revoked",
+ TLS_FAIL_REVOKED);
+ if (err == X509_V_OK)
+ X509_STORE_CTX_set_error(
+ x509_ctx, X509_V_ERR_CERT_REVOKED);
+ } else if (res != OCSP_GOOD &&
+ (conn->flags & TLS_CONN_REQUIRE_OCSP)) {
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "bad certificate status response",
+ TLS_FAIL_UNSPECIFIED);
+ }
+ }
+#endif /* HAVE_OCSP_WOLFSSL */
+ if (depth == 0 && preverify_ok && context->event_cb != NULL)
+ context->event_cb(context->cb_ctx,
+ TLS_CERT_CHAIN_SUCCESS, NULL);
+
+ return preverify_ok;
+}
+
+
+static int tls_connection_ca_cert(void *tls_ctx, struct tls_connection *conn,
+ const char *ca_cert,
+ const u8 *ca_cert_blob, size_t blob_len,
+ const char *ca_path)
+{
+ WOLFSSL_CTX *ctx = tls_ctx;
+
+ wolfSSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+ conn->ca_cert_verify = 1;
+
+ if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Probe for server certificate chain");
+ conn->cert_probe = 1;
+ conn->ca_cert_verify = 0;
+ return 0;
+ }
+
+ if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) {
+#ifdef CONFIG_SHA256
+ const char *pos = ca_cert + 7;
+
+ if (os_strncmp(pos, "server/sha256/", 14) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Unsupported ca_cert hash value '%s'",
+ ca_cert);
+ return -1;
+ }
+ pos += 14;
+ if (os_strlen(pos) != 32 * 2) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Unexpected SHA256 hash length in ca_cert '%s'",
+ ca_cert);
+ return -1;
+ }
+ if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Invalid SHA256 hash value in ca_cert '%s'",
+ ca_cert);
+ return -1;
+ }
+ conn->server_cert_only = 1;
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Checking only server certificate match");
+ return 0;
+#else /* CONFIG_SHA256 */
+ wpa_printf(MSG_INFO,
+ "No SHA256 included in the build - cannot validate server certificate hash");
+ return -1;
+#endif /* CONFIG_SHA256 */
+ }
+
+ if (ca_cert_blob) {
+ if (wolfSSL_CTX_load_verify_buffer(ctx, ca_cert_blob, blob_len,
+ SSL_FILETYPE_ASN1) !=
+ SSL_SUCCESS) {
+ wpa_printf(MSG_INFO, "SSL: failed to load CA blob");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "SSL: use CA cert blob OK");
+ return 0;
+ }
+
+ if (ca_cert || ca_path) {
+ WOLFSSL_X509_STORE *cm = wolfSSL_X509_STORE_new();
+
+ if (!cm) {
+ wpa_printf(MSG_INFO,
+ "SSL: failed to create certificate store");
+ return -1;
+ }
+ wolfSSL_CTX_set_cert_store(ctx, cm);
+
+ if (wolfSSL_CTX_load_verify_locations(ctx, ca_cert, ca_path) !=
+ SSL_SUCCESS) {
+ wpa_printf(MSG_INFO,
+ "SSL: failed to load ca_cert as PEM");
+
+ if (!ca_cert)
+ return -1;
+
+ if (wolfSSL_CTX_der_load_verify_locations(
+ ctx, ca_cert, SSL_FILETYPE_ASN1) !=
+ SSL_SUCCESS) {
+ wpa_printf(MSG_INFO,
+ "SSL: failed to load ca_cert as DER");
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ conn->ca_cert_verify = 0;
+ return 0;
+}
+
+
+static void tls_set_conn_flags(WOLFSSL *ssl, unsigned int flags)
+{
+#ifdef HAVE_SESSION_TICKET
+#if 0
+ if (!(flags & TLS_CONN_DISABLE_SESSION_TICKET))
+ wolfSSL_UseSessionTicket(ssl);
+#endif
+#endif /* HAVE_SESSION_TICKET */
+
+ if (flags & TLS_CONN_DISABLE_TLSv1_0)
+ wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1);
+ if (flags & TLS_CONN_DISABLE_TLSv1_1)
+ wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
+ if (flags & TLS_CONN_DISABLE_TLSv1_2)
+ wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_2);
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+ const struct tls_connection_params *params)
+{
+ wpa_printf(MSG_DEBUG, "SSL: set params");
+
+ if (tls_connection_set_subject_match(conn, params->subject_match,
+ params->altsubject_match,
+ params->suffix_match,
+ params->domain_match) < 0) {
+ wpa_printf(MSG_INFO, "Error setting subject match");
+ return -1;
+ }
+
+ if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
+ params->ca_cert_blob,
+ params->ca_cert_blob_len,
+ params->ca_path) < 0) {
+ wpa_printf(MSG_INFO, "Error setting CA cert");
+ return -1;
+ }
+
+ if (tls_connection_client_cert(conn, params->client_cert,
+ params->client_cert_blob,
+ params->client_cert_blob_len) < 0) {
+ wpa_printf(MSG_INFO, "Error setting client cert");
+ return -1;
+ }
+
+ if (tls_connection_private_key(tls_ctx, conn, params->private_key,
+ params->private_key_passwd,
+ params->private_key_blob,
+ params->private_key_blob_len) < 0) {
+ wpa_printf(MSG_INFO, "Error setting private key");
+ return -1;
+ }
+
+ if (tls_connection_dh(conn, params->dh_file, params->dh_blob,
+ params->dh_blob_len) < 0) {
+ wpa_printf(MSG_INFO, "Error setting DH");
+ return -1;
+ }
+
+ if (params->openssl_ciphers &&
+ wolfSSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "wolfSSL: Failed to set cipher string '%s'",
+ params->openssl_ciphers);
+ return -1;
+ }
+
+ tls_set_conn_flags(conn->ssl, params->flags);
+
+#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+ if (params->flags & TLS_CONN_REQUEST_OCSP) {
+ if (wolfSSL_UseOCSPStapling(conn->ssl, WOLFSSL_CSR_OCSP,
+ WOLFSSL_CSR_OCSP_USE_NONCE) !=
+ SSL_SUCCESS)
+ return -1;
+ wolfSSL_CTX_EnableOCSP(tls_ctx, 0);
+ }
+#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */
+#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
+ if (params->flags & TLS_CONN_REQUEST_OCSP) {
+ if (wolfSSL_UseOCSPStaplingV2(conn->ssl,
+ WOLFSSL_CSR2_OCSP_MULTI, 0) !=
+ SSL_SUCCESS)
+ return -1;
+ wolfSSL_CTX_EnableOCSP(tls_ctx, 0);
+ }
+#endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */
+#if !defined(HAVE_CERTIFICATE_STATUS_REQUEST) && \
+ !defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
+#ifdef HAVE_OCSP
+ if (params->flags & TLS_CONN_REQUEST_OCSP)
+ wolfSSL_CTX_EnableOCSP(ctx, 0);
+#else /* HAVE_OCSP */
+ if (params->flags & TLS_CONN_REQUIRE_OCSP) {
+ wpa_printf(MSG_INFO,
+ "wolfSSL: No OCSP support included - reject configuration");
+ return -1;
+ }
+ if (params->flags & TLS_CONN_REQUEST_OCSP) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: No OCSP support included - allow optional OCSP case to continue");
+ }
+#endif /* HAVE_OCSP */
+#endif /* !HAVE_CERTIFICATE_STATUS_REQUEST &&
+ * !HAVE_CERTIFICATE_STATUS_REQUEST_V2 */
+
+ conn->flags = params->flags;
+
+ return 0;
+}
+
+
+static int tls_global_ca_cert(void *ssl_ctx, const char *ca_cert)
+{
+ WOLFSSL_CTX *ctx = ssl_ctx;
+
+ if (ca_cert) {
+ if (wolfSSL_CTX_load_verify_locations(ctx, ca_cert, NULL) != 1)
+ {
+ wpa_printf(MSG_WARNING,
+ "Failed to load root certificates");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "TLS: Trusted root certificate(s) loaded");
+ }
+
+ return 0;
+}
+
+
+static int tls_global_client_cert(void *ssl_ctx, const char *client_cert)
+{
+ WOLFSSL_CTX *ctx = ssl_ctx;
+
+ if (!client_cert)
+ return 0;
+
+ if (wolfSSL_CTX_use_certificate_chain_file_format(ctx, client_cert,
+ SSL_FILETYPE_ASN1) !=
+ SSL_SUCCESS &&
+ wolfSSL_CTX_use_certificate_chain_file(ctx, client_cert) !=
+ SSL_SUCCESS) {
+ wpa_printf(MSG_INFO, "Failed to load client certificate");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "SSL: Loaded global client certificate: %s",
+ client_cert);
+
+ return 0;
+}
+
+
+static int tls_global_private_key(void *ssl_ctx, const char *private_key,
+ const char *private_key_passwd)
+{
+ WOLFSSL_CTX *ctx = ssl_ctx;
+ char *passwd = NULL;
+ int ret = 0;
+
+ if (!private_key)
+ return 0;
+
+ if (private_key_passwd) {
+ passwd = os_strdup(private_key_passwd);
+ if (!passwd)
+ return -1;
+ }
+
+ wolfSSL_CTX_set_default_passwd_cb(ctx, tls_passwd_cb);
+ wolfSSL_CTX_set_default_passwd_cb_userdata(ctx, passwd);
+
+ if (wolfSSL_CTX_use_PrivateKey_file(ctx, private_key,
+ SSL_FILETYPE_ASN1) != 1 &&
+ wolfSSL_CTX_use_PrivateKey_file(ctx, private_key,
+ SSL_FILETYPE_PEM) != 1) {
+ wpa_printf(MSG_INFO, "Failed to load private key");
+ ret = -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "SSL: Loaded global private key");
+
+ os_free(passwd);
+ wolfSSL_CTX_set_default_passwd_cb(ctx, NULL);
+
+ return ret;
+}
+
+
+static int tls_global_dh(void *ssl_ctx, const char *dh_file,
+ const u8 *dh_blob, size_t blob_len)
+{
+ WOLFSSL_CTX *ctx = ssl_ctx;
+
+ if (!dh_file && !dh_blob)
+ return 0;
+
+ if (dh_blob) {
+ if (wolfSSL_CTX_SetTmpDH_buffer(ctx, dh_blob, blob_len,
+ SSL_FILETYPE_ASN1) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: global use DH DER blob failed");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "SSL: global use DH blob OK");
+ return 0;
+ }
+
+ if (dh_file) {
+ if (wolfSSL_CTX_SetTmpDH_file(ctx, dh_file, SSL_FILETYPE_PEM) <
+ 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: global use DH PEM file failed");
+ if (wolfSSL_CTX_SetTmpDH_file(ctx, dh_file,
+ SSL_FILETYPE_ASN1) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: global use DH DER file failed");
+ return -1;
+ }
+ }
+ wpa_printf(MSG_DEBUG, "SSL: global use DH file OK");
+ return 0;
+ }
+
+ return 0;
+}
+
+
+#ifdef HAVE_OCSP
+
+int ocsp_status_cb(void *unused, const char *url, int url_sz,
+ unsigned char *request, int request_sz,
+ unsigned char **response)
+{
+ size_t len;
+
+ (void) unused;
+
+ if (!url) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: OCSP status callback - no response configured");
+ *response = NULL;
+ return 0;
+ }
+
+ *response = (unsigned char *) os_readfile(url, &len);
+ if (!*response) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: OCSP status callback - could not read response file");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: OCSP status callback - send cached response");
+ return len;
+}
+
+
+void ocsp_resp_free_cb(void *ocsp_stapling_response, unsigned char *response)
+{
+ os_free(response);
+}
+
+#endif /* HAVE_OCSP */
+
+
+int tls_global_set_params(void *tls_ctx,
+ const struct tls_connection_params *params)
+{
+ wpa_printf(MSG_DEBUG, "SSL: global set params");
+
+ if (params->check_cert_subject)
+ return -1; /* not yet supported */
+
+ if (tls_global_ca_cert(tls_ctx, params->ca_cert) < 0) {
+ wpa_printf(MSG_INFO, "SSL: Failed to load ca cert file '%s'",
+ params->ca_cert);
+ return -1;
+ }
+
+ if (tls_global_client_cert(tls_ctx, params->client_cert) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: Failed to load client cert file '%s'",
+ params->client_cert);
+ return -1;
+ }
+
+ if (tls_global_private_key(tls_ctx, params->private_key,
+ params->private_key_passwd) < 0) {
+ wpa_printf(MSG_INFO,
+ "SSL: Failed to load private key file '%s'",
+ params->private_key);
+ return -1;
+ }
+
+ if (tls_global_dh(tls_ctx, params->dh_file, params->dh_blob,
+ params->dh_blob_len) < 0) {
+ wpa_printf(MSG_INFO, "SSL: Failed to load DH file '%s'",
+ params->dh_file);
+ return -1;
+ }
+
+ if (params->openssl_ciphers &&
+ wolfSSL_CTX_set_cipher_list(tls_ctx,
+ params->openssl_ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "wolfSSL: Failed to set cipher string '%s'",
+ params->openssl_ciphers);
+ return -1;
+ }
+
+ if (params->openssl_ecdh_curves) {
+ wpa_printf(MSG_INFO,
+ "wolfSSL: openssl_ecdh_curves not supported");
+ return -1;
+ }
+
+#ifdef HAVE_SESSION_TICKET
+ /* Session ticket is off by default - can't disable once on. */
+ if (!(params->flags & TLS_CONN_DISABLE_SESSION_TICKET))
+ wolfSSL_CTX_UseSessionTicket(tls_ctx);
+#endif /* HAVE_SESSION_TICKET */
+
+#ifdef HAVE_OCSP
+ if (params->ocsp_stapling_response) {
+ wolfSSL_CTX_SetOCSP_OverrideURL(tls_ctx,
+ params->ocsp_stapling_response);
+ wolfSSL_CTX_SetOCSP_Cb(tls_ctx, ocsp_status_cb,
+ ocsp_resp_free_cb, NULL);
+ }
+#endif /* HAVE_OCSP */
+
+ return 0;
+}
+
+
+int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
+{
+ wpa_printf(MSG_DEBUG, "SSL: global set verify: %d", check_crl);
+
+ if (check_crl) {
+ /* Hack to Enable CRLs. */
+ wolfSSL_CTX_LoadCRLBuffer(tls_ctx, NULL, 0, SSL_FILETYPE_PEM);
+ }
+
+ return 0;
+}
+
+
+int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
+ int verify_peer, unsigned int flags,
+ const u8 *session_ctx, size_t session_ctx_len)
+{
+ if (!conn)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "SSL: set verify: %d", verify_peer);
+
+ if (verify_peer) {
+ conn->ca_cert_verify = 1;
+ wolfSSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
+ SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ tls_verify_cb);
+ } else {
+ conn->ca_cert_verify = 0;
+ wolfSSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
+ }
+
+ wolfSSL_set_accept_state(conn->ssl);
+
+ /* TODO: do we need to fake a session like OpenSSL does here? */
+
+ return 0;
+}
+
+
+static struct wpabuf * wolfssl_handshake(struct tls_connection *conn,
+ const struct wpabuf *in_data,
+ int server)
+{
+ int res;
+
+ wolfssl_reset_out_data(&conn->output);
+
+ /* Initiate TLS handshake or continue the existing handshake */
+ if (server) {
+ wolfSSL_set_accept_state(conn->ssl);
+ res = wolfSSL_accept(conn->ssl);
+ wpa_printf(MSG_DEBUG, "SSL: wolfSSL_accept: %d", res);
+ } else {
+ wolfSSL_set_connect_state(conn->ssl);
+ res = wolfSSL_connect(conn->ssl);
+ wpa_printf(MSG_DEBUG, "SSL: wolfSSL_connect: %d", res);
+ }
+
+ if (res != 1) {
+ int err = wolfSSL_get_error(conn->ssl, res);
+
+ if (err == SSL_ERROR_WANT_READ) {
+ wpa_printf(MSG_DEBUG,
+ "SSL: wolfSSL_connect - want more data");
+ } else if (err == SSL_ERROR_WANT_WRITE) {
+ wpa_printf(MSG_DEBUG,
+ "SSL: wolfSSL_connect - want to write");
+ } else {
+ char msg[80];
+
+ wpa_printf(MSG_DEBUG,
+ "SSL: wolfSSL_connect - failed %s",
+ wolfSSL_ERR_error_string(err, msg));
+ conn->failed++;
+ }
+ }
+
+ return conn->output.out_data;
+}
+
+
+static struct wpabuf * wolfssl_get_appl_data(struct tls_connection *conn,
+ size_t max_len)
+{
+ int res;
+ struct wpabuf *appl_data = wpabuf_alloc(max_len + 100);
+
+ if (!appl_data)
+ return NULL;
+
+ res = wolfSSL_read(conn->ssl, wpabuf_mhead(appl_data),
+ wpabuf_size(appl_data));
+ if (res < 0) {
+ int err = wolfSSL_get_error(conn->ssl, res);
+
+ if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
+ wpa_printf(MSG_DEBUG,
+ "SSL: No Application Data included");
+ } else {
+ char msg[80];
+
+ wpa_printf(MSG_DEBUG,
+ "Failed to read possible Application Data %s",
+ wolfSSL_ERR_error_string(err, msg));
+ }
+
+ wpabuf_free(appl_data);
+ return NULL;
+ }
+
+ wpabuf_put(appl_data, res);
+ wpa_hexdump_buf_key(MSG_MSGDUMP,
+ "SSL: Application Data in Finished message",
+ appl_data);
+ return appl_data;
+}
+
+
+static struct wpabuf *
+wolfssl_connection_handshake(struct tls_connection *conn,
+ const struct wpabuf *in_data,
+ struct wpabuf **appl_data, int server)
+{
+ struct wpabuf *out_data;
+
+ wolfssl_reset_in_data(&conn->input, in_data);
+
+ if (appl_data)
+ *appl_data = NULL;
+
+ out_data = wolfssl_handshake(conn, in_data, server);
+ if (!out_data)
+ return NULL;
+
+ if (wolfSSL_is_init_finished(conn->ssl)) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Handshake finished - resumed=%d",
+ tls_connection_resumed(NULL, conn));
+ if (appl_data && in_data)
+ *appl_data = wolfssl_get_appl_data(conn,
+ wpabuf_len(in_data));
+ }
+
+ return out_data;
+}
+
+
+struct wpabuf * tls_connection_handshake(void *tls_ctx,
+ struct tls_connection *conn,
+ const struct wpabuf *in_data,
+ struct wpabuf **appl_data)
+{
+ return wolfssl_connection_handshake(conn, in_data, appl_data, 0);
+}
+
+
+struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
+ struct tls_connection *conn,
+ const struct wpabuf *in_data,
+ struct wpabuf **appl_data)
+{
+ return wolfssl_connection_handshake(conn, in_data, appl_data, 1);
+}
+
+
+struct wpabuf * tls_connection_encrypt(void *tls_ctx,
+ struct tls_connection *conn,
+ const struct wpabuf *in_data)
+{
+ int res;
+
+ if (!conn)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG, "SSL: encrypt: %ld bytes", wpabuf_len(in_data));
+
+ wolfssl_reset_out_data(&conn->output);
+
+ res = wolfSSL_write(conn->ssl, wpabuf_head(in_data),
+ wpabuf_len(in_data));
+ if (res < 0) {
+ int err = wolfSSL_get_error(conn->ssl, res);
+ char msg[80];
+
+ wpa_printf(MSG_INFO, "Encryption failed - SSL_write: %s",
+ wolfSSL_ERR_error_string(err, msg));
+ return NULL;
+ }
+
+ return conn->output.out_data;
+}
+
+
+struct wpabuf * tls_connection_decrypt(void *tls_ctx,
+ struct tls_connection *conn,
+ const struct wpabuf *in_data)
+{
+ int res;
+ struct wpabuf *buf;
+
+ if (!conn)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG, "SSL: decrypt");
+
+ wolfssl_reset_in_data(&conn->input, in_data);
+
+ /* Read decrypted data for further processing */
+ /*
+ * Even though we try to disable TLS compression, it is possible that
+ * this cannot be done with all TLS libraries. Add extra buffer space
+ * to handle the possibility of the decrypted data being longer than
+ * input data.
+ */
+ buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
+ if (!buf)
+ return NULL;
+ res = wolfSSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf));
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "Decryption failed - SSL_read");
+ wpabuf_free(buf);
+ return NULL;
+ }
+ wpabuf_put(buf, res);
+
+ wpa_printf(MSG_DEBUG, "SSL: decrypt: %ld bytes", wpabuf_len(buf));
+
+ return buf;
+}
+
+
+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
+{
+ return conn ? wolfSSL_session_reused(conn->ssl) : 0;
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+ u8 *ciphers)
+{
+ char buf[128], *pos, *end;
+ u8 *c;
+ int ret;
+
+ if (!conn || !conn->ssl || !ciphers)
+ return -1;
+
+ buf[0] = '\0';
+ pos = buf;
+ end = pos + sizeof(buf);
+
+ c = ciphers;
+ while (*c != TLS_CIPHER_NONE) {
+ const char *suite;
+
+ switch (*c) {
+ case TLS_CIPHER_RC4_SHA:
+ suite = "RC4-SHA";
+ break;
+ case TLS_CIPHER_AES128_SHA:
+ suite = "AES128-SHA";
+ break;
+ case TLS_CIPHER_RSA_DHE_AES128_SHA:
+ suite = "DHE-RSA-AES128-SHA";
+ break;
+ case TLS_CIPHER_ANON_DH_AES128_SHA:
+ suite = "ADH-AES128-SHA";
+ break;
+ case TLS_CIPHER_RSA_DHE_AES256_SHA:
+ suite = "DHE-RSA-AES256-SHA";
+ break;
+ case TLS_CIPHER_AES256_SHA:
+ suite = "AES256-SHA";
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "TLS: Unsupported cipher selection: %d", *c);
+ return -1;
+ }
+ ret = os_snprintf(pos, end - pos, ":%s", suite);
+ if (os_snprintf_error(end - pos, ret))
+ break;
+ pos += ret;
+
+ c++;
+ }
+
+ wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites: %s", buf + 1);
+
+ if (wolfSSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
+ wpa_printf(MSG_DEBUG, "Cipher suite configuration failed");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
+ char *buf, size_t buflen)
+{
+ WOLFSSL_CIPHER *cipher;
+ const char *name;
+
+ if (!conn || !conn->ssl)
+ return -1;
+
+ cipher = wolfSSL_get_current_cipher(conn->ssl);
+ if (!cipher)
+ return -1;
+
+ name = wolfSSL_CIPHER_get_name(cipher);
+ if (!name)
+ return -1;
+
+ if (os_strcmp(name, "SSL_RSA_WITH_RC4_128_SHA") == 0)
+ os_strlcpy(buf, "RC4-SHA", buflen);
+ else if (os_strcmp(name, "TLS_RSA_WITH_AES_128_CBC_SHA") == 0)
+ os_strlcpy(buf, "AES128-SHA", buflen);
+ else if (os_strcmp(name, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA") == 0)
+ os_strlcpy(buf, "DHE-RSA-AES128-SHA", buflen);
+ else if (os_strcmp(name, "TLS_DH_anon_WITH_AES_128_CBC_SHA") == 0)
+ os_strlcpy(buf, "ADH-AES128-SHA", buflen);
+ else if (os_strcmp(name, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA") == 0)
+ os_strlcpy(buf, "DHE-RSA-AES256-SHA", buflen);
+ else if (os_strcmp(name, "TLS_RSA_WITH_AES_256_CBC_SHA") == 0)
+ os_strlcpy(buf, "AES256-SHA", buflen);
+ else
+ os_strlcpy(buf, name, buflen);
+
+ return 0;
+}
+
+
+int tls_connection_enable_workaround(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ /* no empty fragments in wolfSSL for now */
+ return 0;
+}
+
+
+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
+{
+ if (!conn)
+ return -1;
+
+ return conn->failed;
+}
+
+
+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
+{
+ if (!conn)
+ return -1;
+
+ /* TODO: this is not incremented anywhere */
+ return conn->read_alerts;
+}
+
+
+int tls_connection_get_write_alerts(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ if (!conn)
+ return -1;
+
+ /* TODO: this is not incremented anywhere */
+ return conn->write_alerts;
+}
+
+
+
+int tls_get_library_version(char *buf, size_t buf_len)
+{
+ return os_snprintf(buf, buf_len, "wolfSSL build=%s run=%s",
+ WOLFSSL_VERSION, wolfSSL_lib_version());
+}
+
+int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
+ char *buf, size_t buflen)
+{
+ const char *name;
+
+ if (!conn || !conn->ssl)
+ return -1;
+
+ name = wolfSSL_get_version(conn->ssl);
+ if (!name)
+ return -1;
+
+ os_strlcpy(buf, name, buflen);
+ return 0;
+}
+
+
+int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
+ struct tls_random *keys)
+{
+ WOLFSSL *ssl;
+
+ if (!conn || !keys)
+ return -1;
+ ssl = conn->ssl;
+ if (!ssl)
+ return -1;
+
+ os_memset(keys, 0, sizeof(*keys));
+ keys->client_random = conn->client_random;
+ keys->client_random_len = wolfSSL_get_client_random(
+ ssl, conn->client_random, sizeof(conn->client_random));
+ keys->server_random = conn->server_random;
+ keys->server_random_len = wolfSSL_get_server_random(
+ ssl, conn->server_random, sizeof(conn->server_random));
+
+ return 0;
+}
+
+
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+ const char *label, const u8 *context,
+ size_t context_len, u8 *out, size_t out_len)
+{
+ if (context)
+ return -1;
+ if (!conn || wolfSSL_make_eap_keys(conn->ssl, out, out_len, label) != 0)
+ return -1;
+ return 0;
+}
+
+
+#define SEED_LEN (RAN_LEN + RAN_LEN)
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+ u8 *out, size_t out_len)
+{
+ byte seed[SEED_LEN];
+ int ret = -1;
+ WOLFSSL *ssl;
+ byte *tmp_out;
+ byte *_out;
+ int skip = 0;
+ byte *master_key;
+ unsigned int master_key_len;
+ byte *server_random;
+ unsigned int server_len;
+ byte *client_random;
+ unsigned int client_len;
+
+ if (!conn || !conn->ssl)
+ return -1;
+ ssl = conn->ssl;
+
+ skip = 2 * (wolfSSL_GetKeySize(ssl) + wolfSSL_GetHmacSize(ssl) +
+ wolfSSL_GetIVSize(ssl));
+
+ tmp_out = os_malloc(skip + out_len);
+ if (!tmp_out)
+ return -1;
+ _out = tmp_out;
+
+ wolfSSL_get_keys(ssl, &master_key, &master_key_len, &server_random,
+ &server_len, &client_random, &client_len);
+ os_memcpy(seed, server_random, RAN_LEN);
+ os_memcpy(seed + RAN_LEN, client_random, RAN_LEN);
+
+ if (wolfSSL_GetVersion(ssl) == WOLFSSL_TLSV1_2) {
+ tls_prf_sha256(master_key, master_key_len,
+ "key expansion", seed, sizeof(seed),
+ _out, skip + out_len);
+ ret = 0;
+ } else {
+ ret = tls_prf_sha1_md5(master_key, master_key_len,
+ "key expansion", seed, sizeof(seed),
+ _out, skip + out_len);
+ }
+
+ os_memset(master_key, 0, master_key_len);
+ if (ret == 0)
+ os_memcpy(out, _out + skip, out_len);
+ bin_clear_free(tmp_out, skip + out_len);
+
+ return ret;
+}
+
+
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+
+int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
+ int ext_type, const u8 *data,
+ size_t data_len)
+{
+ (void) ssl_ctx;
+
+ if (!conn || !conn->ssl || ext_type != 35)
+ return -1;
+
+ if (wolfSSL_set_SessionTicket(conn->ssl, data,
+ (unsigned int) data_len) != 1)
+ return -1;
+
+ return 0;
+}
+
+
+static int tls_sess_sec_cb(WOLFSSL *s, void *secret, int *secret_len, void *arg)
+{
+ struct tls_connection *conn = arg;
+ int ret;
+ unsigned char client_random[RAN_LEN];
+ unsigned char server_random[RAN_LEN];
+ word32 ticket_len = sizeof(conn->session_ticket);
+
+ if (!conn || !conn->session_ticket_cb)
+ return 1;
+
+ if (wolfSSL_get_client_random(s, client_random,
+ sizeof(client_random)) == 0 ||
+ wolfSSL_get_server_random(s, server_random,
+ sizeof(server_random)) == 0 ||
+ wolfSSL_get_SessionTicket(s, conn->session_ticket,
+ &ticket_len) != 1)
+ return 1;
+
+ if (ticket_len == 0)
+ return 0;
+
+ ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
+ conn->session_ticket, ticket_len,
+ client_random, server_random, secret);
+ if (ret <= 0)
+ return 1;
+
+ *secret_len = SECRET_LEN;
+ return 0;
+}
+
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+
+
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+ struct tls_connection *conn,
+ tls_session_ticket_cb cb,
+ void *ctx)
+{
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+ conn->session_ticket_cb = cb;
+ conn->session_ticket_cb_ctx = ctx;
+
+ if (cb) {
+ if (wolfSSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
+ conn) != 1)
+ return -1;
+ } else {
+ if (wolfSSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
+ return -1;
+ }
+
+ return 0;
+#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+ return -1;
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+}
+
+
+void tls_connection_set_success_data_resumed(struct tls_connection *conn)
+{
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Success data accepted for resumed session");
+}
+
+
+void tls_connection_remove_session(struct tls_connection *conn)
+{
+ WOLFSSL_SESSION *sess;
+
+ sess = wolfSSL_get_session(conn->ssl);
+ if (!sess)
+ return;
+
+ wolfSSL_SSL_SESSION_set_timeout(sess, 0);
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Removed cached session to disable session resumption");
+}
+
+
+void tls_connection_set_success_data(struct tls_connection *conn,
+ struct wpabuf *data)
+{
+ WOLFSSL_SESSION *sess;
+ struct wpabuf *old;
+
+ wpa_printf(MSG_DEBUG, "wolfSSL: Set success data");
+
+ sess = wolfSSL_get_session(conn->ssl);
+ if (!sess) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: No session found for success data");
+ goto fail;
+ }
+
+ old = wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+ if (old) {
+ wpa_printf(MSG_DEBUG, "wolfSSL: Replacing old success data %p",
+ old);
+ wpabuf_free(old);
+ }
+ if (wolfSSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "wolfSSL: Stored success data %p", data);
+ conn->success_data = 1;
+ return;
+
+fail:
+ wpa_printf(MSG_INFO, "wolfSSL: Failed to store success data");
+ wpabuf_free(data);
+}
+
+
+const struct wpabuf *
+tls_connection_get_success_data(struct tls_connection *conn)
+{
+ WOLFSSL_SESSION *sess;
+
+ wpa_printf(MSG_DEBUG, "wolfSSL: Get success data");
+
+ sess = wolfSSL_get_session(conn->ssl);
+ if (!sess)
+ return NULL;
+ return wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+}
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index a6307e3..e7c8f31 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -58,6 +58,16 @@
#define HOSTAPD_CHAN_VHT_130_30 0x04000000
#define HOSTAPD_CHAN_VHT_150_10 0x08000000
+/* Allowed bandwidth mask */
+enum hostapd_chan_width_attr {
+ HOSTAPD_CHAN_WIDTH_10 = BIT(0),
+ HOSTAPD_CHAN_WIDTH_20 = BIT(1),
+ HOSTAPD_CHAN_WIDTH_40P = BIT(2),
+ HOSTAPD_CHAN_WIDTH_40M = BIT(3),
+ HOSTAPD_CHAN_WIDTH_80 = BIT(4),
+ HOSTAPD_CHAN_WIDTH_160 = BIT(5),
+};
+
/* Filter gratuitous ARP */
#define WPA_DATA_FRAME_FILTER_FLAG_ARP BIT(0)
/* Filter unsolicited Neighbor Advertisement */
@@ -111,6 +121,13 @@
int flag;
/**
+ * allowed_bw - Allowed channel width bitmask
+ *
+ * See enum hostapd_chan_width_attr.
+ */
+ u32 allowed_bw;
+
+ /**
* max_tx_power - Regulatory transmit power limit in dBm
*/
u8 max_tx_power;
@@ -567,6 +584,18 @@
*/
s8 relative_adjust_rssi;
+ /**
+ * oce_scan
+ *
+ * Enable the following OCE scan features: (WFA OCE TechSpec v1.0)
+ * - Accept broadcast Probe Response frame.
+ * - Probe Request frame deferral and suppression.
+ * - Max Channel Time - driver fills FILS request params IE with
+ * Maximum Channel Time.
+ * - Send 1st Probe Request frame in rate of minimum 5.5 Mbps.
+ */
+ unsigned int oce_scan:1;
+
/*
* NOTE: Whenever adding new parameters here, please make sure
* wpa_scan_clone_params() and wpa_scan_free_params() get updated with
@@ -902,10 +931,10 @@
* passphrase - RSN passphrase for PSK
*
* This value is made available only for WPA/WPA2-Personal (PSK) and
- * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE. This is
- * the 8..63 character ASCII passphrase, if available. Please note that
- * this can be %NULL if passphrase was not used to generate the PSK. In
- * that case, the psk field must be used to fetch the PSK.
+ * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK. This
+ * is the 8..63 character ASCII passphrase, if available. Please note
+ * that this can be %NULL if passphrase was not used to generate the
+ * PSK. In that case, the psk field must be used to fetch the PSK.
*/
const char *passphrase;
@@ -913,9 +942,9 @@
* psk - RSN PSK (alternative for passphrase for PSK)
*
* This value is made available only for WPA/WPA2-Personal (PSK) and
- * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE. This is
- * the 32-octet (256-bit) PSK, if available. The driver wrapper should
- * be prepared to handle %NULL value as an error.
+ * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK. This
+ * is the 32-octet (256-bit) PSK, if available. The driver wrapper
+ * should be prepared to handle %NULL value as an error.
*/
const u8 *psk;
@@ -1355,6 +1384,23 @@
* service).
*/
int multicast_to_unicast;
+
+ /**
+ * ftm_responder - Whether FTM responder is enabled
+ */
+ int ftm_responder;
+
+ /**
+ * lci - Binary data, the content of an LCI report IE with type 8 as
+ * defined in IEEE Std 802.11-2016, 9.4.2.22.10
+ */
+ const struct wpabuf *lci;
+
+ /**
+ * civic - Binary data, the content of a measurement report IE with
+ * type 11 as defined in IEEE Std 802.11-2016, 9.4.2.22.13
+ */
+ const struct wpabuf *civic;
};
struct wpa_driver_mesh_bss_params {
@@ -1412,6 +1458,7 @@
#define WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384 0x00002000
#define WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256 0x00004000
#define WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384 0x00008000
+#define WPA_DRIVER_CAPA_KEY_MGMT_SAE 0x00010000
/** Bitfield of supported key management suites */
unsigned int key_mgmt;
@@ -1445,7 +1492,7 @@
#define WPA_DRIVER_FLAGS_DFS_OFFLOAD 0x00000004
/** Driver takes care of RSN 4-way handshake internally; PMK is configured with
* struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */
-#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE 0x00000008
+#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X 0x00000008
/** Driver is for a wired Ethernet interface */
#define WPA_DRIVER_FLAGS_WIRED 0x00000010
/** Driver provides separate commands for authentication and association (SME in
@@ -1563,6 +1610,14 @@
* functionality but can support only OCE STA-CFON functionality.
*/
#define WPA_DRIVER_FLAGS_OCE_STA_CFON 0x0020000000000000ULL
+/** Driver supports MFP-optional in the connect command */
+#define WPA_DRIVER_FLAGS_MFP_OPTIONAL 0x0040000000000000ULL
+/** Driver is a self-managed regulatory device */
+#define WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY 0x0080000000000000ULL
+/** Driver supports FTM responder functionality */
+#define WPA_DRIVER_FLAGS_FTM_RESPONDER 0x0100000000000000ULL
+/** Driver support 4-way handshake offload for WPA-Personal */
+#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK 0x0200000000000000ULL
u64 flags;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@@ -1692,6 +1747,7 @@
#define STA_DRV_DATA_RX_VHT_NSS BIT(5)
#define STA_DRV_DATA_TX_SHORT_GI BIT(6)
#define STA_DRV_DATA_RX_SHORT_GI BIT(7)
+#define STA_DRV_DATA_LAST_ACK_RSSI BIT(8)
struct hostap_sta_driver_data {
unsigned long rx_packets, tx_packets;
@@ -1704,8 +1760,7 @@
unsigned long num_ps_buf_frames;
unsigned long tx_retry_failed;
unsigned long tx_retry_count;
- int last_rssi;
- int last_ack_rssi;
+ s8 last_ack_rssi;
s8 signal;
u8 rx_vhtmcs;
u8 tx_vhtmcs;
@@ -1875,19 +1930,32 @@
WNM_SLEEP_TFS_IE_DEL /* AP delete the TFS IE */
};
-/* enum chan_width - Channel width definitions */
-enum chan_width {
- CHAN_WIDTH_20_NOHT,
- CHAN_WIDTH_20,
- CHAN_WIDTH_40,
- CHAN_WIDTH_80,
- CHAN_WIDTH_80P80,
- CHAN_WIDTH_160,
- CHAN_WIDTH_UNKNOWN
+/* enum smps_mode - SMPS mode definitions */
+enum smps_mode {
+ SMPS_AUTOMATIC,
+ SMPS_OFF,
+ SMPS_DYNAMIC,
+ SMPS_STATIC,
+
+ /* Keep last */
+ SMPS_INVALID,
};
+#define WPA_INVALID_NOISE 9999
+
/**
* struct wpa_signal_info - Information about channel signal quality
+ * @frequency: control frequency
+ * @above_threshold: true if the above threshold was crossed
+ * (relevant for a CQM event)
+ * @current_signal: in dBm
+ * @avg_signal: in dBm
+ * @avg_beacon_signal: in dBm
+ * @current_noise: %WPA_INVALID_NOISE if not supported
+ * @current_txrate: current TX rate
+ * @chanwidth: channel width
+ * @center_frq1: center frequency for the first segment
+ * @center_frq2: center frequency for the second segment (if relevant)
*/
struct wpa_signal_info {
u32 frequency;
@@ -1903,6 +1971,26 @@
};
/**
+ * struct wpa_channel_info - Information about the current channel
+ * @frequency: Center frequency of the primary 20 MHz channel
+ * @chanwidth: Width of the current operating channel
+ * @sec_channel: Location of the secondary 20 MHz channel (either +1 or -1).
+ * This field is only filled in when using a 40 MHz channel.
+ * @center_frq1: Center frequency of frequency segment 0
+ * @center_frq2: Center frequency of frequency segment 1 (for 80+80 channels)
+ * @seg1_idx: Frequency segment 1 index when using a 80+80 channel. This is
+ * derived from center_frq2 for convenience.
+ */
+struct wpa_channel_info {
+ u32 frequency;
+ enum chan_width chanwidth;
+ int sec_channel;
+ int center_frq1;
+ int center_frq2;
+ u8 seg1_idx;
+};
+
+/**
* struct beacon_data - Beacon data
* @head: Head portion of Beacon frame (before TIM IE)
* @tail: Tail portion of Beacon frame (after TIM IE)
@@ -2052,6 +2140,38 @@
};
/**
+ * struct external_auth - External authentication trigger parameters
+ *
+ * These are used across the external authentication request and event
+ * interfaces.
+ * @action: Action type / trigger for external authentication. Only significant
+ * for the event interface.
+ * @bssid: BSSID of the peer with which the authentication has to happen. Used
+ * by both the request and event interface.
+ * @ssid: SSID of the AP. Used by both the request and event interface.
+ * @ssid_len: SSID length in octets.
+ * @key_mgmt_suite: AKM suite of the respective authentication. Optional for
+ * the request interface.
+ * @status: Status code, %WLAN_STATUS_SUCCESS for successful authentication,
+ * use %WLAN_STATUS_UNSPECIFIED_FAILURE if wpa_supplicant cannot give
+ * the real status code for failures. Used only for the request interface
+ * from user space to the driver.
+ * @pmkid: Generated PMKID as part of external auth exchange (e.g., SAE).
+ */
+struct external_auth {
+ enum {
+ EXT_AUTH_START,
+ EXT_AUTH_ABORT,
+ } action;
+ const u8 *bssid;
+ const u8 *ssid;
+ size_t ssid_len;
+ unsigned int key_mgmt_suite;
+ u16 status;
+ const u8 *pmkid;
+};
+
+/**
* struct wpa_driver_ops - Driver interface API definition
*
* This structure defines the API that each driver interface needs to implement
@@ -3308,6 +3428,14 @@
int (*signal_poll)(void *priv, struct wpa_signal_info *signal_info);
/**
+ * channel_info - Get parameters of the current operating channel
+ * @priv: Private driver interface data
+ * @channel_info: Channel info structure
+ * Returns: 0 on success, negative (<0) on failure
+ */
+ int (*channel_info)(void *priv, struct wpa_channel_info *channel_info);
+
+ /**
* set_authmode - Set authentication algorithm(s) for static WEP
* @priv: Private driver interface data
* @authmode: 1=Open System, 2=Shared Key, 3=both
@@ -3588,7 +3716,7 @@
/**
* status - Get driver interface status information
* @priv: Private driver interface data
- * @buf: Buffer for printing tou the status information
+ * @buf: Buffer for printing the status information
* @buflen: Maximum length of the buffer
* Returns: Length of written status information or -1 on failure
*/
@@ -3611,6 +3739,17 @@
int (*roaming)(void *priv, int allowed, const u8 *bssid);
/**
+ * disable_fils - Enable/disable FILS feature
+ * @priv: Private driver interface data
+ * @disable: 0-enable and 1-disable FILS feature
+ * Returns: 0 on success, -1 on failure
+ *
+ * This callback can be used to configure driver and below layers to
+ * enable/disable all FILS features.
+ */
+ int (*disable_fils)(void *priv, int disable);
+
+ /**
* set_mac_addr - Set MAC address
* @priv: Private driver interface data
* @addr: MAC address to use or %NULL for setting back to permanent
@@ -3701,6 +3840,14 @@
int (*set_transmit_next_pn)(void *priv, struct transmit_sa *sa);
/**
+ * set_receive_lowest_pn - Set receive lowest PN
+ * @priv: Private driver interface data
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+ int (*set_receive_lowest_pn)(void *priv, struct receive_sa *sa);
+
+ /**
* create_receive_sc - create secure channel for receiving
* @priv: Private driver interface data
* @sc: secure channel
@@ -4001,6 +4148,25 @@
int (*update_connect_params)(
void *priv, struct wpa_driver_associate_params *params,
enum wpa_drv_update_connect_params_mask mask);
+
+ /**
+ * send_external_auth_status - Indicate the status of external
+ * authentication processing to the host driver.
+ * @priv: Private driver interface data
+ * @params: Status of authentication processing.
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*send_external_auth_status)(void *priv,
+ struct external_auth *params);
+
+ /**
+ * set_4addr_mode - Set 4-address mode
+ * @priv: Private driver interface data
+ * @bridge_ifname: Bridge interface name
+ * @val: 0 - disable 4addr mode, 1 - enable 4addr mode
+ * Returns: 0 on success, < 0 on failure
+ */
+ int (*set_4addr_mode)(void *priv, const char *bridge_ifname, int val);
};
/**
@@ -4496,6 +4662,47 @@
* performed before start operating on this channel.
*/
EVENT_DFS_PRE_CAC_EXPIRED,
+
+ /**
+ * EVENT_EXTERNAL_AUTH - This event interface is used by host drivers
+ * that do not define separate commands for authentication and
+ * association (~WPA_DRIVER_FLAGS_SME) but offload the 802.11
+ * authentication to wpa_supplicant. This event carries all the
+ * necessary information from the host driver for the authentication to
+ * happen.
+ */
+ EVENT_EXTERNAL_AUTH,
+
+ /**
+ * EVENT_PORT_AUTHORIZED - Notification that a connection is authorized
+ *
+ * This event should be indicated when the driver completes the 4-way
+ * handshake. This event should be preceded by an EVENT_ASSOC that
+ * indicates the completion of IEEE 802.11 association.
+ */
+ EVENT_PORT_AUTHORIZED,
+
+ /**
+ * EVENT_STATION_OPMODE_CHANGED - Notify STA's HT/VHT operation mode
+ * change event.
+ */
+ EVENT_STATION_OPMODE_CHANGED,
+
+ /**
+ * EVENT_INTERFACE_MAC_CHANGED - Notify that interface MAC changed
+ *
+ * This event is emitted when the MAC changes while the interface is
+ * enabled. When an interface was disabled and becomes enabled, it
+ * must be always assumed that the MAC possibly changed.
+ */
+ EVENT_INTERFACE_MAC_CHANGED,
+
+ /**
+ * EVENT_WDS_STA_INTERFACE_STATUS - Notify WDS STA interface status
+ *
+ * This event is emitted when an interface is added/removed for WDS STA.
+ */
+ EVENT_WDS_STA_INTERFACE_STATUS,
};
@@ -5298,6 +5505,37 @@
P2P_LO_STOPPED_REASON_NOT_SUPPORTED,
} reason_code;
} p2p_lo_stop;
+
+ /* For EVENT_EXTERNAL_AUTH */
+ struct external_auth external_auth;
+
+ /**
+ * struct sta_opmode - Station's operation mode change event
+ * @addr: The station MAC address
+ * @smps_mode: SMPS mode of the station
+ * @chan_width: Channel width of the station
+ * @rx_nss: RX_NSS of the station
+ *
+ * This is used as data with EVENT_STATION_OPMODE_CHANGED.
+ */
+ struct sta_opmode {
+ const u8 *addr;
+ enum smps_mode smps_mode;
+ enum chan_width chan_width;
+ u8 rx_nss;
+ } sta_opmode;
+
+ /**
+ * struct wds_sta_interface - Data for EVENT_WDS_STA_INTERFACE_STATUS.
+ */
+ struct wds_sta_interface {
+ const u8 *sta_addr;
+ const char *ifname;
+ enum {
+ INTERFACE_ADDED,
+ INTERFACE_REMOVED
+ } istatus;
+ } wds_sta_interface;
};
/**
@@ -5371,6 +5609,8 @@
/* Convert chan_width to a string for logging and control interfaces */
const char * channel_width_to_string(enum chan_width width);
+int channel_width_to_int(enum chan_width width);
+
int ht_supported(const struct hostapd_hw_modes *mode);
int vht_supported(const struct hostapd_hw_modes *mode);
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index d2b355c..807cd94 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -931,6 +931,12 @@
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth))
break;
os_memset(&event, 0, sizeof(event));
+ if (le_to_host16(mgmt->u.auth.auth_alg) == WLAN_AUTH_SAE) {
+ event.rx_mgmt.frame = buf;
+ event.rx_mgmt.frame_len = len;
+ wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
+ break;
+ }
os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
os_memcpy(event.auth.bssid, mgmt->bssid, ETH_ALEN);
event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
@@ -1212,8 +1218,7 @@
#ifdef ATH_WPS_IE
/* if WPS IE is present, preference is given to WPS */
- if (ie.wps_ie &&
- (ie.wps_ie[1] > 0 && (ie.wps_ie[0] == WLAN_EID_VENDOR_SPECIFIC))) {
+ if (ie.wps_ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie.wps_ie[1] > 0) {
iebuf = ie.wps_ie;
ielen = ie.wps_ie[1];
}
@@ -1323,11 +1328,11 @@
}
atheros_raw_receive(drv, NULL,
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
- } else if (os_strncmp(custom, "Manage.auth ", 12) == 0) {
+ } else if (os_strncmp(custom, "Manage.auth ", 12) == 0) {
/* Format: "Manage.auth <frame len>" | zero padding | frame */
int len = atoi(custom + 12);
- if (len < 0 ||
- MGMT_FRAM_TAG_SIZE + len > end - custom) {
+ if (len < 0 ||
+ MGMT_FRAM_TAG_SIZE + len > end - custom) {
wpa_printf(MSG_DEBUG,
"Invalid Manage.auth event length %d", len);
return;
@@ -1336,7 +1341,7 @@
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R || CONFIG_FILS */
#ifdef ATHEROS_USE_RAW_RECEIVE
- } else if (os_strncmp(custom, "Manage.action ", 14) == 0) {
+ } else if (os_strncmp(custom, "Manage.action ", 14) == 0) {
/* Format: "Manage.assoc_req <frame len>" | zero padding | frame
*/
int len = atoi(custom + 14);
@@ -1352,6 +1357,40 @@
}
}
+
+static void send_action_cb_event(struct atheros_driver_data *drv,
+ char *data, size_t data_len)
+{
+ union wpa_event_data event;
+ struct ieee80211_send_action_cb *sa;
+ const struct ieee80211_hdr *hdr;
+ u16 fc;
+
+ if (data_len < sizeof(*sa) + 24) {
+ wpa_printf(MSG_DEBUG,
+ "athr: Too short event message (data_len=%d sizeof(*sa)=%d)",
+ (int) data_len, (int) sizeof(*sa));
+ wpa_hexdump(MSG_DEBUG, "athr: Short event message",
+ data, data_len);
+ return;
+ }
+
+ sa = (struct ieee80211_send_action_cb *) data;
+
+ hdr = (const struct ieee80211_hdr *) (sa + 1);
+ fc = le_to_host16(hdr->frame_control);
+
+ os_memset(&event, 0, sizeof(event));
+ event.tx_status.type = WLAN_FC_GET_TYPE(fc);
+ event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
+ event.tx_status.dst = sa->dst_addr;
+ event.tx_status.data = (const u8 *) hdr;
+ event.tx_status.data_len = data_len - sizeof(*sa);
+ event.tx_status.ack = sa->ack;
+ wpa_supplicant_event(drv->hapd, EVENT_TX_STATUS, &event);
+}
+
+
/*
* Handle size of data problem. WEXT only allows data of 256 bytes for custom
* events, and p2p data can be much bigger. So the athr driver sends a small
@@ -1416,6 +1455,11 @@
&event);
continue;
}
+ } else if (frame_type == IEEE80211_EV_P2P_SEND_ACTION_CB) {
+ wpa_printf(MSG_DEBUG,
+ "%s: ACTION_CB frame_type=%u len=%zu",
+ __func__, frame_type, data_len);
+ send_action_cb_event(drv, (void *) mgmt, data_len);
} else {
wpa_printf(MSG_DEBUG, "athr: %s unknown type %d",
__func__, frame_type);
@@ -1429,6 +1473,10 @@
int opcode, char *buf, int len)
{
switch (opcode) {
+ case IEEE80211_EV_P2P_SEND_ACTION_CB:
+ wpa_printf(MSG_DEBUG, "WEXT: EV_P2P_SEND_ACTION_CB");
+ fetch_pending_big_events(drv);
+ break;
case IEEE80211_EV_RX_MGMT:
wpa_printf(MSG_DEBUG, "WEXT: EV_RX_MGMT");
fetch_pending_big_events(drv);
@@ -1812,7 +1860,7 @@
os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
iwr.u.essid.flags = 1; /* SSID active */
iwr.u.essid.pointer = (caddr_t) buf;
- iwr.u.essid.length = len + 1;
+ iwr.u.essid.length = len;
if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
wpa_printf(MSG_ERROR, "ioctl[SIOCSIWESSID,len=%d]: %s",
@@ -1925,7 +1973,7 @@
}
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len,
int noack, unsigned int freq,
@@ -1951,7 +1999,7 @@
return set80211priv(drv, IEEE80211_IOCTL_SEND_MGMT, mgmt_frm,
sizeof(struct ieee80211req_mgmtbuf) + data_len);
}
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */
#ifdef CONFIG_IEEE80211R
@@ -2239,7 +2287,7 @@
.sta_assoc = atheros_sta_assoc,
.sta_auth = atheros_sta_auth,
.send_mlme = atheros_send_mgmt,
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */
#ifdef CONFIG_IEEE80211R
.add_tspec = atheros_add_tspec,
.add_sta_node = atheros_add_sta_node,
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 8621aa0..4675496 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -143,7 +143,7 @@
ireq->i_data = arg;
if (ioctl(drv->global->sock, SIOCG80211, ireq) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, "
+ wpa_printf(MSG_ERROR, "ioctl[SIOCG80211, op=%u, "
"arg_len=%u]: %s", op, arg_len, strerror(errno));
return -1;
}
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 0464304..e55e6cd 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -82,6 +82,11 @@
E2S(P2P_LO_STOP);
E2S(BEACON_LOSS);
E2S(DFS_PRE_CAC_EXPIRED);
+ E2S(EXTERNAL_AUTH);
+ E2S(PORT_AUTHORIZED);
+ E2S(STATION_OPMODE_CHANGED);
+ E2S(INTERFACE_MAC_CHANGED);
+ E2S(WDS_STA_INTERFACE_STATUS);
}
return "UNKNOWN";
@@ -110,6 +115,25 @@
}
+int channel_width_to_int(enum chan_width width)
+{
+ switch (width) {
+ case CHAN_WIDTH_20_NOHT:
+ case CHAN_WIDTH_20:
+ return 20;
+ case CHAN_WIDTH_40:
+ return 40;
+ case CHAN_WIDTH_80:
+ return 80;
+ case CHAN_WIDTH_80P80:
+ case CHAN_WIDTH_160:
+ return 160;
+ default:
+ return 0;
+ }
+}
+
+
int ht_supported(const struct hostapd_hw_modes *mode)
{
if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) {
@@ -229,7 +253,8 @@
DF2S(DRIVER_IE);
DF2S(SET_KEYS_AFTER_ASSOC);
DF2S(DFS_OFFLOAD);
- DF2S(4WAY_HANDSHAKE);
+ DF2S(4WAY_HANDSHAKE_PSK);
+ DF2S(4WAY_HANDSHAKE_8021X);
DF2S(WIRED);
DF2S(SME);
DF2S(AP);
@@ -268,6 +293,19 @@
DF2S(OFFCHANNEL_SIMULTANEOUS);
DF2S(FULL_AP_CLIENT_STATE);
DF2S(P2P_LISTEN_OFFLOAD);
+ DF2S(SUPPORT_FILS);
+ DF2S(BEACON_RATE_LEGACY);
+ DF2S(BEACON_RATE_HT);
+ DF2S(BEACON_RATE_VHT);
+ DF2S(MGMT_TX_RANDOM_TA);
+ DF2S(MGMT_TX_RANDOM_TA_CONNECTED);
+ DF2S(SCHED_SCAN_RELATIVE_RSSI);
+ DF2S(HE_CAPABILITIES);
+ DF2S(FILS_SK_OFFLOAD);
+ DF2S(OCE_STA);
+ DF2S(OCE_AP);
+ DF2S(OCE_STA_CFON);
+ DF2S(MFP_OPTIONAL);
}
return "UNKNOWN";
#undef DF2S
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
index 597da33..61b39b1 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -231,7 +231,11 @@
}
memset(&ifr, 0, sizeof(ifr));
- snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface);
+ if (os_snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap",
+ drv->iface) >= (int) sizeof(ifr.ifr_name)) {
+ wpa_printf(MSG_ERROR, "hostap: AP interface name truncated");
+ return -1;
+ }
if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
strerror(errno));
@@ -348,7 +352,10 @@
struct ifreq ifr;
char ifname[IFNAMSIZ];
- os_snprintf(ifname, IFNAMSIZ, "%sap", drv->iface);
+ if (os_snprintf(ifname, IFNAMSIZ, "%sap", drv->iface) >= IFNAMSIZ) {
+ wpa_printf(MSG_ERROR, "hostap: AP interface name truncated");
+ return -1;
+ }
if (linux_set_iface_flags(drv->ioctl_sock, ifname, dev_up) < 0)
return -1;
@@ -1124,6 +1131,7 @@
for (i = 0; i < 14; i++) {
mode->channels[i].chan = i + 1;
mode->channels[i].freq = chan2freq[i];
+ mode->channels[i].allowed_bw = HOSTAPD_CHAN_WIDTH_20;
/* TODO: Get allowed channel list from the driver */
if (i >= 11)
mode->channels[i].flag = HOSTAPD_CHAN_DISABLED;
diff --git a/src/drivers/driver_macsec_linux.c b/src/drivers/driver_macsec_linux.c
index e89b3ba..9d981bb 100644
--- a/src/drivers/driver_macsec_linux.c
+++ b/src/drivers/driver_macsec_linux.c
@@ -177,6 +177,9 @@
if (drv->controlled_port_enabled_set) {
struct rtnl_link *change = rtnl_link_alloc();
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "%s: try_commit controlled_port_enabled=%d",
+ drv->ifname, drv->controlled_port_enabled);
if (!change)
return -1;
@@ -196,13 +199,24 @@
drv->controlled_port_enabled_set = FALSE;
}
- if (drv->protect_frames_set)
+ if (drv->protect_frames_set) {
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "%s: try_commit protect_frames=%d",
+ drv->ifname, drv->protect_frames);
rtnl_link_macsec_set_protect(drv->link, drv->protect_frames);
+ }
- if (drv->encrypt_set)
+ if (drv->encrypt_set) {
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: try_commit encrypt=%d",
+ drv->ifname, drv->encrypt);
rtnl_link_macsec_set_encrypt(drv->link, drv->encrypt);
+ }
if (drv->replay_protect_set) {
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "%s: try_commit replay_protect=%d replay_window=%d",
+ drv->ifname, drv->replay_protect,
+ drv->replay_window);
rtnl_link_macsec_set_replay_protect(drv->link,
drv->replay_protect);
if (drv->replay_protect)
@@ -210,8 +224,12 @@
drv->replay_window);
}
- if (drv->encoding_sa_set)
+ if (drv->encoding_sa_set) {
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "%s: try_commit encoding_sa=%d",
+ drv->ifname, drv->encoding_sa);
rtnl_link_macsec_set_encoding_sa(drv->link, drv->encoding_sa);
+ }
err = rtnl_link_add(drv->sk, drv->link, 0);
if (err < 0)
@@ -318,6 +336,8 @@
drv->common.ifname);
goto cache;
}
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "ifname=%s parent_ifi=%d",
+ drv->common.ifname, drv->parent_ifi);
err = init_genl_ctx(drv);
if (err < 0)
@@ -639,7 +659,7 @@
DRV_PREFIX "failed to communicate: %d (%s)",
ret, nl_geterror(-ret));
- ctx->cb_arg.pn = 0;
+ ctx->cb_arg.pn = NULL;
out_free_msg:
nlmsg_free(msg);
@@ -670,6 +690,50 @@
/**
+ * macsec_drv_set_receive_lowest_pn - Set receive lowest PN
+ * @priv: Private driver interface data
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_set_receive_lowest_pn(void *priv, struct receive_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ int ret = -1;
+
+ wpa_printf(MSG_DEBUG,
+ DRV_PREFIX "%s: set_receive_lowest_pn -> %d: %d",
+ drv->ifname, sa->an, sa->next_pn);
+
+ msg = msg_prepare(MACSEC_CMD_UPD_RXSA, ctx, drv->ifi);
+ if (!msg)
+ return ret;
+
+ nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
+ NLA_PUT_U32(msg, MACSEC_SA_ATTR_PN, sa->next_pn);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to communicate: %d (%s)",
+ ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
* macsec_drv_get_transmit_next_pn - Get transmit next PN
* @priv: Private driver interface data
* @sa: secure association
@@ -754,8 +818,10 @@
struct nl_msg *msg;
int ret = -1;
- wpa_printf(MSG_DEBUG, "%s -> " SCISTR, __func__,
- SCI2STR(sc->sci.addr, sc->sci.port));
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: create_receive_sc -> " SCISTR
+ " (conf_offset=%u validation=%d)",
+ drv->ifname, SCI2STR(sc->sci.addr, sc->sci.port),
+ conf_offset, validation);
msg = msg_prepare(MACSEC_CMD_ADD_RXSC, ctx, drv->ifi);
if (!msg)
@@ -790,8 +856,8 @@
struct nl_msg *msg;
int ret = -1;
- wpa_printf(MSG_DEBUG, "%s -> " SCISTR, __func__,
- SCI2STR(sc->sci.addr, sc->sci.port));
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: delete_receive_sc -> " SCISTR,
+ drv->ifname, SCI2STR(sc->sci.addr, sc->sci.port));
msg = msg_prepare(MACSEC_CMD_DEL_RXSC, ctx, drv->ifi);
if (!msg)
@@ -827,8 +893,17 @@
struct nlattr *nest;
int ret = -1;
- wpa_printf(MSG_DEBUG, "%s -> %d on " SCISTR, __func__, sa->an,
- SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
+ wpa_printf(MSG_DEBUG,
+ DRV_PREFIX "%s: create_receive_sa -> %d on " SCISTR
+ " (enable_receive=%d next_pn=%u)",
+ drv->ifname, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port),
+ sa->enable_receive, sa->next_pn);
+ wpa_hexdump(MSG_DEBUG, DRV_PREFIX "SA keyid",
+ &sa->pkey->key_identifier,
+ sizeof(sa->pkey->key_identifier));
+ wpa_hexdump_key(MSG_DEBUG, DRV_PREFIX "SA key",
+ sa->pkey->key, sa->pkey->key_len);
msg = msg_prepare(MACSEC_CMD_ADD_RXSA, ctx, drv->ifi);
if (!msg)
@@ -877,7 +952,8 @@
struct nlattr *nest;
int ret = -1;
- wpa_printf(MSG_DEBUG, "%s -> %d on " SCISTR, __func__, sa->an,
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: delete_receive_sa -> %d on "
+ SCISTR, drv->ifname, sa->an,
SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
msg = msg_prepare(MACSEC_CMD_DEL_RXSA, ctx, drv->ifi);
@@ -954,7 +1030,8 @@
struct macsec_drv_data *drv = priv;
struct macsec_genl_ctx *ctx = &drv->ctx;
- wpa_printf(MSG_DEBUG, "%s -> %d on " SCISTR, __func__, sa->an,
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: enable_receive_sa -> %d on "
+ SCISTR, drv->ifname, sa->an,
SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
return set_active_rx_sa(ctx, drv->ifi, mka_sci_u64(&sa->sc->sci),
@@ -973,7 +1050,8 @@
struct macsec_drv_data *drv = priv;
struct macsec_genl_ctx *ctx = &drv->ctx;
- wpa_printf(MSG_DEBUG, "%s -> %d on " SCISTR, __func__, sa->an,
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: disable_receive_sa -> %d on "
+ SCISTR, drv->ifname, sa->an,
SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
return set_active_rx_sa(ctx, drv->ifi, mka_sci_u64(&sa->sc->sci),
@@ -1009,7 +1087,7 @@
*/
static int macsec_drv_create_transmit_sc(
void *priv, struct transmit_sc *sc,
- enum confidentiality_offset conf_offset)
+ unsigned int conf_offset)
{
struct macsec_drv_data *drv = priv;
struct rtnl_link *link;
@@ -1017,7 +1095,10 @@
u64 sci;
int err;
- wpa_printf(MSG_DEBUG, "%s", __func__);
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "%s: create_transmit_sc -> " SCISTR " (conf_offset=%d)",
+ drv->common.ifname, SCI2STR(sc->sci.addr, sc->sci.port),
+ conf_offset);
if (!drv->sk) {
wpa_printf(MSG_ERROR, DRV_PREFIX "NULL rtnl socket");
@@ -1060,6 +1141,9 @@
drv->ifi = rtnl_link_get_ifindex(link);
ifname = rtnl_link_get_name(link);
+ wpa_printf(MSG_DEBUG,
+ DRV_PREFIX "%s: create_transmit_sc: ifi=%d ifname=%s",
+ drv->common.ifname, drv->ifi, ifname);
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
rtnl_link_put(link);
@@ -1088,7 +1172,8 @@
struct macsec_drv_data *drv = priv;
int err;
- wpa_printf(MSG_DEBUG, "%s", __func__);
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: delete_transmit_sc -> " SCISTR,
+ drv->ifname, SCI2STR(sc->sci.addr, sc->sci.port));
if (!drv->sk)
return 0;
@@ -1125,7 +1210,16 @@
struct nlattr *nest;
int ret = -1;
- wpa_printf(MSG_DEBUG, "%s -> %d", __func__, sa->an);
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: create_transmit_sa -> %d on "
+ SCISTR " (enable_transmit=%d next_pn=%u)",
+ drv->ifname, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port),
+ sa->enable_transmit, sa->next_pn);
+ wpa_hexdump(MSG_DEBUG, DRV_PREFIX "SA keyid",
+ &sa->pkey->key_identifier,
+ sizeof(sa->pkey->key_identifier));
+ wpa_hexdump_key(MSG_DEBUG, DRV_PREFIX "SA key",
+ sa->pkey->key, sa->pkey->key_len);
msg = msg_prepare(MACSEC_CMD_ADD_TXSA, ctx, drv->ifi);
if (!msg)
@@ -1171,7 +1265,9 @@
struct nlattr *nest;
int ret = -1;
- wpa_printf(MSG_DEBUG, "%s -> %d", __func__, sa->an);
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: delete_transmit_sa -> %d on "
+ SCISTR, drv->ifname, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
msg = msg_prepare(MACSEC_CMD_DEL_TXSA, ctx, drv->ifi);
if (!msg)
@@ -1243,7 +1339,9 @@
struct macsec_genl_ctx *ctx = &drv->ctx;
int ret;
- wpa_printf(MSG_DEBUG, "%s -> %d", __func__, sa->an);
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: enable_transmit_sa -> %d on "
+ SCISTR, drv->ifname, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
ret = set_active_tx_sa(ctx, drv->ifi, sa->an, TRUE);
if (ret < 0) {
@@ -1269,12 +1367,38 @@
struct macsec_drv_data *drv = priv;
struct macsec_genl_ctx *ctx = &drv->ctx;
- wpa_printf(MSG_DEBUG, "%s -> %d", __func__, sa->an);
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: disable_transmit_sa -> %d on "
+ SCISTR, drv->ifname, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
return set_active_tx_sa(ctx, drv->ifi, sa->an, FALSE);
}
+static int macsec_drv_status(void *priv, char *buf, size_t buflen)
+{
+ struct macsec_drv_data *drv = priv;
+ int res;
+ char *pos, *end;
+
+ pos = buf;
+ end = buf + buflen;
+
+ res = os_snprintf(pos, end - pos,
+ "ifname=%s\n"
+ "ifi=%d\n"
+ "parent_ifname=%s\n"
+ "parent_ifi=%d\n",
+ drv->common.ifname, drv->ifi,
+ drv->ifname, drv->parent_ifi);
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+
+ return pos - buf;
+}
+
+
const struct wpa_driver_ops wpa_driver_macsec_linux_ops = {
.name = "macsec_linux",
.desc = "MACsec Ethernet driver for Linux",
@@ -1293,6 +1417,7 @@
.set_current_cipher_suite = macsec_drv_set_current_cipher_suite,
.enable_controlled_port = macsec_drv_enable_controlled_port,
.get_receive_lowest_pn = macsec_drv_get_receive_lowest_pn,
+ .set_receive_lowest_pn = macsec_drv_set_receive_lowest_pn,
.get_transmit_next_pn = macsec_drv_get_transmit_next_pn,
.set_transmit_next_pn = macsec_drv_set_transmit_next_pn,
.create_receive_sc = macsec_drv_create_receive_sc,
@@ -1307,4 +1432,6 @@
.delete_transmit_sa = macsec_drv_delete_transmit_sa,
.enable_transmit_sa = macsec_drv_enable_transmit_sa,
.disable_transmit_sa = macsec_drv_disable_transmit_sa,
+
+ .status = macsec_drv_status,
};
diff --git a/src/drivers/driver_macsec_qca.c b/src/drivers/driver_macsec_qca.c
index d3be19c..8372393 100644
--- a/src/drivers/driver_macsec_qca.c
+++ b/src/drivers/driver_macsec_qca.c
@@ -39,6 +39,9 @@
#define MAXSC 16
+#define SAK_128_LEN 16
+#define SAK_256_LEN 32
+
/* TCI field definition */
#define TCI_ES 0x40
#define TCI_SC 0x20
@@ -226,19 +229,32 @@
}
+static fal_cipher_suite_e macsec_qca_cs_type_get(u64 cs)
+{
+ if (cs == CS_ID_GCM_AES_128)
+ return FAL_CIPHER_SUITE_AES_GCM_128;
+ if (cs == CS_ID_GCM_AES_256)
+ return FAL_CIPHER_SUITE_AES_GCM_256;
+ return FAL_CIPHER_SUITE_MAX;
+}
+
+
static int macsec_qca_set_current_cipher_suite(void *priv, u64 cs)
{
- if (cs != CS_ID_GCM_AES_128) {
+ struct macsec_qca_data *drv = priv;
+ fal_cipher_suite_e cs_type;
+
+ if (cs != CS_ID_GCM_AES_128 && cs != CS_ID_GCM_AES_256) {
wpa_printf(MSG_ERROR,
"%s: NOT supported CipherSuite: %016" PRIx64,
__func__, cs);
return -1;
}
- /* Support default Cipher Suite 0080020001000001 (GCM-AES-128) */
- wpa_printf(MSG_DEBUG, "%s: default support aes-gcm-128", __func__);
+ wpa_printf(MSG_DEBUG, "%s: CipherSuite: %016" PRIx64, __func__, cs);
- return 0;
+ cs_type = macsec_qca_cs_type_get(cs);
+ return nss_macsec_secy_cipher_suite_set(drv->secy_id, cs_type);
}
@@ -367,7 +383,7 @@
}
-int macsec_qca_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
+static int macsec_qca_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
{
struct macsec_qca_data *drv = priv;
int ret = 0;
@@ -436,8 +452,8 @@
os_memset(&entry, 0, sizeof(entry));
os_memcpy(entry.sci, sci_addr, ETH_ALEN);
- entry.sci[6] = (sci_port >> 8) & 0xf;
- entry.sci[7] = sci_port & 0xf;
+ entry.sci[6] = (sci_port >> 8) & 0xff;
+ entry.sci[7] = sci_port & 0xff;
entry.sci_mask = 0xf;
entry.valid = 1;
@@ -499,6 +515,8 @@
fal_rx_sak_t rx_sak;
int i = 0;
u32 channel;
+ fal_rx_prc_lut_t entry;
+ u32 offset;
ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
if (ret != 0)
@@ -508,9 +526,30 @@
__func__, channel, sa->an, sa->lowest_pn);
os_memset(&rx_sak, 0, sizeof(rx_sak));
- for (i = 0; i < 16; i++)
- rx_sak.sak[i] = sa->pkey->key[15 - i];
+ rx_sak.sak_len = sa->pkey->key_len;
+ if (sa->pkey->key_len == SAK_128_LEN) {
+ for (i = 0; i < 16; i++)
+ rx_sak.sak[i] = sa->pkey->key[15 - i];
+ } else if (sa->pkey->key_len == SAK_256_LEN) {
+ for (i = 0; i < 16; i++) {
+ rx_sak.sak1[i] = sa->pkey->key[15 - i];
+ rx_sak.sak[i] = sa->pkey->key[31 - i];
+ }
+ } else {
+ return -1;
+ }
+ if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_0)
+ offset = 0;
+ else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_30)
+ offset = 30;
+ else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_50)
+ offset = 50;
+ else
+ return -1;
+ ret += nss_macsec_secy_rx_prc_lut_get(drv->secy_id, channel, &entry);
+ entry.offset = offset;
+ ret += nss_macsec_secy_rx_prc_lut_set(drv->secy_id, channel, &entry);
ret += nss_macsec_secy_rx_sa_create(drv->secy_id, channel, sa->an);
ret += nss_macsec_secy_rx_sak_set(drv->secy_id, channel, sa->an,
&rx_sak);
@@ -592,6 +631,7 @@
fal_tx_class_lut_t entry;
u8 psci[ETH_ALEN + 2];
u32 channel;
+ u16 sci_port = be_to_host16(sc->sci.port);
ret = macsec_qca_get_available_transmit_sc(priv, &channel);
if (ret != 0)
@@ -607,8 +647,8 @@
entry.channel = channel;
os_memcpy(psci, sc->sci.addr, ETH_ALEN);
- psci[6] = (sc->sci.port >> 8) & 0xf;
- psci[7] = sc->sci.port & 0xf;
+ psci[6] = (sci_port >> 8) & 0xff;
+ psci[7] = sci_port & 0xff;
ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
ret += nss_macsec_secy_tx_sc_create(drv->secy_id, channel, psci, 8);
@@ -655,6 +695,7 @@
fal_tx_sak_t tx_sak;
int i;
u32 channel;
+ u32 offset;
ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
if (ret != 0)
@@ -675,9 +716,30 @@
tci |= TCI_E | TCI_C;
os_memset(&tx_sak, 0, sizeof(tx_sak));
- for (i = 0; i < 16; i++)
- tx_sak.sak[i] = sa->pkey->key[15 - i];
+ tx_sak.sak_len = sa->pkey->key_len;
+ if (sa->pkey->key_len == SAK_128_LEN) {
+ for (i = 0; i < 16; i++)
+ tx_sak.sak[i] = sa->pkey->key[15 - i];
+ } else if (sa->pkey->key_len == SAK_256_LEN) {
+ for (i = 0; i < 16; i++) {
+ tx_sak.sak1[i] = sa->pkey->key[15 - i];
+ tx_sak.sak[i] = sa->pkey->key[31 - i];
+ }
+ } else {
+ return -1;
+ }
+ if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_0)
+ offset = 0;
+ else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_30)
+ offset = 30;
+ else if (sa->pkey->confidentiality_offset == CONFIDENTIALITY_OFFSET_50)
+ offset = 50;
+ else
+ return -1;
+ ret += nss_macsec_secy_tx_sc_confidentiality_offset_set(drv->secy_id,
+ channel,
+ offset);
ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an,
sa->next_pn);
ret += nss_macsec_secy_tx_sak_set(drv->secy_id, channel, sa->an,
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 2ce03ed..21d1398 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -40,6 +40,32 @@
#include "driver_nl80211.h"
+#ifndef NETLINK_CAP_ACK
+#define NETLINK_CAP_ACK 10
+#endif /* NETLINK_CAP_ACK */
+/* support for extack if compilation headers are too old */
+#ifndef NETLINK_EXT_ACK
+#define NETLINK_EXT_ACK 11
+enum nlmsgerr_attrs {
+ NLMSGERR_ATTR_UNUSED,
+ NLMSGERR_ATTR_MSG,
+ NLMSGERR_ATTR_OFFS,
+ NLMSGERR_ATTR_COOKIE,
+
+ __NLMSGERR_ATTR_MAX,
+ NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
+};
+#endif
+#ifndef NLM_F_CAPPED
+#define NLM_F_CAPPED 0x100
+#endif
+#ifndef NLM_F_ACK_TLVS
+#define NLM_F_ACK_TLVS 0x200
+#endif
+#ifndef SOL_NETLINK
+#define SOL_NETLINK 270
+#endif
+
#ifndef CONFIG_LIBNL20
/*
* libnl 1.1 has a bug, it tries to allocate socket numbers densely
@@ -130,7 +156,7 @@
static void nl80211_register_eloop_read(struct nl_handle **handle,
eloop_sock_handler handler,
- void *eloop_data)
+ void *eloop_data, int persist)
{
#ifdef CONFIG_LIBNL20
/*
@@ -151,13 +177,17 @@
nl_socket_set_nonblocking(*handle);
eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
eloop_data, *handle);
- *handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID);
+ if (!persist)
+ *handle = (void *) (((intptr_t) *handle) ^
+ ELOOP_SOCKET_INVALID);
}
-static void nl80211_destroy_eloop_handle(struct nl_handle **handle)
+static void nl80211_destroy_eloop_handle(struct nl_handle **handle, int persist)
{
- *handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID);
+ if (!persist)
+ *handle = (void *) (((intptr_t) *handle) ^
+ ELOOP_SOCKET_INVALID);
eloop_unregister_read_sock(nl_socket_get_fd(*handle));
nl_destroy_handles(handle);
}
@@ -277,6 +307,7 @@
os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
drv->associated = 0;
os_memset(drv->bssid, 0, ETH_ALEN);
+ drv->first_bss->freq = 0;
}
@@ -298,8 +329,35 @@
static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
void *arg)
{
+ struct nlmsghdr *nlh = (struct nlmsghdr *) err - 1;
+ int len = nlh->nlmsg_len;
+ struct nlattr *attrs;
+ struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
int *ret = arg;
+ int ack_len = sizeof(*nlh) + sizeof(int) + sizeof(*nlh);
+
*ret = err->error;
+
+ if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
+ return NL_SKIP;
+
+ if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
+ ack_len += err->msg.nlmsg_len - sizeof(*nlh);
+
+ if (len <= ack_len)
+ return NL_STOP;
+
+ attrs = (void *) ((unsigned char *) nlh + ack_len);
+ len -= ack_len;
+
+ nla_parse(tb, NLMSGERR_ATTR_MAX, attrs, len, NULL);
+ if (tb[NLMSGERR_ATTR_MSG]) {
+ len = strnlen((char *) nla_data(tb[NLMSGERR_ATTR_MSG]),
+ nla_len(tb[NLMSGERR_ATTR_MSG]));
+ wpa_printf(MSG_ERROR, "nl80211: kernel reports: %*s",
+ len, (char *) nla_data(tb[NLMSGERR_ATTR_MSG]));
+ }
+
return NL_SKIP;
}
@@ -338,7 +396,7 @@
void *valid_data)
{
struct nl_cb *cb;
- int err = -ENOMEM;
+ int err = -ENOMEM, opt;
if (!msg)
return -ENOMEM;
@@ -347,6 +405,16 @@
if (!cb)
goto out;
+ /* try to set NETLINK_EXT_ACK to 1, ignoring errors */
+ opt = 1;
+ setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
+ NETLINK_EXT_ACK, &opt, sizeof(opt));
+
+ /* try to set NETLINK_CAP_ACK to 1, ignoring errors */
+ opt = 1;
+ setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
+ NETLINK_CAP_ACK, &opt, sizeof(opt));
+
err = nl_send_auto_complete(nl_handle, msg);
if (err < 0)
goto out;
@@ -723,7 +791,7 @@
}
nl80211_register_eloop_read(&w->nl_beacons,
- nl80211_recv_beacons, w);
+ nl80211_recv_beacons, w, 0);
}
dl_list_add(&nl80211_wiphys, &w->list);
@@ -772,7 +840,7 @@
return;
if (w->nl_beacons)
- nl80211_destroy_eloop_handle(&w->nl_beacons);
+ nl80211_destroy_eloop_handle(&w->nl_beacons, 0);
nl_cb_put(w->nl_cb);
dl_list_del(&w->list);
@@ -947,7 +1015,7 @@
static void nl80211_refresh_mac(struct wpa_driver_nl80211_data *drv,
- int ifindex)
+ int ifindex, int notify)
{
struct i802_bss *bss;
u8 addr[ETH_ALEN];
@@ -966,6 +1034,9 @@
ifindex, bss->ifname,
MAC2STR(bss->addr), MAC2STR(addr));
os_memcpy(bss->addr, addr, ETH_ALEN);
+ if (notify)
+ wpa_supplicant_event(drv->ctx,
+ EVENT_INTERFACE_MAC_CHANGED, NULL);
}
}
@@ -1037,11 +1108,11 @@
namebuf[0] = '\0';
if (if_indextoname(ifi->ifi_index, namebuf) &&
linux_iface_up(drv->global->ioctl_sock, namebuf) > 0) {
- /* Re-read MAC address as it may have changed */
- nl80211_refresh_mac(drv, ifi->ifi_index);
wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
"event since interface %s is up", namebuf);
drv->ignore_if_down_event = 0;
+ /* Re-read MAC address as it may have changed */
+ nl80211_refresh_mac(drv, ifi->ifi_index, 1);
return;
}
wpa_printf(MSG_DEBUG, "nl80211: Interface down (%s/%s)",
@@ -1072,11 +1143,20 @@
}
if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
+ namebuf[0] = '\0';
if (if_indextoname(ifi->ifi_index, namebuf) &&
linux_iface_up(drv->global->ioctl_sock, namebuf) == 0) {
wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
"event since interface %s is down",
namebuf);
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Interface up (%s/%s)",
+ namebuf, ifname);
+ if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Not the main interface (%s) - do not indicate interface up",
+ drv->first_bss->ifname);
} else if (if_nametoindex(drv->first_bss->ifname) == 0) {
wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
"event since interface %s does not exist",
@@ -1087,9 +1167,8 @@
"removed", drv->first_bss->ifname);
} else {
/* Re-read MAC address as it may have changed */
- nl80211_refresh_mac(drv, ifi->ifi_index);
+ nl80211_refresh_mac(drv, ifi->ifi_index, 0);
- wpa_printf(MSG_DEBUG, "nl80211: Interface up");
drv->if_disabled = 0;
wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
NULL);
@@ -1399,7 +1478,7 @@
{
struct nl_msg *msg;
- sig->current_signal = -9999;
+ sig->current_signal = -WPA_INVALID_NOISE;
sig->current_txrate = 0;
if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_STATION)) ||
@@ -1461,7 +1540,7 @@
{
struct nl_msg *msg;
- sig_change->current_noise = 9999;
+ sig_change->current_noise = WPA_INVALID_NOISE;
sig_change->frequency = drv->assoc_freq;
msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
@@ -1469,6 +1548,70 @@
}
+static int get_channel_info(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1] = { 0 };
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct wpa_channel_info *chan_info = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ os_memset(chan_info, 0, sizeof(struct wpa_channel_info));
+ chan_info->chanwidth = CHAN_WIDTH_UNKNOWN;
+
+ if (tb[NL80211_ATTR_WIPHY_FREQ])
+ chan_info->frequency =
+ nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+ if (tb[NL80211_ATTR_CHANNEL_WIDTH])
+ chan_info->chanwidth = convert2width(
+ nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
+ if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+ enum nl80211_channel_type ct =
+ nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+
+ switch (ct) {
+ case NL80211_CHAN_HT40MINUS:
+ chan_info->sec_channel = -1;
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ chan_info->sec_channel = 1;
+ break;
+ default:
+ chan_info->sec_channel = 0;
+ break;
+ }
+ }
+ if (tb[NL80211_ATTR_CENTER_FREQ1])
+ chan_info->center_frq1 =
+ nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+ if (tb[NL80211_ATTR_CENTER_FREQ2])
+ chan_info->center_frq2 =
+ nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+
+ if (chan_info->center_frq2) {
+ u8 seg1_idx = 0;
+
+ if (ieee80211_freq_to_chan(chan_info->center_frq2, &seg1_idx) !=
+ NUM_HOSTAPD_MODES)
+ chan_info->seg1_idx = seg1_idx;
+ }
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_channel_info(void *priv, struct wpa_channel_info *ci)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ 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);
+}
+
+
static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
void *handle)
{
@@ -1631,7 +1774,7 @@
nl80211_register_eloop_read(&global->nl_event,
wpa_driver_nl80211_event_receive,
- global->nl_cb);
+ global->nl_cb, 0);
return 0;
@@ -1997,7 +2140,7 @@
{
nl80211_register_eloop_read(&bss->nl_mgmt,
wpa_driver_nl80211_event_receive,
- bss->nl_cb);
+ bss->nl_cb, 0);
}
@@ -2010,6 +2153,25 @@
}
+static int nl80211_init_connect_handle(struct i802_bss *bss)
+{
+ if (bss->nl_connect) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Connect handle already created (nl_connect=%p)",
+ bss->nl_connect);
+ return -1;
+ }
+
+ bss->nl_connect = nl_create_handle(bss->nl_cb, "connect");
+ if (!bss->nl_connect)
+ return -1;
+ nl80211_register_eloop_read(&bss->nl_connect,
+ wpa_driver_nl80211_event_receive,
+ bss->nl_cb, 1);
+ return 0;
+}
+
+
static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -2020,7 +2182,9 @@
wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
"handle %p", bss->nl_mgmt);
- if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
+ if (drv->nlmode == NL80211_IFTYPE_ADHOC ||
+ ((drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
+ !(drv->capa.flags & WPA_DRIVER_FLAGS_SME))) {
u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
/* register for any AUTH message */
@@ -2078,6 +2242,11 @@
ret = -1;
#endif /* CONFIG_DPP */
#ifdef CONFIG_IEEE80211W
+#ifdef CONFIG_OCV
+ /* SA Query Request */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x08\x00", 2) < 0)
+ ret = -1;
+#endif /* CONFIG_OCV */
/* SA Query Response */
if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
ret = -1;
@@ -2109,6 +2278,11 @@
/* WNM-Sleep Mode Response */
if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
ret = -1;
+#ifdef CONFIG_WNM
+ /* WNM - Collocated Interference Request */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x0b", 2) < 0)
+ ret = -1;
+#endif /* CONFIG_WNM */
#ifdef CONFIG_HS20
/* WNM-Notification */
@@ -2296,6 +2470,16 @@
if (nl80211_action_subscribe_ap(bss))
goto out_err;
+ if (bss->drv->device_ap_sme) {
+ u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
+
+ /* Register for all Authentication frames */
+ if (nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0)
+ < 0)
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to subscribe to handle Authentication frames - SAE offload may not work");
+ }
+
nl80211_mgmt_handle_register_eloop(bss);
return 0;
@@ -2311,7 +2495,7 @@
return;
wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
"(%s)", bss->nl_mgmt, reason);
- nl80211_destroy_eloop_handle(&bss->nl_mgmt);
+ nl80211_destroy_eloop_handle(&bss->nl_mgmt, 0);
nl80211_put_wiphy_data_ap(bss);
}
@@ -2527,6 +2711,8 @@
if (drv->vendor_cmd_test_avail)
qca_vendor_test(drv);
+ nl80211_init_connect_handle(bss);
+
return 0;
}
@@ -2573,9 +2759,11 @@
wpa_printf(MSG_INFO, "nl80211: Failed to remove "
"interface %s from bridge %s: %s",
bss->ifname, bss->brname, strerror(errno));
- if (drv->rtnl_sk)
- nl80211_handle_destroy(drv->rtnl_sk);
}
+
+ if (drv->rtnl_sk)
+ nl80211_handle_destroy(drv->rtnl_sk);
+
if (bss->added_bridge) {
if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
0) < 0)
@@ -2640,6 +2828,9 @@
nl80211_del_p2pdev(bss);
}
+ if (bss->nl_connect)
+ nl80211_destroy_eloop_handle(&bss->nl_connect, 1);
+
nl80211_destroy_bss(drv->first_bss);
os_free(drv->filter_ssids);
@@ -2782,6 +2973,44 @@
#endif /* CONFIG_DRIVER_NL80211_QCA */
+static int nl80211_set_pmk(struct wpa_driver_nl80211_data *drv,
+ const u8 *key, size_t key_len,
+ const u8 *addr)
+{
+ struct nl_msg *msg = NULL;
+ int ret;
+
+ /*
+ * If the authenticator address is not set, assume it is
+ * the current BSSID.
+ */
+ if (!addr && drv->associated)
+ addr = drv->bssid;
+ else if (!addr)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Set PMK to the driver for " MACSTR,
+ MAC2STR(addr));
+ wpa_hexdump_key(MSG_DEBUG, "nl80211: PMK", key, key_len);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_PMK);
+ if (!msg ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ nla_put(msg, NL80211_ATTR_PMK, key_len, key)) {
+ nl80211_nlmsg_clear(msg);
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Set PMK failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ }
+
+ return ret;
+}
+
+
static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
enum wpa_alg alg, const u8 *addr,
int key_idx, int set_tx,
@@ -2820,6 +3049,10 @@
}
#endif /* CONFIG_DRIVER_NL80211_QCA */
+ if (alg == WPA_ALG_PMK &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X))
+ return nl80211_set_pmk(drv, key, key_len, addr);
+
if (alg == WPA_ALG_NONE) {
msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
if (!msg)
@@ -3020,7 +3253,8 @@
int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
const u8 *addr, int cmd, u16 reason_code,
- int local_state_change)
+ int local_state_change,
+ struct nl_handle *nl_connect)
{
int ret;
struct nl_msg *msg;
@@ -3034,7 +3268,10 @@
return -1;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (nl_connect)
+ ret = send_and_recv(drv->global, nl_connect, msg, NULL, NULL);
+ else
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret) {
wpa_dbg(drv->ctx, MSG_DEBUG,
"nl80211: MLME command failed: reason=%u ret=%d (%s)",
@@ -3045,20 +3282,22 @@
static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
- int reason_code)
+ int reason_code,
+ struct nl_handle *nl_connect)
{
int ret;
+ int drv_associated = drv->associated;
wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
nl80211_mark_disconnected(drv);
/* Disconnect command doesn't need BSSID - it uses cached value */
ret = wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
- reason_code, 0);
+ reason_code, 0, nl_connect);
/*
* For locally generated disconnect, supplicant already generates a
* DEAUTH event, so ignore the event from NL80211.
*/
- drv->ignore_next_local_disconnect = ret == 0;
+ drv->ignore_next_local_disconnect = drv_associated && (ret == 0);
return ret;
}
@@ -3069,23 +3308,31 @@
{
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret;
+ int drv_associated = drv->associated;
if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
nl80211_mark_disconnected(drv);
return nl80211_leave_ibss(drv, 1);
}
- if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
- return wpa_driver_nl80211_disconnect(drv, reason_code);
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
+ struct nl_handle *nl_connect = NULL;
+
+ if (bss->use_nl_connect)
+ nl_connect = bss->nl_connect;
+ return wpa_driver_nl80211_disconnect(drv, reason_code,
+ nl_connect);
+ }
wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
__func__, MAC2STR(addr), reason_code);
nl80211_mark_disconnected(drv);
ret = wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
- reason_code, 0);
+ reason_code, 0, NULL);
/*
* For locally generated deauthenticate, supplicant already generates a
* DEAUTH event, so ignore the event from NL80211.
*/
- drv->ignore_next_local_deauth = ret == 0;
+ drv->ignore_next_local_deauth = drv_associated && (ret == 0);
+
return ret;
}
@@ -3241,8 +3488,8 @@
goto fail;
}
if (params->ssid) {
- wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
- params->ssid, params->ssid_len);
+ wpa_printf(MSG_DEBUG, " * SSID=%s",
+ wpa_ssid_txt(params->ssid, params->ssid_len));
if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
params->ssid))
goto fail;
@@ -3273,11 +3520,11 @@
msg = NULL;
if (ret) {
wpa_dbg(drv->ctx, MSG_DEBUG,
- "nl80211: MLME command failed (auth): ret=%d (%s)",
- ret, strerror(-ret));
+ "nl80211: MLME command failed (auth): count=%d ret=%d (%s)",
+ count, ret, strerror(-ret));
count++;
- if (ret == -EALREADY && count == 1 && params->bssid &&
- !params->local_state_change) {
+ if ((ret == -EALREADY || ret == -EEXIST) && count == 1 &&
+ params->bssid && !params->local_state_change) {
/*
* mac80211 does not currently accept new
* authentication if we are already authenticated. As a
@@ -3809,7 +4056,7 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
u8 cmd = NL80211_CMD_NEW_BEACON;
- int ret;
+ int ret = -ENOBUFS;
int beacon_set;
int num_suites;
int smps_mode;
@@ -3838,8 +4085,8 @@
wpa_printf(MSG_DEBUG, "nl80211: beacon_rate=%u", params->beacon_rate);
wpa_printf(MSG_DEBUG, "nl80211: rate_type=%d", params->rate_type);
wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
- wpa_hexdump_ascii(MSG_DEBUG, "nl80211: ssid",
- params->ssid, params->ssid_len);
+ wpa_printf(MSG_DEBUG, "nl80211: ssid=%s",
+ wpa_ssid_txt(params->ssid, params->ssid_len));
if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
nla_put(msg, NL80211_ATTR_BEACON_HEAD, params->head_len,
params->head) ||
@@ -3924,6 +4171,9 @@
nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
goto fail;
+ if (drv->device_ap_sme && (params->key_mgmt_suites & WPA_KEY_MGMT_SAE))
+ nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT);
+
wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
params->pairwise_ciphers);
num_suites = wpa_cipher_to_cipher_suites(params->pairwise_ciphers,
@@ -3957,7 +4207,7 @@
smps_mode = NL80211_SMPS_OFF;
break;
}
- if (nla_put_u32(msg, NL80211_ATTR_SMPS_MODE, smps_mode))
+ if (nla_put_u8(msg, NL80211_ATTR_SMPS_MODE, smps_mode))
goto fail;
}
@@ -4015,6 +4265,29 @@
goto fail;
}
+ if (params->ftm_responder) {
+ struct nlattr *ftm;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_FTM_RESPONDER)) {
+ ret = -ENOTSUP;
+ goto fail;
+ }
+
+ ftm = nla_nest_start(msg, NL80211_ATTR_FTM_RESPONDER);
+ if (!ftm ||
+ nla_put_flag(msg, NL80211_FTM_RESP_ATTR_ENABLED) ||
+ (params->lci &&
+ nla_put(msg, NL80211_FTM_RESP_ATTR_LCI,
+ wpabuf_len(params->lci),
+ wpabuf_head(params->lci))) ||
+ (params->civic &&
+ nla_put(msg, NL80211_FTM_RESP_ATTR_CIVICLOC,
+ wpabuf_len(params->civic),
+ wpabuf_head(params->civic))))
+ goto fail;
+ nla_nest_end(msg, ftm);
+ }
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
@@ -4066,7 +4339,7 @@
return ret;
fail:
nlmsg_free(msg);
- return -ENOBUFS;
+ return ret;
}
@@ -4420,7 +4693,8 @@
goto fail;
#endif /* CONFIG_MESH */
- if (params->flags & WPA_STA_WMM) {
+ if ((!params->set || FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags)) &&
+ (params->flags & WPA_STA_WMM)) {
struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
wpa_printf(MSG_DEBUG, " * qosinfo=0x%x", params->qosinfo);
@@ -5030,8 +5304,8 @@
params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
goto fail;
- wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
- params->ssid, params->ssid_len);
+ wpa_printf(MSG_DEBUG, " * SSID=%s",
+ wpa_ssid_txt(params->ssid, params->ssid_len));
if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
goto fail;
os_memcpy(drv->ssid, params->ssid, params->ssid_len);
@@ -5192,8 +5466,8 @@
}
if (params->ssid) {
- wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
- params->ssid, params->ssid_len);
+ wpa_printf(MSG_DEBUG, " * SSID=%s",
+ wpa_ssid_txt(params->ssid, params->ssid_len));
if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
params->ssid))
return -1;
@@ -5251,12 +5525,17 @@
params->key_mgmt_suite == WPA_KEY_MGMT_OSEN ||
params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE ||
params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X_SHA384 ||
params->key_mgmt_suite == WPA_KEY_MGMT_FILS_SHA256 ||
params->key_mgmt_suite == WPA_KEY_MGMT_FILS_SHA384 ||
params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA256 ||
- params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA384) {
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA384 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_OWE ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_DPP) {
int mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
switch (params->key_mgmt_suite) {
@@ -5281,12 +5560,21 @@
case WPA_KEY_MGMT_OSEN:
mgmt = RSN_AUTH_KEY_MGMT_OSEN;
break;
+ case WPA_KEY_MGMT_SAE:
+ mgmt = RSN_AUTH_KEY_MGMT_SAE;
+ break;
+ case WPA_KEY_MGMT_FT_SAE:
+ mgmt = RSN_AUTH_KEY_MGMT_FT_SAE;
+ break;
case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
break;
case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
break;
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+ mgmt = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
+ break;
case WPA_KEY_MGMT_FILS_SHA256:
mgmt = RSN_AUTH_KEY_MGMT_FILS_SHA256;
break;
@@ -5299,6 +5587,12 @@
case WPA_KEY_MGMT_FT_FILS_SHA384:
mgmt = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
break;
+ case WPA_KEY_MGMT_OWE:
+ mgmt = RSN_AUTH_KEY_MGMT_OWE;
+ break;
+ case WPA_KEY_MGMT_DPP:
+ mgmt = RSN_AUTH_KEY_MGMT_DPP;
+ break;
case WPA_KEY_MGMT_PSK:
default:
mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
@@ -5309,6 +5603,21 @@
return -1;
}
+ if (params->req_key_mgmt_offload &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)) {
+ wpa_printf(MSG_DEBUG, " * WANT_1X_4WAY_HS");
+ if (nla_put_flag(msg, NL80211_ATTR_WANT_1X_4WAY_HS))
+ return -1;
+ }
+
+ /* Add PSK in case of 4-way handshake offload */
+ if (params->psk &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK)) {
+ wpa_hexdump_key(MSG_DEBUG, " * PSK", params->psk, 32);
+ if (nla_put(msg, NL80211_ATTR_PMK, 32, params->psk))
+ return -1;
+ }
+
if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
return -1;
@@ -5320,10 +5629,6 @@
nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
return -1;
- if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
- nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
- return -1;
-
if (params->rrm_used) {
u32 drv_rrm_flags = drv->capa.rrm_flags;
if ((!((drv_rrm_flags &
@@ -5360,13 +5665,19 @@
nl80211_put_fils_connect_params(drv, params, msg) != 0)
return -1;
+ if ((params->auth_alg & WPA_AUTH_ALG_SAE) &&
+ (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) &&
+ nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
+ return -1;
+
return 0;
}
static int wpa_driver_nl80211_try_connect(
struct wpa_driver_nl80211_data *drv,
- struct wpa_driver_associate_params *params)
+ struct wpa_driver_associate_params *params,
+ struct nl_handle *nl_connect)
{
struct nl_msg *msg;
enum nl80211_auth_type type;
@@ -5394,6 +5705,15 @@
if (ret)
goto fail;
+ if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
+ nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
+ goto fail;
+
+ if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_OPTIONAL &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_MFP_OPTIONAL) &&
+ nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_OPTIONAL))
+ goto fail;
+
algs = 0;
if (params->auth_alg & WPA_AUTH_ALG_OPEN)
algs++;
@@ -5403,6 +5723,8 @@
algs++;
if (params->auth_alg & WPA_AUTH_ALG_FILS)
algs++;
+ if (params->auth_alg & WPA_AUTH_ALG_FT)
+ algs++;
if (algs > 1) {
wpa_printf(MSG_DEBUG, " * Leave out Auth Type for automatic "
"selection");
@@ -5420,7 +5742,12 @@
if (ret)
goto fail;
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (nl_connect)
+ ret = send_and_recv(drv->global, nl_connect, msg,
+ NULL, (void *) -1);
+ else
+ ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
+
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
@@ -5431,6 +5758,7 @@
}
fail:
+ nl80211_nlmsg_clear(msg);
nlmsg_free(msg);
return ret;
@@ -5439,7 +5767,8 @@
static int wpa_driver_nl80211_connect(
struct wpa_driver_nl80211_data *drv,
- struct wpa_driver_associate_params *params)
+ struct wpa_driver_associate_params *params,
+ struct nl_handle *nl_connect)
{
int ret;
@@ -5449,7 +5778,7 @@
else
os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
- ret = wpa_driver_nl80211_try_connect(drv, params);
+ ret = wpa_driver_nl80211_try_connect(drv, params, nl_connect);
if (ret == -EALREADY) {
/*
* cfg80211 does not currently accept new connections if
@@ -5460,9 +5789,9 @@
"disconnecting before reassociation "
"attempt");
if (wpa_driver_nl80211_disconnect(
- drv, WLAN_REASON_PREV_AUTH_NOT_VALID))
+ drv, WLAN_REASON_PREV_AUTH_NOT_VALID, nl_connect))
return -1;
- ret = wpa_driver_nl80211_try_connect(drv, params);
+ ret = wpa_driver_nl80211_try_connect(drv, params, nl_connect);
}
return ret;
}
@@ -5487,10 +5816,18 @@
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
enum nl80211_iftype nlmode = params->p2p ?
NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
+ struct nl_handle *nl_connect = NULL;
if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
return -1;
- return wpa_driver_nl80211_connect(drv, params);
+ if (params->auth_alg & WPA_AUTH_ALG_SAE) {
+ nl_connect = bss->nl_connect;
+ bss->use_nl_connect = 1;
+ } else {
+ bss->use_nl_connect = 0;
+ }
+
+ return wpa_driver_nl80211_connect(drv, params, nl_connect);
}
nl80211_mark_disconnected(drv);
@@ -5505,6 +5842,10 @@
if (ret)
goto fail;
+ if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
+ nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
+ goto fail;
+
if (params->fils_kek) {
wpa_printf(MSG_DEBUG, " * FILS KEK (len=%u)",
(unsigned int) params->fils_kek_len);
@@ -5818,6 +6159,7 @@
if (tb[NL80211_ATTR_KEY_SEQ])
memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]),
min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6));
+ nl80211_nlmsg_clear(msg);
return NL_SKIP;
}
@@ -5852,7 +6194,7 @@
int ret;
u32 val;
- if (rts >= 2347)
+ if (rts >= 2347 || rts == -1)
val = (u32) -1;
else
val = rts;
@@ -5880,7 +6222,7 @@
int ret;
u32 val;
- if (frag >= 2346)
+ if (frag >= 2346 || frag == -1)
val = (u32) -1;
else
val = frag;
@@ -5938,6 +6280,7 @@
[NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 },
[NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 },
[NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
+ [NL80211_STA_INFO_ACK_SIGNAL] = { .type = NLA_U8 },
};
struct nlattr *rate[NL80211_RATE_INFO_MAX + 1];
static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
@@ -6000,6 +6343,11 @@
nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
if (stats[NL80211_STA_INFO_SIGNAL])
data->signal = nla_get_u8(stats[NL80211_STA_INFO_SIGNAL]);
+ if (stats[NL80211_STA_INFO_ACK_SIGNAL]) {
+ data->last_ack_rssi =
+ nla_get_u8(stats[NL80211_STA_INFO_ACK_SIGNAL]);
+ data->flags |= STA_DRV_DATA_LAST_ACK_RSSI;
+ }
if (stats[NL80211_STA_INFO_TX_BITRATE] &&
nla_parse_nested(rate, NL80211_RATE_INFO_MAX,
@@ -6086,6 +6434,7 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
struct nlattr *txq, *params;
+ int res;
msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_WIPHY);
if (!msg)
@@ -6131,7 +6480,11 @@
nla_nest_end(msg, txq);
- if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
+ res = send_and_recv_msgs(drv, msg, 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);
+ if (res == 0)
return 0;
msg = NULL;
fail:
@@ -6389,8 +6742,16 @@
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
char name[IFNAMSIZ + 1];
+ union wpa_event_data event;
+ int ret;
- os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
+ ret = os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
+ if (ret >= (int) sizeof(name))
+ wpa_printf(MSG_WARNING,
+ "nl80211: WDS interface name was truncated");
+ else if (ret < 0)
+ return ret;
+
if (ifname_wds)
os_strlcpy(ifname_wds, name, IFNAMSIZ + 1);
@@ -6407,6 +6768,14 @@
linux_br_add_if(drv->global->ioctl_sock,
bridge_ifname, name) < 0)
return -1;
+
+ os_memset(&event, 0, sizeof(event));
+ event.wds_sta_interface.sta_addr = addr;
+ event.wds_sta_interface.ifname = name;
+ event.wds_sta_interface.istatus = INTERFACE_ADDED;
+ wpa_supplicant_event(bss->ctx,
+ EVENT_WDS_STA_INTERFACE_STATUS,
+ &event);
}
if (linux_set_iface_flags(drv->global->ioctl_sock, name, 1)) {
wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
@@ -6414,12 +6783,21 @@
}
return i802_set_sta_vlan(priv, addr, name, 0);
} else {
- if (bridge_ifname)
- linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
- name);
+ if (bridge_ifname &&
+ linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
+ name) < 0)
+ wpa_printf(MSG_INFO,
+ "nl80211: Failed to remove interface %s from bridge %s: %s",
+ name, bridge_ifname, strerror(errno));
i802_set_sta_vlan(priv, addr, bss->ifname, 0);
nl80211_remove_iface(drv, if_nametoindex(name));
+ os_memset(&event, 0, sizeof(event));
+ event.wds_sta_interface.sta_addr = addr;
+ event.wds_sta_interface.ifname = name;
+ event.wds_sta_interface.istatus = INTERFACE_REMOVED;
+ wpa_supplicant_event(bss->ctx, EVENT_WDS_STA_INTERFACE_STATUS,
+ &event);
return 0;
}
}
@@ -6473,8 +6851,10 @@
bss->br_ifindex = br_ifindex;
if (linux_br_get(in_br, ifname) == 0) {
- if (os_strcmp(in_br, brname) == 0)
+ if (os_strcmp(in_br, brname) == 0) {
+ bss->already_in_bridge = 1;
return 0; /* already in the bridge */
+ }
wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
"bridge %s", ifname, in_br);
@@ -6571,7 +6951,7 @@
add_ifidx(drv, br_ifindex, drv->ifindex);
#ifdef CONFIG_LIBNL3_ROUTE
- if (bss->added_if_into_bridge) {
+ if (bss->added_if_into_bridge || bss->already_in_bridge) {
drv->rtnl_sk = nl_socket_alloc();
if (drv->rtnl_sk == NULL) {
wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock");
@@ -7200,7 +7580,7 @@
} else if (bss->nl_preq) {
wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
"reporting nl_preq=%p", bss->nl_preq);
- nl80211_destroy_eloop_handle(&bss->nl_preq);
+ nl80211_destroy_eloop_handle(&bss->nl_preq, 0);
}
return 0;
}
@@ -7225,7 +7605,7 @@
nl80211_register_eloop_read(&bss->nl_preq,
wpa_driver_nl80211_event_receive,
- bss->nl_cb);
+ bss->nl_cb, 0);
return 0;
@@ -7540,7 +7920,7 @@
nl_destroy_handles(&global->nl);
if (global->nl_event)
- nl80211_destroy_eloop_handle(&global->nl_event);
+ nl80211_destroy_eloop_handle(&global->nl_event, 0);
nl_cb_put(global->nl_cb);
@@ -7563,6 +7943,7 @@
struct wpa_pmkid_params *params)
{
struct nl_msg *msg;
+ const size_t PMK_MAX_LEN = 48; /* current cfg80211 limit */
if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
(params->pmkid &&
@@ -7574,19 +7955,22 @@
(params->fils_cache_id &&
nla_put(msg, NL80211_ATTR_FILS_CACHE_ID, 2,
params->fils_cache_id)) ||
- (params->pmk_len &&
+ (cmd != NL80211_CMD_DEL_PMKSA &&
+ params->pmk_len && params->pmk_len <= PMK_MAX_LEN &&
nla_put(msg, NL80211_ATTR_PMK, params->pmk_len, params->pmk))) {
+ nl80211_nlmsg_clear(msg);
nlmsg_free(msg);
return -ENOBUFS;
}
- return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ return send_and_recv_msgs(bss->drv, msg, NULL, (void *) -1);
}
static int nl80211_add_pmkid(void *priv, struct wpa_pmkid_params *params)
{
struct i802_bss *bss = priv;
+ int ret;
if (params->bssid)
wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR,
@@ -7598,13 +7982,21 @@
wpa_ssid_txt(params->ssid, params->ssid_len));
}
- return nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, params);
+ ret = nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, params);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: NL80211_CMD_SET_PMKSA failed: %d (%s)",
+ ret, strerror(-ret));
+ }
+
+ return ret;
}
static int nl80211_remove_pmkid(void *priv, struct wpa_pmkid_params *params)
{
struct i802_bss *bss = priv;
+ int ret;
if (params->bssid)
wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
@@ -7616,7 +8008,14 @@
wpa_ssid_txt(params->ssid, params->ssid_len));
}
- return nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, params);
+ ret = nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, params);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: NL80211_CMD_DEL_PMKSA failed: %d (%s)",
+ ret, strerror(-ret));
+ }
+
+ return ret;
}
@@ -7887,6 +8286,7 @@
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
+ u64 cookie;
int ret;
if (!drv->poll_command_supported) {
@@ -7900,11 +8300,16 @@
return;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "nl80211: Client probe request for "
MACSTR " failed: ret=%d (%s)",
MAC2STR(addr), ret, strerror(-ret));
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Client probe request addr=" MACSTR
+ " cookie=%llu", MAC2STR(addr),
+ (long long unsigned int) cookie);
}
}
@@ -7912,6 +8317,7 @@
static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
{
struct nl_msg *msg;
+ int ret;
if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_POWER_SAVE)) ||
nla_put_u32(msg, NL80211_ATTR_PS_STATE,
@@ -7919,7 +8325,15 @@
nlmsg_free(msg);
return -ENOBUFS;
}
- return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+
+ ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Setting PS state %s failed: %d (%s)",
+ enabled ? "enabled" : "disabled",
+ ret, strerror(-ret));
+ }
+ return ret;
}
@@ -8327,6 +8741,8 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
int res;
char *pos, *end;
+ struct nl_msg *msg;
+ char alpha2[3] = { 0, 0, 0 };
pos = buf;
end = buf + buflen;
@@ -8337,7 +8753,7 @@
"brname=%s\n"
"addr=" MACSTR "\n"
"freq=%d\n"
- "%s%s%s%s%s",
+ "%s%s%s%s%s%s",
bss->ifindex,
bss->ifname,
bss->brname,
@@ -8346,6 +8762,7 @@
bss->beacon_set ? "beacon_set=1\n" : "",
bss->added_if_into_bridge ?
"added_if_into_bridge=1\n" : "",
+ bss->already_in_bridge ? "already_in_bridge=1\n" : "",
bss->added_bridge ? "added_bridge=1\n" : "",
bss->in_deinit ? "in_deinit=1\n" : "",
bss->if_dynamic ? "if_dynamic=1\n" : "");
@@ -8470,6 +8887,23 @@
pos += res;
}
+ msg = nlmsg_alloc();
+ if (msg &&
+ 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[0]) {
+ res = os_snprintf(pos, end - pos, "country=%s\n",
+ alpha2);
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+ }
+ } else {
+ nlmsg_free(msg);
+ }
+
return pos - buf;
}
@@ -8521,8 +8955,9 @@
return -EOPNOTSUPP;
}
- if ((drv->nlmode != NL80211_IFTYPE_AP) &&
- (drv->nlmode != NL80211_IFTYPE_P2P_GO))
+ if (drv->nlmode != NL80211_IFTYPE_AP &&
+ drv->nlmode != NL80211_IFTYPE_P2P_GO &&
+ drv->nlmode != NL80211_IFTYPE_MESH_POINT)
return -EOPNOTSUPP;
/*
@@ -8885,6 +9320,34 @@
}
+static int nl80211_disable_fils(void *priv, int disable)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *params;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Disable FILS=%d", disable);
+
+ if (!drv->set_wifi_conf_vendor_cmd_avail)
+ return -1;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_DISABLE_FILS,
+ disable)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+ nla_nest_end(msg, params);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
+
+
/* Reserved QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID value for wpa_supplicant */
#define WPA_SUPPLICANT_CLIENT_ID 1
@@ -9007,8 +9470,8 @@
size_t mesh_id_len)
{
if (mesh_id) {
- wpa_hexdump_ascii(MSG_DEBUG, " * Mesh ID (SSID)",
- mesh_id, mesh_id_len);
+ wpa_printf(MSG_DEBUG, " * Mesh ID (SSID)=%s",
+ wpa_ssid_txt(mesh_id, mesh_id_len));
return nla_put(msg, NL80211_ATTR_MESH_ID, mesh_id_len, mesh_id);
}
@@ -9026,8 +9489,8 @@
return -1;
if (((params->flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
- nla_put_u32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
- params->auto_plinks)) ||
+ nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
+ params->auto_plinks)) ||
((params->flags & WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS) &&
nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
params->max_peer_links)) ||
@@ -10341,6 +10804,93 @@
}
+static int nl80211_send_external_auth_status(void *priv,
+ struct external_auth *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg = NULL;
+ int ret = -1;
+
+ /* External auth command/status is intended for drivers that implement
+ * intenral SME but want to offload authentication processing (e.g.,
+ * SAE) to hostapd/wpa_supplicant. Do nott send the status to drivers
+ * which do not support AP SME or use wpa_supplicant/hostapd SME.
+ */
+ if (!bss->drv->device_ap_sme ||
+ (drv->capa.flags & WPA_DRIVER_FLAGS_SME))
+ return -1;
+
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: External auth status: %u", params->status);
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_EXTERNAL_AUTH);
+ if (!msg ||
+ nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, params->status) ||
+ (params->ssid && params->ssid_len &&
+ nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid)) ||
+ (params->pmkid &&
+ nla_put(msg, NL80211_ATTR_PMKID, PMKID_LEN, params->pmkid)) ||
+ (params->bssid &&
+ nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid)))
+ goto fail;
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: External Auth status update failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ goto fail;
+ }
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int nl80211_set_4addr_mode(void *priv, const char *bridge_ifname,
+ int val)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret = -ENOBUFS;
+
+ wpa_printf(MSG_DEBUG, "nl80211: %s 4addr mode (bridge_ifname: %s)",
+ val ? "Enable" : "Disable", bridge_ifname);
+
+ msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
+ if (!msg || nla_put_u8(msg, NL80211_ATTR_4ADDR, val))
+ goto fail;
+
+ if (bridge_ifname[0] && bss->added_if_into_bridge && !val) {
+ if (linux_br_del_if(drv->global->ioctl_sock,
+ bridge_ifname, bss->ifname)) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to remove interface %s from bridge %s",
+ bss->ifname, bridge_ifname);
+ return -1;
+ }
+ bss->added_if_into_bridge = 0;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (!ret) {
+ if (bridge_ifname[0] && val &&
+ i802_check_bridge(drv, bss, bridge_ifname, bss->ifname) < 0)
+ return -1;
+ return 0;
+ }
+
+fail:
+ nlmsg_free(msg);
+ wpa_printf(MSG_ERROR, "nl80211: Failed to enable/disable 4addr");
+
+ return ret;
+}
+
+
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
@@ -10400,6 +10950,7 @@
.resume = wpa_driver_nl80211_resume,
.signal_monitor = nl80211_signal_monitor,
.signal_poll = nl80211_signal_poll,
+ .channel_info = nl80211_channel_info,
.send_frame = nl80211_send_frame,
.set_param = nl80211_set_param,
.get_radio_name = nl80211_get_radio_name,
@@ -10450,6 +11001,7 @@
.get_ifindex = nl80211_get_ifindex,
#ifdef CONFIG_DRIVER_NL80211_QCA
.roaming = nl80211_roaming,
+ .disable_fils = nl80211_disable_fils,
.do_acs = wpa_driver_do_acs,
.set_band = nl80211_set_band,
.get_pref_freq_list = nl80211_get_pref_freq_list,
@@ -10467,4 +11019,6 @@
.configure_data_frame_filters = nl80211_configure_data_frame_filters,
.get_ext_capab = nl80211_get_ext_capab,
.update_connect_params = nl80211_update_connection_params,
+ .send_external_auth_status = nl80211_send_external_auth_status,
+ .set_4addr_mode = nl80211_set_4addr_mode,
};
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 23cf9db..1e7fe7a 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -60,11 +60,13 @@
char brname[IFNAMSIZ];
unsigned int beacon_set:1;
unsigned int added_if_into_bridge:1;
+ unsigned int already_in_bridge:1;
unsigned int added_bridge:1;
unsigned int in_deinit:1;
unsigned int wdev_id_set:1;
unsigned int added_if:1;
unsigned int static_ap:1;
+ unsigned int use_nl_connect:1;
u8 addr[ETH_ALEN];
@@ -73,7 +75,7 @@
int if_dynamic;
void *ctx;
- struct nl_handle *nl_preq, *nl_mgmt;
+ struct nl_handle *nl_preq, *nl_mgmt, *nl_connect;
struct nl_cb *nl_cb;
struct nl80211_wiphy_data *wiphy_data;
@@ -164,6 +166,7 @@
unsigned int he_capab_vendor_cmd_avail:1;
unsigned int fetch_bss_trans_status:1;
unsigned int roam_vendor_cmd_avail:1;
+ unsigned int get_supported_akm_suites_avail:1;
u64 vendor_scan_cookie;
u64 remain_on_chan_cookie;
@@ -251,7 +254,8 @@
enum nl80211_iftype nlmode);
int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
const u8 *addr, int cmd, u16 reason_code,
- int local_state_change);
+ int local_state_change,
+ struct nl_handle *nl_connect);
int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv);
void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv);
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index f11a1d7..37eeb5e 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -401,6 +401,38 @@
if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_FILS_SK_OFFLOAD))
capa->flags |= WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK))
+ capa->flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK;
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
+ capa->flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_MFP_OPTIONAL))
+ capa->flags |= WPA_DRIVER_FLAGS_MFP_OPTIONAL;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_DFS_OFFLOAD))
+ capa->flags |= WPA_DRIVER_FLAGS_DFS_OFFLOAD;
+
+#ifdef CONFIG_MBO
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME) &&
+ ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP) &&
+ ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE) &&
+ ext_feature_isset(
+ ext_features, len,
+ NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION))
+ capa->flags |= WPA_DRIVER_FLAGS_OCE_STA;
+#endif /* CONFIG_MBO */
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER))
+ capa->flags |= WPA_DRIVER_FLAGS_FTM_RESPONDER;
}
@@ -755,6 +787,9 @@
case QCA_NL80211_VENDOR_SUBCMD_ROAM:
drv->roam_vendor_cmd_avail = 1;
break;
+ case QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS:
+ drv->get_supported_akm_suites_avail = 1;
+ break;
#endif /* CONFIG_DRIVER_NL80211_QCA */
}
}
@@ -791,6 +826,9 @@
capa->max_csa_counters =
nla_get_u8(tb[NL80211_ATTR_MAX_CSA_COUNTERS]);
+ if (tb[NL80211_ATTR_WIPHY_SELF_MANAGED_REG])
+ capa->flags |= WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY;
+
return NL_SKIP;
}
@@ -924,6 +962,126 @@
}
+static unsigned int get_akm_suites_info(struct nlattr *tb)
+{
+ int i, num;
+ unsigned int key_mgmt = 0;
+ u32 *akms;
+
+ if (!tb)
+ return 0;
+
+ num = nla_len(tb) / sizeof(u32);
+ akms = nla_data(tb);
+ for (i = 0; i < num; i++) {
+ u32 a = akms[i];
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Supported AKM %02x-%02x-%02x:%u",
+ a >> 24, (a >> 16) & 0xff,
+ (a >> 8) & 0xff, a & 0xff);
+ switch (a) {
+ case RSN_AUTH_KEY_MGMT_UNSPEC_802_1X:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2;
+ break;
+ case RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+ break;
+ case RSN_AUTH_KEY_MGMT_FT_802_1X:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT;
+ break;
+ case RSN_AUTH_KEY_MGMT_FT_PSK:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
+ break;
+ case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B;
+ break;
+ case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192;
+ break;
+ case RSN_AUTH_KEY_MGMT_OWE:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_OWE;
+ break;
+ case RSN_AUTH_KEY_MGMT_DPP:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_DPP;
+ break;
+ case RSN_AUTH_KEY_MGMT_FILS_SHA256:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256;
+ break;
+ case RSN_AUTH_KEY_MGMT_FILS_SHA384:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384;
+ break;
+ case RSN_AUTH_KEY_MGMT_FT_FILS_SHA256:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256;
+ break;
+ case RSN_AUTH_KEY_MGMT_FT_FILS_SHA384:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384;
+ break;
+ case RSN_AUTH_KEY_MGMT_SAE:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SAE;
+ break;
+ }
+ }
+
+ return key_mgmt;
+}
+
+
+static int get_akm_suites_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ unsigned int *key_mgmt = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb[NL80211_ATTR_VENDOR_DATA]) {
+ struct nlattr *nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
+ struct nlattr *tb_data[NL80211_ATTR_MAX + 1];
+
+ nla_parse(tb_data, NL80211_ATTR_MAX,
+ nla_data(nl_vend), nla_len(nl_vend), NULL);
+
+ *key_mgmt =
+ get_akm_suites_info(tb_data[NL80211_ATTR_AKM_SUITES]);
+ }
+
+ return NL_SKIP;
+}
+
+
+static int qca_nl80211_get_akm_suites(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ unsigned int key_mgmt = 0;
+ int ret;
+
+ if (!drv->get_supported_akm_suites_avail)
+ return -1;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, get_akm_suites_handler, &key_mgmt);
+ if (!ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Replace capa.key_mgmt based on driver advertised capabilities: 0x%x",
+ key_mgmt);
+ drv->capa.key_mgmt = key_mgmt;
+ }
+
+ return ret;
+}
+
+
static int qca_nl80211_he_capab_handler(struct nl_msg *msg, void *arg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -1149,11 +1307,18 @@
drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256 |
WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384 |
WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256 |
- WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384;
+ WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384 |
+ WPA_DRIVER_CAPA_KEY_MGMT_SAE;
else if (drv->capa.flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD)
drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256 |
WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384;
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ /* Override drv->capa.key_mgmt based on driver advertised capability
+ * constraints, if available. */
+ qca_nl80211_get_akm_suites(drv);
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
WPA_DRIVER_AUTH_SHARED |
WPA_DRIVER_AUTH_LEAP;
@@ -1205,7 +1370,8 @@
drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
#ifdef CONFIG_DRIVER_NL80211_QCA
- qca_nl80211_check_dfs_capa(drv);
+ if (!(info.capa->flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD))
+ qca_nl80211_check_dfs_capa(drv);
qca_nl80211_get_features(drv);
qca_nl80211_check_he_capab(drv);
@@ -1276,6 +1442,7 @@
u8 channel;
chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
chan->flag = 0;
+ chan->allowed_bw = ~0;
chan->dfs_cac_ms = 0;
if (ieee80211_freq_to_chan(chan->freq, &channel) != NUM_HOSTAPD_MODES)
chan->chan = channel;
@@ -1291,6 +1458,19 @@
if (tb_freq[NL80211_FREQUENCY_ATTR_GO_CONCURRENT])
chan->flag |= HOSTAPD_CHAN_GO_CONCURRENT;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_10MHZ])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_10;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_20MHZ])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_20;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_PLUS])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_40P;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_MINUS])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_40M;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_80MHZ])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_80;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_160MHZ])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_160;
+
if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
enum nl80211_dfs_state state =
nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
@@ -1325,6 +1505,12 @@
[NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
[NL80211_FREQUENCY_ATTR_DFS_STATE] = { .type = NLA_U32 },
+ [NL80211_FREQUENCY_ATTR_NO_10MHZ] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_20MHZ] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_HT40_PLUS] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_HT40_MINUS] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_80MHZ] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_160MHZ] = { .type = NLA_FLAG },
};
int new_channels = 0;
struct hostapd_channel_data *channel;
@@ -1890,10 +2076,72 @@
return -ENOMEM;
nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY) {
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, drv->wiphy_idx)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+ }
+
return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
}
+static const char * modestr(enum hostapd_hw_mode mode)
+{
+ switch (mode) {
+ case HOSTAPD_MODE_IEEE80211B:
+ return "802.11b";
+ case HOSTAPD_MODE_IEEE80211G:
+ return "802.11g";
+ case HOSTAPD_MODE_IEEE80211A:
+ return "802.11a";
+ case HOSTAPD_MODE_IEEE80211AD:
+ return "802.11ad";
+ default:
+ return "?";
+ }
+}
+
+
+static void nl80211_dump_chan_list(struct hostapd_hw_modes *modes,
+ u16 num_modes)
+{
+ int i;
+
+ if (!modes)
+ return;
+
+ for (i = 0; i < num_modes; i++) {
+ struct hostapd_hw_modes *mode = &modes[i];
+ char str[200];
+ char *pos = str;
+ char *end = pos + sizeof(str);
+ int j, res;
+
+ for (j = 0; j < mode->num_channels; j++) {
+ struct hostapd_channel_data *chan = &mode->channels[j];
+
+ res = os_snprintf(pos, end - pos, " %d%s%s%s",
+ chan->freq,
+ (chan->flag & HOSTAPD_CHAN_DISABLED) ?
+ "[DISABLED]" : "",
+ (chan->flag & HOSTAPD_CHAN_NO_IR) ?
+ "[NO_IR]" : "",
+ (chan->flag & HOSTAPD_CHAN_RADAR) ?
+ "[RADAR]" : "");
+ if (os_snprintf_error(end - pos, res))
+ break;
+ pos += res;
+ }
+
+ *pos = '\0';
+ wpa_printf(MSG_DEBUG, "nl80211: Mode IEEE %s:%s",
+ modestr(mode->mode), str);
+ }
+}
+
+
struct hostapd_hw_modes *
nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags,
u8 *dfs_domain)
@@ -1925,6 +2173,8 @@
}
if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
+ struct hostapd_hw_modes *modes;
+
nl80211_set_regulatory_flags(drv, &result);
if (result.failed) {
int i;
@@ -1940,8 +2190,10 @@
*dfs_domain = result.dfs_domain;
- return wpa_driver_nl80211_postprocess_modes(result.modes,
- num_modes);
+ modes = wpa_driver_nl80211_postprocess_modes(result.modes,
+ num_modes);
+ nl80211_dump_chan_list(modes, *num_modes);
+ return modes;
}
return NULL;
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index e6bc254..ee7b4da 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -131,6 +131,11 @@
C2S(NL80211_CMD_SET_QOS_MAP)
C2S(NL80211_CMD_ADD_TX_TS)
C2S(NL80211_CMD_DEL_TX_TS)
+ C2S(NL80211_CMD_WIPHY_REG_CHANGE)
+ C2S(NL80211_CMD_PORT_AUTHORIZED)
+ C2S(NL80211_CMD_EXTERNAL_AUTH)
+ C2S(NL80211_CMD_STA_OPMODE_CHANGED)
+ C2S(NL80211_CMD_CONTROL_PORT_FRAME)
default:
return "NL80211_CMD_UNKNOWN";
}
@@ -201,7 +206,8 @@
static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
- const u8 *frame, size_t len, struct nlattr *wmm)
+ const u8 *frame, size_t len, struct nlattr *wmm,
+ struct nlattr *req_ie)
{
const struct ieee80211_mgmt *mgmt;
union wpa_event_data event;
@@ -256,7 +262,10 @@
len - 24 - sizeof(mgmt->u.assoc_resp);
}
- event.assoc_info.freq = drv->assoc_freq;
+ if (req_ie) {
+ event.assoc_info.req_ies = nla_data(req_ie);
+ event.assoc_info.req_ies_len = nla_len(req_ie);
+ }
/* When this association was initiated outside of wpa_supplicant,
* drv->ssid needs to be set here to satisfy later checking. */
@@ -268,6 +277,9 @@
wpa_ssid_txt(drv->ssid, drv->ssid_len));
}
+ event.assoc_info.freq = drv->assoc_freq;
+ drv->first_bss->freq = drv->assoc_freq;
+
nl80211_parse_wmm_params(wmm, &event.assoc_info.wmm_params);
wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
@@ -397,6 +409,7 @@
}
event.assoc_info.freq = nl80211_get_assoc_freq(drv);
+ drv->first_bss->freq = drv->assoc_freq;
if ((!ssid || ssid[1] == 0 || ssid[1] > 32) &&
(ssid_len = nl80211_get_assoc_ssid(drv, drv->ssid)) > 0) {
@@ -673,7 +686,7 @@
cookie_val = nla_get_u64(cookie);
wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
- " cookie=0%llx%s (ack=%d)",
+ " cookie=0x%llx%s (ack=%d)",
(long long unsigned int) cookie_val,
cookie_val == drv->send_action_cookie ?
" (match)" : " (unknown)", ack != NULL);
@@ -749,12 +762,12 @@
* disconnection event for the old AP may show up after
* we have started connection with the new AP.
*/
- wpa_printf(MSG_DEBUG,
- "nl80211: Ignore deauth/disassoc event from old AP "
- MACSTR
- " when already connecting with " MACSTR,
- MAC2STR(bssid),
- MAC2STR(drv->auth_attempt_bssid));
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore deauth/disassoc event from old AP "
+ MACSTR
+ " when already connecting with " MACSTR,
+ MAC2STR(bssid),
+ MAC2STR(drv->auth_attempt_bssid));
return;
}
@@ -863,7 +876,7 @@
struct nlattr *addr, struct nlattr *timed_out,
struct nlattr *freq, struct nlattr *ack,
struct nlattr *cookie, struct nlattr *sig,
- struct nlattr *wmm)
+ struct nlattr *wmm, struct nlattr *req_ie)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
const u8 *data;
@@ -912,7 +925,8 @@
mlme_event_auth(drv, nla_data(frame), nla_len(frame));
break;
case NL80211_CMD_ASSOCIATE:
- mlme_event_assoc(drv, nla_data(frame), nla_len(frame), wmm);
+ mlme_event_assoc(drv, nla_data(frame), nla_len(frame), wmm,
+ req_ie);
break;
case NL80211_CMD_DEAUTHENTICATE:
mlme_event_deauth_disassoc(drv, EVENT_DEAUTH,
@@ -1424,16 +1438,23 @@
struct nlattr **tb)
{
union wpa_event_data data;
+ const u8 *addr;
+ u64 cookie = 0;
- wpa_printf(MSG_DEBUG, "nl80211: Probe client event");
-
- if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
+ addr = nla_data(tb[NL80211_ATTR_MAC]);
+ if (!addr)
+ return;
+ if (tb[NL80211_ATTR_COOKIE])
+ cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
+ wpa_printf(MSG_DEBUG, "nl80211: Probe client event (addr=" MACSTR
+ " ack=%d cookie=%llu)", MAC2STR(addr),
+ tb[NL80211_ATTR_ACK] != NULL,
+ (long long unsigned int) cookie);
+ if (!tb[NL80211_ATTR_ACK])
return;
os_memset(&data, 0, sizeof(data));
- os_memcpy(data.client_poll.addr,
- nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
-
+ os_memcpy(data.client_poll.addr, addr, ETH_ALEN);
wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
}
@@ -1590,6 +1611,9 @@
wpa_supplicant_event(drv->ctx, EVENT_DFS_PRE_CAC_EXPIRED,
&data);
break;
+ case NL80211_RADAR_CAC_STARTED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_STARTED, &data);
+ break;
default:
wpa_printf(MSG_DEBUG, "nl80211: Unknown radar event %d "
"received", event_type);
@@ -2175,11 +2199,196 @@
}
+static void nl80211_dump_freq(const char *title, struct nlattr *nl_freq)
+{
+ static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
+ [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
+ [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
+ };
+ struct nlattr *tb[NL80211_FREQUENCY_ATTR_MAX + 1];
+ u32 freq = 0, max_tx_power = 0;
+
+ nla_parse(tb, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_freq), nla_len(nl_freq), freq_policy);
+
+ if (tb[NL80211_FREQUENCY_ATTR_FREQ])
+ freq = nla_get_u32(tb[NL80211_FREQUENCY_ATTR_FREQ]);
+ if (tb[NL80211_FREQUENCY_ATTR_MAX_TX_POWER])
+ max_tx_power =
+ nla_get_u32(tb[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]);
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Channel (%s): freq=%u max_tx_power=%u%s%s%s",
+ title, freq, max_tx_power,
+ tb[NL80211_FREQUENCY_ATTR_DISABLED] ? " disabled" : "",
+ tb[NL80211_FREQUENCY_ATTR_NO_IR] ? " no-IR" : "",
+ tb[NL80211_FREQUENCY_ATTR_RADAR] ? " radar" : "");
+}
+
+
+static void nl80211_reg_beacon_hint_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
+{
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
+ os_memset(&data, 0, sizeof(data));
+ data.channel_list_changed.initiator = REGDOM_BEACON_HINT;
+
+ if (tb[NL80211_ATTR_FREQ_BEFORE])
+ nl80211_dump_freq("before", tb[NL80211_ATTR_FREQ_BEFORE]);
+ if (tb[NL80211_ATTR_FREQ_AFTER])
+ nl80211_dump_freq("after", tb[NL80211_ATTR_FREQ_AFTER]);
+
+ wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, &data);
+}
+
+
+static void nl80211_external_auth(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data event;
+ enum nl80211_external_auth_action act;
+
+ if (!tb[NL80211_ATTR_AKM_SUITES] ||
+ !tb[NL80211_ATTR_EXTERNAL_AUTH_ACTION] ||
+ !tb[NL80211_ATTR_BSSID] ||
+ !tb[NL80211_ATTR_SSID])
+ return;
+
+ os_memset(&event, 0, sizeof(event));
+ act = nla_get_u32(tb[NL80211_ATTR_EXTERNAL_AUTH_ACTION]);
+ switch (act) {
+ case NL80211_EXTERNAL_AUTH_START:
+ event.external_auth.action = EXT_AUTH_START;
+ break;
+ case NL80211_EXTERNAL_AUTH_ABORT:
+ event.external_auth.action = EXT_AUTH_ABORT;
+ break;
+ default:
+ return;
+ }
+
+ event.external_auth.key_mgmt_suite =
+ nla_get_u32(tb[NL80211_ATTR_AKM_SUITES]);
+
+ event.external_auth.ssid_len = nla_len(tb[NL80211_ATTR_SSID]);
+ if (event.external_auth.ssid_len > SSID_MAX_LEN)
+ return;
+ event.external_auth.ssid = nla_data(tb[NL80211_ATTR_SSID]);
+
+ event.external_auth.bssid = nla_data(tb[NL80211_ATTR_BSSID]);
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: External auth action: %u, AKM: 0x%x",
+ event.external_auth.action,
+ event.external_auth.key_mgmt_suite);
+ wpa_supplicant_event(drv->ctx, EVENT_EXTERNAL_AUTH, &event);
+}
+
+
+static void nl80211_port_authorized(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ const u8 *addr;
+
+ if (!tb[NL80211_ATTR_MAC] ||
+ nla_len(tb[NL80211_ATTR_MAC]) != ETH_ALEN) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore port authorized event without BSSID");
+ return;
+ }
+
+ addr = nla_data(tb[NL80211_ATTR_MAC]);
+ if (os_memcmp(addr, drv->bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore port authorized event for " MACSTR
+ " (not the currently connected BSSID " MACSTR ")",
+ MAC2STR(addr), MAC2STR(drv->bssid));
+ return;
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_PORT_AUTHORIZED, NULL);
+}
+
+
+static void nl80211_sta_opmode_change_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data ed;
+ u8 smps_mode, max_bw;
+
+ if (!tb[NL80211_ATTR_MAC] ||
+ (!tb[NL80211_ATTR_CHANNEL_WIDTH] &&
+ !tb[NL80211_ATTR_SMPS_MODE] &&
+ !tb[NL80211_ATTR_NSS]))
+ return;
+
+ ed.sta_opmode.smps_mode = SMPS_INVALID;
+ ed.sta_opmode.chan_width = CHAN_WIDTH_UNKNOWN;
+ ed.sta_opmode.rx_nss = 0xff;
+ ed.sta_opmode.addr = nla_data(tb[NL80211_ATTR_MAC]);
+
+ if (tb[NL80211_ATTR_SMPS_MODE]) {
+ smps_mode = nla_get_u8(tb[NL80211_ATTR_SMPS_MODE]);
+ switch (smps_mode) {
+ case NL80211_SMPS_OFF:
+ ed.sta_opmode.smps_mode = SMPS_OFF;
+ break;
+ case NL80211_SMPS_STATIC:
+ ed.sta_opmode.smps_mode = SMPS_STATIC;
+ break;
+ case NL80211_SMPS_DYNAMIC:
+ ed.sta_opmode.smps_mode = SMPS_DYNAMIC;
+ break;
+ default:
+ ed.sta_opmode.smps_mode = SMPS_INVALID;
+ break;
+ }
+ }
+
+ if (tb[NL80211_ATTR_CHANNEL_WIDTH]) {
+ max_bw = nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]);
+ switch (max_bw) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ ed.sta_opmode.chan_width = CHAN_WIDTH_20_NOHT;
+ break;
+ case NL80211_CHAN_WIDTH_20:
+ ed.sta_opmode.chan_width = CHAN_WIDTH_20;
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ ed.sta_opmode.chan_width = CHAN_WIDTH_40;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ ed.sta_opmode.chan_width = CHAN_WIDTH_80;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ ed.sta_opmode.chan_width = CHAN_WIDTH_80P80;
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ ed.sta_opmode.chan_width = CHAN_WIDTH_160;
+ break;
+ default:
+ ed.sta_opmode.chan_width = CHAN_WIDTH_UNKNOWN;
+ break;
+
+ }
+ }
+
+ if (tb[NL80211_ATTR_NSS])
+ ed.sta_opmode.rx_nss = nla_get_u8(tb[NL80211_ATTR_NSS]);
+
+ wpa_supplicant_event(drv->ctx, EVENT_STATION_OPMODE_CHANGED, &ed);
+}
+
+
static void do_process_drv_event(struct i802_bss *bss, int cmd,
struct nlattr **tb)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
- union wpa_event_data data;
int external_scan_event = 0;
wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
@@ -2280,7 +2489,8 @@
tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
tb[NL80211_ATTR_COOKIE],
tb[NL80211_ATTR_RX_SIGNAL_DBM],
- tb[NL80211_ATTR_STA_WME]);
+ tb[NL80211_ATTR_STA_WME],
+ tb[NL80211_ATTR_REQ_IE]);
break;
case NL80211_CMD_CONNECT:
case NL80211_CMD_ROAM:
@@ -2328,14 +2538,11 @@
nl80211_cqm_event(drv, tb);
break;
case NL80211_CMD_REG_CHANGE:
+ case NL80211_CMD_WIPHY_REG_CHANGE:
nl80211_reg_change_event(drv, tb);
break;
case NL80211_CMD_REG_BEACON_HINT:
- wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
- os_memset(&data, 0, sizeof(data));
- data.channel_list_changed.initiator = REGDOM_BEACON_HINT;
- wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
- &data);
+ nl80211_reg_beacon_hint_event(drv, tb);
break;
case NL80211_CMD_NEW_STATION:
nl80211_new_station_event(drv, bss, tb);
@@ -2373,6 +2580,12 @@
case NL80211_CMD_NEW_PEER_CANDIDATE:
nl80211_new_peer_candidate(drv, tb);
break;
+ case NL80211_CMD_PORT_AUTHORIZED:
+ nl80211_port_authorized(drv, tb);
+ break;
+ case NL80211_CMD_STA_OPMODE_CHANGED:
+ nl80211_sta_opmode_change_event(drv, tb);
+ break;
default:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", cmd);
@@ -2387,10 +2600,11 @@
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
struct nlattr *tb[NL80211_ATTR_MAX + 1];
struct wpa_driver_nl80211_data *drv, *tmp;
- int ifidx = -1;
+ int ifidx = -1, wiphy_idx = -1, wiphy_idx_rx = -1;
struct i802_bss *bss;
u64 wdev_id = 0;
int wdev_id_set = 0;
+ int wiphy_idx_set = 0;
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
@@ -2400,13 +2614,19 @@
else if (tb[NL80211_ATTR_WDEV]) {
wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
wdev_id_set = 1;
+ } else if (tb[NL80211_ATTR_WIPHY]) {
+ wiphy_idx_rx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
+ wiphy_idx_set = 1;
}
dl_list_for_each_safe(drv, tmp, &global->interfaces,
struct wpa_driver_nl80211_data, list) {
for (bss = drv->first_bss; bss; bss = bss->next) {
- if ((ifidx == -1 && !wdev_id_set) ||
+ if (wiphy_idx_set)
+ wiphy_idx = nl80211_get_wiphy_index(bss);
+ if ((ifidx == -1 && !wiphy_idx_set && !wdev_id_set) ||
ifidx == bss->ifindex ||
+ (wiphy_idx_set && wiphy_idx == wiphy_idx_rx) ||
(wdev_id_set && bss->wdev_id_set &&
wdev_id == bss->wdev_id)) {
do_process_drv_event(bss, gnlh->cmd, tb);
@@ -2443,7 +2663,7 @@
tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
tb[NL80211_ATTR_COOKIE],
tb[NL80211_ATTR_RX_SIGNAL_DBM],
- tb[NL80211_ATTR_STA_WME]);
+ tb[NL80211_ATTR_STA_WME], NULL);
break;
case NL80211_CMD_UNEXPECTED_FRAME:
nl80211_spurious_frame(bss, tb, 0);
@@ -2451,6 +2671,9 @@
case NL80211_CMD_UNEXPECTED_4ADDR_FRAME:
nl80211_spurious_frame(bss, tb, 1);
break;
+ case NL80211_CMD_EXTERNAL_AUTH:
+ nl80211_external_auth(bss->drv, tb);
+ break;
default:
wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", gnlh->cmd);
diff --git a/src/drivers/driver_nl80211_monitor.c b/src/drivers/driver_nl80211_monitor.c
index 9376d11..f25cd79 100644
--- a/src/drivers/driver_nl80211_monitor.c
+++ b/src/drivers/driver_nl80211_monitor.c
@@ -361,8 +361,17 @@
*/
snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss->ifname + 4);
} else {
+ int ret;
+
/* Non-P2P interface with AP functionality. */
- snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss->ifname);
+ ret = os_snprintf(buf, IFNAMSIZ, "mon.%s",
+ drv->first_bss->ifname);
+ if (ret >= (int) sizeof(buf))
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Monitor interface name has been truncated to %s",
+ buf);
+ else if (ret < 0)
+ return ret;
}
buf[IFNAMSIZ - 1] = '\0';
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index 984485b..9afa5b3 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -197,9 +197,9 @@
if (ssids == NULL)
goto fail;
for (i = 0; i < params->num_ssids; i++) {
- wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
- params->ssids[i].ssid,
- params->ssids[i].ssid_len);
+ wpa_printf(MSG_MSGDUMP, "nl80211: Scan SSID %s",
+ wpa_ssid_txt(params->ssids[i].ssid,
+ params->ssids[i].ssid_len));
if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
params->ssids[i].ssid))
goto fail;
@@ -282,6 +282,21 @@
goto fail;
}
+ if (params->oce_scan) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Add NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME");
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Add NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP");
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Add NL80211_SCAN_FLAG_OCE_PROBE_REQ_MIN_TX_RATE");
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Add NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION");
+ scan_flags |= NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME |
+ NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP |
+ NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE |
+ NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION;
+ }
+
if (scan_flags &&
nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags))
goto fail;
@@ -522,10 +537,10 @@
for (i = 0; i < drv->num_filter_ssids; i++) {
struct nlattr *match_set_ssid;
- wpa_hexdump_ascii(MSG_MSGDUMP,
- "nl80211: Sched scan filter SSID",
- drv->filter_ssids[i].ssid,
- drv->filter_ssids[i].ssid_len);
+ wpa_printf(MSG_MSGDUMP,
+ "nl80211: Sched scan filter SSID %s",
+ wpa_ssid_txt(drv->filter_ssids[i].ssid,
+ drv->filter_ssids[i].ssid_len));
match_set_ssid = nla_nest_start(msg, i + 1);
if (match_set_ssid == NULL ||
@@ -851,7 +866,8 @@
"mismatch (" MACSTR ")", MAC2STR(addr));
wpa_driver_nl80211_mlme(drv, addr,
NL80211_CMD_DEAUTHENTICATE,
- WLAN_REASON_PREV_AUTH_NOT_VALID, 1);
+ WLAN_REASON_PREV_AUTH_NOT_VALID, 1,
+ NULL);
}
}
@@ -1082,9 +1098,9 @@
if (ssids == NULL)
goto fail;
for (i = 0; i < params->num_ssids; i++) {
- wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
- params->ssids[i].ssid,
- params->ssids[i].ssid_len);
+ wpa_printf(MSG_MSGDUMP, "nl80211: Scan SSID %s",
+ wpa_ssid_txt(params->ssids[i].ssid,
+ params->ssids[i].ssid_len));
if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
params->ssids[i].ssid))
goto fail;
diff --git a/src/drivers/driver_openbsd.c b/src/drivers/driver_openbsd.c
index e94eda0..c06e75c 100644
--- a/src/drivers/driver_openbsd.c
+++ b/src/drivers/driver_openbsd.c
@@ -62,7 +62,8 @@
wpa_driver_openbsd_get_capa(void *priv, struct wpa_driver_capa *capa)
{
os_memset(capa, 0, sizeof(*capa));
- capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+ capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK |
+ WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X;
return 0;
}
diff --git a/src/drivers/driver_roboswitch.c b/src/drivers/driver_roboswitch.c
index e8a5135..9beb6c4 100644
--- a/src/drivers/driver_roboswitch.c
+++ b/src/drivers/driver_roboswitch.c
@@ -290,21 +290,26 @@
wpa_driver_roboswitch_addr_be16(addr, addr_be16);
- wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, ROBO_ARLCTRL_CONF,
- &_read, 1);
+ if (wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_CONF, &_read, 1) < 0)
+ return -1;
/* If ARL control is disabled, there is nothing to leave. */
if (!(_read & (1 << 4))) return -1;
- wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
- ROBO_ARLCTRL_ADDR_1, addr_read, 3);
- wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, ROBO_ARLCTRL_VEC_1,
- &ports_read, 1);
+ if (wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_1, addr_read, 3) < 0 ||
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_1, &ports_read, 1) < 0)
+ return -1;
/* check if we occupy multiport address 1 */
if (os_memcmp(addr_read, addr_be16, 6) == 0 && ports_read == ports) {
- wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
- ROBO_ARLCTRL_ADDR_2, addr_read, 3);
- wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
- ROBO_ARLCTRL_VEC_2, &ports_read, 1);
+ if (wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_2, addr_read,
+ 3) < 0 ||
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_2, &ports_read,
+ 1) < 0)
+ return -1;
/* and multiport address 2 */
if (os_memcmp(addr_read, addr_be16, 6) == 0 &&
ports_read == ports) {
@@ -327,10 +332,13 @@
&ports_read, 1);
}
} else {
- wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
- ROBO_ARLCTRL_ADDR_2, addr_read, 3);
- wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
- ROBO_ARLCTRL_VEC_2, &ports_read, 1);
+ if (wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_2, addr_read,
+ 3) < 0 ||
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_2, &ports_read,
+ 1) < 0)
+ return -1;
/* or multiport address 2 */
if (os_memcmp(addr_read, addr_be16, 6) == 0 &&
ports_read == ports) {
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 659eda2..f7755cc 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -868,14 +868,16 @@
const char *ifname)
{
char buf[200], *res;
- int type;
+ int type, ret;
FILE *f;
if (strcmp(ifname, ".") == 0 || strcmp(ifname, "..") == 0)
return -1;
- snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/net/%s/type",
- drv->ifname, ifname);
+ ret = snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/net/%s/type",
+ drv->ifname, ifname);
+ if (os_snprintf_error(sizeof(buf), ret))
+ return -1;
f = fopen(buf, "r");
if (!f)
@@ -922,7 +924,7 @@
static void wext_check_hostap(struct wpa_driver_wext_data *drv)
{
- char buf[200], *pos;
+ char path[200], buf[200], *pos;
ssize_t res;
/*
@@ -937,9 +939,9 @@
*/
/* First, try to see if driver information is available from sysfs */
- snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/driver",
+ snprintf(path, sizeof(path), "/sys/class/net/%s/device/driver",
drv->ifname);
- res = readlink(buf, buf, sizeof(buf) - 1);
+ res = readlink(path, buf, sizeof(buf) - 1);
if (res > 0) {
buf[res] = '\0';
pos = strrchr(buf, '/');
@@ -1645,7 +1647,8 @@
if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
if (range->enc_capa & IW_ENC_CAPA_4WAY_HANDSHAKE)
- drv->capa.flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+ drv->capa.flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK |
+ WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X;
drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
WPA_DRIVER_AUTH_SHARED |
WPA_DRIVER_AUTH_LEAP;
@@ -1676,7 +1679,7 @@
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
- if (!(drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X))
return 0;
if (!psk)
@@ -2428,8 +2431,8 @@
struct iwreq iwr;
os_memset(si, 0, sizeof(*si));
- si->current_signal = -9999;
- si->current_noise = 9999;
+ si->current_signal = -WPA_INVALID_NOISE;
+ si->current_noise = WPA_INVALID_NOISE;
si->chanwidth = CHAN_WIDTH_UNKNOWN;
os_memset(&iwr, 0, sizeof(iwr));
diff --git a/src/drivers/driver_wired.c b/src/drivers/driver_wired.c
index 7e09dcf..c7537b7 100644
--- a/src/drivers/driver_wired.c
+++ b/src/drivers/driver_wired.c
@@ -96,16 +96,16 @@
hdr = (struct ieee8023_hdr *) buf;
switch (ntohs(hdr->ethertype)) {
- case ETH_P_PAE:
- wpa_printf(MSG_MSGDUMP, "Received EAPOL packet");
- sa = hdr->src;
- os_memset(&event, 0, sizeof(event));
- event.new_sta.addr = sa;
- wpa_supplicant_event(ctx, EVENT_NEW_STA, &event);
+ case ETH_P_PAE:
+ wpa_printf(MSG_MSGDUMP, "Received EAPOL packet");
+ sa = hdr->src;
+ os_memset(&event, 0, sizeof(event));
+ event.new_sta.addr = sa;
+ wpa_supplicant_event(ctx, EVENT_NEW_STA, &event);
- pos = (u8 *) (hdr + 1);
- left = len - sizeof(*hdr);
- drv_event_eapol_rx(ctx, sa, pos, left);
+ pos = (u8 *) (hdr + 1);
+ left = len - sizeof(*hdr);
+ drv_event_eapol_rx(ctx, sa, pos, left);
break;
default:
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index 1496b47..442c59c 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -22,6 +22,7 @@
DRV_CFLAGS += -DCONFIG_DRIVER_MACSEC_LINUX
DRV_OBJS += ../src/drivers/driver_macsec_linux.o
NEED_DRV_WIRED_COMMON=1
+NEED_LIBNL=y
CONFIG_LIBNL3_ROUTE=y
endif
@@ -51,37 +52,7 @@
NEED_LINUX_IOCTL=y
NEED_RFKILL=y
NEED_RADIOTAP=y
-
-ifdef CONFIG_LIBNL32
- DRV_LIBS += -lnl-3
- DRV_LIBS += -lnl-genl-3
- DRV_CFLAGS += -DCONFIG_LIBNL20
- ifdef LIBNL_INC
- DRV_CFLAGS += -I$(LIBNL_INC)
- else
- PKG_CONFIG ?= pkg-config
- DRV_CFLAGS += $(shell $(PKG_CONFIG) --cflags libnl-3.0)
- endif
-ifdef CONFIG_LIBNL3_ROUTE
- DRV_LIBS += -lnl-route-3
- DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE
-endif
-else
- ifdef CONFIG_LIBNL_TINY
- DRV_LIBS += -lnl-tiny
- else
- ifndef CONFIG_OSX
- DRV_LIBS += -lnl
- endif
- endif
-
- ifdef CONFIG_LIBNL20
- ifndef CONFIG_LIBNL_TINY
- DRV_LIBS += -lnl-genl
- endif
- DRV_CFLAGS += -DCONFIG_LIBNL20
- endif
-endif
+NEED_LIBNL=y
endif
ifdef CONFIG_DRIVER_BSD
@@ -183,26 +154,55 @@
ifdef CONFIG_VLAN_NETLINK
ifdef CONFIG_FULL_DYNAMIC_VLAN
+NEED_LIBNL=y
+CONFIG_LIBNL3_ROUTE=y
+endif
+endif
+
+ifdef NEED_LIBNL
+ifndef CONFIG_LIBNL32
+ifndef CONFIG_LIBNL20
+ifndef CONFIG_LIBNL_TINY
+PKG_CONFIG ?= pkg-config
+HAVE_LIBNL3 := $(shell $(PKG_CONFIG) --exists libnl-3.0; echo $$?)
+ifeq ($(HAVE_LIBNL3),0)
+CONFIG_LIBNL32=y
+endif
+endif
+endif
+endif
+
ifdef CONFIG_LIBNL32
DRV_LIBS += -lnl-3
DRV_LIBS += -lnl-genl-3
- DRV_LIBS += -lnl-route-3
DRV_CFLAGS += -DCONFIG_LIBNL20
+ ifdef LIBNL_INC
+ DRV_CFLAGS += -I$(LIBNL_INC)
+ else
+ PKG_CONFIG ?= pkg-config
+ DRV_CFLAGS += $(shell $(PKG_CONFIG) --cflags libnl-3.0)
+ endif
+ ifdef CONFIG_LIBNL3_ROUTE
+ DRV_LIBS += -lnl-route-3
+ DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE
+ endif
else
ifdef CONFIG_LIBNL_TINY
DRV_LIBS += -lnl-tiny
else
- DRV_LIBS += -lnl
+ ifndef CONFIG_OSX
+ DRV_LIBS += -lnl
+ endif
endif
ifdef CONFIG_LIBNL20
- DRV_LIBS += -lnl-genl
- DRV_LIBS += -lnl-route
+ ifndef CONFIG_LIBNL_TINY
+ DRV_LIBS += -lnl-genl
+ endif
DRV_CFLAGS += -DCONFIG_LIBNL20
endif
endif
endif
-endif
##### COMMON VARS
DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS)
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index cd25133..599a0b5 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -23,6 +23,7 @@
DRV_OBJS += src/drivers/driver_macsec_linux.c
NEED_DRV_WIRED_COMMON=1
CONFIG_LIBNL3_ROUTE=y
+NEED_LIBNL=y
endif
ifdef NEED_DRV_WIRED_COMMON
@@ -46,29 +47,7 @@
NEED_LINUX_IOCTL=y
NEED_RFKILL=y
NEED_RADIOTAP=y
-
-ifdef CONFIG_LIBNL32
- DRV_LIBS += -lnl-3
- DRV_LIBS += -lnl-genl-3
- DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
-ifdef CONFIG_LIBNL3_ROUTE
- DRV_LIBS += -lnl-route-3
- DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE
-endif
-else
- ifdef CONFIG_LIBNL_TINY
- DRV_LIBS += -lnl-tiny
- else
- DRV_LIBS += -lnl
- endif
-
- ifdef CONFIG_LIBNL20
- ifndef CONFIG_LIBNL_TINY
- DRV_LIBS += -lnl-genl
- endif
- DRV_CFLAGS += -DCONFIG_LIBNL20
- endif
-endif
+NEED_LIBNL=y
endif
ifdef CONFIG_DRIVER_BSD
@@ -171,11 +150,20 @@
ifdef CONFIG_VLAN_NETLINK
ifdef CONFIG_FULL_DYNAMIC_VLAN
+NEED_LIBNL=y
+CONFIG_LIBNL3_ROUTE=y
+endif
+endif
+
+ifdef NEED_LIBNL
ifdef CONFIG_LIBNL32
DRV_LIBS += -lnl-3
DRV_LIBS += -lnl-genl-3
+ DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
+ifdef CONFIG_LIBNL3_ROUTE
DRV_LIBS += -lnl-route-3
- DRV_CFLAGS += -DCONFIG_LIBNL20
+ DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE
+endif
else
ifdef CONFIG_LIBNL_TINY
DRV_LIBS += -lnl-tiny
@@ -184,13 +172,13 @@
endif
ifdef CONFIG_LIBNL20
- DRV_LIBS += -lnl-genl
- DRV_LIBS += -lnl-route
+ ifndef CONFIG_LIBNL_TINY
+ DRV_LIBS += -lnl-genl
+ endif
DRV_CFLAGS += -DCONFIG_LIBNL20
endif
endif
endif
-endif
##### COMMON VARS
DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS)
diff --git a/src/drivers/linux_ioctl.c b/src/drivers/linux_ioctl.c
index e21147a..7edb9df 100644
--- a/src/drivers/linux_ioctl.c
+++ b/src/drivers/linux_ioctl.c
@@ -12,6 +12,7 @@
#include <net/if_arp.h>
#include "utils/common.h"
+#include "common/linux_bridge.h"
#include "linux_ioctl.h"
@@ -119,25 +120,14 @@
}
-#ifndef SIOCBRADDBR
-#define SIOCBRADDBR 0x89a0
-#endif
-#ifndef SIOCBRDELBR
-#define SIOCBRDELBR 0x89a1
-#endif
-#ifndef SIOCBRADDIF
-#define SIOCBRADDIF 0x89a2
-#endif
-#ifndef SIOCBRDELIF
-#define SIOCBRDELIF 0x89a3
-#endif
-
-
int linux_br_add(int sock, const char *brname)
{
if (ioctl(sock, SIOCBRADDBR, brname) < 0) {
+ int saved_errno = errno;
+
wpa_printf(MSG_DEBUG, "Could not add bridge %s: %s",
brname, strerror(errno));
+ errno = saved_errno;
return -1;
}
@@ -170,8 +160,11 @@
os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
ifr.ifr_ifindex = ifindex;
if (ioctl(sock, SIOCBRADDIF, &ifr) < 0) {
+ int saved_errno = errno;
+
wpa_printf(MSG_DEBUG, "Could not add interface %s into bridge "
"%s: %s", ifname, brname, strerror(errno));
+ errno = saved_errno;
return -1;
}
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 6095a6c..dd4f86e 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -11,6 +11,7 @@
* Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
* Copyright 2008 Colin McCabe <colin@cozybit.com>
* Copyright 2015-2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -173,6 +174,29 @@
*/
/**
+ * DOC: WPA/WPA2 EAPOL handshake offload
+ *
+ * By setting @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK flag drivers
+ * can indicate they support offloading EAPOL handshakes for WPA/WPA2
+ * preshared key authentication. In %NL80211_CMD_CONNECT the preshared
+ * key should be specified using %NL80211_ATTR_PMK. Drivers supporting
+ * this offload may reject the %NL80211_CMD_CONNECT when no preshared
+ * key material is provided, for example when that driver does not
+ * support setting the temporal keys through %CMD_NEW_KEY.
+ *
+ * Similarly @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X flag can be
+ * set by drivers indicating offload support of the PTK/GTK EAPOL
+ * handshakes during 802.1X authentication. In order to use the offload
+ * the %NL80211_CMD_CONNECT should have %NL80211_ATTR_WANT_1X_4WAY_HS
+ * attribute flag. Drivers supporting this offload may reject the
+ * %NL80211_CMD_CONNECT when the attribute flag is not present.
+ *
+ * For 802.1X the PMK or PMK-R0 are set by providing %NL80211_ATTR_PMK
+ * using %NL80211_CMD_SET_PMK. For offloaded FT support also
+ * %NL80211_ATTR_PMKR0_NAME must be provided.
+ */
+
+/**
* DOC: FILS shared key authentication offload
*
* FILS shared key authentication offload can be advertized by drivers by
@@ -180,7 +204,8 @@
* FILS shared key authentication offload should be able to construct the
* authentication and association frames for FILS shared key authentication and
* eventually do a key derivation as per IEEE 802.11ai. The below additional
- * parameters should be given to driver in %NL80211_CMD_CONNECT.
+ * parameters should be given to driver in %NL80211_CMD_CONNECT and/or in
+ * %NL80211_CMD_UPDATE_CONNECT_PARAMS.
* %NL80211_ATTR_FILS_ERP_USERNAME - used to construct keyname_nai
* %NL80211_ATTR_FILS_ERP_REALM - used to construct keyname_nai
* %NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM - used to construct erp message
@@ -191,7 +216,8 @@
* as specified in IETF RFC 6696.
*
* When FILS shared key authentication is completed, driver needs to provide the
- * below additional parameters to userspace.
+ * below additional parameters to userspace, which can be either after setting
+ * up a connection or after roaming.
* %NL80211_ATTR_FILS_KEK - used for key renewal
* %NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM - used in further EAP-RP exchanges
* %NL80211_ATTR_PMKID - used to identify the PMKSA used/generated
@@ -387,7 +413,9 @@
* are used. Extra IEs can also be passed from the userspace by
* using the %NL80211_ATTR_IE attribute. The first cycle of the
* scheduled scan can be delayed by %NL80211_ATTR_SCHED_SCAN_DELAY
- * is supplied.
+ * is supplied. If the device supports multiple concurrent scheduled
+ * scans, it will allow such when the caller provides the flag attribute
+ * %NL80211_ATTR_SCHED_SCAN_MULTI to indicate user-space support for it.
* @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan. Returns -ENOENT if
* scheduled scan is not running. The caller may assume that as soon
* as the call returns, it is safe to start a new scheduled scan again.
@@ -517,7 +545,8 @@
* IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
* %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
* %NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
- * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, %NL80211_ATTR_MAC_HINT, and
+ * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
+ * %NL80211_ATTR_CONTROL_PORT_OVER_NL80211, %NL80211_ATTR_MAC_HINT, and
* %NL80211_ATTR_WIPHY_FREQ_HINT.
* If included, %NL80211_ATTR_MAC and %NL80211_ATTR_WIPHY_FREQ are
* restrictions on BSS selection, i.e., they effectively prevent roaming
@@ -544,8 +573,14 @@
* authentication/association or not receiving a response from the AP.
* Non-zero %NL80211_ATTR_STATUS_CODE value is indicated in that case as
* well to remain backwards compatible.
- * @NL80211_CMD_ROAM: request that the card roam (currently not implemented),
- * sent as an event when the card/driver roamed by itself.
+ * When establishing a security association, drivers that support 4 way
+ * handshake offload should send %NL80211_CMD_PORT_AUTHORIZED event when
+ * the 4 way handshake is completed successfully.
+ * @NL80211_CMD_ROAM: Notification indicating the card/driver roamed by itself.
+ * When a security association was established with the new AP (e.g. if
+ * the FT protocol was used for roaming or the driver completed the 4 way
+ * handshake), this event should be followed by an
+ * %NL80211_CMD_PORT_AUTHORIZED event.
* @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
* userspace that a connection was dropped by the AP or due to other
* reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
@@ -945,6 +980,91 @@
* does not result in a change for the current association. Currently,
* only the %NL80211_ATTR_IE data is used and updated with this command.
*
+ * @NL80211_CMD_SET_PMK: For offloaded 4-Way handshake, set the PMK or PMK-R0
+ * for the given authenticator address (specified with %NL80211_ATTR_MAC).
+ * When %NL80211_ATTR_PMKR0_NAME is set, %NL80211_ATTR_PMK specifies the
+ * PMK-R0, otherwise it specifies the PMK.
+ * @NL80211_CMD_DEL_PMK: For offloaded 4-Way handshake, delete the previously
+ * configured PMK for the authenticator address identified by
+ * %NL80211_ATTR_MAC.
+ * @NL80211_CMD_PORT_AUTHORIZED: An event that indicates that the 4 way
+ * handshake was completed successfully by the driver. The BSSID is
+ * specified with %NL80211_ATTR_MAC. Drivers that support 4 way handshake
+ * offload should send this event after indicating 802.11 association with
+ * %NL80211_CMD_CONNECT or %NL80211_CMD_ROAM. If the 4 way handshake failed
+ * %NL80211_CMD_DISCONNECT should be indicated instead.
+ *
+ * @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request
+ * and RX notification. This command is used both as a request to transmit
+ * a control port frame and as a notification that a control port frame
+ * has been received. %NL80211_ATTR_FRAME is used to specify the
+ * frame contents. The frame is the raw EAPoL data, without ethernet or
+ * 802.11 headers.
+ * When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
+ * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added
+ * indicating the protocol type of the received frame; whether the frame
+ * was received unencrypted and the MAC address of the peer respectively.
+ *
+ * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded.
+ *
+ * @NL80211_CMD_EXTERNAL_AUTH: This interface is exclusively defined for host
+ * drivers that do not define separate commands for authentication and
+ * association, but rely on user space for the authentication to happen.
+ * This interface acts both as the event request (driver to user space)
+ * to trigger the authentication and command response (userspace to
+ * driver) to indicate the authentication status.
+ *
+ * User space uses the %NL80211_CMD_CONNECT command to the host driver to
+ * trigger a connection. The host driver selects a BSS and further uses
+ * this interface to offload only the authentication part to the user
+ * space. Authentication frames are passed between the driver and user
+ * space through the %NL80211_CMD_FRAME interface. Host driver proceeds
+ * further with the association after getting successful authentication
+ * status. User space indicates the authentication status through
+ * %NL80211_ATTR_STATUS_CODE attribute in %NL80211_CMD_EXTERNAL_AUTH
+ * command interface.
+ *
+ * Host driver reports this status on an authentication failure to the
+ * user space through the connect result as the user space would have
+ * initiated the connection through the connect request.
+ *
+ * @NL80211_CMD_STA_OPMODE_CHANGED: An event that notify station's
+ * ht opmode or vht opmode changes using any of %NL80211_ATTR_SMPS_MODE,
+ * %NL80211_ATTR_CHANNEL_WIDTH,%NL80211_ATTR_NSS attributes with its
+ * address(specified in %NL80211_ATTR_MAC).
+ *
+ * @NL80211_CMD_GET_FTM_RESPONDER_STATS: Retrieve FTM responder statistics, in
+ * the %NL80211_ATTR_FTM_RESPONDER_STATS attribute.
+ *
+ * @NL80211_CMD_PEER_MEASUREMENT_START: start a (set of) peer measurement(s)
+ * with the given parameters, which are encapsulated in the nested
+ * %NL80211_ATTR_PEER_MEASUREMENTS attribute. Optionally, MAC address
+ * randomization may be enabled and configured by specifying the
+ * %NL80211_ATTR_MAC and %NL80211_ATTR_MAC_MASK attributes.
+ * If a timeout is requested, use the %NL80211_ATTR_TIMEOUT attribute.
+ * A u64 cookie for further %NL80211_ATTR_COOKIE use is is returned in
+ * the netlink extended ack message.
+ *
+ * To cancel a measurement, close the socket that requested it.
+ *
+ * Measurement results are reported to the socket that requested the
+ * measurement using @NL80211_CMD_PEER_MEASUREMENT_RESULT when they
+ * become available, so applications must ensure a large enough socket
+ * buffer size.
+ *
+ * Depending on driver support it may or may not be possible to start
+ * multiple concurrent measurements.
+ * @NL80211_CMD_PEER_MEASUREMENT_RESULT: This command number is used for the
+ * result notification from the driver to the requesting socket.
+ * @NL80211_CMD_PEER_MEASUREMENT_COMPLETE: Notification only, indicating that
+ * the measurement completed, using the measurement cookie
+ * (%NL80211_ATTR_COOKIE).
+ *
+ * @NL80211_CMD_NOTIFY_RADAR: Notify the kernel that a radar signal was
+ * detected and reported by a neighboring device on the channel
+ * indicated by %NL80211_ATTR_WIPHY_FREQ and other attributes
+ * determining the width and type.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1144,6 +1264,27 @@
NL80211_CMD_UPDATE_CONNECT_PARAMS,
+ NL80211_CMD_SET_PMK,
+ NL80211_CMD_DEL_PMK,
+
+ NL80211_CMD_PORT_AUTHORIZED,
+
+ NL80211_CMD_RELOAD_REGDB,
+
+ NL80211_CMD_EXTERNAL_AUTH,
+
+ NL80211_CMD_STA_OPMODE_CHANGED,
+
+ NL80211_CMD_CONTROL_PORT_FRAME,
+
+ NL80211_CMD_GET_FTM_RESPONDER_STATS,
+
+ NL80211_CMD_PEER_MEASUREMENT_START,
+ NL80211_CMD_PEER_MEASUREMENT_RESULT,
+ NL80211_CMD_PEER_MEASUREMENT_COMPLETE,
+
+ NL80211_CMD_NOTIFY_RADAR,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1366,8 +1507,12 @@
*
* @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is
* used for the association (&enum nl80211_mfp, represented as a u32);
- * this attribute can be used
- * with %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests
+ * this attribute can be used with %NL80211_CMD_ASSOCIATE and
+ * %NL80211_CMD_CONNECT requests. %NL80211_MFP_OPTIONAL is not allowed for
+ * %NL80211_CMD_ASSOCIATE since user space SME is expected and hence, it
+ * must have decided whether to use management frame protection or not.
+ * Setting %NL80211_MFP_OPTIONAL with a %NL80211_CMD_CONNECT request will
+ * let the driver (or the firmware) decide whether to use MFP or not.
*
* @NL80211_ATTR_STA_FLAGS2: Attribute containing a
* &struct nl80211_sta_flag_update.
@@ -1387,6 +1532,15 @@
* @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with
* %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom
* ethertype frames used for key negotiation must not be encrypted.
+ * @NL80211_ATTR_CONTROL_PORT_OVER_NL80211: A flag indicating whether control
+ * port frames (e.g. of type given in %NL80211_ATTR_CONTROL_PORT_ETHERTYPE)
+ * will be sent directly to the network interface or sent via the NL80211
+ * socket. If this attribute is missing, then legacy behavior of sending
+ * control port frames directly to the network interface is used. If the
+ * flag is included, then control port frames are sent over NL80211 instead
+ * using %CMD_CONTROL_PORT_FRAME. If control port routing over NL80211 is
+ * to be used then userspace must also use the %NL80211_ATTR_SOCKET_OWNER
+ * flag.
*
* @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
* We recommend using nested, driver-specific attributes within this.
@@ -1411,6 +1565,12 @@
* (a u32 with flags from &enum nl80211_wpa_versions).
* @NL80211_ATTR_AKM_SUITES: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
* indicate which key management algorithm(s) to use (an array of u32).
+ * This attribute is also sent in response to @NL80211_CMD_GET_WIPHY,
+ * indicating the supported AKM suites, intended for specific drivers which
+ * implement SME and have constraints on which AKMs are supported and also
+ * the cases where an AKM support is offloaded to the driver/firmware.
+ * If there is no such notification from the driver, user space should
+ * assume the driver supports all the AKM suites.
*
* @NL80211_ATTR_REQ_IE: (Re)association request information elements as
* sent out by the card, for ROAM and successful CONNECT events.
@@ -1587,7 +1747,7 @@
* the values passed in @NL80211_ATTR_SCAN_SSIDS (eg. if an SSID
* is included in the probe request, but the match attributes
* will never let it go through), -EINVAL may be returned.
- * If ommited, no filtering is done.
+ * If omitted, no filtering is done.
*
* @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported
* interface combinations. In each nested item, it contains attributes
@@ -1692,7 +1852,7 @@
*
* @NL80211_ATTR_INACTIVITY_TIMEOUT: timeout value in seconds, this can be
* used by the drivers which has MLME in firmware and does not have support
- * to report per station tx/rx activity to free up the staion entry from
+ * to report per station tx/rx activity to free up the station entry from
* the list. This needs to be used when the driver advertises the
* capability to timeout the stations.
*
@@ -1868,13 +2028,18 @@
* that configured the indoor setting, and the indoor operation would be
* cleared when the socket is closed.
* If set during NAN interface creation, the interface will be destroyed
- * if the socket is closed just like any other interface. Moreover, only
- * the netlink socket that created the interface will be allowed to add
- * and remove functions. NAN notifications will be sent in unicast to that
- * socket. Without this attribute, any socket can add functions and the
- * notifications will be sent to the %NL80211_MCGRP_NAN multicast group.
+ * if the socket is closed just like any other interface. Moreover, NAN
+ * notifications will be sent in unicast to that socket. Without this
+ * attribute, the notifications will be sent to the %NL80211_MCGRP_NAN
+ * multicast group.
* If set during %NL80211_CMD_ASSOCIATE or %NL80211_CMD_CONNECT the
* station will deauthenticate when the socket is closed.
+ * If set during %NL80211_CMD_JOIN_IBSS the IBSS will be automatically
+ * torn down when the socket is closed.
+ * If set during %NL80211_CMD_JOIN_MESH the mesh setup will be
+ * automatically torn down when the socket is closed.
+ * If set during %NL80211_CMD_START_AP the AP will be automatically
+ * disabled when the socket is closed.
*
* @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
* the TDLS link initiator.
@@ -2048,7 +2213,7 @@
*
* @NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST: When present the RSSI level for BSSs in
* the specified band is to be adjusted before doing
- * %NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI based comparision to figure out
+ * %NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI based comparison to figure out
* better BSSs. The attribute value is a packed structure
* value as specified by &struct nl80211_bss_select_rssi_adjust.
*
@@ -2078,8 +2243,70 @@
* identifying the scope of PMKSAs. This is used with
* @NL80211_CMD_SET_PMKSA and @NL80211_CMD_DEL_PMKSA.
*
- * @NL80211_ATTR_PMK: PMK for the PMKSA identified by %NL80211_ATTR_PMKID.
- * This is used with @NL80211_CMD_SET_PMKSA.
+ * @NL80211_ATTR_PMK: attribute for passing PMK key material. Used with
+ * %NL80211_CMD_SET_PMKSA for the PMKSA identified by %NL80211_ATTR_PMKID.
+ * For %NL80211_CMD_CONNECT it is used to provide PSK for offloading 4-way
+ * handshake for WPA/WPA2-PSK networks. For 802.1X authentication it is
+ * used with %NL80211_CMD_SET_PMK. For offloaded FT support this attribute
+ * specifies the PMK-R0 if NL80211_ATTR_PMKR0_NAME is included as well.
+ *
+ * @NL80211_ATTR_SCHED_SCAN_MULTI: flag attribute which user-space shall use to
+ * indicate that it supports multiple active scheduled scan requests.
+ * @NL80211_ATTR_SCHED_SCAN_MAX_REQS: indicates maximum number of scheduled
+ * scan request that may be active for the device (u32).
+ *
+ * @NL80211_ATTR_WANT_1X_4WAY_HS: flag attribute which user-space can include
+ * in %NL80211_CMD_CONNECT to indicate that for 802.1X authentication it
+ * wants to use the supported offload of the 4-way handshake.
+ * @NL80211_ATTR_PMKR0_NAME: PMK-R0 Name for offloaded FT.
+ * @NL80211_ATTR_PORT_AUTHORIZED: (reserved)
+ *
+ * @NL80211_ATTR_EXTERNAL_AUTH_ACTION: Identify the requested external
+ * authentication operation (u32 attribute with an
+ * &enum nl80211_external_auth_action value). This is used with the
+ * %NL80211_CMD_EXTERNAL_AUTH request event.
+ * @NL80211_ATTR_EXTERNAL_AUTH_SUPPORT: Flag attribute indicating that the user
+ * space supports external authentication. This attribute shall be used
+ * with %NL80211_CMD_CONNECT and %NL80211_CMD_START_AP request. The driver
+ * may offload authentication processing to user space if this capability
+ * is indicated in the respective requests from the user space.
+ *
+ * @NL80211_ATTR_NSS: Station's New/updated RX_NSS value notified using this
+ * u8 attribute. This is used with %NL80211_CMD_STA_OPMODE_CHANGED.
+ *
+ * @NL80211_ATTR_TXQ_STATS: TXQ statistics (nested attribute, see &enum
+ * nl80211_txq_stats)
+ * @NL80211_ATTR_TXQ_LIMIT: Total packet limit for the TXQ queues for this phy.
+ * The smaller of this and the memory limit is enforced.
+ * @NL80211_ATTR_TXQ_MEMORY_LIMIT: Total memory memory limit (in bytes) for the
+ * TXQ queues for this phy. The smaller of this and the packet limit is
+ * enforced.
+ * @NL80211_ATTR_TXQ_QUANTUM: TXQ scheduler quantum (bytes). Number of bytes
+ * a flow is assigned on each round of the DRR scheduler.
+ * @NL80211_ATTR_HE_CAPABILITY: HE Capability information element (from
+ * association request when used with NL80211_CMD_NEW_STATION). Can be set
+ * only if %NL80211_STA_FLAG_WME is set.
+ *
+ * @NL80211_ATTR_FTM_RESPONDER: nested attribute which user-space can include
+ * in %NL80211_CMD_START_AP or %NL80211_CMD_SET_BEACON for fine timing
+ * measurement (FTM) responder functionality and containing parameters as
+ * possible, see &enum nl80211_ftm_responder_attr
+ *
+ * @NL80211_ATTR_FTM_RESPONDER_STATS: Nested attribute with FTM responder
+ * statistics, see &enum nl80211_ftm_responder_stats.
+ *
+ * @NL80211_ATTR_TIMEOUT: Timeout for the given operation in milliseconds (u32),
+ * if the attribute is not given no timeout is requested. Note that 0 is an
+ * invalid value.
+ *
+ * @NL80211_ATTR_PEER_MEASUREMENTS: peer measurements request (and result)
+ * data, uses nested attributes specified in
+ * &enum nl80211_peer_measurement_attrs.
+ * This is also used for capability advertisement in the wiphy information,
+ * with the appropriate sub-attributes.
+ *
+ * @NL80211_ATTR_AIRTIME_WEIGHT: Station's weight when scheduled by the airtime
+ * scheduler.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
@@ -2500,6 +2727,38 @@
NL80211_ATTR_PMK,
+ NL80211_ATTR_SCHED_SCAN_MULTI,
+ NL80211_ATTR_SCHED_SCAN_MAX_REQS,
+
+ NL80211_ATTR_WANT_1X_4WAY_HS,
+ NL80211_ATTR_PMKR0_NAME,
+ NL80211_ATTR_PORT_AUTHORIZED,
+
+ NL80211_ATTR_EXTERNAL_AUTH_ACTION,
+ NL80211_ATTR_EXTERNAL_AUTH_SUPPORT,
+
+ NL80211_ATTR_NSS,
+ NL80211_ATTR_ACK_SIGNAL,
+
+ NL80211_ATTR_CONTROL_PORT_OVER_NL80211,
+
+ NL80211_ATTR_TXQ_STATS,
+ NL80211_ATTR_TXQ_LIMIT,
+ NL80211_ATTR_TXQ_MEMORY_LIMIT,
+ NL80211_ATTR_TXQ_QUANTUM,
+
+ NL80211_ATTR_HE_CAPABILITY,
+
+ NL80211_ATTR_FTM_RESPONDER,
+
+ NL80211_ATTR_FTM_RESPONDER_STATS,
+
+ NL80211_ATTR_TIMEOUT,
+
+ NL80211_ATTR_PEER_MEASUREMENTS,
+
+ NL80211_ATTR_AIRTIME_WEIGHT,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -2539,6 +2798,8 @@
#define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
+#define NL80211_WIPHY_NAME_MAXLEN 64
+
#define NL80211_MAX_SUPP_RATES 32
#define NL80211_MAX_SUPP_HT_RATES 77
#define NL80211_MAX_SUPP_REG_RULES 64
@@ -2547,7 +2808,8 @@
#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24
#define NL80211_HT_CAPABILITY_LEN 26
#define NL80211_VHT_CAPABILITY_LEN 12
-
+#define NL80211_HE_MIN_CAPABILITY_LEN 16
+#define NL80211_HE_MAX_CAPABILITY_LEN 51
#define NL80211_MAX_NR_CIPHER_SUITES 5
#define NL80211_MAX_NR_AKM_SUITES 2
@@ -2675,6 +2937,38 @@
} __attribute__((packed));
/**
+ * enum nl80211_he_gi - HE guard interval
+ * @NL80211_RATE_INFO_HE_GI_0_8: 0.8 usec
+ * @NL80211_RATE_INFO_HE_GI_1_6: 1.6 usec
+ * @NL80211_RATE_INFO_HE_GI_3_2: 3.2 usec
+ */
+enum nl80211_he_gi {
+ NL80211_RATE_INFO_HE_GI_0_8,
+ NL80211_RATE_INFO_HE_GI_1_6,
+ NL80211_RATE_INFO_HE_GI_3_2,
+};
+
+/**
+ * enum nl80211_he_ru_alloc - HE RU allocation values
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_26: 26-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_52: 52-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_106: 106-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_242: 242-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_484: 484-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_996: 996-tone RU allocation
+ * @NL80211_RATE_INFO_HE_RU_ALLOC_2x996: 2x996-tone RU allocation
+ */
+enum nl80211_he_ru_alloc {
+ NL80211_RATE_INFO_HE_RU_ALLOC_26,
+ NL80211_RATE_INFO_HE_RU_ALLOC_52,
+ NL80211_RATE_INFO_HE_RU_ALLOC_106,
+ NL80211_RATE_INFO_HE_RU_ALLOC_242,
+ NL80211_RATE_INFO_HE_RU_ALLOC_484,
+ NL80211_RATE_INFO_HE_RU_ALLOC_996,
+ NL80211_RATE_INFO_HE_RU_ALLOC_2x996,
+};
+
+/**
* enum nl80211_rate_info - bitrate information
*
* These attribute types are used with %NL80211_STA_INFO_TXRATE
@@ -2706,6 +3000,13 @@
* @NL80211_RATE_INFO_5_MHZ_WIDTH: 5 MHz width - note that this is
* a legacy rate and will be reported as the actual bitrate, i.e.
* a quarter of the base (20 MHz) rate
+ * @NL80211_RATE_INFO_HE_MCS: HE MCS index (u8, 0-11)
+ * @NL80211_RATE_INFO_HE_NSS: HE NSS value (u8, 1-8)
+ * @NL80211_RATE_INFO_HE_GI: HE guard interval identifier
+ * (u8, see &enum nl80211_he_gi)
+ * @NL80211_RATE_INFO_HE_DCM: HE DCM value (u8, 0/1)
+ * @NL80211_RATE_INFO_RU_ALLOC: HE RU allocation, if not present then
+ * non-OFDMA was used (u8, see &enum nl80211_he_ru_alloc)
* @__NL80211_RATE_INFO_AFTER_LAST: internal use
*/
enum nl80211_rate_info {
@@ -2722,6 +3023,11 @@
NL80211_RATE_INFO_160_MHZ_WIDTH,
NL80211_RATE_INFO_10_MHZ_WIDTH,
NL80211_RATE_INFO_5_MHZ_WIDTH,
+ NL80211_RATE_INFO_HE_MCS,
+ NL80211_RATE_INFO_HE_NSS,
+ NL80211_RATE_INFO_HE_GI,
+ NL80211_RATE_INFO_HE_DCM,
+ NL80211_RATE_INFO_HE_RU_ALLOC,
/* keep last */
__NL80211_RATE_INFO_AFTER_LAST,
@@ -2820,6 +3126,19 @@
* @NL80211_STA_INFO_RX_DURATION: aggregate PPDU duration for all frames
* received from the station (u64, usec)
* @NL80211_STA_INFO_PAD: attribute used for padding for 64-bit alignment
+ * @NL80211_STA_INFO_ACK_SIGNAL: signal strength of the last ACK frame(u8, dBm)
+ * @NL80211_STA_INFO_ACK_SIGNAL_AVG: avg signal strength of ACK frames (s8, dBm)
+ * @NL80211_STA_INFO_RX_MPDUS: total number of received packets (MPDUs)
+ * (u32, from this station)
+ * @NL80211_STA_INFO_FCS_ERROR_COUNT: total number of packets (MPDUs) received
+ * with an FCS error (u32, from this station). This count may not include
+ * some packets with an FCS error due to TA corruption. Hence this counter
+ * might not be fully accurate.
+ * @NL80211_STA_INFO_CONNECTED_TO_GATE: set to true if STA has a path to a
+ * mesh gate (u8, 0 or 1)
+ * @NL80211_STA_INFO_TX_DURATION: aggregate PPDU duration for all frames
+ * sent to the station (u64, usec)
+ * @NL80211_STA_INFO_AIRTIME_WEIGHT: current airtime weight for station (u16)
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@@ -2858,12 +3177,23 @@
NL80211_STA_INFO_TID_STATS,
NL80211_STA_INFO_RX_DURATION,
NL80211_STA_INFO_PAD,
+ NL80211_STA_INFO_ACK_SIGNAL,
+ NL80211_STA_INFO_ACK_SIGNAL_AVG,
+ NL80211_STA_INFO_RX_MPDUS,
+ NL80211_STA_INFO_FCS_ERROR_COUNT,
+ NL80211_STA_INFO_CONNECTED_TO_GATE,
+ NL80211_STA_INFO_TX_DURATION,
+ NL80211_STA_INFO_AIRTIME_WEIGHT,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1
};
+/* we renamed this - stay compatible */
+#define NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG NL80211_STA_INFO_ACK_SIGNAL_AVG
+
+
/**
* enum nl80211_tid_stats - per TID statistics attributes
* @__NL80211_TID_STATS_INVALID: attribute number 0 is reserved
@@ -2875,6 +3205,7 @@
* @NL80211_TID_STATS_TX_MSDU_FAILED: number of failed transmitted
* MSDUs (u64)
* @NL80211_TID_STATS_PAD: attribute used for padding for 64-bit alignment
+ * @NL80211_TID_STATS_TXQ_STATS: TXQ stats (nested attribute)
* @NUM_NL80211_TID_STATS: number of attributes here
* @NL80211_TID_STATS_MAX: highest numbered attribute here
*/
@@ -2885,6 +3216,7 @@
NL80211_TID_STATS_TX_MSDU_RETRIES,
NL80211_TID_STATS_TX_MSDU_FAILED,
NL80211_TID_STATS_PAD,
+ NL80211_TID_STATS_TXQ_STATS,
/* keep last */
NUM_NL80211_TID_STATS,
@@ -2892,6 +3224,44 @@
};
/**
+ * enum nl80211_txq_stats - per TXQ statistics attributes
+ * @__NL80211_TXQ_STATS_INVALID: attribute number 0 is reserved
+ * @NUM_NL80211_TXQ_STATS: number of attributes here
+ * @NL80211_TXQ_STATS_BACKLOG_BYTES: number of bytes currently backlogged
+ * @NL80211_TXQ_STATS_BACKLOG_PACKETS: number of packets currently
+ * backlogged
+ * @NL80211_TXQ_STATS_FLOWS: total number of new flows seen
+ * @NL80211_TXQ_STATS_DROPS: total number of packet drops
+ * @NL80211_TXQ_STATS_ECN_MARKS: total number of packet ECN marks
+ * @NL80211_TXQ_STATS_OVERLIMIT: number of drops due to queue space overflow
+ * @NL80211_TXQ_STATS_OVERMEMORY: number of drops due to memory limit overflow
+ * (only for per-phy stats)
+ * @NL80211_TXQ_STATS_COLLISIONS: number of hash collisions
+ * @NL80211_TXQ_STATS_TX_BYTES: total number of bytes dequeued from TXQ
+ * @NL80211_TXQ_STATS_TX_PACKETS: total number of packets dequeued from TXQ
+ * @NL80211_TXQ_STATS_MAX_FLOWS: number of flow buckets for PHY
+ * @NL80211_TXQ_STATS_MAX: highest numbered attribute here
+ */
+enum nl80211_txq_stats {
+ __NL80211_TXQ_STATS_INVALID,
+ NL80211_TXQ_STATS_BACKLOG_BYTES,
+ NL80211_TXQ_STATS_BACKLOG_PACKETS,
+ NL80211_TXQ_STATS_FLOWS,
+ NL80211_TXQ_STATS_DROPS,
+ NL80211_TXQ_STATS_ECN_MARKS,
+ NL80211_TXQ_STATS_OVERLIMIT,
+ NL80211_TXQ_STATS_OVERMEMORY,
+ NL80211_TXQ_STATS_COLLISIONS,
+ NL80211_TXQ_STATS_TX_BYTES,
+ NL80211_TXQ_STATS_TX_PACKETS,
+ NL80211_TXQ_STATS_MAX_FLOWS,
+
+ /* keep last */
+ NUM_NL80211_TXQ_STATS,
+ NL80211_TXQ_STATS_MAX = NUM_NL80211_TXQ_STATS - 1
+};
+
+/**
* enum nl80211_mpath_flags - nl80211 mesh path flags
*
* @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active
@@ -2923,8 +3293,10 @@
* &enum nl80211_mpath_flags;
* @NL80211_MPATH_INFO_DISCOVERY_TIMEOUT: total path discovery timeout, in msec
* @NL80211_MPATH_INFO_DISCOVERY_RETRIES: mesh path discovery retries
+ * @NL80211_MPATH_INFO_HOP_COUNT: hop count to destination
+ * @NL80211_MPATH_INFO_PATH_CHANGE: total number of path changes to destination
* @NL80211_MPATH_INFO_MAX: highest mesh path information attribute number
- * currently defind
+ * currently defined
* @__NL80211_MPATH_INFO_AFTER_LAST: internal use
*/
enum nl80211_mpath_info {
@@ -2936,6 +3308,8 @@
NL80211_MPATH_INFO_FLAGS,
NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
NL80211_MPATH_INFO_DISCOVERY_RETRIES,
+ NL80211_MPATH_INFO_HOP_COUNT,
+ NL80211_MPATH_INFO_PATH_CHANGE,
/* keep last */
__NL80211_MPATH_INFO_AFTER_LAST,
@@ -2943,6 +3317,38 @@
};
/**
+ * enum nl80211_band_iftype_attr - Interface type data attributes
+ *
+ * @__NL80211_BAND_IFTYPE_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_BAND_IFTYPE_ATTR_IFTYPES: nested attribute containing a flag attribute
+ * for each interface type that supports the band data
+ * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC: HE MAC capabilities as in HE
+ * capabilities IE
+ * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY: HE PHY capabilities as in HE
+ * capabilities IE
+ * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET: HE supported NSS/MCS as in HE
+ * capabilities IE
+ * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE: HE PPE thresholds information as
+ * defined in HE capabilities IE
+ * @NL80211_BAND_IFTYPE_ATTR_MAX: highest band HE capability attribute currently
+ * defined
+ * @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_band_iftype_attr {
+ __NL80211_BAND_IFTYPE_ATTR_INVALID,
+
+ NL80211_BAND_IFTYPE_ATTR_IFTYPES,
+ NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC,
+ NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY,
+ NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET,
+ NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE,
+
+ /* keep last */
+ __NL80211_BAND_IFTYPE_ATTR_AFTER_LAST,
+ NL80211_BAND_IFTYPE_ATTR_MAX = __NL80211_BAND_IFTYPE_ATTR_AFTER_LAST - 1
+};
+
+/**
* enum nl80211_band_attr - band attributes
* @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved
* @NL80211_BAND_ATTR_FREQS: supported frequencies in this band,
@@ -2957,6 +3363,8 @@
* @NL80211_BAND_ATTR_VHT_MCS_SET: 32-byte attribute containing the MCS set as
* defined in 802.11ac
* @NL80211_BAND_ATTR_VHT_CAPA: VHT capabilities, as in the HT information IE
+ * @NL80211_BAND_ATTR_IFTYPE_DATA: nested array attribute, with each entry using
+ * attributes from &enum nl80211_band_iftype_attr
* @NL80211_BAND_ATTR_MAX: highest band attribute currently defined
* @__NL80211_BAND_ATTR_AFTER_LAST: internal use
*/
@@ -2972,6 +3380,7 @@
NL80211_BAND_ATTR_VHT_MCS_SET,
NL80211_BAND_ATTR_VHT_CAPA,
+ NL80211_BAND_ATTR_IFTYPE_DATA,
/* keep last */
__NL80211_BAND_ATTR_AFTER_LAST,
@@ -2981,6 +3390,29 @@
#define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA
/**
+ * enum nl80211_wmm_rule - regulatory wmm rule
+ *
+ * @__NL80211_WMMR_INVALID: attribute number 0 is reserved
+ * @NL80211_WMMR_CW_MIN: Minimum contention window slot.
+ * @NL80211_WMMR_CW_MAX: Maximum contention window slot.
+ * @NL80211_WMMR_AIFSN: Arbitration Inter Frame Space.
+ * @NL80211_WMMR_TXOP: Maximum allowed tx operation time.
+ * @nl80211_WMMR_MAX: highest possible wmm rule.
+ * @__NL80211_WMMR_LAST: Internal use.
+ */
+enum nl80211_wmm_rule {
+ __NL80211_WMMR_INVALID,
+ NL80211_WMMR_CW_MIN,
+ NL80211_WMMR_CW_MAX,
+ NL80211_WMMR_AIFSN,
+ NL80211_WMMR_TXOP,
+
+ /* keep last */
+ __NL80211_WMMR_LAST,
+ NL80211_WMMR_MAX = __NL80211_WMMR_LAST - 1
+};
+
+/**
* enum nl80211_frequency_attr - frequency attributes
* @__NL80211_FREQUENCY_ATTR_INVALID: attribute number 0 is reserved
* @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
@@ -3029,6 +3461,9 @@
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_NO_10MHZ: 10 MHz operation is not allowed
* on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_WMM: this channel has wmm limitations.
+ * This is a nested attribute that contains the wmm limitation per AC.
+ * (see &enum nl80211_wmm_rule)
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -3057,6 +3492,7 @@
NL80211_FREQUENCY_ATTR_IR_CONCURRENT,
NL80211_FREQUENCY_ATTR_NO_20MHZ,
NL80211_FREQUENCY_ATTR_NO_10MHZ,
+ NL80211_FREQUENCY_ATTR_WMM,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -3184,6 +3620,7 @@
* @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved
* @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching,
* only report BSS with matching SSID.
+ * (This cannot be used together with BSSID.)
* @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI: RSSI threshold (in dBm) for reporting a
* BSS in scan results. Filtering is turned off if not specified. Note that
* if this attribute is in a match set of its own, then it is treated as
@@ -3199,6 +3636,8 @@
* BSS-es in the specified band is to be adjusted before doing
* RSSI-based BSS selection. The attribute value is a packed structure
* value as specified by &struct nl80211_bss_select_rssi_adjust.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_BSSID: BSSID to be used for matching
+ * (this cannot be used together with SSID).
* @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
* attribute number currently defined
* @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
@@ -3210,6 +3649,7 @@
NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI,
NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST,
+ NL80211_SCHED_SCAN_MATCH_ATTR_BSSID,
/* keep last */
__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
@@ -3236,7 +3676,7 @@
* @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated
* base on contiguous rules and wider channels will be allowed to cross
* multiple contiguous/overlapping frequency ranges.
- * @NL80211_RRF_IR_CONCURRENT: See &NL80211_FREQUENCY_ATTR_IR_CONCURRENT
+ * @NL80211_RRF_IR_CONCURRENT: See %NL80211_FREQUENCY_ATTR_IR_CONCURRENT
* @NL80211_RRF_NO_HT40MINUS: channels can't be used in HT40- operation
* @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation
* @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed
@@ -3527,6 +3967,11 @@
* remove it from the STA's list of peers. You may set this to 0 to disable
* the removal of the STA. Default is 30 minutes.
*
+ * @NL80211_MESHCONF_CONNECTED_TO_GATE: If set to true then this mesh STA
+ * will advertise that it is connected to a gate in the mesh formation
+ * field. If left unset then the mesh formation field will only
+ * advertise such if there is an active root mesh path.
+ *
* @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
*/
enum nl80211_meshconf_params {
@@ -3559,6 +4004,7 @@
NL80211_MESHCONF_POWER_MODE,
NL80211_MESHCONF_AWAKE_WINDOW,
NL80211_MESHCONF_PLINK_TIMEOUT,
+ NL80211_MESHCONF_CONNECTED_TO_GATE,
/* keep last */
__NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -3779,6 +4225,9 @@
* @NL80211_BSS_PARENT_BSSID. (u64).
* @NL80211_BSS_PARENT_BSSID: the BSS according to which @NL80211_BSS_PARENT_TSF
* is set.
+ * @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_AFTER_LAST: internal
* @NL80211_BSS_MAX: highest BSS attribute
*/
@@ -3802,6 +4251,7 @@
NL80211_BSS_PAD,
NL80211_BSS_PARENT_TSF,
NL80211_BSS_PARENT_BSSID,
+ NL80211_BSS_CHAIN_SIGNAL,
/* keep last */
__NL80211_BSS_AFTER_LAST,
@@ -3878,10 +4328,12 @@
* enum nl80211_mfp - Management frame protection state
* @NL80211_MFP_NO: Management frame protection not used
* @NL80211_MFP_REQUIRED: Management frame protection required
+ * @NL80211_MFP_OPTIONAL: Management frame protection is optional
*/
enum nl80211_mfp {
NL80211_MFP_NO,
NL80211_MFP_REQUIRED,
+ NL80211_MFP_OPTIONAL,
};
enum nl80211_wpa_versions {
@@ -3992,7 +4444,7 @@
* enum nl80211_band - Frequency band
* @NL80211_BAND_2GHZ: 2.4 GHz ISM band
* @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
- * @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 64.80 GHz)
+ * @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 69.12 GHz)
* @NUM_NL80211_BANDS: number of bands, avoid using this in userspace
* since newer kernel versions may support more bands
*/
@@ -4485,7 +4937,7 @@
* numbers = [ #{STA} <= 1, #{P2P-client,P2P-GO} <= 3 ], max = 4
* => allows a STA plus three P2P interfaces
*
- * The list of these four possiblities could completely be contained
+ * The list of these four possibilities could completely be contained
* within the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute to indicate
* that any of these groups must match.
*
@@ -4515,7 +4967,7 @@
* enum nl80211_plink_state - state of a mesh peer link finite state machine
*
* @NL80211_PLINK_LISTEN: initial state, considered the implicit
- * state of non existant mesh peer links
+ * state of non existent mesh peer links
* @NL80211_PLINK_OPN_SNT: mesh plink open frame has been sent to
* this mesh peer
* @NL80211_PLINK_OPN_RCVD: mesh plink open frame has been received
@@ -4838,6 +5290,58 @@
* RSSI threshold values to monitor rather than exactly one threshold.
* @NL80211_EXT_FEATURE_FILS_SK_OFFLOAD: Driver SME supports FILS shared key
* authentication with %NL80211_CMD_CONNECT.
+ * @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK: Device wants to do 4-way
+ * handshake with PSK in station mode (PSK is passed as part of the connect
+ * and associate commands), doing it in the host might not be supported.
+ * @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X: Device wants to do doing 4-way
+ * handshake with 802.1X in station mode (will pass EAP frames to the host
+ * and accept the set_pmk/del_pmk commands), doing it in the host might not
+ * be supported.
+ * @NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME: Driver is capable of overriding
+ * the max channel attribute in the FILS request params IE with the
+ * actual dwell time.
+ * @NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP: Driver accepts broadcast probe
+ * response
+ * @NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE: Driver supports sending
+ * the first probe request in each channel at rate of at least 5.5Mbps.
+ * @NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION: Driver supports
+ * probe request tx deferral and suppression
+ * @NL80211_EXT_FEATURE_MFP_OPTIONAL: Driver supports the %NL80211_MFP_OPTIONAL
+ * value in %NL80211_ATTR_USE_MFP.
+ * @NL80211_EXT_FEATURE_LOW_SPAN_SCAN: Driver supports low span scan.
+ * @NL80211_EXT_FEATURE_LOW_POWER_SCAN: Driver supports low power scan.
+ * @NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN: Driver supports high accuracy scan.
+ * @NL80211_EXT_FEATURE_DFS_OFFLOAD: HW/driver will offload DFS actions.
+ * Device or driver will do all DFS-related actions by itself,
+ * informing user-space about CAC progress, radar detection event,
+ * channel change triggered by radar detection event.
+ * No need to start CAC from user-space, no need to react to
+ * "radar detected" event.
+ * @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211: Driver supports sending and
+ * receiving control port frames over nl80211 instead of the netdevice.
+ * @NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT: This driver/device supports
+ * (average) ACK signal strength reporting.
+ * @NL80211_EXT_FEATURE_TXQS: Driver supports FQ-CoDel-enabled intermediate
+ * TXQs.
+ * @NL80211_EXT_FEATURE_SCAN_RANDOM_SN: Driver/device supports randomizing the
+ * SN in probe request frames if requested by %NL80211_SCAN_FLAG_RANDOM_SN.
+ * @NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT: Driver/device can omit all data
+ * except for supported rates from the probe request content if requested
+ * by the %NL80211_SCAN_FLAG_MIN_PREQ_CONTENT flag.
+ * @NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER: Driver supports enabling fine
+ * timing measurement responder role.
+ *
+ * @NL80211_EXT_FEATURE_CAN_REPLACE_PTK0: Driver/device confirm that they are
+ * able to rekey an in-use key correctly. Userspace must not rekey PTK keys
+ * if this flag is not set. Ignoring this can leak clear text packets and/or
+ * freeze the connection.
+ *
+ * @NL80211_EXT_FEATURE_AIRTIME_FAIRNESS: Driver supports getting airtime
+ * fairness for transmitted packets and has enabled airtime fairness
+ * scheduling.
+ *
+ * @NL80211_EXT_FEATURE_AP_PMKSA_CACHING: Driver/device supports PMKSA caching
+ * (set/del PMKSA operations) in AP mode.
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -4858,6 +5362,28 @@
NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI,
NL80211_EXT_FEATURE_CQM_RSSI_LIST,
NL80211_EXT_FEATURE_FILS_SK_OFFLOAD,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X,
+ NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME,
+ NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP,
+ NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE,
+ NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION,
+ NL80211_EXT_FEATURE_MFP_OPTIONAL,
+ NL80211_EXT_FEATURE_LOW_SPAN_SCAN,
+ NL80211_EXT_FEATURE_LOW_POWER_SCAN,
+ NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN,
+ NL80211_EXT_FEATURE_DFS_OFFLOAD,
+ NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211,
+ NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT,
+ /* we renamed this - stay compatible */
+ NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT = NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT,
+ NL80211_EXT_FEATURE_TXQS,
+ NL80211_EXT_FEATURE_SCAN_RANDOM_SN,
+ NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT,
+ NL80211_EXT_FEATURE_CAN_REPLACE_PTK0,
+ NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER,
+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS,
+ NL80211_EXT_FEATURE_AP_PMKSA_CACHING,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@@ -4918,6 +5444,10 @@
* of NL80211_CMD_TRIGGER_SCAN and NL80211_CMD_START_SCHED_SCAN
* requests.
*
+ * NL80211_SCAN_FLAG_LOW_SPAN, NL80211_SCAN_FLAG_LOW_POWER, and
+ * NL80211_SCAN_FLAG_HIGH_ACCURACY flags are exclusive of each other, i.e., only
+ * one of them can be used in the request.
+ *
* @NL80211_SCAN_FLAG_LOW_PRIORITY: scan request has low priority
* @NL80211_SCAN_FLAG_FLUSH: flush cache before scanning
* @NL80211_SCAN_FLAG_AP: force a scan even if the interface is configured
@@ -4934,12 +5464,52 @@
* locally administered 1, multicast 0) is assumed.
* This flag must not be requested when the feature isn't supported, check
* the nl80211 feature flags for the device.
+ * @NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME: fill the dwell time in the FILS
+ * request parameters IE in the probe request
+ * @NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP: accept broadcast probe responses
+ * @NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE: send probe request frames at
+ * rate of at least 5.5M. In case non OCE AP is discovered in the channel,
+ * only the first probe req in the channel will be sent in high rate.
+ * @NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION: allow probe request
+ * tx deferral (dot11FILSProbeDelay shall be set to 15ms)
+ * and suppression (if it has received a broadcast Probe Response frame,
+ * Beacon frame or FILS Discovery frame from an AP that the STA considers
+ * a suitable candidate for (re-)association - suitable in terms of
+ * SSID and/or RSSI.
+ * @NL80211_SCAN_FLAG_LOW_SPAN: Span corresponds to the total time taken to
+ * accomplish the scan. Thus, this flag intends the driver to perform the
+ * scan request with lesser span/duration. It is specific to the driver
+ * implementations on how this is accomplished. Scan accuracy may get
+ * impacted with this flag.
+ * @NL80211_SCAN_FLAG_LOW_POWER: This flag intends the scan attempts to consume
+ * optimal possible power. Drivers can resort to their specific means to
+ * optimize the power. Scan accuracy may get impacted with this flag.
+ * @NL80211_SCAN_FLAG_HIGH_ACCURACY: Accuracy here intends to the extent of scan
+ * results obtained. Thus HIGH_ACCURACY scan flag aims to get maximum
+ * possible scan results. This flag hints the driver to use the best
+ * possible scan configuration to improve the accuracy in scanning.
+ * Latency and power use may get impacted with this flag.
+ * @NL80211_SCAN_FLAG_RANDOM_SN: randomize the sequence number in probe
+ * request frames from this scan to avoid correlation/tracking being
+ * possible.
+ * @NL80211_SCAN_FLAG_MIN_PREQ_CONTENT: minimize probe request content to
+ * only have supported rates and no additional capabilities (unless
+ * added by userspace explicitly.)
*/
enum nl80211_scan_flags {
- NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,
- NL80211_SCAN_FLAG_FLUSH = 1<<1,
- NL80211_SCAN_FLAG_AP = 1<<2,
- NL80211_SCAN_FLAG_RANDOM_ADDR = 1<<3,
+ NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,
+ NL80211_SCAN_FLAG_FLUSH = 1<<1,
+ NL80211_SCAN_FLAG_AP = 1<<2,
+ NL80211_SCAN_FLAG_RANDOM_ADDR = 1<<3,
+ NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME = 1<<4,
+ NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP = 1<<5,
+ NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE = 1<<6,
+ NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION = 1<<7,
+ NL80211_SCAN_FLAG_LOW_SPAN = 1<<8,
+ NL80211_SCAN_FLAG_LOW_POWER = 1<<9,
+ NL80211_SCAN_FLAG_HIGH_ACCURACY = 1<<10,
+ NL80211_SCAN_FLAG_RANDOM_SN = 1<<11,
+ NL80211_SCAN_FLAG_MIN_PREQ_CONTENT = 1<<12,
};
/**
@@ -4997,6 +5567,8 @@
* non-operating channel is expired and no longer valid. New CAC must
* be done on this channel before starting the operation. This is not
* applicable for ETSI dfs domain where pre-CAC is valid for ever.
+ * @NL80211_RADAR_CAC_STARTED: Channel Availability Check has been started,
+ * should be generated by HW if NL80211_EXT_FEATURE_DFS_OFFLOAD is enabled.
*/
enum nl80211_radar_event {
NL80211_RADAR_DETECTED,
@@ -5004,6 +5576,7 @@
NL80211_RADAR_CAC_ABORTED,
NL80211_RADAR_NOP_FINISHED,
NL80211_RADAR_PRE_CAC_EXPIRED,
+ NL80211_RADAR_CAC_STARTED,
};
/**
@@ -5062,9 +5635,14 @@
* Used by cfg80211_rx_mgmt()
*
* @NL80211_RXMGMT_FLAG_ANSWERED: frame was answered by device/driver.
+ * @NL80211_RXMGMT_FLAG_EXTERNAL_AUTH: Host driver intends to offload
+ * the authentication. Exclusively defined for host drivers that
+ * advertises the SME functionality but would like the userspace
+ * to handle certain authentication algorithms (e.g. SAE).
*/
enum nl80211_rxmgmt_flags {
NL80211_RXMGMT_FLAG_ANSWERED = 1 << 0,
+ NL80211_RXMGMT_FLAG_EXTERNAL_AUTH = 1 << 1,
};
/*
@@ -5295,11 +5873,11 @@
* @NL80211_NAN_SRF_INCLUDE: present if the include bit of the SRF set.
* This is a flag.
* @NL80211_NAN_SRF_BF: Bloom Filter. Present if and only if
- * &NL80211_NAN_SRF_MAC_ADDRS isn't present. This attribute is binary.
+ * %NL80211_NAN_SRF_MAC_ADDRS isn't present. This attribute is binary.
* @NL80211_NAN_SRF_BF_IDX: index of the Bloom Filter. Mandatory if
- * &NL80211_NAN_SRF_BF is present. This is a u8.
+ * %NL80211_NAN_SRF_BF is present. This is a u8.
* @NL80211_NAN_SRF_MAC_ADDRS: list of MAC addresses for the SRF. Present if
- * and only if &NL80211_NAN_SRF_BF isn't present. This is a nested
+ * and only if %NL80211_NAN_SRF_BF isn't present. This is a nested
* attribute. Each nested attribute is a MAC address.
* @NUM_NL80211_NAN_SRF_ATTR: internal
* @NL80211_NAN_SRF_ATTR_MAX: highest NAN SRF attribute
@@ -5339,4 +5917,469 @@
NL80211_NAN_MATCH_ATTR_MAX = NUM_NL80211_NAN_MATCH_ATTR - 1
};
+/**
+ * nl80211_external_auth_action - Action to perform with external
+ * authentication request. Used by NL80211_ATTR_EXTERNAL_AUTH_ACTION.
+ * @NL80211_EXTERNAL_AUTH_START: Start the authentication.
+ * @NL80211_EXTERNAL_AUTH_ABORT: Abort the ongoing authentication.
+ */
+enum nl80211_external_auth_action {
+ NL80211_EXTERNAL_AUTH_START,
+ NL80211_EXTERNAL_AUTH_ABORT,
+};
+
+/**
+ * enum nl80211_ftm_responder_attributes - fine timing measurement
+ * responder attributes
+ * @__NL80211_FTM_RESP_ATTR_INVALID: Invalid
+ * @NL80211_FTM_RESP_ATTR_ENABLED: FTM responder is enabled
+ * @NL80211_FTM_RESP_ATTR_LCI: The content of Measurement Report Element
+ * (9.4.2.22 in 802.11-2016) with type 8 - LCI (9.4.2.22.10),
+ * i.e. starting with the measurement token
+ * @NL80211_FTM_RESP_ATTR_CIVIC: The content of Measurement Report Element
+ * (9.4.2.22 in 802.11-2016) with type 11 - Civic (Section 9.4.2.22.13),
+ * i.e. starting with the measurement token
+ * @__NL80211_FTM_RESP_ATTR_LAST: Internal
+ * @NL80211_FTM_RESP_ATTR_MAX: highest FTM responder attribute.
+ */
+enum nl80211_ftm_responder_attributes {
+ __NL80211_FTM_RESP_ATTR_INVALID,
+
+ NL80211_FTM_RESP_ATTR_ENABLED,
+ NL80211_FTM_RESP_ATTR_LCI,
+ NL80211_FTM_RESP_ATTR_CIVICLOC,
+
+ /* keep last */
+ __NL80211_FTM_RESP_ATTR_LAST,
+ NL80211_FTM_RESP_ATTR_MAX = __NL80211_FTM_RESP_ATTR_LAST - 1,
+};
+
+/*
+ * enum nl80211_ftm_responder_stats - FTM responder statistics
+ *
+ * These attribute types are used with %NL80211_ATTR_FTM_RESPONDER_STATS
+ * when getting FTM responder statistics.
+ *
+ * @__NL80211_FTM_STATS_INVALID: attribute number 0 is reserved
+ * @NL80211_FTM_STATS_SUCCESS_NUM: number of FTM sessions in which all frames
+ * were ssfully answered (u32)
+ * @NL80211_FTM_STATS_PARTIAL_NUM: number of FTM sessions in which part of the
+ * frames were successfully answered (u32)
+ * @NL80211_FTM_STATS_FAILED_NUM: number of failed FTM sessions (u32)
+ * @NL80211_FTM_STATS_ASAP_NUM: number of ASAP sessions (u32)
+ * @NL80211_FTM_STATS_NON_ASAP_NUM: number of non-ASAP sessions (u32)
+ * @NL80211_FTM_STATS_TOTAL_DURATION_MSEC: total sessions durations - gives an
+ * indication of how much time the responder was busy (u64, msec)
+ * @NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM: number of unknown FTM triggers -
+ * triggers from initiators that didn't finish successfully the negotiation
+ * phase with the responder (u32)
+ * @NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM: number of FTM reschedule requests
+ * - initiator asks for a new scheduling although it already has scheduled
+ * FTM slot (u32)
+ * @NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM: number of FTM triggers out of
+ * scheduled window (u32)
+ * @NL80211_FTM_STATS_PAD: used for padding, ignore
+ * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal
+ * @NL80211_FTM_STATS_MAX: highest possible FTM responder stats attribute
+ */
+enum nl80211_ftm_responder_stats {
+ __NL80211_FTM_STATS_INVALID,
+ NL80211_FTM_STATS_SUCCESS_NUM,
+ NL80211_FTM_STATS_PARTIAL_NUM,
+ NL80211_FTM_STATS_FAILED_NUM,
+ NL80211_FTM_STATS_ASAP_NUM,
+ NL80211_FTM_STATS_NON_ASAP_NUM,
+ NL80211_FTM_STATS_TOTAL_DURATION_MSEC,
+ NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM,
+ NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM,
+ NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM,
+ NL80211_FTM_STATS_PAD,
+
+ /* keep last */
+ __NL80211_FTM_STATS_AFTER_LAST,
+ NL80211_FTM_STATS_MAX = __NL80211_FTM_STATS_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_preamble - frame preamble types
+ * @NL80211_PREAMBLE_LEGACY: legacy (HR/DSSS, OFDM, ERP PHY) preamble
+ * @NL80211_PREAMBLE_HT: HT preamble
+ * @NL80211_PREAMBLE_VHT: VHT preamble
+ * @NL80211_PREAMBLE_DMG: DMG preamble
+ */
+enum nl80211_preamble {
+ NL80211_PREAMBLE_LEGACY,
+ NL80211_PREAMBLE_HT,
+ NL80211_PREAMBLE_VHT,
+ NL80211_PREAMBLE_DMG,
+};
+
+/**
+ * enum nl80211_peer_measurement_type - peer measurement types
+ * @NL80211_PMSR_TYPE_INVALID: invalid/unused, needed as we use
+ * these numbers also for attributes
+ *
+ * @NL80211_PMSR_TYPE_FTM: flight time measurement
+ *
+ * @NUM_NL80211_PMSR_TYPES: internal
+ * @NL80211_PMSR_TYPE_MAX: highest type number
+ */
+enum nl80211_peer_measurement_type {
+ NL80211_PMSR_TYPE_INVALID,
+
+ NL80211_PMSR_TYPE_FTM,
+
+ NUM_NL80211_PMSR_TYPES,
+ NL80211_PMSR_TYPE_MAX = NUM_NL80211_PMSR_TYPES - 1
+};
+
+/**
+ * enum nl80211_peer_measurement_status - peer measurement status
+ * @NL80211_PMSR_STATUS_SUCCESS: measurement completed successfully
+ * @NL80211_PMSR_STATUS_REFUSED: measurement was locally refused
+ * @NL80211_PMSR_STATUS_TIMEOUT: measurement timed out
+ * @NL80211_PMSR_STATUS_FAILURE: measurement failed, a type-dependent
+ * reason may be available in the response data
+ */
+enum nl80211_peer_measurement_status {
+ NL80211_PMSR_STATUS_SUCCESS,
+ NL80211_PMSR_STATUS_REFUSED,
+ NL80211_PMSR_STATUS_TIMEOUT,
+ NL80211_PMSR_STATUS_FAILURE,
+};
+
+/**
+ * enum nl80211_peer_measurement_req - peer measurement request attributes
+ * @__NL80211_PMSR_REQ_ATTR_INVALID: invalid
+ *
+ * @NL80211_PMSR_REQ_ATTR_DATA: This is a nested attribute with measurement
+ * type-specific request data inside. The attributes used are from the
+ * enums named nl80211_peer_measurement_<type>_req.
+ * @NL80211_PMSR_REQ_ATTR_GET_AP_TSF: include AP TSF timestamp, if supported
+ * (flag attribute)
+ *
+ * @NUM_NL80211_PMSR_REQ_ATTRS: internal
+ * @NL80211_PMSR_REQ_ATTR_MAX: highest attribute number
+ */
+enum nl80211_peer_measurement_req {
+ __NL80211_PMSR_REQ_ATTR_INVALID,
+
+ NL80211_PMSR_REQ_ATTR_DATA,
+ NL80211_PMSR_REQ_ATTR_GET_AP_TSF,
+
+ /* keep last */
+ NUM_NL80211_PMSR_REQ_ATTRS,
+ NL80211_PMSR_REQ_ATTR_MAX = NUM_NL80211_PMSR_REQ_ATTRS - 1
+};
+
+/**
+ * enum nl80211_peer_measurement_resp - peer measurement response attributes
+ * @__NL80211_PMSR_RESP_ATTR_INVALID: invalid
+ *
+ * @NL80211_PMSR_RESP_ATTR_DATA: This is a nested attribute with measurement
+ * type-specific results inside. The attributes used are from the enums
+ * named nl80211_peer_measurement_<type>_resp.
+ * @NL80211_PMSR_RESP_ATTR_STATUS: u32 value with the measurement status
+ * (using values from &enum nl80211_peer_measurement_status.)
+ * @NL80211_PMSR_RESP_ATTR_HOST_TIME: host time (%CLOCK_BOOTTIME) when the
+ * result was measured; this value is not expected to be accurate to
+ * more than 20ms. (u64, nanoseconds)
+ * @NL80211_PMSR_RESP_ATTR_AP_TSF: TSF of the AP that the interface
+ * doing the measurement is connected to when the result was measured.
+ * This shall be accurately reported if supported and requested
+ * (u64, usec)
+ * @NL80211_PMSR_RESP_ATTR_FINAL: If results are sent to the host partially
+ * (*e.g. with FTM per-burst data) this flag will be cleared on all but
+ * the last result; if all results are combined it's set on the single
+ * result.
+ * @NL80211_PMSR_RESP_ATTR_PAD: padding for 64-bit attributes, ignore
+ *
+ * @NUM_NL80211_PMSR_RESP_ATTRS: internal
+ * @NL80211_PMSR_RESP_ATTR_MAX: highest attribute number
+ */
+enum nl80211_peer_measurement_resp {
+ __NL80211_PMSR_RESP_ATTR_INVALID,
+
+ NL80211_PMSR_RESP_ATTR_DATA,
+ NL80211_PMSR_RESP_ATTR_STATUS,
+ NL80211_PMSR_RESP_ATTR_HOST_TIME,
+ NL80211_PMSR_RESP_ATTR_AP_TSF,
+ NL80211_PMSR_RESP_ATTR_FINAL,
+ NL80211_PMSR_RESP_ATTR_PAD,
+
+ /* keep last */
+ NUM_NL80211_PMSR_RESP_ATTRS,
+ NL80211_PMSR_RESP_ATTR_MAX = NUM_NL80211_PMSR_RESP_ATTRS - 1
+};
+
+/**
+ * enum nl80211_peer_measurement_peer_attrs - peer attributes for measurement
+ * @__NL80211_PMSR_PEER_ATTR_INVALID: invalid
+ *
+ * @NL80211_PMSR_PEER_ATTR_ADDR: peer's MAC address
+ * @NL80211_PMSR_PEER_ATTR_CHAN: channel definition, nested, using top-level
+ * attributes like %NL80211_ATTR_WIPHY_FREQ etc.
+ * @NL80211_PMSR_PEER_ATTR_REQ: This is a nested attribute indexed by
+ * measurement type, with attributes from the
+ * &enum nl80211_peer_measurement_req inside.
+ * @NL80211_PMSR_PEER_ATTR_RESP: This is a nested attribute indexed by
+ * measurement type, with attributes from the
+ * &enum nl80211_peer_measurement_resp inside.
+ *
+ * @NUM_NL80211_PMSR_PEER_ATTRS: internal
+ * @NL80211_PMSR_PEER_ATTR_MAX: highest attribute number
+ */
+enum nl80211_peer_measurement_peer_attrs {
+ __NL80211_PMSR_PEER_ATTR_INVALID,
+
+ NL80211_PMSR_PEER_ATTR_ADDR,
+ NL80211_PMSR_PEER_ATTR_CHAN,
+ NL80211_PMSR_PEER_ATTR_REQ,
+ NL80211_PMSR_PEER_ATTR_RESP,
+
+ /* keep last */
+ NUM_NL80211_PMSR_PEER_ATTRS,
+ NL80211_PMSR_PEER_ATTR_MAX = NUM_NL80211_PMSR_PEER_ATTRS - 1,
+};
+
+/**
+ * enum nl80211_peer_measurement_attrs - peer measurement attributes
+ * @__NL80211_PMSR_ATTR_INVALID: invalid
+ *
+ * @NL80211_PMSR_ATTR_MAX_PEERS: u32 attribute used for capability
+ * advertisement only, indicates the maximum number of peers
+ * measurements can be done with in a single request
+ * @NL80211_PMSR_ATTR_REPORT_AP_TSF: flag attribute in capability
+ * indicating that the connected AP's TSF can be reported in
+ * measurement results
+ * @NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR: flag attribute in capability
+ * indicating that MAC address randomization is supported.
+ * @NL80211_PMSR_ATTR_TYPE_CAPA: capabilities reported by the device,
+ * this contains a nesting indexed by measurement type, and
+ * type-specific capabilities inside, which are from the enums
+ * named nl80211_peer_measurement_<type>_capa.
+ * @NL80211_PMSR_ATTR_PEERS: nested attribute, the nesting index is
+ * meaningless, just a list of peers to measure with, with the
+ * sub-attributes taken from
+ * &enum nl80211_peer_measurement_peer_attrs.
+ *
+ * @NUM_NL80211_PMSR_ATTR: internal
+ * @NL80211_PMSR_ATTR_MAX: highest attribute number
+ */
+enum nl80211_peer_measurement_attrs {
+ __NL80211_PMSR_ATTR_INVALID,
+
+ NL80211_PMSR_ATTR_MAX_PEERS,
+ NL80211_PMSR_ATTR_REPORT_AP_TSF,
+ NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR,
+ NL80211_PMSR_ATTR_TYPE_CAPA,
+ NL80211_PMSR_ATTR_PEERS,
+
+ /* keep last */
+ NUM_NL80211_PMSR_ATTR,
+ NL80211_PMSR_ATTR_MAX = NUM_NL80211_PMSR_ATTR - 1
+};
+
+/**
+ * enum nl80211_peer_measurement_ftm_capa - FTM capabilities
+ * @__NL80211_PMSR_FTM_CAPA_ATTR_INVALID: invalid
+ *
+ * @NL80211_PMSR_FTM_CAPA_ATTR_ASAP: flag attribute indicating ASAP mode
+ * is supported
+ * @NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP: flag attribute indicating non-ASAP
+ * mode is supported
+ * @NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI: flag attribute indicating if LCI
+ * data can be requested during the measurement
+ * @NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC: flag attribute indicating if civic
+ * location data can be requested during the measurement
+ * @NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES: u32 bitmap attribute of bits
+ * from &enum nl80211_preamble.
+ * @NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS: bitmap of values from
+ * &enum nl80211_chan_width indicating the supported channel
+ * bandwidths for FTM. Note that a higher channel bandwidth may be
+ * configured to allow for other measurements types with different
+ * bandwidth requirement in the same measurement.
+ * @NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT: u32 attribute indicating
+ * the maximum bursts exponent that can be used (if not present anything
+ * is valid)
+ * @NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST: u32 attribute indicating
+ * the maximum FTMs per burst (if not present anything is valid)
+ *
+ * @NUM_NL80211_PMSR_FTM_CAPA_ATTR: internal
+ * @NL80211_PMSR_FTM_CAPA_ATTR_MAX: highest attribute number
+ */
+enum nl80211_peer_measurement_ftm_capa {
+ __NL80211_PMSR_FTM_CAPA_ATTR_INVALID,
+
+ NL80211_PMSR_FTM_CAPA_ATTR_ASAP,
+ NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP,
+ NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI,
+ NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC,
+ NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES,
+ NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS,
+ NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT,
+ NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST,
+
+ /* keep last */
+ NUM_NL80211_PMSR_FTM_CAPA_ATTR,
+ NL80211_PMSR_FTM_CAPA_ATTR_MAX = NUM_NL80211_PMSR_FTM_CAPA_ATTR - 1
+};
+
+/**
+ * enum nl80211_peer_measurement_ftm_req - FTM request attributes
+ * @__NL80211_PMSR_FTM_REQ_ATTR_INVALID: invalid
+ *
+ * @NL80211_PMSR_FTM_REQ_ATTR_ASAP: ASAP mode requested (flag)
+ * @NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE: preamble type (see
+ * &enum nl80211_preamble), optional for DMG (u32)
+ * @NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP: number of bursts exponent as in
+ * 802.11-2016 9.4.2.168 "Fine Timing Measurement Parameters element"
+ * (u8, 0-15, optional with default 15 i.e. "no preference")
+ * @NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD: interval between bursts in units
+ * of 100ms (u16, optional with default 0)
+ * @NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION: burst duration, as in 802.11-2016
+ * Table 9-257 "Burst Duration field encoding" (u8, 0-15, optional with
+ * default 15 i.e. "no preference")
+ * @NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST: number of successful FTM frames
+ * requested per burst
+ * (u8, 0-31, optional with default 0 i.e. "no preference")
+ * @NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES: number of FTMR frame retries
+ * (u8, default 3)
+ * @NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI: request LCI data (flag)
+ * @NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC: request civic location data
+ * (flag)
+ *
+ * @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal
+ * @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number
+ */
+enum nl80211_peer_measurement_ftm_req {
+ __NL80211_PMSR_FTM_REQ_ATTR_INVALID,
+
+ NL80211_PMSR_FTM_REQ_ATTR_ASAP,
+ NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE,
+ NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP,
+ NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD,
+ NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION,
+ NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST,
+ NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES,
+ NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI,
+ NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC,
+
+ /* keep last */
+ NUM_NL80211_PMSR_FTM_REQ_ATTR,
+ NL80211_PMSR_FTM_REQ_ATTR_MAX = NUM_NL80211_PMSR_FTM_REQ_ATTR - 1
+};
+
+/**
+ * enum nl80211_peer_measurement_ftm_failure_reasons - FTM failure reasons
+ * @NL80211_PMSR_FTM_FAILURE_UNSPECIFIED: unspecified failure, not used
+ * @NL80211_PMSR_FTM_FAILURE_NO_RESPONSE: no response from the FTM responder
+ * @NL80211_PMSR_FTM_FAILURE_REJECTED: FTM responder rejected measurement
+ * @NL80211_PMSR_FTM_FAILURE_WRONG_CHANNEL: we already know the peer is
+ * on a different channel, so can't measure (if we didn't know, we'd
+ * try and get no response)
+ * @NL80211_PMSR_FTM_FAILURE_PEER_NOT_CAPABLE: peer can't actually do FTM
+ * @NL80211_PMSR_FTM_FAILURE_INVALID_TIMESTAMP: invalid T1/T4 timestamps
+ * received
+ * @NL80211_PMSR_FTM_FAILURE_PEER_BUSY: peer reports busy, you may retry
+ * later (see %NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME)
+ * @NL80211_PMSR_FTM_FAILURE_BAD_CHANGED_PARAMS: parameters were changed
+ * by the peer and are no longer supported
+ */
+enum nl80211_peer_measurement_ftm_failure_reasons {
+ NL80211_PMSR_FTM_FAILURE_UNSPECIFIED,
+ NL80211_PMSR_FTM_FAILURE_NO_RESPONSE,
+ NL80211_PMSR_FTM_FAILURE_REJECTED,
+ NL80211_PMSR_FTM_FAILURE_WRONG_CHANNEL,
+ NL80211_PMSR_FTM_FAILURE_PEER_NOT_CAPABLE,
+ NL80211_PMSR_FTM_FAILURE_INVALID_TIMESTAMP,
+ NL80211_PMSR_FTM_FAILURE_PEER_BUSY,
+ NL80211_PMSR_FTM_FAILURE_BAD_CHANGED_PARAMS,
+};
+
+/**
+ * enum nl80211_peer_measurement_ftm_resp - FTM response attributes
+ * @__NL80211_PMSR_FTM_RESP_ATTR_INVALID: invalid
+ *
+ * @NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON: FTM-specific failure reason
+ * (u32, optional)
+ * @NL80211_PMSR_FTM_RESP_ATTR_BURST_INDEX: optional, if bursts are reported
+ * as separate results then it will be the burst index 0...(N-1) and
+ * the top level will indicate partial results (u32)
+ * @NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_ATTEMPTS: number of FTM Request frames
+ * transmitted (u32, optional)
+ * @NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_SUCCESSES: number of FTM Request frames
+ * that were acknowleged (u32, optional)
+ * @NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME: retry time received from the
+ * busy peer (u32, seconds)
+ * @NL80211_PMSR_FTM_RESP_ATTR_NUM_BURSTS_EXP: actual number of bursts exponent
+ * used by the responder (similar to request, u8)
+ * @NL80211_PMSR_FTM_RESP_ATTR_BURST_DURATION: actual burst duration used by
+ * the responder (similar to request, u8)
+ * @NL80211_PMSR_FTM_RESP_ATTR_FTMS_PER_BURST: actual FTMs per burst used
+ * by the responder (similar to request, u8)
+ * @NL80211_PMSR_FTM_RESP_ATTR_RSSI_AVG: average RSSI across all FTM action
+ * frames (optional, s32, 1/2 dBm)
+ * @NL80211_PMSR_FTM_RESP_ATTR_RSSI_SPREAD: RSSI spread across all FTM action
+ * frames (optional, s32, 1/2 dBm)
+ * @NL80211_PMSR_FTM_RESP_ATTR_TX_RATE: bitrate we used for the response to the
+ * FTM action frame (optional, nested, using &enum nl80211_rate_info
+ * attributes)
+ * @NL80211_PMSR_FTM_RESP_ATTR_RX_RATE: bitrate the responder used for the FTM
+ * action frame (optional, nested, using &enum nl80211_rate_info attrs)
+ * @NL80211_PMSR_FTM_RESP_ATTR_RTT_AVG: average RTT (s64, picoseconds, optional
+ * but one of RTT/DIST must be present)
+ * @NL80211_PMSR_FTM_RESP_ATTR_RTT_VARIANCE: RTT variance (u64, ps^2, note that
+ * standard deviation is the square root of variance, optional)
+ * @NL80211_PMSR_FTM_RESP_ATTR_RTT_SPREAD: RTT spread (u64, picoseconds,
+ * optional)
+ * @NL80211_PMSR_FTM_RESP_ATTR_DIST_AVG: average distance (s64, mm, optional
+ * but one of RTT/DIST must be present)
+ * @NL80211_PMSR_FTM_RESP_ATTR_DIST_VARIANCE: distance variance (u64, mm^2, note
+ * that standard deviation is the square root of variance, optional)
+ * @NL80211_PMSR_FTM_RESP_ATTR_DIST_SPREAD: distance spread (u64, mm, optional)
+ * @NL80211_PMSR_FTM_RESP_ATTR_LCI: LCI data from peer (binary, optional);
+ * this is the contents of the Measurement Report Element (802.11-2016
+ * 9.4.2.22.1) starting with the Measurement Token, with Measurement
+ * Type 8.
+ * @NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC: civic location data from peer
+ * (binary, optional);
+ * this is the contents of the Measurement Report Element (802.11-2016
+ * 9.4.2.22.1) starting with the Measurement Token, with Measurement
+ * Type 11.
+ * @NL80211_PMSR_FTM_RESP_ATTR_PAD: ignore, for u64/s64 padding only
+ *
+ * @NUM_NL80211_PMSR_FTM_RESP_ATTR: internal
+ * @NL80211_PMSR_FTM_RESP_ATTR_MAX: highest attribute number
+ */
+enum nl80211_peer_measurement_ftm_resp {
+ __NL80211_PMSR_FTM_RESP_ATTR_INVALID,
+
+ NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON,
+ NL80211_PMSR_FTM_RESP_ATTR_BURST_INDEX,
+ NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_ATTEMPTS,
+ NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_SUCCESSES,
+ NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME,
+ NL80211_PMSR_FTM_RESP_ATTR_NUM_BURSTS_EXP,
+ NL80211_PMSR_FTM_RESP_ATTR_BURST_DURATION,
+ NL80211_PMSR_FTM_RESP_ATTR_FTMS_PER_BURST,
+ NL80211_PMSR_FTM_RESP_ATTR_RSSI_AVG,
+ NL80211_PMSR_FTM_RESP_ATTR_RSSI_SPREAD,
+ NL80211_PMSR_FTM_RESP_ATTR_TX_RATE,
+ NL80211_PMSR_FTM_RESP_ATTR_RX_RATE,
+ NL80211_PMSR_FTM_RESP_ATTR_RTT_AVG,
+ NL80211_PMSR_FTM_RESP_ATTR_RTT_VARIANCE,
+ NL80211_PMSR_FTM_RESP_ATTR_RTT_SPREAD,
+ NL80211_PMSR_FTM_RESP_ATTR_DIST_AVG,
+ NL80211_PMSR_FTM_RESP_ATTR_DIST_VARIANCE,
+ NL80211_PMSR_FTM_RESP_ATTR_DIST_SPREAD,
+ NL80211_PMSR_FTM_RESP_ATTR_LCI,
+ NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC,
+ NL80211_PMSR_FTM_RESP_ATTR_PAD,
+
+ /* keep last */
+ NUM_NL80211_PMSR_FTM_RESP_ATTR,
+ NL80211_PMSR_FTM_RESP_ATTR_MAX = NUM_NL80211_PMSR_FTM_RESP_ATTR - 1
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/src/eap_common/eap_eke_common.c b/src/eap_common/eap_eke_common.c
index 6217468..438baf1 100644
--- a/src/eap_common/eap_eke_common.c
+++ b/src/eap_common/eap_eke_common.c
@@ -161,7 +161,6 @@
int generator;
u8 gen;
const struct dh_group *dh;
- size_t pub_len, i;
generator = eap_eke_dh_generator(group);
dh = eap_eke_dh_group(group);
@@ -169,33 +168,11 @@
return -1;
gen = generator;
- /* x = random number 2 .. p-1 */
- if (random_get_bytes(ret_priv, dh->prime_len))
- return -1;
- if (os_memcmp(ret_priv, dh->prime, dh->prime_len) > 0) {
- /* Make sure private value is smaller than prime */
- ret_priv[0] = 0;
- }
- for (i = 0; i < dh->prime_len - 1; i++) {
- if (ret_priv[i])
- break;
- }
- if (i == dh->prime_len - 1 && (ret_priv[i] == 0 || ret_priv[i] == 1))
+ if (crypto_dh_init(gen, dh->prime, dh->prime_len, ret_priv,
+ ret_pub) < 0)
return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: DH private value",
ret_priv, dh->prime_len);
-
- /* y = g ^ x (mod p) */
- pub_len = dh->prime_len;
- if (crypto_mod_exp(&gen, 1, ret_priv, dh->prime_len,
- dh->prime, dh->prime_len, ret_pub, &pub_len) < 0)
- return -1;
- if (pub_len < dh->prime_len) {
- size_t pad = dh->prime_len - pub_len;
- os_memmove(ret_pub + pad, ret_pub, pub_len);
- os_memset(ret_pub, 0, pad);
- }
-
wpa_hexdump(MSG_DEBUG, "EAP-EKE: DH public value",
ret_pub, dh->prime_len);
@@ -421,8 +398,9 @@
/* SharedSecret = prf(0+, g ^ (x_s * x_p) (mod p)) */
len = dh->prime_len;
- if (crypto_mod_exp(peer_pub, dh->prime_len, dhpriv, dh->prime_len,
- dh->prime, dh->prime_len, modexp, &len) < 0)
+ if (crypto_dh_derive_secret(*dh->generator, dh->prime, dh->prime_len,
+ NULL, 0, dhpriv, dh->prime_len, peer_pub,
+ dh->prime_len, modexp, &len) < 0)
return -1;
if (len < dh->prime_len) {
size_t pad = dh->prime_len - len;
diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
index 67f8f70..6ca2c8b 100644
--- a/src/eap_common/eap_pwd_common.c
+++ b/src/eap_common/eap_pwd_common.c
@@ -8,11 +8,15 @@
#include "includes.h"
#include "common.h"
+#include "utils/const_time.h"
#include "crypto/sha256.h"
#include "crypto/crypto.h"
#include "eap_defs.h"
#include "eap_pwd_common.h"
+#define MAX_ECC_PRIME_LEN 66
+
+
/* The random function H(x) = HMAC-SHA256(0^32, x) */
struct crypto_hash * eap_pwd_h_init(void)
{
@@ -81,6 +85,49 @@
}
+static int eap_pwd_suitable_group(u16 num)
+{
+ /* Do not allow ECC groups with prime under 256 bits based on guidance
+ * for the similar design in SAE. */
+ return num == 19 || num == 20 || num == 21 ||
+ num == 28 || num == 29 || num == 30;
+}
+
+
+EAP_PWD_group * get_eap_pwd_group(u16 num)
+{
+ EAP_PWD_group *grp;
+
+ if (!eap_pwd_suitable_group(num)) {
+ wpa_printf(MSG_INFO, "EAP-pwd: unsuitable group %u", num);
+ return NULL;
+ }
+ grp = os_zalloc(sizeof(EAP_PWD_group));
+ if (!grp)
+ return NULL;
+ grp->group = crypto_ec_init(num);
+ if (!grp->group) {
+ wpa_printf(MSG_INFO, "EAP-pwd: unable to create EC group");
+ os_free(grp);
+ return NULL;
+ }
+
+ grp->group_num = num;
+ wpa_printf(MSG_INFO, "EAP-pwd: provisioned group %d", num);
+
+ return grp;
+}
+
+
+static void buf_shift_right(u8 *buf, size_t len, size_t bits)
+{
+ size_t i;
+ for (i = len - 1; i > 0; i--)
+ buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits);
+ buf[0] >>= bits;
+}
+
+
/*
* compute a "random" secret point on an elliptic curve based
* on the password and identities.
@@ -91,105 +138,82 @@
const u8 *id_peer, size_t id_peer_len,
const u8 *token)
{
- BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL;
+ struct crypto_bignum *qr = NULL, *qnr = NULL, *one = NULL;
+ struct crypto_bignum *qr_or_qnr = NULL;
+ u8 qr_bin[MAX_ECC_PRIME_LEN];
+ u8 qnr_bin[MAX_ECC_PRIME_LEN];
+ u8 qr_or_qnr_bin[MAX_ECC_PRIME_LEN];
+ u8 x_bin[MAX_ECC_PRIME_LEN];
+ u8 prime_bin[MAX_ECC_PRIME_LEN];
+ struct crypto_bignum *tmp1 = NULL, *tmp2 = NULL, *pm1 = NULL;
struct crypto_hash *hash;
unsigned char pwe_digest[SHA256_MAC_LEN], *prfbuf = NULL, ctr;
- int nid, is_odd, ret = 0;
- size_t primebytelen, primebitlen;
+ int ret = 0, check, res;
+ u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
+ * mask */
+ size_t primebytelen = 0, primebitlen;
+ struct crypto_bignum *x_candidate = NULL;
+ const struct crypto_bignum *prime;
+ u8 mask, found_ctr = 0, is_odd = 0;
- switch (num) { /* from IANA registry for IKE D-H groups */
- case 19:
- nid = NID_X9_62_prime256v1;
- break;
- case 20:
- nid = NID_secp384r1;
- break;
- case 21:
- nid = NID_secp521r1;
- break;
-#ifndef OPENSSL_IS_BORINGSSL
- case 25:
- nid = NID_X9_62_prime192v1;
- break;
-#endif /* OPENSSL_IS_BORINGSSL */
- case 26:
- nid = NID_secp224r1;
- break;
-#ifdef NID_brainpoolP224r1
- case 27:
- nid = NID_brainpoolP224r1;
- break;
-#endif /* NID_brainpoolP224r1 */
-#ifdef NID_brainpoolP256r1
- case 28:
- nid = NID_brainpoolP256r1;
- break;
-#endif /* NID_brainpoolP256r1 */
-#ifdef NID_brainpoolP384r1
- case 29:
- nid = NID_brainpoolP384r1;
- break;
-#endif /* NID_brainpoolP384r1 */
-#ifdef NID_brainpoolP512r1
- case 30:
- nid = NID_brainpoolP512r1;
- break;
-#endif /* NID_brainpoolP512r1 */
- default:
- wpa_printf(MSG_INFO, "EAP-pwd: unsupported group %d", num);
+ if (grp->pwe)
return -1;
- }
- grp->pwe = NULL;
- grp->order = NULL;
- grp->prime = NULL;
+ os_memset(x_bin, 0, sizeof(x_bin));
- if ((grp->group = EC_GROUP_new_by_curve_name(nid)) == NULL) {
- wpa_printf(MSG_INFO, "EAP-pwd: unable to create EC_GROUP");
- goto fail;
- }
-
- if (((rnd = BN_new()) == NULL) ||
- ((cofactor = BN_new()) == NULL) ||
- ((grp->pwe = EC_POINT_new(grp->group)) == NULL) ||
- ((grp->order = BN_new()) == NULL) ||
- ((grp->prime = BN_new()) == NULL) ||
- ((x_candidate = BN_new()) == NULL)) {
+ prime = crypto_ec_get_prime(grp->group);
+ primebitlen = crypto_ec_prime_len_bits(grp->group);
+ primebytelen = crypto_ec_prime_len(grp->group);
+ if (crypto_bignum_to_bin(prime, prime_bin, sizeof(prime_bin),
+ primebytelen) < 0)
+ return -1;
+ grp->pwe = crypto_ec_point_init(grp->group);
+ tmp1 = crypto_bignum_init();
+ pm1 = crypto_bignum_init();
+ one = crypto_bignum_init_set((const u8 *) "\x01", 1);
+ if (!grp->pwe || !tmp1 || !pm1 || !one) {
wpa_printf(MSG_INFO, "EAP-pwd: unable to create bignums");
goto fail;
}
- if (!EC_GROUP_get_curve_GFp(grp->group, grp->prime, NULL, NULL, NULL))
- {
- wpa_printf(MSG_INFO, "EAP-pwd: unable to get prime for GFp "
- "curve");
- goto fail;
- }
- if (!EC_GROUP_get_order(grp->group, grp->order, NULL)) {
- wpa_printf(MSG_INFO, "EAP-pwd: unable to get order for curve");
- goto fail;
- }
- if (!EC_GROUP_get_cofactor(grp->group, cofactor, NULL)) {
- wpa_printf(MSG_INFO, "EAP-pwd: unable to get cofactor for "
- "curve");
- goto fail;
- }
- primebitlen = BN_num_bits(grp->prime);
- primebytelen = BN_num_bytes(grp->prime);
if ((prfbuf = os_malloc(primebytelen)) == NULL) {
wpa_printf(MSG_INFO, "EAP-pwd: unable to malloc space for prf "
"buffer");
goto fail;
}
+ if (crypto_bignum_sub(prime, one, pm1) < 0)
+ goto fail;
+
+ /* get a random quadratic residue and nonresidue */
+ while (!qr || !qnr) {
+ if (crypto_bignum_rand(tmp1, prime) < 0)
+ goto fail;
+ res = crypto_bignum_legendre(tmp1, prime);
+ if (!qr && res == 1) {
+ qr = tmp1;
+ tmp1 = crypto_bignum_init();
+ } else if (!qnr && res == -1) {
+ qnr = tmp1;
+ tmp1 = crypto_bignum_init();
+ }
+ if (!tmp1)
+ goto fail;
+ }
+ if (crypto_bignum_to_bin(qr, qr_bin, sizeof(qr_bin),
+ primebytelen) < 0 ||
+ crypto_bignum_to_bin(qnr, qnr_bin, sizeof(qnr_bin),
+ primebytelen) < 0)
+ goto fail;
+
os_memset(prfbuf, 0, primebytelen);
ctr = 0;
- while (1) {
- if (ctr > 30) {
- wpa_printf(MSG_INFO, "EAP-pwd: unable to find random "
- "point on curve for group %d, something's "
- "fishy", num);
- goto fail;
- }
+
+ /*
+ * Run through the hunting-and-pecking loop 40 times to mask the time
+ * necessary to find PWE. The odds of PWE not being found in 40 loops is
+ * roughly 1 in 1 trillion.
+ */
+ while (ctr < 40) {
ctr++;
/*
@@ -207,114 +231,155 @@
eap_pwd_h_update(hash, &ctr, sizeof(ctr));
eap_pwd_h_final(hash, pwe_digest);
- BN_bin2bn(pwe_digest, SHA256_MAC_LEN, rnd);
-
+ is_odd = const_time_select_u8(
+ found, is_odd, pwe_digest[SHA256_MAC_LEN - 1] & 0x01);
if (eap_pwd_kdf(pwe_digest, SHA256_MAC_LEN,
(u8 *) "EAP-pwd Hunting And Pecking",
os_strlen("EAP-pwd Hunting And Pecking"),
prfbuf, primebitlen) < 0)
goto fail;
-
- BN_bin2bn(prfbuf, primebytelen, x_candidate);
-
- /*
- * eap_pwd_kdf() returns a string of bits 0..primebitlen but
- * BN_bin2bn will treat that string of bits as a big endian
- * number. If the primebitlen is not an even multiple of 8
- * then excessive bits-- those _after_ primebitlen-- so now
- * we have to shift right the amount we masked off.
- */
if (primebitlen % 8)
- BN_rshift(x_candidate, x_candidate,
- (8 - (primebitlen % 8)));
-
- if (BN_ucmp(x_candidate, grp->prime) >= 0)
+ buf_shift_right(prfbuf, primebytelen,
+ 8 - primebitlen % 8);
+ if (const_time_memcmp(prfbuf, prime_bin, primebytelen) >= 0)
continue;
- wpa_hexdump(MSG_DEBUG, "EAP-pwd: x_candidate",
- prfbuf, primebytelen);
-
- /*
- * need to unambiguously identify the solution, if there is
- * one...
- */
- if (BN_is_odd(rnd))
- is_odd = 1;
- else
- is_odd = 0;
-
- /*
- * solve the quadratic equation, if it's not solvable then we
- * don't have a point
- */
- if (!EC_POINT_set_compressed_coordinates_GFp(grp->group,
- grp->pwe,
- x_candidate,
- is_odd, NULL))
- continue;
- /*
- * If there's a solution to the equation then the point must be
- * on the curve so why check again explicitly? OpenSSL code
- * says this is required by X9.62. We're not X9.62 but it can't
- * hurt just to be sure.
- */
- if (!EC_POINT_is_on_curve(grp->group, grp->pwe, NULL)) {
- wpa_printf(MSG_INFO, "EAP-pwd: point is not on curve");
- continue;
+ crypto_bignum_deinit(x_candidate, 1);
+ x_candidate = crypto_bignum_init_set(prfbuf, primebytelen);
+ if (!x_candidate) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: unable to create x_candidate");
+ goto fail;
}
- if (BN_cmp(cofactor, BN_value_one())) {
- /* make sure the point is not in a small sub-group */
- if (!EC_POINT_mul(grp->group, grp->pwe, NULL, grp->pwe,
- cofactor, NULL)) {
- wpa_printf(MSG_INFO, "EAP-pwd: cannot "
- "multiply generator by order");
- continue;
- }
- if (EC_POINT_is_at_infinity(grp->group, grp->pwe)) {
- wpa_printf(MSG_INFO, "EAP-pwd: point is at "
- "infinity");
- continue;
- }
- }
- /* if we got here then we have a new generator. */
- break;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: x_candidate",
+ prfbuf, primebytelen);
+ const_time_select_bin(found, x_bin, prfbuf, primebytelen,
+ x_bin);
+
+ /*
+ * compute y^2 using the equation of the curve
+ *
+ * y^2 = x^3 + ax + b
+ */
+ crypto_bignum_deinit(tmp2, 1);
+ tmp2 = crypto_ec_point_compute_y_sqr(grp->group, x_candidate);
+ if (!tmp2)
+ goto fail;
+
+ /*
+ * mask tmp2 so doing legendre won't leak timing info
+ *
+ * tmp1 is a random number between 1 and p-1
+ */
+ if (crypto_bignum_rand(tmp1, pm1) < 0 ||
+ crypto_bignum_mulmod(tmp2, tmp1, prime, tmp2) < 0 ||
+ crypto_bignum_mulmod(tmp2, tmp1, prime, tmp2) < 0)
+ goto fail;
+
+ /*
+ * Now tmp2 (y^2) is masked, all values between 1 and p-1
+ * are equally probable. Multiplying by r^2 does not change
+ * whether or not tmp2 is a quadratic residue, just masks it.
+ *
+ * Flip a coin, multiply by the random quadratic residue or the
+ * random quadratic nonresidue and record heads or tails.
+ */
+ mask = const_time_eq_u8(crypto_bignum_is_odd(tmp1), 1);
+ check = const_time_select_s8(mask, 1, -1);
+ const_time_select_bin(mask, qr_bin, qnr_bin, primebytelen,
+ qr_or_qnr_bin);
+ crypto_bignum_deinit(qr_or_qnr, 1);
+ qr_or_qnr = crypto_bignum_init_set(qr_or_qnr_bin, primebytelen);
+ if (!qr_or_qnr ||
+ crypto_bignum_mulmod(tmp2, qr_or_qnr, prime, tmp2) < 0)
+ goto fail;
+
+ /*
+ * Now it's safe to do legendre, if check is 1 then it's
+ * a straightforward test (multiplying by qr does not
+ * change result), if check is -1 then it's the opposite test
+ * (multiplying a qr by qnr would make a qnr).
+ */
+ res = crypto_bignum_legendre(tmp2, prime);
+ if (res == -2)
+ goto fail;
+ mask = const_time_eq(res, check);
+ found_ctr = const_time_select_u8(found, found_ctr, ctr);
+ found |= mask;
}
- wpa_printf(MSG_DEBUG, "EAP-pwd: found a PWE in %d tries", ctr);
- grp->group_num = num;
+ if (found == 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: unable to find random point on curve for group %d, something's fishy",
+ num);
+ goto fail;
+ }
+
+ /*
+ * We know x_candidate is a quadratic residue so set it here.
+ */
+ crypto_bignum_deinit(x_candidate, 1);
+ x_candidate = crypto_bignum_init_set(x_bin, primebytelen);
+ if (!x_candidate ||
+ crypto_ec_point_solve_y_coord(grp->group, grp->pwe, x_candidate,
+ is_odd) != 0) {
+ wpa_printf(MSG_INFO, "EAP-pwd: Could not solve for y");
+ goto fail;
+ }
+
+ /*
+ * If there's a solution to the equation then the point must be on the
+ * curve so why check again explicitly? OpenSSL code says this is
+ * required by X9.62. We're not X9.62 but it can't hurt just to be sure.
+ */
+ if (!crypto_ec_point_is_on_curve(grp->group, grp->pwe)) {
+ wpa_printf(MSG_INFO, "EAP-pwd: point is not on curve");
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-pwd: found a PWE in %02d tries", found_ctr);
+
if (0) {
fail:
- EC_GROUP_free(grp->group);
- grp->group = NULL;
- EC_POINT_clear_free(grp->pwe);
+ crypto_ec_point_deinit(grp->pwe, 1);
grp->pwe = NULL;
- BN_clear_free(grp->order);
- grp->order = NULL;
- BN_clear_free(grp->prime);
- grp->prime = NULL;
ret = 1;
}
/* cleanliness and order.... */
- BN_clear_free(cofactor);
- BN_clear_free(x_candidate);
- BN_clear_free(rnd);
- os_free(prfbuf);
+ crypto_bignum_deinit(x_candidate, 1);
+ crypto_bignum_deinit(pm1, 0);
+ crypto_bignum_deinit(tmp1, 1);
+ crypto_bignum_deinit(tmp2, 1);
+ crypto_bignum_deinit(qr, 1);
+ crypto_bignum_deinit(qnr, 1);
+ crypto_bignum_deinit(qr_or_qnr, 1);
+ crypto_bignum_deinit(one, 0);
+ bin_clear_free(prfbuf, primebytelen);
+ os_memset(qr_bin, 0, sizeof(qr_bin));
+ os_memset(qnr_bin, 0, sizeof(qnr_bin));
+ os_memset(qr_or_qnr_bin, 0, sizeof(qr_or_qnr_bin));
+ os_memset(pwe_digest, 0, sizeof(pwe_digest));
return ret;
}
-int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k,
- const BIGNUM *peer_scalar, const BIGNUM *server_scalar,
+int compute_keys(EAP_PWD_group *grp, const struct crypto_bignum *k,
+ const struct crypto_bignum *peer_scalar,
+ const struct crypto_bignum *server_scalar,
const u8 *confirm_peer, const u8 *confirm_server,
const u32 *ciphersuite, u8 *msk, u8 *emsk, u8 *session_id)
{
struct crypto_hash *hash;
u8 mk[SHA256_MAC_LEN], *cruft;
u8 msk_emsk[EAP_MSK_LEN + EAP_EMSK_LEN];
- int offset;
+ size_t prime_len, order_len;
- if ((cruft = os_malloc(BN_num_bytes(grp->prime))) == NULL)
+ prime_len = crypto_ec_prime_len(grp->group);
+ order_len = crypto_ec_order_len(grp->group);
+
+ cruft = os_malloc(prime_len);
+ if (!cruft)
return -1;
/*
@@ -328,14 +393,10 @@
return -1;
}
eap_pwd_h_update(hash, (const u8 *) ciphersuite, sizeof(u32));
- offset = BN_num_bytes(grp->order) - BN_num_bytes(peer_scalar);
- os_memset(cruft, 0, BN_num_bytes(grp->prime));
- BN_bn2bin(peer_scalar, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->order));
- offset = BN_num_bytes(grp->order) - BN_num_bytes(server_scalar);
- os_memset(cruft, 0, BN_num_bytes(grp->prime));
- BN_bn2bin(server_scalar, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->order));
+ crypto_bignum_to_bin(peer_scalar, cruft, order_len, order_len);
+ eap_pwd_h_update(hash, cruft, order_len);
+ crypto_bignum_to_bin(server_scalar, cruft, order_len, order_len);
+ eap_pwd_h_update(hash, cruft, order_len);
eap_pwd_h_final(hash, &session_id[1]);
/* then compute MK = H(k | confirm-peer | confirm-server) */
@@ -344,10 +405,8 @@
os_free(cruft);
return -1;
}
- offset = BN_num_bytes(grp->prime) - BN_num_bytes(k);
- os_memset(cruft, 0, BN_num_bytes(grp->prime));
- BN_bn2bin(k, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->prime));
+ crypto_bignum_to_bin(k, cruft, prime_len, prime_len);
+ eap_pwd_h_update(hash, cruft, prime_len);
os_free(cruft);
eap_pwd_h_update(hash, confirm_peer, SHA256_MAC_LEN);
eap_pwd_h_update(hash, confirm_server, SHA256_MAC_LEN);
@@ -365,3 +424,108 @@
return 1;
}
+
+
+static int eap_pwd_element_coord_ok(const struct crypto_bignum *prime,
+ const u8 *buf, size_t len)
+{
+ struct crypto_bignum *val;
+ int ok = 1;
+
+ val = crypto_bignum_init_set(buf, len);
+ if (!val || crypto_bignum_is_zero(val) ||
+ crypto_bignum_cmp(val, prime) >= 0)
+ ok = 0;
+ crypto_bignum_deinit(val, 0);
+ return ok;
+}
+
+
+struct crypto_ec_point * eap_pwd_get_element(EAP_PWD_group *group,
+ const u8 *buf)
+{
+ struct crypto_ec_point *element;
+ const struct crypto_bignum *prime;
+ size_t prime_len;
+
+ prime = crypto_ec_get_prime(group->group);
+ prime_len = crypto_ec_prime_len(group->group);
+
+ /* RFC 5931, 2.8.5.2.2: 0 < x,y < p */
+ if (!eap_pwd_element_coord_ok(prime, buf, prime_len) ||
+ !eap_pwd_element_coord_ok(prime, buf + prime_len, prime_len)) {
+ wpa_printf(MSG_INFO, "EAP-pwd: Invalid coordinate in element");
+ return NULL;
+ }
+
+ element = crypto_ec_point_from_bin(group->group, buf);
+ if (!element) {
+ wpa_printf(MSG_INFO, "EAP-pwd: EC point from element failed");
+ return NULL;
+ }
+
+ /* RFC 5931, 2.8.5.2.2: on curve and not the point at infinity */
+ if (!crypto_ec_point_is_on_curve(group->group, element) ||
+ crypto_ec_point_is_at_infinity(group->group, element)) {
+ wpa_printf(MSG_INFO, "EAP-pwd: Invalid element");
+ goto fail;
+ }
+
+out:
+ return element;
+fail:
+ crypto_ec_point_deinit(element, 0);
+ element = NULL;
+ goto out;
+}
+
+
+struct crypto_bignum * eap_pwd_get_scalar(EAP_PWD_group *group, const u8 *buf)
+{
+ struct crypto_bignum *scalar;
+ const struct crypto_bignum *order;
+ size_t order_len;
+
+ order = crypto_ec_get_order(group->group);
+ order_len = crypto_ec_order_len(group->group);
+
+ /* RFC 5931, 2.8.5.2: 1 < scalar < r */
+ scalar = crypto_bignum_init_set(buf, order_len);
+ if (!scalar || crypto_bignum_is_zero(scalar) ||
+ crypto_bignum_is_one(scalar) ||
+ crypto_bignum_cmp(scalar, order) >= 0) {
+ wpa_printf(MSG_INFO, "EAP-pwd: received scalar is invalid");
+ crypto_bignum_deinit(scalar, 0);
+ scalar = NULL;
+ }
+
+ return scalar;
+}
+
+
+int eap_pwd_get_rand_mask(EAP_PWD_group *group, struct crypto_bignum *_rand,
+ struct crypto_bignum *_mask,
+ struct crypto_bignum *scalar)
+{
+ const struct crypto_bignum *order;
+ int count;
+
+ order = crypto_ec_get_order(group->group);
+
+ /* Select two random values rand,mask such that 1 < rand,mask < r and
+ * rand + mask mod r > 1. */
+ for (count = 0; count < 100; count++) {
+ if (crypto_bignum_rand(_rand, order) == 0 &&
+ !crypto_bignum_is_zero(_rand) &&
+ crypto_bignum_rand(_mask, order) == 0 &&
+ !crypto_bignum_is_zero(_mask) &&
+ crypto_bignum_add(_rand, _mask, scalar) == 0 &&
+ crypto_bignum_mod(scalar, order, scalar) == 0 &&
+ !crypto_bignum_is_zero(scalar) &&
+ !crypto_bignum_is_one(scalar))
+ return 0;
+ }
+
+ wpa_printf(MSG_INFO, "EAP-pwd: unable to get randomness");
+ return -1;
+}
diff --git a/src/eap_common/eap_pwd_common.h b/src/eap_common/eap_pwd_common.h
index a0d717e..c48acee 100644
--- a/src/eap_common/eap_pwd_common.h
+++ b/src/eap_common/eap_pwd_common.h
@@ -9,20 +9,14 @@
#ifndef EAP_PWD_COMMON_H
#define EAP_PWD_COMMON_H
-#include <openssl/bn.h>
-#include <openssl/ec.h>
-#include <openssl/evp.h>
-
/*
* definition of a finite cyclic group
* TODO: support one based on a prime field
*/
typedef struct group_definition_ {
u16 group_num;
- EC_GROUP *group;
- EC_POINT *pwe;
- BIGNUM *order;
- BIGNUM *prime;
+ struct crypto_ec *group;
+ struct crypto_ec_point *pwe;
} EAP_PWD_group;
/*
@@ -52,21 +46,32 @@
u8 prep;
#define EAP_PWD_PREP_NONE 0
#define EAP_PWD_PREP_MS 1
+#define EAP_PWD_PREP_SSHA1 3
+#define EAP_PWD_PREP_SSHA256 4
+#define EAP_PWD_PREP_SSHA512 5
u8 identity[0]; /* length inferred from payload */
} STRUCT_PACKED;
/* common routines */
+EAP_PWD_group * get_eap_pwd_group(u16 num);
int compute_password_element(EAP_PWD_group *grp, u16 num,
const u8 *password, size_t password_len,
const u8 *id_server, size_t id_server_len,
const u8 *id_peer, size_t id_peer_len,
const u8 *token);
-int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k,
- const BIGNUM *peer_scalar, const BIGNUM *server_scalar,
+int compute_keys(EAP_PWD_group *grp, const struct crypto_bignum *k,
+ const struct crypto_bignum *peer_scalar,
+ const struct crypto_bignum *server_scalar,
const u8 *confirm_peer, const u8 *confirm_server,
const u32 *ciphersuite, u8 *msk, u8 *emsk, u8 *session_id);
struct crypto_hash * eap_pwd_h_init(void);
void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len);
void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest);
+struct crypto_ec_point * eap_pwd_get_element(EAP_PWD_group *group,
+ const u8 *buf);
+struct crypto_bignum * eap_pwd_get_scalar(EAP_PWD_group *group, const u8 *buf);
+int eap_pwd_get_rand_mask(EAP_PWD_group *group, struct crypto_bignum *_rand,
+ struct crypto_bignum *_mask,
+ struct crypto_bignum *scalar);
#endif /* EAP_PWD_COMMON_H */
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 52b0491..974c475 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -94,6 +94,7 @@
sm->eapol_cb->notify_status(sm->eapol_ctx, status, parameter);
}
+
static void eap_report_error(struct eap_sm *sm, int error_code)
{
wpa_printf(MSG_DEBUG, "EAP: Error notification: %d", error_code);
@@ -101,6 +102,7 @@
sm->eapol_cb->notify_eap_error(sm->eapol_ctx, error_code);
}
+
static void eap_sm_free_key(struct eap_sm *sm)
{
if (sm->eapKeyData) {
@@ -668,6 +670,9 @@
}
+/* Note: If ext_session and/or ext_emsk are passed to this function, they are
+ * expected to point to allocated memory and those allocations will be freed
+ * unconditionally. */
void eap_peer_erp_init(struct eap_sm *sm, u8 *ext_session_id,
size_t ext_session_id_len, u8 *ext_emsk,
size_t ext_emsk_len)
@@ -686,7 +691,7 @@
realm = eap_home_realm(sm);
if (!realm)
- return;
+ goto fail;
realm_len = os_strlen(realm);
wpa_printf(MSG_DEBUG, "EAP: Realm for ERP keyName-NAI: %s", realm);
eap_erp_remove_keys_realm(sm, realm);
@@ -773,7 +778,10 @@
dl_list_add(&sm->erp_keys, &erp->list);
erp = NULL;
fail:
- bin_clear_free(emsk, emsk_len);
+ if (ext_emsk)
+ bin_clear_free(ext_emsk, ext_emsk_len);
+ else
+ bin_clear_free(emsk, emsk_len);
bin_clear_free(ext_session_id, ext_session_id_len);
bin_clear_free(erp, sizeof(*erp));
os_free(realm);
@@ -1940,7 +1948,6 @@
const struct eap_hdr *hdr;
size_t plen;
const u8 *pos;
- int error_code;
sm->rxReq = sm->rxResp = sm->rxSuccess = sm->rxFailure = FALSE;
sm->reqId = 0;
@@ -2028,6 +2035,8 @@
/* Get the error code from method */
if (sm->m && sm->m->get_error_code) {
+ int error_code;
+
error_code = sm->m->get_error_code(sm->eap_method_priv);
if (error_code != NO_EAP_METHOD_ERROR)
eap_report_error(sm, error_code);
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index 679f101..a444141 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -1528,14 +1528,16 @@
return key;
}
+
static int eap_aka_get_error_code(void *priv)
{
struct eap_aka_data *data = priv;
+ int current_data_error;
if (!data)
return NO_EAP_METHOD_ERROR;
- int current_data_error = data->error_code;
+ current_data_error = data->error_code;
/* Now reset for next transaction */
data->error_code = NO_EAP_METHOD_ERROR;
@@ -1543,6 +1545,7 @@
return current_data_error;
}
+
int eap_peer_aka_register(void)
{
struct eap_method *eap;
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index d416afd..3a88f2a 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -101,7 +101,7 @@
* certificate store (My user account) is used, whereas computer store
* (Computer account) is used when running wpasvc as a service.
*/
- u8 *ca_cert;
+ char *ca_cert;
/**
* ca_path - Directory path for CA certificate files (PEM)
@@ -112,7 +112,7 @@
* these certificates are added to the list of trusted CAs. ca_cert
* may also be included in that case, but it is not required.
*/
- u8 *ca_path;
+ char *ca_path;
/**
* client_cert - File path to client certificate file (PEM/DER)
@@ -126,7 +126,7 @@
* Alternatively, a named configuration blob can be used by setting
* this to blob://blob_name.
*/
- u8 *client_cert;
+ char *client_cert;
/**
* private_key - File path to client private key file (PEM/DER/PFX)
@@ -153,7 +153,7 @@
* Alternatively, a named configuration blob can be used by setting
* this to blob://blob_name.
*/
- u8 *private_key;
+ char *private_key;
/**
* private_key_passwd - Password for private key file
@@ -178,7 +178,7 @@
* Alternatively, a named configuration blob can be used by setting
* this to blob://blob_name.
*/
- u8 *dh_file;
+ char *dh_file;
/**
* subject_match - Constraint for server certificate subject
@@ -194,7 +194,49 @@
* to do a suffix match against a possible domain name in the CN entry.
* For such a use case, domain_suffix_match should be used instead.
*/
- u8 *subject_match;
+ char *subject_match;
+
+ /**
+ * check_cert_subject - Constraint for server certificate subject fields
+ *
+ * If check_cert_subject is set, the value of every field will be
+ * checked against the DN of the subject in the authentication server
+ * certificate. If the values do not match, the certificate verification
+ * will fail, rejecting the server. This option allows wpa_supplicant to
+ * match every individual field in the right order against the DN of the
+ * subject in the server certificate.
+ *
+ * For example, check_cert_subject=C=US/O=XX/OU=ABC/OU=XYZ/CN=1234 will
+ * check every individual DN field of the subject in the server
+ * certificate. If OU=XYZ comes first in terms of the order in the
+ * server certificate (DN field of server certificate
+ * C=US/O=XX/OU=XYZ/OU=ABC/CN=1234), wpa_supplicant will reject the
+ * server because the order of 'OU' is not matching the specified string
+ * in check_cert_subject.
+ *
+ * This option also allows '*' as a wildcard. This option has some
+ * limitation.
+ * It can only be used as per the following example.
+ *
+ * For example, check_cert_subject=C=US/O=XX/OU=Production* and we have
+ * two servers and DN of the subject in the first server certificate is
+ * (C=US/O=XX/OU=Production Unit) and DN of the subject in the second
+ * server is (C=US/O=XX/OU=Production Factory). In this case,
+ * wpa_supplicant will allow both servers because the value of 'OU'
+ * field in both server certificates matches 'OU' value in
+ * 'check_cert_subject' up to 'wildcard'.
+ *
+ * (Allow all servers, e.g., check_cert_subject=*)
+ */
+ char *check_cert_subject;
+
+ /**
+ * check_cert_subject2 - Constraint for server certificate subject fields
+ *
+ * This field is like check_cert_subject, but used for phase 2 (inside
+ * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ */
+ char *check_cert_subject2;
/**
* altsubject_match - Constraint for server certificate alt. subject
@@ -212,23 +254,26 @@
*
* Following types are supported: EMAIL, DNS, URI
*/
- u8 *altsubject_match;
+ char *altsubject_match;
/**
* domain_suffix_match - Constraint for server domain name
*
- * If set, this FQDN is used as a suffix match requirement for the
- * server certificate in SubjectAltName dNSName element(s). If a
- * matching dNSName is found, this constraint is met. If no dNSName
- * values are present, this constraint is matched against SubjectName CN
- * using same suffix match comparison. Suffix match here means that the
- * host/domain name is compared one label at a time starting from the
- * top-level domain and all the labels in domain_suffix_match shall be
- * included in the certificate. The certificate may include additional
- * sub-level labels in addition to the required labels.
+ * If set, this semicolon deliminated list of FQDNs is used as suffix
+ * match requirements for the server certificate in SubjectAltName
+ * dNSName element(s). If a matching dNSName is found against any of the
+ * specified values, this constraint is met. If no dNSName values are
+ * present, this constraint is matched against SubjectName CN using same
+ * suffix match comparison. Suffix match here means that the host/domain
+ * name is compared case-insentively one label at a time starting from
+ * the top-level domain and all the labels in domain_suffix_match shall
+ * be included in the certificate. The certificate may include
+ * additional sub-level labels in addition to the required labels.
*
* For example, domain_suffix_match=example.com would match
- * test.example.com but would not match test-example.com.
+ * test.example.com but would not match test-example.com. Multiple
+ * match options can be specified in following manner:
+ * example.org;example.com.
*/
char *domain_suffix_match;
@@ -244,6 +289,12 @@
* no subdomains or wildcard matches are allowed. Case-insensitive
* comparison is used, so "Example.com" matches "example.com", but would
* not match "test.Example.com".
+ *
+ * More than one match string can be provided by using semicolons to
+ * separate the strings (e.g., example.org;example.com). When multiple
+ * strings are specified, a match with any one of the values is
+ * considered a sufficient match for the certificate, i.e., the
+ * conditions are ORed together.
*/
char *domain_match;
@@ -263,7 +314,7 @@
* Alternatively, a named configuration blob can be used by setting
* this to blob://blob_name.
*/
- u8 *ca_cert2;
+ char *ca_cert2;
/**
* ca_path2 - Directory path for CA certificate files (PEM) (Phase 2)
@@ -277,7 +328,7 @@
* This field is like ca_path, but used for phase 2 (inside
* EAP-TTLS/PEAP/FAST tunnel) authentication.
*/
- u8 *ca_path2;
+ char *ca_path2;
/**
* client_cert2 - File path to client certificate file
@@ -290,7 +341,7 @@
* Alternatively, a named configuration blob can be used by setting
* this to blob://blob_name.
*/
- u8 *client_cert2;
+ char *client_cert2;
/**
* private_key2 - File path to client private key file
@@ -303,7 +354,7 @@
* Alternatively, a named configuration blob can be used by setting
* this to blob://blob_name.
*/
- u8 *private_key2;
+ char *private_key2;
/**
* private_key2_passwd - Password for private key file
@@ -324,7 +375,7 @@
* Alternatively, a named configuration blob can be used by setting
* this to blob://blob_name.
*/
- u8 *dh_file2;
+ char *dh_file2;
/**
* subject_match2 - Constraint for server certificate subject
@@ -332,7 +383,7 @@
* This field is like subject_match, but used for phase 2 (inside
* EAP-TTLS/PEAP/FAST tunnel) authentication.
*/
- u8 *subject_match2;
+ char *subject_match2;
/**
* altsubject_match2 - Constraint for server certificate alt. subject
@@ -340,7 +391,7 @@
* This field is like altsubject_match, but used for phase 2 (inside
* EAP-TTLS/PEAP/FAST tunnel) authentication.
*/
- u8 *altsubject_match2;
+ char *altsubject_match2;
/**
* domain_suffix_match2 - Constraint for server domain name
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 74cec7d..94ce57d 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -250,8 +250,8 @@
os_memset(data->key_data, 0, EAP_FAST_KEY_LEN);
os_memset(data->emsk, 0, EAP_EMSK_LEN);
os_free(data->session_id);
- wpabuf_free(data->pending_phase2_req);
- wpabuf_free(data->pending_resp);
+ wpabuf_clear_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_resp);
os_free(data);
}
@@ -486,7 +486,7 @@
(config->pending_req_identity || config->pending_req_password ||
config->pending_req_otp || config->pending_req_new_password ||
config->pending_req_sim)) {
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
} else if (*resp == NULL)
return -1;
@@ -801,7 +801,7 @@
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
data->phase2_success = 0;
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return NULL;
}
@@ -815,7 +815,7 @@
} else {
wpa_printf(MSG_ERROR, "EAP-FAST: Failed to derive "
"Session-Id");
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return NULL;
}
}
@@ -1150,7 +1150,7 @@
wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt a Phase 2 "
"frame");
}
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return 0;
}
@@ -1328,14 +1328,14 @@
wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 "
"TLV frame (len=%lu)",
(unsigned long) wpabuf_len(in_decrypted));
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
return -1;
}
res = eap_fast_process_decrypted(sm, data, ret, identifier,
in_decrypted, out_data);
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
return res;
}
@@ -1613,7 +1613,7 @@
if (sm->waiting_ext_cert_check) {
wpa_printf(MSG_DEBUG,
"EAP-FAST: Waiting external server certificate validation");
- wpabuf_free(data->pending_resp);
+ wpabuf_clear_free(data->pending_resp);
data->pending_resp = resp;
return NULL;
}
@@ -1641,7 +1641,7 @@
"EAP-FAST: Could not derive keys");
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return NULL;
}
}
@@ -1650,7 +1650,7 @@
/*
* Application data included in the handshake message.
*/
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = resp;
resp = NULL;
res = eap_fast_decrypt(sm, data, ret, id, &msg, &resp);
@@ -1658,7 +1658,7 @@
}
if (res == 1) {
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return eap_peer_tls_build_ack(id, EAP_TYPE_FAST,
data->fast_version);
}
@@ -1684,9 +1684,9 @@
data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
os_free(data->key_block_p);
data->key_block_p = NULL;
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = NULL;
- wpabuf_free(data->pending_resp);
+ wpabuf_clear_free(data->pending_resp);
data->pending_resp = NULL;
}
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index 5b38969..096f0f2 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -208,10 +208,10 @@
const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len);
/**
- * get_error_code - Get latest EAP method error code
+ * get_error_code - Get the latest EAP method error code
* @priv: Pointer to private EAP method data from eap_method::init()
- * Returns: An int for the EAP Method Error code if exists or
- * NO_EAP_METHOD_ERROR otherwise
+ * Returns: An int for the EAP method specific error code if exists or
+ * NO_EAP_METHOD_ERROR otherwise.
*
* This method is an optional handler that only EAP methods that need to
* report their error code need to implement.
diff --git a/src/eap_peer/eap_mschapv2.c b/src/eap_peer/eap_mschapv2.c
index 877495c..249baec 100644
--- a/src/eap_peer/eap_mschapv2.c
+++ b/src/eap_peer/eap_mschapv2.c
@@ -856,9 +856,13 @@
/* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key, i.e.,
* peer MS-MPPE-Send-Key | MS-MPPE-Recv-Key */
- get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 1, 0);
- get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
- MSCHAPV2_KEY_LEN, 0, 0);
+ if (get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 1,
+ 0) < 0 ||
+ get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
+ MSCHAPV2_KEY_LEN, 0, 0) < 0) {
+ os_free(key);
+ return NULL;
+ }
wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key",
key, key_len);
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 34075b1..8dcf7cc 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -169,7 +169,7 @@
static void eap_peap_free_key(struct eap_peap_data *data)
{
if (data->key_data) {
- bin_clear_free(data->key_data, EAP_TLS_KEY_LEN);
+ bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
data->key_data = NULL;
}
}
@@ -186,9 +186,9 @@
eap_peer_tls_ssl_deinit(sm, &data->ssl);
eap_peap_free_key(data);
os_free(data->session_id);
- wpabuf_free(data->pending_phase2_req);
- wpabuf_free(data->pending_resp);
- os_free(data);
+ wpabuf_clear_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_resp);
+ bin_clear_free(data, sizeof(*data));
}
@@ -253,7 +253,7 @@
{
u8 *tk;
u8 isk[32], imck[60];
- int resumed;
+ int resumed, res;
/*
* Tunnel key (TK) is the first 60 octets of the key generated by
@@ -292,9 +292,11 @@
* in the end of the label just before ISK; is that just a typo?)
*/
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
- if (peap_prfplus(data->peap_version, tk, 40,
- "Inner Methods Compound Keys",
- isk, sizeof(isk), imck, sizeof(imck)) < 0)
+ res = peap_prfplus(data->peap_version, tk, 40,
+ "Inner Methods Compound Keys",
+ isk, sizeof(isk), imck, sizeof(imck));
+ os_memset(isk, 0, sizeof(isk));
+ if (res < 0)
return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
imck, sizeof(imck));
@@ -303,6 +305,7 @@
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
os_memcpy(data->cmk, imck + 40, 20);
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
+ os_memset(imck, 0, sizeof(imck));
return 0;
}
@@ -382,7 +385,7 @@
wpabuf_put_be16(msg, status); /* Status */
if (crypto_tlv_used && eap_tlv_add_cryptobinding(sm, data, msg)) {
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
return NULL;
}
@@ -651,11 +654,11 @@
if (*resp == NULL) {
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
- wpabuf_free(buf);
+ wpabuf_clear_free(buf);
return -1;
}
wpabuf_put_buf(*resp, buf);
- wpabuf_free(buf);
+ wpabuf_clear_free(buf);
break;
}
}
@@ -728,7 +731,7 @@
(config->pending_req_identity || config->pending_req_password ||
config->pending_req_otp || config->pending_req_new_password ||
config->pending_req_sim)) {
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
}
@@ -807,7 +810,7 @@
struct wpabuf *nmsg = wpabuf_alloc(sizeof(struct eap_hdr) +
wpabuf_len(in_decrypted));
if (nmsg == NULL) {
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
return 0;
}
nhdr = wpabuf_put(nmsg, sizeof(*nhdr));
@@ -817,7 +820,7 @@
nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
wpabuf_len(in_decrypted));
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
in_decrypted = nmsg;
}
@@ -826,7 +829,7 @@
wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
"EAP frame (len=%lu)",
(unsigned long) wpabuf_len(in_decrypted));
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
return 0;
}
len = be_to_host16(hdr->length);
@@ -835,7 +838,7 @@
"Phase 2 EAP frame (len=%lu hdr->length=%lu)",
(unsigned long) wpabuf_len(in_decrypted),
(unsigned long) len);
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
return 0;
}
if (len < wpabuf_len(in_decrypted)) {
@@ -852,7 +855,7 @@
case EAP_CODE_REQUEST:
if (eap_peap_phase2_request(sm, data, ret, in_decrypted,
&resp)) {
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request "
"processing failed");
return 0;
@@ -872,7 +875,7 @@
"completed successfully");
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
return 0;
}
wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - "
@@ -882,7 +885,7 @@
ret->methodState = METHOD_DONE;
data->phase2_success = 1;
if (data->peap_outer_success == 2) {
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK "
"to finish authentication");
return 1;
@@ -928,7 +931,7 @@
break;
}
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
if (resp) {
int skip_change2 = 0;
@@ -955,7 +958,7 @@
wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt "
"a Phase 2 frame");
}
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
}
return 0;
@@ -1056,7 +1059,7 @@
if (sm->waiting_ext_cert_check) {
wpa_printf(MSG_DEBUG,
"EAP-PEAP: Waiting external server certificate validation");
- wpabuf_free(data->pending_resp);
+ wpabuf_clear_free(data->pending_resp);
data->pending_resp = resp;
return NULL;
}
@@ -1081,12 +1084,19 @@
"key derivation", label);
data->key_data =
eap_peer_tls_derive_key(sm, &data->ssl, label,
- EAP_TLS_KEY_LEN);
+ NULL, 0,
+ EAP_TLS_KEY_LEN +
+ EAP_EMSK_LEN);
if (data->key_data) {
wpa_hexdump_key(MSG_DEBUG,
"EAP-PEAP: Derived key",
data->key_data,
EAP_TLS_KEY_LEN);
+ wpa_hexdump_key(MSG_DEBUG,
+ "EAP-PEAP: Derived EMSK",
+ data->key_data +
+ EAP_TLS_KEY_LEN,
+ EAP_EMSK_LEN);
} else {
wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to "
"derive key");
@@ -1131,7 +1141,7 @@
/*
* Application data included in the handshake message.
*/
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = resp;
resp = NULL;
res = eap_peap_decrypt(sm, data, ret, req, &msg,
@@ -1144,7 +1154,7 @@
}
if (res == 1) {
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return eap_peer_tls_build_ack(id, EAP_TYPE_PEAP,
data->peap_version);
}
@@ -1168,9 +1178,9 @@
if (data->phase2_priv && data->phase2_method &&
data->phase2_method->deinit_for_reauth)
data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = NULL;
- wpabuf_free(data->pending_resp);
+ wpabuf_clear_free(data->pending_resp);
data->pending_resp = NULL;
data->crypto_binding_used = 0;
}
@@ -1257,6 +1267,7 @@
os_memcpy(key, csk, EAP_TLS_KEY_LEN);
wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
key, EAP_TLS_KEY_LEN);
+ os_memset(csk, 0, sizeof(csk));
} else
os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
@@ -1264,6 +1275,29 @@
}
+static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_peap_data *data = priv;
+ u8 *key;
+
+ if (!data->key_data || !data->phase2_success)
+ return NULL;
+
+ if (data->crypto_binding_used) {
+ /* [MS-PEAP] does not define EMSK derivation */
+ return NULL;
+ }
+
+ key = os_memdup(data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
+ if (!key)
+ return NULL;
+
+ *len = EAP_EMSK_LEN;
+
+ return key;
+}
+
+
static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_peap_data *data = priv;
@@ -1296,6 +1330,7 @@
eap->process = eap_peap_process;
eap->isKeyAvailable = eap_peap_isKeyAvailable;
eap->getKey = eap_peap_getKey;
+ eap->get_emsk = eap_peap_get_emsk;
eap->get_status = eap_peap_get_status;
eap->has_reauth_data = eap_peap_has_reauth_data;
eap->deinit_for_reauth = eap_peap_deinit_for_reauth;
diff --git a/src/eap_peer/eap_proxy_qmi_oc.c b/src/eap_peer/eap_proxy_qmi_oc.c
index 4c07da5..9fcf512 100644
--- a/src/eap_peer/eap_proxy_qmi_oc.c
+++ b/src/eap_peer/eap_proxy_qmi_oc.c
@@ -32,7 +32,7 @@
#ifdef CONFIG_EAP_PROXY
#include "qmi_client.h"
-#include "eap_proxy_qmi.h"
+#include "eap_proxy_qmi_oc.h"
#include "qmi_client.h"
#include "qmi_idl_lib.h"
#include "authentication_service_v01.h"
diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
index ec277ac..76fcad4 100644
--- a/src/eap_peer/eap_pwd.c
+++ b/src/eap_peer/eap_pwd.c
@@ -9,8 +9,11 @@
#include "includes.h"
#include "common.h"
+#include "crypto/sha1.h"
#include "crypto/sha256.h"
+#include "crypto/sha512.h"
#include "crypto/ms_funcs.h"
+#include "crypto/crypto.h"
#include "eap_peer/eap_i.h"
#include "eap_common/eap_pwd_common.h"
@@ -28,6 +31,8 @@
size_t password_len;
int password_hash;
u16 group_num;
+ u8 prep;
+ u8 token[4];
EAP_PWD_group *grp;
struct wpabuf *inbuf;
@@ -36,18 +41,16 @@
size_t out_frag_pos;
size_t mtu;
- BIGNUM *k;
- BIGNUM *private_value;
- BIGNUM *server_scalar;
- BIGNUM *my_scalar;
- EC_POINT *my_element;
- EC_POINT *server_element;
+ struct crypto_bignum *k;
+ struct crypto_bignum *private_value;
+ struct crypto_bignum *server_scalar;
+ struct crypto_bignum *my_scalar;
+ struct crypto_ec_point *my_element;
+ struct crypto_ec_point *server_element;
u8 msk[EAP_MSK_LEN];
u8 emsk[EAP_EMSK_LEN];
u8 session_id[1 + SHA256_MAC_LEN];
-
- BN_CTX *bnctx;
};
@@ -107,15 +110,8 @@
return NULL;
}
- if ((data->bnctx = BN_CTX_new()) == NULL) {
- wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
- os_free(data);
- return NULL;
- }
-
if ((data->id_peer = os_malloc(identity_len)) == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
- BN_CTX_free(data->bnctx);
os_free(data);
return NULL;
}
@@ -125,7 +121,6 @@
if ((data->password = os_malloc(password_len)) == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: memory allocation psk fail");
- BN_CTX_free(data->bnctx);
bin_clear_free(data->id_peer, data->id_peer_len);
os_free(data);
return NULL;
@@ -152,21 +147,18 @@
{
struct eap_pwd_data *data = priv;
- BN_clear_free(data->private_value);
- BN_clear_free(data->server_scalar);
- BN_clear_free(data->my_scalar);
- BN_clear_free(data->k);
- BN_CTX_free(data->bnctx);
- EC_POINT_clear_free(data->my_element);
- EC_POINT_clear_free(data->server_element);
+ crypto_bignum_deinit(data->private_value, 1);
+ crypto_bignum_deinit(data->server_scalar, 1);
+ crypto_bignum_deinit(data->my_scalar, 1);
+ crypto_bignum_deinit(data->k, 1);
+ crypto_ec_point_deinit(data->my_element, 1);
+ crypto_ec_point_deinit(data->server_element, 1);
bin_clear_free(data->id_peer, data->id_peer_len);
bin_clear_free(data->id_server, data->id_server_len);
bin_clear_free(data->password, data->password_len);
if (data->grp) {
- EC_GROUP_free(data->grp->group);
- EC_POINT_clear_free(data->grp->pwe);
- BN_clear_free(data->grp->order);
- BN_clear_free(data->grp->prime);
+ crypto_ec_deinit(data->grp->group);
+ crypto_ec_point_deinit(data->grp->pwe, 1);
os_free(data->grp);
}
wpabuf_free(data->inbuf);
@@ -218,10 +210,6 @@
const u8 *payload, size_t payload_len)
{
struct eap_pwd_id *id;
- const u8 *password;
- size_t password_len;
- u8 pwhashhash[16];
- int res;
if (data->state != PWD_ID_Req) {
ret->ignore = TRUE;
@@ -248,7 +236,10 @@
}
if (id->prep != EAP_PWD_PREP_NONE &&
- id->prep != EAP_PWD_PREP_MS) {
+ id->prep != EAP_PWD_PREP_MS &&
+ id->prep != EAP_PWD_PREP_SSHA1 &&
+ id->prep != EAP_PWD_PREP_SSHA256 &&
+ id->prep != EAP_PWD_PREP_SSHA512) {
wpa_printf(MSG_DEBUG,
"EAP-PWD: Unsupported password pre-processing technique (Prep=%u)",
id->prep);
@@ -266,6 +257,15 @@
wpa_printf(MSG_DEBUG, "EAP-PWD (peer): using group %d",
data->group_num);
+ data->prep = id->prep;
+ os_memcpy(data->token, id->token, sizeof(id->token));
+
+ if (data->id_server || data->grp) {
+ wpa_printf(MSG_INFO, "EAP-pwd: data was already allocated");
+ eap_pwd_state(data, FAILURE);
+ return;
+ }
+
data->id_server = os_malloc(payload_len - sizeof(struct eap_pwd_id));
if (data->id_server == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
@@ -277,7 +277,7 @@
wpa_hexdump_ascii(MSG_INFO, "EAP-PWD (peer): server sent id of",
data->id_server, data->id_server_len);
- data->grp = os_zalloc(sizeof(EAP_PWD_group));
+ data->grp = get_eap_pwd_group(data->group_num);
if (data->grp == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
"group");
@@ -285,54 +285,6 @@
return;
}
- if (id->prep == EAP_PWD_PREP_MS) {
-#ifdef CONFIG_FIPS
- wpa_printf(MSG_ERROR,
- "EAP-PWD (peer): MS password hash not supported in FIPS mode");
- eap_pwd_state(data, FAILURE);
- return;
-#else /* CONFIG_FIPS */
- if (data->password_hash) {
- res = hash_nt_password_hash(data->password, pwhashhash);
- } else {
- u8 pwhash[16];
-
- res = nt_password_hash(data->password,
- data->password_len, pwhash);
- if (res == 0)
- res = hash_nt_password_hash(pwhash, pwhashhash);
- os_memset(pwhash, 0, sizeof(pwhash));
- }
-
- if (res) {
- eap_pwd_state(data, FAILURE);
- return;
- }
-
- password = pwhashhash;
- password_len = sizeof(pwhashhash);
-#endif /* CONFIG_FIPS */
- } else {
- password = data->password;
- password_len = data->password_len;
- }
-
- /* compute PWE */
- res = compute_password_element(data->grp, data->group_num,
- password, password_len,
- data->id_server, data->id_server_len,
- data->id_peer, data->id_peer_len,
- id->token);
- os_memset(pwhashhash, 0, sizeof(pwhashhash));
- if (res) {
- wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute PWE");
- eap_pwd_state(data, FAILURE);
- return;
- }
-
- wpa_printf(MSG_DEBUG, "EAP-PWD (peer): computed %d bit PWE...",
- BN_num_bits(data->grp->prime));
-
data->outbuf = wpabuf_alloc(sizeof(struct eap_pwd_id) +
data->id_peer_len);
if (data->outbuf == NULL) {
@@ -356,206 +308,327 @@
const struct wpabuf *reqData,
const u8 *payload, size_t payload_len)
{
- EC_POINT *K = NULL, *point = NULL;
- BIGNUM *mask = NULL, *x = NULL, *y = NULL, *cofactor = NULL;
- u16 offset;
- u8 *ptr, *scalar = NULL, *element = NULL;
+ struct crypto_ec_point *K = NULL;
+ struct crypto_bignum *mask = NULL;
+ const u8 *ptr = payload;
+ u8 *scalar, *element;
size_t prime_len, order_len;
+ const u8 *password;
+ size_t password_len;
+ u8 pwhashhash[16];
+ const u8 *salt_pwd[2];
+ size_t salt_pwd_len[2], exp_len;
+ u8 salt_len, salthashpwd[64]; /* 64 = SHA512_DIGEST_LENGTH */
+ int res;
if (data->state != PWD_Commit_Req) {
ret->ignore = TRUE;
goto fin;
}
- prime_len = BN_num_bytes(data->grp->prime);
- order_len = BN_num_bytes(data->grp->order);
-
- if (payload_len != 2 * prime_len + order_len) {
- wpa_printf(MSG_INFO,
- "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
- (unsigned int) payload_len,
- (unsigned int) (2 * prime_len + order_len));
+ if (!data->grp) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-PWD (client): uninitialized EAP-pwd group");
+ ret->ignore = TRUE;
goto fin;
}
- if (((data->private_value = BN_new()) == NULL) ||
- ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) ||
- ((cofactor = BN_new()) == NULL) ||
- ((data->my_scalar = BN_new()) == NULL) ||
- ((mask = BN_new()) == NULL)) {
+ prime_len = crypto_ec_prime_len(data->grp->group);
+ order_len = crypto_ec_order_len(data->grp->group);
+
+ switch (data->prep) {
+ case EAP_PWD_PREP_MS:
+ wpa_printf(MSG_DEBUG,
+ "EAP-pwd commit request, password prep is MS");
+#ifdef CONFIG_FIPS
+ wpa_printf(MSG_ERROR,
+ "EAP-PWD (peer): MS password hash not supported in FIPS mode");
+ eap_pwd_state(data, FAILURE);
+ return;
+#else /* CONFIG_FIPS */
+ if (payload_len != 2 * prime_len + order_len) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
+ (unsigned int) payload_len,
+ (unsigned int) (2 * prime_len + order_len));
+ goto fin;
+ }
+ if (data->password_hash) {
+ res = hash_nt_password_hash(data->password, pwhashhash);
+ } else {
+ u8 pwhash[16];
+
+ res = nt_password_hash(data->password,
+ data->password_len, pwhash);
+ if (res == 0)
+ res = hash_nt_password_hash(pwhash, pwhashhash);
+ os_memset(pwhash, 0, sizeof(pwhash));
+ }
+
+ if (res) {
+ eap_pwd_state(data, FAILURE);
+ return;
+ }
+
+ password = pwhashhash;
+ password_len = sizeof(pwhashhash);
+#endif /* CONFIG_FIPS */
+ break;
+ case EAP_PWD_PREP_SSHA1:
+ wpa_printf(MSG_DEBUG,
+ "EAP-pwd commit request, password prep is salted sha1");
+ if (payload_len < 1 || *ptr == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-pwd: Invalid Salt-len");
+ goto fin;
+ }
+ salt_len = *ptr++;
+ exp_len = 1 + salt_len + 2 * prime_len + order_len;
+ if (payload_len != exp_len) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
+ (unsigned int) payload_len,
+ (unsigned int) exp_len);
+ goto fin;
+ }
+
+ /* salted-password = Hash(password | salt) */
+ wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Unsalted password",
+ data->password, data->password_len);
+ wpa_hexdump(MSG_DEBUG, "EAP-pwd: Salt", ptr, salt_len);
+ salt_pwd[0] = data->password;
+ salt_pwd[1] = ptr;
+ salt_pwd_len[0] = data->password_len;
+ salt_pwd_len[1] = salt_len;
+ if (sha1_vector(2, salt_pwd, salt_pwd_len, salthashpwd) < 0)
+ goto fin;
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-pwd: sha1 hashed %d byte salt with password",
+ (int) salt_len);
+ ptr += salt_len;
+ password = salthashpwd;
+ password_len = SHA1_MAC_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Salted password",
+ password, password_len);
+ break;
+ case EAP_PWD_PREP_SSHA256:
+ wpa_printf(MSG_DEBUG,
+ "EAP-pwd commit request, password prep is salted sha256");
+ if (payload_len < 1 || *ptr == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-pwd: Invalid Salt-len");
+ goto fin;
+ }
+ salt_len = *ptr++;
+ exp_len = 1 + salt_len + 2 * prime_len + order_len;
+ if (payload_len != exp_len) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
+ (unsigned int) payload_len,
+ (unsigned int) exp_len);
+ goto fin;
+ }
+
+ /* salted-password = Hash(password | salt) */
+ wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Unsalted password",
+ data->password, data->password_len);
+ wpa_hexdump(MSG_DEBUG, "EAP-pwd: Salt", ptr, salt_len);
+ salt_pwd[0] = data->password;
+ salt_pwd[1] = ptr;
+ salt_pwd_len[0] = data->password_len;
+ salt_pwd_len[1] = salt_len;
+ if (sha256_vector(2, salt_pwd, salt_pwd_len, salthashpwd) < 0)
+ goto fin;
+
+ ptr += salt_len;
+ password = salthashpwd;
+ password_len = SHA256_MAC_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Salted password",
+ password, password_len);
+ break;
+#ifdef CONFIG_SHA512
+ case EAP_PWD_PREP_SSHA512:
+ wpa_printf(MSG_DEBUG,
+ "EAP-pwd commit request, password prep is salted sha512");
+ if (payload_len < 1 || *ptr == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-pwd: Invalid Salt-len");
+ goto fin;
+ }
+ salt_len = *ptr++;
+ exp_len = 1 + salt_len + 2 * prime_len + order_len;
+ if (payload_len != exp_len) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
+ (unsigned int) payload_len,
+ (unsigned int) exp_len);
+ goto fin;
+ }
+
+ /* salted-password = Hash(password | salt) */
+ wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Unsalted password",
+ data->password, data->password_len);
+ wpa_hexdump(MSG_DEBUG, "EAP-pwd: Salt", ptr, salt_len);
+ salt_pwd[0] = data->password;
+ salt_pwd[1] = ptr;
+ salt_pwd_len[0] = data->password_len;
+ salt_pwd_len[1] = salt_len;
+ if (sha512_vector(2, salt_pwd, salt_pwd_len, salthashpwd) < 0)
+ goto fin;
+
+ ptr += salt_len;
+ password = salthashpwd;
+ password_len = SHA512_MAC_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: Salted password",
+ password, password_len);
+ break;
+#endif /* CONFIG_SHA512 */
+ case EAP_PWD_PREP_NONE:
+ wpa_printf(MSG_DEBUG,
+ "EAP-pwd commit request, password prep is NONE");
+ if (data->password_hash) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-PWD: Unhashed password not available");
+ eap_pwd_state(data, FAILURE);
+ return;
+ }
+ if (payload_len != 2 * prime_len + order_len) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: Unexpected Commit payload length %u (expected %u)",
+ (unsigned int) payload_len,
+ (unsigned int) (2 * prime_len + order_len));
+ goto fin;
+ }
+ password = data->password;
+ password_len = data->password_len;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "EAP-pwd: Unsupported password pre-processing technique (Prep=%u)",
+ data->prep);
+ eap_pwd_state(data, FAILURE);
+ return;
+ }
+
+ /* compute PWE */
+ res = compute_password_element(data->grp, data->group_num,
+ password, password_len,
+ data->id_server, data->id_server_len,
+ data->id_peer, data->id_peer_len,
+ data->token);
+ os_memset(pwhashhash, 0, sizeof(pwhashhash));
+ os_memset(salthashpwd, 0, sizeof(salthashpwd));
+ if (res) {
+ wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute PWE");
+ eap_pwd_state(data, FAILURE);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-PWD (peer): computed %d bit PWE...",
+ (int) crypto_ec_prime_len_bits(data->grp->group));
+
+ data->private_value = crypto_bignum_init();
+ data->my_element = crypto_ec_point_init(data->grp->group);
+ data->my_scalar = crypto_bignum_init();
+ mask = crypto_bignum_init();
+ if (!data->private_value || !data->my_element ||
+ !data->my_scalar || !mask) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): scalar allocation fail");
goto fin;
}
- if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) {
- wpa_printf(MSG_INFO, "EAP-pwd (peer): unable to get cofactor "
- "for curve");
+ if (eap_pwd_get_rand_mask(data->grp, data->private_value, mask,
+ data->my_scalar) < 0)
goto fin;
- }
- if (BN_rand_range(data->private_value, data->grp->order) != 1 ||
- BN_rand_range(mask, data->grp->order) != 1 ||
- BN_add(data->my_scalar, data->private_value, mask) != 1 ||
- BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
- data->bnctx) != 1) {
- wpa_printf(MSG_INFO,
- "EAP-pwd (peer): unable to get randomness");
- goto fin;
- }
-
- if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
- data->grp->pwe, mask, data->bnctx)) {
+ if (crypto_ec_point_mul(data->grp->group, data->grp->pwe, mask,
+ data->my_element) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): element allocation "
"fail");
eap_pwd_state(data, FAILURE);
goto fin;
}
- if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx))
- {
+ if (crypto_ec_point_invert(data->grp->group, data->my_element) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): element inversion fail");
goto fin;
}
- if (((x = BN_new()) == NULL) ||
- ((y = BN_new()) == NULL)) {
- wpa_printf(MSG_INFO, "EAP-PWD (peer): point allocation fail");
- goto fin;
- }
-
/* process the request */
- if (((data->server_scalar = BN_new()) == NULL) ||
- ((data->k = BN_new()) == NULL) ||
- ((K = EC_POINT_new(data->grp->group)) == NULL) ||
- ((point = EC_POINT_new(data->grp->group)) == NULL) ||
- ((data->server_element = EC_POINT_new(data->grp->group)) == NULL))
- {
+ data->k = crypto_bignum_init();
+ K = crypto_ec_point_init(data->grp->group);
+ if (!data->k || !K) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): peer data allocation "
"fail");
goto fin;
}
/* element, x then y, followed by scalar */
- ptr = (u8 *) payload;
- BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x);
- ptr += BN_num_bytes(data->grp->prime);
- BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y);
- ptr += BN_num_bytes(data->grp->prime);
- BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->server_scalar);
- if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group,
- data->server_element, x, y,
- data->bnctx)) {
+ data->server_element = eap_pwd_get_element(data->grp, ptr);
+ if (!data->server_element) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): setting peer element "
"fail");
goto fin;
}
-
- /* check to ensure server's element is not in a small sub-group */
- if (BN_cmp(cofactor, BN_value_one())) {
- if (!EC_POINT_mul(data->grp->group, point, NULL,
- data->server_element, cofactor, NULL)) {
- wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply "
- "server element by order!\n");
- goto fin;
- }
- if (EC_POINT_is_at_infinity(data->grp->group, point)) {
- wpa_printf(MSG_INFO, "EAP-PWD (peer): server element "
- "is at infinity!\n");
- goto fin;
- }
+ ptr += prime_len * 2;
+ data->server_scalar = eap_pwd_get_scalar(data->grp, ptr);
+ if (!data->server_scalar) {
+ wpa_printf(MSG_INFO,
+ "EAP-PWD (peer): setting peer scalar fail");
+ goto fin;
}
/* compute the shared key, k */
- if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe,
- data->server_scalar, data->bnctx)) ||
- (!EC_POINT_add(data->grp->group, K, K, data->server_element,
- data->bnctx)) ||
- (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value,
- data->bnctx))) {
+ if (crypto_ec_point_mul(data->grp->group, data->grp->pwe,
+ data->server_scalar, K) < 0 ||
+ crypto_ec_point_add(data->grp->group, K, data->server_element,
+ K) < 0 ||
+ crypto_ec_point_mul(data->grp->group, K, data->private_value,
+ K) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): computing shared key "
"fail");
goto fin;
}
- /* ensure that the shared key isn't in a small sub-group */
- if (BN_cmp(cofactor, BN_value_one())) {
- if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor,
- NULL)) {
- wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply "
- "shared key point by order");
- goto fin;
- }
- }
-
/*
- * This check is strictly speaking just for the case above where
+ * This check is strictly speaking just for the case where
* co-factor > 1 but it was suggested that even though this is probably
* never going to happen it is a simple and safe check "just to be
* sure" so let's be safe.
*/
- if (EC_POINT_is_at_infinity(data->grp->group, K)) {
+ if (crypto_ec_point_is_at_infinity(data->grp->group, K)) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): shared key point is at "
"infinity!\n");
goto fin;
}
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k,
- NULL, data->bnctx)) {
+ if (crypto_ec_point_x(data->grp->group, K, data->k) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to extract "
"shared secret from point");
goto fin;
}
/* now do the response */
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
- data->my_element, x, y,
- data->bnctx)) {
- wpa_printf(MSG_INFO, "EAP-PWD (peer): point assignment fail");
+ data->outbuf = wpabuf_alloc(2 * prime_len + order_len);
+ if (data->outbuf == NULL)
goto fin;
- }
-
- if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) ||
- ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) ==
- NULL)) {
- wpa_printf(MSG_INFO, "EAP-PWD (peer): data allocation fail");
- goto fin;
- }
+ /* We send the element as (x,y) followed by the scalar */
+ element = wpabuf_put(data->outbuf, 2 * prime_len);
+ scalar = wpabuf_put(data->outbuf, order_len);
/*
* bignums occupy as little memory as possible so one that is
* sufficiently smaller than the prime or order might need pre-pending
* with zeros.
*/
- os_memset(scalar, 0, BN_num_bytes(data->grp->order));
- os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2);
- offset = BN_num_bytes(data->grp->order) -
- BN_num_bytes(data->my_scalar);
- BN_bn2bin(data->my_scalar, scalar + offset);
-
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
- BN_bn2bin(x, element + offset);
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
- BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
-
- data->outbuf = wpabuf_alloc(BN_num_bytes(data->grp->order) +
- 2 * BN_num_bytes(data->grp->prime));
- if (data->outbuf == NULL)
+ crypto_bignum_to_bin(data->my_scalar, scalar, order_len, order_len);
+ if (crypto_ec_point_to_bin(data->grp->group, data->my_element, element,
+ element + prime_len) != 0) {
+ wpa_printf(MSG_INFO, "EAP-PWD (peer): point assignment fail");
goto fin;
-
- /* we send the element as (x,y) follwed by the scalar */
- wpabuf_put_data(data->outbuf, element,
- 2 * BN_num_bytes(data->grp->prime));
- wpabuf_put_data(data->outbuf, scalar, BN_num_bytes(data->grp->order));
+ }
fin:
- os_free(scalar);
- os_free(element);
- BN_clear_free(x);
- BN_clear_free(y);
- BN_clear_free(mask);
- BN_clear_free(cofactor);
- EC_POINT_clear_free(K);
- EC_POINT_clear_free(point);
+ crypto_bignum_deinit(mask, 1);
+ crypto_ec_point_deinit(K, 1);
if (data->outbuf == NULL)
eap_pwd_state(data, FAILURE);
else
@@ -569,12 +642,11 @@
const struct wpabuf *reqData,
const u8 *payload, size_t payload_len)
{
- BIGNUM *x = NULL, *y = NULL;
- struct crypto_hash *hash;
+ struct crypto_hash *hash = NULL;
u32 cs;
u16 grp;
u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
- int offset;
+ size_t prime_len = 0, order_len = 0;
if (data->state != PWD_Confirm_Req) {
ret->ignore = TRUE;
@@ -588,6 +660,9 @@
goto fin;
}
+ prime_len = crypto_ec_prime_len(data->grp->group);
+ order_len = crypto_ec_order_len(data->grp->group);
+
/*
* first build up the ciphersuite which is group | random_function |
* prf
@@ -600,9 +675,9 @@
ptr += sizeof(u8);
*ptr = EAP_PWD_DEFAULT_PRF;
- /* each component of the cruft will be at most as big as the prime */
- if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
- ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
+ /* each component of the point will be at most as big as the prime */
+ cruft = os_malloc(prime_len * 2);
+ if (!cruft) {
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm allocation "
"fail");
goto fin;
@@ -620,65 +695,41 @@
* zero the memory each time because this is mod prime math and some
* value may start with a few zeros and the previous one did not.
*/
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
- BN_bn2bin(data->k, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
+ eap_pwd_h_update(hash, cruft, prime_len);
/* server element: x, y */
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
- data->server_element, x, y,
- data->bnctx)) {
+ if (crypto_ec_point_to_bin(data->grp->group, data->server_element,
+ cruft, cruft + prime_len) != 0) {
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
"assignment fail");
goto fin;
}
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
- BN_bn2bin(x, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
- BN_bn2bin(y, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
/* server scalar */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->order) -
- BN_num_bytes(data->server_scalar);
- BN_bn2bin(data->server_scalar, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+ crypto_bignum_to_bin(data->server_scalar, cruft, order_len, order_len);
+ eap_pwd_h_update(hash, cruft, order_len);
/* my element: x, y */
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
- data->my_element, x, y,
- data->bnctx)) {
+ if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft,
+ cruft + prime_len) != 0) {
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
"assignment fail");
goto fin;
}
-
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
- BN_bn2bin(x, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
- BN_bn2bin(y, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
/* my scalar */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->order) -
- BN_num_bytes(data->my_scalar);
- BN_bn2bin(data->my_scalar, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+ crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len);
+ eap_pwd_h_update(hash, cruft, order_len);
/* the ciphersuite */
eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
/* random function fin */
eap_pwd_h_final(hash, conf);
+ hash = NULL;
ptr = (u8 *) payload;
if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
@@ -698,66 +749,43 @@
goto fin;
/* k */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
- BN_bn2bin(data->k, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
+ eap_pwd_h_update(hash, cruft, prime_len);
/* my element */
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
- data->my_element, x, y,
- data->bnctx)) {
+ if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft,
+ cruft + prime_len) != 0) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point "
"assignment fail");
goto fin;
}
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
- BN_bn2bin(x, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
- BN_bn2bin(y, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
/* my scalar */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->order) -
- BN_num_bytes(data->my_scalar);
- BN_bn2bin(data->my_scalar, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+ crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len);
+ eap_pwd_h_update(hash, cruft, order_len);
/* server element: x, y */
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
- data->server_element, x, y,
- data->bnctx)) {
+ if (crypto_ec_point_to_bin(data->grp->group, data->server_element,
+ cruft, cruft + prime_len) != 0) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point "
"assignment fail");
goto fin;
}
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
- BN_bn2bin(x, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
- BN_bn2bin(y, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
/* server scalar */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->order) -
- BN_num_bytes(data->server_scalar);
- BN_bn2bin(data->server_scalar, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+ crypto_bignum_to_bin(data->server_scalar, cruft, order_len, order_len);
+ eap_pwd_h_update(hash, cruft, order_len);
/* the ciphersuite */
eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
/* all done */
eap_pwd_h_final(hash, conf);
+ hash = NULL;
- if (compute_keys(data->grp, data->bnctx, data->k,
+ if (compute_keys(data->grp, data->k,
data->my_scalar, data->server_scalar, conf, ptr,
&cs, data->msk, data->emsk, data->session_id) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute MSK | "
@@ -772,10 +800,7 @@
wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
fin:
- if (data->grp)
- bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
- BN_clear_free(x);
- BN_clear_free(y);
+ bin_clear_free(cruft, prime_len * 2);
if (data->outbuf == NULL) {
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
@@ -783,6 +808,10 @@
} else {
eap_pwd_state(data, SUCCESS_ON_FRAG_COMPLETION);
}
+
+ /* clean allocated memory */
+ if (hash)
+ eap_pwd_h_final(hash, conf);
}
@@ -903,6 +932,13 @@
* buffer and ACK the fragment
*/
if (EAP_PWD_GET_MORE_BIT(lm_exch) || data->in_frag_pos) {
+ if (!data->inbuf) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-pwd: No buffer for reassembly");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ return NULL;
+ }
data->in_frag_pos += len;
if (data->in_frag_pos > wpabuf_size(data->inbuf)) {
wpa_printf(MSG_INFO, "EAP-pwd: Buffer overflow attack "
@@ -929,7 +965,7 @@
/*
* we're buffering and this is the last fragment
*/
- if (data->in_frag_pos) {
+ if (data->in_frag_pos && data->inbuf) {
wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes",
(int) len);
pos = wpabuf_head_u8(data->inbuf);
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index c0896aa..ba5eea9 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -1248,14 +1248,16 @@
return key;
}
+
static int eap_sim_get_error_code(void *priv)
{
struct eap_sim_data *data = priv;
+ int current_data_error;
if (!data)
return NO_EAP_METHOD_ERROR;
- int current_data_error = data->error_code;
+ current_data_error = data->error_code;
/* Now reset for next transaction */
data->error_code = NO_EAP_METHOD_ERROR;
@@ -1263,6 +1265,7 @@
return current_data_error;
}
+
int eap_peer_sim_register(void)
{
struct eap_method *eap;
diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c
index c1820a4..ffea9d2 100644
--- a/src/eap_peer/eap_tls.c
+++ b/src/eap_peer/eap_tls.c
@@ -173,14 +173,32 @@
static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data,
struct eap_method_ret *ret)
{
+ const char *label;
+
wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
- ret->methodState = METHOD_DONE;
- ret->decision = DECISION_UNCOND_SUCC;
+ if (data->ssl.tls_out) {
+ wpa_printf(MSG_DEBUG, "EAP-TLS: Fragment(s) remaining");
+ return;
+ }
+
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+
+ /* A possible NewSessionTicket may be received before
+ * EAP-Success, so need to allow it to be received. */
+ ret->methodState = METHOD_MAY_CONT;
+ ret->decision = DECISION_COND_SUCC;
+ } else {
+ label = "client EAP encryption";
+
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_UNCOND_SUCC;
+ }
eap_tls_free_key(data);
- data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
- "client EAP encryption",
+ data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, label,
+ NULL, 0,
EAP_TLS_KEY_LEN +
EAP_EMSK_LEN);
if (data->key_data) {
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index b3d4aba..cb94c45 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -1,6 +1,6 @@
/*
* EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -70,16 +70,26 @@
params->flags &= ~TLS_CONN_DISABLE_SESSION_TICKET;
if (os_strstr(txt, "tls_disable_tlsv1_0=1"))
params->flags |= TLS_CONN_DISABLE_TLSv1_0;
- if (os_strstr(txt, "tls_disable_tlsv1_0=0"))
+ if (os_strstr(txt, "tls_disable_tlsv1_0=0")) {
params->flags &= ~TLS_CONN_DISABLE_TLSv1_0;
+ params->flags |= TLS_CONN_ENABLE_TLSv1_0;
+ }
if (os_strstr(txt, "tls_disable_tlsv1_1=1"))
params->flags |= TLS_CONN_DISABLE_TLSv1_1;
- if (os_strstr(txt, "tls_disable_tlsv1_1=0"))
+ if (os_strstr(txt, "tls_disable_tlsv1_1=0")) {
params->flags &= ~TLS_CONN_DISABLE_TLSv1_1;
+ params->flags |= TLS_CONN_ENABLE_TLSv1_1;
+ }
if (os_strstr(txt, "tls_disable_tlsv1_2=1"))
params->flags |= TLS_CONN_DISABLE_TLSv1_2;
- if (os_strstr(txt, "tls_disable_tlsv1_2=0"))
+ if (os_strstr(txt, "tls_disable_tlsv1_2=0")) {
params->flags &= ~TLS_CONN_DISABLE_TLSv1_2;
+ params->flags |= TLS_CONN_ENABLE_TLSv1_2;
+ }
+ if (os_strstr(txt, "tls_disable_tlsv1_3=1"))
+ params->flags |= TLS_CONN_DISABLE_TLSv1_3;
+ if (os_strstr(txt, "tls_disable_tlsv1_3=0"))
+ params->flags &= ~TLS_CONN_DISABLE_TLSv1_3;
if (os_strstr(txt, "tls_ext_cert_check=1"))
params->flags |= TLS_CONN_EXT_CERT_CHECK;
if (os_strstr(txt, "tls_ext_cert_check=0"))
@@ -98,14 +108,15 @@
static void eap_tls_params_from_conf1(struct tls_connection_params *params,
struct eap_peer_config *config)
{
- params->ca_cert = (char *) config->ca_cert;
- params->ca_path = (char *) config->ca_path;
- params->client_cert = (char *) config->client_cert;
- params->private_key = (char *) config->private_key;
- params->private_key_passwd = (char *) config->private_key_passwd;
- params->dh_file = (char *) config->dh_file;
- params->subject_match = (char *) config->subject_match;
- params->altsubject_match = (char *) config->altsubject_match;
+ params->ca_cert = config->ca_cert;
+ params->ca_path = config->ca_path;
+ params->client_cert = config->client_cert;
+ params->private_key = config->private_key;
+ params->private_key_passwd = config->private_key_passwd;
+ params->dh_file = config->dh_file;
+ params->subject_match = config->subject_match;
+ params->altsubject_match = config->altsubject_match;
+ params->check_cert_subject = config->check_cert_subject;
params->suffix_match = config->domain_suffix_match;
params->domain_match = config->domain_match;
params->engine = config->engine;
@@ -121,14 +132,15 @@
static void eap_tls_params_from_conf2(struct tls_connection_params *params,
struct eap_peer_config *config)
{
- params->ca_cert = (char *) config->ca_cert2;
- params->ca_path = (char *) config->ca_path2;
- params->client_cert = (char *) config->client_cert2;
- params->private_key = (char *) config->private_key2;
- params->private_key_passwd = (char *) config->private_key2_passwd;
- params->dh_file = (char *) config->dh_file2;
- params->subject_match = (char *) config->subject_match2;
- params->altsubject_match = (char *) config->altsubject_match2;
+ params->ca_cert = config->ca_cert2;
+ params->ca_path = config->ca_path2;
+ params->client_cert = config->client_cert2;
+ params->private_key = config->private_key2;
+ params->private_key_passwd = config->private_key2_passwd;
+ params->dh_file = config->dh_file2;
+ params->subject_match = config->subject_match2;
+ params->altsubject_match = config->altsubject_match2;
+ params->check_cert_subject = config->check_cert_subject2;
params->suffix_match = config->domain_suffix_match2;
params->domain_match = config->domain_match2;
params->engine = config->engine2;
@@ -159,6 +171,25 @@
*/
params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
}
+ if (data->eap_type == EAP_TYPE_FAST ||
+ data->eap_type == EAP_TYPE_TTLS ||
+ data->eap_type == EAP_TYPE_PEAP) {
+ /* The current EAP peer implementation is not yet ready for the
+ * TLS v1.3 changes, so disable this by default for now. */
+ params->flags |= TLS_CONN_DISABLE_TLSv1_3;
+ }
+ if (data->eap_type == EAP_TYPE_TLS ||
+ data->eap_type == EAP_UNAUTH_TLS_TYPE ||
+ data->eap_type == EAP_WFA_UNAUTH_TLS_TYPE) {
+ /* While the current EAP-TLS implementation is more or less
+ * complete for TLS v1.3, there has been no interoperability
+ * testing with other implementations, so disable for by default
+ * for now until there has been chance to confirm that no
+ * significant interoperability issues show up with TLS version
+ * update.
+ */
+ params->flags |= TLS_CONN_DISABLE_TLSv1_3;
+ }
if (phase2) {
wpa_printf(MSG_DEBUG, "TLS: using phase2 config options");
eap_tls_params_from_conf2(params, config);
@@ -318,6 +349,8 @@
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
* @data: Data for TLS processing
* @label: Label string for deriving the keys, e.g., "client EAP encryption"
+ * @context: Optional extra upper-layer context (max len 2^16)
+ * @context_len: The length of the context value
* @len: Length of the key material to generate (usually 64 for MSK)
* Returns: Pointer to allocated key on success or %NULL on failure
*
@@ -326,9 +359,12 @@
* different label to bind the key usage into the generated material.
*
* The caller is responsible for freeing the returned buffer.
+ *
+ * Note: To provide the RFC 5705 context, the context variable must be non-NULL.
*/
u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
- const char *label, size_t len)
+ const char *label, const u8 *context,
+ size_t context_len, size_t len)
{
u8 *out;
@@ -336,8 +372,8 @@
if (out == NULL)
return NULL;
- if (tls_connection_export_key(data->ssl_ctx, data->conn, label, out,
- len)) {
+ if (tls_connection_export_key(data->ssl_ctx, data->conn, label,
+ context, context_len, out, len)) {
os_free(out);
return NULL;
}
@@ -366,6 +402,29 @@
struct tls_random keys;
u8 *out;
+ if (eap_type == EAP_TYPE_TLS && data->tls_v13) {
+ u8 *id, *method_id;
+
+ /* Session-Id = <EAP-Type> || Method-Id
+ * Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id",
+ * "", 64)
+ */
+ *len = 1 + 64;
+ id = os_malloc(*len);
+ if (!id)
+ return NULL;
+ method_id = eap_peer_tls_derive_key(
+ sm, data, "EXPORTER_EAP_TLS_Method-Id", NULL, 0, 64);
+ if (!method_id) {
+ os_free(id);
+ return NULL;
+ }
+ id[0] = eap_type;
+ os_memcpy(id + 1, method_id, 64);
+ os_free(method_id);
+ return id;
+ }
+
if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys) ||
keys.client_random == NULL || keys.server_random == NULL)
return NULL;
@@ -669,6 +728,8 @@
* the AS.
*/
int res = eap_tls_process_input(sm, data, in_data, out_data);
+ char buf[20];
+
if (res) {
/*
* Input processing failed (res = -1) or more data is
@@ -681,6 +742,12 @@
* The incoming message has been reassembled and processed. The
* response was allocated into data->tls_out buffer.
*/
+
+ if (tls_get_version(data->ssl_ctx, data->conn,
+ buf, sizeof(buf)) == 0) {
+ wpa_printf(MSG_DEBUG, "SSL: Using TLS version %s", buf);
+ data->tls_v13 = os_strcmp(buf, "TLSv1.3") == 0;
+ }
}
if (data->tls_out == NULL) {
diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h
index acd2b78..5f82529 100644
--- a/src/eap_peer/eap_tls_common.h
+++ b/src/eap_peer/eap_tls_common.h
@@ -73,6 +73,11 @@
* eap_type - EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
*/
u8 eap_type;
+
+ /**
+ * tls_v13 - Whether TLS v1.3 or newer is used
+ */
+ int tls_v13;
};
@@ -94,7 +99,8 @@
struct eap_peer_config *config, u8 eap_type);
void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
- const char *label, size_t len);
+ const char *label, const u8 *context,
+ size_t context_len, size_t len);
u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
struct eap_ssl_data *data, u8 eap_type,
size_t *len);
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index f18788c..1c8dbe2 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -196,8 +196,8 @@
eap_peer_tls_ssl_deinit(sm, &data->ssl);
eap_ttls_free_key(data);
os_free(data->session_id);
- wpabuf_free(data->pending_phase2_req);
- wpabuf_free(data->pending_resp);
+ wpabuf_clear_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_resp);
os_free(data);
}
@@ -248,7 +248,7 @@
msg = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(*resp) + 4);
if (msg == NULL) {
- wpabuf_free(*resp);
+ wpabuf_clear_free(*resp);
*resp = NULL;
return -1;
}
@@ -258,7 +258,7 @@
os_memcpy(pos, wpabuf_head(*resp), wpabuf_len(*resp));
pos += wpabuf_len(*resp);
AVP_PAD(avp, pos);
- wpabuf_free(*resp);
+ wpabuf_clear_free(*resp);
wpabuf_put(msg, pos - avp);
*resp = msg;
return 0;
@@ -271,6 +271,7 @@
eap_ttls_free_key(data);
data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
"ttls keying material",
+ NULL, 0,
EAP_TLS_KEY_LEN +
EAP_EMSK_LEN);
if (!data->key_data) {
@@ -303,7 +304,8 @@
static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
struct eap_ttls_data *data, size_t len)
{
- return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", len);
+ return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge",
+ NULL, 0, len);
}
#endif /* CONFIG_FIPS */
@@ -510,7 +512,7 @@
challenge = eap_ttls_implicit_challenge(
sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1);
if (challenge == NULL) {
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
"implicit challenge");
return -1;
@@ -529,7 +531,7 @@
*pos++ = 0; /* Flags */
if (os_get_random(pos, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) < 0) {
os_free(challenge);
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to get "
"random data for peer challenge");
return -1;
@@ -543,7 +545,7 @@
peer_challenge, pos, data->auth_response,
data->master_key)) {
os_free(challenge);
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
"response");
return -1;
@@ -604,7 +606,7 @@
challenge = eap_ttls_implicit_challenge(
sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1);
if (challenge == NULL) {
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive "
"implicit challenge");
return -1;
@@ -628,7 +630,7 @@
if (challenge_response(challenge, password, pos)) {
wpa_printf(MSG_ERROR,
"EAP-TTLS/MSCHAP: Failed derive password hash");
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
os_free(challenge);
return -1;
}
@@ -641,7 +643,7 @@
pos)) {
wpa_printf(MSG_ERROR,
"EAP-TTLS/MSCHAP: Failed derive password");
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
os_free(challenge);
return -1;
}
@@ -760,7 +762,7 @@
challenge = eap_ttls_implicit_challenge(
sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1);
if (challenge == NULL) {
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive "
"implicit challenge");
return -1;
@@ -1073,10 +1075,10 @@
resp, out_data)) {
wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 "
"frame");
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return -1;
}
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return 0;
}
@@ -1297,7 +1299,7 @@
config->pending_req_otp ||
config->pending_req_new_password ||
config->pending_req_sim) {
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = wpabuf_dup(in_decrypted);
}
@@ -1340,7 +1342,7 @@
* processing when EAP request is re-processed after
* user input.
*/
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = wpabuf_alloc(0);
}
@@ -1413,7 +1415,7 @@
in_decrypted = data->pending_phase2_req;
data->pending_phase2_req = NULL;
if (wpabuf_len(in_decrypted) == 0) {
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
return eap_ttls_implicit_identity_request(
sm, data, ret, identifier, out_data);
}
@@ -1449,7 +1451,7 @@
&parse, in_decrypted, out_data);
done:
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
os_free(parse.eapdata);
if (retval < 0) {
@@ -1509,7 +1511,7 @@
if (sm->waiting_ext_cert_check) {
wpa_printf(MSG_DEBUG,
"EAP-TTLS: Waiting external server certificate validation");
- wpabuf_free(data->pending_resp);
+ wpabuf_clear_free(data->pending_resp);
data->pending_resp = *out_data;
*out_data = NULL;
return 0;
@@ -1543,7 +1545,7 @@
/*
* Application data included in the handshake message.
*/
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = *out_data;
*out_data = NULL;
res = eap_ttls_decrypt(sm, data, ret, identifier, in_data,
@@ -1646,7 +1648,7 @@
/* FIX: what about res == -1? Could just move all error processing into
* the other functions and get rid of this res==1 case here. */
if (res == 1) {
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return eap_peer_tls_build_ack(id, EAP_TYPE_TTLS,
data->ttls_version);
}
@@ -1669,9 +1671,9 @@
if (data->phase2_priv && data->phase2_method &&
data->phase2_method->deinit_for_reauth)
data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = NULL;
- wpabuf_free(data->pending_resp);
+ wpabuf_clear_free(data->pending_resp);
data->pending_resp = NULL;
data->decision_succ = DECISION_FAIL;
#ifdef EAP_TNC
diff --git a/src/eap_peer/eap_wsc.c b/src/eap_peer/eap_wsc.c
index d140c88..92d5a02 100644
--- a/src/eap_peer/eap_wsc.c
+++ b/src/eap_peer/eap_wsc.c
@@ -255,6 +255,9 @@
cfg.new_ap_settings = &new_ap_settings;
}
+ if (os_strstr(phase1, "multi_ap=1"))
+ cfg.multi_ap_backhaul_sta = 1;
+
data->wps = wps_init(&cfg);
if (data->wps == NULL) {
os_free(data);
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index c67fa82..b130368 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -31,6 +31,8 @@
size_t password_len;
int password_hash; /* whether password is hashed with
* nt_password_hash() */
+ u8 *salt;
+ size_t salt_len;
int phase2;
int force_version;
unsigned int remediation:1;
@@ -38,6 +40,7 @@
int ttls_auth; /* bitfield of
* EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */
struct hostapd_radius_attr *accept_attr;
+ u32 t_c_timestamp;
};
struct eap_eapol_interface {
@@ -149,11 +152,15 @@
void eap_sm_pending_cb(struct eap_sm *sm);
int eap_sm_method_pending(struct eap_sm *sm);
const u8 * eap_get_identity(struct eap_sm *sm, size_t *len);
+const char * eap_get_serial_num(struct eap_sm *sm);
+const char * eap_get_method(struct eap_sm *sm);
+const char * eap_get_imsi(struct eap_sm *sm);
struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm);
void eap_server_clear_identity(struct eap_sm *sm);
void eap_server_mschap_rx_callback(struct eap_sm *sm, const char *source,
const u8 *username, size_t username_len,
const u8 *challenge, const u8 *response);
void eap_erp_update_identity(struct eap_sm *sm, const u8 *eap, size_t len);
+void eap_user_free(struct eap_user *user);
#endif /* EAP_H */
diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h
index 3d6f8d5..1cade10 100644
--- a/src/eap_server/eap_i.h
+++ b/src/eap_server/eap_i.h
@@ -159,6 +159,8 @@
void *eap_method_priv;
u8 *identity;
size_t identity_len;
+ char *serial_num;
+ char imsi[20];
/* Whether Phase 2 method should validate identity match */
int require_identity_match;
int lastId; /* Identifier used in the last EAP-Packet */
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index 9706e25..e8b36e1 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -25,9 +25,6 @@
#define EAP_MAX_AUTH_ROUNDS 50
-static void eap_user_free(struct eap_user *user);
-
-
/* EAP state machines are described in RFC 4137 */
static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
@@ -326,6 +323,9 @@
if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
sm->eap_if.eapReq = TRUE;
}
+
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT MACSTR,
+ MAC2STR(sm->peer_addr));
}
@@ -634,6 +634,9 @@
SM_ENTRY(EAP, TIMEOUT_FAILURE);
sm->eap_if.eapTimeout = TRUE;
+
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TIMEOUT_FAILURE MACSTR,
+ MAC2STR(sm->peer_addr));
}
@@ -1011,6 +1014,9 @@
if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
sm->eap_if.eapReq = TRUE;
}
+
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT2 MACSTR,
+ MAC2STR(sm->peer_addr));
}
@@ -1101,6 +1107,9 @@
SM_ENTRY(EAP, TIMEOUT_FAILURE2);
sm->eap_if.eapTimeout = TRUE;
+
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TIMEOUT_FAILURE2 MACSTR,
+ MAC2STR(sm->peer_addr));
}
@@ -1110,6 +1119,9 @@
eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
sm->eap_if.eapFail = TRUE;
+
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE2 MACSTR,
+ MAC2STR(sm->peer_addr));
}
@@ -1136,6 +1148,9 @@
* started properly.
*/
sm->start_reauth = TRUE;
+
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS2 MACSTR,
+ MAC2STR(sm->peer_addr));
}
@@ -1796,12 +1811,14 @@
}
-static void eap_user_free(struct eap_user *user)
+void eap_user_free(struct eap_user *user)
{
if (user == NULL)
return;
bin_clear_free(user->password, user->password_len);
user->password = NULL;
+ bin_clear_free(user->salt, user->salt_len);
+ user->salt = NULL;
os_free(user);
}
@@ -1900,6 +1917,7 @@
wpabuf_free(sm->lastReqData);
wpabuf_free(sm->eap_if.eapRespData);
os_free(sm->identity);
+ os_free(sm->serial_num);
os_free(sm->pac_opaque_encr_key);
os_free(sm->eap_fast_a_id);
os_free(sm->eap_fast_a_id_info);
@@ -1971,6 +1989,43 @@
}
+/**
+ * eap_get_serial_num - Get the serial number of user certificate
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ * Returns: Pointer to the serial number or %NULL if not available
+ */
+const char * eap_get_serial_num(struct eap_sm *sm)
+{
+ return sm->serial_num;
+}
+
+
+/**
+ * eap_get_method - Get the used EAP method
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ * Returns: Pointer to the method name or %NULL if not available
+ */
+const char * eap_get_method(struct eap_sm *sm)
+{
+ if (!sm || !sm->m)
+ return NULL;
+ return sm->m->name;
+}
+
+
+/**
+ * eap_get_imsi - Get IMSI of the user
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ * Returns: Pointer to IMSI or %NULL if not available
+ */
+const char * eap_get_imsi(struct eap_sm *sm)
+{
+ if (!sm || sm->imsi[0] == '\0')
+ return NULL;
+ return sm->imsi;
+}
+
+
void eap_erp_update_identity(struct eap_sm *sm, const u8 *eap, size_t len)
{
#ifdef CONFIG_ERP
diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index 1750211..1bea706 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -796,6 +796,10 @@
return;
}
+ if (data->permanent[0] == EAP_AKA_PERMANENT_PREFIX ||
+ data->permanent[0] == EAP_AKA_PRIME_PERMANENT_PREFIX)
+ os_strlcpy(sm->imsi, &data->permanent[1], sizeof(sm->imsi));
+
#ifdef EAP_SERVER_AKA_PRIME
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
diff --git a/src/eap_server/eap_server_fast.c b/src/eap_server/eap_server_fast.c
index fa0342f..a63f820 100644
--- a/src/eap_server/eap_server_fast.c
+++ b/src/eap_server/eap_server_fast.c
@@ -1516,7 +1516,7 @@
if (eap_fast_process_phase1(sm, data))
break;
- /* fall through to PHASE2_START */
+ /* fall through */
case PHASE2_START:
eap_fast_process_phase2_start(sm, data);
break;
diff --git a/src/eap_server/eap_server_ikev2.c b/src/eap_server/eap_server_ikev2.c
index 1833419..32e6872 100644
--- a/src/eap_server/eap_server_ikev2.c
+++ b/src/eap_server/eap_server_ikev2.c
@@ -223,7 +223,7 @@
}
data->out_used = 0;
}
- /* pass through */
+ /* fall through */
case WAIT_FRAG_ACK:
return eap_ikev2_build_msg(data, id);
case FRAG_ACK:
diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c
index 6c47bb6..e9e03b0 100644
--- a/src/eap_server/eap_server_mschapv2.c
+++ b/src/eap_server/eap_server_mschapv2.c
@@ -551,9 +551,13 @@
if (key == NULL)
return NULL;
/* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key */
- get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0, 1);
- get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
- MSCHAPV2_KEY_LEN, 1, 1);
+ if (get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0,
+ 1) < 0 ||
+ get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
+ MSCHAPV2_KEY_LEN, 1, 1) < 0) {
+ os_free(key);
+ return NULL;
+ }
wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", key, *len);
return key;
diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c
index 18d31b5..92c0e5e 100644
--- a/src/eap_server/eap_server_peap.c
+++ b/src/eap_server/eap_server_peap.c
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -324,13 +324,14 @@
{
u8 *tk;
u8 isk[32], imck[60];
+ int res;
/*
* Tunnel key (TK) is the first 60 octets of the key generated by
* phase 1 of PEAP (based on TLS).
*/
tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption",
- EAP_TLS_KEY_LEN);
+ NULL, 0, EAP_TLS_KEY_LEN);
if (tk == NULL)
return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
@@ -358,9 +359,11 @@
* in the end of the label just before ISK; is that just a typo?)
*/
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
- if (peap_prfplus(data->peap_version, tk, 40,
- "Inner Methods Compound Keys",
- isk, sizeof(isk), imck, sizeof(imck)) < 0) {
+ res = peap_prfplus(data->peap_version, tk, 40,
+ "Inner Methods Compound Keys",
+ isk, sizeof(isk), imck, sizeof(imck));
+ os_memset(isk, 0, sizeof(isk));
+ if (res < 0) {
os_free(tk);
return -1;
}
@@ -373,6 +376,7 @@
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
os_memcpy(data->cmk, imck + 40, 20);
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
+ os_memset(imck, 0, sizeof(imck));
return 0;
}
@@ -756,7 +760,7 @@
} else {
eap_peap_state(data, FAILURE);
}
-
+
} else if (status == EAP_TLV_RESULT_FAILURE) {
wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure "
"- requested %s", requested);
@@ -1322,14 +1326,17 @@
"key");
}
+ os_memset(csk, 0, sizeof(csk));
+
return eapKeyData;
}
/* TODO: PEAPv1 - different label in some cases */
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "client EAP encryption",
- EAP_TLS_KEY_LEN);
+ "client EAP encryption", NULL, 0,
+ EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
+ os_memset(eapKeyData + EAP_TLS_KEY_LEN, 0, EAP_EMSK_LEN);
*len = EAP_TLS_KEY_LEN;
wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
eapKeyData, EAP_TLS_KEY_LEN);
@@ -1341,6 +1348,40 @@
}
+static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_peap_data *data = priv;
+ u8 *eapKeyData, *emsk;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ if (data->crypto_binding_used) {
+ /* [MS-PEAP] does not define EMSK derivation */
+ return NULL;
+ }
+
+ /* TODO: PEAPv1 - different label in some cases */
+ eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
+ "client EAP encryption", NULL, 0,
+ EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
+ if (eapKeyData) {
+ emsk = os_memdup(eapKeyData + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
+ bin_clear_free(eapKeyData, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
+ if (!emsk)
+ return NULL;
+ *len = EAP_EMSK_LEN;
+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived EMSK",
+ emsk, EAP_EMSK_LEN);
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive EMSK");
+ emsk = NULL;
+ }
+
+ return emsk;
+}
+
+
static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_peap_data *data = priv;
@@ -1376,6 +1417,7 @@
eap->process = eap_peap_process;
eap->isDone = eap_peap_isDone;
eap->getKey = eap_peap_getKey;
+ eap->get_emsk = eap_peap_get_emsk;
eap->isSuccess = eap_peap_isSuccess;
eap->getSessionId = eap_peap_get_session_id;
diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
index 68f0af9..e720a28 100644
--- a/src/eap_server/eap_server_pwd.c
+++ b/src/eap_server/eap_server_pwd.c
@@ -11,6 +11,7 @@
#include "common.h"
#include "crypto/sha256.h"
#include "crypto/ms_funcs.h"
+#include "crypto/crypto.h"
#include "eap_server/eap_i.h"
#include "eap_common/eap_pwd_common.h"
@@ -26,8 +27,11 @@
u8 *password;
size_t password_len;
int password_hash;
+ u8 *salt;
+ size_t salt_len;
u32 token;
u16 group_num;
+ u8 password_prep;
EAP_PWD_group *grp;
struct wpabuf *inbuf;
@@ -36,20 +40,18 @@
size_t out_frag_pos;
size_t mtu;
- BIGNUM *k;
- BIGNUM *private_value;
- BIGNUM *peer_scalar;
- BIGNUM *my_scalar;
- EC_POINT *my_element;
- EC_POINT *peer_element;
+ struct crypto_bignum *k;
+ struct crypto_bignum *private_value;
+ struct crypto_bignum *peer_scalar;
+ struct crypto_bignum *my_scalar;
+ struct crypto_ec_point *my_element;
+ struct crypto_ec_point *peer_element;
u8 my_confirm[SHA256_MAC_LEN];
u8 msk[EAP_MSK_LEN];
u8 emsk[EAP_EMSK_LEN];
u8 session_id[1 + SHA256_MAC_LEN];
-
- BN_CTX *bnctx;
};
@@ -116,13 +118,17 @@
os_memcpy(data->password, sm->user->password, data->password_len);
data->password_hash = sm->user->password_hash;
- data->bnctx = BN_CTX_new();
- if (data->bnctx == NULL) {
- wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
- bin_clear_free(data->password, data->password_len);
- bin_clear_free(data->id_server, data->id_server_len);
- os_free(data);
- return NULL;
+ data->salt_len = sm->user->salt_len;
+ if (data->salt_len) {
+ data->salt = os_memdup(sm->user->salt, sm->user->salt_len);
+ if (!data->salt) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: Memory allocation of salt failed");
+ bin_clear_free(data->id_server, data->id_server_len);
+ bin_clear_free(data->password, data->password_len);
+ os_free(data);
+ return NULL;
+ }
}
data->in_frag_pos = data->out_frag_pos = 0;
@@ -138,21 +144,19 @@
{
struct eap_pwd_data *data = priv;
- BN_clear_free(data->private_value);
- BN_clear_free(data->peer_scalar);
- BN_clear_free(data->my_scalar);
- BN_clear_free(data->k);
- BN_CTX_free(data->bnctx);
- EC_POINT_clear_free(data->my_element);
- EC_POINT_clear_free(data->peer_element);
+ crypto_bignum_deinit(data->private_value, 1);
+ crypto_bignum_deinit(data->peer_scalar, 1);
+ crypto_bignum_deinit(data->my_scalar, 1);
+ crypto_bignum_deinit(data->k, 1);
+ crypto_ec_point_deinit(data->my_element, 1);
+ crypto_ec_point_deinit(data->peer_element, 1);
bin_clear_free(data->id_peer, data->id_peer_len);
bin_clear_free(data->id_server, data->id_server_len);
bin_clear_free(data->password, data->password_len);
+ bin_clear_free(data->salt, data->salt_len);
if (data->grp) {
- EC_GROUP_free(data->grp->group);
- EC_POINT_clear_free(data->grp->pwe);
- BN_clear_free(data->grp->order);
- BN_clear_free(data->grp->prime);
+ crypto_ec_deinit(data->grp->group);
+ crypto_ec_point_deinit(data->grp->pwe, 1);
os_free(data->grp);
}
wpabuf_free(data->inbuf);
@@ -185,12 +189,45 @@
return;
}
+ wpa_hexdump_key(MSG_DEBUG, "EAP-pwd (server): password",
+ data->password, data->password_len);
+ if (data->salt_len)
+ wpa_hexdump(MSG_DEBUG, "EAP-pwd (server): salt",
+ data->salt, data->salt_len);
+
+ /*
+ * If this is a salted password then figure out how it was hashed
+ * based on the length.
+ */
+ if (data->salt_len) {
+ switch (data->password_len) {
+ case 20:
+ data->password_prep = EAP_PWD_PREP_SSHA1;
+ break;
+ case 32:
+ data->password_prep = EAP_PWD_PREP_SSHA256;
+ break;
+ case 64:
+ data->password_prep = EAP_PWD_PREP_SSHA512;
+ break;
+ default:
+ wpa_printf(MSG_INFO,
+ "EAP-pwd (server): bad size %d for salted password",
+ (int) data->password_len);
+ eap_pwd_state(data, FAILURE);
+ return;
+ }
+ } else {
+ /* Otherwise, figure out whether it's MS hashed or plain */
+ data->password_prep = data->password_hash ? EAP_PWD_PREP_MS :
+ EAP_PWD_PREP_NONE;
+ }
+
wpabuf_put_be16(data->outbuf, data->group_num);
wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC);
wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF);
wpabuf_put_data(data->outbuf, &data->token, sizeof(data->token));
- wpabuf_put_u8(data->outbuf, data->password_hash ? EAP_PWD_PREP_MS :
- EAP_PWD_PREP_NONE);
+ wpabuf_put_u8(data->outbuf, data->password_prep);
wpabuf_put_data(data->outbuf, data->id_server, data->id_server_len);
}
@@ -198,9 +235,9 @@
static void eap_pwd_build_commit_req(struct eap_sm *sm,
struct eap_pwd_data *data, u8 id)
{
- BIGNUM *mask = NULL, *x = NULL, *y = NULL;
- u8 *scalar = NULL, *element = NULL;
- u16 offset;
+ struct crypto_bignum *mask = NULL;
+ u8 *scalar, *element;
+ size_t prime_len, order_len;
wpa_printf(MSG_DEBUG, "EAP-pwd: Commit/Request");
/*
@@ -210,93 +247,62 @@
if (data->out_frag_pos)
return;
- if (((data->private_value = BN_new()) == NULL) ||
- ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) ||
- ((data->my_scalar = BN_new()) == NULL) ||
- ((mask = BN_new()) == NULL)) {
+ prime_len = crypto_ec_prime_len(data->grp->group);
+ order_len = crypto_ec_order_len(data->grp->group);
+
+ data->private_value = crypto_bignum_init();
+ data->my_element = crypto_ec_point_init(data->grp->group);
+ data->my_scalar = crypto_bignum_init();
+ mask = crypto_bignum_init();
+ if (!data->private_value || !data->my_element || !data->my_scalar ||
+ !mask) {
wpa_printf(MSG_INFO, "EAP-PWD (server): scalar allocation "
"fail");
goto fin;
}
- if (BN_rand_range(data->private_value, data->grp->order) != 1 ||
- BN_rand_range(mask, data->grp->order) != 1 ||
- BN_add(data->my_scalar, data->private_value, mask) != 1 ||
- BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
- data->bnctx) != 1) {
- wpa_printf(MSG_INFO,
- "EAP-pwd (server): unable to get randomness");
+ if (eap_pwd_get_rand_mask(data->grp, data->private_value, mask,
+ data->my_scalar) < 0)
goto fin;
- }
- if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
- data->grp->pwe, mask, data->bnctx)) {
+ if (crypto_ec_point_mul(data->grp->group, data->grp->pwe, mask,
+ data->my_element) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (server): element allocation "
"fail");
eap_pwd_state(data, FAILURE);
goto fin;
}
- if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx))
- {
+ if (crypto_ec_point_invert(data->grp->group, data->my_element) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (server): element inversion "
"fail");
goto fin;
}
- BN_clear_free(mask);
- if (((x = BN_new()) == NULL) ||
- ((y = BN_new()) == NULL)) {
- wpa_printf(MSG_INFO, "EAP-PWD (server): point allocation "
- "fail");
+ data->outbuf = wpabuf_alloc(2 * prime_len + order_len +
+ (data->salt ? 1 + data->salt_len : 0));
+ if (data->outbuf == NULL)
goto fin;
+
+ /* If we're doing salted password prep, add the salt */
+ if (data->salt_len) {
+ wpabuf_put_u8(data->outbuf, data->salt_len);
+ wpabuf_put_data(data->outbuf, data->salt, data->salt_len);
}
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
- data->my_element, x, y,
- data->bnctx)) {
+
+ /* We send the element as (x,y) followed by the scalar */
+ element = wpabuf_put(data->outbuf, 2 * prime_len);
+ scalar = wpabuf_put(data->outbuf, order_len);
+ crypto_bignum_to_bin(data->my_scalar, scalar, order_len, order_len);
+ if (crypto_ec_point_to_bin(data->grp->group, data->my_element, element,
+ element + prime_len) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (server): point assignment "
"fail");
goto fin;
}
- if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) ||
- ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) ==
- NULL)) {
- wpa_printf(MSG_INFO, "EAP-PWD (server): data allocation fail");
- goto fin;
- }
-
- /*
- * bignums occupy as little memory as possible so one that is
- * sufficiently smaller than the prime or order might need pre-pending
- * with zeros.
- */
- os_memset(scalar, 0, BN_num_bytes(data->grp->order));
- os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2);
- offset = BN_num_bytes(data->grp->order) -
- BN_num_bytes(data->my_scalar);
- BN_bn2bin(data->my_scalar, scalar + offset);
-
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
- BN_bn2bin(x, element + offset);
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
- BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
-
- data->outbuf = wpabuf_alloc(2 * BN_num_bytes(data->grp->prime) +
- BN_num_bytes(data->grp->order));
- if (data->outbuf == NULL)
- goto fin;
-
- /* We send the element as (x,y) followed by the scalar */
- wpabuf_put_data(data->outbuf, element,
- 2 * BN_num_bytes(data->grp->prime));
- wpabuf_put_data(data->outbuf, scalar, BN_num_bytes(data->grp->order));
-
fin:
- os_free(scalar);
- os_free(element);
- BN_clear_free(x);
- BN_clear_free(y);
+ crypto_bignum_deinit(mask, 1);
if (data->outbuf == NULL)
eap_pwd_state(data, FAILURE);
}
@@ -305,11 +311,10 @@
static void eap_pwd_build_confirm_req(struct eap_sm *sm,
struct eap_pwd_data *data, u8 id)
{
- BIGNUM *x = NULL, *y = NULL;
- struct crypto_hash *hash;
+ struct crypto_hash *hash = NULL;
u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
u16 grp;
- int offset;
+ size_t prime_len, order_len;
wpa_printf(MSG_DEBUG, "EAP-pwd: Confirm/Request");
/*
@@ -319,9 +324,12 @@
if (data->out_frag_pos)
return;
+ prime_len = crypto_ec_prime_len(data->grp->group);
+ order_len = crypto_ec_order_len(data->grp->group);
+
/* Each component of the cruft will be at most as big as the prime */
- if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
- ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
+ cruft = os_malloc(prime_len * 2);
+ if (!cruft) {
wpa_printf(MSG_INFO, "EAP-PWD (server): debug allocation "
"fail");
goto fin;
@@ -341,64 +349,38 @@
*
* First is k
*/
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
- BN_bn2bin(data->k, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
+ eap_pwd_h_update(hash, cruft, prime_len);
/* server element: x, y */
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
- data->my_element, x, y,
- data->bnctx)) {
+ if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft,
+ cruft + prime_len) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
"assignment fail");
goto fin;
}
-
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
- BN_bn2bin(x, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
- BN_bn2bin(y, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
/* server scalar */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->order) -
- BN_num_bytes(data->my_scalar);
- BN_bn2bin(data->my_scalar, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+ crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len);
+ eap_pwd_h_update(hash, cruft, order_len);
/* peer element: x, y */
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
- data->peer_element, x, y,
- data->bnctx)) {
+ if (crypto_ec_point_to_bin(data->grp->group, data->peer_element, cruft,
+ cruft + prime_len) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
"assignment fail");
goto fin;
}
-
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
- BN_bn2bin(x, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
- BN_bn2bin(y, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
/* peer scalar */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->order) -
- BN_num_bytes(data->peer_scalar);
- BN_bn2bin(data->peer_scalar, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+ crypto_bignum_to_bin(data->peer_scalar, cruft, order_len, order_len);
+ eap_pwd_h_update(hash, cruft, order_len);
/* ciphersuite */
grp = htons(data->group_num);
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+ os_memset(cruft, 0, prime_len);
ptr = cruft;
os_memcpy(ptr, &grp, sizeof(u16));
ptr += sizeof(u16);
@@ -410,6 +392,7 @@
/* all done with the random function */
eap_pwd_h_final(hash, conf);
+ hash = NULL;
os_memcpy(data->my_confirm, conf, SHA256_MAC_LEN);
data->outbuf = wpabuf_alloc(SHA256_MAC_LEN);
@@ -419,11 +402,10 @@
wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
fin:
- bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
- BN_clear_free(x);
- BN_clear_free(y);
+ bin_clear_free(cruft, prime_len * 2);
if (data->outbuf == NULL)
eap_pwd_state(data, FAILURE);
+ eap_pwd_h_final(hash, NULL);
}
@@ -603,12 +585,15 @@
(id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
(os_memcmp(id->token, (u8 *)&data->token, sizeof(data->token))) ||
(id->prf != EAP_PWD_DEFAULT_PRF) ||
- id->prep !=
- data->password_hash ? EAP_PWD_PREP_MS : EAP_PWD_PREP_NONE) {
+ (id->prep != data->password_prep)) {
wpa_printf(MSG_INFO, "EAP-pwd: peer changed parameters");
eap_pwd_state(data, FAILURE);
return;
}
+ if (data->id_peer || data->grp) {
+ wpa_printf(MSG_INFO, "EAP-pwd: data was already allocated");
+ return;
+ }
data->id_peer = os_malloc(payload_len - sizeof(struct eap_pwd_id));
if (data->id_peer == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
@@ -619,14 +604,19 @@
wpa_hexdump_ascii(MSG_DEBUG, "EAP-PWD (server): peer sent id of",
data->id_peer, data->id_peer_len);
- data->grp = os_zalloc(sizeof(EAP_PWD_group));
+ data->grp = get_eap_pwd_group(data->group_num);
if (data->grp == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
"group");
return;
}
- if (data->password_hash) {
+ /*
+ * If it's PREP_MS then hash the password again, otherwise regardless
+ * of the prep the client is doing, the password we have is the one to
+ * use to generate the password element.
+ */
+ if (data->password_prep == EAP_PWD_PREP_MS) {
res = hash_nt_password_hash(data->password, pwhashhash);
if (res)
return;
@@ -649,7 +639,7 @@
return;
}
wpa_printf(MSG_DEBUG, "EAP-PWD (server): computed %d bit PWE...",
- BN_num_bits(data->grp->prime));
+ (int) crypto_ec_prime_len_bits(data->grp->group));
eap_pwd_state(data, PWD_Commit_Req);
}
@@ -659,16 +649,15 @@
eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
const u8 *payload, size_t payload_len)
{
- u8 *ptr;
- BIGNUM *x = NULL, *y = NULL, *cofactor = NULL;
- EC_POINT *K = NULL, *point = NULL;
+ const u8 *ptr;
+ struct crypto_ec_point *K = NULL;
int res = 0;
size_t prime_len, order_len;
wpa_printf(MSG_DEBUG, "EAP-pwd: Received commit response");
- prime_len = BN_num_bytes(data->grp->prime);
- order_len = BN_num_bytes(data->grp->order);
+ prime_len = crypto_ec_prime_len(data->grp->group);
+ order_len = crypto_ec_order_len(data->grp->group);
if (payload_len != 2 * prime_len + order_len) {
wpa_printf(MSG_INFO,
@@ -678,90 +667,63 @@
goto fin;
}
- if (((data->peer_scalar = BN_new()) == NULL) ||
- ((data->k = BN_new()) == NULL) ||
- ((cofactor = BN_new()) == NULL) ||
- ((x = BN_new()) == NULL) ||
- ((y = BN_new()) == NULL) ||
- ((point = EC_POINT_new(data->grp->group)) == NULL) ||
- ((K = EC_POINT_new(data->grp->group)) == NULL) ||
- ((data->peer_element = EC_POINT_new(data->grp->group)) == NULL)) {
+ data->k = crypto_bignum_init();
+ K = crypto_ec_point_init(data->grp->group);
+ if (!data->k || !K) {
wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
"fail");
goto fin;
}
- if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) {
- wpa_printf(MSG_INFO, "EAP-PWD (server): unable to get "
- "cofactor for curve");
- goto fin;
- }
-
/* element, x then y, followed by scalar */
- ptr = (u8 *) payload;
- BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x);
- ptr += BN_num_bytes(data->grp->prime);
- BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y);
- ptr += BN_num_bytes(data->grp->prime);
- BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->peer_scalar);
- if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group,
- data->peer_element, x, y,
- data->bnctx)) {
+ ptr = payload;
+ data->peer_element = eap_pwd_get_element(data->grp, ptr);
+ if (!data->peer_element) {
wpa_printf(MSG_INFO, "EAP-PWD (server): setting peer element "
"fail");
goto fin;
}
+ ptr += prime_len * 2;
+ data->peer_scalar = eap_pwd_get_scalar(data->grp, ptr);
+ if (!data->peer_scalar) {
+ wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
+ "fail");
+ goto fin;
+ }
- /* check to ensure peer's element is not in a small sub-group */
- if (BN_cmp(cofactor, BN_value_one())) {
- if (!EC_POINT_mul(data->grp->group, point, NULL,
- data->peer_element, cofactor, NULL)) {
- wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
- "multiply peer element by order");
- goto fin;
- }
- if (EC_POINT_is_at_infinity(data->grp->group, point)) {
- wpa_printf(MSG_INFO, "EAP-PWD (server): peer element "
- "is at infinity!\n");
- goto fin;
- }
+ /* detect reflection attacks */
+ if (crypto_bignum_cmp(data->my_scalar, data->peer_scalar) == 0 ||
+ crypto_ec_point_cmp(data->grp->group, data->my_element,
+ data->peer_element) == 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-PWD (server): detected reflection attack!");
+ goto fin;
}
/* compute the shared key, k */
- if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe,
- data->peer_scalar, data->bnctx)) ||
- (!EC_POINT_add(data->grp->group, K, K, data->peer_element,
- data->bnctx)) ||
- (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value,
- data->bnctx))) {
+ if ((crypto_ec_point_mul(data->grp->group, data->grp->pwe,
+ data->peer_scalar, K) < 0) ||
+ (crypto_ec_point_add(data->grp->group, K, data->peer_element,
+ K) < 0) ||
+ (crypto_ec_point_mul(data->grp->group, K, data->private_value,
+ K) < 0)) {
wpa_printf(MSG_INFO, "EAP-PWD (server): computing shared key "
"fail");
goto fin;
}
- /* ensure that the shared key isn't in a small sub-group */
- if (BN_cmp(cofactor, BN_value_one())) {
- if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor,
- NULL)) {
- wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
- "multiply shared key point by order!\n");
- goto fin;
- }
- }
-
/*
- * This check is strictly speaking just for the case above where
+ * This check is strictly speaking just for the case where
* co-factor > 1 but it was suggested that even though this is probably
* never going to happen it is a simple and safe check "just to be
* sure" so let's be safe.
*/
- if (EC_POINT_is_at_infinity(data->grp->group, K)) {
+ if (crypto_ec_point_is_at_infinity(data->grp->group, K)) {
wpa_printf(MSG_INFO, "EAP-PWD (server): shared key point is "
"at infinity");
goto fin;
}
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k,
- NULL, data->bnctx)) {
+ if (crypto_ec_point_x(data->grp->group, K, data->k)) {
wpa_printf(MSG_INFO, "EAP-PWD (server): unable to extract "
"shared secret from secret point");
goto fin;
@@ -769,11 +731,7 @@
res = 1;
fin:
- EC_POINT_clear_free(K);
- EC_POINT_clear_free(point);
- BN_clear_free(cofactor);
- BN_clear_free(x);
- BN_clear_free(y);
+ crypto_ec_point_deinit(K, 1);
if (res)
eap_pwd_state(data, PWD_Confirm_Req);
@@ -786,12 +744,14 @@
eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
const u8 *payload, size_t payload_len)
{
- BIGNUM *x = NULL, *y = NULL;
- struct crypto_hash *hash;
+ struct crypto_hash *hash = NULL;
u32 cs;
u16 grp;
u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
- int offset;
+ size_t prime_len, order_len;
+
+ prime_len = crypto_ec_prime_len(data->grp->group);
+ order_len = crypto_ec_order_len(data->grp->group);
if (payload_len != SHA256_MAC_LEN) {
wpa_printf(MSG_INFO,
@@ -810,8 +770,8 @@
*ptr = EAP_PWD_DEFAULT_PRF;
/* each component of the cruft will be at most as big as the prime */
- if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
- ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
+ cruft = os_malloc(prime_len * 2);
+ if (!cruft) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): allocation fail");
goto fin;
}
@@ -825,66 +785,41 @@
goto fin;
/* k */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
- BN_bn2bin(data->k, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len);
+ eap_pwd_h_update(hash, cruft, prime_len);
/* peer element: x, y */
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
- data->peer_element, x, y,
- data->bnctx)) {
+ if (crypto_ec_point_to_bin(data->grp->group, data->peer_element, cruft,
+ cruft + prime_len) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
"assignment fail");
goto fin;
}
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
- BN_bn2bin(x, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
- BN_bn2bin(y, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
/* peer scalar */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->order) -
- BN_num_bytes(data->peer_scalar);
- BN_bn2bin(data->peer_scalar, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+ crypto_bignum_to_bin(data->peer_scalar, cruft, order_len, order_len);
+ eap_pwd_h_update(hash, cruft, order_len);
/* server element: x, y */
- if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
- data->my_element, x, y,
- data->bnctx)) {
+ if (crypto_ec_point_to_bin(data->grp->group, data->my_element, cruft,
+ cruft + prime_len) < 0) {
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
"assignment fail");
goto fin;
}
-
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
- BN_bn2bin(x, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
- BN_bn2bin(y, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+ eap_pwd_h_update(hash, cruft, prime_len * 2);
/* server scalar */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
- offset = BN_num_bytes(data->grp->order) -
- BN_num_bytes(data->my_scalar);
- BN_bn2bin(data->my_scalar, cruft + offset);
- eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+ crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len);
+ eap_pwd_h_update(hash, cruft, order_len);
/* ciphersuite */
- os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
/* all done */
eap_pwd_h_final(hash, conf);
+ hash = NULL;
ptr = (u8 *) payload;
if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
@@ -894,7 +829,7 @@
}
wpa_printf(MSG_DEBUG, "EAP-pwd (server): confirm verified");
- if (compute_keys(data->grp, data->bnctx, data->k,
+ if (compute_keys(data->grp, data->k,
data->peer_scalar, data->my_scalar, conf,
data->my_confirm, &cs, data->msk, data->emsk,
data->session_id) < 0)
@@ -903,9 +838,8 @@
eap_pwd_state(data, SUCCESS);
fin:
- bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
- BN_clear_free(x);
- BN_clear_free(y);
+ bin_clear_free(cruft, prime_len * 2);
+ eap_pwd_h_final(hash, NULL);
}
@@ -978,6 +912,12 @@
* the first and all intermediate fragments have the M bit set
*/
if (EAP_PWD_GET_MORE_BIT(lm_exch) || data->in_frag_pos) {
+ if (!data->inbuf) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-pwd: No buffer for reassembly");
+ eap_pwd_state(data, FAILURE);
+ return;
+ }
if ((data->in_frag_pos + len) > wpabuf_size(data->inbuf)) {
wpa_printf(MSG_DEBUG, "EAP-pwd: Buffer overflow "
"attack detected! (%d+%d > %d)",
@@ -998,7 +938,7 @@
* last fragment won't have the M bit set (but we're obviously
* buffering fragments so that's how we know it's the last)
*/
- if (data->in_frag_pos) {
+ if (data->in_frag_pos && data->inbuf) {
pos = wpabuf_head_u8(data->inbuf);
len = data->in_frag_pos;
wpa_printf(MSG_DEBUG, "EAP-pwd: Last fragment, %d bytes",
@@ -1098,14 +1038,6 @@
int eap_server_pwd_register(void)
{
struct eap_method *eap;
- struct timeval tp;
- struct timezone tz;
- u32 sr;
-
- sr = 0xdeaddada;
- (void) gettimeofday(&tp, &tz);
- sr ^= (tp.tv_sec ^ tp.tv_usec);
- srandom(sr);
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_PWD,
@@ -1126,4 +1058,3 @@
return eap_server_method_register(eap);
}
-
diff --git a/src/eap_server/eap_server_sim.c b/src/eap_server/eap_server_sim.c
index 10637d4..1287827 100644
--- a/src/eap_server/eap_server_sim.c
+++ b/src/eap_server/eap_server_sim.c
@@ -535,6 +535,9 @@
goto failed;
}
+ if (data->permanent[0] == EAP_SIM_PERMANENT_PREFIX)
+ os_strlcpy(sm->imsi, &data->permanent[1], sizeof(sm->imsi));
+
identity_len = sm->identity_len;
while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop last null "
diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c
index 7249858..357e72a 100644
--- a/src/eap_server/eap_server_tls.c
+++ b/src/eap_server/eap_server_tls.c
@@ -22,6 +22,7 @@
enum { START, CONTINUE, SUCCESS, FAILURE } state;
int established;
u8 eap_type;
+ int phase2;
};
@@ -85,6 +86,8 @@
data->eap_type = EAP_TYPE_TLS;
+ data->phase2 = sm->init_phase2;
+
return data;
}
@@ -202,6 +205,20 @@
wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
eap_tls_state(data, SUCCESS);
eap_tls_valid_session(sm, data);
+ if (sm->serial_num) {
+ char user[128];
+ int user_len;
+
+ user_len = os_snprintf(user, sizeof(user), "cert-%s",
+ sm->serial_num);
+ if (eap_user_get(sm, (const u8 *) user, user_len,
+ data->phase2) < 0)
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: No user entry found based on the serial number of the client certificate ");
+ else
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: Updated user entry based on the serial number of the client certificate ");
+ }
}
return res;
@@ -288,6 +305,8 @@
"EAP-TLS: Resuming previous session");
eap_tls_state(data, SUCCESS);
tls_connection_set_success_data_resumed(data->ssl.conn);
+ /* TODO: Cache serial number with session and update EAP user
+ * information based on the cached serial number */
}
@@ -302,17 +321,23 @@
{
struct eap_tls_data *data = priv;
u8 *eapKeyData;
+ const char *label;
if (data->state != SUCCESS)
return NULL;
- eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "client EAP encryption",
- EAP_TLS_KEY_LEN);
+ if (data->ssl.tls_v13)
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ else
+ label = "client EAP encryption";
+ eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, label,
+ NULL, 0,
+ EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
*len = EAP_TLS_KEY_LEN;
wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key",
eapKeyData, EAP_TLS_KEY_LEN);
+ os_memset(eapKeyData + EAP_TLS_KEY_LEN, 0, EAP_EMSK_LEN);
} else {
wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
}
@@ -325,12 +350,17 @@
{
struct eap_tls_data *data = priv;
u8 *eapKeyData, *emsk;
+ const char *label;
if (data->state != SUCCESS)
return NULL;
- eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "client EAP encryption",
+ if (data->ssl.tls_v13)
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ else
+ label = "client EAP encryption";
+ eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, label,
+ NULL, 0,
EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
emsk = os_malloc(EAP_EMSK_LEN);
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index 3c9027b..0eca0ff 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -107,7 +107,8 @@
u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
- char *label, size_t len)
+ const char *label, const u8 *context,
+ size_t context_len, size_t len)
{
u8 *out;
@@ -115,8 +116,8 @@
if (out == NULL)
return NULL;
- if (tls_connection_export_key(sm->ssl_ctx, data->conn, label, out,
- len)) {
+ if (tls_connection_export_key(sm->ssl_ctx, data->conn, label,
+ context, context_len, out, len)) {
os_free(out);
return NULL;
}
@@ -145,6 +146,29 @@
struct tls_random keys;
u8 *out;
+ if (eap_type == EAP_TYPE_TLS && data->tls_v13) {
+ u8 *id, *method_id;
+
+ /* Session-Id = <EAP-Type> || Method-Id
+ * Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id",
+ * "", 64)
+ */
+ *len = 1 + 64;
+ id = os_malloc(*len);
+ if (!id)
+ return NULL;
+ method_id = eap_server_tls_derive_key(
+ sm, data, "EXPORTER_EAP_TLS_Method-Id", NULL, 0, 64);
+ if (!method_id) {
+ os_free(id);
+ return NULL;
+ }
+ id[0] = eap_type;
+ os_memcpy(id + 1, method_id, 64);
+ os_free(method_id);
+ return id;
+ }
+
if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys))
return NULL;
@@ -305,6 +329,8 @@
int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data)
{
+ char buf[20];
+
if (data->tls_out) {
/* This should not happen.. */
wpa_printf(MSG_INFO, "SSL: pending tls_out data when "
@@ -327,6 +353,16 @@
return -1;
}
+ if (tls_get_version(sm->ssl_ctx, data->conn, buf, sizeof(buf)) == 0) {
+ wpa_printf(MSG_DEBUG, "SSL: Using TLS version %s", buf);
+ data->tls_v13 = os_strcmp(buf, "TLSv1.3") == 0;
+ }
+
+ if (!sm->serial_num &&
+ tls_connection_established(sm->ssl_ctx, data->conn))
+ sm->serial_num = tls_connection_peer_serial_num(sm->ssl_ctx,
+ data->conn);
+
return 0;
}
@@ -373,7 +409,7 @@
if (data->tls_in &&
eap_server_tls_process_cont(data, *pos, end - *pos) < 0)
return -1;
-
+
if (flags & EAP_TLS_FLAGS_MORE_FRAGMENTS) {
if (eap_server_tls_process_fragment(data, flags, tls_msg_len,
*pos, end - *pos) < 0)
diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c
index b14996b..52bff8a 100644
--- a/src/eap_server/eap_server_ttls.c
+++ b/src/eap_server/eap_server_ttls.c
@@ -332,7 +332,7 @@
struct eap_ttls_data *data, size_t len)
{
return eap_server_tls_derive_key(sm, &data->ssl, "ttls challenge",
- len);
+ NULL, 0, len);
}
@@ -1268,7 +1268,7 @@
return NULL;
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "ttls keying material",
+ "ttls keying material", NULL, 0,
EAP_TLS_KEY_LEN);
if (eapKeyData) {
*len = EAP_TLS_KEY_LEN;
@@ -1310,7 +1310,7 @@
return NULL;
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "ttls keying material",
+ "ttls keying material", NULL, 0,
EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
emsk = os_malloc(EAP_EMSK_LEN);
diff --git a/src/eap_server/eap_server_wsc.c b/src/eap_server/eap_server_wsc.c
index 7d9d285..4a5cb98 100644
--- a/src/eap_server/eap_server_wsc.c
+++ b/src/eap_server/eap_server_wsc.c
@@ -257,7 +257,7 @@
}
data->out_used = 0;
}
- /* pass through */
+ /* fall through */
case WAIT_FRAG_ACK:
return eap_wsc_build_msg(data, id);
case FRAG_ACK:
diff --git a/src/eap_server/eap_tls_common.h b/src/eap_server/eap_tls_common.h
index dc943eb..0b04983 100644
--- a/src/eap_server/eap_tls_common.h
+++ b/src/eap_server/eap_tls_common.h
@@ -50,6 +50,11 @@
enum { MSG, FRAG_ACK, WAIT_FRAG_ACK } state;
struct wpabuf tmpbuf;
+
+ /**
+ * tls_v13 - Whether TLS v1.3 or newer is used
+ */
+ int tls_v13;
};
@@ -73,7 +78,8 @@
int verify_peer, int eap_type);
void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
- char *label, size_t len);
+ const char *label, const u8 *context,
+ size_t context_len, size_t len);
u8 * eap_server_tls_derive_session_id(struct eap_sm *sm,
struct eap_ssl_data *data, u8 eap_type,
size_t *len);
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index cb463ef..a0f27fd 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -189,8 +189,9 @@
}
if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) {
- eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx,
- sm);
+ if (eloop_register_timeout(1, 0, eapol_port_timers_tick,
+ eloop_ctx, sm) < 0)
+ sm->timer_tick_enabled = 0;
} else {
wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick");
sm->timer_tick_enabled = 0;
@@ -204,9 +205,9 @@
if (sm->timer_tick_enabled)
return;
wpa_printf(MSG_DEBUG, "EAPOL: enable timer tick");
- sm->timer_tick_enabled = 1;
eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
- eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
+ if (eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm) == 0)
+ sm->timer_tick_enabled = 1;
}
@@ -503,10 +504,14 @@
session_id = eap_proxy_get_eap_session_id(
sm->eap_proxy, &session_id_len);
emsk = eap_proxy_get_emsk(sm->eap_proxy, &emsk_len);
- if (sm->config->erp && session_id && emsk)
+ if (sm->config->erp && session_id && emsk) {
eap_peer_erp_init(sm->eap, session_id,
session_id_len, emsk,
emsk_len);
+ } else {
+ os_free(session_id);
+ bin_clear_free(emsk, emsk_len);
+ }
}
return;
}
@@ -2014,6 +2019,7 @@
sm->ctx->status_cb(sm->ctx->ctx, status, parameter);
}
+
static void eapol_sm_notify_eap_error(void *ctx, int error_code)
{
struct eapol_sm *sm = ctx;
@@ -2022,6 +2028,7 @@
sm->ctx->eap_error_cb(sm->ctx->ctx, error_code);
}
+
#ifdef CONFIG_EAP_PROXY
static void eapol_sm_eap_proxy_cb(void *ctx)
@@ -2135,8 +2142,8 @@
sm->initialize = FALSE;
eapol_sm_step(sm);
- sm->timer_tick_enabled = 1;
- eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
+ if (eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm) == 0)
+ sm->timer_tick_enabled = 1;
return sm;
}
diff --git a/src/fst/fst.h b/src/fst/fst.h
index 0c0e435..2967491 100644
--- a/src/fst/fst.h
+++ b/src/fst/fst.h
@@ -19,10 +19,18 @@
#define US_IN_MS 1000
#define LLT_UNIT_US 32 /* See 10.32.2.2 Transitioning between states */
-#define FST_LLT_MS_TO_VAL(m) (((u32) (m)) * US_IN_MS / LLT_UNIT_US)
-#define FST_LLT_VAL_TO_MS(v) (((u32) (v)) * LLT_UNIT_US / US_IN_MS)
-
-#define FST_MAX_LLT_MS FST_LLT_VAL_TO_MS(-1)
+/*
+ * These were originally
+ * #define FST_LLT_MS_TO_VAL(m) (((u32) (m)) * US_IN_MS / LLT_UNIT_US)
+ * #define FST_LLT_VAL_TO_MS(v) (((u32) (v)) * LLT_UNIT_US / US_IN_MS)
+ * #define FST_MAX_LLT_MS FST_LLT_VAL_TO_MS(-1)
+ * but those can overflow 32-bit unsigned integer, so use alternative defines
+ * to avoid undefined behavior with such overflow.
+ * LLT_UNIT_US/US_IN_MS = 32/1000 = 4/125
+ */
+#define FST_LLT_MS_TO_VAL(m) (((u32) (m)) * 125 / 4)
+#define FST_LLT_VAL_TO_MS(v) (((u32) (v)) * 4 / 125)
+#define FST_MAX_LLT_MS (((u32) -1) / 4)
#define FST_MAX_PRIO_VALUE ((u8) -1)
#define FST_MAX_GROUP_ID_LEN IFNAMSIZ
diff --git a/src/fst/fst_ctrl_aux.h b/src/fst/fst_ctrl_aux.h
index e2133f5..0aff5d0 100644
--- a/src/fst/fst_ctrl_aux.h
+++ b/src/fst/fst_ctrl_aux.h
@@ -35,6 +35,17 @@
* more info */
};
+enum fst_reason {
+ REASON_TEARDOWN,
+ REASON_SETUP,
+ REASON_SWITCH,
+ REASON_STT,
+ REASON_REJECT,
+ REASON_ERROR_PARAMS,
+ REASON_RESET,
+ REASON_DETACH_IFACE,
+};
+
enum fst_initiator {
FST_INITIATOR_UNDEFINED,
FST_INITIATOR_LOCAL,
@@ -57,16 +68,7 @@
enum fst_session_state new_state;
union fst_session_state_switch_extra {
struct {
- enum fst_reason {
- REASON_TEARDOWN,
- REASON_SETUP,
- REASON_SWITCH,
- REASON_STT,
- REASON_REJECT,
- REASON_ERROR_PARAMS,
- REASON_RESET,
- REASON_DETACH_IFACE,
- } reason;
+ enum fst_reason reason;
u8 reject_code; /* REASON_REJECT */
/* REASON_SWITCH,
* REASON_TEARDOWN,
diff --git a/src/fst/fst_ctrl_iface.c b/src/fst/fst_ctrl_iface.c
index 7820e58..7df3362 100644
--- a/src/fst/fst_ctrl_iface.c
+++ b/src/fst/fst_ctrl_iface.c
@@ -49,7 +49,7 @@
if (ss->extra.to_initial.reject_code != WLAN_STATUS_SUCCESS)
os_snprintf(reject_str, sizeof(reject_str), "%u",
ss->extra.to_initial.reject_code);
- /* no break */
+ /* fall through */
case REASON_TEARDOWN:
case REASON_SWITCH:
switch (ss->extra.to_initial.initiator) {
diff --git a/src/l2_packet/l2_packet.h b/src/l2_packet/l2_packet.h
index 2a45245..5387177 100644
--- a/src/l2_packet/l2_packet.h
+++ b/src/l2_packet/l2_packet.h
@@ -42,6 +42,7 @@
enum l2_packet_filter_type {
L2_PACKET_FILTER_DHCP,
L2_PACKET_FILTER_NDISC,
+ L2_PACKET_FILTER_PKTTYPE,
};
/**
diff --git a/src/l2_packet/l2_packet_linux.c b/src/l2_packet/l2_packet_linux.c
index 65b4906..291c9dd 100644
--- a/src/l2_packet/l2_packet_linux.c
+++ b/src/l2_packet/l2_packet_linux.c
@@ -84,6 +84,26 @@
.filter = ndisc_sock_filter_insns,
};
+/* drop packet if skb->pkt_type is PACKET_OTHERHOST (0x03). Generated by:
+ * $ bpfc - <<EOF
+ * > ldb #type
+ * > jeq #0x03, drop
+ * > pass: ret #-1
+ * > drop: ret #0
+ * > EOF
+ */
+static struct sock_filter pkt_type_filter_insns[] = {
+ { 0x30, 0, 0, 0xfffff004 },
+ { 0x15, 1, 0, 0x00000003 },
+ { 0x6, 0, 0, 0xffffffff },
+ { 0x6, 0, 0, 0x00000000 },
+};
+
+static const struct sock_fprog pkt_type_sock_filter = {
+ .len = ARRAY_SIZE(pkt_type_filter_insns),
+ .filter = pkt_type_filter_insns,
+};
+
int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
{
@@ -471,6 +491,9 @@
case L2_PACKET_FILTER_NDISC:
sock_filter = &ndisc_sock_filter;
break;
+ case L2_PACKET_FILTER_PKTTYPE:
+ sock_filter = &pkt_type_sock_filter;
+ break;
default:
return -1;
}
diff --git a/src/lib.rules b/src/lib.rules
index 0c79d99..4ec4711 100644
--- a/src/lib.rules
+++ b/src/lib.rules
@@ -6,6 +6,11 @@
CFLAGS = -MMD -O2 -Wall -g
endif
+ifdef TEST_FUZZ
+CFLAGS += -DCONFIG_NO_RANDOM_POOL
+CFLAGS += -DTEST_FUZZ
+endif
+
CFLAGS += -I.. -I../utils
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 1a31ef2..6107b14 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -1076,7 +1076,7 @@
p2p->after_scan_tx->bssid,
(u8 *) (p2p->after_scan_tx + 1),
p2p->after_scan_tx->len,
- p2p->after_scan_tx->wait_time);
+ p2p->after_scan_tx->wait_time, NULL);
os_free(p2p->after_scan_tx);
p2p->after_scan_tx = NULL;
return 1;
@@ -1172,9 +1172,9 @@
u8 seek_count, const char **seek, int freq)
{
int res;
+ struct os_reltime start;
p2p_dbg(p2p, "Starting find (type=%d)", type);
- os_get_reltime(&p2p->find_start);
if (p2p->p2p_scan_running) {
p2p_dbg(p2p, "p2p_scan is already running");
}
@@ -1258,6 +1258,7 @@
if (timeout)
eloop_register_timeout(timeout, 0, p2p_find_timeout,
p2p, NULL);
+ os_get_reltime(&start);
switch (type) {
case P2P_FIND_START_WITH_FULL:
if (freq > 0) {
@@ -1289,6 +1290,9 @@
return -1;
}
+ if (!res)
+ p2p->find_start = start;
+
if (res != 0 && p2p->p2p_scan_running) {
p2p_dbg(p2p, "Failed to start p2p_scan - another p2p_scan was already running");
/* wait for the previous p2p_scan to complete */
@@ -1470,7 +1474,8 @@
p2p->op_channel = p2p->cfg->op_channel;
} else if (p2p_channel_random_social(&p2p->cfg->channels,
&p2p->op_reg_class,
- &p2p->op_channel) == 0) {
+ &p2p->op_channel,
+ NULL, NULL) == 0) {
p2p_dbg(p2p, "Select random available social channel (op_class %u channel %u) as operating channel preference",
p2p->op_reg_class, p2p->op_channel);
} else {
@@ -1797,7 +1802,12 @@
}
p2p->ssid_set = 0;
- p2p_random(params->passphrase, p2p->cfg->passphrase_len);
+ if (p2p->passphrase_set) {
+ os_memcpy(params->passphrase, p2p->passphrase, os_strlen(p2p->passphrase));
+ } else {
+ p2p_random(params->passphrase, p2p->cfg->passphrase_len);
+ }
+ p2p->passphrase_set = 0;
return 0;
}
@@ -2456,7 +2466,7 @@
if (msg.wps_attributes &&
!p2p_match_dev_type(p2p, msg.wps_attributes)) {
/* No match with Requested Device Type */
- p2p_dbg(p2p, "Probe Req requestred Device Type did not match - ignore it");
+ p2p_dbg(p2p, "Probe Req requested Device Type did not match - ignore it");
p2p_parse_free(&msg);
return P2P_PREQ_NOT_PROCESSED;
}
@@ -3889,6 +3899,19 @@
if (p2p->in_listen)
return 0; /* Internal timeout will trigger the next step */
+ if (p2p->state == P2P_WAIT_PEER_CONNECT && p2p->go_neg_peer &&
+ p2p->pending_listen_freq) {
+ /*
+ * Better wait a bit if the driver is unable to start
+ * offchannel operation for some reason to continue with
+ * P2P_WAIT_PEER_(IDLE/CONNECT) state transitions.
+ */
+ p2p_dbg(p2p,
+ "Listen operation did not seem to start - delay idle phase to avoid busy loop");
+ p2p_set_timeout(p2p, 0, 100000);
+ return 1;
+ }
+
if (p2p->state == P2P_CONNECT_LISTEN && p2p->go_neg_peer) {
if (p2p->go_neg_peer->connect_reqs >= 120) {
p2p_dbg(p2p, "Timeout on sending GO Negotiation Request without getting response");
@@ -4751,9 +4774,12 @@
int p2p_config_get_random_social(struct p2p_config *p2p, u8 *op_class,
- u8 *op_channel)
+ u8 *op_channel,
+ struct wpa_freq_range_list *avoid_list,
+ struct wpa_freq_range_list *disallow_list)
{
- return p2p_channel_random_social(&p2p->channels, op_class, op_channel);
+ return p2p_channel_random_social(&p2p->channels, op_class, op_channel,
+ avoid_list, disallow_list);
}
@@ -4952,6 +4978,8 @@
const u8 *src, const u8 *bssid, const u8 *buf,
size_t len, unsigned int wait_time)
{
+ int res, scheduled;
+
if (p2p->p2p_scan_running) {
p2p_dbg(p2p, "Delay Action frame TX until p2p_scan completes");
if (p2p->after_scan_tx) {
@@ -4972,8 +5000,16 @@
return 0;
}
- return p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, dst, src, bssid,
- buf, len, wait_time);
+ res = p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, dst, src, bssid,
+ buf, len, wait_time, &scheduled);
+ if (res == 0 && scheduled && p2p->in_listen && freq > 0 &&
+ (unsigned int) p2p->drv_in_listen != freq) {
+ p2p_dbg(p2p,
+ "Stop listen on %d MHz to allow a frame to be sent immediately on %d MHz",
+ p2p->drv_in_listen, freq);
+ p2p_stop_listen_for_freq(p2p, freq);
+ }
+ return res;
}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index fac5ce0..425b037 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -104,6 +104,11 @@
unsigned int vht_center_freq2;
/**
+ * he - Indicates if IEEE 802.11ax HE is enabled
+ */
+ int he;
+
+ /**
* ssid - SSID of the group
*/
u8 ssid[SSID_MAX_LEN];
@@ -660,6 +665,8 @@
* @buf: Frame body (starting from Category field)
* @len: Length of buf in octets
* @wait_time: How many msec to wait for a response frame
+ * @scheduled: Return value indicating whether the transmissions was
+ * scheduled to happen once the radio is available
* Returns: 0 on success, -1 on failure
*
* The Action frame may not be transmitted immediately and the status
@@ -670,7 +677,7 @@
*/
int (*send_action)(void *ctx, unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid, const u8 *buf,
- size_t len, unsigned int wait_time);
+ size_t len, unsigned int wait_time, int *scheduled);
/**
* send_action_done - Notify that Action frame sequence was completed
@@ -2005,6 +2012,8 @@
* @p2p: P2P config
* @op_class: Selected operating class
* @op_channel: Selected social channel
+ * @avoid_list: Channel ranges to try to avoid or %NULL
+ * @disallow_list: Channel ranges to discard or %NULL
* Returns: 0 on success, -1 on failure
*
* This function is used before p2p_init is called. A random social channel
@@ -2012,7 +2021,9 @@
* returned on success.
*/
int p2p_config_get_random_social(struct p2p_config *p2p, u8 *op_class,
- u8 *op_channel);
+ u8 *op_channel,
+ struct wpa_freq_range_list *avoid_list,
+ struct wpa_freq_range_list *disallow_list);
int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel,
u8 forced);
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index 2882c6a..63eb2e8 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -802,7 +802,7 @@
wpabuf_put_be16(buf, p2p->cfg->config_methods);
}
- if (wps_build_wfa_ext(buf, 0, NULL, 0) < 0)
+ if (wps_build_wfa_ext(buf, 0, NULL, 0, 0) < 0)
return -1;
if (all_attr && p2p->cfg->num_sec_dev_types) {
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index 16c28a0..aa18af6 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -941,7 +941,8 @@
if (p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, m->addr,
group->cfg->interface_addr,
group->cfg->interface_addr,
- wpabuf_head(req), wpabuf_len(req), 200) < 0)
+ wpabuf_head(req), wpabuf_len(req), 200, NULL)
+ < 0)
{
p2p_dbg(p2p, "Failed to send Action frame");
}
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 6a4d751..64a9977 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -11,6 +11,7 @@
#include "utils/list.h"
#include "p2p.h"
+#include "ap/ap_config.h"
#define P2P_GO_NEG_CNF_MAX_RETRY_COUNT 1
@@ -358,6 +359,16 @@
int ssid_set;
/**
+ * passphrase - WPA2-Personal passphrase for GO Negotiation (if local end will be GO)
+ */
+ char passphrase[MAX_PASSPHRASE_LEN + 1];
+
+ /**
+ * passphrase_set - Whether passphrase is already set for GO Negotiation
+ */
+ int passphrase_set;
+
+ /**
* Regulatory class for own operational channel
*/
u8 op_reg_class;
@@ -707,7 +718,9 @@
int p2p_channel_select(struct p2p_channels *chans, const int *classes,
u8 *op_class, u8 *op_channel);
int p2p_channel_random_social(struct p2p_channels *chans, u8 *op_class,
- u8 *op_channel);
+ u8 *op_channel,
+ struct wpa_freq_range_list *avoid_list,
+ struct wpa_freq_range_list *disallow_list);
/* p2p_parse.c */
void p2p_copy_filter_devname(char *dst, size_t dst_len,
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index bbba001..77d662a 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -488,7 +488,7 @@
if (*msg.status == P2P_SC_FAIL_NO_COMMON_CHANNELS &&
p2p->retry_invite_req &&
p2p_channel_random_social(&p2p->cfg->channels, &p2p->op_reg_class,
- &p2p->op_channel) == 0) {
+ &p2p->op_channel, NULL, NULL) == 0) {
p2p->retry_invite_req = 0;
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index 2e2aa8a..1a62a44 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -413,17 +413,30 @@
int p2p_channel_random_social(struct p2p_channels *chans, u8 *op_class,
- u8 *op_channel)
+ u8 *op_channel,
+ struct wpa_freq_range_list *avoid_list,
+ struct wpa_freq_range_list *disallow_list)
{
u8 chan[4];
unsigned int num_channels = 0;
- /* Try to find available social channels from 2.4 GHz */
- if (p2p_channels_includes(chans, 81, 1))
+ /* Try to find available social channels from 2.4 GHz.
+ * If the avoid_list includes any of the 2.4 GHz social channels, that
+ * channel is not allowed by p2p_channels_includes() rules. However, it
+ * is assumed to allow minimal traffic for P2P negotiation, so allow it
+ * here for social channel selection unless explicitly disallowed in the
+ * disallow_list. */
+ if (p2p_channels_includes(chans, 81, 1) ||
+ (freq_range_list_includes(avoid_list, 2412) &&
+ !freq_range_list_includes(disallow_list, 2412)))
chan[num_channels++] = 1;
- if (p2p_channels_includes(chans, 81, 6))
+ if (p2p_channels_includes(chans, 81, 6) ||
+ (freq_range_list_includes(avoid_list, 2437) &&
+ !freq_range_list_includes(disallow_list, 2437)))
chan[num_channels++] = 6;
- if (p2p_channels_includes(chans, 81, 11))
+ if (p2p_channels_includes(chans, 81, 11) ||
+ (freq_range_list_includes(avoid_list, 2462) &&
+ !freq_range_list_includes(disallow_list, 2462)))
chan[num_channels++] = 11;
/* Try to find available social channels from 60 GHz */
diff --git a/src/pae/ieee802_1x_cp.c b/src/pae/ieee802_1x_cp.c
index 360fcd3..1c4dc3e 100644
--- a/src/pae/ieee802_1x_cp.c
+++ b/src/pae/ieee802_1x_cp.c
@@ -38,12 +38,10 @@
/* Logon -> CP */
enum connect_type connect;
- u8 *authorization_data;
/* KaY -> CP */
Boolean chgd_server; /* clear by CP */
Boolean elected_self;
- u8 *authorization_data1;
enum confidentiality_offset cipher_offset;
u64 cipher_suite;
Boolean new_sak; /* clear by CP */
@@ -216,6 +214,10 @@
SM_ENTRY(CP, RECEIVE);
/* RECEIVE state machine not keep with Figure 12-2 in
* IEEE Std 802.1X-2010 */
+ if (sm->oki) {
+ ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
+ os_free(sm->oki);
+ }
sm->oki = sm->lki;
sm->oan = sm->lan;
sm->otx = sm->ltx;
@@ -320,8 +322,11 @@
SM_ENTRY(CP, RETIRE);
/* RETIRE state machine not keep with Figure 12-2 in
* IEEE Std 802.1X-2010 */
- os_free(sm->oki);
- sm->oki = NULL;
+ if (sm->oki) {
+ ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
+ os_free(sm->oki);
+ sm->oki = NULL;
+ }
sm->orx = FALSE;
sm->otx = FALSE;
ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
@@ -383,7 +388,8 @@
if (!sm->elected_self)
SM_ENTER(CP, READY);
if (sm->elected_self &&
- (sm->all_receiving || !sm->transmit_when))
+ (sm->all_receiving || !sm->controlled_port_enabled ||
+ !sm->transmit_when))
SM_ENTER(CP, TRANSMIT);
break;
@@ -406,8 +412,8 @@
case CP_READY:
if (sm->new_sak || changed_connect(sm))
- SM_ENTER(CP, RECEIVE);
- if (sm->server_transmitting)
+ SM_ENTER(CP, ABANDON);
+ if (sm->server_transmitting || !sm->controlled_port_enabled)
SM_ENTER(CP, TRANSMIT);
break;
case CP_ABANDON:
@@ -464,7 +470,6 @@
sm->retire_delay = MKA_SAK_RETIRE_TIME;
sm->CP_state = CP_BEGIN;
sm->changed = FALSE;
- sm->authorization_data = NULL;
wpa_printf(MSG_DEBUG, "CP: state machine created");
@@ -476,7 +481,6 @@
secy_cp_control_confidentiality_offset(sm->kay,
sm->confidentiality_offset);
- SM_ENTER(CP, INIT);
SM_STEP_RUN(CP);
return sm;
@@ -518,7 +522,6 @@
eloop_cancel_timeout(ieee802_1x_cp_step_cb, sm, NULL);
os_free(sm->lki);
os_free(sm->oki);
- os_free(sm->authorization_data);
os_free(sm);
}
@@ -589,19 +592,6 @@
/**
- * ieee802_1x_cp_set_authorizationdata -
- */
-void ieee802_1x_cp_set_authorizationdata(void *cp_ctx, u8 *pdata, int len)
-{
- struct ieee802_1x_cp_sm *sm = cp_ctx;
- os_free(sm->authorization_data);
- sm->authorization_data = os_zalloc(len);
- if (sm->authorization_data)
- os_memcpy(sm->authorization_data, pdata, len);
-}
-
-
-/**
* ieee802_1x_cp_set_ciphersuite -
*/
void ieee802_1x_cp_set_ciphersuite(void *cp_ctx, u64 cs)
diff --git a/src/pae/ieee802_1x_cp.h b/src/pae/ieee802_1x_cp.h
index 695629e..a357b27 100644
--- a/src/pae/ieee802_1x_cp.h
+++ b/src/pae/ieee802_1x_cp.h
@@ -25,7 +25,6 @@
void ieee802_1x_cp_connect_secure(void *cp_ctx);
void ieee802_1x_cp_signal_chgdserver(void *cp_ctx);
void ieee802_1x_cp_set_electedself(void *cp_ctx, Boolean status);
-void ieee802_1x_cp_set_authorizationdata(void *cp_ctx, u8 *pdata, int len);
void ieee802_1x_cp_set_ciphersuite(void *cp_ctx, u64 cs);
void ieee802_1x_cp_set_offset(void *cp_ctx, enum confidentiality_offset offset);
void ieee802_1x_cp_signal_newsak(void *cp_ctx);
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index cad0292..b4455c8 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -1,5 +1,5 @@
/*
- * IEEE 802.1X-2010 Key Agree Protocol of PAE state machine
+ * IEEE 802.1X-2010 Key Agreement Protocol of PAE state machine
* Copyright (c) 2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
@@ -27,6 +27,9 @@
#define DEFAULT_ICV_LEN 16
#define MAX_ICV_LEN 32 /* 32 bytes, 256 bits */
+#define MAX_MISSING_SAK_USE 10 /* Accept up to 10 inbound MKPDUs without
+ * SAK-USE before dropping */
+
#define PENDING_PN_EXHAUSTION 0xC0000000
#define MKA_ALIGN_LENGTH(len) (((len) + 0x3) & ~0x3)
@@ -43,7 +46,13 @@
.name = CS_NAME_GCM_AES_128,
.capable = MACSEC_CAP_INTEG_AND_CONF_0_30_50,
.sak_len = DEFAULT_SA_KEY_LEN,
- .index = 0,
+ },
+ /* GCM-AES-256 */
+ {
+ .id = CS_ID_GCM_AES_256,
+ .name = CS_NAME_GCM_AES_256,
+ .capable = MACSEC_CAP_INTEG_AND_CONF_0_30_50,
+ .sak_len = 32,
},
};
#define CS_TABLE_SIZE (ARRAY_SIZE(cipher_suite_tbl))
@@ -53,19 +62,13 @@
{
.parameter = MKA_ALGO_AGILITY_2009,
- /* 128-bit CAK, KEK, ICK, ICV */
- .cak_len = DEFAULT_ICV_LEN,
- .kek_len = DEFAULT_ICV_LEN,
- .ick_len = DEFAULT_ICV_LEN,
.icv_len = DEFAULT_ICV_LEN,
- .cak_trfm = ieee802_1x_cak_128bits_aes_cmac,
- .ckn_trfm = ieee802_1x_ckn_128bits_aes_cmac,
- .kek_trfm = ieee802_1x_kek_128bits_aes_cmac,
- .ick_trfm = ieee802_1x_ick_128bits_aes_cmac,
- .icv_hash = ieee802_1x_icv_128bits_aes_cmac,
-
- .index = 1,
+ .cak_trfm = ieee802_1x_cak_aes_cmac,
+ .ckn_trfm = ieee802_1x_ckn_aes_cmac,
+ .kek_trfm = ieee802_1x_kek_aes_cmac,
+ .ick_trfm = ieee802_1x_ick_aes_cmac,
+ .icv_hash = ieee802_1x_icv_aes_cmac,
},
};
#define MKA_ALG_TABLE_SIZE (ARRAY_SIZE(mka_alg_tbl))
@@ -101,6 +104,34 @@
}
+static const char * mi_txt(const u8 *mi)
+{
+ static char txt[MI_LEN * 2 + 1];
+
+ wpa_snprintf_hex(txt, sizeof(txt), mi, MI_LEN);
+ return txt;
+}
+
+
+static const char * sci_txt(const struct ieee802_1x_mka_sci *sci)
+{
+ static char txt[ETH_ALEN * 3 + 1 + 5 + 1];
+
+ os_snprintf(txt, sizeof(txt), MACSTR "@%u",
+ MAC2STR(sci->addr), be_to_host16(sci->port));
+ return txt;
+}
+
+
+static const char * algo_agility_txt(const u8 *algo_agility)
+{
+ static char txt[4 * 2 + 1];
+
+ wpa_snprintf_hex(txt, sizeof(txt), algo_agility, 4);
+ return txt;
+}
+
+
/**
* ieee802_1x_mka_dump_basic_body -
*/
@@ -112,26 +143,25 @@
if (!body)
return;
+ /* IEEE Std 802.1X-2010, Figure 11-8 */
body_len = get_mka_param_body_len(body);
- wpa_printf(MSG_DEBUG, "*** MKA Basic Parameter set ***");
- wpa_printf(MSG_DEBUG, "\tVersion.......: %d", body->version);
- wpa_printf(MSG_DEBUG, "\tPriority......: %d", body->priority);
- wpa_printf(MSG_DEBUG, "\tKeySvr........: %d", body->key_server);
- wpa_printf(MSG_DEBUG, "\tMACSecDesired.: %d", body->macsec_desired);
- wpa_printf(MSG_DEBUG, "\tMACSecCapable.: %d", body->macsec_capability);
- wpa_printf(MSG_DEBUG, "\tBody Length...: %zu", body_len);
- wpa_printf(MSG_DEBUG, "\tSCI MAC.......: " MACSTR,
- MAC2STR(body->actor_sci.addr));
- wpa_printf(MSG_DEBUG, "\tSCI Port .....: %d",
- be_to_host16(body->actor_sci.port));
- wpa_hexdump(MSG_DEBUG, "\tMember Id.....:",
- body->actor_mi, sizeof(body->actor_mi));
- wpa_printf(MSG_DEBUG, "\tMessage Number: %d",
+ wpa_printf(MSG_DEBUG, "MKA Basic Parameter Set");
+ wpa_printf(MSG_DEBUG, "\tMKA Version Identifier: %d", body->version);
+ wpa_printf(MSG_DEBUG, "\tKey Server Priority: %d", body->priority);
+ wpa_printf(MSG_DEBUG, "\tKey Server: %d", body->key_server);
+ wpa_printf(MSG_DEBUG, "\tMACsec Desired: %d", body->macsec_desired);
+ wpa_printf(MSG_DEBUG, "\tMACsec Capability: %d",
+ body->macsec_capability);
+ wpa_printf(MSG_DEBUG, "\tParameter set body length: %zu", body_len);
+ wpa_printf(MSG_DEBUG, "\tSCI: %s", sci_txt(&body->actor_sci));
+ wpa_printf(MSG_DEBUG, "\tActor's Member Identifier: %s",
+ mi_txt(body->actor_mi));
+ wpa_printf(MSG_DEBUG, "\tActor's Message Number: %d",
be_to_host32(body->actor_mn));
- wpa_hexdump(MSG_DEBUG, "\tAlgo Agility..:",
- body->algo_agility, sizeof(body->algo_agility));
- wpa_hexdump_ascii(MSG_DEBUG, "\tCAK Name......:", body->ckn,
- body_len + MKA_HDR_LEN - sizeof(*body));
+ wpa_printf(MSG_DEBUG, "\tAlgorithm Agility: %s",
+ algo_agility_txt(body->algo_agility));
+ wpa_hexdump(MSG_DEBUG, "\tCAK Name", body->ckn,
+ body_len + MKA_HDR_LEN - sizeof(*body));
}
@@ -149,20 +179,21 @@
if (body == NULL)
return;
+ /* IEEE Std 802.1X-2010, Figure 11-9 */
body_len = get_mka_param_body_len(body);
if (body->type == MKA_LIVE_PEER_LIST) {
- wpa_printf(MSG_DEBUG, "*** Live Peer List ***");
- wpa_printf(MSG_DEBUG, "\tBody Length...: %zu", body_len);
+ wpa_printf(MSG_DEBUG, "Live Peer List parameter set");
+ wpa_printf(MSG_DEBUG, "\tBody Length: %zu", body_len);
} else if (body->type == MKA_POTENTIAL_PEER_LIST) {
- wpa_printf(MSG_DEBUG, "*** Potential Live Peer List ***");
- wpa_printf(MSG_DEBUG, "\tBody Length...: %zu", body_len);
+ wpa_printf(MSG_DEBUG, "Potential Peer List parameter set");
+ wpa_printf(MSG_DEBUG, "\tBody Length: %zu", body_len);
}
for (i = 0; i < body_len; i += MI_LEN + sizeof(mn)) {
mi = body->peer + i;
os_memcpy(&mn, mi + MI_LEN, sizeof(mn));
- wpa_hexdump_ascii(MSG_DEBUG, "\tMember Id.....:", mi, MI_LEN);
- wpa_printf(MSG_DEBUG, "\tMessage Number: %d", be_to_host32(mn));
+ wpa_printf(MSG_DEBUG, "\tMember Id: %s Message Number: %d",
+ mi_txt(mi), be_to_host32(mn));
}
}
@@ -178,18 +209,20 @@
if (body == NULL)
return;
+ /* IEEE Std 802.1X-2010, Figure 11-11 and 11-12 */
body_len = get_mka_param_body_len(body);
- wpa_printf(MSG_INFO, "*** Distributed SAK ***");
- wpa_printf(MSG_INFO, "\tDistributed AN........: %d", body->dan);
- wpa_printf(MSG_INFO, "\tConfidentiality Offset: %d",
+ wpa_printf(MSG_DEBUG, "Distributed SAK parameter set");
+ wpa_printf(MSG_DEBUG, "\tDistributed AN........: %d", body->dan);
+ wpa_printf(MSG_DEBUG, "\tConfidentiality Offset: %d",
body->confid_offset);
- wpa_printf(MSG_INFO, "\tBody Length...........: %zu", body_len);
+ wpa_printf(MSG_DEBUG, "\tBody Length...........: %zu", body_len);
if (!body_len)
return;
- wpa_printf(MSG_INFO, "\tKey Number............: %d",
+ wpa_printf(MSG_DEBUG, "\tKey Number............: %d",
be_to_host32(body->kn));
- wpa_hexdump(MSG_INFO, "\tAES Key Wrap of SAK...:", body->sak, 24);
+ /* TODO: Other than GCM-AES-128 case: MACsec Cipher Suite */
+ wpa_hexdump(MSG_DEBUG, "\tAES Key Wrap of SAK...:", body->sak, 24);
}
@@ -210,33 +243,32 @@
if (body == NULL)
return;
+ /* IEEE Std 802.1X-2010, Figure 11-10 */
body_len = get_mka_param_body_len(body);
- wpa_printf(MSG_DEBUG, "*** MACsec SAK Use ***");
+ wpa_printf(MSG_DEBUG, "MACsec SAK Use parameter set");
wpa_printf(MSG_DEBUG, "\tLatest Key AN....: %d", body->lan);
wpa_printf(MSG_DEBUG, "\tLatest Key Tx....: %s", yes_no(body->ltx));
wpa_printf(MSG_DEBUG, "\tLatest Key Rx....: %s", yes_no(body->lrx));
- wpa_printf(MSG_DEBUG, "\tOld Key AN....: %d", body->oan);
- wpa_printf(MSG_DEBUG, "\tOld Key Tx....: %s", yes_no(body->otx));
- wpa_printf(MSG_DEBUG, "\tOld Key Rx....: %s", yes_no(body->orx));
- wpa_printf(MSG_DEBUG, "\tPlain Key Tx....: %s", yes_no(body->ptx));
- wpa_printf(MSG_DEBUG, "\tPlain Key Rx....: %s", yes_no(body->prx));
+ wpa_printf(MSG_DEBUG, "\tOld Key AN.......: %d", body->oan);
+ wpa_printf(MSG_DEBUG, "\tOld Key Tx.......: %s", yes_no(body->otx));
+ wpa_printf(MSG_DEBUG, "\tOld Key Rx.......: %s", yes_no(body->orx));
+ wpa_printf(MSG_DEBUG, "\tPlain Tx.........: %s", yes_no(body->ptx));
+ wpa_printf(MSG_DEBUG, "\tPlain Rx.........: %s", yes_no(body->prx));
wpa_printf(MSG_DEBUG, "\tDelay Protect....: %s",
yes_no(body->delay_protect));
wpa_printf(MSG_DEBUG, "\tBody Length......: %d", body_len);
if (!body_len)
return;
- wpa_hexdump(MSG_DEBUG, "\tKey Server MI....:",
- body->lsrv_mi, sizeof(body->lsrv_mi));
+ wpa_printf(MSG_DEBUG, "\tKey Server MI....: %s", mi_txt(body->lsrv_mi));
wpa_printf(MSG_DEBUG, "\tKey Number.......: %u",
be_to_host32(body->lkn));
wpa_printf(MSG_DEBUG, "\tLowest PN........: %u",
be_to_host32(body->llpn));
- wpa_hexdump_ascii(MSG_DEBUG, "\tOld Key Server MI....:",
- body->osrv_mi, sizeof(body->osrv_mi));
- wpa_printf(MSG_DEBUG, "\tOld Key Number.......: %u",
+ wpa_printf(MSG_DEBUG, "\tOld Key Server MI: %s", mi_txt(body->osrv_mi));
+ wpa_printf(MSG_DEBUG, "\tOld Key Number...: %u",
be_to_host32(body->okn));
- wpa_printf(MSG_DEBUG, "\tOld Lowest PN........: %u",
+ wpa_printf(MSG_DEBUG, "\tOld Lowest PN....: %u",
be_to_host32(body->olpn));
}
@@ -245,13 +277,15 @@
* ieee802_1x_kay_get_participant -
*/
static struct ieee802_1x_mka_participant *
-ieee802_1x_kay_get_participant(struct ieee802_1x_kay *kay, const u8 *ckn)
+ieee802_1x_kay_get_participant(struct ieee802_1x_kay *kay, const u8 *ckn,
+ size_t len)
{
struct ieee802_1x_mka_participant *participant;
dl_list_for_each(participant, &kay->participant_list,
struct ieee802_1x_mka_participant, list) {
- if (os_memcmp(participant->ckn.name, ckn,
+ if (participant->ckn.len == len &&
+ os_memcmp(participant->ckn.name, ckn,
participant->ckn.len) == 0)
return participant;
}
@@ -361,7 +395,7 @@
*/
static struct macsec_ciphersuite *
ieee802_1x_kay_get_cipher_suite(struct ieee802_1x_mka_participant *participant,
- const u8 *cs_id)
+ const u8 *cs_id, unsigned int *idx)
{
unsigned int i;
u64 cs;
@@ -371,8 +405,10 @@
cs = be_to_host64(_cs);
for (i = 0; i < CS_TABLE_SIZE; i++) {
- if (cipher_suite_tbl[i].id == cs)
+ if (cipher_suite_tbl[i].id == cs) {
+ *idx = i;
return &cipher_suite_tbl[i];
+ }
}
return NULL;
@@ -454,7 +490,7 @@
dl_list_add(&psc->sa_list, &psa->list);
wpa_printf(MSG_DEBUG,
- "KaY: Create receive SA(AN: %hhu lowest_pn: %u of SC",
+ "KaY: Create receive SA(an: %hhu lowest_pn: %u) of SC",
an, lowest_pn);
return psa;
@@ -501,8 +537,8 @@
psc->receiving = FALSE;
dl_list_init(&psc->sa_list);
- wpa_printf(MSG_DEBUG, "KaY: Create receive SC");
- wpa_hexdump(MSG_DEBUG, "SCI: ", (u8 *)psci, sizeof(*psci));
+ wpa_printf(MSG_DEBUG, "KaY: Create receive SC: SCI %s",
+ sci_txt(&psc->sci));
return psc;
}
@@ -539,10 +575,8 @@
static void ieee802_1x_kay_dump_peer(struct ieee802_1x_kay_peer *peer)
{
- wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi, sizeof(peer->mi));
- wpa_printf(MSG_DEBUG, "\tMN: %d", peer->mn);
- wpa_hexdump(MSG_DEBUG, "\tSCI Addr: ", peer->sci.addr, ETH_ALEN);
- wpa_printf(MSG_DEBUG, "\tPort: %d", peer->sci.port);
+ wpa_printf(MSG_DEBUG, "\tMI: %s MN: %d SCI: %s",
+ mi_txt(peer->mi), peer->mn, sci_txt(&peer->sci));
}
@@ -561,6 +595,7 @@
peer->mn = mn;
peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
peer->sak_used = FALSE;
+ peer->missing_sak_use_count = 0;
return peer;
}
@@ -589,9 +624,13 @@
return NULL;
}
+ if (secy_create_receive_sc(participant->kay, rxsc)) {
+ os_free(rxsc);
+ os_free(peer);
+ return NULL;
+ }
dl_list_add(&participant->live_peers, &peer->list);
dl_list_add(&participant->rxsc_list, &rxsc->list);
- secy_create_receive_sc(participant->kay, rxsc);
wpa_printf(MSG_DEBUG, "KaY: Live peer created");
ieee802_1x_kay_dump_peer(peer);
@@ -615,7 +654,7 @@
dl_list_add(&participant->potential_peers, &peer->list);
- wpa_printf(MSG_DEBUG, "KaY: potential peer created");
+ wpa_printf(MSG_DEBUG, "KaY: Potential peer created");
ieee802_1x_kay_dump_peer(peer);
return peer;
@@ -645,14 +684,19 @@
peer->mn = mn;
peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
- wpa_printf(MSG_DEBUG, "KaY: move potential peer to live peer");
+ wpa_printf(MSG_DEBUG, "KaY: Move potential peer to live peer");
ieee802_1x_kay_dump_peer(peer);
dl_list_del(&peer->list);
+ if (secy_create_receive_sc(participant->kay, rxsc)) {
+ wpa_printf(MSG_ERROR, "KaY: Can't create SC, discard peer");
+ os_free(rxsc);
+ os_free(peer);
+ return NULL;
+ }
dl_list_add_tail(&participant->live_peers, &peer->list);
dl_list_add(&participant->rxsc_list, &rxsc->list);
- secy_create_receive_sc(participant->kay, rxsc);
return peer;
}
@@ -694,12 +738,15 @@
{
struct ieee802_1x_mka_basic_body *body;
struct ieee802_1x_kay *kay = participant->kay;
- unsigned int length = ieee802_1x_mka_basic_body_length(participant);
+ unsigned int length = sizeof(struct ieee802_1x_mka_basic_body);
- body = wpabuf_put(buf, length);
+ length += participant->ckn.len;
+ body = wpabuf_put(buf, MKA_ALIGN_LENGTH(length));
body->version = kay->mka_version;
body->priority = kay->actor_priority;
+ /* The Key Server flag is set if and only if the participant has not
+ * decided that another participant is or will be the Key Server. */
if (participant->is_elected)
body->key_server = participant->is_key_server;
else
@@ -748,22 +795,33 @@
struct ieee802_1x_mka_participant *participant;
const struct ieee802_1x_mka_basic_body *body;
struct ieee802_1x_kay_peer *peer;
+ size_t ckn_len;
+ size_t body_len;
body = (const struct ieee802_1x_mka_basic_body *) mka_msg;
if (body->version > MKA_VERSION_ID) {
wpa_printf(MSG_DEBUG,
- "KaY: peer's version(%d) greater than mka current version(%d)",
+ "KaY: Peer's version(%d) greater than MKA current version(%d)",
body->version, MKA_VERSION_ID);
}
if (kay->is_obliged_key_server && body->key_server) {
- wpa_printf(MSG_DEBUG, "I must be as key server");
+ wpa_printf(MSG_DEBUG, "KaY: I must be key server - ignore MKPDU claiming to be from a key server");
return NULL;
}
- participant = ieee802_1x_kay_get_participant(kay, body->ckn);
+ body_len = get_mka_param_body_len(body);
+ if (body_len < sizeof(struct ieee802_1x_mka_basic_body) - MKA_HDR_LEN) {
+ wpa_printf(MSG_DEBUG, "KaY: Too small body length %zu",
+ body_len);
+ return NULL;
+ }
+ ckn_len = body_len -
+ (sizeof(struct ieee802_1x_mka_basic_body) - MKA_HDR_LEN);
+ participant = ieee802_1x_kay_get_participant(kay, body->ckn, ckn_len);
if (!participant) {
- wpa_printf(MSG_DEBUG, "Peer is not included in my CA");
+ wpa_printf(MSG_DEBUG,
+ "KaY: Peer is not included in my CA - ignore MKPDU");
return NULL;
}
@@ -771,6 +829,9 @@
if (os_memcmp(body->actor_mi, participant->mi, MI_LEN) == 0) {
if (!reset_participant_mi(participant))
return NULL;
+ wpa_printf(MSG_DEBUG,
+ "KaY: Peer using my MI - selected a new random MI: %s",
+ mi_txt(participant->mi));
}
os_memcpy(participant->current_peer_id.mi, body->actor_mi, MI_LEN);
@@ -782,24 +843,48 @@
/* handler peer */
peer = ieee802_1x_kay_get_peer(participant, body->actor_mi);
if (!peer) {
- /* Check duplicated SCI */
- /* TODO: What policy should be applied to detect duplicated SCI
- * is active attacker or a valid peer whose MI is be changed?
+ /* Check duplicated SCI
+ *
+ * A duplicated SCI indicates either an active attacker or
+ * a valid peer whose MI is being changed. The latter scenario
+ * is more likely because to have gotten this far the received
+ * MKPDU must have had a valid ICV, indicating the peer holds
+ * the same CAK as our participant.
+ *
+ * Before creating a new peer object for the new MI we must
+ * clean up the resources (SCs and SAs) associated with the
+ * old peer. An easy way to do this is to ignore MKPDUs with
+ * the new MI's for now and just wait for the old peer to
+ * time out and clean itself up (within MKA_LIFE_TIME).
+ *
+ * This method is preferable to deleting the old peer here
+ * and now and continuing on with processing because if this
+ * MKPDU is from an attacker it's better to ignore the MKPDU
+ * than to process it (and delete a valid peer as well).
*/
peer = ieee802_1x_kay_get_peer_sci(participant,
&body->actor_sci);
if (peer) {
+ time_t new_expire;
+
wpa_printf(MSG_WARNING,
- "KaY: duplicated SCI detected, Maybe active attacker");
- dl_list_del(&peer->list);
- os_free(peer);
+ "KaY: duplicated SCI detected - maybe active attacker or peer selected new MI - ignore MKPDU");
+ /* Reduce timeout to speed up this process but left the
+ * chance for old one to prove aliveness. */
+ new_expire = time(NULL) + MKA_HELLO_TIME * 1.5 / 1000;
+ if (peer->expire > new_expire)
+ peer->expire = new_expire;
+ return NULL;
}
peer = ieee802_1x_kay_create_potential_peer(
participant, body->actor_mi,
be_to_host32(body->actor_mn));
- if (!peer)
+ if (!peer) {
+ wpa_printf(MSG_DEBUG,
+ "KaY: No potential peer entry found - ignore MKPDU");
return NULL;
+ }
peer->macsec_desired = body->macsec_desired;
peer->macsec_capability = body->macsec_capability;
@@ -807,13 +892,13 @@
peer->key_server_priority = body->priority;
} else if (peer->mn < be_to_host32(body->actor_mn)) {
peer->mn = be_to_host32(body->actor_mn);
- peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
peer->macsec_desired = body->macsec_desired;
peer->macsec_capability = body->macsec_capability;
peer->is_key_server = (Boolean) body->key_server;
peer->key_server_priority = body->priority;
} else {
- wpa_printf(MSG_WARNING, "KaY: The peer MN have received");
+ wpa_printf(MSG_WARNING,
+ "KaY: The peer MN did not increase - ignore MKPDU");
return NULL;
}
@@ -958,8 +1043,8 @@
for (pos = mka_msg, left_len = msg_len;
left_len > MKA_HDR_LEN + DEFAULT_ICV_LEN;
- left_len -= body_len + MKA_HDR_LEN,
- pos += body_len + MKA_HDR_LEN) {
+ left_len -= MKA_ALIGN_LENGTH(body_len) + MKA_HDR_LEN,
+ pos += MKA_ALIGN_LENGTH(body_len) + MKA_HDR_LEN) {
hdr = (struct ieee802_1x_mka_hdr *) pos;
body_len = get_mka_param_body_len(hdr);
body_type = get_mka_param_body_type(hdr);
@@ -994,9 +1079,15 @@
peer_mi = (const struct ieee802_1x_mka_peer_id *)
(pos + MKA_HDR_LEN + i);
if (os_memcmp(peer_mi->mi, participant->mi,
- MI_LEN) == 0 &&
- be_to_host32(peer_mi->mn) == participant->mn)
- return TRUE;
+ MI_LEN) == 0) {
+ u32 mn = be_to_host32(peer_mi->mn);
+
+ wpa_printf(MSG_DEBUG,
+ "KaY: My MI - received MN %u, most recently transmitted MN %u",
+ mn, participant->mn);
+ if (mn == participant->mn)
+ return TRUE;
+ }
}
}
@@ -1052,7 +1143,6 @@
peer = ieee802_1x_kay_get_peer(participant, peer_mi->mi);
if (peer) {
peer->mn = peer_mn;
- peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
} else if (!ieee802_1x_kay_create_potential_peer(
participant, peer_mi->mi, peer_mn)) {
return -1;
@@ -1134,27 +1224,38 @@
/**
- *
+ * ieee802_1x_mka_get_lpn
*/
static u32
ieee802_1x_mka_get_lpn(struct ieee802_1x_mka_participant *principal,
struct ieee802_1x_mka_ki *ki)
{
- struct receive_sa *rxsa;
- struct receive_sc *rxsc;
+ struct transmit_sa *txsa;
u32 lpn = 0;
- dl_list_for_each(rxsc, &principal->rxsc_list, struct receive_sc, list) {
- dl_list_for_each(rxsa, &rxsc->sa_list, struct receive_sa, list)
- {
- if (is_ki_equal(&rxsa->pkey->key_identifier, ki)) {
- secy_get_receive_lowest_pn(principal->kay,
- rxsa);
+ dl_list_for_each(txsa, &principal->txsc->sa_list,
+ struct transmit_sa, list) {
+ if (is_ki_equal(&txsa->pkey->key_identifier, ki)) {
+ /* Per IEEE Std 802.1X-2010, Clause 9, "Each SecY uses
+ * MKA to communicate the lowest PN used for
+ * transmission with the SAK within the last two
+ * seconds". Achieve this 2 second delay by setting the
+ * lpn using the transmit next PN (i.e., txsa->next_pn)
+ * that was read last time here (i.e., mka_hello_time
+ * 2 seconds ago).
+ *
+ * The lowest acceptable PN is the same as the last
+ * transmitted PN, which is one less than the next
+ * transmit PN.
+ *
+ * NOTE: This method only works if mka_hello_time is 2s.
+ */
+ lpn = (txsa->next_pn > 0) ? (txsa->next_pn - 1) : 0;
- lpn = lpn > rxsa->lowest_pn ?
- lpn : rxsa->lowest_pn;
- break;
- }
+ /* Now read the current transmit next PN for use next
+ * time through. */
+ secy_get_transmit_next_pn(principal->kay, txsa);
+ break;
}
}
@@ -1194,8 +1295,9 @@
return 0;
}
- /* data protect, lowest accept packet number */
- body->delay_protect = kay->macsec_replay_protect;
+ /* data delay protect */
+ body->delay_protect = kay->mka_hello_time <= MKA_BOUNDED_HELLO_TIME;
+ /* lowest accept packet number */
pn = ieee802_1x_mka_get_lpn(participant, &participant->lki);
if (pn > kay->pn_exhaustion) {
wpa_printf(MSG_WARNING, "KaY: My LPN exhaustion");
@@ -1256,7 +1358,8 @@
struct ieee802_1x_mka_hdr *hdr;
struct ieee802_1x_mka_sak_use_body *body;
struct ieee802_1x_kay_peer *peer;
- struct transmit_sa *txsa;
+ struct receive_sc *rxsc;
+ struct receive_sa *rxsa;
struct data_key *sa_key = NULL;
size_t body_len;
struct ieee802_1x_mka_ki ki;
@@ -1272,7 +1375,9 @@
peer = ieee802_1x_kay_get_live_peer(participant,
participant->current_peer_id.mi);
if (!peer) {
- wpa_printf(MSG_WARNING, "KaY: the peer is not my live peer");
+ wpa_printf(MSG_WARNING,
+ "KaY: The peer (%s) is not my live peer - ignore MACsec SAK Use parameter set",
+ mi_txt(participant->current_peer_id.mi));
return -1;
}
@@ -1316,7 +1421,7 @@
}
}
if (!found) {
- wpa_printf(MSG_WARNING, "KaY: Latest key is invalid");
+ wpa_printf(MSG_INFO, "KaY: Latest key is invalid");
return -1;
}
if (os_memcmp(participant->lki.mi, body->lsrv_mi,
@@ -1331,8 +1436,8 @@
}
}
- /* check old key is valid */
- if (body->otx || body->orx) {
+ /* check old key is valid (but only if we remember our old key) */
+ if (participant->oki.kn != 0 && (body->otx || body->orx)) {
if (os_memcmp(participant->oki.mi, body->osrv_mi,
sizeof(participant->oki.mi)) != 0 ||
be_to_host32(body->okn) != participant->oki.kn ||
@@ -1346,7 +1451,7 @@
if (body->delay_protect &&
(!be_to_host32(body->llpn) || !be_to_host32(body->olpn))) {
wpa_printf(MSG_WARNING,
- "KaY: Lowest packet number should greater than 0 when delay_protect is TRUE");
+ "KaY: Lowest packet number should be greater than 0 when delay_protect is TRUE");
return -1;
}
@@ -1365,7 +1470,7 @@
ieee802_1x_cp_sm_step(kay->cp);
}
- /* if i'm key server, and detects peer member pn exhaustion, rekey.*/
+ /* if I'm key server, and detects peer member pn exhaustion, rekey. */
lpn = be_to_host32(body->llpn);
if (lpn > kay->pn_exhaustion) {
if (participant->is_key_server) {
@@ -1374,26 +1479,41 @@
}
}
+ if (sa_key)
+ sa_key->next_pn = lpn;
found = FALSE;
- dl_list_for_each(txsa, &participant->txsc->sa_list,
- struct transmit_sa, list) {
- if (sa_key != NULL && txsa->pkey == sa_key) {
- found = TRUE;
- break;
+ dl_list_for_each(rxsc, &participant->rxsc_list, struct receive_sc,
+ list) {
+ dl_list_for_each(rxsa, &rxsc->sa_list, struct receive_sa,
+ list) {
+ if (sa_key && rxsa->pkey == sa_key) {
+ found = TRUE;
+ break;
+ }
}
+ if (found)
+ break;
}
if (!found) {
- wpa_printf(MSG_WARNING, "KaY: Can't find txsa");
+ wpa_printf(MSG_WARNING, "KaY: Can't find rxsa");
return -1;
}
- /* FIXME: Secy creates txsa with default npn. If MKA detected Latest Key
- * npn is larger than txsa's npn, set it to txsa.
- */
- secy_get_transmit_next_pn(kay, txsa);
- if (lpn > txsa->next_pn) {
- secy_set_transmit_next_pn(kay, txsa);
- wpa_printf(MSG_INFO, "KaY: update lpn =0x%x", lpn);
+ if (body->delay_protect) {
+ secy_get_receive_lowest_pn(participant->kay, rxsa);
+ if (lpn > rxsa->lowest_pn) {
+ /* Delay protect window (communicated via MKA) is
+ * tighter than SecY's current replay protect window,
+ * so tell SecY the new (and higher) lpn. */
+ rxsa->lowest_pn = lpn;
+ secy_set_receive_lowest_pn(participant->kay, rxsa);
+ wpa_printf(MSG_DEBUG, "KaY: update lpn =0x%x", lpn);
+ }
+ /* FIX: Delay protection for olpn not implemented.
+ * Note that Old Key is only active for MKA_SAK_RETIRE_TIME
+ * (3 seconds) and delay protection does allow PN's within
+ * a 2 seconds window, so olpn would be a lot of work for
+ * just 1 second's worth of protection. */
}
return 0;
@@ -1407,7 +1527,8 @@
ieee802_1x_mka_dist_sak_body_present(
struct ieee802_1x_mka_participant *participant)
{
- return participant->to_dist_sak && participant->new_key;
+ return participant->is_key_server && participant->to_dist_sak &&
+ participant->new_key;
}
@@ -1458,6 +1579,11 @@
}
sak = participant->new_key;
+ if (!sak) {
+ wpa_printf(MSG_DEBUG,
+ "KaY: No SAK available to build Distributed SAK parameter set");
+ return -1;
+ }
body->confid_offset = sak->confidentiality_offset;
body->dan = sak->an;
body->kn = host_to_be32(sak->key_identifier.kn);
@@ -1472,7 +1598,7 @@
os_memcpy(body->sak, &cs, CS_ID_LEN);
sak_pos = CS_ID_LEN;
}
- if (aes_wrap(participant->kek.key, 16,
+ if (aes_wrap(participant->kek.key, participant->kek.len,
cipher_suite_tbl[cs_index].sak_len / 8,
sak->key, body->sak + sak_pos)) {
wpa_printf(MSG_ERROR, "KaY: AES wrap failed");
@@ -1494,6 +1620,7 @@
pkey->receives = TRUE;
os_get_time(&pkey->created_time);
+ pkey->next_pn = 1;
pkey->user = 1;
}
@@ -1533,7 +1660,7 @@
}
if (participant->is_key_server) {
wpa_printf(MSG_ERROR,
- "KaY: I can't accept the distributed SAK as myself is key server ");
+ "KaY: Reject distributed SAK since I'm a key server");
return -1;
}
if (!kay->macsec_desired ||
@@ -1562,7 +1689,7 @@
participant->advised_desired = FALSE;
ieee802_1x_cp_connect_authenticated(kay->cp);
ieee802_1x_cp_sm_step(kay->cp);
- wpa_printf(MSG_WARNING, "KaY:The Key server advise no MACsec");
+ wpa_printf(MSG_WARNING, "KaY: The Key server advise no MACsec");
participant->to_use_sak = FALSE;
return 0;
}
@@ -1581,7 +1708,8 @@
if (os_memcmp(sa_key->key_identifier.mi,
participant->current_peer_id.mi, MI_LEN) == 0 &&
sa_key->key_identifier.kn == be_to_host32(body->kn)) {
- wpa_printf(MSG_WARNING, "KaY:The Key has installed");
+ wpa_printf(MSG_DEBUG,
+ "KaY: SAK has already been installed - do not set it again");
return 0;
}
}
@@ -1592,7 +1720,10 @@
kay->macsec_csindex = DEFAULT_CS_INDEX;
cs = &cipher_suite_tbl[kay->macsec_csindex];
} else {
- cs = ieee802_1x_kay_get_cipher_suite(participant, body->sak);
+ unsigned int idx;
+
+ cs = ieee802_1x_kay_get_cipher_suite(participant, body->sak,
+ &idx);
if (!cs) {
wpa_printf(MSG_ERROR,
"KaY: I can't support the Cipher Suite advised by key server");
@@ -1600,7 +1731,7 @@
}
sak_len = cs->sak_len;
wrap_sak = body->sak + CS_ID_LEN;
- kay->macsec_csindex = cs->index;
+ kay->macsec_csindex = idx;
}
unwrap_sak = os_zalloc(sak_len);
@@ -1608,13 +1739,14 @@
wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
return -1;
}
- if (aes_unwrap(participant->kek.key, 16, sak_len >> 3, wrap_sak,
- unwrap_sak)) {
+ if (aes_unwrap(participant->kek.key, participant->kek.len,
+ sak_len >> 3, wrap_sak, unwrap_sak)) {
wpa_printf(MSG_ERROR, "KaY: AES unwrap failed");
os_free(unwrap_sak);
return -1;
}
- wpa_hexdump(MSG_DEBUG, "\tAES Key Unwrap of SAK:", unwrap_sak, sak_len);
+ wpa_hexdump_key(MSG_DEBUG, "\tAES Key Unwrap of SAK.:",
+ unwrap_sak, sak_len);
sa_key = os_zalloc(sizeof(*sa_key));
if (!sa_key) {
@@ -1670,7 +1802,12 @@
{
int length;
- length = sizeof(struct ieee802_1x_mka_icv_body);
+ /* Determine if we need space for the ICV Indicator */
+ if (mka_alg_tbl[participant->kay->mka_algindex].icv_len !=
+ DEFAULT_ICV_LEN)
+ length = sizeof(struct ieee802_1x_mka_icv_body);
+ else
+ length = 0;
length += mka_alg_tbl[participant->kay->mka_algindex].icv_len;
return MKA_ALIGN_LENGTH(length);
@@ -1689,20 +1826,23 @@
u8 cmac[MAX_ICV_LEN];
length = ieee802_1x_mka_get_icv_length(participant);
- if (length != DEFAULT_ICV_LEN) {
+ if (mka_alg_tbl[participant->kay->mka_algindex].icv_len !=
+ DEFAULT_ICV_LEN) {
+ wpa_printf(MSG_DEBUG, "KaY: ICV Indicator");
body = wpabuf_put(buf, MKA_HDR_LEN);
body->type = MKA_ICV_INDICATOR;
- set_mka_param_body_len(body, length - MKA_HDR_LEN);
+ length -= MKA_HDR_LEN;
+ set_mka_param_body_len(body, length);
}
if (mka_alg_tbl[participant->kay->mka_algindex].icv_hash(
- participant->ick.key, wpabuf_head(buf), buf->used, cmac)) {
- wpa_printf(MSG_ERROR, "KaY, omac1_aes_128 failed");
+ participant->ick.key, participant->ick.len,
+ wpabuf_head(buf), wpabuf_len(buf), cmac)) {
+ wpa_printf(MSG_ERROR, "KaY: failed to calculate ICV");
return -1;
}
+ wpa_hexdump(MSG_DEBUG, "KaY: ICV", cmac, length);
- if (length != DEFAULT_ICV_LEN)
- length -= MKA_HDR_LEN;
os_memcpy(wpabuf_put(buf, length), cmac, length);
return 0;
@@ -1711,12 +1851,12 @@
/**
* ieee802_1x_mka_decode_icv_body -
*/
-static u8 *
+static const u8 *
ieee802_1x_mka_decode_icv_body(struct ieee802_1x_mka_participant *participant,
const u8 *mka_msg, size_t msg_len)
{
- struct ieee802_1x_mka_hdr *hdr;
- struct ieee802_1x_mka_icv_body *body;
+ const struct ieee802_1x_mka_hdr *hdr;
+ const struct ieee802_1x_mka_icv_body *body;
size_t body_len;
size_t left_len;
u8 body_type;
@@ -1724,12 +1864,12 @@
pos = mka_msg;
left_len = msg_len;
- while (left_len > (MKA_HDR_LEN + DEFAULT_ICV_LEN)) {
- hdr = (struct ieee802_1x_mka_hdr *) pos;
- body_len = get_mka_param_body_len(hdr);
+ while (left_len > MKA_HDR_LEN + DEFAULT_ICV_LEN) {
+ hdr = (const struct ieee802_1x_mka_hdr *) pos;
+ body_len = MKA_ALIGN_LENGTH(get_mka_param_body_len(hdr));
body_type = get_mka_param_body_type(hdr);
- if (left_len < (body_len + MKA_HDR_LEN))
+ if (left_len < body_len + MKA_HDR_LEN)
break;
if (body_type != MKA_ICV_INDICATOR) {
@@ -1738,16 +1878,15 @@
continue;
}
- body = (struct ieee802_1x_mka_icv_body *)pos;
+ body = (const struct ieee802_1x_mka_icv_body *) pos;
if (body_len
- < mka_alg_tbl[participant->kay->mka_algindex].icv_len) {
+ < mka_alg_tbl[participant->kay->mka_algindex].icv_len)
return NULL;
- }
return body->icv;
}
- return (u8 *) (mka_msg + msg_len - DEFAULT_ICV_LEN);
+ return mka_msg + msg_len - DEFAULT_ICV_LEN;
}
@@ -1766,7 +1905,7 @@
body_len = get_mka_param_body_len(hdr);
if (body_len < 28) {
wpa_printf(MSG_ERROR,
- "KaY: MKA Use SAK Packet Body Length (%zu bytes) should be 28 or more octets",
+ "KaY: MKA Use CAK Packet Body Length (%zu bytes) should be 28 or more octets",
body_len);
return -1;
}
@@ -1790,7 +1929,7 @@
body_len = get_mka_param_body_len(hdr);
if (body_len < 5) {
wpa_printf(MSG_ERROR,
- "KaY: MKA Use SAK Packet Body Length (%zu bytes) should be 5 or more octets",
+ "KaY: MKA Use KMD Packet Body Length (%zu bytes) should be 5 or more octets",
body_len);
return -1;
}
@@ -1821,7 +1960,7 @@
static struct mka_param_body_handler mka_body_handler[] = {
- /* basic parameter set */
+ /* Basic parameter set */
{
.body_tx = ieee802_1x_mka_encode_basic_body,
.body_rx = NULL,
@@ -1829,7 +1968,7 @@
.body_present = ieee802_1x_mka_basic_body_present
},
- /* live peer list parameter set */
+ /* Live Peer List parameter set */
{
.body_tx = ieee802_1x_mka_encode_live_peer_body,
.body_rx = ieee802_1x_mka_decode_live_peer_body,
@@ -1837,7 +1976,7 @@
.body_present = ieee802_1x_mka_live_peer_body_present
},
- /* potential peer list parameter set */
+ /* Potential Peer List parameter set */
{
.body_tx = ieee802_1x_mka_encode_potential_peer_body,
.body_rx = ieee802_1x_mka_decode_potential_peer_body,
@@ -1845,7 +1984,7 @@
.body_present = ieee802_1x_mka_potential_peer_body_present
},
- /* sak use parameter set */
+ /* MACsec SAK Use parameter set */
{
.body_tx = ieee802_1x_mka_encode_sak_use_body,
.body_rx = ieee802_1x_mka_decode_sak_use_body,
@@ -1853,7 +1992,7 @@
.body_present = ieee802_1x_mka_sak_use_body_present
},
- /* distribute sak parameter set */
+ /* Distributed SAK parameter set */
{
.body_tx = ieee802_1x_mka_encode_dist_sak_body,
.body_rx = ieee802_1x_mka_decode_dist_sak_body,
@@ -1861,7 +2000,7 @@
.body_present = ieee802_1x_mka_dist_sak_body_present
},
- /* distribute cak parameter set */
+ /* Distribute CAK parameter set */
{
.body_tx = NULL,
.body_rx = ieee802_1x_mka_decode_dist_cak_body,
@@ -1869,7 +2008,7 @@
.body_present = NULL
},
- /* kmd parameter set */
+ /* KMD parameter set */
{
.body_tx = NULL,
.body_rx = ieee802_1x_mka_decode_kmd_body,
@@ -1877,7 +2016,7 @@
.body_present = NULL
},
- /* announce parameter set */
+ /* Announcement parameter set */
{
.body_tx = NULL,
.body_rx = ieee802_1x_mka_decode_announce_body,
@@ -1885,7 +2024,7 @@
.body_present = NULL
},
- /* icv parameter set */
+ /* ICV Indicator parameter set */
{
.body_tx = ieee802_1x_mka_encode_icv_body,
.body_rx = NULL,
@@ -1944,7 +2083,7 @@
*/
if (dl_list_empty(&participant->live_peers)) {
wpa_printf(MSG_ERROR,
- "KaY: Live peers list must not empty when generating fresh SAK");
+ "KaY: Live peers list must not be empty when generating fresh SAK");
return -1;
}
@@ -1958,7 +2097,7 @@
*/
if ((time(NULL) - kay->dist_time) < MKA_LIFE_TIME / 1000) {
wpa_printf(MSG_ERROR,
- "KaY: Life time have not elapsed since prior SAK distributed");
+ "KaY: Life time has not elapsed since prior SAK distributed");
return -1;
}
@@ -1995,17 +2134,20 @@
ctx_offset += sizeof(participant->mi);
os_memcpy(context + ctx_offset, &kay->dist_kn, sizeof(kay->dist_kn));
- if (key_len == 16) {
- ieee802_1x_sak_128bits_aes_cmac(participant->cak.key,
- context, ctx_len, key);
- } else if (key_len == 32) {
- ieee802_1x_sak_128bits_aes_cmac(participant->cak.key,
- context, ctx_len, key);
+ if (key_len == 16 || key_len == 32) {
+ if (ieee802_1x_sak_aes_cmac(participant->cak.key,
+ participant->cak.len,
+ context, ctx_len,
+ key, key_len)) {
+ wpa_printf(MSG_ERROR, "KaY: Failed to generate SAK");
+ goto fail;
+ }
} else {
- wpa_printf(MSG_ERROR, "KaY: SAK Length not support");
+ wpa_printf(MSG_ERROR, "KaY: SAK Length(%u) not supported",
+ key_len);
goto fail;
}
- wpa_hexdump(MSG_DEBUG, "KaY: generated new SAK", key, key_len);
+ wpa_hexdump_key(MSG_DEBUG, "KaY: generated new SAK", key, key_len);
os_free(context);
context = NULL;
@@ -2081,6 +2223,7 @@
struct ieee802_1x_kay_peer *key_server = NULL;
struct ieee802_1x_kay *kay = participant->kay;
Boolean i_is_key_server;
+ int priority_comparison;
if (participant->is_obliged_key_server) {
participant->new_sak = TRUE;
@@ -2111,8 +2254,14 @@
tmp.key_server_priority = kay->actor_priority;
os_memcpy(&tmp.sci, &kay->actor_sci, sizeof(tmp.sci));
- if (compare_priorities(&tmp, key_server) < 0)
+ priority_comparison = compare_priorities(&tmp, key_server);
+ if (priority_comparison < 0) {
i_is_key_server = TRUE;
+ } else if (priority_comparison == 0) {
+ wpa_printf(MSG_WARNING,
+ "KaY: Cannot elect key server between me and peer, duplicate MAC detected");
+ key_server = NULL;
+ }
} else if (participant->can_be_key_server) {
i_is_key_server = TRUE;
}
@@ -2127,7 +2276,7 @@
participant->is_key_server = TRUE;
participant->principal = TRUE;
participant->new_sak = TRUE;
- wpa_printf(MSG_DEBUG, "KaY: I is elected as key server");
+ wpa_printf(MSG_DEBUG, "KaY: I am elected as key server");
participant->to_dist_sak = FALSE;
participant->is_elected = TRUE;
@@ -2135,6 +2284,9 @@
sizeof(kay->key_server_sci));
kay->key_server_priority = kay->actor_priority;
} else if (key_server) {
+ wpa_printf(MSG_DEBUG,
+ "KaY: Peer %s was elected as the key server",
+ mi_txt(key_server->mi));
ieee802_1x_cp_set_electedself(kay->cp, FALSE);
if (!sci_equal(&kay->key_server_sci, &key_server->sci)) {
ieee802_1x_cp_signal_chgdserver(kay->cp);
@@ -2253,11 +2405,19 @@
os_memcpy(ether_hdr->src, participant->kay->actor_sci.addr,
sizeof(ether_hdr->dest));
ether_hdr->ethertype = host_to_be16(ETH_P_EAPOL);
+ wpa_printf(MSG_DEBUG, "KaY: Ethernet header: DA=" MACSTR " SA=" MACSTR
+ " Ethertype=0x%x",
+ MAC2STR(ether_hdr->dest), MAC2STR(ether_hdr->src),
+ be_to_host16(ether_hdr->ethertype));
eapol_hdr = wpabuf_put(pbuf, sizeof(*eapol_hdr));
eapol_hdr->version = EAPOL_VERSION;
eapol_hdr->type = IEEE802_1X_TYPE_EAPOL_MKA;
- eapol_hdr->length = host_to_be16(pbuf->size - pbuf->used);
+ eapol_hdr->length = host_to_be16(wpabuf_tailroom(pbuf));
+ wpa_printf(MSG_DEBUG,
+ "KaY: Common EAPOL PDU structure: Protocol Version=%u Packet Type=%u Packet Body Length=%u",
+ eapol_hdr->version, eapol_hdr->type,
+ be_to_host16(eapol_hdr->length));
for (i = 0; i < ARRAY_SIZE(mka_body_handler); i++) {
if (mka_body_handler[i].body_present &&
@@ -2270,6 +2430,7 @@
return 0;
}
+
/**
* ieee802_1x_participant_send_mkpdu -
*/
@@ -2282,7 +2443,8 @@
size_t length = 0;
unsigned int i;
- wpa_printf(MSG_DEBUG, "KaY: to enpacket and send the MKPDU");
+ wpa_printf(MSG_DEBUG, "KaY: Encode and send an MKPDU (ifname=%s)",
+ kay->if_name);
length += sizeof(struct ieee802_1x_hdr) + sizeof(struct ieee8023_hdr);
for (i = 0; i < ARRAY_SIZE(mka_body_handler); i++) {
if (mka_body_handler[i].body_present &&
@@ -2297,10 +2459,11 @@
}
if (ieee802_1x_kay_encode_mkpdu(participant, buf)) {
- wpa_printf(MSG_ERROR, "KaY: encode mkpdu fail!");
+ wpa_printf(MSG_ERROR, "KaY: encode mkpdu fail");
return -1;
}
+ wpa_hexdump_buf(MSG_MSGDUMP, "KaY: Outgoing MKPDU", buf);
l2_packet_send(kay->l2_mka, NULL, 0, wpabuf_head(buf), wpabuf_len(buf));
wpabuf_free(buf);
@@ -2337,6 +2500,8 @@
participant = (struct ieee802_1x_mka_participant *)eloop_ctx;
kay = participant->kay;
+ wpa_printf(MSG_DEBUG, "KaY: Participant timer (ifname=%s)",
+ kay->if_name);
if (participant->cak_life) {
if (now > participant->cak_life)
goto delete_mka;
@@ -2387,7 +2552,7 @@
participant->orx = FALSE;
participant->is_key_server = FALSE;
participant->is_elected = FALSE;
- kay->authenticated = TRUE;
+ kay->authenticated = FALSE;
kay->secured = FALSE;
kay->failed = FALSE;
kay->ltx_kn = 0;
@@ -2404,7 +2569,7 @@
ieee802_1x_delete_transmit_sa(kay, txsa);
}
- ieee802_1x_cp_connect_authenticated(kay->cp);
+ ieee802_1x_cp_connect_pending(kay->cp);
ieee802_1x_cp_sm_step(kay->cp);
} else {
ieee802_1x_kay_elect_key_server(participant);
@@ -2424,7 +2589,7 @@
}
}
- if (participant->new_sak) {
+ if (participant->new_sak && participant->is_key_server) {
if (!ieee802_1x_kay_generate_new_sak(participant))
participant->to_dist_sak = TRUE;
@@ -2437,7 +2602,7 @@
participant->retry_count++;
}
- eloop_register_timeout(MKA_HELLO_TIME / 1000, 0,
+ eloop_register_timeout(kay->mka_hello_time / 1000, 0,
ieee802_1x_participant_timer,
participant, NULL);
@@ -2486,7 +2651,7 @@
dl_list_add(&psc->sa_list, &psa->list);
wpa_printf(MSG_DEBUG,
- "KaY: Create transmit SA(an: %hhu, next_PN: %u) of SC",
+ "KaY: Create transmit SA(an: %hhu, next_pn: %u) of SC",
an, next_PN);
return psa;
@@ -2529,8 +2694,8 @@
psc->enciphering_sa = FALSE;
dl_list_init(&psc->sa_list);
- wpa_printf(MSG_DEBUG, "KaY: Create transmit SC");
- wpa_hexdump(MSG_DEBUG, "SCI: ", (u8 *)sci , sizeof(*sci));
+ wpa_printf(MSG_DEBUG, "KaY: Create transmit SC - SCI: %s",
+ sci_txt(&psc->sci));
return psc;
}
@@ -2681,7 +2846,7 @@
}
}
if (!latest_sak) {
- wpa_printf(MSG_ERROR, "lki related sak not found");
+ wpa_printf(MSG_ERROR, "KaY: lki related sak not found");
return -1;
}
@@ -2702,7 +2867,9 @@
ieee802_1x_delete_transmit_sa(kay, txsa);
txsa = ieee802_1x_kay_init_transmit_sa(principal->txsc, latest_sak->an,
- 1, latest_sak);
+ latest_sak->next_pn ?
+ latest_sak->next_pn : 1,
+ latest_sak);
if (!txsa)
return -1;
@@ -2751,12 +2918,12 @@
dl_list_for_each_safe(sa_key, pre_key, &principal->sak_list,
struct data_key, list) {
if (is_ki_equal(&sa_key->key_identifier, ki)) {
+ if (principal->new_key == sa_key)
+ principal->new_key = NULL;
dl_list_del(&sa_key->list);
ieee802_1x_kay_deinit_data_key(sa_key);
break;
}
- if (principal->new_key == sa_key)
- principal->new_key = NULL;
}
return 0;
@@ -2844,7 +3011,8 @@
/**
* ieee802_1x_kay_mkpdu_sanity_check -
- * sanity check specified in clause 11.11.2 of IEEE802.1X-2010
+ * Sanity checks specified in IEEE Std 802.1X-2010, 11.11.2 (Validation of
+ * MKPDUs)
*/
static int ieee802_1x_kay_mkpdu_sanity_check(struct ieee802_1x_kay *kay,
const u8 *buf, size_t len)
@@ -2856,35 +3024,51 @@
size_t mka_msg_len;
struct ieee802_1x_mka_participant *participant;
size_t body_len;
+ size_t ckn_len;
u8 icv[MAX_ICV_LEN];
- u8 *msg_icv;
+ const u8 *msg_icv;
+ /* len > eth+eapol header already verified in kay_l2_receive();
+ * likewise, eapol_hdr->length validated there */
eth_hdr = (struct ieee8023_hdr *) buf;
eapol_hdr = (struct ieee802_1x_hdr *) (eth_hdr + 1);
mka_hdr = (struct ieee802_1x_mka_hdr *) (eapol_hdr + 1);
- /* destination address should be not individual address */
+ wpa_printf(MSG_DEBUG, "KaY: Ethernet header: DA=" MACSTR " SA=" MACSTR
+ " Ethertype=0x%x",
+ MAC2STR(eth_hdr->dest), MAC2STR(eth_hdr->src),
+ be_to_host16(eth_hdr->ethertype));
+
+ /* the destination address shall not be an individual address */
if (os_memcmp(eth_hdr->dest, pae_group_addr, ETH_ALEN) != 0) {
- wpa_printf(MSG_MSGDUMP,
+ wpa_printf(MSG_DEBUG,
"KaY: ethernet destination address is not PAE group address");
return -1;
}
- /* MKPDU should not be less than 32 octets */
+ wpa_printf(MSG_DEBUG,
+ "KaY: Common EAPOL PDU structure: Protocol Version=%u Packet Type=%u Packet Body Length=%u",
+ eapol_hdr->version, eapol_hdr->type,
+ be_to_host16(eapol_hdr->length));
+
+ /* MKPDU shall not be less than 32 octets */
mka_msg_len = be_to_host16(eapol_hdr->length);
if (mka_msg_len < 32) {
- wpa_printf(MSG_MSGDUMP, "KaY: MKPDU is less than 32 octets");
+ wpa_printf(MSG_DEBUG, "KaY: MKPDU is less than 32 octets");
return -1;
}
- /* MKPDU should be a multiple of 4 octets */
+ /* MKPDU shall be a multiple of 4 octets */
if ((mka_msg_len % 4) != 0) {
- wpa_printf(MSG_MSGDUMP,
+ wpa_printf(MSG_DEBUG,
"KaY: MKPDU is not multiple of 4 octets");
return -1;
}
+ wpa_hexdump(MSG_MSGDUMP, "KaY: EAPOL-MKA Packet Body (MKPDU)",
+ mka_hdr, mka_msg_len);
+
+ /* Room for body_len already verified in kay_l2_receive() */
body = (struct ieee802_1x_mka_basic_body *) mka_hdr;
- ieee802_1x_mka_dump_basic_body(body);
body_len = get_mka_param_body_len(body);
/* EAPOL-MKA body should comprise basic parameter set and ICV */
if (mka_msg_len < MKA_HDR_LEN + body_len + DEFAULT_ICV_LEN) {
@@ -2895,18 +3079,35 @@
return -1;
}
+ if (body_len < sizeof(struct ieee802_1x_mka_basic_body) - MKA_HDR_LEN) {
+ wpa_printf(MSG_DEBUG, "KaY: Too small body length %zu",
+ body_len);
+ return -1;
+ }
+ ckn_len = body_len -
+ (sizeof(struct ieee802_1x_mka_basic_body) - MKA_HDR_LEN);
+ if (ckn_len < 1 || ckn_len > MAX_CKN_LEN) {
+ wpa_printf(MSG_WARNING,
+ "KaY: Received EAPOL-MKA CKN Length (%zu bytes) is out of range (<= %u bytes)",
+ ckn_len, MAX_CKN_LEN);
+ return -1;
+ }
+
+ ieee802_1x_mka_dump_basic_body(body);
+
/* CKN should be owned by I */
- participant = ieee802_1x_kay_get_participant(kay, body->ckn);
+ participant = ieee802_1x_kay_get_participant(kay, body->ckn, ckn_len);
if (!participant) {
- wpa_printf(MSG_DEBUG, "CKN is not included in my CA");
+ wpa_printf(MSG_DEBUG, "KaY: CKN is not included in my CA");
return -1;
}
/* algorithm agility check */
if (os_memcmp(body->algo_agility, mka_algo_agility,
sizeof(body->algo_agility)) != 0) {
- wpa_printf(MSG_ERROR,
- "KaY: peer's algorithm agility not supported for me");
+ wpa_printf(MSG_INFO,
+ "KaY: Peer's algorithm agility (%s) not supported",
+ algo_agility_txt(body->algo_agility));
return -1;
}
@@ -2916,23 +3117,29 @@
* its size, not the fixed length 16 octets, indicated by the EAPOL
* packet body length.
*/
- if (mka_alg_tbl[kay->mka_algindex].icv_hash(
- participant->ick.key,
+ if (len < mka_alg_tbl[kay->mka_algindex].icv_len ||
+ mka_alg_tbl[kay->mka_algindex].icv_hash(
+ participant->ick.key, participant->ick.len,
buf, len - mka_alg_tbl[kay->mka_algindex].icv_len, icv)) {
- wpa_printf(MSG_ERROR, "KaY: omac1_aes_128 failed");
+ wpa_printf(MSG_ERROR, "KaY: Failed to calculate ICV");
return -1;
}
- msg_icv = ieee802_1x_mka_decode_icv_body(participant, (u8 *) mka_hdr,
+ msg_icv = ieee802_1x_mka_decode_icv_body(participant,
+ (const u8 *) mka_hdr,
mka_msg_len);
if (!msg_icv) {
- wpa_printf(MSG_ERROR, "KaY: No ICV");
+ wpa_printf(MSG_WARNING, "KaY: No ICV in MKPDU - ignore it");
return -1;
}
+ wpa_hexdump(MSG_DEBUG, "KaY: Received ICV",
+ msg_icv, mka_alg_tbl[kay->mka_algindex].icv_len);
if (os_memcmp_const(msg_icv, icv,
mka_alg_tbl[kay->mka_algindex].icv_len) != 0) {
- wpa_printf(MSG_ERROR,
+ wpa_printf(MSG_WARNING,
"KaY: Computed ICV is not equal to Received ICV");
+ wpa_hexdump(MSG_DEBUG, "KaY: Calculated ICV",
+ icv, mka_alg_tbl[kay->mka_algindex].icv_len);
return -1;
}
@@ -2948,13 +3155,19 @@
{
struct ieee802_1x_mka_participant *participant;
struct ieee802_1x_mka_hdr *hdr;
+ struct ieee802_1x_kay_peer *peer;
size_t body_len;
size_t left_len;
u8 body_type;
int i;
const u8 *pos;
Boolean handled[256];
+ Boolean bad_sak_use = FALSE; /* Error detected while processing SAK Use
+ * parameter set */
+ Boolean i_in_peerlist, is_in_live_peer, is_in_potential_peer;
+ wpa_printf(MSG_DEBUG, "KaY: Decode received MKPDU (ifname=%s)",
+ kay->if_name);
if (ieee802_1x_kay_mkpdu_sanity_check(kay, buf, len))
return -1;
@@ -2968,17 +3181,24 @@
/* to skip basic parameter set */
hdr = (struct ieee802_1x_mka_hdr *) pos;
- body_len = get_mka_param_body_len(hdr);
+ body_len = MKA_ALIGN_LENGTH(get_mka_param_body_len(hdr));
+ if (left_len < body_len + MKA_HDR_LEN)
+ return -1;
pos += body_len + MKA_HDR_LEN;
left_len -= body_len + MKA_HDR_LEN;
/* check i am in the peer's peer list */
- if (ieee802_1x_mka_i_in_peerlist(participant, pos, left_len) &&
- !ieee802_1x_kay_is_in_live_peer(participant,
- participant->current_peer_id.mi)) {
+ i_in_peerlist = ieee802_1x_mka_i_in_peerlist(participant, pos,
+ left_len);
+ is_in_live_peer = ieee802_1x_kay_is_in_live_peer(
+ participant, participant->current_peer_id.mi);
+ wpa_printf(MSG_DEBUG, "KaY: i_in_peerlist=%s is_in_live_peer=%s",
+ yes_no(i_in_peerlist), yes_no(is_in_live_peer));
+ if (i_in_peerlist && !is_in_live_peer) {
/* accept the peer as live peer */
- if (ieee802_1x_kay_is_in_potential_peer(
- participant, participant->current_peer_id.mi)) {
+ is_in_potential_peer = ieee802_1x_kay_is_in_potential_peer(
+ participant, participant->current_peer_id.mi);
+ if (is_in_potential_peer) {
if (!ieee802_1x_kay_move_live_peer(
participant,
participant->current_peer_id.mi,
@@ -3008,7 +3228,7 @@
pos += body_len + MKA_HDR_LEN,
left_len -= body_len + MKA_HDR_LEN) {
hdr = (struct ieee802_1x_mka_hdr *) pos;
- body_len = get_mka_param_body_len(hdr);
+ body_len = MKA_ALIGN_LENGTH(get_mka_param_body_len(hdr));
body_type = get_mka_param_body_type(hdr);
if (body_type == MKA_ICV_INDICATOR)
@@ -3022,21 +3242,103 @@
return -1;
}
- if (handled[body_type])
+ if (handled[body_type]) {
+ wpa_printf(MSG_DEBUG,
+ "KaY: Ignore duplicated body type %u",
+ body_type);
continue;
+ }
handled[body_type] = TRUE;
if (body_type < ARRAY_SIZE(mka_body_handler) &&
mka_body_handler[body_type].body_rx) {
- mka_body_handler[body_type].body_rx
- (participant, pos, left_len);
+ if (mka_body_handler[body_type].body_rx
+ (participant, pos, left_len) != 0) {
+ /* Handle parameter set failure */
+ if (body_type != MKA_SAK_USE) {
+ wpa_printf(MSG_INFO,
+ "KaY: Discarding Rx MKPDU: decode of parameter set type (%d) failed",
+ body_type);
+ return -1;
+ }
+
+ /* Ideally DIST-SAK should be processed before
+ * SAK-USE. Unfortunately IEEE Std 802.1X-2010,
+ * 11.11.3 (Encoding MKPDUs) states SAK-USE(3)
+ * must always be encoded before DIST-SAK(4).
+ * Rather than redesigning mka_body_handler so
+ * that it somehow processes DIST-SAK before
+ * SAK-USE, just ignore SAK-USE failures if
+ * DIST-SAK is also present in this MKPDU. */
+ bad_sak_use = TRUE;
+ }
} else {
wpa_printf(MSG_ERROR,
- "The type %d is not supported in this MKA version %d",
+ "KaY: The body type %d is not supported in this MKA version %d",
body_type, MKA_VERSION_ID);
}
}
+ if (bad_sak_use && !handled[MKA_DISTRIBUTED_SAK]) {
+ wpa_printf(MSG_INFO,
+ "KaY: Discarding Rx MKPDU: decode of parameter set type (%d) failed",
+ MKA_SAK_USE);
+ if (!reset_participant_mi(participant))
+ wpa_printf(MSG_DEBUG, "KaY: Could not update mi");
+ else
+ wpa_printf(MSG_DEBUG,
+ "KaY: Selected a new random MI: %s",
+ mi_txt(participant->mi));
+ return -1;
+ }
+
+ /* Detect missing parameter sets */
+ peer = ieee802_1x_kay_get_live_peer(participant,
+ participant->current_peer_id.mi);
+ if (peer) {
+ /* MKPDU is from live peer */
+ if (!handled[MKA_SAK_USE]) {
+ /* Once a live peer starts sending SAK-USE, it should be
+ * sent every time. */
+ if (peer->sak_used) {
+ wpa_printf(MSG_INFO,
+ "KaY: Discarding Rx MKPDU: Live Peer stopped sending SAK-USE");
+ return -1;
+ }
+
+ /* Live peer is probably hung if it hasn't sent SAK-USE
+ * after a reasonable number of MKPDUs. Drop the MKPDU,
+ * which will eventually force an timeout. */
+ if (++peer->missing_sak_use_count >
+ MAX_MISSING_SAK_USE) {
+ wpa_printf(MSG_INFO,
+ "KaY: Discarding Rx MKPDU: Live Peer not sending SAK-USE");
+ return -1;
+ }
+ } else {
+ peer->missing_sak_use_count = 0;
+
+ /* Only update live peer watchdog after successful
+ * decode of all parameter sets */
+ peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
+ }
+ } else {
+ /* MKPDU is from new or potential peer */
+ peer = ieee802_1x_kay_get_peer(participant,
+ participant->current_peer_id.mi);
+ if (!peer) {
+ wpa_printf(MSG_DEBUG, "KaY: No peer entry found");
+ return -1;
+ }
+
+ /* Do not update potential peer watchdog. Per IEEE Std
+ * 802.1X-2010, 9.4.3, potential peers need to show liveness by
+ * including our MI/MN in their transmitted MKPDU (within
+ * potential or live parameter sets). Whena potential peer does
+ * include our MI/MN in an MKPDU, we respond by moving the peer
+ * from 'potential_peers' to 'live_peers'. */
+ }
+
kay->active = TRUE;
participant->retry_count = 0;
participant->active = TRUE;
@@ -3052,6 +3354,9 @@
struct ieee802_1x_kay *kay = ctx;
struct ieee8023_hdr *eth_hdr;
struct ieee802_1x_hdr *eapol_hdr;
+ size_t calc_len;
+
+ /* IEEE Std 802.1X-2010, 11.4 (Validation of received EAPOL PDUs) */
/* must contain at least ieee8023_hdr + ieee802_1x_hdr */
if (len < sizeof(*eth_hdr) + sizeof(*eapol_hdr)) {
@@ -3062,13 +3367,21 @@
eth_hdr = (struct ieee8023_hdr *) buf;
eapol_hdr = (struct ieee802_1x_hdr *) (eth_hdr + 1);
- if (len != sizeof(*eth_hdr) + sizeof(*eapol_hdr) +
- be_to_host16(eapol_hdr->length)) {
- wpa_printf(MSG_MSGDUMP, "KAY: EAPOL MPDU is invalid: (%lu-%lu)",
+ calc_len = sizeof(*eth_hdr) + sizeof(*eapol_hdr) +
+ be_to_host16(eapol_hdr->length);
+ if (len < calc_len) {
+ wpa_printf(MSG_MSGDUMP, "KaY: EAPOL MPDU is invalid: (received len %lu, calculated len %lu, EAPOL length %u)",
(unsigned long) len,
- (unsigned long) be_to_host16(eapol_hdr->length));
+ (unsigned long) calc_len,
+ be_to_host16(eapol_hdr->length));
return;
}
+ if (len > calc_len) {
+ wpa_hexdump(MSG_DEBUG,
+ "KaY: Ignore extra octets following the Packey Body field",
+ &buf[calc_len], len - calc_len);
+ len = calc_len;
+ }
if (eapol_hdr->version < EAPOL_VERSION) {
wpa_printf(MSG_MSGDUMP, "KaY: version %d does not support MKA",
@@ -3077,11 +3390,12 @@
}
if (be_to_host16(eth_hdr->ethertype) != ETH_P_PAE ||
eapol_hdr->type != IEEE802_1X_TYPE_EAPOL_MKA)
- return;
+ return; /* ignore other EAPOL types silently here */
- wpa_hexdump(MSG_DEBUG, "RX EAPOL-MKA: ", buf, len);
+ wpa_hexdump(MSG_DEBUG, "KaY: RX EAPOL-MKA", buf, len);
if (dl_list_empty(&kay->participant_list)) {
- wpa_printf(MSG_ERROR, "KaY: no MKA participant instance");
+ wpa_printf(MSG_ERROR,
+ "KaY: No MKA participant instance - ignore EAPOL-MKA");
return;
}
@@ -3094,10 +3408,14 @@
*/
struct ieee802_1x_kay *
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
+ Boolean macsec_replay_protect, u32 macsec_replay_window,
u16 port, u8 priority, const char *ifname, const u8 *addr)
{
struct ieee802_1x_kay *kay;
+ wpa_printf(MSG_DEBUG, "KaY: Initialize - ifname=%s addr=" MACSTR
+ " port=%u priority=%u",
+ ifname, MAC2STR(addr), port, priority);
kay = os_zalloc(sizeof(*kay));
if (!kay) {
wpa_printf(MSG_ERROR, "KaY-%s: out of memory", __func__);
@@ -3118,6 +3436,8 @@
os_strlcpy(kay->if_name, ifname, IFNAMSIZ);
os_memcpy(kay->actor_sci.addr, addr, ETH_ALEN);
kay->actor_sci.port = host_to_be16(port ? port : 0x0001);
+ wpa_printf(MSG_DEBUG, "KaY: Generated SCI: %s",
+ sci_txt(&kay->actor_sci));
kay->actor_priority = priority;
/* While actor acts as a key server, shall distribute sakey */
@@ -3144,21 +3464,27 @@
kay->macsec_capable = MACSEC_CAP_NOT_IMPLEMENTED;
kay->macsec_desired = FALSE;
kay->macsec_protect = FALSE;
+ kay->macsec_encrypt = FALSE;
kay->macsec_validate = Disabled;
kay->macsec_replay_protect = FALSE;
kay->macsec_replay_window = 0;
kay->macsec_confidentiality = CONFIDENTIALITY_NONE;
+ kay->mka_hello_time = MKA_HELLO_TIME;
} else {
kay->macsec_desired = TRUE;
kay->macsec_protect = TRUE;
- kay->macsec_encrypt = policy == SHOULD_ENCRYPT;
- kay->macsec_validate = Strict;
- kay->macsec_replay_protect = FALSE;
- kay->macsec_replay_window = 0;
- if (kay->macsec_capable >= MACSEC_CAP_INTEG_AND_CONF)
+ if (kay->macsec_capable >= MACSEC_CAP_INTEG_AND_CONF &&
+ policy == SHOULD_ENCRYPT) {
+ kay->macsec_encrypt = TRUE;
kay->macsec_confidentiality = CONFIDENTIALITY_OFFSET_0;
- else
+ } else { /* SHOULD_SECURE */
+ kay->macsec_encrypt = FALSE;
kay->macsec_confidentiality = CONFIDENTIALITY_NONE;
+ }
+ kay->macsec_validate = Strict;
+ kay->macsec_replay_protect = macsec_replay_protect;
+ kay->macsec_replay_window = macsec_replay_window;
+ kay->mka_hello_time = MKA_HELLO_TIME;
}
wpa_printf(MSG_DEBUG, "KaY: state machine created");
@@ -3230,28 +3556,47 @@
}
+static const char * mode_txt(enum mka_created_mode mode)
+{
+ switch (mode) {
+ case PSK:
+ return "PSK";
+ case EAP_EXCHANGE:
+ return "EAP";
+ }
+
+ return "?";
+}
+
+
/**
* ieee802_1x_kay_create_mka -
*/
struct ieee802_1x_mka_participant *
-ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay, struct mka_key_name *ckn,
- struct mka_key *cak, u32 life,
+ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay,
+ const struct mka_key_name *ckn,
+ const struct mka_key *cak, u32 life,
enum mka_created_mode mode, Boolean is_authenticator)
{
struct ieee802_1x_mka_participant *participant;
unsigned int usecs;
+ wpa_printf(MSG_DEBUG,
+ "KaY: Create MKA (ifname=%s mode=%s authenticator=%s)",
+ kay->if_name, mode_txt(mode), yes_no(is_authenticator));
+
if (!kay || !ckn || !cak) {
wpa_printf(MSG_ERROR, "KaY: ckn or cak is null");
return NULL;
}
- if (cak->len != mka_alg_tbl[kay->mka_algindex].cak_len) {
- wpa_printf(MSG_ERROR, "KaY: CAK length not follow key schema");
+ if (cak->len != 16 && cak->len != 32) {
+ wpa_printf(MSG_ERROR, "KaY: Unexpected CAK length %u",
+ (unsigned int) cak->len);
return NULL;
}
if (ckn->len > MAX_CKN_LEN) {
- wpa_printf(MSG_ERROR, "KaY: CKN is out of range(<=32 bytes)");
+ wpa_printf(MSG_ERROR, "KaY: CKN is out of range (>32 bytes)");
return NULL;
}
if (!kay->enable) {
@@ -3267,8 +3612,12 @@
participant->ckn.len = ckn->len;
os_memcpy(participant->ckn.name, ckn->name, ckn->len);
+ wpa_hexdump(MSG_DEBUG, "KaY: CKN", participant->ckn.name,
+ participant->ckn.len);
participant->cak.len = cak->len;
os_memcpy(participant->cak.key, cak->key, cak->len);
+ wpa_hexdump_key(MSG_DEBUG, "KaY: CAK", participant->cak.key,
+ participant->cak.len);
if (life)
participant->cak_life = life + time(NULL);
@@ -3318,6 +3667,8 @@
if (!reset_participant_mi(participant))
goto fail;
+ wpa_printf(MSG_DEBUG, "KaY: Selected random MI: %s",
+ mi_txt(participant->mi));
participant->lrx = FALSE;
participant->ltx = FALSE;
@@ -3333,37 +3684,40 @@
secy_cp_control_protect_frames(kay, kay->macsec_protect);
secy_cp_control_replay(kay, kay->macsec_replay_protect,
kay->macsec_replay_window);
- secy_create_transmit_sc(kay, participant->txsc);
+ if (secy_create_transmit_sc(kay, participant->txsc))
+ goto fail;
/* to derive KEK from CAK and CKN */
- participant->kek.len = mka_alg_tbl[kay->mka_algindex].kek_len;
+ participant->kek.len = participant->cak.len;
if (mka_alg_tbl[kay->mka_algindex].kek_trfm(participant->cak.key,
+ participant->cak.len,
participant->ckn.name,
participant->ckn.len,
- participant->kek.key)) {
- wpa_printf(MSG_ERROR, "KaY: Derived KEK failed");
+ participant->kek.key,
+ participant->kek.len)) {
+ wpa_printf(MSG_ERROR, "KaY: KEK derivation failed");
goto fail;
}
wpa_hexdump_key(MSG_DEBUG, "KaY: Derived KEK",
participant->kek.key, participant->kek.len);
/* to derive ICK from CAK and CKN */
- participant->ick.len = mka_alg_tbl[kay->mka_algindex].ick_len;
+ participant->ick.len = participant->cak.len;
if (mka_alg_tbl[kay->mka_algindex].ick_trfm(participant->cak.key,
+ participant->cak.len,
participant->ckn.name,
participant->ckn.len,
- participant->ick.key)) {
- wpa_printf(MSG_ERROR, "KaY: Derived ICK failed");
+ participant->ick.key,
+ participant->ick.len)) {
+ wpa_printf(MSG_ERROR, "KaY: ICK derivation failed");
goto fail;
}
wpa_hexdump_key(MSG_DEBUG, "KaY: Derived ICK",
participant->ick.key, participant->ick.len);
dl_list_add(&kay->participant_list, &participant->list);
- wpa_hexdump(MSG_DEBUG, "KaY: Participant created:",
- ckn->name, ckn->len);
- usecs = os_random() % (MKA_HELLO_TIME * 1000);
+ usecs = os_random() % (kay->mka_hello_time * 1000);
eloop_register_timeout(0, usecs, ieee802_1x_participant_timer,
participant, NULL);
@@ -3381,6 +3735,7 @@
return participant;
fail:
+ os_free(participant->txsc);
os_free(participant);
return NULL;
}
@@ -3403,7 +3758,7 @@
wpa_printf(MSG_DEBUG, "KaY: participant removed");
/* get the participant */
- participant = ieee802_1x_kay_get_participant(kay, ckn->name);
+ participant = ieee802_1x_kay_get_participant(kay, ckn->name, ckn->len);
if (!participant) {
wpa_hexdump(MSG_DEBUG, "KaY: participant is not found",
ckn->name, ckn->len);
@@ -3462,7 +3817,7 @@
if (!kay || !ckn)
return;
- participant = ieee802_1x_kay_get_participant(kay, ckn->name);
+ participant = ieee802_1x_kay_get_participant(kay, ckn->name, ckn->len);
if (!participant)
return;
@@ -3536,6 +3891,7 @@
#ifdef CONFIG_CTRL_IFACE
+
/**
* ieee802_1x_kay_get_status - Get IEEE 802.1X KaY status details
* @sm: Pointer to KaY allocated with ieee802_1x_kay_init()
@@ -3544,19 +3900,24 @@
* @verbose: Whether to include verbose status information
* Returns: Number of bytes written to buf.
*
- * Query KAY status information. This function fills in a text area with current
+ * Query KaY status information. This function fills in a text area with current
* status information. If the buffer (buf) is not large enough, status
* information will be truncated to fit the buffer.
*/
int ieee802_1x_kay_get_status(struct ieee802_1x_kay *kay, char *buf,
size_t buflen)
{
- int len;
+ char *pos, *end;
+ int res, count;
+ struct ieee802_1x_mka_participant *p;
if (!kay)
return 0;
- len = os_snprintf(buf, buflen,
+ pos = buf;
+ end = buf + buflen;
+
+ res = os_snprintf(pos, end - pos,
"PAE KaY status=%s\n"
"Authenticated=%s\n"
"Secured=%s\n"
@@ -3565,7 +3926,8 @@
"Key Server Priority=%u\n"
"Is Key Server=%s\n"
"Number of Keys Distributed=%u\n"
- "Number of Keys Received=%u\n",
+ "Number of Keys Received=%u\n"
+ "MKA Hello Time=%u\n",
kay->active ? "Active" : "Not-Active",
kay->authenticated ? "Yes" : "No",
kay->secured ? "Yes" : "No",
@@ -3574,10 +3936,162 @@
kay->key_server_priority,
kay->is_key_server ? "Yes" : "No",
kay->dist_kn - 1,
- kay->rcvd_keys);
- if (os_snprintf_error(buflen, len))
+ kay->rcvd_keys,
+ kay->mka_hello_time);
+ if (os_snprintf_error(buflen, res))
+ return 0;
+ pos += res;
+
+ res = os_snprintf(pos, end - pos,
+ "actor_sci=%s\n", sci_txt(&kay->actor_sci));
+ if (os_snprintf_error(buflen, res))
+ return end - pos;
+ pos += res;
+
+ res = os_snprintf(pos, end - pos,
+ "key_server_sci=%s\n", sci_txt(&kay->key_server_sci));
+ if (os_snprintf_error(buflen, res))
+ return end - pos;
+ pos += res;
+
+ count = 0;
+ dl_list_for_each(p, &kay->participant_list,
+ struct ieee802_1x_mka_participant, list) {
+ char *pos2 = pos;
+
+ res = os_snprintf(pos2, end - pos2, "participant_idx=%d\nckn=",
+ count);
+ if (os_snprintf_error(buflen, res))
+ return end - pos;
+ pos2 += res;
+ count++;
+
+ pos2 += wpa_snprintf_hex(pos2, end - pos2, p->ckn.name,
+ p->ckn.len);
+
+ res = os_snprintf(pos2, end - pos2,
+ "\nmi=%s\n"
+ "mn=%u\n"
+ "active=%s\n"
+ "participant=%s\n"
+ "retain=%s\n"
+ "live_peers=%u\n"
+ "potential_peers=%u\n"
+ "is_key_server=%s\n"
+ "is_elected=%s\n",
+ mi_txt(p->mi), p->mn,
+ yes_no(p->active),
+ yes_no(p->participant),
+ yes_no(p->retain),
+ dl_list_len(&p->live_peers),
+ dl_list_len(&p->potential_peers),
+ yes_no(p->is_key_server),
+ yes_no(p->is_elected));
+ if (os_snprintf_error(buflen, res))
+ return end - pos;
+ pos2 += res;
+ pos = pos2;
+ }
+
+ return pos - buf;
+}
+
+
+static const char * true_false(Boolean val)
+{
+ return val ? "true" : "false";
+}
+
+
+static const char * activate_control_txt(enum activate_ctrl activate)
+{
+ switch (activate) {
+ case DEFAULT:
+ return "default";
+ case DISABLED:
+ return "disabled";
+ case ON_OPER_UP:
+ return "onOperUp";
+ case ALWAYS:
+ return "always";
+ }
+
+ return "?";
+}
+
+
+static char * mka_mib_peer(struct dl_list *peers, Boolean live, char *buf,
+ char *end)
+{
+ char *pos = buf;
+ struct ieee802_1x_kay_peer *p;
+ int res;
+
+ dl_list_for_each(p, peers, struct ieee802_1x_kay_peer, list) {
+ res = os_snprintf(pos, end - pos,
+ "ieee8021XKayMkaPeerListMI=%s\n"
+ "ieee8021XKayMkaPeerListMN=%u\n"
+ "ieee8021XKayMkaPeerListType=%u\n"
+ "ieee8021XKayMkaPeerListSCI=%s\n",
+ mi_txt(p->mi),
+ p->mn,
+ live ? 1 : 2,
+ sci_txt(&p->sci));
+ if (os_snprintf_error(end - pos, res))
+ return pos;
+ pos += res;
+ }
+
+ return pos;
+}
+
+
+int ieee802_1x_kay_get_mib(struct ieee802_1x_kay *kay, char *buf,
+ size_t buflen)
+{
+ char *pos, *end;
+ int res;
+ struct ieee802_1x_mka_participant *p;
+
+ if (!kay)
return 0;
- return len;
+ pos = buf;
+ end = buf + buflen;
+
+ dl_list_for_each(p, &kay->participant_list,
+ struct ieee802_1x_mka_participant, list) {
+ char *pos2 = pos;
+
+ res = os_snprintf(pos2, end - pos2, "ieee8021XKayMkaPartCKN=");
+ if (os_snprintf_error(buflen, res))
+ return end - pos;
+ pos2 += res;
+
+ pos2 += wpa_snprintf_hex(pos2, end - pos2, p->ckn.name,
+ p->ckn.len);
+
+ res = os_snprintf(pos2, end - pos2,
+ "\nieee8021XKayMkaPartCached=%s\n"
+ "ieee8021XKayMkaPartActive=%s\n"
+ "ieee8021XKayMkaPartRetain=%s\n"
+ "ieee8021XKayMkaPartActivateControl=%s\n"
+ "ieee8021XKayMkaPartPrincipal=%s\n",
+ true_false(p->cached),
+ true_false(p->active),
+ true_false(p->retain),
+ activate_control_txt(p->activate),
+ true_false(p->principal));
+ if (os_snprintf_error(buflen, res))
+ return end - pos;
+ pos2 += res;
+ pos = pos2;
+
+ pos = mka_mib_peer(&p->live_peers, TRUE, pos, end);
+ pos = mka_mib_peer(&p->potential_peers, FALSE, pos, end);
+ }
+
+ return pos - buf;
}
+
#endif /* CONFIG_CTRL_IFACE */
diff --git a/src/pae/ieee802_1x_kay.h b/src/pae/ieee802_1x_kay.h
index 8f394fd..3367d3a 100644
--- a/src/pae/ieee802_1x_kay.h
+++ b/src/pae/ieee802_1x_kay.h
@@ -21,6 +21,7 @@
/* MKA timer, unit: millisecond */
#define MKA_HELLO_TIME 2000
+#define MKA_BOUNDED_HELLO_TIME 500
#define MKA_LIFE_TIME 6000
#define MKA_SAK_RETIRE_TIME 3000
@@ -38,7 +39,7 @@
struct ieee802_1x_mka_sci {
u8 addr[ETH_ALEN];
be16 port;
-};
+} STRUCT_PACKED;
struct mka_key {
u8 key[MAX_KEY_LEN];
@@ -149,6 +150,7 @@
int (*get_receive_lowest_pn)(void *ctx, struct receive_sa *sa);
int (*get_transmit_next_pn)(void *ctx, struct transmit_sa *sa);
int (*set_transmit_next_pn)(void *ctx, struct transmit_sa *sa);
+ int (*set_receive_lowest_pn)(void *ctx, struct receive_sa *sa);
int (*create_receive_sc)(void *ctx, struct receive_sc *sc,
enum validate_frames vf,
enum confidentiality_offset co);
@@ -187,6 +189,7 @@
u32 macsec_replay_window;
enum validate_frames macsec_validate;
enum confidentiality_offset macsec_confidentiality;
+ u32 mka_hello_time;
u32 ltx_kn;
u8 ltx_an;
@@ -236,12 +239,14 @@
struct ieee802_1x_kay *
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
+ Boolean macsec_replay_protect, u32 macsec_replay_window,
u16 port, u8 priority, const char *ifname, const u8 *addr);
void ieee802_1x_kay_deinit(struct ieee802_1x_kay *kay);
struct ieee802_1x_mka_participant *
ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay,
- struct mka_key_name *ckn, struct mka_key *cak,
+ const struct mka_key_name *ckn,
+ const struct mka_key *cak,
u32 life, enum mka_created_mode mode,
Boolean is_authenticator);
void ieee802_1x_kay_delete_mka(struct ieee802_1x_kay *kay,
@@ -270,5 +275,7 @@
int ieee802_1x_kay_enable_new_info(struct ieee802_1x_kay *kay);
int ieee802_1x_kay_get_status(struct ieee802_1x_kay *kay, char *buf,
size_t buflen);
+int ieee802_1x_kay_get_mib(struct ieee802_1x_kay *kay, char *buf,
+ size_t buflen);
#endif /* IEEE802_1X_KAY_H */
diff --git a/src/pae/ieee802_1x_kay_i.h b/src/pae/ieee802_1x_kay_i.h
index bc522d8..f9cd3f4 100644
--- a/src/pae/ieee802_1x_kay_i.h
+++ b/src/pae/ieee802_1x_kay_i.h
@@ -15,7 +15,7 @@
#define MKA_VERSION_ID 1
-/* IEEE Std 802.1X-2010, 11.11.1, Table 11-7 */
+/* IEEE Std 802.1X-2010, 11.11.1, Table 11-7 (MKPDU parameter sets) */
enum mka_packet_type {
MKA_BASIC_PARAMETER_SET = MKA_VERSION_ID,
MKA_LIVE_PEER_LIST = 1,
@@ -39,7 +39,7 @@
struct ieee802_1x_mka_peer_id {
u8 mi[MI_LEN];
be32 mn;
-};
+} STRUCT_PACKED;
struct ieee802_1x_kay_peer {
struct ieee802_1x_mka_sci sci;
@@ -51,6 +51,7 @@
Boolean macsec_desired;
enum macsec_cap macsec_capability;
Boolean sak_used;
+ int missing_sak_use_count;
struct dl_list list;
};
@@ -59,25 +60,24 @@
char name[32];
enum macsec_cap capable;
int sak_len; /* unit: byte */
-
- u32 index;
};
struct mka_alg {
u8 parameter[4];
- size_t cak_len;
- size_t kek_len;
- size_t ick_len;
size_t icv_len;
- int (*cak_trfm)(const u8 *msk, const u8 *mac1, const u8 *mac2, u8 *cak);
- int (*ckn_trfm)(const u8 *msk, const u8 *mac1, const u8 *mac2,
- const u8 *sid, size_t sid_len, u8 *ckn);
- int (*kek_trfm)(const u8 *cak, const u8 *ckn, size_t ckn_len, u8 *kek);
- int (*ick_trfm)(const u8 *cak, const u8 *ckn, size_t ckn_len, u8 *ick);
- int (*icv_hash)(const u8 *ick, const u8 *msg, size_t msg_len, u8 *icv);
-
- int index; /* index for configuring */
+ int (*cak_trfm)(const u8 *msk, size_t msk_bytes, const u8 *mac1,
+ const u8 *mac2, u8 *cak, size_t cak_bytes);
+ int (*ckn_trfm)(const u8 *msk, size_t msk_bytes, const u8 *mac1,
+ const u8 *mac2, const u8 *sid, size_t sid_len, u8 *ckn);
+ int (*kek_trfm)(const u8 *cak, size_t cak_bytes,
+ const u8 *ckn, size_t ckn_len,
+ u8 *kek, size_t kek_bytes);
+ int (*ick_trfm)(const u8 *cak, size_t cak_bytes,
+ const u8 *ckn, size_t ckn_len,
+ u8 *ick, size_t ick_bytes);
+ int (*icv_hash)(const u8 *ick, size_t ick_bytes,
+ const u8 *msg, size_t msg_len, u8 *icv);
};
#define DEFAULT_MKA_ALG_INDEX 0
@@ -95,7 +95,7 @@
Boolean retain;
enum mka_created_mode mode;
- enum { DEFAULT, DISABLED, ON_OPER_UP, ALWAYS } activate;
+ enum activate_ctrl { DEFAULT, DISABLED, ON_OPER_UP, ALWAYS } activate;
/* used for active participant */
Boolean principal;
@@ -131,8 +131,10 @@
u8 mi[MI_LEN];
u32 mn;
+ /* Current peer MI and SCI during MKPDU processing */
struct ieee802_1x_mka_peer_id current_peer_id;
struct ieee802_1x_mka_sci current_peer_sci;
+
time_t cak_life;
time_t mka_life;
Boolean to_dist_sak;
@@ -165,7 +167,7 @@
#endif
/* octet 4 */
u8 length1;
-};
+} STRUCT_PACKED;
#define MKA_HDR_LEN sizeof(struct ieee802_1x_mka_hdr)
@@ -210,9 +212,9 @@
be32 actor_mn;
u8 algo_agility[4];
- /* followed by CAK Name*/
+ /* followed by CAK Name */
u8 ckn[0];
-};
+} STRUCT_PACKED;
/**
* struct ieee802_1x_mka_peer_body - Live Peer List and Potential Peer List
@@ -238,9 +240,9 @@
/* octet 4 */
u8 length1;
- u8 peer[0];
/* followed by Peers */
-};
+ u8 peer[0];
+} STRUCT_PACKED;
/**
* struct ieee802_1x_mka_sak_use_body - MACsec SAK Use parameter set (Figure
@@ -315,7 +317,7 @@
be32 okn;
/* octet 41 - 44 */
be32 olpn;
-};
+} STRUCT_PACKED;
/**
* struct ieee802_1x_mka_dist_sak_body - Distributed SAK parameter set
@@ -362,7 +364,7 @@
* for other cipher suite: octet 9-16: cipher suite id, octet 17-: SAK
*/
u8 sak[0];
-};
+} STRUCT_PACKED;
/**
* struct ieee802_1x_mka_dist_cak_body - Distributed CAK parameter set (Figure
@@ -398,7 +400,7 @@
/* followed by CAK Name, 29- */
u8 ckn[0];
-};
+} STRUCT_PACKED;
struct ieee802_1x_mka_icv_body {
/* octet 1 */
@@ -418,6 +420,6 @@
/* octet 5 - */
u8 icv[0];
-};
+} STRUCT_PACKED;
#endif /* IEEE802_1X_KAY_I_H */
diff --git a/src/pae/ieee802_1x_key.c b/src/pae/ieee802_1x_key.c
index 9a8d923..d63ca7f 100644
--- a/src/pae/ieee802_1x_key.c
+++ b/src/pae/ieee802_1x_key.c
@@ -31,8 +31,9 @@
/* IEEE Std 802.1X-2010, 6.2.1 KDF */
-static int aes_kdf_128(const u8 *kdk, const char *label, const u8 *context,
- int ctx_bits, int ret_bits, u8 *ret)
+static int aes_kdf(const u8 *kdk, size_t kdk_bits,
+ const char *label, const u8 *context,
+ int ctx_bits, int ret_bits, u8 *ret)
{
const int h = 128;
const int r = 8;
@@ -40,6 +41,9 @@
int lab_len, ctx_len, ret_len, buf_len;
u8 *buf;
+ if (kdk_bits != 128 && kdk_bits != 256)
+ return -1;
+
lab_len = os_strlen(label);
ctx_len = (ctx_bits + 7) / 8;
ret_len = ((ret_bits & 0xffff) + 7) / 8;
@@ -60,8 +64,14 @@
WPA_PUT_BE16(&buf[buf_len - 2], ret_bits);
for (i = 0; i < n; i++) {
+ int res;
+
buf[0] = (u8) (i + 1);
- if (omac1_aes_128(kdk, buf, buf_len, ret)) {
+ if (kdk_bits == 128)
+ res = omac1_aes_128(kdk, buf, buf_len, ret);
+ else
+ res = omac1_aes_256(kdk, buf, buf_len, ret);
+ if (res) {
os_free(buf);
return -1;
}
@@ -72,33 +82,32 @@
}
-/********** AES-CMAC-128 **********/
/**
- * ieee802_1x_cak_128bits_aes_cmac
+ * ieee802_1x_cak_aes_cmac
*
* IEEE Std 802.1X-2010, 6.2.2
* CAK = KDF(Key, Label, mac1 | mac2, CAKlength)
*/
-int ieee802_1x_cak_128bits_aes_cmac(const u8 *msk, const u8 *mac1,
- const u8 *mac2, u8 *cak)
+int ieee802_1x_cak_aes_cmac(const u8 *msk, size_t msk_bytes, const u8 *mac1,
+ const u8 *mac2, u8 *cak, size_t cak_bytes)
{
u8 context[2 * ETH_ALEN];
joint_two_mac(mac1, mac2, context);
- return aes_kdf_128(msk, "IEEE8021 EAP CAK",
- context, sizeof(context) * 8, 128, cak);
+ return aes_kdf(msk, 8 * msk_bytes, "IEEE8021 EAP CAK",
+ context, sizeof(context) * 8, 8 * cak_bytes, cak);
}
/**
- * ieee802_1x_ckn_128bits_aes_cmac
+ * ieee802_1x_ckn_aes_cmac
*
* IEEE Std 802.1X-2010, 6.2.2
* CKN = KDF(Key, Label, ID | mac1 | mac2, CKNlength)
*/
-int ieee802_1x_ckn_128bits_aes_cmac(const u8 *msk, const u8 *mac1,
- const u8 *mac2, const u8 *sid,
- size_t sid_bytes, u8 *ckn)
+int ieee802_1x_ckn_aes_cmac(const u8 *msk, size_t msk_bytes, const u8 *mac1,
+ const u8 *mac2, const u8 *sid,
+ size_t sid_bytes, u8 *ckn)
{
int res;
u8 *context;
@@ -112,21 +121,21 @@
os_memcpy(context, sid, sid_bytes);
joint_two_mac(mac1, mac2, context + sid_bytes);
- res = aes_kdf_128(msk, "IEEE8021 EAP CKN", context, ctx_len * 8,
- 128, ckn);
+ res = aes_kdf(msk, 8 * msk_bytes, "IEEE8021 EAP CKN",
+ context, ctx_len * 8, 128, ckn);
os_free(context);
return res;
}
/**
- * ieee802_1x_kek_128bits_aes_cmac
+ * ieee802_1x_kek_aes_cmac
*
* IEEE Std 802.1X-2010, 9.3.3
* KEK = KDF(Key, Label, Keyid, KEKLength)
*/
-int ieee802_1x_kek_128bits_aes_cmac(const u8 *cak, const u8 *ckn,
- size_t ckn_bytes, u8 *kek)
+int ieee802_1x_kek_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ckn,
+ size_t ckn_bytes, u8 *kek, size_t kek_bytes)
{
u8 context[16];
@@ -134,19 +143,20 @@
os_memset(context, 0, sizeof(context));
os_memcpy(context, ckn, (ckn_bytes < 16) ? ckn_bytes : 16);
- return aes_kdf_128(cak, "IEEE8021 KEK", context, sizeof(context) * 8,
- 128, kek);
+ return aes_kdf(cak, 8 * cak_bytes, "IEEE8021 KEK",
+ context, sizeof(context) * 8,
+ 8 * kek_bytes, kek);
}
/**
- * ieee802_1x_ick_128bits_aes_cmac
+ * ieee802_1x_ick_aes_cmac
*
* IEEE Std 802.1X-2010, 9.3.3
* ICK = KDF(Key, Label, Keyid, ICKLength)
*/
-int ieee802_1x_ick_128bits_aes_cmac(const u8 *cak, const u8 *ckn,
- size_t ckn_bytes, u8 *ick)
+int ieee802_1x_ick_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ckn,
+ size_t ckn_bytes, u8 *ick, size_t ick_bytes)
{
u8 context[16];
@@ -154,22 +164,32 @@
os_memset(context, 0, sizeof(context));
os_memcpy(context, ckn, (ckn_bytes < 16) ? ckn_bytes : 16);
- return aes_kdf_128(cak, "IEEE8021 ICK", context, sizeof(context) * 8,
- 128, ick);
+ return aes_kdf(cak, 8 *cak_bytes, "IEEE8021 ICK",
+ context, sizeof(context) * 8,
+ 8 * ick_bytes, ick);
}
/**
- * ieee802_1x_icv_128bits_aes_cmac
+ * ieee802_1x_icv_aes_cmac
*
* IEEE Std 802.1X-2010, 9.4.1
* ICV = AES-CMAC(ICK, M, 128)
*/
-int ieee802_1x_icv_128bits_aes_cmac(const u8 *ick, const u8 *msg,
- size_t msg_bytes, u8 *icv)
+int ieee802_1x_icv_aes_cmac(const u8 *ick, size_t ick_bytes, const u8 *msg,
+ size_t msg_bytes, u8 *icv)
{
- if (omac1_aes_128(ick, msg, msg_bytes, icv)) {
- wpa_printf(MSG_ERROR, "MKA: omac1_aes_128 failed");
+ int res;
+
+ if (ick_bytes == 16)
+ res = omac1_aes_128(ick, msg, msg_bytes, icv);
+ else if (ick_bytes == 32)
+ res = omac1_aes_256(ick, msg, msg_bytes, icv);
+ else
+ return -1;
+ if (res) {
+ wpa_printf(MSG_ERROR,
+ "MKA: AES-CMAC failed for ICV calculation");
return -1;
}
return 0;
@@ -177,13 +197,14 @@
/**
- * ieee802_1x_sak_128bits_aes_cmac
+ * ieee802_1x_sak_aes_cmac
*
* IEEE Std 802.1X-2010, 9.8.1
* SAK = KDF(Key, Label, KS-nonce | MI-value list | KN, SAKLength)
*/
-int ieee802_1x_sak_128bits_aes_cmac(const u8 *cak, const u8 *ctx,
- size_t ctx_bytes, u8 *sak)
+int ieee802_1x_sak_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ctx,
+ size_t ctx_bytes, u8 *sak, size_t sak_bytes)
{
- return aes_kdf_128(cak, "IEEE8021 SAK", ctx, ctx_bytes * 8, 128, sak);
+ return aes_kdf(cak, cak_bytes * 8, "IEEE8021 SAK", ctx, ctx_bytes * 8,
+ sak_bytes * 8, sak);
}
diff --git a/src/pae/ieee802_1x_key.h b/src/pae/ieee802_1x_key.h
index ea318ea..1f9058d 100644
--- a/src/pae/ieee802_1x_key.h
+++ b/src/pae/ieee802_1x_key.h
@@ -9,18 +9,18 @@
#ifndef IEEE802_1X_KEY_H
#define IEEE802_1X_KEY_H
-int ieee802_1x_cak_128bits_aes_cmac(const u8 *msk, const u8 *mac1,
- const u8 *mac2, u8 *cak);
-int ieee802_1x_ckn_128bits_aes_cmac(const u8 *msk, const u8 *mac1,
- const u8 *mac2, const u8 *sid,
- size_t sid_bytes, u8 *ckn);
-int ieee802_1x_kek_128bits_aes_cmac(const u8 *cak, const u8 *ckn,
- size_t ckn_bytes, u8 *kek);
-int ieee802_1x_ick_128bits_aes_cmac(const u8 *cak, const u8 *ckn,
- size_t ckn_bytes, u8 *ick);
-int ieee802_1x_icv_128bits_aes_cmac(const u8 *ick, const u8 *msg,
- size_t msg_bytes, u8 *icv);
-int ieee802_1x_sak_128bits_aes_cmac(const u8 *cak, const u8 *ctx,
- size_t ctx_bytes, u8 *sak);
+int ieee802_1x_cak_aes_cmac(const u8 *msk, size_t msk_bytes, const u8 *mac1,
+ const u8 *mac2, u8 *cak, size_t cak_bytes);
+int ieee802_1x_ckn_aes_cmac(const u8 *msk, size_t msk_bytes, const u8 *mac1,
+ const u8 *mac2, const u8 *sid,
+ size_t sid_bytes, u8 *ckn);
+int ieee802_1x_kek_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ckn,
+ size_t ckn_bytes, u8 *kek, size_t kek_bytes);
+int ieee802_1x_ick_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ckn,
+ size_t ckn_bytes, u8 *ick, size_t ick_bytes);
+int ieee802_1x_icv_aes_cmac(const u8 *ick, size_t ick_bytes, const u8 *msg,
+ size_t msg_bytes, u8 *icv);
+int ieee802_1x_sak_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ctx,
+ size_t ctx_bytes, u8 *sak, size_t sak_bytes);
#endif /* IEEE802_1X_KEY_H */
diff --git a/src/pae/ieee802_1x_secy_ops.c b/src/pae/ieee802_1x_secy_ops.c
index ab5339b..84ee42b 100644
--- a/src/pae/ieee802_1x_secy_ops.c
+++ b/src/pae/ieee802_1x_secy_ops.c
@@ -187,7 +187,7 @@
ops = kay->ctx;
if (!ops || !ops->get_transmit_next_pn) {
wpa_printf(MSG_ERROR,
- "KaY: secy get_receive_lowest_pn operation not supported");
+ "KaY: secy get_transmit_next_pn operation not supported");
return -1;
}
@@ -208,7 +208,7 @@
ops = kay->ctx;
if (!ops || !ops->set_transmit_next_pn) {
wpa_printf(MSG_ERROR,
- "KaY: secy get_receive_lowest_pn operation not supported");
+ "KaY: secy set_transmit_next_pn operation not supported");
return -1;
}
@@ -216,6 +216,27 @@
}
+int secy_set_receive_lowest_pn(struct ieee802_1x_kay *kay,
+ struct receive_sa *rxsa)
+{
+ struct ieee802_1x_kay_ctx *ops;
+
+ if (!kay || !rxsa) {
+ wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
+ return -1;
+ }
+
+ ops = kay->ctx;
+ if (!ops || !ops->set_receive_lowest_pn) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy set_receive_lowest_pn operation not supported");
+ return -1;
+ }
+
+ return ops->set_receive_lowest_pn(ops->ctx, rxsa);
+}
+
+
int secy_create_receive_sc(struct ieee802_1x_kay *kay, struct receive_sc *rxsc)
{
struct ieee802_1x_kay_ctx *ops;
diff --git a/src/pae/ieee802_1x_secy_ops.h b/src/pae/ieee802_1x_secy_ops.h
index 9fb29c3..2d112ba 100644
--- a/src/pae/ieee802_1x_secy_ops.h
+++ b/src/pae/ieee802_1x_secy_ops.h
@@ -36,6 +36,8 @@
struct transmit_sa *txsa);
int secy_set_transmit_next_pn(struct ieee802_1x_kay *kay,
struct transmit_sa *txsa);
+int secy_set_receive_lowest_pn(struct ieee802_1x_kay *kay,
+ struct receive_sa *txsa);
int secy_create_receive_sc(struct ieee802_1x_kay *kay, struct receive_sc *rxsc);
int secy_delete_receive_sc(struct ieee802_1x_kay *kay, struct receive_sc *rxsc);
int secy_create_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa);
diff --git a/src/radius/radius.c b/src/radius/radius.c
index fc98ad6..07240ea 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -250,6 +250,8 @@
{ RADIUS_ATTR_MOBILITY_DOMAIN_ID, "Mobility-Domain-Id",
RADIUS_ATTR_INT32 },
{ RADIUS_ATTR_WLAN_HESSID, "WLAN-HESSID", RADIUS_ATTR_TEXT },
+ { RADIUS_ATTR_WLAN_REASON_CODE, "WLAN-Reason-Code",
+ RADIUS_ATTR_INT32 },
{ RADIUS_ATTR_WLAN_PAIRWISE_CIPHER, "WLAN-Pairwise-Cipher",
RADIUS_ATTR_HEXDUMP },
{ RADIUS_ATTR_WLAN_GROUP_CIPHER, "WLAN-Group-Cipher",
diff --git a/src/radius/radius.h b/src/radius/radius.h
index cd510d2..630c0f9 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -102,8 +102,13 @@
RADIUS_ATTR_EXTENDED_LOCATION_POLICY_RULES = 130,
RADIUS_ATTR_LOCATION_CAPABLE = 131,
RADIUS_ATTR_REQUESTED_LOCATION_INFO = 132,
+ RADIUS_ATTR_GSS_ACCEPTOR_SERVICE_NAME = 164,
+ RADIUS_ATTR_GSS_ACCEPTOR_HOST_NAME = 165,
+ RADIUS_ATTR_GSS_ACCEPTOR_SERVICE_SPECIFICS = 166,
+ RADIUS_ATTR_GSS_ACCEPTOR_REALM_NAME = 167,
RADIUS_ATTR_MOBILITY_DOMAIN_ID = 177,
RADIUS_ATTR_WLAN_HESSID = 181,
+ RADIUS_ATTR_WLAN_REASON_CODE = 185,
RADIUS_ATTR_WLAN_PAIRWISE_CIPHER = 186,
RADIUS_ATTR_WLAN_GROUP_CIPHER = 187,
RADIUS_ATTR_WLAN_AKM_SUITE = 188,
@@ -193,6 +198,11 @@
RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION = 3,
RADIUS_VENDOR_ATTR_WFA_HS20_DEAUTH_REQ = 4,
RADIUS_VENDOR_ATTR_WFA_HS20_SESSION_INFO_URL = 5,
+ RADIUS_VENDOR_ATTR_WFA_HS20_ROAMING_CONSORTIUM = 6,
+ RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILENAME = 7,
+ RADIUS_VENDOR_ATTR_WFA_HS20_TIMESTAMP = 8,
+ RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING = 9,
+ RADIUS_VENDOR_ATTR_WFA_HS20_T_C_URL = 10,
};
#ifdef _MSC_VER
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 06c804d..a3db404 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -26,12 +26,12 @@
#define RADIUS_CLIENT_MAX_WAIT 120
/**
- * RADIUS_CLIENT_MAX_RETRIES - RADIUS client maximum retries
+ * RADIUS_CLIENT_MAX_FAILOVER - RADIUS client maximum retries
*
- * Maximum number of retransmit attempts before the entry is removed from
+ * Maximum number of server failovers before the entry is removed from
* retransmit list.
*/
-#define RADIUS_CLIENT_MAX_RETRIES 10
+#define RADIUS_CLIENT_MAX_FAILOVER 3
/**
* RADIUS_CLIENT_MAX_ENTRIES - RADIUS client maximum pending messages
@@ -110,11 +110,16 @@
os_time_t next_try;
/**
- * attempts - Number of transmission attempts
+ * attempts - Number of transmission attempts for one server
*/
int attempts;
/**
+ * accu_attempts - Number of accumulated attempts
+ */
+ int accu_attempts;
+
+ /**
* next_wait - Next retransmission wait time in seconds
*/
int next_wait;
@@ -367,9 +372,11 @@
size_t prev_num_msgs;
u8 *acct_delay_time;
size_t acct_delay_time_len;
+ int num_servers;
if (entry->msg_type == RADIUS_ACCT ||
entry->msg_type == RADIUS_ACCT_INTERIM) {
+ num_servers = conf->num_acct_servers;
if (radius->acct_sock < 0)
radius_client_init_acct(radius);
if (radius->acct_sock < 0 && conf->num_acct_servers > 1) {
@@ -386,6 +393,7 @@
conf->acct_server->retransmissions++;
}
} else {
+ num_servers = conf->num_auth_servers;
if (radius->auth_sock < 0)
radius_client_init_auth(radius);
if (radius->auth_sock < 0 && conf->num_auth_servers > 1) {
@@ -449,7 +457,15 @@
}
/* retransmit; remove entry if too many attempts */
+ if (entry->accu_attempts > RADIUS_CLIENT_MAX_FAILOVER *
+ RADIUS_CLIENT_NUM_FAILOVER * num_servers) {
+ wpa_printf(MSG_INFO,
+ "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
+ return 1;
+ }
+
entry->attempts++;
+ entry->accu_attempts++;
hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
radius_msg_get_hdr(entry->msg)->identifier);
@@ -466,10 +482,6 @@
entry->next_wait *= 2;
if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
- if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
- wpa_printf(MSG_INFO, "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
- return 1;
- }
return 0;
}
@@ -490,6 +502,30 @@
return;
os_get_reltime(&now);
+
+ while (entry) {
+ if (now.sec >= entry->next_try) {
+ s = entry->msg_type == RADIUS_AUTH ? radius->auth_sock :
+ radius->acct_sock;
+ if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER ||
+ (s < 0 && entry->attempts > 0)) {
+ if (entry->msg_type == RADIUS_ACCT ||
+ entry->msg_type == RADIUS_ACCT_INTERIM)
+ acct_failover++;
+ else
+ auth_failover++;
+ }
+ }
+ entry = entry->next;
+ }
+
+ if (auth_failover)
+ radius_client_auth_failover(radius);
+
+ if (acct_failover)
+ radius_client_acct_failover(radius);
+
+ entry = radius->msgs;
first = 0;
prev = NULL;
@@ -517,17 +553,6 @@
continue;
}
- s = entry->msg_type == RADIUS_AUTH ? radius->auth_sock :
- radius->acct_sock;
- if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER ||
- (s < 0 && entry->attempts > 0)) {
- if (entry->msg_type == RADIUS_ACCT ||
- entry->msg_type == RADIUS_ACCT_INTERIM)
- acct_failover++;
- else
- auth_failover++;
- }
-
if (first == 0 || entry->next_try < first)
first = entry->next_try;
@@ -538,6 +563,7 @@
if (radius->msgs) {
if (first < now.sec)
first = now.sec;
+ eloop_cancel_timeout(radius_client_timer, radius, NULL);
eloop_register_timeout(first - now.sec, 0,
radius_client_timer, radius, NULL);
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
@@ -545,12 +571,6 @@
"retransmit in %ld seconds",
(long int) (first - now.sec));
}
-
- if (auth_failover)
- radius_client_auth_failover(radius);
-
- if (acct_failover)
- radius_client_acct_failover(radius);
}
@@ -674,7 +694,10 @@
entry->first_try = entry->last_attempt.sec;
entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
entry->attempts = 1;
+ entry->accu_attempts = 1;
entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
+ if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
+ entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
entry->next = radius->msgs;
radius->msgs = entry;
radius_client_update_timeout(radius);
@@ -713,9 +736,9 @@
*
* The message is added on the retransmission queue and will be retransmitted
* automatically until a response is received or maximum number of retries
- * (RADIUS_CLIENT_MAX_RETRIES) is reached. No such retries are used with
- * RADIUS_ACCT_INTERIM, i.e., such a pending message is removed from the queue
- * automatically on transmission failure.
+ * (RADIUS_CLIENT_MAX_FAILOVER * RADIUS_CLIENT_NUM_FAILOVER) is reached. No
+ * such retries are used with RADIUS_ACCT_INTERIM, i.e., such a pending message
+ * is removed from the queue automatically on transmission failure.
*
* The related device MAC address can be used to identify pending messages that
* can be removed with radius_client_flush_auth().
@@ -904,13 +927,13 @@
switch (res) {
case RADIUS_RX_PROCESSED:
radius_msg_free(msg);
- /* continue */
+ /* fall through */
case RADIUS_RX_QUEUED:
radius_client_msg_free(req);
return;
case RADIUS_RX_INVALID_AUTHENTICATOR:
invalid_authenticator++;
- /* continue */
+ /* fall through */
case RADIUS_RX_UNKNOWN:
/* continue with next handler */
break;
@@ -1087,14 +1110,13 @@
}
}
- /* Reset retry counters for the new server */
- for (entry = radius->msgs; oserv && oserv != nserv && entry;
- entry = entry->next) {
+ /* Reset retry counters */
+ for (entry = radius->msgs; oserv && entry; entry = entry->next) {
if ((auth && entry->msg_type != RADIUS_AUTH) ||
(!auth && entry->msg_type != RADIUS_ACCT))
continue;
entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
- entry->attempts = 0;
+ entry->attempts = 1;
entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
}
diff --git a/src/radius/radius_das.c b/src/radius/radius_das.c
index ed24c19..aaa3fc2 100644
--- a/src/radius/radius_das.c
+++ b/src/radius/radius_das.c
@@ -27,6 +27,7 @@
void *ctx;
enum radius_das_res (*disconnect)(void *ctx,
struct radius_das_attrs *attr);
+ enum radius_das_res (*coa)(void *ctx, struct radius_das_attrs *attr);
};
@@ -161,6 +162,10 @@
abuf, from_port);
error = 508;
break;
+ case RADIUS_DAS_COA_FAILED:
+ /* not used with Disconnect-Request */
+ error = 405;
+ break;
case RADIUS_DAS_SUCCESS:
error = 0;
break;
@@ -184,6 +189,195 @@
}
+static struct radius_msg * radius_das_coa(struct radius_das_data *das,
+ struct radius_msg *msg,
+ const char *abuf, int from_port)
+{
+ struct radius_hdr *hdr;
+ struct radius_msg *reply;
+ u8 allowed[] = {
+ RADIUS_ATTR_USER_NAME,
+ RADIUS_ATTR_NAS_IP_ADDRESS,
+ RADIUS_ATTR_CALLING_STATION_ID,
+ RADIUS_ATTR_NAS_IDENTIFIER,
+ RADIUS_ATTR_ACCT_SESSION_ID,
+ RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
+ RADIUS_ATTR_EVENT_TIMESTAMP,
+ RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
+ RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+#ifdef CONFIG_HS20
+ RADIUS_ATTR_VENDOR_SPECIFIC,
+#endif /* CONFIG_HS20 */
+#ifdef CONFIG_IPV6
+ RADIUS_ATTR_NAS_IPV6_ADDRESS,
+#endif /* CONFIG_IPV6 */
+ 0
+ };
+ int error = 405;
+ u8 attr;
+ enum radius_das_res res;
+ struct radius_das_attrs attrs;
+ u8 *buf;
+ size_t len;
+ char tmp[100];
+ u8 sta_addr[ETH_ALEN];
+
+ hdr = radius_msg_get_hdr(msg);
+
+ if (!das->coa) {
+ wpa_printf(MSG_INFO, "DAS: CoA not supported");
+ goto fail;
+ }
+
+ attr = radius_msg_find_unlisted_attr(msg, allowed);
+ if (attr) {
+ wpa_printf(MSG_INFO,
+ "DAS: Unsupported attribute %u in CoA-Request from %s:%d",
+ attr, abuf, from_port);
+ error = 401;
+ goto fail;
+ }
+
+ os_memset(&attrs, 0, sizeof(attrs));
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
+ &buf, &len, NULL) == 0) {
+ if (len != 4) {
+ wpa_printf(MSG_INFO, "DAS: Invalid NAS-IP-Address from %s:%d",
+ abuf, from_port);
+ error = 407;
+ goto fail;
+ }
+ attrs.nas_ip_addr = buf;
+ }
+
+#ifdef CONFIG_IPV6
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
+ &buf, &len, NULL) == 0) {
+ if (len != 16) {
+ wpa_printf(MSG_INFO, "DAS: Invalid NAS-IPv6-Address from %s:%d",
+ abuf, from_port);
+ error = 407;
+ goto fail;
+ }
+ attrs.nas_ipv6_addr = buf;
+ }
+#endif /* CONFIG_IPV6 */
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
+ &buf, &len, NULL) == 0) {
+ attrs.nas_identifier = buf;
+ attrs.nas_identifier_len = len;
+ }
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID,
+ &buf, &len, NULL) == 0) {
+ if (len >= sizeof(tmp))
+ len = sizeof(tmp) - 1;
+ os_memcpy(tmp, buf, len);
+ tmp[len] = '\0';
+ if (hwaddr_aton2(tmp, sta_addr) < 0) {
+ wpa_printf(MSG_INFO, "DAS: Invalid Calling-Station-Id "
+ "'%s' from %s:%d", tmp, abuf, from_port);
+ error = 407;
+ goto fail;
+ }
+ attrs.sta_addr = sta_addr;
+ }
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
+ &buf, &len, NULL) == 0) {
+ attrs.user_name = buf;
+ attrs.user_name_len = len;
+ }
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
+ &buf, &len, NULL) == 0) {
+ attrs.acct_session_id = buf;
+ attrs.acct_session_id_len = len;
+ }
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
+ &buf, &len, NULL) == 0) {
+ attrs.acct_multi_session_id = buf;
+ attrs.acct_multi_session_id_len = len;
+ }
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+ &buf, &len, NULL) == 0) {
+ attrs.cui = buf;
+ attrs.cui_len = len;
+ }
+
+#ifdef CONFIG_HS20
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
+ &buf, &len, NULL) == 0) {
+ if (len < 10 || WPA_GET_BE32(buf) != RADIUS_VENDOR_ID_WFA ||
+ buf[4] != RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING ||
+ buf[5] < 6) {
+ wpa_printf(MSG_INFO,
+ "DAS: Unsupported attribute %u in CoA-Request from %s:%d",
+ attr, abuf, from_port);
+ error = 401;
+ goto fail;
+ }
+ attrs.hs20_t_c_filtering = &buf[6];
+ }
+
+ if (!attrs.hs20_t_c_filtering) {
+ wpa_printf(MSG_INFO,
+ "DAS: No supported authorization change attribute in CoA-Request from %s:%d",
+ abuf, from_port);
+ error = 402;
+ goto fail;
+ }
+#endif /* CONFIG_HS20 */
+
+ res = das->coa(das->ctx, &attrs);
+ switch (res) {
+ case RADIUS_DAS_NAS_MISMATCH:
+ wpa_printf(MSG_INFO, "DAS: NAS mismatch from %s:%d",
+ abuf, from_port);
+ error = 403;
+ break;
+ case RADIUS_DAS_SESSION_NOT_FOUND:
+ wpa_printf(MSG_INFO,
+ "DAS: Session not found for request from %s:%d",
+ abuf, from_port);
+ error = 503;
+ break;
+ case RADIUS_DAS_MULTI_SESSION_MATCH:
+ wpa_printf(MSG_INFO,
+ "DAS: Multiple sessions match for request from %s:%d",
+ abuf, from_port);
+ error = 508;
+ break;
+ case RADIUS_DAS_COA_FAILED:
+ wpa_printf(MSG_INFO, "DAS: CoA failed for request from %s:%d",
+ abuf, from_port);
+ error = 407;
+ break;
+ case RADIUS_DAS_SUCCESS:
+ error = 0;
+ break;
+ }
+
+fail:
+ reply = radius_msg_new(error ? RADIUS_CODE_COA_NAK :
+ RADIUS_CODE_COA_ACK, hdr->identifier);
+ if (!reply)
+ return NULL;
+
+ if (error &&
+ !radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, error)) {
+ radius_msg_free(reply);
+ return NULL;
+ }
+
+ return reply;
+}
+
+
static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
struct radius_das_data *das = eloop_ctx;
@@ -219,7 +413,8 @@
wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
len, abuf, from_port);
- if (das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) {
+ if (das->client_addr.u.v4.s_addr &&
+ das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) {
wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
return;
}
@@ -270,19 +465,7 @@
reply = radius_das_disconnect(das, msg, abuf, from_port);
break;
case RADIUS_CODE_COA_REQUEST:
- /* TODO */
- reply = radius_msg_new(RADIUS_CODE_COA_NAK,
- hdr->identifier);
- if (reply == NULL)
- break;
-
- /* Unsupported Service */
- if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE,
- 405)) {
- radius_msg_free(reply);
- reply = NULL;
- break;
- }
+ reply = radius_das_coa(das, msg, abuf, from_port);
break;
default:
wpa_printf(MSG_DEBUG, "DAS: Unexpected RADIUS code %u in "
@@ -369,6 +552,7 @@
conf->require_message_authenticator;
das->ctx = conf->ctx;
das->disconnect = conf->disconnect;
+ das->coa = conf->coa;
os_memcpy(&das->client_addr, conf->client_addr,
sizeof(das->client_addr));
diff --git a/src/radius/radius_das.h b/src/radius/radius_das.h
index 9863fdc..233d662 100644
--- a/src/radius/radius_das.h
+++ b/src/radius/radius_das.h
@@ -16,6 +16,7 @@
RADIUS_DAS_NAS_MISMATCH,
RADIUS_DAS_SESSION_NOT_FOUND,
RADIUS_DAS_MULTI_SESSION_MATCH,
+ RADIUS_DAS_COA_FAILED,
};
struct radius_das_attrs {
@@ -35,6 +36,9 @@
size_t acct_multi_session_id_len;
const u8 *cui;
size_t cui_len;
+
+ /* Authorization changes */
+ const u8 *hs20_t_c_filtering;
};
struct radius_das_conf {
@@ -48,6 +52,7 @@
void *ctx;
enum radius_das_res (*disconnect)(void *ctx,
struct radius_das_attrs *attr);
+ enum radius_das_res (*coa)(void *ctx, struct radius_das_attrs *attr);
};
struct radius_das_data *
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index c76bb22..b621ada 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -1,6 +1,6 @@
/*
* RADIUS authentication server
- * Copyright (c) 2005-2009, 2011-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2009, 2011-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -80,6 +80,7 @@
struct eap_eapol_interface *eap_if;
char *username; /* from User-Name attribute */
char *nas_ip;
+ u8 mac_addr[ETH_ALEN]; /* from Calling-Station-Id attribute */
struct radius_msg *last_msg;
char *last_from_addr;
@@ -92,8 +93,11 @@
unsigned int remediation:1;
unsigned int macacl:1;
+ unsigned int t_c_filtering:1;
struct hostapd_radius_attr *accept_attr;
+
+ u32 t_c_timestamp; /* Last read T&C timestamp from user DB */
};
/**
@@ -111,6 +115,14 @@
int shared_secret_len;
struct radius_session *sessions;
struct radius_server_counters counters;
+
+ u8 next_dac_identifier;
+ struct radius_msg *pending_dac_coa_req;
+ u8 pending_dac_coa_id;
+ u8 pending_dac_coa_addr[ETH_ALEN];
+ struct radius_msg *pending_dac_disconnect_req;
+ u8 pending_dac_disconnect_id;
+ u8 pending_dac_disconnect_addr[ETH_ALEN];
};
/**
@@ -345,6 +357,9 @@
char *subscr_remediation_url;
u8 subscr_remediation_method;
+ char *hs20_sim_provisioning_url;
+
+ char *t_c_server_url;
#ifdef CONFIG_SQLITE
sqlite3 *db;
@@ -366,6 +381,44 @@
static void radius_server_session_remove_timeout(void *eloop_ctx,
void *timeout_ctx);
+#ifdef CONFIG_SQLITE
+#ifdef CONFIG_HS20
+
+static int db_table_exists(sqlite3 *db, const char *name)
+{
+ char cmd[128];
+
+ os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
+ return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
+}
+
+
+static int db_table_create_sim_provisioning(sqlite3 *db)
+{
+ char *err = NULL;
+ const char *sql =
+ "CREATE TABLE sim_provisioning("
+ " mobile_identifier_hash TEXT PRIMARY KEY,"
+ " imsi TEXT,"
+ " mac_addr TEXT,"
+ " eap_method TEXT,"
+ " timestamp TEXT"
+ ");";
+
+ RADIUS_DEBUG("Adding database table for SIM provisioning information");
+ if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
+ RADIUS_ERROR("SQLite error: %s", err);
+ sqlite3_free(err);
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_HS20 */
+#endif /* CONFIG_SQLITE */
+
+
void srv_log(struct radius_session *sess, const char *fmt, ...)
PRINTF_FORMAT(2, 3);
@@ -623,17 +676,34 @@
}
+#ifdef CONFIG_ERP
+static struct eap_server_erp_key *
+radius_server_erp_find_key(struct radius_server_data *data, const char *keyname)
+{
+ struct eap_server_erp_key *erp;
+
+ dl_list_for_each(erp, &data->erp_keys, struct eap_server_erp_key,
+ list) {
+ if (os_strcmp(erp->keyname_nai, keyname) == 0)
+ return erp;
+ }
+
+ return NULL;
+}
+#endif /* CONFIG_ERP */
+
+
static struct radius_session *
radius_server_get_new_session(struct radius_server_data *data,
struct radius_client *client,
struct radius_msg *msg, const char *from_addr)
{
- u8 *user;
- size_t user_len;
+ u8 *user, *id;
+ size_t user_len, id_len;
int res;
struct radius_session *sess;
struct eap_config eap_conf;
- struct eap_user tmp;
+ struct eap_user *tmp;
RADIUS_DEBUG("Creating a new session");
@@ -644,12 +714,27 @@
}
RADIUS_DUMP_ASCII("User-Name", user, user_len);
- os_memset(&tmp, 0, sizeof(tmp));
- res = data->get_eap_user(data->conf_ctx, user, user_len, 0, &tmp);
- bin_clear_free(tmp.password, tmp.password_len);
+ tmp = os_zalloc(sizeof(*tmp));
+ if (!tmp)
+ return NULL;
+ res = data->get_eap_user(data->conf_ctx, user, user_len, 0, tmp);
+#ifdef CONFIG_ERP
+ if (res != 0 && data->erp) {
+ char *username;
+
+ username = os_zalloc(user_len + 1);
+ if (username) {
+ os_memcpy(username, user, user_len);
+ if (radius_server_erp_find_key(data, username))
+ res = 0;
+ os_free(username);
+ }
+ }
+#endif /* CONFIG_ERP */
if (res != 0) {
RADIUS_DEBUG("User-Name not found from user database");
+ eap_user_free(tmp);
return NULL;
}
@@ -657,10 +742,12 @@
sess = radius_server_new_session(data, client);
if (sess == NULL) {
RADIUS_DEBUG("Failed to create a new session");
+ eap_user_free(tmp);
return NULL;
}
- sess->accept_attr = tmp.accept_attr;
- sess->macacl = tmp.macacl;
+ sess->accept_attr = tmp->accept_attr;
+ sess->macacl = tmp->macacl;
+ eap_user_free(tmp);
sess->username = os_malloc(user_len * 4 + 1);
if (sess->username == NULL) {
@@ -675,6 +762,21 @@
return NULL;
}
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID, &id,
+ &id_len, NULL) == 0) {
+ char buf[3 * ETH_ALEN];
+
+ os_memset(buf, 0, sizeof(buf));
+ if (id_len >= sizeof(buf))
+ id_len = sizeof(buf) - 1;
+ os_memcpy(buf, id, id_len);
+ if (hwaddr_aton2(buf, sess->mac_addr) < 0)
+ os_memset(sess->mac_addr, 0, ETH_ALEN);
+ else
+ RADIUS_DEBUG("Calling-Station-Id: " MACSTR,
+ MAC2STR(sess->mac_addr));
+ }
+
srv_log(sess, "New session created");
os_memset(&eap_conf, 0, sizeof(eap_conf));
@@ -718,6 +820,236 @@
}
+#ifdef CONFIG_HS20
+static void radius_srv_hs20_t_c_pending(struct radius_session *sess)
+{
+#ifdef CONFIG_SQLITE
+ char *sql;
+ char addr[3 * ETH_ALEN], *id_str;
+ const u8 *id;
+ size_t id_len;
+
+ if (!sess->server->db || !sess->eap ||
+ is_zero_ether_addr(sess->mac_addr))
+ return;
+
+ os_snprintf(addr, sizeof(addr), MACSTR, MAC2STR(sess->mac_addr));
+
+ id = eap_get_identity(sess->eap, &id_len);
+ if (!id)
+ return;
+ id_str = os_malloc(id_len + 1);
+ if (!id_str)
+ return;
+ os_memcpy(id_str, id, id_len);
+ id_str[id_len] = '\0';
+
+ sql = sqlite3_mprintf("INSERT OR REPLACE INTO pending_tc (mac_addr,identity) VALUES (%Q,%Q)",
+ addr, id_str);
+ os_free(id_str);
+ if (!sql)
+ return;
+
+ if (sqlite3_exec(sess->server->db, sql, NULL, NULL, NULL) !=
+ SQLITE_OK) {
+ RADIUS_ERROR("Failed to add pending_tc entry into sqlite database: %s",
+ sqlite3_errmsg(sess->server->db));
+ }
+ sqlite3_free(sql);
+#endif /* CONFIG_SQLITE */
+}
+#endif /* CONFIG_HS20 */
+
+
+static void radius_server_add_session(struct radius_session *sess)
+{
+#ifdef CONFIG_SQLITE
+ char *sql;
+ char addr_txt[ETH_ALEN * 3];
+ struct os_time now;
+
+ if (!sess->server->db)
+ return;
+
+
+ os_snprintf(addr_txt, sizeof(addr_txt), MACSTR,
+ MAC2STR(sess->mac_addr));
+
+ os_get_time(&now);
+ sql = sqlite3_mprintf("INSERT OR REPLACE INTO current_sessions(mac_addr,identity,start_time,nas,hs20_t_c_filtering) VALUES (%Q,%Q,%d,%Q,%u)",
+ addr_txt, sess->username, now.sec,
+ sess->nas_ip, sess->t_c_filtering);
+ if (sql) {
+ if (sqlite3_exec(sess->server->db, sql, NULL, NULL,
+ NULL) != SQLITE_OK) {
+ RADIUS_ERROR("Failed to add current_sessions entry into sqlite database: %s",
+ sqlite3_errmsg(sess->server->db));
+ }
+ sqlite3_free(sql);
+ }
+#endif /* CONFIG_SQLITE */
+}
+
+
+static void db_update_last_msk(struct radius_session *sess, const char *msk)
+{
+#ifdef CONFIG_RADIUS_TEST
+#ifdef CONFIG_SQLITE
+ char *sql = NULL;
+ char *id_str = NULL;
+ const u8 *id;
+ size_t id_len;
+ const char *serial_num;
+
+ if (!sess->server->db)
+ return;
+
+ serial_num = eap_get_serial_num(sess->eap);
+ if (serial_num) {
+ id_len = 5 + os_strlen(serial_num) + 1;
+ id_str = os_malloc(id_len);
+ if (!id_str)
+ return;
+ os_snprintf(id_str, id_len, "cert-%s", serial_num);
+ } else {
+ id = eap_get_identity(sess->eap, &id_len);
+ if (!id)
+ return;
+ id_str = os_malloc(id_len + 1);
+ if (!id_str)
+ return;
+ os_memcpy(id_str, id, id_len);
+ id_str[id_len] = '\0';
+ }
+
+ sql = sqlite3_mprintf("UPDATE users SET last_msk=%Q WHERE identity=%Q",
+ msk, id_str);
+ os_free(id_str);
+ if (!sql)
+ return;
+
+ if (sqlite3_exec(sess->server->db, sql, NULL, NULL, NULL) !=
+ SQLITE_OK) {
+ RADIUS_DEBUG("Failed to update last_msk: %s",
+ sqlite3_errmsg(sess->server->db));
+ }
+ sqlite3_free(sql);
+#endif /* CONFIG_SQLITE */
+#endif /* CONFIG_RADIUS_TEST */
+}
+
+
+#ifdef CONFIG_HS20
+
+static int radius_server_is_sim_method(struct radius_session *sess)
+{
+ const char *name;
+
+ name = eap_get_method(sess->eap);
+ return name &&
+ (os_strcmp(name, "SIM") == 0 ||
+ os_strcmp(name, "AKA") == 0 ||
+ os_strcmp(name, "AKA'") == 0);
+}
+
+
+static int radius_server_hs20_missing_sim_pps(struct radius_msg *request)
+{
+ u8 *buf, *pos, *end, type, sublen;
+ size_t len;
+
+ buf = NULL;
+ for (;;) {
+ if (radius_msg_get_attr_ptr(request,
+ RADIUS_ATTR_VENDOR_SPECIFIC,
+ &buf, &len, buf) < 0)
+ return 0;
+ if (len < 6)
+ continue;
+ pos = buf;
+ end = buf + len;
+ if (WPA_GET_BE32(pos) != RADIUS_VENDOR_ID_WFA)
+ continue;
+ pos += 4;
+
+ type = *pos++;
+ sublen = *pos++;
+ if (sublen < 2)
+ continue; /* invalid length */
+ sublen -= 2; /* skip header */
+ if (pos + sublen > end)
+ continue; /* invalid WFA VSA */
+
+ if (type != RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION)
+ continue;
+
+ RADIUS_DUMP("HS2.0 mobile device version", pos, sublen);
+ if (sublen < 1 + 2)
+ continue;
+ if (pos[0] == 0)
+ continue; /* Release 1 STA does not support provisioning
+
+ */
+ /* UpdateIdentifier 0 indicates no PPS MO */
+ return WPA_GET_BE16(pos + 1) == 0;
+ }
+}
+
+
+#define HS20_MOBILE_ID_HASH_LEN 16
+
+static int radius_server_sim_provisioning_session(struct radius_session *sess,
+ const u8 *hash)
+{
+#ifdef CONFIG_SQLITE
+ char *sql;
+ char addr_txt[ETH_ALEN * 3];
+ char hash_txt[2 * HS20_MOBILE_ID_HASH_LEN + 1];
+ struct os_time now;
+ int res;
+ const char *imsi, *eap_method;
+
+ if (!sess->server->db ||
+ (!db_table_exists(sess->server->db, "sim_provisioning") &&
+ db_table_create_sim_provisioning(sess->server->db) < 0))
+ return -1;
+
+ imsi = eap_get_imsi(sess->eap);
+ if (!imsi)
+ return -1;
+
+ eap_method = eap_get_method(sess->eap);
+ if (!eap_method)
+ return -1;
+
+ os_snprintf(addr_txt, sizeof(addr_txt), MACSTR,
+ MAC2STR(sess->mac_addr));
+ wpa_snprintf_hex(hash_txt, sizeof(hash_txt), hash,
+ HS20_MOBILE_ID_HASH_LEN);
+
+ os_get_time(&now);
+ sql = sqlite3_mprintf("INSERT INTO sim_provisioning(mobile_identifier_hash,imsi,mac_addr,eap_method,timestamp) VALUES (%Q,%Q,%Q,%Q,%u)",
+ hash_txt, imsi, addr_txt, eap_method, now.sec);
+ if (!sql)
+ return -1;
+
+ if (sqlite3_exec(sess->server->db, sql, NULL, NULL, NULL) !=
+ SQLITE_OK) {
+ RADIUS_ERROR("Failed to add SIM provisioning entry into sqlite database: %s",
+ sqlite3_errmsg(sess->server->db));
+ res = -1;
+ } else {
+ res = 0;
+ }
+ sqlite3_free(sql);
+ return res;
+#endif /* CONFIG_SQLITE */
+ return -1;
+}
+
+#endif /* CONFIG_HS20 */
+
+
static struct radius_msg *
radius_server_encapsulate_eap(struct radius_server_data *data,
struct radius_client *client,
@@ -728,6 +1060,7 @@
int code;
unsigned int sess_id;
struct radius_hdr *hdr = radius_msg_get_hdr(request);
+ u16 reason = WLAN_REASON_IEEE_802_1X_AUTH_FAILED;
if (sess->eap_if->eapFail) {
sess->eap_if->eapFail = FALSE;
@@ -762,9 +1095,18 @@
if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eap_if->eapKeyData) {
int len;
#ifdef CONFIG_RADIUS_TEST
+ char buf[2 * 64 + 1];
+
+ len = sess->eap_if->eapKeyDataLen;
+ if (len > 64)
+ len = 64;
+ len = wpa_snprintf_hex(buf, sizeof(buf),
+ sess->eap_if->eapKeyData, len);
+ buf[len] = '\0';
+
if (data->dump_msk_file) {
FILE *f;
- char buf[2 * 64 + 1];
+
f = fopen(data->dump_msk_file, "a");
if (f) {
len = sess->eap_if->eapKeyDataLen;
@@ -778,6 +1120,8 @@
fclose(f);
}
}
+
+ db_update_last_msk(sess, buf);
#endif /* CONFIG_RADIUS_TEST */
if (sess->eap_if->eapKeyDataLen > 64) {
len = 32;
@@ -819,6 +1163,103 @@
buf, 0)) {
RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem");
}
+ } else if (code == RADIUS_CODE_ACCESS_ACCEPT &&
+ data->hs20_sim_provisioning_url &&
+ radius_server_is_sim_method(sess) &&
+ radius_server_hs20_missing_sim_pps(request)) {
+ u8 *buf, *pos, hash[HS20_MOBILE_ID_HASH_LEN];
+ size_t prefix_len, url_len;
+
+ RADIUS_DEBUG("Device needs HS 2.0 SIM provisioning");
+
+ if (os_get_random(hash, HS20_MOBILE_ID_HASH_LEN) < 0) {
+ radius_msg_free(msg);
+ return NULL;
+ }
+ RADIUS_DUMP("hotspot2dot0-mobile-identifier-hash",
+ hash, HS20_MOBILE_ID_HASH_LEN);
+
+ if (radius_server_sim_provisioning_session(sess, hash) < 0) {
+ radius_msg_free(msg);
+ return NULL;
+ }
+
+ prefix_len = os_strlen(data->hs20_sim_provisioning_url);
+ url_len = prefix_len + 2 * HS20_MOBILE_ID_HASH_LEN;
+ buf = os_malloc(1 + url_len + 1);
+ if (!buf) {
+ radius_msg_free(msg);
+ return NULL;
+ }
+ pos = buf;
+ *pos++ = data->subscr_remediation_method;
+ os_memcpy(pos, data->hs20_sim_provisioning_url, prefix_len);
+ pos += prefix_len;
+ wpa_snprintf_hex((char *) pos, 2 * HS20_MOBILE_ID_HASH_LEN + 1,
+ hash, HS20_MOBILE_ID_HASH_LEN);
+ RADIUS_DEBUG("HS 2.0 subscription remediation URL: %s",
+ (char *) &buf[1]);
+ if (!radius_msg_add_wfa(
+ msg, RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION,
+ buf, 1 + url_len)) {
+ RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem");
+ }
+ os_free(buf);
+ }
+
+ if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->t_c_filtering) {
+ u8 buf[4] = { 0x01, 0x00, 0x00, 0x00 }; /* E=1 */
+ const char *url = data->t_c_server_url, *pos;
+ char *url2, *end2, *pos2;
+ size_t url_len;
+
+ if (!radius_msg_add_wfa(
+ msg, RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING,
+ buf, sizeof(buf))) {
+ RADIUS_DEBUG("Failed to add WFA-HS20-T-C-Filtering");
+ radius_msg_free(msg);
+ return NULL;
+ }
+
+ if (!url) {
+ RADIUS_DEBUG("No t_c_server_url configured");
+ radius_msg_free(msg);
+ return NULL;
+ }
+
+ pos = os_strstr(url, "@1@");
+ if (!pos) {
+ RADIUS_DEBUG("No @1@ macro in t_c_server_url");
+ radius_msg_free(msg);
+ return NULL;
+ }
+
+ url_len = os_strlen(url) + ETH_ALEN * 3 - 1 - 3;
+ url2 = os_malloc(url_len + 1);
+ if (!url2) {
+ RADIUS_DEBUG("Failed to allocate room for T&C Server URL");
+ os_free(url2);
+ radius_msg_free(msg);
+ return NULL;
+ }
+ pos2 = url2;
+ end2 = url2 + url_len + 1;
+ os_memcpy(pos2, url, pos - url);
+ pos2 += pos - url;
+ os_snprintf(pos2, end2 - pos2, MACSTR, MAC2STR(sess->mac_addr));
+ pos2 += ETH_ALEN * 3 - 1;
+ os_memcpy(pos2, pos + 3, os_strlen(pos + 3));
+ if (!radius_msg_add_wfa(msg,
+ RADIUS_VENDOR_ATTR_WFA_HS20_T_C_URL,
+ (const u8 *) url2, url_len)) {
+ RADIUS_DEBUG("Failed to add WFA-HS20-T-C-URL");
+ os_free(url2);
+ radius_msg_free(msg);
+ return NULL;
+ }
+ os_free(url2);
+
+ radius_srv_hs20_t_c_pending(sess);
}
#endif /* CONFIG_HS20 */
@@ -841,12 +1282,24 @@
}
}
+ if (code == RADIUS_CODE_ACCESS_REJECT) {
+ if (radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE,
+ reason) < 0) {
+ RADIUS_DEBUG("Failed to add WLAN-Reason-Code attribute");
+ radius_msg_free(msg);
+ return NULL;
+ }
+ }
+
if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
client->shared_secret_len,
hdr->authenticator) < 0) {
RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
}
+ if (code == RADIUS_CODE_ACCESS_ACCEPT)
+ radius_server_add_session(sess);
+
return msg;
}
@@ -993,6 +1446,51 @@
}
+static void radius_server_hs20_t_c_check(struct radius_session *sess,
+ struct radius_msg *msg)
+{
+#ifdef CONFIG_HS20
+ u8 *buf, *pos, *end, type, sublen, *timestamp = NULL;
+ size_t len;
+
+ buf = NULL;
+ for (;;) {
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
+ &buf, &len, buf) < 0)
+ break;
+ if (len < 6)
+ continue;
+ pos = buf;
+ end = buf + len;
+ if (WPA_GET_BE32(pos) != RADIUS_VENDOR_ID_WFA)
+ continue;
+ pos += 4;
+
+ type = *pos++;
+ sublen = *pos++;
+ if (sublen < 2)
+ continue; /* invalid length */
+ sublen -= 2; /* skip header */
+ if (pos + sublen > end)
+ continue; /* invalid WFA VSA */
+
+ if (type == RADIUS_VENDOR_ATTR_WFA_HS20_TIMESTAMP && len >= 4) {
+ timestamp = pos;
+ break;
+ }
+ }
+
+ if (!timestamp)
+ return;
+ RADIUS_DEBUG("HS20-Timestamp: %u", WPA_GET_BE32(timestamp));
+ if (sess->t_c_timestamp != WPA_GET_BE32(timestamp)) {
+ RADIUS_DEBUG("Last read T&C timestamp does not match HS20-Timestamp --> require filtering");
+ sess->t_c_filtering = 1;
+ }
+#endif /* CONFIG_HS20 */
+}
+
+
static int radius_server_request(struct radius_server_data *data,
struct radius_msg *msg,
struct sockaddr *from, socklen_t fromlen,
@@ -1123,10 +1621,15 @@
if (sess->eap_if->eapSuccess || sess->eap_if->eapFail)
is_complete = 1;
- if (sess->eap_if->eapFail)
+ if (sess->eap_if->eapFail) {
srv_log(sess, "EAP authentication failed");
- else if (sess->eap_if->eapSuccess)
+ db_update_last_msk(sess, "FAIL");
+ } else if (sess->eap_if->eapSuccess) {
srv_log(sess, "EAP authentication succeeded");
+ }
+
+ if (sess->eap_if->eapSuccess)
+ radius_server_hs20_t_c_check(sess, msg);
reply = radius_server_encapsulate_eap(data, client, sess, msg);
@@ -1189,6 +1692,116 @@
}
+static void
+radius_server_receive_disconnect_resp(struct radius_server_data *data,
+ struct radius_client *client,
+ struct radius_msg *msg, int ack)
+{
+ struct radius_hdr *hdr;
+
+ if (!client->pending_dac_disconnect_req) {
+ RADIUS_DEBUG("Ignore unexpected Disconnect response");
+ radius_msg_free(msg);
+ return;
+ }
+
+ hdr = radius_msg_get_hdr(msg);
+ if (hdr->identifier != client->pending_dac_disconnect_id) {
+ RADIUS_DEBUG("Ignore unexpected Disconnect response with unexpected identifier %u (expected %u)",
+ hdr->identifier,
+ client->pending_dac_disconnect_id);
+ radius_msg_free(msg);
+ return;
+ }
+
+ if (radius_msg_verify(msg, (const u8 *) client->shared_secret,
+ client->shared_secret_len,
+ client->pending_dac_disconnect_req, 0)) {
+ RADIUS_DEBUG("Ignore Disconnect response with invalid authenticator");
+ radius_msg_free(msg);
+ return;
+ }
+
+ RADIUS_DEBUG("Disconnect-%s received for " MACSTR,
+ ack ? "ACK" : "NAK",
+ MAC2STR(client->pending_dac_disconnect_addr));
+
+ radius_msg_free(msg);
+ radius_msg_free(client->pending_dac_disconnect_req);
+ client->pending_dac_disconnect_req = NULL;
+}
+
+
+static void radius_server_receive_coa_resp(struct radius_server_data *data,
+ struct radius_client *client,
+ struct radius_msg *msg, int ack)
+{
+ struct radius_hdr *hdr;
+#ifdef CONFIG_SQLITE
+ char addrtxt[3 * ETH_ALEN];
+ char *sql;
+ int res;
+#endif /* CONFIG_SQLITE */
+
+ if (!client->pending_dac_coa_req) {
+ RADIUS_DEBUG("Ignore unexpected CoA response");
+ radius_msg_free(msg);
+ return;
+ }
+
+ hdr = radius_msg_get_hdr(msg);
+ if (hdr->identifier != client->pending_dac_coa_id) {
+ RADIUS_DEBUG("Ignore unexpected CoA response with unexpected identifier %u (expected %u)",
+ hdr->identifier,
+ client->pending_dac_coa_id);
+ radius_msg_free(msg);
+ return;
+ }
+
+ if (radius_msg_verify(msg, (const u8 *) client->shared_secret,
+ client->shared_secret_len,
+ client->pending_dac_coa_req, 0)) {
+ RADIUS_DEBUG("Ignore CoA response with invalid authenticator");
+ radius_msg_free(msg);
+ return;
+ }
+
+ RADIUS_DEBUG("CoA-%s received for " MACSTR,
+ ack ? "ACK" : "NAK",
+ MAC2STR(client->pending_dac_coa_addr));
+
+ radius_msg_free(msg);
+ radius_msg_free(client->pending_dac_coa_req);
+ client->pending_dac_coa_req = NULL;
+
+#ifdef CONFIG_SQLITE
+ if (!data->db)
+ return;
+
+ os_snprintf(addrtxt, sizeof(addrtxt), MACSTR,
+ MAC2STR(client->pending_dac_coa_addr));
+
+ if (ack) {
+ sql = sqlite3_mprintf("UPDATE current_sessions SET hs20_t_c_filtering=0, waiting_coa_ack=0, coa_ack_received=1 WHERE mac_addr=%Q",
+ addrtxt);
+ } else {
+ sql = sqlite3_mprintf("UPDATE current_sessions SET waiting_coa_ack=0 WHERE mac_addr=%Q",
+ addrtxt);
+ }
+ if (!sql)
+ return;
+
+ res = sqlite3_exec(data->db, sql, NULL, NULL, NULL);
+ sqlite3_free(sql);
+ if (res != SQLITE_OK) {
+ RADIUS_ERROR("Failed to update current_sessions entry: %s",
+ sqlite3_errmsg(data->db));
+ return;
+ }
+#endif /* CONFIG_SQLITE */
+}
+
+
static void radius_server_receive_auth(int sock, void *eloop_ctx,
void *sock_ctx)
{
@@ -1269,6 +1882,26 @@
radius_msg_dump(msg);
}
+ if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_DISCONNECT_ACK) {
+ radius_server_receive_disconnect_resp(data, client, msg, 1);
+ return;
+ }
+
+ if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_DISCONNECT_NAK) {
+ radius_server_receive_disconnect_resp(data, client, msg, 0);
+ return;
+ }
+
+ if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_COA_ACK) {
+ radius_server_receive_coa_resp(data, client, msg, 1);
+ return;
+ }
+
+ if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_COA_NAK) {
+ radius_server_receive_coa_resp(data, client, msg, 0);
+ return;
+ }
+
if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCESS_REQUEST) {
RADIUS_DEBUG("Unexpected RADIUS code %d",
radius_msg_get_hdr(msg)->code);
@@ -1529,6 +2162,8 @@
radius_server_free_sessions(data, prev->sessions);
os_free(prev->shared_secret);
+ radius_msg_free(prev->pending_dac_coa_req);
+ radius_msg_free(prev->pending_dac_disconnect_req);
os_free(prev);
}
}
@@ -1650,7 +2285,7 @@
entry->addr.s_addr = addr.s_addr;
val = 0;
for (i = 0; i < mask; i++)
- val |= 1 << (31 - i);
+ val |= 1U << (31 - i);
entry->mask.s_addr = htonl(val);
}
#ifdef CONFIG_IPV6
@@ -1764,6 +2399,12 @@
os_strdup(conf->subscr_remediation_url);
}
data->subscr_remediation_method = conf->subscr_remediation_method;
+ if (conf->hs20_sim_provisioning_url)
+ data->hs20_sim_provisioning_url =
+ os_strdup(conf->hs20_sim_provisioning_url);
+
+ if (conf->t_c_server_url)
+ data->t_c_server_url = os_strdup(conf->t_c_server_url);
#ifdef CONFIG_SQLITE
if (conf->sqlite_file) {
@@ -1881,6 +2522,8 @@
os_free(data->dump_msk_file);
#endif /* CONFIG_RADIUS_TEST */
os_free(data->subscr_remediation_url);
+ os_free(data->hs20_sim_provisioning_url);
+ os_free(data->t_c_server_url);
#ifdef CONFIG_SQLITE
if (data->db)
@@ -2049,6 +2692,7 @@
sess->accept_attr = user->accept_attr;
sess->remediation = user->remediation;
sess->macacl = user->macacl;
+ sess->t_c_timestamp = user->t_c_timestamp;
}
if (ret) {
@@ -2092,15 +2736,8 @@
{
struct radius_session *sess = ctx;
struct radius_server_data *data = sess->server;
- struct eap_server_erp_key *erp;
- dl_list_for_each(erp, &data->erp_keys, struct eap_server_erp_key,
- list) {
- if (os_strcmp(erp->keyname_nai, keyname) == 0)
- return erp;
- }
-
- return NULL;
+ return radius_server_erp_find_key(data, keyname);
}
@@ -2175,3 +2812,212 @@
radius_msg_free(msg);
}
+
+
+#ifdef CONFIG_SQLITE
+
+struct db_session_fields {
+ char *identity;
+ char *nas;
+ int hs20_t_c_filtering;
+ int waiting_coa_ack;
+ int coa_ack_received;
+};
+
+
+static int get_db_session_fields(void *ctx, int argc, char *argv[], char *col[])
+{
+ struct db_session_fields *fields = ctx;
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ if (!argv[i])
+ continue;
+
+ RADIUS_DEBUG("Session DB: %s=%s", col[i], argv[i]);
+
+ if (os_strcmp(col[i], "identity") == 0) {
+ os_free(fields->identity);
+ fields->identity = os_strdup(argv[i]);
+ } else if (os_strcmp(col[i], "nas") == 0) {
+ os_free(fields->nas);
+ fields->nas = os_strdup(argv[i]);
+ } else if (os_strcmp(col[i], "hs20_t_c_filtering") == 0) {
+ fields->hs20_t_c_filtering = atoi(argv[i]);
+ } else if (os_strcmp(col[i], "waiting_coa_ack") == 0) {
+ fields->waiting_coa_ack = atoi(argv[i]);
+ } else if (os_strcmp(col[i], "coa_ack_received") == 0) {
+ fields->coa_ack_received = atoi(argv[i]);
+ }
+ }
+
+ return 0;
+}
+
+
+static void free_db_session_fields(struct db_session_fields *fields)
+{
+ os_free(fields->identity);
+ fields->identity = NULL;
+ os_free(fields->nas);
+ fields->nas = NULL;
+}
+
+#endif /* CONFIG_SQLITE */
+
+
+int radius_server_dac_request(struct radius_server_data *data, const char *req)
+{
+#ifdef CONFIG_SQLITE
+ char *sql;
+ int res;
+ int disconnect;
+ const char *pos = req;
+ u8 addr[ETH_ALEN];
+ char addrtxt[3 * ETH_ALEN];
+ int t_c_clear = 0;
+ struct db_session_fields fields;
+ struct sockaddr_in das;
+ struct radius_client *client;
+ struct radius_msg *msg;
+ struct wpabuf *buf;
+ u8 identifier;
+ struct os_time now;
+
+ if (!data)
+ return -1;
+
+ /* req: <disconnect|coa> <MAC Address> [t_c_clear] */
+
+ if (os_strncmp(pos, "disconnect ", 11) == 0) {
+ disconnect = 1;
+ pos += 11;
+ } else if (os_strncmp(req, "coa ", 4) == 0) {
+ disconnect = 0;
+ pos += 4;
+ } else {
+ return -1;
+ }
+
+ if (hwaddr_aton(pos, addr))
+ return -1;
+ pos = os_strchr(pos, ' ');
+ if (pos) {
+ if (os_strstr(pos, "t_c_clear"))
+ t_c_clear = 1;
+ }
+
+ if (!disconnect && !t_c_clear) {
+ RADIUS_ERROR("DAC request for CoA without any authorization change");
+ return -1;
+ }
+
+ if (!data->db) {
+ RADIUS_ERROR("SQLite database not in use");
+ return -1;
+ }
+
+ os_snprintf(addrtxt, sizeof(addrtxt), MACSTR, MAC2STR(addr));
+
+ sql = sqlite3_mprintf("SELECT * FROM current_sessions WHERE mac_addr=%Q",
+ addrtxt);
+ if (!sql)
+ return -1;
+
+ os_memset(&fields, 0, sizeof(fields));
+ res = sqlite3_exec(data->db, sql, get_db_session_fields, &fields, NULL);
+ sqlite3_free(sql);
+ if (res != SQLITE_OK) {
+ RADIUS_ERROR("Failed to find matching current_sessions entry from sqlite database: %s",
+ sqlite3_errmsg(data->db));
+ free_db_session_fields(&fields);
+ return -1;
+ }
+
+ if (!fields.nas) {
+ RADIUS_ERROR("No NAS information found from current_sessions");
+ free_db_session_fields(&fields);
+ return -1;
+ }
+
+ os_memset(&das, 0, sizeof(das));
+ das.sin_family = AF_INET;
+ das.sin_addr.s_addr = inet_addr(fields.nas);
+ das.sin_port = htons(3799);
+
+ free_db_session_fields(&fields);
+
+ client = radius_server_get_client(data, &das.sin_addr, 0);
+ if (!client) {
+ RADIUS_ERROR("No NAS information available to protect the packet");
+ return -1;
+ }
+
+ identifier = client->next_dac_identifier++;
+
+ msg = radius_msg_new(disconnect ? RADIUS_CODE_DISCONNECT_REQUEST :
+ RADIUS_CODE_COA_REQUEST, identifier);
+ if (!msg)
+ return -1;
+
+ os_snprintf(addrtxt, sizeof(addrtxt), RADIUS_802_1X_ADDR_FORMAT,
+ MAC2STR(addr));
+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
+ (u8 *) addrtxt, os_strlen(addrtxt))) {
+ RADIUS_ERROR("Could not add Calling-Station-Id");
+ radius_msg_free(msg);
+ return -1;
+ }
+
+ if (!disconnect && t_c_clear) {
+ u8 val[4] = { 0x00, 0x00, 0x00, 0x00 }; /* E=0 */
+
+ if (!radius_msg_add_wfa(
+ msg, RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING,
+ val, sizeof(val))) {
+ RADIUS_DEBUG("Failed to add WFA-HS20-T-C-Filtering");
+ radius_msg_free(msg);
+ return -1;
+ }
+ }
+
+ os_get_time(&now);
+ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
+ now.sec)) {
+ RADIUS_ERROR("Failed to add Event-Timestamp attribute");
+ radius_msg_free(msg);
+ return -1;
+ }
+
+ radius_msg_finish_acct(msg, (u8 *) client->shared_secret,
+ client->shared_secret_len);
+
+ if (wpa_debug_level <= MSG_MSGDUMP)
+ radius_msg_dump(msg);
+
+ buf = radius_msg_get_buf(msg);
+ if (sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0,
+ (struct sockaddr *) &das, sizeof(das)) < 0) {
+ RADIUS_ERROR("Failed to send packet - sendto: %s",
+ strerror(errno));
+ radius_msg_free(msg);
+ return -1;
+ }
+
+ if (disconnect) {
+ radius_msg_free(client->pending_dac_disconnect_req);
+ client->pending_dac_disconnect_req = msg;
+ client->pending_dac_disconnect_id = identifier;
+ os_memcpy(client->pending_dac_disconnect_addr, addr, ETH_ALEN);
+ } else {
+ radius_msg_free(client->pending_dac_coa_req);
+ client->pending_dac_coa_req = msg;
+ client->pending_dac_coa_id = identifier;
+ os_memcpy(client->pending_dac_coa_addr, addr, ETH_ALEN);
+ }
+
+ return 0;
+#else /* CONFIG_SQLITE */
+ return -1;
+#endif /* CONFIG_SQLITE */
+}
diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h
index 996f00e..53728f9 100644
--- a/src/radius/radius_server.h
+++ b/src/radius/radius_server.h
@@ -233,6 +233,9 @@
char *subscr_remediation_url;
u8 subscr_remediation_method;
+ char *hs20_sim_provisioning_url;
+
+ char *t_c_server_url;
};
@@ -246,5 +249,6 @@
size_t buflen);
void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx);
+int radius_server_dac_request(struct radius_server_data *data, const char *req);
#endif /* RADIUS_SERVER_H */
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index f5024f2..d720f7b 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -96,7 +96,7 @@
eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa :
- pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL);
+ pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL, 0);
if (entry) {
sec = pmksa->pmksa->reauth_time - now.sec;
if (sec < 0)
@@ -263,7 +263,8 @@
}
pmksa->pmksa_count++;
wpa_printf(MSG_DEBUG, "RSN: Added PMKSA cache entry for " MACSTR
- " network_ctx=%p", MAC2STR(entry->aa), entry->network_ctx);
+ " network_ctx=%p akmp=0x%x", MAC2STR(entry->aa),
+ entry->network_ctx, entry->akmp);
wpa_sm_add_pmkid(pmksa->sm, entry->network_ctx, entry->aa, entry->pmkid,
entry->fils_cache_id_set ? entry->fils_cache_id : NULL,
entry->pmk, entry->pmk_len);
@@ -341,17 +342,20 @@
* @aa: Authenticator address or %NULL to match any
* @pmkid: PMKID or %NULL to match any
* @network_ctx: Network context or %NULL to match any
+ * @akmp: Specific AKMP to search for or 0 for any
* Returns: Pointer to PMKSA cache entry or %NULL if no match was found
*/
struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
const u8 *aa, const u8 *pmkid,
- const void *network_ctx)
+ const void *network_ctx,
+ int akmp)
{
struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
while (entry) {
if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) &&
(pmkid == NULL ||
os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) &&
+ (!akmp || akmp == entry->akmp) &&
(network_ctx == NULL || network_ctx == entry->network_ctx))
return entry;
entry = entry->next;
@@ -390,6 +394,7 @@
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @network_ctx: Network configuration context
* @aa: Authenticator address for the new AP
+ * @akmp: Specific AKMP to search for or 0 for any
* Returns: Pointer to a new PMKSA cache entry or %NULL if not available
*
* Try to create a new PMKSA cache entry opportunistically by guessing that the
@@ -398,7 +403,7 @@
*/
struct rsn_pmksa_cache_entry *
pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx,
- const u8 *aa)
+ const u8 *aa, int akmp)
{
struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
@@ -406,7 +411,8 @@
if (network_ctx == NULL)
return NULL;
while (entry) {
- if (entry->network_ctx == network_ctx) {
+ if (entry->network_ctx == network_ctx &&
+ (!akmp || entry->akmp == akmp)) {
entry = pmksa_cache_clone_entry(pmksa, entry, aa);
if (entry) {
wpa_printf(MSG_DEBUG, "RSN: added "
@@ -476,11 +482,13 @@
*/
int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
const u8 *bssid, void *network_ctx,
- int try_opportunistic, const u8 *fils_cache_id)
+ int try_opportunistic, const u8 *fils_cache_id,
+ int akmp)
{
struct rsn_pmksa_cache *pmksa = sm->pmksa;
wpa_printf(MSG_DEBUG, "RSN: PMKSA cache search - network_ctx=%p "
- "try_opportunistic=%d", network_ctx, try_opportunistic);
+ "try_opportunistic=%d akmp=0x%x",
+ network_ctx, try_opportunistic, akmp);
if (pmkid)
wpa_hexdump(MSG_DEBUG, "RSN: Search for PMKID",
pmkid, PMKID_LEN);
@@ -495,14 +503,14 @@
sm->cur_pmksa = NULL;
if (pmkid)
sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid,
- network_ctx);
+ network_ctx, akmp);
if (sm->cur_pmksa == NULL && bssid)
sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL,
- network_ctx);
+ network_ctx, akmp);
if (sm->cur_pmksa == NULL && try_opportunistic && bssid)
sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa,
network_ctx,
- bssid);
+ bssid, akmp);
if (sm->cur_pmksa == NULL && fils_cache_id)
sm->cur_pmksa = pmksa_cache_get_fils_cache_id(pmksa,
network_ctx,
diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h
index f9a72a6..6c49fa9 100644
--- a/src/rsn_supp/pmksa_cache.h
+++ b/src/rsn_supp/pmksa_cache.h
@@ -61,7 +61,8 @@
void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
const u8 *aa, const u8 *pmkid,
- const void *network_ctx);
+ const void *network_ctx,
+ int akmp);
int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
struct rsn_pmksa_cache_entry * pmksa_cache_head(struct rsn_pmksa_cache *pmksa);
struct rsn_pmksa_cache_entry *
@@ -76,10 +77,11 @@
void pmksa_cache_clear_current(struct wpa_sm *sm);
int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
const u8 *bssid, void *network_ctx,
- int try_opportunistic, const u8 *fils_cache_id);
+ int try_opportunistic, const u8 *fils_cache_id,
+ int akmp);
struct rsn_pmksa_cache_entry *
pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
- void *network_ctx, const u8 *aa);
+ void *network_ctx, const u8 *aa, int akmp);
void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
const u8 *pmk, size_t pmk_len);
@@ -99,7 +101,7 @@
static inline struct rsn_pmksa_cache_entry *
pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *pmkid,
- const void *network_ctx)
+ const void *network_ctx, int akmp)
{
return NULL;
}
@@ -146,7 +148,8 @@
const u8 *bssid,
void *network_ctx,
int try_opportunistic,
- const u8 *fils_cache_id)
+ const u8 *fils_cache_id,
+ int akmp)
{
return -1;
}
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index d4276b9..d0c43f4 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -323,7 +323,7 @@
dl_list_for_each_safe(candidate, n, &sm->pmksa_candidates,
struct rsn_pmksa_candidate, list) {
struct rsn_pmksa_cache_entry *p = NULL;
- p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL, NULL);
+ p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL, NULL, 0);
if (os_memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 &&
(p == NULL || p->opportunistic)) {
wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA "
@@ -372,7 +372,7 @@
if (sm->network_ctx && sm->proactive_key_caching)
pmksa_cache_get_opportunistic(sm->pmksa, sm->network_ctx,
- bssid);
+ bssid, 0);
if (!preauth) {
wpa_printf(MSG_DEBUG, "RSN: Ignored PMKID candidate without "
@@ -483,7 +483,7 @@
if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie))
return;
- pmksa = pmksa_cache_get(sm->pmksa, bssid, NULL, NULL);
+ pmksa = pmksa_cache_get(sm->pmksa, bssid, NULL, NULL, 0);
if (pmksa && (!pmksa->opportunistic ||
!(ie.capabilities & WPA_CAPABILITY_PREAUTH)))
return;
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 5e350ed..704c95e 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -35,6 +35,7 @@
#define TDLS_TESTING_DECLINE_RESP BIT(9)
#define TDLS_TESTING_IGNORE_AP_PROHIBIT BIT(10)
#define TDLS_TESTING_WRONG_MIC BIT(11)
+#define TDLS_TESTING_DOUBLE_TPK_M2 BIT(12)
unsigned int tdls_testing = 0;
#endif /* CONFIG_TDLS_TESTING */
@@ -1593,7 +1594,7 @@
peer->supp_rates, sizeof(peer->supp_rates),
kde->supp_rates + 2, kde->supp_rates_len - 2,
kde->ext_supp_rates ? kde->ext_supp_rates + 2 : NULL,
- kde->ext_supp_rates_len - 2);
+ kde->ext_supp_rates ? kde->ext_supp_rates_len - 2 : 0);
return 0;
}
@@ -2124,6 +2125,13 @@
goto error;
}
+#ifdef CONFIG_TDLS_TESTING
+ if (tdls_testing & TDLS_TESTING_DOUBLE_TPK_M2) {
+ wpa_printf(MSG_INFO, "TDLS: Testing - Send another TPK M2");
+ wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer);
+ }
+#endif /* CONFIG_TDLS_TESTING */
+
return 0;
error:
@@ -2151,11 +2159,11 @@
eloop_register_timeout(lifetime, 0, wpa_tdls_tpk_timeout,
sm, peer);
#ifdef CONFIG_TDLS_TESTING
- if (tdls_testing & TDLS_TESTING_NO_TPK_EXPIRATION) {
- wpa_printf(MSG_DEBUG, "TDLS: Testing - disable TPK "
- "expiration");
- eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
- }
+ if (tdls_testing & TDLS_TESTING_NO_TPK_EXPIRATION) {
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Testing - disable TPK expiration");
+ eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
+ }
#endif /* CONFIG_TDLS_TESTING */
}
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index ff4a6ed..66a8643 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - WPA state machine and EAPOL-Key processing
- * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
* Copyright(c) 2015 Intel Deutschland GmbH
*
* This software may be distributed under the terms of the BSD license.
@@ -20,8 +20,10 @@
#include "crypto/sha512.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/ocv.h"
#include "eap_common/eap_defs.h"
#include "eapol_supp/eapol_supp_sm.h"
+#include "drivers/driver.h"
#include "wpa.h"
#include "eloop.h"
#include "preauth.h"
@@ -181,8 +183,7 @@
int key_info, ver;
u8 bssid[ETH_ALEN], *rbuf, *key_mic, *mic;
- if (sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
- wpa_key_mgmt_suite_b(sm->key_mgmt))
+ if (wpa_use_akm_defined(sm->key_mgmt))
ver = WPA_KEY_INFO_TYPE_AKM_DEFINED;
else if (wpa_key_mgmt_ft(sm->key_mgmt) ||
wpa_key_mgmt_sha256(sm->key_mgmt))
@@ -269,7 +270,7 @@
* event before receiving this 1/4 message, so try to find a
* matching PMKSA cache entry here. */
sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, pmkid,
- NULL);
+ NULL, 0);
if (sm->cur_pmksa) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"RSN: found matching PMKID from PMKSA cache");
@@ -289,6 +290,18 @@
eapol_sm_notify_cached(sm->eapol);
#ifdef CONFIG_IEEE80211R
sm->xxkey_len = 0;
+#ifdef CONFIG_SAE
+ if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE &&
+ sm->pmk_len == PMK_LEN) {
+ /* Need to allow FT key derivation to proceed with
+ * PMK from SAE being used as the XXKey in cases where
+ * the PMKID in msg 1/4 matches the PMKSA entry that was
+ * just added based on SAE authentication for the
+ * initial mobility domain association. */
+ os_memcpy(sm->xxkey, sm->pmk, sm->pmk_len);
+ sm->xxkey_len = sm->pmk_len;
+ }
+#endif /* CONFIG_SAE */
#endif /* CONFIG_IEEE80211R */
} else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && sm->eapol) {
int res, pmk_len;
@@ -312,8 +325,15 @@
u8 buf[2 * PMK_LEN];
if (eapol_sm_get_key(sm->eapol, buf, 2 * PMK_LEN) == 0)
{
- os_memcpy(sm->xxkey, buf + PMK_LEN, PMK_LEN);
- sm->xxkey_len = PMK_LEN;
+ if (wpa_key_mgmt_sha384(sm->key_mgmt)) {
+ os_memcpy(sm->xxkey, buf,
+ SHA384_MAC_LEN);
+ sm->xxkey_len = SHA384_MAC_LEN;
+ } else {
+ os_memcpy(sm->xxkey, buf + PMK_LEN,
+ PMK_LEN);
+ sm->xxkey_len = PMK_LEN;
+ }
os_memset(buf, 0, sizeof(buf));
}
#endif /* CONFIG_IEEE80211R */
@@ -343,8 +363,8 @@
fils_cache_id);
}
if (!sm->cur_pmksa && pmkid &&
- pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL))
- {
+ pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL,
+ 0)) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"RSN: the new PMK matches with the "
"PMKID");
@@ -514,15 +534,25 @@
static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
{
+ const u8 *z = NULL;
+ size_t z_len = 0;
+
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt))
return wpa_derive_ptk_ft(sm, src_addr, key, ptk);
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_DPP2
+ if (sm->key_mgmt == WPA_KEY_MGMT_DPP && sm->dpp_z) {
+ z = wpabuf_head(sm->dpp_z);
+ z_len = wpabuf_len(sm->dpp_z);
+ }
+#endif /* CONFIG_DPP2 */
+
return wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
sm->own_addr, sm->bssid, sm->snonce,
key->key_nonce, ptk, sm->key_mgmt,
- sm->pairwise_cipher);
+ sm->pairwise_cipher, z, z_len);
}
@@ -600,6 +630,33 @@
kde = sm->assoc_wpa_ie;
kde_len = sm->assoc_wpa_ie_len;
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm)) {
+ struct wpa_channel_info ci;
+ u8 *pos;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in EAPOL-Key 2/4");
+ goto failed;
+ }
+
+ kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 3);
+ if (!kde_buf) {
+ wpa_printf(MSG_WARNING,
+ "Failed to allocate memory for KDE with OCI in EAPOL-Key 2/4");
+ goto failed;
+ }
+
+ os_memcpy(kde_buf, kde, kde_len);
+ kde = kde_buf;
+ pos = kde + kde_len;
+ if (ocv_insert_oci_kde(&ci, &pos) < 0)
+ goto failed;
+ kde_len = pos - kde;
+ }
+#endif /* CONFIG_OCV */
+
#ifdef CONFIG_P2P
if (sm->p2p) {
kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 1);
@@ -668,7 +725,9 @@
* likelihood of the first preauth EAPOL-Start frame getting to
* the target AP.
*/
- eloop_register_timeout(1, 0, wpa_sm_start_preauth, sm, NULL);
+ if (!dl_list_empty(&sm->pmksa_candidates))
+ eloop_register_timeout(1, 0, wpa_sm_start_preauth,
+ sm, NULL);
}
if (sm->cur_pmksa && sm->cur_pmksa->opportunistic) {
@@ -962,8 +1021,6 @@
}
os_memset(&gd, 0, sizeof(gd));
- wpa_supplicant_key_neg_complete(sm, sm->bssid,
- key_info & WPA_KEY_INFO_SECURE);
return 0;
}
@@ -989,7 +1046,7 @@
}
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
- "WPA: IGTK keyid %d pn %02x%02x%02x%02x%02x%02x",
+ "WPA: IGTK keyid %d pn " COMPACT_MACSTR,
keyidx, MAC2STR(igtk->pn));
wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, len);
if (keyidx > 4095) {
@@ -1001,9 +1058,27 @@
broadcast_ether_addr,
keyidx, 0, igtk->pn, sizeof(igtk->pn),
igtk->igtk, len) < 0) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "WPA: Failed to configure IGTK to the driver");
- return -1;
+ if (keyidx == 0x0400 || keyidx == 0x0500) {
+ /* Assume the AP has broken PMF implementation since it
+ * seems to have swapped the KeyID bytes. The AP cannot
+ * be trusted to implement BIP correctly or provide a
+ * valid IGTK, so do not try to configure this key with
+ * swapped KeyID bytes. Instead, continue without
+ * configuring the IGTK so that the driver can drop any
+ * received group-addressed robust management frames due
+ * to missing keys.
+ *
+ * Normally, this error behavior would result in us
+ * disconnecting, but there are number of deployed APs
+ * with this broken behavior, so as an interoperability
+ * workaround, allow the connection to proceed. */
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: Ignore IGTK configuration error due to invalid IGTK KeyID byte order");
+ } else {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Failed to configure IGTK to the driver");
+ return -1;
+ }
}
if (wnm_sleep) {
@@ -1400,6 +1475,26 @@
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "Failed to get channel info to validate received OCI in EAPOL-Key 3/4");
+ return;
+ }
+
+ 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);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
&sm->ptk) < 0) {
goto failed;
@@ -1424,8 +1519,11 @@
wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED) {
- wpa_supplicant_key_neg_complete(sm, sm->bssid,
- key_info & WPA_KEY_INFO_SECURE);
+ /* No GTK to be set to the driver */
+ } else if (!ie.gtk && sm->proto == WPA_PROTO_RSN) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: No GTK KDE included in EAPOL-Key msg 3/4");
+ goto failed;
} else if (ie.gtk &&
wpa_supplicant_pairwise_gtk(sm, key,
ie.gtk, ie.gtk_len, key_info) < 0) {
@@ -1440,10 +1538,20 @@
goto failed;
}
+ if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED || ie.gtk)
+ wpa_supplicant_key_neg_complete(sm, sm->bssid,
+ key_info & WPA_KEY_INFO_SECURE);
+
if (ie.gtk)
wpa_sm_set_rekey_offload(sm);
- if (sm->proto == WPA_PROTO_RSN && wpa_key_mgmt_suite_b(sm->key_mgmt)) {
+ /* Add PMKSA cache entry for Suite B AKMs here since PMKID can be
+ * calculated only after KCK has been derived. Though, do not replace an
+ * existing PMKSA entry after each 4-way handshake (i.e., new KCK/PMKID)
+ * to avoid unnecessary changes of PMKID while continuing to use the
+ * same PMK. */
+ if (sm->proto == WPA_PROTO_RSN && wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+ !sm->cur_pmksa) {
struct rsn_pmksa_cache_entry *sa;
sa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len, NULL,
@@ -1487,6 +1595,26 @@
}
maxkeylen = gd->gtk_len = ie.gtk_len - 2;
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "Failed to get channel info to validate received OCI in EAPOL-Key group msg 1/2");
+ return -1;
+ }
+
+ 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);
+ return -1;
+ }
+ }
+#endif /* CONFIG_OCV */
+
if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
gd->gtk_len, maxkeylen,
&gd->key_rsc_len, &gd->alg))
@@ -1607,11 +1735,17 @@
size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
u8 *rbuf, *key_mic;
+ size_t kde_len = 0;
+
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm))
+ kde_len = OCV_OCI_KDE_LEN;
+#endif /* CONFIG_OCV */
mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len);
hdrlen = sizeof(*reply) + mic_len + 2;
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- hdrlen, &rlen, (void *) &reply);
+ hdrlen + kde_len, &rlen, (void *) &reply);
if (rbuf == NULL)
return -1;
@@ -1633,7 +1767,27 @@
WPA_REPLAY_COUNTER_LEN);
key_mic = (u8 *) (reply + 1);
- WPA_PUT_BE16(key_mic + mic_len, 0);
+ WPA_PUT_BE16(key_mic + mic_len, kde_len); /* Key Data Length */
+
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm)) {
+ struct wpa_channel_info ci;
+ u8 *pos;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in EAPOL-Key 2/2");
+ os_free(rbuf);
+ return -1;
+ }
+
+ pos = key_mic + mic_len + 2; /* Key Data */
+ if (ocv_insert_oci_kde(&ci, &pos) < 0) {
+ os_free(rbuf);
+ return -1;
+ }
+ }
+#endif /* CONFIG_OCV */
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
return wpa_eapol_key_send(sm, &sm->ptk, ver, sm->bssid, ETH_P_EAPOL,
@@ -1731,7 +1885,15 @@
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid EAPOL-Key MIC "
"when using TPTK - ignoring TPTK");
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore Key MIC failure for fuzz testing");
+ goto continue_fuzz;
+#endif /* TEST_FUZZ */
} else {
+#ifdef TEST_FUZZ
+ continue_fuzz:
+#endif /* TEST_FUZZ */
ok = 1;
sm->tptk_set = 0;
sm->ptk_set = 1;
@@ -1739,7 +1901,7 @@
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
/*
* This assures the same TPTK in sm->tptk can never be
- * copied twice to sm->pkt as the new PTK. In
+ * copied twice to sm->ptk as the new PTK. In
* combination with the installed flag in the wpa_ptk
* struct, this assures the same PTK is only installed
* once.
@@ -1757,8 +1919,16 @@
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid EAPOL-Key MIC - "
"dropping packet");
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore Key MIC failure for fuzz testing");
+ goto continue_fuzz2;
+#endif /* TEST_FUZZ */
return -1;
}
+#ifdef TEST_FUZZ
+ continue_fuzz2:
+#endif /* TEST_FUZZ */
ok = 1;
}
@@ -1814,10 +1984,7 @@
#endif /* CONFIG_NO_RC4 */
} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
ver == WPA_KEY_INFO_TYPE_AES_128_CMAC ||
- sm->key_mgmt == WPA_KEY_MGMT_OWE ||
- sm->key_mgmt == WPA_KEY_MGMT_DPP ||
- sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
- wpa_key_mgmt_suite_b(sm->key_mgmt)) {
+ wpa_use_aes_key_wrap(sm->key_mgmt)) {
u8 *buf;
wpa_printf(MSG_DEBUG,
@@ -1836,14 +2003,25 @@
"WPA: No memory for AES-UNWRAP buffer");
return -1;
}
+#ifdef TEST_FUZZ
+ os_memset(buf, 0x11, *key_data_len);
+#endif /* TEST_FUZZ */
if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, *key_data_len / 8,
key_data, buf)) {
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore AES unwrap failure for fuzz testing");
+ goto continue_fuzz;
+#endif /* TEST_FUZZ */
bin_clear_free(buf, *key_data_len);
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: AES unwrap failed - "
"could not decrypt EAPOL-Key key data");
return -1;
}
+#ifdef TEST_FUZZ
+ continue_fuzz:
+#endif /* TEST_FUZZ */
os_memcpy(key_data, buf, *key_data_len);
bin_clear_free(buf, *key_data_len);
WPA_PUT_BE16(((u8 *) (key + 1)) + mic_len, *key_data_len);
@@ -2094,29 +2272,14 @@
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
- !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
- !wpa_key_mgmt_fils(sm->key_mgmt) &&
- sm->key_mgmt != WPA_KEY_MGMT_OWE &&
- sm->key_mgmt != WPA_KEY_MGMT_DPP &&
- sm->key_mgmt != WPA_KEY_MGMT_OSEN) {
+ !wpa_use_akm_defined(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: Unsupported EAPOL-Key descriptor version %d",
ver);
goto out;
}
- if (sm->key_mgmt == WPA_KEY_MGMT_OSEN &&
- ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
- wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
- "OSEN: Unsupported EAPOL-Key descriptor version %d",
- ver);
- goto out;
- }
-
- if ((wpa_key_mgmt_suite_b(sm->key_mgmt) ||
- wpa_key_mgmt_fils(sm->key_mgmt) ||
- sm->key_mgmt == WPA_KEY_MGMT_DPP ||
- sm->key_mgmt == WPA_KEY_MGMT_OWE) &&
+ if (wpa_use_akm_defined(sm->key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"RSN: Unsupported EAPOL-Key descriptor version %d (expected AKM defined = 0)",
@@ -2127,7 +2290,8 @@
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt)) {
/* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */
- if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+ if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
+ !wpa_use_akm_defined(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"FT: AP did not use AES-128-CMAC");
goto out;
@@ -2137,9 +2301,7 @@
#ifdef CONFIG_IEEE80211W
if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
- sm->key_mgmt != WPA_KEY_MGMT_OSEN &&
- !wpa_key_mgmt_fils(sm->key_mgmt) &&
- !wpa_key_mgmt_suite_b(sm->key_mgmt)) {
+ !wpa_use_akm_defined(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: AP did not use the "
"negotiated AES-128-CMAC");
@@ -2148,10 +2310,7 @@
} else
#endif /* CONFIG_IEEE80211W */
if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
- !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
- !wpa_key_mgmt_fils(sm->key_mgmt) &&
- sm->key_mgmt != WPA_KEY_MGMT_OWE &&
- sm->key_mgmt != WPA_KEY_MGMT_DPP &&
+ !wpa_use_akm_defined(sm->key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: CCMP is used, but EAPOL-Key "
@@ -2171,7 +2330,7 @@
} else
goto out;
} else if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
- !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+ !wpa_use_akm_defined(sm->key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: GCMP is used, but EAPOL-Key "
@@ -2219,6 +2378,17 @@
if ((sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) &&
(key_info & WPA_KEY_INFO_ENCR_KEY_DATA) && mic_len) {
+ /*
+ * Only decrypt the Key Data field if the frame's authenticity
+ * was verified. When using AES-SIV (FILS), the MIC flag is not
+ * set, so this check should only be performed if mic_len != 0
+ * which is the case in this code branch.
+ */
+ if (!(key_info & WPA_KEY_INFO_MIC)) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Ignore EAPOL-Key with encrypted but unauthenticated data");
+ goto out;
+ }
if (wpa_supplicant_decrypt_key_data(sm, key, mic_len,
ver, key_data,
&key_data_len))
@@ -2427,6 +2597,7 @@
}
if (deauth) {
+ sm->pmk_len = 0;
os_memset(sm->pmk, 0, sizeof(sm->pmk));
wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
}
@@ -2499,6 +2670,9 @@
#ifdef CONFIG_OWE
crypto_ecdh_deinit(sm->owe_ecdh);
#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP2
+ wpabuf_clear_free(sm->dpp_z);
+#endif /* CONFIG_DPP2 */
os_free(sm);
}
@@ -2850,6 +3024,9 @@
case WPA_PARAM_MFP:
sm->mfp = value;
break;
+ case WPA_PARAM_OCV:
+ sm->ocv = value;
+ break;
default:
break;
}
@@ -2924,6 +3101,19 @@
}
+int wpa_sm_ocv_enabled(struct wpa_sm *sm)
+{
+ struct wpa_ie_data rsn;
+
+ if (!sm->ocv || !sm->ap_rsn_ie)
+ return 0;
+
+ return wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len,
+ &rsn) >= 0 &&
+ (rsn.capabilities & WPA_CAPABILITY_OCVC);
+}
+
+
/**
* wpa_sm_set_assoc_wpa_ie_default - Generate own WPA/RSN IE from configuration
* @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -3140,7 +3330,7 @@
int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid,
const void *network_ctx)
{
- return pmksa_cache_get(sm->pmksa, bssid, NULL, network_ctx) != NULL;
+ return pmksa_cache_get(sm->pmksa, bssid, NULL, network_ctx, 0) != NULL;
}
@@ -3149,6 +3339,7 @@
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK");
sm->ptk_set = 0;
sm->tptk_set = 0;
+ sm->pmk_len = 0;
os_memset(sm->pmk, 0, sizeof(sm->pmk));
os_memset(&sm->ptk, 0, sizeof(sm->ptk));
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
@@ -3160,8 +3351,11 @@
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
+ sm->xxkey_len = 0;
os_memset(sm->pmk_r0, 0, sizeof(sm->pmk_r0));
+ sm->pmk_r0_len = 0;
os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1));
+ sm->pmk_r1_len = 0;
#endif /* CONFIG_IEEE80211R */
}
@@ -3306,6 +3500,12 @@
#endif /* CONFIG_TESTING_OPTIONS */
+unsigned int wpa_sm_get_key_mgmt(struct wpa_sm *sm)
+{
+ return sm->key_mgmt;
+}
+
+
#ifdef CONFIG_FILS
struct wpabuf * fils_build_auth(struct wpa_sm *sm, int dh_group, const u8 *md)
@@ -3531,6 +3731,7 @@
os_memcpy(sm->fils_anonce, elems.fils_nonce, FILS_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "FILS: ANonce", sm->fils_anonce, FILS_NONCE_LEN);
+#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt)) {
struct wpa_ft_ies parse;
@@ -3539,7 +3740,8 @@
goto fail;
}
- if (wpa_ft_parse_ies(pos, end - pos, &parse) < 0) {
+ if (wpa_ft_parse_ies(pos, end - pos, &parse,
+ wpa_key_mgmt_sha384(sm->key_mgmt)) < 0) {
wpa_printf(MSG_DEBUG, "FILS+FT: Failed to parse IEs");
goto fail;
}
@@ -3578,6 +3780,7 @@
wpabuf_free(sm->fils_ft_ies);
sm->fils_ft_ies = NULL;
}
+#endif /* CONFIG_IEEE80211R */
/* PMKID List */
if (rsn.pmkid && rsn.num_pmkid > 0) {
@@ -3738,6 +3941,7 @@
struct rsn_ie_hdr *rsnie;
u16 capab;
u8 *pos;
+ int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
/* RSNIE[PMKR0Name/PMKR1Name] */
rsnie = wpabuf_put(buf, sizeof(*rsnie));
@@ -3789,6 +3993,8 @@
if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC)
capab |= WPA_CAPABILITY_MFPC;
#endif /* CONFIG_IEEE80211W */
+ if (sm->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
wpabuf_put_le16(buf, capab);
/* PMKID Count */
@@ -3805,22 +4011,26 @@
if (wpa_derive_pmk_r0(sm->fils_ft, sm->fils_ft_len, sm->ssid,
sm->ssid_len, sm->mobility_domain,
sm->r0kh_id, sm->r0kh_id_len, sm->own_addr,
- sm->pmk_r0, sm->pmk_r0_name) < 0) {
+ sm->pmk_r0, sm->pmk_r0_name, use_sha384) < 0) {
wpa_printf(MSG_WARNING, "FILS+FT: Could not derive PMK-R0");
return -1;
}
- wpa_hexdump_key(MSG_DEBUG, "FILS+FT: PMK-R0", sm->pmk_r0, PMK_LEN);
+ 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);
if (wpa_derive_pmk_r1_name(sm->pmk_r0_name, sm->r1kh_id, sm->own_addr,
- pos) < 0) {
+ sm->pmk_r1_name, use_sha384) < 0) {
wpa_printf(MSG_WARNING, "FILS+FT: Could not derive PMKR1Name");
return -1;
}
- wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR1Name", pos, WPA_PMK_NAME_LEN);
+ 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);
#ifdef CONFIG_IEEE80211W
if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
@@ -3921,6 +4131,26 @@
/* TODO: FILS IP Address Assignment */
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm)) {
+ struct wpa_channel_info ci;
+ u8 *pos;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "FILS: Failed to get channel info for OCI element");
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ pos = wpabuf_put(buf, OCV_OCI_EXTENDED_LEN);
+ if (ocv_insert_extended_oci(&ci, pos) < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+ }
+#endif /* CONFIG_OCV */
+
wpa_hexdump_buf(MSG_DEBUG, "FILS: Association Request plaintext", buf);
*kek = sm->ptk.kek;
@@ -4084,6 +4314,43 @@
goto fail;
}
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info to validate received OCI in FILS (Re)Association Response frame");
+ goto fail;
+ }
+
+ 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);
+ goto fail;
+ }
+ }
+#endif /* CONFIG_OCV */
+
+#ifdef CONFIG_IEEE80211R
+ if (wpa_key_mgmt_ft(sm->key_mgmt) && sm->fils_ft_ies) {
+ struct wpa_ie_data rsn;
+
+ /* Check that PMKR1Name derived by the AP matches */
+ if (!elems.rsn_ie ||
+ wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ &rsn) < 0 ||
+ !rsn.pmkid || rsn.num_pmkid != 1 ||
+ os_memcmp(rsn.pmkid, sm->pmk_r1_name,
+ WPA_PMK_NAME_LEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "FILS+FT: No RSNE[PMKR1Name] match in AssocResp");
+ goto fail;
+ }
+ }
+#endif /* CONFIG_IEEE80211R */
+
/* Key Delivery */
if (!elems.key_delivery) {
wpa_printf(MSG_DEBUG, "FILS: No Key Delivery element");
@@ -4378,8 +4645,10 @@
res = hmac_sha512_kdf(prk, hash_len, NULL, (const u8 *) info,
os_strlen(info), sm->pmk, hash_len);
os_memset(prk, 0, SHA512_MAC_LEN);
- if (res < 0)
+ if (res < 0) {
+ sm->pmk_len = 0;
return -1;
+ }
sm->pmk_len = hash_len;
wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sm->pmk, sm->pmk_len);
@@ -4403,3 +4672,14 @@
}
#endif /* CONFIG_FILS */
}
+
+
+#ifdef CONFIG_DPP2
+void wpa_sm_set_dpp_z(struct wpa_sm *sm, const struct wpabuf *z)
+{
+ if (sm) {
+ wpabuf_clear_free(sm->dpp_z);
+ sm->dpp_z = z ? wpabuf_dup(z) : NULL;
+ }
+}
+#endif /* CONFIG_DPP2 */
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 81c0171..8903f8e 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -18,6 +18,7 @@
struct eapol_sm;
struct wpa_config_blob;
struct hostapd_freq_params;
+struct wpa_channel_info;
struct wpa_sm_ctx {
void *ctx; /* pointer to arbitrary upper level context */
@@ -82,6 +83,7 @@
int (*key_mgmt_set_pmk)(void *ctx, const u8 *pmk, size_t pmk_len);
void (*fils_hlp_rx)(void *ctx, const u8 *dst, const u8 *src,
const u8 *pkt, size_t pkt_len);
+ int (*channel_info)(void *ctx, struct wpa_channel_info *ci);
};
@@ -95,7 +97,8 @@
WPA_PARAM_KEY_MGMT,
WPA_PARAM_MGMT_GROUP,
WPA_PARAM_RSN_ENABLED,
- WPA_PARAM_MFP
+ WPA_PARAM_MFP,
+ WPA_PARAM_OCV
};
struct rsn_supp_config {
@@ -141,6 +144,7 @@
int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
int verbose);
int wpa_sm_pmf_enabled(struct wpa_sm *sm);
+int wpa_sm_ocv_enabled(struct wpa_sm *sm);
void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise);
@@ -279,6 +283,11 @@
return 0;
}
+static inline int wpa_sm_ocv_enabled(struct wpa_sm *sm)
+{
+ return 0;
+}
+
static inline void wpa_sm_key_request(struct wpa_sm *sm, int error,
int pairwise)
{
@@ -353,6 +362,9 @@
int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len);
int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie);
+int wpa_ft_add_mdie(struct wpa_sm *sm, u8 *ies, size_t ies_len,
+ const u8 *mdie);
+const u8 * wpa_sm_get_ft_md(struct wpa_sm *sm);
int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
int ft_action, const u8 *target_ap,
const u8 *ric_ies, size_t ric_ies_len);
@@ -377,6 +389,12 @@
return 0;
}
+static inline int wpa_ft_add_mdie(struct wpa_sm *sm, u8 *ies, size_t ies_len,
+ const u8 *mdie)
+{
+ return 0;
+}
+
static inline int
wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
int ft_action, const u8 *target_ap)
@@ -429,6 +447,7 @@
int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf);
void wpa_sm_set_test_assoc_ie(struct wpa_sm *sm, struct wpabuf *buf);
const u8 * wpa_sm_get_anonce(struct wpa_sm *sm);
+unsigned int wpa_sm_get_key_mgmt(struct wpa_sm *sm);
struct wpabuf * fils_build_auth(struct wpa_sm *sm, int dh_group, const u8 *md);
int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data,
@@ -446,5 +465,6 @@
void wpa_sm_set_reset_fils_completed(struct wpa_sm *sm, int set);
void wpa_sm_set_fils_cache_id(struct wpa_sm *sm, const u8 *fils_cache_id);
+void wpa_sm_set_dpp_z(struct wpa_sm *sm, const struct wpabuf *z);
#endif /* WPA_H */
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 1ff7afe..7dcb104 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - IEEE 802.11r - Fast BSS Transition
- * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,9 +10,12 @@
#include "common.h"
#include "crypto/aes_wrap.h"
+#include "crypto/sha384.h"
#include "crypto/random.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/ocv.h"
+#include "drivers/driver.h"
#include "wpa.h"
#include "wpa_i.h"
@@ -23,6 +26,7 @@
{
u8 ptk_name[WPA_PMK_NAME_LEN];
const u8 *anonce = key->key_nonce;
+ int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
if (sm->xxkey_len == 0) {
wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
@@ -30,21 +34,26 @@
return -1;
}
- wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, sm->ssid,
- sm->ssid_len, sm->mobility_domain,
- sm->r0kh_id, sm->r0kh_id_len, sm->own_addr,
- sm->pmk_r0, sm->pmk_r0_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", sm->pmk_r0, PMK_LEN);
+ sm->pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
+ if (wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, sm->ssid,
+ sm->ssid_len, sm->mobility_domain,
+ 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);
- wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id,
- sm->own_addr, sm->pmk_r1, sm->pmk_r1_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_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->snonce, anonce, sm->own_addr,
- sm->bssid, sm->pmk_r1_name, ptk, ptk_name,
- sm->key_mgmt, sm->pairwise_cipher);
+ 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);
}
@@ -58,11 +67,13 @@
int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
{
struct wpa_ft_ies ft;
+ int use_sha384;
if (sm == NULL)
return 0;
- if (wpa_ft_parse_ies(ies, ies_len, &ft) < 0)
+ use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
+ if (wpa_ft_parse_ies(ies, ies_len, &ft, use_sha384) < 0)
return -1;
if (ft.mdie && ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1)
@@ -146,16 +157,17 @@
const u8 *ap_mdie)
{
size_t buf_len;
- u8 *buf, *pos, *ftie_len, *ftie_pos;
+ u8 *buf, *pos, *ftie_len, *ftie_pos, *fte_mic, *elem_count;
struct rsn_mdie *mdie;
- struct rsn_ftie *ftie;
struct rsn_ie_hdr *rsnie;
u16 capab;
+ int mdie_len;
sm->ft_completed = 0;
sm->ft_reassoc_completed = 0;
- buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
+ buf_len = 2 + sizeof(struct rsn_mdie) + 2 +
+ sizeof(struct rsn_ftie_sha384) +
2 + sm->r0kh_id_len + ric_ies_len + 100;
buf = os_zalloc(buf_len);
if (buf == NULL)
@@ -201,6 +213,10 @@
/* Authenticated Key Management Suite List */
if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X)
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
+#ifdef CONFIG_SHA384
+ else if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384);
+#endif /* CONFIG_SHA384 */
else if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK)
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
else if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE)
@@ -222,9 +238,14 @@
/* RSN Capabilities */
capab = 0;
#ifdef CONFIG_IEEE80211W
- if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC)
+ if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC ||
+ sm->mgmt_group_cipher == WPA_CIPHER_BIP_GMAC_128 ||
+ sm->mgmt_group_cipher == WPA_CIPHER_BIP_GMAC_256 ||
+ sm->mgmt_group_cipher == WPA_CIPHER_BIP_CMAC_256)
capab |= WPA_CAPABILITY_MFPC;
#endif /* CONFIG_IEEE80211W */
+ if (sm->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
WPA_PUT_LE16(pos, capab);
pos += 2;
@@ -237,34 +258,63 @@
pos += WPA_PMK_NAME_LEN;
#ifdef CONFIG_IEEE80211W
- if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
- /* Management Group Cipher Suite */
+ /* Management Group Cipher Suite */
+ switch (sm->mgmt_group_cipher) {
+ case WPA_CIPHER_AES_128_CMAC:
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
pos += RSN_SELECTOR_LEN;
+ break;
+ case WPA_CIPHER_BIP_GMAC_128:
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_128);
+ pos += RSN_SELECTOR_LEN;
+ break;
+ case WPA_CIPHER_BIP_GMAC_256:
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_256);
+ pos += RSN_SELECTOR_LEN;
+ break;
+ case WPA_CIPHER_BIP_CMAC_256:
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_CMAC_256);
+ pos += RSN_SELECTOR_LEN;
+ break;
}
#endif /* CONFIG_IEEE80211W */
rsnie->len = (pos - (u8 *) rsnie) - 2;
/* MDIE */
- *pos++ = WLAN_EID_MOBILITY_DOMAIN;
- *pos++ = sizeof(*mdie);
- mdie = (struct rsn_mdie *) pos;
- pos += sizeof(*mdie);
- os_memcpy(mdie->mobility_domain, sm->mobility_domain,
- MOBILITY_DOMAIN_ID_LEN);
- mdie->ft_capab = ap_mdie && ap_mdie[1] >= 3 ? ap_mdie[4] :
- sm->mdie_ft_capab;
+ mdie_len = wpa_ft_add_mdie(sm, pos, buf_len - (pos - buf), ap_mdie);
+ if (mdie_len <= 0) {
+ os_free(buf);
+ return NULL;
+ }
+ mdie = (struct rsn_mdie *) (pos + 2);
+ pos += mdie_len;
/* FTIE[SNonce, [R1KH-ID,] R0KH-ID ] */
ftie_pos = pos;
*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
ftie_len = pos++;
- ftie = (struct rsn_ftie *) pos;
- pos += sizeof(*ftie);
- os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN);
- if (anonce)
- os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN);
+ if (wpa_key_mgmt_sha384(sm->key_mgmt)) {
+ struct rsn_ftie_sha384 *ftie;
+
+ ftie = (struct rsn_ftie_sha384 *) pos;
+ fte_mic = ftie->mic;
+ elem_count = &ftie->mic_control[1];
+ pos += sizeof(*ftie);
+ os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN);
+ if (anonce)
+ os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN);
+ } else {
+ struct rsn_ftie *ftie;
+
+ ftie = (struct rsn_ftie *) pos;
+ fte_mic = ftie->mic;
+ elem_count = &ftie->mic_control[1];
+ pos += sizeof(*ftie);
+ os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN);
+ if (anonce)
+ os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN);
+ }
if (kck) {
/* R1KH-ID sub-element in third FT message */
*pos++ = FTIE_SUBELEM_R1KH_ID;
@@ -277,6 +327,26 @@
*pos++ = sm->r0kh_id_len;
os_memcpy(pos, sm->r0kh_id, sm->r0kh_id_len);
pos += sm->r0kh_id_len;
+#ifdef CONFIG_OCV
+ if (kck && wpa_sm_ocv_enabled(sm)) {
+ /* OCI sub-element in the third FT message */
+ struct wpa_channel_info ci;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in FTE");
+ os_free(buf);
+ return NULL;
+ }
+
+ *pos++ = FTIE_SUBELEM_OCI;
+ *pos++ = OCV_OCI_LEN;
+ if (ocv_insert_oci(&ci, &pos) < 0) {
+ os_free(buf);
+ return NULL;
+ }
+ }
+#endif /* CONFIG_OCV */
*ftie_len = pos - ftie_len - 1;
if (ric_ies) {
@@ -298,13 +368,12 @@
* RIC-Request (if present)
*/
/* Information element count */
- ftie->mic_control[1] = 3 + ieee802_11_ie_count(ric_ies,
- ric_ies_len);
+ *elem_count = 3 + ieee802_11_ie_count(ric_ies, ric_ies_len);
if (wpa_ft_mic(kck, kck_len, sm->own_addr, target_ap, 5,
((u8 *) mdie) - 2, 2 + sizeof(*mdie),
ftie_pos, 2 + *ftie_len,
(u8 *) rsnie, 2 + rsnie->len, ric_ies,
- ric_ies_len, ftie->mic) < 0) {
+ ric_ies_len, fte_mic) < 0) {
wpa_printf(MSG_INFO, "FT: Failed to calculate MIC");
os_free(buf);
return NULL;
@@ -373,6 +442,37 @@
}
+int wpa_ft_add_mdie(struct wpa_sm *sm, u8 *buf, size_t buf_len,
+ const u8 *ap_mdie)
+{
+ u8 *pos = buf;
+ struct rsn_mdie *mdie;
+
+ if (buf_len < 2 + sizeof(*mdie)) {
+ wpa_printf(MSG_INFO,
+ "FT: Failed to add MDIE: short buffer, length=%zu",
+ buf_len);
+ return 0;
+ }
+
+ *pos++ = WLAN_EID_MOBILITY_DOMAIN;
+ *pos++ = sizeof(*mdie);
+ mdie = (struct rsn_mdie *) pos;
+ os_memcpy(mdie->mobility_domain, sm->mobility_domain,
+ MOBILITY_DOMAIN_ID_LEN);
+ mdie->ft_capab = ap_mdie && ap_mdie[1] >= 3 ? ap_mdie[4] :
+ sm->mdie_ft_capab;
+
+ return 2 + sizeof(*mdie);
+}
+
+
+const u8 * wpa_sm_get_ft_md(struct wpa_sm *sm)
+{
+ return sm->mobility_domain;
+}
+
+
int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
int ft_action, const u8 *target_ap,
const u8 *ric_ies, size_t ric_ies_len)
@@ -381,10 +481,13 @@
size_t ft_ies_len;
struct wpa_ft_ies parse;
struct rsn_mdie *mdie;
- struct rsn_ftie *ftie;
u8 ptk_name[WPA_PMK_NAME_LEN];
int ret;
const u8 *bssid;
+ const u8 *kck;
+ size_t kck_len;
+ int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
+ const u8 *anonce, *snonce;
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len);
@@ -410,7 +513,7 @@
return -1;
}
- if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+ if (wpa_ft_parse_ies(ies, ies_len, &parse, use_sha384) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
return -1;
}
@@ -423,16 +526,34 @@
return -1;
}
- ftie = (struct rsn_ftie *) parse.ftie;
- if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
- wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
- return -1;
+ if (use_sha384) {
+ struct rsn_ftie_sha384 *ftie;
+
+ ftie = (struct rsn_ftie_sha384 *) parse.ftie;
+ if (!ftie || parse.ftie_len < sizeof(*ftie)) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+ return -1;
+ }
+
+ anonce = ftie->anonce;
+ snonce = ftie->snonce;
+ } else {
+ struct rsn_ftie *ftie;
+
+ ftie = (struct rsn_ftie *) parse.ftie;
+ if (!ftie || parse.ftie_len < sizeof(*ftie)) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+ return -1;
+ }
+
+ anonce = ftie->anonce;
+ snonce = ftie->snonce;
}
- if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
+ if (os_memcmp(snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
- ftie->snonce, WPA_NONCE_LEN);
+ snonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
sm->snonce, WPA_NONCE_LEN);
return -1;
@@ -471,23 +592,34 @@
os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN);
wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN);
wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN);
- wpa_hexdump(MSG_DEBUG, "FT: ANonce", ftie->anonce, WPA_NONCE_LEN);
- os_memcpy(sm->anonce, ftie->anonce, WPA_NONCE_LEN);
- wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id,
- sm->own_addr, sm->pmk_r1, sm->pmk_r1_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: ANonce", anonce, WPA_NONCE_LEN);
+ os_memcpy(sm->anonce, anonce, WPA_NONCE_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;
+ 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->snonce, ftie->anonce,
- sm->own_addr, bssid, sm->pmk_r1_name, &sm->ptk,
- ptk_name, sm->key_mgmt, sm->pairwise_cipher) < 0)
+ if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce,
+ anonce, sm->own_addr, bssid,
+ sm->pmk_r1_name, &sm->ptk, ptk_name, sm->key_mgmt,
+ sm->pairwise_cipher) < 0)
return -1;
- ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce,
+ if (wpa_key_mgmt_fils(sm->key_mgmt)) {
+ kck = sm->ptk.kck2;
+ kck_len = sm->ptk.kck2_len;
+ } else {
+ kck = sm->ptk.kck;
+ kck_len = sm->ptk.kck_len;
+ }
+ ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, anonce,
sm->pmk_r1_name,
- sm->ptk.kck, sm->ptk.kck_len, bssid,
+ kck, kck_len, bssid,
ric_ies, ric_ies_len,
parse.mdie ? parse.mdie - 2 : NULL);
if (ft_ies) {
@@ -550,6 +682,16 @@
int keyidx;
enum wpa_alg alg;
size_t gtk_len, keylen, rsc_len;
+ const u8 *kek;
+ size_t kek_len;
+
+ if (wpa_key_mgmt_fils(sm->key_mgmt)) {
+ kek = sm->ptk.kek2;
+ kek_len = sm->ptk.kek2_len;
+ } else {
+ kek = sm->ptk.kek;
+ kek_len = sm->ptk.kek_len;
+ }
if (gtk_elem == NULL) {
wpa_printf(MSG_DEBUG, "FT: No GTK included in FTIE");
@@ -566,8 +708,7 @@
return -1;
}
gtk_len = gtk_elem_len - 19;
- if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, gtk_len / 8, gtk_elem + 11,
- gtk)) {
+ if (aes_unwrap(kek, kek_len, gtk_len / 8, gtk_elem + 11, gtk)) {
wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
"decrypt GTK");
return -1;
@@ -621,10 +762,24 @@
static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
size_t igtk_elem_len)
{
- u8 igtk[WPA_IGTK_LEN];
+ u8 igtk[WPA_IGTK_MAX_LEN];
+ size_t igtk_len;
u16 keyidx;
+ const u8 *kek;
+ size_t kek_len;
- if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC)
+ if (wpa_key_mgmt_fils(sm->key_mgmt)) {
+ kek = sm->ptk.kek2;
+ kek_len = sm->ptk.kek2_len;
+ } else {
+ kek = sm->ptk.kek;
+ kek_len = sm->ptk.kek_len;
+ }
+
+ if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC &&
+ sm->mgmt_group_cipher != WPA_CIPHER_BIP_GMAC_128 &&
+ sm->mgmt_group_cipher != WPA_CIPHER_BIP_GMAC_256 &&
+ sm->mgmt_group_cipher != WPA_CIPHER_BIP_CMAC_256)
return 0;
if (igtk_elem == NULL) {
@@ -635,19 +790,19 @@
wpa_hexdump_key(MSG_DEBUG, "FT: Received IGTK in Reassoc Resp",
igtk_elem, igtk_elem_len);
- if (igtk_elem_len != 2 + 6 + 1 + WPA_IGTK_LEN + 8) {
+ igtk_len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+ if (igtk_elem_len != 2 + 6 + 1 + igtk_len + 8) {
wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem "
"length %lu", (unsigned long) igtk_elem_len);
return -1;
}
- if (igtk_elem[8] != WPA_IGTK_LEN) {
+ if (igtk_elem[8] != igtk_len) {
wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem Key Length "
"%d", igtk_elem[8]);
return -1;
}
- if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, WPA_IGTK_LEN / 8,
- igtk_elem + 9, igtk)) {
+ if (aes_unwrap(kek, kek_len, igtk_len / 8, igtk_elem + 9, igtk)) {
wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
"decrypt IGTK");
return -1;
@@ -658,13 +813,16 @@
keyidx = WPA_GET_LE16(igtk_elem);
wpa_hexdump_key(MSG_DEBUG, "FT: IGTK from Reassoc Resp", igtk,
- WPA_IGTK_LEN);
- if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr, keyidx, 0,
- igtk_elem + 2, 6, igtk, WPA_IGTK_LEN) < 0) {
+ igtk_len);
+ if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+ broadcast_ether_addr, keyidx, 0,
+ igtk_elem + 2, 6, igtk, igtk_len) < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the "
"driver.");
+ os_memset(igtk, 0, sizeof(igtk));
return -1;
}
+ os_memset(igtk, 0, sizeof(igtk));
return 0;
}
@@ -676,9 +834,13 @@
{
struct wpa_ft_ies parse;
struct rsn_mdie *mdie;
- struct rsn_ftie *ftie;
unsigned int count;
u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+ const u8 *kck;
+ size_t kck_len;
+ int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
+ const u8 *anonce, *snonce, *fte_mic;
+ u8 fte_elem_count;
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
@@ -693,7 +855,7 @@
return 0;
}
- if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+ if (wpa_ft_parse_ies(ies, ies_len, &parse, use_sha384) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
return -1;
}
@@ -706,25 +868,47 @@
return -1;
}
- ftie = (struct rsn_ftie *) parse.ftie;
- if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
- wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
- return -1;
+ if (use_sha384) {
+ struct rsn_ftie_sha384 *ftie;
+
+ ftie = (struct rsn_ftie_sha384 *) parse.ftie;
+ if (!ftie || parse.ftie_len < sizeof(*ftie)) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+ return -1;
+ }
+
+ anonce = ftie->anonce;
+ snonce = ftie->snonce;
+ fte_elem_count = ftie->mic_control[1];
+ fte_mic = ftie->mic;
+ } else {
+ struct rsn_ftie *ftie;
+
+ ftie = (struct rsn_ftie *) parse.ftie;
+ if (!ftie || parse.ftie_len < sizeof(*ftie)) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+ return -1;
+ }
+
+ anonce = ftie->anonce;
+ snonce = ftie->snonce;
+ fte_elem_count = ftie->mic_control[1];
+ fte_mic = ftie->mic;
}
- if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
+ if (os_memcmp(snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
- ftie->snonce, WPA_NONCE_LEN);
+ snonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
sm->snonce, WPA_NONCE_LEN);
return -1;
}
- if (os_memcmp(ftie->anonce, sm->anonce, WPA_NONCE_LEN) != 0) {
+ if (os_memcmp(anonce, sm->anonce, WPA_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE");
wpa_hexdump(MSG_DEBUG, "FT: Received ANonce",
- ftie->anonce, WPA_NONCE_LEN);
+ anonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce",
sm->anonce, WPA_NONCE_LEN);
return -1;
@@ -769,14 +953,22 @@
count = 3;
if (parse.ric)
count += ieee802_11_ie_count(parse.ric, parse.ric_len);
- if (ftie->mic_control[1] != count) {
+ if (fte_elem_count != count) {
wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
"Control: received %u expected %u",
- ftie->mic_control[1], count);
+ fte_elem_count, count);
return -1;
}
- if (wpa_ft_mic(sm->ptk.kck, sm->ptk.kck_len, sm->own_addr, src_addr, 6,
+ if (wpa_key_mgmt_fils(sm->key_mgmt)) {
+ kck = sm->ptk.kck2;
+ kck_len = sm->ptk.kck2_len;
+ } else {
+ kck = sm->ptk.kck;
+ kck_len = sm->ptk.kck_len;
+ }
+
+ if (wpa_ft_mic(kck, kck_len, sm->own_addr, src_addr, 6,
parse.mdie - 2, parse.mdie_len + 2,
parse.ftie - 2, parse.ftie_len + 2,
parse.rsn - 2, parse.rsn_len + 2,
@@ -786,13 +978,32 @@
return -1;
}
- if (os_memcmp_const(mic, ftie->mic, 16) != 0) {
+ if (os_memcmp_const(mic, fte_mic, 16) != 0) {
wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
- wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
+ wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", fte_mic, 16);
wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
return -1;
}
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info to validate received OCI in (Re)Assoc Response");
+ return -1;
+ }
+
+ 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);
+ return -1;
+ }
+ }
+#endif /* CONFIG_OCV */
+
sm->ft_reassoc_completed = 1;
if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index e8da194..5dc9f2e 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -1,6 +1,6 @@
/*
* Internal WPA/RSN supplicant state machine definitions
- * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -86,6 +86,7 @@
int rsn_enabled; /* Whether RSN is enabled in configuration */
int mfp; /* 0 = disabled, 1 = optional, 2 = mandatory */
+ int ocv; /* Operating Channel Validation */
u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
size_t assoc_wpa_ie_len;
@@ -112,11 +113,14 @@
#endif /* CONFIG_TDLS */
#ifdef CONFIG_IEEE80211R
- u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */
+ u8 xxkey[PMK_LEN_MAX]; /* PSK or the second 256 bits of MSK, or the
+ * first 384 bits of MSK */
size_t xxkey_len;
- u8 pmk_r0[PMK_LEN];
+ u8 pmk_r0[PMK_LEN_MAX];
+ size_t pmk_r0_len;
u8 pmk_r0_name[WPA_PMK_NAME_LEN];
- u8 pmk_r1[PMK_LEN];
+ u8 pmk_r1[PMK_LEN_MAX];
+ size_t pmk_r1_len;
u8 pmk_r1_name[WPA_PMK_NAME_LEN];
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
u8 r0kh_id[FT_R0KH_ID_MAX_LEN];
@@ -164,6 +168,10 @@
struct crypto_ecdh *owe_ecdh;
u16 owe_group;
#endif /* CONFIG_OWE */
+
+#ifdef CONFIG_DPP2
+ struct wpabuf *dpp_z;
+#endif /* CONFIG_DPP2 */
};
@@ -392,6 +400,14 @@
sm->ctx->fils_hlp_rx(sm->ctx->ctx, dst, src, pkt, pkt_len);
}
+static inline int wpa_sm_channel_info(struct wpa_sm *sm,
+ struct wpa_channel_info *ci)
+{
+ if (!sm->ctx->channel_info)
+ return -1;
+ return sm->ctx->channel_info(sm->ctx->ctx, ci);
+}
+
int wpa_eapol_key_send(struct wpa_sm *sm, struct wpa_ptk *ptk,
int ver, const u8 *dest, u16 proto,
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index d649058..ae9f4ca 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - WPA/RSN IE and KDE processing
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -161,6 +161,10 @@
#ifdef CONFIG_IEEE80211R
} else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
+#ifdef CONFIG_SHA384
+ } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384);
+#endif /* CONFIG_SHA384 */
} else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
#endif /* CONFIG_IEEE80211R */
@@ -200,6 +204,10 @@
} else if (key_mgmt & WPA_KEY_MGMT_DPP) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_DPP);
#endif /* CONFIG_DPP */
+#ifdef CONFIG_HS20
+ } else if (key_mgmt & WPA_KEY_MGMT_OSEN) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
+#endif /* CONFIG_HS20 */
} else {
wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
key_mgmt);
@@ -215,6 +223,8 @@
if (sm->mfp == 2)
capab |= WPA_CAPABILITY_MFPR;
#endif /* CONFIG_IEEE80211W */
+ if (sm->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
WPA_PUT_LE16(pos, capab);
pos += 2;
@@ -455,6 +465,17 @@
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_OCV
+ if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
+ ie->oci = pos + 2 + RSN_SELECTOR_LEN;
+ ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: OCI KDE in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+#endif /* CONFIG_OCV */
+
return 0;
}
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index 0e72af5..9d53973 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -53,6 +53,10 @@
const u8 *ip_addr_req;
const u8 *ip_addr_alloc;
#endif /* CONFIG_P2P */
+#ifdef CONFIG_OCV
+ const u8 *oci;
+ size_t oci_len;
+#endif /* CONFIG_OCV */
};
int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
diff --git a/src/tls/asn1.c b/src/tls/asn1.c
index cec1092..822f87c 100644
--- a/src/tls/asn1.c
+++ b/src/tls/asn1.c
@@ -31,6 +31,10 @@
pos = buf;
end = buf + len;
+ if (pos >= end) {
+ wpa_printf(MSG_DEBUG, "ASN.1: No room for Identifier");
+ return -1;
+ }
hdr->identifier = *pos++;
hdr->class = hdr->identifier >> 6;
hdr->constructed = !!(hdr->identifier & (1 << 5));
@@ -51,6 +55,10 @@
} else
hdr->tag = hdr->identifier & 0x1f;
+ if (pos >= end) {
+ wpa_printf(MSG_DEBUG, "ASN.1: No room for Length");
+ return -1;
+ }
tmp = *pos++;
if (tmp & 0x80) {
if (tmp == 0xff) {
diff --git a/src/tls/bignum.c b/src/tls/bignum.c
index f3baafe..1a87c82 100644
--- a/src/tls/bignum.c
+++ b/src/tls/bignum.c
@@ -119,10 +119,10 @@
/**
- * bignum_cmd_d - Compare bignum to standard integer
+ * bignum_cmp_d - Compare bignum to standard integer
* @a: Bignum from bignum_init()
* @b: Small integer
- * Returns: 0 on success, -1 on failure
+ * Returns: -1 if a < b, 0 if a == b, 1 if a > b
*/
int bignum_cmp_d(const struct bignum *a, unsigned long b)
{
diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c
index 76e1974..a147a54 100644
--- a/src/tls/tlsv1_client.c
+++ b/src/tls/tlsv1_client.c
@@ -1,6 +1,6 @@
/*
* TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
- * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -514,6 +514,8 @@
* tlsv1_client_prf - Use TLS-PRF to derive keying material
* @conn: TLSv1 client connection data from tlsv1_client_init()
* @label: Label (e.g., description of the key) for PRF
+ * @context: Optional extra upper-layer context (max len 2^16)
+ * @context_len: The length of the context value
* @server_random_first: seed is 0 = client_random|server_random,
* 1 = server_random|client_random
* @out: Buffer for output data from TLS-PRF
@@ -521,13 +523,26 @@
* Returns: 0 on success, -1 on failure
*/
int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
+ const u8 *context, size_t context_len,
int server_random_first, u8 *out, size_t out_len)
{
- u8 seed[2 * TLS_RANDOM_LEN];
+ u8 *seed, *pos;
+ size_t seed_len = 2 * TLS_RANDOM_LEN;
+ int res;
if (conn->state != ESTABLISHED)
return -1;
+ if (context_len > 65535)
+ return -1;
+
+ if (context)
+ seed_len += 2 + context_len;
+
+ seed = os_malloc(seed_len);
+ if (!seed)
+ return -1;
+
if (server_random_first) {
os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
@@ -538,9 +553,18 @@
TLS_RANDOM_LEN);
}
- return tls_prf(conn->rl.tls_version,
- conn->master_secret, TLS_MASTER_SECRET_LEN,
- label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
+ if (context) {
+ pos = seed + 2 * TLS_RANDOM_LEN;
+ WPA_PUT_BE16(pos, context_len);
+ pos += 2;
+ os_memcpy(pos, context, context_len);
+ }
+
+ res = tls_prf(conn->rl.tls_version,
+ conn->master_secret, TLS_MASTER_SECRET_LEN,
+ label, seed, seed_len, out, out_len);
+ os_free(seed);
+ return res;
}
diff --git a/src/tls/tlsv1_client.h b/src/tls/tlsv1_client.h
index 40fa6c7..7fcc256 100644
--- a/src/tls/tlsv1_client.h
+++ b/src/tls/tlsv1_client.h
@@ -1,6 +1,6 @@
/*
* TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -19,6 +19,7 @@
void tlsv1_client_deinit(struct tlsv1_client *conn);
int tlsv1_client_established(struct tlsv1_client *conn);
int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
+ const u8 *context, size_t context_len,
int server_random_first, u8 *out, size_t out_len);
u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
const u8 *in_data, size_t in_len,
diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c
index e66f1a9..80874e5 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -290,7 +290,7 @@
return;
os_memset(&ev, 0, sizeof(ev));
- if (conn->cred->cert_probe || conn->cert_in_cb) {
+ if ((conn->cred && conn->cred->cert_probe) || conn->cert_in_cb) {
cert_buf = wpabuf_alloc_copy(cert->cert_start,
cert->cert_len);
ev.peer_cert.cert = cert_buf;
diff --git a/src/tls/tlsv1_client_write.c b/src/tls/tlsv1_client_write.c
index 04d895e..4a1147b 100644
--- a/src/tls/tlsv1_client_write.c
+++ b/src/tls/tlsv1_client_write.c
@@ -72,6 +72,9 @@
*out_len = 0;
os_get_time(&now);
+#ifdef TEST_FUZZ
+ now.sec = 0xfffefdfc;
+#endif /* TEST_FUZZ */
WPA_PUT_BE32(conn->client_random, now.sec);
if (random_get_bytes(conn->client_random + 4, TLS_RANDOM_LEN - 4)) {
wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
diff --git a/src/tls/tlsv1_server.c b/src/tls/tlsv1_server.c
index 5406969..12dcc85 100644
--- a/src/tls/tlsv1_server.c
+++ b/src/tls/tlsv1_server.c
@@ -1,6 +1,6 @@
/*
* TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
- * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -164,7 +164,8 @@
/* need more data */
wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
"yet supported");
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
goto failed;
}
ct = pos[0];
@@ -204,6 +205,7 @@
msg = tlsv1_server_send_alert(conn, conn->alert_level,
conn->alert_description,
out_len);
+ conn->write_alerts++;
}
return msg;
@@ -296,6 +298,7 @@
}
tlsv1_server_log(conn, "Received alert %d:%d",
out_pos[0], out_pos[1]);
+ conn->read_alerts++;
if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
/* Continue processing */
pos += used;
@@ -459,6 +462,8 @@
* tlsv1_server_prf - Use TLS-PRF to derive keying material
* @conn: TLSv1 server connection data from tlsv1_server_init()
* @label: Label (e.g., description of the key) for PRF
+ * @context: Optional extra upper-layer context (max len 2^16)
+ * @context_len: The length of the context value
* @server_random_first: seed is 0 = client_random|server_random,
* 1 = server_random|client_random
* @out: Buffer for output data from TLS-PRF
@@ -466,13 +471,26 @@
* Returns: 0 on success, -1 on failure
*/
int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
+ const u8 *context, size_t context_len,
int server_random_first, u8 *out, size_t out_len)
{
- u8 seed[2 * TLS_RANDOM_LEN];
+ u8 *seed, *pos;
+ size_t seed_len = 2 * TLS_RANDOM_LEN;
+ int res;
if (conn->state != ESTABLISHED)
return -1;
+ if (context_len > 65535)
+ return -1;
+
+ if (context)
+ seed_len += 2 + context_len;
+
+ seed = os_malloc(seed_len);
+ if (!seed)
+ return -1;
+
if (server_random_first) {
os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
@@ -483,9 +501,18 @@
TLS_RANDOM_LEN);
}
- return tls_prf(conn->rl.tls_version,
- conn->master_secret, TLS_MASTER_SECRET_LEN,
- label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
+ if (context) {
+ pos = seed + 2 * TLS_RANDOM_LEN;
+ WPA_PUT_BE16(pos, context_len);
+ pos += 2;
+ os_memcpy(pos, context, context_len);
+ }
+
+ res = tls_prf(conn->rl.tls_version,
+ conn->master_secret, TLS_MASTER_SECRET_LEN,
+ label, seed, seed_len, out, out_len);
+ os_free(seed);
+ return res;
}
@@ -708,6 +735,24 @@
}
+int tlsv1_server_get_failed(struct tlsv1_server *conn)
+{
+ return conn->state == FAILED;
+}
+
+
+int tlsv1_server_get_read_alerts(struct tlsv1_server *conn)
+{
+ return conn->read_alerts;
+}
+
+
+int tlsv1_server_get_write_alerts(struct tlsv1_server *conn)
+{
+ return conn->write_alerts;
+}
+
+
#ifdef CONFIG_TESTING_OPTIONS
void tlsv1_server_set_test_flags(struct tlsv1_server *conn, u32 flags)
{
diff --git a/src/tls/tlsv1_server.h b/src/tls/tlsv1_server.h
index 10e7699..c9c0875 100644
--- a/src/tls/tlsv1_server.h
+++ b/src/tls/tlsv1_server.h
@@ -1,6 +1,6 @@
/*
* TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
- * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -19,6 +19,7 @@
void tlsv1_server_deinit(struct tlsv1_server *conn);
int tlsv1_server_established(struct tlsv1_server *conn);
int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
+ const u8 *context, size_t context_len,
int server_random_first, u8 *out, size_t out_len);
u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
const u8 *in_data, size_t in_len, size_t *out_len);
@@ -48,6 +49,10 @@
void tlsv1_server_set_log_cb(struct tlsv1_server *conn,
void (*cb)(void *ctx, const char *msg), void *ctx);
+int tlsv1_server_get_failed(struct tlsv1_server *conn);
+int tlsv1_server_get_read_alerts(struct tlsv1_server *conn);
+int tlsv1_server_get_write_alerts(struct tlsv1_server *conn);
+
void tlsv1_server_set_test_flags(struct tlsv1_server *conn, u32 flags);
#endif /* TLSV1_SERVER_H */
diff --git a/src/tls/tlsv1_server_i.h b/src/tls/tlsv1_server_i.h
index 29c6678..2622585 100644
--- a/src/tls/tlsv1_server_i.h
+++ b/src/tls/tlsv1_server_i.h
@@ -30,6 +30,8 @@
u8 alert_level;
u8 alert_description;
+ int read_alerts, write_alerts;
+
struct crypto_public_key *client_rsa_key;
struct tls_verify_hash verify;
diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c
index 4aa8a01..e957678 100644
--- a/src/tls/tlsv1_server_read.c
+++ b/src/tls/tlsv1_server_read.c
@@ -139,8 +139,11 @@
pos = in_data;
left = *in_len;
- if (left < 4)
+ if (left < 4) {
+ tlsv1_server_log(conn,
+ "Truncated handshake message (expected ClientHello)");
goto decode_error;
+ }
/* HandshakeType msg_type */
if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
@@ -157,8 +160,12 @@
pos += 3;
left -= 4;
- if (len > left)
+ if (len > left) {
+ tlsv1_server_log(conn,
+ "Truncated ClientHello (len=%d left=%d)",
+ (int) len, (int) left);
goto decode_error;
+ }
/* body - ClientHello */
@@ -166,8 +173,10 @@
end = pos + len;
/* ProtocolVersion client_version */
- if (end - pos < 2)
+ if (end - pos < 2) {
+ tlsv1_server_log(conn, "Truncated ClientHello/client_version");
goto decode_error;
+ }
conn->client_version = WPA_GET_BE16(pos);
tlsv1_server_log(conn, "Client version %d.%d",
conn->client_version >> 8,
@@ -196,8 +205,10 @@
tls_version_str(conn->rl.tls_version));
/* Random random */
- if (end - pos < TLS_RANDOM_LEN)
+ if (end - pos < TLS_RANDOM_LEN) {
+ tlsv1_server_log(conn, "Truncated ClientHello/client_random");
goto decode_error;
+ }
os_memcpy(conn->client_random, pos, TLS_RANDOM_LEN);
pos += TLS_RANDOM_LEN;
@@ -205,25 +216,36 @@
conn->client_random, TLS_RANDOM_LEN);
/* SessionID session_id */
- if (end - pos < 1)
+ if (end - pos < 1) {
+ tlsv1_server_log(conn, "Truncated ClientHello/session_id len");
goto decode_error;
- if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
+ }
+ if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN) {
+ tlsv1_server_log(conn, "Truncated ClientHello/session_id");
goto decode_error;
+ }
wpa_hexdump(MSG_MSGDUMP, "TLSv1: client session_id", pos + 1, *pos);
pos += 1 + *pos;
/* TODO: add support for session resumption */
/* CipherSuite cipher_suites<2..2^16-1> */
- if (end - pos < 2)
+ if (end - pos < 2) {
+ tlsv1_server_log(conn,
+ "Truncated ClientHello/cipher_suites len");
goto decode_error;
+ }
num_suites = WPA_GET_BE16(pos);
pos += 2;
- if (end - pos < num_suites)
+ if (end - pos < num_suites) {
+ tlsv1_server_log(conn, "Truncated ClientHello/cipher_suites");
goto decode_error;
+ }
wpa_hexdump(MSG_MSGDUMP, "TLSv1: client cipher suites",
pos, num_suites);
- if (num_suites & 1)
+ if (num_suites & 1) {
+ tlsv1_server_log(conn, "Odd len ClientHello/cipher_suites");
goto decode_error;
+ }
num_suites /= 2;
cipher_suite = 0;
@@ -259,11 +281,17 @@
conn->cipher_suite = cipher_suite;
/* CompressionMethod compression_methods<1..2^8-1> */
- if (end - pos < 1)
+ if (end - pos < 1) {
+ tlsv1_server_log(conn,
+ "Truncated ClientHello/compression_methods len");
goto decode_error;
+ }
num_suites = *pos++;
- if (end - pos < num_suites)
+ if (end - pos < num_suites) {
+ tlsv1_server_log(conn,
+ "Truncated ClientHello/compression_methods");
goto decode_error;
+ }
wpa_hexdump(MSG_MSGDUMP, "TLSv1: client compression_methods",
pos, num_suites);
compr_null_found = 0;
@@ -1217,6 +1245,7 @@
if (os_memcmp_const(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
tlsv1_server_log(conn, "Mismatch in verify_data");
+ conn->state = FAILED;
return -1;
}
diff --git a/src/tls/tlsv1_server_write.c b/src/tls/tlsv1_server_write.c
index bdc6c11..8d36cf1 100644
--- a/src/tls/tlsv1_server_write.c
+++ b/src/tls/tlsv1_server_write.c
@@ -26,7 +26,7 @@
size_t len = 0;
struct x509_certificate *cert;
- cert = conn->cred->cert;
+ cert = conn->cred ? conn->cred->cert : NULL;
while (cert) {
len += 3 + cert->cert_len;
if (x509_certificate_self_signed(cert))
@@ -53,6 +53,9 @@
pos += TLS_RECORD_HEADER_LEN;
os_get_time(&now);
+#ifdef TEST_FUZZ
+ now.sec = 0xfffefdfc;
+#endif /* TEST_FUZZ */
WPA_PUT_BE32(conn->server_random, now.sec);
if (random_get_bytes(conn->server_random + 4, TLS_RANDOM_LEN - 4)) {
wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c
index f80c9a3..fa4d442 100644
--- a/src/tls/x509v3.c
+++ b/src/tls/x509v3.c
@@ -532,6 +532,8 @@
}
done:
+ if (pos < end)
+ *pos = '\0';
end[-1] = '\0';
}
diff --git a/src/utils/Makefile b/src/utils/Makefile
index 52efc53..1ee2bee 100644
--- a/src/utils/Makefile
+++ b/src/utils/Makefile
@@ -19,6 +19,7 @@
common.o \
crc32.o \
ip_addr.o \
+ json.o \
radiotap.o \
trace.o \
uuid.o \
diff --git a/src/utils/base64.c b/src/utils/base64.c
index 8eb4ba1..53a92f4 100644
--- a/src/utils/base64.c
+++ b/src/utils/base64.c
@@ -1,12 +1,13 @@
/*
* Base64 encoding/decoding (RFC1341)
- * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
+#include <stdint.h>
#include "os.h"
#include "base64.h"
@@ -27,6 +28,8 @@
size_t olen;
int line_len;
+ if (len >= SIZE_MAX / 4)
+ return NULL;
olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
if (add_pad)
olen += olen / 72; /* line feeds */
diff --git a/src/utils/browser-wpadebug.c b/src/utils/browser-wpadebug.c
index 062e6fe..dfb4b67 100644
--- a/src/utils/browser-wpadebug.c
+++ b/src/utils/browser-wpadebug.c
@@ -97,6 +97,7 @@
if (pid == 0) {
/* run the external command in the child process */
char *argv[14];
+ char *envp[] = { "PATH=/system/bin:/vendor/bin", NULL };
argv[0] = "browser-wpadebug";
argv[1] = "start";
@@ -113,8 +114,8 @@
argv[12] = "-3"; /* USER_CURRENT_OR_SELF */
argv[13] = NULL;
- execv("/system/bin/am", argv);
- wpa_printf(MSG_ERROR, "execv: %s", strerror(errno));
+ execve("/system/bin/am", argv, envp);
+ wpa_printf(MSG_ERROR, "execve: %s", strerror(errno));
exit(0);
return -1;
}
diff --git a/src/utils/browser.c b/src/utils/browser.c
index 9cf6152..ad0b382 100644
--- a/src/utils/browser.c
+++ b/src/utils/browser.c
@@ -166,8 +166,7 @@
g_object_set(G_OBJECT(s), "ssl-strict", FALSE, NULL);
ctx.win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_wmclass(GTK_WINDOW(ctx.win), "Hotspot 2.0 client",
- "Hotspot 2.0 client");
+ gtk_window_set_role(GTK_WINDOW(ctx.win), "Hotspot 2.0 client");
gtk_window_set_default_size(GTK_WINDOW(ctx.win), 800, 600);
scroll = gtk_scrolled_window_new(NULL, NULL);
diff --git a/src/utils/common.c b/src/utils/common.c
index 1eb3370..b9c8bfd 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -1,6 +1,6 @@
/*
* wpa_supplicant/hostapd / common helper functions, etc.
- * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -1073,7 +1073,8 @@
in_size--;
}
- while (in_size--) {
+ while (in_size) {
+ in_size--;
if (res_size >= out_size)
return 0;
@@ -1084,8 +1085,9 @@
return res_size;
case '\\':
- if (!in_size--)
+ if (!in_size)
return 0;
+ in_size--;
inp++;
/* fall through */
@@ -1116,7 +1118,8 @@
if (!in_size)
in_size = os_strlen(inp);
- while (in_size--) {
+ while (in_size) {
+ in_size--;
if (res_size++ >= out_size)
return 0;
@@ -1221,3 +1224,28 @@
return 220;
return (rssi + 110) * 2;
}
+
+
+char * get_param(const char *cmd, const char *param)
+{
+ const char *pos, *end;
+ char *val;
+ size_t len;
+
+ pos = os_strstr(cmd, param);
+ if (!pos)
+ return NULL;
+
+ pos += os_strlen(param);
+ end = os_strchr(pos, ' ');
+ if (end)
+ len = end - pos;
+ else
+ len = os_strlen(pos);
+ val = os_malloc(len + 1);
+ if (!val)
+ return NULL;
+ os_memcpy(val, pos, len);
+ val[len] = '\0';
+ return val;
+}
diff --git a/src/utils/common.h b/src/utils/common.h
index 46e96a6..792a30a 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -150,6 +150,7 @@
#define host_to_le32(n) (n)
#define be_to_host32(n) wpa_swap_32(n)
#define host_to_be32(n) wpa_swap_32(n)
+#define host_to_le64(n) (n)
#define WPA_BYTE_SWAP_DEFINED
@@ -435,6 +436,7 @@
#define __bitwise __attribute__((bitwise))
#else
#define __force
+#undef __bitwise
#define __bitwise
#endif
@@ -565,6 +567,7 @@
int str_starts(const char *str, const char *start);
u8 rssi_to_rcpi(int rssi);
+char * get_param(const char *cmd, const char *param);
/*
* gcc 4.4 ends up generating strict-aliasing warnings about some very common
diff --git a/src/utils/const_time.h b/src/utils/const_time.h
new file mode 100644
index 0000000..ab8f611
--- /dev/null
+++ b/src/utils/const_time.h
@@ -0,0 +1,191 @@
+/*
+ * Helper functions for constant time operations
+ * Copyright (c) 2019, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * These helper functions can be used to implement logic that needs to minimize
+ * externally visible differences in execution path by avoiding use of branches,
+ * avoiding early termination or other time differences, and forcing same memory
+ * access pattern regardless of values.
+ */
+
+#ifndef CONST_TIME_H
+#define CONST_TIME_H
+
+
+#if defined(__clang__)
+#define NO_UBSAN_UINT_OVERFLOW \
+ __attribute__((no_sanitize("unsigned-integer-overflow")))
+#else
+#define NO_UBSAN_UINT_OVERFLOW
+#endif
+
+
+/**
+ * const_time_fill_msb - Fill all bits with MSB value
+ * @val: Input value
+ * Returns: Value with all the bits set to the MSB of the input val
+ */
+static inline unsigned int const_time_fill_msb(unsigned int val)
+{
+ /* Move the MSB to LSB and multiple by -1 to fill in all bits. */
+ return (val >> (sizeof(val) * 8 - 1)) * ~0U;
+}
+
+
+/* Returns: -1 if val is zero; 0 if val is not zero */
+static inline unsigned int const_time_is_zero(unsigned int val)
+ NO_UBSAN_UINT_OVERFLOW
+{
+ /* Set MSB to 1 for 0 and fill rest of bits with the MSB value */
+ return const_time_fill_msb(~val & (val - 1));
+}
+
+
+/* Returns: -1 if a == b; 0 if a != b */
+static inline unsigned int const_time_eq(unsigned int a, unsigned int b)
+{
+ return const_time_is_zero(a ^ b);
+}
+
+
+/* Returns: -1 if a == b; 0 if a != b */
+static inline u8 const_time_eq_u8(unsigned int a, unsigned int b)
+{
+ return (u8) const_time_eq(a, b);
+}
+
+
+/**
+ * const_time_eq_bin - Constant time memory comparison
+ * @a: First buffer to compare
+ * @b: Second buffer to compare
+ * @len: Number of octets to compare
+ * Returns: -1 if buffers are equal, 0 if not
+ *
+ * This function is meant for comparing passwords or hash values where
+ * difference in execution time or memory access pattern could provide external
+ * observer information about the location of the difference in the memory
+ * buffers. The return value does not behave like memcmp(), i.e.,
+ * const_time_eq_bin() cannot be used to sort items into a defined order. Unlike
+ * memcmp(), the execution time of const_time_eq_bin() does not depend on the
+ * contents of the compared memory buffers, but only on the total compared
+ * length.
+ */
+static inline unsigned int const_time_eq_bin(const void *a, const void *b,
+ size_t len)
+{
+ const u8 *aa = a;
+ const u8 *bb = b;
+ size_t i;
+ u8 res = 0;
+
+ for (i = 0; i < len; i++)
+ res |= aa[i] ^ bb[i];
+
+ return const_time_is_zero(res);
+}
+
+
+/**
+ * const_time_select - Constant time unsigned int selection
+ * @mask: 0 (false) or -1 (true) to identify which value to select
+ * @true_val: Value to select for the true case
+ * @false_val: Value to select for the false case
+ * Returns: true_val if mask == -1, false_val if mask == 0
+ */
+static inline unsigned int const_time_select(unsigned int mask,
+ unsigned int true_val,
+ unsigned int false_val)
+{
+ return (mask & true_val) | (~mask & false_val);
+}
+
+
+/**
+ * const_time_select_int - Constant time int selection
+ * @mask: 0 (false) or -1 (true) to identify which value to select
+ * @true_val: Value to select for the true case
+ * @false_val: Value to select for the false case
+ * Returns: true_val if mask == -1, false_val if mask == 0
+ */
+static inline int const_time_select_int(unsigned int mask, int true_val,
+ int false_val)
+{
+ return (int) const_time_select(mask, (unsigned int) true_val,
+ (unsigned int) false_val);
+}
+
+
+/**
+ * const_time_select_u8 - Constant time u8 selection
+ * @mask: 0 (false) or -1 (true) to identify which value to select
+ * @true_val: Value to select for the true case
+ * @false_val: Value to select for the false case
+ * Returns: true_val if mask == -1, false_val if mask == 0
+ */
+static inline u8 const_time_select_u8(u8 mask, u8 true_val, u8 false_val)
+{
+ return (u8) const_time_select(mask, true_val, false_val);
+}
+
+
+/**
+ * const_time_select_s8 - Constant time s8 selection
+ * @mask: 0 (false) or -1 (true) to identify which value to select
+ * @true_val: Value to select for the true case
+ * @false_val: Value to select for the false case
+ * Returns: true_val if mask == -1, false_val if mask == 0
+ */
+static inline s8 const_time_select_s8(u8 mask, s8 true_val, s8 false_val)
+{
+ return (s8) const_time_select(mask, (unsigned int) true_val,
+ (unsigned int) false_val);
+}
+
+
+/**
+ * const_time_select_bin - Constant time binary buffer selection copy
+ * @mask: 0 (false) or -1 (true) to identify which value to copy
+ * @true_val: Buffer to copy for the true case
+ * @false_val: Buffer to copy for the false case
+ * @len: Number of octets to copy
+ * @dst: Destination buffer for the copy
+ *
+ * This function copies the specified buffer into the destination buffer using
+ * operations with identical memory access pattern regardless of which buffer
+ * is being copied.
+ */
+static inline void const_time_select_bin(u8 mask, const u8 *true_val,
+ const u8 *false_val, size_t len,
+ u8 *dst)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++)
+ dst[i] = const_time_select_u8(mask, true_val[i], false_val[i]);
+}
+
+
+static inline int const_time_memcmp(const void *a, const void *b, size_t len)
+{
+ const u8 *aa = a;
+ const u8 *bb = b;
+ int diff, res = 0;
+ unsigned int mask;
+
+ if (len == 0)
+ return 0;
+ do {
+ len--;
+ diff = (int) aa[len] - (int) bb[len];
+ mask = const_time_is_zero((unsigned int) diff);
+ res = const_time_select_int(mask, res, diff);
+ } while (len);
+
+ return res;
+}
+
+#endif /* CONST_TIME_H */
diff --git a/src/utils/eloop.c b/src/utils/eloop.c
index 436bc8c..bb375be 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -224,22 +224,25 @@
#ifdef CONFIG_ELOOP_KQUEUE
-static int eloop_sock_queue(int sock, eloop_event_type type)
-{
- int filter;
- struct kevent ke;
+static short event_type_kevent_filter(eloop_event_type type)
+{
switch (type) {
case EVENT_TYPE_READ:
- filter = EVFILT_READ;
- break;
+ return EVFILT_READ;
case EVENT_TYPE_WRITE:
- filter = EVFILT_WRITE;
- break;
+ return EVFILT_WRITE;
default:
- filter = 0;
+ return 0;
}
- EV_SET(&ke, sock, filter, EV_ADD, 0, 0, 0);
+}
+
+
+static int eloop_sock_queue(int sock, eloop_event_type type)
+{
+ struct kevent ke;
+
+ EV_SET(&ke, sock, event_type_kevent_filter(type), EV_ADD, 0, 0, 0);
if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) == -1) {
wpa_printf(MSG_ERROR, "%s: kevent(ADD) for fd=%d failed: %s",
__func__, sock, strerror(errno));
@@ -247,6 +250,7 @@
}
return 0;
}
+
#endif /* CONFIG_ELOOP_KQUEUE */
@@ -301,7 +305,7 @@
#endif /* CONFIG_ELOOP_POLL */
#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
if (new_max_sock >= eloop.max_fd) {
- next = eloop.max_fd == 0 ? 16 : eloop.max_fd * 2;
+ next = new_max_sock + 16;
temp_table = os_realloc_array(eloop.fd_table, next,
sizeof(struct eloop_sock));
if (temp_table == NULL)
@@ -411,7 +415,8 @@
os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock));
#endif /* CONFIG_ELOOP_EPOLL */
#ifdef CONFIG_ELOOP_KQUEUE
- EV_SET(&ke, sock, 0, EV_DELETE, 0, 0, 0);
+ EV_SET(&ke, sock, event_type_kevent_filter(table->type), EV_DELETE, 0,
+ 0, 0);
if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) < 0) {
wpa_printf(MSG_ERROR, "%s: kevent(DEL) for fd=%d failed: %s",
__func__, sock, strerror(errno));
diff --git a/src/utils/http_curl.c b/src/utils/http_curl.c
index 58519ea..e62fbf9 100644
--- a/src/utils/http_curl.c
+++ b/src/utils/http_curl.c
@@ -31,6 +31,14 @@
#endif /* EAP_TLS_OPENSSL */
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x)
+{
+ return ASN1_STRING_data((ASN1_STRING *) x);
+}
+#endif /* OpenSSL < 1.1.0 */
+
+
struct http_ctx {
void *ctx;
struct xml_node_ctx *xml;
@@ -446,6 +454,7 @@
#define sk_ASN1_IA5STRING_value(st, i) (ASN1_IA5STRING *) \
sk_value(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_IA5STRING) *, (st)), (i))
#else /* OPENSSL_IS_BORINGSSL */
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
#define sk_LogotypeInfo_num(st) SKM_sk_num(LogotypeInfo, (st))
#define sk_LogotypeInfo_value(st, i) SKM_sk_value(LogotypeInfo, (st), (i))
#define sk_LogotypeImage_num(st) SKM_sk_num(LogotypeImage, (st))
@@ -456,6 +465,13 @@
#define sk_HashAlgAndValue_value(st, i) SKM_sk_value(HashAlgAndValue, (st), (i))
#define sk_ASN1_IA5STRING_num(st) SKM_sk_num(ASN1_IA5STRING, (st))
#define sk_ASN1_IA5STRING_value(st, i) SKM_sk_value(ASN1_IA5STRING, (st), (i))
+#else
+DEFINE_STACK_OF(LogotypeInfo)
+DEFINE_STACK_OF(LogotypeImage)
+DEFINE_STACK_OF(LogotypeAudio)
+DEFINE_STACK_OF(HashAlgAndValue)
+DEFINE_STACK_OF(ASN1_IA5STRING)
+#endif
#endif /* OPENSSL_IS_BORINGSSL */
@@ -486,7 +502,8 @@
return;
n->hash_len = ASN1_STRING_length(hash->hashValue);
- n->hash = os_memdup(ASN1_STRING_data(hash->hashValue), n->hash_len);
+ n->hash = os_memdup(ASN1_STRING_get0_data(hash->hashValue),
+ n->hash_len);
if (n->hash == NULL) {
os_free(n->alg_oid);
return;
@@ -499,7 +516,7 @@
os_free(n->hash);
return;
}
- os_memcpy(n->uri, ASN1_STRING_data(uri), len);
+ os_memcpy(n->uri, ASN1_STRING_get0_data(uri), len);
n->uri[len] = '\0';
hcert->num_logo++;
@@ -814,9 +831,9 @@
}
wpa_hexdump(MSG_DEBUG, "logotypeExtn",
- ASN1_STRING_data(os), ASN1_STRING_length(os));
+ ASN1_STRING_get0_data(os), ASN1_STRING_length(os));
- data = ASN1_STRING_data(os);
+ data = ASN1_STRING_get0_data(os);
logo = d2i_LogotypeExtn(NULL, &data, ASN1_STRING_length(os));
if (logo == NULL) {
wpa_printf(MSG_INFO, "Failed to parse logotypeExtn");
@@ -1136,7 +1153,7 @@
return 0;
}
- store = SSL_CTX_get_cert_store(s->ctx);
+ store = SSL_CTX_get_cert_store(SSL_get_SSL_CTX(s));
if (ctx->peer_issuer) {
wpa_printf(MSG_DEBUG, "OpenSSL: Add issuer");
debug_dump_cert("OpenSSL: Issuer certificate",
@@ -1272,12 +1289,13 @@
}
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
static SSL_METHOD patch_ssl_method;
static const SSL_METHOD *real_ssl_method;
static int curl_patch_ssl_new(SSL *s)
{
- SSL_CTX *ssl = s->ctx;
+ SSL_CTX *ssl = SSL_get_SSL_CTX(s);
int ret;
ssl->method = real_ssl_method;
@@ -1288,6 +1306,7 @@
return ret;
}
+#endif /* OpenSSL < 1.1.0 */
#endif /* HAVE_OCSP */
@@ -1306,6 +1325,7 @@
SSL_CTX_set_tlsext_status_cb(ssl, ocsp_resp_cb);
SSL_CTX_set_tlsext_status_arg(ssl, ctx);
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
/*
* Use a temporary SSL_METHOD to get a callback on SSL_new()
* from libcurl since there is no proper callback registration
@@ -1315,6 +1335,7 @@
patch_ssl_method.ssl_new = curl_patch_ssl_new;
real_ssl_method = ssl->method;
ssl->method = &patch_ssl_method;
+#endif /* OpenSSL < 1.1.0 */
}
#endif /* HAVE_OCSP */
@@ -1351,7 +1372,7 @@
#ifdef EAP_TLS_OPENSSL
curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, curl_cb_ssl);
curl_easy_setopt(curl, CURLOPT_SSL_CTX_DATA, ctx);
-#ifdef OPENSSL_IS_BORINGSSL
+#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER >= 0x10100000L)
/* For now, using the CURLOPT_SSL_VERIFYSTATUS option only
* with BoringSSL since the OpenSSL specific callback hack to
* enable OCSP is not available with BoringSSL. The OCSP
diff --git a/src/utils/json.c b/src/utils/json.c
index eae627d..b644339 100644
--- a/src/utils/json.c
+++ b/src/utils/json.c
@@ -103,6 +103,11 @@
return str;
case '\\':
pos++;
+ if (pos >= end) {
+ wpa_printf(MSG_DEBUG,
+ "JSON: Truncated \\ escape");
+ goto fail;
+ }
switch (*pos) {
case '"':
case '\\':
@@ -165,6 +170,8 @@
break;
}
}
+ if (pos == end)
+ pos--;
if (pos < *json_pos)
return -1;
len = pos - *json_pos + 1;
@@ -230,6 +237,8 @@
token = json_alloc_token(&tokens);
if (!token)
goto fail;
+ if (!root)
+ root = token;
} else if (curr_token->state == JSON_WAITING_VALUE) {
token = curr_token;
} else if (curr_token->parent &&
diff --git a/src/utils/list.h b/src/utils/list.h
index ee2f485..85aa5e3 100644
--- a/src/utils/list.h
+++ b/src/utils/list.h
@@ -1,6 +1,6 @@
/*
* Doubly-linked list
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -76,8 +76,8 @@
dl_list_entry((list)->prev, type, member))
#define dl_list_for_each(item, list, type, member) \
- for (item = dl_list_entry((list)->next, type, member); \
- &item->member != (list); \
+ for (item = dl_list_first((list), type, member); \
+ item && item != dl_list_entry((list), type, member); \
item = dl_list_entry(item->member.next, type, member))
#define dl_list_for_each_safe(item, n, list, type, member) \
diff --git a/src/utils/os_internal.c b/src/utils/os_internal.c
index ed6eb3c..474c8a3 100644
--- a/src/utils/os_internal.c
+++ b/src/utils/os_internal.c
@@ -430,22 +430,6 @@
}
-char * os_strncpy(char *dest, const char *src, size_t n)
-{
- char *d = dest;
-
- while (n--) {
- *d = *src;
- if (*src == '\0')
- break;
- d++;
- src++;
- }
-
- return dest;
-}
-
-
size_t os_strlcpy(char *dest, const char *src, size_t siz)
{
const char *s = src;
diff --git a/src/utils/os_none.c b/src/utils/os_none.c
index e74f206..5e0a3ad 100644
--- a/src/utils/os_none.c
+++ b/src/utils/os_none.c
@@ -218,12 +218,6 @@
}
-char * os_strncpy(char *dest, const char *src, size_t n)
-{
- return dest;
-}
-
-
size_t os_strlcpy(char *dest, const char *src, size_t size)
{
return 0;
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 381846a..b56bab2 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -1,6 +1,6 @@
/*
* OS specific functions for UNIX/POSIX systems
- * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -252,6 +252,13 @@
int os_get_random(unsigned char *buf, size_t len)
{
+#ifdef TEST_FUZZ
+ size_t i;
+
+ for (i = 0; i < len; i++)
+ buf[i] = i & 0xff;
+ return 0;
+#else /* TEST_FUZZ */
FILE *f;
size_t rc;
@@ -268,6 +275,7 @@
fclose(f);
return rc != len ? -1 : 0;
+#endif /* TEST_FUZZ */
}
@@ -538,7 +546,7 @@
{
void *r = os_malloc(len);
- if (r)
+ if (r && src)
os_memcpy(r, src, len);
return r;
}
diff --git a/src/utils/utils_module_tests.c b/src/utils/utils_module_tests.c
index 1b8ff82..3af4fcd 100644
--- a/src/utils/utils_module_tests.c
+++ b/src/utils/utils_module_tests.c
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/const_time.h"
#include "common/ieee802_11_defs.h"
#include "utils/bitfield.h"
#include "utils/ext_password.h"
@@ -919,6 +920,294 @@
}
+static int const_time_tests(void)
+{
+ struct const_time_fill_msb_test {
+ unsigned int val;
+ unsigned int expected;
+ } const_time_fill_msb_tests[] = {
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 0 },
+ { 1 << (sizeof(unsigned int) * 8 - 1), ~0 },
+ { ~0 - 1, ~0 },
+ { ~0, ~0 }
+ };
+ struct const_time_is_zero_test {
+ unsigned int val;
+ unsigned int expected;
+ } const_time_is_zero_tests[] = {
+ { 0, ~0 },
+ { 1, 0 },
+ { 2, 0 },
+ { 1 << (sizeof(unsigned int) * 8 - 1), 0 },
+ { ~0 - 1, 0 },
+ { ~0, 0 }
+ };
+ struct const_time_eq_test {
+ unsigned int a;
+ unsigned int b;
+ unsigned int expected;
+ unsigned int expected_u8;
+ } const_time_eq_tests[] = {
+ { 0, 1, 0, 0 },
+ { 1, 2, 0, 0 },
+ { 1, 1, ~0, 0xff },
+ { ~0, ~0, ~0, 0xff },
+ { ~0, ~0 - 1, 0, 0 },
+ { 0, 0, ~0, 0xff }
+ };
+ struct const_time_eq_bin_test {
+ u8 *a;
+ u8 *b;
+ size_t len;
+ unsigned int expected;
+ } const_time_eq_bin_tests[] = {
+ { (u8 *) "", (u8 *) "", 0, ~0 },
+ { (u8 *) "abcde", (u8 *) "abcde", 5, ~0 },
+ { (u8 *) "abcde", (u8 *) "Abcde", 5, 0 },
+ { (u8 *) "abcde", (u8 *) "aBcde", 5, 0 },
+ { (u8 *) "abcde", (u8 *) "abCde", 5, 0 },
+ { (u8 *) "abcde", (u8 *) "abcDe", 5, 0 },
+ { (u8 *) "abcde", (u8 *) "abcdE", 5, 0 },
+ { (u8 *) "\x00", (u8 *) "\x01", 1, 0 },
+ { (u8 *) "\x00", (u8 *) "\x80", 1, 0 },
+ { (u8 *) "\x00", (u8 *) "\x00", 1, ~0 }
+ };
+ struct const_time_select_test {
+ unsigned int mask;
+ unsigned int true_val;
+ unsigned int false_val;
+ unsigned int expected;
+ } const_time_select_tests[] = {
+ { ~0, ~0, ~0, ~0 },
+ { 0, ~0, ~0, ~0 },
+ { ~0, ~0, 0, ~0 },
+ { 0, ~0, 0, 0 },
+ { ~0, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa },
+ { 0, 0xaaaaaaaa, 0x55555555, 0x55555555 },
+ { ~0, 3, 3, 3 },
+ { 0, 3, 3, 3 },
+ { ~0, 1, 2, 1 },
+ { 0, 1, 2, 2 }
+ };
+ struct const_time_select_int_test {
+ unsigned int mask;
+ int true_val;
+ int false_val;
+ int expected;
+ } const_time_select_int_tests[] = {
+ { ~0, -128, 127, -128 },
+ { 0, -128, 127, 127 },
+ { ~0, -2147483648, 2147483647, -2147483648 },
+ { 0, -2147483648, 2147483647, 2147483647 },
+ { ~0, 0, 0, 0 },
+ { 0, 0, 0, 0 },
+ { ~0, -1, 1, -1 },
+ { 0, -1, 1, 1 }
+ };
+ struct const_time_select_u8_test {
+ u8 mask;
+ u8 true_val;
+ u8 false_val;
+ u8 expected;
+ } const_time_select_u8_tests[] = {
+ { ~0, ~0, ~0, ~0 },
+ { 0, ~0, ~0, ~0 },
+ { ~0, ~0, 0, ~0 },
+ { 0, ~0, 0, 0 },
+ { ~0, 0xaa, 0x55, 0xaa },
+ { 0, 0xaa, 0x55, 0x55 },
+ { ~0, 1, 2, 1 },
+ { 0, 1, 2, 2 }
+ };
+ struct const_time_select_s8_test {
+ u8 mask;
+ s8 true_val;
+ s8 false_val;
+ s8 expected;
+ } const_time_select_s8_tests[] = {
+ { ~0, -128, 127, -128 },
+ { 0, -128, 127, 127 },
+ { ~0, 0, 0, 0 },
+ { 0, 0, 0, 0 },
+ { ~0, -1, 1, -1 },
+ { 0, -1, 1, 1 }
+ };
+ struct const_time_select_bin_test {
+ u8 mask;
+ u8 *true_val;
+ u8 *false_val;
+ size_t len;
+ u8 *expected;
+ } const_time_select_bin_tests[] = {
+ { ~0, (u8 *) "abcde", (u8 *) "ABCDE", 5, (u8 *) "abcde" },
+ { 0, (u8 *) "abcde", (u8 *) "ABCDE", 5, (u8 *) "ABCDE" },
+ { ~0, (u8 *) "", (u8 *) "", 0, (u8 *) "" },
+ { 0, (u8 *) "", (u8 *) "", 0, (u8 *) "" }
+ };
+ struct const_time_memcmp_test {
+ char *a;
+ char *b;
+ size_t len;
+ int expected;
+ } const_time_memcmp_tests[] = {
+ { "abcde", "abcde", 5, 0 },
+ { "abcde", "bbcde", 5, -1 },
+ { "bbcde", "abcde", 5, 1 },
+ { "accde", "abcde", 5, 1 },
+ { "abcee", "abcde", 5, 1 },
+ { "abcdf", "abcde", 5, 1 },
+ { "cbcde", "aXXXX", 5, 2 },
+ { "a", "d", 1, -3 },
+ { "", "", 0, 0 }
+ };
+ unsigned int i;
+ int ret = 0;
+
+ wpa_printf(MSG_INFO, "constant time tests");
+
+ for (i = 0; i < ARRAY_SIZE(const_time_fill_msb_tests); i++) {
+ struct const_time_fill_msb_test *test;
+
+ test = &const_time_fill_msb_tests[i];
+ if (const_time_fill_msb(test->val) != test->expected) {
+ wpa_printf(MSG_ERROR,
+ "const_time_fill_msb(0x%x) test failed",
+ test->val);
+ ret = -1;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(const_time_is_zero_tests); i++) {
+ struct const_time_is_zero_test *test;
+
+ test = &const_time_is_zero_tests[i];
+ if (const_time_is_zero(test->val) != test->expected) {
+ wpa_printf(MSG_ERROR,
+ "const_time_is_zero(0x%x) test failed",
+ test->val);
+ ret = -1;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(const_time_eq_tests); i++) {
+ struct const_time_eq_test *test;
+
+ test = &const_time_eq_tests[i];
+ if (const_time_eq(test->a, test->b) != test->expected) {
+ wpa_printf(MSG_ERROR,
+ "const_time_eq(0x%x,0x%x) test failed",
+ test->a, test->b);
+ ret = -1;
+ }
+ if (const_time_eq_u8(test->a, test->b) != test->expected_u8) {
+ wpa_printf(MSG_ERROR,
+ "const_time_eq_u8(0x%x,0x%x) test failed",
+ test->a, test->b);
+ ret = -1;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(const_time_eq_bin_tests); i++) {
+ struct const_time_eq_bin_test *test;
+
+ test = &const_time_eq_bin_tests[i];
+ if (const_time_eq_bin(test->a, test->b, test->len) !=
+ test->expected) {
+ wpa_printf(MSG_ERROR,
+ "const_time_eq_bin(len=%u) test failed",
+ (unsigned int) test->len);
+ ret = -1;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(const_time_select_tests); i++) {
+ struct const_time_select_test *test;
+
+ test = &const_time_select_tests[i];
+ if (const_time_select(test->mask, test->true_val,
+ test->false_val) != test->expected) {
+ wpa_printf(MSG_ERROR,
+ "const_time_select(0x%x,0x%x,0x%x) test failed",
+ test->mask, test->true_val, test->false_val);
+ ret = -1;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(const_time_select_int_tests); i++) {
+ struct const_time_select_int_test *test;
+
+ test = &const_time_select_int_tests[i];
+ if (const_time_select_int(test->mask, test->true_val,
+ test->false_val) != test->expected) {
+ wpa_printf(MSG_ERROR,
+ "const_time_select_int(0x%x,%d,%d) test failed",
+ test->mask, test->true_val, test->false_val);
+ ret = -1;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(const_time_select_u8_tests); i++) {
+ struct const_time_select_u8_test *test;
+
+ test = &const_time_select_u8_tests[i];
+ if (const_time_select_u8(test->mask, test->true_val,
+ test->false_val) != test->expected) {
+ wpa_printf(MSG_ERROR,
+ "const_time_select_u8(0x%x,0x%x,0x%x) test failed",
+ test->mask, test->true_val, test->false_val);
+ ret = -1;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(const_time_select_s8_tests); i++) {
+ struct const_time_select_s8_test *test;
+
+ test = &const_time_select_s8_tests[i];
+ if (const_time_select_s8(test->mask, test->true_val,
+ test->false_val) != test->expected) {
+ wpa_printf(MSG_ERROR,
+ "const_time_select_s8(0x%x,0x%x,0x%x) test failed",
+ test->mask, test->true_val, test->false_val);
+ ret = -1;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(const_time_select_bin_tests); i++) {
+ struct const_time_select_bin_test *test;
+ u8 dst[100];
+
+ test = &const_time_select_bin_tests[i];
+ const_time_select_bin(test->mask, test->true_val,
+ test->false_val, test->len, dst);
+ if (os_memcmp(dst, test->expected, test->len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "const_time_select_bin(0x%x,%u) test failed",
+ test->mask, (unsigned int) test->len);
+ ret = -1;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(const_time_memcmp_tests); i++) {
+ struct const_time_memcmp_test *test;
+ int res;
+
+ test = &const_time_memcmp_tests[i];
+ res = const_time_memcmp(test->a, test->b, test->len);
+ if (res != test->expected) {
+ wpa_printf(MSG_ERROR,
+ "const_time_memcmp(%s,%s,%d) test failed (%d != %d)",
+ test->a, test->b, (int) test->len,
+ res, test->expected);
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+
int utils_module_tests(void)
{
int ret = 0;
@@ -936,6 +1225,7 @@
ip_addr_tests() < 0 ||
eloop_tests() < 0 ||
json_tests() < 0 ||
+ const_time_tests() < 0 ||
int_array_tests() < 0)
ret = -1;
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index 62758d8..c437000 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -58,6 +58,10 @@
#ifndef CONFIG_NO_STDOUT_DEBUG
#ifdef CONFIG_DEBUG_FILE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
static FILE *out_file = NULL;
#endif /* CONFIG_DEBUG_FILE */
@@ -418,6 +422,12 @@
#ifdef CONFIG_ANDROID_LOG
_wpa_hexdump(level, title, buf, len, show);
#else /* CONFIG_ANDROID_LOG */
+#ifdef CONFIG_DEBUG_SYSLOG
+ if (wpa_debug_syslog) {
+ _wpa_hexdump(level, title, buf, len, show);
+ return;
+ }
+#endif /* CONFIG_DEBUG_SYSLOG */
wpa_debug_print_timestamp();
#ifdef CONFIG_DEBUG_FILE
if (out_file) {
@@ -539,6 +549,8 @@
int wpa_debug_open_file(const char *path)
{
#ifdef CONFIG_DEBUG_FILE
+ int out_fd;
+
if (!path)
return 0;
@@ -548,10 +560,28 @@
last_path = os_strdup(path);
}
- out_file = fopen(path, "a");
+ out_fd = open(path, O_CREAT | O_APPEND | O_WRONLY,
+ S_IRUSR | S_IWUSR | S_IRGRP);
+ if (out_fd < 0) {
+ wpa_printf(MSG_ERROR,
+ "%s: Failed to open output file descriptor, using standard output",
+ __func__);
+ return -1;
+ }
+
+#ifdef __linux__
+ if (fcntl(out_fd, F_SETFD, FD_CLOEXEC) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "%s: Failed to set FD_CLOEXEC - continue without: %s",
+ __func__, strerror(errno));
+ }
+#endif /* __linux__ */
+
+ out_file = fdopen(out_fd, "a");
if (out_file == NULL) {
wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open "
"output file, using standard output");
+ close(out_fd);
return -1;
}
#ifndef _WIN32
diff --git a/src/utils/xml-utils.c b/src/utils/xml-utils.c
index a37a92d..dae91fe 100644
--- a/src/utils/xml-utils.c
+++ b/src/utils/xml-utils.c
@@ -246,7 +246,9 @@
xml_node_create_text(ctx, tnds, NULL, "Path", uri);
val = get_val(ctx, node);
- xml_node_create_text(ctx, tnds, NULL, "Value", val ? val : "");
+ if (val || !xml_node_first_child(ctx, node))
+ xml_node_create_text(ctx, tnds, NULL, "Value",
+ val ? val : "");
xml_node_get_text_free(ctx, val);
new_uri = add_path(uri, name);
diff --git a/src/wps/wps.c b/src/wps/wps.c
index 8d22827..484df26 100644
--- a/src/wps/wps.c
+++ b/src/wps/wps.c
@@ -145,6 +145,8 @@
data->peer_pubkey_hash_set = 1;
}
+ data->multi_ap_backhaul_sta = cfg->multi_ap_backhaul_sta;
+
return data;
}
@@ -430,7 +432,7 @@
if (wps_build_version(ie) ||
wps_build_req_type(ie, req_type) ||
- wps_build_wfa_ext(ie, 0, NULL, 0)) {
+ wps_build_wfa_ext(ie, 0, NULL, 0, 0)) {
wpabuf_free(ie);
return NULL;
}
@@ -464,7 +466,7 @@
if (wps_build_version(ie) ||
wps_build_resp_type(ie, WPS_RESP_AP) ||
- wps_build_wfa_ext(ie, 0, NULL, 0)) {
+ wps_build_wfa_ext(ie, 0, NULL, 0, 0)) {
wpabuf_free(ie);
return NULL;
}
@@ -516,7 +518,7 @@
wps_build_model_name(dev, ie) ||
wps_build_model_number(dev, ie) ||
wps_build_dev_name(dev, ie) ||
- wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0) ||
+ wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0, 0) ||
wps_build_req_dev_type(dev, ie, num_req_dev_types, req_dev_types)
||
wps_build_secondary_dev_type(dev, ie)
diff --git a/src/wps/wps.h b/src/wps/wps.h
index 2505d2d..14ce863 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -100,6 +100,7 @@
struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
int p2p;
+ u8 multi_ap_ext;
};
/**
@@ -187,6 +188,12 @@
* peer_pubkey_hash - Peer public key hash or %NULL if not known
*/
const u8 *peer_pubkey_hash;
+
+ /**
+ * multi_ap_backhaul_sta - Whether this is a Multi-AP backhaul STA
+ * enrollee
+ */
+ int multi_ap_backhaul_sta;
};
struct wps_data * wps_init(const struct wps_config *cfg);
@@ -395,6 +402,37 @@
* PSK is set for a network.
*/
int force_per_enrollee_psk;
+
+ /**
+ * multi_ap_backhaul_ssid - SSID to supply to a Multi-AP backhaul
+ * enrollee
+ *
+ * This SSID is used by the Registrar to fill in information for
+ * Credentials when the enrollee advertises it is a Multi-AP backhaul
+ * STA.
+ */
+ const u8 *multi_ap_backhaul_ssid;
+
+ /**
+ * multi_ap_backhaul_ssid_len - Length of multi_ap_backhaul_ssid in
+ * octets
+ */
+ size_t multi_ap_backhaul_ssid_len;
+
+ /**
+ * multi_ap_backhaul_network_key - The Network Key (PSK) for the
+ * Multi-AP backhaul enrollee.
+ *
+ * This key can be either the ASCII passphrase (8..63 characters) or the
+ * 32-octet PSK (64 hex characters).
+ */
+ const u8 *multi_ap_backhaul_network_key;
+
+ /**
+ * multi_ap_backhaul_network_key_len - Length of
+ * multi_ap_backhaul_network_key in octets
+ */
+ size_t multi_ap_backhaul_network_key_len;
};
diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c
index 770f5e9..4e872f3 100644
--- a/src/wps/wps_attr_build.c
+++ b/src/wps/wps_attr_build.c
@@ -60,7 +60,8 @@
}
wps->dh_privkey = wpabuf_dup(wps->wps->ap_nfc_dh_privkey);
pubkey = wpabuf_dup(wps->wps->ap_nfc_dh_pubkey);
- wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, pubkey);
+ if (wps->dh_privkey && pubkey)
+ wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, pubkey);
#endif /* CONFIG_WPS_NFC */
} else {
wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys");
@@ -203,7 +204,8 @@
int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
- const u8 *auth_macs, size_t auth_macs_count)
+ const u8 *auth_macs, size_t auth_macs_count,
+ u8 multi_ap_subelem)
{
u8 *len;
@@ -244,6 +246,14 @@
MAC2STR(&auth_macs[i * ETH_ALEN]));
}
+ if (multi_ap_subelem) {
+ wpa_printf(MSG_DEBUG, "WPS: * Multi-AP (0x%x)",
+ multi_ap_subelem);
+ wpabuf_put_u8(msg, WFA_ELEM_MULTI_AP);
+ wpabuf_put_u8(msg, 1); /* length */
+ wpabuf_put_u8(msg, multi_ap_subelem);
+ }
+
WPA_PUT_BE16(len, (u8 *) wpabuf_put(msg, 0) - len - 2);
#ifdef CONFIG_WPS_TESTING
diff --git a/src/wps/wps_attr_parse.c b/src/wps/wps_attr_parse.c
index 756d57e..fd51635 100644
--- a/src/wps/wps_attr_parse.c
+++ b/src/wps/wps_attr_parse.c
@@ -67,6 +67,17 @@
}
attr->registrar_configuration_methods = pos;
break;
+ case WFA_ELEM_MULTI_AP:
+ if (len != 1) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: Invalid Multi-AP Extension length %u",
+ len);
+ return -1;
+ }
+ attr->multi_ap_ext = *pos;
+ wpa_printf(MSG_DEBUG, "WPS: Multi-AP Extension 0x%02x",
+ attr->multi_ap_ext);
+ break;
default:
wpa_printf(MSG_MSGDUMP, "WPS: Skipped unknown WFA Vendor "
"Extension subelement %u", id);
diff --git a/src/wps/wps_attr_parse.h b/src/wps/wps_attr_parse.h
index 8188fe9..4de27b2 100644
--- a/src/wps/wps_attr_parse.h
+++ b/src/wps/wps_attr_parse.h
@@ -97,6 +97,7 @@
const u8 *cred[MAX_CRED_COUNT];
const u8 *req_dev_type[MAX_REQ_DEV_TYPE_COUNT];
const u8 *vendor_ext[MAX_WPS_PARSE_VENDOR_EXT];
+ u8 multi_ap_ext;
};
int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr);
diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c
index 2e34721..747dc47 100644
--- a/src/wps/wps_common.c
+++ b/src/wps/wps_common.c
@@ -374,7 +374,7 @@
(rf_band && wps_build_rf_bands_attr(plain, rf_band)) ||
(channel && wps_build_ap_channel(plain, channel)) ||
wps_build_mac_addr(plain, wps->dev.mac_addr) ||
- wps_build_wfa_ext(plain, 0, NULL, 0)) {
+ wps_build_wfa_ext(plain, 0, NULL, 0, 0)) {
os_free(data.new_psk);
wpabuf_clear_free(plain);
return NULL;
@@ -421,7 +421,7 @@
if (wps_build_oob_dev_pw(data, dev_pw_id, pubkey,
wpabuf_head(dev_pw), wpabuf_len(dev_pw)) ||
- wps_build_wfa_ext(data, 0, NULL, 0)) {
+ wps_build_wfa_ext(data, 0, NULL, 0, 0)) {
wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password "
"token");
wpabuf_clear_free(data);
@@ -586,7 +586,7 @@
wps_build_msg_type(msg, WPS_WSC_ACK) ||
wps_build_enrollee_nonce(wps, msg) ||
wps_build_registrar_nonce(wps, msg) ||
- wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
wpabuf_free(msg);
return NULL;
}
@@ -610,7 +610,7 @@
wps_build_enrollee_nonce(wps, msg) ||
wps_build_registrar_nonce(wps, msg) ||
wps_build_config_error(msg, wps->config_error) ||
- wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
wpabuf_free(msg);
return NULL;
}
@@ -654,6 +654,7 @@
pub = wpabuf_zeropad(pub, 192);
if (pub == NULL) {
wpabuf_free(priv);
+ dh5_free(dh_ctx);
return -1;
}
wpa_hexdump_buf(MSG_DEBUG, "WPS: Generated new DH pubkey", pub);
@@ -725,7 +726,7 @@
if (wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER,
nfc_dh_pubkey, NULL, 0) ||
wps_build_uuid_e(msg, ctx->uuid) ||
- wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
wpabuf_free(msg);
return NULL;
}
@@ -808,7 +809,7 @@
wps_build_ssid(msg, ctx) ||
wps_build_ap_freq(msg, freq) ||
(bssid && wps_build_mac_addr(msg, bssid)) ||
- wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
wpabuf_free(msg);
return NULL;
}
@@ -847,7 +848,7 @@
wps_build_rf_bands(&ctx->dev, msg, 0) ||
wps_build_serial_number(&ctx->dev, msg) ||
wps_build_uuid_e(msg, ctx->uuid) ||
- wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
wpabuf_free(msg);
return NULL;
}
@@ -899,7 +900,7 @@
wps_build_rf_bands(&ctx->dev, msg, 0) ||
wps_build_serial_number(&ctx->dev, msg) ||
wps_build_uuid_e(msg, ctx->uuid) ||
- wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
wpabuf_free(msg);
return NULL;
}
diff --git a/src/wps/wps_defs.h b/src/wps/wps_defs.h
index 301864d..9fccb4e 100644
--- a/src/wps/wps_defs.h
+++ b/src/wps/wps_defs.h
@@ -152,7 +152,8 @@
WFA_ELEM_NETWORK_KEY_SHAREABLE = 0x02,
WFA_ELEM_REQUEST_TO_ENROLL = 0x03,
WFA_ELEM_SETTINGS_DELAY_TIME = 0x04,
- WFA_ELEM_REGISTRAR_CONFIGURATION_METHODS = 0x05
+ WFA_ELEM_REGISTRAR_CONFIGURATION_METHODS = 0x05,
+ WFA_ELEM_MULTI_AP = 0x06
};
/* Device Password ID */
diff --git a/src/wps/wps_dev_attr.c b/src/wps/wps_dev_attr.c
index 0d01211..b209fea 100644
--- a/src/wps/wps_dev_attr.c
+++ b/src/wps/wps_dev_attr.c
@@ -390,6 +390,14 @@
}
+void wps_process_vendor_ext_m1(struct wps_device_data *dev, const u8 ext)
+{
+ dev->multi_ap_ext = ext;
+ wpa_printf(MSG_DEBUG, "WPS: Multi-AP extension value %02x",
+ dev->multi_ap_ext);
+}
+
+
int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands)
{
if (bands == NULL) {
diff --git a/src/wps/wps_dev_attr.h b/src/wps/wps_dev_attr.h
index c9034ad..a4b4173 100644
--- a/src/wps/wps_dev_attr.h
+++ b/src/wps/wps_dev_attr.h
@@ -29,6 +29,7 @@
int wps_process_device_attrs(struct wps_device_data *dev,
struct wps_parse_attr *attr);
int wps_process_os_version(struct wps_device_data *dev, const u8 *ver);
+void wps_process_vendor_ext_m1(struct wps_device_data *dev, const u8 ext);
int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands);
void wps_device_data_free(struct wps_device_data *dev);
int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg);
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 4175077..80ed603 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -105,6 +105,7 @@
{
struct wpabuf *msg;
u16 config_methods;
+ u8 multi_ap_backhaul_sta = 0;
if (random_get_bytes(wps->nonce_e, WPS_NONCE_LEN) < 0)
return NULL;
@@ -134,6 +135,9 @@
WPS_CONFIG_PHY_PUSHBUTTON);
}
+ if (wps->multi_ap_backhaul_sta)
+ multi_ap_backhaul_sta = MULTI_AP_BACKHAUL_STA;
+
if (wps_build_version(msg) ||
wps_build_msg_type(msg, WPS_M1) ||
wps_build_uuid_e(msg, wps->uuid_e) ||
@@ -152,7 +156,7 @@
wps_build_dev_password_id(msg, wps->dev_pw_id) ||
wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
wps_build_os_version(&wps->wps->dev, msg) ||
- wps_build_wfa_ext(msg, 0, NULL, 0) ||
+ wps_build_wfa_ext(msg, 0, NULL, 0, multi_ap_backhaul_sta) ||
wps_build_vendor_ext_m1(&wps->wps->dev, msg)) {
wpabuf_free(msg);
return NULL;
@@ -190,7 +194,7 @@
wps_build_msg_type(msg, WPS_M3) ||
wps_build_registrar_nonce(wps, msg) ||
wps_build_e_hash(wps, msg) ||
- wps_build_wfa_ext(msg, 0, NULL, 0) ||
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0) ||
wps_build_authenticator(wps, msg)) {
wpabuf_free(msg);
return NULL;
@@ -223,7 +227,7 @@
wps_build_e_snonce1(wps, plain) ||
wps_build_key_wrap_auth(wps, plain) ||
wps_build_encr_settings(wps, msg, plain) ||
- wps_build_wfa_ext(msg, 0, NULL, 0) ||
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0) ||
wps_build_authenticator(wps, msg)) {
wpabuf_clear_free(plain);
wpabuf_free(msg);
@@ -393,7 +397,7 @@
(wps->wps->ap && wps_build_ap_settings(wps, plain)) ||
wps_build_key_wrap_auth(wps, plain) ||
wps_build_encr_settings(wps, msg, plain) ||
- wps_build_wfa_ext(msg, 0, NULL, 0) ||
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0) ||
wps_build_authenticator(wps, msg)) {
wpabuf_clear_free(plain);
wpabuf_free(msg);
@@ -430,7 +434,7 @@
wps_build_msg_type(msg, WPS_WSC_DONE) ||
wps_build_enrollee_nonce(wps, msg) ||
wps_build_registrar_nonce(wps, msg) ||
- wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
wpabuf_free(msg);
return NULL;
}
diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c
index affd6a4..06a8fda 100644
--- a/src/wps/wps_er.c
+++ b/src/wps/wps_er.c
@@ -1530,7 +1530,7 @@
wps_er_build_selected_registrar(msg, sel_reg) ||
wps_er_build_dev_password_id(msg, dev_passwd_id) ||
wps_er_build_sel_reg_config_methods(msg, sel_reg_config_methods) ||
- wps_build_wfa_ext(msg, 0, auth_macs, count) ||
+ wps_build_wfa_ext(msg, 0, auth_macs, count, 0) ||
wps_er_build_uuid_r(msg, er->wps->uuid)) {
wpabuf_free(msg);
return;
@@ -2048,7 +2048,7 @@
data.wps = wps;
data.use_cred = cred;
if (wps_build_cred(&data, ret) ||
- wps_build_wfa_ext(ret, 0, NULL, 0)) {
+ wps_build_wfa_ext(ret, 0, NULL, 0, 0)) {
wpabuf_free(ret);
return NULL;
}
diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h
index fe0c60b..2cf22d4 100644
--- a/src/wps/wps_i.h
+++ b/src/wps/wps_i.h
@@ -125,6 +125,8 @@
int pbc_in_m1;
struct wps_nfc_pw_token *nfc_pw_token;
+
+ int multi_ap_backhaul_sta;
};
@@ -163,7 +165,8 @@
struct wpabuf *plain);
int wps_build_version(struct wpabuf *msg);
int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
- const u8 *auth_macs, size_t auth_macs_count);
+ const u8 *auth_macs, size_t auth_macs_count,
+ u8 multi_ap_subelem);
int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type);
int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg);
int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg);
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 379925e..0ac5b28 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -188,6 +188,37 @@
#ifdef WPS_WORKAROUNDS
struct os_reltime pbc_ignore_start;
#endif /* WPS_WORKAROUNDS */
+
+ /**
+ * multi_ap_backhaul_ssid - SSID to supply to a Multi-AP backhaul
+ * enrollee
+ *
+ * This SSID is used by the Registrar to fill in information for
+ * Credentials when the enrollee advertises it is a Multi-AP backhaul
+ * STA.
+ */
+ u8 multi_ap_backhaul_ssid[SSID_MAX_LEN];
+
+ /**
+ * multi_ap_backhaul_ssid_len - Length of multi_ap_backhaul_ssid in
+ * octets
+ */
+ size_t multi_ap_backhaul_ssid_len;
+
+ /**
+ * multi_ap_backhaul_network_key - The Network Key (PSK) for the
+ * Multi-AP backhaul enrollee.
+ *
+ * This key can be either the ASCII passphrase (8..63 characters) or the
+ * 32-octet PSK (64 hex characters).
+ */
+ u8 *multi_ap_backhaul_network_key;
+
+ /**
+ * multi_ap_backhaul_network_key_len - Length of
+ * multi_ap_backhaul_network_key in octets
+ */
+ size_t multi_ap_backhaul_network_key_len;
};
@@ -667,6 +698,22 @@
reg->dualband = cfg->dualband;
reg->force_per_enrollee_psk = cfg->force_per_enrollee_psk;
+ if (cfg->multi_ap_backhaul_ssid) {
+ os_memcpy(reg->multi_ap_backhaul_ssid,
+ cfg->multi_ap_backhaul_ssid,
+ cfg->multi_ap_backhaul_ssid_len);
+ reg->multi_ap_backhaul_ssid_len =
+ cfg->multi_ap_backhaul_ssid_len;
+ }
+ if (cfg->multi_ap_backhaul_network_key) {
+ reg->multi_ap_backhaul_network_key =
+ os_memdup(cfg->multi_ap_backhaul_network_key,
+ cfg->multi_ap_backhaul_network_key_len);
+ if (reg->multi_ap_backhaul_network_key)
+ reg->multi_ap_backhaul_network_key_len =
+ cfg->multi_ap_backhaul_network_key_len;
+ }
+
if (wps_set_ie(reg)) {
wps_registrar_deinit(reg);
return NULL;
@@ -704,6 +751,8 @@
eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
wps_registrar_flush(reg);
wpabuf_clear_free(reg->extra_cred);
+ bin_clear_free(reg->multi_ap_backhaul_network_key,
+ reg->multi_ap_backhaul_network_key_len);
os_free(reg);
}
@@ -1281,7 +1330,7 @@
wps_build_sel_reg_config_methods(reg, beacon) ||
wps_build_sel_pbc_reg_uuid_e(reg, beacon) ||
(reg->dualband && wps_build_rf_bands(®->wps->dev, beacon, 0)) ||
- wps_build_wfa_ext(beacon, 0, auth_macs, count) ||
+ wps_build_wfa_ext(beacon, 0, auth_macs, count, 0) ||
wps_build_vendor_ext(®->wps->dev, beacon)) {
wpabuf_free(beacon);
wpabuf_free(probe);
@@ -1311,7 +1360,7 @@
wps_build_device_attrs(®->wps->dev, probe) ||
wps_build_probe_config_methods(reg, probe) ||
(reg->dualband && wps_build_rf_bands(®->wps->dev, probe, 0)) ||
- wps_build_wfa_ext(probe, 0, auth_macs, count) ||
+ wps_build_wfa_ext(probe, 0, auth_macs, count, 0) ||
wps_build_vendor_ext(®->wps->dev, probe)) {
wpabuf_free(beacon);
wpabuf_free(probe);
@@ -1592,6 +1641,7 @@
int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
{
struct wpabuf *cred;
+ struct wps_registrar *reg = wps->wps->registrar;
if (wps->wps->registrar->skip_cred_build)
goto skip_cred_build;
@@ -1603,6 +1653,29 @@
}
os_memset(&wps->cred, 0, sizeof(wps->cred));
+ if (wps->peer_dev.multi_ap_ext == MULTI_AP_BACKHAUL_STA &&
+ reg->multi_ap_backhaul_ssid_len) {
+ wpa_printf(MSG_DEBUG, "WPS: Use backhaul STA credentials");
+ os_memcpy(wps->cred.ssid, reg->multi_ap_backhaul_ssid,
+ reg->multi_ap_backhaul_ssid_len);
+ wps->cred.ssid_len = reg->multi_ap_backhaul_ssid_len;
+ /* Backhaul is always WPA2PSK */
+ wps->cred.auth_type = WPS_AUTH_WPA2PSK;
+ wps->cred.encr_type = WPS_ENCR_AES;
+ /* Set MAC address in the Credential to be the Enrollee's MAC
+ * address
+ */
+ os_memcpy(wps->cred.mac_addr, wps->mac_addr_e, ETH_ALEN);
+ if (reg->multi_ap_backhaul_network_key) {
+ os_memcpy(wps->cred.key,
+ reg->multi_ap_backhaul_network_key,
+ reg->multi_ap_backhaul_network_key_len);
+ wps->cred.key_len =
+ reg->multi_ap_backhaul_network_key_len;
+ }
+ goto use_provided;
+ }
+
os_memcpy(wps->cred.ssid, wps->wps->ssid, wps->wps->ssid_len);
wps->cred.ssid_len = wps->wps->ssid_len;
@@ -1845,7 +1918,7 @@
wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
wps_build_dev_password_id(msg, wps->dev_pw_id) ||
wps_build_os_version(&wps->wps->dev, msg) ||
- wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
wpabuf_free(msg);
return NULL;
}
@@ -1913,7 +1986,7 @@
wps_build_assoc_state(wps, msg) ||
wps_build_config_error(msg, err) ||
wps_build_os_version(&wps->wps->dev, msg) ||
- wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
wpabuf_free(msg);
return NULL;
}
@@ -1949,7 +2022,7 @@
wps_build_r_snonce1(wps, plain) ||
wps_build_key_wrap_auth(wps, plain) ||
wps_build_encr_settings(wps, msg, plain) ||
- wps_build_wfa_ext(msg, 0, NULL, 0) ||
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0) ||
wps_build_authenticator(wps, msg)) {
wpabuf_clear_free(plain);
wpabuf_free(msg);
@@ -1984,7 +2057,7 @@
wps_build_r_snonce2(wps, plain) ||
wps_build_key_wrap_auth(wps, plain) ||
wps_build_encr_settings(wps, msg, plain) ||
- wps_build_wfa_ext(msg, 0, NULL, 0) ||
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0) ||
wps_build_authenticator(wps, msg)) {
wpabuf_clear_free(plain);
wpabuf_free(msg);
@@ -2021,7 +2094,7 @@
(!wps->wps->ap && !wps->er && wps_build_ap_settings(wps, plain)) ||
wps_build_key_wrap_auth(wps, plain) ||
wps_build_encr_settings(wps, msg, plain) ||
- wps_build_wfa_ext(msg, 0, NULL, 0) ||
+ wps_build_wfa_ext(msg, 0, NULL, 0, 0) ||
wps_build_authenticator(wps, msg)) {
wpabuf_clear_free(plain);
wpabuf_clear_free(msg);
@@ -2705,6 +2778,7 @@
wps->use_psk_key = 1;
}
#endif /* WPS_WORKAROUNDS */
+ wps_process_vendor_ext_m1(&wps->peer_dev, attr->multi_ap_ext);
wps->state = SEND_M2;
return WPS_CONTINUE;
diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c
index 0c458c6..ca893a4 100644
--- a/src/wps/wps_upnp.c
+++ b/src/wps/wps_upnp.c
@@ -599,7 +599,7 @@
wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE);
wpabuf_put_be16(msg, WPS_NONCE_LEN);
wpabuf_put(msg, WPS_NONCE_LEN);
- if (wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ if (wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
wpabuf_free(msg);
return NULL;
}
diff --git a/src/wps/wps_validate.c b/src/wps/wps_validate.c
index 267b565..5c12bce 100644
--- a/src/wps/wps_validate.c
+++ b/src/wps/wps_validate.c
@@ -1057,7 +1057,7 @@
}
-static int wps_validate_credential(const u8 *cred[], size_t len[], size_t num,
+static int wps_validate_credential(const u8 *cred[], u16 len[], size_t num,
int mandatory)
{
size_t i;
diff --git a/tests/test-eapol.c b/tests/test-eapol.c
new file mode 100644
index 0000000..0a0844b
--- /dev/null
+++ b/tests/test-eapol.c
@@ -0,0 +1,606 @@
+/*
+ * Testing tool for EAPOL-Key Supplicant/Authenticator routines
+ * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
+ *
+ * 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/eloop.h"
+#include "rsn_supp/wpa.h"
+#include "ap/wpa_auth.h"
+
+
+struct wpa {
+ enum { AUTH, SUPP } test_peer;
+ enum { READ, WRITE } test_oper;
+ FILE *f;
+ int wpa1;
+
+ u8 auth_addr[ETH_ALEN];
+ u8 supp_addr[ETH_ALEN];
+ u8 psk[PMK_LEN];
+
+ /* from authenticator */
+ u8 *auth_eapol;
+ size_t auth_eapol_len;
+
+ /* from supplicant */
+ u8 *supp_eapol;
+ size_t supp_eapol_len;
+
+ struct wpa_sm *supp;
+ struct wpa_authenticator *auth_group;
+ struct wpa_state_machine *auth;
+
+ u8 supp_ie[80];
+ size_t supp_ie_len;
+
+ int key_request_done;
+ int key_request_done1;
+ int auth_sent;
+};
+
+
+const struct wpa_driver_ops *const wpa_drivers[] = { NULL };
+
+
+static int auth_read_msg(struct wpa *wpa);
+static void supp_eapol_key_request(void *eloop_data, void *user_ctx);
+
+
+static void usage(void) {
+ wpa_printf(MSG_INFO,
+ "usage: test-eapol <auth/supp> <read/write> <file>");
+ exit(-1);
+}
+
+
+static void write_msg(FILE *f, const u8 *msg, size_t msg_len)
+{
+ u8 len[2];
+
+ wpa_printf(MSG_DEBUG, "TEST: Write message to file (msg_len=%u)",
+ (unsigned int) msg_len);
+ WPA_PUT_BE16(len, msg_len);
+ fwrite(len, 2, 1, f);
+ fwrite(msg, msg_len, 1, f);
+}
+
+
+static u8 * read_msg(FILE *f, size_t *ret_len)
+{
+ u8 len[2];
+ u16 msg_len;
+ u8 *msg;
+
+ if (fread(len, 2, 1, f) != 1) {
+ wpa_printf(MSG_ERROR, "TEST-ERROR: Could not read msg len");
+ eloop_terminate();
+ return NULL;
+ }
+ msg_len = WPA_GET_BE16(len);
+
+ msg = os_malloc(msg_len);
+ if (!msg)
+ return NULL;
+ if (msg_len > 0 && fread(msg, msg_len, 1, f) != 1) {
+ wpa_printf(MSG_ERROR, "TEST-ERROR: Truncated msg (msg_len=%u)",
+ msg_len);
+ os_free(msg);
+ eloop_terminate();
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG, "TEST: Read message from file", msg, msg_len);
+
+ *ret_len = msg_len;
+ return msg;
+}
+
+
+static int supp_get_bssid(void *ctx, u8 *bssid)
+{
+ struct wpa *wpa = ctx;
+ wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
+ os_memcpy(bssid, wpa->auth_addr, ETH_ALEN);
+ return 0;
+}
+
+
+static void supp_set_state(void *ctx, enum wpa_states state)
+{
+ wpa_printf(MSG_DEBUG, "SUPP: %s(state=%d)", __func__, state);
+}
+
+
+static void auth_eapol_rx(void *eloop_data, void *user_ctx)
+{
+ struct wpa *wpa = eloop_data;
+
+ wpa_printf(MSG_DEBUG, "AUTH: RX EAPOL frame");
+ wpa->auth_sent = 0;
+ wpa_receive(wpa->auth_group, wpa->auth, wpa->supp_eapol,
+ wpa->supp_eapol_len);
+ if (!wpa->auth_sent && wpa->test_peer == SUPP &&
+ wpa->test_oper == READ) {
+ /* Speed up process by not going through retransmit timeout */
+ wpa_printf(MSG_DEBUG,
+ "AUTH: No response was sent - process next message");
+ auth_read_msg(wpa);
+ }
+ if (wpa->wpa1 && wpa->key_request_done && !wpa->key_request_done1) {
+ wpa->key_request_done1 = 1;
+ eloop_register_timeout(0, 0, supp_eapol_key_request,
+ wpa, NULL);
+ }
+
+}
+
+
+static void supp_eapol_rx(void *eloop_data, void *user_ctx)
+{
+ struct wpa *wpa = eloop_data;
+
+ wpa_printf(MSG_DEBUG, "SUPP: RX EAPOL frame");
+ wpa_sm_rx_eapol(wpa->supp, wpa->auth_addr, wpa->auth_eapol,
+ wpa->auth_eapol_len);
+}
+
+
+static int supp_read_msg(struct wpa *wpa)
+{
+ os_free(wpa->auth_eapol);
+ wpa->auth_eapol = read_msg(wpa->f, &wpa->auth_eapol_len);
+ if (!wpa->auth_eapol)
+ return -1;
+ eloop_register_timeout(0, 0, supp_eapol_rx, wpa, NULL);
+ return 0;
+}
+
+
+static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
+ size_t len)
+{
+ struct wpa *wpa = ctx;
+
+ wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x "
+ "len=%lu)",
+ __func__, MAC2STR(dest), proto, (unsigned long) len);
+
+ if (wpa->test_peer == SUPP && wpa->test_oper == WRITE)
+ write_msg(wpa->f, buf, len);
+
+ if (wpa->test_peer == AUTH && wpa->test_oper == READ)
+ return supp_read_msg(wpa);
+
+ os_free(wpa->supp_eapol);
+ wpa->supp_eapol = os_malloc(len);
+ if (!wpa->supp_eapol)
+ return -1;
+ os_memcpy(wpa->supp_eapol, buf, len);
+ wpa->supp_eapol_len = len;
+ eloop_register_timeout(0, 0, auth_eapol_rx, wpa, NULL);
+
+ return 0;
+}
+
+
+static u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data,
+ u16 data_len, size_t *msg_len, void **data_pos)
+{
+ struct ieee802_1x_hdr *hdr;
+
+ wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)",
+ __func__, type, data_len);
+
+ *msg_len = sizeof(*hdr) + data_len;
+ hdr = os_malloc(*msg_len);
+ if (hdr == NULL)
+ return NULL;
+
+ hdr->version = 2;
+ hdr->type = type;
+ hdr->length = host_to_be16(data_len);
+
+ if (data)
+ os_memcpy(hdr + 1, data, data_len);
+ else
+ os_memset(hdr + 1, 0, data_len);
+
+ if (data_pos)
+ *data_pos = hdr + 1;
+
+ return (u8 *) hdr;
+}
+
+
+static int supp_get_beacon_ie(void *ctx)
+{
+ struct wpa *wpa = ctx;
+ const u8 *ie;
+ size_t ielen;
+
+ wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
+
+ ie = wpa_auth_get_wpa_ie(wpa->auth_group, &ielen);
+ if (ie == NULL || ielen < 1)
+ return -1;
+ if (ie[0] == WLAN_EID_RSN)
+ return wpa_sm_set_ap_rsn_ie(wpa->supp, ie, 2 + ie[1]);
+ return wpa_sm_set_ap_wpa_ie(wpa->supp, ie, 2 + ie[1]);
+}
+
+
+static int supp_set_key(void *ctx, enum wpa_alg alg,
+ const u8 *addr, int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d "
+ "set_tx=%d)",
+ __func__, alg, MAC2STR(addr), key_idx, set_tx);
+ wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len);
+ wpa_hexdump(MSG_DEBUG, "SUPP: set_key - key", key, key_len);
+ return 0;
+}
+
+
+static int supp_mlme_setprotection(void *ctx, const u8 *addr,
+ int protection_type, int key_type)
+{
+ wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d "
+ "key_type=%d)",
+ __func__, MAC2STR(addr), protection_type, key_type);
+ return 0;
+}
+
+
+static void supp_cancel_auth_timeout(void *ctx)
+{
+ wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
+}
+
+
+static void * supp_get_network_ctx(void *ctx)
+{
+ return (void *) 1;
+}
+
+
+static void supp_deauthenticate(void *ctx, int reason_code)
+{
+ wpa_printf(MSG_DEBUG, "SUPP: %s(%d)", __func__, reason_code);
+}
+
+
+static enum wpa_states supp_get_state(void *ctx)
+{
+ return WPA_COMPLETED;
+}
+
+
+static int supp_init(struct wpa *wpa)
+{
+ struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx));
+
+ if (!ctx)
+ return -1;
+
+ ctx->ctx = wpa;
+ ctx->msg_ctx = wpa;
+ ctx->set_state = supp_set_state;
+ ctx->get_bssid = supp_get_bssid;
+ ctx->ether_send = supp_ether_send;
+ ctx->get_beacon_ie = supp_get_beacon_ie;
+ ctx->alloc_eapol = supp_alloc_eapol;
+ ctx->set_key = supp_set_key;
+ ctx->mlme_setprotection = supp_mlme_setprotection;
+ ctx->cancel_auth_timeout = supp_cancel_auth_timeout;
+ ctx->get_network_ctx = supp_get_network_ctx;
+ ctx->deauthenticate = supp_deauthenticate;
+ ctx->get_state = supp_get_state;
+ wpa->supp = wpa_sm_init(ctx);
+ if (!wpa->supp) {
+ wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
+ return -1;
+ }
+
+ wpa_sm_set_own_addr(wpa->supp, wpa->supp_addr);
+ if (wpa->wpa1) {
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_RSN_ENABLED, 0);
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_PROTO, WPA_PROTO_WPA);
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_PAIRWISE,
+ WPA_CIPHER_TKIP);
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_GROUP, WPA_CIPHER_TKIP);
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_KEY_MGMT,
+ WPA_KEY_MGMT_PSK);
+ } else {
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_RSN_ENABLED, 1);
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN);
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_PAIRWISE,
+ WPA_CIPHER_CCMP);
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP);
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_KEY_MGMT,
+ WPA_KEY_MGMT_PSK);
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_MFP,
+ MGMT_FRAME_PROTECTION_OPTIONAL);
+ }
+ wpa_sm_set_pmk(wpa->supp, wpa->psk, PMK_LEN, NULL, NULL);
+
+ wpa->supp_ie_len = sizeof(wpa->supp_ie);
+ if (wpa_sm_set_assoc_wpa_ie_default(wpa->supp, wpa->supp_ie,
+ &wpa->supp_ie_len) < 0) {
+ wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()"
+ " failed");
+ return -1;
+ }
+
+ wpa_sm_notify_assoc(wpa->supp, wpa->auth_addr);
+
+ return 0;
+}
+
+
+static void auth_logger(void *ctx, const u8 *addr, logger_level level,
+ const char *txt)
+{
+ if (addr)
+ wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s",
+ MAC2STR(addr), txt);
+ else
+ wpa_printf(MSG_DEBUG, "AUTH: %s", txt);
+}
+
+
+static int auth_read_msg(struct wpa *wpa)
+{
+ os_free(wpa->supp_eapol);
+ wpa->supp_eapol = read_msg(wpa->f, &wpa->supp_eapol_len);
+ if (!wpa->supp_eapol)
+ return -1;
+ eloop_register_timeout(0, 0, auth_eapol_rx, wpa, NULL);
+ return 0;
+}
+
+
+static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data,
+ size_t data_len, int encrypt)
+{
+ struct wpa *wpa = ctx;
+
+ wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu "
+ "encrypt=%d)",
+ __func__, MAC2STR(addr), (unsigned long) data_len, encrypt);
+ wpa->auth_sent = 1;
+
+ if (wpa->test_peer == AUTH && wpa->test_oper == WRITE)
+ write_msg(wpa->f, data, data_len);
+
+ if (wpa->test_peer == SUPP && wpa->test_oper == READ)
+ return auth_read_msg(wpa);
+
+ os_free(wpa->auth_eapol);
+ wpa->auth_eapol = os_malloc(data_len);
+ if (!wpa->auth_eapol)
+ return -1;
+ os_memcpy(wpa->auth_eapol, data, data_len);
+ wpa->auth_eapol_len = data_len;
+ eloop_register_timeout(0, 0, supp_eapol_rx, wpa, NULL);
+
+ return 0;
+}
+
+
+static const u8 * auth_get_psk(void *ctx, const u8 *addr,
+ const u8 *p2p_dev_addr, const u8 *prev_psk,
+ size_t *psk_len)
+{
+ struct wpa *wpa = ctx;
+
+ wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
+ __func__, MAC2STR(addr), prev_psk);
+ if (psk_len)
+ *psk_len = PMK_LEN;
+ if (prev_psk)
+ return NULL;
+ return wpa->psk;
+}
+
+
+static void supp_eapol_key_request(void *eloop_data, void *user_ctx)
+{
+ struct wpa *wpa = eloop_data;
+
+ wpa_printf(MSG_DEBUG, "SUPP: EAPOL-Key Request trigger");
+ if (wpa->test_peer == SUPP && wpa->test_oper == READ) {
+ if (!eloop_is_timeout_registered(auth_eapol_rx, wpa, NULL))
+ auth_read_msg(wpa);
+ } else {
+ wpa_sm_key_request(wpa->supp, 0, 1);
+ }
+}
+
+
+static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
+ const u8 *addr, int idx, u8 *key,
+ size_t key_len)
+{
+ struct wpa *wpa = ctx;
+
+ wpa_printf(MSG_DEBUG, "AUTH: %s (vlan_id=%d alg=%d idx=%d key_len=%d)",
+ __func__, vlan_id, alg, idx, (int) key_len);
+ if (addr)
+ wpa_printf(MSG_DEBUG, "AUTH: addr=" MACSTR, MAC2STR(addr));
+
+ if (alg != WPA_ALG_NONE && idx == 0 && key_len > 0 &&
+ !wpa->key_request_done) {
+ wpa_printf(MSG_DEBUG, "Test EAPOL-Key Request");
+ wpa->key_request_done = 1;
+ if (!wpa->wpa1)
+ eloop_register_timeout(0, 0, supp_eapol_key_request,
+ wpa, NULL);
+ }
+
+ return 0;
+}
+
+
+static int auth_init_group(struct wpa *wpa)
+{
+ struct wpa_auth_config conf;
+ struct wpa_auth_callbacks cb;
+
+ wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
+
+ os_memset(&conf, 0, sizeof(conf));
+ if (wpa->wpa1) {
+ conf.wpa = 1;
+ conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+ conf.wpa_pairwise = WPA_CIPHER_TKIP;
+ conf.wpa_group = WPA_CIPHER_TKIP;
+ } else {
+ conf.wpa = 2;
+ conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+ conf.wpa_pairwise = WPA_CIPHER_CCMP;
+ conf.rsn_pairwise = WPA_CIPHER_CCMP;
+ conf.wpa_group = WPA_CIPHER_CCMP;
+ conf.ieee80211w = 2;
+ conf.group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC;
+ }
+ conf.eapol_version = 2;
+ conf.wpa_group_update_count = 4;
+ conf.wpa_pairwise_update_count = 4;
+
+ os_memset(&cb, 0, sizeof(cb));
+ cb.logger = auth_logger;
+ cb.send_eapol = auth_send_eapol;
+ cb.get_psk = auth_get_psk;
+ cb.set_key = auth_set_key,
+
+ wpa->auth_group = wpa_init(wpa->auth_addr, &conf, &cb, wpa);
+ if (!wpa->auth_group) {
+ wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int auth_init(struct wpa *wpa)
+{
+ if (wpa->test_peer == AUTH && wpa->test_oper == READ)
+ return supp_read_msg(wpa);
+
+ wpa->auth = wpa_auth_sta_init(wpa->auth_group, wpa->supp_addr, NULL);
+ if (!wpa->auth) {
+ wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed");
+ return -1;
+ }
+
+ if (wpa_validate_wpa_ie(wpa->auth_group, wpa->auth, wpa->supp_ie,
+ wpa->supp_ie_len, NULL, 0, NULL, 0) !=
+ WPA_IE_OK) {
+ wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
+ return -1;
+ }
+
+ wpa_auth_sm_event(wpa->auth, WPA_ASSOC);
+
+ wpa_auth_sta_associated(wpa->auth_group, wpa->auth);
+
+ return 0;
+}
+
+
+static void deinit(struct wpa *wpa)
+{
+ wpa_auth_sta_deinit(wpa->auth);
+ wpa_sm_deinit(wpa->supp);
+ wpa_deinit(wpa->auth_group);
+ os_free(wpa->auth_eapol);
+ wpa->auth_eapol = NULL;
+ os_free(wpa->supp_eapol);
+ wpa->supp_eapol = NULL;
+}
+
+
+int main(int argc, char *argv[])
+{
+ const char *file;
+ int ret;
+ struct wpa wpa;
+
+ if (os_program_init())
+ return -1;
+
+ wpa_debug_level = 0;
+ wpa_debug_show_keys = 1;
+ os_memset(&wpa, 0, sizeof(wpa));
+
+ if (argc < 4)
+ usage();
+
+ if (os_strcmp(argv[1], "auth") == 0) {
+ wpa.test_peer = AUTH;
+ } else if (os_strcmp(argv[1], "auth1") == 0) {
+ wpa.test_peer = AUTH;
+ wpa.wpa1 = 1;
+ } else if (os_strcmp(argv[1], "supp") == 0) {
+ wpa.test_peer = SUPP;
+ } else if (os_strcmp(argv[1], "supp1") == 0) {
+ wpa.test_peer = SUPP;
+ wpa.wpa1 = 1;
+ } else {
+ usage();
+ }
+
+ if (os_strcmp(argv[2], "read") == 0)
+ wpa.test_oper = READ;
+ else if (os_strcmp(argv[2], "write") == 0)
+ wpa.test_oper = WRITE;
+ else
+ usage();
+
+ file = argv[3];
+
+ wpa.f = fopen(file, wpa.test_oper == READ ? "r" : "w");
+ if (!wpa.f)
+ return -1;
+
+ os_memset(wpa.auth_addr, 0x12, ETH_ALEN);
+ os_memset(wpa.supp_addr, 0x32, ETH_ALEN);
+ os_memset(wpa.psk, 0x44, PMK_LEN);
+
+ if (eloop_init()) {
+ wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+ goto fail;
+ }
+
+ if (auth_init_group(&wpa) < 0)
+ goto fail;
+
+ if (supp_init(&wpa) < 0)
+ goto fail;
+
+ if (auth_init(&wpa) < 0)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "Starting eloop");
+ eloop_run();
+ wpa_printf(MSG_DEBUG, "eloop done");
+
+ ret = 0;
+fail:
+ deinit(&wpa);
+ fclose(wpa.f);
+
+ eloop_destroy();
+
+ os_program_deinit();
+
+ return ret;
+}
diff --git a/tests/test-json.c b/tests/test-json.c
new file mode 100644
index 0000000..c7cb460
--- /dev/null
+++ b/tests/test-json.c
@@ -0,0 +1,44 @@
+/*
+ * JSON parser - test program
+ * Copyright (c) 2019, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/os.h"
+#include "utils/json.h"
+
+
+int main(int argc, char *argv[])
+{
+ char *buf;
+ size_t len;
+ struct json_token *root;
+
+ if (argc < 2)
+ return -1;
+
+ buf = os_readfile(argv[1], &len);
+ if (!buf)
+ return -1;
+
+ root = json_parse(buf, len);
+ os_free(buf);
+ if (root) {
+ size_t buflen = 10000;
+
+ buf = os_zalloc(buflen);
+ if (buf) {
+ json_print_tree(root, buf, buflen);
+ printf("%s\n", buf);
+ os_free(buf);
+ }
+ json_free(root);
+ } else {
+ printf("JSON parsing failed\n");
+ }
+
+ return 0;
+}
diff --git a/tests/test-tls.c b/tests/test-tls.c
new file mode 100644
index 0000000..9941fb5
--- /dev/null
+++ b/tests/test-tls.c
@@ -0,0 +1,243 @@
+/*
+ * Testing tool for TLSv1 client/server routines
+ * Copyright (c) 2019, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/tls.h"
+
+
+static void usage(void) {
+ wpa_printf(MSG_INFO,
+ "usage: test-tls <server/client> <read/write> <file>");
+ exit(-1);
+}
+
+
+static void write_msg(FILE *f, struct wpabuf *msg)
+{
+ u8 len[2];
+
+ wpa_printf(MSG_DEBUG, "TEST: Write message to file (msg_len=%u)",
+ (unsigned int) wpabuf_len(msg));
+ WPA_PUT_BE16(len, wpabuf_len(msg));
+ fwrite(len, 2, 1, f);
+ fwrite(wpabuf_head(msg), wpabuf_len(msg), 1, f);
+}
+
+
+static struct wpabuf * read_msg(FILE *f)
+{
+ u8 len[2];
+ u16 msg_len;
+ struct wpabuf *msg;
+
+ if (fread(len, 2, 1, f) != 1) {
+ wpa_printf(MSG_ERROR, "TEST-ERROR: Could not read msg len");
+ return NULL;
+ }
+ msg_len = WPA_GET_BE16(len);
+
+ msg = wpabuf_alloc(msg_len);
+ if (!msg)
+ return NULL;
+ if (msg_len > 0 &&
+ fread(wpabuf_put(msg, msg_len), msg_len, 1, f) != 1) {
+ wpa_printf(MSG_ERROR, "TEST-ERROR: Truncated msg (msg_len=%u)",
+ msg_len);
+ wpabuf_free(msg);
+ return NULL;
+ }
+ wpa_hexdump_buf(MSG_DEBUG, "TEST: Read message from file", msg);
+
+ return msg;
+}
+
+
+int main(int argc, char *argv[])
+{
+ struct tls_config conf;
+ void *tls_server, *tls_client;
+ struct tls_connection_params params;
+ struct tls_connection *conn_server = NULL, *conn_client = NULL;
+ int ret = -1;
+ struct wpabuf *in = NULL, *out = NULL, *appl;
+ enum { SERVER, CLIENT } test_peer;
+ enum { READ, WRITE } test_oper;
+ const char *file;
+ FILE *f;
+
+ wpa_debug_level = 0;
+ wpa_debug_show_keys = 1;
+
+ if (argc < 4)
+ usage();
+
+ if (os_strcmp(argv[1], "server") == 0)
+ test_peer = SERVER;
+ else if (os_strcmp(argv[1], "client") == 0)
+ test_peer = CLIENT;
+ else
+ usage();
+
+ if (os_strcmp(argv[2], "read") == 0)
+ test_oper = READ;
+ else if (os_strcmp(argv[2], "write") == 0)
+ test_oper = WRITE;
+ else
+ usage();
+
+ file = argv[3];
+
+ f = fopen(file, test_oper == READ ? "r" : "w");
+ if (!f)
+ return -1;
+
+ os_memset(&conf, 0, sizeof(conf));
+ tls_server = tls_init(&conf);
+ tls_client = tls_init(&conf);
+ if (!tls_server || !tls_client)
+ goto fail;
+
+ os_memset(¶ms, 0, sizeof(params));
+ params.ca_cert = "hwsim/auth_serv/ca.pem";
+ params.client_cert = "hwsim/auth_serv/server.pem";
+ params.private_key = "hwsim/auth_serv/server.key";
+ params.dh_file = "hwsim/auth_serv/dh.conf";
+
+ if (tls_global_set_params(tls_server, ¶ms)) {
+ wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
+ goto fail;
+ }
+
+ conn_server = tls_connection_init(tls_server);
+ conn_client = tls_connection_init(tls_client);
+ if (!conn_server || !conn_client)
+ goto fail;
+
+ in = NULL;
+ for (;;) {
+ appl = NULL;
+ if (test_peer == CLIENT && test_oper == READ)
+ out = read_msg(f);
+ else
+ out = tls_connection_handshake(tls_client, conn_client,
+ in, &appl);
+ wpabuf_free(in);
+ in = NULL;
+ if (!out)
+ goto fail;
+ if (test_peer == CLIENT && test_oper == WRITE &&
+ wpabuf_len(out) > 0)
+ write_msg(f, out);
+ if (!(test_peer == CLIENT && test_oper == READ) &&
+ tls_connection_get_failed(tls_client, conn_client)) {
+ wpa_printf(MSG_ERROR, "TLS handshake failed");
+ goto fail;
+ }
+ if (((test_peer == CLIENT && test_oper == READ) ||
+ tls_connection_established(tls_client, conn_client)) &&
+ ((test_peer == SERVER && test_oper == READ) ||
+ tls_connection_established(tls_server, conn_server)))
+ break;
+
+ appl = NULL;
+ if (test_peer == SERVER && test_oper == READ)
+ in = read_msg(f);
+ else
+ in = tls_connection_server_handshake(tls_server,
+ conn_server,
+ out, &appl);
+ wpabuf_free(out);
+ out = NULL;
+ if (!in)
+ goto fail;
+ if (test_peer == SERVER && test_oper == WRITE)
+ write_msg(f, in);
+ if (!(test_peer == SERVER && test_oper == READ) &&
+ tls_connection_get_failed(tls_server, conn_server)) {
+ wpa_printf(MSG_ERROR, "TLS handshake failed");
+ goto fail;
+ }
+ if (((test_peer == CLIENT && test_oper == READ) ||
+ tls_connection_established(tls_client, conn_client)) &&
+ ((test_peer == SERVER && test_oper == READ) ||
+ tls_connection_established(tls_server, conn_server)))
+ break;
+ }
+
+ wpabuf_free(in);
+ in = wpabuf_alloc(100);
+ if (!in)
+ goto fail;
+ wpabuf_put_str(in, "PING");
+ wpabuf_free(out);
+ if (test_peer == CLIENT && test_oper == READ)
+ out = read_msg(f);
+ else
+ out = tls_connection_encrypt(tls_client, conn_client, in);
+ wpabuf_free(in);
+ in = NULL;
+ if (!out)
+ goto fail;
+ if (test_peer == CLIENT && test_oper == WRITE)
+ write_msg(f, out);
+
+ if (!(test_peer == SERVER && test_oper == READ)) {
+ in = tls_connection_decrypt(tls_server, conn_server, out);
+ wpabuf_free(out);
+ out = NULL;
+ if (!in)
+ goto fail;
+ wpa_hexdump_buf(MSG_DEBUG, "Server decrypted ApplData", in);
+ }
+
+ wpabuf_free(in);
+ in = wpabuf_alloc(100);
+ if (!in)
+ goto fail;
+ wpabuf_put_str(in, "PONG");
+ wpabuf_free(out);
+ if (test_peer == SERVER && test_oper == READ)
+ out = read_msg(f);
+ else
+ out = tls_connection_encrypt(tls_server, conn_server, in);
+ wpabuf_free(in);
+ in = NULL;
+ if (!out)
+ goto fail;
+ if (test_peer == SERVER && test_oper == WRITE)
+ write_msg(f, out);
+
+ if (!(test_peer == CLIENT && test_oper == READ)) {
+ in = tls_connection_decrypt(tls_client, conn_client, out);
+ wpabuf_free(out);
+ out = NULL;
+ if (!in)
+ goto fail;
+ wpa_hexdump_buf(MSG_DEBUG, "Client decrypted ApplData", in);
+ }
+
+ ret = 0;
+fail:
+ if (tls_server) {
+ if (conn_server)
+ tls_connection_deinit(tls_server, conn_server);
+ tls_deinit(tls_server);
+ }
+ if (tls_client) {
+ if (conn_client)
+ tls_connection_deinit(tls_server, conn_client);
+ tls_deinit(tls_client);
+ }
+ wpabuf_free(in);
+ wpabuf_free(out);
+ fclose(f);
+
+ return ret;
+}
diff --git a/wpa_supplicant/.gitignore b/wpa_supplicant/.gitignore
index 0e3ad1b..30e3fd4 100644
--- a/wpa_supplicant/.gitignore
+++ b/wpa_supplicant/.gitignore
@@ -1 +1,2 @@
*.service
+.settings
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 51ec414..8bcd7ef 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -12,6 +12,10 @@
CONFIG_DRIVER_$(BOARD_WPA_SUPPLICANT_DRIVER) := y
endif
+ifeq ($(BOARD_WLAN_DEVICE), qcwcn)
+ CONFIG_DRIVER_NL80211_QCA=y
+endif
+
include $(LOCAL_PATH)/android.config
# To ignore possible wrong network configurations
@@ -234,16 +238,18 @@
NEED_SHA384=y
endif
+ifdef CONFIG_OCV
+L_CFLAGS += -DCONFIG_OCV
+OBJS += src/common/ocv.c
+CONFIG_IEEE80211W=y
+endif
+
ifdef CONFIG_IEEE80211W
L_CFLAGS += -DCONFIG_IEEE80211W
NEED_SHA256=y
NEED_AES_OMAC1=y
endif
-ifdef CONFIG_IEEE80211R_AP
-CONFIG_IEEE80211R=y
-endif
-
ifdef CONFIG_IEEE80211R
L_CFLAGS += -DCONFIG_IEEE80211R
OBJS += src/rsn_supp/wpa_ft.c
@@ -284,6 +290,9 @@
NEED_JSON=y
NEED_GAS_SERVER=y
NEED_BASE64=y
+ifdef CONFIG_DPP2
+L_CFLAGS += -DCONFIG_DPP2
+endif
endif
ifdef CONFIG_OWE
@@ -711,6 +720,7 @@
OBJS += src/eap_peer/eap_pwd.c src/eap_common/eap_pwd_common.c
CONFIG_IEEE8021X_EAPOL=y
NEED_SHA256=y
+NEED_ECC=y
endif
ifdef CONFIG_EAP_EKE
@@ -955,10 +965,6 @@
OBJS += src/ap/wpa_auth.c
OBJS += src/ap/wpa_auth_ie.c
OBJS += src/ap/pmksa_cache_auth.c
-ifdef CONFIG_IEEE80211R_AP
-L_CFLAGS += -DCONFIG_IEEE80211R_AP
-OBJS += src/ap/wpa_auth_ft.c
-endif
endif
ifdef CONFIG_ACS
@@ -1066,22 +1072,33 @@
endif
ifeq ($(CONFIG_TLS), gnutls)
+ifndef CONFIG_CRYPTO
+# default to libgcrypt
+CONFIG_CRYPTO=gnutls
+endif
ifdef TLS_FUNCS
OBJS += src/crypto/tls_gnutls.c
LIBS += -lgnutls -lgpg-error
endif
-OBJS += src/crypto/crypto_gnutls.c
-OBJS_p += src/crypto/crypto_gnutls.c
+OBJS += src/crypto/crypto_$(CONFIG_CRYPTO).c
+OBJS_p += src/crypto/crypto_$(CONFIG_CRYPTO).c
ifdef NEED_FIPS186_2_PRF
OBJS += src/crypto/fips_prf_internal.c
OBJS += src/crypto/sha1-internal.c
endif
+ifeq ($(CONFIG_CRYPTO), gnutls)
LIBS += -lgcrypt
LIBS_p += -lgcrypt
-CONFIG_INTERNAL_SHA256=y
CONFIG_INTERNAL_RC4=y
CONFIG_INTERNAL_DH_GROUP5=y
endif
+ifeq ($(CONFIG_CRYPTO), nettle)
+LIBS += -lnettle -lgmp
+LIBS_p += -lnettle -lgmp
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+endif
ifeq ($(CONFIG_TLS), internal)
ifndef CONFIG_CRYPTO
@@ -1268,8 +1285,10 @@
SHA1OBJS =
ifdef NEED_SHA1
ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
SHA1OBJS += src/crypto/sha1.c
endif
+endif
SHA1OBJS += src/crypto/sha1-prf.c
ifdef CONFIG_INTERNAL_SHA1
SHA1OBJS += src/crypto/sha1-internal.c
@@ -1295,9 +1314,11 @@
MD5OBJS =
ifndef CONFIG_FIPS
ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
MD5OBJS += src/crypto/md5.c
endif
endif
+endif
ifdef NEED_MD5
ifdef CONFIG_INTERNAL_MD5
MD5OBJS += src/crypto/md5-internal.c
@@ -1335,8 +1356,10 @@
ifdef NEED_SHA256
L_CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
SHA256OBJS += src/crypto/sha256.c
endif
+endif
SHA256OBJS += src/crypto/sha256-prf.c
ifdef CONFIG_INTERNAL_SHA256
SHA256OBJS += src/crypto/sha256-internal.c
@@ -1369,15 +1392,19 @@
ifdef NEED_SHA384
L_CFLAGS += -DCONFIG_SHA384
ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
OBJS += src/crypto/sha384.c
endif
+endif
OBJS += src/crypto/sha384-prf.c
endif
ifdef NEED_SHA512
L_CFLAGS += -DCONFIG_SHA512
ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), gnutls)
OBJS += src/crypto/sha512.c
endif
+endif
OBJS += src/crypto/sha512-prf.c
endif
@@ -1430,44 +1457,25 @@
OBJS += ctrl_iface.c ctrl_iface_$(CONFIG_CTRL_IFACE).c
endif
-ifdef CONFIG_CTRL_IFACE_DBUS
-DBUS=y
-DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS -DDBUS_API_SUBJECT_TO_CHANGE
-DBUS_OBJS += dbus/dbus_old.c dbus/dbus_old_handlers.c
-ifdef CONFIG_WPS
-DBUS_OBJS += dbus/dbus_old_handlers_wps.c
-endif
-DBUS_OBJS += dbus/dbus_dict_helpers.c
-DBUS_CFLAGS += $(DBUS_INCLUDE)
-endif
-
ifdef CONFIG_CTRL_IFACE_DBUS_NEW
-DBUS=y
-DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW
-DBUS_OBJS ?= dbus/dbus_dict_helpers.c
-DBUS_OBJS += dbus/dbus_new_helpers.c
-DBUS_OBJS += dbus/dbus_new.c dbus/dbus_new_handlers.c
+L_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW
+OBJS += dbus/dbus_dict_helpers.c
+OBJS += dbus/dbus_new_helpers.c
+OBJS += dbus/dbus_new.c dbus/dbus_new_handlers.c
+OBJS += dbus/dbus_common.c
ifdef CONFIG_WPS
-DBUS_OBJS += dbus/dbus_new_handlers_wps.c
+OBJS += dbus/dbus_new_handlers_wps.c
endif
ifdef CONFIG_P2P
-DBUS_OBJS += dbus/dbus_new_handlers_p2p.c
+OBJS += dbus/dbus_new_handlers_p2p.c
endif
ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
-DBUS_OBJS += dbus/dbus_new_introspect.c
-DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO
+OBJS += dbus/dbus_new_introspect.c
+L_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO
endif
-DBUS_CFLAGS += $(DBUS_INCLUDE)
+L_CFLAGS += $(DBUS_INCLUDE)
endif
-ifdef DBUS
-DBUS_CFLAGS += -DCONFIG_DBUS
-DBUS_OBJS += dbus/dbus_common.c
-endif
-
-OBJS += $(DBUS_OBJS)
-L_CFLAGS += $(DBUS_CFLAGS)
-
ifdef CONFIG_CTRL_IFACE_HIDL
WPA_SUPPLICANT_USE_HIDL=y
L_CFLAGS += -DCONFIG_HIDL -DCONFIG_CTRL_IFACE_HIDL
@@ -1724,6 +1732,7 @@
ifeq ($(WPA_SUPPLICANT_USE_HIDL), y)
LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant@1.0
LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant@1.1
+LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant@1.2
LOCAL_SHARED_LIBRARIES += libhidlbase libhidltransport libhwbinder libutils libbase
LOCAL_STATIC_LIBRARIES += libwpa_hidl
endif
@@ -1774,7 +1783,7 @@
LOCAL_CPPFLAGS := $(L_CPPFLAGS)
LOCAL_CFLAGS := $(L_CFLAGS)
LOCAL_C_INCLUDES := $(INCLUDES)
-HIDL_INTERFACE_VERSION = 1.1
+HIDL_INTERFACE_VERSION = 1.2
LOCAL_SRC_FILES := \
hidl/$(HIDL_INTERFACE_VERSION)/hidl.cpp \
hidl/$(HIDL_INTERFACE_VERSION)/hidl_manager.cpp \
@@ -1787,11 +1796,13 @@
LOCAL_SHARED_LIBRARIES := \
android.hardware.wifi.supplicant@1.0 \
android.hardware.wifi.supplicant@1.1 \
+ android.hardware.wifi.supplicant@1.2 \
libbase \
libhidlbase \
libhidltransport \
libutils \
- liblog
+ liblog \
+ libssl
LOCAL_EXPORT_C_INCLUDE_DIRS := \
$(LOCAL_PATH)/hidl/$(HIDL_INTERFACE_VERSION)
include $(BUILD_STATIC_LIBRARY)
diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog
index f28055f..bf4daaa 100644
--- a/wpa_supplicant/ChangeLog
+++ b/wpa_supplicant/ChangeLog
@@ -1,5 +1,75 @@
ChangeLog for wpa_supplicant
+2018-12-02 - v2.7
+ * fixed WPA packet number reuse with replayed messages and key
+ reinstallation
+ [https://w1.fi/security/2017-1/] (CVE-2017-13077, CVE-2017-13078,
+ CVE-2017-13079, CVE-2017-13080, CVE-2017-13081, CVE-2017-13082,
+ CVE-2017-13086, CVE-2017-13087, CVE-2017-13088)
+ * fixed unauthenticated EAPOL-Key decryption in wpa_supplicant
+ [https://w1.fi/security/2018-1/] (CVE-2018-14526)
+ * added support for FILS (IEEE 802.11ai) shared key authentication
+ * added support for OWE (Opportunistic Wireless Encryption, RFC 8110;
+ and transition mode defined by WFA)
+ * added support for DPP (Wi-Fi Device Provisioning Protocol)
+ * added support for RSA 3k key case with Suite B 192-bit level
+ * fixed Suite B PMKSA caching not to update PMKID during each 4-way
+ handshake
+ * fixed EAP-pwd pre-processing with PasswordHashHash
+ * added EAP-pwd client support for salted passwords
+ * fixed a regression in TDLS prohibited bit validation
+ * started to use estimated throughput to avoid undesired signal
+ strength based roaming decision
+ * MACsec/MKA:
+ - new macsec_linux driver interface support for the Linux
+ kernel macsec module
+ - number of fixes and extensions
+ * added support for external persistent storage of PMKSA cache
+ (PMKSA_GET/PMKSA_ADD control interface commands; and
+ MESH_PMKSA_GET/MESH_PMKSA_SET for the mesh case)
+ * fixed mesh channel configuration pri/sec switch case
+ * added support for beacon report
+ * large number of other fixes, cleanup, and extensions
+ * added support for randomizing local address for GAS queries
+ (gas_rand_mac_addr parameter)
+ * fixed EAP-SIM/AKA/AKA' ext auth cases within TLS tunnel
+ * added option for using random WPS UUID (auto_uuid=1)
+ * added SHA256-hash support for OCSP certificate matching
+ * fixed EAP-AKA' to add AT_KDF into Synchronization-Failure
+ * fixed a regression in RSN pre-authentication candidate selection
+ * added option to configure allowed group management cipher suites
+ (group_mgmt network profile parameter)
+ * removed all PeerKey functionality
+ * fixed nl80211 AP and mesh mode configuration regression with
+ Linux 4.15 and newer
+ * added ap_isolate configuration option for AP mode
+ * added support for nl80211 to offload 4-way handshake into the driver
+ * added support for using wolfSSL cryptographic library
+ * SAE
+ - added support for configuring SAE password separately of the
+ WPA2 PSK/passphrase
+ - fixed PTK and EAPOL-Key integrity and key-wrap algorithm selection
+ for SAE;
+ note: this is not backwards compatible, i.e., both the AP and
+ station side implementations will need to be update at the same
+ time to maintain interoperability
+ - added support for Password Identifier
+ - fixed FT-SAE PMKID matching
+ * Hotspot 2.0
+ - added support for fetching of Operator Icon Metadata ANQP-element
+ - added support for Roaming Consortium Selection element
+ - added support for Terms and Conditions
+ - added support for OSEN connection in a shared RSN BSS
+ - added support for fetching Venue URL information
+ * added support for using OpenSSL 1.1.1
+ * FT
+ - disabled PMKSA caching with FT since it is not fully functional
+ - added support for SHA384 based AKM
+ - added support for BIP ciphers BIP-CMAC-256, BIP-GMAC-128,
+ BIP-GMAC-256 in addition to previously supported BIP-CMAC-128
+ - fixed additional IE inclusion in Reassociation Request frame when
+ using FT protocol
+
2016-10-02 - v2.6
* fixed WNM Sleep Mode processing when PMF is not enabled
[http://w1.fi/security/2015-6/] (CVE-2015-5310)
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 65205d8..e81238e 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -55,7 +55,6 @@
ALL += systemd/wpa_supplicant@.service
ALL += systemd/wpa_supplicant-nl80211@.service
ALL += systemd/wpa_supplicant-wired@.service
-ALL += dbus/fi.epitest.hostap.WPASupplicant.service
ALL += dbus/fi.w1.wpa_supplicant1.service
ifdef CONFIG_BUILD_WPA_CLIENT_SO
ALL += libwpa_client.so
@@ -240,16 +239,18 @@
NEED_SHA384=y
endif
+ifdef CONFIG_OCV
+CFLAGS += -DCONFIG_OCV
+OBJS += ../src/common/ocv.o
+CONFIG_IEEE80211W=y
+endif
+
ifdef CONFIG_IEEE80211W
CFLAGS += -DCONFIG_IEEE80211W
NEED_SHA256=y
NEED_AES_OMAC1=y
endif
-ifdef CONFIG_IEEE80211R_AP
-CONFIG_IEEE80211R=y
-endif
-
ifdef CONFIG_IEEE80211R
CFLAGS += -DCONFIG_IEEE80211R
OBJS += ../src/rsn_supp/wpa_ft.o
@@ -290,6 +291,9 @@
NEED_JSON=y
NEED_GAS_SERVER=y
NEED_BASE64=y
+ifdef CONFIG_DPP2
+CFLAGS += -DCONFIG_DPP2
+endif
endif
ifdef CONFIG_OWE
@@ -709,9 +713,13 @@
ifdef CONFIG_EAP_PWD
CFLAGS += -DEAP_PWD
+ifeq ($(CONFIG_TLS), wolfssl)
+CFLAGS += -DCONFIG_ECC
+endif
OBJS += ../src/eap_peer/eap_pwd.o ../src/eap_common/eap_pwd_common.o
CONFIG_IEEE8021X_EAPOL=y
NEED_SHA256=y
+NEED_ECC=y
endif
ifdef CONFIG_EAP_EKE
@@ -966,10 +974,6 @@
OBJS += ../src/ap/wpa_auth.o
OBJS += ../src/ap/wpa_auth_ie.o
OBJS += ../src/ap/pmksa_cache_auth.o
-ifdef CONFIG_IEEE80211R_AP
-CFLAGS += -DCONFIG_IEEE80211R_AP
-OBJS += ../src/ap/wpa_auth_ft.o
-endif
endif
ifdef CONFIG_ACS
@@ -1053,6 +1057,21 @@
NEED_SHA256=y
endif
+ifeq ($(CONFIG_TLS), wolfssl)
+ifdef TLS_FUNCS
+CFLAGS += -DWOLFSSL_DER_LOAD -I/usr/local/include/wolfssl
+OBJS += ../src/crypto/tls_wolfssl.o
+endif
+OBJS += ../src/crypto/crypto_wolfssl.o
+OBJS_p += ../src/crypto/crypto_wolfssl.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_wolfssl.o
+endif
+NEED_TLS_PRF_SHA256=y
+LIBS += -lwolfssl -lm
+LIBS_p += -lwolfssl -lm
+endif
+
ifeq ($(CONFIG_TLS), openssl)
ifdef TLS_FUNCS
CFLAGS += -DEAP_TLS_OPENSSL
@@ -1081,23 +1100,34 @@
endif
ifeq ($(CONFIG_TLS), gnutls)
+ifndef CONFIG_CRYPTO
+# default to libgcrypt
+CONFIG_CRYPTO=gnutls
+endif
ifdef TLS_FUNCS
OBJS += ../src/crypto/tls_gnutls.o
LIBS += -lgnutls -lgpg-error
endif
-OBJS += ../src/crypto/crypto_gnutls.o
-OBJS_p += ../src/crypto/crypto_gnutls.o
-OBJS_priv += ../src/crypto/crypto_gnutls.o
+OBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
+OBJS_p += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
+OBJS_priv += ../src/crypto/crypto_$(CONFIG_CRYPTO).o
ifdef NEED_FIPS186_2_PRF
OBJS += ../src/crypto/fips_prf_internal.o
SHA1OBJS += ../src/crypto/sha1-internal.o
endif
+ifeq ($(CONFIG_CRYPTO), gnutls)
LIBS += -lgcrypt
LIBS_p += -lgcrypt
-CONFIG_INTERNAL_SHA256=y
CONFIG_INTERNAL_RC4=y
CONFIG_INTERNAL_DH_GROUP5=y
endif
+ifeq ($(CONFIG_CRYPTO), nettle)
+LIBS += -lnettle -lgmp
+LIBS_p += -lnettle -lgmp
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+endif
ifeq ($(CONFIG_TLS), internal)
ifndef CONFIG_CRYPTO
@@ -1262,8 +1292,10 @@
endif
ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), wolfssl)
NEED_INTERNAL_AES_WRAP=y
endif
+endif
ifdef CONFIG_OPENSSL_INTERNAL_AES_WRAP
# Seems to be needed at least with BoringSSL
NEED_INTERNAL_AES_WRAP=y
@@ -1302,10 +1334,12 @@
CFLAGS += -DCONFIG_OPENSSL_CMAC
else
ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
AESOBJS += ../src/crypto/aes-omac1.o
endif
endif
endif
+endif
ifdef NEED_AES_WRAP
NEED_AES_ENC=y
ifdef NEED_INTERNAL_AES_WRAP
@@ -1316,10 +1350,12 @@
NEED_AES_ENC=y
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), wolfssl)
AESOBJS += ../src/crypto/aes-cbc.o
endif
endif
endif
+endif
ifdef NEED_AES_ENC
ifdef CONFIG_INTERNAL_AES
AESOBJS += ../src/crypto/aes-internal-enc.o
@@ -1332,9 +1368,13 @@
ifdef NEED_SHA1
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
SHA1OBJS += ../src/crypto/sha1.o
endif
endif
+endif
+endif
SHA1OBJS += ../src/crypto/sha1-prf.o
ifdef CONFIG_INTERNAL_SHA1
SHA1OBJS += ../src/crypto/sha1-internal.o
@@ -1346,9 +1386,11 @@
CFLAGS += -DCONFIG_NO_PBKDF2
else
ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), wolfssl)
SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
endif
endif
+endif
ifdef NEED_T_PRF
SHA1OBJS += ../src/crypto/sha1-tprf.o
endif
@@ -1360,10 +1402,14 @@
ifndef CONFIG_FIPS
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
MD5OBJS += ../src/crypto/md5.o
endif
endif
endif
+endif
+endif
ifdef NEED_MD5
ifdef CONFIG_INTERNAL_MD5
MD5OBJS += ../src/crypto/md5-internal.o
@@ -1381,6 +1427,9 @@
DESOBJS = # none needed when not internal
ifdef NEED_DES
+ifndef CONFIG_FIPS
+CFLAGS += -DCONFIG_DES
+endif
ifdef CONFIG_INTERNAL_DES
DESOBJS += ../src/crypto/des-internal.o
endif
@@ -1403,9 +1452,13 @@
CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
SHA256OBJS += ../src/crypto/sha256.o
endif
endif
+endif
+endif
SHA256OBJS += ../src/crypto/sha256-prf.o
ifdef CONFIG_INTERNAL_SHA256
SHA256OBJS += ../src/crypto/sha256-internal.o
@@ -1438,18 +1491,26 @@
ifdef NEED_SHA384
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
OBJS += ../src/crypto/sha384.o
endif
endif
+endif
+endif
CFLAGS += -DCONFIG_SHA384
OBJS += ../src/crypto/sha384-prf.o
endif
ifdef NEED_SHA512
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
+ifneq ($(CONFIG_TLS), gnutls)
+ifneq ($(CONFIG_TLS), wolfssl)
OBJS += ../src/crypto/sha512.o
endif
endif
+endif
+endif
CFLAGS += -DCONFIG_SHA512
OBJS += ../src/crypto/sha512-prf.o
endif
@@ -1473,6 +1534,9 @@
ifdef CONFIG_NO_RANDOM_POOL
CFLAGS += -DCONFIG_NO_RANDOM_POOL
else
+ifdef CONFIG_GETRANDOM
+CFLAGS += -DCONFIG_GETRANDOM
+endif
OBJS += ../src/crypto/random.o
endif
@@ -1514,35 +1578,17 @@
OBJS += ctrl_iface.o ctrl_iface_$(CONFIG_CTRL_IFACE).o
endif
-ifdef CONFIG_CTRL_IFACE_DBUS
-DBUS=y
-DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS -DDBUS_API_SUBJECT_TO_CHANGE
-DBUS_OBJS += dbus/dbus_old.o dbus/dbus_old_handlers.o
-ifdef CONFIG_WPS
-DBUS_OBJS += dbus/dbus_old_handlers_wps.o
-endif
-DBUS_OBJS += dbus/dbus_dict_helpers.o
-ifndef DBUS_LIBS
-DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1)
-endif
-ifndef DBUS_INCLUDE
-DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1)
-endif
-DBUS_CFLAGS += $(DBUS_INCLUDE)
-DBUS_INTERFACE=fi.epitest.hostap.WPASupplicant
-endif
-
ifdef CONFIG_CTRL_IFACE_DBUS_NEW
-DBUS=y
-DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW
-DBUS_OBJS ?= dbus/dbus_dict_helpers.o
-DBUS_OBJS += dbus/dbus_new_helpers.o
-DBUS_OBJS += dbus/dbus_new.o dbus/dbus_new_handlers.o
+CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW
+OBJS += dbus/dbus_dict_helpers.o
+OBJS += dbus/dbus_new_helpers.o
+OBJS += dbus/dbus_new.o dbus/dbus_new_handlers.o
+OBJS += dbus/dbus_common.o
ifdef CONFIG_WPS
-DBUS_OBJS += dbus/dbus_new_handlers_wps.o
+OBJS += dbus/dbus_new_handlers_wps.o
endif
ifdef CONFIG_P2P
-DBUS_OBJS += dbus/dbus_new_handlers_p2p.o
+OBJS += dbus/dbus_new_handlers_p2p.o
endif
ifndef DBUS_LIBS
DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1)
@@ -1551,21 +1597,12 @@
DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1)
endif
ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
-DBUS_OBJS += dbus/dbus_new_introspect.o
-DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO
+OBJS += dbus/dbus_new_introspect.o
+CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO
endif
-DBUS_CFLAGS += $(DBUS_INCLUDE)
-DBUS_INTERFACE=fi.w1.wpa_supplicant1
-endif
-
-ifdef DBUS
-DBUS_CFLAGS += -DCONFIG_DBUS
-DBUS_OBJS += dbus/dbus_common.o
-endif
-
-OBJS += $(DBUS_OBJS)
-CFLAGS += $(DBUS_CFLAGS)
+CFLAGS += $(DBUS_INCLUDE)
LIBS += $(DBUS_LIBS)
+endif
ifdef CONFIG_READLINE
OBJS_c += ../src/utils/edit_readline.o
@@ -1646,9 +1683,11 @@
ifdef CONFIG_FIPS
CFLAGS += -DCONFIG_FIPS
ifneq ($(CONFIG_TLS), openssl)
+ifneq ($(CONFIG_TLS), wolfssl)
$(error CONFIG_FIPS=y requires CONFIG_TLS=openssl)
endif
endif
+endif
OBJS += $(SHA1OBJS) $(DESOBJS)
@@ -1846,7 +1885,7 @@
@$(E) " LD " $@
wpa_passphrase: $(OBJS_p)
- $(Q)$(LDO) $(LDFLAGS) -o wpa_passphrase $(OBJS_p) $(LIBS_p)
+ $(Q)$(LDO) $(LDFLAGS) -o wpa_passphrase $(OBJS_p) $(LIBS_p) $(LIBS)
@$(E) " LD " $@
wpa_cli: $(OBJS_c)
@@ -1926,13 +1965,11 @@
endif
%.service: %.service.in
- $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' \
- -e 's|\@DBUS_INTERFACE\@|$(DBUS_INTERFACE)|g' $< >$@
+ $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
@$(E) " sed" $<
%@.service: %.service.arg.in
- $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' \
- -e 's|\@DBUS_INTERFACE\@|$(DBUS_INTERFACE)|g' $< >$@
+ $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
@$(E) " sed" $<
wpa_supplicant.exe: wpa_supplicant
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index 730714b..bbc86b1 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -1,7 +1,7 @@
-WPA Supplicant
+wpa_supplicant
==============
-Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
This program is licensed under the BSD license (the one with
diff --git a/wpa_supplicant/README-DPP b/wpa_supplicant/README-DPP
new file mode 100644
index 0000000..6496733
--- /dev/null
+++ b/wpa_supplicant/README-DPP
@@ -0,0 +1,195 @@
+Device Provisioning Protocol (DPP)
+==================================
+
+This document describes how the Device Provisioning Protocol (DPP)
+implementation in wpa_supplicant and hostapd can be configured and how
+the STA device and AP can be configured to connect each other using DPP
+Connector mechanism.
+
+Introduction to DPP
+-------------------
+
+Device provisioning Protocol allows enrolling of interface-less devices
+in a secure Wi-Fi network using many methods like QR code based
+authentication( detailed below ), PKEX based authentication etc. In DPP
+a Configurator is used to provide network credentials to the devices.
+The three phases of DPP connection are authentication, configuration and
+network introduction.
+
+Build config setup
+------------------
+
+The following changes must go in the config file used to compile hostapd
+and wpa_supplicant.
+
+wpa_supplicant build config
+---------------------------
+
+Enable DPP and protected management frame in wpa_supplicant build config
+file
+
+CONFIG_IEEE80211W=y
+CONFIG_DPP=y
+
+hostapd build config
+--------------------
+
+Enable DPP and protected management frame in hostapd build config file
+
+CONFIG_IEEE80211W=y
+CONFIG_DPP=y
+
+Configurator build config
+-------------------------
+
+Any STA or AP device can act as a Configurator. Enable DPP and protected
+managment frames in build config. For an AP to act as Configurator,
+Interworking needs to be enabled. For wpa_supplicant it is not required.
+
+CONFIG_INTERWORKING=y
+
+
+Sample supplicant config file before provisioning
+-------------------------------------------------
+
+ctrl_interface=DIR=/var/run/wpa_supplicant
+ctrl_interface_group=0
+update_config=1
+pmf=2
+dpp_config_processing=2
+
+Sample hostapd config file before provisioning
+----------------------------------------------
+
+interface=wlan0
+driver=nl80211
+ctrl_interface=/var/run/hostapd
+ssid=test
+channel=1
+wpa=2
+wpa_key_mgmt=DPP
+ieee80211w=1
+wpa_pairwise=CCMP
+rsn_pairwise=CCMP
+
+
+Pre-requisites
+--------------
+
+It is assumed that an AP and client station are up by running hostapd
+and wpa_supplicant using respective config files.
+
+
+Creating Configurator
+---------------------
+
+Add a Configurator over the control interface (wpa_cli/hostapd_cli)
+
+> dpp_configurator_add
+(returns id)
+
+To get key of Configurator
+> dpp_configurator_get_key <id>
+
+
+How to configure an enrollee using Configurator
+-----------------------------------------------
+
+On enrollee side:
+
+Generate QR code for the device. Store the qr code id returned by the
+command.
+
+> dpp_bootstrap_gen type=qrcode mac=<mac-address-of-device> chan=<operating-channel> key=<key of the device>
+(returns bootstrapping info id)
+
+Get QR Code of device using the bootstrap info id.
+> dpp_bootstrap_get_uri <bootstrap-id>
+
+Make device listen to DPP request (The central frequency of channel 1 is
+2412) in case if enrollee is a client device.
+
+> dpp_listen <frequency>
+
+On Configurator side:
+
+Enter the QR Code in the Configurator.
+> dpp_qr_code "<QR-Code-read-from-enrollee>"
+
+On successfully adding QR Code, a bootstrapping info id is returned.
+
+Send provisioning request to enrollee. (conf is ap-dpp if enrollee is an
+AP. conf is sta-dpp if enrollee is a client)
+> dpp_auth_init peer=<qr-code-id> conf=<ap-dpp|sta-dpp> configurator=<configurator-id>
+
+The DPP values will be printed in the console. Save this values into the
+config file. If the enrollee is an AP, we need to manually write these
+values to the hostapd config file. If the enrollee is a client device,
+these details can be automatically saved to config file using the
+following command.
+
+> save_config
+
+To set values in runtime for AP enrollees
+
+> set dpp_connector <Connector-value-printed-on-console>
+> set dpp_csign <csign-value-on-console>
+> set dpp_netaccesskey <netaccess-value-on-console>
+
+To set values in runtime for client enrollees, set dpp_config_processing
+to 2 in wpa_supplicant conf file.
+
+Once the values are set in run-time (if not set in run-time, but saved
+in config files, they are taken up in next restart), the client device
+will automatically connect to the already provisioned AP and connection
+will be established.
+
+
+Self-configuring a device
+-------------------------
+
+It is possible for a device to configure itself if it is the
+Configurator for the network.
+
+Create a Configurator in the device and use the dpp_configurator_sign
+command to get DPP credentials.
+
+> dpp_configurator_add
+(returns configurator id)
+> dpp_configurator_sign conf=<ap-dpp|sta-dpp> configurator=<configurator-id>
+
+
+Sample AP configuration files after provisioning
+------------------------------------------------
+
+interface=wlan0
+driver=nl80211
+ctrl_interface=/var/run/hostapd
+ssid=test
+channel=1
+wpa=2
+wpa_key_mgmt=DPP
+ieee80211w=1
+wpa_pairwise=CCMP
+rsn_pairwise=CCMP
+dpp_connector=<Connector value provided by Configurator>
+dpp_csign=<C-Sign-Key value provided by Configurator>
+dpp_netaccesskey=<Net access key provided by Configurator>
+
+
+Sample station configuration file after provisioning
+----------------------------------------------------
+
+ctrl_interface=DIR=/var/run/wpa_supplicant
+ctrl_interface_group=0
+update_config=1
+pmf=2
+dpp_config_processing=2
+network={
+ ssid="test"
+ key_mgmt=DPP
+ ieee80211w=2
+ dpp_connector="<Connector value provided by Configurator>"
+ dpp_netaccesskey=<Net access key provided by Configurator>
+ dpp_csign=<C-sign-key value provided by Configurator>
+}
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
index e4eed20..3342871 100644
--- a/wpa_supplicant/README-HS20
+++ b/wpa_supplicant/README-HS20
@@ -197,6 +197,20 @@
# pre-configured with the credential since the NAI Realm information
# may not be available or fetched.
#
+# required_roaming_consortium: Required Roaming Consortium OI
+# If required_roaming_consortium_len is non-zero, this field contains the
+# Roaming Consortium OI that is required to be advertised by the AP for
+# the credential to be considered matching.
+#
+# roaming_consortiums: Roaming Consortium OI(s) memberships
+# This string field contains one or more comma delimited OIs (hexdump)
+# identifying the roaming consortiums of which the provider is a member.
+# The list is sorted from the most preferred one to the least preferred
+# one. A match between the Roaming Consortium OIs advertised by an AP and
+# the OIs in this list indicates that successful authentication is
+# possible.
+# (Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/RoamingConsortiumOI)
+#
# eap: Pre-configured EAP method
# This optional field can be used to specify which EAP method will be
# used with this credential. If not set, the EAP method is selected
@@ -295,6 +309,7 @@
# ca_cert="/etc/wpa_supplicant/ca.pem"
# domain="example.com"
# roaming_consortium=223344
+# roaming_consortiums="112233,4455667788,aabbcc"
# eap=TTLS
# phase2="auth=MSCHAPV2"
#}
@@ -591,7 +606,7 @@
Hotspot 2.0 connection with external network selection
------------------------------------------------------
-When an component controlling wpa_supplicant takes care of Interworking
+When a component controlling wpa_supplicant takes care of Interworking
network selection, following configuration and network profile
parameters can be used to configure a temporary network profile for a
Hotspot 2.0 connection (e.g., with SET, ADD_NETWORK, SET_NETWORK, and
@@ -613,6 +628,7 @@
eap=TTLS
phase2="auth=MSCHAPV2"
update_identifier=54321
+ roaming_consortium_selection=112233
#ocsp=2
}
@@ -628,4 +644,5 @@
ca_cert: from the downloaded trust root based on PPS information
eap: Credential/UsernamePassword/EAPMethod or NAI Realm list
phase2: Credential/UsernamePassword/EAPMethod or NAI Realm list
+roaming_consortium_selection: Matching OI from HomeSP/RoamingConsortiumOI
ocsp: Credential/CheckAAAServerCertStatus
diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P
index 23ac7fa..55a60a2 100644
--- a/wpa_supplicant/README-P2P
+++ b/wpa_supplicant/README-P2P
@@ -150,7 +150,7 @@
p2p_connect <peer device address> <pbc|pin|PIN#|p2ps> [display|keypad|p2ps]
[persistent|persistent=<network id>] [join|auth]
- [go_intent=<0..15>] [freq=<in MHz>] [ht40] [vht] [provdisc] [auto]
+ [go_intent=<0..15>] [freq=<in MHz>] [ht40] [vht] [he] [provdisc] [auto]
[ssid=<hexdump>]
Start P2P group formation with a discovered P2P peer. This includes
@@ -262,7 +262,7 @@
session_mac - Mandatory MAC address that owns/initiated the session
p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>]
- [ht40] [vht]
+ [ht40] [vht] [he]
Set up a P2P group owner manually (i.e., without group owner
negotiation with a specific peer). This is also known as autonomous
@@ -558,7 +558,7 @@
Invitation
p2p_invite [persistent=<network id>|group=<group ifname>] [peer=address]
- [go_dev_addr=address] [freq=<freq in MHz>] [ht40] [vht]
+ [go_dev_addr=address] [freq=<freq in MHz>] [ht40] [vht] [he]
[pref=<MHz>]
Invite a peer to join a group (e.g., group=wlan1) or to reinvoke a
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index fd65584..b9b5d9d 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -32,9 +32,6 @@
#CONFIG_DRIVER_NL80211=y
CONFIG_LIBNL20=y
-# QCA vendor extensions to nl80211
-CONFIG_DRIVER_NL80211_QCA=y
-
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
#CONFIG_DRIVER_BSD=y
#CFLAGS += -I/usr/local/include
@@ -91,9 +88,6 @@
CONFIG_EAP_TTLS=y
# EAP-FAST
-# Note: If OpenSSL is used as the TLS library, OpenSSL 1.0 or newer is needed
-# for EAP-FAST support. Older OpenSSL releases would need to be patched, e.g.,
-# with openssl-0.9.8x-tls-extensions.patch, to add the needed functions.
#CONFIG_EAP_FAST=y
# EAP-GTC
@@ -280,6 +274,9 @@
# Driver support is also needed for IEEE 802.11w.
CONFIG_IEEE80211W=y
+# Support Operating Channel Validation
+#CONFIG_OCV=y
+
# Select TLS implementation
# openssl = OpenSSL (default)
# gnutls = GnuTLS
@@ -327,10 +324,6 @@
#CONFIG_NDIS_EVENTS_INTEGRATED=y
#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib"
-# Add support for old DBus control interface
-# (fi.epitest.hostap.WPASupplicant)
-#CONFIG_CTRL_IFACE_DBUS=y
-
# Add support for new DBus control interface
# (fi.w1.hostap.wpa_supplicant1)
#CONFIG_CTRL_IFACE_DBUS_NEW=y
@@ -366,10 +359,6 @@
# IEEE Std 802.11r-2008 (Fast BSS Transition) for station mode
CONFIG_IEEE80211R=y
-# IEEE Std 802.11r-2008 (Fast BSS Transition) for AP mode (implies
-# CONFIG_IEEE80211R).
-#CONFIG_IEEE80211R_AP=y
-
# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
#CONFIG_DEBUG_FILE=y
@@ -491,8 +480,8 @@
# Enable TDLS support
CONFIG_TDLS=y
-# Wi-Fi Direct
-# This can be used to enable Wi-Fi Direct extensions for P2P using an external
+# Wi-Fi Display
+# This can be used to enable Wi-Fi Display extensions for P2P using an external
# program to control the additional information exchanges in the messages.
CONFIG_WIFI_DISPLAY=y
@@ -521,8 +510,6 @@
#CONFIG_MBO=y
# Fast Initial Link Setup (FILS) (IEEE 802.11ai)
-# Note: This is an experimental and not yet complete implementation. This
-# should not be enabled for production use.
#CONFIG_FILS=y
# Support RSN on IBSS networks
@@ -550,6 +537,16 @@
# Opportunistic Wireless Encryption (OWE)
# Experimental implementation of draft-harkins-owe-07.txt
-#CONFIG_OWE=y
+CONFIG_OWE=y
+
+# Easy Connect (Device Provisioning Protocol - DPP)
+CONFIG_DPP=y
+
+# WPA3-Personal (SAE)
+CONFIG_SAE=y
+
+# WPA3-Enterprise (SuiteB-192)
+CONFIG_SUITEB=y
+CONFIG_SUITEB192=y
include $(wildcard $(LOCAL_PATH)/android_config_*.inc)
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 6668d58..4e19169 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -71,6 +71,8 @@
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);
return;
}
@@ -79,9 +81,15 @@
case VHT_CHANWIDTH_80MHZ:
case VHT_CHANWIDTH_80P80MHZ:
center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel);
+ wpa_printf(MSG_DEBUG,
+ "VHT center channel %u for 80 or 80+80 MHz bandwidth",
+ center_chan);
break;
case VHT_CHANWIDTH_160MHZ:
center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel);
+ wpa_printf(MSG_DEBUG,
+ "VHT center channel %u for 160 MHz bandwidth",
+ center_chan);
break;
default:
/*
@@ -91,10 +99,17 @@
*/
conf->vht_oper_chwidth = VHT_CHANWIDTH_160MHZ;
center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel);
- if (!center_chan) {
+ if (center_chan) {
+ wpa_printf(MSG_DEBUG,
+ "VHT center channel %u for auto-selected 160 MHz bandwidth",
+ center_chan);
+ } else {
conf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
center_chan = wpas_p2p_get_vht80_center(wpa_s, mode,
channel);
+ wpa_printf(MSG_DEBUG,
+ "VHT center channel %u for auto-selected 80 MHz bandwidth",
+ center_chan);
}
break;
}
@@ -102,10 +117,15 @@
goto no_vht;
conf->vht_oper_centr_freq_seg0_idx = center_chan;
+ wpa_printf(MSG_DEBUG, "VHT seg0 index %d for P2P GO",
+ conf->vht_oper_centr_freq_seg0_idx);
return;
#endif /* CONFIG_P2P */
no_vht:
+ 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 = VHT_CHANWIDTH_USE_HT;
@@ -139,6 +159,11 @@
if (wpa_s->hw.modes) {
struct hostapd_hw_modes *mode = NULL;
int i, 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];
@@ -152,28 +177,45 @@
#endif /* CONFIG_HT_OVERRIDES */
if (!ssid->ht) {
+ wpa_printf(MSG_DEBUG,
+ "HT not enabled in network profile");
conf->ieee80211n = 0;
conf->ht_capab = 0;
no_ht = 1;
}
if (!no_ht && mode && mode->ht_capab) {
+ wpa_printf(MSG_DEBUG,
+ "Enable HT support (p2p_group=%d 11a=%d ht40_hw_capab=%d ssid->ht40=%d)",
+ ssid->p2p_group,
+ conf->hw_mode == HOSTAPD_MODE_IEEE80211A,
+ !!(mode->ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET),
+ ssid->ht40);
conf->ieee80211n = 1;
#ifdef CONFIG_P2P
if (ssid->p2p_group &&
conf->hw_mode == HOSTAPD_MODE_IEEE80211A &&
(mode->ht_capab &
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
- ssid->ht40)
+ ssid->ht40) {
conf->secondary_channel =
wpas_p2p_get_ht40_mode(wpa_s, mode,
conf->channel);
+ wpa_printf(MSG_DEBUG,
+ "HT secondary channel offset %d for P2P group",
+ conf->secondary_channel);
+ }
#endif /* CONFIG_P2P */
if (!ssid->p2p_group &&
(mode->ht_capab &
- HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
conf->secondary_channel = ssid->ht40;
+ wpa_printf(MSG_DEBUG,
+ "HT secondary channel offset %d for AP",
+ conf->secondary_channel);
+ }
if (conf->secondary_channel)
conf->ht_capab |=
@@ -256,7 +298,8 @@
}
#endif /* CONFIG_ACS */
- if (ieee80211_is_dfs(ssid->frequency) && wpa_s->conf->country[0]) {
+ if (ieee80211_is_dfs(ssid->frequency, wpa_s->hw.modes,
+ wpa_s->hw.num_modes) && wpa_s->conf->country[0]) {
conf->ieee80211h = 1;
conf->ieee80211d = 1;
conf->country[0] = wpa_s->conf->country[0];
@@ -293,6 +336,12 @@
conf->supported_rates = list;
}
+#ifdef CONFIG_IEEE80211AX
+ if (ssid->mode == WPAS_MODE_P2P_GO ||
+ ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
+ conf->ieee80211ax = ssid->he;
+#endif /* CONFIG_IEEE80211AX */
+
bss->isolate = !wpa_s->conf->p2p_intra_bss;
bss->force_per_enrollee_psk = wpa_s->global->p2p_per_sta_psk;
@@ -451,6 +500,10 @@
bss->ieee80211w = ssid->ieee80211w;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ bss->ocv = ssid->ocv;
+#endif /* CONFIG_OCV */
+
#ifdef CONFIG_WPS
/*
* Enable WPS by default for open and WPA/WPA2-Personal network, but
@@ -506,6 +559,9 @@
else
bss->max_num_sta = wpa_s->conf->max_num_sta;
+ if (!bss->isolate)
+ bss->isolate = wpa_s->conf->ap_isolate;
+
bss->disassoc_low_ack = wpa_s->conf->disassoc_low_ack;
if (wpa_s->conf->ap_vendor_elements) {
@@ -630,9 +686,18 @@
{
struct wpa_supplicant *wpa_s = ctx;
+ wpa_printf(MSG_DEBUG, "AP interface setup completed - state %s",
+ hostapd_state_text(wpa_s->ap_iface->state));
+ if (wpa_s->ap_iface->state == HAPD_IFACE_DISABLED) {
+ wpa_supplicant_ap_deinit(wpa_s);
+ return;
+ }
+
#ifdef CONFIG_ACS
- if (wpa_s->current_ssid && wpa_s->current_ssid->acs)
+ if (wpa_s->current_ssid && wpa_s->current_ssid->acs) {
wpa_s->assoc_freq = wpa_s->ap_iface->freq;
+ wpa_s->current_ssid->frequency = wpa_s->ap_iface->freq;
+ }
#endif /* CONFIG_ACS */
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
@@ -707,7 +772,8 @@
else
params.uapsd = -1;
- if (ieee80211_is_dfs(params.freq.freq))
+ if (ieee80211_is_dfs(params.freq.freq, wpa_s->hw.modes,
+ wpa_s->hw.num_modes))
params.freq.freq = 0; /* set channel after CAC */
if (params.p2p)
@@ -815,6 +881,14 @@
os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
wpa_s->assoc_freq = ssid->frequency;
+#if defined(CONFIG_P2P) && defined(CONFIG_ACS)
+ if (wpa_s->p2p_go_do_acs) {
+ wpa_s->ap_iface->conf->channel = 0;
+ wpa_s->ap_iface->conf->hw_mode = wpa_s->p2p_go_acs_band;
+ ssid->acs = 1;
+ }
+#endif /* CONFIG_P2P && CONFIG_ACS */
+
if (hostapd_setup_interface(wpa_s->ap_iface)) {
wpa_printf(MSG_ERROR, "Failed to initialize AP interface");
wpa_supplicant_ap_deinit(wpa_s);
@@ -1315,13 +1389,16 @@
void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
int offset, int width, int cf1, int cf2)
{
- if (!wpa_s->ap_iface)
- return;
+ struct hostapd_iface *iface = wpa_s->ap_iface;
+ if (!iface)
+ iface = wpa_s->ifmsh;
+ if (!iface)
+ return;
wpa_s->assoc_freq = freq;
if (wpa_s->current_ssid)
wpa_s->current_ssid->frequency = freq;
- hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht,
+ hostapd_event_ch_switch(iface->bss[0], freq, ht,
offset, width, cf1, cf2);
}
@@ -1515,62 +1592,82 @@
#ifdef NEED_AP_MLME
-void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
- struct dfs_event *radar)
+void wpas_ap_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
{
- if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ struct hostapd_iface *iface = wpa_s->ap_iface;
+
+ if (!iface)
+ iface = wpa_s->ifmsh;
+ if (!iface || !iface->bss[0])
return;
wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq);
- hostapd_dfs_radar_detected(wpa_s->ap_iface, radar->freq,
+ hostapd_dfs_radar_detected(iface, radar->freq,
radar->ht_enabled, radar->chan_offset,
radar->chan_width,
radar->cf1, radar->cf2);
}
-void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
- struct dfs_event *radar)
+void wpas_ap_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
{
- if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ struct hostapd_iface *iface = wpa_s->ap_iface;
+
+ if (!iface)
+ iface = wpa_s->ifmsh;
+ if (!iface || !iface->bss[0])
return;
wpa_printf(MSG_DEBUG, "DFS CAC started on %d MHz", radar->freq);
- hostapd_dfs_start_cac(wpa_s->ap_iface, radar->freq,
+ hostapd_dfs_start_cac(iface, radar->freq,
radar->ht_enabled, radar->chan_offset,
radar->chan_width, radar->cf1, radar->cf2);
}
-void wpas_event_dfs_cac_finished(struct wpa_supplicant *wpa_s,
- struct dfs_event *radar)
+void wpas_ap_event_dfs_cac_finished(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
{
- if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ struct hostapd_iface *iface = wpa_s->ap_iface;
+
+ if (!iface)
+ iface = wpa_s->ifmsh;
+ if (!iface || !iface->bss[0])
return;
wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq);
- hostapd_dfs_complete_cac(wpa_s->ap_iface, 1, radar->freq,
+ hostapd_dfs_complete_cac(iface, 1, radar->freq,
radar->ht_enabled, radar->chan_offset,
radar->chan_width, radar->cf1, radar->cf2);
}
-void wpas_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s,
- struct dfs_event *radar)
+void wpas_ap_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
{
- if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ struct hostapd_iface *iface = wpa_s->ap_iface;
+
+ if (!iface)
+ iface = wpa_s->ifmsh;
+ if (!iface || !iface->bss[0])
return;
wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq);
- hostapd_dfs_complete_cac(wpa_s->ap_iface, 0, radar->freq,
+ hostapd_dfs_complete_cac(iface, 0, radar->freq,
radar->ht_enabled, radar->chan_offset,
radar->chan_width, radar->cf1, radar->cf2);
}
-void wpas_event_dfs_cac_nop_finished(struct wpa_supplicant *wpa_s,
- struct dfs_event *radar)
+void wpas_ap_event_dfs_cac_nop_finished(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
{
- if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ struct hostapd_iface *iface = wpa_s->ap_iface;
+
+ if (!iface)
+ iface = wpa_s->ifmsh;
+ if (!iface || !iface->bss[0])
return;
wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq);
- hostapd_dfs_nop_finished(wpa_s->ap_iface, radar->freq,
+ hostapd_dfs_nop_finished(iface, radar->freq,
radar->ht_enabled, radar->chan_offset,
radar->chan_width, radar->cf1, radar->cf2);
}
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 3fa656f..447b551 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -89,16 +89,16 @@
char *buf, size_t len);
int wpas_ap_pmksa_cache_add_external(struct wpa_supplicant *wpa_s, char *cmd);
-void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
+void wpas_ap_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar);
+void wpas_ap_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
struct dfs_event *radar);
-void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
- struct dfs_event *radar);
-void wpas_event_dfs_cac_finished(struct wpa_supplicant *wpa_s,
- struct dfs_event *radar);
-void wpas_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s,
- struct dfs_event *radar);
-void wpas_event_dfs_cac_nop_finished(struct wpa_supplicant *wpa_s,
- struct dfs_event *radar);
+void wpas_ap_event_dfs_cac_finished(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar);
+void wpas_ap_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar);
+void wpas_ap_event_dfs_cac_nop_finished(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar);
void ap_periodic(struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 708b58a..9b19f37 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -1,6 +1,6 @@
/*
* BSS table
- * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -102,6 +102,8 @@
ANQP_DUP(hs20_connection_capability);
ANQP_DUP(hs20_operating_class);
ANQP_DUP(hs20_osu_providers_list);
+ ANQP_DUP(hs20_operator_icon_metadata);
+ ANQP_DUP(hs20_osu_providers_nai_list);
#endif /* CONFIG_HS20 */
#undef ANQP_DUP
@@ -185,6 +187,8 @@
wpabuf_free(anqp->hs20_connection_capability);
wpabuf_free(anqp->hs20_operating_class);
wpabuf_free(anqp->hs20_osu_providers_list);
+ wpabuf_free(anqp->hs20_operator_icon_metadata);
+ wpabuf_free(anqp->hs20_osu_providers_nai_list);
#endif /* CONFIG_HS20 */
os_free(anqp);
@@ -1333,3 +1337,10 @@
return NULL;
}
#endif /* CONFIG_FILS */
+
+
+int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab)
+{
+ return ieee802_11_ext_capab(wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB),
+ capab);
+}
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 37d9fb6..3ce8cd3 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -1,6 +1,6 @@
/*
* BSS table
- * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -50,6 +50,8 @@
struct wpabuf *hs20_connection_capability;
struct wpabuf *hs20_operating_class;
struct wpabuf *hs20_osu_providers_list;
+ struct wpabuf *hs20_operator_icon_metadata;
+ struct wpabuf *hs20_osu_providers_nai_list;
#endif /* CONFIG_HS20 */
};
@@ -146,6 +148,7 @@
struct wpa_bss_anqp * wpa_bss_anqp_alloc(void);
int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss);
const u8 * wpa_bss_get_fils_cache_id(struct wpa_bss *bss);
+int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab);
static inline int bss_is_dmg(const struct wpa_bss *bss)
{
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index a22434c..a7ca41c 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Configuration parser and common functions
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -735,6 +735,10 @@
val |= WPA_KEY_MGMT_FT_PSK;
else if (os_strcmp(start, "FT-EAP") == 0)
val |= WPA_KEY_MGMT_FT_IEEE8021X;
+#ifdef CONFIG_SHA384
+ else if (os_strcmp(start, "FT-EAP-SHA384") == 0)
+ val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
@@ -892,6 +896,18 @@
}
pos += ret;
}
+
+#ifdef CONFIG_SHA384
+ if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+ ret = os_snprintf(pos, end - pos, "%sFT-EAP-SHA384",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
+#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
@@ -1027,6 +1043,30 @@
#endif /* CONFIG_IEEE80211R */
#endif /* CONFIG_FILS */
+#ifdef CONFIG_DPP
+ if (ssid->key_mgmt & WPA_KEY_MGMT_DPP) {
+ ret = os_snprintf(pos, end - pos, "%sDPP",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
+#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_OWE
+ if (ssid->key_mgmt & WPA_KEY_MGMT_OWE) {
+ ret = os_snprintf(pos, end - pos, "%sOWE",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
+#endif /* CONFIG_OWE */
+
if (pos == buf) {
os_free(buf);
buf = NULL;
@@ -1962,16 +2002,21 @@
struct wpa_ssid *ssid, int line,
const char *value)
{
- if (hexstr2bin(value, ssid->mka_cak, MACSEC_CAK_LEN) ||
- value[MACSEC_CAK_LEN * 2] != '\0') {
+ size_t len;
+
+ len = os_strlen(value);
+ if (len > 2 * MACSEC_CAK_MAX_LEN ||
+ (len != 2 * 16 && len != 2 * 32) ||
+ hexstr2bin(value, ssid->mka_cak, len / 2)) {
wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CAK '%s'.",
line, value);
return -1;
}
-
+ ssid->mka_cak_len = len / 2;
ssid->mka_psk_set |= MKA_PSK_SET_CAK;
- wpa_hexdump_key(MSG_MSGDUMP, "MKA-CAK", ssid->mka_cak, MACSEC_CAK_LEN);
+ wpa_hexdump_key(MSG_MSGDUMP, "MKA-CAK", ssid->mka_cak,
+ ssid->mka_cak_len);
return 0;
}
@@ -1980,8 +2025,18 @@
struct wpa_ssid *ssid, int line,
const char *value)
{
- if (hexstr2bin(value, ssid->mka_ckn, MACSEC_CKN_LEN) ||
- value[MACSEC_CKN_LEN * 2] != '\0') {
+ size_t len;
+
+ len = os_strlen(value);
+ if (len > 2 * MACSEC_CKN_MAX_LEN || /* too long */
+ len < 2 || /* too short */
+ len % 2 != 0 /* not an integral number of bytes */) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.",
+ line, value);
+ return -1;
+ }
+ ssid->mka_ckn_len = len / 2;
+ if (hexstr2bin(value, ssid->mka_ckn, ssid->mka_ckn_len)) {
wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.",
line, value);
return -1;
@@ -1989,7 +2044,8 @@
ssid->mka_psk_set |= MKA_PSK_SET_CKN;
- wpa_hexdump_key(MSG_MSGDUMP, "MKA-CKN", ssid->mka_ckn, MACSEC_CKN_LEN);
+ wpa_hexdump_key(MSG_MSGDUMP, "MKA-CKN", ssid->mka_ckn,
+ ssid->mka_ckn_len);
return 0;
}
@@ -2002,7 +2058,7 @@
if (!(ssid->mka_psk_set & MKA_PSK_SET_CAK))
return NULL;
- return wpa_config_write_string_hex(ssid->mka_cak, MACSEC_CAK_LEN);
+ return wpa_config_write_string_hex(ssid->mka_cak, ssid->mka_cak_len);
}
@@ -2011,7 +2067,7 @@
{
if (!(ssid->mka_psk_set & MKA_PSK_SET_CKN))
return NULL;
- return wpa_config_write_string_hex(ssid->mka_ckn, MACSEC_CKN_LEN);
+ return wpa_config_write_string_hex(ssid->mka_ckn, ssid->mka_ckn_len);
}
#endif /* NO_CONFIG_WRITE */
@@ -2019,6 +2075,43 @@
#endif /* CONFIG_MACSEC */
+#ifdef CONFIG_OCV
+
+static int wpa_config_parse_ocv(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ char *end;
+
+ ssid->ocv = strtol(value, &end, 0);
+ if (*end || ssid->ocv < 0 || ssid->ocv > 1) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid ocv value '%s'.",
+ line, value);
+ return -1;
+ }
+ if (ssid->ocv && ssid->ieee80211w == NO_MGMT_FRAME_PROTECTION)
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
+ return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_ocv(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ char *value = os_malloc(20);
+
+ if (!value)
+ return NULL;
+ os_snprintf(value, 20, "%d", ssid->ocv);
+ value[20 - 1] = '\0';
+ return value;
+}
+#endif /* NO_CONFIG_WRITE */
+
+#endif /* CONFIG_OCV */
+
+
static int wpa_config_parse_peerkey(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
@@ -2134,6 +2227,7 @@
{ FUNC_KEY(psk) },
{ INT(mem_only_psk) },
{ STR_KEY(sae_password) },
+ { STR(sae_password_id) },
{ FUNC(proto) },
{ FUNC(key_mgmt) },
{ INT(bg_scan_period) },
@@ -2163,6 +2257,7 @@
{ STR_KEYe(private_key_passwd) },
{ STRe(dh_file) },
{ STRe(subject_match) },
+ { STRe(check_cert_subject) },
{ STRe(altsubject_match) },
{ STRe(domain_suffix_match) },
{ STRe(domain_match) },
@@ -2173,6 +2268,7 @@
{ STR_KEYe(private_key2_passwd) },
{ STRe(dh_file2) },
{ STRe(subject_match2) },
+ { STRe(check_cert_subject2) },
{ STRe(altsubject_match2) },
{ STRe(domain_suffix_match2) },
{ STRe(domain_match2) },
@@ -2221,6 +2317,9 @@
#ifdef CONFIG_IEEE80211W
{ INT_RANGE(ieee80211w, 0, 2) },
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ { FUNC(ocv) },
+#endif /* CONFIG_OCV */
{ FUNC(peerkey) /* obsolete - removed */ },
{ INT_RANGE(mixed_cell, 0, 1) },
{ INT_RANGE(frequency, 0, 65000) },
@@ -2250,6 +2349,8 @@
{ INT_RANGE(disable_sgi, 0, 1) },
{ INT_RANGE(disable_ldpc, 0, 1) },
{ INT_RANGE(ht40_intolerant, 0, 1) },
+ { INT_RANGE(tx_stbc, -1, 1) },
+ { INT_RANGE(rx_stbc, -1, 3) },
{ INT_RANGE(disable_max_amsdu, -1, 1) },
{ INT_RANGE(ampdu_factor, -1, 3) },
{ INT_RANGE(ampdu_density, -1, 7) },
@@ -2282,6 +2383,8 @@
#ifdef CONFIG_MACSEC
{ INT_RANGE(macsec_policy, 0, 1) },
{ INT_RANGE(macsec_integ_only, 0, 1) },
+ { INT_RANGE(macsec_replay_protect, 0, 1) },
+ { INT(macsec_replay_window) },
{ INT_RANGE(macsec_port, 1, 65534) },
{ INT_RANGE(mka_priority, 0, 255) },
{ FUNC_KEY(mka_cak) },
@@ -2289,6 +2392,7 @@
#endif /* CONFIG_MACSEC */
#ifdef CONFIG_HS20
{ INT(update_identifier) },
+ { STR_RANGE(roaming_consortium_selection, 0, MAX_ROAMING_CONS_OI_LEN) },
#endif /* CONFIG_HS20 */
{ INT_RANGE(mac_addr, 0, 2) },
{ INT_RANGE(pbss, 0, 2) },
@@ -2301,6 +2405,8 @@
{ STR_LEN(dpp_csign) },
#endif /* CONFIG_DPP */
{ INT_RANGE(owe_group, 0, 65535) },
+ { INT_RANGE(owe_only, 0, 1) },
+ { INT_RANGE(multi_ap_backhaul_sta, 0, 1) },
};
#undef OFFSET
@@ -2421,6 +2527,7 @@
str_clear_free(eap->private_key_passwd);
os_free(eap->dh_file);
os_free(eap->subject_match);
+ os_free(eap->check_cert_subject);
os_free(eap->altsubject_match);
os_free(eap->domain_suffix_match);
os_free(eap->domain_match);
@@ -2431,6 +2538,7 @@
str_clear_free(eap->private_key2_passwd);
os_free(eap->dh_file2);
os_free(eap->subject_match2);
+ os_free(eap->check_cert_subject2);
os_free(eap->altsubject_match2);
os_free(eap->domain_suffix_match2);
os_free(eap->domain_match2);
@@ -2472,6 +2580,7 @@
str_clear_free(ssid->passphrase);
os_free(ssid->ext_psk);
str_clear_free(ssid->sae_password);
+ os_free(ssid->sae_password_id);
#ifdef IEEE8021X_EAPOL
eap_peer_config_free(&ssid->eap);
#endif /* IEEE8021X_EAPOL */
@@ -2488,6 +2597,9 @@
#ifdef CONFIG_MESH
os_free(ssid->mesh_basic_rates);
#endif /* CONFIG_MESH */
+#ifdef CONFIG_HS20
+ os_free(ssid->roaming_consortium_selection);
+#endif /* CONFIG_HS20 */
os_free(ssid->dpp_connector);
bin_clear_free(ssid->dpp_netaccesskey, ssid->dpp_netaccesskey_len);
os_free(ssid->dpp_csign);
@@ -2763,6 +2875,8 @@
ssid->disable_ht40 = DEFAULT_DISABLE_HT40;
ssid->disable_sgi = DEFAULT_DISABLE_SGI;
ssid->disable_ldpc = DEFAULT_DISABLE_LDPC;
+ ssid->tx_stbc = DEFAULT_TX_STBC;
+ ssid->rx_stbc = DEFAULT_RX_STBC;
ssid->disable_max_amsdu = DEFAULT_DISABLE_MAX_AMSDU;
ssid->ampdu_factor = DEFAULT_AMPDU_FACTOR;
ssid->ampdu_density = DEFAULT_AMPDU_DENSITY;
@@ -2793,6 +2907,7 @@
ssid->mka_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
#endif /* CONFIG_MACSEC */
ssid->mac_addr = -1;
+ ssid->max_oper_chwidth = DEFAULT_MAX_OPER_CHWIDTH;
}
@@ -3103,11 +3218,64 @@
}
+static int wpa_config_set_cred_roaming_consortiums(struct wpa_cred *cred,
+ const char *value)
+{
+ u8 roaming_consortiums[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN];
+ size_t roaming_consortiums_len[MAX_ROAMING_CONS];
+ unsigned int num_roaming_consortiums = 0;
+ const char *pos, *end;
+ size_t len;
+
+ os_memset(roaming_consortiums, 0, sizeof(roaming_consortiums));
+ os_memset(roaming_consortiums_len, 0, sizeof(roaming_consortiums_len));
+
+ for (pos = value;;) {
+ end = os_strchr(pos, ',');
+ len = end ? (size_t) (end - pos) : os_strlen(pos);
+ if (!end && len == 0)
+ break;
+ if (len == 0 || (len & 1) != 0 ||
+ len / 2 > MAX_ROAMING_CONS_OI_LEN ||
+ hexstr2bin(pos,
+ roaming_consortiums[num_roaming_consortiums],
+ len / 2) < 0) {
+ wpa_printf(MSG_INFO,
+ "Invalid roaming_consortiums entry: %s",
+ pos);
+ return -1;
+ }
+ roaming_consortiums_len[num_roaming_consortiums] = len / 2;
+ num_roaming_consortiums++;
+
+ if (!end)
+ break;
+
+ if (num_roaming_consortiums >= MAX_ROAMING_CONS) {
+ wpa_printf(MSG_INFO,
+ "Too many roaming_consortiums OIs");
+ return -1;
+ }
+
+ pos = end + 1;
+ }
+
+ os_memcpy(cred->roaming_consortiums, roaming_consortiums,
+ sizeof(roaming_consortiums));
+ os_memcpy(cred->roaming_consortiums_len, roaming_consortiums_len,
+ sizeof(roaming_consortiums_len));
+ cred->num_roaming_consortiums = num_roaming_consortiums;
+
+ return 0;
+}
+
+
int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
const char *value, int line)
{
char *val;
size_t len;
+ int res;
if (os_strcmp(var, "temporary") == 0) {
cred->temporary = atoi(value);
@@ -3330,6 +3498,16 @@
return 0;
}
+ if (os_strcmp(var, "roaming_consortiums") == 0) {
+ res = wpa_config_set_cred_roaming_consortiums(cred, val);
+ if (res < 0)
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid roaming_consortiums",
+ line);
+ os_free(val);
+ return res;
+ }
+
if (os_strcmp(var, "excluded_ssid") == 0) {
struct excluded_ssid *e;
@@ -3641,6 +3819,31 @@
return buf;
}
+ if (os_strcmp(var, "roaming_consortiums") == 0) {
+ size_t buflen;
+ char *buf, *pos;
+ size_t i;
+
+ if (!cred->num_roaming_consortiums)
+ return NULL;
+ buflen = cred->num_roaming_consortiums *
+ MAX_ROAMING_CONS_OI_LEN * 2 + 1;
+ buf = os_malloc(buflen);
+ if (!buf)
+ return NULL;
+ pos = buf;
+ for (i = 0; i < cred->num_roaming_consortiums; i++) {
+ if (i > 0)
+ *pos++ = ',';
+ pos += wpa_snprintf_hex(
+ pos, buf + buflen - pos,
+ cred->roaming_consortiums[i],
+ cred->roaming_consortiums_len[i]);
+ }
+ *pos = '\0';
+ return buf;
+ }
+
if (os_strcmp(var, "excluded_ssid") == 0) {
unsigned int i;
char *buf, *end, *pos;
@@ -3898,6 +4101,7 @@
config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE;
config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT;
config->max_num_sta = DEFAULT_MAX_NUM_STA;
+ config->ap_isolate = DEFAULT_AP_ISOLATE;
config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE;
config->scan_cur_freq = DEFAULT_SCAN_CUR_FREQ;
config->wmm_ac_params[0] = ac_be;
@@ -4328,6 +4532,20 @@
return 0;
}
+static int wpa_config_process_p2p_device_persistent_mac_addr(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ if (hwaddr_aton2(pos, config->p2p_device_persistent_mac_addr) < 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid p2p_device_persistent_mac_addr '%s'",
+ line, pos);
+ return -1;
+ }
+
+ return 0;
+}
+
#endif /* CONFIG_P2P */
@@ -4538,6 +4756,7 @@
{ FUNC(os_version), CFG_CHANGED_OS_VERSION },
{ STR(config_methods), CFG_CHANGED_CONFIG_METHODS },
{ INT_RANGE(wps_cred_processing, 0, 2), 0 },
+ { INT_RANGE(wps_cred_add_sae, 0, 1), 0 },
{ FUNC(wps_vendor_ext_m1), CFG_CHANGED_VENDOR_EXTENSION },
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
@@ -4560,6 +4779,7 @@
{ INT_RANGE(p2p_optimize_listen_chan, 0, 1), 0 },
{ INT(p2p_go_ht40), 0 },
{ INT(p2p_go_vht), 0 },
+ { INT(p2p_go_he), 0 },
{ INT(p2p_disabled), 0 },
{ INT_RANGE(p2p_go_ctwindow, 0, 127), 0 },
{ INT(p2p_no_group_iface), 0 },
@@ -4569,6 +4789,9 @@
{ IPV4(ip_addr_start), 0 },
{ IPV4(ip_addr_end), 0 },
{ INT_RANGE(p2p_cli_probe, 0, 1), 0 },
+ { INT(p2p_device_random_mac_addr), 0 },
+ { FUNC(p2p_device_persistent_mac_addr), 0 },
+ { INT(p2p_interface_random_mac_addr), 0 },
#endif /* CONFIG_P2P */
{ FUNC(country), CFG_CHANGED_COUNTRY },
{ INT(bss_max_count), 0 },
@@ -4577,6 +4800,7 @@
{ INT_RANGE(filter_ssids, 0, 1), 0 },
{ INT_RANGE(filter_rssi, -100, 0), 0 },
{ INT(max_num_sta), 0 },
+ { INT_RANGE(ap_isolate, 0, 1), 0 },
{ INT_RANGE(disassoc_low_ack, 0, 1), 0 },
#ifdef CONFIG_HS20
{ INT_RANGE(hs20, 0, 1), 0 },
@@ -4642,6 +4866,8 @@
{ INT(gas_rand_addr_lifetime), 0 },
{ INT_RANGE(gas_rand_mac_addr, 0, 2), 0 },
{ INT_RANGE(dpp_config_processing, 0, 2), 0 },
+ { INT_RANGE(coloc_intf_reporting, 0, 1), 0 },
+ { INT_RANGE(bss_no_flush_when_down, 0, 1), 0 },
};
#undef FUNC
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 07b67e6..95817ff 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -32,6 +32,7 @@
#define DEFAULT_BSS_EXPIRATION_AGE 180
#define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2
#define DEFAULT_MAX_NUM_STA 128
+#define DEFAULT_AP_ISOLATE 0
#define DEFAULT_ACCESS_NETWORK_TYPE 15
#define DEFAULT_SCAN_CUR_FREQ 0
#define DEFAULT_P2P_SEARCH_DELAY 500
@@ -50,6 +51,9 @@
#include "common/ieee802_11_common.h"
+#define MAX_ROAMING_CONS 36
+#define MAX_ROAMING_CONS_OI_LEN 15
+
struct wpa_cred {
/**
* next - Next credential in the list
@@ -224,10 +228,43 @@
*/
size_t roaming_consortium_len;
+ /**
+ * required_roaming_consortium - Required Roaming Consortium OI
+ *
+ * If required_roaming_consortium_len is non-zero, this field contains
+ * the Roaming Consortium OI that is required to be advertised by the AP
+ * for the credential to be considered matching.
+ */
u8 required_roaming_consortium[15];
+
+ /**
+ * required_roaming_consortium_len - Length of required_roaming_consortium
+ */
size_t required_roaming_consortium_len;
/**
+ * roaming_consortiums - Roaming Consortium OI(s) memberships
+ *
+ * This field contains one or more OIs identifying the roaming
+ * consortiums of which the provider is a member. The list is sorted
+ * from the most preferred one to the least preferred one. A match
+ * between the Roaming Consortium OIs advertised by an AP and the OIs
+ * in this list indicates that successful authentication is possible.
+ * (Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/RoamingConsortiumOI)
+ */
+ u8 roaming_consortiums[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN];
+
+ /**
+ * roaming_consortiums_len - Length on roaming_consortiums[i]
+ */
+ size_t roaming_consortiums_len[MAX_ROAMING_CONS];
+
+ /**
+ * num_roaming_consortiums - Number of entries in roaming_consortiums
+ */
+ unsigned int num_roaming_consortiums;
+
+ /**
* eap_method - EAP method to use
*
* Pre-configured EAP method to use with this credential or %NULL to
@@ -708,6 +745,16 @@
*/
int wps_cred_processing;
+ /**
+ * wps_cred_add_sae - Whether to enable SAE automatically for WPS
+ *
+ * 0 = only add the explicitly listed WPA2-PSK configuration
+ * 1 = add both the WPA2-PSK and SAE configuration and enable PMF so
+ * that the station gets configured in WPA3-Personal transition mode
+ * (supports both WPA2-Personal (PSK) and WPA3-Personal (SAE) APs).
+ */
+ int wps_cred_add_sae;
+
#define MAX_SEC_DEVICE_TYPES 5
/**
* sec_device_types - Secondary Device Types (P2P)
@@ -843,6 +890,20 @@
unsigned int max_num_sta;
/**
+ * ap_isolate - Whether to use client isolation feature
+ *
+ * Client isolation can be used to prevent low-level bridging of
+ * frames between associated stations in the BSS. By default,
+ * this bridging is allowed (ap_isolate=0); except in P2P GO case,
+ * where p2p_intra_bss parameter is used to determine whether to allow
+ * intra-BSS forwarding (ap_isolate = !p2p_intra_bss).
+ *
+ * 0 = do not enable AP isolation
+ * 1 = enable AP isolation
+ */
+ int ap_isolate;
+
+ /**
* freq_list - Array of allowed scan frequencies or %NULL for all
*
* This is an optional zero-terminated array of frequencies in
@@ -864,7 +925,7 @@
unsigned int changed_parameters;
/**
- * disassoc_low_ack - Disassocicate stations with massive packet loss
+ * disassoc_low_ack - Disassociate stations with massive packet loss
*/
int disassoc_low_ack;
@@ -1028,6 +1089,16 @@
int p2p_go_vht;
/**
+ * p2p_go_he - Default mode for 11ax HE enable when operating as GO
+ *
+ * This will take effect for p2p_group_add, p2p_connect, and p2p_invite.
+ * Note that regulatory constraints and driver capabilities are
+ * consulted anyway, so setting it to 1 can't do real harm.
+ * By default: 0 (disabled)
+ */
+ int p2p_go_he;
+
+ /**
* p2p_go_ctwindow - CTWindow to use when operating as GO
*
* By default: 0 (no CTWindow). Values 0-127 can be used to indicate
@@ -1418,6 +1489,52 @@
* profile automatically
*/
int dpp_config_processing;
+
+ /**
+ * coloc_intf_reporting - Colocated interference reporting
+ *
+ * dot11CoLocIntfReportingActivated
+ * 0 = disabled (false)
+ * 1 = enabled (true)
+ */
+ int coloc_intf_reporting;
+
+ /**
+ * p2p_device_random_mac_addr - P2P Device MAC address policy default
+ *
+ * 0 = use permanent MAC address
+ * 1 = use random MAC address on creating the interface if there is no
+ * persistent groups.
+ *
+ * By default, permanent MAC address is used.
+ */
+ int p2p_device_random_mac_addr;
+
+ /**
+ * p2p_device_persistent_mac_addr - Record last used MAC address
+ *
+ * If there are saved persistent groups, P2P cannot generate another
+ * random MAC address, and need to restore to last used MAC address.
+ */
+ u8 p2p_device_persistent_mac_addr[ETH_ALEN];
+
+ /**
+ * p2p_interface_random_mac_addr - P2P Interface MAC address policy default
+ *
+ * 0 = use permanent MAC address
+ * 1 = use random MAC address on creating the interface.
+ *
+ * By default, permanent MAC address is used.
+ */
+ int p2p_interface_random_mac_addr;
+
+ /**
+ * bss_no_flush_when_down - Whether to flush BSS entries when the interface is disabled
+ *
+ * 0 = Flush BSS entries when the interface becomes disabled (Default)
+ * 1 = Do not flush BSS entries when the interface becomes disabled
+ */
+ int bss_no_flush_when_down;
};
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 1fd432d..2c6035c 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -141,8 +141,9 @@
ssid->p2p_persistent_group = 1;
if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
- !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
- !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
+ !(ssid->pairwise_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_CCMP_256 |
+ WPA_CIPHER_GCMP | WPA_CIPHER_GCMP_256 |
+ WPA_CIPHER_NONE))) {
/* Group cipher cannot be stronger than the pairwise cipher. */
wpa_printf(MSG_DEBUG, "Line %d: removed CCMP from group cipher"
" list since it was not allowed for pairwise "
@@ -159,6 +160,15 @@
errors++;
}
+#ifdef CONFIG_OCV
+ if (ssid->ocv && ssid->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: PMF needs to be enabled whenever using OCV",
+ line);
+ errors++;
+ }
+#endif /* CONFIG_OCV */
+
return errors;
}
@@ -464,7 +474,8 @@
#ifndef WPA_IGNORE_CONFIG_ERRORS
if (errors) {
- wpa_config_free(config);
+ if (config != cfgp)
+ wpa_config_free(config);
config = NULL;
head = NULL;
}
@@ -482,7 +493,7 @@
if (value == NULL)
return;
fprintf(f, "\t%s=%s\n", field, value);
- os_free(value);
+ str_clear_free(value);
}
@@ -747,6 +758,7 @@
write_psk(f, ssid);
INT(mem_only_psk);
STR(sae_password);
+ STR(sae_password_id);
write_proto(f, ssid);
write_key_mgmt(f, ssid);
INT_DEF(bg_scan_period, DEFAULT_BG_SCAN_PERIOD);
@@ -770,6 +782,7 @@
STR(private_key_passwd);
STR(dh_file);
STR(subject_match);
+ STR(check_cert_subject);
STR(altsubject_match);
STR(domain_suffix_match);
STR(domain_match);
@@ -780,6 +793,7 @@
STR(private_key2_passwd);
STR(dh_file2);
STR(subject_match2);
+ STR(check_cert_subject2);
STR(altsubject_match2);
STR(domain_suffix_match2);
STR(domain_match2);
@@ -826,7 +840,7 @@
INT(vht);
INT_DEF(ht, 1);
INT(ht40);
- INT(max_oper_chwidth);
+ INT_DEF(max_oper_chwidth, DEFAULT_MAX_OPER_CHWIDTH);
INT(vht_center_freq1);
INT(vht_center_freq2);
INT(pbss);
@@ -850,11 +864,14 @@
write_mka_cak(f, ssid);
write_mka_ckn(f, ssid);
INT(macsec_integ_only);
+ INT(macsec_replay_protect);
+ INT(macsec_replay_window);
INT(macsec_port);
INT_DEF(mka_priority, DEFAULT_PRIO_NOT_KEY_SERVER);
#endif /* CONFIG_MACSEC */
#ifdef CONFIG_HS20
INT(update_identifier);
+ STR(roaming_consortium_selection);
#endif /* CONFIG_HS20 */
write_int(f, "mac_addr", ssid->mac_addr, -1);
#ifdef CONFIG_MESH
@@ -875,12 +892,16 @@
STR(dpp_csign);
#endif /* CONFIG_DPP */
INT(owe_group);
+ INT(owe_only);
+ INT(multi_ap_backhaul_sta);
#ifdef CONFIG_HT_OVERRIDES
INT_DEF(disable_ht, DEFAULT_DISABLE_HT);
INT_DEF(disable_ht40, DEFAULT_DISABLE_HT40);
INT_DEF(disable_sgi, DEFAULT_DISABLE_SGI);
INT_DEF(disable_ldpc, DEFAULT_DISABLE_LDPC);
INT(ht40_intolerant);
+ INT_DEF(tx_stbc, DEFAULT_TX_STBC);
+ INT_DEF(rx_stbc, DEFAULT_RX_STBC);
INT_DEF(disable_max_amsdu, DEFAULT_DISABLE_MAX_AMSDU);
INT_DEF(ampdu_factor, DEFAULT_AMPDU_FACTOR);
INT_DEF(ampdu_density, DEFAULT_AMPDU_DENSITY);
@@ -1037,6 +1058,20 @@
fprintf(f, "\n");
}
+ if (cred->num_roaming_consortiums) {
+ size_t j;
+
+ fprintf(f, "\troaming_consortiums=\"");
+ for (i = 0; i < cred->num_roaming_consortiums; i++) {
+ if (i > 0)
+ fprintf(f, ",");
+ for (j = 0; j < cred->roaming_consortiums_len[i]; j++)
+ fprintf(f, "%02x",
+ cred->roaming_consortiums[i][j]);
+ }
+ fprintf(f, "\"\n");
+ }
+
if (cred->sim_num != DEFAULT_USER_SELECTED_SIM)
fprintf(f, "\tsim_num=%d\n", cred->sim_num);
}
@@ -1154,6 +1189,9 @@
if (config->wps_cred_processing)
fprintf(f, "wps_cred_processing=%d\n",
config->wps_cred_processing);
+ if (config->wps_cred_add_sae)
+ fprintf(f, "wps_cred_add_sae=%d\n",
+ config->wps_cred_add_sae);
if (config->wps_vendor_ext_m1) {
int i, len = wpabuf_len(config->wps_vendor_ext_m1);
const u8 *p = wpabuf_head_u8(config->wps_vendor_ext_m1);
@@ -1229,6 +1267,8 @@
fprintf(f, "p2p_go_ht40=%d\n", config->p2p_go_ht40);
if (config->p2p_go_vht)
fprintf(f, "p2p_go_vht=%d\n", config->p2p_go_vht);
+ if (config->p2p_go_he)
+ fprintf(f, "p2p_go_he=%d\n", config->p2p_go_he);
if (config->p2p_go_ctwindow != DEFAULT_P2P_GO_CTWINDOW)
fprintf(f, "p2p_go_ctwindow=%d\n", config->p2p_go_ctwindow);
if (config->p2p_disabled)
@@ -1280,6 +1320,8 @@
fprintf(f, "filter_rssi=%d\n", config->filter_rssi);
if (config->max_num_sta != DEFAULT_MAX_NUM_STA)
fprintf(f, "max_num_sta=%u\n", config->max_num_sta);
+ if (config->ap_isolate != DEFAULT_AP_ISOLATE)
+ fprintf(f, "ap_isolate=%u\n", config->ap_isolate);
if (config->disassoc_low_ack)
fprintf(f, "disassoc_low_ack=%d\n", config->disassoc_low_ack);
#ifdef CONFIG_HS20
@@ -1490,6 +1532,21 @@
if (config->dpp_config_processing)
fprintf(f, "dpp_config_processing=%d\n",
config->dpp_config_processing);
+ if (config->coloc_intf_reporting)
+ fprintf(f, "coloc_intf_reporting=%d\n",
+ config->coloc_intf_reporting);
+ if (config->p2p_device_random_mac_addr)
+ fprintf(f, "p2p_device_random_mac_addr=%d\n",
+ config->p2p_device_random_mac_addr);
+ if (!is_zero_ether_addr(config->p2p_device_persistent_mac_addr))
+ fprintf(f, "p2p_device_persistent_mac_addr=" MACSTR "\n",
+ MAC2STR(config->p2p_device_persistent_mac_addr));
+ if (config->p2p_interface_random_mac_addr)
+ fprintf(f, "p2p_interface_random_mac_addr=%d\n",
+ config->p2p_interface_random_mac_addr);
+ if (config->bss_no_flush_when_down)
+ fprintf(f, "bss_no_flush_when_down=%d\n",
+ config->bss_no_flush_when_down);
}
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 83d657d..1b2b1f1 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -33,10 +33,13 @@
#define DEFAULT_DISABLE_HT40 0
#define DEFAULT_DISABLE_SGI 0
#define DEFAULT_DISABLE_LDPC 0
+#define DEFAULT_TX_STBC -1 /* no change */
+#define DEFAULT_RX_STBC -1 /* no change */
#define DEFAULT_DISABLE_MAX_AMSDU -1 /* no change */
#define DEFAULT_AMPDU_FACTOR -1 /* no change */
#define DEFAULT_AMPDU_DENSITY -1 /* no change */
#define DEFAULT_USER_SELECTED_SIM 1
+#define DEFAULT_MAX_OPER_CHWIDTH -1
struct psk_list_entry {
struct dl_list list;
@@ -194,6 +197,14 @@
char *sae_password;
/**
+ * sae_password_id - SAE password identifier
+ *
+ * This parameter can be used to identify a specific SAE password. If
+ * not included, the default SAE password is used instead.
+ */
+ char *sae_password_id;
+
+ /**
* ext_psk - PSK/passphrase name in external storage
*
* If this is set, PSK/passphrase will be fetched from external storage
@@ -449,6 +460,17 @@
enum mfp_options ieee80211w;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ /**
+ * ocv - Enable/disable operating channel validation
+ *
+ * If this parameter is set to 1, stations will exchange OCI element
+ * to cryptographically verify the operating channel. Setting this
+ * parameter to 0 disables this option. Default value: 0.
+ */
+ int ocv;
+#endif /* CONFIG_OCV */
+
/**
* frequency - Channel frequency in megahertz (MHz) for IBSS
*
@@ -497,7 +519,9 @@
int vht;
- u8 max_oper_chwidth;
+ int he;
+
+ int max_oper_chwidth;
unsigned int vht_center_freq1;
unsigned int vht_center_freq2;
@@ -674,6 +698,22 @@
* By default (empty string): Use whatever the OS has configured.
*/
char *ht_mcs;
+
+ /**
+ * tx_stbc - Indicate STBC support for TX streams
+ *
+ * Value: -1..1, by default (-1): use whatever the OS or card has
+ * configured. See IEEE Std 802.11-2016, 9.4.2.56.2.
+ */
+ int tx_stbc;
+
+ /**
+ * rx_stbc - Indicate STBC support for RX streams
+ *
+ * Value: -1..3, by default (-1): use whatever the OS or card has
+ * configured. See IEEE Std 802.11-2016, 9.4.2.56.2.
+ */
+ int rx_stbc;
#endif /* CONFIG_HT_OVERRIDES */
#ifdef CONFIG_VHT_OVERRIDES
@@ -766,6 +806,33 @@
int macsec_integ_only;
/**
+ * macsec_replay_protect - Enable MACsec replay protection
+ *
+ * This setting applies only when MACsec is in use, i.e.,
+ * - macsec_policy is enabled
+ * - the key server has decided to enable MACsec
+ *
+ * 0: Replay protection disabled (default)
+ * 1: Replay protection enabled
+ */
+ int macsec_replay_protect;
+
+ /**
+ * macsec_replay_window - MACsec replay protection window
+ *
+ * A window in which replay is tolerated, to allow receipt of frames
+ * that have been misordered by the network.
+ *
+ * This setting applies only when MACsec replay protection active, i.e.,
+ * - macsec_replay_protect is enabled
+ * - the key server has decided to enable MACsec
+ *
+ * 0: No replay window, strict check (default)
+ * 1..2^32-1: number of packets that could be misordered
+ */
+ u32 macsec_replay_window;
+
+ /**
* macsec_port - MACsec port (in SCI)
*
* Port component of the SCI.
@@ -784,14 +851,16 @@
/**
* mka_ckn - MKA pre-shared CKN
*/
-#define MACSEC_CKN_LEN 32
- u8 mka_ckn[MACSEC_CKN_LEN];
+#define MACSEC_CKN_MAX_LEN 32
+ size_t mka_ckn_len;
+ u8 mka_ckn[MACSEC_CKN_MAX_LEN];
/**
* mka_cak - MKA pre-shared CAK
*/
-#define MACSEC_CAK_LEN 16
- u8 mka_cak[MACSEC_CAK_LEN];
+#define MACSEC_CAK_MAX_LEN 32
+ size_t mka_cak_len;
+ u8 mka_cak[MACSEC_CAK_MAX_LEN];
#define MKA_PSK_SET_CKN BIT(0)
#define MKA_PSK_SET_CAK BIT(1)
@@ -804,6 +873,19 @@
#ifdef CONFIG_HS20
int update_identifier;
+
+ /**
+ * roaming_consortium_selection - Roaming Consortium Selection
+ *
+ * The matching Roaming Consortium OI that was used to generate this
+ * network profile.
+ */
+ u8 *roaming_consortium_selection;
+
+ /**
+ * roaming_consortium_selection_len - roaming_consortium_selection len
+ */
+ size_t roaming_consortium_selection_len;
#endif /* CONFIG_HS20 */
unsigned int wps_run;
@@ -889,13 +971,40 @@
/**
* owe_group - OWE DH Group
*
- * 0 = use default (19)
+ * 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.
*/
int owe_group;
+
+ /**
+ * owe_only - 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)
+ */
+ int owe_only;
+
+ /**
+ * owe_transition_bss_select_count - OWE transition BSS select count
+ *
+ * This is an internally used variable (i.e., not used in external
+ * configuration) to track the number of selection attempts done for
+ * OWE BSS in transition mode. This allows fallback to an open BSS if
+ * the selection attempts for OWE BSS exceed the configured threshold.
+ */
+ int owe_transition_bss_select_count;
+
+ /**
+ * multi_ap_backhaul_sta - Multi-AP backhaul STA
+ * 0 = normal (non-Multi-AP) station
+ * 1 = Multi-AP backhaul station
+ */
+ int multi_ap_backhaul_sta;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 0ba1aa5..6328e91 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -255,6 +255,8 @@
errors++;
wpa_config_read_reg_dword(hk, TEXT("wps_cred_processing"),
&config->wps_cred_processing);
+ wpa_config_read_reg_dword(hk, TEXT("wps_cred_add_sae"),
+ &config->wps_cred_add_sae);
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
config->p2p_ssid_postfix = wpa_config_read_reg_string(
@@ -604,6 +606,8 @@
}
wpa_config_write_reg_dword(hk, TEXT("wps_cred_processing"),
config->wps_cred_processing, 0);
+ wpa_config_write_reg_dword(hk, TEXT("wps_cred_add_sae"),
+ config->wps_cred_add_sae, 0);
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
wpa_config_write_reg_string(hk, "p2p_ssid_postfix",
@@ -619,6 +623,8 @@
config->filter_ssids, 0);
wpa_config_write_reg_dword(hk, TEXT("max_num_sta"),
config->max_num_sta, DEFAULT_MAX_NUM_STA);
+ wpa_config_write_reg_dword(hk, TEXT("ap_isolate"),
+ config->ap_isolate, DEFAULT_AP_ISOLATE);
wpa_config_write_reg_dword(hk, TEXT("disassoc_low_ack"),
config->disassoc_low_ack, 0);
@@ -871,6 +877,7 @@
write_bssid(netw, ssid);
write_psk(netw, ssid);
STR(sae_password);
+ STR(sae_password_id);
write_proto(netw, ssid);
write_key_mgmt(netw, ssid);
write_pairwise(netw, ssid);
@@ -889,6 +896,7 @@
STR(private_key_passwd);
STR(dh_file);
STR(subject_match);
+ STR(check_cert_subject);
STR(altsubject_match);
STR(ca_cert2);
STR(ca_path2);
@@ -897,6 +905,7 @@
STR(private_key2_passwd);
STR(dh_file2);
STR(subject_match2);
+ STR(check_cert_subject2);
STR(altsubject_match2);
STR(phase1);
STR(phase2);
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index c4d8dfe..198ac56 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Control interface (shared code for all backends)
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -20,6 +20,9 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
+#ifdef CONFIG_DPP
+#include "common/dpp.h"
+#endif /* CONFIG_DPP */
#include "crypto/tls.h"
#include "ap/hostapd.h"
#include "eap_peer/eap.h"
@@ -53,6 +56,7 @@
#include "drivers/driver.h"
#include "mesh.h"
#include "dpp_supplicant.h"
+#include "sme.h"
static int wpa_supplicant_global_iface_list(struct wpa_global *global,
char *buf, int len);
@@ -63,28 +67,6 @@
char *val);
-#ifdef CONFIG_FILS
-
-static int wpa_is_fils_supported(struct wpa_supplicant *wpa_s)
-{
- return (((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
- (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS)) ||
- (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
- (wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD)));
-}
-
-
-#ifdef CONFIG_FILS_SK_PFS
-static int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s)
-{
- return (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
- (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS);
-}
-#endif /* CONFIG_FILS_SK_PFS */
-
-#endif /* CONFIG_FILS */
-
-
static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val)
{
char *pos;
@@ -604,6 +586,54 @@
} else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) {
os_free(wpa_s->dpp_configurator_params);
wpa_s->dpp_configurator_params = os_strdup(value);
+ } else if (os_strcasecmp(cmd, "dpp_init_max_tries") == 0) {
+ wpa_s->dpp_init_max_tries = atoi(value);
+ } else if (os_strcasecmp(cmd, "dpp_init_retry_time") == 0) {
+ wpa_s->dpp_init_retry_time = atoi(value);
+ } else if (os_strcasecmp(cmd, "dpp_resp_wait_time") == 0) {
+ wpa_s->dpp_resp_wait_time = atoi(value);
+ } else if (os_strcasecmp(cmd, "dpp_resp_max_tries") == 0) {
+ wpa_s->dpp_resp_max_tries = atoi(value);
+ } else if (os_strcasecmp(cmd, "dpp_resp_retry_time") == 0) {
+ wpa_s->dpp_resp_retry_time = atoi(value);
+#ifdef CONFIG_TESTING_OPTIONS
+ } else if (os_strcasecmp(cmd, "dpp_pkex_own_mac_override") == 0) {
+ if (hwaddr_aton(value, dpp_pkex_own_mac_override))
+ ret = -1;
+ } else if (os_strcasecmp(cmd, "dpp_pkex_peer_mac_override") == 0) {
+ if (hwaddr_aton(value, dpp_pkex_peer_mac_override))
+ ret = -1;
+ } else if (os_strcasecmp(cmd, "dpp_pkex_ephemeral_key_override") == 0) {
+ size_t hex_len = os_strlen(value);
+
+ if (hex_len >
+ 2 * sizeof(dpp_pkex_ephemeral_key_override))
+ ret = -1;
+ else if (hexstr2bin(value, dpp_pkex_ephemeral_key_override,
+ hex_len / 2))
+ ret = -1;
+ else
+ dpp_pkex_ephemeral_key_override_len = hex_len / 2;
+ } else if (os_strcasecmp(cmd, "dpp_protocol_key_override") == 0) {
+ size_t hex_len = os_strlen(value);
+
+ if (hex_len > 2 * sizeof(dpp_protocol_key_override))
+ ret = -1;
+ else if (hexstr2bin(value, dpp_protocol_key_override,
+ hex_len / 2))
+ ret = -1;
+ else
+ dpp_protocol_key_override_len = hex_len / 2;
+ } else if (os_strcasecmp(cmd, "dpp_nonce_override") == 0) {
+ size_t hex_len = os_strlen(value);
+
+ if (hex_len > 2 * sizeof(dpp_nonce_override))
+ ret = -1;
+ else if (hexstr2bin(value, dpp_nonce_override, hex_len / 2))
+ ret = -1;
+ else
+ dpp_nonce_override_len = hex_len / 2;
+#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_DPP */
#ifdef CONFIG_TESTING_OPTIONS
} else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
@@ -645,18 +675,35 @@
#ifdef CONFIG_DPP
} else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
os_free(wpa_s->dpp_config_obj_override);
- wpa_s->dpp_config_obj_override = os_strdup(value);
+ if (value[0] == '\0')
+ wpa_s->dpp_config_obj_override = NULL;
+ else
+ wpa_s->dpp_config_obj_override = os_strdup(value);
} else if (os_strcasecmp(cmd, "dpp_discovery_override") == 0) {
os_free(wpa_s->dpp_discovery_override);
- wpa_s->dpp_discovery_override = os_strdup(value);
+ if (value[0] == '\0')
+ wpa_s->dpp_discovery_override = NULL;
+ else
+ wpa_s->dpp_discovery_override = os_strdup(value);
} else if (os_strcasecmp(cmd, "dpp_groups_override") == 0) {
os_free(wpa_s->dpp_groups_override);
- wpa_s->dpp_groups_override = os_strdup(value);
+ if (value[0] == '\0')
+ wpa_s->dpp_groups_override = NULL;
+ else
+ wpa_s->dpp_groups_override = os_strdup(value);
} else if (os_strcasecmp(cmd,
"dpp_ignore_netaccesskey_mismatch") == 0) {
wpa_s->dpp_ignore_netaccesskey_mismatch = atoi(value);
+ } else if (os_strcasecmp(cmd, "dpp_test") == 0) {
+ dpp_test = atoi(value);
#endif /* CONFIG_DPP */
#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_FILS
+ } else if (os_strcasecmp(cmd, "disable_fils") == 0) {
+ wpa_s->disable_fils = !!atoi(value);
+ wpa_drv_disable_fils(wpa_s, wpa_s->disable_fils);
+ wpa_supplicant_set_default_scan_ies(wpa_s);
+#endif /* CONFIG_FILS */
#ifndef CONFIG_NO_CONFIG_BLOBS
} else if (os_strcmp(cmd, "blob") == 0) {
ret = wpas_ctrl_set_blob(wpa_s, value);
@@ -704,6 +751,15 @@
ret = wpas_ctrl_iface_set_ric_ies(wpa_s, value);
} else if (os_strcasecmp(cmd, "roaming") == 0) {
ret = wpa_drv_roaming(wpa_s, atoi(value), NULL);
+#ifdef CONFIG_WNM
+ } else if (os_strcasecmp(cmd, "coloc_intf_elems") == 0) {
+ struct wpabuf *elems;
+
+ elems = wpabuf_parse_bin(value);
+ if (!elems)
+ return -1;
+ wnm_set_coloc_intf_elems(wpa_s, elems);
+#endif /* CONFIG_WNM */
} else {
value[-1] = '=';
ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -1112,8 +1168,11 @@
#ifdef CONFIG_AP
u8 *_p2p_dev_addr = NULL;
#endif /* CONFIG_AP */
+ char *pos;
+ int multi_ap = 0;
- if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
+ if (!cmd || os_strcmp(cmd, "any") == 0 ||
+ os_strncmp(cmd, "any ", 4) == 0) {
_bssid = NULL;
#ifdef CONFIG_P2P
} else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
@@ -1125,18 +1184,29 @@
}
_p2p_dev_addr = p2p_dev_addr;
#endif /* CONFIG_P2P */
+ } else if (os_strncmp(cmd, "multi_ap=", 9) == 0) {
+ _bssid = NULL;
+ multi_ap = atoi(cmd + 9);
} else if (hwaddr_aton(cmd, bssid)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
cmd);
return -1;
}
+ if (cmd) {
+ pos = os_strstr(cmd, " multi_ap=");
+ if (pos) {
+ pos += 10;
+ multi_ap = atoi(pos);
+ }
+ }
+
#ifdef CONFIG_AP
if (wpa_s->ap_iface)
return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr);
#endif /* CONFIG_AP */
- return wpas_wps_start_pbc(wpa_s, _bssid, 0);
+ return wpas_wps_start_pbc(wpa_s, _bssid, 0, multi_ap);
}
@@ -2062,6 +2132,18 @@
pos += ret;
}
+ if (wpa_s->connection_set &&
+ (wpa_s->connection_ht || wpa_s->connection_vht ||
+ wpa_s->connection_he)) {
+ ret = os_snprintf(pos, end - pos,
+ "wifi_generation=%u\n",
+ wpa_s->connection_he ? 6 :
+ (wpa_s->connection_vht ? 5 : 4));
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
#ifdef CONFIG_AP
if (wpa_s->ap_iface) {
pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos,
@@ -2246,6 +2328,13 @@
}
#endif /* CONFIG_WPS */
+ if (wpa_s->ieee80211ac) {
+ ret = os_snprintf(pos, end - pos, "ieee80211ac=1\n");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
#ifdef ANDROID
/*
* Allow using the STATUS command with default behavior, say for debug,
@@ -2850,6 +2939,12 @@
pos += ret;
}
#endif /* CONFIG_FST */
+ if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_UTF_8_SSID)) {
+ ret = os_snprintf(pos, end - pos, "[UTF-8]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
ret = os_snprintf(pos, end - pos, "\t%s",
wpa_ssid_txt(bss->ssid, bss->ssid_len));
@@ -3925,6 +4020,22 @@
}
#endif /* CONFIG_IEEE80211R */
#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R
+ if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) {
+ ret = os_snprintf(pos, end - pos, " FT-PSK");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+ if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) {
+ ret = os_snprintf(pos, end - pos, " SAE");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SAE */
return pos - buf;
}
@@ -4325,6 +4436,26 @@
}
#endif /* CONFIG_FILS */
+ if (os_strcmp(field, "multibss") == 0 && wpa_s->multi_bss_support) {
+ res = os_snprintf(buf, buflen, "MULTIBSS-STA");
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+
+#ifdef CONFIG_DPP
+ if (os_strcmp(field, "dpp") == 0) {
+#ifdef CONFIG_DPP2
+ res = os_snprintf(buf, buflen, "DPP=2");
+#else /* CONFIG_DPP2 */
+ res = os_snprintf(buf, buflen, "DPP=1");
+#endif /* CONFIG_DPP2 */
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+#endif /* CONFIG_DPP */
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
field);
@@ -4655,6 +4786,20 @@
pos += ret;
}
#endif /* CONFIG_FILS */
+#ifdef CONFIG_FST
+ if (wpa_bss_get_ie(bss, WLAN_EID_MULTI_BAND)) {
+ ret = os_snprintf(pos, end - pos, "[FST]");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+#endif /* CONFIG_FST */
+ if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_UTF_8_SSID)) {
+ ret = os_snprintf(pos, end - pos, "[UTF-8]");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
ret = os_snprintf(pos, end - pos, "\n");
if (os_snprintf_error(end - pos, ret))
@@ -4754,6 +4899,10 @@
anqp->hs20_operating_class);
pos = anqp_add_hex(pos, end, "hs20_osu_providers_list",
anqp->hs20_osu_providers_list);
+ pos = anqp_add_hex(pos, end, "hs20_operator_icon_metadata",
+ anqp->hs20_operator_icon_metadata);
+ pos = anqp_add_hex(pos, end, "hs20_osu_providers_nai_list",
+ anqp->hs20_osu_providers_nai_list);
#endif /* CONFIG_HS20 */
dl_list_for_each(elem, &anqp->anqp_elems,
@@ -4947,10 +5096,11 @@
bss = NULL;
dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id)
{
- if (i-- == 0) {
+ if (i == 0) {
bss = tmp;
break;
}
+ i--;
}
}
@@ -5436,6 +5586,7 @@
int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
u8 _group_ssid[SSID_MAX_LEN], *group_ssid = NULL;
size_t group_ssid_len = 0;
+ int he;
if (!wpa_s->global->p2p_init_wpa_s)
return -1;
@@ -5448,7 +5599,7 @@
/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps]
* [persistent|persistent=<network id>]
* [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
- * [ht40] [vht] [auto] [ssid=<hexdump>] */
+ * [ht40] [vht] [he] [auto] [ssid=<hexdump>] */
if (hwaddr_aton(cmd, addr))
return -1;
@@ -5479,6 +5630,7 @@
vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
vht;
+ he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he;
pos2 = os_strstr(pos, " go_intent=");
if (pos2) {
@@ -5549,7 +5701,7 @@
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, automatic, join,
auth, go_intent, freq, freq2, persistent_id,
- pd, ht40, vht, max_oper_chwidth,
+ pd, ht40, vht, max_oper_chwidth, he,
group_ssid, group_ssid_len);
if (new_pin == -2) {
os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
@@ -6105,7 +6257,7 @@
struct wpa_ssid *ssid;
u8 *_peer = NULL, peer[ETH_ALEN];
int freq = 0, pref_freq = 0;
- int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
+ int ht40, vht, he, max_oper_chwidth, chwidth = 0, freq2 = 0;
id = atoi(cmd);
pos = os_strstr(cmd, " peer=");
@@ -6142,6 +6294,7 @@
vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
vht;
+ he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he;
pos = os_strstr(cmd, "freq2=");
if (pos)
@@ -6156,7 +6309,7 @@
return -1;
return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
- max_oper_chwidth, pref_freq);
+ max_oper_chwidth, pref_freq, he);
}
@@ -6204,7 +6357,8 @@
static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
int id, int freq, int vht_center_freq2,
- int ht40, int vht, int vht_chwidth)
+ int ht40, int vht, int vht_chwidth,
+ int he)
{
struct wpa_ssid *ssid;
@@ -6218,7 +6372,7 @@
return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq,
vht_center_freq2, 0, ht40, vht,
- vht_chwidth, NULL, 0, 0);
+ vht_chwidth, he, NULL, 0, 0);
}
@@ -6227,20 +6381,31 @@
int freq = 0, persistent = 0, group_id = -1;
int vht = wpa_s->conf->p2p_go_vht;
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
+ int he = wpa_s->conf->p2p_go_he;
int max_oper_chwidth, chwidth = 0, freq2 = 0;
char *token, *context = NULL;
+#ifdef CONFIG_ACS
+ int acs = 0;
+#endif /* CONFIG_ACS */
while ((token = str_token(cmd, " ", &context))) {
- if (sscanf(token, "freq=%d", &freq) == 1 ||
- sscanf(token, "freq2=%d", &freq2) == 1 ||
+ if (sscanf(token, "freq2=%d", &freq2) == 1 ||
sscanf(token, "persistent=%d", &group_id) == 1 ||
sscanf(token, "max_oper_chwidth=%d", &chwidth) == 1) {
continue;
+#ifdef CONFIG_ACS
+ } else if (os_strcmp(token, "freq=acs") == 0) {
+ acs = 1;
+#endif /* CONFIG_ACS */
+ } else if (sscanf(token, "freq=%d", &freq) == 1) {
+ continue;
} else if (os_strcmp(token, "ht40") == 0) {
ht40 = 1;
} else if (os_strcmp(token, "vht") == 0) {
vht = 1;
ht40 = 1;
+ } else if (os_strcmp(token, "he") == 0) {
+ he = 1;
} else if (os_strcmp(token, "persistent") == 0) {
persistent = 1;
} else {
@@ -6251,6 +6416,26 @@
}
}
+#ifdef CONFIG_ACS
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) &&
+ (acs || freq == 2 || freq == 5)) {
+ if (freq == 2 && wpa_s->best_24_freq <= 0) {
+ wpa_s->p2p_go_acs_band = HOSTAPD_MODE_IEEE80211G;
+ wpa_s->p2p_go_do_acs = 1;
+ freq = 0;
+ } else if (freq == 5 && wpa_s->best_5_freq <= 0) {
+ wpa_s->p2p_go_acs_band = HOSTAPD_MODE_IEEE80211A;
+ wpa_s->p2p_go_do_acs = 1;
+ freq = 0;
+ } else {
+ wpa_s->p2p_go_acs_band = HOSTAPD_MODE_IEEE80211ANY;
+ wpa_s->p2p_go_do_acs = 1;
+ }
+ } else {
+ wpa_s->p2p_go_do_acs = 0;
+ }
+#endif /* CONFIG_ACS */
+
max_oper_chwidth = parse_freq(chwidth, freq2);
if (max_oper_chwidth < 0)
return -1;
@@ -6258,10 +6443,10 @@
if (group_id >= 0)
return p2p_ctrl_group_add_persistent(wpa_s, group_id,
freq, freq2, ht40, vht,
- max_oper_chwidth);
+ max_oper_chwidth, he);
return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht,
- max_oper_chwidth);
+ max_oper_chwidth, he);
}
@@ -7354,6 +7539,22 @@
list);
}
+
+static int wpas_ctrl_iface_coloc_intf_report(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ struct wpabuf *elems;
+ int ret;
+
+ elems = wpabuf_parse_bin(cmd);
+ if (!elems)
+ return -1;
+
+ ret = wnm_send_coloc_intf_report(wpa_s, 0, elems);
+ wpabuf_free(elems);
+ return ret;
+}
+
#endif /* CONFIG_WNM */
@@ -7387,10 +7588,17 @@
pos += ret;
}
- if (si.center_frq1 > 0 && si.center_frq2 > 0) {
- ret = os_snprintf(pos, end - pos,
- "CENTER_FRQ1=%d\nCENTER_FRQ2=%d\n",
- si.center_frq1, si.center_frq2);
+ if (si.center_frq1 > 0) {
+ ret = os_snprintf(pos, end - pos, "CENTER_FRQ1=%d\n",
+ si.center_frq1);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+
+ if (si.center_frq2 > 0) {
+ ret = os_snprintf(pos, end - pos, "CENTER_FRQ2=%d\n",
+ si.center_frq2);
if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
@@ -7507,7 +7715,7 @@
wpa_printf(MSG_DEBUG,
"CTRL_IFACE: GET_PREF_FREQ_LIST iface_type=%d (%s)",
- iface_type, buf);
+ iface_type, cmd);
ret = wpa_drv_get_pref_freq_list(wpa_s, iface_type, &num, freq_list);
if (ret)
@@ -7708,6 +7916,18 @@
#ifdef CONFIG_DPP
wpas_dpp_deinit(wpa_s);
+ wpa_s->dpp_init_max_tries = 0;
+ wpa_s->dpp_init_retry_time = 0;
+ wpa_s->dpp_resp_wait_time = 0;
+ wpa_s->dpp_resp_max_tries = 0;
+ wpa_s->dpp_resp_retry_time = 0;
+#ifdef CONFIG_TESTING_OPTIONS
+ os_memset(dpp_pkex_own_mac_override, 0, ETH_ALEN);
+ os_memset(dpp_pkex_peer_mac_override, 0, ETH_ALEN);
+ dpp_pkex_ephemeral_key_override_len = 0;
+ dpp_protocol_key_override_len = 0;
+ dpp_nonce_override_len = 0;
+#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_DPP */
#ifdef CONFIG_TDLS
@@ -7778,6 +7998,15 @@
wpa_s->get_pref_freq_list_override = NULL;
wpabuf_free(wpa_s->sae_commit_override);
wpa_s->sae_commit_override = NULL;
+#ifdef CONFIG_DPP
+ os_free(wpa_s->dpp_config_obj_override);
+ wpa_s->dpp_config_obj_override = NULL;
+ os_free(wpa_s->dpp_discovery_override);
+ wpa_s->dpp_discovery_override = NULL;
+ os_free(wpa_s->dpp_groups_override);
+ wpa_s->dpp_groups_override = NULL;
+ dpp_test = DPP_TEST_DISABLED;
+#endif /* CONFIG_DPP */
#endif /* CONFIG_TESTING_OPTIONS */
wpa_s->disconnected = 0;
@@ -7805,6 +8034,10 @@
wpabuf_free(wpa_s->ric_ies);
wpa_s->ric_ies = NULL;
+
+ wpa_supplicant_update_channel_list(wpa_s, NULL);
+
+ free_bss_tmp_disallowed(wpa_s);
}
@@ -8627,26 +8860,39 @@
struct iphdr ip;
const u8 *pos;
unsigned int i;
+ char extra[30];
- if (len != HWSIM_PACKETLEN)
+ if (len < sizeof(*eth) + sizeof(ip) || len > HWSIM_PACKETLEN) {
+ wpa_printf(MSG_DEBUG,
+ "test data: RX - ignore unexpected length %d",
+ (int) len);
return;
+ }
eth = (const struct ether_header *) buf;
os_memcpy(&ip, eth + 1, sizeof(ip));
pos = &buf[sizeof(*eth) + sizeof(ip)];
if (ip.ihl != 5 || ip.version != 4 ||
- ntohs(ip.tot_len) != HWSIM_IP_LEN)
+ ntohs(ip.tot_len) > HWSIM_IP_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "test data: RX - ignore unexpect IP header");
return;
-
- for (i = 0; i < HWSIM_IP_LEN - sizeof(ip); i++) {
- if (*pos != (u8) i)
- return;
- pos++;
}
- wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
- MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
+ for (i = 0; i < ntohs(ip.tot_len) - sizeof(ip); i++) {
+ if (*pos != (u8) i) {
+ wpa_printf(MSG_DEBUG,
+ "test data: RX - ignore mismatching payload");
+ return;
+ }
+ pos++;
+ }
+ extra[0] = '\0';
+ if (ntohs(ip.tot_len) != HWSIM_IP_LEN)
+ os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.tot_len));
+ wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s",
+ MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra);
}
@@ -8690,7 +8936,7 @@
static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
{
u8 dst[ETH_ALEN], src[ETH_ALEN];
- char *pos;
+ char *pos, *pos2;
int used;
long int val;
u8 tos;
@@ -8699,11 +8945,12 @@
struct iphdr *ip;
u8 *dpos;
unsigned int i;
+ size_t send_len = HWSIM_IP_LEN;
if (wpa_s->l2_test == NULL)
return -1;
- /* format: <dst> <src> <tos> */
+ /* format: <dst> <src> <tos> [len=<length>] */
pos = cmd;
used = hwaddr_aton2(pos, dst);
@@ -8717,11 +8964,19 @@
return -1;
pos += used;
- val = strtol(pos, NULL, 0);
+ val = strtol(pos, &pos2, 0);
if (val < 0 || val > 0xff)
return -1;
tos = val;
+ pos = os_strstr(pos2, " len=");
+ if (pos) {
+ i = atoi(pos + 5);
+ if (i < sizeof(*ip) || i > HWSIM_IP_LEN)
+ return -1;
+ send_len = i;
+ }
+
eth = (struct ether_header *) &buf[2];
os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
os_memcpy(eth->ether_shost, src, ETH_ALEN);
@@ -8732,17 +8987,17 @@
ip->version = 4;
ip->ttl = 64;
ip->tos = tos;
- ip->tot_len = htons(HWSIM_IP_LEN);
+ ip->tot_len = htons(send_len);
ip->protocol = 1;
ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
dpos = (u8 *) (ip + 1);
- for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++)
+ for (i = 0; i < send_len - sizeof(*ip); i++)
*dpos++ = i;
if (l2_packet_send(wpa_s->l2_test, dst, ETHERTYPE_IP, &buf[2],
- HWSIM_PACKETLEN) < 0)
+ sizeof(struct ether_header) + send_len) < 0)
return -1;
wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX dst=" MACSTR " src=" MACSTR
@@ -9322,13 +9577,6 @@
return -1;
}
- if ((wpa_s->mac_addr_rand_supported & type) != type) {
- wpa_printf(MSG_INFO,
- "CTRL: MAC_RAND_SCAN types=%u != supported=%u",
- type, wpa_s->mac_addr_rand_supported);
- return -1;
- }
-
if (enable > 1) {
wpa_printf(MSG_INFO,
"CTRL: MAC_RAND_SCAN enable=<0/1> not specified");
@@ -9362,21 +9610,25 @@
}
if (type & MAC_ADDR_RAND_SCAN) {
- wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
- addr, mask);
+ if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
+ addr, mask))
+ return -1;
}
if (type & MAC_ADDR_RAND_SCHED_SCAN) {
- wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
- addr, mask);
+ if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
+ addr, mask))
+ return -1;
if (wpa_s->sched_scanning && !wpa_s->pno)
wpas_scan_restart_sched_scan(wpa_s);
}
if (type & MAC_ADDR_RAND_PNO) {
- wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
- addr, mask);
+ if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
+ addr, mask))
+ return -1;
+
if (wpa_s->pno) {
wpas_stop_pno(wpa_s);
wpas_start_pno(wpa_s);
@@ -9722,6 +9974,11 @@
reply_len += eapol_sm_get_mib(wpa_s->eapol,
reply + reply_len,
reply_size - reply_len);
+#ifdef CONFIG_MACSEC
+ reply_len += ieee802_1x_kay_get_mib(
+ wpa_s->kay, reply + reply_len,
+ reply_size - reply_len);
+#endif /* CONFIG_MACSEC */
}
} else if (os_strncmp(buf, "STATUS", 6) == 0) {
reply_len = wpa_supplicant_ctrl_iface_status(
@@ -10312,6 +10569,9 @@
} else if (os_strncmp(buf, "WNM_BSS_QUERY ", 14) == 0) {
if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 14))
reply_len = -1;
+ } else if (os_strncmp(buf, "COLOC_INTF_REPORT ", 18) == 0) {
+ if (wpas_ctrl_iface_coloc_intf_report(wpa_s, buf + 18))
+ reply_len = -1;
#endif /* CONFIG_WNM */
} else if (os_strcmp(buf, "FLUSH") == 0) {
wpa_supplicant_ctrl_iface_flush(wpa_s);
@@ -10367,6 +10627,12 @@
} else if (os_strcmp(buf, "RESEND_ASSOC") == 0) {
if (wpas_ctrl_resend_assoc(wpa_s) < 0)
reply_len = -1;
+#ifdef CONFIG_IEEE80211W
+ } else if (os_strcmp(buf, "UNPROT_DEAUTH") == 0) {
+ sme_event_unprot_disconnect(
+ wpa_s, wpa_s->bssid, NULL,
+ WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
+#endif /* CONFIG_IEEE80211W */
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
@@ -10410,7 +10676,7 @@
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) {
int res;
- res = wpas_dpp_bootstrap_gen(wpa_s, buf + 18);
+ res = dpp_bootstrap_gen(wpa_s->dpp, buf + 18);
if (res < 0) {
reply_len = -1;
} else {
@@ -10419,12 +10685,12 @@
reply_len = -1;
}
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_REMOVE ", 21) == 0) {
- if (wpas_dpp_bootstrap_remove(wpa_s, buf + 21) < 0)
+ if (dpp_bootstrap_remove(wpa_s->dpp, buf + 21) < 0)
reply_len = -1;
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_GET_URI ", 22) == 0) {
const char *uri;
- uri = wpas_dpp_bootstrap_get_uri(wpa_s, atoi(buf + 22));
+ uri = dpp_bootstrap_get_uri(wpa_s->dpp, atoi(buf + 22));
if (!uri) {
reply_len = -1;
} else {
@@ -10433,8 +10699,8 @@
reply_len = -1;
}
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_INFO ", 19) == 0) {
- reply_len = wpas_dpp_bootstrap_info(wpa_s, atoi(buf + 19),
- reply, reply_size);
+ reply_len = dpp_bootstrap_info(wpa_s->dpp, atoi(buf + 19),
+ reply, reply_size);
} else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
if (wpas_dpp_auth_init(wpa_s, buf + 13) < 0)
reply_len = -1;
@@ -10442,11 +10708,12 @@
if (wpas_dpp_listen(wpa_s, buf + 11) < 0)
reply_len = -1;
} else if (os_strcmp(buf, "DPP_STOP_LISTEN") == 0) {
+ wpas_dpp_stop(wpa_s);
wpas_dpp_listen_stop(wpa_s);
} else if (os_strncmp(buf, "DPP_CONFIGURATOR_ADD", 20) == 0) {
int res;
- res = wpas_dpp_configurator_add(wpa_s, buf + 20);
+ res = dpp_configurator_add(wpa_s->dpp, buf + 20);
if (res < 0) {
reply_len = -1;
} else {
@@ -10455,11 +10722,15 @@
reply_len = -1;
}
} else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) {
- if (wpas_dpp_configurator_remove(wpa_s, buf + 24) < 0)
+ if (dpp_configurator_remove(wpa_s->dpp, buf + 24) < 0)
reply_len = -1;
} else if (os_strncmp(buf, "DPP_CONFIGURATOR_SIGN ", 22) == 0) {
- if (wpas_dpp_configurator_sign(wpa_s, buf + 22) < 0)
+ if (wpas_dpp_configurator_sign(wpa_s, buf + 21) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "DPP_CONFIGURATOR_GET_KEY ", 25) == 0) {
+ reply_len = dpp_configurator_get_key_id(wpa_s->dpp,
+ atoi(buf + 25),
+ reply, reply_size);
} else if (os_strncmp(buf, "DPP_PKEX_ADD ", 13) == 0) {
int res;
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index 0dc0937..8a6057a 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -219,7 +219,7 @@
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct ctrl_iface_priv *priv = sock_ctx;
- char buf[256], *pos;
+ char buf[4096], *pos;
int res;
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
struct sockaddr_in6 from;
@@ -600,7 +600,7 @@
{
struct wpa_global *global = eloop_ctx;
struct ctrl_iface_global_priv *priv = sock_ctx;
- char buf[256], *pos;
+ char buf[4096], *pos;
int res;
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
struct sockaddr_in6 from;
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 4db712f..71fe7ed 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -103,7 +103,7 @@
struct sockaddr_storage *from,
socklen_t fromlen, int global)
{
- return ctrl_iface_attach(ctrl_dst, from, fromlen);
+ return ctrl_iface_attach(ctrl_dst, from, fromlen, NULL);
}
@@ -570,8 +570,8 @@
}
}
- if (gid_set && chown(dir, -1, gid) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s",
+ if (gid_set && lchown(dir, -1, gid) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface=%s,gid=%d]: %s",
dir, (int) gid, strerror(errno));
goto fail;
}
@@ -638,8 +638,8 @@
}
}
- if (gid_set && chown(fname, -1, gid) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s",
+ if (gid_set && lchown(fname, -1, gid) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface=%s,gid=%d]: %s",
fname, (int) gid, strerror(errno));
goto fail;
}
@@ -1235,9 +1235,9 @@
wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
(int) gid);
}
- if (chown(ctrl, -1, gid) < 0) {
+ if (lchown(ctrl, -1, gid) < 0) {
wpa_printf(MSG_ERROR,
- "chown[global_ctrl_interface=%s,gid=%d]: %s",
+ "lchown[global_ctrl_interface=%s,gid=%d]: %s",
ctrl, (int) gid, strerror(errno));
goto fail;
}
diff --git a/wpa_supplicant/dbus/Makefile b/wpa_supplicant/dbus/Makefile
index f355ebe..4d87004 100644
--- a/wpa_supplicant/dbus/Makefile
+++ b/wpa_supplicant/dbus/Makefile
@@ -36,7 +36,6 @@
endif
CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW
-CFLAGS += -DCONFIG_CTRL_IFACE_DBUS
ifndef DBUS_LIBS
DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1)
@@ -54,8 +53,6 @@
LIB_OBJS= \
dbus_common.o \
- dbus_old.o \
- dbus_old_handlers.o \
dbus_new.o \
dbus_new_handlers.o \
dbus_new_helpers.o \
@@ -63,7 +60,6 @@
dbus_dict_helpers.o
ifdef CONFIG_WPS
-LIB_OBJS += dbus_old_handlers_wps.o
LIB_OBJS += dbus_new_handlers_wps.o
endif
diff --git a/wpa_supplicant/dbus/dbus-wpa_supplicant.conf b/wpa_supplicant/dbus/dbus-wpa_supplicant.conf
index 382dcb3..e81b495 100644
--- a/wpa_supplicant/dbus/dbus-wpa_supplicant.conf
+++ b/wpa_supplicant/dbus/dbus-wpa_supplicant.conf
@@ -3,11 +3,6 @@
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy user="root">
- <allow own="fi.epitest.hostap.WPASupplicant"/>
-
- <allow send_destination="fi.epitest.hostap.WPASupplicant"/>
- <allow send_interface="fi.epitest.hostap.WPASupplicant"/>
-
<allow own="fi.w1.wpa_supplicant1"/>
<allow send_destination="fi.w1.wpa_supplicant1"/>
@@ -15,9 +10,6 @@
<allow receive_sender="fi.w1.wpa_supplicant1" receive_type="signal"/>
</policy>
<policy context="default">
- <deny own="fi.epitest.hostap.WPASupplicant"/>
- <deny send_destination="fi.epitest.hostap.WPASupplicant"/>
-
<deny own="fi.w1.wpa_supplicant1"/>
<deny send_destination="fi.w1.wpa_supplicant1"/>
<deny receive_sender="fi.w1.wpa_supplicant1" receive_type="signal"/>
diff --git a/wpa_supplicant/dbus/dbus_common.c b/wpa_supplicant/dbus/dbus_common.c
index 7ef6cad..efa6c7b 100644
--- a/wpa_supplicant/dbus/dbus_common.c
+++ b/wpa_supplicant/dbus/dbus_common.c
@@ -16,7 +16,6 @@
#include "dbus_common.h"
#include "dbus_common_i.h"
#include "dbus_new.h"
-#include "dbus_old.h"
#include "../wpa_supplicant_i.h"
@@ -351,9 +350,6 @@
#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
wpas_dbus_ctrl_iface_init(priv) < 0 ||
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
-#ifdef CONFIG_CTRL_IFACE_DBUS
- wpa_supplicant_dbus_ctrl_iface_init(priv) < 0 ||
-#endif /* CONFIG_CTRL_IFACE_DBUS */
wpas_dbus_init_common_finish(priv) < 0) {
wpas_dbus_deinit(priv);
return NULL;
@@ -372,9 +368,5 @@
wpas_dbus_ctrl_iface_deinit(priv);
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
-#ifdef CONFIG_CTRL_IFACE_DBUS
- /* TODO: is any deinit needed? */
-#endif /* CONFIG_CTRL_IFACE_DBUS */
-
wpas_dbus_deinit_common(priv);
}
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 8115f77..fc2fc2e 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -13,6 +13,7 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
#include "wps/wps.h"
+#include "ap/sta_info.h"
#include "../config.h"
#include "../wpa_supplicant_i.h"
#include "../bss.h"
@@ -128,7 +129,8 @@
* Notify listeners about event related with interface
*/
static void wpas_dbus_signal_interface(struct wpa_supplicant *wpa_s,
- const char *sig_name, int properties)
+ const char *sig_name,
+ dbus_bool_t properties)
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
@@ -230,7 +232,7 @@
*/
static void wpas_dbus_signal_bss(struct wpa_supplicant *wpa_s,
const char *bss_obj_path,
- const char *sig_name, int properties)
+ const char *sig_name, dbus_bool_t properties)
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
@@ -364,7 +366,7 @@
*/
static void wpas_dbus_signal_network(struct wpa_supplicant *wpa_s,
int id, const char *sig_name,
- int properties)
+ dbus_bool_t properties)
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
@@ -1077,6 +1079,79 @@
}
+/**
+ * wpas_dbus_signal_station - Send an event signal related to a station object
+ * @wpa_s: %wpa_supplicant network interface data
+ * @station_obj_path: Station object path
+ * @sig_name: signal name - StationAdded or StationRemoved
+ * @properties: Whether to add second argument with object properties
+ *
+ * Notify listeners about event related with station.
+ */
+static void wpas_dbus_signal_station(struct wpa_supplicant *wpa_s,
+ const char *station_obj_path,
+ const char *sig_name,
+ dbus_bool_t properties)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (!iface || !wpa_s->dbus_new_path)
+ return;
+
+ wpa_printf(MSG_DEBUG, "dbus: STA signal %s", sig_name);
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE, sig_name);
+ if (!msg)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &station_obj_path) ||
+ (properties &&
+ !wpa_dbus_get_object_properties(iface, station_obj_path,
+ WPAS_DBUS_NEW_IFACE_STA,
+ &iter)))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+ dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_station_added - Send a Station added signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @station_obj_path: new Station object path
+ *
+ * Notify listeners about adding new Station
+ */
+static void wpas_dbus_signal_station_added(struct wpa_supplicant *wpa_s,
+ const char *station_obj_path)
+{
+ wpas_dbus_signal_station(wpa_s, station_obj_path, "StationAdded", TRUE);
+}
+
+
+/**
+ * wpas_dbus_signal_station_removed - Send a Station removed signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @station_obj_path: Station object path
+ *
+ * Notify listeners about removing Station
+ */
+static void wpas_dbus_signal_station_removed(struct wpa_supplicant *wpa_s,
+ const char *station_obj_path)
+{
+ wpas_dbus_signal_station(wpa_s, station_obj_path, "StationRemoved",
+ FALSE);
+}
+
+
#ifdef CONFIG_P2P
/**
@@ -1882,7 +1957,7 @@
*/
static void wpas_dbus_signal_persistent_group(struct wpa_supplicant *wpa_s,
int id, const char *sig_name,
- int properties)
+ dbus_bool_t properties)
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
@@ -2027,6 +2102,9 @@
if (iface == NULL)
return;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
msg = dbus_message_new_signal(wpa_s->dbus_new_path,
WPAS_DBUS_NEW_IFACE_P2PDEVICE,
"GroupFormationFailure");
@@ -2068,6 +2146,9 @@
if (iface == NULL)
return;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
msg = dbus_message_new_signal(wpa_s->dbus_new_path,
WPAS_DBUS_NEW_IFACE_P2PDEVICE,
"InvitationReceived");
@@ -2125,11 +2206,6 @@
case WPAS_DBUS_PROP_AP_SCAN:
prop = "ApScan";
break;
-#ifdef CONFIG_IEEE80211W
- case WPAS_DBUS_PROP_PMF:
- prop = "Pmf";
- break;
-#endif /* CONFIG_IEEE80211W */
case WPAS_DBUS_PROP_SCANNING:
prop = "Scanning";
break;
@@ -2145,6 +2221,9 @@
case WPAS_DBUS_PROP_BSSS:
prop = "BSSs";
break;
+ case WPAS_DBUS_PROP_STATIONS:
+ prop = "Stations";
+ break;
case WPAS_DBUS_PROP_CURRENT_AUTH_MODE:
prop = "CurrentAuthMode";
break;
@@ -2152,10 +2231,26 @@
prop = "DisconnectReason";
flush = TRUE;
break;
+ case WPAS_DBUS_PROP_AUTH_STATUS_CODE:
+ prop = "AuthStatusCode";
+ flush = TRUE;
+ break;
case WPAS_DBUS_PROP_ASSOC_STATUS_CODE:
prop = "AssocStatusCode";
flush = TRUE;
break;
+ case WPAS_DBUS_PROP_ROAM_TIME:
+ prop = "RoamTime";
+ break;
+ case WPAS_DBUS_PROP_ROAM_COMPLETE:
+ prop = "RoamComplete";
+ break;
+ case WPAS_DBUS_PROP_SESSION_LENGTH:
+ prop = "SessionLength";
+ break;
+ case WPAS_DBUS_PROP_BSS_TM_STATUS:
+ prop = "BSSTMStatus";
+ break;
default:
wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
__func__, property);
@@ -2238,6 +2333,41 @@
/**
+ * wpas_dbus_sta_signal_prop_changed - Signals change of STA property
+ * @wpa_s: %wpa_supplicant network interface data
+ * @property: indicates which property has changed
+ * @address: unique BSS identifier
+ *
+ * Sends PropertyChanged signals with path, interface, and arguments depending
+ * on which property has changed.
+ */
+void wpas_dbus_sta_signal_prop_changed(struct wpa_supplicant *wpa_s,
+ enum wpas_dbus_bss_prop property,
+ u8 address[ETH_ALEN])
+{
+ char path[WPAS_DBUS_OBJECT_PATH_MAX];
+ char *prop;
+
+ switch (property) {
+ case WPAS_DBUS_STA_PROP_ADDRESS:
+ prop = "Address";
+ break;
+ default:
+ wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
+ __func__, property);
+ return;
+ }
+
+ os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(address));
+
+ wpa_dbus_mark_property_changed(wpa_s->global->dbus, path,
+ WPAS_DBUS_NEW_IFACE_STA, prop);
+}
+
+
+/**
* wpas_dbus_signal_debug_level_changed - Signals change of debug param
* @global: wpa_global structure
*
@@ -2725,6 +2855,30 @@
NULL,
NULL
},
+ {
+ "RoamTime", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+ wpas_dbus_getter_roam_time,
+ NULL,
+ NULL
+ },
+ {
+ "RoamComplete", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
+ wpas_dbus_getter_roam_complete,
+ NULL,
+ NULL
+ },
+ {
+ "SessionLength", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+ wpas_dbus_getter_session_length,
+ NULL,
+ NULL
+ },
+ {
+ "BSSTMStatus", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+ wpas_dbus_getter_bss_tm_status,
+ NULL,
+ NULL
+ },
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -2851,6 +3005,157 @@
}
+static const struct wpa_dbus_property_desc wpas_dbus_sta_properties[] = {
+ { "Address", WPAS_DBUS_NEW_IFACE_STA, "ay",
+ wpas_dbus_getter_sta_address,
+ NULL, NULL
+ },
+ { "AID", WPAS_DBUS_NEW_IFACE_STA, "q",
+ wpas_dbus_getter_sta_aid,
+ NULL, NULL
+ },
+ { "Capabilities", WPAS_DBUS_NEW_IFACE_STA, "q",
+ wpas_dbus_getter_sta_caps,
+ NULL, NULL
+ },
+ { "RxPackets", WPAS_DBUS_NEW_IFACE_STA, "t",
+ wpas_dbus_getter_sta_rx_packets,
+ NULL, NULL
+ },
+ { "TxPackets", WPAS_DBUS_NEW_IFACE_STA, "t",
+ wpas_dbus_getter_sta_tx_packets,
+ NULL, NULL
+ },
+ { "RxBytes", WPAS_DBUS_NEW_IFACE_STA, "t",
+ wpas_dbus_getter_sta_rx_bytes,
+ NULL, NULL
+ },
+ { "TxBytes", WPAS_DBUS_NEW_IFACE_STA, "t",
+ wpas_dbus_getter_sta_tx_bytes,
+ NULL, NULL
+ },
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+
+static const struct wpa_dbus_signal_desc wpas_dbus_sta_signals[] = {
+ /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
+ { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_STA,
+ {
+ { "properties", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { NULL, NULL, { END_ARGS } }
+};
+
+
+/**
+ * wpas_dbus_unregister_sta - Unregister a connected station from dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @sta: station MAC address
+ * Returns: 0 on success, -1 on failure
+ *
+ * Unregisters STA representing object from dbus.
+ */
+int wpas_dbus_unregister_sta(struct wpa_supplicant *wpa_s, const u8 *sta)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+ char station_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+ /* Do nothing if the control interface is not turned on */
+ if (!wpa_s || !wpa_s->global)
+ return 0;
+ ctrl_iface = wpa_s->global->dbus;
+ if (!ctrl_iface)
+ return 0;
+
+ os_snprintf(station_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(sta));
+
+ wpa_printf(MSG_DEBUG, "dbus: Unregister STA object '%s'",
+ station_obj_path);
+ if (wpa_dbus_unregister_object_per_iface(ctrl_iface,
+ station_obj_path)) {
+ wpa_printf(MSG_ERROR, "dbus: Cannot unregister STA object %s",
+ station_obj_path);
+ return -1;
+ }
+
+ wpas_dbus_signal_station_removed(wpa_s, station_obj_path);
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATIONS);
+
+ return 0;
+}
+
+
+/**
+ * wpas_dbus_register_sta - Register a connected station with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @sta: station MAC address
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers STA representing object with dbus.
+ */
+int wpas_dbus_register_sta(struct wpa_supplicant *wpa_s, const u8 *sta)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+ struct wpa_dbus_object_desc *obj_desc;
+ char station_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+ struct sta_handler_args *arg;
+
+ /* Do nothing if the control interface is not turned on */
+ if (!wpa_s || !wpa_s->global)
+ return 0;
+ ctrl_iface = wpa_s->global->dbus;
+ if (!ctrl_iface)
+ return 0;
+
+ os_snprintf(station_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(sta));
+
+ obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+ if (!obj_desc) {
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create object description");
+ goto err;
+ }
+
+ arg = os_zalloc(sizeof(struct sta_handler_args));
+ if (!arg) {
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create arguments for handler");
+ goto err;
+ }
+ arg->wpa_s = wpa_s;
+ arg->sta = sta;
+
+ wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
+ wpas_dbus_sta_properties, wpas_dbus_sta_signals);
+
+ wpa_printf(MSG_DEBUG, "dbus: Register STA object '%s'",
+ station_obj_path);
+ if (wpa_dbus_register_object_per_iface(ctrl_iface, station_obj_path,
+ wpa_s->ifname, obj_desc)) {
+ wpa_printf(MSG_ERROR,
+ "Cannot register STA dbus object %s",
+ station_obj_path);
+ goto err;
+ }
+
+ wpas_dbus_signal_station_added(wpa_s, station_obj_path);
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATIONS);
+
+ return 0;
+
+err:
+ free_dbus_object_desc(obj_desc);
+ return -1;
+}
+
+
static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
{ "Scan", WPAS_DBUS_NEW_IFACE_INTERFACE,
(WPADBusMethodHandler) wpas_dbus_handler_scan,
@@ -3301,13 +3606,6 @@
wpas_dbus_setter_ap_scan,
NULL
},
-#ifdef CONFIG_IEEE80211W
- { "Pmf", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
- wpas_dbus_getter_pmf,
- wpas_dbus_setter_pmf,
- NULL
- },
-#endif /* CONFIG_IEEE80211W */
{ "BSSExpireAge", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
wpas_dbus_getter_bss_expire_age,
wpas_dbus_setter_bss_expire_age,
@@ -3478,6 +3776,11 @@
NULL,
NULL
},
+ { "AuthStatusCode", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
+ wpas_dbus_getter_auth_status_code,
+ NULL,
+ NULL
+ },
{ "AssocStatusCode", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
wpas_dbus_getter_assoc_status_code,
NULL,
@@ -3495,6 +3798,11 @@
NULL
},
#endif /* CONFIG_MESH */
+ { "Stations", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
+ wpas_dbus_getter_stas,
+ NULL,
+ NULL
+ },
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -3764,6 +4072,19 @@
END_ARGS
}
},
+ { "StationAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "path", "o", ARG_OUT },
+ { "properties", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "StationRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "path", "o", ARG_OUT },
+ END_ARGS
+ }
+ },
{ "NetworkRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
{
{ "path", "o", ARG_OUT },
@@ -4044,6 +4365,11 @@
NULL,
NULL
},
+ { "VSIE", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
+ wpas_dbus_getter_p2p_peer_vsie,
+ NULL,
+ NULL
+ },
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -4072,7 +4398,7 @@
*/
static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s,
const u8 *dev_addr, const char *interface,
- const char *sig_name, int properties)
+ const char *sig_name, dbus_bool_t properties)
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
@@ -4266,7 +4592,13 @@
iface = wpa_s->global->dbus;
/* Do nothing if the control interface is not turned on */
- if (iface == NULL || !wpa_s->dbus_new_path)
+ if (iface == NULL)
+ return;
+
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
+ if (!wpa_s->dbus_new_path)
return;
msg = dbus_message_new_signal(wpa_s->dbus_new_path,
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index e68acb7..42db389 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -22,15 +22,20 @@
enum wpas_dbus_prop {
WPAS_DBUS_PROP_AP_SCAN,
- WPAS_DBUS_PROP_PMF,
WPAS_DBUS_PROP_SCANNING,
WPAS_DBUS_PROP_STATE,
WPAS_DBUS_PROP_CURRENT_BSS,
WPAS_DBUS_PROP_CURRENT_NETWORK,
WPAS_DBUS_PROP_CURRENT_AUTH_MODE,
WPAS_DBUS_PROP_BSSS,
+ WPAS_DBUS_PROP_STATIONS,
WPAS_DBUS_PROP_DISCONNECT_REASON,
+ WPAS_DBUS_PROP_AUTH_STATUS_CODE,
WPAS_DBUS_PROP_ASSOC_STATUS_CODE,
+ WPAS_DBUS_PROP_ROAM_TIME,
+ WPAS_DBUS_PROP_ROAM_COMPLETE,
+ WPAS_DBUS_PROP_SESSION_LENGTH,
+ WPAS_DBUS_PROP_BSS_TM_STATUS,
};
enum wpas_dbus_bss_prop {
@@ -46,6 +51,10 @@
WPAS_DBUS_BSS_PROP_AGE,
};
+enum wpas_dbus_sta_prop {
+ WPAS_DBUS_STA_PROP_ADDRESS,
+};
+
#define WPAS_DBUS_OBJECT_PATH_MAX 150
#define WPAS_DBUS_NEW_SERVICE "fi.w1.wpa_supplicant1"
@@ -62,6 +71,9 @@
#define WPAS_DBUS_NEW_BSSIDS_PART "BSSs"
#define WPAS_DBUS_NEW_IFACE_BSS WPAS_DBUS_NEW_INTERFACE ".BSS"
+#define WPAS_DBUS_NEW_STAS_PART "Stations"
+#define WPAS_DBUS_NEW_IFACE_STA WPAS_DBUS_NEW_INTERFACE ".Station"
+
#define WPAS_DBUS_NEW_IFACE_P2PDEVICE \
WPAS_DBUS_NEW_IFACE_INTERFACE ".P2PDevice"
@@ -164,6 +176,8 @@
u8 bssid[ETH_ALEN], unsigned int id);
int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s,
u8 bssid[ETH_ALEN], unsigned int id);
+int wpas_dbus_unregister_sta(struct wpa_supplicant *wpa_s, const u8 *sta);
+int wpas_dbus_register_sta(struct wpa_supplicant *wpa_s, const u8 *sta);
void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s,
const char *name);
void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s,
@@ -346,6 +360,18 @@
return 0;
}
+static inline int wpas_dbus_unregister_sta(struct wpa_supplicant *wpa_s,
+ const u8 *sta)
+{
+ return 0;
+}
+
+static inline int wpas_dbus_register_sta(struct wpa_supplicant *wpa_s,
+ const u8 *sta)
+{
+ return 0;
+}
+
static inline void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s,
const char *name)
{
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 564c868..6c36d91 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -15,6 +15,9 @@
#include "eap_peer/eap_methods.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "rsn_supp/wpa.h"
+#include "ap/hostapd.h"
+#include "ap/sta_info.h"
+#include "ap/ap_drv_ops.h"
#include "../config.h"
#include "../wpa_supplicant_i.h"
#include "../driver_i.h"
@@ -22,6 +25,7 @@
#include "../bss.h"
#include "../scan.h"
#include "../autoscan.h"
+#include "../ap.h"
#include "dbus_new_helpers.h"
#include "dbus_new.h"
#include "dbus_new_handlers.h"
@@ -980,8 +984,21 @@
const struct wpa_dbus_property_desc *property_desc,
DBusMessageIter *iter, DBusError *error, void *user_data)
{
- const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL };
+ const char *capabilities[10] = { NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL };
size_t num_items = 0;
+#ifdef CONFIG_FILS
+ struct wpa_global *global = user_data;
+ struct wpa_supplicant *wpa_s;
+ int fils_supported = 0, fils_sk_pfs_supported = 0;
+
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ if (wpa_is_fils_supported(wpa_s))
+ fils_supported = 1;
+ if (wpa_is_fils_sk_pfs_supported(wpa_s))
+ fils_sk_pfs_supported = 1;
+ }
+#endif /* CONFIG_FILS */
#ifdef CONFIG_AP
capabilities[num_items++] = "ap";
@@ -998,6 +1015,21 @@
#ifdef CONFIG_IEEE80211W
capabilities[num_items++] = "pmf";
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_MESH
+ capabilities[num_items++] = "mesh";
+#endif /* CONFIG_MESH */
+#ifdef CONFIG_FILS
+ if (fils_supported)
+ capabilities[num_items++] = "fils";
+ if (fils_sk_pfs_supported)
+ capabilities[num_items++] = "fils_sk_pfs";
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R
+ capabilities[num_items++] = "ft";
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SHA384
+ capabilities[num_items++] = "sha384";
+#endif /* CONFIG_SHA384 */
return wpas_dbus_simple_array_property_getter(iter,
DBUS_TYPE_STRING,
@@ -2990,61 +3022,6 @@
}
-#ifdef CONFIG_IEEE80211W
-
-/**
- * wpas_dbus_getter_pmf - Control PMF default
- * @iter: Pointer to incoming dbus message iter
- * @error: Location to store error on failure
- * @user_data: Function specific data
- * Returns: TRUE on success, FALSE on failure
- *
- * Getter function for "Pmf" property.
- */
-dbus_bool_t wpas_dbus_getter_pmf(
- const struct wpa_dbus_property_desc *property_desc,
- DBusMessageIter *iter, DBusError *error, void *user_data)
-{
- struct wpa_supplicant *wpa_s = user_data;
- dbus_uint32_t pmf = wpa_s->conf->pmf;
-
- return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
- &pmf, error);
-}
-
-
-/**
- * wpas_dbus_setter_pmf - Control PMF default
- * @iter: Pointer to incoming dbus message iter
- * @error: Location to store error on failure
- * @user_data: Function specific data
- * Returns: TRUE on success, FALSE on failure
- *
- * Setter function for "Pmf" property.
- */
-dbus_bool_t wpas_dbus_setter_pmf(
- const struct wpa_dbus_property_desc *property_desc,
- DBusMessageIter *iter, DBusError *error, void *user_data)
-{
- struct wpa_supplicant *wpa_s = user_data;
- dbus_uint32_t pmf;
-
- if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
- &pmf))
- return FALSE;
-
- if (pmf > 2) {
- dbus_set_error_const(error, DBUS_ERROR_FAILED,
- "Pmf must be 0, 1, or 2");
- return FALSE;
- }
- wpa_s->conf->pmf = pmf;
- return TRUE;
-}
-
-#endif /* CONFIG_IEEE80211W */
-
-
/**
* wpas_dbus_getter_fast_reauth - Control fast
* reauthentication (TLS session resumption)
@@ -3116,6 +3093,27 @@
/**
+ * wpas_dbus_getter_auth_status_code - Get most recent auth status code
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "AuthStatusCode" property.
+ */
+dbus_bool_t wpas_dbus_getter_auth_status_code(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_int32_t reason = wpa_s->auth_status_code;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
+ &reason, error);
+}
+
+
+/**
* wpas_dbus_getter_assoc_status_code - Get most recent failed assoc status code
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
@@ -3137,6 +3135,97 @@
/**
+ * wpas_dbus_getter_roam_time - Get most recent roam time
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "RoamTime" property.
+ */
+dbus_bool_t wpas_dbus_getter_roam_time(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_uint32_t roam_time = wpa_s->roam_time.sec * 1000 +
+ wpa_s->roam_time.usec / 1000;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
+ &roam_time, error);
+}
+
+
+/**
+ * wpas_dbus_getter_roam_complete - Get most recent roam success or failure
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "RoamComplete" property.
+ */
+dbus_bool_t wpas_dbus_getter_roam_complete(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_bool_t roam_complete = os_reltime_initialized(&wpa_s->roam_time);
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+ &roam_complete, error);
+}
+
+
+/**
+ * wpas_dbus_getter_session_length - Get most recent BSS session length
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "SessionLength" property.
+ */
+dbus_bool_t wpas_dbus_getter_session_length(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_uint32_t session_length = wpa_s->session_length.sec * 1000 +
+ wpa_s->session_length.usec / 1000;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
+ &session_length, error);
+}
+
+
+/**
+ * wpas_dbus_getter_bss_tm_status - Get most BSS Transition Management request
+ * status code
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "BSSTMStatus" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_tm_status(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_WNM
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_uint32_t bss_tm_status = wpa_s->bss_tm_status;
+#else /* CONFIG_WNM */
+ dbus_uint32_t bss_tm_status = 0;
+#endif /* CONFIG_WNM */
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
+ &bss_tm_status, error);
+}
+
+
+/**
* wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
@@ -3832,6 +3921,320 @@
}
+/**
+ * wpas_dbus_getter_stas - Get connected stations for an interface
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: a list of stations
+ *
+ * Getter for "Stations" property.
+ */
+dbus_bool_t wpas_dbus_getter_stas(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ struct sta_info *sta = NULL;
+ char **paths = NULL;
+ unsigned int i = 0, num = 0;
+ dbus_bool_t success = FALSE;
+
+ if (!wpa_s->dbus_new_path) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: no D-Bus interface", __func__);
+ return FALSE;
+ }
+
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface) {
+ struct hostapd_data *hapd;
+
+ hapd = wpa_s->ap_iface->bss[0];
+ sta = hapd->sta_list;
+ num = hapd->num_sta;
+ }
+#endif /* CONFIG_AP */
+
+ paths = os_calloc(num, sizeof(char *));
+ if (!paths) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+ return FALSE;
+ }
+
+ /* Loop through scan results and append each result's object path */
+ for (; sta; sta = sta->next) {
+ paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
+ if (!paths[i]) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+ "no memory");
+ goto out;
+ }
+ /* Construct the object path for this BSS. */
+ os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(sta->addr));
+ }
+
+ success = wpas_dbus_simple_array_property_getter(iter,
+ DBUS_TYPE_OBJECT_PATH,
+ paths, num,
+ error);
+
+out:
+ while (i)
+ os_free(paths[--i]);
+ os_free(paths);
+ return success;
+}
+
+
+/**
+ * wpas_dbus_getter_sta_address - Return the address of a connected station
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "Address" property.
+ */
+dbus_bool_t wpas_dbus_getter_sta_address(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_AP
+ struct sta_handler_args *args = user_data;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta);
+ if (!sta)
+ return FALSE;
+
+ return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+ sta->addr, ETH_ALEN,
+ error);
+#else /* CONFIG_AP */
+ return FALSE;
+#endif /* CONFIG_AP */
+}
+
+
+/**
+ * wpas_dbus_getter_sta_aid - Return the AID of a connected station
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "AID" property.
+ */
+dbus_bool_t wpas_dbus_getter_sta_aid(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_AP
+ struct sta_handler_args *args = user_data;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta);
+ if (!sta)
+ return FALSE;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
+ &sta->aid,
+ error);
+#else /* CONFIG_AP */
+ return FALSE;
+#endif /* CONFIG_AP */
+}
+
+
+/**
+ * wpas_dbus_getter_sta_caps - Return the capabilities of a station
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "Capabilities" property.
+ */
+dbus_bool_t wpas_dbus_getter_sta_caps(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_AP
+ struct sta_handler_args *args = user_data;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta);
+ if (!sta)
+ return FALSE;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
+ &sta->capability,
+ error);
+#else /* CONFIG_AP */
+ return FALSE;
+#endif /* CONFIG_AP */
+}
+
+
+/**
+ * wpas_dbus_getter_rx_packets - Return the received packets for a station
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "RxPackets" property.
+ */
+dbus_bool_t wpas_dbus_getter_sta_rx_packets(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_AP
+ struct sta_handler_args *args = user_data;
+ struct sta_info *sta;
+ struct hostap_sta_driver_data data;
+ struct hostapd_data *hapd;
+
+ if (!args->wpa_s->ap_iface)
+ return FALSE;
+
+ hapd = args->wpa_s->ap_iface->bss[0];
+ sta = ap_get_sta(hapd, args->sta);
+ if (!sta)
+ return FALSE;
+
+ if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
+ return FALSE;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
+ &data.rx_packets,
+ error);
+#else /* CONFIG_AP */
+ return FALSE;
+#endif /* CONFIG_AP */
+}
+
+
+/**
+ * wpas_dbus_getter_tx_packets - Return the transmitted packets for a station
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "TxPackets" property.
+ */
+dbus_bool_t wpas_dbus_getter_sta_tx_packets(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_AP
+ struct sta_handler_args *args = user_data;
+ struct sta_info *sta;
+ struct hostap_sta_driver_data data;
+ struct hostapd_data *hapd;
+
+ if (!args->wpa_s->ap_iface)
+ return FALSE;
+
+ hapd = args->wpa_s->ap_iface->bss[0];
+ sta = ap_get_sta(hapd, args->sta);
+ if (!sta)
+ return FALSE;
+
+ if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
+ return FALSE;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
+ &data.tx_packets,
+ error);
+#else /* CONFIG_AP */
+ return FALSE;
+#endif /* CONFIG_AP */
+}
+
+
+/**
+ * wpas_dbus_getter_tx_bytes - Return the transmitted bytes for a station
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "TxBytes" property.
+ */
+dbus_bool_t wpas_dbus_getter_sta_tx_bytes(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_AP
+ struct sta_handler_args *args = user_data;
+ struct sta_info *sta;
+ struct hostap_sta_driver_data data;
+ struct hostapd_data *hapd;
+
+ if (!args->wpa_s->ap_iface)
+ return FALSE;
+
+ hapd = args->wpa_s->ap_iface->bss[0];
+ sta = ap_get_sta(hapd, args->sta);
+ if (!sta)
+ return FALSE;
+
+ if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
+ return FALSE;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
+ &data.tx_bytes,
+ error);
+#else /* CONFIG_AP */
+ return FALSE;
+#endif /* CONFIG_AP */
+}
+
+
+/**
+ * wpas_dbus_getter_rx_bytes - Return the received bytes for a station
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "RxBytes" property.
+ */
+dbus_bool_t wpas_dbus_getter_sta_rx_bytes(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_AP
+ struct sta_handler_args *args = user_data;
+ struct sta_info *sta;
+ struct hostap_sta_driver_data data;
+ struct hostapd_data *hapd;
+
+ if (!args->wpa_s->ap_iface)
+ return FALSE;
+
+ hapd = args->wpa_s->ap_iface->bss[0];
+ sta = ap_get_sta(hapd, args->sta);
+ if (!sta)
+ return FALSE;
+
+ if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
+ return FALSE;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
+ &data.rx_bytes,
+ error);
+#else /* CONFIG_AP */
+ return FALSE;
+#endif /* CONFIG_AP */
+}
+
+
static struct wpa_bss * get_bss_helper(struct bss_handler_args *args,
DBusError *error, const char *func_name)
{
@@ -4094,7 +4497,7 @@
DBusMessageIter iter_dict, variant_iter;
const char *group;
const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
- const char *key_mgmt[9]; /* max 9 key managements may be supported */
+ const char *key_mgmt[15]; /* max 15 key managements may be supported */
int n;
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
@@ -4104,7 +4507,12 @@
if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
goto nomem;
- /* KeyMgmt */
+ /*
+ * KeyMgmt
+ *
+ * When adding a new entry here, please take care to extend key_mgmt[]
+ * and keep documentation in doc/dbus.doxygen up to date.
+ */
n = 0;
if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK)
key_mgmt[n++] = "wpa-psk";
@@ -4126,6 +4534,22 @@
if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
key_mgmt[n++] = "wpa-eap-suite-b-192";
#endif /* CONFIG_SUITEB192 */
+#ifdef CONFIG_FILS
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_FILS_SHA256)
+ key_mgmt[n++] = "wpa-fils-sha256";
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_FILS_SHA384)
+ key_mgmt[n++] = "wpa-fils-sha384";
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256)
+ key_mgmt[n++] = "wpa-ft-fils-sha256";
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384)
+ key_mgmt[n++] = "wpa-ft-fils-sha384";
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_SAE
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_SAE)
+ key_mgmt[n++] = "sae";
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_SAE)
+ key_mgmt[n++] = "ft-sae";
+#endif /* CONFIG_SAE */
if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
key_mgmt[n++] = "wpa-none";
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index 26652ad..d922ce1 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -22,6 +22,11 @@
unsigned int id;
};
+struct sta_handler_args {
+ struct wpa_supplicant *wpa_s;
+ const u8 *sta;
+};
+
dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter,
const int type,
const void *val,
@@ -141,13 +146,16 @@
DECLARE_ACCESSOR(wpas_dbus_getter_scanning);
DECLARE_ACCESSOR(wpas_dbus_getter_ap_scan);
DECLARE_ACCESSOR(wpas_dbus_setter_ap_scan);
-DECLARE_ACCESSOR(wpas_dbus_getter_pmf);
-DECLARE_ACCESSOR(wpas_dbus_setter_pmf);
DECLARE_ACCESSOR(wpas_dbus_getter_fast_reauth);
DECLARE_ACCESSOR(wpas_dbus_setter_fast_reauth);
DECLARE_ACCESSOR(wpas_dbus_getter_disconnect_reason);
DECLARE_ACCESSOR(wpas_dbus_getter_disassociate_reason);
+DECLARE_ACCESSOR(wpas_dbus_getter_auth_status_code);
DECLARE_ACCESSOR(wpas_dbus_getter_assoc_status_code);
+DECLARE_ACCESSOR(wpas_dbus_getter_roam_time);
+DECLARE_ACCESSOR(wpas_dbus_getter_roam_complete);
+DECLARE_ACCESSOR(wpas_dbus_getter_session_length);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_tm_status);
DECLARE_ACCESSOR(wpas_dbus_getter_bss_expire_age);
DECLARE_ACCESSOR(wpas_dbus_setter_bss_expire_age);
DECLARE_ACCESSOR(wpas_dbus_getter_bss_expire_count);
@@ -168,6 +176,14 @@
DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_engine_path);
DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_module_path);
DECLARE_ACCESSOR(wpas_dbus_getter_blobs);
+DECLARE_ACCESSOR(wpas_dbus_getter_stas);
+DECLARE_ACCESSOR(wpas_dbus_getter_sta_address);
+DECLARE_ACCESSOR(wpas_dbus_getter_sta_aid);
+DECLARE_ACCESSOR(wpas_dbus_getter_sta_caps);
+DECLARE_ACCESSOR(wpas_dbus_getter_sta_rx_packets);
+DECLARE_ACCESSOR(wpas_dbus_getter_sta_tx_packets);
+DECLARE_ACCESSOR(wpas_dbus_getter_sta_tx_bytes);
+DECLARE_ACCESSOR(wpas_dbus_getter_sta_rx_bytes);
DECLARE_ACCESSOR(wpas_dbus_getter_bss_bssid);
DECLARE_ACCESSOR(wpas_dbus_getter_bss_ssid);
DECLARE_ACCESSOR(wpas_dbus_getter_bss_privacy);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index a04783d..8cdd885 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -146,8 +146,11 @@
wpa_s = wpa_s->global->p2p_init_wpa_s;
- wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types,
- NULL, 0, 0, NULL, freq);
+ if (wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types,
+ req_dev_types, NULL, 0, 0, NULL, freq))
+ reply = wpas_dbus_error_unknown_error(
+ message, "Could not start P2P find");
+
os_free(req_dev_types);
return reply;
@@ -381,14 +384,14 @@
goto inv_args;
if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0, 0,
- 0, 0, NULL, 0, 0)) {
+ 0, 0, 0, NULL, 0, 0)) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
goto out;
}
} else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0, 0, 0,
- 0))
+ 0, 0))
goto inv_args;
out:
@@ -502,6 +505,7 @@
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ wpas_p2p_stop_find(wpa_s);
os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
wpa_s->force_long_sd = 0;
p2p_flush(wpa_s->global->p2p);
@@ -529,6 +533,7 @@
int new_pin;
char *err_msg = NULL;
char *iface = NULL;
+ int ret;
if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
return reply;
@@ -600,13 +605,19 @@
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, 0, join, authorize_only,
- go_intent, freq, 0, -1, 0, 0, 0, 0, NULL, 0);
+ go_intent, freq, 0, -1, 0, 0, 0, 0, 0,
+ NULL, 0);
if (new_pin >= 0) {
char npin[9];
char *generated_pin;
- os_snprintf(npin, sizeof(npin), "%08d", new_pin);
+ ret = os_snprintf(npin, sizeof(npin), "%08d", new_pin);
+ if (os_snprintf_error(sizeof(npin), ret)) {
+ reply = wpas_dbus_error_unknown_error(message,
+ "invalid PIN");
+ goto out;
+ }
generated_pin = npin;
reply = dbus_message_new_method_return(message);
dbus_message_append_args(reply, DBUS_TYPE_STRING,
@@ -752,7 +763,7 @@
goto err;
if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0, 0,
- 0) < 0) {
+ 0, 0) < 0) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
@@ -1907,6 +1918,30 @@
return success;
}
+dbus_bool_t wpas_dbus_getter_p2p_peer_vsie(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct peer_handler_args *peer_args = user_data;
+ const struct p2p_peer_info *info;
+
+ info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
+ peer_args->p2p_device_addr, 0);
+ if (!info) {
+ dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
+ return FALSE;
+ }
+
+ if (!info->vendor_elems)
+ return wpas_dbus_simple_array_property_getter(iter,
+ DBUS_TYPE_BYTE,
+ NULL, 0, error);
+
+ return wpas_dbus_simple_array_property_getter(
+ iter, DBUS_TYPE_BYTE, (char *) info->vendor_elems->buf,
+ info->vendor_elems->used, error);
+}
+
/**
* wpas_dbus_getter_persistent_groups - Get array of persistent group objects
@@ -2658,7 +2693,7 @@
if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
goto error;
- if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
@@ -2670,26 +2705,27 @@
bonjour = 1;
else
goto error_clear;
- wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "version") == 0 &&
+ entry.type == DBUS_TYPE_INT32) {
+ version = entry.uint32_value;
+ } else if (os_strcmp(entry.key, "service") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ os_free(service);
+ service = os_strdup(entry.str_value);
+ } else if (os_strcmp(entry.key, "query") == 0) {
+ if (entry.type != DBUS_TYPE_ARRAY ||
+ entry.array_type != DBUS_TYPE_BYTE)
+ goto error_clear;
+ wpabuf_free(query);
+ query = wpabuf_alloc_copy(entry.bytearray_value,
+ entry.array_len);
+ } else {
+ goto error_clear;
}
+
+ wpa_dbus_dict_entry_clear(&entry);
}
if (upnp == 1) {
- while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
- if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
- goto error;
- if (os_strcmp(entry.key, "version") == 0 &&
- entry.type == DBUS_TYPE_INT32)
- version = entry.uint32_value;
- else if (os_strcmp(entry.key, "service") == 0 &&
- entry.type == DBUS_TYPE_STRING) {
- os_free(service);
- service = os_strdup(entry.str_value);
- } else
- goto error_clear;
-
- wpa_dbus_dict_entry_clear(&entry);
- }
-
if (version <= 0 || service == NULL)
goto error;
@@ -2697,24 +2733,6 @@
if (ret != 0)
goto error;
} else if (bonjour == 1) {
- while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
- if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
- goto error;
-
- if (os_strcmp(entry.key, "query") == 0) {
- if (entry.type != DBUS_TYPE_ARRAY ||
- entry.array_type != DBUS_TYPE_BYTE)
- goto error_clear;
- wpabuf_free(query);
- query = wpabuf_alloc_copy(
- entry.bytearray_value,
- entry.array_len);
- } else
- goto error_clear;
-
- wpa_dbus_dict_entry_clear(&entry);
- }
-
if (query == NULL)
goto error;
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
index c4c0261..b3c45c1 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
@@ -114,6 +114,7 @@
DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_ies);
DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_device_address);
DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_groups);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_vsie);
/*
* P2P Group properties
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_wps.c b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
index f762b3f..1594daf 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_wps.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
@@ -286,10 +286,14 @@
ret = wpas_wps_start_pin(wpa_s, params.bssid,
params.pin, 0,
DEV_PW_DEFAULT);
- if (ret > 0)
- os_snprintf(npin, sizeof(npin), "%08d", ret);
+ if (ret > 0) {
+ ret = os_snprintf(npin, sizeof(npin), "%08d", ret);
+ if (os_snprintf_error(sizeof(npin), ret))
+ return wpas_dbus_error_unknown_error(
+ message, "invalid PIN");
+ }
} else {
- ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0);
+ ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0, 0);
}
if (ret < 0) {
diff --git a/wpa_supplicant/dbus/dbus_old.c b/wpa_supplicant/dbus/dbus_old.c
deleted file mode 100644
index 88227af..0000000
--- a/wpa_supplicant/dbus/dbus_old.c
+++ /dev/null
@@ -1,745 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface
- * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-#include <dbus/dbus.h>
-
-#include "common.h"
-#include "eloop.h"
-#include "wps/wps.h"
-#include "../config.h"
-#include "../wpa_supplicant_i.h"
-#include "../bss.h"
-#include "dbus_old.h"
-#include "dbus_old_handlers.h"
-#include "dbus_common_i.h"
-
-
-/**
- * wpas_dbus_decompose_object_path - Decompose an interface object path into parts
- * @path: The dbus object path
- * @network: (out) the configured network this object path refers to, if any
- * @bssid: (out) the scanned bssid this object path refers to, if any
- * Returns: The object path of the network interface this path refers to
- *
- * For a given object path, decomposes the object path into object id, network,
- * and BSSID parts, if those parts exist.
- */
-char * wpas_dbus_decompose_object_path(const char *path, char **network,
- char **bssid)
-{
- const unsigned int dev_path_prefix_len =
- strlen(WPAS_DBUS_PATH_INTERFACES "/");
- char *obj_path_only;
- char *next_sep;
-
- /* Be a bit paranoid about path */
- if (!path || strncmp(path, WPAS_DBUS_PATH_INTERFACES "/",
- dev_path_prefix_len))
- return NULL;
-
- /* Ensure there's something at the end of the path */
- if ((path + dev_path_prefix_len)[0] == '\0')
- return NULL;
-
- obj_path_only = os_strdup(path);
- if (obj_path_only == NULL)
- return NULL;
-
- next_sep = strchr(obj_path_only + dev_path_prefix_len, '/');
- if (next_sep != NULL) {
- const char *net_part = strstr(next_sep,
- WPAS_DBUS_NETWORKS_PART "/");
- const char *bssid_part = strstr(next_sep,
- WPAS_DBUS_BSSIDS_PART "/");
-
- if (network && net_part) {
- /* Deal with a request for a configured network */
- const char *net_name = net_part +
- strlen(WPAS_DBUS_NETWORKS_PART "/");
- *network = NULL;
- if (strlen(net_name))
- *network = os_strdup(net_name);
- } else if (bssid && bssid_part) {
- /* Deal with a request for a scanned BSSID */
- const char *bssid_name = bssid_part +
- strlen(WPAS_DBUS_BSSIDS_PART "/");
- if (strlen(bssid_name))
- *bssid = os_strdup(bssid_name);
- else
- *bssid = NULL;
- }
-
- /* Cut off interface object path before "/" */
- *next_sep = '\0';
- }
-
- return obj_path_only;
-}
-
-
-/**
- * wpas_dbus_new_invalid_iface_error - Return a new invalid interface error message
- * @message: Pointer to incoming dbus message this error refers to
- * Returns: A dbus error message
- *
- * Convenience function to create and return an invalid interface error
- */
-DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message)
-{
- return dbus_message_new_error(
- message, WPAS_ERROR_INVALID_IFACE,
- "wpa_supplicant knows nothing about this interface.");
-}
-
-
-/**
- * wpas_dbus_new_invalid_network_error - Return a new invalid network error message
- * @message: Pointer to incoming dbus message this error refers to
- * Returns: a dbus error message
- *
- * Convenience function to create and return an invalid network error
- */
-DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message)
-{
- return dbus_message_new_error(message, WPAS_ERROR_INVALID_NETWORK,
- "The requested network does not exist.");
-}
-
-
-/**
- * wpas_dbus_new_invalid_bssid_error - Return a new invalid bssid error message
- * @message: Pointer to incoming dbus message this error refers to
- * Returns: a dbus error message
- *
- * Convenience function to create and return an invalid bssid error
- */
-static DBusMessage * wpas_dbus_new_invalid_bssid_error(DBusMessage *message)
-{
- return dbus_message_new_error(message, WPAS_ERROR_INVALID_BSSID,
- "The BSSID requested was invalid.");
-}
-
-
-/**
- * wpas_dispatch_network_method - dispatch messages for configured networks
- * @message: the incoming dbus message
- * @wpa_s: a network interface's data
- * @network_id: id of the configured network we're interested in
- * Returns: a reply dbus message, or a dbus error message
- *
- * This function dispatches all incoming dbus messages for configured networks.
- */
-static DBusMessage * wpas_dispatch_network_method(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- int network_id)
-{
- DBusMessage *reply = NULL;
- const char *method = dbus_message_get_member(message);
- struct wpa_ssid *ssid;
-
- ssid = wpa_config_get_network(wpa_s->conf, network_id);
- if (ssid == NULL)
- return wpas_dbus_new_invalid_network_error(message);
-
- if (!strcmp(method, "set"))
- reply = wpas_dbus_iface_set_network(message, wpa_s, ssid);
- else if (!strcmp(method, "enable"))
- reply = wpas_dbus_iface_enable_network(message, wpa_s, ssid);
- else if (!strcmp(method, "disable"))
- reply = wpas_dbus_iface_disable_network(message, wpa_s, ssid);
-
- return reply;
-}
-
-
-/**
- * wpas_dispatch_bssid_method - dispatch messages for scanned networks
- * @message: the incoming dbus message
- * @wpa_s: a network interface's data
- * @bssid: bssid of the scanned network we're interested in
- * Returns: a reply dbus message, or a dbus error message
- *
- * This function dispatches all incoming dbus messages for scanned networks.
- */
-static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- const char *bssid_txt)
-{
- u8 bssid[ETH_ALEN];
- struct wpa_bss *bss;
-
- if (hexstr2bin(bssid_txt, bssid, ETH_ALEN) < 0)
- return wpas_dbus_new_invalid_bssid_error(message);
-
- bss = wpa_bss_get_bssid(wpa_s, bssid);
- if (bss == NULL)
- return wpas_dbus_new_invalid_bssid_error(message);
-
- /* Dispatch the method call against the scanned bssid */
- if (os_strcmp(dbus_message_get_member(message), "properties") == 0)
- return wpas_dbus_bssid_properties(message, wpa_s, bss);
-
- return NULL;
-}
-
-
-/**
- * wpas_iface_message_handler - Dispatch messages for interfaces or networks
- * @connection: Connection to the system message bus
- * @message: An incoming dbus message
- * @user_data: A pointer to a dbus control interface data structure
- * Returns: Whether or not the message was handled
- *
- * This function dispatches all incoming dbus messages for network interfaces,
- * or objects owned by them, such as scanned BSSIDs and configured networks.
- */
-static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection,
- DBusMessage *message,
- void *user_data)
-{
- struct wpa_supplicant *wpa_s = user_data;
- const char *method = dbus_message_get_member(message);
- const char *path = dbus_message_get_path(message);
- const char *msg_interface = dbus_message_get_interface(message);
- char *iface_obj_path = NULL;
- char *network = NULL;
- char *bssid = NULL;
- DBusMessage *reply = NULL;
-
- /* Caller must specify a message interface */
- if (!msg_interface)
- goto out;
-
- wpa_printf(MSG_MSGDUMP, "dbus[old/iface]: %s.%s (%s) [%s]",
- msg_interface, method, path,
- dbus_message_get_signature(message));
-
- iface_obj_path = wpas_dbus_decompose_object_path(path, &network,
- &bssid);
- if (iface_obj_path == NULL) {
- reply = wpas_dbus_new_invalid_iface_error(message);
- goto out;
- }
-
- /* Make sure the message's object path actually refers to the
- * wpa_supplicant structure it's supposed to (which is wpa_s)
- */
- if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global,
- iface_obj_path) != wpa_s) {
- reply = wpas_dbus_new_invalid_iface_error(message);
- goto out;
- }
-
- if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) {
- /* A method for one of this interface's configured networks */
- int nid = strtoul(network, NULL, 10);
-
- if (errno != EINVAL)
- reply = wpas_dispatch_network_method(message, wpa_s,
- nid);
- else
- reply = wpas_dbus_new_invalid_network_error(message);
- } else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) {
- /* A method for one of this interface's scanned BSSIDs */
- reply = wpas_dispatch_bssid_method(message, wpa_s, bssid);
- } else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) {
- /* A method for an interface only. */
- if (!strcmp(method, "scan"))
- reply = wpas_dbus_iface_scan(message, wpa_s);
- else if (!strcmp(method, "scanResults"))
- reply = wpas_dbus_iface_scan_results(message, wpa_s);
- else if (!strcmp(method, "addNetwork"))
- reply = wpas_dbus_iface_add_network(message, wpa_s);
- else if (!strcmp(method, "removeNetwork"))
- reply = wpas_dbus_iface_remove_network(message, wpa_s);
- else if (!strcmp(method, "selectNetwork"))
- reply = wpas_dbus_iface_select_network(message, wpa_s);
- else if (!strcmp(method, "capabilities"))
- reply = wpas_dbus_iface_capabilities(message, wpa_s);
- else if (!strcmp(method, "disconnect"))
- reply = wpas_dbus_iface_disconnect(message, wpa_s);
- else if (!strcmp(method, "setAPScan"))
- reply = wpas_dbus_iface_set_ap_scan(message, wpa_s);
- else if (!strcmp(method, "setSmartcardModules"))
- reply = wpas_dbus_iface_set_smartcard_modules(message,
- wpa_s);
- else if (!strcmp(method, "state"))
- reply = wpas_dbus_iface_get_state(message, wpa_s);
- else if (!strcmp(method, "scanning"))
- reply = wpas_dbus_iface_get_scanning(message, wpa_s);
-#ifndef CONFIG_NO_CONFIG_BLOBS
- else if (!strcmp(method, "setBlobs"))
- reply = wpas_dbus_iface_set_blobs(message, wpa_s);
- else if (!strcmp(method, "removeBlobs"))
- reply = wpas_dbus_iface_remove_blobs(message, wpa_s);
-#endif /* CONFIG_NO_CONFIG_BLOBS */
-#ifdef CONFIG_WPS
- else if (os_strcmp(method, "wpsPbc") == 0)
- reply = wpas_dbus_iface_wps_pbc(message, wpa_s);
- else if (os_strcmp(method, "wpsPin") == 0)
- reply = wpas_dbus_iface_wps_pin(message, wpa_s);
- else if (os_strcmp(method, "wpsReg") == 0)
- reply = wpas_dbus_iface_wps_reg(message, wpa_s);
-#endif /* CONFIG_WPS */
- else if (os_strcmp(method, "flush") == 0)
- reply = wpas_dbus_iface_flush(message, wpa_s);
- }
-
- /* If the message was handled, send back the reply */
-out:
- if (reply) {
- if (!dbus_message_get_no_reply(message))
- dbus_connection_send(connection, reply, NULL);
- dbus_message_unref(reply);
- }
-
- os_free(iface_obj_path);
- os_free(network);
- os_free(bssid);
- return reply ? DBUS_HANDLER_RESULT_HANDLED :
- DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-
-/**
- * wpas_message_handler - dispatch incoming dbus messages
- * @connection: connection to the system message bus
- * @message: an incoming dbus message
- * @user_data: a pointer to a dbus control interface data structure
- * Returns: whether or not the message was handled
- *
- * This function dispatches all incoming dbus messages to the correct
- * handlers, depending on what the message's target object path is,
- * and what the method call is.
- */
-static DBusHandlerResult wpas_message_handler(DBusConnection *connection,
- DBusMessage *message, void *user_data)
-{
- struct wpas_dbus_priv *ctrl_iface = user_data;
- const char *method;
- const char *path;
- const char *msg_interface;
- DBusMessage *reply = NULL;
-
- method = dbus_message_get_member(message);
- path = dbus_message_get_path(message);
- msg_interface = dbus_message_get_interface(message);
- if (!method || !path || !ctrl_iface || !msg_interface)
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
- wpa_printf(MSG_MSGDUMP, "dbus[old]: %s.%s (%s) [%s]",
- msg_interface, method, path,
- dbus_message_get_signature(message));
-
- /* Validate the method interface */
- if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0)
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
- if (!strcmp(path, WPAS_DBUS_PATH)) {
- /* dispatch methods against our global dbus interface here */
- if (!strcmp(method, "addInterface")) {
- reply = wpas_dbus_global_add_interface(
- message, ctrl_iface->global);
- } else if (!strcmp(method, "removeInterface")) {
- reply = wpas_dbus_global_remove_interface(
- message, ctrl_iface->global);
- } else if (!strcmp(method, "getInterface")) {
- reply = wpas_dbus_global_get_interface(
- message, ctrl_iface->global);
- } else if (!strcmp(method, "setDebugParams")) {
- reply = wpas_dbus_global_set_debugparams(
- message, ctrl_iface->global);
- }
- }
-
- /* If the message was handled, send back the reply */
- if (reply) {
- if (!dbus_message_get_no_reply(message))
- dbus_connection_send(connection, reply, NULL);
- dbus_message_unref(reply);
- }
-
- return reply ? DBUS_HANDLER_RESULT_HANDLED :
- DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-
-/**
- * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal
- * @wpa_s: %wpa_supplicant network interface data
- * Returns: 0 on success, -1 on failure
- *
- * Notify listeners that this interface has updated scan results.
- */
-void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s)
-{
- struct wpas_dbus_priv *iface = wpa_s->global->dbus;
- DBusMessage *_signal;
-
- /* Do nothing if the control interface is not turned on */
- if (iface == NULL || !wpa_s->dbus_path)
- return;
-
- _signal = dbus_message_new_signal(wpa_s->dbus_path,
- WPAS_DBUS_IFACE_INTERFACE,
- "ScanResultsAvailable");
- if (_signal == NULL) {
- wpa_printf(MSG_ERROR,
- "dbus: Not enough memory to send scan results signal");
- return;
- }
- dbus_connection_send(iface->con, _signal, NULL);
- dbus_message_unref(_signal);
-}
-
-
-/**
- * wpa_supplicant_dbus_notify_state_change - Send a state change signal
- * @wpa_s: %wpa_supplicant network interface data
- * @new_state: new state wpa_supplicant is entering
- * @old_state: old state wpa_supplicant is leaving
- * Returns: 0 on success, -1 on failure
- *
- * Notify listeners that wpa_supplicant has changed state
- */
-void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
- enum wpa_states new_state,
- enum wpa_states old_state)
-{
- struct wpas_dbus_priv *iface;
- DBusMessage *_signal = NULL;
- const char *new_state_str, *old_state_str;
-
- if (wpa_s->dbus_path == NULL)
- return; /* Skip signal since D-Bus setup is not yet ready */
-
- /* Do nothing if the control interface is not turned on */
- if (wpa_s->global == NULL)
- return;
- iface = wpa_s->global->dbus;
- if (iface == NULL)
- return;
-
- /* Only send signal if state really changed */
- if (new_state == old_state)
- return;
-
- _signal = dbus_message_new_signal(wpa_s->dbus_path,
- WPAS_DBUS_IFACE_INTERFACE,
- "StateChange");
- if (_signal == NULL) {
- wpa_printf(MSG_ERROR,
- "dbus: %s: could not create dbus signal; likely out of memory",
- __func__);
- return;
- }
-
- new_state_str = wpa_supplicant_state_txt(new_state);
- old_state_str = wpa_supplicant_state_txt(old_state);
-
- if (!dbus_message_append_args(_signal,
- DBUS_TYPE_STRING, &new_state_str,
- DBUS_TYPE_STRING, &old_state_str,
- DBUS_TYPE_INVALID)) {
- wpa_printf(MSG_ERROR,
- "dbus: %s: Not enough memory to construct state change signal",
- __func__);
- goto out;
- }
-
- dbus_connection_send(iface->con, _signal, NULL);
-
-out:
- dbus_message_unref(_signal);
-}
-
-
-/**
- * wpa_supplicant_dbus_notify_scanning - send scanning status
- * @wpa_s: %wpa_supplicant network interface data
- * Returns: 0 on success, -1 on failure
- *
- * Notify listeners of interface scanning state changes
- */
-void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s)
-{
- struct wpas_dbus_priv *iface = wpa_s->global->dbus;
- DBusMessage *_signal;
- dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
-
- /* Do nothing if the control interface is not turned on */
- if (iface == NULL || !wpa_s->dbus_path)
- return;
-
- _signal = dbus_message_new_signal(wpa_s->dbus_path,
- WPAS_DBUS_IFACE_INTERFACE,
- "Scanning");
- if (_signal == NULL) {
- wpa_printf(MSG_ERROR,
- "dbus: Not enough memory to send scan results signal");
- return;
- }
-
- if (dbus_message_append_args(_signal,
- DBUS_TYPE_BOOLEAN, &scanning,
- DBUS_TYPE_INVALID)) {
- dbus_connection_send(iface->con, _signal, NULL);
- } else {
- wpa_printf(MSG_ERROR,
- "dbus: Not enough memory to construct signal");
- }
- dbus_message_unref(_signal);
-}
-
-
-#ifdef CONFIG_WPS
-void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
- const struct wps_credential *cred)
-{
- struct wpas_dbus_priv *iface;
- DBusMessage *_signal = NULL;
-
- /* Do nothing if the control interface is not turned on */
- if (wpa_s->global == NULL)
- return;
- iface = wpa_s->global->dbus;
- if (iface == NULL || !wpa_s->dbus_path)
- return;
-
- _signal = dbus_message_new_signal(wpa_s->dbus_path,
- WPAS_DBUS_IFACE_INTERFACE,
- "WpsCred");
- if (_signal == NULL) {
- wpa_printf(MSG_ERROR,
- "dbus: %s: Could not create dbus signal; likely out of memory",
- __func__);
- return;
- }
-
- if (!dbus_message_append_args(_signal,
- DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
- &cred->cred_attr, cred->cred_attr_len,
- DBUS_TYPE_INVALID)) {
- wpa_printf(MSG_ERROR,
- "dbus: %s: Not enough memory to construct signal",
- __func__);
- goto out;
- }
-
- dbus_connection_send(iface->con, _signal, NULL);
-
-out:
- dbus_message_unref(_signal);
-}
-#else /* CONFIG_WPS */
-void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
- const struct wps_credential *cred)
-{
-}
-#endif /* CONFIG_WPS */
-
-void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s,
- int depth, const char *subject,
- const char *cert_hash,
- const struct wpabuf *cert)
-{
- struct wpas_dbus_priv *iface;
- DBusMessage *_signal = NULL;
- const char *hash;
- const char *cert_hex;
- int cert_hex_len;
-
- /* Do nothing if the control interface is not turned on */
- if (wpa_s->global == NULL)
- return;
- iface = wpa_s->global->dbus;
- if (iface == NULL || !wpa_s->dbus_path)
- return;
-
- _signal = dbus_message_new_signal(wpa_s->dbus_path,
- WPAS_DBUS_IFACE_INTERFACE,
- "Certification");
- if (_signal == NULL) {
- wpa_printf(MSG_ERROR,
- "dbus: %s: Could not create dbus signal; likely out of memory",
- __func__);
- return;
- }
-
- hash = cert_hash ? cert_hash : "";
- cert_hex = cert ? wpabuf_head(cert) : "";
- cert_hex_len = cert ? wpabuf_len(cert) : 0;
-
- if (!dbus_message_append_args(_signal,
- DBUS_TYPE_INT32, &depth,
- DBUS_TYPE_STRING, &subject,
- DBUS_TYPE_STRING, &hash,
- DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
- &cert_hex, cert_hex_len,
- DBUS_TYPE_INVALID)) {
- wpa_printf(MSG_ERROR,
- "dbus: %s: Not enough memory to construct signal",
- __func__);
- goto out;
- }
-
- dbus_connection_send(iface->con, _signal, NULL);
-
-out:
- dbus_message_unref(_signal);
-
-}
-
-
-/**
- * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface
- * @global: Pointer to global data from wpa_supplicant_init()
- * Returns: 0 on success, -1 on failure
- *
- * Initialize the dbus control interface and start receiving commands from
- * external programs over the bus.
- */
-int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface)
-{
- DBusError error;
- int ret = -1;
- DBusObjectPathVTable wpas_vtable = {
- NULL, &wpas_message_handler, NULL, NULL, NULL, NULL
- };
-
- /* Register the message handler for the global dbus interface */
- if (!dbus_connection_register_object_path(iface->con,
- WPAS_DBUS_PATH, &wpas_vtable,
- iface)) {
- wpa_printf(MSG_ERROR, "dbus: Could not set up message handler");
- return -1;
- }
-
- /* Register our service with the message bus */
- dbus_error_init(&error);
- switch (dbus_bus_request_name(iface->con, WPAS_DBUS_SERVICE,
- 0, &error)) {
- case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
- ret = 0;
- break;
- case DBUS_REQUEST_NAME_REPLY_EXISTS:
- case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
- case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
- wpa_printf(MSG_ERROR,
- "dbus: Could not request service name: already registered");
- break;
- default:
- wpa_printf(MSG_ERROR,
- "dbus: Could not request service name: %s %s",
- error.name, error.message);
- break;
- }
- dbus_error_free(&error);
-
- if (ret != 0)
- return -1;
-
- wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE
- "'.");
-
- return 0;
-}
-
-
-/**
- * wpas_dbus_register_new_iface - Register a new interface with dbus
- * @wpa_s: %wpa_supplicant interface description structure to register
- * Returns: 0 on success, -1 on error
- *
- * Registers a new interface with dbus and assigns it a dbus object path.
- */
-int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
-{
- struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus;
- DBusConnection * con;
- u32 next;
- DBusObjectPathVTable vtable = {
- NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL
- };
-
- /* Do nothing if the control interface is not turned on */
- if (ctrl_iface == NULL)
- return 0;
-
- con = ctrl_iface->con;
- next = ctrl_iface->next_objid++;
-
- /* Create and set the interface's object path */
- wpa_s->dbus_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
- if (wpa_s->dbus_path == NULL)
- return -1;
- os_snprintf(wpa_s->dbus_path, WPAS_DBUS_OBJECT_PATH_MAX,
- WPAS_DBUS_PATH_INTERFACES "/%u",
- next);
-
- /* Register the message handler for the interface functions */
- if (!dbus_connection_register_fallback(con, wpa_s->dbus_path, &vtable,
- wpa_s)) {
- wpa_printf(MSG_ERROR,
- "dbus: Could not set up message handler for interface %s",
- wpa_s->ifname);
- return -1;
- }
-
- return 0;
-}
-
-
-/**
- * wpas_dbus_unregister_iface - Unregister an interface from dbus
- * @wpa_s: wpa_supplicant interface structure
- * Returns: 0 on success, -1 on failure
- *
- * Unregisters the interface with dbus
- */
-int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s)
-{
- struct wpas_dbus_priv *ctrl_iface;
- DBusConnection *con;
-
- /* Do nothing if the control interface is not turned on */
- if (wpa_s == NULL || wpa_s->global == NULL)
- return 0;
- ctrl_iface = wpa_s->global->dbus;
- if (ctrl_iface == NULL || wpa_s->dbus_path == NULL)
- return 0;
-
- con = ctrl_iface->con;
- if (!dbus_connection_unregister_object_path(con, wpa_s->dbus_path))
- return -1;
-
- os_free(wpa_s->dbus_path);
- wpa_s->dbus_path = NULL;
-
- return 0;
-}
-
-
-/**
- * wpa_supplicant_get_iface_by_dbus_path - Get a new network interface
- * @global: Pointer to global data from wpa_supplicant_init()
- * @path: Pointer to a dbus object path representing an interface
- * Returns: Pointer to the interface or %NULL if not found
- */
-struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path(
- struct wpa_global *global, const char *path)
-{
- struct wpa_supplicant *wpa_s;
-
- for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
- if (wpa_s->dbus_path && strcmp(wpa_s->dbus_path, path) == 0)
- return wpa_s;
- }
- return NULL;
-}
diff --git a/wpa_supplicant/dbus/dbus_old.h b/wpa_supplicant/dbus/dbus_old.h
deleted file mode 100644
index 451a9f8..0000000
--- a/wpa_supplicant/dbus/dbus_old.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface
- * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef CTRL_IFACE_DBUS_H
-#define CTRL_IFACE_DBUS_H
-
-struct wps_credential;
-
-#ifdef CONFIG_CTRL_IFACE_DBUS
-
-#define WPAS_DBUS_OBJECT_PATH_MAX 150
-
-#define WPAS_DBUS_SERVICE "fi.epitest.hostap.WPASupplicant"
-#define WPAS_DBUS_PATH "/fi/epitest/hostap/WPASupplicant"
-#define WPAS_DBUS_INTERFACE "fi.epitest.hostap.WPASupplicant"
-
-#define WPAS_DBUS_PATH_INTERFACES WPAS_DBUS_PATH "/Interfaces"
-#define WPAS_DBUS_IFACE_INTERFACE WPAS_DBUS_INTERFACE ".Interface"
-
-#define WPAS_DBUS_NETWORKS_PART "Networks"
-#define WPAS_DBUS_IFACE_NETWORK WPAS_DBUS_INTERFACE ".Network"
-
-#define WPAS_DBUS_BSSIDS_PART "BSSIDs"
-#define WPAS_DBUS_IFACE_BSSID WPAS_DBUS_INTERFACE ".BSSID"
-
-
-/* Errors */
-#define WPAS_ERROR_INVALID_NETWORK \
- WPAS_DBUS_IFACE_INTERFACE ".InvalidNetwork"
-#define WPAS_ERROR_INVALID_BSSID \
- WPAS_DBUS_IFACE_INTERFACE ".InvalidBSSID"
-
-#define WPAS_ERROR_INVALID_OPTS \
- WPAS_DBUS_INTERFACE ".InvalidOptions"
-#define WPAS_ERROR_INVALID_IFACE \
- WPAS_DBUS_INTERFACE ".InvalidInterface"
-
-#define WPAS_ERROR_ADD_ERROR \
- WPAS_DBUS_INTERFACE ".AddError"
-#define WPAS_ERROR_EXISTS_ERROR \
- WPAS_DBUS_INTERFACE ".ExistsError"
-#define WPAS_ERROR_REMOVE_ERROR \
- WPAS_DBUS_INTERFACE ".RemoveError"
-
-#define WPAS_ERROR_SCAN_ERROR \
- WPAS_DBUS_IFACE_INTERFACE ".ScanError"
-#define WPAS_ERROR_ADD_NETWORK_ERROR \
- WPAS_DBUS_IFACE_INTERFACE ".AddNetworkError"
-#define WPAS_ERROR_INTERNAL_ERROR \
- WPAS_DBUS_IFACE_INTERFACE ".InternalError"
-#define WPAS_ERROR_REMOVE_NETWORK_ERROR \
- WPAS_DBUS_IFACE_INTERFACE ".RemoveNetworkError"
-
-#define WPAS_ERROR_WPS_PBC_ERROR \
- WPAS_DBUS_IFACE_INTERFACE ".WpsPbcError"
-#define WPAS_ERROR_WPS_PIN_ERROR \
- WPAS_DBUS_IFACE_INTERFACE ".WpsPinError"
-#define WPAS_ERROR_WPS_REG_ERROR \
- WPAS_DBUS_IFACE_INTERFACE ".WpsRegError"
-
-#define WPAS_DBUS_BSSID_FORMAT "%02x%02x%02x%02x%02x%02x"
-
-struct wpa_global;
-struct wpa_supplicant;
-
-int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface);
-void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s);
-void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s);
-void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
- enum wpa_states new_state,
- enum wpa_states old_state);
-void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
- const struct wps_credential *cred);
-void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s,
- int depth, const char *subject,
- const char *cert_hash,
- const struct wpabuf *cert);
-
-char * wpas_dbus_decompose_object_path(const char *path, char **network,
- char **bssid);
-
-int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s);
-int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s);
-
-
-/* Methods internal to the dbus control interface */
-struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path(
- struct wpa_global *global, const char *path);
-
-#else /* CONFIG_CTRL_IFACE_DBUS */
-
-static inline void
-wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s)
-{
-}
-
-static inline void
-wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s)
-{
-}
-
-static inline void
-wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
- enum wpa_states new_state,
- enum wpa_states old_state)
-{
-}
-
-static inline void
-wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
- const struct wps_credential *cred)
-{
-}
-
-static inline void
-wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s,
- int depth, const char *subject,
- const char *cert_hash,
- const struct wpabuf *cert)
-{
-}
-
-static inline int
-wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
-{
- return 0;
-}
-
-static inline int
-wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s)
-{
- return 0;
-}
-
-#endif /* CONFIG_CTRL_IFACE_DBUS */
-
-#endif /* CTRL_IFACE_DBUS_H */
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c
deleted file mode 100644
index e540832..0000000
--- a/wpa_supplicant/dbus/dbus_old_handlers.c
+++ /dev/null
@@ -1,1393 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface
- * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-#include <dbus/dbus.h>
-
-#include "common.h"
-#include "eap_peer/eap_methods.h"
-#include "common/ieee802_11_defs.h"
-#include "eapol_supp/eapol_supp_sm.h"
-#include "rsn_supp/wpa.h"
-#include "../config.h"
-#include "../wpa_supplicant_i.h"
-#include "../driver_i.h"
-#include "../notify.h"
-#include "../wpas_glue.h"
-#include "../bss.h"
-#include "../scan.h"
-#include "dbus_old.h"
-#include "dbus_old_handlers.h"
-#include "dbus_dict_helpers.h"
-
-/**
- * wpas_dbus_new_invalid_opts_error - Return a new invalid options error message
- * @message: Pointer to incoming dbus message this error refers to
- * Returns: a dbus error message
- *
- * Convenience function to create and return an invalid options error
- */
-DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message,
- const char *arg)
-{
- DBusMessage *reply;
-
- reply = dbus_message_new_error(
- message, WPAS_ERROR_INVALID_OPTS,
- "Did not receive correct message arguments.");
- if (arg != NULL)
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
- DBUS_TYPE_INVALID);
-
- return reply;
-}
-
-
-/**
- * wpas_dbus_new_success_reply - Return a new success reply message
- * @message: Pointer to incoming dbus message this reply refers to
- * Returns: a dbus message containing a single UINT32 that indicates
- * success (ie, a value of 1)
- *
- * Convenience function to create and return a success reply message
- */
-DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message)
-{
- DBusMessage *reply;
- unsigned int success = 1;
-
- reply = dbus_message_new_method_return(message);
- dbus_message_append_args(reply, DBUS_TYPE_UINT32, &success,
- DBUS_TYPE_INVALID);
- return reply;
-}
-
-
-/**
- * wpas_dbus_global_add_interface - Request registration of a network interface
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: The object path of the new interface object,
- * or a dbus error message with more information
- *
- * Handler function for "addInterface" method call. Handles requests
- * by dbus clients to register a network interface that wpa_supplicant
- * will manage.
- */
-DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
- struct wpa_global *global)
-{
- char *ifname = NULL;
- char *driver = NULL;
- char *driver_param = NULL;
- char *confname = NULL;
- char *bridge_ifname = NULL;
- DBusMessage *reply = NULL;
- DBusMessageIter iter;
-
- dbus_message_iter_init(message, &iter);
-
- /* First argument: interface name (DBUS_TYPE_STRING)
- * Required; must be non-zero length
- */
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
- goto error;
- dbus_message_iter_get_basic(&iter, &ifname);
- if (!os_strlen(ifname))
- goto error;
-
- /* Second argument: dict of options */
- if (dbus_message_iter_next(&iter)) {
- DBusMessageIter iter_dict;
- struct wpa_dbus_dict_entry entry;
-
- if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
- goto error;
- while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
- if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
- goto error;
- if (!strcmp(entry.key, "driver") &&
- entry.type == DBUS_TYPE_STRING) {
- os_free(driver);
- driver = os_strdup(entry.str_value);
- wpa_dbus_dict_entry_clear(&entry);
- if (driver == NULL)
- goto error;
- } else if (!strcmp(entry.key, "driver-params") &&
- entry.type == DBUS_TYPE_STRING) {
- os_free(driver_param);
- driver_param = os_strdup(entry.str_value);
- wpa_dbus_dict_entry_clear(&entry);
- if (driver_param == NULL)
- goto error;
- } else if (!strcmp(entry.key, "config-file") &&
- entry.type == DBUS_TYPE_STRING) {
- os_free(confname);
- confname = os_strdup(entry.str_value);
- wpa_dbus_dict_entry_clear(&entry);
- if (confname == NULL)
- goto error;
- } else if (!strcmp(entry.key, "bridge-ifname") &&
- entry.type == DBUS_TYPE_STRING) {
- os_free(bridge_ifname);
- bridge_ifname = os_strdup(entry.str_value);
- wpa_dbus_dict_entry_clear(&entry);
- if (bridge_ifname == NULL)
- goto error;
- } else {
- wpa_dbus_dict_entry_clear(&entry);
- goto error;
- }
- }
- }
-
- /*
- * Try to get the wpa_supplicant record for this iface, return
- * an error if we already control it.
- */
- if (wpa_supplicant_get_iface(global, ifname) != NULL) {
- reply = dbus_message_new_error(
- message, WPAS_ERROR_EXISTS_ERROR,
- "wpa_supplicant already controls this interface.");
- } else {
- struct wpa_supplicant *wpa_s;
- struct wpa_interface iface;
-
- os_memset(&iface, 0, sizeof(iface));
- iface.ifname = ifname;
- iface.driver = driver;
- iface.driver_param = driver_param;
- iface.confname = confname;
- iface.bridge_ifname = bridge_ifname;
- /* Otherwise, have wpa_supplicant attach to it. */
- wpa_s = wpa_supplicant_add_iface(global, &iface, NULL);
- if (wpa_s && wpa_s->dbus_path) {
- const char *path = wpa_s->dbus_path;
-
- reply = dbus_message_new_method_return(message);
- dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
- &path, DBUS_TYPE_INVALID);
- } else {
- reply = dbus_message_new_error(
- message, WPAS_ERROR_ADD_ERROR,
- "wpa_supplicant couldn't grab this interface.");
- }
- }
-
-out:
- os_free(driver);
- os_free(driver_param);
- os_free(confname);
- os_free(bridge_ifname);
- return reply;
-
-error:
- reply = wpas_dbus_new_invalid_opts_error(message, NULL);
- goto out;
-}
-
-
-/**
- * wpas_dbus_global_remove_interface - Request deregistration of an interface
- * @message: Pointer to incoming dbus message
- * @global: wpa_supplicant global data structure
- * Returns: a dbus message containing a UINT32 indicating success (1) or
- * failure (0), or returns a dbus error message with more information
- *
- * Handler function for "removeInterface" method call. Handles requests
- * by dbus clients to deregister a network interface that wpa_supplicant
- * currently manages.
- */
-DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
- struct wpa_global *global)
-{
- struct wpa_supplicant *wpa_s;
- char *path;
- DBusMessage *reply = NULL;
-
- if (!dbus_message_get_args(message, NULL,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID)) {
- reply = wpas_dbus_new_invalid_opts_error(message, NULL);
- goto out;
- }
-
- wpa_s = wpa_supplicant_get_iface_by_dbus_path(global, path);
- if (wpa_s == NULL) {
- reply = wpas_dbus_new_invalid_iface_error(message);
- goto out;
- }
-
- if (!wpa_supplicant_remove_iface(global, wpa_s, 0)) {
- reply = wpas_dbus_new_success_reply(message);
- } else {
- reply = dbus_message_new_error(
- message, WPAS_ERROR_REMOVE_ERROR,
- "wpa_supplicant couldn't remove this interface.");
- }
-
-out:
- return reply;
-}
-
-
-/**
- * wpas_dbus_global_get_interface - Get the object path for an interface name
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: The object path of the interface object,
- * or a dbus error message with more information
- *
- * Handler function for "getInterface" method call. Handles requests
- * by dbus clients for the object path of an specific network interface.
- */
-DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message,
- struct wpa_global *global)
-{
- DBusMessage *reply = NULL;
- const char *ifname;
- const char *path;
- struct wpa_supplicant *wpa_s;
-
- if (!dbus_message_get_args(message, NULL,
- DBUS_TYPE_STRING, &ifname,
- DBUS_TYPE_INVALID)) {
- reply = wpas_dbus_new_invalid_opts_error(message, NULL);
- goto out;
- }
-
- wpa_s = wpa_supplicant_get_iface(global, ifname);
- if (wpa_s == NULL || !wpa_s->dbus_path) {
- reply = wpas_dbus_new_invalid_iface_error(message);
- goto out;
- }
-
- path = wpa_s->dbus_path;
- reply = dbus_message_new_method_return(message);
- dbus_message_append_args(reply,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID);
-
-out:
- return reply;
-}
-
-
-/**
- * wpas_dbus_global_set_debugparams- Set the debug params
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: a dbus message containing a UINT32 indicating success (1) or
- * failure (0), or returns a dbus error message with more information
- *
- * Handler function for "setDebugParams" method call. Handles requests
- * by dbus clients for the object path of an specific network interface.
- */
-DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message,
- struct wpa_global *global)
-{
- DBusMessage *reply = NULL;
- int debug_level;
- dbus_bool_t debug_timestamp;
- dbus_bool_t debug_show_keys;
-
- if (!dbus_message_get_args(message, NULL,
- DBUS_TYPE_INT32, &debug_level,
- DBUS_TYPE_BOOLEAN, &debug_timestamp,
- DBUS_TYPE_BOOLEAN, &debug_show_keys,
- DBUS_TYPE_INVALID)) {
- return wpas_dbus_new_invalid_opts_error(message, NULL);
- }
-
- if (wpa_supplicant_set_debug_params(global, debug_level,
- debug_timestamp ? 1 : 0,
- debug_show_keys ? 1 : 0)) {
- return wpas_dbus_new_invalid_opts_error(message, NULL);
- }
-
- reply = wpas_dbus_new_success_reply(message);
-
- return reply;
-}
-
-
-/**
- * wpas_dbus_iface_scan - Request a wireless scan on an interface
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: a dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "scan" method call of a network device. Requests
- * that wpa_supplicant perform a wireless scan as soon as possible
- * on a particular wireless interface.
- */
-DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- wpa_s->scan_req = MANUAL_SCAN_REQ;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- return wpas_dbus_new_success_reply(message);
-}
-
-
-/**
- * wpas_dbus_iface_scan_results - Get the results of a recent scan request
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: a dbus message containing a dbus array of objects paths, or returns
- * a dbus error message if not scan results could be found
- *
- * Handler function for "scanResults" method call of a network device. Returns
- * a dbus message containing the object paths of wireless networks found.
- */
-DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessage *reply;
- DBusMessageIter iter;
- DBusMessageIter sub_iter;
- struct wpa_bss *bss;
-
- if (!wpa_s->dbus_path)
- return dbus_message_new_error(message,
- WPAS_ERROR_INTERNAL_ERROR,
- "no D-Bus interface available");
-
- /* Create and initialize the return message */
- reply = dbus_message_new_method_return(message);
- dbus_message_iter_init_append(reply, &iter);
- if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_OBJECT_PATH_AS_STRING,
- &sub_iter))
- goto error;
-
- /* Loop through scan results and append each result's object path */
- dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
- char path_buf[WPAS_DBUS_OBJECT_PATH_MAX];
- char *path = path_buf;
-
- /* Construct the object path for this network. Note that ':'
- * is not a valid character in dbus object paths.
- */
- os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
- "%s/" WPAS_DBUS_BSSIDS_PART "/"
- WPAS_DBUS_BSSID_FORMAT,
- wpa_s->dbus_path, MAC2STR(bss->bssid));
- if (!dbus_message_iter_append_basic(&sub_iter,
- DBUS_TYPE_OBJECT_PATH,
- &path))
- goto error;
- }
-
- if (!dbus_message_iter_close_container(&iter, &sub_iter))
- goto error;
-
- return reply;
-
-error:
- dbus_message_unref(reply);
- return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
- "an internal error occurred returning scan results");
-}
-
-
-/**
- * wpas_dbus_bssid_properties - Return the properties of a scanned network
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * @res: wpa_supplicant scan result for which to get properties
- * Returns: a dbus message containing the properties for the requested network
- *
- * Handler function for "properties" method call of a scanned network.
- * Returns a dbus message containing the the properties.
- */
-DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- struct wpa_bss *bss)
-{
- DBusMessage *reply;
- DBusMessageIter iter, iter_dict;
- const u8 *wpa_ie, *rsn_ie, *wps_ie;
-
- /* Dump the properties into a dbus message */
- reply = dbus_message_new_method_return(message);
-
- wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
- rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
- wps_ie = wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
-
- dbus_message_iter_init_append(reply, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &iter_dict) ||
- !wpa_dbus_dict_append_byte_array(&iter_dict, "bssid",
- (const char *) bss->bssid,
- ETH_ALEN) ||
- !wpa_dbus_dict_append_byte_array(&iter_dict, "ssid",
- (const char *) bss->ssid,
- bss->ssid_len) ||
- (wpa_ie &&
- !wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie",
- (const char *) wpa_ie,
- wpa_ie[1] + 2)) ||
- (rsn_ie &&
- !wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie",
- (const char *) rsn_ie,
- rsn_ie[1] + 2)) ||
- (wps_ie &&
- !wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie",
- (const char *) wps_ie,
- wps_ie[1] + 2)) ||
- (bss->freq &&
- !wpa_dbus_dict_append_int32(&iter_dict, "frequency", bss->freq)) ||
- !wpa_dbus_dict_append_uint16(&iter_dict, "capabilities",
- bss->caps) ||
- (!(bss->flags & WPA_BSS_QUAL_INVALID) &&
- !wpa_dbus_dict_append_int32(&iter_dict, "quality", bss->qual)) ||
- (!(bss->flags & WPA_BSS_NOISE_INVALID) &&
- !wpa_dbus_dict_append_int32(&iter_dict, "noise", bss->noise)) ||
- (!(bss->flags & WPA_BSS_LEVEL_INVALID) &&
- !wpa_dbus_dict_append_int32(&iter_dict, "level", bss->level)) ||
- !wpa_dbus_dict_append_int32(&iter_dict, "maxrate",
- wpa_bss_get_max_rate(bss) * 500000) ||
- !wpa_dbus_dict_close_write(&iter, &iter_dict)) {
- if (reply)
- dbus_message_unref(reply);
- reply = dbus_message_new_error(
- message, WPAS_ERROR_INTERNAL_ERROR,
- "an internal error occurred returning BSSID properties.");
- }
-
- return reply;
-}
-
-
-/**
- * wpas_dbus_iface_capabilities - Return interface capabilities
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a dict of strings
- *
- * Handler function for "capabilities" method call of an interface.
- */
-DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessage *reply = NULL;
- struct wpa_driver_capa capa;
- int res;
- DBusMessageIter iter, iter_dict;
- char **eap_methods;
- size_t num_items;
- dbus_bool_t strict = FALSE;
- DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
-
- if (!dbus_message_get_args(message, NULL,
- DBUS_TYPE_BOOLEAN, &strict,
- DBUS_TYPE_INVALID))
- strict = FALSE;
-
- reply = dbus_message_new_method_return(message);
-
- dbus_message_iter_init_append(reply, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
- goto error;
-
- /* EAP methods */
- eap_methods = eap_get_names_as_string_array(&num_items);
- if (eap_methods) {
- dbus_bool_t success;
- size_t i = 0;
-
- success = wpa_dbus_dict_append_string_array(
- &iter_dict, "eap", (const char **) eap_methods,
- num_items);
-
- /* free returned method array */
- while (eap_methods[i])
- os_free(eap_methods[i++]);
- os_free(eap_methods);
-
- if (!success)
- goto error;
- }
-
- res = wpa_drv_get_capa(wpa_s, &capa);
-
- /***** pairwise cipher */
- if (res < 0) {
- if (!strict) {
- const char *args[] = {"CCMP", "TKIP", "NONE"};
-
- if (!wpa_dbus_dict_append_string_array(
- &iter_dict, "pairwise", args,
- ARRAY_SIZE(args)))
- goto error;
- }
- } else {
- if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise",
- &iter_dict_entry,
- &iter_dict_val,
- &iter_array) ||
- ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "CCMP")) ||
- ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "TKIP")) ||
- ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "NONE")) ||
- !wpa_dbus_dict_end_string_array(&iter_dict,
- &iter_dict_entry,
- &iter_dict_val,
- &iter_array))
- goto error;
- }
-
- /***** group cipher */
- if (res < 0) {
- if (!strict) {
- const char *args[] = {
- "CCMP", "TKIP", "WEP104", "WEP40"
- };
-
- if (!wpa_dbus_dict_append_string_array(
- &iter_dict, "group", args,
- ARRAY_SIZE(args)))
- goto error;
- }
- } else {
- if (!wpa_dbus_dict_begin_string_array(&iter_dict, "group",
- &iter_dict_entry,
- &iter_dict_val,
- &iter_array))
- goto error;
-
- if (((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "CCMP")) ||
- ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "TKIP")) ||
- ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "WEP104")) ||
- ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "WEP40")) ||
- !wpa_dbus_dict_end_string_array(&iter_dict,
- &iter_dict_entry,
- &iter_dict_val,
- &iter_array))
- goto error;
- }
-
- /***** key management */
- if (res < 0) {
- if (!strict) {
- const char *args[] = {
- "WPA-PSK", "WPA-EAP", "IEEE8021X", "WPA-NONE",
- "NONE"
- };
- if (!wpa_dbus_dict_append_string_array(
- &iter_dict, "key_mgmt", args,
- ARRAY_SIZE(args)))
- goto error;
- }
- } else {
- if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt",
- &iter_dict_entry,
- &iter_dict_val,
- &iter_array) ||
- !wpa_dbus_dict_string_array_add_element(&iter_array,
- "NONE") ||
- !wpa_dbus_dict_string_array_add_element(&iter_array,
- "IEEE8021X") ||
- ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "WPA-EAP")) ||
- ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "WPA-PSK")) ||
- ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "WPA-NONE")) ||
- !wpa_dbus_dict_end_string_array(&iter_dict,
- &iter_dict_entry,
- &iter_dict_val,
- &iter_array))
- goto error;
- }
-
- /***** WPA protocol */
- if (res < 0) {
- if (!strict) {
- const char *args[] = { "RSN", "WPA" };
-
- if (!wpa_dbus_dict_append_string_array(
- &iter_dict, "proto", args,
- ARRAY_SIZE(args)))
- goto error;
- }
- } else {
- if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto",
- &iter_dict_entry,
- &iter_dict_val,
- &iter_array) ||
- ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "RSN")) ||
- ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "WPA")) ||
- !wpa_dbus_dict_end_string_array(&iter_dict,
- &iter_dict_entry,
- &iter_dict_val,
- &iter_array))
- goto error;
- }
-
- /***** auth alg */
- if (res < 0) {
- if (!strict) {
- const char *args[] = { "OPEN", "SHARED", "LEAP" };
-
- if (!wpa_dbus_dict_append_string_array(
- &iter_dict, "auth_alg", args,
- ARRAY_SIZE(args)))
- goto error;
- }
- } else {
- if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg",
- &iter_dict_entry,
- &iter_dict_val,
- &iter_array) ||
- ((capa.auth & WPA_DRIVER_AUTH_OPEN) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "OPEN")) ||
- ((capa.auth & WPA_DRIVER_AUTH_SHARED) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "SHARED")) ||
- ((capa.auth & WPA_DRIVER_AUTH_LEAP) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "LEAP")) ||
- !wpa_dbus_dict_end_string_array(&iter_dict,
- &iter_dict_entry,
- &iter_dict_val,
- &iter_array))
- goto error;
- }
-
- if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
- goto error;
-
- return reply;
-
-error:
- if (reply)
- dbus_message_unref(reply);
- return dbus_message_new_error(
- message, WPAS_ERROR_INTERNAL_ERROR,
- "an internal error occurred returning interface capabilities.");
-}
-
-
-/**
- * wpas_dbus_iface_add_network - Add a new configured network
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing the object path of the new network
- *
- * Handler function for "addNetwork" method call of a network interface.
- */
-DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessage *reply = NULL;
- struct wpa_ssid *ssid = NULL;
- char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
-
- if (wpa_s->dbus_path)
- ssid = wpa_supplicant_add_network(wpa_s);
- if (ssid == NULL) {
- reply = dbus_message_new_error(
- message, WPAS_ERROR_ADD_NETWORK_ERROR,
- "wpa_supplicant could not add a network on this interface.");
- goto out;
- }
-
- /* Construct the object path for this network. */
- os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
- "%s/" WPAS_DBUS_NETWORKS_PART "/%d",
- wpa_s->dbus_path, ssid->id);
-
- reply = dbus_message_new_method_return(message);
- dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
- &path, DBUS_TYPE_INVALID);
-
-out:
- return reply;
-}
-
-
-/**
- * wpas_dbus_iface_remove_network - Remove a configured network
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "removeNetwork" method call of a network interface.
- */
-DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessage *reply = NULL;
- const char *op;
- char *iface = NULL, *net_id = NULL;
- int id;
- int result;
-
- if (!dbus_message_get_args(message, NULL,
- DBUS_TYPE_OBJECT_PATH, &op,
- DBUS_TYPE_INVALID)) {
- reply = wpas_dbus_new_invalid_opts_error(message, NULL);
- goto out;
- }
-
- /* Extract the network ID */
- iface = wpas_dbus_decompose_object_path(op, &net_id, NULL);
- if (iface == NULL || net_id == NULL) {
- reply = wpas_dbus_new_invalid_network_error(message);
- goto out;
- }
-
- /* Ensure the network is actually a child of this interface */
- if (!wpa_s->dbus_path || os_strcmp(iface, wpa_s->dbus_path) != 0) {
- reply = wpas_dbus_new_invalid_network_error(message);
- goto out;
- }
-
- id = strtoul(net_id, NULL, 10);
- result = wpa_supplicant_remove_network(wpa_s, id);
- if (result == -1) {
- reply = wpas_dbus_new_invalid_network_error(message);
- goto out;
- }
- if (result == -2) {
- reply = dbus_message_new_error(
- message, WPAS_ERROR_REMOVE_NETWORK_ERROR,
- "error removing the specified on this interface.");
- goto out;
- }
-
- reply = wpas_dbus_new_success_reply(message);
-
-out:
- os_free(iface);
- os_free(net_id);
- return reply;
-}
-
-
-static const char * const dont_quote[] = {
- "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
- "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
- "bssid", "scan_freq", "freq_list", NULL
-};
-
-
-static dbus_bool_t should_quote_opt(const char *key)
-{
- int i = 0;
-
- while (dont_quote[i] != NULL) {
- if (os_strcmp(key, dont_quote[i]) == 0)
- return FALSE;
- i++;
- }
- return TRUE;
-}
-
-
-/**
- * wpas_dbus_iface_set_network - Set options for a configured network
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * @ssid: wpa_ssid structure for a configured network
- * Returns: a dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "set" method call of a configured network.
- */
-DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
-{
- DBusMessage *reply = NULL;
- struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
- DBusMessageIter iter, iter_dict;
-
- dbus_message_iter_init(message, &iter);
-
- if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) {
- reply = wpas_dbus_new_invalid_opts_error(message, NULL);
- goto out;
- }
-
- while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
- char *value = NULL;
- size_t size = 50;
- int ret;
-
- if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
- reply = wpas_dbus_new_invalid_opts_error(message,
- NULL);
- goto out;
- }
-
- /* Type conversions, since wpa_supplicant wants strings */
- if (entry.type == DBUS_TYPE_ARRAY &&
- entry.array_type == DBUS_TYPE_BYTE) {
- if (entry.array_len <= 0)
- goto error;
-
- size = entry.array_len * 2 + 1;
- value = os_zalloc(size);
- if (value == NULL)
- goto error;
- ret = wpa_snprintf_hex(value, size,
- (u8 *) entry.bytearray_value,
- entry.array_len);
- if (ret <= 0)
- goto error;
- } else if (entry.type == DBUS_TYPE_STRING) {
- if (should_quote_opt(entry.key)) {
- size = os_strlen(entry.str_value);
- /* Zero-length option check */
- if (size == 0)
- goto error;
- size += 3; /* For quotes and terminator */
- value = os_zalloc(size);
- if (value == NULL)
- goto error;
- ret = os_snprintf(value, size, "\"%s\"",
- entry.str_value);
- if (os_snprintf_error(size, ret))
- goto error;
- } else {
- value = os_strdup(entry.str_value);
- if (value == NULL)
- goto error;
- }
- } else if (entry.type == DBUS_TYPE_UINT32) {
- value = os_zalloc(size);
- if (value == NULL)
- goto error;
- ret = os_snprintf(value, size, "%u",
- entry.uint32_value);
- if (os_snprintf_error(size, ret))
- goto error;
- } else if (entry.type == DBUS_TYPE_INT32) {
- value = os_zalloc(size);
- if (value == NULL)
- goto error;
- ret = os_snprintf(value, size, "%d",
- entry.int32_value);
- if (os_snprintf_error(size, ret))
- goto error;
- } else
- goto error;
-
- if (wpa_config_set(ssid, entry.key, value, 0) < 0)
- goto error;
-
- if ((os_strcmp(entry.key, "psk") == 0 &&
- value[0] == '"' && ssid->ssid_len) ||
- (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
- wpa_config_update_psk(ssid);
- else if (os_strcmp(entry.key, "priority") == 0)
- wpa_config_update_prio_list(wpa_s->conf);
-
- os_free(value);
- wpa_dbus_dict_entry_clear(&entry);
- continue;
-
- error:
- os_free(value);
- reply = wpas_dbus_new_invalid_opts_error(message, entry.key);
- wpa_dbus_dict_entry_clear(&entry);
- break;
- }
-
- if (!reply)
- reply = wpas_dbus_new_success_reply(message);
-
-out:
- return reply;
-}
-
-
-/**
- * wpas_dbus_iface_enable_network - Mark a configured network as enabled
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * @ssid: wpa_ssid structure for a configured network
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "enable" method call of a configured network.
- */
-DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
-{
- wpa_supplicant_enable_network(wpa_s, ssid);
- return wpas_dbus_new_success_reply(message);
-}
-
-
-/**
- * wpas_dbus_iface_disable_network - Mark a configured network as disabled
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * @ssid: wpa_ssid structure for a configured network
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "disable" method call of a configured network.
- */
-DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
-{
- wpa_supplicant_disable_network(wpa_s, ssid);
- return wpas_dbus_new_success_reply(message);
-}
-
-
-/**
- * wpas_dbus_iface_select_network - Attempt association with a configured network
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "selectNetwork" method call of network interface.
- */
-DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessage *reply = NULL;
- const char *op;
- struct wpa_ssid *ssid;
- char *iface_obj_path = NULL;
- char *network = NULL;
-
- if (os_strlen(dbus_message_get_signature(message)) == 0) {
- /* Any network */
- ssid = NULL;
- } else {
- int nid;
-
- if (!dbus_message_get_args(message, NULL,
- DBUS_TYPE_OBJECT_PATH, &op,
- DBUS_TYPE_INVALID)) {
- reply = wpas_dbus_new_invalid_opts_error(message,
- NULL);
- goto out;
- }
-
- /* Extract the network number */
- iface_obj_path = wpas_dbus_decompose_object_path(op,
- &network,
- NULL);
- if (iface_obj_path == NULL) {
- reply = wpas_dbus_new_invalid_iface_error(message);
- goto out;
- }
- /* Ensure the object path really points to this interface */
- if (network == NULL || !wpa_s->dbus_path ||
- os_strcmp(iface_obj_path, wpa_s->dbus_path) != 0) {
- reply = wpas_dbus_new_invalid_network_error(message);
- goto out;
- }
-
- nid = strtoul(network, NULL, 10);
- if (errno == EINVAL) {
- reply = wpas_dbus_new_invalid_network_error(message);
- goto out;
- }
-
- ssid = wpa_config_get_network(wpa_s->conf, nid);
- if (ssid == NULL) {
- reply = wpas_dbus_new_invalid_network_error(message);
- goto out;
- }
- }
-
- /* Finally, associate with the network */
- wpa_supplicant_select_network(wpa_s, ssid);
-
- reply = wpas_dbus_new_success_reply(message);
-
-out:
- os_free(iface_obj_path);
- os_free(network);
- return reply;
-}
-
-
-/**
- * wpas_dbus_iface_disconnect - Terminate the current connection
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "disconnect" method call of network interface.
- */
-DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- wpas_request_disconnection(wpa_s);
-
- return wpas_dbus_new_success_reply(message);
-}
-
-
-/**
- * wpas_dbus_iface_set_ap_scan - Control roaming mode
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "setAPScan" method call.
- */
-DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessage *reply = NULL;
- dbus_uint32_t ap_scan = 1;
-
- if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan,
- DBUS_TYPE_INVALID)) {
- reply = wpas_dbus_new_invalid_opts_error(message, NULL);
- goto out;
- }
-
- if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
- reply = wpas_dbus_new_invalid_opts_error(message, NULL);
- goto out;
- }
-
- reply = wpas_dbus_new_success_reply(message);
-
-out:
- return reply;
-}
-
-
-/**
- * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "setSmartcardModules" method call.
- */
-DBusMessage * wpas_dbus_iface_set_smartcard_modules(
- DBusMessage *message, struct wpa_supplicant *wpa_s)
-{
- DBusMessageIter iter, iter_dict;
- char *opensc_engine_path = NULL;
- char *pkcs11_engine_path = NULL;
- char *pkcs11_module_path = NULL;
- struct wpa_dbus_dict_entry entry;
-
- if (!dbus_message_iter_init(message, &iter))
- goto error;
-
- if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
- goto error;
-
- while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
- if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
- goto error;
- if (!strcmp(entry.key, "opensc_engine_path") &&
- entry.type == DBUS_TYPE_STRING) {
- os_free(opensc_engine_path);
- opensc_engine_path = os_strdup(entry.str_value);
- wpa_dbus_dict_entry_clear(&entry);
- if (opensc_engine_path == NULL)
- goto error;
- } else if (!strcmp(entry.key, "pkcs11_engine_path") &&
- entry.type == DBUS_TYPE_STRING) {
- os_free(pkcs11_engine_path);
- pkcs11_engine_path = os_strdup(entry.str_value);
- wpa_dbus_dict_entry_clear(&entry);
- if (pkcs11_engine_path == NULL)
- goto error;
- } else if (!strcmp(entry.key, "pkcs11_module_path") &&
- entry.type == DBUS_TYPE_STRING) {
- os_free(pkcs11_module_path);
- pkcs11_module_path = os_strdup(entry.str_value);
- wpa_dbus_dict_entry_clear(&entry);
- if (pkcs11_module_path == NULL)
- goto error;
- } else {
- wpa_dbus_dict_entry_clear(&entry);
- goto error;
- }
- }
-
- os_free(wpa_s->conf->opensc_engine_path);
- wpa_s->conf->opensc_engine_path = opensc_engine_path;
- os_free(wpa_s->conf->pkcs11_engine_path);
- wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path;
- os_free(wpa_s->conf->pkcs11_module_path);
- wpa_s->conf->pkcs11_module_path = pkcs11_module_path;
-
- wpa_sm_set_eapol(wpa_s->wpa, NULL);
- eapol_sm_deinit(wpa_s->eapol);
- wpa_s->eapol = NULL;
- wpa_supplicant_init_eapol(wpa_s);
- wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
-
- return wpas_dbus_new_success_reply(message);
-
-error:
- os_free(opensc_engine_path);
- os_free(pkcs11_engine_path);
- os_free(pkcs11_module_path);
- return wpas_dbus_new_invalid_opts_error(message, NULL);
-}
-
-
-/**
- * wpas_dbus_iface_get_state - Get interface state
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a STRING representing the current
- * interface state
- *
- * Handler function for "state" method call.
- */
-DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessage *reply = NULL;
- const char *str_state;
-
- reply = dbus_message_new_method_return(message);
- if (reply != NULL) {
- str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state,
- DBUS_TYPE_INVALID);
- }
-
- return reply;
-}
-
-
-/**
- * wpas_dbus_iface_get_scanning - Get interface scanning state
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing whether the interface is scanning
- *
- * Handler function for "scanning" method call.
- */
-DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessage *reply = NULL;
- dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
-
- reply = dbus_message_new_method_return(message);
- if (reply != NULL) {
- dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &scanning,
- DBUS_TYPE_INVALID);
- } else {
- wpa_printf(MSG_ERROR,
- "dbus: Not enough memory to return scanning state");
- }
-
- return reply;
-}
-
-
-#ifndef CONFIG_NO_CONFIG_BLOBS
-
-/**
- * wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates)
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Asks wpa_supplicant to internally store a one or more binary blobs.
- */
-DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessage *reply = NULL;
- struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
- DBusMessageIter iter, iter_dict;
-
- dbus_message_iter_init(message, &iter);
-
- if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
- return wpas_dbus_new_invalid_opts_error(message, NULL);
-
- while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
- struct wpa_config_blob *blob;
-
- if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
- reply = wpas_dbus_new_invalid_opts_error(message,
- NULL);
- break;
- }
-
- if (entry.type != DBUS_TYPE_ARRAY ||
- entry.array_type != DBUS_TYPE_BYTE) {
- reply = wpas_dbus_new_invalid_opts_error(
- message, "Byte array expected.");
- break;
- }
-
- if ((entry.array_len <= 0) || (entry.array_len > 65536) ||
- !strlen(entry.key)) {
- reply = wpas_dbus_new_invalid_opts_error(
- message, "Invalid array size.");
- break;
- }
-
- blob = os_zalloc(sizeof(*blob));
- if (blob == NULL) {
- reply = dbus_message_new_error(
- message, WPAS_ERROR_ADD_ERROR,
- "Not enough memory to add blob.");
- break;
- }
- blob->data = os_zalloc(entry.array_len);
- if (blob->data == NULL) {
- reply = dbus_message_new_error(
- message, WPAS_ERROR_ADD_ERROR,
- "Not enough memory to add blob data.");
- os_free(blob);
- break;
- }
-
- blob->name = os_strdup(entry.key);
- blob->len = entry.array_len;
- os_memcpy(blob->data, (u8 *) entry.bytearray_value,
- entry.array_len);
- if (blob->name == NULL) {
- wpa_config_free_blob(blob);
- reply = dbus_message_new_error(
- message, WPAS_ERROR_ADD_ERROR,
- "Error adding blob.");
- break;
- }
-
- /* Success */
- if (!wpa_config_remove_blob(wpa_s->conf, blob->name))
- wpas_notify_blob_removed(wpa_s, blob->name);
- wpa_config_set_blob(wpa_s->conf, blob);
- wpas_notify_blob_added(wpa_s, blob->name);
-
- wpa_dbus_dict_entry_clear(&entry);
- }
- wpa_dbus_dict_entry_clear(&entry);
-
- return reply ? reply : wpas_dbus_new_success_reply(message);
-}
-
-
-/**
- * wpas_dbus_iface_remove_blob - Remove named binary blobs
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Asks wpa_supplicant to remove one or more previously stored binary blobs.
- */
-DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessageIter iter, array;
- char *err_msg = NULL;
-
- dbus_message_iter_init(message, &iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
- dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
- return wpas_dbus_new_invalid_opts_error(message, NULL);
-
- dbus_message_iter_recurse(&iter, &array);
- while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
- const char *name;
-
- dbus_message_iter_get_basic(&array, &name);
- if (!os_strlen(name))
- err_msg = "Invalid blob name.";
- else if (wpa_config_remove_blob(wpa_s->conf, name) != 0)
- err_msg = "Error removing blob.";
- else
- wpas_notify_blob_removed(wpa_s, name);
- dbus_message_iter_next(&array);
- }
-
- if (err_msg)
- return dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR,
- err_msg);
-
- return wpas_dbus_new_success_reply(message);
-}
-
-#endif /* CONFIG_NO_CONFIG_BLOBS */
-
-
-/**
- * wpas_dbus_iface_flush - Clear BSS of old or all inactive entries
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: a dbus message containing a UINT32 indicating success (1) or
- * failure (0), or returns a dbus error message with more information
- *
- * Handler function for "flush" method call. Handles requests for an
- * interface with an optional "age" parameter that specifies the minimum
- * age of a BSS to be flushed.
- */
-DBusMessage * wpas_dbus_iface_flush(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- int flush_age = 0;
-
- if (os_strlen(dbus_message_get_signature(message)) != 0 &&
- !dbus_message_get_args(message, NULL,
- DBUS_TYPE_INT32, &flush_age,
- DBUS_TYPE_INVALID)) {
- return wpas_dbus_new_invalid_opts_error(message, NULL);
- }
-
- if (flush_age == 0)
- wpa_bss_flush(wpa_s);
- else
- wpa_bss_flush_by_age(wpa_s, flush_age);
-
- return wpas_dbus_new_success_reply(message);
-}
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.h b/wpa_supplicant/dbus/dbus_old_handlers.h
deleted file mode 100644
index e60ad06..0000000
--- a/wpa_supplicant/dbus/dbus_old_handlers.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface
- * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef CTRL_IFACE_DBUS_HANDLERS_H
-#define CTRL_IFACE_DBUS_HANDLERS_H
-
-struct wpa_bss;
-
-DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message);
-DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message);
-
-DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
- struct wpa_global *global);
-
-DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
- struct wpa_global *global);
-
-DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message,
- struct wpa_global *global);
-
-DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message,
- struct wpa_global *global);
-
-DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- struct wpa_bss *bss);
-
-DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid);
-
-DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid);
-
-DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid);
-
-DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_set_smartcard_modules(
- DBusMessage *message, struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_wps_pbc(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_wps_pin(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_wps_reg(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_flush(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message);
-DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message,
- const char *arg);
-
-#endif /* CTRL_IFACE_DBUS_HANDLERS_H */
-
diff --git a/wpa_supplicant/dbus/dbus_old_handlers_wps.c b/wpa_supplicant/dbus/dbus_old_handlers_wps.c
deleted file mode 100644
index 5309a53..0000000
--- a/wpa_supplicant/dbus/dbus_old_handlers_wps.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface (WPS)
- * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-#include <dbus/dbus.h>
-
-#include "common.h"
-#include "../config.h"
-#include "../wpa_supplicant_i.h"
-#include "../wps_supplicant.h"
-#include "dbus_old.h"
-#include "dbus_old_handlers.h"
-
-/**
- * wpas_dbus_iface_wps_pbc - Request credentials using WPS PBC method
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "wpsPbc" method call
- */
-DBusMessage * wpas_dbus_iface_wps_pbc(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- char *arg_bssid = NULL;
- u8 bssid[ETH_ALEN];
- int ret = 0;
-
- if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid,
- DBUS_TYPE_INVALID))
- return wpas_dbus_new_invalid_opts_error(message, NULL);
-
- if (os_strcmp(arg_bssid, "any") == 0)
- ret = wpas_wps_start_pbc(wpa_s, NULL, 0);
- else if (!hwaddr_aton(arg_bssid, bssid))
- ret = wpas_wps_start_pbc(wpa_s, bssid, 0);
- else {
- return wpas_dbus_new_invalid_opts_error(message,
- "Invalid BSSID");
- }
-
- if (ret < 0) {
- return dbus_message_new_error(
- message, WPAS_ERROR_WPS_PBC_ERROR,
- "Could not start PBC negotiation");
- }
-
- return wpas_dbus_new_success_reply(message);
-}
-
-
-/**
- * wpas_dbus_iface_wps_pin - Establish the PIN number of the enrollee
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "wpsPin" method call
- */
-DBusMessage * wpas_dbus_iface_wps_pin(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- DBusMessage *reply = NULL;
- char *arg_bssid;
- char *pin = NULL;
- u8 bssid[ETH_ALEN], *_bssid = NULL;
- int ret = 0;
- char npin[9];
-
- if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid,
- DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID))
- return wpas_dbus_new_invalid_opts_error(message, NULL);
-
- if (os_strcmp(arg_bssid, "any") == 0)
- _bssid = NULL;
- else if (!hwaddr_aton(arg_bssid, bssid))
- _bssid = bssid;
- else {
- return wpas_dbus_new_invalid_opts_error(message,
- "Invalid BSSID");
- }
-
- if (os_strlen(pin) > 0)
- ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0,
- DEV_PW_DEFAULT);
- else
- ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0,
- DEV_PW_DEFAULT);
-
- if (ret < 0) {
- return dbus_message_new_error(message,
- WPAS_ERROR_WPS_PIN_ERROR,
- "Could not init PIN");
- }
-
- reply = dbus_message_new_method_return(message);
- if (reply == NULL)
- return NULL;
-
- if (ret > 0) {
- os_snprintf(npin, sizeof(npin), "%08d", ret);
- pin = npin;
- }
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &pin,
- DBUS_TYPE_INVALID);
- return reply;
-}
-
-
-/**
- * wpas_dbus_iface_wps_reg - Request credentials using the PIN of the AP
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- * failure (0)
- *
- * Handler function for "wpsReg" method call
- */
-DBusMessage * wpas_dbus_iface_wps_reg(DBusMessage *message,
- struct wpa_supplicant *wpa_s)
-{
- char *arg_bssid;
- char *pin = NULL;
- u8 bssid[ETH_ALEN];
- int ret = 0;
-
- if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid,
- DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID))
- return wpas_dbus_new_invalid_opts_error(message, NULL);
-
- if (!hwaddr_aton(arg_bssid, bssid))
- ret = wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
- else {
- return wpas_dbus_new_invalid_opts_error(message,
- "Invalid BSSID");
- }
-
- if (ret < 0) {
- return dbus_message_new_error(message,
- WPAS_ERROR_WPS_REG_ERROR,
- "Could not request credentials");
- }
-
- return wpas_dbus_new_success_reply(message);
-}
diff --git a/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in b/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in
deleted file mode 100644
index a75918f..0000000
--- a/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in
+++ /dev/null
@@ -1,5 +0,0 @@
-[D-BUS Service]
-Name=fi.epitest.hostap.WPASupplicant
-Exec=@BINDIR@/wpa_supplicant -u
-User=root
-SystemdService=wpa_supplicant.service
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 450023e..88cd790 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -44,7 +44,7 @@
#CONFIG_LIBNL20=y
# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
-#CONFIG_LIBNL32=y
+CONFIG_LIBNL32=y
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
@@ -73,6 +73,12 @@
# Driver interface for wired Ethernet drivers
CONFIG_DRIVER_WIRED=y
+# Driver interface for MACsec capable Qualcomm Atheros drivers
+#CONFIG_DRIVER_MACSEC_QCA=y
+
+# Driver interface for Linux MACsec drivers
+#CONFIG_DRIVER_MACSEC_LINUX=y
+
# Driver interface for the Broadcom RoboSwitch family
#CONFIG_DRIVER_ROBOSWITCH=y
@@ -83,8 +89,8 @@
#LIBS += -lsocket -ldlpi -lnsl
#LIBS_c += -lsocket
-# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
-# included)
+# Enable IEEE 802.1X Supplicant (automatically included if any EAP method or
+# MACsec is included)
CONFIG_IEEE8021X_EAPOL=y
# EAP-MD5
@@ -103,10 +109,7 @@
CONFIG_EAP_TTLS=y
# EAP-FAST
-# Note: If OpenSSL is used as the TLS library, OpenSSL 1.0 or newer is needed
-# for EAP-FAST support. Older OpenSSL releases would need to be patched, e.g.,
-# with openssl-0.9.8x-tls-extensions.patch, to add the needed functions.
-#CONFIG_EAP_FAST=y
+CONFIG_EAP_FAST=y
# EAP-GTC
CONFIG_EAP_GTC=y
@@ -121,10 +124,10 @@
#CONFIG_EAP_PSK=y
# EAP-pwd (secure authentication using only a password)
-#CONFIG_EAP_PWD=y
+CONFIG_EAP_PWD=y
# EAP-PAX
-#CONFIG_EAP_PAX=y
+CONFIG_EAP_PAX=y
# LEAP
CONFIG_EAP_LEAP=y
@@ -140,18 +143,18 @@
#CONFIG_USIM_SIMULATOR=y
# EAP-SAKE
-#CONFIG_EAP_SAKE=y
+CONFIG_EAP_SAKE=y
# EAP-GPSK
-#CONFIG_EAP_GPSK=y
+CONFIG_EAP_GPSK=y
# Include support for optional SHA256 cipher suite in EAP-GPSK
-#CONFIG_EAP_GPSK_SHA256=y
+CONFIG_EAP_GPSK_SHA256=y
# EAP-TNC and related Trusted Network Connect support (experimental)
-#CONFIG_EAP_TNC=y
+CONFIG_EAP_TNC=y
# Wi-Fi Protected Setup (WPS)
-#CONFIG_WPS=y
+CONFIG_WPS=y
# Enable WPS external registrar functionality
#CONFIG_WPS_ER=y
# Disable credentials for an open network by default when acting as a WPS
@@ -161,11 +164,14 @@
#CONFIG_WPS_NFC=y
# EAP-IKEv2
-#CONFIG_EAP_IKEV2=y
+CONFIG_EAP_IKEV2=y
# EAP-EKE
#CONFIG_EAP_EKE=y
+# MACsec
+#CONFIG_MACSEC=y
+
# PKCS#12 (PFX) support (used to read private key and certificate file from
# a file that usually has extension .p12 or .pfx)
CONFIG_PKCS12=y
@@ -226,6 +232,9 @@
# wpa_passphrase). This saves about 0.5 kB in code size.
#CONFIG_NO_WPA_PASSPHRASE=y
+# Simultaneous Authentication of Equals (SAE), WPA3-Personal
+CONFIG_SAE=y
+
# Disable scan result processing (ap_mode=1) to save code size by about 1 kB.
# This can be used if ap_scan=1 mode is never enabled.
#CONFIG_NO_SCAN_PROCESSING=y
@@ -290,7 +299,10 @@
# IEEE 802.11w (management frame protection), also known as PMF
# Driver support is also needed for IEEE 802.11w.
-#CONFIG_IEEE80211W=y
+CONFIG_IEEE80211W=y
+
+# Support Operating Channel Validation
+#CONFIG_OCV=y
# Select TLS implementation
# openssl = OpenSSL (default)
@@ -340,16 +352,12 @@
#CONFIG_NDIS_EVENTS_INTEGRATED=y
#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib"
-# Add support for old DBus control interface
-# (fi.epitest.hostap.WPASupplicant)
-#CONFIG_CTRL_IFACE_DBUS=y
-
# Add support for new DBus control interface
# (fi.w1.hostap.wpa_supplicant1)
-#CONFIG_CTRL_IFACE_DBUS_NEW=y
+CONFIG_CTRL_IFACE_DBUS_NEW=y
# Add introspection support for new DBus control interface
-#CONFIG_CTRL_IFACE_DBUS_INTRO=y
+CONFIG_CTRL_IFACE_DBUS_INTRO=y
# Add support for loading EAP methods dynamically as shared libraries.
# When this option is enabled, each EAP method can be either included
@@ -373,17 +381,13 @@
#CONFIG_DYNAMIC_EAP_METHODS=y
# IEEE Std 802.11r-2008 (Fast BSS Transition) for station mode
-#CONFIG_IEEE80211R=y
-
-# IEEE Std 802.11r-2008 (Fast BSS Transition) for AP mode (implies
-# CONFIG_IEEE80211R).
-#CONFIG_IEEE80211R_AP=y
+CONFIG_IEEE80211R=y
# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
-#CONFIG_DEBUG_FILE=y
+CONFIG_DEBUG_FILE=y
# Send debug messages to syslog instead of stdout
-#CONFIG_DEBUG_SYSLOG=y
+CONFIG_DEBUG_SYSLOG=y
# Set syslog facility for debug messages
#CONFIG_DEBUG_SYSLOG_FACILITY=LOG_DAEMON
@@ -453,12 +457,17 @@
# that meet the requirements described above.
#CONFIG_NO_RANDOM_POOL=y
+# Should we attempt to use the getrandom(2) call that provides more reliable
+# yet secure randomness source than /dev/random on Linux 3.17 and newer.
+# Requires glibc 2.25 to build, falls back to /dev/random if unavailable.
+#CONFIG_GETRANDOM=y
+
# IEEE 802.11n (High Throughput) support (mainly for AP mode)
-#CONFIG_IEEE80211N=y
+CONFIG_IEEE80211N=y
# IEEE 802.11ac (Very High Throughput) support (mainly for AP mode)
# (depends on CONFIG_IEEE80211N)
-#CONFIG_IEEE80211AC=y
+CONFIG_IEEE80211AC=y
# Wireless Network Management (IEEE Std 802.11v-2011)
# Note: This is experimental and not complete implementation.
@@ -468,10 +477,10 @@
# This can be used to enable functionality to improve interworking with
# external networks (GAS/ANQP to learn more about the networks and network
# selection based on available credentials).
-#CONFIG_INTERWORKING=y
+CONFIG_INTERWORKING=y
# Hotspot 2.0
-#CONFIG_HS20=y
+CONFIG_HS20=y
# Enable interface matching in wpa_supplicant
#CONFIG_MATCH_IFACE=y
@@ -484,20 +493,20 @@
# should be noted that this is mainly aimed at simple cases like
# WPA2-Personal while more complex configurations like WPA2-Enterprise with an
# external RADIUS server can be supported with hostapd.
-#CONFIG_AP=y
+CONFIG_AP=y
# P2P (Wi-Fi Direct)
# This can be used to enable P2P support in wpa_supplicant. See README-P2P for
# more information on P2P operations.
-#CONFIG_P2P=y
+CONFIG_P2P=y
# Enable TDLS support
#CONFIG_TDLS=y
-# Wi-Fi Direct
-# This can be used to enable Wi-Fi Direct extensions for P2P using an external
+# Wi-Fi Display
+# This can be used to enable Wi-Fi Display extensions for P2P using an external
# program to control the additional information exchanges in the messages.
-#CONFIG_WIFI_DISPLAY=y
+CONFIG_WIFI_DISPLAY=y
# Autoscan
# This can be used to enable automatic scan support in wpa_supplicant.
@@ -556,8 +565,6 @@
#CONFIG_MBO=y
# Fast Initial Link Setup (FILS) (IEEE 802.11ai)
-# Note: This is an experimental and not yet complete implementation. This
-# should not be enabled for production use.
#CONFIG_FILS=y
# FILS shared key authentication with PFS
#CONFIG_FILS_SK_PFS=y
@@ -565,7 +572,7 @@
# Support RSN on IBSS networks
# This is needed to be able to use mode=1 network profile with proto=RSN and
# key_mgmt=WPA-PSK (i.e., full key management instead of WPA-None).
-#CONFIG_IBSS_RSN=y
+CONFIG_IBSS_RSN=y
# External PMKSA cache control
# This can be used to enable control interface commands that allow the current
@@ -580,7 +587,7 @@
# operations for roaming within an ESS (same SSID). See the bgscan parameter in
# the wpa_supplicant.conf file for more details.
# Periodic background scans based on signal strength
-#CONFIG_BGSCAN_SIMPLE=y
+CONFIG_BGSCAN_SIMPLE=y
# Learn channels used by the network and try to avoid bgscans on other
# channels (experimental)
#CONFIG_BGSCAN_LEARN=y
@@ -588,3 +595,8 @@
# Opportunistic Wireless Encryption (OWE)
# Experimental implementation of draft-harkins-owe-07.txt
#CONFIG_OWE=y
+
+# Device Provisioning Protocol (DPP)
+# This requires CONFIG_IEEE80211W=y to be enabled, too. (see
+# wpa_supplicant/README-DPP for details)
+CONFIG_DPP=y
diff --git a/wpa_supplicant/doc/docbook/eapol_test.sgml b/wpa_supplicant/doc/docbook/eapol_test.sgml
index 25cfd06..e7705ab 100644
--- a/wpa_supplicant/doc/docbook/eapol_test.sgml
+++ b/wpa_supplicant/doc/docbook/eapol_test.sgml
@@ -194,7 +194,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2017,
+ <para>wpa_supplicant is copyright (c) 2003-2019,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_background.sgml b/wpa_supplicant/doc/docbook/wpa_background.sgml
index fa94ae4..f6a0ca8 100644
--- a/wpa_supplicant/doc/docbook/wpa_background.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_background.sgml
@@ -90,7 +90,7 @@
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2017,
+ <para>wpa_supplicant is copyright (c) 2003-2019,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_cli.sgml b/wpa_supplicant/doc/docbook/wpa_cli.sgml
index be3045a..dc7fee4 100644
--- a/wpa_supplicant/doc/docbook/wpa_cli.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_cli.sgml
@@ -345,7 +345,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2017,
+ <para>wpa_supplicant is copyright (c) 2003-2019,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_gui.sgml b/wpa_supplicant/doc/docbook/wpa_gui.sgml
index cee9ed6..31214e3 100644
--- a/wpa_supplicant/doc/docbook/wpa_gui.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_gui.sgml
@@ -91,7 +91,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2017,
+ <para>wpa_supplicant is copyright (c) 2003-2019,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
index 6667a07..ed9baf1 100644
--- a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
@@ -62,7 +62,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2017,
+ <para>wpa_supplicant is copyright (c) 2003-2019,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_priv.sgml b/wpa_supplicant/doc/docbook/wpa_priv.sgml
index 3796b93..dd44565 100644
--- a/wpa_supplicant/doc/docbook/wpa_priv.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_priv.sgml
@@ -137,7 +137,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2017,
+ <para>wpa_supplicant is copyright (c) 2003-2019,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
index 80b3878..aaff150 100644
--- a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
@@ -246,9 +246,18 @@
<variablelist>
<varlistentry>
+ <term>nl80211</term>
+ <listitem>
+ <para>Uses the modern Linux nl80211/cfg80211 netlink-based
+ interface (most new drivers).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>wext</term>
<listitem>
- <para>Linux wireless extensions (generic).</para>
+ <para>Uses the legacy Linux wireless extensions ioctl-based
+ interface (older hardware/drivers).</para>
</listitem>
</varlistentry>
@@ -462,7 +471,7 @@
<para>Enable DBus control interface. If enabled, interface
definitions may be omitted. (This is only available
if <command>wpa_supplicant</command> was built with
- the <literal>CONFIG_DBUS</literal> option.)</para>
+ the <literal>CONFIG_CTRL_IFACE_DBUS_NEW</literal> option.)</para>
</listitem>
</varlistentry>
@@ -538,10 +547,14 @@
<itemizedlist>
<listitem>
- <para>Linux kernel 2.4.x or 2.6.x with Linux Wireless
- Extensions v15 or newer</para>
+ <para>Linux kernel 2.6.30 or higher with
+ nl80211/cfg80211 support</para>
</listitem>
+ <listitem>
+ <para>Linux kernel 2.4.x or higher with Linux Wireless
+ Extensions v15 or newer</para>
+ </listitem>
<listitem>
<para>FreeBSD 6-CURRENT</para>
@@ -558,6 +571,13 @@
<title>Supported Drivers</title>
<variablelist>
<varlistentry>
+ <term>Linux nl80211/cfg80211</term>
+ <listitem>
+ <para>This is the preferred driver for Linux.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>Linux wireless extensions</term>
<listitem>
<para>In theory, any driver that supports Linux wireless
@@ -729,7 +749,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2017,
+ <para>wpa_supplicant is copyright (c) 2003-2019,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index bf29f19..8a9e444 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -1,6 +1,7 @@
/*
* wpa_supplicant - DPP
* Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2019, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -24,6 +25,7 @@
#include "scan.h"
#include "notify.h"
#include "dpp_supplicant.h"
+#include "hidl.h"
static int wpas_dpp_listen_start(struct wpa_supplicant *wpa_s,
@@ -35,6 +37,14 @@
const u8 *src, const u8 *bssid,
const u8 *data, size_t data_len,
enum offchannel_send_action_result result);
+static void wpas_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
+static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s);
+static void
+wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *dst,
+ const u8 *src, const u8 *bssid,
+ const u8 *data, size_t data_len,
+ enum offchannel_send_action_result result);
static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@@ -43,34 +53,6 @@
static const u8 TRANSACTION_ID = 1;
-static struct dpp_configurator *
-dpp_configurator_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
-{
- struct dpp_configurator *conf;
-
- dl_list_for_each(conf, &wpa_s->dpp_configurator,
- struct dpp_configurator, list) {
- if (conf->id == id)
- return conf;
- }
- return NULL;
-}
-
-
-static unsigned int wpas_dpp_next_id(struct wpa_supplicant *wpa_s)
-{
- struct dpp_bootstrap_info *bi;
- unsigned int max_id = 0;
-
- dl_list_for_each(bi, &wpa_s->dpp_bootstrap, struct dpp_bootstrap_info,
- list) {
- if (bi->id > max_id)
- max_id = bi->id;
- }
- return max_id + 1;
-}
-
-
/**
* wpas_dpp_qr_code - Parse and add DPP bootstrapping info from a QR Code
* @wpa_s: Pointer to wpa_supplicant data
@@ -82,17 +64,18 @@
struct dpp_bootstrap_info *bi;
struct dpp_authentication *auth = wpa_s->dpp_auth;
- bi = dpp_parse_qr_code(cmd);
+ bi = dpp_add_qr_code(wpa_s->dpp, cmd);
if (!bi)
return -1;
- bi->id = wpas_dpp_next_id(wpa_s);
- dl_list_add(&wpa_s->dpp_bootstrap, &bi->list);
-
if (auth && auth->response_pending &&
dpp_notify_new_qr_code(auth, bi) == 1) {
wpa_printf(MSG_DEBUG,
"DPP: Sending out pending authentication response");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d",
+ MAC2STR(auth->peer_mac_addr), auth->curr_freq,
+ DPP_PA_AUTHENTICATION_RESP);
offchannel_send_action(wpa_s, auth->curr_freq,
auth->peer_mac_addr, wpa_s->own_addr,
broadcast,
@@ -105,192 +88,72 @@
}
-static char * get_param(const char *cmd, const char *param)
+static void wpas_dpp_auth_resp_retry_timeout(void *eloop_ctx, void *timeout_ctx)
{
- const char *pos, *end;
- char *val;
- size_t len;
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
- pos = os_strstr(cmd, param);
- if (!pos)
- return NULL;
+ if (!auth || !auth->resp_msg)
+ return;
- pos += os_strlen(param);
- end = os_strchr(pos, ' ');
- if (end)
- len = end - pos;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Retry Authentication Response after timeout");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d",
+ MAC2STR(auth->peer_mac_addr), auth->curr_freq,
+ DPP_PA_AUTHENTICATION_RESP);
+ offchannel_send_action(wpa_s, auth->curr_freq, auth->peer_mac_addr,
+ wpa_s->own_addr, broadcast,
+ wpabuf_head(auth->resp_msg),
+ wpabuf_len(auth->resp_msg),
+ 500, wpas_dpp_tx_status, 0);
+}
+
+
+static void wpas_dpp_auth_resp_retry(struct wpa_supplicant *wpa_s)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ unsigned int wait_time, max_tries;
+
+ if (!auth || !auth->resp_msg)
+ return;
+
+ if (wpa_s->dpp_resp_max_tries)
+ max_tries = wpa_s->dpp_resp_max_tries;
else
- len = os_strlen(pos);
- val = os_malloc(len + 1);
- if (!val)
- return NULL;
- os_memcpy(val, pos, len);
- val[len] = '\0';
- return val;
-}
+ max_tries = 5;
+ auth->auth_resp_tries++;
+ if (auth->auth_resp_tries >= max_tries) {
+ wpa_printf(MSG_INFO, "DPP: No confirm received from initiator - stopping exchange");
+ offchannel_send_action_done(wpa_s);
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
-
-int wpas_dpp_bootstrap_gen(struct wpa_supplicant *wpa_s, const char *cmd)
-{
- char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL;
- char *key = NULL;
- u8 *privkey = NULL;
- size_t privkey_len = 0;
- size_t len;
- int ret = -1;
- struct dpp_bootstrap_info *bi;
-
- bi = os_zalloc(sizeof(*bi));
- if (!bi)
- goto fail;
-
- if (os_strstr(cmd, "type=qrcode"))
- bi->type = DPP_BOOTSTRAP_QR_CODE;
- else if (os_strstr(cmd, "type=pkex"))
- bi->type = DPP_BOOTSTRAP_PKEX;
+ if (wpa_s->dpp_resp_retry_time)
+ wait_time = wpa_s->dpp_resp_retry_time;
else
- goto fail;
-
- chan = get_param(cmd, " chan=");
- mac = get_param(cmd, " mac=");
- info = get_param(cmd, " info=");
- curve = get_param(cmd, " curve=");
- key = get_param(cmd, " key=");
-
- if (key) {
- privkey_len = os_strlen(key) / 2;
- privkey = os_malloc(privkey_len);
- if (!privkey ||
- hexstr2bin(key, privkey, privkey_len) < 0)
- goto fail;
- }
-
- pk = dpp_keygen(bi, curve, privkey, privkey_len);
- if (!pk)
- goto fail;
-
- len = 4; /* "DPP:" */
- if (chan) {
- if (dpp_parse_uri_chan_list(bi, chan) < 0)
- goto fail;
- len += 3 + os_strlen(chan); /* C:...; */
- }
- if (mac) {
- if (dpp_parse_uri_mac(bi, mac) < 0)
- goto fail;
- len += 3 + os_strlen(mac); /* M:...; */
- }
- if (info) {
- if (dpp_parse_uri_info(bi, info) < 0)
- goto fail;
- len += 3 + os_strlen(info); /* I:...; */
- }
- len += 4 + os_strlen(pk);
- bi->uri = os_malloc(len + 1);
- if (!bi->uri)
- goto fail;
- os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
- chan ? "C:" : "", chan ? chan : "", chan ? ";" : "",
- mac ? "M:" : "", mac ? mac : "", mac ? ";" : "",
- info ? "I:" : "", info ? info : "", info ? ";" : "",
- pk);
- bi->id = wpas_dpp_next_id(wpa_s);
- dl_list_add(&wpa_s->dpp_bootstrap, &bi->list);
- ret = bi->id;
- bi = NULL;
-fail:
- os_free(curve);
- os_free(pk);
- os_free(chan);
- os_free(mac);
- os_free(info);
- str_clear_free(key);
- bin_clear_free(privkey, privkey_len);
- dpp_bootstrap_info_free(bi);
- return ret;
+ wait_time = 1000;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Schedule retransmission of Authentication Response frame in %u ms",
+ wait_time);
+ eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
+ eloop_register_timeout(wait_time / 1000,
+ (wait_time % 1000) * 1000,
+ wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
}
-static struct dpp_bootstrap_info *
-dpp_bootstrap_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
+static void wpas_dpp_try_to_connect(struct wpa_supplicant *wpa_s)
{
- struct dpp_bootstrap_info *bi;
-
- dl_list_for_each(bi, &wpa_s->dpp_bootstrap, struct dpp_bootstrap_info,
- list) {
- if (bi->id == id)
- return bi;
- }
- return NULL;
-}
-
-
-static int dpp_bootstrap_del(struct wpa_supplicant *wpa_s, unsigned int id)
-{
- struct dpp_bootstrap_info *bi, *tmp;
- int found = 0;
-
- dl_list_for_each_safe(bi, tmp, &wpa_s->dpp_bootstrap,
- struct dpp_bootstrap_info, list) {
- if (id && bi->id != id)
- continue;
- found = 1;
- dl_list_del(&bi->list);
- dpp_bootstrap_info_free(bi);
- }
-
- if (id == 0)
- return 0; /* flush succeeds regardless of entries found */
- return found ? 0 : -1;
-}
-
-
-int wpas_dpp_bootstrap_remove(struct wpa_supplicant *wpa_s, const char *id)
-{
- unsigned int id_val;
-
- if (os_strcmp(id, "*") == 0) {
- id_val = 0;
- } else {
- id_val = atoi(id);
- if (id_val == 0)
- return -1;
- }
-
- return dpp_bootstrap_del(wpa_s, id_val);
-}
-
-
-const char * wpas_dpp_bootstrap_get_uri(struct wpa_supplicant *wpa_s,
- unsigned int id)
-{
- struct dpp_bootstrap_info *bi;
-
- bi = dpp_bootstrap_get_id(wpa_s, id);
- if (!bi)
- return NULL;
- return bi->uri;
-}
-
-
-int wpas_dpp_bootstrap_info(struct wpa_supplicant *wpa_s, int id,
- char *reply, int reply_size)
-{
- struct dpp_bootstrap_info *bi;
-
- bi = dpp_bootstrap_get_id(wpa_s, id);
- if (!bi)
- return -1;
- return os_snprintf(reply, reply_size, "type=%s\n"
- "mac_addr=" MACSTR "\n"
- "info=%s\n"
- "num_freq=%u\n"
- "curve=%s\n",
- dpp_bootstrap_type_txt(bi->type),
- MAC2STR(bi->mac_addr),
- bi->info ? bi->info : "",
- bi->num_freq,
- bi->curve->name);
+ wpa_printf(MSG_DEBUG, "DPP: Trying to connect to the new network");
+ wpa_s->disconnected = 0;
+ wpa_s->reassociate = 1;
+ wpa_s->scan_runs = 0;
+ wpa_s->normal_scans = 0;
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
}
@@ -300,12 +163,16 @@
const u8 *data, size_t data_len,
enum offchannel_send_action_result result)
{
+ const char *res_txt;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
+ (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
+ "FAILED");
wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
- " result=%s",
- freq, MAC2STR(dst),
- result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
- (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
- "FAILED"));
+ " result=%s", freq, MAC2STR(dst), res_txt);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
+ " freq=%u result=%s", MAC2STR(dst), freq, res_txt);
if (!wpa_s->dpp_auth) {
wpa_printf(MSG_DEBUG,
@@ -313,10 +180,24 @@
return;
}
+#ifdef CONFIG_DPP2
+ if (auth->connect_on_tx_status) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Try to connect after completed configuration result");
+ wpas_dpp_try_to_connect(wpa_s);
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
+#endif /* CONFIG_DPP2 */
+
if (wpa_s->dpp_auth->remove_on_tx_status) {
wpa_printf(MSG_DEBUG,
"DPP: Terminate authentication exchange due to an earlier error");
+ eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
+ NULL);
offchannel_send_action_done(wpa_s);
dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL;
@@ -330,21 +211,105 @@
result != OFFCHANNEL_SEND_ACTION_SUCCESS) {
wpa_printf(MSG_DEBUG,
"DPP: Unicast DPP Action frame was not ACKed");
- /* TODO: In case of DPP Authentication Request frame, move to
- * the next channel immediately */
+ if (auth->waiting_auth_resp) {
+ /* In case of DPP Authentication Request frame, move to
+ * the next channel immediately. */
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_auth_init_next(wpa_s);
+ return;
+ }
+ if (auth->waiting_auth_conf) {
+ wpas_dpp_auth_resp_retry(wpa_s);
+ return;
+ }
}
+
+ if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp &&
+ result == OFFCHANNEL_SEND_ACTION_SUCCESS) {
+ /* Allow timeout handling to stop iteration if no response is
+ * received from a peer that has ACKed a request. */
+ auth->auth_req_ack = 1;
+ }
+
+ if (!wpa_s->dpp_auth_ok_on_ack && wpa_s->dpp_auth->neg_freq > 0 &&
+ wpa_s->dpp_auth->curr_freq != wpa_s->dpp_auth->neg_freq) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Move from curr_freq %u MHz to neg_freq %u MHz for response",
+ wpa_s->dpp_auth->curr_freq,
+ wpa_s->dpp_auth->neg_freq);
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_start(wpa_s, wpa_s->dpp_auth->neg_freq);
+ }
+
+ if (wpa_s->dpp_auth_ok_on_ack)
+ wpa_s->dpp_auth_ok_on_ack = 0;
}
static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ unsigned int freq;
+ struct os_reltime now, diff;
+ unsigned int wait_time, diff_ms;
- if (!wpa_s->dpp_auth)
+ if (!auth || !auth->waiting_auth_resp)
return;
- wpa_printf(MSG_DEBUG, "DPP: Continue reply wait on channel %u MHz",
- wpa_s->dpp_auth->curr_freq);
- wpas_dpp_listen_start(wpa_s, wpa_s->dpp_auth->curr_freq);
+
+ wait_time = wpa_s->dpp_resp_wait_time ?
+ wpa_s->dpp_resp_wait_time : 2000;
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &wpa_s->dpp_last_init, &diff);
+ diff_ms = diff.sec * 1000 + diff.usec / 1000;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Reply wait timeout - wait_time=%u diff_ms=%u",
+ wait_time, diff_ms);
+
+ if (auth->auth_req_ack && diff_ms >= wait_time) {
+ /* Peer ACK'ed Authentication Request frame, but did not reply
+ * with Authentication Response frame within two seconds. */
+ wpa_printf(MSG_INFO,
+ "DPP: No response received from responder - stopping initiation attempt");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED);
+ wpas_notify_dpp_timeout(wpa_s);
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_stop(wpa_s);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
+
+ if (diff_ms >= wait_time) {
+ /* Authentication Request frame was not ACK'ed and no reply
+ * was receiving within two seconds. */
+ wpa_printf(MSG_DEBUG,
+ "DPP: Continue Initiator channel iteration");
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_stop(wpa_s);
+ wpas_dpp_auth_init_next(wpa_s);
+ return;
+ }
+
+ /* Driver did not support 2000 ms long wait_time with TX command, so
+ * schedule listen operation to continue waiting for the response.
+ *
+ * DPP listen operations continue until stopped, so simply schedule a
+ * new call to this function at the point when the two second reply
+ * wait has expired. */
+ wait_time -= diff_ms;
+
+ freq = auth->curr_freq;
+ if (auth->neg_freq > 0)
+ freq = auth->neg_freq;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Continue reply wait on channel %u MHz for %u ms",
+ freq, wait_time);
+ wpa_s->dpp_in_response_listen = 1;
+ wpas_dpp_listen_start(wpa_s, freq);
+
+ eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
+ wpas_dpp_reply_wait_timeout, wpa_s, NULL);
}
@@ -367,131 +332,103 @@
}
-static void wpas_dpp_set_configurator(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth,
- const char *cmd)
+static void wpas_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx)
{
- const char *pos, *end;
- struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
- struct dpp_configurator *conf = NULL;
- u8 ssid[32] = { "test" };
- size_t ssid_len = 4;
- char pass[64] = { };
- size_t pass_len = 0;
- u8 psk[PMK_LEN];
- int psk_set = 0;
+ struct wpa_supplicant *wpa_s = eloop_ctx;
- if (!cmd)
+ if (!wpa_s->dpp_auth)
return;
+ wpa_printf(MSG_DEBUG, "DPP: Retry initiation after timeout");
+ wpas_dpp_auth_init_next(wpa_s);
+}
- wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
- pos = os_strstr(cmd, " ssid=");
- if (pos) {
- pos += 6;
- end = os_strchr(pos, ' ');
- ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
- ssid_len /= 2;
- if (ssid_len > sizeof(ssid) ||
- hexstr2bin(pos, ssid, ssid_len) < 0)
- goto fail;
- }
- pos = os_strstr(cmd, " pass=");
- if (pos) {
- pos += 6;
- end = os_strchr(pos, ' ');
- pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
- pass_len /= 2;
- if (pass_len > sizeof(pass) - 1 || pass_len < 8 ||
- hexstr2bin(pos, (u8 *) pass, pass_len) < 0)
- goto fail;
- }
+static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ const u8 *dst;
+ unsigned int wait_time, max_wait_time, freq, max_tries, used;
+ struct os_reltime now, diff;
- pos = os_strstr(cmd, " psk=");
- if (pos) {
- pos += 5;
- if (hexstr2bin(pos, psk, PMK_LEN) < 0)
- goto fail;
- psk_set = 1;
- }
+ wpa_s->dpp_in_response_listen = 0;
+ if (!auth)
+ return -1;
- if (os_strstr(cmd, " conf=sta-")) {
- conf_sta = os_zalloc(sizeof(struct dpp_configuration));
- if (!conf_sta)
- goto fail;
- os_memcpy(conf_sta->ssid, ssid, ssid_len);
- conf_sta->ssid_len = ssid_len;
- if (os_strstr(cmd, " conf=sta-psk")) {
- conf_sta->dpp = 0;
- if (psk_set) {
- os_memcpy(conf_sta->psk, psk, PMK_LEN);
- } else {
- conf_sta->passphrase = os_strdup(pass);
- if (!conf_sta->passphrase)
- goto fail;
- }
- } else if (os_strstr(cmd, " conf=sta-dpp")) {
- conf_sta->dpp = 1;
- } else {
- goto fail;
- }
- }
+ if (auth->freq_idx == 0)
+ os_get_reltime(&wpa_s->dpp_init_iter_start);
- if (os_strstr(cmd, " conf=ap-")) {
- conf_ap = os_zalloc(sizeof(struct dpp_configuration));
- if (!conf_ap)
- goto fail;
- os_memcpy(conf_ap->ssid, ssid, ssid_len);
- conf_ap->ssid_len = ssid_len;
- if (os_strstr(cmd, " conf=ap-psk")) {
- conf_ap->dpp = 0;
- if (psk_set) {
- os_memcpy(conf_ap->psk, psk, PMK_LEN);
- } else {
- conf_ap->passphrase = os_strdup(pass);
- if (!conf_ap->passphrase)
- goto fail;
- }
- } else if (os_strstr(cmd, " conf=ap-dpp")) {
- conf_ap->dpp = 1;
- } else {
- goto fail;
- }
- }
-
- pos = os_strstr(cmd, " expiry=");
- if (pos) {
- long int val;
-
- pos += 8;
- val = strtol(pos, NULL, 0);
- if (val <= 0)
- goto fail;
- if (conf_sta)
- conf_sta->netaccesskey_expiry = val;
- if (conf_ap)
- conf_ap->netaccesskey_expiry = val;
- }
-
- pos = os_strstr(cmd, " configurator=");
- if (pos) {
- pos += 14;
- conf = dpp_configurator_get_id(wpa_s, atoi(pos));
- if (!conf) {
+ if (auth->freq_idx >= auth->num_freq) {
+ auth->num_freq_iters++;
+ if (wpa_s->dpp_init_max_tries)
+ max_tries = wpa_s->dpp_init_max_tries;
+ else
+ max_tries = 5;
+ if (auth->num_freq_iters >= max_tries || auth->auth_req_ack) {
wpa_printf(MSG_INFO,
- "DPP: Could not find the specified configurator");
- goto fail;
+ "DPP: No response received from responder - stopping initiation attempt");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_INIT_FAILED);
+ wpas_notify_dpp_timeout(wpa_s);
+ eloop_cancel_timeout(wpas_dpp_reply_wait_timeout,
+ wpa_s, NULL);
+ offchannel_send_action_done(wpa_s);
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return -1;
}
+ auth->freq_idx = 0;
+ eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
+ if (wpa_s->dpp_init_retry_time)
+ wait_time = wpa_s->dpp_init_retry_time;
+ else
+ wait_time = 10000;
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &wpa_s->dpp_init_iter_start, &diff);
+ used = diff.sec * 1000 + diff.usec / 1000;
+ if (used > wait_time)
+ wait_time = 0;
+ else
+ wait_time -= used;
+ wpa_printf(MSG_DEBUG, "DPP: Next init attempt in %u ms",
+ wait_time);
+ eloop_register_timeout(wait_time / 1000,
+ (wait_time % 1000) * 1000,
+ wpas_dpp_init_timeout, wpa_s,
+ NULL);
+ return 0;
}
- auth->conf_sta = conf_sta;
- auth->conf_ap = conf_ap;
- auth->conf = conf;
- return;
+ freq = auth->freq[auth->freq_idx++];
+ auth->curr_freq = freq;
-fail:
- wpa_printf(MSG_DEBUG, "DPP: Failed to set configurator parameters");
- dpp_configuration_free(conf_sta);
- dpp_configuration_free(conf_ap);
+ if (is_zero_ether_addr(auth->peer_bi->mac_addr))
+ dst = broadcast;
+ else
+ dst = auth->peer_bi->mac_addr;
+ wpa_s->dpp_auth_ok_on_ack = 0;
+ eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+ wait_time = wpa_s->max_remain_on_chan;
+ max_wait_time = wpa_s->dpp_resp_wait_time ?
+ wpa_s->dpp_resp_wait_time : 2000;
+ if (wait_time > max_wait_time)
+ wait_time = max_wait_time;
+ wait_time += 10; /* give the driver some extra time to complete */
+ eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
+ wpas_dpp_reply_wait_timeout,
+ wpa_s, NULL);
+ wait_time -= 10;
+ if (auth->neg_freq > 0 && freq != auth->neg_freq) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Initiate on %u MHz and move to neg_freq %u MHz for response",
+ freq, auth->neg_freq);
+ }
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(dst), freq, DPP_PA_AUTHENTICATION_REQ);
+ auth->auth_req_ack = 0;
+ os_get_reltime(&wpa_s->dpp_last_init);
+ return offchannel_send_action(wpa_s, freq, dst,
+ wpa_s->own_addr, broadcast,
+ wpabuf_head(auth->req_msg),
+ wpabuf_len(auth->req_msg),
+ wait_time, wpas_dpp_tx_status, 0);
}
@@ -499,10 +436,8 @@
{
const char *pos;
struct dpp_bootstrap_info *peer_bi, *own_bi = NULL;
- const u8 *dst;
- int res;
- int configurator = 1;
- unsigned int wait_time;
+ u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
+ unsigned int neg_freq = 0;
wpa_s->dpp_gas_client = 0;
@@ -510,7 +445,7 @@
if (!pos)
return -1;
pos += 6;
- peer_bi = dpp_bootstrap_get_id(wpa_s, atoi(pos));
+ peer_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
if (!peer_bi) {
wpa_printf(MSG_INFO,
"DPP: Could not find bootstrapping info for the identified peer");
@@ -520,7 +455,7 @@
pos = os_strstr(cmd, " own=");
if (pos) {
pos += 5;
- own_bi = dpp_bootstrap_get_id(wpa_s, atoi(pos));
+ own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
if (!own_bi) {
wpa_printf(MSG_INFO,
"DPP: Could not find bootstrapping info for the identified local entry");
@@ -539,9 +474,12 @@
if (pos) {
pos += 6;
if (os_strncmp(pos, "configurator", 12) == 0)
- configurator = 1;
+ allowed_roles = DPP_CAPAB_CONFIGURATOR;
else if (os_strncmp(pos, "enrollee", 8) == 0)
- configurator = 0;
+ allowed_roles = DPP_CAPAB_ENROLLEE;
+ else if (os_strncmp(pos, "either", 6) == 0)
+ allowed_roles = DPP_CAPAB_CONFIGURATOR |
+ DPP_CAPAB_ENROLLEE;
else
goto fail;
}
@@ -552,47 +490,37 @@
wpa_s->dpp_netrole_ap = os_strncmp(pos, "ap", 2) == 0;
}
+ pos = os_strstr(cmd, " neg_freq=");
+ if (pos)
+ neg_freq = atoi(pos + 10);
+
if (wpa_s->dpp_auth) {
+ eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
+ NULL);
offchannel_send_action_done(wpa_s);
dpp_auth_deinit(wpa_s->dpp_auth);
}
- wpa_s->dpp_auth = dpp_auth_init(wpa_s, peer_bi, own_bi, configurator);
+ wpa_s->dpp_auth = dpp_auth_init(wpa_s, peer_bi, own_bi, allowed_roles,
+ neg_freq,
+ wpa_s->hw.modes, wpa_s->hw.num_modes);
if (!wpa_s->dpp_auth)
goto fail;
wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth);
- wpas_dpp_set_configurator(wpa_s, wpa_s->dpp_auth, cmd);
+ if (dpp_set_configurator(wpa_s->dpp, wpa_s, wpa_s->dpp_auth, cmd) < 0) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ goto fail;
+ }
- /* TODO: Support iteration over all frequencies and filtering of
- * frequencies based on locally enabled channels that allow initiation
- * of transmission. */
- if (peer_bi->num_freq > 0)
- wpa_s->dpp_auth->curr_freq = peer_bi->freq[0];
- else
- wpa_s->dpp_auth->curr_freq = 2412;
+ wpa_s->dpp_auth->neg_freq = neg_freq;
- if (is_zero_ether_addr(peer_bi->mac_addr)) {
- dst = broadcast;
- } else {
- dst = peer_bi->mac_addr;
+ if (!is_zero_ether_addr(peer_bi->mac_addr))
os_memcpy(wpa_s->dpp_auth->peer_mac_addr, peer_bi->mac_addr,
ETH_ALEN);
- }
- wpa_s->dpp_auth_ok_on_ack = 0;
- eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
- wait_time = wpa_s->max_remain_on_chan;
- if (wait_time > 2000)
- wait_time = 2000;
- eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
- wpas_dpp_reply_wait_timeout,
- wpa_s, NULL);
- res = offchannel_send_action(wpa_s, wpa_s->dpp_auth->curr_freq,
- dst, wpa_s->own_addr, broadcast,
- wpabuf_head(wpa_s->dpp_auth->req_msg),
- wpabuf_len(wpa_s->dpp_auth->req_msg),
- wait_time, wpas_dpp_tx_status, 0);
- return res;
+ return wpas_dpp_auth_init_next(wpa_s);
fail:
return -1;
}
@@ -650,6 +578,7 @@
wpa_printf(MSG_DEBUG,
"DPP: Failed to request the driver to remain on channel (%u MHz) for listen",
lwork->freq);
+ wpa_s->dpp_listen_freq = 0;
wpas_dpp_listen_work_done(wpa_s);
wpa_s->dpp_pending_listen_freq = 0;
return;
@@ -718,6 +647,7 @@
void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s)
{
+ wpa_s->dpp_in_response_listen = 0;
if (!wpa_s->dpp_listen_freq)
return;
@@ -729,40 +659,23 @@
}
-void wpas_dpp_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
- unsigned int freq)
-{
- if (!wpa_s->dpp_listen_freq && !wpa_s->dpp_pending_listen_freq)
- return;
-
- wpa_printf(MSG_DEBUG,
- "DPP: remain-on-channel callback (off_channel_freq=%u dpp_pending_listen_freq=%d roc_waiting_drv_freq=%d freq=%u)",
- wpa_s->off_channel_freq, wpa_s->dpp_pending_listen_freq,
- wpa_s->roc_waiting_drv_freq, freq);
- if (wpa_s->off_channel_freq &&
- wpa_s->off_channel_freq == wpa_s->dpp_pending_listen_freq) {
- wpa_printf(MSG_DEBUG, "DPP: Listen on %u MHz started", freq);
- wpa_s->dpp_pending_listen_freq = 0;
- } else {
- wpa_printf(MSG_DEBUG,
- "DPP: Ignore remain-on-channel callback (off_channel_freq=%u dpp_pending_listen_freq=%d freq=%u)",
- wpa_s->off_channel_freq,
- wpa_s->dpp_pending_listen_freq, freq);
- }
-}
-
-
void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq)
{
wpas_dpp_listen_work_done(wpa_s);
- if (wpa_s->dpp_auth && !wpa_s->dpp_gas_client) {
+ if (wpa_s->dpp_auth && wpa_s->dpp_in_response_listen) {
+ unsigned int new_freq;
+
/* Continue listen with a new remain-on-channel */
+ if (wpa_s->dpp_auth->neg_freq > 0)
+ new_freq = wpa_s->dpp_auth->neg_freq;
+ else
+ new_freq = wpa_s->dpp_auth->curr_freq;
wpa_printf(MSG_DEBUG,
"DPP: Continue wait on %u MHz for the ongoing DPP provisioning session",
- wpa_s->dpp_auth->curr_freq);
- wpas_dpp_listen_start(wpa_s, wpa_s->dpp_auth->curr_freq);
+ new_freq);
+ wpas_dpp_listen_start(wpa_s, new_freq);
return;
}
@@ -777,29 +690,21 @@
const u8 *hdr, const u8 *buf, size_t len,
unsigned int freq)
{
- const u8 *r_bootstrap, *i_bootstrap, *wrapped_data;
- u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len;
- struct dpp_bootstrap_info *bi, *own_bi = NULL, *peer_bi = NULL;
+ const u8 *r_bootstrap, *i_bootstrap;
+ u16 r_bootstrap_len, i_bootstrap_len;
+ struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
+
+ if (!wpa_s->dpp)
+ return;
wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
MAC2STR(src));
- wrapped_data = dpp_get_attr(buf, len, DPP_ATTR_WRAPPED_DATA,
- &wrapped_data_len);
- if (!wrapped_data) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing required Wrapped data attribute");
- return;
- }
- wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped data",
- wrapped_data, wrapped_data_len);
-
r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
&r_bootstrap_len);
- if (!r_bootstrap || r_bootstrap > wrapped_data ||
- r_bootstrap_len != SHA256_MAC_LEN) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Responder Bootstrapping Key Hash attribute");
return;
}
wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
@@ -807,10 +712,9 @@
i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
&i_bootstrap_len);
- if (!i_bootstrap || i_bootstrap > wrapped_data ||
- i_bootstrap_len != SHA256_MAC_LEN) {
- wpa_printf(MSG_DEBUG,
- "DPP: Missing or invalid required Initiator Bootstrapping Key Hash attribute");
+ if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
return;
}
wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
@@ -818,37 +722,17 @@
/* Try to find own and peer bootstrapping key matches based on the
* received hash values */
- dl_list_for_each(bi, &wpa_s->dpp_bootstrap, struct dpp_bootstrap_info,
- list) {
- if (!own_bi && bi->own &&
- os_memcmp(bi->pubkey_hash, r_bootstrap,
- SHA256_MAC_LEN) == 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Found matching own bootstrapping information");
- own_bi = bi;
- }
-
- if (!peer_bi && !bi->own &&
- os_memcmp(bi->pubkey_hash, i_bootstrap,
- SHA256_MAC_LEN) == 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Found matching peer bootstrapping information");
- peer_bi = bi;
- }
-
- if (own_bi && peer_bi)
- break;
- }
-
+ dpp_bootstrap_find_pair(wpa_s->dpp, i_bootstrap, r_bootstrap,
+ &own_bi, &peer_bi);
if (!own_bi) {
- wpa_printf(MSG_DEBUG,
- "DPP: No matching own bootstrapping key found - ignore message");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "No matching own bootstrapping key found - ignore message");
return;
}
if (wpa_s->dpp_auth) {
- wpa_printf(MSG_DEBUG,
- "DPP: Already in DPP authentication exchange - ignore new one");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "Already in DPP authentication exchange - ignore new one");
return;
}
@@ -856,17 +740,31 @@
wpa_s->dpp_auth_ok_on_ack = 0;
wpa_s->dpp_auth = dpp_auth_req_rx(wpa_s, wpa_s->dpp_allowed_roles,
wpa_s->dpp_qr_mutual,
- peer_bi, own_bi, freq, hdr, buf,
- wrapped_data, wrapped_data_len);
+ peer_bi, own_bi, freq, hdr, buf, len);
if (!wpa_s->dpp_auth) {
wpa_printf(MSG_DEBUG, "DPP: No response generated");
return;
}
wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth);
- wpas_dpp_set_configurator(wpa_s, wpa_s->dpp_auth,
- wpa_s->dpp_configurator_params);
+ if (dpp_set_configurator(wpa_s->dpp, wpa_s, wpa_s->dpp_auth,
+ wpa_s->dpp_configurator_params) < 0) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
os_memcpy(wpa_s->dpp_auth->peer_mac_addr, src, ETH_ALEN);
+ if (wpa_s->dpp_listen_freq &&
+ wpa_s->dpp_listen_freq != wpa_s->dpp_auth->curr_freq) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Stop listen on %u MHz to allow response on the request %u MHz",
+ wpa_s->dpp_listen_freq, wpa_s->dpp_auth->curr_freq);
+ wpas_dpp_listen_stop(wpa_s);
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(src), wpa_s->dpp_auth->curr_freq,
+ DPP_PA_AUTHENTICATION_RESP);
offchannel_send_action(wpa_s, wpa_s->dpp_auth->curr_freq,
src, wpa_s->own_addr, broadcast,
wpabuf_head(wpa_s->dpp_auth->resp_msg),
@@ -886,6 +784,27 @@
{
struct wpa_ssid *ssid;
+#ifdef CONFIG_DPP2
+ if (auth->akm == DPP_AKM_SAE) {
+#ifdef CONFIG_SAE
+ struct wpa_driver_capa capa;
+ int res;
+
+ res = wpa_drv_get_capa(wpa_s, &capa);
+ if (res == 0 &&
+ !(capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: SAE not supported by the driver");
+ return NULL;
+ }
+#else /* CONFIG_SAE */
+ wpa_printf(MSG_DEBUG, "DPP: SAE not supported in the build");
+ return NULL;
+#endif /* CONFIG_SAE */
+ }
+#endif /* CONFIG_DPP2 */
+
ssid = wpa_config_add_network(wpa_s->conf);
if (!ssid)
return NULL;
@@ -901,6 +820,7 @@
if (auth->connector) {
ssid->key_mgmt = WPA_KEY_MGMT_DPP;
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
ssid->dpp_connector = os_strdup(auth->connector);
if (!ssid->dpp_connector)
goto fail;
@@ -927,8 +847,17 @@
ssid->dpp_netaccesskey_expiry = auth->net_access_key_expiry;
}
- if (!auth->connector) {
- ssid->key_mgmt = WPA_KEY_MGMT_PSK;
+ if (!auth->connector || dpp_akm_psk(auth->akm) ||
+ dpp_akm_sae(auth->akm)) {
+ if (!auth->connector)
+ ssid->key_mgmt = 0;
+ if (dpp_akm_psk(auth->akm))
+ ssid->key_mgmt |= WPA_KEY_MGMT_PSK |
+ WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_FT_PSK;
+ if (dpp_akm_sae(auth->akm))
+ ssid->key_mgmt |= WPA_KEY_MGMT_SAE |
+ WPA_KEY_MGMT_FT_SAE;
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
if (auth->passphrase[0]) {
if (wpa_config_set_quoted(ssid, "psk",
auth->passphrase) < 0)
@@ -949,35 +878,50 @@
}
-static void wpas_dpp_process_config(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth)
+static int wpas_dpp_process_config(struct wpa_supplicant *wpa_s,
+ struct dpp_authentication *auth)
{
struct wpa_ssid *ssid;
if (wpa_s->conf->dpp_config_processing < 1)
- return;
+ return 0;
ssid = wpas_dpp_add_network(wpa_s, auth);
if (!ssid)
- return;
+ return -1;
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_NETWORK_ID "%d", ssid->id);
- if (wpa_s->conf->dpp_config_processing < 2)
- return;
- wpa_printf(MSG_DEBUG, "DPP: Trying to connect to the new network");
- ssid->disabled = 0;
- wpa_s->disconnected = 0;
- wpa_s->reassociate = 1;
- wpa_s->scan_runs = 0;
- wpa_s->normal_scans = 0;
- wpa_supplicant_cancel_sched_scan(wpa_s);
- wpa_supplicant_req_scan(wpa_s, 0, 0);
+ wpas_notify_dpp_config_received(wpa_s, ssid);
+
+ if (wpa_s->conf->dpp_config_processing == 2)
+ ssid->disabled = 0;
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+ if (wpa_s->conf->update_config &&
+ wpa_config_write(wpa_s->confname, wpa_s->conf))
+ wpa_printf(MSG_DEBUG, "DPP: Failed to update configuration");
+#endif /* CONFIG_NO_CONFIG_WRITE */
+
+ if (wpa_s->conf->dpp_config_processing < 2)
+ return 0;
+
+#ifdef CONFIG_DPP2
+ if (auth->peer_version >= 2) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Postpone connection attempt to wait for completion of DPP Configuration Result");
+ auth->connect_on_tx_status = 1;
+ return 0;
+ }
+#endif /* CONFIG_DPP2 */
+
+ wpas_dpp_try_to_connect(wpa_s);
+ return 0;
}
-static void wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth)
+static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
+ struct dpp_authentication *auth)
{
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
if (auth->ssid_len)
@@ -1029,7 +973,7 @@
}
}
- wpas_dpp_process_config(wpa_s, auth);
+ return wpas_dpp_process_config(wpa_s, auth);
}
@@ -1041,12 +985,17 @@
struct wpa_supplicant *wpa_s = ctx;
const u8 *pos;
struct dpp_authentication *auth = wpa_s->dpp_auth;
+ int res;
+ enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
+
+ wpa_s->dpp_gas_dialog_token = -1;
if (!auth || !auth->auth_success) {
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
return;
}
- if (!resp || status_code != WLAN_STATUS_SUCCESS) {
+ if (result != GAS_QUERY_SUCCESS ||
+ !resp || status_code != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed");
goto fail;
}
@@ -1075,13 +1024,48 @@
goto fail;
}
- wpas_dpp_handle_config_obj(wpa_s, auth);
- dpp_auth_deinit(wpa_s->dpp_auth);
- wpa_s->dpp_auth = NULL;
- return;
+ res = wpas_dpp_handle_config_obj(wpa_s, auth);
+ if (res < 0)
+ goto fail;
+ status = DPP_STATUS_OK;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_REJECT_CONFIG) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - Reject Config Object");
+ status = DPP_STATUS_CONFIG_REJECTED;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
fail:
- wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ if (status != DPP_STATUS_OK) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ wpas_notify_dpp_configuration_failure(wpa_s);
+ }
+#ifdef CONFIG_DPP2
+ if (auth->peer_version >= 2 &&
+ auth->conf_resp_status == DPP_STATUS_OK) {
+ struct wpabuf *msg;
+
+ wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
+ msg = dpp_build_conf_result(auth, status);
+ if (!msg)
+ goto fail2;
+
+ wpa_msg(wpa_s, MSG_INFO,
+ DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(addr), auth->curr_freq,
+ DPP_PA_CONFIGURATION_RESULT);
+ offchannel_send_action(wpa_s, auth->curr_freq,
+ addr, wpa_s->own_addr, broadcast,
+ wpabuf_head(msg),
+ wpabuf_len(msg),
+ 500, wpas_dpp_tx_status, 0);
+ wpabuf_free(msg);
+
+ /* This exchange will be terminated in the TX status handler */
+ return;
+ }
+fail2:
+#endif /* CONFIG_DPP2 */
dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL;
}
@@ -1090,7 +1074,7 @@
static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s)
{
struct dpp_authentication *auth = wpa_s->dpp_auth;
- struct wpabuf *buf, *conf_req;
+ struct wpabuf *buf;
char json[100];
int res;
@@ -1100,50 +1084,36 @@
"\"wi-fi_tech\":\"infra\","
"\"netRole\":\"%s\"}",
wpa_s->dpp_netrole_ap ? "ap" : "sta");
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
+ json[29] = 'k'; /* replace "infra" with "knfra" */
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
- conf_req = dpp_build_conf_req(auth, json);
- if (!conf_req) {
+ buf = dpp_build_conf_req(auth, json);
+ if (!buf) {
wpa_printf(MSG_DEBUG,
"DPP: No configuration request data available");
return;
}
- buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req));
- if (!buf) {
- wpabuf_free(conf_req);
- return;
- }
-
- /* Advertisement Protocol IE */
- wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
- wpabuf_put_u8(buf, 8); /* Length */
- wpabuf_put_u8(buf, 0x7f);
- wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
- wpabuf_put_u8(buf, 5);
- wpabuf_put_be24(buf, OUI_WFA);
- wpabuf_put_u8(buf, DPP_OUI_TYPE);
- wpabuf_put_u8(buf, 0x01);
-
- /* GAS Query */
- wpabuf_put_le16(buf, wpabuf_len(conf_req));
- wpabuf_put_buf(buf, conf_req);
- wpabuf_free(conf_req);
-
wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR " (freq %u MHz)",
MAC2STR(auth->peer_mac_addr), auth->curr_freq);
res = gas_query_req(wpa_s->gas, auth->peer_mac_addr, auth->curr_freq,
- buf, wpas_dpp_gas_resp_cb, wpa_s);
+ 1, buf, wpas_dpp_gas_resp_cb, wpa_s);
if (res < 0) {
wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request");
wpabuf_free(buf);
} else {
wpa_printf(MSG_DEBUG,
"DPP: GAS query started with dialog token %u", res);
+ wpa_s->dpp_gas_dialog_token = res;
}
}
@@ -1152,6 +1122,18 @@
{
wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d", initiator);
+ wpas_notify_dpp_auth_success(wpa_s);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - stop at Authentication Confirm");
+ if (wpa_s->dpp_auth->configurator) {
+ /* Prevent GAS response */
+ wpa_s->dpp_auth->auth_success = 0;
+ }
+ return;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_s->dpp_auth->configurator)
wpas_dpp_start_gas_server(wpa_s);
@@ -1161,13 +1143,14 @@
static void wpas_dpp_rx_auth_resp(struct wpa_supplicant *wpa_s, const u8 *src,
- const u8 *hdr, const u8 *buf, size_t len)
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
{
struct dpp_authentication *auth = wpa_s->dpp_auth;
struct wpabuf *msg;
- wpa_printf(MSG_DEBUG, "DPP: Authentication Response from " MACSTR,
- MAC2STR(src));
+ wpa_printf(MSG_DEBUG, "DPP: Authentication Response from " MACSTR
+ " (freq %u MHz)", MAC2STR(src), freq);
if (!auth) {
wpa_printf(MSG_DEBUG,
@@ -1184,11 +1167,19 @@
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+ if (auth->curr_freq != freq && auth->neg_freq == freq) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Responder accepted request for different negotiation channel");
+ auth->curr_freq = freq;
+ }
+
+ eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
msg = dpp_auth_resp_rx(auth, hdr, buf, len);
if (!msg) {
if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
wpa_printf(MSG_DEBUG,
"DPP: Start wait for full response");
+ wpas_notify_dpp_resp_pending(wpa_s);
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_start(wpa_s, auth->curr_freq);
return;
@@ -1198,6 +1189,8 @@
}
os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(src), auth->curr_freq, DPP_PA_AUTHENTICATION_CONF);
offchannel_send_action(wpa_s, auth->curr_freq,
src, wpa_s->own_addr, broadcast,
wpabuf_head(msg), wpabuf_len(msg),
@@ -1229,6 +1222,7 @@
if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
+ wpas_notify_dpp_auth_failure(wpa_s);
return;
}
@@ -1236,19 +1230,76 @@
}
+#ifdef CONFIG_DPP2
+
+static void wpas_dpp_config_result_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!auth || !auth->waiting_conf_result)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Timeout while waiting for Configuration Result");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+}
+
+
+static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ enum dpp_status_error status;
+
+ wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR,
+ MAC2STR(src));
+
+ if (!auth || !auth->waiting_conf_result) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for result - drop");
+ return;
+ }
+
+ if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
+ MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
+ return;
+ }
+
+ status = dpp_conf_result_rx(auth, hdr, buf, len);
+
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_stop(wpa_s);
+ if (status == DPP_STATUS_OK)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT);
+ else
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+ eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
+}
+
+#endif /* CONFIG_DPP2 */
+
+
static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
const u8 *src,
const u8 *buf, size_t len)
{
struct wpa_ssid *ssid;
- const u8 *connector, *trans_id;
- u16 connector_len, trans_id_len;
+ const u8 *connector, *trans_id, *status;
+ u16 connector_len, trans_id_len, status_len;
struct dpp_introduction intro;
struct rsn_pmksa_cache_entry *entry;
struct os_time now;
struct os_reltime rnow;
os_time_t expiry;
unsigned int seconds;
+ enum dpp_status_error res;
wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Response from " MACSTR,
MAC2STR(src));
@@ -1276,12 +1327,32 @@
if (!trans_id || trans_id_len != 1) {
wpa_printf(MSG_DEBUG,
"DPP: Peer did not include Transaction ID");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+ " fail=missing_transaction_id", MAC2STR(src));
goto fail;
}
if (trans_id[0] != TRANSACTION_ID) {
wpa_printf(MSG_DEBUG,
"DPP: Ignore frame with unexpected Transaction ID %u",
trans_id[0]);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+ " fail=transaction_id_mismatch", MAC2STR(src));
+ goto fail;
+ }
+
+ status = dpp_get_attr(buf, len, DPP_ATTR_STATUS, &status_len);
+ if (!status || status_len != 1) {
+ wpa_printf(MSG_DEBUG, "DPP: Peer did not include Status");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+ " fail=missing_status", MAC2STR(src));
+ goto fail;
+ }
+ if (status[0] != DPP_STATUS_OK) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer rejected network introduction: Status %u",
+ status[0]);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+ " status=%u", MAC2STR(src), status[0]);
goto fail;
}
@@ -1289,17 +1360,22 @@
if (!connector) {
wpa_printf(MSG_DEBUG,
"DPP: Peer did not include its Connector");
- return;
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+ " fail=missing_connector", MAC2STR(src));
+ goto fail;
}
- if (dpp_peer_intro(&intro, ssid->dpp_connector,
- ssid->dpp_netaccesskey,
- ssid->dpp_netaccesskey_len,
- ssid->dpp_csign,
- ssid->dpp_csign_len,
- connector, connector_len, &expiry) < 0) {
+ res = dpp_peer_intro(&intro, ssid->dpp_connector,
+ ssid->dpp_netaccesskey,
+ ssid->dpp_netaccesskey_len,
+ ssid->dpp_csign,
+ ssid->dpp_csign_len,
+ connector, connector_len, &expiry);
+ if (res != DPP_STATUS_OK) {
wpa_printf(MSG_INFO,
"DPP: Network Introduction protocol resulted in failure");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+ " fail=peer_connector_validation_failed", MAC2STR(src));
goto fail;
}
@@ -1323,6 +1399,9 @@
entry->network_ctx = ssid;
wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+ " status=%u", MAC2STR(src), status[0]);
+
wpa_printf(MSG_DEBUG,
"DPP: Try connection again after successful network introduction");
if (wpa_supplicant_fast_associate(wpa_s) != 1) {
@@ -1334,6 +1413,94 @@
}
+static int wpas_dpp_allow_ir(struct wpa_supplicant *wpa_s, unsigned int freq)
+{
+ int i, j;
+
+ if (!wpa_s->hw.modes)
+ return -1;
+
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
+
+ for (j = 0; j < mode->num_channels; j++) {
+ struct hostapd_channel_data *chan = &mode->channels[j];
+
+ if (chan->freq != (int) freq)
+ continue;
+
+ if (chan->flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_NO_IR |
+ HOSTAPD_CHAN_RADAR))
+ continue;
+
+ return 1;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Frequency %u MHz not supported or does not allow PKEX initiation in the current channel list",
+ freq);
+
+ return 0;
+}
+
+
+static int wpas_dpp_pkex_next_channel(struct wpa_supplicant *wpa_s,
+ struct dpp_pkex *pkex)
+{
+ if (pkex->freq == 2437)
+ pkex->freq = 5745;
+ else if (pkex->freq == 5745)
+ pkex->freq = 5220;
+ else if (pkex->freq == 5220)
+ pkex->freq = 60480;
+ else
+ return -1; /* no more channels to try */
+
+ if (wpas_dpp_allow_ir(wpa_s, pkex->freq) == 1) {
+ wpa_printf(MSG_DEBUG, "DPP: Try to initiate on %u MHz",
+ pkex->freq);
+ return 0;
+ }
+
+ /* Could not use this channel - try the next one */
+ return wpas_dpp_pkex_next_channel(wpa_s, pkex);
+}
+
+
+static void wpas_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_pkex *pkex = wpa_s->dpp_pkex;
+
+ if (!pkex || !pkex->exchange_req)
+ return;
+ if (pkex->exch_req_tries >= 5) {
+ if (wpas_dpp_pkex_next_channel(wpa_s, pkex) < 0) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "No response from PKEX peer");
+ dpp_pkex_free(pkex);
+ wpa_s->dpp_pkex = NULL;
+ return;
+ }
+ pkex->exch_req_tries = 0;
+ }
+
+ pkex->exch_req_tries++;
+ wpa_printf(MSG_DEBUG, "DPP: Retransmit PKEX Exchange Request (try %u)",
+ pkex->exch_req_tries);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(broadcast), pkex->freq, DPP_PA_PKEX_EXCHANGE_REQ);
+ offchannel_send_action(wpa_s, pkex->freq, broadcast,
+ wpa_s->own_addr, broadcast,
+ wpabuf_head(pkex->exchange_req),
+ wpabuf_len(pkex->exchange_req),
+ pkex->exch_req_wait_time,
+ wpas_dpp_tx_pkex_status, 0);
+}
+
+
static void
wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
unsigned int freq, const u8 *dst,
@@ -1341,13 +1508,43 @@
const u8 *data, size_t data_len,
enum offchannel_send_action_result result)
{
+ const char *res_txt;
+ struct dpp_pkex *pkex = wpa_s->dpp_pkex;
+
+ res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
+ (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
+ "FAILED");
wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
" result=%s (PKEX)",
- freq, MAC2STR(dst),
- result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
- (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
- "FAILED"));
- /* TODO: Time out wait for response more quickly in error cases? */
+ freq, MAC2STR(dst), res_txt);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
+ " freq=%u result=%s", MAC2STR(dst), freq, res_txt);
+
+ if (!pkex) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore TX status since there is no ongoing PKEX exchange");
+ return;
+ }
+
+ if (pkex->failed) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Terminate PKEX exchange due to an earlier error");
+ if (pkex->t > pkex->own_bi->pkex_t)
+ pkex->own_bi->pkex_t = pkex->t;
+ dpp_pkex_free(pkex);
+ wpa_s->dpp_pkex = NULL;
+ return;
+ }
+
+ if (pkex->exch_req_wait_time && pkex->exchange_req) {
+ /* Wait for PKEX Exchange Response frame and retry request if
+ * no response is seen. */
+ eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
+ eloop_register_timeout(pkex->exch_req_wait_time / 1000,
+ (pkex->exch_req_wait_time % 1000) * 1000,
+ wpas_dpp_pkex_retry_timeout, wpa_s,
+ NULL);
+ }
}
@@ -1377,7 +1574,7 @@
return;
}
- wpa_s->dpp_pkex = dpp_pkex_rx_exchange_req(wpa_s->dpp_pkex_bi,
+ wpa_s->dpp_pkex = dpp_pkex_rx_exchange_req(wpa_s, wpa_s->dpp_pkex_bi,
wpa_s->own_addr, src,
wpa_s->dpp_pkex_identifier,
wpa_s->dpp_pkex_code,
@@ -1392,6 +1589,8 @@
wait_time = wpa_s->max_remain_on_chan;
if (wait_time > 2000)
wait_time = 2000;
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(src), freq, DPP_PA_PKEX_EXCHANGE_RESP);
offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr,
broadcast,
wpabuf_head(msg), wpabuf_len(msg),
@@ -1418,8 +1617,10 @@
return;
}
- os_memcpy(wpa_s->dpp_pkex->peer_mac, src, ETH_ALEN);
- msg = dpp_pkex_rx_exchange_resp(wpa_s->dpp_pkex, buf, len);
+ eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
+ wpa_s->dpp_pkex->exch_req_wait_time = 0;
+
+ msg = dpp_pkex_rx_exchange_resp(wpa_s->dpp_pkex, src, buf, len);
if (!msg) {
wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
return;
@@ -1431,6 +1632,8 @@
wait_time = wpa_s->max_remain_on_chan;
if (wait_time > 2000)
wait_time = 2000;
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(src), freq, DPP_PA_PKEX_COMMIT_REVEAL_REQ);
offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr,
broadcast,
wpabuf_head(msg), wpabuf_len(msg),
@@ -1439,6 +1642,20 @@
}
+static struct dpp_bootstrap_info *
+wpas_dpp_pkex_finish(struct wpa_supplicant *wpa_s, const u8 *peer,
+ unsigned int freq)
+{
+ struct dpp_bootstrap_info *bi;
+
+ bi = dpp_pkex_finish(wpa_s->dpp, wpa_s->dpp_pkex, peer, freq);
+ if (!bi)
+ return NULL;
+ wpa_s->dpp_pkex = NULL;
+ return bi;
+}
+
+
static void
wpas_dpp_rx_pkex_commit_reveal_req(struct wpa_supplicant *wpa_s, const u8 *src,
const u8 *hdr, const u8 *buf, size_t len,
@@ -1447,7 +1664,6 @@
struct wpabuf *msg;
unsigned int wait_time;
struct dpp_pkex *pkex = wpa_s->dpp_pkex;
- struct dpp_bootstrap_info *bi;
wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Request from " MACSTR,
MAC2STR(src));
@@ -1460,6 +1676,13 @@
msg = dpp_pkex_rx_commit_reveal_req(pkex, hdr, buf, len);
if (!msg) {
wpa_printf(MSG_DEBUG, "DPP: Failed to process the request");
+ if (pkex->failed) {
+ wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange");
+ if (pkex->t > pkex->own_bi->pkex_t)
+ pkex->own_bi->pkex_t = pkex->t;
+ dpp_pkex_free(wpa_s->dpp_pkex);
+ wpa_s->dpp_pkex = NULL;
+ }
return;
}
@@ -1469,30 +1692,15 @@
wait_time = wpa_s->max_remain_on_chan;
if (wait_time > 2000)
wait_time = 2000;
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(src), freq, DPP_PA_PKEX_COMMIT_REVEAL_RESP);
offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr,
broadcast,
wpabuf_head(msg), wpabuf_len(msg),
wait_time, wpas_dpp_tx_pkex_status, 0);
wpabuf_free(msg);
- bi = os_zalloc(sizeof(*bi));
- if (!bi)
- return;
- bi->id = wpas_dpp_next_id(wpa_s);
- bi->type = DPP_BOOTSTRAP_PKEX;
- os_memcpy(bi->mac_addr, src, ETH_ALEN);
- bi->num_freq = 1;
- bi->freq[0] = freq;
- bi->curve = pkex->own_bi->curve;
- bi->pubkey = pkex->peer_bootstrap_key;
- pkex->peer_bootstrap_key = NULL;
- dpp_pkex_free(pkex);
- wpa_s->dpp_pkex = NULL;
- if (dpp_bootstrap_key_hash(bi) < 0) {
- dpp_bootstrap_info_free(bi);
- return;
- }
- dl_list_add(&wpa_s->dpp_bootstrap, &bi->list);
+ wpas_dpp_pkex_finish(wpa_s, src, freq);
}
@@ -1502,7 +1710,7 @@
unsigned int freq)
{
int res;
- struct dpp_bootstrap_info *bi, *own_bi;
+ struct dpp_bootstrap_info *bi;
struct dpp_pkex *pkex = wpa_s->dpp_pkex;
char cmd[500];
@@ -1520,26 +1728,9 @@
return;
}
- own_bi = pkex->own_bi;
-
- bi = os_zalloc(sizeof(*bi));
+ bi = wpas_dpp_pkex_finish(wpa_s, src, freq);
if (!bi)
return;
- bi->id = wpas_dpp_next_id(wpa_s);
- bi->type = DPP_BOOTSTRAP_PKEX;
- os_memcpy(bi->mac_addr, src, ETH_ALEN);
- bi->num_freq = 1;
- bi->freq[0] = freq;
- bi->curve = own_bi->curve;
- bi->pubkey = pkex->peer_bootstrap_key;
- pkex->peer_bootstrap_key = NULL;
- dpp_pkex_free(pkex);
- wpa_s->dpp_pkex = NULL;
- if (dpp_bootstrap_key_hash(bi) < 0) {
- dpp_bootstrap_info_free(bi);
- return;
- }
- dl_list_add(&wpa_s->dpp_bootstrap, &bi->list);
os_snprintf(cmd, sizeof(cmd), " peer=%u %s",
bi->id,
@@ -1561,6 +1752,7 @@
u8 crypto_suite;
enum dpp_public_action_frame_type type;
const u8 *hdr;
+ unsigned int pkex_t;
if (len < DPP_HDR_LEN)
return;
@@ -1580,18 +1772,27 @@
if (crypto_suite != 1) {
wpa_printf(MSG_DEBUG, "DPP: Unsupported crypto suite %u",
crypto_suite);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
+ " freq=%u type=%d ignore=unsupported-crypto-suite",
+ MAC2STR(src), freq, type);
return;
}
wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes", buf, len);
- if (dpp_check_attrs(buf, len) < 0)
+ if (dpp_check_attrs(buf, len) < 0) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
+ " freq=%u type=%d ignore=invalid-attributes",
+ MAC2STR(src), freq, type);
return;
+ }
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR " freq=%u type=%d",
+ MAC2STR(src), freq, type);
switch (type) {
case DPP_PA_AUTHENTICATION_REQ:
wpas_dpp_rx_auth_req(wpa_s, src, hdr, buf, len, freq);
break;
case DPP_PA_AUTHENTICATION_RESP:
- wpas_dpp_rx_auth_resp(wpa_s, src, hdr, buf, len);
+ wpas_dpp_rx_auth_resp(wpa_s, src, hdr, buf, len, freq);
break;
case DPP_PA_AUTHENTICATION_CONF:
wpas_dpp_rx_auth_conf(wpa_s, src, hdr, buf, len);
@@ -1613,11 +1814,27 @@
wpas_dpp_rx_pkex_commit_reveal_resp(wpa_s, src, hdr, buf, len,
freq);
break;
+#ifdef CONFIG_DPP2
+ case DPP_PA_CONFIGURATION_RESULT:
+ wpas_dpp_rx_conf_result(wpa_s, src, hdr, buf, len);
+ break;
+#endif /* CONFIG_DPP2 */
default:
wpa_printf(MSG_DEBUG,
"DPP: Ignored unsupported frame subtype %d", type);
break;
}
+
+ if (wpa_s->dpp_pkex)
+ pkex_t = wpa_s->dpp_pkex->t;
+ else if (wpa_s->dpp_pkex_bi)
+ pkex_t = wpa_s->dpp_pkex_bi->pkex_t;
+ else
+ pkex_t = 0;
+ if (pkex_t >= PKEX_COUNTER_T_LIMIT) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PKEX_T_LIMIT "id=0");
+ wpas_dpp_pkex_remove(wpa_s, "*");
+ }
}
@@ -1639,9 +1856,14 @@
wpa_hexdump(MSG_DEBUG,
"DPP: Received Configuration Request (GAS Query Request)",
query, query_len);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_REQ_RX "src=" MACSTR,
+ MAC2STR(sa));
resp = dpp_conf_req_rx(auth, query, query_len);
- if (!resp)
+ if (!resp) {
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ wpas_notify_dpp_configuration_failure(wpa_s);
+ }
+ auth->conf_resp = resp;
return resp;
}
@@ -1656,109 +1878,49 @@
wpabuf_free(resp);
return;
}
+ if (auth->conf_resp != resp) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore GAS status report (ok=%d) for unknown response",
+ ok);
+ wpabuf_free(resp);
+ return;
+ }
wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
ok);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
+#ifdef CONFIG_DPP2
+ if (ok && auth->peer_version >= 2 &&
+ auth->conf_resp_status == DPP_STATUS_OK) {
+ wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
+ auth->waiting_conf_result = 1;
+ auth->conf_resp = NULL;
+ wpabuf_free(resp);
+ eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout,
+ wpa_s, NULL);
+ eloop_register_timeout(2, 0,
+ wpas_dpp_config_result_wait_timeout,
+ wpa_s, NULL);
+ return;
+ }
+#endif /* CONFIG_DPP2 */
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
- if (ok)
+ if (ok) {
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT);
- else
+ wpas_notify_dpp_config_sent(wpa_s);
+ }
+ else {
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ wpas_notify_dpp_configuration_failure(wpa_s);
+ }
dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL;
wpabuf_free(resp);
}
-static unsigned int wpas_dpp_next_configurator_id(struct wpa_supplicant *wpa_s)
-{
- struct dpp_configurator *conf;
- unsigned int max_id = 0;
-
- dl_list_for_each(conf, &wpa_s->dpp_configurator,
- struct dpp_configurator, list) {
- if (conf->id > max_id)
- max_id = conf->id;
- }
- return max_id + 1;
-}
-
-
-int wpas_dpp_configurator_add(struct wpa_supplicant *wpa_s, const char *cmd)
-{
- char *curve = NULL;
- char *key = NULL;
- u8 *privkey = NULL;
- size_t privkey_len = 0;
- int ret = -1;
- struct dpp_configurator *conf = NULL;
-
- curve = get_param(cmd, " curve=");
- key = get_param(cmd, " key=");
-
- if (key) {
- privkey_len = os_strlen(key) / 2;
- privkey = os_malloc(privkey_len);
- if (!privkey ||
- hexstr2bin(key, privkey, privkey_len) < 0)
- goto fail;
- }
-
- conf = dpp_keygen_configurator(curve, privkey, privkey_len);
- if (!conf)
- goto fail;
-
- conf->id = wpas_dpp_next_configurator_id(wpa_s);
- dl_list_add(&wpa_s->dpp_configurator, &conf->list);
- ret = conf->id;
- conf = NULL;
-fail:
- os_free(curve);
- str_clear_free(key);
- bin_clear_free(privkey, privkey_len);
- dpp_configurator_free(conf);
- return ret;
-}
-
-
-static int dpp_configurator_del(struct wpa_supplicant *wpa_s, unsigned int id)
-{
- struct dpp_configurator *conf, *tmp;
- int found = 0;
-
- dl_list_for_each_safe(conf, tmp, &wpa_s->dpp_configurator,
- struct dpp_configurator, list) {
- if (id && conf->id != id)
- continue;
- found = 1;
- dl_list_del(&conf->list);
- dpp_configurator_free(conf);
- }
-
- if (id == 0)
- return 0; /* flush succeeds regardless of entries found */
- return found ? 0 : -1;
-}
-
-
-int wpas_dpp_configurator_remove(struct wpa_supplicant *wpa_s, const char *id)
-{
- unsigned int id_val;
-
- if (os_strcmp(id, "*") == 0) {
- id_val = 0;
- } else {
- id_val = atoi(id);
- if (id_val == 0)
- return -1;
- }
-
- return dpp_configurator_del(wpa_s, id_val);
-}
-
-
int wpas_dpp_configurator_sign(struct wpa_supplicant *wpa_s, const char *cmd)
{
struct dpp_authentication *auth;
@@ -1770,12 +1932,10 @@
return -1;
curve = get_param(cmd, " curve=");
- wpas_dpp_set_configurator(wpa_s, auth, cmd);
-
- if (dpp_configurator_own_config(auth, curve) == 0) {
- wpas_dpp_handle_config_obj(wpa_s, auth);
- ret = 0;
- }
+ wpas_dpp_set_testing_options(wpa_s, auth);
+ if (dpp_set_configurator(wpa_s->dpp, wpa_s, auth, cmd) == 0 &&
+ dpp_configurator_own_config(auth, curve, 0) == 0)
+ ret = wpas_dpp_handle_config_obj(wpa_s, auth);
dpp_auth_deinit(auth);
os_free(curve);
@@ -1791,12 +1951,16 @@
const u8 *data, size_t data_len,
enum offchannel_send_action_result result)
{
+ const char *res_txt;
+
+ res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
+ (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
+ "FAILED");
wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
" result=%s (DPP Peer Discovery Request)",
- freq, MAC2STR(dst),
- result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
- (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
- "FAILED"));
+ freq, MAC2STR(dst), res_txt);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
+ " freq=%u result=%s", MAC2STR(dst), freq, res_txt);
/* TODO: Time out wait for response more quickly in error cases? */
}
@@ -1807,9 +1971,15 @@
struct os_time now;
struct wpabuf *msg;
unsigned int wait_time;
+ const u8 *rsn;
+ struct wpa_ie_data ied;
if (!(ssid->key_mgmt & WPA_KEY_MGMT_DPP) || !bss)
return 0; /* Not using DPP AKM - continue */
+ rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 &&
+ !(ied.key_mgmt & WPA_KEY_MGMT_DPP))
+ return 0; /* AP does not support DPP AKM - continue */
if (wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid))
return 0; /* PMKSA exists for DPP AKM - continue */
@@ -1826,7 +1996,7 @@
os_get_time(&now);
if (ssid->dpp_netaccesskey_expiry &&
- ssid->dpp_netaccesskey_expiry < now.sec) {
+ (os_time_t) ssid->dpp_netaccesskey_expiry < now.sec) {
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_MISSING_CONNECTOR
"netAccessKey expired");
return -1;
@@ -1841,20 +2011,63 @@
if (!msg)
return -1;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Transaction ID");
+ goto skip_trans_id;
+ }
+ if (dpp_test == DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Transaction ID");
+ wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
+ wpabuf_put_le16(msg, 0);
+ goto skip_trans_id;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
/* Transaction ID */
wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
wpabuf_put_le16(msg, 1);
wpabuf_put_u8(msg, TRANSACTION_ID);
+#ifdef CONFIG_TESTING_OPTIONS
+skip_trans_id:
+ if (dpp_test == DPP_TEST_NO_CONNECTOR_PEER_DISC_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Connector");
+ goto skip_connector;
+ }
+ if (dpp_test == DPP_TEST_INVALID_CONNECTOR_PEER_DISC_REQ) {
+ char *connector;
+
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Connector");
+ connector = dpp_corrupt_connector_signature(
+ ssid->dpp_connector);
+ if (!connector) {
+ wpabuf_free(msg);
+ return -1;
+ }
+ wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
+ wpabuf_put_le16(msg, os_strlen(connector));
+ wpabuf_put_str(msg, connector);
+ os_free(connector);
+ goto skip_connector;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
/* DPP Connector */
wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
wpabuf_put_le16(msg, os_strlen(ssid->dpp_connector));
wpabuf_put_str(msg, ssid->dpp_connector);
+#ifdef CONFIG_TESTING_OPTIONS
+skip_connector:
+#endif /* CONFIG_TESTING_OPTIONS */
+
/* TODO: Timeout on AP response */
wait_time = wpa_s->max_remain_on_chan;
if (wait_time > 2000)
wait_time = 2000;
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(bss->bssid), bss->freq, DPP_PA_PEER_DISCOVERY_REQ);
offchannel_send_action(wpa_s, bss->freq, bss->bssid, wpa_s->own_addr,
broadcast,
wpabuf_head(msg), wpabuf_len(msg),
@@ -1879,7 +2092,7 @@
if (!pos)
return -1;
pos += 5;
- own_bi = dpp_bootstrap_get_id(wpa_s, atoi(pos));
+ own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
if (!own_bi) {
wpa_printf(MSG_DEBUG,
"DPP: Identified bootstrap info not found");
@@ -1891,6 +2104,7 @@
return -1;
}
wpa_s->dpp_pkex_bi = own_bi;
+ own_bi->pkex_t = 0; /* clear pending errors on new code */
os_free(wpa_s->dpp_pkex_identifier);
wpa_s->dpp_pkex_identifier = NULL;
@@ -1916,25 +2130,35 @@
return -1;
if (os_strstr(cmd, " init=1")) {
+ struct dpp_pkex *pkex;
struct wpabuf *msg;
wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX");
dpp_pkex_free(wpa_s->dpp_pkex);
- wpa_s->dpp_pkex = dpp_pkex_init(own_bi, wpa_s->own_addr,
+ wpa_s->dpp_pkex = dpp_pkex_init(wpa_s, own_bi, wpa_s->own_addr,
wpa_s->dpp_pkex_identifier,
wpa_s->dpp_pkex_code);
- if (!wpa_s->dpp_pkex)
+ pkex = wpa_s->dpp_pkex;
+ if (!pkex)
return -1;
- msg = wpa_s->dpp_pkex->exchange_req;
+ msg = pkex->exchange_req;
wait_time = wpa_s->max_remain_on_chan;
if (wait_time > 2000)
wait_time = 2000;
- /* TODO: Which channel to use? */
- offchannel_send_action(wpa_s, 2437, broadcast, wpa_s->own_addr,
- broadcast,
+ pkex->freq = 2437;
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d",
+ MAC2STR(broadcast), pkex->freq,
+ DPP_PA_PKEX_EXCHANGE_REQ);
+ offchannel_send_action(wpa_s, pkex->freq, broadcast,
+ wpa_s->own_addr, broadcast,
wpabuf_head(msg), wpabuf_len(msg),
wait_time, wpas_dpp_tx_pkex_status, 0);
+ if (wait_time == 0)
+ wait_time = 2000;
+ pkex->exch_req_wait_time = wait_time;
+ pkex->exch_req_tries = 1;
}
/* TODO: Support multiple PKEX info entries */
@@ -1976,6 +2200,17 @@
}
+void wpas_dpp_stop(struct wpa_supplicant *wpa_s)
+{
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ dpp_pkex_free(wpa_s->dpp_pkex);
+ wpa_s->dpp_pkex = NULL;
+ if (wpa_s->dpp_gas_client && wpa_s->dpp_gas_dialog_token >= 0)
+ gas_query_stop(wpa_s->gas, wpa_s->dpp_gas_dialog_token);
+}
+
+
int wpas_dpp_init(struct wpa_supplicant *wpa_s)
{
u8 adv_proto_id[7];
@@ -1990,10 +2225,8 @@
sizeof(adv_proto_id), wpas_dpp_gas_req_handler,
wpas_dpp_gas_status_handler, wpa_s) < 0)
return -1;
- dl_list_init(&wpa_s->dpp_bootstrap);
- dl_list_init(&wpa_s->dpp_configurator);
- wpa_s->dpp_init_done = 1;
- return 0;
+ wpa_s->dpp = dpp_global_init();
+ return wpa_s->dpp ? 0 : -1;
}
@@ -2008,17 +2241,22 @@
wpa_s->dpp_groups_override = NULL;
wpa_s->dpp_ignore_netaccesskey_mismatch = 0;
#endif /* CONFIG_TESTING_OPTIONS */
- if (!wpa_s->dpp_init_done)
+ 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);
+ eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
+#ifdef CONFIG_DPP2
+ eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
+ dpp_pfs_free(wpa_s->dpp_pfs);
+ wpa_s->dpp_pfs = NULL;
+#endif /* CONFIG_DPP2 */
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
- dpp_bootstrap_del(wpa_s, 0);
- dpp_configurator_del(wpa_s, 0);
- dpp_auth_deinit(wpa_s->dpp_auth);
- wpa_s->dpp_auth = NULL;
+ wpas_dpp_stop(wpa_s);
wpas_dpp_pkex_remove(wpa_s, "*");
- wpa_s->dpp_pkex = NULL;
os_memset(wpa_s->dpp_intro_bssid, 0, ETH_ALEN);
os_free(wpa_s->dpp_configurator_params);
wpa_s->dpp_configurator_params = NULL;
diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h
index 05a466d..ecb7a7d 100644
--- a/wpa_supplicant/dpp_supplicant.h
+++ b/wpa_supplicant/dpp_supplicant.h
@@ -10,26 +10,17 @@
#define DPP_SUPPLICANT_H
int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd);
-int wpas_dpp_bootstrap_gen(struct wpa_supplicant *wpa_s, const char *cmd);
-int wpas_dpp_bootstrap_remove(struct wpa_supplicant *wpa_s, const char *id);
-const char * wpas_dpp_bootstrap_get_uri(struct wpa_supplicant *wpa_s,
- unsigned int id);
-int wpas_dpp_bootstrap_info(struct wpa_supplicant *wpa_s, int id,
- char *reply, int reply_size);
int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd);
int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd);
void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s);
-void wpas_dpp_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
- unsigned int freq);
void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq);
void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
const u8 *buf, size_t len, unsigned int freq);
-int wpas_dpp_configurator_add(struct wpa_supplicant *wpa_s, const char *cmd);
-int wpas_dpp_configurator_remove(struct wpa_supplicant *wpa_s, const char *id);
int wpas_dpp_configurator_sign(struct wpa_supplicant *wpa_s, const char *cmd);
int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd);
int wpas_dpp_pkex_remove(struct wpa_supplicant *wpa_s, const char *id);
+void wpas_dpp_stop(struct wpa_supplicant *wpa_s);
int wpas_dpp_init(struct wpa_supplicant *wpa_s);
void wpas_dpp_deinit(struct wpa_supplicant *wpa_s);
int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index e131653..4a9f472 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -492,6 +492,14 @@
return -1;
}
+static inline int wpa_drv_channel_info(struct wpa_supplicant *wpa_s,
+ struct wpa_channel_info *ci)
+{
+ if (wpa_s->driver->channel_info)
+ return wpa_s->driver->channel_info(wpa_s->drv_priv, ci);
+ return -1;
+}
+
static inline int wpa_drv_pktcnt_poll(struct wpa_supplicant *wpa_s,
struct hostap_sta_driver_data *sta)
{
@@ -689,6 +697,14 @@
return wpa_s->driver->roaming(wpa_s->drv_priv, allowed, bssid);
}
+static inline int wpa_drv_disable_fils(struct wpa_supplicant *wpa_s,
+ int disable)
+{
+ if (!wpa_s->driver->disable_fils)
+ return -1;
+ return wpa_s->driver->disable_fils(wpa_s->drv_priv, disable);
+}
+
static inline int wpa_drv_set_mac_addr(struct wpa_supplicant *wpa_s,
const u8 *addr)
{
@@ -788,6 +804,14 @@
return wpa_s->driver->set_transmit_next_pn(wpa_s->drv_priv, sa);
}
+static inline int wpa_drv_set_receive_lowest_pn(struct wpa_supplicant *wpa_s,
+ struct receive_sa *sa)
+{
+ if (!wpa_s->driver->set_receive_lowest_pn)
+ return -1;
+ return wpa_s->driver->set_receive_lowest_pn(wpa_s->drv_priv, sa);
+}
+
static inline int
wpa_drv_create_receive_sc(struct wpa_supplicant *wpa_s, struct receive_sc *sc,
unsigned int conf_offset, int validation)
@@ -1028,4 +1052,22 @@
mask);
}
+static inline int
+wpa_drv_send_external_auth_status(struct wpa_supplicant *wpa_s,
+ struct external_auth *params)
+{
+ if (!wpa_s->driver->send_external_auth_status)
+ return -1;
+ return wpa_s->driver->send_external_auth_status(wpa_s->drv_priv,
+ params);
+}
+
+static inline int wpa_drv_set_4addr_mode(struct wpa_supplicant *wpa_s, int val)
+{
+ if (!wpa_s->driver->set_4addr_mode)
+ return -1;
+ return wpa_s->driver->set_4addr_mode(wpa_s->drv_priv,
+ wpa_s->bridge_ifname, val);
+}
+
#endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index 6548bd1..3fd4ce6 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -711,7 +711,8 @@
eap = (struct eap_hdr *) (hdr + 1);
eap->code = EAP_CODE_REQUEST;
- eap->identifier = 0;
+ if (os_get_random((u8 *) &eap->identifier, sizeof(eap->identifier)) < 0)
+ eap->identifier = os_random() & 0xff;
eap->length = htons(5);
pos = (u8 *) (eap + 1);
*pos = EAP_TYPE_IDENTITY;
diff --git a/wpa_supplicant/eapol_test.py b/wpa_supplicant/eapol_test.py
index 80e7dfc..734428d 100644
--- a/wpa_supplicant/eapol_test.py
+++ b/wpa_supplicant/eapol_test.py
@@ -136,7 +136,7 @@
results = res[i].get(False)
except:
results = "N/A"
- print "%d: %s" % (i, results)
+ print("%d: %s" % (i, results))
if __name__ == "__main__":
main()
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 63cf773..815b994 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Driver event processing
- * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -29,6 +29,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/gas_server.h"
+#include "common/dpp.h"
#include "crypto/random.h"
#include "blacklist.h"
#include "wpas_glue.h"
@@ -50,6 +51,9 @@
#include "dpp_supplicant.h"
+#define MAX_OWE_TRANSITION_BSS_SELECT_COUNT 5
+
+
#ifndef CONFIG_NO_SCAN_PROCESSING
static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
int new_scan, int own_request);
@@ -290,6 +294,13 @@
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
return;
+ if (os_reltime_initialized(&wpa_s->session_start)) {
+ os_reltime_age(&wpa_s->session_start, &wpa_s->session_length);
+ wpa_s->session_start.sec = 0;
+ wpa_s->session_start.usec = 0;
+ wpas_notify_session_length(wpa_s);
+ }
+
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
os_memset(wpa_s->bssid, 0, ETH_ALEN);
@@ -314,11 +325,16 @@
wpas_rrm_reset(wpa_s);
wpa_s->wnmsleep_used = 0;
+ wnm_clear_coloc_intf_reporting(wpa_s);
#ifdef CONFIG_TESTING_OPTIONS
wpa_s->last_tk_alg = WPA_ALG_NONE;
os_memset(wpa_s->last_tk, 0, sizeof(wpa_s->last_tk));
#endif /* CONFIG_TESTING_OPTIONS */
+ wpa_s->ieee80211ac = 0;
+
+ if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0)
+ wpa_s->enabled_4addr_mode = 0;
}
@@ -335,7 +351,7 @@
for (i = 0; i < ie.num_pmkid; i++) {
pmksa_set = pmksa_cache_set_current(wpa_s->wpa,
ie.pmkid + i * PMKID_LEN,
- NULL, NULL, 0, NULL);
+ NULL, NULL, 0, NULL, 0);
if (pmksa_set == 0) {
eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
break;
@@ -487,6 +503,11 @@
return 1;
#endif /* CONFIG_WPS */
+#ifdef CONFIG_OWE
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) && !ssid->owe_only)
+ return 1;
+#endif /* CONFIG_OWE */
+
if (has_wep_key(ssid))
privacy = 1;
@@ -530,7 +551,7 @@
(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA));
rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
- while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) {
+ while ((ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)) && rsn_ie) {
proto_match++;
if (wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) {
@@ -539,6 +560,10 @@
" skip RSN IE - parse failed");
break;
}
+ if (!ie.has_pairwise)
+ ie.pairwise_cipher = wpa_default_rsn_cipher(bss->freq);
+ if (!ie.has_group)
+ ie.group_cipher = wpa_default_rsn_cipher(bss->freq);
if (wep_ok &&
(ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
@@ -549,7 +574,8 @@
return 1;
}
- if (!(ie.proto & ssid->proto)) {
+ if (!(ie.proto & ssid->proto) &&
+ !(ssid->proto & WPA_PROTO_OSEN)) {
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG,
" skip RSN IE - proto mismatch");
@@ -622,7 +648,8 @@
}
#ifdef CONFIG_IEEE80211W
- if (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
+ if (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED &&
+ (!(ssid->key_mgmt & WPA_KEY_MGMT_OWE) || ssid->owe_only)) {
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG,
" skip - MFP Required but network not MFP Capable");
@@ -692,6 +719,29 @@
return 1;
}
+#ifdef CONFIG_OWE
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) && !ssid->owe_only &&
+ !wpa_ie && !rsn_ie) {
+ if (wpa_s->owe_transition_select &&
+ wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE) &&
+ ssid->owe_transition_bss_select_count + 1 <=
+ MAX_OWE_TRANSITION_BSS_SELECT_COUNT) {
+ ssid->owe_transition_bss_select_count++;
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip OWE transition BSS (selection count %d does not exceed %d)",
+ ssid->owe_transition_bss_select_count,
+ MAX_OWE_TRANSITION_BSS_SELECT_COUNT);
+ wpa_s->owe_transition_search = 1;
+ return 0;
+ }
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " allow in OWE transition mode");
+ return 1;
+ }
+#endif /* CONFIG_OWE */
+
if ((ssid->proto & (WPA_PROTO_WPA | WPA_PROTO_RSN)) &&
wpa_key_mgmt_wpa(ssid->key_mgmt) && proto_match == 0) {
if (debug_print)
@@ -968,18 +1018,22 @@
struct wpa_blacklist *e;
const u8 *ie;
struct wpa_ssid *ssid;
- int osen;
+ int osen, rsn_osen = 0;
#ifdef CONFIG_MBO
const u8 *assoc_disallow;
#endif /* CONFIG_MBO */
const u8 *match_ssid;
size_t match_ssid_len;
+ struct wpa_ie_data data;
ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
wpa_ie_len = ie ? ie[1] : 0;
ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
rsn_ie_len = ie ? ie[1] : 0;
+ if (ie && wpa_parse_wpa_ie_rsn(ie, 2 + ie[1], &data) == 0 &&
+ (data.key_mgmt & WPA_KEY_MGMT_OSEN))
+ rsn_osen = 1;
ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
osen = ie != NULL;
@@ -1137,6 +1191,7 @@
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,
@@ -1152,7 +1207,8 @@
continue;
}
- if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen) {
+ 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");
@@ -1294,10 +1350,10 @@
continue;
}
- if (wpa_is_bss_tmp_disallowed(wpa_s, bss->bssid)) {
+ if (wpa_is_bss_tmp_disallowed(wpa_s, bss)) {
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - MBO retry delay has not passed yet");
+ " skip - AP temporarily disallowed");
continue;
}
#ifdef CONFIG_TESTING_OPTIONS
@@ -1363,8 +1419,11 @@
for (i = 0; i < wpa_s->last_scan_res_used; i++) {
struct wpa_bss *bss = wpa_s->last_scan_res[i];
+
+ wpa_s->owe_transition_select = 1;
*selected_ssid = wpa_scan_res_match(wpa_s, i, bss, group,
only_first_ssid, 1);
+ wpa_s->owe_transition_select = 0;
if (!*selected_ssid)
continue;
wpa_dbg(wpa_s, MSG_DEBUG, " selected BSS " MACSTR
@@ -1845,7 +1904,7 @@
if (sme_proc_obss_scan(wpa_s) > 0)
goto scan_work_done;
- if (own_request &&
+ if (own_request && data &&
wpas_beacon_rep_scan_process(wpa_s, scan_res, &data->scan_info) > 0)
goto scan_work_done;
@@ -1911,6 +1970,7 @@
if (wpa_s->p2p_mgmt)
return 0; /* no normal connection on p2p_mgmt interface */
+ wpa_s->owe_transition_search = 0;
selected = wpa_supplicant_pick_network(wpa_s, &ssid);
#ifdef CONFIG_MESH
@@ -2012,6 +2072,17 @@
return 0;
}
#endif /* CONFIG_WPS */
+#ifdef CONFIG_OWE
+ if (wpa_s->owe_transition_search) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "OWE: Use shorter wait during transition mode search");
+ timeout_sec = 0;
+ timeout_usec = 500000;
+ wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
+ timeout_usec);
+ return 0;
+ }
+#endif /* CONFIG_OWE */
if (wpa_supplicant_req_sched_scan(wpa_s))
wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
timeout_usec);
@@ -2211,6 +2282,57 @@
#endif /* CONFIG_INTERWORKING */
+static void multi_ap_process_assoc_resp(struct wpa_supplicant *wpa_s,
+ const u8 *ies, size_t ies_len)
+{
+ struct ieee802_11_elems elems;
+ const u8 *map_sub_elem, *pos;
+ size_t len;
+
+ if (!wpa_s->current_ssid ||
+ !wpa_s->current_ssid->multi_ap_backhaul_sta ||
+ !ies ||
+ ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
+ return;
+
+ if (!elems.multi_ap || elems.multi_ap_len < 7) {
+ wpa_printf(MSG_INFO, "AP doesn't support Multi-AP protocol");
+ goto fail;
+ }
+
+ pos = elems.multi_ap + 4;
+ len = elems.multi_ap_len - 4;
+
+ map_sub_elem = get_ie(pos, len, MULTI_AP_SUB_ELEM_TYPE);
+ if (!map_sub_elem || map_sub_elem[1] < 1) {
+ wpa_printf(MSG_INFO, "invalid Multi-AP sub elem type");
+ goto fail;
+ }
+
+ if (!(map_sub_elem[2] & MULTI_AP_BACKHAUL_BSS)) {
+ if ((map_sub_elem[2] & MULTI_AP_FRONTHAUL_BSS) &&
+ wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+ wpa_printf(MSG_INFO,
+ "WPS active, accepting fronthaul-only BSS");
+ /* Don't set 4addr mode in this case, so just return */
+ return;
+ }
+ wpa_printf(MSG_INFO, "AP doesn't support backhaul BSS");
+ goto fail;
+ }
+
+ if (wpa_drv_set_4addr_mode(wpa_s, 1) < 0) {
+ wpa_printf(MSG_ERROR, "Failed to set 4addr mode");
+ goto fail;
+ }
+ wpa_s->enabled_4addr_mode = 1;
+ return;
+
+fail:
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+}
+
+
#ifdef CONFIG_FST
static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s,
const u8 *ie, size_t ie_len)
@@ -2260,9 +2382,9 @@
{
int l, len, found = 0, wpa_found, rsn_found;
const u8 *p;
-#ifdef CONFIG_IEEE80211R
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_OWE)
u8 bssid[ETH_ALEN];
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R || CONFIG_OWE */
wpa_dbg(wpa_s, MSG_DEBUG, "Association info event");
if (data->assoc_info.req_ies)
@@ -2283,6 +2405,13 @@
interworking_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len);
#endif /* CONFIG_INTERWORKING */
+ if (wpa_s->hw_capab == CAPAB_VHT &&
+ get_ie(data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len, WLAN_EID_VHT_CAP))
+ wpa_s->ieee80211ac = 1;
+
+ multi_ap_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len);
}
if (data->assoc_info.beacon_ies)
wpa_hexdump(MSG_DEBUG, "beacon_ies",
@@ -2292,6 +2421,26 @@
wpa_dbg(wpa_s, MSG_DEBUG, "freq=%u MHz",
data->assoc_info.freq);
+ wpa_s->connection_set = 0;
+ if (data->assoc_info.req_ies && data->assoc_info.resp_ies) {
+ struct ieee802_11_elems req_elems, resp_elems;
+
+ if (ieee802_11_parse_elems(data->assoc_info.req_ies,
+ data->assoc_info.req_ies_len,
+ &req_elems, 0) != ParseFailed &&
+ ieee802_11_parse_elems(data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len,
+ &resp_elems, 0) != ParseFailed) {
+ wpa_s->connection_set = 1;
+ wpa_s->connection_ht = req_elems.ht_capabilities &&
+ resp_elems.ht_capabilities;
+ wpa_s->connection_vht = req_elems.vht_capabilities &&
+ resp_elems.vht_capabilities;
+ wpa_s->connection_he = req_elems.he_capabilities &&
+ resp_elems.he_capabilities;
+ }
+ }
+
p = data->assoc_info.req_ies;
l = data->assoc_info.req_ies_len;
@@ -2350,6 +2499,28 @@
}
#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP2
+ wpa_sm_set_dpp_z(wpa_s->wpa, NULL);
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && wpa_s->dpp_pfs) {
+ struct ieee802_11_elems elems;
+
+ if (ieee802_11_parse_elems(data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len,
+ &elems, 0) == ParseFailed ||
+ !elems.owe_dh)
+ goto no_pfs;
+ if (dpp_pfs_process(wpa_s->dpp_pfs, elems.owe_dh,
+ elems.owe_dh_len) < 0) {
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_UNSPECIFIED);
+ return -1;
+ }
+
+ wpa_sm_set_dpp_z(wpa_s->wpa, wpa_s->dpp_pfs->secret);
+ }
+no_pfs:
+#endif /* CONFIG_DPP2 */
+
#ifdef CONFIG_IEEE80211R
#ifdef CONFIG_SME
if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) {
@@ -2588,6 +2759,16 @@
wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);
if (os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
+ if (os_reltime_initialized(&wpa_s->session_start)) {
+ os_reltime_age(&wpa_s->session_start,
+ &wpa_s->session_length);
+ wpa_s->session_start.sec = 0;
+ wpa_s->session_start.usec = 0;
+ wpas_notify_session_length(wpa_s);
+ } else {
+ wpas_notify_auth_changed(wpa_s);
+ os_get_reltime(&wpa_s->session_start);
+ }
wpa_dbg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID="
MACSTR, MAC2STR(bssid));
new_bss = 1;
@@ -2678,25 +2859,7 @@
}
wpa_supplicant_cancel_scan(wpa_s);
- if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
- wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
- /*
- * We are done; the driver will take care of RSN 4-way
- * handshake.
- */
- wpa_supplicant_cancel_auth_timeout(wpa_s);
- wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
- eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
- eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
- } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
- wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
- /*
- * The driver will take care of RSN 4-way handshake, so we need
- * to allow EAPOL supplicant to complete its work without
- * waiting for WPA supplicant.
- */
- eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
- } else if (ft_completed) {
+ if (ft_completed) {
/*
* FT protocol completed - make sure EAPOL state machine ends
* up in authenticated.
@@ -2705,6 +2868,24 @@
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+ } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
+ wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
+ /*
+ * We are done; the driver will take care of RSN 4-way
+ * handshake.
+ */
+ wpa_supplicant_cancel_auth_timeout(wpa_s);
+ wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+ eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+ eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+ } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) &&
+ wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
+ /*
+ * The driver will take care of RSN 4-way handshake, so we need
+ * to allow EAPOL supplicant to complete its work without
+ * waiting for WPA supplicant.
+ */
+ eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
}
wpa_s->last_eapol_matches_bssid = 0;
@@ -2950,7 +3131,7 @@
!disallowed_ssid(wpa_s, fast_reconnect->ssid,
fast_reconnect->ssid_len) &&
!wpas_temp_disabled(wpa_s, fast_reconnect_ssid) &&
- !wpa_is_bss_tmp_disallowed(wpa_s, fast_reconnect->bssid)) {
+ !wpa_is_bss_tmp_disallowed(wpa_s, fast_reconnect)) {
#ifndef CONFIG_NO_SCAN_PROCESSING
wpa_dbg(wpa_s, MSG_DEBUG, "Try to reconnect to the same BSS");
if (wpa_supplicant_connect(wpa_s, fast_reconnect,
@@ -3523,8 +3704,8 @@
}
-static void wpa_supplicant_update_channel_list(
- struct wpa_supplicant *wpa_s, struct channel_list_changed *info)
+void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s,
+ struct channel_list_changed *info)
{
struct wpa_supplicant *ifs;
u8 dfs_domain;
@@ -3538,10 +3719,13 @@
for (ifs = wpa_s; ifs->parent && ifs != ifs->parent; ifs = ifs->parent)
;
- wpa_msg(ifs, MSG_INFO, WPA_EVENT_REGDOM_CHANGE "init=%s type=%s%s%s",
- reg_init_str(info->initiator), reg_type_str(info->type),
- info->alpha2[0] ? " alpha2=" : "",
- info->alpha2[0] ? info->alpha2 : "");
+ if (info) {
+ wpa_msg(ifs, MSG_INFO,
+ WPA_EVENT_REGDOM_CHANGE "init=%s type=%s%s%s",
+ reg_init_str(info->initiator), reg_type_str(info->type),
+ info->alpha2[0] ? " alpha2=" : "",
+ info->alpha2[0] ? info->alpha2 : "");
+ }
if (wpa_s->drv_priv == NULL)
return; /* Ignore event during drv initialization */
@@ -3743,18 +3927,101 @@
}
-static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s,
- union wpa_event_data *data)
+static void wpa_supplicant_event_port_authorized(struct wpa_supplicant *wpa_s)
{
- wpa_dbg(wpa_s, MSG_DEBUG,
- "Connection authorized by device, previous state %d",
- wpa_s->wpa_state);
if (wpa_s->wpa_state == WPA_ASSOCIATED) {
wpa_supplicant_cancel_auth_timeout(wpa_s);
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
}
+}
+
+
+static unsigned int wpas_event_cac_ms(const struct wpa_supplicant *wpa_s,
+ int freq)
+{
+ size_t i;
+ int j;
+
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ const struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
+
+ for (j = 0; j < mode->num_channels; j++) {
+ const struct hostapd_channel_data *chan;
+
+ chan = &mode->channels[j];
+ if (chan->freq == freq)
+ return chan->dfs_cac_ms;
+ }
+ }
+
+ return 0;
+}
+
+
+static void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
+{
+#if defined(NEED_AP_MLME) && defined(CONFIG_AP)
+ if (wpa_s->ap_iface || wpa_s->ifmsh) {
+ wpas_ap_event_dfs_cac_started(wpa_s, radar);
+ } else
+#endif /* NEED_AP_MLME && CONFIG_AP */
+ {
+ unsigned int cac_time = wpas_event_cac_ms(wpa_s, radar->freq);
+
+ cac_time /= 1000; /* convert from ms to sec */
+ if (!cac_time)
+ cac_time = 10 * 60; /* max timeout: 10 minutes */
+
+ /* Restart auth timeout: CAC time added to initial timeout */
+ wpas_auth_timeout_restart(wpa_s, cac_time);
+ }
+}
+
+
+static void wpas_event_dfs_cac_finished(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
+{
+#if defined(NEED_AP_MLME) && defined(CONFIG_AP)
+ if (wpa_s->ap_iface || wpa_s->ifmsh) {
+ wpas_ap_event_dfs_cac_finished(wpa_s, radar);
+ } else
+#endif /* NEED_AP_MLME && CONFIG_AP */
+ {
+ /* Restart auth timeout with original value after CAC is
+ * finished */
+ wpas_auth_timeout_restart(wpa_s, 0);
+ }
+}
+
+
+static void wpas_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
+{
+#if defined(NEED_AP_MLME) && defined(CONFIG_AP)
+ if (wpa_s->ap_iface || wpa_s->ifmsh) {
+ wpas_ap_event_dfs_cac_aborted(wpa_s, radar);
+ } else
+#endif /* NEED_AP_MLME && CONFIG_AP */
+ {
+ /* Restart auth timeout with original value after CAC is
+ * aborted */
+ wpas_auth_timeout_restart(wpa_s, 0);
+ }
+}
+
+
+static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Connection authorized by device, previous state %d",
+ wpa_s->wpa_state);
+
+ wpa_supplicant_event_port_authorized(wpa_s);
+
wpa_sm_set_rx_replay_ctr(wpa_s->wpa, data->assoc_info.key_replay_ctr);
wpa_sm_set_ptk_kck_kek(wpa_s->wpa, data->assoc_info.ptk_kck,
data->assoc_info.ptk_kck_len,
@@ -3780,18 +4047,144 @@
/* Update the current PMKSA used for this connection */
pmksa_cache_set_current(wpa_s->wpa,
data->assoc_info.fils_pmkid,
- NULL, NULL, 0, NULL);
+ NULL, NULL, 0, NULL, 0);
}
}
#endif /* CONFIG_FILS */
}
+static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ const u8 *bssid = data->assoc_reject.bssid;
+
+ if (!bssid || is_zero_ether_addr(bssid))
+ bssid = wpa_s->pending_bssid;
+
+ if (data->assoc_reject.bssid)
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
+ "bssid=" MACSTR " status_code=%u%s%s%s",
+ MAC2STR(data->assoc_reject.bssid),
+ data->assoc_reject.status_code,
+ data->assoc_reject.timed_out ? " timeout" : "",
+ data->assoc_reject.timeout_reason ? "=" : "",
+ data->assoc_reject.timeout_reason ?
+ data->assoc_reject.timeout_reason : "");
+ else
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
+ "status_code=%u%s%s%s",
+ data->assoc_reject.status_code,
+ data->assoc_reject.timed_out ? " timeout" : "",
+ data->assoc_reject.timeout_reason ? "=" : "",
+ data->assoc_reject.timeout_reason ?
+ data->assoc_reject.timeout_reason : "");
+ wpa_s->assoc_status_code = data->assoc_reject.status_code;
+ wpa_s->assoc_timed_out = data->assoc_reject.timed_out;
+ wpas_notify_assoc_status_code(wpa_s);
+
+#ifdef CONFIG_OWE
+ if (data->assoc_reject.status_code ==
+ WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
+ wpa_s->key_mgmt == WPA_KEY_MGMT_OWE &&
+ wpa_s->current_ssid &&
+ wpa_s->current_ssid->owe_group == 0 &&
+ wpa_s->last_owe_group != 21) {
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct wpa_bss *bss = wpa_s->current_bss;
+
+ if (!bss) {
+ bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
+ if (!bss) {
+ wpas_connection_failed(wpa_s, bssid);
+ wpa_supplicant_mark_disassoc(wpa_s);
+ return;
+ }
+ }
+ wpa_printf(MSG_DEBUG, "OWE: Try next supported DH group");
+ wpas_connect_work_done(wpa_s);
+ wpa_supplicant_mark_disassoc(wpa_s);
+ wpa_supplicant_connect(wpa_s, bss, ssid);
+ return;
+ }
+#endif /* CONFIG_OWE */
+
+#ifdef CONFIG_MBO
+ if (data->assoc_reject.status_code ==
+ WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
+ wpa_s->current_bss && data->assoc_reject.bssid &&
+ data->assoc_reject.resp_ies) {
+ const u8 *rssi_rej;
+
+ rssi_rej = mbo_get_attr_from_ies(
+ data->assoc_reject.resp_ies,
+ data->assoc_reject.resp_ies_len,
+ OCE_ATTR_ID_RSSI_BASED_ASSOC_REJECT);
+ if (rssi_rej && rssi_rej[1] == 2) {
+ wpa_printf(MSG_DEBUG,
+ "OCE: RSSI-based association rejection from "
+ MACSTR " (Delta RSSI: %u, Retry Delay: %u)",
+ MAC2STR(data->assoc_reject.bssid),
+ rssi_rej[2], rssi_rej[3]);
+ wpa_bss_tmp_disallow(wpa_s,
+ data->assoc_reject.bssid,
+ rssi_rej[3],
+ rssi_rej[2] +
+ wpa_s->current_bss->level);
+ }
+ }
+#endif /* CONFIG_MBO */
+
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) {
+ sme_event_assoc_reject(wpa_s, data);
+ return;
+ }
+
+ /* Driver-based SME cases */
+
+#ifdef CONFIG_SAE
+ if (wpa_s->current_ssid &&
+ wpa_key_mgmt_sae(wpa_s->current_ssid->key_mgmt) &&
+ !data->assoc_reject.timed_out) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "SAE: Drop PMKSA cache entry");
+ wpa_sm_aborted_cached(wpa_s->wpa);
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, wpa_s->current_ssid);
+ }
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_DPP
+ if (wpa_s->current_ssid &&
+ wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_DPP &&
+ !data->assoc_reject.timed_out) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "DPP: Drop PMKSA cache entry");
+ wpa_sm_aborted_cached(wpa_s->wpa);
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, wpa_s->current_ssid);
+ }
+#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_FILS
+ /* Update ERP next sequence number */
+ if (wpa_s->auth_alg == WPA_AUTH_ALG_FILS) {
+ eapol_sm_update_erp_next_seq_num(
+ wpa_s->eapol,
+ data->assoc_reject.fils_erp_next_seq_num);
+ fils_connection_failure(wpa_s);
+ }
+#endif /* CONFIG_FILS */
+
+ wpas_connection_failed(wpa_s, bssid);
+ wpa_supplicant_mark_disassoc(wpa_s);
+}
+
+
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
struct wpa_supplicant *wpa_s = ctx;
int resched;
+#ifndef CONFIG_NO_STDOUT_DEBUG
+ int level = MSG_DEBUG;
+#endif /* CONFIG_NO_STDOUT_DEBUG */
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED &&
event != EVENT_INTERFACE_ENABLED &&
@@ -3805,9 +4198,6 @@
}
#ifndef CONFIG_NO_STDOUT_DEBUG
-{
- int level = MSG_DEBUG;
-
if (event == EVENT_RX_MGMT && data->rx_mgmt.frame_len >= 24) {
const struct ieee80211_hdr *hdr;
u16 fc;
@@ -3820,7 +4210,6 @@
wpa_dbg(wpa_s, level, "Event %s (%d) received",
event_to_string(event), event);
-}
#endif /* CONFIG_NO_STDOUT_DEBUG */
switch (event) {
@@ -3832,6 +4221,8 @@
"FST: MB IEs updated from auth IE");
#endif /* CONFIG_FST */
sme_event_auth(wpa_s, data);
+ wpa_s->auth_status_code = data->auth.status_code;
+ wpas_notify_auth_status_code(wpa_s);
break;
case EVENT_ASSOC:
#ifdef CONFIG_TESTING_OPTIONS
@@ -3847,6 +4238,7 @@
}
#endif /* CONFIG_TESTING_OPTIONS */
wpa_supplicant_event_assoc(wpa_s, data);
+ wpa_s->assoc_status_code = WLAN_STATUS_SUCCESS;
if (data &&
(data->assoc_info.authorized ||
(!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
@@ -3967,44 +4359,7 @@
break;
#endif /* CONFIG_IBSS_RSN */
case EVENT_ASSOC_REJECT:
- if (data->assoc_reject.bssid)
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
- "bssid=" MACSTR " status_code=%u%s%s%s",
- MAC2STR(data->assoc_reject.bssid),
- data->assoc_reject.status_code,
- data->assoc_reject.timed_out ? " timeout" : "",
- data->assoc_reject.timeout_reason ? "=" : "",
- data->assoc_reject.timeout_reason ?
- data->assoc_reject.timeout_reason : "");
- else
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
- "status_code=%u%s%s%s",
- data->assoc_reject.status_code,
- data->assoc_reject.timed_out ? " timeout" : "",
- data->assoc_reject.timeout_reason ? "=" : "",
- data->assoc_reject.timeout_reason ?
- data->assoc_reject.timeout_reason : "");
- wpa_s->assoc_status_code = data->assoc_reject.status_code;
- wpa_s->assoc_timed_out = data->assoc_reject.timed_out;
- wpas_notify_assoc_status_code(wpa_s);
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
- sme_event_assoc_reject(wpa_s, data);
- else {
- const u8 *bssid = data->assoc_reject.bssid;
-
-#ifdef CONFIG_FILS
- /* Update ERP next sequence number */
- if (wpa_s->auth_alg == WPA_AUTH_ALG_FILS)
- eapol_sm_update_erp_next_seq_num(
- wpa_s->eapol,
- data->assoc_reject.fils_erp_next_seq_num);
-#endif /* CONFIG_FILS */
-
- if (bssid == NULL || is_zero_ether_addr(bssid))
- bssid = wpa_s->pending_bssid;
- wpas_connection_failed(wpa_s, bssid);
- wpa_supplicant_mark_disassoc(wpa_s);
- }
+ wpas_event_assoc_reject(wpa_s, data);
break;
case EVENT_AUTH_TIMED_OUT:
/* It is possible to get this event from earlier connection */
@@ -4106,6 +4461,7 @@
ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.addr,
data->rx_from_unknown.wds);
break;
+#endif /* CONFIG_AP */
case EVENT_CH_SWITCH:
if (!data || !wpa_s->current_ssid)
break;
@@ -4122,8 +4478,10 @@
wpa_s->assoc_freq = data->ch_switch.freq;
wpa_s->current_ssid->frequency = data->ch_switch.freq;
+#ifdef CONFIG_AP
if (wpa_s->current_ssid->mode == WPAS_MODE_AP ||
wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO ||
+ wpa_s->current_ssid->mode == WPAS_MODE_MESH ||
wpa_s->current_ssid->mode ==
WPAS_MODE_P2P_GROUP_FORMATION) {
wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
@@ -4133,14 +4491,28 @@
data->ch_switch.cf1,
data->ch_switch.cf2);
}
+#endif /* CONFIG_AP */
+#ifdef CONFIG_IEEE80211W
+ sme_event_ch_switch(wpa_s);
+#endif /* CONFIG_IEEE80211W */
wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_CS);
+ wnm_clear_coloc_intf_reporting(wpa_s);
break;
+#ifdef CONFIG_AP
#ifdef NEED_AP_MLME
case EVENT_DFS_RADAR_DETECTED:
if (data)
- wpas_event_dfs_radar_detected(wpa_s, &data->dfs_event);
+ wpas_ap_event_dfs_radar_detected(wpa_s,
+ &data->dfs_event);
break;
+ case EVENT_DFS_NOP_FINISHED:
+ if (data)
+ wpas_ap_event_dfs_cac_nop_finished(wpa_s,
+ &data->dfs_event);
+ break;
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_AP */
case EVENT_DFS_CAC_STARTED:
if (data)
wpas_event_dfs_cac_started(wpa_s, &data->dfs_event);
@@ -4153,13 +4525,6 @@
if (data)
wpas_event_dfs_cac_aborted(wpa_s, &data->dfs_event);
break;
- case EVENT_DFS_NOP_FINISHED:
- if (data)
- wpas_event_dfs_cac_nop_finished(wpa_s,
- &data->dfs_event);
- break;
-#endif /* NEED_AP_MLME */
-#endif /* CONFIG_AP */
case EVENT_RX_MGMT: {
u16 fc, stype;
const struct ieee80211_mgmt *mgmt;
@@ -4231,6 +4596,16 @@
break;
}
+#ifdef CONFIG_SAE
+ if (stype == WLAN_FC_STYPE_AUTH &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
+ sme_external_auth_mgmt_rx(
+ wpa_s, data->rx_mgmt.frame,
+ data->rx_mgmt.frame_len);
+ break;
+ }
+#endif /* CONFIG_SAE */
wpa_dbg(wpa_s, MSG_DEBUG, "AP: ignore received "
"management frame in non-AP mode");
break;
@@ -4320,6 +4695,9 @@
data->signal_change.current_noise,
data->signal_change.current_txrate);
break;
+ case EVENT_INTERFACE_MAC_CHANGED:
+ wpa_supplicant_update_mac_addr(wpa_s);
+ break;
case EVENT_INTERFACE_ENABLED:
wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled");
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
@@ -4390,7 +4768,8 @@
wpa_s, WLAN_REASON_DEAUTH_LEAVING, 1);
}
wpa_supplicant_mark_disassoc(wpa_s);
- wpa_bss_flush(wpa_s);
+ if (!wpa_s->conf->bss_no_flush_when_down)
+ wpa_bss_flush(wpa_s);
radio_remove_works(wpa_s, NULL, 0);
wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
@@ -4486,7 +4865,7 @@
break;
case EVENT_WPS_BUTTON_PUSHED:
#ifdef CONFIG_WPS
- wpas_wps_start_pbc(wpa_s, NULL, 0);
+ wpas_wps_start_pbc(wpa_s, NULL, 0, 0);
#endif /* CONFIG_WPS */
break;
case EVENT_AVOID_FREQUENCIES:
@@ -4543,6 +4922,30 @@
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_BEACON_LOSS);
bgscan_notify_beacon_loss(wpa_s);
break;
+ case EVENT_EXTERNAL_AUTH:
+#ifdef CONFIG_SAE
+ if (!wpa_s->current_ssid) {
+ wpa_printf(MSG_DEBUG, "SAE: current_ssid is NULL");
+ break;
+ }
+ sme_external_auth_trigger(wpa_s, data);
+#endif /* CONFIG_SAE */
+ break;
+ case EVENT_PORT_AUTHORIZED:
+ wpa_supplicant_event_port_authorized(wpa_s);
+ break;
+ case EVENT_STATION_OPMODE_CHANGED:
+#ifdef CONFIG_AP
+ if (!wpa_s->ap_iface || !data)
+ break;
+
+ hostapd_event_sta_opmode_changed(wpa_s->ap_iface->bss[0],
+ data->sta_opmode.addr,
+ data->sta_opmode.smps_mode,
+ data->sta_opmode.chan_width,
+ data->sta_opmode.rx_nss);
+#endif /* CONFIG_AP */
+ break;
default:
wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
break;
diff --git a/wpa_supplicant/examples/dbus-listen-preq.py b/wpa_supplicant/examples/dbus-listen-preq.py
index 5ac9859..337519f 100755
--- a/wpa_supplicant/examples/dbus-listen-preq.py
+++ b/wpa_supplicant/examples/dbus-listen-preq.py
@@ -1,5 +1,6 @@
#!/usr/bin/python
+from __future__ import print_function
import dbus
import sys
import time
@@ -12,21 +13,24 @@
WPAS_DBUS_INTERFACES_INTERFACE = "fi.w1.wpa_supplicant1.Interface"
def usage():
- print "Usage: %s <ifname>" % sys.argv[0]
- print "Press Ctrl-C to stop"
+ print("Usage: %s <ifname>" % sys.argv[0])
+ print("Press Ctrl-C to stop")
def ProbeRequest(args):
if 'addr' in args:
- print '%.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['addr']),
+ print('%.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['addr']),
+ end=' ')
if 'dst' in args:
- print '-> %.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['dst']),
+ print('-> %.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['dst']),
+ end=' ')
if 'bssid' in args:
- print '(bssid %.2x:%.2x:%.2x:%.2x:%.2x:%.2x)' % tuple(args['dst']),
+ print('(bssid %.2x:%.2x:%.2x:%.2x:%.2x:%.2x)' % tuple(args['dst']),
+ end=' ')
if 'signal' in args:
- print 'signal:%d' % args['signal'],
+ print('signal:%d' % args['signal'], end=' ')
if 'ies' in args:
- print 'have IEs (%d bytes)' % len(args['ies']),
- print ''
+ print('have IEs (%d bytes)' % len(args['ies']), end=' ')
+ print('')
if __name__ == "__main__":
global bus
diff --git a/wpa_supplicant/examples/dpp-qrcode.py b/wpa_supplicant/examples/dpp-qrcode.py
index e2a00c9..b468d15 100644
--- a/wpa_supplicant/examples/dpp-qrcode.py
+++ b/wpa_supplicant/examples/dpp-qrcode.py
@@ -24,19 +24,19 @@
if os.path.isdir(wpas_ctrl):
try:
ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
- except OSError, error:
- print "Could not find wpa_supplicant: ", error
+ except OSError as error:
+ print("Could not find wpa_supplicant: ", error)
return None
if len(ifaces) < 1:
- print "No wpa_supplicant control interface found"
+ print("No wpa_supplicant control interface found")
return None
for ctrl in ifaces:
try:
wpas = wpaspy.Ctrl(ctrl)
return wpas
- except Exception, e:
+ except Exception as e:
pass
return None
@@ -55,27 +55,27 @@
continue
if not uri.startswith('DPP:'):
continue
- print "Found DPP bootstrap info URI:"
- print uri
+ print("Found DPP bootstrap info URI:")
+ print(uri)
wpas = wpas_connect()
if not wpas:
- print "Could not connect to wpa_supplicant"
- print
+ print("Could not connect to wpa_supplicant")
+ print('')
continue
res = wpas.request("DPP_QR_CODE " + uri);
try:
id = int(res)
except ValueError:
- print "QR Code URI rejected"
+ print("QR Code URI rejected")
continue
- print "QR Code URI accepted - ID=%d" % id
- print wpas.request("DPP_BOOTSTRAP_INFO %d" % id)
+ print("QR Code URI accepted - ID=%d" % id)
+ print(wpas.request("DPP_BOOTSTRAP_INFO %d" % id))
del wpas
def dpp_display(curve):
wpas = wpas_connect()
if not wpas:
- print "Could not connect to wpa_supplicant"
+ print("Could not connect to wpa_supplicant")
return
res = wpas.request("STATUS")
addr = None
@@ -93,18 +93,18 @@
try:
id = int(res)
except ValueError:
- print "Failed to generate bootstrap info URI"
+ print("Failed to generate bootstrap info URI")
return
- print "Bootstrap information - ID=%d" % id
- print wpas.request("DPP_BOOTSTRAP_INFO %d" % id)
+ print("Bootstrap information - ID=%d" % id)
+ print(wpas.request("DPP_BOOTSTRAP_INFO %d" % id))
uri = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % id)
- print uri
- print "ID=%d" % id
+ print(uri)
+ print("ID=%d" % id)
qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_M,
border=3)
qr.add_data(uri, optimize=5)
qr.print_ascii(tty=True)
- print "ID=%d" % id
+ print("ID=%d" % id)
del wpas
def main():
diff --git a/wpa_supplicant/examples/p2p-nfc.py b/wpa_supplicant/examples/p2p-nfc.py
index 91eba28..889ac8b 100644
--- a/wpa_supplicant/examples/p2p-nfc.py
+++ b/wpa_supplicant/examples/p2p-nfc.py
@@ -37,7 +37,7 @@
success_file = None
def summary(txt):
- print txt
+ print(txt)
if summary_file:
with open(summary_file, 'a') as f:
f.write(txt + "\n")
@@ -53,12 +53,12 @@
if os.path.isdir(wpas_ctrl):
try:
ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
- except OSError, error:
- print "Could not find wpa_supplicant: ", error
+ except OSError as error:
+ print("Could not find wpa_supplicant: ", error)
return None
if len(ifaces) < 1:
- print "No wpa_supplicant control interface found"
+ print("No wpa_supplicant control interface found")
return None
for ctrl in ifaces:
@@ -66,10 +66,10 @@
if ifname not in ctrl:
continue
try:
- print "Trying to use control interface " + ctrl
+ print("Trying to use control interface " + ctrl)
wpas = wpaspy.Ctrl(ctrl)
return wpas
- except Exception, e:
+ except Exception as e:
pass
return None
@@ -160,30 +160,30 @@
if (data == None):
summary("Could not get handover request carrier record from wpa_supplicant")
return
- print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
+ print("Handover request carrier record from wpa_supplicant: " + data.encode("hex"))
datamsg = nfc.ndef.Message(data)
message.add_carrier(datamsg[0], "active", datamsg[1:])
global include_wps_req
if include_wps_req:
- print "Handover request (pre-WPS):"
+ print("Handover request (pre-WPS):")
try:
- print message.pretty()
- except Exception, e:
- print e
+ print(message.pretty())
+ except Exception as e:
+ print(e)
data = wpas_get_handover_req_wps()
if data:
- print "Add WPS request in addition to P2P"
+ print("Add WPS request in addition to P2P")
datamsg = nfc.ndef.Message(data)
message.add_carrier(datamsg[0], "active", datamsg[1:])
- print "Handover request:"
+ print("Handover request:")
try:
- print message.pretty()
- except Exception, e:
- print e
- print str(message).encode("hex")
+ print(message.pretty())
+ except Exception as e:
+ print(e)
+ print(str(message).encode("hex"))
client = nfc.handover.HandoverClient(llc)
try:
@@ -194,7 +194,7 @@
summary("Handover connection refused")
client.close()
return
- except Exception, e:
+ except Exception as e:
summary("Other exception: " + str(e))
client.close()
return
@@ -217,41 +217,41 @@
client.close()
return
- print "Received message"
+ print("Received message")
try:
- print message.pretty()
- except Exception, e:
- print e
- print str(message).encode("hex")
+ print(message.pretty())
+ except Exception as e:
+ print(e)
+ print(str(message).encode("hex"))
message = nfc.ndef.HandoverSelectMessage(message)
summary("Handover select received")
try:
- print message.pretty()
- except Exception, e:
- print e
+ print(message.pretty())
+ except Exception as e:
+ print(e)
for carrier in message.carriers:
- print "Remote carrier type: " + carrier.type
+ print("Remote carrier type: " + carrier.type)
if carrier.type == "application/vnd.wfa.p2p":
- print "P2P carrier type match - send to wpa_supplicant"
+ print("P2P carrier type match - send to wpa_supplicant")
if "OK" in wpas_report_handover(data, carrier.record, "INIT"):
success_report("P2P handover reported successfully (initiator)")
else:
summary("P2P handover report rejected")
break
- print "Remove peer"
+ print("Remove peer")
client.close()
- print "Done with handover"
+ print("Done with handover")
global only_one
if only_one:
- print "only_one -> stop loop"
+ print("only_one -> stop loop")
global continue_loop
continue_loop = False
global no_wait
if no_wait:
- print "Trying to exit.."
+ print("Trying to exit..")
global terminate_now
terminate_now = True
@@ -283,33 +283,33 @@
def process_request(self, request):
self.ho_server_processing = True
clear_raw_mode()
- print "HandoverServer - request received"
+ print("HandoverServer - request received")
try:
- print "Parsed handover request: " + request.pretty()
- except Exception, e:
- print e
+ print("Parsed handover request: " + request.pretty())
+ except Exception as e:
+ print(e)
sel = nfc.ndef.HandoverSelectMessage(version="1.2")
found = False
for carrier in request.carriers:
- print "Remote carrier type: " + carrier.type
+ print("Remote carrier type: " + carrier.type)
if carrier.type == "application/vnd.wfa.p2p":
- print "P2P carrier type match - add P2P carrier record"
+ print("P2P carrier type match - add P2P carrier record")
found = True
self.received_carrier = carrier.record
- print "Carrier record:"
+ print("Carrier record:")
try:
- print carrier.record.pretty()
- except Exception, e:
- print e
+ print(carrier.record.pretty())
+ except Exception as e:
+ print(e)
data = wpas_get_handover_sel()
if data is None:
- print "Could not get handover select carrier record from wpa_supplicant"
+ print("Could not get handover select carrier record from wpa_supplicant")
continue
- print "Handover select carrier record from wpa_supplicant:"
- print data.encode("hex")
+ print("Handover select carrier record from wpa_supplicant:")
+ print(data.encode("hex"))
self.sent_carrier = data
if "OK" in wpas_report_handover(self.received_carrier, self.sent_carrier, "RESP"):
success_report("P2P handover reported successfully (responder)")
@@ -324,22 +324,22 @@
for carrier in request.carriers:
if found:
break
- print "Remote carrier type: " + carrier.type
+ print("Remote carrier type: " + carrier.type)
if carrier.type == "application/vnd.wfa.wsc":
- print "WSC carrier type match - add WSC carrier record"
+ print("WSC carrier type match - add WSC carrier record")
found = True
self.received_carrier = carrier.record
- print "Carrier record:"
+ print("Carrier record:")
try:
- print carrier.record.pretty()
- except Exception, e:
- print e
+ print(carrier.record.pretty())
+ except Exception as e:
+ print(e)
data = wpas_get_handover_sel_wps()
if data is None:
- print "Could not get handover select carrier record from wpa_supplicant"
+ print("Could not get handover select carrier record from wpa_supplicant")
continue
- print "Handover select carrier record from wpa_supplicant:"
- print data.encode("hex")
+ print("Handover select carrier record from wpa_supplicant:")
+ print(data.encode("hex"))
self.sent_carrier = data
if "OK" in wpas_report_handover_wsc(self.received_carrier, self.sent_carrier, "RESP"):
success_report("WSC handover reported successfully")
@@ -352,12 +352,12 @@
found = True
break
- print "Handover select:"
+ print("Handover select:")
try:
- print sel.pretty()
- except Exception, e:
- print e
- print str(sel).encode("hex")
+ print(sel.pretty())
+ except Exception as e:
+ print(e)
+ print(str(sel).encode("hex"))
summary("Sending handover select")
self.success = True
@@ -396,7 +396,7 @@
success = False
if len(tag.ndef.message):
for record in tag.ndef.message:
- print "record type " + record.type
+ print("record type " + record.type)
if record.type == "application/vnd.wfa.wsc":
summary("WPS tag - send to wpa_supplicant")
success = wpas_tag_read(tag.ndef.message)
@@ -419,7 +419,7 @@
global p2p_sel_data
tag.ndef.message = str(p2p_sel_data)
success_report("Tag write succeeded")
- print "Done - remove tag"
+ print("Done - remove tag")
global only_one
if only_one:
global continue_loop
@@ -428,7 +428,7 @@
return p2p_sel_wait_remove
def wps_write_p2p_handover_sel(clf, wait_remove=True):
- print "Write P2P handover select"
+ print("Write P2P handover select")
data = wpas_get_handover_sel(tag=True)
if (data == None):
summary("Could not get P2P handover select from wpa_supplicant")
@@ -440,14 +440,14 @@
p2p_sel_data = nfc.ndef.HandoverSelectMessage(version="1.2")
message = nfc.ndef.Message(data);
p2p_sel_data.add_carrier(message[0], "active", message[1:])
- print "Handover select:"
+ print("Handover select:")
try:
- print p2p_sel_data.pretty()
- except Exception, e:
- print e
- print str(p2p_sel_data).encode("hex")
+ print(p2p_sel_data.pretty())
+ except Exception as e:
+ print(e)
+ print(str(p2p_sel_data).encode("hex"))
- print "Touch an NFC tag"
+ print("Touch an NFC tag")
clf.connect(rdwr={'on-connect': rdwr_connected_p2p_write})
@@ -456,11 +456,11 @@
summary("Tag connected: " + str(tag))
if tag.ndef:
- print "NDEF tag: " + tag.type
+ print("NDEF tag: " + tag.type)
try:
- print tag.ndef.message.pretty()
- except Exception, e:
- print e
+ print(tag.ndef.message.pretty())
+ except Exception as e:
+ print(e)
success = p2p_tag_read(tag)
if only_one and success:
global continue_loop
@@ -475,15 +475,15 @@
def llcp_worker(llc):
global init_on_touch
if init_on_touch:
- print "Starting handover client"
+ print("Starting handover client")
p2p_handover_client(llc)
return
global no_input
if no_input:
- print "Wait for handover to complete"
+ print("Wait for handover to complete")
else:
- print "Wait for handover to complete - press 'i' to initiate ('w' for WPS only, 'p' for P2P only)"
+ print("Wait for handover to complete - press 'i' to initiate ('w' for WPS only, 'p' for P2P only)")
global srv
global wait_connection
while not wait_connection and srv.sent_carrier is None:
@@ -506,21 +506,21 @@
else:
continue
clear_raw_mode()
- print "Starting handover client"
+ print("Starting handover client")
p2p_handover_client(llc)
return
clear_raw_mode()
- print "Exiting llcp_worker thread"
+ print("Exiting llcp_worker thread")
def llcp_startup(clf, llc):
- print "Start LLCP server"
+ print("Start LLCP server")
global srv
srv = HandoverServer(llc)
return llc
def llcp_connected(llc):
- print "P2P LLCP connected"
+ print("P2P LLCP connected")
global wait_connection
wait_connection = False
global init_on_touch
@@ -587,7 +587,7 @@
if args.ifname:
global ifname
ifname = args.ifname
- print "Selected ifname " + ifname
+ print("Selected ifname " + ifname)
if args.no_wps_req:
global include_wps_req
@@ -610,7 +610,7 @@
try:
if not clf.open("usb"):
- print "Could not open connection with an NFC device"
+ print("Could not open connection with an NFC device")
raise SystemExit
if args.command == "write-p2p-sel":
@@ -619,7 +619,7 @@
global continue_loop
while continue_loop:
- print "Waiting for a tag or peer to be touched"
+ print("Waiting for a tag or peer to be touched")
wait_connection = True
try:
if args.tag_read_only:
@@ -636,8 +636,8 @@
'on-connect': llcp_connected},
terminate=terminate_loop):
break
- except Exception, e:
- print "clf.connect failed"
+ except Exception as e:
+ print("clf.connect failed")
global srv
if only_one and srv and srv.success:
diff --git a/wpa_supplicant/examples/p2p/p2p_connect.py b/wpa_supplicant/examples/p2p/p2p_connect.py
index 59b0a9d..6e3d94e 100644
--- a/wpa_supplicant/examples/p2p/p2p_connect.py
+++ b/wpa_supplicant/examples/p2p/p2p_connect.py
@@ -13,40 +13,40 @@
def usage():
- print "Usage:"
- print " %s -i <interface_name> -m <wps_method> \ " \
- % sys.argv[0]
- print " -a <addr> [-p <pin>] [-g <go_intent>] \ "
- print " [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -m = wps method"
- print " -a = peer address"
- print " -p = pin number (8 digits)"
- print " -g = group owner intent"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i wlan0 -a 0015008352c0 -m display -p 12345670" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> -m <wps_method> \ " \
+ % sys.argv[0])
+ print(" -a <addr> [-p <pin>] [-g <go_intent>] \ ")
+ print(" [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -m = wps method")
+ print(" -a = peer address")
+ print(" -p = pin number (8 digits)")
+ print(" -g = group owner intent")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i wlan0 -a 0015008352c0 -m display -p 12345670" % sys.argv[0])
# Required Signals
def GONegotiationSuccess(status):
- print "Go Negotiation Success"
+ print("Go Negotiation Success")
def GONegotiationFailure(status):
- print 'Go Negotiation Failed. Status:'
- print format(status)
+ print('Go Negotiation Failed. Status:')
+ print(format(status))
os._exit(0)
def GroupStarted(properties):
if properties.has_key("group_object"):
- print 'Group Formation Complete %s' \
- % properties["group_object"]
+ print('Group Formation Complete %s' \
+ % properties["group_object"])
os._exit(0)
def WpsFailure(status, etc):
- print "WPS Authentication Failure".format(status)
- print etc
+ print("WPS Authentication Failure".format(status))
+ print(etc)
os._exit(0)
class P2P_Connect():
@@ -118,7 +118,7 @@
{'Ifname': ifname, 'Driver': 'test'})
time.sleep(1)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
if not str(exc).startswith(
self.wpas_dbus_interface + \
".InterfaceExists:"):
@@ -157,12 +157,12 @@
if (self.pin != None):
self.p2p_connect_arguements.update({'pin':self.pin})
else:
- print "Error:\n Pin required for wps_method=display"
+ print("Error:\n Pin required for wps_method=display")
usage()
quit()
if (self.go_intent != None and int(self.go_intent) != 15):
- print "go_intent overwritten to 15"
+ print("go_intent overwritten to 15")
self.go_intent = '15'
@@ -171,14 +171,14 @@
if (self.pin != None):
self.p2p_connect_arguements.update({'pin':self.pin})
else:
- print "Error:\n Pin required for wps_method=keypad"
+ print("Error:\n Pin required for wps_method=keypad")
usage()
quit()
if (self.go_intent != None and int(self.go_intent) == 15):
error = "Error :\n Group Owner intent cannot be" + \
" 15 for wps_method=keypad"
- print error
+ print(error)
usage()
quit()
@@ -186,15 +186,15 @@
# for ./wpa_cli, p2p_connect [mac] [pin#], wps_method=keypad
elif (self.wps_method == 'pin'):
if (self.pin != None):
- print "pin ignored"
+ print("pin ignored")
# No pin is required for pbc so it is ignored
elif (self.wps_method == 'pbc'):
if (self.pin != None):
- print "pin ignored"
+ print("pin ignored")
else:
- print "Error:\n wps_method not supported or does not exist"
+ print("Error:\n wps_method not supported or does not exist")
usage()
quit()
@@ -209,12 +209,12 @@
result_pin = self.p2p_interface.Connect(
self.p2p_connect_arguements)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
raise exc
if (self.wps_method == 'pin' and \
not self.p2p_connect_arguements.has_key('pin') ):
- print "Connect return with pin value of %d " % int(result_pin)
+ print("Connect return with pin value of %d " % int(result_pin))
gobject.MainLoop().run()
if __name__ == "__main__":
@@ -268,19 +268,19 @@
# Required Arguements check
if (interface_name == None or wps_method == None or addr == None):
- print "Error:\n Required arguements not specified"
+ print("Error:\n Required arguements not specified")
usage()
quit()
# Group Owner Intent Check
if (go_intent != None and (int(go_intent) > 15 or int(go_intent) < 0) ):
- print "Error:\n Group Owner Intent must be between 0 and 15 inclusive"
+ print("Error:\n Group Owner Intent must be between 0 and 15 inclusive")
usage()
quit()
# Pin Check
if (pin != None and len(pin) != 8):
- print "Error:\n Pin is not 8 digits"
+ print("Error:\n Pin is not 8 digits")
usage()
quit()
@@ -289,7 +289,7 @@
addr,pin,wps_method,go_intent)
except:
- print "Error:\n Invalid Arguements"
+ print("Error:\n Invalid Arguements")
usage()
quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_disconnect.py b/wpa_supplicant/examples/p2p/p2p_disconnect.py
index c3e39b3..85b5a8b 100644
--- a/wpa_supplicant/examples/p2p/p2p_disconnect.py
+++ b/wpa_supplicant/examples/p2p/p2p_disconnect.py
@@ -12,19 +12,19 @@
from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> \ " \
- % sys.argv[0]
- print " [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i p2p-wlan0-0" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> \ " \
+ % sys.argv[0])
+ print(" [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i p2p-wlan0-0" % sys.argv[0])
# Required Signals
def GroupFinished(status, etc):
- print "Disconnected"
+ print("Disconnected")
os._exit(0)
class P2P_Disconnect (threading.Thread):
@@ -81,10 +81,10 @@
try:
self.path = self.wpas.GetInterface(
self.interface_name)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
error = 'Error:\n Interface ' + self.interface_name \
+ ' was not found'
- print error
+ print(error)
usage()
os._exit(0)
@@ -142,7 +142,7 @@
# Interface name is required and was not given
if (interface_name == None):
- print "Error:\n interface_name is required"
+ print("Error:\n interface_name is required")
usage()
quit()
@@ -152,7 +152,7 @@
wpas_dbus_interface,timeout)
except:
- print "Error:\n Invalid wpas_dbus_interface"
+ print("Error:\n Invalid wpas_dbus_interface")
usage()
quit()
@@ -165,5 +165,5 @@
except:
pass
- print "Disconnect timed out"
+ print("Disconnect timed out")
quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_find.py b/wpa_supplicant/examples/p2p/p2p_find.py
index 973d46a..e2df528 100644
--- a/wpa_supplicant/examples/p2p/p2p_find.py
+++ b/wpa_supplicant/examples/p2p/p2p_find.py
@@ -13,23 +13,23 @@
from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> [-t <timeout>] \ " \
- % sys.argv[0]
- print " [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -t = timeout = 0s (infinite)"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i wlan0 -t 10" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> [-t <timeout>] \ " \
+ % sys.argv[0])
+ print(" [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -t = timeout = 0s (infinite)")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i wlan0 -t 10" % sys.argv[0])
# Required Signals
def deviceFound(devicepath):
- print "Device found: %s" % (devicepath)
+ print("Device found: %s" % (devicepath))
def deviceLost(devicepath):
- print "Device lost: %s" % (devicepath)
+ print("Device lost: %s" % (devicepath))
class P2P_Find (threading.Thread):
# Needed Variables
@@ -85,10 +85,10 @@
try:
self.path = self.wpas.GetInterface(
self.interface_name)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
error = 'Error:\n Interface ' + self.interface_name \
+ ' was not found'
- print error
+ print(error)
usage()
os._exit(0)
@@ -150,7 +150,7 @@
if ( int(value) >= 0):
timeout = value
else:
- print "Error:\n Timeout cannot be negative"
+ print("Error:\n Timeout cannot be negative")
usage()
quit()
# Dbus interface
@@ -161,7 +161,7 @@
# Interface name is required and was not given
if (interface_name == None):
- print "Error:\n interface_name is required"
+ print("Error:\n interface_name is required")
usage()
quit()
@@ -170,7 +170,7 @@
p2p_find_test = P2P_Find(interface_name, wpas_dbus_interface, timeout)
except:
- print "Error:\n Invalid wpas_dbus_interface"
+ print("Error:\n Invalid wpas_dbus_interface")
usage()
quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_flush.py b/wpa_supplicant/examples/p2p/p2p_flush.py
index ff8509d..42fc7a3 100644
--- a/wpa_supplicant/examples/p2p/p2p_flush.py
+++ b/wpa_supplicant/examples/p2p/p2p_flush.py
@@ -13,19 +13,19 @@
from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> \ " \
- % sys.argv[0]
- print " [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i wlan0" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> \ " \
+ % sys.argv[0])
+ print(" [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i wlan0" % sys.argv[0])
# Required Signals\
def deviceLost(devicepath):
- print "Device lost: %s" % (devicepath)
+ print("Device lost: %s" % (devicepath))
class P2P_Flush (threading.Thread):
# Needed Variables
@@ -81,10 +81,10 @@
try:
self.path = self.wpas.GetInterface(
self.interface_name)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
error = 'Error:\n Interface ' + self.interface_name \
+ ' was not found'
- print error
+ print(error)
usage()
os._exit(0)
@@ -142,7 +142,7 @@
# Interface name is required and was not given
if (interface_name == None):
- print "Error:\n interface_name is required"
+ print("Error:\n interface_name is required")
usage()
quit()
@@ -151,7 +151,7 @@
p2p_flush_test = P2P_Flush(interface_name, wpas_dbus_interface,timeout)
except:
- print "Error:\n Invalid wpas_dbus_interface"
+ print("Error:\n Invalid wpas_dbus_interface")
usage()
quit()
@@ -164,5 +164,5 @@
except:
pass
- print "p2p_flush complete"
+ print("p2p_flush complete")
quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_group_add.py b/wpa_supplicant/examples/p2p/p2p_group_add.py
index 5c8fdaf..6d40821 100644
--- a/wpa_supplicant/examples/p2p/p2p_group_add.py
+++ b/wpa_supplicant/examples/p2p/p2p_group_add.py
@@ -11,30 +11,30 @@
from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> [-p <persistent>] \ " \
- % sys.argv[0]
- print " [-f <frequency>] [-o <group_object_path>] \ "
- print " [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -p = persistant group = 0 (0=false, 1=true)"
- print " -f = frequency"
- print " -o = persistent group object path"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i wlan0" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> [-p <persistent>] \ " \
+ % sys.argv[0])
+ print(" [-f <frequency>] [-o <group_object_path>] \ ")
+ print(" [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -p = persistant group = 0 (0=false, 1=true)")
+ print(" -f = frequency")
+ print(" -o = persistent group object path")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i wlan0" % sys.argv[0])
# Required Signals
def GroupStarted(properties):
if properties.has_key("group_object"):
- print 'Group Formation Complete %s' \
- % properties["group_object"]
+ print('Group Formation Complete %s' \
+ % properties["group_object"])
os._exit(0)
def WpsFailure(status, etc):
- print "WPS Authentication Failure".format(status)
- print etc
+ print("WPS Authentication Failure".format(status))
+ print(etc)
os._exit(0)
class P2P_Group_Add (threading.Thread):
@@ -99,10 +99,10 @@
try:
self.path = self.wpas.GetInterface(
self.interface_name)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
error = 'Error:\n Interface ' + self.interface_name \
+ ' was not found'
- print error
+ print(error)
usage()
os._exit(0)
@@ -127,7 +127,7 @@
if (int(self.frequency) > 0):
self.P2PDictionary.update({'frequency':int(self.frequency)})
else:
- print "Error:\n Frequency must be greater than 0"
+ print("Error:\n Frequency must be greater than 0")
usage()
os._exit(0)
@@ -141,7 +141,7 @@
self.p2p_interface.GroupAdd(self.P2PDictionary)
except:
- print "Error:\n Could not preform group add"
+ print("Error:\n Could not preform group add")
usage()
os._exit(0)
@@ -188,7 +188,7 @@
elif (value == '1'):
persistent = True
else:
- print "Error:\n Persistent can only be 1 or 0"
+ print("Error:\n Persistent can only be 1 or 0")
usage()
os._exit(0)
# Frequency
@@ -205,7 +205,7 @@
# Interface name is required and was not given
if (interface_name == None):
- print "Error:\n interface_name is required"
+ print("Error:\n interface_name is required")
usage()
quit()
@@ -213,10 +213,10 @@
p2p_group_add_test = P2P_Group_Add(interface_name,wpas_dbus_interface,
persistent,frequency,persistent_group_object)
except:
- print "Error:\n Invalid Arguements"
+ print("Error:\n Invalid Arguements")
p2p_group_add_test.constructArguements()
p2p_group_add_test.start()
time.sleep(5)
- print "Error:\n Group formation timed out"
+ print("Error:\n Group formation timed out")
os._exit(0)
diff --git a/wpa_supplicant/examples/p2p/p2p_invite.py b/wpa_supplicant/examples/p2p/p2p_invite.py
index 6deb397..341dcd0 100644
--- a/wpa_supplicant/examples/p2p/p2p_invite.py
+++ b/wpa_supplicant/examples/p2p/p2p_invite.py
@@ -11,29 +11,29 @@
from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> -a <addr> \ " \
- % sys.argv[0]
- print " [-o <persistent_group_object>] [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -a = address of peer"
- print " -o = persistent group object path"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i p2p-wlan0-0 -a 00150083523c" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> -a <addr> \ " \
+ % sys.argv[0])
+ print(" [-o <persistent_group_object>] [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -a = address of peer")
+ print(" -o = persistent group object path")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i p2p-wlan0-0 -a 00150083523c" % sys.argv[0])
# Required Signals
def InvitationResult(invite_result):
- print "Inviation Result signal :"
+ print("Inviation Result signal :")
status = invite_result['status']
- print "status = ", status
+ print("status = ", status)
if invite_result.has_key('BSSID'):
bssid = invite_result['BSSID']
- print "BSSID = ", hex(bssid[0]) , ":" , \
+ print("BSSID = ", hex(bssid[0]) , ":" , \
hex(bssid[1]) , ":" , hex(bssid[2]) , ":", \
hex(bssid[3]) , ":" , hex(bssid[4]) , ":" , \
- hex(bssid[5])
+ hex(bssid[5]))
os._exit(0)
class P2P_Invite (threading.Thread):
@@ -96,10 +96,10 @@
try:
self.path = self.wpas.GetInterface(
self.interface_name)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
error = 'Error:\n Interface ' + self.interface_name \
+ ' was not found'
- print error
+ print(error)
usage()
os._exit(0)
@@ -127,7 +127,7 @@
self.p2p_interface.Invite(self.P2PDictionary)
except:
- print "Error:\n Invalid Arguements"
+ print("Error:\n Invalid Arguements")
usage()
os._exit(0)
@@ -176,12 +176,12 @@
# Interface name is required and was not given
if (interface_name == None):
- print "Error:\n interface_name is required"
+ print("Error:\n interface_name is required")
usage()
quit()
if (addr == None):
- print "Error:\n peer address is required"
+ print("Error:\n peer address is required")
usage()
quit()
@@ -190,12 +190,12 @@
P2P_Invite(interface_name,wpas_dbus_interface,
addr,persistent_group_object)
except:
- print "Error:\n Invalid Arguements"
+ print("Error:\n Invalid Arguements")
usage()
os._exit(1)
p2p_invite_test.constructArguements()
p2p_invite_test.start()
time.sleep(10)
- print "Error:\n p2p_invite timed out"
+ print("Error:\n p2p_invite timed out")
os._exit(0)
diff --git a/wpa_supplicant/examples/p2p/p2p_listen.py b/wpa_supplicant/examples/p2p/p2p_listen.py
index bb3c1e4..b0837d9 100644
--- a/wpa_supplicant/examples/p2p/p2p_listen.py
+++ b/wpa_supplicant/examples/p2p/p2p_listen.py
@@ -13,20 +13,20 @@
from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> [-t <timeout>] \ " \
- % sys.argv[0]
- print " [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -t = timeout = 0s (infinite)"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i wlan0 -t 5" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> [-t <timeout>] \ " \
+ % sys.argv[0])
+ print(" [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -t = timeout = 0s (infinite)")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i wlan0 -t 5" % sys.argv[0])
# Required Signals
def p2pStateChange(status):
- print status
+ print(status)
class P2P_Listen(threading.Thread):
# Needed Variables
@@ -82,10 +82,10 @@
try:
self.path = self.wpas.GetInterface(
self.interface_name)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
error = 'Error:\n Interface ' + self.interface_name \
+ ' was not found'
- print error
+ print(error)
usage()
os._exit(0)
@@ -140,7 +140,7 @@
if ( int(value) >= 0):
timeout = value
else:
- print "Error:\n Timeout cannot be negative"
+ print("Error:\n Timeout cannot be negative")
usage()
quit()
# Dbus interface
@@ -151,7 +151,7 @@
# Interface name is required and was not given
if (interface_name == None):
- print "Error:\n interface_name is required"
+ print("Error:\n interface_name is required")
usage()
quit()
@@ -160,7 +160,7 @@
p2p_listen_test = P2P_Listen(interface_name, wpas_dbus_interface, timeout)
except:
- print "Error:\n Invalid wpas_dbus_interface"
+ print("Error:\n Invalid wpas_dbus_interface")
usage()
quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_stop_find.py b/wpa_supplicant/examples/p2p/p2p_stop_find.py
index f6c03b0..bdb4c0e 100644
--- a/wpa_supplicant/examples/p2p/p2p_stop_find.py
+++ b/wpa_supplicant/examples/p2p/p2p_stop_find.py
@@ -11,22 +11,22 @@
from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> \ " \
- % sys.argv[0]
- print " [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i wlan0" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> \ " \
+ % sys.argv[0])
+ print(" [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i wlan0" % sys.argv[0])
# Required Signals
def deviceLost(devicepath):
- print "Device lost: %s" % (devicepath)
+ print("Device lost: %s" % (devicepath))
def p2pStateChange(status):
- print status
+ print(status)
os._exit(0)
class P2P_Stop_Find (threading.Thread):
@@ -83,10 +83,10 @@
try:
self.path = self.wpas.GetInterface(
self.interface_name)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
error = 'Error:\n Interface ' + self.interface_name \
+ ' was not found'
- print error
+ print(error)
usage()
os._exit(0)
@@ -147,7 +147,7 @@
# Interface name is required and was not given
if (interface_name == None):
- print "Error:\n interface_name is required"
+ print("Error:\n interface_name is required")
usage()
quit()
@@ -157,7 +157,7 @@
wpas_dbus_interface,timeout)
except:
- print "Error:\n Invalid wpas_dbus_interface"
+ print("Error:\n Invalid wpas_dbus_interface")
usage()
quit()
@@ -170,5 +170,5 @@
except:
pass
- print "p2p find stopped"
+ print("p2p find stopped")
quit()
diff --git a/wpa_supplicant/examples/wpas-dbus-new-getall.py b/wpa_supplicant/examples/wpas-dbus-new-getall.py
index 03da187..732f54d 100755
--- a/wpa_supplicant/examples/wpas-dbus-new-getall.py
+++ b/wpa_supplicant/examples/wpas-dbus-new-getall.py
@@ -11,8 +11,8 @@
"/fi/w1/wpa_supplicant1")
props = wpas_obj.GetAll("fi.w1.wpa_supplicant1",
dbus_interface=dbus.PROPERTIES_IFACE)
- print "GetAll(fi.w1.wpa_supplicant1, /fi/w1/wpa_supplicant1):"
- print props
+ print("GetAll(fi.w1.wpa_supplicant1, /fi/w1/wpa_supplicant1):")
+ print(props)
if len(sys.argv) != 2:
os._exit(1)
@@ -24,15 +24,15 @@
if_obj = bus.get_object("fi.w1.wpa_supplicant1", path)
props = if_obj.GetAll("fi.w1.wpa_supplicant1.Interface",
dbus_interface=dbus.PROPERTIES_IFACE)
- print
- print "GetAll(fi.w1.wpa_supplicant1.Interface, %s):" % (path)
- print props
+ print('')
+ print("GetAll(fi.w1.wpa_supplicant1.Interface, %s):" % (path))
+ print(props)
props = if_obj.GetAll("fi.w1.wpa_supplicant1.Interface.WPS",
dbus_interface=dbus.PROPERTIES_IFACE)
- print
- print "GetAll(fi.w1.wpa_supplicant1.Interface.WPS, %s):" % (path)
- print props
+ print('')
+ print("GetAll(fi.w1.wpa_supplicant1.Interface.WPS, %s):" % (path))
+ print(props)
res = if_obj.Get("fi.w1.wpa_supplicant1.Interface", 'BSSs',
dbus_interface=dbus.PROPERTIES_IFACE)
@@ -40,9 +40,9 @@
bss_obj = bus.get_object("fi.w1.wpa_supplicant1", res[0])
props = bss_obj.GetAll("fi.w1.wpa_supplicant1.BSS",
dbus_interface=dbus.PROPERTIES_IFACE)
- print
- print "GetAll(fi.w1.wpa_supplicant1.BSS, %s):" % (res[0])
- print props
+ print('')
+ print("GetAll(fi.w1.wpa_supplicant1.BSS, %s):" % (res[0]))
+ print(props)
res = if_obj.Get("fi.w1.wpa_supplicant1.Interface", 'Networks',
dbus_interface=dbus.PROPERTIES_IFACE)
@@ -50,10 +50,9 @@
net_obj = bus.get_object("fi.w1.wpa_supplicant1", res[0])
props = net_obj.GetAll("fi.w1.wpa_supplicant1.Network",
dbus_interface=dbus.PROPERTIES_IFACE)
- print
- print "GetAll(fi.w1.wpa_supplicant1.Network, %s):" % (res[0])
- print props
+ print('')
+ print("GetAll(fi.w1.wpa_supplicant1.Network, %s):" % (res[0]))
+ print(props)
if __name__ == "__main__":
main()
-
diff --git a/wpa_supplicant/examples/wpas-dbus-new-signals.py b/wpa_supplicant/examples/wpas-dbus-new-signals.py
index d90ef18..366a655 100755
--- a/wpa_supplicant/examples/wpas-dbus-new-signals.py
+++ b/wpa_supplicant/examples/wpas-dbus-new-signals.py
@@ -32,17 +32,17 @@
if_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
ifname = if_obj.Get(WPAS_DBUS_INTERFACES_INTERFACE, 'Ifname',
dbus_interface=dbus.PROPERTIES_IFACE)
- print ifname
+ print(ifname)
def interfaceAdded(interface, properties):
- print "InterfaceAdded(%s): Ifname=%s" % (interface, properties['Ifname'])
+ print("InterfaceAdded(%s): Ifname=%s" % (interface, properties['Ifname']))
def interfaceRemoved(interface):
- print "InterfaceRemoved(%s)" % (interface)
+ print("InterfaceRemoved(%s)" % (interface))
def propertiesChanged(properties):
for i in properties:
- print "PropertiesChanged: %s=%s" % (i, properties[i])
+ print("PropertiesChanged: %s=%s" % (i, properties[i]))
def showBss(bss):
net_obj = bus.get_object(WPAS_DBUS_SERVICE, bss)
@@ -80,48 +80,48 @@
else:
maxrate = 0
- print " %s :: ssid='%s' wpa=%s wpa2=%s signal=%d rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq)
+ print(" %s :: ssid='%s' wpa=%s wpa2=%s signal=%d rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq))
def scanDone(success):
gobject.MainLoop().quit()
- print "Scan done: success=%s" % success
+ print("Scan done: success=%s" % success)
def scanDone2(success, path=None):
- print "Scan done: success=%s [path=%s]" % (success, path)
+ print("Scan done: success=%s [path=%s]" % (success, path))
def bssAdded(bss, properties):
- print "BSS added: %s" % (bss)
+ print("BSS added: %s" % (bss))
showBss(bss)
def bssRemoved(bss):
- print "BSS removed: %s" % (bss)
+ print("BSS removed: %s" % (bss))
def blobAdded(blob):
- print "BlobAdded(%s)" % (blob)
+ print("BlobAdded(%s)" % (blob))
def blobRemoved(blob):
- print "BlobRemoved(%s)" % (blob)
+ print("BlobRemoved(%s)" % (blob))
def networkAdded(network, properties):
- print "NetworkAdded(%s)" % (network)
+ print("NetworkAdded(%s)" % (network))
def networkRemoved(network):
- print "NetworkRemoved(%s)" % (network)
+ print("NetworkRemoved(%s)" % (network))
def networkSelected(network):
- print "NetworkSelected(%s)" % (network)
+ print("NetworkSelected(%s)" % (network))
def propertiesChangedInterface(properties):
for i in properties:
- print "PropertiesChanged(interface): %s=%s" % (i, properties[i])
+ print("PropertiesChanged(interface): %s=%s" % (i, properties[i]))
def propertiesChangedBss(properties):
for i in properties:
- print "PropertiesChanged(BSS): %s=%s" % (i, properties[i])
+ print("PropertiesChanged(BSS): %s=%s" % (i, properties[i]))
def propertiesChangedNetwork(properties):
for i in properties:
- print "PropertiesChanged(Network): %s=%s" % (i, properties[i])
+ print("PropertiesChanged(Network): %s=%s" % (i, properties[i]))
def main():
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
diff --git a/wpa_supplicant/examples/wpas-dbus-new-wps.py b/wpa_supplicant/examples/wpas-dbus-new-wps.py
index b886385..7d87b1e 100755
--- a/wpa_supplicant/examples/wpas-dbus-new-wps.py
+++ b/wpa_supplicant/examples/wpas-dbus-new-wps.py
@@ -15,23 +15,23 @@
def propertiesChanged(properties):
if properties.has_key("State"):
- print "PropertiesChanged: State: %s" % (properties["State"])
+ print("PropertiesChanged: State: %s" % (properties["State"]))
def scanDone(success):
- print "Scan done: success=%s" % success
+ print("Scan done: success=%s" % success)
def bssAdded(bss, properties):
- print "BSS added: %s" % (bss)
+ print("BSS added: %s" % (bss))
def bssRemoved(bss):
- print "BSS removed: %s" % (bss)
+ print("BSS removed: %s" % (bss))
def wpsEvent(name, args):
- print "WPS event: %s" % (name)
- print args
+ print("WPS event: %s" % (name))
+ print(args)
def credentials(cred):
- print "WPS credentials: %s" % (cred)
+ print("WPS credentials: %s" % (cred))
def main():
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
@@ -40,7 +40,7 @@
wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH)
if len(sys.argv) != 2:
- print "Missing ifname argument"
+ print("Missing ifname argument")
os._exit(1)
wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE)
diff --git a/wpa_supplicant/examples/wpas-dbus-new.py b/wpa_supplicant/examples/wpas-dbus-new.py
index 25072ce..6bf74ae 100755
--- a/wpa_supplicant/examples/wpas-dbus-new.py
+++ b/wpa_supplicant/examples/wpas-dbus-new.py
@@ -31,11 +31,11 @@
if_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
ifname = if_obj.Get(WPAS_DBUS_INTERFACES_INTERFACE, 'Ifname',
dbus_interface=dbus.PROPERTIES_IFACE)
- print ifname
+ print(ifname)
def propertiesChanged(properties):
if properties.has_key("State"):
- print "PropertiesChanged: State: %s" % (properties["State"])
+ print("PropertiesChanged: State: %s" % (properties["State"]))
def showBss(bss):
net_obj = bus.get_object(WPAS_DBUS_SERVICE, bss)
@@ -73,25 +73,25 @@
else:
maxrate = 0
- print " %s :: ssid='%s' wpa=%s wpa2=%s signal=%d rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq)
+ print(" %s :: ssid='%s' wpa=%s wpa2=%s signal=%d rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq))
def scanDone(success):
- print "Scan done: success=%s" % success
+ print("Scan done: success=%s" % success)
res = if_obj.Get(WPAS_DBUS_INTERFACES_INTERFACE, 'BSSs',
dbus_interface=dbus.PROPERTIES_IFACE)
- print "Scanned wireless networks:"
+ print("Scanned wireless networks:")
for opath in res:
- print opath
+ print(opath)
showBss(opath)
def bssAdded(bss, properties):
- print "BSS added: %s" % (bss)
+ print("BSS added: %s" % (bss))
showBss(bss)
def bssRemoved(bss):
- print "BSS removed: %s" % (bss)
+ print("BSS removed: %s" % (bss))
def main():
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
@@ -123,14 +123,14 @@
path = None
try:
path = wpas.GetInterface(ifname)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
if not str(exc).startswith("fi.w1.wpa_supplicant1.InterfaceUnknown:"):
raise exc
try:
path = wpas.CreateInterface({'Ifname': ifname, 'Driver': 'test'})
time.sleep(1)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
if not str(exc).startswith("fi.w1.wpa_supplicant1.InterfaceExists:"):
raise exc
diff --git a/wpa_supplicant/examples/wpas-test.py b/wpa_supplicant/examples/wpas-test.py
deleted file mode 100755
index fd7f73d..0000000
--- a/wpa_supplicant/examples/wpas-test.py
+++ /dev/null
@@ -1,91 +0,0 @@
-#!/usr/bin/python
-
-import dbus
-import sys, os
-import time
-
-WPAS_DBUS_SERVICE = "fi.epitest.hostap.WPASupplicant"
-WPAS_DBUS_INTERFACE = "fi.epitest.hostap.WPASupplicant"
-WPAS_DBUS_OPATH = "/fi/epitest/hostap/WPASupplicant"
-
-WPAS_DBUS_INTERFACES_INTERFACE = "fi.epitest.hostap.WPASupplicant.Interface"
-WPAS_DBUS_INTERFACES_OPATH = "/fi/epitest/hostap/WPASupplicant/Interfaces"
-WPAS_DBUS_BSSID_INTERFACE = "fi.epitest.hostap.WPASupplicant.BSSID"
-
-def byte_array_to_string(s):
- import urllib
- r = ""
- for c in s:
- if c >= 32 and c < 127:
- r += "%c" % c
- else:
- r += urllib.quote(chr(c))
- return r
-
-def main():
- if len(sys.argv) != 2:
- print "Usage: wpas-test.py <interface>"
- os._exit(1)
-
- ifname = sys.argv[1]
-
- bus = dbus.SystemBus()
- wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH)
- wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE)
-
- # See if wpa_supplicant already knows about this interface
- path = None
- try:
- path = wpas.getInterface(ifname)
- except dbus.dbus_bindings.DBusException, exc:
- if str(exc) != "wpa_supplicant knows nothing about this interface.":
- raise exc
- try:
- path = wpas.addInterface(ifname, {'driver': dbus.Variant('wext')})
- except dbus.dbus_bindings.DBusException, exc:
- if str(exc) != "wpa_supplicant already controls this interface.":
- raise exc
-
- if_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
- iface = dbus.Interface(if_obj, WPAS_DBUS_INTERFACES_INTERFACE)
- iface.scan()
- # Should really wait for the "scanResults" signal instead of sleeping
- time.sleep(5)
- res = iface.scanResults()
-
- print "Scanned wireless networks:"
- for opath in res:
- net_obj = bus.get_object(WPAS_DBUS_SERVICE, opath)
- net = dbus.Interface(net_obj, WPAS_DBUS_BSSID_INTERFACE)
- props = net.properties()
-
- # Convert the byte-array for SSID and BSSID to printable strings
- bssid = ""
- for item in props["bssid"]:
- bssid = bssid + ":%02x" % item
- bssid = bssid[1:]
- ssid = byte_array_to_string(props["ssid"])
- wpa = "no"
- if props.has_key("wpaie"):
- wpa = "yes"
- wpa2 = "no"
- if props.has_key("rsnie"):
- wpa2 = "yes"
- freq = 0
- if props.has_key("frequency"):
- freq = props["frequency"]
- caps = props["capabilities"]
- qual = props["quality"]
- level = props["level"]
- noise = props["noise"]
- maxrate = props["maxrate"] / 1000000
-
- print " %s :: ssid='%s' wpa=%s wpa2=%s quality=%d%% rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, qual, maxrate, freq)
-
- wpas.removeInterface(dbus.ObjectPath(path))
- # Should fail here with unknown interface error
- iface.scan()
-
-if __name__ == "__main__":
- main()
-
diff --git a/wpa_supplicant/examples/wps-ap-cli b/wpa_supplicant/examples/wps-ap-cli
index cc2cff2..15d913e 100755
--- a/wpa_supplicant/examples/wps-ap-cli
+++ b/wpa_supplicant/examples/wps-ap-cli
@@ -14,12 +14,12 @@
enter_pin()
{
echo "Enter a PIN from a station to be enrolled to the network."
- echo -n "Enrollee PIN: "
+ printf "Enrollee PIN: "
read pin
cpin=`$CLI wps_check_pin "$pin" | tail -1`
if [ "$cpin" = "FAIL-CHECKSUM" ]; then
echo "Checksum digit is not valid"
- echo -n "Do you want to use this PIN (y/n)? "
+ printf "Do you want to use this PIN (y/n)? "
read resp
case "$resp" in
y*)
@@ -52,7 +52,7 @@
echo "3: Show current configuration"
echo "0: Exit wps-ap-cli"
- echo -n "Command: "
+ printf "Command: "
read cmd
case "$cmd" in
diff --git a/wpa_supplicant/examples/wps-nfc.py b/wpa_supplicant/examples/wps-nfc.py
index 7459eb9..bb458fb 100755
--- a/wpa_supplicant/examples/wps-nfc.py
+++ b/wpa_supplicant/examples/wps-nfc.py
@@ -30,7 +30,7 @@
success_file = None
def summary(txt):
- print txt
+ print(txt)
if summary_file:
with open(summary_file, 'a') as f:
f.write(txt + "\n")
@@ -46,19 +46,19 @@
if os.path.isdir(wpas_ctrl):
try:
ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
- except OSError, error:
- print "Could not find wpa_supplicant: ", error
+ except OSError as error:
+ print("Could not find wpa_supplicant: ", error)
return None
if len(ifaces) < 1:
- print "No wpa_supplicant control interface found"
+ print("No wpa_supplicant control interface found")
return None
for ctrl in ifaces:
try:
wpas = wpaspy.Ctrl(ctrl)
return wpas
- except Exception, e:
+ except Exception as e:
pass
return None
@@ -163,22 +163,22 @@
self.ho_server_processing = True
summary("HandoverServer - request received")
try:
- print "Parsed handover request: " + request.pretty()
- except Exception, e:
- print e
+ print("Parsed handover request: " + request.pretty())
+ except Exception as e:
+ print(e)
sel = nfc.ndef.HandoverSelectMessage(version="1.2")
for carrier in request.carriers:
- print "Remote carrier type: " + carrier.type
+ print("Remote carrier type: " + carrier.type)
if carrier.type == "application/vnd.wfa.wsc":
summary("WPS carrier type match - add WPS carrier record")
data = wpas_get_handover_sel(self.uuid)
if data is None:
summary("Could not get handover select carrier record from wpa_supplicant")
continue
- print "Handover select carrier record from wpa_supplicant:"
- print data.encode("hex")
+ print("Handover select carrier record from wpa_supplicant:")
+ print(data.encode("hex"))
self.sent_carrier = data
if "OK" in wpas_report_handover(carrier.record, self.sent_carrier, "RESP"):
success_report("Handover reported successfully (responder)")
@@ -188,12 +188,12 @@
message = nfc.ndef.Message(data);
sel.add_carrier(message[0], "active", message[1:])
- print "Handover select:"
+ print("Handover select:")
try:
- print sel.pretty()
- except Exception, e:
- print e
- print str(sel).encode("hex")
+ print(sel.pretty())
+ except Exception as e:
+ print(e)
+ print(str(sel).encode("hex"))
summary("Sending handover select")
self.success = True
@@ -207,19 +207,19 @@
if (data == None):
summary("Could not get handover request carrier record from wpa_supplicant")
return
- print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
+ print("Handover request carrier record from wpa_supplicant: " + data.encode("hex"))
message = nfc.ndef.HandoverRequestMessage(version="1.2")
message.nonce = random.randint(0, 0xffff)
datamsg = nfc.ndef.Message(data)
message.add_carrier(datamsg[0], "active", datamsg[1:])
- print "Handover request:"
+ print("Handover request:")
try:
- print message.pretty()
- except Exception, e:
- print e
- print str(message).encode("hex")
+ print(message.pretty())
+ except Exception as e:
+ print(e)
+ print(str(message).encode("hex"))
client = nfc.handover.HandoverClient(llc)
try:
@@ -230,7 +230,7 @@
summary("Handover connection refused")
client.close()
return
- except Exception, e:
+ except Exception as e:
summary("Other exception: " + str(e))
client.close()
return
@@ -253,23 +253,23 @@
client.close()
return
- print "Received message"
+ print("Received message")
try:
- print message.pretty()
- except Exception, e:
- print e
- print str(message).encode("hex")
+ print(message.pretty())
+ except Exception as e:
+ print(e)
+ print(str(message).encode("hex"))
message = nfc.ndef.HandoverSelectMessage(message)
summary("Handover select received")
try:
- print message.pretty()
- except Exception, e:
- print e
+ print(message.pretty())
+ except Exception as e:
+ print(e)
for carrier in message.carriers:
- print "Remote carrier type: " + carrier.type
+ print("Remote carrier type: " + carrier.type)
if carrier.type == "application/vnd.wfa.wsc":
- print "WPS carrier type match - send to wpa_supplicant"
+ print("WPS carrier type match - send to wpa_supplicant")
if "OK" in wpas_report_handover(data, carrier.record, "INIT"):
success_report("Handover reported successfully (initiator)")
else:
@@ -278,9 +278,9 @@
#wifi = nfc.ndef.WifiConfigRecord(carrier.record)
#print wifi.pretty()
- print "Remove peer"
+ print("Remove peer")
client.close()
- print "Done with handover"
+ print("Done with handover")
global only_one
if only_one:
global continue_loop
@@ -288,7 +288,7 @@
global no_wait
if no_wait:
- print "Trying to exit.."
+ print("Trying to exit..")
global terminate_now
terminate_now = True
@@ -296,7 +296,7 @@
success = False
if len(tag.ndef.message):
for record in tag.ndef.message:
- print "record type " + record.type
+ print("record type " + record.type)
if record.type == "application/vnd.wfa.wsc":
summary("WPS tag - send to wpa_supplicant")
success = wpas_tag_read(tag.ndef.message)
@@ -308,7 +308,7 @@
success_report("Tag read succeeded")
if wait_remove:
- print "Remove tag"
+ print("Remove tag")
while tag.is_present:
time.sleep(0.1)
@@ -320,7 +320,7 @@
global write_data
tag.ndef.message = str(write_data)
success_report("Tag write succeeded")
- print "Done - remove tag"
+ print("Done - remove tag")
global only_one
if only_one:
global continue_loop
@@ -330,41 +330,41 @@
time.sleep(0.1)
def wps_write_config_tag(clf, id=None, wait_remove=True):
- print "Write WPS config token"
+ print("Write WPS config token")
global write_data, write_wait_remove
write_wait_remove = wait_remove
write_data = wpas_get_config_token(id)
if write_data == None:
- print "Could not get WPS config token from wpa_supplicant"
+ print("Could not get WPS config token from wpa_supplicant")
sys.exit(1)
return
- print "Touch an NFC tag"
+ print("Touch an NFC tag")
clf.connect(rdwr={'on-connect': rdwr_connected_write})
def wps_write_er_config_tag(clf, uuid, wait_remove=True):
- print "Write WPS ER config token"
+ print("Write WPS ER config token")
global write_data, write_wait_remove
write_wait_remove = wait_remove
write_data = wpas_get_er_config_token(uuid)
if write_data == None:
- print "Could not get WPS config token from wpa_supplicant"
+ print("Could not get WPS config token from wpa_supplicant")
return
- print "Touch an NFC tag"
+ print("Touch an NFC tag")
clf.connect(rdwr={'on-connect': rdwr_connected_write})
def wps_write_password_tag(clf, wait_remove=True):
- print "Write WPS password token"
+ print("Write WPS password token")
global write_data, write_wait_remove
write_wait_remove = wait_remove
write_data = wpas_get_password_token()
if write_data == None:
- print "Could not get WPS password token from wpa_supplicant"
+ print("Could not get WPS password token from wpa_supplicant")
return
- print "Touch an NFC tag"
+ print("Touch an NFC tag")
clf.connect(rdwr={'on-connect': rdwr_connected_write})
@@ -373,11 +373,11 @@
summary("Tag connected: " + str(tag))
if tag.ndef:
- print "NDEF tag: " + tag.type
+ print("NDEF tag: " + tag.type)
try:
- print tag.ndef.message.pretty()
- except Exception, e:
- print e
+ print(tag.ndef.message.pretty())
+ except Exception as e:
+ print(e)
success = wps_tag_read(tag, not only_one)
if only_one and success:
global continue_loop
@@ -393,7 +393,7 @@
global arg_uuid
if arg_uuid is None:
wps_handover_init(llc)
- print "Exiting llcp_worker thread"
+ print("Exiting llcp_worker thread")
return
global srv
@@ -405,19 +405,19 @@
def llcp_startup(clf, llc):
global arg_uuid
if arg_uuid:
- print "Start LLCP server"
+ print("Start LLCP server")
global srv
srv = HandoverServer(llc)
if arg_uuid is "ap":
- print "Trying to handle WPS handover"
+ print("Trying to handle WPS handover")
srv.uuid = None
else:
- print "Trying to handle WPS handover with AP " + arg_uuid
+ print("Trying to handle WPS handover with AP " + arg_uuid)
srv.uuid = arg_uuid
return llc
def llcp_connected(llc):
- print "P2P LLCP connected"
+ print("P2P LLCP connected")
global wait_connection
wait_connection = False
global arg_uuid
@@ -426,7 +426,7 @@
srv.start()
else:
threading.Thread(target=llcp_worker, args=(llc,)).start()
- print "llcp_connected returning"
+ print("llcp_connected returning")
return True
@@ -482,7 +482,7 @@
try:
if not clf.open("usb"):
- print "Could not open connection with an NFC device"
+ print("Could not open connection with an NFC device")
raise SystemExit
if args.command == "write-config":
@@ -499,7 +499,7 @@
global continue_loop
while continue_loop:
- print "Waiting for a tag or peer to be touched"
+ print("Waiting for a tag or peer to be touched")
wait_connection = True
try:
if not clf.connect(rdwr={'on-connect': rdwr_connected},
@@ -507,8 +507,8 @@
'on-connect': llcp_connected},
terminate=terminate_loop):
break
- except Exception, e:
- print "clf.connect failed"
+ except Exception as e:
+ print("clf.connect failed")
global srv
if only_one and srv and srv.success:
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 91cf19a..8e977a3 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -42,6 +42,7 @@
unsigned int wait_comeback:1;
unsigned int offchannel_tx_started:1;
unsigned int retry:1;
+ unsigned int wildcard_bssid:1;
int freq;
u16 status_code;
struct wpabuf *req;
@@ -121,6 +122,8 @@
return "PEER_ERROR";
case GAS_QUERY_INTERNAL_ERROR:
return "INTERNAL_ERROR";
+ case GAS_QUERY_STOPPED:
+ return "STOPPED";
case GAS_QUERY_DELETED_AT_DEINIT:
return "DELETED_AT_DEINIT";
}
@@ -269,7 +272,7 @@
}
-static int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr)
+int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr)
{
if (wpa_s->current_ssid == NULL ||
wpa_s->wpa_state < WPA_4WAY_HANDSHAKE ||
@@ -300,10 +303,11 @@
if (gas->wpa_s->max_remain_on_chan &&
wait_time > gas->wpa_s->max_remain_on_chan)
wait_time = gas->wpa_s->max_remain_on_chan;
- if (!gas->wpa_s->conf->gas_address3 ||
- (gas->wpa_s->current_ssid &&
- gas->wpa_s->wpa_state >= WPA_ASSOCIATED &&
- os_memcmp(query->addr, gas->wpa_s->bssid, ETH_ALEN) == 0))
+ if (!query->wildcard_bssid &&
+ (!gas->wpa_s->conf->gas_address3 ||
+ (gas->wpa_s->current_ssid &&
+ gas->wpa_s->wpa_state >= WPA_ASSOCIATED &&
+ os_memcmp(query->addr, gas->wpa_s->bssid, ETH_ALEN) == 0)))
bssid = query->addr;
else
bssid = wildcard_bssid;
@@ -803,7 +807,7 @@
* Returns: dialog token (>= 0) on success or -1 on failure
*/
int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
- struct wpabuf *req,
+ int wildcard_bssid, struct wpabuf *req,
void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
enum gas_query_result result,
const struct wpabuf *adv_proto,
@@ -831,6 +835,7 @@
}
os_memcpy(query->addr, dst, ETH_ALEN);
query->dialog_token = dialog_token;
+ query->wildcard_bssid = !!wildcard_bssid;
query->freq = freq;
query->cb = cb;
query->ctx = ctx;
@@ -852,3 +857,27 @@
return dialog_token;
}
+
+
+int gas_query_stop(struct gas_query *gas, u8 dialog_token)
+{
+ struct gas_query_pending *query;
+
+ dl_list_for_each(query, &gas->pending, struct gas_query_pending, list) {
+ if (query->dialog_token == dialog_token) {
+ if (!gas->work) {
+ /* The pending radio work has not yet been
+ * started, but the pending entry has a
+ * reference to the soon to be freed query.
+ * Need to remove that radio work now to avoid
+ * leaving behind a reference to freed memory.
+ */
+ radio_remove_pending_work(gas->wpa_s, query);
+ }
+ gas_query_done(gas, query, GAS_QUERY_STOPPED);
+ return 0;
+ }
+ }
+
+ return -1;
+}
diff --git a/wpa_supplicant/gas_query.h b/wpa_supplicant/gas_query.h
index ef82097..d2b4554 100644
--- a/wpa_supplicant/gas_query.h
+++ b/wpa_supplicant/gas_query.h
@@ -19,6 +19,7 @@
int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
const u8 *bssid, u8 categ, const u8 *data, size_t len,
int freq);
+int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr);
/**
* enum gas_query_result - GAS query result
@@ -29,16 +30,18 @@
GAS_QUERY_TIMEOUT,
GAS_QUERY_PEER_ERROR,
GAS_QUERY_INTERNAL_ERROR,
+ GAS_QUERY_STOPPED,
GAS_QUERY_DELETED_AT_DEINIT
};
int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
- struct wpabuf *req,
+ int wildcard_bssid, struct wpabuf *req,
void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
enum gas_query_result result,
const struct wpabuf *adv_proto,
const struct wpabuf *resp, u16 status_code),
void *ctx);
+int gas_query_stop(struct gas_query *gas, u8 dialog_token);
#else /* CONFIG_GAS */
diff --git a/wpa_supplicant/hidl/1.0/hidl.cpp b/wpa_supplicant/hidl/1.0/hidl.cpp
deleted file mode 100644
index ce8a459..0000000
--- a/wpa_supplicant/hidl/1.0/hidl.cpp
+++ /dev/null
@@ -1,627 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include <hwbinder/IPCThreadState.h>
-
-#include <hidl/HidlTransportSupport.h>
-#include "hidl_manager.h"
-
-extern "C" {
-#include "hidl.h"
-#include "hidl_i.h"
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "utils/includes.h"
-}
-
-using android::hardware::configureRpcThreadpool;
-using android::hardware::setupTransportPolling;
-using android::hardware::handleTransportPoll;
-using android::hardware::wifi::supplicant::V1_0::implementation::HidlManager;
-
-void wpas_hidl_sock_handler(
- int sock, void * /* eloop_ctx */, void * /* sock_ctx */)
-{
- handleTransportPoll(sock);
-}
-
-struct wpas_hidl_priv *wpas_hidl_init(struct wpa_global *global)
-{
- struct wpas_hidl_priv *priv;
- HidlManager *hidl_manager;
-
- priv = (wpas_hidl_priv *)os_zalloc(sizeof(*priv));
- if (!priv)
- return NULL;
- priv->global = global;
-
- wpa_printf(MSG_DEBUG, "Initing hidl control");
-
- configureRpcThreadpool(1, true /* callerWillJoin */);
- priv->hidl_fd = setupTransportPolling();
- if (priv->hidl_fd < 0)
- goto err;
-
- wpa_printf(MSG_INFO, "Processing hidl events on FD %d", priv->hidl_fd);
- // Look for read events from the hidl socket in the eloop.
- if (eloop_register_read_sock(
- priv->hidl_fd, wpas_hidl_sock_handler, global, priv) < 0)
- goto err;
-
- hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- goto err;
- hidl_manager->registerHidlService(global);
- // We may not need to store this hidl manager reference in the
- // global data strucure because we've made it a singleton class.
- priv->hidl_manager = (void *)hidl_manager;
-
- return priv;
-err:
- wpas_hidl_deinit(priv);
- return NULL;
-}
-
-void wpas_hidl_deinit(struct wpas_hidl_priv *priv)
-{
- if (!priv)
- return;
-
- wpa_printf(MSG_DEBUG, "Deiniting hidl control");
-
- HidlManager::destroyInstance();
- eloop_unregister_read_sock(priv->hidl_fd);
- os_free(priv);
-}
-
-int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s || !wpa_s->global->hidl)
- return 1;
-
- wpa_printf(
- MSG_DEBUG, "Registering interface to hidl control: %s",
- wpa_s->ifname);
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return 1;
-
- return hidl_manager->registerInterface(wpa_s);
-}
-
-int wpas_hidl_unregister_interface(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s || !wpa_s->global->hidl)
- return 1;
-
- wpa_printf(
- MSG_DEBUG, "Deregistering interface from hidl control: %s",
- wpa_s->ifname);
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return 1;
-
- return hidl_manager->unregisterInterface(wpa_s);
-}
-
-int wpas_hidl_register_network(
- struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
-{
- if (!wpa_s || !wpa_s->global->hidl || !ssid)
- return 1;
-
- wpa_printf(
- MSG_DEBUG, "Registering network to hidl control: %d", ssid->id);
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return 1;
-
- return hidl_manager->registerNetwork(wpa_s, ssid);
-}
-
-int wpas_hidl_unregister_network(
- struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
-{
- if (!wpa_s || !wpa_s->global->hidl || !ssid)
- return 1;
-
- wpa_printf(
- MSG_DEBUG, "Deregistering network from hidl control: %d", ssid->id);
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return 1;
-
- return hidl_manager->unregisterNetwork(wpa_s, ssid);
-}
-
-int wpas_hidl_notify_state_changed(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s || !wpa_s->global->hidl)
- return 1;
-
- wpa_printf(
- MSG_DEBUG, "Notifying state change event to hidl control: %d",
- wpa_s->wpa_state);
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return 1;
-
- return hidl_manager->notifyStateChange(wpa_s);
-}
-
-int wpas_hidl_notify_network_request(
- struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
- enum wpa_ctrl_req_type rtype, const char *default_txt)
-{
- if (!wpa_s || !wpa_s->global->hidl || !ssid)
- return 1;
-
- wpa_printf(
- MSG_DEBUG, "Notifying network request to hidl control: %d",
- ssid->id);
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return 1;
-
- return hidl_manager->notifyNetworkRequest(
- wpa_s, ssid, rtype, default_txt);
-}
-
-void wpas_hidl_notify_anqp_query_done(
- struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
- const struct wpa_bss_anqp *anqp)
-{
- if (!wpa_s || !wpa_s->global->hidl || !bssid || !result || !anqp)
- return;
-
- wpa_printf(
- MSG_DEBUG,
- "Notifying ANQP query done to hidl control: " MACSTR "result: %s",
- MAC2STR(bssid), result);
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyAnqpQueryDone(wpa_s, bssid, result, anqp);
-}
-
-void wpas_hidl_notify_hs20_icon_query_done(
- struct wpa_supplicant *wpa_s, const u8 *bssid, const char *file_name,
- const u8 *image, u32 image_length)
-{
- if (!wpa_s || !wpa_s->global->hidl || !bssid || !file_name || !image)
- return;
-
- wpa_printf(
- MSG_DEBUG, "Notifying HS20 icon query done to hidl control: " MACSTR
- "file_name: %s",
- MAC2STR(bssid), file_name);
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyHs20IconQueryDone(
- wpa_s, bssid, file_name, image, image_length);
-}
-
-void wpas_hidl_notify_hs20_rx_subscription_remediation(
- struct wpa_supplicant *wpa_s, const char *url, u8 osu_method)
-{
- if (!wpa_s || !wpa_s->global->hidl || !url)
- return;
-
- wpa_printf(
- MSG_DEBUG,
- "Notifying HS20 subscription remediation rx to hidl control: %s",
- url);
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyHs20RxSubscriptionRemediation(
- wpa_s, url, osu_method);
-}
-
-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)
- return;
-
- wpa_printf(
- MSG_DEBUG,
- "Notifying HS20 deauth imminent notice rx to hidl control: %s",
- url);
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyHs20RxDeauthImminentNotice(
- wpa_s, code, reauth_delay, url);
-}
-
-void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s)
- return;
-
- wpa_printf(
- MSG_DEBUG, "Notifying disconnect reason to hidl control: %d",
- wpa_s->disconnect_reason);
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyDisconnectReason(wpa_s);
-}
-
-void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s)
- return;
-
- wpa_printf(
- MSG_DEBUG, "Notifying assoc reject to hidl control: %d",
- wpa_s->assoc_status_code);
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyAssocReject(wpa_s);
-}
-
-void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s)
- return;
-
- wpa_printf(MSG_DEBUG, "Notifying auth timeout to hidl control");
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyAuthTimeout(wpa_s);
-}
-
-void wpas_hidl_notify_bssid_changed(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s)
- return;
-
- wpa_printf(MSG_DEBUG, "Notifying bssid changed to hidl control");
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyBssidChanged(wpa_s);
-}
-
-void wpas_hidl_notify_wps_event_fail(
- struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
- uint16_t error_indication)
-{
- if (!wpa_s || !peer_macaddr)
- return;
-
- wpa_printf(
- MSG_DEBUG, "Notifying Wps event fail to hidl control: %d, %d",
- config_error, error_indication);
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyWpsEventFail(
- wpa_s, peer_macaddr, config_error, error_indication);
-}
-
-void wpas_hidl_notify_wps_event_success(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s)
- return;
-
- wpa_printf(MSG_DEBUG, "Notifying Wps event success to hidl control");
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyWpsEventSuccess(wpa_s);
-}
-
-void wpas_hidl_notify_wps_event_pbc_overlap(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s)
- return;
-
- wpa_printf(
- MSG_DEBUG, "Notifying Wps event PBC overlap to hidl control");
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyWpsEventPbcOverlap(wpa_s);
-}
-
-void wpas_hidl_notify_p2p_device_found(
- struct wpa_supplicant *wpa_s, const u8 *addr,
- const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
- u8 peer_wfd_device_info_len)
-{
- if (!wpa_s || !addr || !info)
- return;
-
- wpa_printf(
- MSG_DEBUG, "Notifying P2P device found to hidl control " MACSTR,
- MAC2STR(info->p2p_device_addr));
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyP2pDeviceFound(
- wpa_s, addr, info, peer_wfd_device_info, peer_wfd_device_info_len);
-}
-
-void wpas_hidl_notify_p2p_device_lost(
- struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr)
-{
- if (!wpa_s || !p2p_device_addr)
- return;
-
- wpa_printf(
- MSG_DEBUG, "Notifying P2P device lost to hidl control " MACSTR,
- MAC2STR(p2p_device_addr));
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyP2pDeviceLost(wpa_s, p2p_device_addr);
-}
-
-void wpas_hidl_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s)
- return;
-
- wpa_printf(MSG_DEBUG, "Notifying P2P find stop to hidl control");
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyP2pFindStopped(wpa_s);
-}
-
-void wpas_hidl_notify_p2p_go_neg_req(
- struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
- u8 go_intent)
-{
- if (!wpa_s || !src_addr)
- return;
-
- wpa_printf(
- MSG_DEBUG,
- "Notifying P2P GO negotiation request to hidl control " MACSTR,
- MAC2STR(src_addr));
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyP2pGoNegReq(
- wpa_s, src_addr, dev_passwd_id, go_intent);
-}
-
-void wpas_hidl_notify_p2p_go_neg_completed(
- struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res)
-{
- if (!wpa_s || !res)
- return;
-
- wpa_printf(
- MSG_DEBUG,
- "Notifying P2P GO negotiation completed to hidl control: %d",
- res->status);
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyP2pGoNegCompleted(wpa_s, res);
-}
-
-void wpas_hidl_notify_p2p_group_formation_failure(
- struct wpa_supplicant *wpa_s, const char *reason)
-{
- if (!wpa_s || !reason)
- return;
-
- wpa_printf(
- MSG_DEBUG,
- "Notifying P2P Group formation failure to hidl control: %s",
- reason);
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyP2pGroupFormationFailure(wpa_s, reason);
-}
-
-void wpas_hidl_notify_p2p_group_started(
- struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, int persistent,
- int client)
-{
- if (!wpa_s || !ssid)
- return;
-
- wpa_printf(
- MSG_DEBUG, "Notifying P2P Group start to hidl control: %d",
- ssid->id);
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyP2pGroupStarted(wpa_s, ssid, persistent, client);
-}
-
-void wpas_hidl_notify_p2p_group_removed(
- struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, const char *role)
-{
- if (!wpa_s || !ssid || !role)
- return;
-
- wpa_printf(
- MSG_DEBUG, "Notifying P2P Group removed to hidl control: %d",
- ssid->id);
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyP2pGroupRemoved(wpa_s, ssid, role);
-}
-
-void wpas_hidl_notify_p2p_invitation_received(
- struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
- const u8 *bssid, int id, int op_freq)
-{
- if (!wpa_s || !sa || !go_dev_addr || !bssid)
- return;
-
- wpa_printf(
- MSG_DEBUG,
- "Notifying P2P invitation received to hidl control: %d " MACSTR, id,
- MAC2STR(bssid));
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyP2pInvitationReceived(
- wpa_s, sa, go_dev_addr, bssid, id, op_freq);
-}
-
-void wpas_hidl_notify_p2p_invitation_result(
- struct wpa_supplicant *wpa_s, int status, const u8 *bssid)
-{
- if (!wpa_s)
- return;
- if (bssid) {
- wpa_printf(
- MSG_DEBUG,
- "Notifying P2P invitation result to hidl control: " MACSTR,
- MAC2STR(bssid));
- } else {
- wpa_printf(
- MSG_DEBUG,
- "Notifying P2P invitation result to hidl control: NULL bssid");
- }
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyP2pInvitationResult(wpa_s, status, bssid);
-}
-
-void wpas_hidl_notify_p2p_provision_discovery(
- struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
- enum p2p_prov_disc_status status, u16 config_methods,
- unsigned int generated_pin)
-{
- if (!wpa_s || !dev_addr)
- return;
-
- wpa_printf(
- MSG_DEBUG,
- "Notifying P2P provision discovery to hidl control " MACSTR,
- MAC2STR(dev_addr));
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyP2pProvisionDiscovery(
- wpa_s, dev_addr, request, status, config_methods, generated_pin);
-}
-
-void wpas_hidl_notify_p2p_sd_response(
- struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
- const u8 *tlvs, size_t tlvs_len)
-{
- if (!wpa_s || !sa || !tlvs)
- return;
-
- wpa_printf(
- MSG_DEBUG,
- "Notifying P2P service discovery response to hidl control " MACSTR,
- MAC2STR(sa));
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyP2pSdResponse(
- wpa_s, sa, update_indic, tlvs, tlvs_len);
-}
-
-void wpas_hidl_notify_ap_sta_authorized(
- struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
-{
- if (!wpa_s || !sta)
- return;
-
- wpa_printf(
- MSG_DEBUG,
- "Notifying P2P AP STA authorized to hidl control " MACSTR,
- MAC2STR(sta));
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyApStaAuthorized(wpa_s, sta, p2p_dev_addr);
-}
-
-void wpas_hidl_notify_ap_sta_deauthorized(
- struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
-{
- if (!wpa_s || !sta)
- return;
-
- wpa_printf(
- MSG_DEBUG,
- "Notifying P2P AP STA deauthorized to hidl control " MACSTR,
- MAC2STR(sta));
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager)
- return;
-
- hidl_manager->notifyApStaDeauthorized(wpa_s, sta, p2p_dev_addr);
-}
diff --git a/wpa_supplicant/hidl/1.0/hidl.h b/wpa_supplicant/hidl/1.0/hidl.h
deleted file mode 100644
index 96631f2..0000000
--- a/wpa_supplicant/hidl/1.0/hidl.h
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef WPA_SUPPLICANT_HIDL_HIDL_H
-#define WPA_SUPPLICANT_HIDL_HIDL_H
-
-#ifdef _cplusplus
-extern "C" {
-#endif // _cplusplus
-
-/**
- * This is the hidl RPC interface entry point to the wpa_supplicant core.
- * This initializes the hidl driver & HidlManager instance and then forwards
- * all the notifcations from the supplicant core to the HidlManager.
- */
-struct wpas_hidl_priv;
-struct wpa_global;
-
-struct wpas_hidl_priv *wpas_hidl_init(struct wpa_global *global);
-void wpas_hidl_deinit(struct wpas_hidl_priv *priv);
-
-#ifdef CONFIG_CTRL_IFACE_HIDL
-int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s);
-int wpas_hidl_unregister_interface(struct wpa_supplicant *wpa_s);
-int wpas_hidl_register_network(
- struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
-int wpas_hidl_unregister_network(
- struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
-int wpas_hidl_notify_state_changed(struct wpa_supplicant *wpa_s);
-int wpas_hidl_notify_network_request(
- struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
- enum wpa_ctrl_req_type rtype, const char *default_txt);
-void wpas_hidl_notify_anqp_query_done(
- struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
- const struct wpa_bss_anqp *anqp);
-void wpas_hidl_notify_hs20_icon_query_done(
- struct wpa_supplicant *wpa_s, const u8 *bssid, const char *file_name,
- const u8 *image, u32 image_length);
-void wpas_hidl_notify_hs20_rx_subscription_remediation(
- struct wpa_supplicant *wpa_s, const char *url, u8 osu_method);
-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_disconnect_reason(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_bssid_changed(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_wps_event_fail(
- struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
- uint16_t error_indication);
-void wpas_hidl_notify_wps_event_success(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_wps_event_pbc_overlap(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_p2p_device_found(
- struct wpa_supplicant *wpa_s, const u8 *addr,
- const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
- u8 peer_wfd_device_info_len);
-void wpas_hidl_notify_p2p_device_lost(
- struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr);
-void wpas_hidl_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_p2p_go_neg_req(
- struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
- u8 go_intent);
-void wpas_hidl_notify_p2p_go_neg_completed(
- struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res);
-void wpas_hidl_notify_p2p_group_formation_failure(
- struct wpa_supplicant *wpa_s, const char *reason);
-void wpas_hidl_notify_p2p_group_started(
- struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, int persistent,
- int client);
-void wpas_hidl_notify_p2p_group_removed(
- struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid,
- const char *role);
-void wpas_hidl_notify_p2p_invitation_received(
- struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
- const u8 *bssid, int id, int op_freq);
-void wpas_hidl_notify_p2p_invitation_result(
- struct wpa_supplicant *wpa_s, int status, const u8 *bssid);
-void wpas_hidl_notify_p2p_provision_discovery(
- struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
- enum p2p_prov_disc_status status, u16 config_methods,
- unsigned int generated_pin);
-void wpas_hidl_notify_p2p_sd_response(
- struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
- const u8 *tlvs, size_t tlvs_len);
-void wpas_hidl_notify_ap_sta_authorized(
- struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr);
-void wpas_hidl_notify_ap_sta_deauthorized(
- struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr);
-#else // CONFIG_CTRL_IFACE_HIDL
-static inline int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s)
-{
- return 0;
-}
-static inline int wpas_hidl_unregister_interface(struct wpa_supplicant *wpa_s)
-{
- return 0;
-}
-static inline int wpas_hidl_register_network(
- struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
-{
- return 0;
-}
-static inline int wpas_hidl_unregister_network(
- struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
-{
- return 0;
-}
-static inline int wpas_hidl_notify_state_changed(struct wpa_supplicant *wpa_s)
-{
- return 0;
-}
-static inline int wpas_hidl_notify_network_request(
- struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
- enum wpa_ctrl_req_type rtype, const char *default_txt)
-{
- return 0;
-}
-static void wpas_hidl_notify_anqp_query_done(
- struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
- const struct wpa_bss_anqp *anqp)
-{
-}
-static void wpas_hidl_notify_hs20_icon_query_done(
- struct wpa_supplicant *wpa_s, const u8 *bssid, const char *file_name,
- const u8 *image, u32 image_length)
-{
-}
-static void wpas_hidl_notify_hs20_rx_subscription_remediation(
- struct wpa_supplicant *wpa_s, const char *url, u8 osu_method)
-{
-}
-static void wpas_hidl_notify_hs20_rx_deauth_imminent_notice(
- struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, 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) {}
-static void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_wps_event_fail(
- struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
- uint16_t error_indication)
-{
-}
-static void wpas_hidl_notify_bssid_changed(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_wps_event_success(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_wps_event_pbc_overlap(struct wpa_supplicant *wpa_s)
-{
-}
-static void wpas_hidl_notify_p2p_device_found(
- struct wpa_supplicant *wpa_s, const u8 *addr,
- const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
- u8 peer_wfd_device_info_len);
-{
-}
-static void wpas_hidl_notify_p2p_device_lost(
- struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr)
-{
-}
-static void wpas_hidl_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_p2p_go_neg_req(
- struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
- u8 go_intent)
-{
-}
-static void wpas_hidl_notify_p2p_go_neg_completed(
- struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res)
-{
-}
-static void wpas_hidl_notify_p2p_group_formation_failure(
- struct wpa_supplicant *wpa_s, const char *reason)
-{
-}
-static void wpas_hidl_notify_p2p_group_started(
- struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, int persistent,
- int client)
-{
-}
-static void wpas_hidl_notify_p2p_group_removed(
- struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, const char *role)
-{
-}
-static void wpas_hidl_notify_p2p_invitation_received(
- struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
- const u8 *bssid, int id, int op_freq)
-{
-}
-static void wpas_hidl_notify_p2p_invitation_result(
- struct wpa_supplicant *wpa_s, int status, const u8 *bssid)
-{
-}
-static void wpas_hidl_notify_p2p_provision_discovery(
- struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
- enum p2p_prov_disc_status status, u16 config_methods,
- unsigned int generated_pin)
-{
-}
-static void wpas_hidl_notify_p2p_sd_response(
- struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
- const u8 *tlvs, size_t tlvs_len)
-{
-}
-static void wpas_hidl_notify_ap_sta_authorized(
- struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
-{
-}
-static void wpas_hidl_notify_ap_sta_deauthorized(
- struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
-{
-}
-#endif // CONFIG_CTRL_IFACE_HIDL
-
-#ifdef _cplusplus
-}
-#endif // _cplusplus
-
-#endif // WPA_SUPPLICANT_HIDL_HIDL_H
diff --git a/wpa_supplicant/hidl/1.0/hidl_manager.cpp b/wpa_supplicant/hidl/1.0/hidl_manager.cpp
deleted file mode 100644
index 4655da2..0000000
--- a/wpa_supplicant/hidl/1.0/hidl_manager.cpp
+++ /dev/null
@@ -1,1777 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include <algorithm>
-#include <regex>
-
-#include "hidl_manager.h"
-#include "misc_utils.h"
-
-extern "C" {
-#include "src/eap_common/eap_sim_common.h"
-}
-
-namespace {
-using android::hardware::hidl_array;
-
-constexpr uint8_t kWfdDeviceInfoLen = 6;
-// GSM-AUTH:<RAND1>:<RAND2>[:<RAND3>]
-constexpr char kGsmAuthRegex2[] = "GSM-AUTH:([0-9a-f]+):([0-9a-f]+)";
-constexpr char kGsmAuthRegex3[] =
- "GSM-AUTH:([0-9a-f]+):([0-9a-f]+):([0-9a-f]+)";
-// UMTS-AUTH:<RAND>:<AUTN>
-constexpr char kUmtsAuthRegex[] = "UMTS-AUTH:([0-9a-f]+):([0-9a-f]+)";
-constexpr size_t kGsmRandLenBytes = GSM_RAND_LEN;
-constexpr size_t kUmtsRandLenBytes = EAP_AKA_RAND_LEN;
-constexpr size_t kUmtsAutnLenBytes = EAP_AKA_AUTN_LEN;
-constexpr u8 kZeroBssid[6] = {0, 0, 0, 0, 0, 0};
-/**
- * Check if the provided |wpa_supplicant| structure represents a P2P iface or
- * not.
- */
-constexpr bool isP2pIface(const struct wpa_supplicant *wpa_s)
-{
- return (wpa_s->global->p2p_init_wpa_s == wpa_s);
-}
-
-/**
- * Creates a unique key for the network using the provided |ifname| and
- * |network_id| to be used in the internal map of |ISupplicantNetwork| objects.
- * This is of the form |ifname|_|network_id|. For ex: "wlan0_1".
- *
- * @param ifname Name of the corresponding interface.
- * @param network_id ID of the corresponding network.
- */
-const std::string getNetworkObjectMapKey(
- const std::string &ifname, int network_id)
-{
- return ifname + "_" + std::to_string(network_id);
-}
-
-/**
- * Add callback to the corresponding list after linking to death on the
- * corresponding hidl object reference.
- */
-template <class CallbackType>
-int registerForDeathAndAddCallbackHidlObjectToList(
- const android::sp<CallbackType> &callback,
- const std::function<void(const android::sp<CallbackType> &)>
- &on_hidl_died_fctor,
- std::vector<android::sp<CallbackType>> &callback_list)
-{
-#if 0 // TODO(b/31632518): HIDL object death notifications.
- auto death_notifier = new CallbackObjectDeathNotifier<CallbackType>(
- callback, on_hidl_died_fctor);
- // Use the |callback.get()| as cookie so that we don't need to
- // store a reference to this |CallbackObjectDeathNotifier| instance
- // to use in |unlinkToDeath| later.
- // NOTE: This may cause an immediate callback if the object is already
- // dead, so add it to the list before we register for callback!
- if (android::hardware::IInterface::asBinder(callback)->linkToDeath(
- death_notifier, callback.get()) != android::OK) {
- wpa_printf(
- MSG_ERROR,
- "Error registering for death notification for "
- "supplicant callback object");
- callback_list.erase(
- std::remove(
- callback_list.begin(), callback_list.end(), callback),
- callback_list.end());
- return 1;
- }
-#endif // TODO(b/31632518): HIDL object death notifications.
- callback_list.push_back(callback);
- return 0;
-}
-
-template <class ObjectType>
-int addHidlObjectToMap(
- const std::string &key, const android::sp<ObjectType> object,
- std::map<const std::string, android::sp<ObjectType>> &object_map)
-{
- // Return failure if we already have an object for that |key|.
- if (object_map.find(key) != object_map.end())
- return 1;
- object_map[key] = object;
- if (!object_map[key].get())
- return 1;
- return 0;
-}
-
-template <class ObjectType>
-int removeHidlObjectFromMap(
- const std::string &key,
- std::map<const std::string, android::sp<ObjectType>> &object_map)
-{
- // Return failure if we dont have an object for that |key|.
- const auto &object_iter = object_map.find(key);
- if (object_iter == object_map.end())
- return 1;
- object_iter->second->invalidate();
- object_map.erase(object_iter);
- return 0;
-}
-
-template <class CallbackType>
-int addIfaceCallbackHidlObjectToMap(
- const std::string &ifname, const android::sp<CallbackType> &callback,
- const std::function<void(const android::sp<CallbackType> &)>
- &on_hidl_died_fctor,
- std::map<const std::string, std::vector<android::sp<CallbackType>>>
- &callbacks_map)
-{
- if (ifname.empty())
- return 1;
-
- auto iface_callback_map_iter = callbacks_map.find(ifname);
- if (iface_callback_map_iter == callbacks_map.end())
- return 1;
- auto &iface_callback_list = iface_callback_map_iter->second;
-
- // Register for death notification before we add it to our list.
- return registerForDeathAndAddCallbackHidlObjectToList<CallbackType>(
- callback, on_hidl_died_fctor, iface_callback_list);
-}
-
-template <class CallbackType>
-int addNetworkCallbackHidlObjectToMap(
- const std::string &ifname, int network_id,
- const android::sp<CallbackType> &callback,
- const std::function<void(const android::sp<CallbackType> &)>
- &on_hidl_died_fctor,
- std::map<const std::string, std::vector<android::sp<CallbackType>>>
- &callbacks_map)
-{
- if (ifname.empty() || network_id < 0)
- return 1;
-
- // 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 1;
- auto &network_callback_list = network_callback_map_iter->second;
-
- // Register for death notification before we add it to our list.
- return registerForDeathAndAddCallbackHidlObjectToList<CallbackType>(
- callback, on_hidl_died_fctor, network_callback_list);
-}
-
-template <class CallbackType>
-int removeAllIfaceCallbackHidlObjectsFromMap(
- const std::string &ifname,
- std::map<const std::string, std::vector<android::sp<CallbackType>>>
- &callbacks_map)
-{
- auto iface_callback_map_iter = callbacks_map.find(ifname);
- if (iface_callback_map_iter == callbacks_map.end())
- return 1;
-#if 0 // TODO(b/31632518): HIDL object death notifications.
- const auto &iface_callback_list = iface_callback_map_iter->second;
- for (const auto &callback : iface_callback_list) {
- if (android::hardware::IInterface::asBinder(callback)
- ->unlinkToDeath(nullptr, callback.get()) !=
- android::OK) {
- wpa_printf(
- MSG_ERROR,
- "Error deregistering for death notification for "
- "iface callback object");
- }
- }
-#endif // TODO(b/31632518): HIDL object death notifications.
- callbacks_map.erase(iface_callback_map_iter);
- return 0;
-}
-
-template <class CallbackType>
-int removeAllNetworkCallbackHidlObjectsFromMap(
- const std::string &network_key,
- std::map<const std::string, std::vector<android::sp<CallbackType>>>
- &callbacks_map)
-{
- auto network_callback_map_iter = callbacks_map.find(network_key);
- if (network_callback_map_iter == callbacks_map.end())
- return 1;
-#if 0 // TODO(b/31632518): HIDL object death notifications.
- const auto &network_callback_list = network_callback_map_iter->second;
- for (const auto &callback : network_callback_list) {
- if (android::hardware::IInterface::asBinder(callback)
- ->unlinkToDeath(nullptr, callback.get()) !=
- android::OK) {
- wpa_printf(
- MSG_ERROR,
- "Error deregistering for death "
- "notification for "
- "network callback object");
- }
- }
-#endif // TODO(b/31632518): HIDL object death notifications.
- callbacks_map.erase(network_callback_map_iter);
- return 0;
-}
-
-template <class CallbackType>
-void removeIfaceCallbackHidlObjectFromMap(
- const std::string &ifname, const android::sp<CallbackType> &callback,
- std::map<const std::string, std::vector<android::sp<CallbackType>>>
- &callbacks_map)
-{
- if (ifname.empty())
- return;
-
- auto iface_callback_map_iter = callbacks_map.find(ifname);
- if (iface_callback_map_iter == callbacks_map.end())
- return;
-
- auto &iface_callback_list = iface_callback_map_iter->second;
- iface_callback_list.erase(
- std::remove(
- iface_callback_list.begin(), iface_callback_list.end(),
- callback),
- iface_callback_list.end());
-}
-
-template <class CallbackType>
-void removeNetworkCallbackHidlObjectFromMap(
- const std::string &ifname, int network_id,
- const android::sp<CallbackType> &callback,
- std::map<const std::string, std::vector<android::sp<CallbackType>>>
- &callbacks_map)
-{
- if (ifname.empty() || network_id < 0)
- 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;
-
- auto &network_callback_list = network_callback_map_iter->second;
- network_callback_list.erase(
- std::remove(
- network_callback_list.begin(), network_callback_list.end(),
- callback),
- network_callback_list.end());
-}
-
-template <class CallbackType>
-void callWithEachIfaceCallback(
- const std::string &ifname,
- const std::function<
- android::hardware::Return<void>(android::sp<CallbackType>)> &method,
- const std::map<const std::string, std::vector<android::sp<CallbackType>>>
- &callbacks_map)
-{
- if (ifname.empty())
- return;
-
- auto iface_callback_map_iter = callbacks_map.find(ifname);
- if (iface_callback_map_iter == callbacks_map.end())
- return;
- const auto &iface_callback_list = iface_callback_map_iter->second;
- for (const auto &callback : iface_callback_list) {
- if (!method(callback).isOk()) {
- wpa_printf(
- MSG_ERROR, "Failed to invoke HIDL iface callback");
- }
- }
-}
-
-template <class CallbackType>
-void callWithEachNetworkCallback(
- const std::string &ifname, int network_id,
- const std::function<
- android::hardware::Return<void>(android::sp<CallbackType>)> &method,
- const std::map<const std::string, std::vector<android::sp<CallbackType>>>
- &callbacks_map)
-{
- if (ifname.empty() || network_id < 0)
- 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) {
- if (!method(callback).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)
-{
- std::smatch matches;
- std::regex params_gsm_regex2(kGsmAuthRegex2);
- std::regex params_gsm_regex3(kGsmAuthRegex3);
- if (!std::regex_match(params_str, matches, params_gsm_regex3) &&
- !std::regex_match(params_str, matches, params_gsm_regex2)) {
- return 1;
- }
- for (uint32_t i = 1; i < matches.size(); i++) {
- hidl_array<uint8_t, kGsmRandLenBytes> rand;
- const auto &match = matches[i];
- WPA_ASSERT(match.size() >= 2 * rand.size());
- if (hexstr2bin(match.str().c_str(), rand.data(), rand.size())) {
- wpa_printf(
- MSG_ERROR, "Failed to parse GSM auth params");
- return 1;
- }
- out_rands->push_back(rand);
- }
- return 0;
-}
-
-int parseUmtsAuthNetworkRequest(
- const std::string ¶ms_str,
- hidl_array<uint8_t, kUmtsRandLenBytes> *out_rand,
- hidl_array<uint8_t, kUmtsAutnLenBytes> *out_autn)
-{
- std::smatch matches;
- std::regex params_umts_regex(kUmtsAuthRegex);
- if (!std::regex_match(params_str, matches, params_umts_regex)) {
- return 1;
- }
- WPA_ASSERT(matches[1].size() >= 2 * out_rand->size());
- if (hexstr2bin(
- matches[1].str().c_str(), out_rand->data(), out_rand->size())) {
- wpa_printf(MSG_ERROR, "Failed to parse UMTS auth params");
- return 1;
- }
- WPA_ASSERT(matches[2].size() >= 2 * out_autn->size());
- if (hexstr2bin(
- matches[2].str().c_str(), out_autn->data(), out_autn->size())) {
- wpa_printf(MSG_ERROR, "Failed to parse UMTS auth params");
- return 1;
- }
- return 0;
-}
-} // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-
-HidlManager *HidlManager::instance_ = NULL;
-
-HidlManager *HidlManager::getInstance()
-{
- if (!instance_)
- instance_ = new HidlManager();
- return instance_;
-}
-
-void HidlManager::destroyInstance()
-{
- if (instance_)
- delete instance_;
- instance_ = NULL;
-}
-
-int HidlManager::registerHidlService(struct wpa_global *global)
-{
- // Create the main hidl service object and register it.
- supplicant_object_ = new Supplicant(global);
- if (supplicant_object_->registerAsService() != android::NO_ERROR) {
- return 1;
- }
- if (!supplicant_object_->ensureConfigFileExists()) {
- // If config file does not exist, we cannot start supplicant.
- return 1;
- }
- return 0;
-}
-
-/**
- * Register an interface to hidl manager.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::registerInterface(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s)
- return 1;
-
- if (isP2pIface(wpa_s)) {
- if (addHidlObjectToMap<P2pIface>(
- wpa_s->ifname,
- new P2pIface(wpa_s->global, wpa_s->ifname),
- p2p_iface_object_map_)) {
- wpa_printf(
- MSG_ERROR,
- "Failed to register P2P interface with HIDL "
- "control: %s",
- wpa_s->ifname);
- return 1;
- }
- p2p_iface_callbacks_map_[wpa_s->ifname] =
- std::vector<android::sp<ISupplicantP2pIfaceCallback>>();
- } else {
- if (addHidlObjectToMap<StaIface>(
- wpa_s->ifname,
- new StaIface(wpa_s->global, wpa_s->ifname),
- sta_iface_object_map_)) {
- wpa_printf(
- MSG_ERROR,
- "Failed to register STA interface with HIDL "
- "control: %s",
- wpa_s->ifname);
- return 1;
- }
- sta_iface_callbacks_map_[wpa_s->ifname] =
- std::vector<android::sp<ISupplicantStaIfaceCallback>>();
- }
-
- // Invoke the |onInterfaceCreated| method on all registered callbacks.
- callWithEachSupplicantCallback(std::bind(
- &ISupplicantCallback::onInterfaceCreated, std::placeholders::_1,
- wpa_s->ifname));
- return 0;
-}
-
-/**
- * Unregister an interface from hidl manager.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::unregisterInterface(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s)
- return 1;
-
- if (isP2pIface(wpa_s)) {
- if (removeHidlObjectFromMap(
- wpa_s->ifname, p2p_iface_object_map_)) {
- wpa_printf(
- MSG_ERROR,
- "Failed to unregister P2P interface with HIDL "
- "control: %s",
- wpa_s->ifname);
- return 1;
- }
- if (removeAllIfaceCallbackHidlObjectsFromMap(
- wpa_s->ifname, p2p_iface_callbacks_map_)) {
- return 1;
- }
- } else {
- if (removeHidlObjectFromMap(
- wpa_s->ifname, sta_iface_object_map_)) {
- wpa_printf(
- MSG_ERROR,
- "Failed to unregister STA interface with HIDL "
- "control: %s",
- wpa_s->ifname);
- return 1;
- }
- if (removeAllIfaceCallbackHidlObjectsFromMap(
- wpa_s->ifname, sta_iface_callbacks_map_)) {
- return 1;
- }
- }
-
- // Invoke the |onInterfaceRemoved| method on all registered callbacks.
- callWithEachSupplicantCallback(std::bind(
- &ISupplicantCallback::onInterfaceRemoved, std::placeholders::_1,
- wpa_s->ifname));
- return 0;
-}
-
-/**
- * Register a network to hidl manager.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
- * the network is added.
- * @param ssid |wpa_ssid| struct corresponding to the network being added.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::registerNetwork(
- struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
-{
- if (!wpa_s || !ssid)
- return 1;
-
- // Generate the key to be used to lookup the network.
- const std::string network_key =
- getNetworkObjectMapKey(wpa_s->ifname, ssid->id);
-
- if (isP2pIface(wpa_s)) {
- if (addHidlObjectToMap<P2pNetwork>(
- network_key,
- new P2pNetwork(wpa_s->global, wpa_s->ifname, ssid->id),
- p2p_network_object_map_)) {
- wpa_printf(
- MSG_ERROR,
- "Failed to register P2P network with HIDL "
- "control: %d",
- ssid->id);
- return 1;
- }
- p2p_network_callbacks_map_[network_key] =
- std::vector<android::sp<ISupplicantP2pNetworkCallback>>();
- // Invoke the |onNetworkAdded| method on all registered
- // callbacks.
- callWithEachP2pIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantP2pIfaceCallback::onNetworkAdded,
- std::placeholders::_1, ssid->id));
- } else {
- if (addHidlObjectToMap<StaNetwork>(
- network_key,
- new StaNetwork(wpa_s->global, wpa_s->ifname, ssid->id),
- sta_network_object_map_)) {
- wpa_printf(
- MSG_ERROR,
- "Failed to register STA network with HIDL "
- "control: %d",
- ssid->id);
- return 1;
- }
- sta_network_callbacks_map_[network_key] =
- std::vector<android::sp<ISupplicantStaNetworkCallback>>();
- // Invoke the |onNetworkAdded| method on all registered
- // callbacks.
- callWithEachStaIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantStaIfaceCallback::onNetworkAdded,
- std::placeholders::_1, ssid->id));
- }
- return 0;
-}
-
-/**
- * Unregister a network from hidl manager.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
- * the network is added.
- * @param ssid |wpa_ssid| struct corresponding to the network being added.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::unregisterNetwork(
- struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
-{
- if (!wpa_s || !ssid)
- return 1;
-
- // Generate the key to be used to lookup the network.
- const std::string network_key =
- getNetworkObjectMapKey(wpa_s->ifname, ssid->id);
-
- if (isP2pIface(wpa_s)) {
- if (removeHidlObjectFromMap(
- network_key, p2p_network_object_map_)) {
- wpa_printf(
- MSG_ERROR,
- "Failed to unregister P2P network with HIDL "
- "control: %d",
- ssid->id);
- return 1;
- }
- if (removeAllNetworkCallbackHidlObjectsFromMap(
- network_key, p2p_network_callbacks_map_))
- return 1;
-
- // Invoke the |onNetworkRemoved| method on all registered
- // callbacks.
- callWithEachP2pIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantP2pIfaceCallback::onNetworkRemoved,
- std::placeholders::_1, ssid->id));
- } else {
- if (removeHidlObjectFromMap(
- network_key, sta_network_object_map_)) {
- wpa_printf(
- MSG_ERROR,
- "Failed to unregister STA network with HIDL "
- "control: %d",
- ssid->id);
- return 1;
- }
- if (removeAllNetworkCallbackHidlObjectsFromMap(
- network_key, sta_network_callbacks_map_))
- return 1;
-
- // Invoke the |onNetworkRemoved| method on all registered
- // callbacks.
- callWithEachStaIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantStaIfaceCallback::onNetworkRemoved,
- std::placeholders::_1, ssid->id));
- }
- return 0;
-}
-
-/**
- * Notify all listeners about any state changes on a particular interface.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
- * the state change event occured.
- */
-int HidlManager::notifyStateChange(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s)
- return 1;
-
- if (sta_iface_object_map_.find(wpa_s->ifname) ==
- sta_iface_object_map_.end())
- return 1;
-
- // Invoke the |onStateChanged| method on all registered callbacks.
- uint32_t hidl_network_id = UINT32_MAX;
- std::vector<uint8_t> hidl_ssid;
- if (wpa_s->current_ssid) {
- hidl_network_id = wpa_s->current_ssid->id;
- hidl_ssid.assign(
- wpa_s->current_ssid->ssid,
- wpa_s->current_ssid->ssid + wpa_s->current_ssid->ssid_len);
- }
- uint8_t *bssid;
- // wpa_supplicant sets the |pending_bssid| field when it starts a
- // connection. Only after association state does it update the |bssid|
- // field. So, in the HIDL callback send the appropriate bssid.
- if (wpa_s->wpa_state <= WPA_ASSOCIATED) {
- bssid = wpa_s->pending_bssid;
- } else {
- bssid = wpa_s->bssid;
- }
- callWithEachStaIfaceCallback(
- wpa_s->ifname, std::bind(
- &ISupplicantStaIfaceCallback::onStateChanged,
- std::placeholders::_1,
- static_cast<ISupplicantStaIfaceCallback::State>(
- wpa_s->wpa_state),
- bssid, hidl_network_id, hidl_ssid));
- return 0;
-}
-
-/**
- * Notify all listeners about a request on a particular network.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
- * the network is present.
- * @param ssid |wpa_ssid| struct corresponding to the network.
- * @param type type of request.
- * @param param addition params associated with the request.
- */
-int HidlManager::notifyNetworkRequest(
- struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int type,
- const char *param)
-{
- if (!wpa_s || !ssid)
- return 1;
-
- const std::string network_key =
- getNetworkObjectMapKey(wpa_s->ifname, ssid->id);
- if (sta_network_object_map_.find(network_key) ==
- sta_network_object_map_.end())
- return 1;
-
- if (type == WPA_CTRL_REQ_EAP_IDENTITY) {
- callWithEachStaNetworkCallback(
- wpa_s->ifname, ssid->id,
- std::bind(
- &ISupplicantStaNetworkCallback::
- onNetworkEapIdentityRequest,
- std::placeholders::_1));
- return 0;
- }
- if (type == WPA_CTRL_REQ_SIM) {
- std::vector<hidl_array<uint8_t, 16>> gsm_rands;
- hidl_array<uint8_t, 16> umts_rand;
- hidl_array<uint8_t, 16> umts_autn;
- if (!parseGsmAuthNetworkRequest(param, &gsm_rands)) {
- ISupplicantStaNetworkCallback::
- NetworkRequestEapSimGsmAuthParams hidl_params;
- hidl_params.rands = gsm_rands;
- callWithEachStaNetworkCallback(
- wpa_s->ifname, ssid->id,
- std::bind(
- &ISupplicantStaNetworkCallback::
- onNetworkEapSimGsmAuthRequest,
- std::placeholders::_1, hidl_params));
- return 0;
- }
- if (!parseUmtsAuthNetworkRequest(
- param, &umts_rand, &umts_autn)) {
- ISupplicantStaNetworkCallback::
- NetworkRequestEapSimUmtsAuthParams hidl_params;
- hidl_params.rand = umts_rand;
- hidl_params.autn = umts_autn;
- callWithEachStaNetworkCallback(
- wpa_s->ifname, ssid->id,
- std::bind(
- &ISupplicantStaNetworkCallback::
- onNetworkEapSimUmtsAuthRequest,
- std::placeholders::_1, hidl_params));
- return 0;
- }
- }
- return 1;
-}
-
-/**
- * Notify all listeners about the end of an ANQP query.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface.
- * @param bssid BSSID of the access point.
- * @param result Result of the operation ("SUCCESS" or "FAILURE").
- * @param anqp |wpa_bss_anqp| ANQP data fetched.
- */
-void HidlManager::notifyAnqpQueryDone(
- struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
- const struct wpa_bss_anqp *anqp)
-{
- if (!wpa_s || !bssid || !result || !anqp)
- return;
-
- if (sta_iface_object_map_.find(wpa_s->ifname) ==
- sta_iface_object_map_.end())
- return;
-
- ISupplicantStaIfaceCallback::AnqpData hidl_anqp_data;
- ISupplicantStaIfaceCallback::Hs20AnqpData hidl_hs20_anqp_data;
- if (std::string(result) == "SUCCESS") {
- hidl_anqp_data.venueName =
- misc_utils::convertWpaBufToVector(anqp->venue_name);
- hidl_anqp_data.roamingConsortium =
- misc_utils::convertWpaBufToVector(anqp->roaming_consortium);
- hidl_anqp_data.ipAddrTypeAvailability =
- misc_utils::convertWpaBufToVector(
- anqp->ip_addr_type_availability);
- hidl_anqp_data.naiRealm =
- misc_utils::convertWpaBufToVector(anqp->nai_realm);
- hidl_anqp_data.anqp3gppCellularNetwork =
- misc_utils::convertWpaBufToVector(anqp->anqp_3gpp);
- hidl_anqp_data.domainName =
- misc_utils::convertWpaBufToVector(anqp->domain_name);
-
- hidl_hs20_anqp_data.operatorFriendlyName =
- misc_utils::convertWpaBufToVector(
- anqp->hs20_operator_friendly_name);
- hidl_hs20_anqp_data.wanMetrics =
- misc_utils::convertWpaBufToVector(anqp->hs20_wan_metrics);
- hidl_hs20_anqp_data.connectionCapability =
- misc_utils::convertWpaBufToVector(
- anqp->hs20_connection_capability);
- hidl_hs20_anqp_data.osuProvidersList =
- misc_utils::convertWpaBufToVector(
- anqp->hs20_osu_providers_list);
- }
-
- callWithEachStaIfaceCallback(
- wpa_s->ifname, std::bind(
- &ISupplicantStaIfaceCallback::onAnqpQueryDone,
- std::placeholders::_1, bssid, hidl_anqp_data,
- hidl_hs20_anqp_data));
-}
-
-/**
- * Notify all listeners about the end of an HS20 icon query.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface.
- * @param bssid BSSID of the access point.
- * @param file_name Name of the icon file.
- * @param image Raw bytes of the icon file.
- * @param image_length Size of the the icon file.
- */
-void HidlManager::notifyHs20IconQueryDone(
- struct wpa_supplicant *wpa_s, const u8 *bssid, const char *file_name,
- const u8 *image, u32 image_length)
-{
- if (!wpa_s || !bssid || !file_name || !image)
- return;
-
- if (sta_iface_object_map_.find(wpa_s->ifname) ==
- sta_iface_object_map_.end())
- return;
-
- callWithEachStaIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantStaIfaceCallback::onHs20IconQueryDone,
- std::placeholders::_1, bssid, file_name,
- std::vector<uint8_t>(image, image + image_length)));
-}
-
-/**
- * Notify all listeners about the reception of HS20 subscription
- * remediation notification from the server.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface.
- * @param url URL of the server.
- * @param osu_method OSU method (OMA_DM or SOAP_XML_SPP).
- */
-void HidlManager::notifyHs20RxSubscriptionRemediation(
- struct wpa_supplicant *wpa_s, const char *url, u8 osu_method)
-{
- if (!wpa_s || !url)
- return;
-
- if (sta_iface_object_map_.find(wpa_s->ifname) ==
- sta_iface_object_map_.end())
- return;
-
- ISupplicantStaIfaceCallback::OsuMethod hidl_osu_method = {};
- if (osu_method & 0x1) {
- hidl_osu_method =
- ISupplicantStaIfaceCallback::OsuMethod::OMA_DM;
- } else if (osu_method & 0x2) {
- hidl_osu_method =
- ISupplicantStaIfaceCallback::OsuMethod::SOAP_XML_SPP;
- }
- callWithEachStaIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantStaIfaceCallback::onHs20SubscriptionRemediation,
- std::placeholders::_1, wpa_s->bssid, hidl_osu_method, url));
-}
-
-/**
- * Notify all listeners about the reception of HS20 immient 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.
- */
-void HidlManager::notifyHs20RxDeauthImminentNotice(
- struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url)
-{
- if (!wpa_s || !url)
- return;
-
- if (sta_iface_object_map_.find(wpa_s->ifname) ==
- sta_iface_object_map_.end())
- return;
-
- callWithEachStaIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantStaIfaceCallback::onHs20DeauthImminentNotice,
- std::placeholders::_1, wpa_s->bssid, code, reauth_delay, url));
-}
-
-/**
- * Notify all listeners about the reason code for disconnection from the
- * currently connected network.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
- * the network is present.
- */
-void HidlManager::notifyDisconnectReason(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s)
- return;
-
- if (sta_iface_object_map_.find(wpa_s->ifname) ==
- sta_iface_object_map_.end())
- return;
-
- const u8 *bssid = wpa_s->bssid;
- if (is_zero_ether_addr(bssid)) {
- bssid = wpa_s->pending_bssid;
- }
-
- callWithEachStaIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantStaIfaceCallback::onDisconnected,
- std::placeholders::_1, bssid, wpa_s->disconnect_reason < 0,
- static_cast<ISupplicantStaIfaceCallback::ReasonCode>(
- abs(wpa_s->disconnect_reason))));
-}
-
-/**
- * Notify all listeners about association reject from the access point to which
- * we are attempting to connect.
- *
- * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
- * the network is present.
- */
-void HidlManager::notifyAssocReject(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s)
- return;
-
- if (sta_iface_object_map_.find(wpa_s->ifname) ==
- sta_iface_object_map_.end())
- return;
-
- const u8 *bssid = wpa_s->bssid;
- if (is_zero_ether_addr(bssid)) {
- bssid = wpa_s->pending_bssid;
- }
-
- callWithEachStaIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantStaIfaceCallback::onAssociationRejected,
- std::placeholders::_1, bssid,
- static_cast<ISupplicantStaIfaceCallback::StatusCode>(
- wpa_s->assoc_status_code),
- wpa_s->assoc_timed_out == 1));
-}
-
-void HidlManager::notifyAuthTimeout(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s)
- return;
-
- const std::string ifname(wpa_s->ifname);
- if (sta_iface_object_map_.find(ifname) == sta_iface_object_map_.end())
- return;
-
- const u8 *bssid = wpa_s->bssid;
- if (is_zero_ether_addr(bssid)) {
- bssid = wpa_s->pending_bssid;
- }
- callWithEachStaIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantStaIfaceCallback::onAuthenticationTimeout,
- std::placeholders::_1, bssid));
-}
-
-void HidlManager::notifyBssidChanged(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s)
- return;
-
- const std::string ifname(wpa_s->ifname);
- if (sta_iface_object_map_.find(ifname) == sta_iface_object_map_.end())
- return;
-
- // wpa_supplicant does not explicitly give us the reason for bssid
- // change, but we figure that out from what is set out of |wpa_s->bssid|
- // & |wpa_s->pending_bssid|.
- const u8 *bssid;
- ISupplicantStaIfaceCallback::BssidChangeReason reason;
- if (is_zero_ether_addr(wpa_s->bssid) &&
- !is_zero_ether_addr(wpa_s->pending_bssid)) {
- bssid = wpa_s->pending_bssid;
- reason =
- ISupplicantStaIfaceCallback::BssidChangeReason::ASSOC_START;
- } else if (
- !is_zero_ether_addr(wpa_s->bssid) &&
- is_zero_ether_addr(wpa_s->pending_bssid)) {
- bssid = wpa_s->bssid;
- reason = ISupplicantStaIfaceCallback::BssidChangeReason::
- ASSOC_COMPLETE;
- } else if (
- is_zero_ether_addr(wpa_s->bssid) &&
- is_zero_ether_addr(wpa_s->pending_bssid)) {
- bssid = wpa_s->pending_bssid;
- reason =
- ISupplicantStaIfaceCallback::BssidChangeReason::DISASSOC;
- } else {
- wpa_printf(MSG_ERROR, "Unknown bssid change reason");
- return;
- }
-
- callWithEachStaIfaceCallback(
- wpa_s->ifname, std::bind(
- &ISupplicantStaIfaceCallback::onBssidChanged,
- std::placeholders::_1, reason, bssid));
-}
-
-void HidlManager::notifyWpsEventFail(
- struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
- uint16_t error_indication)
-{
- if (!wpa_s || !peer_macaddr)
- return;
-
- if (sta_iface_object_map_.find(wpa_s->ifname) ==
- sta_iface_object_map_.end())
- return;
-
- callWithEachStaIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantStaIfaceCallback::onWpsEventFail,
- std::placeholders::_1, peer_macaddr,
- static_cast<ISupplicantStaIfaceCallback::WpsConfigError>(
- config_error),
- static_cast<ISupplicantStaIfaceCallback::WpsErrorIndication>(
- error_indication)));
-}
-
-void HidlManager::notifyWpsEventSuccess(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s)
- return;
-
- if (sta_iface_object_map_.find(wpa_s->ifname) ==
- sta_iface_object_map_.end())
- return;
-
- callWithEachStaIfaceCallback(
- wpa_s->ifname, std::bind(
- &ISupplicantStaIfaceCallback::onWpsEventSuccess,
- std::placeholders::_1));
-}
-
-void HidlManager::notifyWpsEventPbcOverlap(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s)
- return;
-
- if (sta_iface_object_map_.find(wpa_s->ifname) ==
- sta_iface_object_map_.end())
- return;
-
- callWithEachStaIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantStaIfaceCallback::onWpsEventPbcOverlap,
- std::placeholders::_1));
-}
-
-void HidlManager::notifyP2pDeviceFound(
- struct wpa_supplicant *wpa_s, const u8 *addr,
- const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
- u8 peer_wfd_device_info_len)
-{
- if (!wpa_s || !addr || !info)
- return;
-
- if (p2p_iface_object_map_.find(wpa_s->ifname) ==
- p2p_iface_object_map_.end())
- return;
-
- std::array<uint8_t, kWfdDeviceInfoLen> hidl_peer_wfd_device_info{};
- if (peer_wfd_device_info) {
- if (peer_wfd_device_info_len != kWfdDeviceInfoLen) {
- wpa_printf(
- MSG_ERROR, "Unexpected WFD device info len: %d",
- peer_wfd_device_info_len);
- } else {
- os_memcpy(
- hidl_peer_wfd_device_info.data(),
- peer_wfd_device_info, kWfdDeviceInfoLen);
- }
- }
-
- callWithEachP2pIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantP2pIfaceCallback::onDeviceFound,
- std::placeholders::_1, addr, info->p2p_device_addr,
- info->pri_dev_type, info->device_name, info->config_methods,
- info->dev_capab, info->group_capab, hidl_peer_wfd_device_info));
-}
-
-void HidlManager::notifyP2pDeviceLost(
- struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr)
-{
- if (!wpa_s || !p2p_device_addr)
- return;
-
- if (p2p_iface_object_map_.find(wpa_s->ifname) ==
- p2p_iface_object_map_.end())
- return;
-
- callWithEachP2pIfaceCallback(
- wpa_s->ifname, std::bind(
- &ISupplicantP2pIfaceCallback::onDeviceLost,
- std::placeholders::_1, p2p_device_addr));
-}
-
-void HidlManager::notifyP2pFindStopped(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s)
- return;
-
- if (p2p_iface_object_map_.find(wpa_s->ifname) ==
- p2p_iface_object_map_.end())
- return;
-
- callWithEachP2pIfaceCallback(
- wpa_s->ifname, std::bind(
- &ISupplicantP2pIfaceCallback::onFindStopped,
- std::placeholders::_1));
-}
-
-void HidlManager::notifyP2pGoNegReq(
- struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
- u8 /* go_intent */)
-{
- if (!wpa_s || !src_addr)
- return;
-
- if (p2p_iface_object_map_.find(wpa_s->ifname) ==
- p2p_iface_object_map_.end())
- return;
-
- callWithEachP2pIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantP2pIfaceCallback::onGoNegotiationRequest,
- std::placeholders::_1, src_addr,
- static_cast<ISupplicantP2pIfaceCallback::WpsDevPasswordId>(
- dev_passwd_id)));
-}
-
-void HidlManager::notifyP2pGoNegCompleted(
- struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res)
-{
- if (!wpa_s || !res)
- return;
-
- if (p2p_iface_object_map_.find(wpa_s->ifname) ==
- p2p_iface_object_map_.end())
- return;
-
- callWithEachP2pIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantP2pIfaceCallback::onGoNegotiationCompleted,
- std::placeholders::_1,
- static_cast<ISupplicantP2pIfaceCallback::P2pStatusCode>(
- res->status)));
-}
-
-void HidlManager::notifyP2pGroupFormationFailure(
- struct wpa_supplicant *wpa_s, const char *reason)
-{
- if (!wpa_s || !reason)
- return;
-
- if (p2p_iface_object_map_.find(wpa_s->ifname) ==
- p2p_iface_object_map_.end())
- return;
-
- callWithEachP2pIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantP2pIfaceCallback::onGroupFormationFailure,
- std::placeholders::_1, reason));
-}
-
-void HidlManager::notifyP2pGroupStarted(
- struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid, int persistent, int client)
-{
- if (!wpa_group_s || !wpa_group_s->parent || !ssid)
- return;
-
- // For group notifications, need to use the parent iface for callbacks.
- struct wpa_supplicant *wpa_s = wpa_group_s->parent;
- if (p2p_iface_object_map_.find(wpa_s->ifname) ==
- p2p_iface_object_map_.end())
- return;
-
- uint32_t hidl_freq = wpa_group_s->current_bss
- ? wpa_group_s->current_bss->freq
- : wpa_group_s->assoc_freq;
- std::array<uint8_t, 32> hidl_psk;
- if (ssid->psk_set) {
- os_memcpy(hidl_psk.data(), ssid->psk, 32);
- }
- bool hidl_is_go = (client == 0 ? true : false);
- bool hidl_is_persistent = (persistent == 1 ? true : false);
-
- callWithEachP2pIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantP2pIfaceCallback::onGroupStarted,
- std::placeholders::_1, wpa_group_s->ifname, hidl_is_go,
- std::vector<uint8_t>{ssid->ssid, ssid->ssid + ssid->ssid_len},
- hidl_freq, hidl_psk, ssid->passphrase, wpa_group_s->go_dev_addr,
- hidl_is_persistent));
-}
-
-void HidlManager::notifyP2pGroupRemoved(
- struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid,
- const char *role)
-{
- if (!wpa_group_s || !wpa_group_s->parent || !ssid || !role)
- return;
-
- // For group notifications, need to use the parent iface for callbacks.
- struct wpa_supplicant *wpa_s = wpa_group_s->parent;
- if (p2p_iface_object_map_.find(wpa_s->ifname) ==
- p2p_iface_object_map_.end())
- return;
-
- bool hidl_is_go = (std::string(role) == "GO");
-
- callWithEachP2pIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantP2pIfaceCallback::onGroupRemoved,
- std::placeholders::_1, wpa_group_s->ifname, hidl_is_go));
-}
-
-void HidlManager::notifyP2pInvitationReceived(
- struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
- const u8 *bssid, int id, int op_freq)
-{
- if (!wpa_s || !sa || !go_dev_addr || !bssid)
- return;
-
- if (p2p_iface_object_map_.find(wpa_s->ifname) ==
- p2p_iface_object_map_.end())
- return;
-
- SupplicantNetworkId hidl_network_id;
- if (id < 0) {
- hidl_network_id = UINT32_MAX;
- }
- hidl_network_id = id;
-
- callWithEachP2pIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantP2pIfaceCallback::onInvitationReceived,
- std::placeholders::_1, sa, go_dev_addr, bssid, hidl_network_id,
- op_freq));
-}
-
-void HidlManager::notifyP2pInvitationResult(
- struct wpa_supplicant *wpa_s, int status, const u8 *bssid)
-{
- if (!wpa_s)
- return;
-
- if (p2p_iface_object_map_.find(wpa_s->ifname) ==
- p2p_iface_object_map_.end())
- return;
-
- callWithEachP2pIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantP2pIfaceCallback::onInvitationResult,
- std::placeholders::_1, bssid ? bssid : kZeroBssid,
- static_cast<ISupplicantP2pIfaceCallback::P2pStatusCode>(
- status)));
-}
-
-void HidlManager::notifyP2pProvisionDiscovery(
- struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
- enum p2p_prov_disc_status status, u16 config_methods,
- unsigned int generated_pin)
-{
- if (!wpa_s || !dev_addr)
- return;
-
- if (p2p_iface_object_map_.find(wpa_s->ifname) ==
- p2p_iface_object_map_.end())
- return;
-
- std::string hidl_generated_pin;
- if (generated_pin > 0) {
- hidl_generated_pin =
- misc_utils::convertWpsPinToString(generated_pin);
- }
- bool hidl_is_request = (request == 1 ? true : false);
-
- callWithEachP2pIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantP2pIfaceCallback::onProvisionDiscoveryCompleted,
- std::placeholders::_1, dev_addr, hidl_is_request,
- static_cast<ISupplicantP2pIfaceCallback::P2pProvDiscStatusCode>(
- status),
- config_methods, hidl_generated_pin));
-}
-
-void HidlManager::notifyP2pSdResponse(
- struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
- const u8 *tlvs, size_t tlvs_len)
-{
- if (!wpa_s || !sa || !tlvs)
- return;
-
- if (p2p_iface_object_map_.find(wpa_s->ifname) ==
- p2p_iface_object_map_.end())
- return;
-
- callWithEachP2pIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantP2pIfaceCallback::onServiceDiscoveryResponse,
- std::placeholders::_1, sa, update_indic,
- std::vector<uint8_t>{tlvs, tlvs + tlvs_len}));
-}
-
-void HidlManager::notifyApStaAuthorized(
- struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
-{
- if (!wpa_s || !wpa_s->parent || !sta)
- return;
- if (p2p_iface_object_map_.find(wpa_s->parent->ifname) ==
- p2p_iface_object_map_.end())
- return;
- callWithEachP2pIfaceCallback(
- wpa_s->parent->ifname, std::bind(
- &ISupplicantP2pIfaceCallback::onStaAuthorized,
- std::placeholders::_1, sta, p2p_dev_addr ? p2p_dev_addr : kZeroBssid));
-}
-
-void HidlManager::notifyApStaDeauthorized(
- struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
-{
- if (!wpa_s || !wpa_s->parent || !sta)
- return;
- if (p2p_iface_object_map_.find(wpa_s->parent->ifname) ==
- p2p_iface_object_map_.end())
- return;
-
- callWithEachP2pIfaceCallback(
- wpa_s->parent->ifname, std::bind(
- &ISupplicantP2pIfaceCallback::onStaDeauthorized,
- std::placeholders::_1, sta, p2p_dev_addr ? p2p_dev_addr : kZeroBssid));
-}
-
-void HidlManager::notifyExtRadioWorkStart(
- struct wpa_supplicant *wpa_s, uint32_t id)
-{
- if (!wpa_s)
- return;
-
- if (sta_iface_object_map_.find(wpa_s->ifname) ==
- sta_iface_object_map_.end())
- return;
-
- callWithEachStaIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantStaIfaceCallback::onExtRadioWorkStart,
- std::placeholders::_1, id));
-}
-
-void HidlManager::notifyExtRadioWorkTimeout(
- struct wpa_supplicant *wpa_s, uint32_t id)
-{
- if (!wpa_s)
- return;
-
- if (sta_iface_object_map_.find(wpa_s->ifname) ==
- sta_iface_object_map_.end())
- return;
-
- callWithEachStaIfaceCallback(
- wpa_s->ifname,
- std::bind(
- &ISupplicantStaIfaceCallback::onExtRadioWorkTimeout,
- std::placeholders::_1, id));
-}
-
-/**
- * Retrieve the |ISupplicantP2pIface| hidl object reference using the provided
- * ifname.
- *
- * @param ifname Name of the corresponding interface.
- * @param iface_object Hidl reference corresponding to the iface.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::getP2pIfaceHidlObjectByIfname(
- const std::string &ifname, android::sp<ISupplicantP2pIface> *iface_object)
-{
- if (ifname.empty() || !iface_object)
- return 1;
-
- auto iface_object_iter = p2p_iface_object_map_.find(ifname);
- if (iface_object_iter == p2p_iface_object_map_.end())
- return 1;
-
- *iface_object = iface_object_iter->second;
- return 0;
-}
-
-/**
- * Retrieve the |ISupplicantStaIface| hidl object reference using the provided
- * ifname.
- *
- * @param ifname Name of the corresponding interface.
- * @param iface_object Hidl reference corresponding to the iface.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::getStaIfaceHidlObjectByIfname(
- const std::string &ifname, android::sp<ISupplicantStaIface> *iface_object)
-{
- if (ifname.empty() || !iface_object)
- return 1;
-
- auto iface_object_iter = sta_iface_object_map_.find(ifname);
- if (iface_object_iter == sta_iface_object_map_.end())
- return 1;
-
- *iface_object = iface_object_iter->second;
- return 0;
-}
-
-/**
- * Retrieve the |ISupplicantP2pNetwork| hidl object reference using the provided
- * ifname and network_id.
- *
- * @param ifname Name of the corresponding interface.
- * @param network_id ID of the corresponding network.
- * @param network_object Hidl reference corresponding to the network.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::getP2pNetworkHidlObjectByIfnameAndNetworkId(
- const std::string &ifname, int network_id,
- android::sp<ISupplicantP2pNetwork> *network_object)
-{
- if (ifname.empty() || network_id < 0 || !network_object)
- return 1;
-
- // Generate the key to be used to lookup the network.
- const std::string network_key =
- getNetworkObjectMapKey(ifname, network_id);
-
- auto network_object_iter = p2p_network_object_map_.find(network_key);
- if (network_object_iter == p2p_network_object_map_.end())
- return 1;
-
- *network_object = network_object_iter->second;
- return 0;
-}
-
-/**
- * Retrieve the |ISupplicantStaNetwork| hidl object reference using the provided
- * ifname and network_id.
- *
- * @param ifname Name of the corresponding interface.
- * @param network_id ID of the corresponding network.
- * @param network_object Hidl reference corresponding to the network.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::getStaNetworkHidlObjectByIfnameAndNetworkId(
- const std::string &ifname, int network_id,
- android::sp<ISupplicantStaNetwork> *network_object)
-{
- if (ifname.empty() || network_id < 0 || !network_object)
- return 1;
-
- // Generate the key to be used to lookup the network.
- const std::string network_key =
- getNetworkObjectMapKey(ifname, network_id);
-
- auto network_object_iter = sta_network_object_map_.find(network_key);
- if (network_object_iter == sta_network_object_map_.end())
- return 1;
-
- *network_object = network_object_iter->second;
- return 0;
-}
-
-/**
- * Add a new |ISupplicantCallback| hidl object reference to our
- * global callback list.
- *
- * @param callback Hidl reference of the |ISupplicantCallback| object.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::addSupplicantCallbackHidlObject(
- const android::sp<ISupplicantCallback> &callback)
-{
- // Register for death notification before we add it to our list.
- auto on_hidl_died_fctor = std::bind(
- &HidlManager::removeSupplicantCallbackHidlObject, this,
- std::placeholders::_1);
- return registerForDeathAndAddCallbackHidlObjectToList<
- ISupplicantCallback>(
- callback, on_hidl_died_fctor, supplicant_callbacks_);
-}
-
-/**
- * Add a new iface callback hidl object reference to our
- * interface callback list.
- *
- * @param ifname Name of the corresponding interface.
- * @param callback Hidl reference of the callback object.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::addP2pIfaceCallbackHidlObject(
- const std::string &ifname,
- const android::sp<ISupplicantP2pIfaceCallback> &callback)
-{
- const std::function<void(
- const android::sp<ISupplicantP2pIfaceCallback> &)>
- on_hidl_died_fctor = std::bind(
- &HidlManager::removeP2pIfaceCallbackHidlObject, this, ifname,
- std::placeholders::_1);
- return addIfaceCallbackHidlObjectToMap(
- ifname, callback, on_hidl_died_fctor, p2p_iface_callbacks_map_);
-}
-
-/**
- * Add a new iface callback hidl object reference to our
- * interface callback list.
- *
- * @param ifname Name of the corresponding interface.
- * @param callback Hidl reference of the callback object.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::addStaIfaceCallbackHidlObject(
- const std::string &ifname,
- const android::sp<ISupplicantStaIfaceCallback> &callback)
-{
- const std::function<void(
- const android::sp<ISupplicantStaIfaceCallback> &)>
- on_hidl_died_fctor = std::bind(
- &HidlManager::removeStaIfaceCallbackHidlObject, this, ifname,
- std::placeholders::_1);
- return addIfaceCallbackHidlObjectToMap(
- ifname, callback, on_hidl_died_fctor, sta_iface_callbacks_map_);
-}
-
-/**
- * Add a new network callback hidl object reference to our network callback
- * list.
- *
- * @param ifname Name of the corresponding interface.
- * @param network_id ID of the corresponding network.
- * @param callback Hidl reference of the callback object.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::addP2pNetworkCallbackHidlObject(
- const std::string &ifname, int network_id,
- const android::sp<ISupplicantP2pNetworkCallback> &callback)
-{
- const std::function<void(
- const android::sp<ISupplicantP2pNetworkCallback> &)>
- on_hidl_died_fctor = std::bind(
- &HidlManager::removeP2pNetworkCallbackHidlObject, this, ifname,
- network_id, std::placeholders::_1);
- return addNetworkCallbackHidlObjectToMap(
- ifname, network_id, callback, on_hidl_died_fctor,
- p2p_network_callbacks_map_);
-}
-
-/**
- * Add a new network callback hidl object reference to our network callback
- * list.
- *
- * @param ifname Name of the corresponding interface.
- * @param network_id ID of the corresponding network.
- * @param callback Hidl reference of the callback object.
- *
- * @return 0 on success, 1 on failure.
- */
-int HidlManager::addStaNetworkCallbackHidlObject(
- const std::string &ifname, int network_id,
- const android::sp<ISupplicantStaNetworkCallback> &callback)
-{
- const std::function<void(
- const android::sp<ISupplicantStaNetworkCallback> &)>
- on_hidl_died_fctor = std::bind(
- &HidlManager::removeStaNetworkCallbackHidlObject, this, ifname,
- network_id, std::placeholders::_1);
- return addNetworkCallbackHidlObjectToMap(
- ifname, network_id, callback, on_hidl_died_fctor,
- sta_network_callbacks_map_);
-}
-
-/**
- * Removes the provided |ISupplicantCallback| hidl object reference
- * from our global callback list.
- *
- * @param callback Hidl reference of the |ISupplicantCallback| object.
- */
-void HidlManager::removeSupplicantCallbackHidlObject(
- const android::sp<ISupplicantCallback> &callback)
-{
- supplicant_callbacks_.erase(
- std::remove(
- supplicant_callbacks_.begin(), supplicant_callbacks_.end(),
- callback),
- supplicant_callbacks_.end());
-}
-
-/**
- * Removes the provided iface callback hidl object reference from
- * our interface callback list.
- *
- * @param ifname Name of the corresponding interface.
- * @param callback Hidl reference of the callback object.
- */
-void HidlManager::removeP2pIfaceCallbackHidlObject(
- const std::string &ifname,
- const android::sp<ISupplicantP2pIfaceCallback> &callback)
-{
- return removeIfaceCallbackHidlObjectFromMap(
- ifname, callback, p2p_iface_callbacks_map_);
-}
-
-/**
- * Removes the provided iface callback hidl object reference from
- * our interface callback list.
- *
- * @param ifname Name of the corresponding interface.
- * @param callback Hidl reference of the callback object.
- */
-void HidlManager::removeStaIfaceCallbackHidlObject(
- const std::string &ifname,
- const android::sp<ISupplicantStaIfaceCallback> &callback)
-{
- return removeIfaceCallbackHidlObjectFromMap(
- ifname, callback, sta_iface_callbacks_map_);
-}
-
-/**
- * Removes the provided network callback hidl object reference from
- * our network callback list.
- *
- * @param ifname Name of the corresponding interface.
- * @param network_id ID of the corresponding network.
- * @param callback Hidl reference of the callback object.
- */
-void HidlManager::removeP2pNetworkCallbackHidlObject(
- const std::string &ifname, int network_id,
- const android::sp<ISupplicantP2pNetworkCallback> &callback)
-{
- return removeNetworkCallbackHidlObjectFromMap(
- ifname, network_id, callback, p2p_network_callbacks_map_);
-}
-
-/**
- * Removes the provided network callback hidl object reference from
- * our network callback list.
- *
- * @param ifname Name of the corresponding interface.
- * @param network_id ID of the corresponding network.
- * @param callback Hidl reference of the callback object.
- */
-void HidlManager::removeStaNetworkCallbackHidlObject(
- const std::string &ifname, int network_id,
- const android::sp<ISupplicantStaNetworkCallback> &callback)
-{
- return removeNetworkCallbackHidlObjectFromMap(
- ifname, network_id, callback, sta_network_callbacks_map_);
-}
-
-/**
- * Helper function to invoke the provided callback method on all the
- * registered |ISupplicantCallback| callback hidl objects.
- *
- * @param method Pointer to the required hidl method from
- * |ISupplicantCallback|.
- */
-void HidlManager::callWithEachSupplicantCallback(
- const std::function<Return<void>(android::sp<ISupplicantCallback>)> &method)
-{
- for (const auto &callback : supplicant_callbacks_) {
- if (!method(callback).isOk()) {
- wpa_printf(MSG_ERROR, "Failed to invoke HIDL callback");
- }
- }
-}
-
-/**
- * Helper fucntion to invoke the provided callback method on all the
- * registered iface callback hidl objects for the specified
- * |ifname|.
- *
- * @param ifname Name of the corresponding interface.
- * @param method Pointer to the required hidl method from
- * |ISupplicantIfaceCallback|.
- */
-void HidlManager::callWithEachP2pIfaceCallback(
- const std::string &ifname,
- const std::function<Return<void>(android::sp<ISupplicantP2pIfaceCallback>)>
- &method)
-{
- callWithEachIfaceCallback(ifname, method, p2p_iface_callbacks_map_);
-}
-
-/**
- * Helper fucntion to invoke the provided callback method on all the
- * registered iface callback hidl objects for the specified
- * |ifname|.
- *
- * @param ifname Name of the corresponding interface.
- * @param method Pointer to the required hidl method from
- * |ISupplicantIfaceCallback|.
- */
-void HidlManager::callWithEachStaIfaceCallback(
- const std::string &ifname,
- const std::function<Return<void>(android::sp<ISupplicantStaIfaceCallback>)>
- &method)
-{
- callWithEachIfaceCallback(ifname, method, sta_iface_callbacks_map_);
-}
-
-/**
- * Helper function to invoke the provided callback method on all the
- * registered network callback hidl objects for the specified
- * |ifname| & |network_id|.
- *
- * @param ifname Name of the corresponding interface.
- * @param network_id ID of the corresponding network.
- * @param method Pointer to the required hidl method from
- * |ISupplicantP2pNetworkCallback| or |ISupplicantStaNetworkCallback| .
- */
-void HidlManager::callWithEachP2pNetworkCallback(
- const std::string &ifname, int network_id,
- const std::function<
- Return<void>(android::sp<ISupplicantP2pNetworkCallback>)> &method)
-{
- callWithEachNetworkCallback(
- ifname, network_id, method, p2p_network_callbacks_map_);
-}
-
-/**
- * Helper function to invoke the provided callback method on all the
- * registered network callback hidl objects for the specified
- * |ifname| & |network_id|.
- *
- * @param ifname Name of the corresponding interface.
- * @param network_id ID of the corresponding network.
- * @param method Pointer to the required hidl method from
- * |ISupplicantP2pNetworkCallback| or |ISupplicantStaNetworkCallback| .
- */
-void HidlManager::callWithEachStaNetworkCallback(
- const std::string &ifname, int network_id,
- const std::function<
- Return<void>(android::sp<ISupplicantStaNetworkCallback>)> &method)
-{
- callWithEachNetworkCallback(
- ifname, network_id, method, sta_network_callbacks_map_);
-}
-} // namespace implementation
-} // namespace V1_0
-} // namespace wifi
-} // namespace supplicant
-} // namespace hardware
-} // namespace android
diff --git a/wpa_supplicant/hidl/1.0/hidl_manager.h b/wpa_supplicant/hidl/1.0/hidl_manager.h
deleted file mode 100644
index 9d9527c..0000000
--- a/wpa_supplicant/hidl/1.0/hidl_manager.h
+++ /dev/null
@@ -1,678 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef WPA_SUPPLICANT_HIDL_HIDL_MANAGER_H
-#define WPA_SUPPLICANT_HIDL_HIDL_MANAGER_H
-
-#include <map>
-#include <string>
-
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantCallback.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIfaceCallback.h>
-#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 "p2p_iface.h"
-#include "p2p_network.h"
-#include "sta_iface.h"
-#include "sta_network.h"
-#include "supplicant.h"
-
-extern "C" {
-#include "utils/common.h"
-#include "utils/includes.h"
-#include "wpa_supplicant_i.h"
-#include "driver_i.h"
-}
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-
-/**
- * HidlManager is responsible for managing the lifetime of all
- * hidl objects created by wpa_supplicant. This is a singleton
- * class which is created by the supplicant core and can be used
- * to get references to the hidl objects.
- */
-class HidlManager
-{
-public:
- static HidlManager *getInstance();
- static void destroyInstance();
-
- // Methods called from wpa_supplicant core.
- int registerHidlService(struct wpa_global *global);
- int registerInterface(struct wpa_supplicant *wpa_s);
- int unregisterInterface(struct wpa_supplicant *wpa_s);
- int registerNetwork(
- struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
- int unregisterNetwork(
- struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
- int notifyStateChange(struct wpa_supplicant *wpa_s);
- int notifyNetworkRequest(
- struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int type,
- const char *param);
- void notifyAnqpQueryDone(
- struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
- const struct wpa_bss_anqp *anqp);
- void notifyHs20IconQueryDone(
- struct wpa_supplicant *wpa_s, const u8 *bssid,
- const char *file_name, const u8 *image, u32 image_length);
- void notifyHs20RxSubscriptionRemediation(
- 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);
- void notifyDisconnectReason(struct wpa_supplicant *wpa_s);
- void notifyAssocReject(struct wpa_supplicant *wpa_s);
- void notifyAuthTimeout(struct wpa_supplicant *wpa_s);
- void notifyBssidChanged(struct wpa_supplicant *wpa_s);
- void notifyWpsEventFail(
- struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr,
- uint16_t config_error, uint16_t error_indication);
- void notifyWpsEventSuccess(struct wpa_supplicant *wpa_s);
- void notifyWpsEventPbcOverlap(struct wpa_supplicant *wpa_s);
- void notifyP2pDeviceFound(
- struct wpa_supplicant *wpa_s, const u8 *addr,
- const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
- u8 peer_wfd_device_info_len);
- void notifyP2pDeviceLost(
- struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr);
- void notifyP2pFindStopped(struct wpa_supplicant *wpa_s);
- void notifyP2pGoNegReq(
- struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
- u8 go_intent);
- void notifyP2pGoNegCompleted(
- struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res);
- void notifyP2pGroupFormationFailure(
- struct wpa_supplicant *wpa_s, const char *reason);
- void notifyP2pGroupStarted(
- struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid,
- int persistent, int client);
- void notifyP2pGroupRemoved(
- struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid,
- const char *role);
- void notifyP2pInvitationReceived(
- struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
- const u8 *bssid, int id, int op_freq);
- void notifyP2pInvitationResult(
- struct wpa_supplicant *wpa_s, int status, const u8 *bssid);
- void notifyP2pProvisionDiscovery(
- struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
- enum p2p_prov_disc_status status, u16 config_methods,
- unsigned int generated_pin);
- void notifyP2pSdResponse(
- struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
- const u8 *tlvs, size_t tlvs_len);
- void notifyApStaAuthorized(
- struct wpa_supplicant *wpa_s, const u8 *sta,
- const u8 *p2p_dev_addr);
- void notifyApStaDeauthorized(
- struct wpa_supplicant *wpa_s, const u8 *sta,
- const u8 *p2p_dev_addr);
-
- // Methods called from hidl objects.
- void notifyExtRadioWorkStart(struct wpa_supplicant *wpa_s, uint32_t id);
- void notifyExtRadioWorkTimeout(
- struct wpa_supplicant *wpa_s, uint32_t id);
-
- int getP2pIfaceHidlObjectByIfname(
- const std::string &ifname,
- android::sp<ISupplicantP2pIface> *iface_object);
- int getStaIfaceHidlObjectByIfname(
- const std::string &ifname,
- android::sp<ISupplicantStaIface> *iface_object);
- int getP2pNetworkHidlObjectByIfnameAndNetworkId(
- const std::string &ifname, int network_id,
- android::sp<ISupplicantP2pNetwork> *network_object);
- int getStaNetworkHidlObjectByIfnameAndNetworkId(
- const std::string &ifname, int network_id,
- android::sp<ISupplicantStaNetwork> *network_object);
- int addSupplicantCallbackHidlObject(
- const android::sp<ISupplicantCallback> &callback);
- int addP2pIfaceCallbackHidlObject(
- const std::string &ifname,
- const android::sp<ISupplicantP2pIfaceCallback> &callback);
- int addStaIfaceCallbackHidlObject(
- const std::string &ifname,
- const android::sp<ISupplicantStaIfaceCallback> &callback);
- int addP2pNetworkCallbackHidlObject(
- const std::string &ifname, int network_id,
- const android::sp<ISupplicantP2pNetworkCallback> &callback);
- int addStaNetworkCallbackHidlObject(
- const std::string &ifname, int network_id,
- const android::sp<ISupplicantStaNetworkCallback> &callback);
-
-private:
- HidlManager() = default;
- ~HidlManager() = default;
- HidlManager(const HidlManager &) = default;
- HidlManager &operator=(const HidlManager &) = default;
-
- void removeSupplicantCallbackHidlObject(
- const android::sp<ISupplicantCallback> &callback);
- void removeP2pIfaceCallbackHidlObject(
- const std::string &ifname,
- const android::sp<ISupplicantP2pIfaceCallback> &callback);
- void removeStaIfaceCallbackHidlObject(
- const std::string &ifname,
- const android::sp<ISupplicantStaIfaceCallback> &callback);
- void removeP2pNetworkCallbackHidlObject(
- const std::string &ifname, int network_id,
- const android::sp<ISupplicantP2pNetworkCallback> &callback);
- void removeStaNetworkCallbackHidlObject(
- const std::string &ifname, int network_id,
- const android::sp<ISupplicantStaNetworkCallback> &callback);
-
- void callWithEachSupplicantCallback(
- const std::function<android::hardware::Return<void>(
- android::sp<ISupplicantCallback>)> &method);
- void callWithEachP2pIfaceCallback(
- const std::string &ifname,
- const std::function<android::hardware::Return<void>(
- android::sp<ISupplicantP2pIfaceCallback>)> &method);
- void callWithEachStaIfaceCallback(
- const std::string &ifname,
- const std::function<android::hardware::Return<void>(
- android::sp<ISupplicantStaIfaceCallback>)> &method);
- void callWithEachP2pNetworkCallback(
- const std::string &ifname, int network_id,
- const std::function<android::hardware::Return<void>(
- android::sp<ISupplicantP2pNetworkCallback>)> &method);
- void callWithEachStaNetworkCallback(
- const std::string &ifname, int network_id,
- const std::function<android::hardware::Return<void>(
- android::sp<ISupplicantStaNetworkCallback>)> &method);
-
- // Singleton instance of this class.
- static HidlManager *instance_;
- // The main hidl service object.
- android::sp<Supplicant> supplicant_object_;
- // Map of all the P2P interface specific hidl objects controlled by
- // wpa_supplicant. This map is keyed in by the corresponding
- // |ifname|.
- std::map<const std::string, android::sp<P2pIface>>
- p2p_iface_object_map_;
- // Map of all the STA interface specific hidl objects controlled by
- // wpa_supplicant. This map is keyed in by the corresponding
- // |ifname|.
- std::map<const std::string, android::sp<StaIface>>
- sta_iface_object_map_;
- // Map of all the P2P network specific hidl objects controlled by
- // wpa_supplicant. This map is keyed in by the corresponding
- // |ifname| & |network_id|.
- std::map<const std::string, android::sp<P2pNetwork>>
- p2p_network_object_map_;
- // Map of all the STA network specific hidl objects controlled by
- // wpa_supplicant. This map is keyed in by the corresponding
- // |ifname| & |network_id|.
- std::map<const std::string, android::sp<StaNetwork>>
- sta_network_object_map_;
-
- // Callback registered for the main hidl service object.
- std::vector<android::sp<ISupplicantCallback>> supplicant_callbacks_;
- // Map of all the callbacks registered for P2P interface specific
- // hidl objects controlled by wpa_supplicant. This map is keyed in by
- // the corresponding |ifname|.
- std::map<
- const std::string,
- std::vector<android::sp<ISupplicantP2pIfaceCallback>>>
- p2p_iface_callbacks_map_;
- // Map of all the callbacks registered for STA interface specific
- // hidl objects controlled by wpa_supplicant. This map is keyed in by
- // the corresponding |ifname|.
- std::map<
- const std::string,
- std::vector<android::sp<ISupplicantStaIfaceCallback>>>
- sta_iface_callbacks_map_;
- // Map of all the callbacks registered for P2P network specific
- // hidl objects controlled by wpa_supplicant. This map is keyed in by
- // the corresponding |ifname| & |network_id|.
- std::map<
- const std::string,
- std::vector<android::sp<ISupplicantP2pNetworkCallback>>>
- p2p_network_callbacks_map_;
- // Map of all the callbacks registered for STA network specific
- // hidl objects controlled by wpa_supplicant. This map is keyed in by
- // the corresponding |ifname| & |network_id|.
- std::map<
- const std::string,
- std::vector<android::sp<ISupplicantStaNetworkCallback>>>
- sta_network_callbacks_map_;
-
-#if 0 // TODO(b/31632518): HIDL object death notifications.
- /**
- * Helper class used to deregister the callback object reference from
- * our callback list on the death of the hidl object.
- * This class stores a reference of the callback hidl object and a
- * function to be called to indicate the death of the hidl object.
- */
- template <class CallbackType>
- class CallbackObjectDeathNotifier
- : public android::hardware::IBinder::DeathRecipient
- {
- public:
- CallbackObjectDeathNotifier(
- const android::sp<CallbackType> &callback,
- const std::function<void(const android::sp<CallbackType> &)>
- &on_hidl_died)
- : callback_(callback), on_hidl_died_(on_hidl_died)
- {
- }
- void binderDied(const android::wp<android::hardware::IBinder>
- & /* who */) override
- {
- on_hidl_died_(callback_);
- }
-
- private:
- // The callback hidl object reference.
- const android::sp<CallbackType> callback_;
- // Callback function to be called when the hidl dies.
- const std::function<void(const android::sp<CallbackType> &)>
- on_hidl_died_;
- };
-#endif
-};
-
-// The hidl interface uses some values which are the same as internal ones to
-// avoid nasty runtime conversion functions. So, adding compile time asserts
-// to guard against any internal changes breaking the hidl interface.
-static_assert(
- static_cast<uint32_t>(ISupplicant::DebugLevel::EXCESSIVE) == MSG_EXCESSIVE,
- "Debug level value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicant::DebugLevel::ERROR) == MSG_ERROR,
- "Debug level value mismatch");
-
-static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::NONE) ==
- WPA_KEY_MGMT_NONE,
- "KeyMgmt value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK) ==
- WPA_KEY_MGMT_PSK,
- "KeyMgmt value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP) ==
- WPA_KEY_MGMT_IEEE8021X,
- "KeyMgmt value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X) ==
- WPA_KEY_MGMT_IEEE8021X_NO_WPA,
- "KeyMgmt value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::FT_EAP) ==
- WPA_KEY_MGMT_FT_IEEE8021X,
- "KeyMgmt value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::FT_PSK) ==
- WPA_KEY_MGMT_FT_PSK,
- "KeyMgmt value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::OSEN) ==
- WPA_KEY_MGMT_OSEN,
- "KeyMgmt value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::WPA) ==
- WPA_PROTO_WPA,
- "Proto value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::RSN) ==
- WPA_PROTO_RSN,
- "Proto value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::OSEN) ==
- WPA_PROTO_OSEN,
- "Proto value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::OPEN) ==
- WPA_AUTH_ALG_OPEN,
- "AuthAlg value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::SHARED) ==
- WPA_AUTH_ALG_SHARED,
- "AuthAlg value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::LEAP) ==
- WPA_AUTH_ALG_LEAP,
- "AuthAlg value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::WEP40) ==
- WPA_CIPHER_WEP40,
- "GroupCipher value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::WEP104) ==
- WPA_CIPHER_WEP104,
- "GroupCipher value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::TKIP) ==
- WPA_CIPHER_TKIP,
- "GroupCipher value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::CCMP) ==
- WPA_CIPHER_CCMP,
- "GroupCipher value mismatch");
-static_assert(
- static_cast<uint32_t>(
- ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED) ==
- WPA_CIPHER_GTK_NOT_USED,
- "GroupCipher value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::NONE) ==
- WPA_CIPHER_NONE,
- "PairwiseCipher value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::TKIP) ==
- WPA_CIPHER_TKIP,
- "PairwiseCipher value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::CCMP) ==
- WPA_CIPHER_CCMP,
- "PairwiseCipher value mismatch");
-
-static_assert(
- static_cast<uint32_t>(ISupplicantStaIfaceCallback::State::DISCONNECTED) ==
- WPA_DISCONNECTED,
- "State value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaIfaceCallback::State::COMPLETED) ==
- WPA_COMPLETED,
- "State value mismatch");
-
-static_assert(
- static_cast<uint32_t>(ISupplicantStaIface::AnqpInfoId::VENUE_NAME) ==
- ANQP_VENUE_NAME,
- "ANQP ID value mismatch");
-static_assert(
- static_cast<uint32_t>(
- ISupplicantStaIface::AnqpInfoId::ROAMING_CONSORTIUM) ==
- ANQP_ROAMING_CONSORTIUM,
- "ANQP ID value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaIface::AnqpInfoId::NAI_REALM) ==
- ANQP_NAI_REALM,
- "ANQP ID value mismatch");
-static_assert(
- static_cast<uint32_t>(
- ISupplicantStaIface::AnqpInfoId::IP_ADDR_TYPE_AVAILABILITY) ==
- ANQP_IP_ADDR_TYPE_AVAILABILITY,
- "ANQP ID value mismatch");
-static_assert(
- static_cast<uint32_t>(
- ISupplicantStaIface::AnqpInfoId::ANQP_3GPP_CELLULAR_NETWORK) ==
- ANQP_3GPP_CELLULAR_NETWORK,
- "ANQP ID value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaIface::AnqpInfoId::DOMAIN_NAME) ==
- ANQP_DOMAIN_NAME,
- "ANQP ID value mismatch");
-static_assert(
- static_cast<uint32_t>(
- ISupplicantStaIface::Hs20AnqpSubtypes::OPERATOR_FRIENDLY_NAME) ==
- HS20_STYPE_OPERATOR_FRIENDLY_NAME,
- "HS Subtype value mismatch");
-static_assert(
- static_cast<uint32_t>(ISupplicantStaIface::Hs20AnqpSubtypes::WAN_METRICS) ==
- HS20_STYPE_WAN_METRICS,
- "HS Subtype value mismatch");
-static_assert(
- static_cast<uint32_t>(
- ISupplicantStaIface::Hs20AnqpSubtypes::CONNECTION_CAPABILITY) ==
- HS20_STYPE_CONNECTION_CAPABILITY,
- "HS Subtype value mismatch");
-static_assert(
- static_cast<uint32_t>(
- ISupplicantStaIface::Hs20AnqpSubtypes::OSU_PROVIDERS_LIST) ==
- HS20_STYPE_OSU_PROVIDERS_LIST,
- "HS Subtype value mismatch");
-
-static_assert(
- static_cast<uint16_t>(
- ISupplicantStaIfaceCallback::WpsConfigError::NO_ERROR) ==
- WPS_CFG_NO_ERROR,
- "Wps config error value mismatch");
-static_assert(
- static_cast<uint16_t>(ISupplicantStaIfaceCallback::WpsConfigError::
- PUBLIC_KEY_HASH_MISMATCH) ==
- WPS_CFG_PUBLIC_KEY_HASH_MISMATCH,
- "Wps config error value mismatch");
-static_assert(
- static_cast<uint16_t>(
- ISupplicantStaIfaceCallback::WpsErrorIndication::NO_ERROR) ==
- WPS_EI_NO_ERROR,
- "Wps error indication value mismatch");
-static_assert(
- static_cast<uint16_t>(
- ISupplicantStaIfaceCallback::WpsErrorIndication::AUTH_FAILURE) ==
- WPS_EI_AUTH_FAILURE,
- "Wps error indication value mismatch");
-
-static_assert(
- static_cast<uint32_t>(WpsConfigMethods::USBA) == WPS_CONFIG_USBA,
- "Wps config value mismatch");
-static_assert(
- static_cast<uint32_t>(WpsConfigMethods::ETHERNET) == WPS_CONFIG_ETHERNET,
- "Wps config value mismatch");
-static_assert(
- static_cast<uint32_t>(WpsConfigMethods::LABEL) == WPS_CONFIG_LABEL,
- "Wps config value mismatch");
-static_assert(
- static_cast<uint32_t>(WpsConfigMethods::DISPLAY) == WPS_CONFIG_DISPLAY,
- "Wps config value mismatch");
-static_assert(
- static_cast<uint32_t>(WpsConfigMethods::INT_NFC_TOKEN) ==
- WPS_CONFIG_INT_NFC_TOKEN,
- "Wps config value mismatch");
-static_assert(
- static_cast<uint32_t>(WpsConfigMethods::EXT_NFC_TOKEN) ==
- WPS_CONFIG_EXT_NFC_TOKEN,
- "Wps config value mismatch");
-static_assert(
- static_cast<uint32_t>(WpsConfigMethods::NFC_INTERFACE) ==
- WPS_CONFIG_NFC_INTERFACE,
- "Wps config value mismatch");
-static_assert(
- static_cast<uint32_t>(WpsConfigMethods::PUSHBUTTON) ==
- WPS_CONFIG_PUSHBUTTON,
- "Wps config value mismatch");
-static_assert(
- static_cast<uint32_t>(WpsConfigMethods::KEYPAD) == WPS_CONFIG_KEYPAD,
- "Wps config value mismatch");
-static_assert(
- static_cast<uint32_t>(WpsConfigMethods::VIRT_PUSHBUTTON) ==
- WPS_CONFIG_VIRT_PUSHBUTTON,
- "Wps config value mismatch");
-static_assert(
- static_cast<uint32_t>(WpsConfigMethods::PHY_PUSHBUTTON) ==
- WPS_CONFIG_PHY_PUSHBUTTON,
- "Wps config value mismatch");
-static_assert(
- static_cast<uint32_t>(WpsConfigMethods::P2PS) == WPS_CONFIG_P2PS,
- "Wps config value mismatch");
-static_assert(
- static_cast<uint32_t>(WpsConfigMethods::VIRT_DISPLAY) ==
- WPS_CONFIG_VIRT_DISPLAY,
- "Wps config value mismatch");
-static_assert(
- static_cast<uint32_t>(WpsConfigMethods::PHY_DISPLAY) ==
- WPS_CONFIG_PHY_DISPLAY,
- "Wps config value mismatch");
-
-static_assert(
- static_cast<uint32_t>(P2pGroupCapabilityMask::GROUP_OWNER) ==
- P2P_GROUP_CAPAB_GROUP_OWNER,
- "P2P capability value mismatch");
-static_assert(
- static_cast<uint32_t>(P2pGroupCapabilityMask::PERSISTENT_GROUP) ==
- P2P_GROUP_CAPAB_PERSISTENT_GROUP,
- "P2P capability value mismatch");
-static_assert(
- static_cast<uint32_t>(P2pGroupCapabilityMask::GROUP_LIMIT) ==
- P2P_GROUP_CAPAB_GROUP_LIMIT,
- "P2P capability value mismatch");
-static_assert(
- static_cast<uint32_t>(P2pGroupCapabilityMask::INTRA_BSS_DIST) ==
- P2P_GROUP_CAPAB_INTRA_BSS_DIST,
- "P2P capability value mismatch");
-static_assert(
- static_cast<uint32_t>(P2pGroupCapabilityMask::CROSS_CONN) ==
- P2P_GROUP_CAPAB_CROSS_CONN,
- "P2P capability value mismatch");
-static_assert(
- static_cast<uint32_t>(P2pGroupCapabilityMask::PERSISTENT_RECONN) ==
- P2P_GROUP_CAPAB_PERSISTENT_RECONN,
- "P2P capability value mismatch");
-static_assert(
- static_cast<uint32_t>(P2pGroupCapabilityMask::GROUP_FORMATION) ==
- P2P_GROUP_CAPAB_GROUP_FORMATION,
- "P2P capability value mismatch");
-
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::WpsDevPasswordId::DEFAULT) ==
- DEV_PW_DEFAULT,
- "Wps dev password id value mismatch");
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::WpsDevPasswordId::USER_SPECIFIED) ==
- DEV_PW_USER_SPECIFIED,
- "Wps dev password id value mismatch");
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::WpsDevPasswordId::MACHINE_SPECIFIED) ==
- DEV_PW_MACHINE_SPECIFIED,
- "Wps dev password id value mismatch");
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::WpsDevPasswordId::REKEY) == DEV_PW_REKEY,
- "Wps dev password id value mismatch");
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::WpsDevPasswordId::PUSHBUTTON) ==
- DEV_PW_PUSHBUTTON,
- "Wps dev password id value mismatch");
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::WpsDevPasswordId::REGISTRAR_SPECIFIED) ==
- DEV_PW_REGISTRAR_SPECIFIED,
- "Wps dev password id value mismatch");
-static_assert(
- static_cast<uint16_t>(ISupplicantP2pIfaceCallback::WpsDevPasswordId::
- NFC_CONNECTION_HANDOVER) ==
- DEV_PW_NFC_CONNECTION_HANDOVER,
- "Wps dev password id value mismatch");
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::WpsDevPasswordId::P2PS_DEFAULT) ==
- DEV_PW_P2PS_DEFAULT,
- "Wps dev password id value mismatch");
-
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::P2pStatusCode::SUCCESS) == P2P_SC_SUCCESS,
- "P2P status code value mismatch");
-static_assert(
- static_cast<uint16_t>(ISupplicantP2pIfaceCallback::P2pStatusCode::
- FAIL_INFO_CURRENTLY_UNAVAILABLE) ==
- P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE,
- "P2P status code value mismatch");
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_INCOMPATIBLE_PARAMS) ==
- P2P_SC_FAIL_INCOMPATIBLE_PARAMS,
- "P2P status code value mismatch");
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_LIMIT_REACHED) ==
- P2P_SC_FAIL_LIMIT_REACHED,
- "P2P status code value mismatch");
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_INVALID_PARAMS) ==
- P2P_SC_FAIL_INVALID_PARAMS,
- "P2P status code value mismatch");
-static_assert(
- static_cast<uint16_t>(ISupplicantP2pIfaceCallback::P2pStatusCode::
- FAIL_UNABLE_TO_ACCOMMODATE) ==
- P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE,
- "P2P status code value mismatch");
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_PREV_PROTOCOL_ERROR) ==
- P2P_SC_FAIL_PREV_PROTOCOL_ERROR,
- "P2P status code value mismatch");
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_NO_COMMON_CHANNELS) ==
- P2P_SC_FAIL_NO_COMMON_CHANNELS,
- "P2P status code value mismatch");
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_UNKNOWN_GROUP) ==
- P2P_SC_FAIL_UNKNOWN_GROUP,
- "P2P status code value mismatch");
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_BOTH_GO_INTENT_15) ==
- P2P_SC_FAIL_BOTH_GO_INTENT_15,
- "P2P status code value mismatch");
-static_assert(
- static_cast<uint16_t>(ISupplicantP2pIfaceCallback::P2pStatusCode::
- FAIL_INCOMPATIBLE_PROV_METHOD) ==
- P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD,
- "P2P status code value mismatch");
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_REJECTED_BY_USER) ==
- P2P_SC_FAIL_REJECTED_BY_USER,
- "P2P status code value mismatch");
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::P2pStatusCode::SUCCESS_DEFERRED) ==
- P2P_SC_SUCCESS_DEFERRED,
- "P2P status code value mismatch");
-
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::P2pProvDiscStatusCode::SUCCESS) ==
- P2P_PROV_DISC_SUCCESS,
- "P2P status code value mismatch");
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::P2pProvDiscStatusCode::TIMEOUT) ==
- P2P_PROV_DISC_TIMEOUT,
- "P2P status code value mismatch");
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::P2pProvDiscStatusCode::REJECTED) ==
- P2P_PROV_DISC_REJECTED,
- "P2P status code value mismatch");
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::P2pProvDiscStatusCode::TIMEOUT_JOIN) ==
- P2P_PROV_DISC_TIMEOUT_JOIN,
- "P2P status code value mismatch");
-static_assert(
- static_cast<uint16_t>(
- ISupplicantP2pIfaceCallback::P2pProvDiscStatusCode::INFO_UNAVAILABLE) ==
- P2P_PROV_DISC_INFO_UNAVAILABLE,
- "P2P status code value mismatch");
-} // namespace implementation
-} // namespace V1_0
-} // namespace wifi
-} // namespace supplicant
-} // namespace hardware
-} // namespace android
-#endif // WPA_SUPPLICANT_HIDL_HIDL_MANAGER_H
diff --git a/wpa_supplicant/hidl/1.0/hidl_return_util.h b/wpa_supplicant/hidl/1.0/hidl_return_util.h
deleted file mode 100644
index c077fc8..0000000
--- a/wpa_supplicant/hidl/1.0/hidl_return_util.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef HIDL_RETURN_UTIL_H_
-#define HIDL_RETURN_UTIL_H_
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-namespace hidl_return_util {
-
-/**
- * These utility functions are used to invoke a method on the provided
- * HIDL interface object.
- * These functions checks if the provided HIDL interface object is valid.
- * a) if valid, Invokes the corresponding internal implementation function of
- * the HIDL method. It then invokes the HIDL continuation callback with
- * the status and any returned values.
- * b) if invalid, invokes the HIDL continuation callback with the
- * provided error status and default values.
- */
-// Use for HIDL methods which return only an instance of SupplicantStatus.
-template <typename ObjT, typename WorkFuncT, typename... Args>
-Return<void> validateAndCall(
- ObjT* obj, SupplicantStatusCode status_code_if_invalid, WorkFuncT&& work,
- const std::function<void(const SupplicantStatus&)>& hidl_cb, Args&&... args)
-{
- if (obj->isValid()) {
- hidl_cb((obj->*work)(std::forward<Args>(args)...));
- } else {
- hidl_cb({status_code_if_invalid, ""});
- }
- return Void();
-}
-
-// Use for HIDL methods which return instance of SupplicantStatus and a single
-// return value.
-template <typename ObjT, typename WorkFuncT, 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,
- Args&&... args)
-{
- if (obj->isValid()) {
- const auto& ret_pair =
- (obj->*work)(std::forward<Args>(args)...);
- const SupplicantStatus& status = std::get<0>(ret_pair);
- const auto& ret_value = std::get<1>(ret_pair);
- hidl_cb(status, ret_value);
- } else {
- hidl_cb(
- {status_code_if_invalid, ""},
- typename std::remove_reference<ReturnT>::type());
- }
- return Void();
-}
-
-// Use for HIDL methods which return instance of SupplicantStatus and 2 return
-// values.
-template <
- typename ObjT, typename WorkFuncT, 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)>&
- 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 auto& ret_value1 = std::get<1>(ret_tuple);
- const auto& ret_value2 = std::get<2>(ret_tuple);
- hidl_cb(status, ret_value1, ret_value2);
- } else {
- hidl_cb(
- {status_code_if_invalid, ""},
- typename std::remove_reference<ReturnT1>::type(),
- typename std::remove_reference<ReturnT2>::type());
- }
- return Void();
-}
-
-} // namespace hidl_util
-} // namespace implementation
-} // namespace V1_0
-} // namespace supplicant
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-#endif // HIDL_RETURN_UTIL_H_
diff --git a/wpa_supplicant/hidl/1.0/misc_utils.h b/wpa_supplicant/hidl/1.0/misc_utils.h
deleted file mode 100644
index 354ec32..0000000
--- a/wpa_supplicant/hidl/1.0/misc_utils.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef MISC_UTILS_H_
-#define MISC_UTILS_H_
-
-extern "C" {
-#include "wpabuf.h"
-}
-
-namespace {
-constexpr size_t kWpsPinNumDigits = 8;
-// Custom deleter for wpabuf.
-void freeWpaBuf(wpabuf *ptr) { wpabuf_free(ptr); }
-} // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-namespace misc_utils {
-using wpabuf_unique_ptr = std::unique_ptr<wpabuf, void (*)(wpabuf *)>;
-
-// Creates a unique_ptr for wpabuf ptr with a custom deleter.
-inline wpabuf_unique_ptr createWpaBufUniquePtr(struct wpabuf *raw_ptr)
-{
- return {raw_ptr, freeWpaBuf};
-}
-
-// Creates a wpabuf ptr with a custom deleter copying the data from the provided
-// vector.
-inline wpabuf_unique_ptr convertVectorToWpaBuf(const std::vector<uint8_t> &data)
-{
- return createWpaBufUniquePtr(
- wpabuf_alloc_copy(data.data(), data.size()));
-}
-
-// Copies the provided wpabuf contents to a std::vector.
-inline std::vector<uint8_t> convertWpaBufToVector(const struct wpabuf *buf)
-{
- if (buf) {
- return std::vector<uint8_t>(
- wpabuf_head_u8(buf), wpabuf_head_u8(buf) + wpabuf_len(buf));
- } else {
- return std::vector<uint8_t>();
- }
-}
-
-// Returns a string holding the wps pin.
-inline std::string convertWpsPinToString(int pin)
-{
- char pin_str[kWpsPinNumDigits + 1];
- snprintf(pin_str, sizeof(pin_str), "%08d", pin);
- return pin_str;
-}
-
-} // namespace misc_utils
-} // namespace implementation
-} // namespace V1_0
-} // namespace supplicant
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-#endif // MISC_UTILS_H_
diff --git a/wpa_supplicant/hidl/1.0/p2p_network.h b/wpa_supplicant/hidl/1.0/p2p_network.h
deleted file mode 100644
index 6164f43..0000000
--- a/wpa_supplicant/hidl/1.0/p2p_network.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef WPA_SUPPLICANT_HIDL_P2P_NETWORK_H
-#define WPA_SUPPLICANT_HIDL_P2P_NETWORK_H
-
-#include <android-base/macros.h>
-
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetwork.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetworkCallback.h>
-
-extern "C" {
-#include "utils/common.h"
-#include "utils/includes.h"
-#include "wpa_supplicant_i.h"
-}
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-
-/**
- * Implementation of P2pNetwork hidl object. Each unique hidl
- * object is used for control operations on a specific network
- * controlled by wpa_supplicant.
- */
-class P2pNetwork : public ISupplicantP2pNetwork
-{
-public:
- P2pNetwork(
- struct wpa_global* wpa_global, const char ifname[], int network_id);
- ~P2pNetwork() override = default;
- // Refer to |StaIface::invalidate()|.
- void invalidate();
- bool isValid();
-
- // Hidl methods exposed.
- Return<void> getId(getId_cb _hidl_cb) override;
- Return<void> getInterfaceName(getInterfaceName_cb _hidl_cb) override;
- Return<void> getType(getType_cb _hidl_cb) override;
- Return<void> registerCallback(
- const sp<ISupplicantP2pNetworkCallback>& callback,
- registerCallback_cb _hidl_cb) override;
- Return<void> getSsid(getSsid_cb _hidl_cb) override;
- Return<void> getBssid(getBssid_cb _hidl_cb) override;
- Return<void> isCurrent(isCurrent_cb _hidl_cb) override;
- Return<void> isPersistent(isPersistent_cb _hidl_cb) override;
- Return<void> isGo(isGo_cb _hidl_cb) override;
- Return<void> setClientList(
- const hidl_vec<hidl_array<uint8_t, 6>>& clients,
- setClientList_cb _hidl_cb) override;
- Return<void> getClientList(getClientList_cb _hidl_cb) override;
-
-private:
- // Corresponding worker functions for the HIDL methods.
- std::pair<SupplicantStatus, uint32_t> getIdInternal();
- std::pair<SupplicantStatus, std::string> getInterfaceNameInternal();
- std::pair<SupplicantStatus, IfaceType> getTypeInternal();
- SupplicantStatus registerCallbackInternal(
- const sp<ISupplicantP2pNetworkCallback>& callback);
- std::pair<SupplicantStatus, std::vector<uint8_t>> getSsidInternal();
- std::pair<SupplicantStatus, std::array<uint8_t, 6>> getBssidInternal();
- std::pair<SupplicantStatus, bool> isCurrentInternal();
- std::pair<SupplicantStatus, bool> isPersistentInternal();
- std::pair<SupplicantStatus, bool> isGoInternal();
- SupplicantStatus setClientListInternal(
- const std::vector<hidl_array<uint8_t, 6>>& clients);
- std::pair<SupplicantStatus, std::vector<hidl_array<uint8_t, 6>>>
- getClientListInternal();
-
- struct wpa_ssid* retrieveNetworkPtr();
- struct wpa_supplicant* retrieveIfacePtr();
-
- // Reference to the global wpa_struct. This is assumed to be valid
- // for the lifetime of the process.
- const struct wpa_global* wpa_global_;
- // Name of the iface this network belongs to.
- const std::string ifname_;
- // Id of the network this hidl object controls.
- const int network_id_;
- bool is_valid_;
-
- DISALLOW_COPY_AND_ASSIGN(P2pNetwork);
-};
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace wifi
-} // namespace supplicant
-} // namespace hardware
-} // namespace android
-
-#endif // WPA_SUPPLICANT_HIDL_P2P_NETWORK_H
diff --git a/wpa_supplicant/hidl/1.0/sta_iface.cpp b/wpa_supplicant/hidl/1.0/sta_iface.cpp
deleted file mode 100644
index 8498e69..0000000
--- a/wpa_supplicant/hidl/1.0/sta_iface.cpp
+++ /dev/null
@@ -1,1020 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "hidl_manager.h"
-#include "hidl_return_util.h"
-#include "iface_config_utils.h"
-#include "misc_utils.h"
-#include "sta_iface.h"
-
-extern "C" {
-#include "utils/eloop.h"
-#include "gas_query.h"
-#include "interworking.h"
-#include "hs20_supplicant.h"
-#include "wps_supplicant.h"
-}
-
-namespace {
-using android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface;
-using android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
-using android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
-using android::hardware::wifi::supplicant::V1_0::implementation::HidlManager;
-
-constexpr uint32_t kMaxAnqpElems = 100;
-constexpr char kGetMacAddress[] = "MACADDR";
-constexpr char kStartRxFilter[] = "RXFILTER-START";
-constexpr char kStopRxFilter[] = "RXFILTER-STOP";
-constexpr char kAddRxFilter[] = "RXFILTER-ADD";
-constexpr char kRemoveRxFilter[] = "RXFILTER-REMOVE";
-constexpr char kSetBtCoexistenceMode[] = "BTCOEXMODE";
-constexpr char kSetBtCoexistenceScanStart[] = "BTCOEXSCAN-START";
-constexpr char kSetBtCoexistenceScanStop[] = "BTCOEXSCAN-STOP";
-constexpr char kSetSupendModeEnabled[] = "SETSUSPENDMODE 1";
-constexpr char kSetSupendModeDisabled[] = "SETSUSPENDMODE 0";
-constexpr char kSetCountryCode[] = "COUNTRY";
-constexpr uint32_t kExtRadioWorkDefaultTimeoutInSec = static_cast<uint32_t>(
- ISupplicantStaIface::ExtRadioWorkDefaults::TIMEOUT_IN_SECS);
-constexpr char kExtRadioWorkNamePrefix[] = "ext:";
-
-uint8_t convertHidlRxFilterTypeToInternal(
- ISupplicantStaIface::RxFilterType type)
-{
- switch (type) {
- case ISupplicantStaIface::RxFilterType::V4_MULTICAST:
- return 2;
- case ISupplicantStaIface::RxFilterType::V6_MULTICAST:
- return 3;
- };
- WPA_ASSERT(false);
-}
-
-uint8_t convertHidlBtCoexModeToInternal(
- ISupplicantStaIface::BtCoexistenceMode mode)
-{
- switch (mode) {
- case ISupplicantStaIface::BtCoexistenceMode::ENABLED:
- return 0;
- case ISupplicantStaIface::BtCoexistenceMode::DISABLED:
- return 1;
- case ISupplicantStaIface::BtCoexistenceMode::SENSE:
- return 2;
- };
- WPA_ASSERT(false);
-}
-
-SupplicantStatus doZeroArgDriverCommand(
- struct wpa_supplicant *wpa_s, const char *cmd)
-{
- std::vector<char> cmd_vec(cmd, cmd + strlen(cmd) + 1);
- char driver_cmd_reply_buf[4096] = {};
- if (wpa_drv_driver_cmd(
- wpa_s, cmd_vec.data(), driver_cmd_reply_buf,
- sizeof(driver_cmd_reply_buf))) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus doOneArgDriverCommand(
- struct wpa_supplicant *wpa_s, const char *cmd, uint8_t arg)
-{
- std::string cmd_str = std::string(cmd) + " " + std::to_string(arg);
- return doZeroArgDriverCommand(wpa_s, cmd_str.c_str());
-}
-
-SupplicantStatus doOneArgDriverCommand(
- struct wpa_supplicant *wpa_s, const char *cmd, const std::string &arg)
-{
- std::string cmd_str = std::string(cmd) + " " + arg;
- return doZeroArgDriverCommand(wpa_s, cmd_str.c_str());
-}
-
-void endExtRadioWork(struct wpa_radio_work *work)
-{
- auto *ework = static_cast<struct wpa_external_work *>(work->ctx);
- work->wpa_s->ext_work_in_progress = 0;
- radio_work_done(work);
- os_free(ework);
-}
-
-void extRadioWorkTimeoutCb(void *eloop_ctx, void *timeout_ctx)
-{
- auto *work = static_cast<struct wpa_radio_work *>(eloop_ctx);
- auto *ework = static_cast<struct wpa_external_work *>(work->ctx);
- wpa_dbg(
- work->wpa_s, MSG_DEBUG, "Timing out external radio work %u (%s)",
- ework->id, work->type);
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- WPA_ASSERT(hidl_manager);
- hidl_manager->notifyExtRadioWorkTimeout(work->wpa_s, ework->id);
-
- endExtRadioWork(work);
-}
-
-void startExtRadioWork(struct wpa_radio_work *work)
-{
- auto *ework = static_cast<struct wpa_external_work *>(work->ctx);
- work->wpa_s->ext_work_in_progress = 1;
- if (!ework->timeout) {
- ework->timeout = kExtRadioWorkDefaultTimeoutInSec;
- }
- eloop_register_timeout(
- ework->timeout, 0, extRadioWorkTimeoutCb, work, nullptr);
-}
-
-void extRadioWorkStartCb(struct wpa_radio_work *work, int deinit)
-{
- // deinit==1 is invoked during interface removal. Since the HIDL
- // interface does not support interface addition/removal, we don't
- // need to handle this scenario.
- WPA_ASSERT(!deinit);
-
- auto *ework = static_cast<struct wpa_external_work *>(work->ctx);
- wpa_dbg(
- work->wpa_s, MSG_DEBUG, "Starting external radio work %u (%s)",
- ework->id, ework->type);
-
- HidlManager *hidl_manager = HidlManager::getInstance();
- WPA_ASSERT(hidl_manager);
- hidl_manager->notifyExtRadioWorkStart(work->wpa_s, ework->id);
-
- startExtRadioWork(work);
-}
-
-} // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-StaIface::StaIface(struct wpa_global *wpa_global, const char ifname[])
- : wpa_global_(wpa_global), ifname_(ifname), is_valid_(true)
-{
-}
-
-void StaIface::invalidate() { is_valid_ = false; }
-bool StaIface::isValid()
-{
- return (is_valid_ && (retrieveIfacePtr() != nullptr));
-}
-
-Return<void> StaIface::getName(getName_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::getNameInternal, _hidl_cb);
-}
-
-Return<void> StaIface::getType(getType_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::getTypeInternal, _hidl_cb);
-}
-
-Return<void> StaIface::addNetwork(addNetwork_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::addNetworkInternal, _hidl_cb);
-}
-
-Return<void> StaIface::removeNetwork(
- SupplicantNetworkId id, removeNetwork_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::removeNetworkInternal, _hidl_cb, id);
-}
-
-Return<void> StaIface::getNetwork(
- SupplicantNetworkId id, getNetwork_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::getNetworkInternal, _hidl_cb, id);
-}
-
-Return<void> StaIface::listNetworks(listNetworks_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::listNetworksInternal, _hidl_cb);
-}
-
-Return<void> StaIface::registerCallback(
- const sp<ISupplicantStaIfaceCallback> &callback,
- registerCallback_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::registerCallbackInternal, _hidl_cb, callback);
-}
-
-Return<void> StaIface::reassociate(reassociate_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::reassociateInternal, _hidl_cb);
-}
-
-Return<void> StaIface::reconnect(reconnect_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::reconnectInternal, _hidl_cb);
-}
-
-Return<void> StaIface::disconnect(disconnect_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::disconnectInternal, _hidl_cb);
-}
-
-Return<void> StaIface::setPowerSave(bool enable, setPowerSave_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::setPowerSaveInternal, _hidl_cb, enable);
-}
-
-Return<void> StaIface::initiateTdlsDiscover(
- const hidl_array<uint8_t, 6> &mac_address, initiateTdlsDiscover_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::initiateTdlsDiscoverInternal, _hidl_cb, mac_address);
-}
-
-Return<void> StaIface::initiateTdlsSetup(
- const hidl_array<uint8_t, 6> &mac_address, initiateTdlsSetup_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::initiateTdlsSetupInternal, _hidl_cb, mac_address);
-}
-
-Return<void> StaIface::initiateTdlsTeardown(
- const hidl_array<uint8_t, 6> &mac_address, initiateTdlsTeardown_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::initiateTdlsTeardownInternal, _hidl_cb, mac_address);
-}
-Return<void> StaIface::initiateAnqpQuery(
- const hidl_array<uint8_t, 6> &mac_address,
- const hidl_vec<ISupplicantStaIface::AnqpInfoId> &info_elements,
- const hidl_vec<ISupplicantStaIface::Hs20AnqpSubtypes> &sub_types,
- initiateAnqpQuery_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::initiateAnqpQueryInternal, _hidl_cb, mac_address,
- info_elements, sub_types);
-}
-
-Return<void> StaIface::initiateHs20IconQuery(
- const hidl_array<uint8_t, 6> &mac_address, const hidl_string &file_name,
- initiateHs20IconQuery_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::initiateHs20IconQueryInternal, _hidl_cb, mac_address,
- file_name);
-}
-
-Return<void> StaIface::getMacAddress(getMacAddress_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::getMacAddressInternal, _hidl_cb);
-}
-
-Return<void> StaIface::startRxFilter(startRxFilter_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::startRxFilterInternal, _hidl_cb);
-}
-
-Return<void> StaIface::stopRxFilter(stopRxFilter_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::stopRxFilterInternal, _hidl_cb);
-}
-
-Return<void> StaIface::addRxFilter(
- ISupplicantStaIface::RxFilterType type, addRxFilter_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::addRxFilterInternal, _hidl_cb, type);
-}
-
-Return<void> StaIface::removeRxFilter(
- ISupplicantStaIface::RxFilterType type, removeRxFilter_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::removeRxFilterInternal, _hidl_cb, type);
-}
-
-Return<void> StaIface::setBtCoexistenceMode(
- ISupplicantStaIface::BtCoexistenceMode mode,
- setBtCoexistenceMode_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::setBtCoexistenceModeInternal, _hidl_cb, mode);
-}
-
-Return<void> StaIface::setBtCoexistenceScanModeEnabled(
- bool enable, setBtCoexistenceScanModeEnabled_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::setBtCoexistenceScanModeEnabledInternal, _hidl_cb,
- enable);
-}
-
-Return<void> StaIface::setSuspendModeEnabled(
- bool enable, setSuspendModeEnabled_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::setSuspendModeEnabledInternal, _hidl_cb, enable);
-}
-
-Return<void> StaIface::setCountryCode(
- const hidl_array<int8_t, 2> &code, setCountryCode_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::setCountryCodeInternal, _hidl_cb, code);
-}
-
-Return<void> StaIface::startWpsRegistrar(
- const hidl_array<uint8_t, 6> &bssid, const hidl_string &pin,
- startWpsRegistrar_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::startWpsRegistrarInternal, _hidl_cb, bssid, pin);
-}
-
-Return<void> StaIface::startWpsPbc(
- const hidl_array<uint8_t, 6> &bssid, startWpsPbc_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::startWpsPbcInternal, _hidl_cb, bssid);
-}
-
-Return<void> StaIface::startWpsPinKeypad(
- const hidl_string &pin, startWpsPinKeypad_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::startWpsPinKeypadInternal, _hidl_cb, pin);
-}
-
-Return<void> StaIface::startWpsPinDisplay(
- const hidl_array<uint8_t, 6> &bssid, startWpsPinDisplay_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::startWpsPinDisplayInternal, _hidl_cb, bssid);
-}
-
-Return<void> StaIface::cancelWps(cancelWps_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::cancelWpsInternal, _hidl_cb);
-}
-
-Return<void> StaIface::setWpsDeviceName(
- const hidl_string &name, setWpsDeviceName_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::setWpsDeviceNameInternal, _hidl_cb, name);
-}
-
-Return<void> StaIface::setWpsDeviceType(
- const hidl_array<uint8_t, 8> &type, setWpsDeviceType_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::setWpsDeviceTypeInternal, _hidl_cb, type);
-}
-
-Return<void> StaIface::setWpsManufacturer(
- const hidl_string &manufacturer, setWpsManufacturer_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::setWpsManufacturerInternal, _hidl_cb, manufacturer);
-}
-
-Return<void> StaIface::setWpsModelName(
- const hidl_string &model_name, setWpsModelName_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::setWpsModelNameInternal, _hidl_cb, model_name);
-}
-
-Return<void> StaIface::setWpsModelNumber(
- const hidl_string &model_number, setWpsModelNumber_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::setWpsModelNumberInternal, _hidl_cb, model_number);
-}
-
-Return<void> StaIface::setWpsSerialNumber(
- const hidl_string &serial_number, setWpsSerialNumber_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::setWpsSerialNumberInternal, _hidl_cb, serial_number);
-}
-
-Return<void> StaIface::setWpsConfigMethods(
- uint16_t config_methods, setWpsConfigMethods_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::setWpsConfigMethodsInternal, _hidl_cb, config_methods);
-}
-
-Return<void> StaIface::setExternalSim(
- bool useExternalSim, setExternalSim_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::setExternalSimInternal, _hidl_cb, useExternalSim);
-}
-
-Return<void> StaIface::addExtRadioWork(
- const hidl_string &name, uint32_t freq_in_mhz, uint32_t timeout_in_sec,
- addExtRadioWork_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::addExtRadioWorkInternal, _hidl_cb, name, freq_in_mhz,
- timeout_in_sec);
-}
-
-Return<void> StaIface::removeExtRadioWork(
- uint32_t id, removeExtRadioWork_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::removeExtRadioWorkInternal, _hidl_cb, id);
-}
-
-Return<void> StaIface::enableAutoReconnect(
- bool enable, enableAutoReconnect_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &StaIface::enableAutoReconnectInternal, _hidl_cb, enable);
-}
-
-std::pair<SupplicantStatus, std::string> StaIface::getNameInternal()
-{
- return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
-}
-
-std::pair<SupplicantStatus, IfaceType> StaIface::getTypeInternal()
-{
- return {{SupplicantStatusCode::SUCCESS, ""}, IfaceType::STA};
-}
-
-std::pair<SupplicantStatus, sp<ISupplicantNetwork>>
-StaIface::addNetworkInternal()
-{
- android::sp<ISupplicantStaNetwork> network;
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- struct wpa_ssid *ssid = wpa_supplicant_add_network(wpa_s);
- if (!ssid) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
- }
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager ||
- hidl_manager->getStaNetworkHidlObjectByIfnameAndNetworkId(
- wpa_s->ifname, ssid->id, &network)) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
- }
- return {{SupplicantStatusCode::SUCCESS, ""}, network};
-}
-
-SupplicantStatus StaIface::removeNetworkInternal(SupplicantNetworkId id)
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- int result = wpa_supplicant_remove_network(wpa_s, id);
- if (result == -1) {
- return {SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN, ""};
- }
- if (result != 0) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, sp<ISupplicantNetwork>>
-StaIface::getNetworkInternal(SupplicantNetworkId id)
-{
- android::sp<ISupplicantStaNetwork> network;
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- struct wpa_ssid *ssid = wpa_config_get_network(wpa_s->conf, id);
- if (!ssid) {
- return {{SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN, ""},
- network};
- }
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager ||
- hidl_manager->getStaNetworkHidlObjectByIfnameAndNetworkId(
- wpa_s->ifname, ssid->id, &network)) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
- }
- return {{SupplicantStatusCode::SUCCESS, ""}, network};
-}
-
-std::pair<SupplicantStatus, std::vector<SupplicantNetworkId>>
-StaIface::listNetworksInternal()
-{
- std::vector<SupplicantNetworkId> network_ids;
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- for (struct wpa_ssid *wpa_ssid = wpa_s->conf->ssid; wpa_ssid;
- wpa_ssid = wpa_ssid->next) {
- network_ids.emplace_back(wpa_ssid->id);
- }
- return {{SupplicantStatusCode::SUCCESS, ""}, std::move(network_ids)};
-}
-
-SupplicantStatus StaIface::registerCallbackInternal(
- const sp<ISupplicantStaIfaceCallback> &callback)
-{
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager ||
- hidl_manager->addStaIfaceCallbackHidlObject(ifname_, callback)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::reassociateInternal()
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
- return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
- }
- wpas_request_connection(wpa_s);
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::reconnectInternal()
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
- return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
- }
- if (!wpa_s->disconnected) {
- return {SupplicantStatusCode::FAILURE_IFACE_NOT_DISCONNECTED,
- ""};
- }
- wpas_request_connection(wpa_s);
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::disconnectInternal()
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
- return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
- }
- wpas_request_disconnection(wpa_s);
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::setPowerSaveInternal(bool enable)
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
- return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
- }
- if (wpa_drv_set_p2p_powersave(wpa_s, enable, -1, -1)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::initiateTdlsDiscoverInternal(
- const std::array<uint8_t, 6> &mac_address)
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- int ret;
- const u8 *peer = mac_address.data();
- if (wpa_tdls_is_external_setup(wpa_s->wpa)) {
- ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
- } else {
- ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
- }
- if (ret) {
- wpa_printf(MSG_INFO, "StaIface: TDLS discover failed: %d", ret);
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::initiateTdlsSetupInternal(
- const std::array<uint8_t, 6> &mac_address)
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- int ret;
- const u8 *peer = mac_address.data();
- if (wpa_tdls_is_external_setup(wpa_s->wpa) &&
- !(wpa_s->conf->tdls_external_control)) {
- wpa_tdls_remove(wpa_s->wpa, peer);
- ret = wpa_tdls_start(wpa_s->wpa, peer);
- } else {
- ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
- }
- if (ret) {
- wpa_printf(MSG_INFO, "StaIface: TDLS setup failed: %d", ret);
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::initiateTdlsTeardownInternal(
- const std::array<uint8_t, 6> &mac_address)
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- int ret;
- const u8 *peer = mac_address.data();
- if (wpa_tdls_is_external_setup(wpa_s->wpa) &&
- !(wpa_s->conf->tdls_external_control)) {
- ret = wpa_tdls_teardown_link(
- wpa_s->wpa, peer, WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
- } else {
- ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
- }
- if (ret) {
- wpa_printf(MSG_INFO, "StaIface: TDLS teardown failed: %d", ret);
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::initiateAnqpQueryInternal(
- const std::array<uint8_t, 6> &mac_address,
- const std::vector<ISupplicantStaIface::AnqpInfoId> &info_elements,
- const std::vector<ISupplicantStaIface::Hs20AnqpSubtypes> &sub_types)
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- if (info_elements.size() > kMaxAnqpElems) {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
- }
- uint16_t info_elems_buf[kMaxAnqpElems];
- uint32_t num_info_elems = 0;
- for (const auto &info_element : info_elements) {
- info_elems_buf[num_info_elems++] =
- static_cast<std::underlying_type<
- ISupplicantStaIface::AnqpInfoId>::type>(info_element);
- }
- uint32_t sub_types_bitmask = 0;
- for (const auto &type : sub_types) {
- sub_types_bitmask |= BIT(
- 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)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::initiateHs20IconQueryInternal(
- const std::array<uint8_t, 6> &mac_address, const std::string &file_name)
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- wpa_s->fetch_osu_icon_in_progress = 0;
- if (hs20_anqp_send_req(
- wpa_s, mac_address.data(), BIT(HS20_STYPE_ICON_REQUEST),
- reinterpret_cast<const uint8_t *>(file_name.c_str()),
- file_name.size(), true)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, std::array<uint8_t, 6>>
-StaIface::getMacAddressInternal()
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- std::vector<char> cmd(
- kGetMacAddress, kGetMacAddress + sizeof(kGetMacAddress));
- char driver_cmd_reply_buf[4096] = {};
- int ret = wpa_drv_driver_cmd(
- wpa_s, cmd.data(), driver_cmd_reply_buf,
- sizeof(driver_cmd_reply_buf));
- // Reply is of the format: "Macaddr = XX:XX:XX:XX:XX:XX"
- std::string reply_str = driver_cmd_reply_buf;
- if (ret < 0 || reply_str.empty() ||
- reply_str.find("=") == std::string::npos) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- // Remove all whitespace first and then split using the delimiter "=".
- reply_str.erase(
- remove_if(reply_str.begin(), reply_str.end(), isspace),
- reply_str.end());
- std::string mac_addr_str =
- reply_str.substr(reply_str.find("=") + 1, reply_str.size());
- std::array<uint8_t, 6> mac_addr;
- if (hwaddr_aton(mac_addr_str.c_str(), mac_addr.data())) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- return {{SupplicantStatusCode::SUCCESS, ""}, mac_addr};
-}
-
-SupplicantStatus StaIface::startRxFilterInternal()
-{
- return doZeroArgDriverCommand(retrieveIfacePtr(), kStartRxFilter);
-}
-
-SupplicantStatus StaIface::stopRxFilterInternal()
-{
- return doZeroArgDriverCommand(retrieveIfacePtr(), kStopRxFilter);
-}
-
-SupplicantStatus StaIface::addRxFilterInternal(
- ISupplicantStaIface::RxFilterType type)
-{
- return doOneArgDriverCommand(
- retrieveIfacePtr(), kAddRxFilter,
- convertHidlRxFilterTypeToInternal(type));
-}
-
-SupplicantStatus StaIface::removeRxFilterInternal(
- ISupplicantStaIface::RxFilterType type)
-{
- return doOneArgDriverCommand(
- retrieveIfacePtr(), kRemoveRxFilter,
- convertHidlRxFilterTypeToInternal(type));
-}
-
-SupplicantStatus StaIface::setBtCoexistenceModeInternal(
- ISupplicantStaIface::BtCoexistenceMode mode)
-{
- return doOneArgDriverCommand(
- retrieveIfacePtr(), kSetBtCoexistenceMode,
- convertHidlBtCoexModeToInternal(mode));
-}
-
-SupplicantStatus StaIface::setBtCoexistenceScanModeEnabledInternal(bool enable)
-{
- const char *cmd;
- if (enable) {
- cmd = kSetBtCoexistenceScanStart;
- } else {
- cmd = kSetBtCoexistenceScanStop;
- }
- return doZeroArgDriverCommand(retrieveIfacePtr(), cmd);
-}
-
-SupplicantStatus StaIface::setSuspendModeEnabledInternal(bool enable)
-{
- const char *cmd;
- if (enable) {
- cmd = kSetSupendModeEnabled;
- } else {
- cmd = kSetSupendModeDisabled;
- }
- return doZeroArgDriverCommand(retrieveIfacePtr(), cmd);
-}
-
-SupplicantStatus StaIface::setCountryCodeInternal(
- const std::array<int8_t, 2> &code)
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- SupplicantStatus status = doOneArgDriverCommand(
- wpa_s, kSetCountryCode,
- std::string(std::begin(code), std::end(code)));
- if (status.code != SupplicantStatusCode::SUCCESS) {
- return status;
- }
- struct p2p_data *p2p = wpa_s->global->p2p;
- if (p2p) {
- char country[3];
- country[0] = code[0];
- country[1] = code[1];
- country[2] = 0x04;
- p2p_set_country(p2p, country);
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::startWpsRegistrarInternal(
- const std::array<uint8_t, 6> &bssid, const std::string &pin)
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- if (wpas_wps_start_reg(wpa_s, bssid.data(), pin.c_str(), nullptr)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::startWpsPbcInternal(
- const std::array<uint8_t, 6> &bssid)
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- const uint8_t *bssid_addr =
- is_zero_ether_addr(bssid.data()) ? nullptr : bssid.data();
- if (wpas_wps_start_pbc(wpa_s, bssid_addr, 0)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::startWpsPinKeypadInternal(const std::string &pin)
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- if (wpas_wps_start_pin(
- wpa_s, nullptr, pin.c_str(), 0, DEV_PW_DEFAULT)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, std::string> StaIface::startWpsPinDisplayInternal(
- const std::array<uint8_t, 6> &bssid)
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- const uint8_t *bssid_addr =
- is_zero_ether_addr(bssid.data()) ? nullptr : bssid.data();
- int pin =
- wpas_wps_start_pin(wpa_s, bssid_addr, nullptr, 0, DEV_PW_DEFAULT);
- if (pin < 0) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, ""};
- }
- return {{SupplicantStatusCode::SUCCESS, ""},
- misc_utils::convertWpsPinToString(pin)};
-}
-
-SupplicantStatus StaIface::cancelWpsInternal()
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- if (wpas_wps_cancel(wpa_s)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaIface::setWpsDeviceNameInternal(const std::string &name)
-{
- return iface_config_utils::setWpsDeviceName(retrieveIfacePtr(), name);
-}
-
-SupplicantStatus StaIface::setWpsDeviceTypeInternal(
- const std::array<uint8_t, 8> &type)
-{
- return iface_config_utils::setWpsDeviceType(retrieveIfacePtr(), type);
-}
-
-SupplicantStatus StaIface::setWpsManufacturerInternal(
- const std::string &manufacturer)
-{
- return iface_config_utils::setWpsManufacturer(
- retrieveIfacePtr(), manufacturer);
-}
-
-SupplicantStatus StaIface::setWpsModelNameInternal(
- const std::string &model_name)
-{
- return iface_config_utils::setWpsModelName(
- retrieveIfacePtr(), model_name);
-}
-
-SupplicantStatus StaIface::setWpsModelNumberInternal(
- const std::string &model_number)
-{
- return iface_config_utils::setWpsModelNumber(
- retrieveIfacePtr(), model_number);
-}
-
-SupplicantStatus StaIface::setWpsSerialNumberInternal(
- const std::string &serial_number)
-{
- return iface_config_utils::setWpsSerialNumber(
- retrieveIfacePtr(), serial_number);
-}
-
-SupplicantStatus StaIface::setWpsConfigMethodsInternal(uint16_t config_methods)
-{
- return iface_config_utils::setWpsConfigMethods(
- retrieveIfacePtr(), config_methods);
-}
-
-SupplicantStatus StaIface::setExternalSimInternal(bool useExternalSim)
-{
- return iface_config_utils::setExternalSim(
- retrieveIfacePtr(), useExternalSim);
-}
-
-std::pair<SupplicantStatus, uint32_t> StaIface::addExtRadioWorkInternal(
- const std::string &name, uint32_t freq_in_mhz, uint32_t timeout_in_sec)
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- auto *ework = static_cast<struct wpa_external_work *>(
- os_zalloc(sizeof(struct wpa_external_work)));
- if (!ework) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""},
- UINT32_MAX};
- }
-
- std::string radio_work_name = kExtRadioWorkNamePrefix + name;
- os_strlcpy(ework->type, radio_work_name.c_str(), sizeof(ework->type));
- ework->timeout = timeout_in_sec;
- wpa_s->ext_work_id++;
- if (wpa_s->ext_work_id == 0) {
- wpa_s->ext_work_id++;
- }
- ework->id = wpa_s->ext_work_id;
-
- if (radio_add_work(
- wpa_s, freq_in_mhz, ework->type, 0, extRadioWorkStartCb,
- ework)) {
- os_free(ework);
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""},
- UINT32_MAX};
- }
- return {SupplicantStatus{SupplicantStatusCode::SUCCESS, ""}, ework->id};
-}
-
-SupplicantStatus StaIface::removeExtRadioWorkInternal(uint32_t id)
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- struct wpa_radio_work *work;
- dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
- {
- if (os_strncmp(
- work->type, kExtRadioWorkNamePrefix,
- sizeof(kExtRadioWorkNamePrefix)) != 0)
- continue;
-
- auto *ework =
- static_cast<struct wpa_external_work *>(work->ctx);
- if (ework->id != id)
- continue;
-
- wpa_dbg(
- wpa_s, MSG_DEBUG, "Completed external radio work %u (%s)",
- ework->id, ework->type);
- eloop_cancel_timeout(extRadioWorkTimeoutCb, work, NULL);
- endExtRadioWork(work);
-
- return {SupplicantStatusCode::SUCCESS, ""};
- }
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-}
-
-SupplicantStatus StaIface::enableAutoReconnectInternal(bool enable)
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- wpa_s->auto_reconnect_disabled = enable ? 0 : 1;
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-/**
- * Retrieve the underlying |wpa_supplicant| struct
- * pointer for this iface.
- * If the underlying iface is removed, then all RPC method calls on this object
- * will return failure.
- */
-wpa_supplicant *StaIface::retrieveIfacePtr()
-{
- return wpa_supplicant_get_iface(wpa_global_, ifname_.c_str());
-}
-} // namespace implementation
-} // namespace V1_0
-} // namespace wifi
-} // namespace supplicant
-} // namespace hardware
-} // namespace android
diff --git a/wpa_supplicant/hidl/1.0/sta_iface.h b/wpa_supplicant/hidl/1.0/sta_iface.h
deleted file mode 100644
index 6e62260..0000000
--- a/wpa_supplicant/hidl/1.0/sta_iface.h
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef WPA_SUPPLICANT_HIDL_STA_IFACE_H
-#define WPA_SUPPLICANT_HIDL_STA_IFACE_H
-
-#include <array>
-#include <vector>
-
-#include <android-base/macros.h>
-
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaIface.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetwork.h>
-
-extern "C" {
-#include "utils/common.h"
-#include "utils/includes.h"
-#include "wpa_supplicant_i.h"
-#include "config.h"
-#include "driver_i.h"
-#include "wpa.h"
-}
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-
-/**
- * Implementation of StaIface hidl object. Each unique hidl
- * object is used for control operations on a specific interface
- * controlled by wpa_supplicant.
- */
-class StaIface
- : public android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface
-{
-public:
- StaIface(struct wpa_global* wpa_global, const char ifname[]);
- ~StaIface() override = default;
- // HIDL does not provide a built-in mechanism to let the server
- // invalidate a HIDL interface object after creation. If any client
- // process holds onto a reference to the object in their context,
- // any method calls on that reference will continue to be directed to
- // the server.
- // However Supplicant HAL needs to control the lifetime of these
- // objects. So, add a public |invalidate| method to all |Iface| and
- // |Network| objects.
- // This will be used to mark an object invalid when the corresponding
- // iface or network is removed.
- // All HIDL method implementations should check if the object is still
- // marked valid before processing them.
- void invalidate();
- bool isValid();
-
- // Hidl methods exposed.
- Return<void> getName(getName_cb _hidl_cb) override;
- Return<void> getType(getType_cb _hidl_cb) override;
- Return<void> addNetwork(addNetwork_cb _hidl_cb) override;
- Return<void> removeNetwork(
- SupplicantNetworkId id, removeNetwork_cb _hidl_cb) override;
- Return<void> getNetwork(
- SupplicantNetworkId id, getNetwork_cb _hidl_cb) override;
- Return<void> listNetworks(listNetworks_cb _hidl_cb) override;
- Return<void> registerCallback(
- const sp<ISupplicantStaIfaceCallback>& callback,
- registerCallback_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;
- Return<void> setPowerSave(
- bool enable, setPowerSave_cb _hidl_cb) override;
- Return<void> initiateTdlsDiscover(
- const hidl_array<uint8_t, 6>& mac_address,
- initiateTdlsDiscover_cb _hidl_cb) override;
- Return<void> initiateTdlsSetup(
- const hidl_array<uint8_t, 6>& mac_address,
- initiateTdlsSetup_cb _hidl_cb) override;
- Return<void> initiateTdlsTeardown(
- const hidl_array<uint8_t, 6>& mac_address,
- initiateTdlsTeardown_cb _hidl_cb) override;
- Return<void> initiateAnqpQuery(
- const hidl_array<uint8_t, 6>& mac_address,
- const hidl_vec<ISupplicantStaIface::AnqpInfoId>& info_elements,
- const hidl_vec<ISupplicantStaIface::Hs20AnqpSubtypes>& sub_types,
- initiateAnqpQuery_cb _hidl_cb) override;
- Return<void> initiateHs20IconQuery(
- const hidl_array<uint8_t, 6>& mac_address,
- const hidl_string& file_name,
- initiateHs20IconQuery_cb _hidl_cb) override;
- Return<void> getMacAddress(getMacAddress_cb _hidl_cb) override;
- Return<void> startRxFilter(startRxFilter_cb _hidl_cb) override;
- Return<void> stopRxFilter(stopRxFilter_cb _hidl_cb) override;
- Return<void> addRxFilter(
- ISupplicantStaIface::RxFilterType type,
- addRxFilter_cb _hidl_cb) override;
- Return<void> removeRxFilter(
- ISupplicantStaIface::RxFilterType type,
- removeRxFilter_cb _hidl_cb) override;
- Return<void> setBtCoexistenceMode(
- ISupplicantStaIface::BtCoexistenceMode mode,
- setBtCoexistenceMode_cb _hidl_cb) override;
- Return<void> setBtCoexistenceScanModeEnabled(
- bool enable, setBtCoexistenceScanModeEnabled_cb _hidl_cb) override;
- Return<void> setSuspendModeEnabled(
- bool enable, setSuspendModeEnabled_cb _hidl_cb) override;
- Return<void> setCountryCode(
- const hidl_array<int8_t, 2>& code,
- setCountryCode_cb _hidl_cb) override;
- Return<void> startWpsRegistrar(
- const hidl_array<uint8_t, 6>& bssid, const hidl_string& pin,
- startWpsRegistrar_cb _hidl_cb) override;
- Return<void> startWpsPbc(
- const hidl_array<uint8_t, 6>& bssid,
- startWpsPbc_cb _hidl_cb) override;
- Return<void> startWpsPinKeypad(
- const hidl_string& pin, startWpsPinKeypad_cb _hidl_cb) override;
- Return<void> startWpsPinDisplay(
- const hidl_array<uint8_t, 6>& bssid,
- startWpsPinDisplay_cb _hidl_cb) override;
- Return<void> cancelWps(cancelWps_cb _hidl_cb) override;
- Return<void> setWpsDeviceName(
- const hidl_string& name, setWpsDeviceName_cb _hidl_cb) override;
- Return<void> setWpsDeviceType(
- const hidl_array<uint8_t, 8>& type,
- setWpsDeviceType_cb _hidl_cb) override;
- Return<void> setWpsManufacturer(
- const hidl_string& manufacturer,
- setWpsManufacturer_cb _hidl_cb) override;
- Return<void> setWpsModelName(
- const hidl_string& model_name,
- setWpsModelName_cb _hidl_cb) override;
- Return<void> setWpsModelNumber(
- const hidl_string& model_number,
- setWpsModelNumber_cb _hidl_cb) override;
- Return<void> setWpsSerialNumber(
- const hidl_string& serial_number,
- setWpsSerialNumber_cb _hidl_cb) override;
- Return<void> setWpsConfigMethods(
- uint16_t config_methods, setWpsConfigMethods_cb _hidl_cb) override;
- Return<void> setExternalSim(
- bool useExternalSim, setExternalSim_cb _hidl_cb) override;
- Return<void> addExtRadioWork(
- const hidl_string& name, uint32_t freq_in_mhz,
- uint32_t timeout_in_sec, addExtRadioWork_cb _hidl_cb) override;
- Return<void> removeExtRadioWork(
- uint32_t id, removeExtRadioWork_cb _hidl_cb) override;
- Return<void> enableAutoReconnect(
- bool enable, enableAutoReconnect_cb _hidl_cb) override;
-
-private:
- // Corresponding worker functions for the HIDL methods.
- std::pair<SupplicantStatus, std::string> getNameInternal();
- std::pair<SupplicantStatus, IfaceType> getTypeInternal();
- std::pair<SupplicantStatus, sp<ISupplicantNetwork>>
- addNetworkInternal();
- SupplicantStatus removeNetworkInternal(SupplicantNetworkId id);
- std::pair<SupplicantStatus, sp<ISupplicantNetwork>> getNetworkInternal(
- SupplicantNetworkId id);
- std::pair<SupplicantStatus, std::vector<SupplicantNetworkId>>
- listNetworksInternal();
- SupplicantStatus registerCallbackInternal(
- const sp<ISupplicantStaIfaceCallback>& callback);
- SupplicantStatus reassociateInternal();
- SupplicantStatus reconnectInternal();
- SupplicantStatus disconnectInternal();
- SupplicantStatus setPowerSaveInternal(bool enable);
- SupplicantStatus initiateTdlsDiscoverInternal(
- const std::array<uint8_t, 6>& mac_address);
- SupplicantStatus initiateTdlsSetupInternal(
- const std::array<uint8_t, 6>& mac_address);
- SupplicantStatus initiateTdlsTeardownInternal(
- const std::array<uint8_t, 6>& mac_address);
- SupplicantStatus initiateAnqpQueryInternal(
- const std::array<uint8_t, 6>& mac_address,
- const std::vector<ISupplicantStaIface::AnqpInfoId>& info_elements,
- const std::vector<ISupplicantStaIface::Hs20AnqpSubtypes>&
- sub_types);
- SupplicantStatus initiateHs20IconQueryInternal(
- const std::array<uint8_t, 6>& mac_address,
- const std::string& file_name);
- std::pair<SupplicantStatus, std::array<uint8_t, 6>>
- getMacAddressInternal();
- SupplicantStatus startRxFilterInternal();
- SupplicantStatus stopRxFilterInternal();
- SupplicantStatus addRxFilterInternal(
- ISupplicantStaIface::RxFilterType type);
- SupplicantStatus removeRxFilterInternal(
- ISupplicantStaIface::RxFilterType type);
- SupplicantStatus setBtCoexistenceModeInternal(
- ISupplicantStaIface::BtCoexistenceMode mode);
- SupplicantStatus setBtCoexistenceScanModeEnabledInternal(bool enable);
- SupplicantStatus setSuspendModeEnabledInternal(bool enable);
- SupplicantStatus setCountryCodeInternal(
- const std::array<int8_t, 2>& code);
- SupplicantStatus startWpsRegistrarInternal(
- const std::array<uint8_t, 6>& bssid, const std::string& pin);
- SupplicantStatus startWpsPbcInternal(
- const std::array<uint8_t, 6>& bssid);
- SupplicantStatus startWpsPinKeypadInternal(const std::string& pin);
- std::pair<SupplicantStatus, std::string> startWpsPinDisplayInternal(
- const std::array<uint8_t, 6>& bssid);
- SupplicantStatus cancelWpsInternal();
- SupplicantStatus setWpsDeviceNameInternal(const std::string& name);
- SupplicantStatus setWpsDeviceTypeInternal(
- const std::array<uint8_t, 8>& type);
- SupplicantStatus setWpsManufacturerInternal(
- const std::string& manufacturer);
- SupplicantStatus setWpsModelNameInternal(const std::string& model_name);
- SupplicantStatus setWpsModelNumberInternal(
- const std::string& model_number);
- SupplicantStatus setWpsSerialNumberInternal(
- const std::string& serial_number);
- SupplicantStatus setWpsConfigMethodsInternal(uint16_t config_methods);
- SupplicantStatus setExternalSimInternal(bool useExternalSim);
- std::pair<SupplicantStatus, uint32_t> addExtRadioWorkInternal(
- const std::string& name, uint32_t freq_in_mhz,
- uint32_t timeout_in_sec);
- SupplicantStatus removeExtRadioWorkInternal(uint32_t id);
- SupplicantStatus enableAutoReconnectInternal(bool enable);
-
- struct wpa_supplicant* retrieveIfacePtr();
-
- // Reference to the global wpa_struct. This is assumed to be valid for
- // the lifetime of the process.
- struct wpa_global* wpa_global_;
- // Name of the iface this hidl object controls
- const std::string ifname_;
- bool is_valid_;
-
- DISALLOW_COPY_AND_ASSIGN(StaIface);
-};
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace wifi
-} // namespace supplicant
-} // namespace hardware
-} // namespace android
-
-#endif // WPA_SUPPLICANT_HIDL_STA_IFACE_H
diff --git a/wpa_supplicant/hidl/1.0/sta_network.cpp b/wpa_supplicant/hidl/1.0/sta_network.cpp
deleted file mode 100644
index f471941..0000000
--- a/wpa_supplicant/hidl/1.0/sta_network.cpp
+++ /dev/null
@@ -1,1825 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "hidl_manager.h"
-#include "hidl_return_util.h"
-#include "misc_utils.h"
-#include "sta_network.h"
-
-extern "C" {
-#include "wps_supplicant.h"
-}
-
-namespace {
-using android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
-using android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
-
-constexpr uint8_t kZeroBssid[6] = {0, 0, 0, 0, 0, 0};
-
-constexpr uint32_t kAllowedKeyMgmtMask =
- (static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::NONE) |
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK) |
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP) |
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X) |
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::FT_EAP) |
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::FT_PSK) |
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::OSEN));
-constexpr uint32_t kAllowedProtoMask =
- (static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::WPA) |
- static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::RSN) |
- static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::OSEN));
-constexpr uint32_t kAllowedAuthAlgMask =
- (static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::OPEN) |
- static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::SHARED) |
- static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::LEAP));
-constexpr uint32_t kAllowedGroupCipherMask =
- (static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::WEP40) |
- static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::WEP104) |
- static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::TKIP) |
- static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::CCMP) |
- static_cast<uint32_t>(
- ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED));
-constexpr uint32_t kAllowedPairwisewCipherMask =
- (static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::NONE) |
- static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::TKIP) |
- static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::CCMP));
-
-constexpr uint32_t kEapMethodMax =
- static_cast<uint32_t>(ISupplicantStaNetwork::EapMethod::WFA_UNAUTH_TLS) + 1;
-constexpr char const *kEapMethodStrings[kEapMethodMax] = {
- "PEAP", "TLS", "TTLS", "PWD", "SIM", "AKA", "AKA'", "WFA-UNAUTH-TLS"};
-constexpr uint32_t kEapPhase2MethodMax =
- static_cast<uint32_t>(ISupplicantStaNetwork::EapPhase2Method::AKA_PRIME) +
- 1;
-constexpr char const *kEapPhase2MethodStrings[kEapPhase2MethodMax] = {
- "", "PAP", "MSCHAP", "MSCHAPV2", "GTC", "SIM", "AKA", "AKA'"};
-constexpr char kEapPhase2AuthPrefix[] = "auth=";
-constexpr char kEapPhase2AuthEapPrefix[] = "autheap=";
-constexpr char kNetworkEapSimGsmAuthResponse[] = "GSM-AUTH";
-constexpr char kNetworkEapSimUmtsAuthResponse[] = "UMTS-AUTH";
-constexpr char kNetworkEapSimUmtsAutsResponse[] = "UMTS-AUTS";
-constexpr char kNetworkEapSimGsmAuthFailure[] = "GSM-FAIL";
-constexpr char kNetworkEapSimUmtsAuthFailure[] = "UMTS-FAIL";
-} // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-StaNetwork::StaNetwork(
- struct wpa_global *wpa_global, const char ifname[], int network_id)
- : wpa_global_(wpa_global),
- ifname_(ifname),
- network_id_(network_id),
- is_valid_(true)
-{
-}
-
-void StaNetwork::invalidate() { is_valid_ = false; }
-bool StaNetwork::isValid()
-{
- return (is_valid_ && (retrieveNetworkPtr() != nullptr));
-}
-
-Return<void> StaNetwork::getId(getId_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getIdInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getInterfaceName(getInterfaceName_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getInterfaceNameInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getType(getType_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getTypeInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::registerCallback(
- const sp<ISupplicantStaNetworkCallback> &callback,
- registerCallback_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::registerCallbackInternal, _hidl_cb, callback);
-}
-
-Return<void> StaNetwork::setSsid(
- const hidl_vec<uint8_t> &ssid, setSsid_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setSsidInternal, _hidl_cb, ssid);
-}
-
-Return<void> StaNetwork::setBssid(
- const hidl_array<uint8_t, 6> &bssid, setBssid_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setBssidInternal, _hidl_cb, bssid);
-}
-
-Return<void> StaNetwork::setScanSsid(bool enable, setScanSsid_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setScanSsidInternal, _hidl_cb, enable);
-}
-
-Return<void> StaNetwork::setKeyMgmt(
- uint32_t key_mgmt_mask, setKeyMgmt_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setKeyMgmtInternal, _hidl_cb, key_mgmt_mask);
-}
-
-Return<void> StaNetwork::setProto(uint32_t proto_mask, setProto_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setProtoInternal, _hidl_cb, proto_mask);
-}
-
-Return<void> StaNetwork::setAuthAlg(
- uint32_t auth_alg_mask,
- std::function<void(const SupplicantStatus &status)> _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setAuthAlgInternal, _hidl_cb, auth_alg_mask);
-}
-
-Return<void> StaNetwork::setGroupCipher(
- uint32_t group_cipher_mask, setGroupCipher_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setGroupCipherInternal, _hidl_cb, group_cipher_mask);
-}
-
-Return<void> StaNetwork::setPairwiseCipher(
- uint32_t pairwise_cipher_mask, setPairwiseCipher_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setPairwiseCipherInternal, _hidl_cb,
- pairwise_cipher_mask);
-}
-
-Return<void> StaNetwork::setPskPassphrase(
- const hidl_string &psk, setPskPassphrase_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setPskPassphraseInternal, _hidl_cb, psk);
-}
-
-Return<void> StaNetwork::setPsk(
- const hidl_array<uint8_t, 32> &psk, setPsk_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setPskInternal, _hidl_cb, psk);
-}
-
-Return<void> StaNetwork::setWepKey(
- uint32_t key_idx, const hidl_vec<uint8_t> &wep_key, setWepKey_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setWepKeyInternal, _hidl_cb, key_idx, wep_key);
-}
-
-Return<void> StaNetwork::setWepTxKeyIdx(
- uint32_t key_idx, setWepTxKeyIdx_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setWepTxKeyIdxInternal, _hidl_cb, key_idx);
-}
-
-Return<void> StaNetwork::setRequirePmf(bool enable, setRequirePmf_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setRequirePmfInternal, _hidl_cb, enable);
-}
-
-Return<void> StaNetwork::setEapMethod(
- ISupplicantStaNetwork::EapMethod method, setEapMethod_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setEapMethodInternal, _hidl_cb, method);
-}
-
-Return<void> StaNetwork::setEapPhase2Method(
- ISupplicantStaNetwork::EapPhase2Method method,
- setEapPhase2Method_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setEapPhase2MethodInternal, _hidl_cb, method);
-}
-
-Return<void> StaNetwork::setEapIdentity(
- const hidl_vec<uint8_t> &identity, setEapIdentity_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setEapIdentityInternal, _hidl_cb, identity);
-}
-
-Return<void> StaNetwork::setEapAnonymousIdentity(
- const hidl_vec<uint8_t> &identity, setEapAnonymousIdentity_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setEapAnonymousIdentityInternal, _hidl_cb, identity);
-}
-
-Return<void> StaNetwork::setEapPassword(
- const hidl_vec<uint8_t> &password, setEapPassword_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setEapPasswordInternal, _hidl_cb, password);
-}
-
-Return<void> StaNetwork::setEapCACert(
- const hidl_string &path, setEapCACert_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setEapCACertInternal, _hidl_cb, path);
-}
-
-Return<void> StaNetwork::setEapCAPath(
- const hidl_string &path, setEapCAPath_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setEapCAPathInternal, _hidl_cb, path);
-}
-
-Return<void> StaNetwork::setEapClientCert(
- const hidl_string &path, setEapClientCert_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setEapClientCertInternal, _hidl_cb, path);
-}
-
-Return<void> StaNetwork::setEapPrivateKeyId(
- const hidl_string &id, setEapPrivateKeyId_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setEapPrivateKeyIdInternal, _hidl_cb, id);
-}
-
-Return<void> StaNetwork::setEapSubjectMatch(
- const hidl_string &match, setEapSubjectMatch_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setEapSubjectMatchInternal, _hidl_cb, match);
-}
-
-Return<void> StaNetwork::setEapAltSubjectMatch(
- const hidl_string &match, setEapAltSubjectMatch_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setEapAltSubjectMatchInternal, _hidl_cb, match);
-}
-
-Return<void> StaNetwork::setEapEngine(bool enable, setEapEngine_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setEapEngineInternal, _hidl_cb, enable);
-}
-
-Return<void> StaNetwork::setEapEngineID(
- const hidl_string &id, setEapEngineID_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setEapEngineIDInternal, _hidl_cb, id);
-}
-
-Return<void> StaNetwork::setEapDomainSuffixMatch(
- const hidl_string &match, setEapDomainSuffixMatch_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setEapDomainSuffixMatchInternal, _hidl_cb, match);
-}
-
-Return<void> StaNetwork::setProactiveKeyCaching(
- bool enable, setProactiveKeyCaching_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setProactiveKeyCachingInternal, _hidl_cb, enable);
-}
-
-Return<void> StaNetwork::setIdStr(
- const hidl_string &id_str, setIdStr_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setIdStrInternal, _hidl_cb, id_str);
-}
-
-Return<void> StaNetwork::setUpdateIdentifier(
- uint32_t id, setUpdateIdentifier_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setUpdateIdentifierInternal, _hidl_cb, id);
-}
-
-Return<void> StaNetwork::getSsid(getSsid_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getSsidInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getBssid(getBssid_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getBssidInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getScanSsid(getScanSsid_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getScanSsidInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getKeyMgmt(getKeyMgmt_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getKeyMgmtInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getProto(getProto_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getProtoInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getAuthAlg(getAuthAlg_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getAuthAlgInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getGroupCipher(getGroupCipher_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getGroupCipherInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getPairwiseCipher(getPairwiseCipher_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getPairwiseCipherInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getPskPassphrase(getPskPassphrase_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getPskPassphraseInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getPsk(getPsk_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getPskInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getWepKey(uint32_t key_idx, getWepKey_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getWepKeyInternal, _hidl_cb, key_idx);
-}
-
-Return<void> StaNetwork::getWepTxKeyIdx(getWepTxKeyIdx_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getWepTxKeyIdxInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getRequirePmf(getRequirePmf_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getRequirePmfInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapMethod(getEapMethod_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getEapMethodInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapPhase2Method(getEapPhase2Method_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getEapPhase2MethodInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapIdentity(getEapIdentity_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getEapIdentityInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapAnonymousIdentity(
- getEapAnonymousIdentity_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getEapAnonymousIdentityInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapPassword(getEapPassword_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getEapPasswordInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapCACert(getEapCACert_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getEapCACertInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapCAPath(getEapCAPath_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getEapCAPathInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapClientCert(getEapClientCert_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getEapClientCertInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapPrivateKeyId(getEapPrivateKeyId_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getEapPrivateKeyIdInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapSubjectMatch(getEapSubjectMatch_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getEapSubjectMatchInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapAltSubjectMatch(
- getEapAltSubjectMatch_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getEapAltSubjectMatchInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapEngine(getEapEngine_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getEapEngineInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapEngineID(getEapEngineID_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getEapEngineIDInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getEapDomainSuffixMatch(
- getEapDomainSuffixMatch_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getEapDomainSuffixMatchInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getIdStr(getIdStr_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getIdStrInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::getWpsNfcConfigurationToken(
- getWpsNfcConfigurationToken_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::getWpsNfcConfigurationTokenInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::enable(bool no_connect, enable_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::enableInternal, _hidl_cb, no_connect);
-}
-
-Return<void> StaNetwork::disable(disable_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::disableInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::select(select_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::selectInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::sendNetworkEapSimGsmAuthResponse(
- const hidl_vec<ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams>
- &vec_params,
- sendNetworkEapSimGsmAuthResponse_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::sendNetworkEapSimGsmAuthResponseInternal, _hidl_cb,
- vec_params);
-}
-
-Return<void> StaNetwork::sendNetworkEapSimGsmAuthFailure(
- sendNetworkEapSimGsmAuthFailure_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::sendNetworkEapSimGsmAuthFailureInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::sendNetworkEapSimUmtsAuthResponse(
- const ISupplicantStaNetwork::NetworkResponseEapSimUmtsAuthParams ¶ms,
- sendNetworkEapSimUmtsAuthResponse_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::sendNetworkEapSimUmtsAuthResponseInternal, _hidl_cb,
- params);
-}
-
-Return<void> StaNetwork::sendNetworkEapSimUmtsAutsResponse(
- const hidl_array<uint8_t, 14> &auts,
- sendNetworkEapSimUmtsAutsResponse_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::sendNetworkEapSimUmtsAutsResponseInternal, _hidl_cb,
- auts);
-}
-
-Return<void> StaNetwork::sendNetworkEapSimUmtsAuthFailure(
- sendNetworkEapSimUmtsAuthFailure_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::sendNetworkEapSimUmtsAuthFailureInternal, _hidl_cb);
-}
-
-Return<void> StaNetwork::sendNetworkEapIdentityResponse(
- const hidl_vec<uint8_t> &identity,
- sendNetworkEapIdentityResponse_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::sendNetworkEapIdentityResponseInternal, _hidl_cb,
- identity);
-}
-
-std::pair<SupplicantStatus, uint32_t> StaNetwork::getIdInternal()
-{
- return {{SupplicantStatusCode::SUCCESS, ""}, network_id_};
-}
-
-std::pair<SupplicantStatus, std::string> StaNetwork::getInterfaceNameInternal()
-{
- return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
-}
-
-std::pair<SupplicantStatus, IfaceType> StaNetwork::getTypeInternal()
-{
- return {{SupplicantStatusCode::SUCCESS, ""}, IfaceType::STA};
-}
-
-SupplicantStatus StaNetwork::registerCallbackInternal(
- const sp<ISupplicantStaNetworkCallback> &callback)
-{
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager ||
- hidl_manager->addStaNetworkCallbackHidlObject(
- ifname_, network_id_, callback)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setSsidInternal(const std::vector<uint8_t> &ssid)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (ssid.size() == 0 ||
- ssid.size() >
- static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
- SSID_MAX_LEN_IN_BYTES)) {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
- }
- if (setByteArrayFieldAndResetState(
- ssid.data(), ssid.size(), &(wpa_ssid->ssid),
- &(wpa_ssid->ssid_len), "ssid")) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- if (wpa_ssid->passphrase) {
- wpa_config_update_psk(wpa_ssid);
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setBssidInternal(
- const std::array<uint8_t, 6> &bssid)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- int prev_bssid_set = wpa_ssid->bssid_set;
- u8 prev_bssid[ETH_ALEN];
- os_memcpy(prev_bssid, wpa_ssid->bssid, ETH_ALEN);
- // Zero'ed array is used to clear out the BSSID value.
- if (os_memcmp(bssid.data(), kZeroBssid, ETH_ALEN) == 0) {
- wpa_ssid->bssid_set = 0;
- wpa_printf(MSG_MSGDUMP, "BSSID any");
- } else {
- os_memcpy(wpa_ssid->bssid, bssid.data(), ETH_ALEN);
- wpa_ssid->bssid_set = 1;
- wpa_hexdump(MSG_MSGDUMP, "BSSID", wpa_ssid->bssid, ETH_ALEN);
- }
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- if ((wpa_ssid->bssid_set != prev_bssid_set ||
- os_memcmp(wpa_ssid->bssid, prev_bssid, ETH_ALEN) != 0)) {
- wpas_notify_network_bssid_set_changed(wpa_s, wpa_ssid);
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setScanSsidInternal(bool enable)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- wpa_ssid->scan_ssid = enable ? 1 : 0;
- resetInternalStateAfterParamsUpdate();
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setKeyMgmtInternal(uint32_t key_mgmt_mask)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (key_mgmt_mask & ~kAllowedKeyMgmtMask) {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
- }
- wpa_ssid->key_mgmt = key_mgmt_mask;
- wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", wpa_ssid->key_mgmt);
- resetInternalStateAfterParamsUpdate();
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setProtoInternal(uint32_t proto_mask)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (proto_mask & ~kAllowedProtoMask) {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
- }
- wpa_ssid->proto = proto_mask;
- wpa_printf(MSG_MSGDUMP, "proto: 0x%x", wpa_ssid->proto);
- resetInternalStateAfterParamsUpdate();
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setAuthAlgInternal(uint32_t auth_alg_mask)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (auth_alg_mask & ~kAllowedAuthAlgMask) {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
- }
- wpa_ssid->auth_alg = auth_alg_mask;
- wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", wpa_ssid->auth_alg);
- resetInternalStateAfterParamsUpdate();
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setGroupCipherInternal(uint32_t group_cipher_mask)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (group_cipher_mask & ~kAllowedGroupCipherMask) {
- return {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, ""};
-}
-
-SupplicantStatus StaNetwork::setPairwiseCipherInternal(
- uint32_t pairwise_cipher_mask)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (pairwise_cipher_mask & ~kAllowedPairwisewCipherMask) {
- return {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, ""};
-}
-
-SupplicantStatus StaNetwork::setPskPassphraseInternal(const std::string &psk)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (isPskPassphraseValid(psk)) {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
- }
- if (wpa_ssid->passphrase &&
- os_strlen(wpa_ssid->passphrase) == psk.size() &&
- os_memcmp(wpa_ssid->passphrase, psk.c_str(), psk.size()) == 0) {
- return {SupplicantStatusCode::SUCCESS, ""};
- }
- // Flag to indicate if raw psk is calculated or not using
- // |wpa_config_update_psk|. Deferred if ssid not already set.
- wpa_ssid->psk_set = 0;
- if (setStringKeyFieldAndResetState(
- psk.c_str(), &(wpa_ssid->passphrase), "psk passphrase")) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- if (wpa_ssid->ssid_len) {
- wpa_config_update_psk(wpa_ssid);
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setPskInternal(const std::array<uint8_t, 32> &psk)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- WPA_ASSERT(psk.size() == sizeof(wpa_ssid->psk));
- str_clear_free(wpa_ssid->passphrase);
- wpa_ssid->passphrase = nullptr;
- os_memcpy(wpa_ssid->psk, psk.data(), sizeof(wpa_ssid->psk));
- wpa_ssid->psk_set = 1;
- resetInternalStateAfterParamsUpdate();
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setWepKeyInternal(
- uint32_t key_idx, const std::vector<uint8_t> &wep_key)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (key_idx >=
- static_cast<uint32_t>(
- ISupplicantStaNetwork::ParamSizeLimits::WEP_KEYS_MAX_NUM)) {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
- }
- if (wep_key.size() !=
- static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
- WEP40_KEY_LEN_IN_BYTES) &&
- wep_key.size() !=
- static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
- WEP104_KEY_LEN_IN_BYTES)) {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
- }
- os_memcpy(wpa_ssid->wep_key[key_idx], wep_key.data(), wep_key.size());
- wpa_ssid->wep_key_len[key_idx] = wep_key.size();
- std::string msg_dump_title("wep_key" + std::to_string(key_idx));
- wpa_hexdump_key(
- MSG_MSGDUMP, msg_dump_title.c_str(), wpa_ssid->wep_key[key_idx],
- wpa_ssid->wep_key_len[key_idx]);
- resetInternalStateAfterParamsUpdate();
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setWepTxKeyIdxInternal(uint32_t key_idx)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (key_idx >=
- static_cast<uint32_t>(
- ISupplicantStaNetwork::ParamSizeLimits::WEP_KEYS_MAX_NUM)) {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
- }
- wpa_ssid->wep_tx_keyidx = key_idx;
- resetInternalStateAfterParamsUpdate();
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setRequirePmfInternal(bool enable)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- wpa_ssid->ieee80211w =
- enable ? MGMT_FRAME_PROTECTION_REQUIRED : NO_MGMT_FRAME_PROTECTION;
- resetInternalStateAfterParamsUpdate();
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapMethodInternal(
- ISupplicantStaNetwork::EapMethod method)
-{
- uint32_t eap_method_idx = static_cast<
- std::underlying_type<ISupplicantStaNetwork::EapMethod>::type>(
- method);
- if (eap_method_idx >= kEapMethodMax) {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
- }
-
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- int retrieved_vendor, retrieved_method;
- const char *method_str = kEapMethodStrings[eap_method_idx];
- // This string lookup is needed to check if the device supports the
- // corresponding EAP type.
- retrieved_method = eap_peer_get_type(method_str, &retrieved_vendor);
- if (retrieved_vendor == EAP_VENDOR_IETF &&
- retrieved_method == EAP_TYPE_NONE) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- if (wpa_ssid->eap.eap_methods) {
- os_free(wpa_ssid->eap.eap_methods);
- }
- // wpa_supplicant can support setting multiple eap methods for each
- // network. But, this is not really used by Android. So, just adding
- // support for setting one EAP method for each network. The additional
- // |eap_method_type| member in the array is used to indicate the end
- // of list.
- wpa_ssid->eap.eap_methods =
- (eap_method_type *)os_malloc(sizeof(eap_method_type) * 2);
- if (!wpa_ssid->eap.eap_methods) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- wpa_ssid->eap.eap_methods[0].vendor = retrieved_vendor;
- wpa_ssid->eap.eap_methods[0].method = retrieved_method;
- wpa_ssid->eap.eap_methods[1].vendor = EAP_VENDOR_IETF;
- wpa_ssid->eap.eap_methods[1].method = EAP_TYPE_NONE;
-
- wpa_ssid->leap = 0;
- wpa_ssid->non_leap = 0;
- if (retrieved_vendor == EAP_VENDOR_IETF &&
- retrieved_method == EAP_TYPE_LEAP) {
- wpa_ssid->leap++;
- } else {
- wpa_ssid->non_leap++;
- }
- wpa_hexdump(
- MSG_MSGDUMP, "eap methods", (u8 *)wpa_ssid->eap.eap_methods,
- sizeof(eap_method_type) * 2);
- resetInternalStateAfterParamsUpdate();
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapPhase2MethodInternal(
- ISupplicantStaNetwork::EapPhase2Method method)
-{
- uint32_t eap_phase2_method_idx = static_cast<
- std::underlying_type<ISupplicantStaNetwork::EapPhase2Method>::type>(
- method);
- if (eap_phase2_method_idx >= kEapPhase2MethodMax) {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
- }
-
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- // EAP method needs to be set for us to construct the eap
- // phase 2 method string.
- SupplicantStatus status;
- ISupplicantStaNetwork::EapMethod eap_method;
- std::tie(status, eap_method) = getEapMethodInternal();
- if (status.code != SupplicantStatusCode::SUCCESS) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN,
- "EAP method not set"};
- }
- std::string eap_phase2_str;
- if (method == ISupplicantStaNetwork::EapPhase2Method::NONE) {
- eap_phase2_str = "";
- } else if (
- eap_method == ISupplicantStaNetwork::EapMethod::TTLS &&
- method == ISupplicantStaNetwork::EapPhase2Method::GTC) {
- eap_phase2_str = kEapPhase2AuthEapPrefix;
- } else {
- eap_phase2_str = kEapPhase2AuthPrefix;
- }
- eap_phase2_str += kEapPhase2MethodStrings[eap_phase2_method_idx];
- if (setStringFieldAndResetState(
- eap_phase2_str.c_str(), &(wpa_ssid->eap.phase2),
- "eap phase2")) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapIdentityInternal(
- const std::vector<uint8_t> &identity)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (setByteArrayFieldAndResetState(
- identity.data(), identity.size(), &(wpa_ssid->eap.identity),
- &(wpa_ssid->eap.identity_len), "eap identity")) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapAnonymousIdentityInternal(
- const std::vector<uint8_t> &identity)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (setByteArrayFieldAndResetState(
- identity.data(), identity.size(),
- &(wpa_ssid->eap.anonymous_identity),
- &(wpa_ssid->eap.anonymous_identity_len),
- "eap anonymous_identity")) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapPasswordInternal(
- const std::vector<uint8_t> &password)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (setByteArrayKeyFieldAndResetState(
- password.data(), password.size(), &(wpa_ssid->eap.password),
- &(wpa_ssid->eap.password_len), "eap password")) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- wpa_ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
- wpa_ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapCACertInternal(const std::string &path)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (setStringFieldAndResetState(
- path.c_str(), &(wpa_ssid->eap.ca_cert), "eap ca_cert")) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapCAPathInternal(const std::string &path)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (setStringFieldAndResetState(
- path.c_str(), &(wpa_ssid->eap.ca_path), "eap ca_path")) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapClientCertInternal(const std::string &path)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (setStringFieldAndResetState(
- path.c_str(), &(wpa_ssid->eap.client_cert),
- "eap client_cert")) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapPrivateKeyIdInternal(const std::string &id)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (setStringFieldAndResetState(
- id.c_str(), &(wpa_ssid->eap.key_id), "eap key_id")) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapSubjectMatchInternal(
- const std::string &match)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (setStringFieldAndResetState(
- match.c_str(), &(wpa_ssid->eap.subject_match),
- "eap subject_match")) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapAltSubjectMatchInternal(
- const std::string &match)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (setStringFieldAndResetState(
- match.c_str(), &(wpa_ssid->eap.altsubject_match),
- "eap altsubject_match")) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapEngineInternal(bool enable)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- wpa_ssid->eap.engine = enable ? 1 : 0;
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapEngineIDInternal(const std::string &id)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (setStringFieldAndResetState(
- id.c_str(), &(wpa_ssid->eap.engine_id), "eap engine_id")) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setEapDomainSuffixMatchInternal(
- const std::string &match)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (setStringFieldAndResetState(
- match.c_str(), &(wpa_ssid->eap.domain_suffix_match),
- "eap domain_suffix_match")) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setProactiveKeyCachingInternal(bool enable)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- wpa_ssid->proactive_key_caching = enable ? 1 : 0;
- resetInternalStateAfterParamsUpdate();
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setIdStrInternal(const std::string &id_str)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (setStringFieldAndResetState(
- id_str.c_str(), &(wpa_ssid->id_str), "id_str")) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::setUpdateIdentifierInternal(uint32_t id)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- wpa_ssid->update_identifier = id;
- wpa_printf(
- MSG_MSGDUMP, "update_identifier: %d", wpa_ssid->update_identifier);
- resetInternalStateAfterParamsUpdate();
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, std::vector<uint8_t>> StaNetwork::getSsidInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- std::vector<uint8_t> ssid;
- ssid.assign(wpa_ssid->ssid, wpa_ssid->ssid + wpa_ssid->ssid_len);
- return {{SupplicantStatusCode::SUCCESS, ""}, std::move(ssid)};
-}
-
-std::pair<SupplicantStatus, std::array<uint8_t, 6>>
-StaNetwork::getBssidInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- std::array<uint8_t, 6> bssid{};
- os_memcpy(bssid.data(), kZeroBssid, ETH_ALEN);
- if (wpa_ssid->bssid_set) {
- os_memcpy(bssid.data(), wpa_ssid->bssid, ETH_ALEN);
- }
- return {{SupplicantStatusCode::SUCCESS, ""}, std::move(bssid)};
-}
-
-std::pair<SupplicantStatus, bool> StaNetwork::getScanSsidInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""},
- (wpa_ssid->scan_ssid == 1)};
-}
-
-std::pair<SupplicantStatus, uint32_t> StaNetwork::getKeyMgmtInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""},
- wpa_ssid->key_mgmt & kAllowedKeyMgmtMask};
-}
-
-std::pair<SupplicantStatus, uint32_t> StaNetwork::getProtoInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""},
- wpa_ssid->proto & kAllowedProtoMask};
-}
-
-std::pair<SupplicantStatus, uint32_t> StaNetwork::getAuthAlgInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""},
- wpa_ssid->auth_alg & kAllowedAuthAlgMask};
-}
-
-std::pair<SupplicantStatus, uint32_t> StaNetwork::getGroupCipherInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""},
- wpa_ssid->group_cipher & kAllowedGroupCipherMask};
-}
-
-std::pair<SupplicantStatus, uint32_t> StaNetwork::getPairwiseCipherInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""},
- wpa_ssid->pairwise_cipher & kAllowedPairwisewCipherMask};
-}
-
-std::pair<SupplicantStatus, std::string> StaNetwork::getPskPassphraseInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->passphrase) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->passphrase};
-}
-
-std::pair<SupplicantStatus, std::array<uint8_t, 32>>
-StaNetwork::getPskInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- WPA_ASSERT(psk.size() == sizeof(wpa_ssid->psk));
- if (!wpa_ssid->psk_set) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- std::array<uint8_t, 32> psk;
- os_memcpy(psk.data(), wpa_ssid->psk, psk.size());
- return {{SupplicantStatusCode::SUCCESS, ""}, psk};
-}
-
-std::pair<SupplicantStatus, std::vector<uint8_t>> StaNetwork::getWepKeyInternal(
- uint32_t key_idx)
-{
- std::vector<uint8_t> wep_key;
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (key_idx >=
- static_cast<uint32_t>(
- ISupplicantStaNetwork::ParamSizeLimits::WEP_KEYS_MAX_NUM)) {
- return {{SupplicantStatusCode::FAILURE_ARGS_INVALID, ""},
- wep_key};
- }
- wep_key.assign(
- wpa_ssid->wep_key[key_idx],
- wpa_ssid->wep_key[key_idx] + wpa_ssid->wep_key_len[key_idx]);
- return {{SupplicantStatusCode::SUCCESS, ""}, std::move(wep_key)};
-}
-
-std::pair<SupplicantStatus, uint32_t> StaNetwork::getWepTxKeyIdxInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->wep_tx_keyidx};
-}
-
-std::pair<SupplicantStatus, bool> StaNetwork::getRequirePmfInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""},
- (wpa_ssid->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)};
-}
-
-std::pair<SupplicantStatus, ISupplicantStaNetwork::EapMethod>
-StaNetwork::getEapMethodInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.eap_methods) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- // wpa_supplicant can support setting multiple eap methods for each
- // network. But, this is not really used by Android. So, just reading
- // the first EAP method for each network.
- const std::string eap_method_str = eap_get_name(
- wpa_ssid->eap.eap_methods[0].vendor,
- static_cast<EapType>(wpa_ssid->eap.eap_methods[0].method));
- size_t eap_method_idx =
- std::find(
- std::begin(kEapMethodStrings), std::end(kEapMethodStrings),
- eap_method_str) -
- std::begin(kEapMethodStrings);
- if (eap_method_idx >= kEapMethodMax) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- return {{SupplicantStatusCode::SUCCESS, ""},
- static_cast<ISupplicantStaNetwork::EapMethod>(eap_method_idx)};
-}
-
-std::pair<SupplicantStatus, ISupplicantStaNetwork::EapPhase2Method>
-StaNetwork::getEapPhase2MethodInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.phase2) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- const std::string eap_phase2_method_str_with_prefix =
- wpa_ssid->eap.phase2;
- std::string eap_phase2_method_str;
- // Strip out the phase 2 method prefix before doing a reverse lookup
- // of phase 2 string to the Eap Phase 2 type.
- if (eap_phase2_method_str_with_prefix.find(kEapPhase2AuthPrefix) == 0) {
- eap_phase2_method_str =
- eap_phase2_method_str_with_prefix.substr(
- strlen(kEapPhase2AuthPrefix),
- eap_phase2_method_str_with_prefix.size());
- } else if (
- eap_phase2_method_str_with_prefix.find(kEapPhase2AuthEapPrefix) ==
- 0) {
- eap_phase2_method_str =
- eap_phase2_method_str_with_prefix.substr(
- strlen(kEapPhase2AuthEapPrefix),
- eap_phase2_method_str_with_prefix.size());
- }
- size_t eap_phase2_method_idx =
- std::find(
- std::begin(kEapPhase2MethodStrings),
- std::end(kEapPhase2MethodStrings), eap_phase2_method_str) -
- std::begin(kEapPhase2MethodStrings);
- if (eap_phase2_method_idx >= kEapPhase2MethodMax) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- return {{SupplicantStatusCode::SUCCESS, ""},
- static_cast<ISupplicantStaNetwork::EapPhase2Method>(
- eap_phase2_method_idx)};
-}
-
-std::pair<SupplicantStatus, std::vector<uint8_t>>
-StaNetwork::getEapIdentityInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.identity) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- return {{SupplicantStatusCode::SUCCESS, ""},
- std::vector<uint8_t>(
- wpa_ssid->eap.identity,
- wpa_ssid->eap.identity + wpa_ssid->eap.identity_len)};
-}
-
-std::pair<SupplicantStatus, std::vector<uint8_t>>
-StaNetwork::getEapAnonymousIdentityInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.anonymous_identity) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- return {{SupplicantStatusCode::SUCCESS, ""},
- std::vector<uint8_t>(
- wpa_ssid->eap.anonymous_identity,
- wpa_ssid->eap.anonymous_identity +
- wpa_ssid->eap.anonymous_identity_len)};
-}
-
-std::pair<SupplicantStatus, std::vector<uint8_t>>
-StaNetwork::getEapPasswordInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.password) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- return {{SupplicantStatusCode::SUCCESS, ""},
- std::vector<uint8_t>(
- wpa_ssid->eap.password,
- wpa_ssid->eap.password + wpa_ssid->eap.password_len)};
-}
-
-std::pair<SupplicantStatus, std::string> StaNetwork::getEapCACertInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.ca_cert) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- return {{SupplicantStatusCode::SUCCESS, ""},
- reinterpret_cast<char *>(wpa_ssid->eap.ca_cert)};
-}
-
-std::pair<SupplicantStatus, std::string> StaNetwork::getEapCAPathInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.ca_path) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- return {{SupplicantStatusCode::SUCCESS, ""},
- reinterpret_cast<char *>(wpa_ssid->eap.ca_path)};
-}
-
-std::pair<SupplicantStatus, std::string> StaNetwork::getEapClientCertInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.client_cert) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- return {{SupplicantStatusCode::SUCCESS, ""},
- reinterpret_cast<char *>(wpa_ssid->eap.client_cert)};
-}
-
-std::pair<SupplicantStatus, std::string>
-StaNetwork::getEapPrivateKeyIdInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.key_id) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->eap.key_id};
-}
-
-std::pair<SupplicantStatus, std::string>
-StaNetwork::getEapSubjectMatchInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.subject_match) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- return {{SupplicantStatusCode::SUCCESS, ""},
- reinterpret_cast<char *>(wpa_ssid->eap.subject_match)};
-}
-
-std::pair<SupplicantStatus, std::string>
-StaNetwork::getEapAltSubjectMatchInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.altsubject_match) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- return {{SupplicantStatusCode::SUCCESS, ""},
- reinterpret_cast<char *>(wpa_ssid->eap.altsubject_match)};
-}
-
-std::pair<SupplicantStatus, bool> StaNetwork::getEapEngineInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->eap.engine == 1};
-}
-
-std::pair<SupplicantStatus, std::string> StaNetwork::getEapEngineIDInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.engine_id) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- return {{SupplicantStatusCode::SUCCESS, ""}, {wpa_ssid->eap.engine_id}};
-}
-
-std::pair<SupplicantStatus, std::string>
-StaNetwork::getEapDomainSuffixMatchInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.domain_suffix_match) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- return {{SupplicantStatusCode::SUCCESS, ""},
- {wpa_ssid->eap.domain_suffix_match}};
-}
-
-std::pair<SupplicantStatus, std::string> StaNetwork::getIdStrInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->id_str) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- return {{SupplicantStatusCode::SUCCESS, ""}, {wpa_ssid->id_str}};
-}
-
-std::pair<SupplicantStatus, std::vector<uint8_t>>
-StaNetwork::getWpsNfcConfigurationTokenInternal()
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- auto token_buf = misc_utils::createWpaBufUniquePtr(
- wpas_wps_network_config_token(wpa_s, 0, wpa_ssid));
- if (!token_buf) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- return {{SupplicantStatusCode::SUCCESS, ""},
- misc_utils::convertWpaBufToVector(token_buf.get())};
-}
-
-SupplicantStatus StaNetwork::enableInternal(bool no_connect)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (wpa_ssid->disabled == 2) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- if (no_connect) {
- wpa_ssid->disabled = 0;
- } else {
- wpa_s->scan_min_time.sec = 0;
- wpa_s->scan_min_time.usec = 0;
- wpa_supplicant_enable_network(wpa_s, wpa_ssid);
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::disableInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (wpa_ssid->disabled == 2) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- wpa_supplicant_disable_network(wpa_s, wpa_ssid);
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::selectInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (wpa_ssid->disabled == 2) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- wpa_s->scan_min_time.sec = 0;
- wpa_s->scan_min_time.usec = 0;
- wpa_supplicant_select_network(wpa_s, wpa_ssid);
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::sendNetworkEapSimGsmAuthResponseInternal(
- const std::vector<ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams>
- &vec_params)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- // Convert the incoming parameters to a string to pass to
- // wpa_supplicant.
- std::string ctrl_rsp_param = std::string(kNetworkEapSimGsmAuthResponse);
- for (const auto ¶ms : vec_params) {
- uint32_t kc_hex_len = params.kc.size() * 2 + 1;
- std::vector<char> kc_hex(kc_hex_len);
- uint32_t sres_hex_len = params.sres.size() * 2 + 1;
- std::vector<char> sres_hex(sres_hex_len);
- wpa_snprintf_hex(
- kc_hex.data(), kc_hex.size(), params.kc.data(),
- params.kc.size());
- wpa_snprintf_hex(
- sres_hex.data(), sres_hex.size(), params.sres.data(),
- params.sres.size());
- ctrl_rsp_param += ":" + std::string(kc_hex.data()) + ":" +
- std::string(sres_hex.data());
- }
- enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_SIM;
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- if (wpa_supplicant_ctrl_rsp_handle(
- wpa_s, wpa_ssid, rtype, ctrl_rsp_param.data(),
- ctrl_rsp_param.size())) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- eapol_sm_notify_ctrl_response(wpa_s->eapol);
- wpa_hexdump_ascii_key(
- MSG_DEBUG, "network sim gsm auth response param",
- (const u8 *)ctrl_rsp_param.c_str(), ctrl_rsp_param.size());
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::sendNetworkEapSimGsmAuthFailureInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_SIM;
- if (wpa_supplicant_ctrl_rsp_handle(
- wpa_s, wpa_ssid, rtype, kNetworkEapSimGsmAuthFailure,
- strlen(kNetworkEapSimGsmAuthFailure))) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- eapol_sm_notify_ctrl_response(wpa_s->eapol);
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::sendNetworkEapSimUmtsAuthResponseInternal(
- const ISupplicantStaNetwork::NetworkResponseEapSimUmtsAuthParams ¶ms)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- // Convert the incoming parameters to a string to pass to
- // wpa_supplicant.
- uint32_t ik_hex_len = params.ik.size() * 2 + 1;
- std::vector<char> ik_hex(ik_hex_len);
- uint32_t ck_hex_len = params.ck.size() * 2 + 1;
- std::vector<char> ck_hex(ck_hex_len);
- uint32_t res_hex_len = params.res.size() * 2 + 1;
- std::vector<char> res_hex(res_hex_len);
- wpa_snprintf_hex(
- ik_hex.data(), ik_hex.size(), params.ik.data(), params.ik.size());
- wpa_snprintf_hex(
- ck_hex.data(), ck_hex.size(), params.ck.data(), params.ck.size());
- wpa_snprintf_hex(
- res_hex.data(), res_hex.size(), params.res.data(),
- params.res.size());
- std::string ctrl_rsp_param =
- std::string(kNetworkEapSimUmtsAuthResponse) + ":" +
- std::string(ik_hex.data()) + ":" + std::string(ck_hex.data()) +
- ":" + std::string(res_hex.data());
- enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_SIM;
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- if (wpa_supplicant_ctrl_rsp_handle(
- wpa_s, wpa_ssid, rtype, ctrl_rsp_param.data(),
- ctrl_rsp_param.size())) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- eapol_sm_notify_ctrl_response(wpa_s->eapol);
- wpa_hexdump_ascii_key(
- MSG_DEBUG, "network sim umts auth response param",
- (const u8 *)ctrl_rsp_param.c_str(), ctrl_rsp_param.size());
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::sendNetworkEapSimUmtsAutsResponseInternal(
- const std::array<uint8_t, 14> &auts)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- uint32_t auts_hex_len = auts.size() * 2 + 1;
- std::vector<char> auts_hex(auts_hex_len);
- wpa_snprintf_hex(
- auts_hex.data(), auts_hex.size(), auts.data(), auts.size());
- std::string ctrl_rsp_param =
- std::string(kNetworkEapSimUmtsAutsResponse) + ":" +
- std::string(auts_hex.data());
- enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_SIM;
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- if (wpa_supplicant_ctrl_rsp_handle(
- wpa_s, wpa_ssid, rtype, ctrl_rsp_param.data(),
- ctrl_rsp_param.size())) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- eapol_sm_notify_ctrl_response(wpa_s->eapol);
- wpa_hexdump_ascii_key(
- MSG_DEBUG, "network sim umts auts response param",
- (const u8 *)ctrl_rsp_param.c_str(), ctrl_rsp_param.size());
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::sendNetworkEapSimUmtsAuthFailureInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_SIM;
- if (wpa_supplicant_ctrl_rsp_handle(
- wpa_s, wpa_ssid, rtype, kNetworkEapSimUmtsAuthFailure,
- strlen(kNetworkEapSimUmtsAuthFailure))) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- eapol_sm_notify_ctrl_response(wpa_s->eapol);
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus StaNetwork::sendNetworkEapIdentityResponseInternal(
- const std::vector<uint8_t> &identity)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- std::string ctrl_rsp_param(identity.begin(), identity.end());
- enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_EAP_IDENTITY;
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- if (wpa_supplicant_ctrl_rsp_handle(
- wpa_s, wpa_ssid, rtype, ctrl_rsp_param.data(),
- ctrl_rsp_param.size())) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- eapol_sm_notify_ctrl_response(wpa_s->eapol);
- wpa_hexdump_ascii_key(
- MSG_DEBUG, "network identity response param",
- (const u8 *)ctrl_rsp_param.c_str(), ctrl_rsp_param.size());
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-/**
- * Retrieve the underlying |wpa_ssid| struct pointer for
- * this network.
- * If the underlying network is removed or the interface
- * this network belong to
- * is removed, all RPC method calls on this object will
- * return failure.
- */
-struct wpa_ssid *StaNetwork::retrieveNetworkPtr()
-{
- wpa_supplicant *wpa_s = retrieveIfacePtr();
- if (!wpa_s)
- return nullptr;
- return wpa_config_get_network(wpa_s->conf, network_id_);
-}
-
-/**
- * Retrieve the underlying |wpa_supplicant| struct
- * pointer for
- * this network.
- */
-struct wpa_supplicant *StaNetwork::retrieveIfacePtr()
-{
- return wpa_supplicant_get_iface(wpa_global_, ifname_.c_str());
-}
-
-/**
- * Check if the provided psk passhrase is valid or not.
- *
- * Returns 0 if valid, 1 otherwise.
- */
-int StaNetwork::isPskPassphraseValid(const std::string &psk)
-{
- if (psk.size() <
- static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
- PSK_PASSPHRASE_MIN_LEN_IN_BYTES) ||
- psk.size() >
- static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
- PSK_PASSPHRASE_MAX_LEN_IN_BYTES)) {
- return 1;
- }
- if (has_ctrl_char((u8 *)psk.c_str(), psk.size())) {
- return 1;
- }
- return 0;
-}
-
-/**
- * Reset internal wpa_supplicant state machine state
- * after params update (except
- * bssid).
- */
-void StaNetwork::resetInternalStateAfterParamsUpdate()
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
-
- wpa_sm_pmksa_cache_flush(wpa_s->wpa, wpa_ssid);
-
- if (wpa_s->current_ssid == wpa_ssid || wpa_s->current_ssid == NULL) {
- /*
- * Invalidate the EAP session cache if
- * anything in the
- * current or previously used
- * configuration changes.
- */
- eapol_sm_invalidate_cached_session(wpa_s->eapol);
- }
-}
-
-/**
- * Helper function to set value in a string field in |wpa_ssid| structue
- * instance for this network.
- * This function frees any existing data in these fields.
- */
-int StaNetwork::setStringFieldAndResetState(
- const char *value, uint8_t **to_update_field, const char *hexdump_prefix)
-{
- return setStringFieldAndResetState(
- value, (char **)to_update_field, hexdump_prefix);
-}
-
-/**
- * Helper function to set value in a string field in |wpa_ssid| structue
- * instance for this network.
- * This function frees any existing data in these fields.
- */
-int StaNetwork::setStringFieldAndResetState(
- const char *value, char **to_update_field, const char *hexdump_prefix)
-{
- int value_len = strlen(value);
- if (*to_update_field) {
- os_free(*to_update_field);
- }
- *to_update_field = dup_binstr(value, value_len);
- if (!(*to_update_field)) {
- return 1;
- }
- wpa_hexdump_ascii(
- MSG_MSGDUMP, hexdump_prefix, *to_update_field, value_len);
- resetInternalStateAfterParamsUpdate();
- return 0;
-}
-
-/**
- * Helper function to set value in a string key field in |wpa_ssid| structue
- * instance for this network.
- * This function frees any existing data in these fields.
- */
-int StaNetwork::setStringKeyFieldAndResetState(
- const char *value, char **to_update_field, const char *hexdump_prefix)
-{
- int value_len = strlen(value);
- if (*to_update_field) {
- str_clear_free(*to_update_field);
- }
- *to_update_field = dup_binstr(value, value_len);
- if (!(*to_update_field)) {
- return 1;
- }
- wpa_hexdump_ascii_key(
- MSG_MSGDUMP, hexdump_prefix, *to_update_field, value_len);
- resetInternalStateAfterParamsUpdate();
- return 0;
-}
-
-/**
- * Helper function to set value in a string field with a corresponding length
- * field in |wpa_ssid| structue instance for this network.
- * This function frees any existing data in these fields.
- */
-int StaNetwork::setByteArrayFieldAndResetState(
- const uint8_t *value, const size_t value_len, uint8_t **to_update_field,
- size_t *to_update_field_len, const char *hexdump_prefix)
-{
- if (*to_update_field) {
- os_free(*to_update_field);
- }
- *to_update_field = (uint8_t *)os_malloc(value_len);
- if (!(*to_update_field)) {
- return 1;
- }
- os_memcpy(*to_update_field, value, value_len);
- *to_update_field_len = value_len;
-
- wpa_hexdump_ascii(
- MSG_MSGDUMP, hexdump_prefix, *to_update_field,
- *to_update_field_len);
- resetInternalStateAfterParamsUpdate();
- return 0;
-}
-
-/**
- * Helper function to set value in a string key field with a corresponding
- * length field in |wpa_ssid| structue instance for this network.
- * This function frees any existing data in these fields.
- */
-int StaNetwork::setByteArrayKeyFieldAndResetState(
- const uint8_t *value, const size_t value_len, uint8_t **to_update_field,
- size_t *to_update_field_len, const char *hexdump_prefix)
-{
- if (*to_update_field) {
- bin_clear_free(*to_update_field, *to_update_field_len);
- }
- *to_update_field = (uint8_t *)os_malloc(value_len);
- if (!(*to_update_field)) {
- return 1;
- }
- os_memcpy(*to_update_field, value, value_len);
- *to_update_field_len = value_len;
-
- wpa_hexdump_ascii_key(
- MSG_MSGDUMP, hexdump_prefix, *to_update_field,
- *to_update_field_len);
- resetInternalStateAfterParamsUpdate();
- return 0;
-}
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace wifi
-} // namespace supplicant
-} // namespace hardware
-} // namespace android
diff --git a/wpa_supplicant/hidl/1.0/sta_network.h b/wpa_supplicant/hidl/1.0/sta_network.h
deleted file mode 100644
index 6e8d42b..0000000
--- a/wpa_supplicant/hidl/1.0/sta_network.h
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef WPA_SUPPLICANT_HIDL_STA_NETWORK_H
-#define WPA_SUPPLICANT_HIDL_STA_NETWORK_H
-
-#include <array>
-#include <vector>
-
-#include <android-base/macros.h>
-
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetwork.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetworkCallback.h>
-
-extern "C" {
-#include "utils/common.h"
-#include "utils/includes.h"
-#include "config.h"
-#include "wpa_supplicant_i.h"
-#include "notify.h"
-#include "eapol_supp/eapol_supp_sm.h"
-#include "eap_peer/eap.h"
-#include "rsn_supp/wpa.h"
-}
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-
-/**
- * Implementation of StaNetwork hidl object. Each unique hidl
- * object is used for control operations on a specific network
- * controlled by wpa_supplicant.
- */
-class StaNetwork : public ISupplicantStaNetwork
-{
-public:
- StaNetwork(
- struct wpa_global* wpa_global, const char ifname[], int network_id);
- ~StaNetwork() override = default;
- // Refer to |StaIface::invalidate()|.
- void invalidate();
- bool isValid();
-
- // Hidl methods exposed.
- Return<void> getId(getId_cb _hidl_cb) override;
- Return<void> getInterfaceName(getInterfaceName_cb _hidl_cb) override;
- Return<void> getType(getType_cb _hidl_cb) override;
- Return<void> registerCallback(
- const sp<ISupplicantStaNetworkCallback>& callback,
- registerCallback_cb _hidl_cb) override;
- Return<void> setSsid(
- const hidl_vec<uint8_t>& ssid, setSsid_cb _hidl_cb) override;
- Return<void> setBssid(
- const hidl_array<uint8_t, 6>& bssid, setBssid_cb _hidl_cb) override;
- Return<void> setScanSsid(bool enable, setScanSsid_cb _hidl_cb) override;
- Return<void> setKeyMgmt(
- uint32_t key_mgmt_mask, setKeyMgmt_cb _hidl_cb) override;
- Return<void> setProto(
- uint32_t proto_mask, setProto_cb _hidl_cb) override;
- Return<void> setAuthAlg(
- uint32_t auth_alg_mask, setAuthAlg_cb _hidl_cb) override;
- Return<void> setGroupCipher(
- uint32_t group_cipher_mask, setGroupCipher_cb _hidl_cb) override;
- Return<void> setPairwiseCipher(
- uint32_t pairwise_cipher_mask,
- setPairwiseCipher_cb _hidl_cb) override;
- Return<void> setPskPassphrase(
- const hidl_string& psk, setPskPassphrase_cb _hidl_cb) override;
- Return<void> setPsk(
- const hidl_array<uint8_t, 32>& psk, setPsk_cb _hidl_cb) override;
- Return<void> setWepKey(
- uint32_t key_idx, const hidl_vec<uint8_t>& wep_key,
- setWepKey_cb _hidl_cb) override;
- Return<void> setWepTxKeyIdx(
- uint32_t key_idx, setWepTxKeyIdx_cb _hidl_cb) override;
- Return<void> setRequirePmf(
- bool enable, setRequirePmf_cb _hidl_cb) override;
- Return<void> setEapMethod(
- ISupplicantStaNetwork::EapMethod method,
- setEapMethod_cb _hidl_cb) override;
- Return<void> setEapPhase2Method(
- ISupplicantStaNetwork::EapPhase2Method method,
- setEapPhase2Method_cb _hidl_cb) override;
- Return<void> setEapIdentity(
- const hidl_vec<uint8_t>& identity,
- setEapIdentity_cb _hidl_cb) override;
- Return<void> setEapAnonymousIdentity(
- const hidl_vec<uint8_t>& identity,
- setEapAnonymousIdentity_cb _hidl_cb) override;
- Return<void> setEapPassword(
- const hidl_vec<uint8_t>& password,
- setEapPassword_cb _hidl_cb) override;
- Return<void> setEapCACert(
- const hidl_string& path, setEapCACert_cb _hidl_cb) override;
- Return<void> setEapCAPath(
- const hidl_string& path, setEapCAPath_cb _hidl_cb) override;
- Return<void> setEapClientCert(
- const hidl_string& path, setEapClientCert_cb _hidl_cb) override;
- Return<void> setEapPrivateKeyId(
- const hidl_string& id, setEapPrivateKeyId_cb _hidl_cb) override;
- Return<void> setEapSubjectMatch(
- const hidl_string& match, setEapSubjectMatch_cb _hidl_cb) override;
- Return<void> setEapAltSubjectMatch(
- const hidl_string& match,
- setEapAltSubjectMatch_cb _hidl_cb) override;
- Return<void> setEapEngine(
- bool enable, setEapEngine_cb _hidl_cb) override;
- Return<void> setEapEngineID(
- const hidl_string& id, setEapEngineID_cb _hidl_cb) override;
- Return<void> setEapDomainSuffixMatch(
- const hidl_string& match,
- setEapDomainSuffixMatch_cb _hidl_cb) override;
- Return<void> setProactiveKeyCaching(
- bool enable, setProactiveKeyCaching_cb _hidl_cb) override;
- Return<void> setIdStr(
- const hidl_string& id_str, setIdStr_cb _hidl_cb) override;
- Return<void> setUpdateIdentifier(
- uint32_t id, setUpdateIdentifier_cb _hidl_cb) override;
- Return<void> getSsid(getSsid_cb _hidl_cb) override;
- Return<void> getBssid(getBssid_cb _hidl_cb) override;
- Return<void> getScanSsid(getScanSsid_cb _hidl_cb) override;
- Return<void> getKeyMgmt(getKeyMgmt_cb _hidl_cb) override;
- Return<void> getProto(getProto_cb _hidl_cb) override;
- Return<void> getAuthAlg(getAuthAlg_cb _hidl_cb) override;
- Return<void> getGroupCipher(getGroupCipher_cb _hidl_cb) override;
- Return<void> getPairwiseCipher(getPairwiseCipher_cb _hidl_cb) override;
- Return<void> getPskPassphrase(getPskPassphrase_cb _hidl_cb) override;
- Return<void> getPsk(getPsk_cb _hidl_cb) override;
- Return<void> getWepKey(
- uint32_t key_idx, getWepKey_cb _hidl_cb) override;
- Return<void> getWepTxKeyIdx(getWepTxKeyIdx_cb _hidl_cb) override;
- Return<void> getRequirePmf(getRequirePmf_cb _hidl_cb) override;
- Return<void> getEapMethod(getEapMethod_cb _hidl_cb) override;
- Return<void> getEapPhase2Method(
- getEapPhase2Method_cb _hidl_cb) override;
- Return<void> getEapIdentity(getEapIdentity_cb _hidl_cb) override;
- Return<void> getEapAnonymousIdentity(
- getEapAnonymousIdentity_cb _hidl_cb) override;
- Return<void> getEapPassword(getEapPassword_cb _hidl_cb) override;
- Return<void> getEapCACert(getEapCACert_cb _hidl_cb) override;
- Return<void> getEapCAPath(getEapCAPath_cb _hidl_cb) override;
- Return<void> getEapClientCert(getEapClientCert_cb _hidl_cb) override;
- Return<void> getEapPrivateKeyId(
- getEapPrivateKeyId_cb _hidl_cb) override;
- Return<void> getEapSubjectMatch(
- getEapSubjectMatch_cb _hidl_cb) override;
- Return<void> getEapAltSubjectMatch(
- getEapAltSubjectMatch_cb _hidl_cb) override;
- Return<void> getEapEngine(getEapEngine_cb _hidl_cb) override;
- Return<void> getEapEngineID(getEapEngineID_cb _hidl_cb) override;
- Return<void> getEapDomainSuffixMatch(
- getEapDomainSuffixMatch_cb _hidl_cb) override;
- Return<void> getIdStr(getIdStr_cb _hidl_cb) override;
- Return<void> getWpsNfcConfigurationToken(
- getWpsNfcConfigurationToken_cb _hidl_cb) override;
- Return<void> enable(bool no_connect, enable_cb _hidl_cb) override;
- Return<void> disable(disable_cb _hidl_cb) override;
- Return<void> select(select_cb _hidl_cb) override;
- Return<void> sendNetworkEapSimGsmAuthResponse(
- const hidl_vec<
- ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams>&
- vec_params,
- sendNetworkEapSimGsmAuthResponse_cb _hidl_cb) override;
- Return<void> sendNetworkEapSimGsmAuthFailure(
- sendNetworkEapSimGsmAuthFailure_cb _hidl_cb) override;
- Return<void> sendNetworkEapSimUmtsAuthResponse(
- const ISupplicantStaNetwork::NetworkResponseEapSimUmtsAuthParams&
- params,
- sendNetworkEapSimUmtsAuthResponse_cb _hidl_cb) override;
- Return<void> sendNetworkEapSimUmtsAutsResponse(
- const hidl_array<uint8_t, 14>& auts,
- sendNetworkEapSimUmtsAutsResponse_cb _hidl_cb) override;
- Return<void> sendNetworkEapSimUmtsAuthFailure(
- sendNetworkEapSimUmtsAuthFailure_cb _hidl_cb) override;
- Return<void> sendNetworkEapIdentityResponse(
- const hidl_vec<uint8_t>& identity,
- sendNetworkEapIdentityResponse_cb _hidl_cb) override;
-
-private:
- // Corresponding worker functions for the HIDL methods.
- std::pair<SupplicantStatus, uint32_t> getIdInternal();
- std::pair<SupplicantStatus, std::string> getInterfaceNameInternal();
- std::pair<SupplicantStatus, IfaceType> getTypeInternal();
- SupplicantStatus registerCallbackInternal(
- const sp<ISupplicantStaNetworkCallback>& callback);
- SupplicantStatus setSsidInternal(const std::vector<uint8_t>& ssid);
- SupplicantStatus setBssidInternal(const std::array<uint8_t, 6>& bssid);
- SupplicantStatus setScanSsidInternal(bool enable);
- SupplicantStatus setKeyMgmtInternal(uint32_t key_mgmt_mask);
- SupplicantStatus setProtoInternal(uint32_t proto_mask);
- SupplicantStatus setAuthAlgInternal(uint32_t auth_alg_mask);
- SupplicantStatus setGroupCipherInternal(uint32_t group_cipher_mask);
- SupplicantStatus setPairwiseCipherInternal(
- uint32_t pairwise_cipher_mask);
- SupplicantStatus setPskPassphraseInternal(const std::string& psk);
- SupplicantStatus setPskInternal(const std::array<uint8_t, 32>& psk);
- SupplicantStatus setWepKeyInternal(
- uint32_t key_idx, const std::vector<uint8_t>& wep_key);
- SupplicantStatus setWepTxKeyIdxInternal(uint32_t key_idx);
- SupplicantStatus setRequirePmfInternal(bool enable);
- SupplicantStatus setEapMethodInternal(
- ISupplicantStaNetwork::EapMethod method);
- SupplicantStatus setEapPhase2MethodInternal(
- ISupplicantStaNetwork::EapPhase2Method method);
- SupplicantStatus setEapIdentityInternal(
- const std::vector<uint8_t>& identity);
- SupplicantStatus setEapAnonymousIdentityInternal(
- const std::vector<uint8_t>& identity);
- SupplicantStatus setEapPasswordInternal(
- const std::vector<uint8_t>& password);
- SupplicantStatus setEapCACertInternal(const std::string& path);
- SupplicantStatus setEapCAPathInternal(const std::string& path);
- SupplicantStatus setEapClientCertInternal(const std::string& path);
- SupplicantStatus setEapPrivateKeyIdInternal(const std::string& id);
- SupplicantStatus setEapSubjectMatchInternal(const std::string& match);
- SupplicantStatus setEapAltSubjectMatchInternal(
- const std::string& match);
- SupplicantStatus setEapEngineInternal(bool enable);
- SupplicantStatus setEapEngineIDInternal(const std::string& id);
- SupplicantStatus setEapDomainSuffixMatchInternal(
- const std::string& match);
- SupplicantStatus setProactiveKeyCachingInternal(bool enable);
- SupplicantStatus setIdStrInternal(const std::string& id_str);
- SupplicantStatus setUpdateIdentifierInternal(uint32_t id);
- std::pair<SupplicantStatus, std::vector<uint8_t>> getSsidInternal();
- std::pair<SupplicantStatus, std::array<uint8_t, 6>> getBssidInternal();
- std::pair<SupplicantStatus, bool> getScanSsidInternal();
- std::pair<SupplicantStatus, uint32_t> getKeyMgmtInternal();
- std::pair<SupplicantStatus, uint32_t> getProtoInternal();
- std::pair<SupplicantStatus, uint32_t> getAuthAlgInternal();
- std::pair<SupplicantStatus, uint32_t> getGroupCipherInternal();
- std::pair<SupplicantStatus, uint32_t> getPairwiseCipherInternal();
- std::pair<SupplicantStatus, std::string> getPskPassphraseInternal();
- std::pair<SupplicantStatus, std::array<uint8_t, 32>> getPskInternal();
- std::pair<SupplicantStatus, std::vector<uint8_t>> getWepKeyInternal(
- uint32_t key_idx);
- std::pair<SupplicantStatus, uint32_t> getWepTxKeyIdxInternal();
- std::pair<SupplicantStatus, bool> getRequirePmfInternal();
- std::pair<SupplicantStatus, ISupplicantStaNetwork::EapMethod>
- getEapMethodInternal();
- std::pair<SupplicantStatus, ISupplicantStaNetwork::EapPhase2Method>
- getEapPhase2MethodInternal();
- std::pair<SupplicantStatus, std::vector<uint8_t>>
- getEapIdentityInternal();
- std::pair<SupplicantStatus, std::vector<uint8_t>>
- getEapAnonymousIdentityInternal();
- std::pair<SupplicantStatus, std::vector<uint8_t>>
- getEapPasswordInternal();
- std::pair<SupplicantStatus, std::string> getEapCACertInternal();
- std::pair<SupplicantStatus, std::string> getEapCAPathInternal();
- std::pair<SupplicantStatus, std::string> getEapClientCertInternal();
- std::pair<SupplicantStatus, std::string> getEapPrivateKeyIdInternal();
- std::pair<SupplicantStatus, std::string> getEapSubjectMatchInternal();
- std::pair<SupplicantStatus, std::string>
- getEapAltSubjectMatchInternal();
- std::pair<SupplicantStatus, bool> getEapEngineInternal();
- std::pair<SupplicantStatus, std::string> getEapEngineIDInternal();
- std::pair<SupplicantStatus, std::string>
- getEapDomainSuffixMatchInternal();
- std::pair<SupplicantStatus, std::string> getIdStrInternal();
- std::pair<SupplicantStatus, std::vector<uint8_t>>
- getWpsNfcConfigurationTokenInternal();
- SupplicantStatus enableInternal(bool no_connect);
- SupplicantStatus disableInternal();
- SupplicantStatus selectInternal();
- SupplicantStatus sendNetworkEapSimGsmAuthResponseInternal(
- const std::vector<
- ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams>&
- vec_params);
- SupplicantStatus sendNetworkEapSimGsmAuthFailureInternal();
- SupplicantStatus sendNetworkEapSimUmtsAuthResponseInternal(
- const ISupplicantStaNetwork::NetworkResponseEapSimUmtsAuthParams&
- params);
- SupplicantStatus sendNetworkEapSimUmtsAutsResponseInternal(
- const std::array<uint8_t, 14>& auts);
- SupplicantStatus sendNetworkEapSimUmtsAuthFailureInternal();
- SupplicantStatus sendNetworkEapIdentityResponseInternal(
- const std::vector<uint8_t>& identity);
-
- struct wpa_ssid* retrieveNetworkPtr();
- struct wpa_supplicant* retrieveIfacePtr();
- int isPskPassphraseValid(const std::string& psk);
- void resetInternalStateAfterParamsUpdate();
- int setStringFieldAndResetState(
- const char* value, uint8_t** to_update_field,
- const char* hexdump_prefix);
- int setStringFieldAndResetState(
- const char* value, char** to_update_field,
- const char* hexdump_prefix);
- int setStringKeyFieldAndResetState(
- const char* value, char** to_update_field,
- const char* hexdump_prefix);
- int setByteArrayFieldAndResetState(
- const uint8_t* value, const size_t value_len,
- uint8_t** to_update_field, size_t* to_update_field_len,
- const char* hexdump_prefix);
- int setByteArrayKeyFieldAndResetState(
- const uint8_t* value, const size_t value_len,
- uint8_t** to_update_field, size_t* to_update_field_len,
- const char* hexdump_prefix);
-
- // Reference to the global wpa_struct. This is assumed to be valid
- // for the lifetime of the process.
- struct wpa_global* wpa_global_;
- // Name of the iface this network belongs to.
- const std::string ifname_;
- // Id of the network this hidl object controls.
- const int network_id_;
- bool is_valid_;
-
- DISALLOW_COPY_AND_ASSIGN(StaNetwork);
-};
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace wifi
-} // namespace supplicant
-} // namespace hardware
-} // namespace android
-
-#endif // WPA_SUPPLICANT_HIDL_STA_NETWORK_H
diff --git a/wpa_supplicant/hidl/1.0/supplicant.cpp b/wpa_supplicant/hidl/1.0/supplicant.cpp
deleted file mode 100644
index bf009b5..0000000
--- a/wpa_supplicant/hidl/1.0/supplicant.cpp
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "hidl_manager.h"
-#include "hidl_return_util.h"
-#include "supplicant.h"
-
-#include <android-base/file.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-namespace {
-constexpr char kStaIfaceConfPath[] =
- "/data/misc/wifi/wpa_supplicant.conf";
-constexpr char kP2pIfaceConfPath[] =
- "/data/misc/wifi/p2p_supplicant.conf";
-// Migrate conf files for existing devices.
-constexpr char kTemplateConfPath[] =
- "/vendor/etc/wifi/wpa_supplicant.conf";
-constexpr mode_t kConfigFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
-
-int copyFile(
- const std::string& src_file_path, const std::string& dest_file_path)
-{
- std::string file_contents;
- if (!android::base::ReadFileToString(src_file_path, &file_contents)) {
- wpa_printf(
- MSG_ERROR, "Failed to read from %s. Errno: %s",
- src_file_path.c_str(), strerror(errno));
- return -1;
- }
- if (!android::base::WriteStringToFile(
- file_contents, dest_file_path, kConfigFileMode, getuid(),
- getgid())) {
- wpa_printf(
- MSG_ERROR, "Failed to write to %s. Errno: %s",
- dest_file_path.c_str(), strerror(errno));
- return -1;
- }
- return 0;
-}
-
-/**
- * Copy |src_file_path| to |dest_file_path| if it exists.
- *
- * Returns 1 if |src_file_path| does not exists,
- * Returns -1 if the copy fails.
- * Returns 0 if the copy succeeds.
- */
-int copyFileIfItExists(
- const std::string& src_file_path, const std::string& dest_file_path)
-{
- int ret = access(src_file_path.c_str(), R_OK);
- if ((ret != 0) && (errno == ENOENT)) {
- return 1;
- }
- ret = copyFile(src_file_path, dest_file_path);
- if (ret != 0) {
- wpa_printf(
- MSG_ERROR, "Failed copying %s to %s.",
- src_file_path.c_str(), dest_file_path.c_str());
- return -1;
- }
- return 0;
-}
-
-/**
- * Ensure that the specified config file pointed by |config_file_path| exists.
- * a) If the |config_file_path| exists with the correct permissions, return.
- * b) If the |config_file_path| does not exists, copy over the contents of
- * |template_config_file_path|.
- */
-int copyTemplateConfigFileIfNotExists(
- const std::string& config_file_path,
- const std::string& template_config_file_path)
-{
- int ret = access(config_file_path.c_str(), R_OK | W_OK);
- if (ret == 0) {
- return 0;
- }
- if (errno == EACCES) {
- ret = chmod(config_file_path.c_str(), kConfigFileMode);
- if (ret == 0) {
- return 0;
- } else {
- wpa_printf(
- MSG_ERROR, "Cannot set RW to %s. Errno: %s",
- config_file_path.c_str(), strerror(errno));
- return -1;
- }
- } else if (errno != ENOENT) {
- wpa_printf(
- MSG_ERROR, "Cannot acces %s. Errno: %s",
- config_file_path.c_str(), strerror(errno));
- return -1;
- }
- ret = copyFileIfItExists(template_config_file_path, config_file_path);
- if (ret == 0) {
- wpa_printf(
- MSG_INFO, "Copied template conf file from %s to %s",
- template_config_file_path.c_str(), config_file_path.c_str());
- return 0;
- } else if (ret == -1) {
- unlink(config_file_path.c_str());
- return -1;
- }
- // Did not create the conf file.
- return -1;
-}
-} // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-// These are hardcoded for android.
-const char Supplicant::kDriverName[] = "nl80211";
-const char Supplicant::kConfigFilePath[] =
- "/data/misc/wifi/wpa_supplicant.conf";
-
-Supplicant::Supplicant(struct wpa_global* global) : wpa_global_(global) {}
-bool Supplicant::isValid()
-{
- // This top level object cannot be invalidated.
- return true;
-}
-
-bool Supplicant::ensureConfigFileExists()
-{
- // To support Android P Wifi framework, make sure the config file exists.
- if (copyTemplateConfigFileIfNotExists(
- kStaIfaceConfPath, kTemplateConfPath) != 0) {
- wpa_printf(MSG_ERROR, "Conf file does not exists: %s",
- kStaIfaceConfPath);
- return false;
- }
- // P2P configuration file is not madatory but required for some devices.
- if (copyTemplateConfigFileIfNotExists(
- kP2pIfaceConfPath, kTemplateConfPath) != 0) {
- wpa_printf(MSG_INFO, "Conf file does not exists: %s",
- kP2pIfaceConfPath);
- }
- return true;
-}
-
-Return<void> Supplicant::getInterface(
- const IfaceInfo& iface_info, getInterface_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &Supplicant::getInterfaceInternal, _hidl_cb, iface_info);
-}
-
-Return<void> Supplicant::listInterfaces(listInterfaces_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &Supplicant::listInterfacesInternal, _hidl_cb);
-}
-
-Return<void> Supplicant::registerCallback(
- const sp<ISupplicantCallback>& callback, registerCallback_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &Supplicant::registerCallbackInternal, _hidl_cb, callback);
-}
-
-Return<void> Supplicant::setDebugParams(
- ISupplicant::DebugLevel level, bool show_timestamp, bool show_keys,
- setDebugParams_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &Supplicant::setDebugParamsInternal, _hidl_cb, level,
- show_timestamp, show_keys);
-}
-
-Return<void> Supplicant::setConcurrencyPriority(
- IfaceType type, setConcurrencyPriority_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &Supplicant::setConcurrencyPriorityInternal, _hidl_cb, type);
-}
-
-Return<ISupplicant::DebugLevel> Supplicant::getDebugLevel()
-{
- // TODO: Add SupplicantStatus in this method return for uniformity with
- // the other methods in supplicant HIDL interface.
- return (ISupplicant::DebugLevel)wpa_debug_level;
-}
-
-Return<bool> Supplicant::isDebugShowTimestampEnabled()
-{
- // TODO: Add SupplicantStatus in this method return for uniformity with
- // the other methods in supplicant HIDL interface.
- return ((wpa_debug_timestamp != 0) ? true : false);
-}
-
-Return<bool> Supplicant::isDebugShowKeysEnabled()
-{
- // TODO: Add SupplicantStatus in this method return for uniformity with
- // the other methods in supplicant HIDL interface.
- return ((wpa_debug_show_keys != 0) ? true : false);
-}
-
-std::pair<SupplicantStatus, sp<ISupplicantIface>>
-Supplicant::getInterfaceInternal(const IfaceInfo& iface_info)
-{
- struct wpa_supplicant* wpa_s =
- wpa_supplicant_get_iface(wpa_global_, iface_info.name.c_str());
- if (!wpa_s) {
- return {{SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""},
- nullptr};
- }
- HidlManager* hidl_manager = HidlManager::getInstance();
- if (iface_info.type == IfaceType::P2P) {
- android::sp<ISupplicantP2pIface> iface;
- if (!hidl_manager ||
- hidl_manager->getP2pIfaceHidlObjectByIfname(
- wpa_s->ifname, &iface)) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""},
- iface};
- }
- // Set this flag true here, since there is no HIDL initialize method for the p2p
- // config, and the supplicant interface is not ready when the p2p iface is created.
- wpa_s->conf->persistent_reconnect = true;
- return {{SupplicantStatusCode::SUCCESS, ""}, iface};
- } else {
- android::sp<ISupplicantStaIface> iface;
- if (!hidl_manager ||
- hidl_manager->getStaIfaceHidlObjectByIfname(
- wpa_s->ifname, &iface)) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""},
- iface};
- }
- return {{SupplicantStatusCode::SUCCESS, ""}, iface};
- }
-}
-
-std::pair<SupplicantStatus, std::vector<ISupplicant::IfaceInfo>>
-Supplicant::listInterfacesInternal()
-{
- std::vector<ISupplicant::IfaceInfo> ifaces;
- for (struct wpa_supplicant* wpa_s = wpa_global_->ifaces; wpa_s;
- wpa_s = wpa_s->next) {
- if (wpa_s->global->p2p_init_wpa_s == wpa_s) {
- ifaces.emplace_back(ISupplicant::IfaceInfo{
- IfaceType::P2P, wpa_s->ifname});
- } else {
- ifaces.emplace_back(ISupplicant::IfaceInfo{
- IfaceType::STA, wpa_s->ifname});
- }
- }
- return {{SupplicantStatusCode::SUCCESS, ""}, std::move(ifaces)};
-}
-
-SupplicantStatus Supplicant::registerCallbackInternal(
- const sp<ISupplicantCallback>& callback)
-{
- HidlManager* hidl_manager = HidlManager::getInstance();
- if (!hidl_manager ||
- hidl_manager->addSupplicantCallbackHidlObject(callback)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus Supplicant::setDebugParamsInternal(
- ISupplicant::DebugLevel level, bool show_timestamp, bool show_keys)
-{
- if (wpa_supplicant_set_debug_params(
- wpa_global_, static_cast<uint32_t>(level), show_timestamp,
- show_keys)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus Supplicant::setConcurrencyPriorityInternal(IfaceType type)
-{
- if (type == IfaceType::STA) {
- wpa_global_->conc_pref =
- wpa_global::wpa_conc_pref::WPA_CONC_PREF_STA;
- } else if (type == IfaceType::P2P) {
- wpa_global_->conc_pref =
- wpa_global::wpa_conc_pref::WPA_CONC_PREF_P2P;
- } else {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
- }
- return SupplicantStatus{SupplicantStatusCode::SUCCESS, ""};
-}
-} // namespace implementation
-} // namespace V1_0
-} // namespace wifi
-} // namespace supplicant
-} // namespace hardware
-} // namespace android
diff --git a/wpa_supplicant/hidl/1.0/supplicant.h b/wpa_supplicant/hidl/1.0/supplicant.h
deleted file mode 100644
index 04d1ae1..0000000
--- a/wpa_supplicant/hidl/1.0/supplicant.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef WPA_SUPPLICANT_HIDL_SUPPLICANT_H
-#define WPA_SUPPLICANT_HIDL_SUPPLICANT_H
-
-#include <android-base/macros.h>
-
-#include <android/hardware/wifi/supplicant/1.0/ISupplicant.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantCallback.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantIface.h>
-
-extern "C" {
-#include "utils/common.h"
-#include "utils/includes.h"
-#include "utils/wpa_debug.h"
-#include "wpa_supplicant_i.h"
-}
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_0 {
-namespace implementation {
-/**
- * Implementation of the supplicant hidl object. This hidl
- * object is used core for global control operations on
- * wpa_supplicant.
- */
-class Supplicant : public android::hardware::wifi::supplicant::V1_0::ISupplicant
-{
-public:
- Supplicant(struct wpa_global* global);
- ~Supplicant() override = default;
- bool isValid();
- bool ensureConfigFileExists();
-
- // Hidl methods exposed.
- Return<void> getInterface(
- const IfaceInfo& iface_info, getInterface_cb _hidl_cb) override;
- Return<void> listInterfaces(listInterfaces_cb _hidl_cb) override;
- Return<void> registerCallback(
- const sp<ISupplicantCallback>& callback,
- registerCallback_cb _hidl_cb) override;
- Return<void> setDebugParams(
- ISupplicant::DebugLevel level, bool show_timestamp, bool show_keys,
- setDebugParams_cb _hidl_cb) override;
- Return<ISupplicant::DebugLevel> getDebugLevel() override;
- Return<bool> isDebugShowTimestampEnabled() override;
- Return<bool> isDebugShowKeysEnabled() override;
- Return<void> setConcurrencyPriority(
- IfaceType type, setConcurrencyPriority_cb _hidl_cb) override;
-
-private:
- // Corresponding worker functions for the HIDL methods.
- std::pair<SupplicantStatus, sp<ISupplicantIface>> getInterfaceInternal(
- const IfaceInfo& iface_info);
- std::pair<SupplicantStatus, std::vector<ISupplicant::IfaceInfo>>
- listInterfacesInternal();
- SupplicantStatus registerCallbackInternal(
- const sp<ISupplicantCallback>& callback);
- SupplicantStatus setDebugParamsInternal(
- ISupplicant::DebugLevel level, bool show_timestamp, bool show_keys);
- SupplicantStatus setConcurrencyPriorityInternal(IfaceType type);
-
- // Raw pointer to the global structure maintained by the core.
- struct wpa_global* wpa_global_;
- // Driver name to be used for creating interfaces.
- static const char kDriverName[];
- // wpa_supplicant.conf file location on the device.
- static const char kConfigFilePath[];
-
- DISALLOW_COPY_AND_ASSIGN(Supplicant);
-};
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace wifi
-} // namespace supplicant
-} // namespace hardware
-} // namespace android
-
-#endif // WPA_SUPPLICANT_HIDL_SUPPLICANT_H
diff --git a/wpa_supplicant/hidl/1.1/hidl.h b/wpa_supplicant/hidl/1.1/hidl.h
deleted file mode 100644
index 1dfadc6..0000000
--- a/wpa_supplicant/hidl/1.1/hidl.h
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef WPA_SUPPLICANT_HIDL_HIDL_H
-#define WPA_SUPPLICANT_HIDL_HIDL_H
-
-#ifdef _cplusplus
-extern "C" {
-#endif // _cplusplus
-
-/**
- * This is the hidl RPC interface entry point to the wpa_supplicant core.
- * This initializes the hidl driver & HidlManager instance and then forwards
- * all the notifcations from the supplicant core to the HidlManager.
- */
-struct wpas_hidl_priv;
-struct wpa_global;
-
-struct wpas_hidl_priv *wpas_hidl_init(struct wpa_global *global);
-void wpas_hidl_deinit(struct wpas_hidl_priv *priv);
-
-#ifdef CONFIG_CTRL_IFACE_HIDL
-int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s);
-int wpas_hidl_unregister_interface(struct wpa_supplicant *wpa_s);
-int wpas_hidl_register_network(
- struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
-int wpas_hidl_unregister_network(
- struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
-int wpas_hidl_notify_state_changed(struct wpa_supplicant *wpa_s);
-int wpas_hidl_notify_network_request(
- struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
- enum wpa_ctrl_req_type rtype, const char *default_txt);
-void wpas_hidl_notify_anqp_query_done(
- struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
- const struct wpa_bss_anqp *anqp);
-void wpas_hidl_notify_hs20_icon_query_done(
- struct wpa_supplicant *wpa_s, const u8 *bssid, const char *file_name,
- const u8 *image, u32 image_length);
-void wpas_hidl_notify_hs20_rx_subscription_remediation(
- struct wpa_supplicant *wpa_s, const char *url, u8 osu_method);
-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_disconnect_reason(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_bssid_changed(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_wps_event_fail(
- struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
- uint16_t error_indication);
-void wpas_hidl_notify_wps_event_success(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_wps_event_pbc_overlap(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_p2p_device_found(
- struct wpa_supplicant *wpa_s, const u8 *addr,
- const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
- u8 peer_wfd_device_info_len);
-void wpas_hidl_notify_p2p_device_lost(
- struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr);
-void wpas_hidl_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s);
-void wpas_hidl_notify_p2p_go_neg_req(
- struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
- u8 go_intent);
-void wpas_hidl_notify_p2p_go_neg_completed(
- struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res);
-void wpas_hidl_notify_p2p_group_formation_failure(
- struct wpa_supplicant *wpa_s, const char *reason);
-void wpas_hidl_notify_p2p_group_started(
- struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, int persistent,
- int client);
-void wpas_hidl_notify_p2p_group_removed(
- struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid,
- const char *role);
-void wpas_hidl_notify_p2p_invitation_received(
- struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
- const u8 *bssid, int id, int op_freq);
-void wpas_hidl_notify_p2p_invitation_result(
- struct wpa_supplicant *wpa_s, int status, const u8 *bssid);
-void wpas_hidl_notify_p2p_provision_discovery(
- struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
- enum p2p_prov_disc_status status, u16 config_methods,
- unsigned int generated_pin);
-void wpas_hidl_notify_p2p_sd_response(
- struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
- const u8 *tlvs, size_t tlvs_len);
-void wpas_hidl_notify_ap_sta_authorized(
- struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr);
-void wpas_hidl_notify_ap_sta_deauthorized(
- struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr);
-void wpas_hidl_notify_eap_error(struct wpa_supplicant *wpa_s, int error_code);
-#else // CONFIG_CTRL_IFACE_HIDL
-static inline int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s)
-{
- return 0;
-}
-static inline int wpas_hidl_unregister_interface(struct wpa_supplicant *wpa_s)
-{
- return 0;
-}
-static inline int wpas_hidl_register_network(
- struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
-{
- return 0;
-}
-static inline int wpas_hidl_unregister_network(
- struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
-{
- return 0;
-}
-static inline int wpas_hidl_notify_state_changed(struct wpa_supplicant *wpa_s)
-{
- return 0;
-}
-static inline int wpas_hidl_notify_network_request(
- struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
- enum wpa_ctrl_req_type rtype, const char *default_txt)
-{
- return 0;
-}
-static void wpas_hidl_notify_anqp_query_done(
- struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
- const struct wpa_bss_anqp *anqp)
-{
-}
-static void wpas_hidl_notify_hs20_icon_query_done(
- struct wpa_supplicant *wpa_s, const u8 *bssid, const char *file_name,
- const u8 *image, u32 image_length)
-{
-}
-static void wpas_hidl_notify_hs20_rx_subscription_remediation(
- struct wpa_supplicant *wpa_s, const char *url, u8 osu_method)
-{
-}
-static void wpas_hidl_notify_hs20_rx_deauth_imminent_notice(
- struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, 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) {}
-static void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_wps_event_fail(
- struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
- uint16_t error_indication)
-{
-}
-static void wpas_hidl_notify_bssid_changed(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_wps_event_success(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_wps_event_pbc_overlap(struct wpa_supplicant *wpa_s)
-{
-}
-static void wpas_hidl_notify_p2p_device_found(
- struct wpa_supplicant *wpa_s, const u8 *addr,
- const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
- u8 peer_wfd_device_info_len);
-{
-}
-static void wpas_hidl_notify_p2p_device_lost(
- struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr)
-{
-}
-static void wpas_hidl_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s) {}
-static void wpas_hidl_notify_p2p_go_neg_req(
- struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
- u8 go_intent)
-{
-}
-static void wpas_hidl_notify_p2p_go_neg_completed(
- struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res)
-{
-}
-static void wpas_hidl_notify_p2p_group_formation_failure(
- struct wpa_supplicant *wpa_s, const char *reason)
-{
-}
-static void wpas_hidl_notify_p2p_group_started(
- struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, int persistent,
- int client)
-{
-}
-static void wpas_hidl_notify_p2p_group_removed(
- struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, const char *role)
-{
-}
-static void wpas_hidl_notify_p2p_invitation_received(
- struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
- const u8 *bssid, int id, int op_freq)
-{
-}
-static void wpas_hidl_notify_p2p_invitation_result(
- struct wpa_supplicant *wpa_s, int status, const u8 *bssid)
-{
-}
-static void wpas_hidl_notify_p2p_provision_discovery(
- struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
- enum p2p_prov_disc_status status, u16 config_methods,
- unsigned int generated_pin)
-{
-}
-static void wpas_hidl_notify_p2p_sd_response(
- struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
- const u8 *tlvs, size_t tlvs_len)
-{
-}
-static void wpas_hidl_notify_ap_sta_authorized(
- struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
-{
-}
-static void wpas_hidl_notify_ap_sta_deauthorized(
- struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
-{
-}
-static void wpas_hidl_notify_eap_error(
- struct wpa_supplicant *wpa_s, int error_code)
-{
-}
-#endif // CONFIG_CTRL_IFACE_HIDL
-
-#ifdef _cplusplus
-}
-#endif // _cplusplus
-
-#endif // WPA_SUPPLICANT_HIDL_HIDL_H
diff --git a/wpa_supplicant/hidl/1.1/hidl_constants.h b/wpa_supplicant/hidl/1.1/hidl_constants.h
deleted file mode 100644
index 988a590..0000000
--- a/wpa_supplicant/hidl/1.1/hidl_constants.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef WPA_SUPPLICANT_HIDL_HIDL_CONSTANTS_H
-#define WPA_SUPPLICANT_HIDL_HIDL_CONSTANTS_H
-
-namespace wpa_supplicant_hidl {
-namespace hidl_constants {
-
-extern const char kServiceName[];
-
-} /* namespace hidl_constants */
-} /* namespace wpa_supplicant_hidl */
-
-#endif /* WPA_SUPPLICANT_HIDL_HIDL_CONSTANTS_H */
diff --git a/wpa_supplicant/hidl/1.1/hidl_i.h b/wpa_supplicant/hidl/1.1/hidl_i.h
deleted file mode 100644
index c7a0142..0000000
--- a/wpa_supplicant/hidl/1.1/hidl_i.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef HIDL_I_H
-#define HIDL_I_H
-
-#ifdef _cplusplus
-extern "C" {
-#endif // _cplusplus
-
-struct wpas_hidl_priv
-{
- int hidl_fd;
- struct wpa_global *global;
- void *hidl_manager;
-};
-
-#ifdef _cplusplus
-}
-#endif // _cplusplus
-
-#endif // HIDL_I_H
diff --git a/wpa_supplicant/hidl/1.1/iface_config_utils.cpp b/wpa_supplicant/hidl/1.1/iface_config_utils.cpp
deleted file mode 100644
index 7fe6d19..0000000
--- a/wpa_supplicant/hidl/1.1/iface_config_utils.cpp
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (struct wpa_supplicant* wpa_s, c) 2004-2016, Jouni Malinen
- * <j@w1.fi>
- * Copyright (struct wpa_supplicant* wpa_s, c) 2004-2016, Roshan Pius
- * <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "hidl_manager.h"
-#include "hidl_return_util.h"
-#include "iface_config_utils.h"
-
-namespace {
-constexpr uint32_t kMaxWpsDeviceNameSize = WPS_DEV_NAME_MAX_LEN;
-constexpr uint32_t kMaxWpsManufacturerSize = WPS_MANUFACTURER_MAX_LEN;
-constexpr uint32_t kMaxWpsModelNameSize = WPS_MODEL_NAME_MAX_LEN;
-constexpr uint32_t kMaxWpsModelNumberSize = WPS_MODEL_NUMBER_MAX_LEN;
-constexpr uint32_t kMaxWpsSerialNumberSize = WPS_SERIAL_NUMBER_MAX_LEN;
-
-void processConfigUpdate(struct wpa_supplicant* wpa_s, uint32_t changed_param)
-{
- wpa_s->conf->changed_parameters |= changed_param;
- wpa_supplicant_update_config(wpa_s);
-}
-
-// Free any existing pointer stored in |dst| and store the provided string value
-// there.
-int freeAndSetStringConfigParam(
- struct wpa_supplicant* wpa_s, const std::string& value, uint32_t max_size,
- uint32_t changed_param, char** dst)
-{
- if (value.size() > max_size) {
- return -1;
- }
- WPA_ASSERT(dst);
- os_free(static_cast<void*>(*dst));
- *dst = os_strdup(value.c_str());
- processConfigUpdate(wpa_s, changed_param);
- return 0;
-}
-
-std::string convertWpsConfigMethodsMaskToString(uint16_t config_methods)
-{
- using WpsConfigMethods =
- android::hardware::wifi::supplicant::V1_0::WpsConfigMethods;
- std::string config_methods_str;
- for (const auto& flag_and_name :
- {std::make_pair(WpsConfigMethods::USBA, "usba"),
- {WpsConfigMethods::ETHERNET, "ethernet"},
- {WpsConfigMethods::LABEL, "label"},
- {WpsConfigMethods::DISPLAY, "display"},
- {WpsConfigMethods::INT_NFC_TOKEN, "int_nfc_token"},
- {WpsConfigMethods::EXT_NFC_TOKEN, "ext_nfc_token"},
- {WpsConfigMethods::NFC_INTERFACE, "nfc_interface"},
- {WpsConfigMethods::PUSHBUTTON, "push_button"},
- {WpsConfigMethods::KEYPAD, "keypad"},
- {WpsConfigMethods::VIRT_PUSHBUTTON, "virtual_push_button"},
- {WpsConfigMethods::PHY_PUSHBUTTON, "physical_push_button"},
- {WpsConfigMethods::P2PS, "p2ps"},
- {WpsConfigMethods::VIRT_DISPLAY, "virtual_display"},
- {WpsConfigMethods::PHY_DISPLAY, "physical_display"}}) {
- const auto flag =
- static_cast<std::underlying_type<WpsConfigMethods>::type>(
- flag_and_name.first);
- if ((config_methods & flag) == flag) {
- config_methods_str += flag_and_name.second;
- config_methods_str += " ";
- }
- }
- return config_methods_str;
-}
-} // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_1 {
-namespace implementation {
-namespace iface_config_utils {
-SupplicantStatus setWpsDeviceName(
- struct wpa_supplicant* wpa_s, const std::string& name)
-{
- WPA_ASSERT(wpa_s);
- if (freeAndSetStringConfigParam(
- wpa_s, name, kMaxWpsDeviceNameSize, CFG_CHANGED_DEVICE_NAME,
- &wpa_s->conf->device_name)) {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus setWpsDeviceType(
- struct wpa_supplicant* wpa_s, const std::array<uint8_t, 8>& type)
-{
- WPA_ASSERT(wpa_s);
- WPA_ASSERT(type.size() == WPS_DEV_TYPE_LEN);
- os_memcpy(wpa_s->conf->device_type, type.data(), WPS_DEV_TYPE_LEN);
- processConfigUpdate(wpa_s, CFG_CHANGED_DEVICE_TYPE);
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus setWpsManufacturer(
- struct wpa_supplicant* wpa_s, const std::string& manufacturer)
-{
- WPA_ASSERT(wpa_s);
- if (freeAndSetStringConfigParam(
- wpa_s, manufacturer, kMaxWpsManufacturerSize,
- CFG_CHANGED_WPS_STRING, &wpa_s->conf->manufacturer)) {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus setWpsModelName(
- struct wpa_supplicant* wpa_s, const std::string& model_name)
-{
- WPA_ASSERT(wpa_s);
- if (freeAndSetStringConfigParam(
- wpa_s, model_name, kMaxWpsModelNameSize, CFG_CHANGED_WPS_STRING,
- &wpa_s->conf->model_name)) {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus setWpsModelNumber(
- struct wpa_supplicant* wpa_s, const std::string& model_number)
-{
- WPA_ASSERT(wpa_s);
- if (freeAndSetStringConfigParam(
- wpa_s, model_number, kMaxWpsModelNumberSize,
- CFG_CHANGED_WPS_STRING, &wpa_s->conf->model_number)) {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus setWpsSerialNumber(
- struct wpa_supplicant* wpa_s, const std::string& serial_number)
-{
- WPA_ASSERT(wpa_s);
- if (freeAndSetStringConfigParam(
- wpa_s, serial_number, kMaxWpsSerialNumberSize,
- CFG_CHANGED_WPS_STRING, &wpa_s->conf->serial_number)) {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus setWpsConfigMethods(
- struct wpa_supplicant* wpa_s, uint16_t config_methods)
-{
- WPA_ASSERT(wpa_s);
- if (freeAndSetStringConfigParam(
- wpa_s, convertWpsConfigMethodsMaskToString(config_methods),
- UINT32_MAX, CFG_CHANGED_CONFIG_METHODS,
- &wpa_s->conf->config_methods)) {
- return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus setExternalSim(
- struct wpa_supplicant* wpa_s, bool useExternalSim)
-{
- WPA_ASSERT(wpa_s);
- wpa_s->conf->external_sim = useExternalSim ? 1 : 0;
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-} // namespace iface_config_utils
-} // namespace implementation
-} // namespace V1_1
-} // namespace wifi
-} // namespace supplicant
-} // namespace hardware
-} // namespace android
diff --git a/wpa_supplicant/hidl/1.1/iface_config_utils.h b/wpa_supplicant/hidl/1.1/iface_config_utils.h
deleted file mode 100644
index 39f5548..0000000
--- a/wpa_supplicant/hidl/1.1/iface_config_utils.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (struct wpa_supplicant* wpa_s, c) 2004-2016, Jouni Malinen
- * <j@w1.fi>
- * Copyright (struct wpa_supplicant* wpa_s, c) 2004-2016, Roshan Pius
- * <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef WPA_SUPPLICANT_HIDL_IFACE_CONFIG_UTILS_H
-#define WPA_SUPPLICANT_HIDL_IFACE_CONFIG_UTILS_H
-
-#include <android-base/macros.h>
-
-extern "C" {
-#include "utils/common.h"
-#include "utils/includes.h"
-#include "wpa_supplicant_i.h"
-#include "config.h"
-}
-
-/**
- * Utility functions to set various config parameters of an iface via HIDL
- * methods.
- */
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_1 {
-namespace implementation {
-namespace iface_config_utils {
-SupplicantStatus setWpsDeviceName(
- struct wpa_supplicant* wpa_s, const std::string& name);
-SupplicantStatus setWpsDeviceType(
- struct wpa_supplicant* wpa_s, const std::array<uint8_t, 8>& type);
-SupplicantStatus setWpsManufacturer(
- struct wpa_supplicant* wpa_s, const std::string& manufacturer);
-SupplicantStatus setWpsModelName(
- struct wpa_supplicant* wpa_s, const std::string& model_name);
-SupplicantStatus setWpsModelNumber(
- struct wpa_supplicant* wpa_s, const std::string& model_number);
-SupplicantStatus setWpsSerialNumber(
- struct wpa_supplicant* wpa_s, const std::string& serial_number);
-SupplicantStatus setWpsConfigMethods(
- struct wpa_supplicant* wpa_s, uint16_t config_methods);
-SupplicantStatus setExternalSim(
- struct wpa_supplicant* wpa_s, bool useExternalSim);
-} // namespace iface_config_utils
-} // namespace implementation
-} // namespace V1_1
-} // namespace wifi
-} // namespace supplicant
-} // namespace hardware
-} // namespace android
-
-#endif // WPA_SUPPLICANT_HIDL_IFACE_CONFIG_UTILS_H
diff --git a/wpa_supplicant/hidl/1.1/p2p_iface.cpp b/wpa_supplicant/hidl/1.1/p2p_iface.cpp
deleted file mode 100644
index 5de383d..0000000
--- a/wpa_supplicant/hidl/1.1/p2p_iface.cpp
+++ /dev/null
@@ -1,1284 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- * Copyright (C) 2017 Sony Mobile Communications Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "hidl_manager.h"
-#include "hidl_return_util.h"
-#include "iface_config_utils.h"
-#include "misc_utils.h"
-#include "p2p_iface.h"
-
-extern "C" {
-#include "ap.h"
-#include "wps_supplicant.h"
-#include "wifi_display.h"
-}
-
-namespace {
-const char kConfigMethodStrPbc[] = "pbc";
-const char kConfigMethodStrDisplay[] = "display";
-const char kConfigMethodStrKeypad[] = "keypad";
-constexpr char kSetMiracastMode[] = "MIRACAST ";
-constexpr uint8_t kWfdDeviceInfoSubelemId = 0;
-constexpr char kWfdDeviceInfoSubelemLenHexStr[] = "0006";
-
-using android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface;
-uint8_t convertHidlMiracastModeToInternal(
- ISupplicantP2pIface::MiracastMode mode)
-{
- switch (mode) {
- case ISupplicantP2pIface::MiracastMode::DISABLED:
- return 0;
- case ISupplicantP2pIface::MiracastMode::SOURCE:
- return 1;
- case ISupplicantP2pIface::MiracastMode::SINK:
- return 2;
- };
- WPA_ASSERT(false);
-}
-} // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_1 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-P2pIface::P2pIface(struct wpa_global* wpa_global, const char ifname[])
- : wpa_global_(wpa_global), ifname_(ifname), is_valid_(true)
-{
-}
-
-void P2pIface::invalidate() { is_valid_ = false; }
-bool P2pIface::isValid()
-{
- return (is_valid_ && (retrieveIfacePtr() != nullptr));
-}
-Return<void> P2pIface::getName(getName_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::getNameInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::getType(getType_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::getTypeInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::addNetwork(addNetwork_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::addNetworkInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::removeNetwork(
- SupplicantNetworkId id, removeNetwork_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::removeNetworkInternal, _hidl_cb, id);
-}
-
-Return<void> P2pIface::getNetwork(
- SupplicantNetworkId id, getNetwork_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::getNetworkInternal, _hidl_cb, id);
-}
-
-Return<void> P2pIface::listNetworks(listNetworks_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::listNetworksInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::registerCallback(
- const sp<ISupplicantP2pIfaceCallback>& callback,
- registerCallback_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::registerCallbackInternal, _hidl_cb, callback);
-}
-
-Return<void> P2pIface::getDeviceAddress(getDeviceAddress_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::getDeviceAddressInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::setSsidPostfix(
- const hidl_vec<uint8_t>& postfix, setSsidPostfix_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::setSsidPostfixInternal, _hidl_cb, postfix);
-}
-
-Return<void> P2pIface::setGroupIdle(
- const hidl_string& group_ifname, uint32_t timeout_in_sec,
- setGroupIdle_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::setGroupIdleInternal, _hidl_cb, group_ifname,
- timeout_in_sec);
-}
-
-Return<void> P2pIface::setPowerSave(
- const hidl_string& group_ifname, bool enable, setPowerSave_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::setPowerSaveInternal, _hidl_cb, group_ifname, enable);
-}
-
-Return<void> P2pIface::find(uint32_t timeout_in_sec, find_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::findInternal, _hidl_cb, timeout_in_sec);
-}
-
-Return<void> P2pIface::stopFind(stopFind_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::stopFindInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::flush(flush_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::flushInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::connect(
- const hidl_array<uint8_t, 6>& peer_address,
- ISupplicantP2pIface::WpsProvisionMethod provision_method,
- const hidl_string& pre_selected_pin, bool join_existing_group,
- bool persistent, uint32_t go_intent, connect_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::connectInternal, _hidl_cb, peer_address,
- provision_method, pre_selected_pin, join_existing_group, persistent,
- go_intent);
-}
-
-Return<void> P2pIface::cancelConnect(cancelConnect_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::cancelConnectInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::provisionDiscovery(
- const hidl_array<uint8_t, 6>& peer_address,
- ISupplicantP2pIface::WpsProvisionMethod provision_method,
- provisionDiscovery_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::provisionDiscoveryInternal, _hidl_cb, peer_address,
- provision_method);
-}
-
-Return<void> P2pIface::addGroup(
- bool persistent, SupplicantNetworkId persistent_network_id,
- addGroup_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::addGroupInternal, _hidl_cb, persistent,
- persistent_network_id);
-}
-
-Return<void> P2pIface::removeGroup(
- const hidl_string& group_ifname, removeGroup_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::removeGroupInternal, _hidl_cb, group_ifname);
-}
-
-Return<void> P2pIface::reject(
- const hidl_array<uint8_t, 6>& peer_address, reject_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::rejectInternal, _hidl_cb, peer_address);
-}
-
-Return<void> P2pIface::invite(
- const hidl_string& group_ifname,
- const hidl_array<uint8_t, 6>& go_device_address,
- const hidl_array<uint8_t, 6>& peer_address, invite_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::inviteInternal, _hidl_cb, group_ifname,
- go_device_address, peer_address);
-}
-
-Return<void> P2pIface::reinvoke(
- SupplicantNetworkId persistent_network_id,
- const hidl_array<uint8_t, 6>& peer_address, reinvoke_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::reinvokeInternal, _hidl_cb, persistent_network_id,
- peer_address);
-}
-
-Return<void> P2pIface::configureExtListen(
- uint32_t period_in_millis, uint32_t interval_in_millis,
- configureExtListen_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::configureExtListenInternal, _hidl_cb, period_in_millis,
- interval_in_millis);
-}
-
-Return<void> P2pIface::setListenChannel(
- uint32_t channel, uint32_t operating_class, setListenChannel_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::setListenChannelInternal, _hidl_cb, channel,
- operating_class);
-}
-
-Return<void> P2pIface::setDisallowedFrequencies(
- const hidl_vec<FreqRange>& ranges, setDisallowedFrequencies_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::setDisallowedFrequenciesInternal, _hidl_cb, ranges);
-}
-
-Return<void> P2pIface::getSsid(
- const hidl_array<uint8_t, 6>& peer_address, getSsid_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::getSsidInternal, _hidl_cb, peer_address);
-}
-
-Return<void> P2pIface::getGroupCapability(
- const hidl_array<uint8_t, 6>& peer_address, getGroupCapability_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::getGroupCapabilityInternal, _hidl_cb, peer_address);
-}
-
-Return<void> P2pIface::addBonjourService(
- const hidl_vec<uint8_t>& query, const hidl_vec<uint8_t>& response,
- addBonjourService_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::addBonjourServiceInternal, _hidl_cb, query, response);
-}
-
-Return<void> P2pIface::removeBonjourService(
- const hidl_vec<uint8_t>& query, removeBonjourService_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::removeBonjourServiceInternal, _hidl_cb, query);
-}
-
-Return<void> P2pIface::addUpnpService(
- uint32_t version, const hidl_string& service_name,
- addUpnpService_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::addUpnpServiceInternal, _hidl_cb, version, service_name);
-}
-
-Return<void> P2pIface::removeUpnpService(
- uint32_t version, const hidl_string& service_name,
- removeUpnpService_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::removeUpnpServiceInternal, _hidl_cb, version,
- service_name);
-}
-
-Return<void> P2pIface::flushServices(flushServices_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::flushServicesInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::requestServiceDiscovery(
- const hidl_array<uint8_t, 6>& peer_address, const hidl_vec<uint8_t>& query,
- requestServiceDiscovery_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::requestServiceDiscoveryInternal, _hidl_cb, peer_address,
- query);
-}
-
-Return<void> P2pIface::cancelServiceDiscovery(
- uint64_t identifier, cancelServiceDiscovery_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::cancelServiceDiscoveryInternal, _hidl_cb, identifier);
-}
-
-Return<void> P2pIface::setMiracastMode(
- ISupplicantP2pIface::MiracastMode mode, setMiracastMode_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::setMiracastModeInternal, _hidl_cb, mode);
-}
-
-Return<void> P2pIface::startWpsPbc(
- const hidl_string& group_ifname, const hidl_array<uint8_t, 6>& bssid,
- startWpsPbc_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::startWpsPbcInternal, _hidl_cb, group_ifname, bssid);
-}
-
-Return<void> P2pIface::startWpsPinKeypad(
- const hidl_string& group_ifname, const hidl_string& pin,
- startWpsPinKeypad_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::startWpsPinKeypadInternal, _hidl_cb, group_ifname, pin);
-}
-
-Return<void> P2pIface::startWpsPinDisplay(
- const hidl_string& group_ifname, const hidl_array<uint8_t, 6>& bssid,
- startWpsPinDisplay_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::startWpsPinDisplayInternal, _hidl_cb, group_ifname,
- bssid);
-}
-
-Return<void> P2pIface::cancelWps(
- const hidl_string& group_ifname, cancelWps_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::cancelWpsInternal, _hidl_cb, group_ifname);
-}
-
-Return<void> P2pIface::setWpsDeviceName(
- const hidl_string& name, setWpsDeviceName_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::setWpsDeviceNameInternal, _hidl_cb, name);
-}
-
-Return<void> P2pIface::setWpsDeviceType(
- const hidl_array<uint8_t, 8>& type, setWpsDeviceType_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::setWpsDeviceTypeInternal, _hidl_cb, type);
-}
-
-Return<void> P2pIface::setWpsManufacturer(
- const hidl_string& manufacturer, setWpsManufacturer_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::setWpsManufacturerInternal, _hidl_cb, manufacturer);
-}
-
-Return<void> P2pIface::setWpsModelName(
- const hidl_string& model_name, setWpsModelName_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::setWpsModelNameInternal, _hidl_cb, model_name);
-}
-
-Return<void> P2pIface::setWpsModelNumber(
- const hidl_string& model_number, setWpsModelNumber_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::setWpsModelNumberInternal, _hidl_cb, model_number);
-}
-
-Return<void> P2pIface::setWpsSerialNumber(
- const hidl_string& serial_number, setWpsSerialNumber_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::setWpsSerialNumberInternal, _hidl_cb, serial_number);
-}
-
-Return<void> P2pIface::setWpsConfigMethods(
- uint16_t config_methods, setWpsConfigMethods_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::setWpsConfigMethodsInternal, _hidl_cb, config_methods);
-}
-
-Return<void> P2pIface::enableWfd(bool enable, enableWfd_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::enableWfdInternal, _hidl_cb, enable);
-}
-
-Return<void> P2pIface::setWfdDeviceInfo(
- const hidl_array<uint8_t, 6>& info, setWfdDeviceInfo_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::setWfdDeviceInfoInternal, _hidl_cb, info);
-}
-
-Return<void> P2pIface::createNfcHandoverRequestMessage(
- createNfcHandoverRequestMessage_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::createNfcHandoverRequestMessageInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::createNfcHandoverSelectMessage(
- createNfcHandoverSelectMessage_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::createNfcHandoverSelectMessageInternal, _hidl_cb);
-}
-
-Return<void> P2pIface::reportNfcHandoverResponse(
- const hidl_vec<uint8_t>& request, reportNfcHandoverResponse_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::reportNfcHandoverResponseInternal, _hidl_cb, request);
-}
-
-Return<void> P2pIface::reportNfcHandoverInitiation(
- const hidl_vec<uint8_t>& select, reportNfcHandoverInitiation_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::reportNfcHandoverInitiationInternal, _hidl_cb, select);
-}
-
-Return<void> P2pIface::saveConfig(saveConfig_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::saveConfigInternal, _hidl_cb);
-}
-
-std::pair<SupplicantStatus, std::string> P2pIface::getNameInternal()
-{
- return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
-}
-
-std::pair<SupplicantStatus, IfaceType> P2pIface::getTypeInternal()
-{
- return {{SupplicantStatusCode::SUCCESS, ""}, IfaceType::P2P};
-}
-
-std::pair<SupplicantStatus, sp<ISupplicantP2pNetwork>>
-P2pIface::addNetworkInternal()
-{
- android::sp<ISupplicantP2pNetwork> network;
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- struct wpa_ssid* ssid = wpa_supplicant_add_network(wpa_s);
- if (!ssid) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
- }
- HidlManager* hidl_manager = HidlManager::getInstance();
- if (!hidl_manager ||
- hidl_manager->getP2pNetworkHidlObjectByIfnameAndNetworkId(
- wpa_s->ifname, ssid->id, &network)) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
- }
- return {{SupplicantStatusCode::SUCCESS, ""}, network};
-}
-
-SupplicantStatus P2pIface::removeNetworkInternal(SupplicantNetworkId id)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- int result = wpa_supplicant_remove_network(wpa_s, id);
- if (result == -1) {
- return {SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN, ""};
- }
- if (result != 0) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, sp<ISupplicantP2pNetwork>>
-P2pIface::getNetworkInternal(SupplicantNetworkId id)
-{
- android::sp<ISupplicantP2pNetwork> network;
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- struct wpa_ssid* ssid = wpa_config_get_network(wpa_s->conf, id);
- if (!ssid) {
- return {{SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN, ""},
- network};
- }
- HidlManager* hidl_manager = HidlManager::getInstance();
- if (!hidl_manager ||
- hidl_manager->getP2pNetworkHidlObjectByIfnameAndNetworkId(
- wpa_s->ifname, ssid->id, &network)) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
- }
- return {{SupplicantStatusCode::SUCCESS, ""}, network};
-}
-
-std::pair<SupplicantStatus, std::vector<SupplicantNetworkId>>
-P2pIface::listNetworksInternal()
-{
- std::vector<SupplicantNetworkId> network_ids;
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- for (struct wpa_ssid* wpa_ssid = wpa_s->conf->ssid; wpa_ssid;
- wpa_ssid = wpa_ssid->next) {
- network_ids.emplace_back(wpa_ssid->id);
- }
- return {{SupplicantStatusCode::SUCCESS, ""}, std::move(network_ids)};
-}
-
-SupplicantStatus P2pIface::registerCallbackInternal(
- const sp<ISupplicantP2pIfaceCallback>& callback)
-{
- HidlManager* hidl_manager = HidlManager::getInstance();
- if (!hidl_manager ||
- hidl_manager->addP2pIfaceCallbackHidlObject(ifname_, callback)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, std::array<uint8_t, 6>>
-P2pIface::getDeviceAddressInternal()
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- std::array<uint8_t, 6> addr;
- static_assert(ETH_ALEN == addr.size(), "Size mismatch");
- os_memcpy(addr.data(), wpa_s->global->p2p_dev_addr, ETH_ALEN);
- return {{SupplicantStatusCode::SUCCESS, ""}, addr};
-}
-
-SupplicantStatus P2pIface::setSsidPostfixInternal(
- const std::vector<uint8_t>& postfix)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- if (p2p_set_ssid_postfix(
- wpa_s->global->p2p, postfix.data(), postfix.size())) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::setGroupIdleInternal(
- const std::string& group_ifname, uint32_t timeout_in_sec)
-{
- struct wpa_supplicant* wpa_group_s =
- retrieveGroupIfacePtr(group_ifname);
- if (!wpa_group_s) {
- return {SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""};
- }
- wpa_group_s->conf->p2p_group_idle = timeout_in_sec;
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::setPowerSaveInternal(
- const std::string& group_ifname, bool enable)
-{
- struct wpa_supplicant* wpa_group_s =
- retrieveGroupIfacePtr(group_ifname);
- if (!wpa_group_s) {
- return {SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""};
- }
- if (wpa_drv_set_p2p_powersave(wpa_group_s, enable, -1, -1)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::findInternal(uint32_t timeout_in_sec)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
- return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
- }
- uint32_t search_delay = wpas_p2p_search_delay(wpa_s);
- if (wpas_p2p_find(
- wpa_s, timeout_in_sec, P2P_FIND_START_WITH_FULL, 0, nullptr,
- nullptr, search_delay, 0, nullptr, 0)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::stopFindInternal()
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
- return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
- }
- wpas_p2p_stop_find(wpa_s);
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::flushInternal()
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
- wpa_s->force_long_sd = 0;
- wpas_p2p_stop_find(wpa_s);
- wpa_s->parent->p2ps_method_config_any = 0;
- if (wpa_s->global->p2p)
- p2p_flush(wpa_s->global->p2p);
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-// This method only implements support for subset (needed by Android framework)
-// of parameters that can be specified for connect.
-std::pair<SupplicantStatus, std::string> P2pIface::connectInternal(
- const std::array<uint8_t, 6>& peer_address,
- ISupplicantP2pIface::WpsProvisionMethod provision_method,
- const std::string& pre_selected_pin, bool join_existing_group,
- bool persistent, uint32_t go_intent)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- if (go_intent > 15) {
- return {{SupplicantStatusCode::FAILURE_ARGS_INVALID, ""}, {}};
- }
- int go_intent_signed = join_existing_group ? -1 : go_intent;
- p2p_wps_method wps_method = {};
- switch (provision_method) {
- case WpsProvisionMethod::PBC:
- wps_method = WPS_PBC;
- break;
- case WpsProvisionMethod::DISPLAY:
- wps_method = WPS_PIN_DISPLAY;
- break;
- case WpsProvisionMethod::KEYPAD:
- wps_method = WPS_PIN_KEYPAD;
- break;
- }
- int vht = wpa_s->conf->p2p_go_vht;
- int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
- const char* pin = pre_selected_pin.length() > 0 ? pre_selected_pin.data() : nullptr;
- int new_pin = wpas_p2p_connect(
- wpa_s, peer_address.data(), pin, wps_method,
- persistent, false, join_existing_group, false, go_intent_signed, 0, 0, -1,
- false, ht40, vht, VHT_CHANWIDTH_USE_HT, nullptr, 0);
- if (new_pin < 0) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- std::string pin_ret;
- if (provision_method == WpsProvisionMethod::DISPLAY &&
- pre_selected_pin.empty()) {
- pin_ret = misc_utils::convertWpsPinToString(new_pin);
- }
- return {{SupplicantStatusCode::SUCCESS, ""}, pin_ret};
-}
-
-SupplicantStatus P2pIface::cancelConnectInternal()
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- if (wpas_p2p_cancel(wpa_s)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::provisionDiscoveryInternal(
- const std::array<uint8_t, 6>& peer_address,
- ISupplicantP2pIface::WpsProvisionMethod provision_method)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- p2ps_provision* prov_param;
- const char* config_method_str = nullptr;
- switch (provision_method) {
- case WpsProvisionMethod::PBC:
- config_method_str = kConfigMethodStrPbc;
- break;
- case WpsProvisionMethod::DISPLAY:
- config_method_str = kConfigMethodStrDisplay;
- break;
- case WpsProvisionMethod::KEYPAD:
- config_method_str = kConfigMethodStrKeypad;
- break;
- }
- if (wpas_p2p_prov_disc(
- wpa_s, peer_address.data(), config_method_str,
- WPAS_P2P_PD_FOR_GO_NEG, nullptr)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::addGroupInternal(
- bool persistent, SupplicantNetworkId persistent_network_id)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- int vht = wpa_s->conf->p2p_go_vht;
- int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
- struct wpa_ssid* ssid =
- wpa_config_get_network(wpa_s->conf, persistent_network_id);
- if (ssid == NULL) {
- if (wpas_p2p_group_add(
- wpa_s, persistent, 0, 0, ht40, vht,
- VHT_CHANWIDTH_USE_HT)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- } else {
- return {SupplicantStatusCode::SUCCESS, ""};
- }
- } else if (ssid->disabled == 2) {
- if (wpas_p2p_group_add_persistent(
- wpa_s, ssid, 0, 0, 0, 0, ht40, vht,
- VHT_CHANWIDTH_USE_HT, NULL, 0, 0)) {
- return {SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN,
- ""};
- } else {
- return {SupplicantStatusCode::SUCCESS, ""};
- }
- }
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
-}
-
-SupplicantStatus P2pIface::removeGroupInternal(const std::string& group_ifname)
-{
- struct wpa_supplicant* wpa_group_s =
- retrieveGroupIfacePtr(group_ifname);
- if (!wpa_group_s) {
- return {SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""};
- }
- if (wpas_p2p_group_remove(wpa_group_s, group_ifname.c_str())) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::rejectInternal(
- const std::array<uint8_t, 6>& peer_address)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) {
- return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
- }
- if (wpas_p2p_reject(wpa_s, peer_address.data())) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::inviteInternal(
- const std::string& group_ifname,
- const std::array<uint8_t, 6>& go_device_address,
- const std::array<uint8_t, 6>& peer_address)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- if (wpas_p2p_invite_group(
- wpa_s, group_ifname.c_str(), peer_address.data(),
- go_device_address.data())) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::reinvokeInternal(
- SupplicantNetworkId persistent_network_id,
- const std::array<uint8_t, 6>& peer_address)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- int vht = wpa_s->conf->p2p_go_vht;
- int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
- struct wpa_ssid* ssid =
- wpa_config_get_network(wpa_s->conf, persistent_network_id);
- if (ssid == NULL || ssid->disabled != 2) {
- return {SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN, ""};
- }
- if (wpas_p2p_invite(
- wpa_s, peer_address.data(), ssid, NULL, 0, 0, ht40, vht,
- VHT_CHANWIDTH_USE_HT, 0)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::configureExtListenInternal(
- uint32_t period_in_millis, uint32_t interval_in_millis)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- if (wpas_p2p_ext_listen(wpa_s, period_in_millis, interval_in_millis)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::setListenChannelInternal(
- uint32_t channel, uint32_t operating_class)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- if (p2p_set_listen_channel(
- wpa_s->global->p2p, operating_class, channel, 1)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::setDisallowedFrequenciesInternal(
- const std::vector<FreqRange>& ranges)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- using DestT = struct wpa_freq_range_list::wpa_freq_range;
- DestT* freq_ranges = nullptr;
- // Empty ranges is used to enable all frequencies.
- if (ranges.size() != 0) {
- freq_ranges =
- static_cast<DestT*>(os_malloc(sizeof(DestT) * ranges.size()));
- if (!freq_ranges) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- uint32_t i = 0;
- for (const auto& range : ranges) {
- freq_ranges[i].min = range.min;
- freq_ranges[i].max = range.max;
- i++;
- }
- }
-
- os_free(wpa_s->global->p2p_disallow_freq.range);
- wpa_s->global->p2p_disallow_freq.range = freq_ranges;
- wpa_s->global->p2p_disallow_freq.num = ranges.size();
- wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_DISALLOW);
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, std::vector<uint8_t>> P2pIface::getSsidInternal(
- const std::array<uint8_t, 6>& peer_address)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- const struct p2p_peer_info* info =
- p2p_get_peer_info(wpa_s->global->p2p, peer_address.data(), 0);
- if (!info) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- const struct p2p_device* dev =
- reinterpret_cast<const struct p2p_device*>(
- (reinterpret_cast<const uint8_t*>(info)) -
- offsetof(struct p2p_device, info));
- std::vector<uint8_t> ssid;
- if (dev && dev->oper_ssid_len) {
- ssid.assign(
- dev->oper_ssid, dev->oper_ssid + dev->oper_ssid_len);
- }
- return {{SupplicantStatusCode::SUCCESS, ""}, ssid};
-}
-
-std::pair<SupplicantStatus, uint32_t> P2pIface::getGroupCapabilityInternal(
- const std::array<uint8_t, 6>& peer_address)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- const struct p2p_peer_info* info =
- p2p_get_peer_info(wpa_s->global->p2p, peer_address.data(), 0);
- if (!info) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- return {{SupplicantStatusCode::SUCCESS, ""}, info->group_capab};
-}
-
-SupplicantStatus P2pIface::addBonjourServiceInternal(
- const std::vector<uint8_t>& query, const std::vector<uint8_t>& response)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- auto query_buf = misc_utils::convertVectorToWpaBuf(query);
- auto response_buf = misc_utils::convertVectorToWpaBuf(response);
- if (!query_buf || !response_buf) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- if (wpas_p2p_service_add_bonjour(
- wpa_s, query_buf.get(), response_buf.get())) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- // If successful, the wpabuf is referenced internally and hence should
- // not be freed.
- query_buf.release();
- response_buf.release();
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::removeBonjourServiceInternal(
- const std::vector<uint8_t>& query)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- auto query_buf = misc_utils::convertVectorToWpaBuf(query);
- if (!query_buf) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- if (wpas_p2p_service_del_bonjour(wpa_s, query_buf.get())) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::addUpnpServiceInternal(
- uint32_t version, const std::string& service_name)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- if (wpas_p2p_service_add_upnp(wpa_s, version, service_name.c_str())) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::removeUpnpServiceInternal(
- uint32_t version, const std::string& service_name)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- if (wpas_p2p_service_del_upnp(wpa_s, version, service_name.c_str())) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::flushServicesInternal()
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- wpas_p2p_service_flush(wpa_s);
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, uint64_t> P2pIface::requestServiceDiscoveryInternal(
- const std::array<uint8_t, 6>& peer_address,
- const std::vector<uint8_t>& query)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- auto query_buf = misc_utils::convertVectorToWpaBuf(query);
- if (!query_buf) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- const uint8_t* dst_addr = is_zero_ether_addr(peer_address.data())
- ? nullptr
- : peer_address.data();
- uint64_t identifier =
- wpas_p2p_sd_request(wpa_s, dst_addr, query_buf.get());
- if (identifier == 0) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- return {{SupplicantStatusCode::SUCCESS, ""}, identifier};
-}
-
-SupplicantStatus P2pIface::cancelServiceDiscoveryInternal(uint64_t identifier)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- if (wpas_p2p_sd_cancel_request(wpa_s, identifier)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::setMiracastModeInternal(
- ISupplicantP2pIface::MiracastMode mode)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- uint8_t mode_internal = convertHidlMiracastModeToInternal(mode);
- const std::string cmd_str =
- kSetMiracastMode + std::to_string(mode_internal);
- std::vector<char> cmd(
- cmd_str.c_str(), cmd_str.c_str() + cmd_str.size() + 1);
- char driver_cmd_reply_buf[4096] = {};
- if (wpa_drv_driver_cmd(
- wpa_s, cmd.data(), driver_cmd_reply_buf,
- sizeof(driver_cmd_reply_buf))) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::startWpsPbcInternal(
- const std::string& group_ifname, const std::array<uint8_t, 6>& bssid)
-{
- struct wpa_supplicant* wpa_group_s =
- retrieveGroupIfacePtr(group_ifname);
- if (!wpa_group_s) {
- return {SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""};
- }
- const uint8_t* bssid_addr =
- is_zero_ether_addr(bssid.data()) ? nullptr : bssid.data();
-#ifdef CONFIG_AP
- if (wpa_group_s->ap_iface) {
- if (wpa_supplicant_ap_wps_pbc(wpa_group_s, bssid_addr, NULL)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
- }
-#endif /* CONFIG_AP */
- if (wpas_wps_start_pbc(wpa_group_s, bssid_addr, 0)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::startWpsPinKeypadInternal(
- const std::string& group_ifname, const std::string& pin)
-{
- struct wpa_supplicant* wpa_group_s =
- retrieveGroupIfacePtr(group_ifname);
- if (!wpa_group_s) {
- return {SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""};
- }
-#ifdef CONFIG_AP
- if (wpa_group_s->ap_iface) {
- if (wpa_supplicant_ap_wps_pin(
- wpa_group_s, nullptr, pin.c_str(), nullptr, 0, 0) < 0) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
- }
-#endif /* CONFIG_AP */
- if (wpas_wps_start_pin(
- wpa_group_s, nullptr, pin.c_str(), 0, DEV_PW_DEFAULT)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, std::string> P2pIface::startWpsPinDisplayInternal(
- const std::string& group_ifname, const std::array<uint8_t, 6>& bssid)
-{
- struct wpa_supplicant* wpa_group_s =
- retrieveGroupIfacePtr(group_ifname);
- if (!wpa_group_s) {
- return {{SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""}, ""};
- }
- const uint8_t* bssid_addr =
- is_zero_ether_addr(bssid.data()) ? nullptr : bssid.data();
- int pin = wpas_wps_start_pin(
- wpa_group_s, bssid_addr, nullptr, 0, DEV_PW_DEFAULT);
- if (pin < 0) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, ""};
- }
- return {{SupplicantStatusCode::SUCCESS, ""},
- misc_utils::convertWpsPinToString(pin)};
-}
-
-SupplicantStatus P2pIface::cancelWpsInternal(const std::string& group_ifname)
-{
- struct wpa_supplicant* wpa_group_s =
- retrieveGroupIfacePtr(group_ifname);
- if (!wpa_group_s) {
- return {SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""};
- }
- if (wpas_wps_cancel(wpa_group_s)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::setWpsDeviceNameInternal(const std::string& name)
-{
- return iface_config_utils::setWpsDeviceName(retrieveIfacePtr(), name);
-}
-
-SupplicantStatus P2pIface::setWpsDeviceTypeInternal(
- const std::array<uint8_t, 8>& type)
-{
- return iface_config_utils::setWpsDeviceType(retrieveIfacePtr(), type);
-}
-
-SupplicantStatus P2pIface::setWpsManufacturerInternal(
- const std::string& manufacturer)
-{
- return iface_config_utils::setWpsManufacturer(
- retrieveIfacePtr(), manufacturer);
-}
-
-SupplicantStatus P2pIface::setWpsModelNameInternal(
- const std::string& model_name)
-{
- return iface_config_utils::setWpsModelName(
- retrieveIfacePtr(), model_name);
-}
-
-SupplicantStatus P2pIface::setWpsModelNumberInternal(
- const std::string& model_number)
-{
- return iface_config_utils::setWpsModelNumber(
- retrieveIfacePtr(), model_number);
-}
-
-SupplicantStatus P2pIface::setWpsSerialNumberInternal(
- const std::string& serial_number)
-{
- return iface_config_utils::setWpsSerialNumber(
- retrieveIfacePtr(), serial_number);
-}
-
-SupplicantStatus P2pIface::setWpsConfigMethodsInternal(uint16_t config_methods)
-{
- return iface_config_utils::setWpsConfigMethods(
- retrieveIfacePtr(), config_methods);
-}
-
-SupplicantStatus P2pIface::enableWfdInternal(bool enable)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- wifi_display_enable(wpa_s->global, enable);
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::setWfdDeviceInfoInternal(
- const std::array<uint8_t, 6>& info)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- std::vector<char> wfd_device_info_hex(info.size() * 2 + 1);
- wpa_snprintf_hex(
- wfd_device_info_hex.data(), wfd_device_info_hex.size(), info.data(),
- info.size());
- // |wifi_display_subelem_set| expects the first 2 bytes
- // to hold the lenght of the subelement. In this case it's
- // fixed to 6, so prepend that.
- std::string wfd_device_info_set_cmd_str =
- std::to_string(kWfdDeviceInfoSubelemId) + " " +
- kWfdDeviceInfoSubelemLenHexStr + wfd_device_info_hex.data();
- std::vector<char> wfd_device_info_set_cmd(
- wfd_device_info_set_cmd_str.c_str(),
- wfd_device_info_set_cmd_str.c_str() +
- wfd_device_info_set_cmd_str.size() + 1);
- if (wifi_display_subelem_set(
- wpa_s->global, wfd_device_info_set_cmd.data())) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, std::vector<uint8_t>>
-P2pIface::createNfcHandoverRequestMessageInternal()
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- auto buf = misc_utils::createWpaBufUniquePtr(
- wpas_p2p_nfc_handover_req(wpa_s, 1));
- if (!buf) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- return {{SupplicantStatusCode::SUCCESS, ""},
- misc_utils::convertWpaBufToVector(buf.get())};
-}
-
-std::pair<SupplicantStatus, std::vector<uint8_t>>
-P2pIface::createNfcHandoverSelectMessageInternal()
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- auto buf = misc_utils::createWpaBufUniquePtr(
- wpas_p2p_nfc_handover_sel(wpa_s, 1, 0));
- if (!buf) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- return {{SupplicantStatusCode::SUCCESS, ""},
- misc_utils::convertWpaBufToVector(buf.get())};
-}
-
-SupplicantStatus P2pIface::reportNfcHandoverResponseInternal(
- const std::vector<uint8_t>& request)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- auto req = misc_utils::convertVectorToWpaBuf(request);
- auto sel = misc_utils::convertVectorToWpaBuf(std::vector<uint8_t>{0});
- if (!req || !sel) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
-
- if (wpas_p2p_nfc_report_handover(wpa_s, 0, req.get(), sel.get(), 0)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::reportNfcHandoverInitiationInternal(
- const std::vector<uint8_t>& select)
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- auto req = misc_utils::convertVectorToWpaBuf(std::vector<uint8_t>{0});
- auto sel = misc_utils::convertVectorToWpaBuf(select);
- if (!req || !sel) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
-
- if (wpas_p2p_nfc_report_handover(wpa_s, 1, req.get(), sel.get(), 0)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-SupplicantStatus P2pIface::saveConfigInternal()
-{
- struct wpa_supplicant* wpa_s = retrieveIfacePtr();
- if (!wpa_s->conf->update_config) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- if (wpa_config_write(wpa_s->confname, wpa_s->conf)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-/**
- * Retrieve the underlying |wpa_supplicant| struct
- * pointer for this iface.
- * If the underlying iface is removed, then all RPC method calls on this object
- * will return failure.
- */
-wpa_supplicant* P2pIface::retrieveIfacePtr()
-{
- return wpa_supplicant_get_iface(wpa_global_, ifname_.c_str());
-}
-
-/**
- * Retrieve the underlying |wpa_supplicant| struct
- * pointer for this group iface.
- */
-wpa_supplicant* P2pIface::retrieveGroupIfacePtr(const std::string& group_ifname)
-{
- return wpa_supplicant_get_iface(wpa_global_, group_ifname.c_str());
-}
-
-} // namespace implementation
-} // namespace V1_1
-} // namespace wifi
-} // namespace supplicant
-} // namespace hardware
-} // namespace android
diff --git a/wpa_supplicant/hidl/1.1/p2p_iface.h b/wpa_supplicant/hidl/1.1/p2p_iface.h
deleted file mode 100644
index 019e534..0000000
--- a/wpa_supplicant/hidl/1.1/p2p_iface.h
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef WPA_SUPPLICANT_HIDL_P2P_IFACE_H
-#define WPA_SUPPLICANT_HIDL_P2P_IFACE_H
-
-#include <array>
-#include <vector>
-
-#include <android-base/macros.h>
-
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIface.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIfaceCallback.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetwork.h>
-
-extern "C" {
-#include "utils/common.h"
-#include "utils/includes.h"
-#include "p2p/p2p.h"
-#include "p2p/p2p_i.h"
-#include "p2p_supplicant.h"
-#include "p2p_supplicant.h"
-#include "config.h"
-}
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_1 {
-namespace implementation {
-using namespace android::hardware::wifi::supplicant::V1_0;
-
-/**
- * Implementation of P2pIface hidl object. Each unique hidl
- * object is used for control operations on a specific interface
- * controlled by wpa_supplicant.
- */
-class P2pIface : public ISupplicantP2pIface
-{
-public:
- P2pIface(struct wpa_global* wpa_global, const char ifname[]);
- ~P2pIface() override = default;
- // Refer to |StaIface::invalidate()|.
- void invalidate();
- bool isValid();
-
- // Hidl methods exposed.
- Return<void> getName(getName_cb _hidl_cb) override;
- Return<void> getType(getType_cb _hidl_cb) override;
- Return<void> addNetwork(addNetwork_cb _hidl_cb) override;
- Return<void> removeNetwork(
- SupplicantNetworkId id, removeNetwork_cb _hidl_cb) override;
- Return<void> getNetwork(
- SupplicantNetworkId id, getNetwork_cb _hidl_cb) override;
- Return<void> listNetworks(listNetworks_cb _hidl_cb) override;
- Return<void> registerCallback(
- const sp<ISupplicantP2pIfaceCallback>& callback,
- registerCallback_cb _hidl_cb) override;
- Return<void> getDeviceAddress(getDeviceAddress_cb _hidl_cb) override;
- Return<void> setSsidPostfix(
- const hidl_vec<uint8_t>& postfix,
- setSsidPostfix_cb _hidl_cb) override;
- Return<void> setGroupIdle(
- const hidl_string& group_ifname, uint32_t timeout_in_sec,
- setGroupIdle_cb _hidl_cb) override;
- Return<void> setPowerSave(
- const hidl_string& group_ifname, bool enable,
- setPowerSave_cb _hidl_cb) override;
- Return<void> find(uint32_t timeout_in_sec, find_cb _hidl_cb) override;
- Return<void> stopFind(stopFind_cb _hidl_cb) override;
- Return<void> flush(flush_cb _hidl_cb) override;
- Return<void> connect(
- const hidl_array<uint8_t, 6>& peer_address,
- ISupplicantP2pIface::WpsProvisionMethod provision_method,
- const hidl_string& pre_selected_pin, bool join_existing_group,
- bool persistent, uint32_t go_intent, connect_cb _hidl_cb) override;
- Return<void> cancelConnect(cancelConnect_cb _hidl_cb) override;
- Return<void> provisionDiscovery(
- const hidl_array<uint8_t, 6>& peer_address,
- ISupplicantP2pIface::WpsProvisionMethod provision_method,
- provisionDiscovery_cb _hidl_cb) override;
- Return<void> addGroup(
- bool persistent, SupplicantNetworkId persistent_network_id,
- addGroup_cb _hidl_cb) override;
- Return<void> removeGroup(
- const hidl_string& group_ifname, removeGroup_cb _hidl_cb) override;
- Return<void> reject(
- const hidl_array<uint8_t, 6>& peer_address,
- reject_cb _hidl_cb) override;
- Return<void> invite(
- const hidl_string& group_ifname,
- const hidl_array<uint8_t, 6>& go_device_address,
- const hidl_array<uint8_t, 6>& peer_address,
- invite_cb _hidl_cb) override;
- Return<void> reinvoke(
- SupplicantNetworkId persistent_network_id,
- const hidl_array<uint8_t, 6>& peer_address,
- reinvoke_cb _hidl_cb) override;
- Return<void> configureExtListen(
- uint32_t period_in_millis, uint32_t interval_in_millis,
- configureExtListen_cb _hidl_cb) override;
- Return<void> setListenChannel(
- uint32_t channel, uint32_t operating_class,
- setListenChannel_cb _hidl_cb) override;
- Return<void> setDisallowedFrequencies(
- const hidl_vec<FreqRange>& ranges,
- setDisallowedFrequencies_cb _hidl_cb) override;
- Return<void> getSsid(
- const hidl_array<uint8_t, 6>& peer_address,
- getSsid_cb _hidl_cb) override;
- Return<void> getGroupCapability(
- const hidl_array<uint8_t, 6>& peer_address,
- getGroupCapability_cb _hidl_cb) override;
- Return<void> addBonjourService(
- const hidl_vec<uint8_t>& query, const hidl_vec<uint8_t>& response,
- addBonjourService_cb _hidl_cb) override;
- Return<void> removeBonjourService(
- const hidl_vec<uint8_t>& query,
- removeBonjourService_cb _hidl_cb) override;
- Return<void> addUpnpService(
- uint32_t version, const hidl_string& service_name,
- addUpnpService_cb _hidl_cb) override;
- Return<void> removeUpnpService(
- uint32_t version, const hidl_string& service_name,
- removeUpnpService_cb _hidl_cb) override;
- Return<void> flushServices(flushServices_cb _hidl_cb) override;
- Return<void> requestServiceDiscovery(
- const hidl_array<uint8_t, 6>& peer_address,
- const hidl_vec<uint8_t>& query,
- requestServiceDiscovery_cb _hidl_cb) override;
- Return<void> cancelServiceDiscovery(
- uint64_t identifier, cancelServiceDiscovery_cb _hidl_cb) override;
- Return<void> setMiracastMode(
- ISupplicantP2pIface::MiracastMode mode,
- setMiracastMode_cb _hidl_cb) override;
- Return<void> startWpsPbc(
- const hidl_string& groupIfName, const hidl_array<uint8_t, 6>& bssid,
- startWpsPbc_cb _hidl_cb) override;
- Return<void> startWpsPinKeypad(
- const hidl_string& groupIfName, const hidl_string& pin,
- startWpsPinKeypad_cb _hidl_cb) override;
- Return<void> startWpsPinDisplay(
- const hidl_string& groupIfName, const hidl_array<uint8_t, 6>& bssid,
- startWpsPinDisplay_cb _hidl_cb) override;
- Return<void> cancelWps(
- const hidl_string& groupIfName, cancelWps_cb _hidl_cb) override;
- Return<void> setWpsDeviceName(
- const hidl_string& name, setWpsDeviceName_cb _hidl_cb) override;
- Return<void> setWpsDeviceType(
- const hidl_array<uint8_t, 8>& type,
- setWpsDeviceType_cb _hidl_cb) override;
- Return<void> setWpsManufacturer(
- const hidl_string& manufacturer,
- setWpsManufacturer_cb _hidl_cb) override;
- Return<void> setWpsModelName(
- const hidl_string& model_name,
- setWpsModelName_cb _hidl_cb) override;
- Return<void> setWpsModelNumber(
- const hidl_string& model_number,
- setWpsModelNumber_cb _hidl_cb) override;
- Return<void> setWpsSerialNumber(
- const hidl_string& serial_number,
- setWpsSerialNumber_cb _hidl_cb) override;
- Return<void> setWpsConfigMethods(
- uint16_t config_methods, setWpsConfigMethods_cb _hidl_cb) override;
- Return<void> enableWfd(bool enable, enableWfd_cb _hidl_cb) override;
- Return<void> setWfdDeviceInfo(
- const hidl_array<uint8_t, 6>& info,
- setWfdDeviceInfo_cb _hidl_cb) override;
- Return<void> createNfcHandoverRequestMessage(
- createNfcHandoverRequestMessage_cb _hidl_cb) override;
- Return<void> createNfcHandoverSelectMessage(
- createNfcHandoverSelectMessage_cb _hidl_cb) override;
- Return<void> reportNfcHandoverResponse(
- const hidl_vec<uint8_t>& request,
- reportNfcHandoverResponse_cb _hidl_cb) override;
- Return<void> reportNfcHandoverInitiation(
- const hidl_vec<uint8_t>& select,
- reportNfcHandoverInitiation_cb _hidl_cb) override;
- Return<void> saveConfig(saveConfig_cb _hidl_cb) override;
-
-private:
- // Corresponding worker functions for the HIDL methods.
- std::pair<SupplicantStatus, std::string> getNameInternal();
- std::pair<SupplicantStatus, IfaceType> getTypeInternal();
- std::pair<SupplicantStatus, sp<ISupplicantP2pNetwork>>
- addNetworkInternal();
- SupplicantStatus removeNetworkInternal(SupplicantNetworkId id);
- std::pair<SupplicantStatus, sp<ISupplicantP2pNetwork>>
- getNetworkInternal(SupplicantNetworkId id);
- std::pair<SupplicantStatus, std::vector<SupplicantNetworkId>>
- listNetworksInternal();
- SupplicantStatus registerCallbackInternal(
- const sp<ISupplicantP2pIfaceCallback>& callback);
- std::pair<SupplicantStatus, std::array<uint8_t, 6>>
- getDeviceAddressInternal();
- SupplicantStatus setSsidPostfixInternal(
- const std::vector<uint8_t>& postfix);
- SupplicantStatus setGroupIdleInternal(
- const std::string& group_ifname, uint32_t timeout_in_sec);
- SupplicantStatus setPowerSaveInternal(
- const std::string& group_ifname, bool enable);
- SupplicantStatus findInternal(uint32_t timeout_in_sec);
- SupplicantStatus stopFindInternal();
- SupplicantStatus flushInternal();
- std::pair<SupplicantStatus, std::string> connectInternal(
- const std::array<uint8_t, 6>& peer_address,
- ISupplicantP2pIface::WpsProvisionMethod provision_method,
- const std::string& pre_selected_pin, bool join_existing_group,
- bool persistent, uint32_t go_intent);
- SupplicantStatus cancelConnectInternal();
- SupplicantStatus provisionDiscoveryInternal(
- const std::array<uint8_t, 6>& peer_address,
- ISupplicantP2pIface::WpsProvisionMethod provision_method);
- SupplicantStatus addGroupInternal(
- bool persistent, SupplicantNetworkId persistent_network_id);
- SupplicantStatus removeGroupInternal(const std::string& group_ifname);
- SupplicantStatus rejectInternal(
- const std::array<uint8_t, 6>& peer_address);
- SupplicantStatus inviteInternal(
- const std::string& group_ifname,
- const std::array<uint8_t, 6>& go_device_address,
- const std::array<uint8_t, 6>& peer_address);
- SupplicantStatus reinvokeInternal(
- SupplicantNetworkId persistent_network_id,
- const std::array<uint8_t, 6>& peer_address);
- SupplicantStatus configureExtListenInternal(
- uint32_t period_in_millis, uint32_t interval_in_millis);
- SupplicantStatus setListenChannelInternal(
- uint32_t channel, uint32_t operating_class);
- SupplicantStatus setDisallowedFrequenciesInternal(
- const std::vector<FreqRange>& ranges);
- std::pair<SupplicantStatus, std::vector<uint8_t>> getSsidInternal(
- const std::array<uint8_t, 6>& peer_address);
- std::pair<SupplicantStatus, uint32_t> getGroupCapabilityInternal(
- const std::array<uint8_t, 6>& peer_address);
- SupplicantStatus addBonjourServiceInternal(
- const std::vector<uint8_t>& query,
- const std::vector<uint8_t>& response);
- SupplicantStatus removeBonjourServiceInternal(
- const std::vector<uint8_t>& query);
- SupplicantStatus addUpnpServiceInternal(
- uint32_t version, const std::string& service_name);
- SupplicantStatus removeUpnpServiceInternal(
- uint32_t version, const std::string& service_name);
- SupplicantStatus flushServicesInternal();
- std::pair<SupplicantStatus, uint64_t> requestServiceDiscoveryInternal(
- const std::array<uint8_t, 6>& peer_address,
- const std::vector<uint8_t>& query);
- SupplicantStatus cancelServiceDiscoveryInternal(uint64_t identifier);
- SupplicantStatus setMiracastModeInternal(
- ISupplicantP2pIface::MiracastMode mode);
- SupplicantStatus startWpsPbcInternal(
- const std::string& group_ifname,
- const std::array<uint8_t, 6>& bssid);
- SupplicantStatus startWpsPinKeypadInternal(
- const std::string& group_ifname, const std::string& pin);
- std::pair<SupplicantStatus, std::string> startWpsPinDisplayInternal(
- const std::string& group_ifname,
- const std::array<uint8_t, 6>& bssid);
- SupplicantStatus cancelWpsInternal(const std::string& group_ifname);
- SupplicantStatus setWpsDeviceNameInternal(const std::string& name);
- SupplicantStatus setWpsDeviceTypeInternal(
- const std::array<uint8_t, 8>& type);
- SupplicantStatus setWpsManufacturerInternal(
- const std::string& manufacturer);
- SupplicantStatus setWpsModelNameInternal(const std::string& model_name);
- SupplicantStatus setWpsModelNumberInternal(
- const std::string& model_number);
- SupplicantStatus setWpsSerialNumberInternal(
- const std::string& serial_number);
- SupplicantStatus setWpsConfigMethodsInternal(uint16_t config_methods);
- SupplicantStatus enableWfdInternal(bool enable);
- SupplicantStatus setWfdDeviceInfoInternal(
- const std::array<uint8_t, 6>& info);
- std::pair<SupplicantStatus, std::vector<uint8_t>>
- createNfcHandoverRequestMessageInternal();
- std::pair<SupplicantStatus, std::vector<uint8_t>>
- createNfcHandoverSelectMessageInternal();
- SupplicantStatus reportNfcHandoverResponseInternal(
- const std::vector<uint8_t>& request);
- SupplicantStatus reportNfcHandoverInitiationInternal(
- const std::vector<uint8_t>& select);
- SupplicantStatus saveConfigInternal();
-
- struct wpa_supplicant* retrieveIfacePtr();
- struct wpa_supplicant* retrieveGroupIfacePtr(
- const std::string& group_ifname);
-
- // Reference to the global wpa_struct. This is assumed to be valid for
- // the lifetime of the process.
- struct wpa_global* wpa_global_;
- // Name of the iface this hidl object controls
- const std::string ifname_;
- bool is_valid_;
-
- DISALLOW_COPY_AND_ASSIGN(P2pIface);
-};
-
-} // namespace implementation
-} // namespace V1_1
-} // namespace wifi
-} // namespace supplicant
-} // namespace hardware
-} // namespace android
-
-#endif // WPA_SUPPLICANT_HIDL_P2P_IFACE_H
diff --git a/wpa_supplicant/hidl/1.1/p2p_network.cpp b/wpa_supplicant/hidl/1.1/p2p_network.cpp
deleted file mode 100644
index 7458fd9..0000000
--- a/wpa_supplicant/hidl/1.1/p2p_network.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * hidl interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "hidl_manager.h"
-#include "hidl_return_util.h"
-#include "p2p_network.h"
-
-extern "C" {
-#include "config_ssid.h"
-}
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace supplicant {
-namespace V1_1 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-P2pNetwork::P2pNetwork(
- struct wpa_global *wpa_global, const char ifname[], int network_id)
- : wpa_global_(wpa_global),
- ifname_(ifname),
- network_id_(network_id),
- is_valid_(true)
-{
-}
-
-void P2pNetwork::invalidate() { is_valid_ = false; }
-bool P2pNetwork::isValid()
-{
- return (is_valid_ && (retrieveNetworkPtr() != nullptr));
-}
-
-Return<void> P2pNetwork::getId(getId_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &P2pNetwork::getIdInternal, _hidl_cb);
-}
-
-Return<void> P2pNetwork::getInterfaceName(getInterfaceName_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &P2pNetwork::getInterfaceNameInternal, _hidl_cb);
-}
-
-Return<void> P2pNetwork::getType(getType_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &P2pNetwork::getTypeInternal, _hidl_cb);
-}
-
-Return<void> P2pNetwork::registerCallback(
- const sp<ISupplicantP2pNetworkCallback> &callback,
- registerCallback_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &P2pNetwork::registerCallbackInternal, _hidl_cb, callback);
-}
-
-Return<void> P2pNetwork::getSsid(getSsid_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &P2pNetwork::getSsidInternal, _hidl_cb);
-}
-
-Return<void> P2pNetwork::getBssid(getBssid_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &P2pNetwork::getBssidInternal, _hidl_cb);
-}
-
-Return<void> P2pNetwork::isCurrent(isCurrent_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &P2pNetwork::isCurrentInternal, _hidl_cb);
-}
-
-Return<void> P2pNetwork::isPersistent(isPersistent_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &P2pNetwork::isPersistentInternal, _hidl_cb);
-}
-
-Return<void> P2pNetwork::isGo(isGo_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &P2pNetwork::isGoInternal, _hidl_cb);
-}
-
-Return<void> P2pNetwork::setClientList(
- const hidl_vec<hidl_array<uint8_t, 6>> &clients, setClientList_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &P2pNetwork::setClientListInternal, _hidl_cb, clients);
-}
-
-Return<void> P2pNetwork::getClientList(getClientList_cb _hidl_cb)
-{
- return validateAndCall(
- this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &P2pNetwork::getClientListInternal, _hidl_cb);
-}
-
-std::pair<SupplicantStatus, uint32_t> P2pNetwork::getIdInternal()
-{
- return {{SupplicantStatusCode::SUCCESS, ""}, network_id_};
-}
-
-std::pair<SupplicantStatus, std::string> P2pNetwork::getInterfaceNameInternal()
-{
- return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
-}
-
-std::pair<SupplicantStatus, IfaceType> P2pNetwork::getTypeInternal()
-{
- return {{SupplicantStatusCode::SUCCESS, ""}, IfaceType::P2P};
-}
-
-SupplicantStatus P2pNetwork::registerCallbackInternal(
- const sp<ISupplicantP2pNetworkCallback> &callback)
-{
- HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager ||
- hidl_manager->addP2pNetworkCallbackHidlObject(
- ifname_, network_id_, callback)) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, std::vector<uint8_t>> P2pNetwork::getSsidInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""},
- {wpa_ssid->ssid, wpa_ssid->ssid + wpa_ssid->ssid_len}};
-}
-
-std::pair<SupplicantStatus, std::array<uint8_t, 6>>
-P2pNetwork::getBssidInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- std::array<uint8_t, 6> bssid{};
- if (wpa_ssid->bssid_set) {
- os_memcpy(bssid.data(), wpa_ssid->bssid, ETH_ALEN);
- }
- return {{SupplicantStatusCode::SUCCESS, ""}, bssid};
-}
-
-std::pair<SupplicantStatus, bool> P2pNetwork::isCurrentInternal()
-{
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""},
- (wpa_s->current_ssid == wpa_ssid)};
-}
-
-std::pair<SupplicantStatus, bool> P2pNetwork::isPersistentInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""}, (wpa_ssid->disabled == 2)};
-}
-
-std::pair<SupplicantStatus, bool> P2pNetwork::isGoInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""},
- (wpa_ssid->mode == wpa_ssid::wpas_mode::WPAS_MODE_P2P_GO)};
-}
-
-SupplicantStatus P2pNetwork::setClientListInternal(
- const std::vector<hidl_array<uint8_t, 6>> &clients)
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- os_free(wpa_ssid->p2p_client_list);
- // Internal representation uses a generic MAC addr/mask storage format
- // (even though the mask is always 0xFF'ed for p2p_client_list). So, the
- // first 6 bytes holds the client MAC address and the next 6 bytes are
- // OxFF'ed.
- wpa_ssid->p2p_client_list =
- (u8 *)os_malloc(ETH_ALEN * 2 * clients.size());
- if (!wpa_ssid->p2p_client_list) {
- return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
- }
- u8 *list = wpa_ssid->p2p_client_list;
- for (const auto &client : clients) {
- os_memcpy(list, client.data(), ETH_ALEN);
- list += ETH_ALEN;
- os_memset(list, 0xFF, ETH_ALEN);
- list += ETH_ALEN;
- }
- wpa_ssid->num_p2p_clients = clients.size();
- return {SupplicantStatusCode::SUCCESS, ""};
-}
-
-std::pair<SupplicantStatus, std::vector<hidl_array<uint8_t, 6>>>
-P2pNetwork::getClientListInternal()
-{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->p2p_client_list) {
- return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
- }
- std::vector<hidl_array<uint8_t, 6>> clients;
- u8 *list = wpa_ssid->p2p_client_list;
- for (size_t i = 0; i < wpa_ssid->num_p2p_clients; i++) {
- clients.emplace_back(list);
- list += 2 * ETH_ALEN;
- }
- return {{SupplicantStatusCode::SUCCESS, ""}, clients};
-}
-
-/**
- * Retrieve the underlying |wpa_ssid| struct pointer for
- * this network.
- * If the underlying network is removed or the interface
- * this network belong to is removed, all RPC method calls
- * on this object will return failure.
- */
-struct wpa_ssid *P2pNetwork::retrieveNetworkPtr()
-{
- wpa_supplicant *wpa_s = retrieveIfacePtr();
- if (!wpa_s)
- return nullptr;
- return wpa_config_get_network(wpa_s->conf, network_id_);
-}
-
-/**
- * Retrieve the underlying |wpa_supplicant| struct
- * pointer for this network.
- */
-struct wpa_supplicant *P2pNetwork::retrieveIfacePtr()
-{
- return wpa_supplicant_get_iface(
- (struct wpa_global *)wpa_global_, ifname_.c_str());
-}
-} // namespace implementation
-} // namespace V1_1
-} // namespace wifi
-} // namespace supplicant
-} // namespace hardware
-} // namespace android
diff --git a/wpa_supplicant/hidl/1.1/hidl.cpp b/wpa_supplicant/hidl/1.2/hidl.cpp
similarity index 81%
rename from wpa_supplicant/hidl/1.1/hidl.cpp
rename to wpa_supplicant/hidl/1.2/hidl.cpp
index 95194af..ea1fa98 100644
--- a/wpa_supplicant/hidl/1.1/hidl.cpp
+++ b/wpa_supplicant/hidl/1.2/hidl.cpp
@@ -12,7 +12,8 @@
#include <hidl/HidlTransportSupport.h>
#include "hidl_manager.h"
-extern "C" {
+extern "C"
+{
#include "hidl.h"
#include "hidl_i.h"
#include "utils/common.h"
@@ -21,9 +22,13 @@
}
using android::hardware::configureRpcThreadpool;
-using android::hardware::setupTransportPolling;
using android::hardware::handleTransportPoll;
-using android::hardware::wifi::supplicant::V1_1::implementation::HidlManager;
+using android::hardware::setupTransportPolling;
+using android::hardware::wifi::supplicant::V1_2::implementation::HidlManager;
+using namespace android::hardware::wifi::supplicant::V1_2;
+
+static void wpas_hidl_notify_dpp_failure(struct wpa_supplicant *wpa_s, DppFailureCode code);
+static void wpas_hidl_notify_dpp_progress(struct wpa_supplicant *wpa_s, DppProgressCode code);
void wpas_hidl_sock_handler(
int sock, void * /* eloop_ctx */, void * /* sock_ctx */)
@@ -206,8 +211,9 @@
return;
wpa_printf(
- MSG_DEBUG, "Notifying HS20 icon query done to hidl control: " MACSTR
- "file_name: %s",
+ MSG_DEBUG,
+ "Notifying HS20 icon query done to hidl control: " MACSTR
+ "file_name: %s",
MAC2STR(bssid), file_name);
HidlManager *hidl_manager = HidlManager::getInstance();
@@ -533,13 +539,14 @@
return;
if (bssid) {
wpa_printf(
- MSG_DEBUG,
- "Notifying P2P invitation result to hidl control: " MACSTR,
- MAC2STR(bssid));
+ MSG_DEBUG,
+ "Notifying P2P invitation result to hidl control: " MACSTR,
+ MAC2STR(bssid));
} else {
wpa_printf(
- MSG_DEBUG,
- "Notifying P2P invitation result to hidl control: NULL bssid");
+ MSG_DEBUG,
+ "Notifying P2P invitation result to hidl control: NULL "
+ "bssid");
}
HidlManager *hidl_manager = HidlManager::getInstance();
@@ -626,15 +633,12 @@
hidl_manager->notifyApStaDeauthorized(wpa_s, sta, p2p_dev_addr);
}
-void wpas_hidl_notify_eap_error(
- struct wpa_supplicant *wpa_s, int error_code)
+void wpas_hidl_notify_eap_error(struct wpa_supplicant *wpa_s, int error_code)
{
if (!wpa_s)
return;
- wpa_printf(
- MSG_DEBUG,
- "Notifying EAP Error: %d ", error_code);
+ wpa_printf(MSG_DEBUG, "Notifying EAP Error: %d ", error_code);
HidlManager *hidl_manager = HidlManager::getInstance();
if (!hidl_manager)
@@ -643,3 +647,132 @@
hidl_manager->notifyEapError(wpa_s, error_code);
}
+void wpas_hidl_notify_dpp_config_received(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ if (!wpa_s || !ssid)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG,
+ "Notifying DPP configuration received for SSID %d", ssid->id);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyDppConfigReceived(wpa_s, ssid);
+}
+
+void wpas_hidl_notify_dpp_config_sent(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG,
+ "Notifying DPP configuration sent");
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyDppConfigSent(wpa_s);
+}
+
+/* DPP Progress notifications */
+void wpas_hidl_notify_dpp_auth_success(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ wpas_hidl_notify_dpp_progress(wpa_s, DppProgressCode::AUTHENTICATION_SUCCESS);
+}
+
+void wpas_hidl_notify_dpp_resp_pending(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ wpas_hidl_notify_dpp_progress(wpa_s, DppProgressCode::RESPONSE_PENDING);
+}
+
+/* DPP Failure notifications */
+void wpas_hidl_notify_dpp_not_compatible(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ wpas_hidl_notify_dpp_failure(wpa_s, DppFailureCode::NOT_COMPATIBLE);
+}
+
+void wpas_hidl_notify_dpp_missing_auth(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+}
+
+void wpas_hidl_notify_dpp_configuration_failure(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ wpas_hidl_notify_dpp_failure(wpa_s, DppFailureCode::CONFIGURATION);
+}
+
+void wpas_hidl_notify_dpp_timeout(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ wpas_hidl_notify_dpp_failure(wpa_s, DppFailureCode::TIMEOUT);
+}
+
+void wpas_hidl_notify_dpp_auth_failure(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ wpas_hidl_notify_dpp_failure(wpa_s, DppFailureCode::AUTHENTICATION);
+}
+
+void wpas_hidl_notify_dpp_fail(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ wpas_hidl_notify_dpp_failure(wpa_s, DppFailureCode::FAILURE);
+}
+
+/* DPP notification helper functions */
+static void wpas_hidl_notify_dpp_failure(struct wpa_supplicant *wpa_s, DppFailureCode code)
+{
+ if (!wpa_s)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG,
+ "Notifying DPP failure event %d", code);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyDppFailure(wpa_s, code);
+}
+
+static void wpas_hidl_notify_dpp_progress(struct wpa_supplicant *wpa_s, DppProgressCode code)
+{
+ if (!wpa_s)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG,
+ "Notifying DPP progress event %d", code);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyDppProgress(wpa_s, code);
+}
diff --git a/wpa_supplicant/hidl/1.2/hidl.h b/wpa_supplicant/hidl/1.2/hidl.h
new file mode 100644
index 0000000..a177f6e
--- /dev/null
+++ b/wpa_supplicant/hidl/1.2/hidl.h
@@ -0,0 +1,248 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_HIDL_HIDL_H
+#define WPA_SUPPLICANT_HIDL_HIDL_H
+
+#ifdef _cplusplus
+extern "C"
+{
+#endif // _cplusplus
+
+ /**
+ * This is the hidl RPC interface entry point to the wpa_supplicant
+ * core. This initializes the hidl driver & HidlManager instance and
+ * then forwards all the notifcations from the supplicant core to the
+ * HidlManager.
+ */
+ struct wpas_hidl_priv;
+ struct wpa_global;
+
+ struct wpas_hidl_priv *wpas_hidl_init(struct wpa_global *global);
+ void wpas_hidl_deinit(struct wpas_hidl_priv *priv);
+
+#ifdef CONFIG_CTRL_IFACE_HIDL
+ int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s);
+ int wpas_hidl_unregister_interface(struct wpa_supplicant *wpa_s);
+ int wpas_hidl_register_network(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+ int wpas_hidl_unregister_network(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+ int wpas_hidl_notify_state_changed(struct wpa_supplicant *wpa_s);
+ int wpas_hidl_notify_network_request(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ enum wpa_ctrl_req_type rtype, const char *default_txt);
+ void wpas_hidl_notify_anqp_query_done(
+ struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
+ const struct wpa_bss_anqp *anqp);
+ void wpas_hidl_notify_hs20_icon_query_done(
+ struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const char *file_name, const u8 *image, u32 image_length);
+ void wpas_hidl_notify_hs20_rx_subscription_remediation(
+ struct wpa_supplicant *wpa_s, const char *url, u8 osu_method);
+ 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_disconnect_reason(struct wpa_supplicant *wpa_s);
+ void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s);
+ void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s);
+ void wpas_hidl_notify_bssid_changed(struct wpa_supplicant *wpa_s);
+ void wpas_hidl_notify_wps_event_fail(
+ struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr,
+ uint16_t config_error, uint16_t error_indication);
+ void wpas_hidl_notify_wps_event_success(struct wpa_supplicant *wpa_s);
+ void wpas_hidl_notify_wps_event_pbc_overlap(
+ struct wpa_supplicant *wpa_s);
+ void wpas_hidl_notify_p2p_device_found(
+ struct wpa_supplicant *wpa_s, const u8 *addr,
+ const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
+ u8 peer_wfd_device_info_len);
+ void wpas_hidl_notify_p2p_device_lost(
+ struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr);
+ void wpas_hidl_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s);
+ void wpas_hidl_notify_p2p_go_neg_req(
+ struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
+ u8 go_intent);
+ void wpas_hidl_notify_p2p_go_neg_completed(
+ struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res);
+ void wpas_hidl_notify_p2p_group_formation_failure(
+ struct wpa_supplicant *wpa_s, const char *reason);
+ void wpas_hidl_notify_p2p_group_started(
+ struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid,
+ int persistent, int client);
+ void wpas_hidl_notify_p2p_group_removed(
+ struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid,
+ const char *role);
+ void wpas_hidl_notify_p2p_invitation_received(
+ struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
+ const u8 *bssid, int id, int op_freq);
+ void wpas_hidl_notify_p2p_invitation_result(
+ struct wpa_supplicant *wpa_s, int status, const u8 *bssid);
+ void wpas_hidl_notify_p2p_provision_discovery(
+ struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
+ enum p2p_prov_disc_status status, u16 config_methods,
+ unsigned int generated_pin);
+ void wpas_hidl_notify_p2p_sd_response(
+ struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
+ const u8 *tlvs, size_t tlvs_len);
+ void wpas_hidl_notify_ap_sta_authorized(
+ struct wpa_supplicant *wpa_s, const u8 *sta,
+ const u8 *p2p_dev_addr);
+ void wpas_hidl_notify_ap_sta_deauthorized(
+ struct wpa_supplicant *wpa_s, const u8 *sta,
+ const u8 *p2p_dev_addr);
+ void wpas_hidl_notify_eap_error(
+ struct wpa_supplicant *wpa_s, int error_code);
+ void wpas_hidl_notify_dpp_config_received(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
+ void wpas_hidl_notify_dpp_config_sent(struct wpa_supplicant *wpa_s);
+ void wpas_hidl_notify_dpp_auth_success(struct wpa_supplicant *wpa_s);
+ void wpas_hidl_notify_dpp_resp_pending(struct wpa_supplicant *wpa_s);
+ void wpas_hidl_notify_dpp_not_compatible(struct wpa_supplicant *wpa_s);
+ void wpas_hidl_notify_dpp_missing_auth(struct wpa_supplicant *wpa_s);
+ void wpas_hidl_notify_dpp_configuration_failure(struct wpa_supplicant *wpa_s);
+ void wpas_hidl_notify_dpp_invalid_uri(struct wpa_supplicant *wpa_s);
+ void wpas_hidl_notify_dpp_timeout(struct wpa_supplicant *wpa_s);
+ void wpas_hidl_notify_dpp_auth_failure(struct wpa_supplicant *wpa_s);
+ void wpas_hidl_notify_dpp_fail(struct wpa_supplicant *wpa_s);
+#else // CONFIG_CTRL_IFACE_HIDL
+static inline int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+static inline int wpas_hidl_unregister_interface(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+static inline int wpas_hidl_register_network(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+ return 0;
+}
+static inline int wpas_hidl_unregister_network(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+ return 0;
+}
+static inline int wpas_hidl_notify_state_changed(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+static inline int wpas_hidl_notify_network_request(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ enum wpa_ctrl_req_type rtype, const char *default_txt)
+{
+ return 0;
+}
+static void wpas_hidl_notify_anqp_query_done(
+ struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
+ const struct wpa_bss_anqp *anqp)
+{}
+static void wpas_hidl_notify_hs20_icon_query_done(
+ struct wpa_supplicant *wpa_s, const u8 *bssid, const char *file_name,
+ const u8 *image, u32 image_length)
+{}
+static void wpas_hidl_notify_hs20_rx_subscription_remediation(
+ struct wpa_supplicant *wpa_s, const char *url, u8 osu_method)
+{}
+static void wpas_hidl_notify_hs20_rx_deauth_imminent_notice(
+ struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, 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) {}
+static void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s) {}
+static void wpas_hidl_notify_wps_event_fail(
+ struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
+ uint16_t error_indication)
+{}
+static void wpas_hidl_notify_bssid_changed(struct wpa_supplicant *wpa_s) {}
+static void wpas_hidl_notify_wps_event_success(struct wpa_supplicant *wpa_s) {}
+static void wpas_hidl_notify_wps_event_pbc_overlap(struct wpa_supplicant *wpa_s)
+{}
+static void wpas_hidl_notify_p2p_device_found(
+ struct wpa_supplicant *wpa_s, const u8 *addr,
+ const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
+ u8 peer_wfd_device_info_len);
+{}
+static void wpas_hidl_notify_p2p_device_lost(
+ struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr)
+{}
+static void wpas_hidl_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s) {}
+static void wpas_hidl_notify_p2p_go_neg_req(
+ struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
+ u8 go_intent)
+{}
+static void wpas_hidl_notify_p2p_go_neg_completed(
+ struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res)
+{}
+static void wpas_hidl_notify_p2p_group_formation_failure(
+ struct wpa_supplicant *wpa_s, const char *reason)
+{}
+static void wpas_hidl_notify_p2p_group_started(
+ struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, int persistent,
+ int client)
+{}
+static void wpas_hidl_notify_p2p_group_removed(
+ struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, const char *role)
+{}
+static void wpas_hidl_notify_p2p_invitation_received(
+ struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
+ const u8 *bssid, int id, int op_freq)
+{}
+static void wpas_hidl_notify_p2p_invitation_result(
+ struct wpa_supplicant *wpa_s, int status, const u8 *bssid)
+{}
+static void wpas_hidl_notify_p2p_provision_discovery(
+ struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
+ enum p2p_prov_disc_status status, u16 config_methods,
+ unsigned int generated_pin)
+{}
+static void wpas_hidl_notify_p2p_sd_response(
+ struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
+ const u8 *tlvs, size_t tlvs_len)
+{}
+static void wpas_hidl_notify_ap_sta_authorized(
+ struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+{}
+static void wpas_hidl_notify_ap_sta_deauthorized(
+ struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+{}
+static void wpas_hidl_notify_eap_error(
+ struct wpa_supplicant *wpa_s, int error_code)
+{}
+static void wpas_hidl_notify_dpp_config_received(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{}
+static void wpas_hidl_notify_dpp_config_received(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
+static void wpas_hidl_notify_dpp_config_sent(struct wpa_supplicant *wpa_s)
+{}
+static void wpas_hidl_notify_dpp_auth_success(struct wpa_supplicant *wpa_s)
+{}
+static void wpas_hidl_notify_dpp_resp_pending(struct wpa_supplicant *wpa_s)
+{}
+static void wpas_hidl_notify_dpp_not_compatible(struct wpa_supplicant *wpa_s)
+{}
+static void wpas_hidl_notify_dpp_missing_auth(struct wpa_supplicant *wpa_s)
+{}
+static void wpas_hidl_notify_dpp_configuration_failure(struct wpa_supplicant *wpa_s)
+{}
+static void wpas_hidl_notify_dpp_invalid_uri(struct wpa_supplicant *wpa_s)
+{}
+static void wpas_hidl_notify_dpp_timeout(struct wpa_supplicant *wpa_s)
+{}
+static void wpas_hidl_notify_dpp_failure(struct wpa_supplicant *wpa_s)
+{}
+#endif // CONFIG_CTRL_IFACE_HIDL
+
+#ifdef _cplusplus
+}
+#endif // _cplusplus
+
+#endif // WPA_SUPPLICANT_HIDL_HIDL_H
diff --git a/wpa_supplicant/hidl/1.0/hidl_constants.h b/wpa_supplicant/hidl/1.2/hidl_constants.h
similarity index 100%
rename from wpa_supplicant/hidl/1.0/hidl_constants.h
rename to wpa_supplicant/hidl/1.2/hidl_constants.h
diff --git a/wpa_supplicant/hidl/1.0/hidl_i.h b/wpa_supplicant/hidl/1.2/hidl_i.h
similarity index 79%
rename from wpa_supplicant/hidl/1.0/hidl_i.h
rename to wpa_supplicant/hidl/1.2/hidl_i.h
index c7a0142..9cff40d 100644
--- a/wpa_supplicant/hidl/1.0/hidl_i.h
+++ b/wpa_supplicant/hidl/1.2/hidl_i.h
@@ -11,15 +11,16 @@
#define HIDL_I_H
#ifdef _cplusplus
-extern "C" {
+extern "C"
+{
#endif // _cplusplus
-struct wpas_hidl_priv
-{
- int hidl_fd;
- struct wpa_global *global;
- void *hidl_manager;
-};
+ struct wpas_hidl_priv
+ {
+ int hidl_fd;
+ struct wpa_global *global;
+ void *hidl_manager;
+ };
#ifdef _cplusplus
}
diff --git a/wpa_supplicant/hidl/1.1/hidl_manager.cpp b/wpa_supplicant/hidl/1.2/hidl_manager.cpp
similarity index 90%
rename from wpa_supplicant/hidl/1.1/hidl_manager.cpp
rename to wpa_supplicant/hidl/1.2/hidl_manager.cpp
index ca614d2..b69fe04 100644
--- a/wpa_supplicant/hidl/1.1/hidl_manager.cpp
+++ b/wpa_supplicant/hidl/1.2/hidl_manager.cpp
@@ -14,11 +14,13 @@
#include "misc_utils.h"
extern "C" {
+#include "scan.h"
#include "src/eap_common/eap_sim_common.h"
}
namespace {
using android::hardware::hidl_array;
+using namespace android::hardware::wifi::supplicant::V1_2;
constexpr uint8_t kWfdDeviceInfoLen = 6;
// GSM-AUTH:<RAND1>:<RAND2>[:<RAND3>]
@@ -292,7 +294,8 @@
const std::string &ifname,
const std::function<
android::hardware::Return<void>(android::sp<CallbackTypeV1_1>)> &method,
- const std::map<const std::string, std::vector<android::sp<CallbackTypeV1_0>>>
+ const std::map<
+ const std::string, std::vector<android::sp<CallbackTypeV1_0>>>
&callbacks_map)
{
if (ifname.empty())
@@ -315,6 +318,35 @@
}
}
+template <class CallbackTypeV1_0, class CallbackTypeV1_2>
+void callWithEachIfaceCallback_1_2(
+ const std::string &ifname,
+ const std::function<
+ android::hardware::Return<void>(android::sp<CallbackTypeV1_2>)> &method,
+ const std::map<
+ const std::string, std::vector<android::sp<CallbackTypeV1_0>>>
+ &callbacks_map)
+{
+ if (ifname.empty())
+ return;
+
+ auto iface_callback_map_iter = callbacks_map.find(ifname);
+ if (iface_callback_map_iter == callbacks_map.end())
+ return;
+ const auto &iface_callback_list = iface_callback_map_iter->second;
+ for (const auto &callback : iface_callback_list) {
+ android::sp<CallbackTypeV1_2> callback_1_2 =
+ CallbackTypeV1_2::castFrom(callback);
+ if (callback_1_2 == nullptr)
+ continue;
+
+ if (!method(callback_1_2).isOk()) {
+ wpa_printf(
+ MSG_ERROR, "Failed to invoke HIDL iface callback");
+ }
+ }
+}
+
template <class CallbackType>
void callWithEachNetworkCallback(
const std::string &ifname, int network_id,
@@ -397,11 +429,10 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
namespace implementation {
-using namespace android::hardware::wifi::supplicant::V1_0;
-using namespace android::hardware::wifi::supplicant::V1_1;
+using namespace android::hardware::wifi::supplicant::V1_2;
using V1_0::ISupplicantStaIfaceCallback;
HidlManager *HidlManager::instance_ = NULL;
@@ -470,6 +501,18 @@
}
sta_iface_callbacks_map_[wpa_s->ifname] =
std::vector<android::sp<ISupplicantStaIfaceCallback>>();
+ // Turn on Android specific customizations for STA interfaces
+ // here!
+ //
+ // Turn on scan mac randomization only if driver supports.
+ if (wpa_s->mac_addr_rand_supported & MAC_ADDR_RAND_SCAN) {
+ if (wpas_mac_addr_rand_scan_set(
+ wpa_s, MAC_ADDR_RAND_SCAN, nullptr, nullptr)) {
+ wpa_printf(
+ MSG_ERROR,
+ "Failed to enable scan mac randomization");
+ }
+ }
}
// Invoke the |onInterfaceCreated| method on all registered callbacks.
@@ -1204,7 +1247,8 @@
}
void HidlManager::notifyP2pGroupStarted(
- struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid, int persistent, int client)
+ struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid,
+ int persistent, int client)
{
if (!wpa_group_s || !wpa_group_s->parent || !ssid)
return;
@@ -1358,9 +1402,11 @@
p2p_iface_object_map_.end())
return;
callWithEachP2pIfaceCallback(
- wpa_s->parent->ifname, std::bind(
- &ISupplicantP2pIfaceCallback::onStaAuthorized,
- std::placeholders::_1, sta, p2p_dev_addr ? p2p_dev_addr : kZeroBssid));
+ wpa_s->parent->ifname,
+ std::bind(
+ &ISupplicantP2pIfaceCallback::onStaAuthorized,
+ std::placeholders::_1, sta,
+ p2p_dev_addr ? p2p_dev_addr : kZeroBssid));
}
void HidlManager::notifyApStaDeauthorized(
@@ -1373,9 +1419,11 @@
return;
callWithEachP2pIfaceCallback(
- wpa_s->parent->ifname, std::bind(
- &ISupplicantP2pIfaceCallback::onStaDeauthorized,
- std::placeholders::_1, sta, p2p_dev_addr ? p2p_dev_addr : kZeroBssid));
+ wpa_s->parent->ifname,
+ std::bind(
+ &ISupplicantP2pIfaceCallback::onStaDeauthorized,
+ std::placeholders::_1, sta,
+ p2p_dev_addr ? p2p_dev_addr : kZeroBssid));
}
void HidlManager::notifyExtRadioWorkStart(
@@ -1420,22 +1468,105 @@
return;
switch (static_cast<EapErrorCode>(error_code)) {
- case EapErrorCode::SIM_GENERAL_FAILURE_AFTER_AUTH:
- case EapErrorCode::SIM_TEMPORARILY_DENIED:
- case EapErrorCode::SIM_NOT_SUBSCRIBED:
- case EapErrorCode::SIM_GENERAL_FAILURE_BEFORE_AUTH:
- case EapErrorCode::SIM_VENDOR_SPECIFIC_EXPIRED_CERT:
- break;
- default:
- return;
+ case EapErrorCode::SIM_GENERAL_FAILURE_AFTER_AUTH:
+ case EapErrorCode::SIM_TEMPORARILY_DENIED:
+ case EapErrorCode::SIM_NOT_SUBSCRIBED:
+ case EapErrorCode::SIM_GENERAL_FAILURE_BEFORE_AUTH:
+ case EapErrorCode::SIM_VENDOR_SPECIFIC_EXPIRED_CERT:
+ break;
+ default:
+ return;
}
callWithEachStaIfaceCallback_1_1(
wpa_s->ifname,
std::bind(
&V1_1::ISupplicantStaIfaceCallback::onEapFailure_1_1,
- std::placeholders::_1,
- static_cast<EapErrorCode>(error_code)));
+ std::placeholders::_1, static_cast<EapErrorCode>(error_code)));
+}
+
+/**
+ * Notify listener about a new DPP configuration received success event
+ *
+ * @param ifname Interface name
+ * @param config Configuration object
+ */
+void HidlManager::notifyDppConfigReceived(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *config)
+{
+ DppAkm securityAkm;
+ char *password;
+ std::string hidl_ifname = wpa_s->ifname;
+
+ if ((config->key_mgmt & WPA_KEY_MGMT_SAE) &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
+ securityAkm = DppAkm::SAE;
+ } else if (config->key_mgmt & WPA_KEY_MGMT_PSK) {
+ securityAkm = DppAkm::PSK;
+ } else {
+ /* Unsupported AKM */
+ wpa_printf(MSG_ERROR, "DPP: Error: Unsupported AKM 0x%X",
+ config->key_mgmt);
+ notifyDppFailure(wpa_s, DppFailureCode::NOT_SUPPORTED);
+ return;
+ }
+
+ password = config->passphrase;
+ std::vector < uint8_t > hidl_ssid;
+ hidl_ssid.assign(config->ssid, config->ssid + config->ssid_len);
+
+ /* At this point, the network is already registered, notify about new
+ * received configuration
+ */
+ callWithEachStaIfaceCallback_1_2(hidl_ifname,
+ std::bind(
+ &V1_2::ISupplicantStaIfaceCallback::onDppSuccessConfigReceived,
+ std::placeholders::_1, hidl_ssid, password, config->psk,
+ securityAkm));
+}
+
+/**
+ * Notify listener about a DPP configuration sent success event
+ *
+ * @param ifname Interface name
+ */
+void HidlManager::notifyDppConfigSent(struct wpa_supplicant *wpa_s)
+{
+ std::string hidl_ifname = wpa_s->ifname;
+
+ callWithEachStaIfaceCallback_1_2(hidl_ifname,
+ std::bind(&V1_2::ISupplicantStaIfaceCallback::onDppSuccessConfigSent,
+ std::placeholders::_1));
+}
+
+/**
+ * Notify listener about a DPP failure event
+ *
+ * @param ifname Interface name
+ * @param code Status code
+ */
+void HidlManager::notifyDppFailure(struct wpa_supplicant *wpa_s, DppFailureCode code)
+{
+ std::string hidl_ifname = wpa_s->ifname;
+
+ callWithEachStaIfaceCallback_1_2(hidl_ifname,
+ std::bind(&V1_2::ISupplicantStaIfaceCallback::onDppFailure,
+ std::placeholders::_1, code));
+}
+
+/**
+ * Notify listener about a DPP progress event
+ *
+ * @param ifname Interface name
+ * @param code Status code
+ */
+void HidlManager::notifyDppProgress(struct wpa_supplicant *wpa_s, DppProgressCode code)
+{
+ std::string hidl_ifname = wpa_s->ifname;
+
+ callWithEachStaIfaceCallback_1_2(hidl_ifname,
+ std::bind(&V1_2::ISupplicantStaIfaceCallback::onDppProgress,
+ std::placeholders::_1, code));
}
/**
@@ -1767,8 +1898,8 @@
}
/**
- * Helper fucntion to invoke the provided callback method on all the
- * registered V1.1 iface callback hidl objects for the specified
+ * Helper function to invoke the provided callback method on all the
+ * registered V1.1 interface callback hidl objects for the specified
* |ifname|.
*
* @param ifname Name of the corresponding interface.
@@ -1777,15 +1908,32 @@
*/
void HidlManager::callWithEachStaIfaceCallback_1_1(
const std::string &ifname,
- const std::function<Return<void>
- (android::sp<V1_1::ISupplicantStaIfaceCallback>)> &method)
+ const std::function<
+ Return<void>(android::sp<V1_1::ISupplicantStaIfaceCallback>)> &method)
{
callWithEachIfaceCallback_1_1(ifname, method, sta_iface_callbacks_map_);
}
/**
- * Helper fucntion to invoke the provided callback method on all the
- * registered iface callback hidl objects for the specified
+ * Helper function to invoke the provided callback method on all the
+ * registered V1.2 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_2::ISupplicantIfaceCallback|.
+ */
+void HidlManager::callWithEachStaIfaceCallback_1_2(
+ const std::string &ifname,
+ const std::function<
+ Return<void>(android::sp<V1_2::ISupplicantStaIfaceCallback>)> &method)
+{
+ callWithEachIfaceCallback_1_2(ifname, method, sta_iface_callbacks_map_);
+}
+
+/**
+ * Helper function to invoke the provided callback method on all the
+ * registered interface callback hidl objects for the specified
* |ifname|.
*
* @param ifname Name of the corresponding interface.
@@ -1838,8 +1986,8 @@
ifname, network_id, method, sta_network_callbacks_map_);
}
} // namespace implementation
-} // namespace V1_1
-} // namespace wifi
+} // namespace V1_2
} // namespace supplicant
+} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wpa_supplicant/hidl/1.1/hidl_manager.h b/wpa_supplicant/hidl/1.2/hidl_manager.h
similarity index 92%
rename from wpa_supplicant/hidl/1.1/hidl_manager.h
rename to wpa_supplicant/hidl/1.2/hidl_manager.h
index 4f100aa..910e2bf 100644
--- a/wpa_supplicant/hidl/1.1/hidl_manager.h
+++ b/wpa_supplicant/hidl/1.2/hidl_manager.h
@@ -16,7 +16,7 @@
#include <android/hardware/wifi/supplicant/1.0/ISupplicantCallback.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIfaceCallback.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetworkCallback.h>
-#include <android/hardware/wifi/supplicant/1.1/ISupplicantStaIfaceCallback.h>
+#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIfaceCallback.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetworkCallback.h>
#include "p2p_iface.h"
@@ -25,7 +25,8 @@
#include "sta_network.h"
#include "supplicant.h"
-extern "C" {
+extern "C"
+{
#include "utils/common.h"
#include "utils/includes.h"
#include "wpa_supplicant_i.h"
@@ -36,11 +37,13 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
namespace implementation {
-using namespace android::hardware::wifi::supplicant::V1_0;
-using namespace android::hardware::wifi::supplicant::V1_1;
+using namespace android::hardware::wifi::supplicant::V1_2;
+using V1_0::ISupplicantP2pIface;
using V1_0::ISupplicantStaIfaceCallback;
+using V1_1::ISupplicant;
+using V1_1::ISupplicantStaIface;
/**
* HidlManager is responsible for managing the lifetime of all
@@ -124,8 +127,12 @@
void notifyApStaDeauthorized(
struct wpa_supplicant *wpa_s, const u8 *sta,
const u8 *p2p_dev_addr);
- void notifyEapError(
- struct wpa_supplicant *wpa_s, int error_code);
+ void notifyEapError(struct wpa_supplicant *wpa_s, int error_code);
+ void notifyDppConfigReceived(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *config);
+ void notifyDppConfigSent(struct wpa_supplicant *wpa_s);
+ void notifyDppFailure(struct wpa_supplicant *wpa_s, DppFailureCode code);
+ void notifyDppProgress(struct wpa_supplicant *wpa_s, DppProgressCode code);
// Methods called from hidl objects.
void notifyExtRadioWorkStart(struct wpa_supplicant *wpa_s, uint32_t id);
@@ -137,7 +144,7 @@
android::sp<ISupplicantP2pIface> *iface_object);
int getStaIfaceHidlObjectByIfname(
const std::string &ifname,
- android::sp<ISupplicantStaIface> *iface_object);
+ android::sp<V1_1::ISupplicantStaIface> *iface_object);
int getP2pNetworkHidlObjectByIfnameAndNetworkId(
const std::string &ifname, int network_id,
android::sp<ISupplicantP2pNetwork> *network_object);
@@ -195,6 +202,10 @@
const std::string &ifname,
const std::function<android::hardware::Return<void>(
android::sp<V1_1::ISupplicantStaIfaceCallback>)> &method);
+ void callWithEachStaIfaceCallback_1_2(
+ const std::string &ifname,
+ const std::function<android::hardware::Return<void>(
+ android::sp<V1_2::ISupplicantStaIfaceCallback>)> &method);
void callWithEachP2pNetworkCallback(
const std::string &ifname, int network_id,
const std::function<android::hardware::Return<void>(
@@ -334,6 +345,26 @@
WPA_KEY_MGMT_OSEN,
"KeyMgmt value mismatch");
static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::SAE) ==
+ WPA_KEY_MGMT_SAE,
+ "KeyMgmt value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::SUITE_B_192) ==
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B_192,
+ "KeyMgmt value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::OWE) ==
+ WPA_KEY_MGMT_OWE,
+ "KeyMgmt value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK_SHA256) ==
+ WPA_KEY_MGMT_PSK_SHA256,
+ "KeyMgmt value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP_SHA256) ==
+ WPA_KEY_MGMT_IEEE8021X_SHA256,
+ "KeyMgmt value mismatch");
+static_assert(
static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::WPA) ==
WPA_PROTO_WPA,
"Proto value mismatch");
@@ -374,6 +405,10 @@
WPA_CIPHER_CCMP,
"GroupCipher value mismatch");
static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::GCMP_256) ==
+ WPA_CIPHER_GCMP_256,
+ "GroupCipher value mismatch");
+static_assert(
static_cast<uint32_t>(
ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED) ==
WPA_CIPHER_GTK_NOT_USED,
@@ -390,7 +425,11 @@
static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::CCMP) ==
WPA_CIPHER_CCMP,
"PairwiseCipher value mismatch");
-
+static_assert(
+ static_cast<uint32_t>(
+ ISupplicantStaNetwork::PairwiseCipherMask::GCMP_256) ==
+ WPA_CIPHER_GCMP_256,
+ "PairwiseCipher value mismatch");
static_assert(
static_cast<uint32_t>(ISupplicantStaIfaceCallback::State::DISCONNECTED) ==
WPA_DISCONNECTED,
@@ -679,9 +718,9 @@
P2P_PROV_DISC_INFO_UNAVAILABLE,
"P2P status code value mismatch");
} // namespace implementation
-} // namespace V1_1
-} // namespace wifi
+} // namespace V1_2
} // namespace supplicant
+} // namespace wifi
} // namespace hardware
} // namespace android
#endif // WPA_SUPPLICANT_HIDL_HIDL_MANAGER_H
diff --git a/wpa_supplicant/hidl/1.1/hidl_return_util.h b/wpa_supplicant/hidl/1.2/hidl_return_util.h
similarity index 97%
rename from wpa_supplicant/hidl/1.1/hidl_return_util.h
rename to wpa_supplicant/hidl/1.2/hidl_return_util.h
index dba5f37..238646a 100644
--- a/wpa_supplicant/hidl/1.1/hidl_return_util.h
+++ b/wpa_supplicant/hidl/1.2/hidl_return_util.h
@@ -14,7 +14,7 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
namespace implementation {
namespace hidl_return_util {
@@ -91,9 +91,9 @@
return Void();
}
-} // namespace hidl_util
+} // namespace hidl_return_util
} // namespace implementation
-} // namespace V1_1
+} // namespace V1_2
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.0/iface_config_utils.cpp b/wpa_supplicant/hidl/1.2/iface_config_utils.cpp
similarity index 96%
rename from wpa_supplicant/hidl/1.0/iface_config_utils.cpp
rename to wpa_supplicant/hidl/1.2/iface_config_utils.cpp
index 7dc5a6c..43908e3 100644
--- a/wpa_supplicant/hidl/1.0/iface_config_utils.cpp
+++ b/wpa_supplicant/hidl/1.2/iface_config_utils.cpp
@@ -14,6 +14,9 @@
#include "iface_config_utils.h"
namespace {
+using android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+using android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+
constexpr uint32_t kMaxWpsDeviceNameSize = WPS_DEV_NAME_MAX_LEN;
constexpr uint32_t kMaxWpsManufacturerSize = WPS_MANUFACTURER_MAX_LEN;
constexpr uint32_t kMaxWpsModelNameSize = WPS_MODEL_NAME_MAX_LEN;
@@ -78,7 +81,7 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_0 {
+namespace V1_2 {
namespace implementation {
namespace iface_config_utils {
SupplicantStatus setWpsDeviceName(
@@ -173,8 +176,8 @@
}
} // namespace iface_config_utils
} // namespace implementation
-} // namespace V1_0
-} // namespace wifi
+} // namespace V1_2
} // namespace supplicant
+} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wpa_supplicant/hidl/1.0/iface_config_utils.h b/wpa_supplicant/hidl/1.2/iface_config_utils.h
similarity index 97%
rename from wpa_supplicant/hidl/1.0/iface_config_utils.h
rename to wpa_supplicant/hidl/1.2/iface_config_utils.h
index 789cc38..9e88b3e 100644
--- a/wpa_supplicant/hidl/1.0/iface_config_utils.h
+++ b/wpa_supplicant/hidl/1.2/iface_config_utils.h
@@ -14,7 +14,8 @@
#include <android-base/macros.h>
-extern "C" {
+extern "C"
+{
#include "utils/common.h"
#include "utils/includes.h"
#include "wpa_supplicant_i.h"
@@ -29,7 +30,7 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_0 {
+namespace V1_2 {
namespace implementation {
namespace iface_config_utils {
SupplicantStatus setWpsDeviceName(
@@ -50,9 +51,9 @@
struct wpa_supplicant* wpa_s, bool useExternalSim);
} // namespace iface_config_utils
} // namespace implementation
-} // namespace V1_0
-} // namespace wifi
+} // namespace V1_2
} // namespace supplicant
+} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wpa_supplicant/hidl/1.1/misc_utils.h b/wpa_supplicant/hidl/1.2/misc_utils.h
similarity index 96%
rename from wpa_supplicant/hidl/1.1/misc_utils.h
rename to wpa_supplicant/hidl/1.2/misc_utils.h
index 8b2ae3f..1360e6b 100644
--- a/wpa_supplicant/hidl/1.1/misc_utils.h
+++ b/wpa_supplicant/hidl/1.2/misc_utils.h
@@ -10,7 +10,8 @@
#ifndef MISC_UTILS_H_
#define MISC_UTILS_H_
-extern "C" {
+extern "C"
+{
#include "wpabuf.h"
}
@@ -24,7 +25,7 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
namespace implementation {
namespace misc_utils {
using wpabuf_unique_ptr = std::unique_ptr<wpabuf, void (*)(wpabuf *)>;
@@ -64,7 +65,7 @@
} // namespace misc_utils
} // namespace implementation
-} // namespace V1_1
+} // namespace V1_2
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.0/p2p_iface.cpp b/wpa_supplicant/hidl/1.2/p2p_iface.cpp
similarity index 71%
rename from wpa_supplicant/hidl/1.0/p2p_iface.cpp
rename to wpa_supplicant/hidl/1.2/p2p_iface.cpp
index 7a94a31..7dddee9 100644
--- a/wpa_supplicant/hidl/1.0/p2p_iface.cpp
+++ b/wpa_supplicant/hidl/1.2/p2p_iface.cpp
@@ -13,13 +13,20 @@
#include "iface_config_utils.h"
#include "misc_utils.h"
#include "p2p_iface.h"
+#include "sta_network.h"
-extern "C" {
+extern "C"
+{
#include "ap.h"
#include "wps_supplicant.h"
#include "wifi_display.h"
+#include "utils/eloop.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
}
+#define P2P_MAX_JOIN_SCAN_ATTEMPTS 10
+
namespace {
const char kConfigMethodStrPbc[] = "pbc";
const char kConfigMethodStrDisplay[] = "display";
@@ -28,7 +35,11 @@
constexpr uint8_t kWfdDeviceInfoSubelemId = 0;
constexpr char kWfdDeviceInfoSubelemLenHexStr[] = "0006";
+std::function<void()> pending_join_scan_callback = NULL;
+std::function<void()> pending_scan_res_join_callback = NULL;
+
using android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface;
+using android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
uint8_t convertHidlMiracastModeToInternal(
ISupplicantP2pIface::MiracastMode mode)
{
@@ -42,20 +53,343 @@
};
WPA_ASSERT(false);
}
+
+/**
+ * Check if the provided ssid is valid or not.
+ *
+ * Returns 1 if valid, 0 otherwise.
+ */
+int isSsidValid(const std::vector<uint8_t>& ssid)
+{
+ if (ssid.size() == 0 ||
+ ssid.size() >
+ static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
+ SSID_MAX_LEN_IN_BYTES)) {
+ return 0;
+ }
+ return 1;
+}
+
+/**
+ * Check if the provided psk passhrase is valid or not.
+ *
+ * Returns 1 if valid, 0 otherwise.
+ */
+int isPskPassphraseValid(const std::string &psk)
+{
+ if (psk.size() <
+ static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
+ PSK_PASSPHRASE_MIN_LEN_IN_BYTES) ||
+ psk.size() >
+ static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
+ PSK_PASSPHRASE_MAX_LEN_IN_BYTES)) {
+ return 0;
+ }
+ if (has_ctrl_char((u8 *)psk.c_str(), psk.size())) {
+ return 0;
+ }
+ return 1;
+}
+
+void setBandScanFreqsList(
+ struct wpa_supplicant *wpa_s,
+ enum hostapd_hw_mode band,
+ struct wpa_driver_scan_params *params)
+{
+ /* Include only supported channels for the specified band */
+ struct hostapd_hw_modes *mode;
+ int count, i;
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band);
+ if (mode == NULL) {
+ /* No channels supported in this band. */
+ return;
+ }
+
+ params->freqs = (int *) os_calloc(mode->num_channels + 1, sizeof(int));
+ if (params->freqs == NULL)
+ return;
+ for (count = 0, i = 0; i < mode->num_channels; i++) {
+ if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+ params->freqs[count++] = mode->channels[i].freq;
+ }
+}
+/*
+ * isAnyEtherAddr - match any ether address
+ *
+ */
+int isAnyEtherAddr(const u8 *a)
+{
+ // 02:00:00:00:00:00
+ return (a[0] == 2) && !(a[1] | a[2] | a[3] | a[4] | a[5]);
+}
+
+/**
+ * findBssBySsid - Fetch a BSS table entry based on SSID and optional BSSID.
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID, 02:00:00:00:00:00 matches any bssid
+ * @ssid: SSID
+ * @ssid_len: Length of @ssid
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
+struct wpa_bss* findBssBySsid(
+ struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_bss *bss;
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ if ((isAnyEtherAddr(bssid) ||
+ os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0) &&
+ bss->ssid_len == ssid_len &&
+ os_memcmp(bss->ssid, ssid, ssid_len) == 0)
+ return bss;
+ }
+ return NULL;
+}
+
+struct wpa_ssid* addGroupClientNetwork(
+ struct wpa_supplicant* wpa_s,
+ uint8_t *group_owner_bssid,
+ const std::vector<uint8_t>& ssid,
+ const std::string& passphrase)
+{
+ struct wpa_ssid* wpa_network = wpa_config_add_network(wpa_s->conf);
+ if (!wpa_network) {
+ return NULL;
+ }
+ // set general network defaults
+ wpa_config_set_network_defaults(wpa_network);
+
+ // set P2p network defaults
+ wpa_network->p2p_group = 1;
+ wpa_network->mode = wpa_ssid::wpas_mode::WPAS_MODE_INFRA;
+
+ wpa_network->auth_alg = WPA_AUTH_ALG_OPEN;
+ wpa_network->key_mgmt = WPA_KEY_MGMT_PSK;
+ wpa_network->proto = WPA_PROTO_RSN;
+ wpa_network->pairwise_cipher = WPA_CIPHER_CCMP;
+ wpa_network->group_cipher = WPA_CIPHER_CCMP;
+ wpa_network->disabled = 2;
+
+ // set necessary fields
+ os_memcpy(wpa_network->bssid, group_owner_bssid, ETH_ALEN);
+ wpa_network->bssid_set = 1;
+
+ wpa_network->ssid = (uint8_t *)os_malloc(ssid.size());
+ if (wpa_network->ssid == NULL) {
+ wpa_config_remove_network(wpa_s->conf, wpa_network->id);
+ return NULL;
+ }
+ memcpy(wpa_network->ssid, ssid.data(), ssid.size());
+ wpa_network->ssid_len = ssid.size();
+
+ wpa_network->psk_set = 0;
+ wpa_network->passphrase = dup_binstr(passphrase.c_str(), passphrase.length());
+ if (wpa_network->passphrase == NULL) {
+ wpa_config_remove_network(wpa_s->conf, wpa_network->id);
+ return NULL;
+ }
+ wpa_config_update_psk(wpa_network);
+
+ return wpa_network;
+
+}
+
+void joinScanWrapper(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = (struct wpa_supplicant *) eloop_ctx;
+
+ if (pending_join_scan_callback != NULL) {
+ pending_join_scan_callback();
+ }
+}
+
+void scanResJoinWrapper(
+ struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ if (pending_scan_res_join_callback) {
+ pending_scan_res_join_callback();
+ }
+}
+
+int joinScanReq(
+ struct wpa_supplicant* wpa_s,
+ const std::vector<uint8_t>& ssid,
+ int freq)
+{
+ int ret;
+ struct wpa_driver_scan_params params;
+ struct wpabuf *ies;
+ size_t ielen;
+ unsigned int bands;
+
+ os_memset(¶ms, 0, sizeof(params));
+ if (ssid.size() > 0) {
+ params.ssids[0].ssid = ssid.data();
+ params.ssids[0].ssid_len = ssid.size();
+ } else {
+ params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
+ params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+ }
+ wpa_printf(MSG_DEBUG, "Scan SSID %s for join with frequency %d (reinvoke)",
+ wpa_ssid_txt(params.ssids[0].ssid, params.ssids[0].ssid_len), freq);
+
+ if (freq > 0) {
+ if (freq == 2 || freq == 5) {
+ if (wpa_s->hw.modes != NULL) {
+ switch (freq) {
+ case 2:
+ setBandScanFreqsList(wpa_s,
+ HOSTAPD_MODE_IEEE80211G, ¶ms);
+ break;
+ case 5:
+ setBandScanFreqsList(wpa_s,
+ HOSTAPD_MODE_IEEE80211A, ¶ms);
+ break;
+ }
+ if (!params.freqs) {
+ wpa_printf(MSG_ERROR,
+ "P2P: No supported channels in %dG band.", freq);
+ return -1;
+ }
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Unknown what %dG channels the driver supports.", freq);
+ }
+ } else {
+ if (0 == p2p_supported_freq_cli(wpa_s->global->p2p, freq)) {
+ wpa_printf(MSG_ERROR,
+ "P2P: freq %d is not supported for a client.", freq);
+ return -1;
+ }
+
+ /*
+ * Allocate memory for frequency array, allocate one extra
+ * slot for the zero-terminator.
+ */
+ params.freqs = (int *) os_calloc(2, sizeof(int));
+ if (params.freqs) {
+ params.freqs[0] = freq;
+ } else {
+ wpa_printf(MSG_ERROR,
+ "P2P: Cannot allocate memory for scan params.");
+ return -1;
+ }
+ }
+ }
+
+ ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
+ ies = wpabuf_alloc(ielen);
+ if (ies == NULL) {
+ if (params.freqs) {
+ os_free(params.freqs);
+ }
+ return -1;
+ }
+
+ bands = wpas_get_bands(wpa_s, params.freqs);
+ p2p_scan_ie(wpa_s->global->p2p, ies, NULL, bands);
+
+ params.p2p_probe = 1;
+ params.extra_ies = (u8 *) wpabuf_head(ies);
+ params.extra_ies_len = wpabuf_len(ies);
+ if (wpa_s->clear_driver_scan_cache) {
+ wpa_printf(MSG_DEBUG,
+ "Request driver to clear scan cache due to local BSS flush");
+ params.only_new_results = 1;
+ }
+
+ ret = wpa_drv_scan(wpa_s, ¶ms);
+ if (!ret) {
+ os_get_reltime(&wpa_s->scan_trigger_time);
+ wpa_s->scan_res_handler = scanResJoinWrapper;
+ wpa_s->own_scan_requested = 1;
+ wpa_s->clear_driver_scan_cache = 0;
+ }
+
+ if (params.freqs) {
+ os_free(params.freqs);
+ }
+
+ wpabuf_free(ies);
+
+ return ret;
+}
+
+int joinGroup(
+ struct wpa_supplicant* wpa_s,
+ uint8_t *group_owner_bssid,
+ const std::vector<uint8_t>& ssid,
+ const std::string& passphrase)
+{
+ int ret = 0;
+ int vht = wpa_s->conf->p2p_go_vht;
+ int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
+
+ // Construct a network for adding group.
+ // Group client follows the persistent attribute of Group Owner.
+ // If joined group is persistent, it adds a persistent network on GroupStarted.
+ struct wpa_ssid *wpa_network = addGroupClientNetwork(
+ wpa_s, group_owner_bssid, ssid, passphrase);
+ if (wpa_network == NULL) {
+ wpa_printf(MSG_ERROR, "P2P: Cannot construct a network for group join.");
+ return -1;
+ }
+
+ // this is temporary network only for establishing the connection.
+ wpa_network->temporary = 1;
+
+ if (wpas_p2p_group_add_persistent(
+ wpa_s, wpa_network, 0, 0, 0, 0, ht40, vht,
+ VHT_CHANWIDTH_USE_HT, 0, NULL, 0, 1)) {
+ ret = -1;
+ }
+
+ // Always remove this temporary network at the end.
+ wpa_config_remove_network(wpa_s->conf, wpa_network->id);
+ return ret;
+}
+
+void notifyGroupJoinFailure(
+ struct wpa_supplicant* wpa_s)
+{
+ u8 zero_addr[ETH_ALEN] = {0};
+ std::vector<uint8_t> ssid = {'D', 'I', 'R', 'E','C', 'T', '-'};
+ std::string passphrase = "";
+ struct wpa_ssid *wpa_network = addGroupClientNetwork(
+ wpa_s, zero_addr, ssid, passphrase);
+ if (wpa_network) {
+ wpa_network->temporary = 1;
+ wpas_notify_p2p_group_formation_failure(wpa_s, "Failed to find the group.");
+ wpas_notify_p2p_group_removed(
+ wpa_s, wpa_network, "client");
+ wpa_config_remove_network(
+ wpa_s->conf, wpa_network->id);
+ } else {
+ wpa_printf(MSG_ERROR,
+ "P2P: Cannot construct a network.");
+ }
+}
+
+void scanResJoinIgnore(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) {
+ wpa_printf(MSG_DEBUG, "P2P: Ignore group join scan results.");
+}
+
} // namespace
namespace android {
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_0 {
+namespace V1_2 {
namespace implementation {
using hidl_return_util::validateAndCall;
P2pIface::P2pIface(struct wpa_global* wpa_global, const char ifname[])
: wpa_global_(wpa_global), ifname_(ifname), is_valid_(true)
-{
-}
+{}
void P2pIface::invalidate() { is_valid_ = false; }
bool P2pIface::isValid()
@@ -505,6 +839,24 @@
&P2pIface::saveConfigInternal, _hidl_cb);
}
+Return<void> P2pIface::addGroup_1_2(
+ const hidl_vec<uint8_t>& ssid, const hidl_string& passphrase,
+ bool persistent, uint32_t freq, const hidl_array<uint8_t, 6>& peer_address,
+ bool join, addGroup_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::addGroup_1_2Internal, _hidl_cb,
+ ssid, passphrase, persistent, freq, peer_address, join);
+}
+
+Return<void> P2pIface::setMacRandomization(bool enable, setMacRandomization_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::setMacRandomizationInternal, _hidl_cb, enable);
+}
+
std::pair<SupplicantStatus, std::string> P2pIface::getNameInternal()
{
return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
@@ -656,6 +1008,11 @@
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
}
+ if (wpa_s->scan_res_handler == scanResJoinWrapper) {
+ wpa_printf(MSG_DEBUG, "P2P: Stop pending group scan for stopping find).");
+ pending_scan_res_join_callback = NULL;
+ wpa_s->scan_res_handler = scanResJoinIgnore;
+ }
wpas_p2p_stop_find(wpa_s);
return {SupplicantStatusCode::SUCCESS, ""};
}
@@ -699,11 +1056,12 @@
}
int vht = wpa_s->conf->p2p_go_vht;
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
- const char* pin = pre_selected_pin.length() > 0 ? pre_selected_pin.data() : nullptr;
+ const char* pin =
+ pre_selected_pin.length() > 0 ? pre_selected_pin.data() : nullptr;
int new_pin = wpas_p2p_connect(
- wpa_s, peer_address.data(), pin, wps_method,
- persistent, false, join_existing_group, false, go_intent_signed, 0, 0, -1,
- false, ht40, vht, VHT_CHANWIDTH_USE_HT, nullptr, 0);
+ wpa_s, peer_address.data(), pin, wps_method, persistent, false,
+ join_existing_group, false, go_intent_signed, 0, 0, -1, false, ht40,
+ vht, VHT_CHANWIDTH_USE_HT, 0, nullptr, 0);
if (new_pin < 0) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
@@ -718,6 +1076,11 @@
SupplicantStatus P2pIface::cancelConnectInternal()
{
struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ if (wpa_s->scan_res_handler == scanResJoinWrapper) {
+ wpa_printf(MSG_DEBUG, "P2P: Stop pending group scan for canceling connect");
+ pending_scan_res_join_callback = NULL;
+ wpa_s->scan_res_handler = scanResJoinIgnore;
+ }
if (wpas_p2p_cancel(wpa_s)) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
@@ -761,7 +1124,7 @@
if (ssid == NULL) {
if (wpas_p2p_group_add(
wpa_s, persistent, 0, 0, ht40, vht,
- VHT_CHANWIDTH_USE_HT)) {
+ VHT_CHANWIDTH_USE_HT, 0)) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
} else {
return {SupplicantStatusCode::SUCCESS, ""};
@@ -769,7 +1132,7 @@
} else if (ssid->disabled == 2) {
if (wpas_p2p_group_add_persistent(
wpa_s, ssid, 0, 0, 0, 0, ht40, vht,
- VHT_CHANWIDTH_USE_HT, NULL, 0, 0)) {
+ VHT_CHANWIDTH_USE_HT, 0, NULL, 0, 0)) {
return {SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN,
""};
} else {
@@ -833,7 +1196,7 @@
}
if (wpas_p2p_invite(
wpa_s, peer_address.data(), ssid, NULL, 0, 0, ht40, vht,
- VHT_CHANWIDTH_USE_HT, 0)) {
+ VHT_CHANWIDTH_USE_HT, 0, 0)) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -868,8 +1231,8 @@
DestT* freq_ranges = nullptr;
// Empty ranges is used to enable all frequencies.
if (ranges.size() != 0) {
- freq_ranges =
- static_cast<DestT*>(os_malloc(sizeof(DestT) * ranges.size()));
+ freq_ranges = static_cast<DestT*>(
+ os_malloc(sizeof(DestT) * ranges.size()));
if (!freq_ranges) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
@@ -1047,7 +1410,7 @@
return {SupplicantStatusCode::SUCCESS, ""};
}
#endif /* CONFIG_AP */
- if (wpas_wps_start_pbc(wpa_group_s, bssid_addr, 0)) {
+ if (wpas_wps_start_pbc(wpa_group_s, bssid_addr, 0, 0)) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -1064,7 +1427,7 @@
#ifdef CONFIG_AP
if (wpa_group_s->ap_iface) {
if (wpa_supplicant_ap_wps_pin(
- wpa_group_s, nullptr, pin.c_str(), nullptr, 0, 0) < 0) {
+ wpa_group_s, nullptr, pin.c_str(), nullptr, 0, 0) < 0) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -1256,6 +1619,180 @@
return {SupplicantStatusCode::SUCCESS, ""};
}
+SupplicantStatus P2pIface::addGroup_1_2Internal(
+ const std::vector<uint8_t>& ssid, const std::string& passphrase,
+ bool persistent, uint32_t freq, const std::array<uint8_t, 6>& peer_address,
+ bool joinExistingGroup)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ int vht = wpa_s->conf->p2p_go_vht;
+ int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
+
+ if (!isSsidValid(ssid)) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, "SSID is invalid."};
+ }
+
+ if (!isPskPassphraseValid(passphrase)) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, "passphrase is invalid."};
+ }
+
+ if (!joinExistingGroup) {
+ if (wpa_s->global->p2p == NULL) {
+ return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
+ }
+
+ struct p2p_data *p2p = wpa_s->global->p2p;
+ os_memcpy(p2p->ssid, ssid.data(), ssid.size());
+ p2p->ssid_len = ssid.size();
+ p2p->ssid_set = 1;
+
+ os_memset(p2p->passphrase, 0, sizeof(p2p->passphrase));
+ os_memcpy(p2p->passphrase, passphrase.c_str(), passphrase.length());
+ p2p->passphrase_set = 1;
+
+ if (wpas_p2p_group_add(
+ wpa_s, persistent, freq, 0, ht40, vht,
+ VHT_CHANWIDTH_USE_HT, 0)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+ }
+
+ // The rest is for group join.
+ wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND before group join.");
+ wpas_p2p_stop_find(wpa_s);
+
+ struct wpa_bss *bss = findBssBySsid(
+ wpa_s, peer_address.data(),
+ ssid.data(), ssid.size());
+ if (bss != NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Join group with Group Owner " MACSTR,
+ MAC2STR(bss->bssid));
+ if (0 != joinGroup(wpa_s, bss->bssid, ssid, passphrase)) {
+ // no need to notify group join failure here,
+ // it will be handled by wpas_p2p_group_add_persistent
+ // called in joinGroup.
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, "Failed to join a group."};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+ }
+
+ wpa_printf(MSG_INFO, "No matched BSS exists, try to find it by scan");
+
+ if (pending_scan_res_join_callback != NULL) {
+ wpa_printf(MSG_WARNING, "P2P: Renew scan result callback with new request.");
+ }
+
+ pending_join_scan_callback =
+ [wpa_s, ssid, freq]() {
+ int ret = joinScanReq(wpa_s, ssid, freq);
+ // for BUSY case, the scan might be occupied by WiFi.
+ // Do not give up immediately, but try again later.
+ if (-EBUSY == ret) {
+ // re-schedule this join scan and don't consume retry count.
+ if (pending_scan_res_join_callback) {
+ wpa_s->p2p_join_scan_count--;
+ pending_scan_res_join_callback();
+ }
+ } else if (0 != ret) {
+ notifyGroupJoinFailure(wpa_s);
+ pending_scan_res_join_callback = NULL;
+ }
+ };
+
+ pending_scan_res_join_callback = [wpa_s, ssid, passphrase, peer_address, this]() {
+ if (wpa_s->global->p2p_disabled) {
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: Scan results received for join (reinvoke).");
+
+ struct wpa_bss *bss = findBssBySsid(
+ wpa_s, peer_address.data(), ssid.data(), ssid.size());
+ if (bss) {
+ if (0 != joinGroup(wpa_s, bss->bssid, ssid, passphrase)) {
+ wpa_printf(MSG_ERROR, "P2P: Failed to join a group.");
+ }
+ // no need to notify group join failure here,
+ // it will be handled by wpas_p2p_group_add_persistent
+ // called in joinGroup.
+ pending_scan_res_join_callback = NULL;
+ return;
+ }
+
+ wpa_s->p2p_join_scan_count++;
+ wpa_printf(MSG_DEBUG, "P2P: Join scan attempt %d.", wpa_s->p2p_join_scan_count);
+ eloop_cancel_timeout(joinScanWrapper, wpa_s, NULL);
+ if (wpa_s->p2p_join_scan_count <= P2P_MAX_JOIN_SCAN_ATTEMPTS) {
+ wpa_printf(MSG_DEBUG, "P2P: Try join again later.");
+ eloop_register_timeout(1, 0, joinScanWrapper, wpa_s, this);
+ return;
+ }
+
+ wpa_printf(MSG_ERROR, "P2P: Failed to find the group with "
+ "network name %s - stop join attempt",
+ ssid.data());
+ notifyGroupJoinFailure(wpa_s);
+ pending_scan_res_join_callback = NULL;
+ };
+
+ wpa_s->p2p_join_scan_count = 0;
+ pending_join_scan_callback();
+ if (pending_scan_res_join_callback == NULL) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, "Failed to start scan."};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::setMacRandomizationInternal(bool enable)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ bool currentEnabledState = !!wpa_s->conf->p2p_device_random_mac_addr;
+ u8 *addr = NULL;
+
+ // The same state, no change is needed.
+ if (currentEnabledState == enable) {
+ wpa_printf(MSG_DEBUG, "The random MAC is %s already.",
+ (enable) ? "enabled" : "disabled");
+ return {SupplicantStatusCode::SUCCESS, ""};
+ }
+
+ if (enable) {
+ wpa_s->conf->p2p_device_random_mac_addr = 1;
+ wpa_s->conf->p2p_interface_random_mac_addr = 1;
+
+ // restore config if it failed to set up MAC address.
+ if (wpas_p2p_mac_setup(wpa_s) < 0) {
+ wpa_s->conf->p2p_device_random_mac_addr = 0;
+ wpa_s->conf->p2p_interface_random_mac_addr = 0;
+ return {SupplicantStatusCode::FAILURE_UNKNOWN,
+ "Failed to set up MAC address."};
+ }
+ } else {
+ // disable random MAC will use original MAC address
+ // regardless of any saved persistent groups.
+ if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
+ wpa_printf(MSG_ERROR, "Failed to restore MAC address");
+ return {SupplicantStatusCode::FAILURE_UNKNOWN,
+ "Failed to restore MAC address."};
+ }
+
+ if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
+ wpa_printf(MSG_INFO, "Could not update MAC address information");
+ return {SupplicantStatusCode::FAILURE_UNKNOWN,
+ "Failed to update MAC address."};
+ }
+ wpa_s->conf->p2p_device_random_mac_addr = 0;
+ wpa_s->conf->p2p_interface_random_mac_addr = 0;
+ }
+
+ // update internal data to send out correct device address in action frame.
+ os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
+ os_memcpy(wpa_s->global->p2p->cfg->dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
+
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
/**
* Retrieve the underlying |wpa_supplicant| struct
* pointer for this iface.
@@ -1277,8 +1814,8 @@
}
} // namespace implementation
-} // namespace V1_0
-} // namespace wifi
+} // namespace V1_2
} // namespace supplicant
+} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wpa_supplicant/hidl/1.0/p2p_iface.h b/wpa_supplicant/hidl/1.2/p2p_iface.h
similarity index 93%
rename from wpa_supplicant/hidl/1.0/p2p_iface.h
rename to wpa_supplicant/hidl/1.2/p2p_iface.h
index 4f4a79d..bd43a5a 100644
--- a/wpa_supplicant/hidl/1.0/p2p_iface.h
+++ b/wpa_supplicant/hidl/1.2/p2p_iface.h
@@ -15,11 +15,12 @@
#include <android-base/macros.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIface.h>
+#include <android/hardware/wifi/supplicant/1.2/ISupplicantP2pIface.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIfaceCallback.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetwork.h>
-extern "C" {
+extern "C"
+{
#include "utils/common.h"
#include "utils/includes.h"
#include "p2p/p2p.h"
@@ -33,16 +34,17 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_0 {
+namespace V1_2 {
namespace implementation {
+using namespace android::hardware::wifi::supplicant::V1_0;
+using namespace android::hardware::wifi::supplicant::V1_1;
/**
* Implementation of P2pIface hidl object. Each unique hidl
* object is used for control operations on a specific interface
* controlled by wpa_supplicant.
*/
-class P2pIface
- : public android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface
+class P2pIface : public V1_2::ISupplicantP2pIface
{
public:
P2pIface(struct wpa_global* wpa_global, const char ifname[]);
@@ -185,6 +187,12 @@
const hidl_vec<uint8_t>& select,
reportNfcHandoverInitiation_cb _hidl_cb) override;
Return<void> saveConfig(saveConfig_cb _hidl_cb) override;
+ Return<void> addGroup_1_2(
+ const hidl_vec<uint8_t>& ssid, const hidl_string& passphrase,
+ bool persistent, uint32_t freq, const hidl_array<uint8_t, 6>& peer_address,
+ bool joinExistingGroup, addGroup_1_2_cb _hidl_cb) override;
+ Return<void> setMacRandomization(
+ bool enable, setMacRandomization_cb _hidl_cb) override;
private:
// Corresponding worker functions for the HIDL methods.
@@ -289,6 +297,11 @@
SupplicantStatus reportNfcHandoverInitiationInternal(
const std::vector<uint8_t>& select);
SupplicantStatus saveConfigInternal();
+ SupplicantStatus addGroup_1_2Internal(
+ const std::vector<uint8_t>& ssid, const std::string& passphrase,
+ bool persistent, uint32_t freq, const std::array<uint8_t, 6>& peer_address,
+ bool joinExistingGroup);
+ SupplicantStatus setMacRandomizationInternal(bool enable);
struct wpa_supplicant* retrieveIfacePtr();
struct wpa_supplicant* retrieveGroupIfacePtr(
@@ -305,9 +318,9 @@
};
} // namespace implementation
-} // namespace V1_0
-} // namespace wifi
+} // namespace V1_2
} // namespace supplicant
+} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wpa_supplicant/hidl/1.0/p2p_network.cpp b/wpa_supplicant/hidl/1.2/p2p_network.cpp
similarity index 97%
rename from wpa_supplicant/hidl/1.0/p2p_network.cpp
rename to wpa_supplicant/hidl/1.2/p2p_network.cpp
index 7daa453..693b2c0 100644
--- a/wpa_supplicant/hidl/1.0/p2p_network.cpp
+++ b/wpa_supplicant/hidl/1.2/p2p_network.cpp
@@ -11,7 +11,8 @@
#include "hidl_return_util.h"
#include "p2p_network.h"
-extern "C" {
+extern "C"
+{
#include "config_ssid.h"
}
@@ -19,7 +20,7 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_0 {
+namespace V1_2 {
namespace implementation {
using hidl_return_util::validateAndCall;
@@ -29,8 +30,7 @@
ifname_(ifname),
network_id_(network_id),
is_valid_(true)
-{
-}
+{}
void P2pNetwork::invalidate() { is_valid_ = false; }
bool P2pNetwork::isValid()
@@ -137,9 +137,8 @@
const sp<ISupplicantP2pNetworkCallback> &callback)
{
HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager ||
- hidl_manager->addP2pNetworkCallbackHidlObject(
- ifname_, network_id_, callback)) {
+ if (!hidl_manager || hidl_manager->addP2pNetworkCallbackHidlObject(
+ ifname_, network_id_, callback)) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -250,8 +249,8 @@
(struct wpa_global *)wpa_global_, ifname_.c_str());
}
} // namespace implementation
-} // namespace V1_0
-} // namespace wifi
+} // namespace V1_2
} // namespace supplicant
+} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wpa_supplicant/hidl/1.1/p2p_network.h b/wpa_supplicant/hidl/1.2/p2p_network.h
similarity index 96%
rename from wpa_supplicant/hidl/1.1/p2p_network.h
rename to wpa_supplicant/hidl/1.2/p2p_network.h
index 3c36f6d..e2e8ec2 100644
--- a/wpa_supplicant/hidl/1.1/p2p_network.h
+++ b/wpa_supplicant/hidl/1.2/p2p_network.h
@@ -15,7 +15,8 @@
#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetwork.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetworkCallback.h>
-extern "C" {
+extern "C"
+{
#include "utils/common.h"
#include "utils/includes.h"
#include "wpa_supplicant_i.h"
@@ -25,9 +26,10 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
namespace implementation {
using namespace android::hardware::wifi::supplicant::V1_0;
+using namespace android::hardware::wifi::supplicant::V1_1;
/**
* Implementation of P2pNetwork hidl object. Each unique hidl
@@ -94,9 +96,9 @@
};
} // namespace implementation
-} // namespace V1_1
-} // namespace wifi
+} // namespace V1_2
} // namespace supplicant
+} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wpa_supplicant/hidl/1.1/sta_iface.cpp b/wpa_supplicant/hidl/1.2/sta_iface.cpp
similarity index 78%
rename from wpa_supplicant/hidl/1.1/sta_iface.cpp
rename to wpa_supplicant/hidl/1.2/sta_iface.cpp
index 6436745..1ca440e 100644
--- a/wpa_supplicant/hidl/1.1/sta_iface.cpp
+++ b/wpa_supplicant/hidl/1.2/sta_iface.cpp
@@ -13,19 +13,22 @@
#include "misc_utils.h"
#include "sta_iface.h"
-extern "C" {
+extern "C"
+{
#include "utils/eloop.h"
#include "gas_query.h"
#include "interworking.h"
#include "hs20_supplicant.h"
#include "wps_supplicant.h"
+#include "dpp_supplicant.h"
+#include "dpp.h"
}
namespace {
-using android::hardware::wifi::supplicant::V1_1::ISupplicantStaIface;
using android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
using android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
-using android::hardware::wifi::supplicant::V1_1::implementation::HidlManager;
+using android::hardware::wifi::supplicant::V1_2::ISupplicantStaIface;
+using android::hardware::wifi::supplicant::V1_2::implementation::HidlManager;
constexpr uint32_t kMaxAnqpElems = 100;
constexpr char kGetMacAddress[] = "MACADDR";
@@ -155,7 +158,7 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
namespace implementation {
using hidl_return_util::validateAndCall;
@@ -165,8 +168,7 @@
StaIface::StaIface(struct wpa_global *wpa_global, const char ifname[])
: wpa_global_(wpa_global), ifname_(ifname), is_valid_(true)
-{
-}
+{}
void StaIface::invalidate() { is_valid_ = false; }
bool StaIface::isValid()
@@ -219,8 +221,8 @@
}
Return<void> StaIface::registerCallback(
- const sp<ISupplicantStaIfaceCallback>
- & callback, registerCallback_cb _hidl_cb)
+ const sp<ISupplicantStaIfaceCallback> &callback,
+ registerCallback_cb _hidl_cb)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
@@ -231,12 +233,22 @@
const sp<V1_1::ISupplicantStaIfaceCallback> &callback,
registerCallback_cb _hidl_cb)
{
- sp<V1_0::ISupplicantStaIfaceCallback> callback_1_0 = callback;
+ sp<V1_0::ISupplicantStaIfaceCallback> callback_1_0 = callback;
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::registerCallbackInternal, _hidl_cb, callback_1_0);
}
+Return<void> StaIface::registerCallback_1_2(
+ const sp<V1_2::ISupplicantStaIfaceCallback> &callback,
+ registerCallback_cb _hidl_cb)
+{
+ sp<V1_1::ISupplicantStaIfaceCallback> callback_1_1 = callback;
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::registerCallbackInternal, _hidl_cb, callback_1_1);
+}
+
Return<void> StaIface::reassociate(reassociate_cb _hidl_cb)
{
return validateAndCall(
@@ -511,6 +523,58 @@
&StaIface::enableAutoReconnectInternal, _hidl_cb, enable);
}
+Return<void> StaIface::getKeyMgmtCapabilities(
+ getKeyMgmtCapabilities_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaIface::getKeyMgmtCapabilitiesInternal, _hidl_cb);
+}
+
+Return<void> StaIface::addDppPeerUri(const hidl_string& uri,
+ addDppPeerUri_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaIface::addDppPeerUriInternal, _hidl_cb, uri);
+}
+
+Return<void> StaIface::removeDppUri(uint32_t bootstrap_id,
+ removeDppUri_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaIface::removeDppUriInternal, _hidl_cb, bootstrap_id);
+}
+
+Return<void> StaIface::startDppConfiguratorInitiator(uint32_t peer_bootstrap_id,
+ uint32_t own_bootstrap_id, const hidl_string& ssid,
+ const hidl_string& password, const hidl_string& psk,
+ DppNetRole net_role, DppAkm security_akm,
+ startDppConfiguratorInitiator_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaIface::startDppConfiguratorInitiatorInternal, _hidl_cb, peer_bootstrap_id,
+ own_bootstrap_id, ssid, password, psk, net_role, security_akm);
+}
+
+Return<void> StaIface::startDppEnrolleeInitiator(uint32_t peer_bootstrap_id,
+ uint32_t own_bootstrap_id, startDppConfiguratorInitiator_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaIface::startDppEnrolleeInitiatorInternal, _hidl_cb, peer_bootstrap_id,
+ own_bootstrap_id);
+}
+
+Return<void> StaIface::stopDppInitiator(stopDppInitiator_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaIface::stopDppInitiatorInternal, _hidl_cb);
+}
+
std::pair<SupplicantStatus, std::string> StaIface::getNameInternal()
{
return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
@@ -861,7 +925,7 @@
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
const uint8_t *bssid_addr =
is_zero_ether_addr(bssid.data()) ? nullptr : bssid.data();
- if (wpas_wps_start_pbc(wpa_s, bssid_addr, 0)) {
+ if (wpas_wps_start_pbc(wpa_s, bssid_addr, 0, 0)) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -1016,6 +1080,225 @@
return {SupplicantStatusCode::SUCCESS, ""};
}
+std::pair<SupplicantStatus, uint32_t>
+StaIface::getKeyMgmtCapabilitiesInternal()
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ struct wpa_driver_capa capa;
+ uint32_t mask = 0;
+
+ /* Get capabilities from driver and populate the key management mask */
+ if (wpa_drv_get_capa(wpa_s, &capa) < 0) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, mask};
+ }
+
+ /* Logic from ctrl_iface.c, NONE and IEEE8021X have no capability
+ * flags and always enabled.
+ */
+ mask |=
+ (ISupplicantStaNetwork::KeyMgmtMask::NONE |
+ ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X);
+
+ if (capa.key_mgmt &
+ (WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
+ mask |= ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP;
+ }
+
+ if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+ mask |= ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK;
+ }
+#ifdef CONFIG_SUITEB192
+ if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) {
+ mask |= ISupplicantStaNetwork::KeyMgmtMask::SUITE_B_192;
+ }
+#endif /* CONFIG_SUITEB192 */
+#ifdef CONFIG_OWE
+ if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE) {
+ mask |= ISupplicantStaNetwork::KeyMgmtMask::OWE;
+ }
+#endif /* CONFIG_OWE */
+#ifdef CONFIG_SAE
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) {
+ mask |= ISupplicantStaNetwork::KeyMgmtMask::SAE;
+ }
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_DPP
+ if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_DPP) {
+ mask |= ISupplicantStaNetwork::KeyMgmtMask::DPP;
+ }
+#endif
+ return {{SupplicantStatusCode::SUCCESS, ""}, mask};
+}
+
+std::pair<SupplicantStatus, uint32_t>
+StaIface::addDppPeerUriInternal(const std::string& uri)
+{
+#ifdef CONFIG_DPP
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ int32_t id;
+
+ id = wpas_dpp_qr_code(wpa_s, uri.c_str());
+
+ if (id > 0) {
+ return {{SupplicantStatusCode::SUCCESS, ""}, id};
+ }
+#endif
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, -1};
+}
+
+SupplicantStatus StaIface::removeDppUriInternal(uint32_t bootstrap_id)
+{
+#ifdef CONFIG_DPP
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ std::string bootstrap_id_str;
+
+ if (bootstrap_id == 0) {
+ bootstrap_id_str = "*";
+ }
+ else {
+ bootstrap_id_str = std::to_string(bootstrap_id);
+ }
+
+ if (dpp_bootstrap_remove(wpa_s->dpp, bootstrap_id_str.c_str()) >= 0) {
+ return {SupplicantStatusCode::SUCCESS, ""};
+ }
+#endif
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+}
+
+SupplicantStatus StaIface::startDppConfiguratorInitiatorInternal(
+ uint32_t peer_bootstrap_id, uint32_t own_bootstrap_id,
+ const std::string& ssid, const std::string& password,
+ const std::string& psk, DppNetRole net_role, DppAkm security_akm)
+{
+#ifdef CONFIG_DPP
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ std::string cmd = "";
+
+ if (net_role != DppNetRole::AP &&
+ net_role != DppNetRole::STA) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Error: Invalid network role specified: %d", net_role);
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+
+ cmd += " peer=" + std::to_string(peer_bootstrap_id);
+ cmd += (own_bootstrap_id > 0) ?
+ " own=" + std::to_string(own_bootstrap_id) : "";
+
+ /* Check for supported AKMs */
+ if (security_akm != DppAkm::PSK && security_akm != DppAkm::SAE &&
+ security_akm != DppAkm::PSK_SAE) {
+ wpa_printf(MSG_ERROR, "DPP: Error: invalid AKM specified: %d",
+ security_akm);
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+
+ /* SAE AKM requires SSID and password to be initialized */
+ if ((security_akm == DppAkm::SAE ||
+ security_akm == DppAkm::PSK_SAE) &&
+ (ssid.empty() || password.empty())) {
+ wpa_printf(MSG_ERROR, "DPP: Error: Password or SSID not specified");
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ } else if (security_akm == DppAkm::PSK ||
+ security_akm == DppAkm::PSK_SAE) {
+ /* PSK AKM requires SSID and password/psk to be initialized */
+ if (ssid.empty()) {
+ wpa_printf(MSG_ERROR, "DPP: Error: SSID not specified");
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ if (password.empty() && psk.empty()) {
+ wpa_printf(MSG_ERROR, "DPP: Error: Password or PSK not specified");
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ }
+
+ cmd += " role=configurator";
+ cmd += (ssid.empty()) ? "" : " ssid=" + ssid;
+
+ if (!psk.empty()) {
+ cmd += " psk=" + psk;
+ } else {
+ cmd += (password.empty()) ? "" : " pass=" + password;
+ }
+
+ std::string role = "";
+ if (net_role == DppNetRole::AP) {
+ role = "ap-";
+ }
+ else {
+ role = "sta-";
+ }
+
+ switch (security_akm) {
+ case DppAkm::PSK:
+ role += "psk";
+ break;
+
+ case DppAkm::SAE:
+ role += "sae";
+ break;
+
+ case DppAkm::PSK_SAE:
+ role += "psk-sae";
+ break;
+
+ default:
+ wpa_printf(MSG_ERROR,
+ "DPP: Invalid or unsupported security AKM specified: %d", security_akm);
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+
+ cmd += " conf=";
+ cmd += role;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP initiator command: %s", cmd.c_str());
+
+ if (wpas_dpp_auth_init(wpa_s, cmd.c_str()) == 0) {
+ return {SupplicantStatusCode::SUCCESS, ""};
+ }
+#endif
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+}
+
+SupplicantStatus StaIface::startDppEnrolleeInitiatorInternal(uint32_t peer_bootstrap_id,
+ uint32_t own_bootstrap_id) {
+#ifdef CONFIG_DPP
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ std::string cmd = "";
+
+ /* Report received configuration to HIDL and create an internal profile */
+ wpa_s->conf->dpp_config_processing = 1;
+
+ cmd += " peer=" + std::to_string(peer_bootstrap_id);
+ cmd += (own_bootstrap_id > 0) ?
+ " own=" + std::to_string(own_bootstrap_id) : "";
+
+ cmd += " role=enrollee";
+
+ wpa_printf(MSG_DEBUG,
+ "DPP initiator command: %s", cmd.c_str());
+
+ if (wpas_dpp_auth_init(wpa_s, cmd.c_str()) == 0) {
+ return {SupplicantStatusCode::SUCCESS, ""};
+ }
+#endif
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+}
+SupplicantStatus StaIface::stopDppInitiatorInternal()
+{
+#ifdef CONFIG_DPP
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+
+ wpas_dpp_stop(wpa_s);
+ return {SupplicantStatusCode::SUCCESS, ""};
+#else
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+#endif
+}
+
/**
* Retrieve the underlying |wpa_supplicant| struct
* pointer for this iface.
@@ -1027,8 +1310,8 @@
return wpa_supplicant_get_iface(wpa_global_, ifname_.c_str());
}
} // namespace implementation
-} // namespace V1_1
-} // namespace wifi
+} // namespace V1_2
} // namespace supplicant
+} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wpa_supplicant/hidl/1.1/sta_iface.h b/wpa_supplicant/hidl/1.2/sta_iface.h
similarity index 81%
rename from wpa_supplicant/hidl/1.1/sta_iface.h
rename to wpa_supplicant/hidl/1.2/sta_iface.h
index 1f1e64b..5a04ee3 100644
--- a/wpa_supplicant/hidl/1.1/sta_iface.h
+++ b/wpa_supplicant/hidl/1.2/sta_iface.h
@@ -15,11 +15,12 @@
#include <android-base/macros.h>
-#include <android/hardware/wifi/supplicant/1.1/ISupplicantStaIface.h>
-#include <android/hardware/wifi/supplicant/1.1/ISupplicantStaIfaceCallback.h>
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetwork.h>
+#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIfaceCallback.h>
+#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaNetwork.h>
-extern "C" {
+extern "C"
+{
#include "utils/common.h"
#include "utils/includes.h"
#include "wpa_supplicant_i.h"
@@ -32,16 +33,16 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
namespace implementation {
-using namespace android::hardware::wifi::supplicant::V1_0;
+using namespace android::hardware::wifi::supplicant::V1_2;
/**
* Implementation of StaIface hidl object. Each unique hidl
* object is used for control operations on a specific interface
* controlled by wpa_supplicant.
*/
-class StaIface : public ISupplicantStaIface
+class StaIface : public V1_2::ISupplicantStaIface
{
public:
StaIface(struct wpa_global* wpa_global, const char ifname[]);
@@ -71,10 +72,13 @@
SupplicantNetworkId id, getNetwork_cb _hidl_cb) override;
Return<void> listNetworks(listNetworks_cb _hidl_cb) override;
Return<void> registerCallback(
- const sp<android::hardware::wifi::supplicant::V1_0::ISupplicantStaIfaceCallback>
- & callback, registerCallback_cb _hidl_cb) override;
+ const sp<V1_0::ISupplicantStaIfaceCallback>& callback,
+ registerCallback_cb _hidl_cb) override;
Return<void> registerCallback_1_1(
- const sp<ISupplicantStaIfaceCallback>& callback,
+ const sp<V1_1::ISupplicantStaIfaceCallback>& callback,
+ registerCallback_cb _hidl_cb) override;
+ Return<void> registerCallback_1_2(
+ const sp<V1_2::ISupplicantStaIfaceCallback>& callback,
registerCallback_cb _hidl_cb) override;
Return<void> reassociate(reassociate_cb _hidl_cb) override;
Return<void> reconnect(reconnect_cb _hidl_cb) override;
@@ -158,6 +162,21 @@
uint32_t id, removeExtRadioWork_cb _hidl_cb) override;
Return<void> enableAutoReconnect(
bool enable, enableAutoReconnect_cb _hidl_cb) override;
+ Return<void> getKeyMgmtCapabilities(
+ getKeyMgmtCapabilities_cb _hidl_cb) override;
+ Return<void> addDppPeerUri(const hidl_string& uri,
+ addDppPeerUri_cb _hidl_cb) override;
+ Return<void> removeDppUri(uint32_t bootstrap_id,
+ removeDppUri_cb _hidl_cb) override;
+ Return<void> startDppConfiguratorInitiator(uint32_t peer_bootstrap_id,
+ uint32_t own_bootstrap_id, const hidl_string& ssid,
+ const hidl_string& password, const hidl_string& psk,
+ DppNetRole net_role, DppAkm security_akm,
+ startDppConfiguratorInitiator_cb _hidl_cb) override;
+ Return<void> startDppEnrolleeInitiator(uint32_t peer_bootstrap_id,
+ uint32_t own_bootstrap_id,
+ startDppConfiguratorInitiator_cb _hidl_cb) override;
+ Return<void> stopDppInitiator(stopDppInitiator_cb _hidl_cb) override;
private:
// Corresponding worker functions for the HIDL methods.
@@ -171,10 +190,9 @@
std::pair<SupplicantStatus, std::vector<SupplicantNetworkId>>
listNetworksInternal();
SupplicantStatus registerCallbackInternal(
- const sp<android::hardware::wifi::supplicant::V1_0::ISupplicantStaIfaceCallback>
- & callback);
+ const sp<V1_0::ISupplicantStaIfaceCallback>& callback);
SupplicantStatus registerCallbackInternal_1_1(
- const sp<ISupplicantStaIfaceCallback>& callback);
+ const sp<V1_1::ISupplicantStaIfaceCallback>& callback);
SupplicantStatus reassociateInternal();
SupplicantStatus reconnectInternal();
SupplicantStatus disconnectInternal();
@@ -232,6 +250,17 @@
uint32_t timeout_in_sec);
SupplicantStatus removeExtRadioWorkInternal(uint32_t id);
SupplicantStatus enableAutoReconnectInternal(bool enable);
+ std::pair<SupplicantStatus, uint32_t> getKeyMgmtCapabilitiesInternal();
+ std::pair<SupplicantStatus, uint32_t> addDppPeerUriInternal(const std::string& uri);
+ SupplicantStatus removeDppUriInternal(uint32_t bootstrap_id);
+ SupplicantStatus startDppConfiguratorInitiatorInternal(uint32_t peer_bootstrap_id,
+ uint32_t own_bootstrap_id,
+ const std::string& ssid, const std::string& password,
+ const std::string& psk, DppNetRole net_role, DppAkm security_akm);
+ SupplicantStatus startDppEnrolleeInitiatorInternal(uint32_t peer_bootstrap_id,
+ uint32_t own_bootstrap_id);
+ SupplicantStatus stopDppInitiatorInternal();
+
struct wpa_supplicant* retrieveIfacePtr();
@@ -246,9 +275,9 @@
};
} // namespace implementation
-} // namespace V1_1
-} // namespace wifi
+} // namespace V1_2
} // namespace supplicant
+} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wpa_supplicant/hidl/1.1/sta_network.cpp b/wpa_supplicant/hidl/1.2/sta_network.cpp
similarity index 85%
rename from wpa_supplicant/hidl/1.1/sta_network.cpp
rename to wpa_supplicant/hidl/1.2/sta_network.cpp
index 9d4cc91..9f4e9d2 100644
--- a/wpa_supplicant/hidl/1.1/sta_network.cpp
+++ b/wpa_supplicant/hidl/1.2/sta_network.cpp
@@ -12,13 +12,15 @@
#include "misc_utils.h"
#include "sta_network.h"
-extern "C" {
+extern "C"
+{
#include "wps_supplicant.h"
}
namespace {
-using android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
using android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+using android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork;
+using namespace android::hardware::wifi::supplicant::V1_2;
constexpr uint8_t kZeroBssid[6] = {0, 0, 0, 0, 0, 0};
@@ -29,7 +31,12 @@
static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X) |
static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::FT_EAP) |
static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::FT_PSK) |
- static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::OSEN));
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::OSEN) |
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::SAE) |
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::SUITE_B_192) |
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::OWE) |
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK_SHA256) |
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP_SHA256));
constexpr uint32_t kAllowedProtoMask =
(static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::WPA) |
static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::RSN) |
@@ -44,11 +51,21 @@
static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::TKIP) |
static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::CCMP) |
static_cast<uint32_t>(
- ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED));
+ ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED) |
+ static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::GCMP_256));
constexpr uint32_t kAllowedPairwisewCipherMask =
(static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::NONE) |
static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::TKIP) |
- static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::CCMP));
+ static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::CCMP) |
+ static_cast<uint32_t>(
+ ISupplicantStaNetwork::PairwiseCipherMask::GCMP_256));
+constexpr uint32_t kAllowedGroupMgmtCipherMask =
+ (static_cast<uint32_t>(
+ ISupplicantStaNetwork::GroupMgmtCipherMask::BIP_GMAC_128) |
+ static_cast<uint32_t>(
+ ISupplicantStaNetwork::GroupMgmtCipherMask::BIP_GMAC_256) |
+ static_cast<uint32_t>(
+ ISupplicantStaNetwork::GroupMgmtCipherMask::BIP_CMAC_256));
constexpr uint32_t kEapMethodMax =
static_cast<uint32_t>(ISupplicantStaNetwork::EapMethod::WFA_UNAUTH_TLS) + 1;
@@ -72,7 +89,7 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
namespace implementation {
using hidl_return_util::validateAndCall;
@@ -82,8 +99,7 @@
ifname_(ifname),
network_id_(network_id),
is_valid_(true)
-{
-}
+{}
void StaNetwork::invalidate() { is_valid_ = false; }
bool StaNetwork::isValid()
@@ -250,11 +266,13 @@
}
Return<void> StaNetwork::setEapEncryptedImsiIdentity(
- const EapSimEncryptedIdentity &identity, setEapEncryptedImsiIdentity_cb _hidl_cb)
+ const EapSimEncryptedIdentity &identity,
+ setEapEncryptedImsiIdentity_cb _hidl_cb)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
- &StaNetwork::setEapEncryptedImsiIdentityInternal, _hidl_cb, identity);
+ &StaNetwork::setEapEncryptedImsiIdentityInternal, _hidl_cb,
+ identity);
}
Return<void> StaNetwork::setEapAnonymousIdentity(
@@ -438,6 +456,20 @@
&StaNetwork::getPskInternal, _hidl_cb);
}
+Return<void> StaNetwork::getSaePassword(getSaePassword_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getSaePasswordInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getSaePasswordId(getSaePasswordId_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getSaePasswordIdInternal, _hidl_cb);
+}
+
Return<void> StaNetwork::getWepKey(uint32_t key_idx, getWepKey_cb _hidl_cb)
{
return validateAndCall(
@@ -664,6 +696,101 @@
identity, encrypted_imsi_identity);
}
+Return<void> StaNetwork::setKeyMgmt_1_2(
+ uint32_t key_mgmt_mask, setKeyMgmt_1_2_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setKeyMgmtInternal, _hidl_cb, key_mgmt_mask);
+}
+
+Return<void> StaNetwork::setGroupCipher_1_2(
+ uint32_t group_cipher_mask, setGroupCipher_1_2_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setGroupCipherInternal, _hidl_cb, group_cipher_mask);
+}
+
+Return<void> StaNetwork::setGroupMgmtCipher(
+ uint32_t group_mgmt_cipher_mask, setGroupMgmtCipher_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setGroupMgmtCipherInternal,
+ _hidl_cb, group_mgmt_cipher_mask);
+}
+
+Return<void> StaNetwork::getGroupMgmtCipher(getGroupMgmtCipher_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getGroupMgmtCipherInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::setPairwiseCipher_1_2(
+ uint32_t pairwise_cipher_mask, setPairwiseCipher_1_2_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setPairwiseCipherInternal, _hidl_cb,
+ pairwise_cipher_mask);
+}
+
+Return<void> StaNetwork::getKeyMgmt_1_2(getKeyMgmt_1_2_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getKeyMgmtInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getGroupCipher_1_2(getGroupCipher_1_2_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getGroupCipherInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getPairwiseCipher_1_2(
+ getPairwiseCipher_1_2_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getPairwiseCipherInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::enableTlsSuiteBEapPhase1Param(
+ bool enable, enableTlsSuiteBEapPhase1Param_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::enableTlsSuiteBEapPhase1ParamInternal, _hidl_cb, enable);
+}
+
+Return<void> StaNetwork::enableSuiteBEapOpenSslCiphers(
+ enableSuiteBEapOpenSslCiphers_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::enableSuiteBEapOpenSslCiphersInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::setSaePassword(
+ const hidl_string &sae_password, setSaePassword_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setSaePasswordInternal, _hidl_cb, sae_password);
+}
+
+Return<void> StaNetwork::setSaePasswordId(
+ const hidl_string &sae_password_id, setSaePasswordId_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setSaePasswordIdInternal, _hidl_cb, sae_password_id);
+}
+
std::pair<SupplicantStatus, uint32_t> StaNetwork::getIdInternal()
{
return {{SupplicantStatusCode::SUCCESS, ""}, network_id_};
@@ -683,9 +810,8 @@
const sp<ISupplicantStaNetworkCallback> &callback)
{
HidlManager *hidl_manager = HidlManager::getInstance();
- if (!hidl_manager ||
- hidl_manager->addStaNetworkCallbackHidlObject(
- ifname_, network_id_, callback)) {
+ if (!hidl_manager || hidl_manager->addStaNetworkCallbackHidlObject(
+ ifname_, network_id_, callback)) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -749,6 +875,7 @@
if (key_mgmt_mask & ~kAllowedKeyMgmtMask) {
return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
}
+ setFastTransitionKeyMgmt(key_mgmt_mask);
wpa_ssid->key_mgmt = key_mgmt_mask;
wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", wpa_ssid->key_mgmt);
resetInternalStateAfterParamsUpdate();
@@ -989,13 +1116,14 @@
if (setByteArrayFieldAndResetState(
identity.data(), identity.size(), &(wpa_ssid->eap.identity),
&(wpa_ssid->eap.identity_len), "eap identity")) {
- return { SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
// plain IMSI identity
if (setByteArrayFieldAndResetState(
- identity.data(), identity.size(), &(wpa_ssid->eap.imsi_identity),
+ identity.data(), identity.size(),
+ &(wpa_ssid->eap.imsi_identity),
&(wpa_ssid->eap.imsi_identity_len), "eap imsi identity")) {
- return { SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
}
@@ -1193,8 +1321,10 @@
std::pair<SupplicantStatus, uint32_t> StaNetwork::getKeyMgmtInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""},
- wpa_ssid->key_mgmt & kAllowedKeyMgmtMask};
+ uint32_t key_mgmt_mask = wpa_ssid->key_mgmt & kAllowedKeyMgmtMask;
+
+ resetFastTransitionKeyMgmt(key_mgmt_mask);
+ return {{SupplicantStatusCode::SUCCESS, ""}, key_mgmt_mask};
}
std::pair<SupplicantStatus, uint32_t> StaNetwork::getProtoInternal()
@@ -1247,6 +1377,24 @@
return {{SupplicantStatusCode::SUCCESS, ""}, psk};
}
+std::pair<SupplicantStatus, std::string> StaNetwork::getSaePasswordInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (!wpa_ssid->sae_password) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->sae_password};
+}
+
+std::pair<SupplicantStatus, std::string> StaNetwork::getSaePasswordIdInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (!wpa_ssid->sae_password_id) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->sae_password_id};
+}
+
std::pair<SupplicantStatus, std::vector<uint8_t>> StaNetwork::getWepKeyInternal(
uint32_t key_idx)
{
@@ -1681,13 +1829,16 @@
}
SupplicantStatus StaNetwork::sendNetworkEapIdentityResponseInternal_1_1(
- const std::vector<uint8_t> &identity, const std::vector<uint8_t> &encrypted_imsi_identity)
+ const std::vector<uint8_t> &identity,
+ const std::vector<uint8_t> &encrypted_imsi_identity)
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- // format: plain identity + ":" + encrypted identity(encrypted_imsi_identity)
+ // format: plain identity + ":" + encrypted
+ // identity(encrypted_imsi_identity)
std::string ctrl_rsp_param =
- std::string(identity.begin(), identity.end()) + ":" +
- std::string(encrypted_imsi_identity.begin(), encrypted_imsi_identity.end());
+ std::string(identity.begin(), identity.end()) + ":" +
+ std::string(
+ encrypted_imsi_identity.begin(), encrypted_imsi_identity.end());
enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_EAP_IDENTITY;
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
if (wpa_supplicant_ctrl_rsp_handle(
@@ -1702,6 +1853,99 @@
return {SupplicantStatusCode::SUCCESS, ""};
}
+SupplicantStatus StaNetwork::enableTlsSuiteBEapPhase1ParamInternal(bool enable)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ int val = enable == true ? 1 : 0;
+ std::string suiteb_phase1("tls_suiteb=" + std::to_string(val));
+
+ if (setStringKeyFieldAndResetState(
+ suiteb_phase1.c_str(), &(wpa_ssid->eap.phase1), "phase1")) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::enableSuiteBEapOpenSslCiphersInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ const char openssl_suiteb_cipher[] = "SUITEB192";
+
+ if (setStringKeyFieldAndResetState(
+ openssl_suiteb_cipher, &(wpa_ssid->eap.openssl_ciphers),
+ "openssl_ciphers")) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setSaePasswordInternal(
+ const std::string &sae_password)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (sae_password.length() < 1) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ if (wpa_ssid->sae_password &&
+ os_strlen(wpa_ssid->sae_password) == sae_password.length() &&
+ os_memcmp(
+ wpa_ssid->sae_password, sae_password.c_str(),
+ sae_password.length()) == 0) {
+ return {SupplicantStatusCode::SUCCESS, ""};
+ }
+ wpa_ssid->psk_set = 1;
+ if (setStringKeyFieldAndResetState(
+ sae_password.c_str(), &(wpa_ssid->sae_password),
+ "sae password")) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setSaePasswordIdInternal(
+ const std::string &sae_password_id)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (sae_password_id.length() < 1) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ if (wpa_ssid->sae_password_id &&
+ os_strlen(wpa_ssid->sae_password_id) == sae_password_id.length() &&
+ os_memcmp(
+ wpa_ssid->sae_password_id, sae_password_id.c_str(),
+ sae_password_id.length()) == 0) {
+ return {SupplicantStatusCode::SUCCESS, ""};
+ }
+ wpa_ssid->psk_set = 1;
+ if (setStringKeyFieldAndResetState(
+ sae_password_id.c_str(), &(wpa_ssid->sae_password_id),
+ "sae password id")) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setGroupMgmtCipherInternal(uint32_t
+ group_mgmt_cipher_mask)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (group_mgmt_cipher_mask & ~kAllowedGroupMgmtCipherMask) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ wpa_ssid->group_mgmt_cipher = group_mgmt_cipher_mask;
+ wpa_printf(MSG_MSGDUMP, "group_mgmt_cipher: 0x%x",
+ wpa_ssid->group_mgmt_cipher);
+ resetInternalStateAfterParamsUpdate();
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+std::pair<SupplicantStatus, uint32_t> StaNetwork::getGroupMgmtCipherInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ wpa_ssid->group_mgmt_cipher & kAllowedGroupMgmtCipherMask};
+}
+
/**
* Retrieve the underlying |wpa_ssid| struct pointer for
* this network.
@@ -1880,9 +2124,46 @@
return 0;
}
+/**
+ * Helper function to set the fast transition bits in the key management
+ * bitmask, to allow FT support when possible.
+ */
+void StaNetwork::setFastTransitionKeyMgmt(uint32_t &key_mgmt_mask)
+{
+ if (key_mgmt_mask & WPA_KEY_MGMT_SAE) {
+ key_mgmt_mask |= WPA_KEY_MGMT_FT_SAE;
+ }
+
+ if (key_mgmt_mask & WPA_KEY_MGMT_PSK) {
+ key_mgmt_mask |= WPA_KEY_MGMT_FT_PSK;
+ }
+
+ if (key_mgmt_mask & WPA_KEY_MGMT_IEEE8021X) {
+ key_mgmt_mask |= WPA_KEY_MGMT_FT_IEEE8021X;
+ }
+}
+
+/**
+ * Helper function to reset the fast transition bits in the key management
+ * bitmask.
+ */
+void StaNetwork::resetFastTransitionKeyMgmt(uint32_t &key_mgmt_mask)
+{
+ if (key_mgmt_mask & WPA_KEY_MGMT_SAE) {
+ key_mgmt_mask &= ~WPA_KEY_MGMT_FT_SAE;
+ }
+
+ if (key_mgmt_mask & WPA_KEY_MGMT_PSK) {
+ key_mgmt_mask &= ~WPA_KEY_MGMT_FT_PSK;
+ }
+
+ if (key_mgmt_mask & WPA_KEY_MGMT_IEEE8021X) {
+ key_mgmt_mask &= ~WPA_KEY_MGMT_FT_IEEE8021X;
+ }
+}
} // namespace implementation
-} // namespace V1_1
-} // namespace wifi
+} // namespace V1_2
} // namespace supplicant
+} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wpa_supplicant/hidl/1.1/sta_network.h b/wpa_supplicant/hidl/1.2/sta_network.h
similarity index 85%
rename from wpa_supplicant/hidl/1.1/sta_network.h
rename to wpa_supplicant/hidl/1.2/sta_network.h
index b647773..16d065e 100644
--- a/wpa_supplicant/hidl/1.1/sta_network.h
+++ b/wpa_supplicant/hidl/1.2/sta_network.h
@@ -15,10 +15,11 @@
#include <android-base/macros.h>
-#include <android/hardware/wifi/supplicant/1.1/ISupplicantStaNetwork.h>
+#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaNetwork.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetworkCallback.h>
-extern "C" {
+extern "C"
+{
#include "utils/common.h"
#include "utils/includes.h"
#include "config.h"
@@ -33,16 +34,17 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
namespace implementation {
using namespace android::hardware::wifi::supplicant::V1_0;
+using namespace android::hardware::wifi::supplicant::V1_1;
/**
* Implementation of StaNetwork hidl object. Each unique hidl
* object is used for control operations on a specific network
* controlled by wpa_supplicant.
*/
-class StaNetwork : public V1_1::ISupplicantStaNetwork
+class StaNetwork : public V1_2::ISupplicantStaNetwork
{
public:
StaNetwork(
@@ -109,9 +111,9 @@
const hidl_string& path, setEapClientCert_cb _hidl_cb) override;
Return<void> setEapPrivateKeyId(
const hidl_string& id, setEapPrivateKeyId_cb _hidl_cb) override;
- Return<void> setEapEncryptedImsiIdentity(
- const EapSimEncryptedIdentity& identity,
- setEapEncryptedImsiIdentity_cb _hidl_cb) override;
+ Return<void> setEapEncryptedImsiIdentity(
+ const EapSimEncryptedIdentity& identity,
+ setEapEncryptedImsiIdentity_cb _hidl_cb) override;
Return<void> setEapSubjectMatch(
const hidl_string& match, setEapSubjectMatch_cb _hidl_cb) override;
Return<void> setEapAltSubjectMatch(
@@ -140,6 +142,8 @@
Return<void> getPairwiseCipher(getPairwiseCipher_cb _hidl_cb) override;
Return<void> getPskPassphrase(getPskPassphrase_cb _hidl_cb) override;
Return<void> getPsk(getPsk_cb _hidl_cb) override;
+ Return<void> getSaePassword(getSaePassword_cb _hidl_cb) override;
+ Return<void> getSaePasswordId(getSaePasswordId_cb _hidl_cb) override;
Return<void> getWepKey(
uint32_t key_idx, getWepKey_cb _hidl_cb) override;
Return<void> getWepTxKeyIdx(getWepTxKeyIdx_cb _hidl_cb) override;
@@ -193,6 +197,34 @@
const EapSimIdentity& identity,
const EapSimEncryptedIdentity& imsiIdentity,
sendNetworkEapIdentityResponse_1_1_cb _hidl_cb) override;
+ Return<void> setKeyMgmt_1_2(
+ uint32_t key_mgmt_mask, setKeyMgmt_1_2_cb _hidl_cb) override;
+ Return<void> getKeyMgmt_1_2(getKeyMgmt_1_2_cb _hidl_cb) override;
+ Return<void> setPairwiseCipher_1_2(
+ uint32_t pairwise_cipher_mask,
+ setPairwiseCipher_1_2_cb _hidl_cb) override;
+ Return<void> getPairwiseCipher_1_2(
+ getPairwiseCipher_1_2_cb _hidl_cb) override;
+ Return<void> setGroupCipher_1_2(
+ uint32_t group_cipher_mask,
+ setGroupCipher_1_2_cb _hidl_cb) override;
+ Return<void> getGroupCipher_1_2(
+ getGroupCipher_1_2_cb _hidl_cb) override;
+ Return<void> setGroupMgmtCipher(
+ uint32_t group_mgmt_cipher_mask,
+ setGroupMgmtCipher_cb _hidl_cb) override;
+ Return<void> getGroupMgmtCipher(
+ getGroupMgmtCipher_cb _hidl_cb) override;
+ Return<void> enableTlsSuiteBEapPhase1Param(
+ bool enable, enableTlsSuiteBEapPhase1Param_cb _hidl_cb) override;
+ Return<void> enableSuiteBEapOpenSslCiphers(
+ enableSuiteBEapOpenSslCiphers_cb _hidl_cb) override;
+ Return<void> setSaePassword(
+ const hidl_string& sae_password,
+ setSaePassword_cb _hidl_cb) override;
+ Return<void> setSaePasswordId(
+ const hidl_string& sae_password_id,
+ setSaePasswordId_cb _hidl_cb) override;
private:
// Corresponding worker functions for the HIDL methods.
@@ -222,7 +254,7 @@
ISupplicantStaNetwork::EapPhase2Method method);
SupplicantStatus setEapIdentityInternal(
const std::vector<uint8_t>& identity);
- SupplicantStatus setEapEncryptedImsiIdentityInternal(
+ SupplicantStatus setEapEncryptedImsiIdentityInternal(
const std::vector<uint8_t>& identity);
SupplicantStatus setEapAnonymousIdentityInternal(
const std::vector<uint8_t>& identity);
@@ -252,6 +284,8 @@
std::pair<SupplicantStatus, uint32_t> getPairwiseCipherInternal();
std::pair<SupplicantStatus, std::string> getPskPassphraseInternal();
std::pair<SupplicantStatus, std::array<uint8_t, 32>> getPskInternal();
+ std::pair<SupplicantStatus, std::string> getSaePasswordInternal();
+ std::pair<SupplicantStatus, std::string> getSaePasswordIdInternal();
std::pair<SupplicantStatus, std::vector<uint8_t>> getWepKeyInternal(
uint32_t key_idx);
std::pair<SupplicantStatus, uint32_t> getWepTxKeyIdxInternal();
@@ -299,6 +333,14 @@
SupplicantStatus sendNetworkEapIdentityResponseInternal_1_1(
const std::vector<uint8_t>& identity,
const std::vector<uint8_t>& imsi_identity);
+ SupplicantStatus enableTlsSuiteBEapPhase1ParamInternal(bool enable);
+ SupplicantStatus enableSuiteBEapOpenSslCiphersInternal();
+ SupplicantStatus setSaePasswordInternal(
+ const std::string& sae_password);
+ SupplicantStatus setSaePasswordIdInternal(
+ const std::string& sae_password_id);
+ SupplicantStatus setGroupMgmtCipherInternal(uint32_t group_mgmt_cipher_mask);
+ std::pair<SupplicantStatus, uint32_t> getGroupMgmtCipherInternal();
struct wpa_ssid* retrieveNetworkPtr();
struct wpa_supplicant* retrieveIfacePtr();
@@ -321,6 +363,8 @@
const uint8_t* value, const size_t value_len,
uint8_t** to_update_field, size_t* to_update_field_len,
const char* hexdump_prefix);
+ void setFastTransitionKeyMgmt(uint32_t &key_mgmt_mask);
+ void resetFastTransitionKeyMgmt(uint32_t &key_mgmt_mask);
// Reference to the global wpa_struct. This is assumed to be valid
// for the lifetime of the process.
@@ -335,9 +379,9 @@
};
} // namespace implementation
-} // namespace V1_1
-} // namespace wifi
+} // namespace V1_2
} // namespace supplicant
+} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wpa_supplicant/hidl/1.1/supplicant.cpp b/wpa_supplicant/hidl/1.2/supplicant.cpp
similarity index 96%
rename from wpa_supplicant/hidl/1.1/supplicant.cpp
rename to wpa_supplicant/hidl/1.2/supplicant.cpp
index 4785c37..9342ace 100644
--- a/wpa_supplicant/hidl/1.1/supplicant.cpp
+++ b/wpa_supplicant/hidl/1.2/supplicant.cpp
@@ -16,6 +16,8 @@
#include <sys/stat.h>
namespace {
+using namespace android::hardware::wifi::supplicant::V1_2;
+
// Pre-populated interface params for interfaces controlled by wpa_supplicant.
// Note: This may differ for other OEM's. So, modify this accordingly.
constexpr char kIfaceDriverName[] = "nl80211";
@@ -32,10 +34,8 @@
"/system/etc/wifi/wpa_supplicant.conf";
constexpr char kVendorTemplateConfPath[] =
"/vendor/etc/wifi/wpa_supplicant.conf";
-constexpr char kOldStaIfaceConfPath[] =
- "/data/misc/wifi/wpa_supplicant.conf";
-constexpr char kOldP2pIfaceConfPath[] =
- "/data/misc/wifi/p2p_supplicant.conf";
+constexpr char kOldStaIfaceConfPath[] = "/data/misc/wifi/wpa_supplicant.conf";
+constexpr char kOldP2pIfaceConfPath[] = "/data/misc/wifi/p2p_supplicant.conf";
constexpr mode_t kConfigFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
int copyFile(
@@ -157,7 +157,7 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
namespace implementation {
using hidl_return_util::validateAndCall;
@@ -347,8 +347,9 @@
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""},
iface};
}
- // Set this flag true here, since there is no HIDL initialize method for the p2p
- // config, and the supplicant interface is not ready when the p2p iface is created.
+ // Set this flag true here, since there is no HIDL initialize
+ // method for the p2p config, and the supplicant interface is
+ // not ready when the p2p iface is created.
wpa_s->conf->persistent_reconnect = true;
return {{SupplicantStatusCode::SUCCESS, ""}, iface};
} else {
@@ -416,8 +417,8 @@
return SupplicantStatus{SupplicantStatusCode::SUCCESS, ""};
}
} // namespace implementation
-} // namespace V1_1
-} // namespace wifi
+} // namespace V1_2
} // namespace supplicant
+} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wpa_supplicant/hidl/1.1/supplicant.h b/wpa_supplicant/hidl/1.2/supplicant.h
similarity index 92%
rename from wpa_supplicant/hidl/1.1/supplicant.h
rename to wpa_supplicant/hidl/1.2/supplicant.h
index 327e061..8985854 100644
--- a/wpa_supplicant/hidl/1.1/supplicant.h
+++ b/wpa_supplicant/hidl/1.2/supplicant.h
@@ -10,13 +10,15 @@
#ifndef WPA_SUPPLICANT_HIDL_SUPPLICANT_H
#define WPA_SUPPLICANT_HIDL_SUPPLICANT_H
-#include <android-base/macros.h>
-
-#include <android/hardware/wifi/supplicant/1.1/ISupplicant.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantCallback.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantIface.h>
+#include <android/hardware/wifi/supplicant/1.0/types.h>
+#include <android/hardware/wifi/supplicant/1.2/ISupplicant.h>
+#include <android-base/macros.h>
+#include <hidl/Status.h>
-extern "C" {
+extern "C"
+{
#include "utils/common.h"
#include "utils/includes.h"
#include "utils/wpa_debug.h"
@@ -27,7 +29,7 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_1 {
+namespace V1_2 {
namespace implementation {
using namespace android::hardware::wifi::supplicant::V1_0;
@@ -36,7 +38,7 @@
* object is used core for global control operations on
* wpa_supplicant.
*/
-class Supplicant : public V1_1::ISupplicant
+class Supplicant : public V1_2::ISupplicant
{
public:
Supplicant(struct wpa_global* global);
@@ -90,9 +92,9 @@
};
} // namespace implementation
-} // namespace V1_1
-} // namespace wifi
+} // namespace V1_2
} // namespace supplicant
+} // namespace wifi
} // namespace hardware
} // namespace android
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index f9b7e4c..e81fef1 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -50,9 +50,12 @@
u8 bssid[ETH_ALEN];
u8 osu_ssid[SSID_MAX_LEN];
u8 osu_ssid_len;
+ u8 osu_ssid2[SSID_MAX_LEN];
+ u8 osu_ssid2_len;
char server_uri[256];
u32 osu_methods; /* bit 0 = OMA-DM, bit 1 = SOAP-XML SPP */
char osu_nai[256];
+ char osu_nai2[256];
struct osu_lang_string friendly_name[OSU_MAX_ITEMS];
size_t friendly_name_count;
struct osu_lang_string serv_desc[OSU_MAX_ITEMS];
@@ -93,8 +96,7 @@
return;
}
- /* Check if Proxy ARP is enabled (2nd byte in the IE) */
- if (ext_capa[3] & BIT(4))
+ if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_PROXY_ARP))
filter |= WPA_DATA_FRAME_FILTER_FLAG_ARP |
WPA_DATA_FRAME_FILTER_FLAG_NA;
@@ -102,15 +104,22 @@
}
-void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id)
+void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id, int ap_release)
{
+ int release;
u8 conf;
+ release = (HS20_VERSION >> 4) + 1;
+ if (ap_release > 0 && release > ap_release)
+ release = ap_release;
+ if (release < 2)
+ pps_mo_id = -1;
+
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
wpabuf_put_u8(buf, pps_mo_id >= 0 ? 7 : 5);
wpabuf_put_be24(buf, OUI_WFA);
wpabuf_put_u8(buf, HS20_INDICATION_OUI_TYPE);
- conf = HS20_VERSION;
+ conf = (release - 1) << 4;
if (pps_mo_id >= 0)
conf |= HS20_PPS_MO_ID_PRESENT;
wpabuf_put_u8(buf, conf);
@@ -119,6 +128,37 @@
}
+void wpas_hs20_add_roam_cons_sel(struct wpabuf *buf,
+ const struct wpa_ssid *ssid)
+{
+ if (!ssid->roaming_consortium_selection ||
+ !ssid->roaming_consortium_selection_len)
+ return;
+
+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(buf, 4 + ssid->roaming_consortium_selection_len);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_ROAMING_CONS_SEL_OUI_TYPE);
+ wpabuf_put_data(buf, ssid->roaming_consortium_selection,
+ ssid->roaming_consortium_selection_len);
+}
+
+
+int get_hs20_version(struct wpa_bss *bss)
+{
+ const u8 *ie;
+
+ if (!bss)
+ return 0;
+
+ ie = wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE);
+ if (!ie || ie[1] < 5)
+ return 0;
+
+ return ((ie[6] >> 4) & 0x0f) + 1;
+}
+
+
int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_bss *bss)
{
@@ -249,7 +289,7 @@
if (buf == NULL)
return -1;
- res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
+ res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, anqp_resp_cb, wpa_s);
if (res < 0) {
wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
wpabuf_free(buf);
@@ -392,7 +432,7 @@
return;
}
- if (chown(fname, statbuf.st_uid, statbuf.st_gid) < 0) {
+ if (lchown(fname, statbuf.st_uid, statbuf.st_gid) < 0) {
wpa_printf(MSG_WARNING, "Cannot change the ownership for %s",
fname);
}
@@ -650,6 +690,25 @@
wpa_s, NULL);
}
break;
+ case HS20_STYPE_OPERATOR_ICON_METADATA:
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
+ " Operator Icon Metadata", MAC2STR(sa));
+ wpa_hexdump(MSG_DEBUG, "Operator Icon Metadata", pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->hs20_operator_icon_metadata);
+ anqp->hs20_operator_icon_metadata =
+ wpabuf_alloc_copy(pos, slen);
+ }
+ break;
+ case HS20_STYPE_OSU_PROVIDERS_NAI_LIST:
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
+ " OSU Providers NAI List", MAC2STR(sa));
+ if (anqp) {
+ wpabuf_free(anqp->hs20_osu_providers_nai_list);
+ anqp->hs20_osu_providers_nai_list =
+ wpabuf_alloc_copy(pos, slen);
+ }
+ break;
default:
wpa_printf(MSG_DEBUG, "HS20: Unsupported subtype %u", subtype);
break;
@@ -729,8 +788,15 @@
wpa_ssid_txt(osu->osu_ssid,
osu->osu_ssid_len));
}
+ if (osu->osu_ssid2_len) {
+ fprintf(f, "osu_ssid2=%s\n",
+ wpa_ssid_txt(osu->osu_ssid2,
+ osu->osu_ssid2_len));
+ }
if (osu->osu_nai[0])
fprintf(f, "osu_nai=%s\n", osu->osu_nai);
+ if (osu->osu_nai2[0])
+ fprintf(f, "osu_nai2=%s\n", osu->osu_nai2);
for (j = 0; j < osu->friendly_name_count; j++) {
fprintf(f, "friendly_name=%s:%s\n",
osu->friendly_name[j].lang,
@@ -794,6 +860,7 @@
static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
const u8 *osu_ssid, u8 osu_ssid_len,
+ const u8 *osu_ssid2, u8 osu_ssid2_len,
const u8 *pos, size_t len)
{
struct osu_provider *prov;
@@ -815,6 +882,9 @@
os_memcpy(prov->bssid, bss->bssid, ETH_ALEN);
os_memcpy(prov->osu_ssid, osu_ssid, osu_ssid_len);
prov->osu_ssid_len = osu_ssid_len;
+ if (osu_ssid2)
+ os_memcpy(prov->osu_ssid2, osu_ssid2, osu_ssid2_len);
+ prov->osu_ssid2_len = osu_ssid2_len;
/* OSU Friendly Name Length */
if (end - pos < 2) {
@@ -996,18 +1066,30 @@
struct wpabuf *prov_anqp;
const u8 *pos, *end;
u16 len;
- const u8 *osu_ssid;
- u8 osu_ssid_len;
+ const u8 *osu_ssid, *osu_ssid2;
+ u8 osu_ssid_len, osu_ssid2_len;
u8 num_providers;
hs20_free_osu_prov(wpa_s);
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ struct wpa_ie_data data;
+ const u8 *ie;
+
if (bss->anqp == NULL)
continue;
prov_anqp = bss->anqp->hs20_osu_providers_list;
if (prov_anqp == NULL)
continue;
+ ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &data) == 0 &&
+ (data.key_mgmt & WPA_KEY_MGMT_OSEN)) {
+ osu_ssid2 = bss->ssid;
+ osu_ssid2_len = bss->ssid_len;
+ } else {
+ osu_ssid2 = NULL;
+ osu_ssid2_len = 0;
+ }
wpa_printf(MSG_DEBUG, "HS 2.0: Parsing OSU Providers list from "
MACSTR, MAC2STR(bss->bssid));
wpa_hexdump_buf(MSG_DEBUG, "HS 2.0: OSU Providers list",
@@ -1049,7 +1131,8 @@
if (len > (unsigned int) (end - pos))
break;
hs20_osu_add_prov(wpa_s, bss, osu_ssid,
- osu_ssid_len, pos, len);
+ osu_ssid_len, osu_ssid2,
+ osu_ssid2_len, pos, len);
pos += len;
}
@@ -1058,6 +1141,35 @@
"extra data after OSU Providers",
(int) (end - pos));
}
+
+ prov_anqp = bss->anqp->hs20_osu_providers_nai_list;
+ if (!prov_anqp)
+ continue;
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Parsing OSU Providers NAI List from "
+ MACSTR, MAC2STR(bss->bssid));
+ wpa_hexdump_buf(MSG_DEBUG, "HS 2.0: OSU Providers NAI List",
+ prov_anqp);
+ pos = wpabuf_head(prov_anqp);
+ end = pos + wpabuf_len(prov_anqp);
+ num_providers = 0;
+ while (end - pos > 0) {
+ len = *pos++;
+ if (end - pos < len) {
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Not enough room for OSU_NAI");
+ break;
+ }
+ if (num_providers >= wpa_s->osu_prov_count) {
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Ignore unexpected OSU Provider NAI List entries");
+ break;
+ }
+ os_memcpy(wpa_s->osu_prov[num_providers].osu_nai2,
+ pos, len);
+ pos += len;
+ num_providers++;
+ }
}
wpa_s->fetch_osu_icon_in_progress = 1;
@@ -1213,6 +1325,18 @@
}
+void hs20_rx_t_c_acceptance(struct wpa_supplicant *wpa_s, const char *url)
+{
+ if (!wpa_sm_pmf_enabled(wpa_s->wpa)) {
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Ignore Terms and Conditions Acceptance since PMF was not enabled");
+ return;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, HS20_T_C_ACCEPTANCE "%s", url);
+}
+
+
void hs20_init(struct wpa_supplicant *wpa_s)
{
dl_list_init(&wpa_s->icon_head);
diff --git a/wpa_supplicant/hs20_supplicant.h b/wpa_supplicant/hs20_supplicant.h
index 0dd559f..e43414b 100644
--- a/wpa_supplicant/hs20_supplicant.h
+++ b/wpa_supplicant/hs20_supplicant.h
@@ -9,7 +9,10 @@
#define HS20_SUPPLICANT_H
void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s);
-void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id);
+void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id,
+ int ap_release);
+void wpas_hs20_add_roam_cons_sel(struct wpabuf *buf,
+ const struct wpa_ssid *ssid);
int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
const u8 *payload, size_t payload_len, int inmem);
@@ -18,6 +21,7 @@
void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, const u8 *sa,
const u8 *data, size_t slen, u8 dialog_token);
+int get_hs20_version(struct wpa_bss *bss);
int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_bss *bss);
int hs20_get_pps_mo_id(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
@@ -27,6 +31,7 @@
const char *url, u8 osu_method);
void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code,
u16 reauth_delay, const char *url);
+void hs20_rx_t_c_acceptance(struct wpa_supplicant *wpa_s, const char *url);
void hs20_free_osu_prov(struct wpa_supplicant *wpa_s);
void hs20_next_osu_icon(struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 00919d1..e96ea65 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -260,12 +260,14 @@
static const u8 * auth_get_psk(void *ctx, const u8 *addr,
const u8 *p2p_dev_addr, const u8 *prev_psk,
- size_t *psk_len)
+ size_t *psk_len, int *vlan_id)
{
struct ibss_rsn *ibss_rsn = ctx;
if (psk_len)
*psk_len = PMK_LEN;
+ if (vlan_id)
+ *vlan_id = 0;
wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
__func__, MAC2STR(addr), prev_psk);
if (prev_psk)
@@ -457,7 +459,7 @@
}
/* TODO: get peer RSN IE with Probe Request */
- if (wpa_validate_wpa_ie(ibss_rsn->auth_group, peer->auth,
+ if (wpa_validate_wpa_ie(ibss_rsn->auth_group, peer->auth, 0,
(u8 *) "\x30\x14\x01\x00"
"\x00\x0f\xac\x04"
"\x01\x00\x00\x0f\xac\x04"
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 4c79356..c66a09b 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -148,6 +148,8 @@
return 1;
if (cred->required_roaming_consortium_len)
return 1;
+ if (cred->num_roaming_consortiums)
+ return 1;
}
return 0;
}
@@ -301,8 +303,10 @@
wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY);
if (all)
wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS);
- if (all)
+ if (all) {
wpabuf_put_u8(extra, HS20_STYPE_OSU_PROVIDERS_LIST);
+ wpabuf_put_u8(extra, HS20_STYPE_OSU_PROVIDERS_NAI_LIST);
+ }
gas_anqp_set_element_len(extra, len_pos);
}
#endif /* CONFIG_HS20 */
@@ -312,7 +316,7 @@
if (buf == NULL)
return -1;
- res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, buf,
+ res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, 0, buf,
interworking_anqp_resp_cb, wpa_s);
if (res < 0) {
wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request");
@@ -954,6 +958,7 @@
"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, "pairwise", "CCMP", 0) < 0)
return -1;
return 0;
@@ -1145,6 +1150,23 @@
}
+static int cred_roaming_consortiums_match(const u8 *ie,
+ const struct wpabuf *anqp,
+ const struct wpa_cred *cred)
+{
+ unsigned int i;
+
+ for (i = 0; i < cred->num_roaming_consortiums; i++) {
+ if (roaming_consortium_match(ie, anqp,
+ cred->roaming_consortiums[i],
+ cred->roaming_consortiums_len[i]))
+ return 1;
+ }
+
+ return 0;
+}
+
+
static int cred_no_required_oi_match(struct wpa_cred *cred, struct wpa_bss *bss)
{
const u8 *ie;
@@ -1349,27 +1371,28 @@
{
struct wpa_cred *cred, *selected = NULL;
const u8 *ie;
+ const struct wpabuf *anqp;
int is_excluded = 0;
ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
+ anqp = bss->anqp ? bss->anqp->roaming_consortium : NULL;
- if (ie == NULL &&
- (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
+ if (!ie && !anqp)
return NULL;
if (wpa_s->conf->cred == NULL)
return NULL;
for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
- if (cred->roaming_consortium_len == 0)
+ if (cred->roaming_consortium_len == 0 &&
+ cred->num_roaming_consortiums == 0)
continue;
- if (!roaming_consortium_match(ie,
- bss->anqp ?
- bss->anqp->roaming_consortium :
- NULL,
- cred->roaming_consortium,
- cred->roaming_consortium_len))
+ if ((cred->roaming_consortium_len == 0 ||
+ !roaming_consortium_match(ie, anqp,
+ cred->roaming_consortium,
+ cred->roaming_consortium_len)) &&
+ !cred_roaming_consortiums_match(ie, anqp, cred))
continue;
if (cred_no_required_oi_match(cred, bss))
@@ -1535,6 +1558,9 @@
struct wpa_bss *bss, int only_add)
{
struct wpa_ssid *ssid;
+ const u8 *ie;
+ const struct wpabuf *anqp;
+ unsigned int i;
wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Connect with " MACSTR
" based on roaming consortium match", MAC2STR(bss->bssid));
@@ -1564,6 +1590,26 @@
if (interworking_set_hs20_params(wpa_s, ssid) < 0)
goto fail;
+ ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
+ anqp = bss->anqp ? bss->anqp->roaming_consortium : NULL;
+ for (i = 0; (ie || anqp) && i < cred->num_roaming_consortiums; i++) {
+ if (!roaming_consortium_match(
+ ie, anqp, cred->roaming_consortiums[i],
+ cred->roaming_consortiums_len[i]))
+ continue;
+
+ ssid->roaming_consortium_selection =
+ os_malloc(cred->roaming_consortiums_len[i]);
+ if (!ssid->roaming_consortium_selection)
+ goto fail;
+ os_memcpy(ssid->roaming_consortium_selection,
+ cred->roaming_consortiums[i],
+ cred->roaming_consortiums_len[i]);
+ ssid->roaming_consortium_selection_len =
+ cred->roaming_consortiums_len[i];
+ break;
+ }
+
if (cred->eap_method == NULL) {
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: No EAP method set for credential using roaming consortium");
@@ -2580,7 +2626,6 @@
{
struct wpa_bss *bss;
int found = 0;
- const u8 *ie;
wpa_printf(MSG_DEBUG, "Interworking: next_anqp_fetch - "
"fetch_anqp_in_progress=%d fetch_osu_icon_in_progress=%d",
@@ -2603,8 +2648,7 @@
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
if (!(bss->caps & IEEE80211_CAP_ESS))
continue;
- ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
- if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80))
+ if (!wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_INTERWORKING))
continue; /* AP does not support Interworking */
if (disallowed_bssid(wpa_s, bss->bssid) ||
disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len))
@@ -2752,7 +2796,7 @@
if (buf == NULL)
return -1;
- res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
+ res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, anqp_resp_cb, wpa_s);
if (res < 0) {
wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request");
wpabuf_free(buf);
@@ -2801,6 +2845,31 @@
}
+static void interworking_parse_venue_url(struct wpa_supplicant *wpa_s,
+ const u8 *data, size_t len)
+{
+ const u8 *pos = data, *end = data + len;
+ char url[255];
+
+ while (end - pos >= 2) {
+ u8 slen, num;
+
+ slen = *pos++;
+ if (slen < 1 || slen > end - pos) {
+ wpa_printf(MSG_DEBUG,
+ "ANQP: Truncated Venue URL Duple field");
+ return;
+ }
+
+ num = *pos++;
+ os_memcpy(url, pos, slen - 1);
+ url[slen - 1] = '\0';
+ wpa_msg(wpa_s, MSG_INFO, RX_VENUE_URL "%u %s", num, url);
+ pos += slen - 1;
+ }
+}
+
+
static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, const u8 *sa,
u16 info_id,
@@ -2907,6 +2976,18 @@
}
break;
#endif /* CONFIG_FILS */
+ case ANQP_VENUE_URL:
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " Venue URL",
+ MAC2STR(sa));
+ anqp_add_extra(wpa_s, anqp, info_id, pos, slen);
+
+ if (!pmf_in_use(wpa_s, sa)) {
+ wpa_printf(MSG_DEBUG,
+ "ANQP: Ignore Venue URL since PMF was not enabled");
+ break;
+ }
+ interworking_parse_venue_url(wpa_s, pos, slen);
+ break;
case ANQP_VENDOR_SPECIFIC:
if (slen < 3)
return;
@@ -3155,7 +3236,7 @@
} else
wpabuf_put_le16(buf, 0);
- res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s);
+ res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, gas_resp_cb, wpa_s);
if (res < 0) {
wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request");
wpabuf_free(buf);
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index e08c2fd..51a8a02 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -28,9 +28,9 @@
"s"
#endif /* CONFIG_DEBUG_SYSLOG */
"t"
-#ifdef CONFIG_DBUS
+#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
"u"
-#endif /* CONFIG_DBUS */
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
"vW] [-P<pid file>] "
"[-g<global ctrl>] \\\n"
" [-G<group>] \\\n"
@@ -98,9 +98,9 @@
" -T = record to Linux tracing in addition to logging\n"
" (records all messages regardless of debug verbosity)\n"
#endif /* CONFIG_DEBUG_LINUX_TRACING */
-#ifdef CONFIG_DBUS
+#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
" -u = enable DBus control interface\n"
-#endif /* CONFIG_DBUS */
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
" -v = show version\n"
" -W = wait for a control interface monitor before starting\n");
@@ -295,11 +295,11 @@
case 't':
params.wpa_debug_timestamp++;
break;
-#ifdef CONFIG_DBUS
+#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
case 'u':
params.dbus_ctrl_interface = 1;
break;
-#endif /* CONFIG_DBUS */
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
case 'v':
printf("%s\n", wpa_supplicant_version);
exitcode = 0;
diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c
index 129d205..43b1fa7 100644
--- a/wpa_supplicant/mbo.c
+++ b/wpa_supplicant/mbo.c
@@ -38,6 +38,32 @@
}
+const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr)
+{
+ const u8 *mbo;
+ u8 ie_len = mbo_ie[1];
+
+ if (ie_len < MBO_IE_HEADER - 2)
+ return NULL;
+ mbo = mbo_ie + MBO_IE_HEADER;
+
+ return get_ie(mbo, 2 + ie_len - MBO_IE_HEADER, attr);
+}
+
+
+const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len,
+ enum mbo_attr_id attr)
+{
+ const u8 *mbo_ie;
+
+ mbo_ie = get_vendor_ie(ies, ies_len, MBO_IE_VENDOR_TYPE);
+ if (!mbo_ie)
+ return NULL;
+
+ return mbo_attr_from_mbo_ie(mbo_ie, attr);
+}
+
+
const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr)
{
const u8 *mbo, *end;
@@ -72,6 +98,13 @@
}
+static void wpas_mbo_non_pref_chan_attr_hdr(struct wpabuf *mbo, size_t size)
+{
+ wpabuf_put_u8(mbo, MBO_ATTR_ID_NON_PREF_CHAN_REPORT);
+ wpabuf_put_u8(mbo, size); /* Length */
+}
+
+
static void wpas_mbo_non_pref_chan_attr(struct wpa_supplicant *wpa_s,
struct wpabuf *mbo, u8 start, u8 end)
{
@@ -80,9 +113,7 @@
if (size + 2 > wpabuf_tailroom(mbo))
return;
- wpabuf_put_u8(mbo, MBO_ATTR_ID_NON_PREF_CHAN_REPORT);
- wpabuf_put_u8(mbo, size); /* Length */
-
+ wpas_mbo_non_pref_chan_attr_hdr(mbo, size);
wpas_mbo_non_pref_chan_attr_body(wpa_s, mbo, start, end);
}
@@ -119,6 +150,8 @@
if (!wpa_s->non_pref_chan || !wpa_s->non_pref_chan_num) {
if (subelement)
wpas_mbo_non_pref_chan_subelem_hdr(mbo, 4);
+ else
+ wpas_mbo_non_pref_chan_attr_hdr(mbo, 0);
return;
}
start_pref = &wpa_s->non_pref_chan[0];
@@ -149,7 +182,8 @@
}
-int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len)
+int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len,
+ int add_oce_capa)
{
struct wpabuf *mbo;
int res;
@@ -175,7 +209,7 @@
wpabuf_put_u8(mbo, wpa_s->conf->mbo_cell_capa);
/* Add OCE capability indication attribute if OCE is enabled */
- if (wpa_s->enable_oce & OCE_STA) {
+ if ((wpa_s->enable_oce & OCE_STA) && add_oce_capa) {
wpabuf_put_u8(mbo, OCE_ATTR_ID_CAPA_IND);
wpabuf_put_u8(mbo, 1);
wpabuf_put_u8(mbo, OCE_RELEASE);
@@ -241,6 +275,7 @@
wpas_mbo_non_pref_chan_attrs(wpa_s, buf, 1);
wpas_mbo_send_wnm_notification(wpa_s, wpabuf_head_u8(buf),
wpabuf_len(buf));
+ wpas_update_mbo_connect_params(wpa_s);
wpabuf_free(buf);
}
@@ -266,10 +301,10 @@
const struct wpa_mbo_non_pref_channel *a = _a, *b = _b;
if (a->oper_class != b->oper_class)
- return a->oper_class - b->oper_class;
+ return (int) a->oper_class - (int) b->oper_class;
if (a->reason != b->reason)
- return a->reason - b->reason;
- return a->preference - b->preference;
+ return (int) a->reason - (int) b->reason;
+ return (int) a->preference - (int) b->preference;
}
@@ -487,7 +522,7 @@
if (disallowed_sec && wpa_s->current_bss)
wpa_bss_tmp_disallow(wpa_s, wpa_s->current_bss->bssid,
- disallowed_sec);
+ disallowed_sec, 0);
return;
fail:
@@ -531,6 +566,7 @@
wpas_mbo_send_wnm_notification(wpa_s, cell_capa, 7);
wpa_supplicant_set_default_scan_ies(wpa_s);
+ wpas_update_mbo_connect_params(wpa_s);
}
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index c0c8f91..9260021 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -34,6 +34,8 @@
wpa_s->current_ssid = NULL;
os_free(wpa_s->mesh_rsn);
wpa_s->mesh_rsn = NULL;
+ os_free(wpa_s->mesh_params);
+ wpa_s->mesh_params = NULL;
/* TODO: leave mesh (stop beacon). This will happen on link down
* anyway, so it's not urgent */
}
@@ -93,6 +95,9 @@
conf->ieee80211w = NO_MGMT_FRAME_PROTECTION;
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ conf->ocv = ssid->ocv;
+#endif /* CONFIG_OCV */
cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher, 0);
if (cipher < 0 || cipher == WPA_CIPHER_TKIP) {
@@ -147,6 +152,93 @@
}
+static int wpas_mesh_init_rsn(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_iface *ifmsh = wpa_s->ifmsh;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct hostapd_data *bss = ifmsh->bss[0];
+ static int default_groups[] = { 19, 20, 21, 25, 26, -1 };
+ const char *password;
+ size_t len;
+
+ password = ssid->sae_password;
+ if (!password)
+ password = ssid->passphrase;
+ if (!password) {
+ wpa_printf(MSG_ERROR,
+ "mesh: Passphrase for SAE not configured");
+ return -1;
+ }
+
+ bss->conf->wpa = ssid->proto;
+ bss->conf->wpa_key_mgmt = ssid->key_mgmt;
+
+ if (wpa_s->conf->sae_groups && wpa_s->conf->sae_groups[0] > 0) {
+ wpas_mesh_copy_groups(bss, wpa_s);
+ } else {
+ bss->conf->sae_groups = os_memdup(default_groups,
+ sizeof(default_groups));
+ if (!bss->conf->sae_groups)
+ return -1;
+ }
+
+ len = os_strlen(password);
+ bss->conf->ssid.wpa_passphrase = dup_binstr(password, len);
+
+ wpa_s->mesh_rsn = mesh_rsn_auth_init(wpa_s, ifmsh->mconf);
+ return !wpa_s->mesh_rsn ? -1 : 0;
+}
+
+
+static int wpas_mesh_complete(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_iface *ifmsh = wpa_s->ifmsh;
+ struct wpa_driver_mesh_join_params *params = wpa_s->mesh_params;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ int ret;
+
+ if (!params || !ssid || !ifmsh) {
+ wpa_printf(MSG_ERROR, "mesh: %s called without active mesh",
+ __func__);
+ return -1;
+ }
+
+ if (ifmsh->mconf->security != MESH_CONF_SEC_NONE &&
+ wpas_mesh_init_rsn(wpa_s)) {
+ wpa_printf(MSG_ERROR,
+ "mesh: RSN initialization failed - deinit mesh");
+ wpa_supplicant_mesh_deinit(wpa_s);
+ return -1;
+ }
+
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+ wpa_s->pairwise_cipher = wpa_s->mesh_rsn->pairwise_cipher;
+ wpa_s->group_cipher = wpa_s->mesh_rsn->group_cipher;
+ wpa_s->mgmt_group_cipher = wpa_s->mesh_rsn->mgmt_group_cipher;
+ }
+
+ params->ies = ifmsh->mconf->rsn_ie;
+ params->ie_len = ifmsh->mconf->rsn_ie_len;
+ params->basic_rates = ifmsh->basic_rates;
+ params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE;
+ params->conf.ht_opmode = ifmsh->bss[0]->iface->ht_op_mode;
+
+ wpa_msg(wpa_s, MSG_INFO, "joining mesh %s",
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+ ret = wpa_drv_join_mesh(wpa_s, params);
+ if (ret)
+ wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d", ret);
+
+ /* hostapd sets the interface down until we associate */
+ wpa_drv_set_operstate(wpa_s, 1);
+
+ if (!ret)
+ wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+
+ return ret;
+}
+
+
static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
struct hostapd_freq_params *freq)
@@ -156,8 +248,6 @@
struct hostapd_config *conf;
struct mesh_conf *mconf;
int basic_rates_erp[] = { 10, 20, 55, 60, 110, 120, 240, -1 };
- static int default_groups[] = { 19, 20, 21, 25, 26, -1 };
- size_t len;
int rate_len;
int frequency;
@@ -168,7 +258,7 @@
return 0;
}
- wpa_s->ifmsh = ifmsh = os_zalloc(sizeof(*wpa_s->ifmsh));
+ wpa_s->ifmsh = ifmsh = hostapd_alloc_iface();
if (!ifmsh)
return -ENOMEM;
@@ -183,6 +273,7 @@
if (!bss)
goto out_free;
+ ifmsh->bss[0]->msg_ctx = wpa_s;
os_memcpy(bss->own_addr, wpa_s->own_addr, ETH_ALEN);
bss->driver = wpa_s->driver;
bss->drv_priv = wpa_s->drv_priv;
@@ -206,6 +297,16 @@
bss->conf->start_disabled = 1;
bss->conf->mesh = MESH_ENABLED;
bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity;
+
+ if (ieee80211_is_dfs(ssid->frequency, wpa_s->hw.modes,
+ wpa_s->hw.num_modes) && wpa_s->conf->country[0]) {
+ conf->ieee80211h = 1;
+ conf->ieee80211d = 1;
+ conf->country[0] = wpa_s->conf->country[0];
+ conf->country[1] = wpa_s->conf->country[1];
+ conf->country[2] = ' ';
+ }
+
bss->iconf = conf;
ifmsh->conf = conf;
@@ -229,7 +330,8 @@
if (ssid->ht40)
conf->secondary_channel = ssid->ht40;
if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A && ssid->vht) {
- conf->vht_oper_chwidth = ssid->max_oper_chwidth;
+ if (ssid->max_oper_chwidth != DEFAULT_MAX_OPER_CHWIDTH)
+ conf->vht_oper_chwidth = ssid->max_oper_chwidth;
switch (conf->vht_oper_chwidth) {
case VHT_CHANWIDTH_80MHZ:
case VHT_CHANWIDTH_80P80MHZ:
@@ -279,45 +381,15 @@
conf->basic_rates[rate_len] = -1;
}
- if (hostapd_setup_interface(ifmsh)) {
- wpa_printf(MSG_ERROR,
- "Failed to initialize hostapd interface for mesh");
- return -1;
- }
-
if (wpa_drv_init_mesh(wpa_s)) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh in driver");
return -1;
}
- if (mconf->security != MESH_CONF_SEC_NONE) {
- if (ssid->passphrase == NULL) {
- wpa_printf(MSG_ERROR,
- "mesh: Passphrase for SAE not configured");
- goto out_free;
- }
-
- bss->conf->wpa = ssid->proto;
- bss->conf->wpa_key_mgmt = ssid->key_mgmt;
-
- if (wpa_s->conf->sae_groups &&
- wpa_s->conf->sae_groups[0] > 0) {
- wpas_mesh_copy_groups(bss, wpa_s);
- } else {
- bss->conf->sae_groups =
- os_memdup(default_groups,
- sizeof(default_groups));
- if (!bss->conf->sae_groups)
- goto out_free;
- }
-
- len = os_strlen(ssid->passphrase);
- bss->conf->ssid.wpa_passphrase =
- dup_binstr(ssid->passphrase, len);
-
- wpa_s->mesh_rsn = mesh_rsn_auth_init(wpa_s, mconf);
- if (!wpa_s->mesh_rsn)
- goto out_free;
+ if (hostapd_setup_interface(ifmsh)) {
+ wpa_printf(MSG_ERROR,
+ "Failed to initialize hostapd interface for mesh");
+ return -1;
}
wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
@@ -362,11 +434,13 @@
int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
- struct wpa_driver_mesh_join_params params;
+ struct wpa_driver_mesh_join_params *params = os_zalloc(sizeof(*params));
int ret = 0;
- if (!ssid || !ssid->ssid || !ssid->ssid_len || !ssid->frequency) {
+ if (!ssid || !ssid->ssid || !ssid->ssid_len || !ssid->frequency ||
+ !params) {
ret = -ENOENT;
+ os_free(params);
goto out;
}
@@ -376,22 +450,23 @@
wpa_s->group_cipher = WPA_CIPHER_NONE;
wpa_s->mgmt_group_cipher = 0;
- os_memset(¶ms, 0, sizeof(params));
- params.meshid = ssid->ssid;
- params.meshid_len = ssid->ssid_len;
- ibss_mesh_setup_freq(wpa_s, ssid, ¶ms.freq);
- wpa_s->mesh_ht_enabled = !!params.freq.ht_enabled;
- wpa_s->mesh_vht_enabled = !!params.freq.vht_enabled;
- if (params.freq.ht_enabled && params.freq.sec_channel_offset)
- ssid->ht40 = params.freq.sec_channel_offset;
+ params->meshid = ssid->ssid;
+ params->meshid_len = ssid->ssid_len;
+ ibss_mesh_setup_freq(wpa_s, ssid, ¶ms->freq);
+ wpa_s->mesh_ht_enabled = !!params->freq.ht_enabled;
+ wpa_s->mesh_vht_enabled = !!params->freq.vht_enabled;
+ if (params->freq.ht_enabled && params->freq.sec_channel_offset)
+ ssid->ht40 = params->freq.sec_channel_offset;
+
if (wpa_s->mesh_vht_enabled) {
ssid->vht = 1;
- switch (params.freq.bandwidth) {
+ ssid->vht_center_freq1 = params->freq.center_freq1;
+ switch (params->freq.bandwidth) {
case 80:
- if (params.freq.center_freq2) {
+ if (params->freq.center_freq2) {
ssid->max_oper_chwidth = VHT_CHANWIDTH_80P80MHZ;
ssid->vht_center_freq2 =
- params.freq.center_freq2;
+ params->freq.center_freq2;
} else {
ssid->max_oper_chwidth = VHT_CHANWIDTH_80MHZ;
}
@@ -405,67 +480,44 @@
}
}
if (ssid->beacon_int > 0)
- params.beacon_int = ssid->beacon_int;
+ params->beacon_int = ssid->beacon_int;
else if (wpa_s->conf->beacon_int > 0)
- params.beacon_int = wpa_s->conf->beacon_int;
+ params->beacon_int = wpa_s->conf->beacon_int;
if (ssid->dtim_period > 0)
- params.dtim_period = ssid->dtim_period;
+ params->dtim_period = ssid->dtim_period;
else if (wpa_s->conf->dtim_period > 0)
- params.dtim_period = wpa_s->conf->dtim_period;
- params.conf.max_peer_links = wpa_s->conf->max_peer_links;
+ params->dtim_period = wpa_s->conf->dtim_period;
+ params->conf.max_peer_links = wpa_s->conf->max_peer_links;
if (ssid->mesh_rssi_threshold < DEFAULT_MESH_RSSI_THRESHOLD) {
- params.conf.rssi_threshold = ssid->mesh_rssi_threshold;
- params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD;
+ params->conf.rssi_threshold = ssid->mesh_rssi_threshold;
+ params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD;
}
if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
- params.flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
- params.flags |= WPA_DRIVER_MESH_FLAG_AMPE;
+ params->flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
+ params->flags |= WPA_DRIVER_MESH_FLAG_AMPE;
wpa_s->conf->user_mpm = 1;
}
if (wpa_s->conf->user_mpm) {
- params.flags |= WPA_DRIVER_MESH_FLAG_USER_MPM;
- params.conf.auto_plinks = 0;
+ params->flags |= WPA_DRIVER_MESH_FLAG_USER_MPM;
+ params->conf.auto_plinks = 0;
} else {
- params.flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
- params.conf.auto_plinks = 1;
+ params->flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
+ params->conf.auto_plinks = 1;
}
- params.conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity;
+ params->conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity;
- if (wpa_supplicant_mesh_init(wpa_s, ssid, ¶ms.freq)) {
+ os_free(wpa_s->mesh_params);
+ wpa_s->mesh_params = params;
+ if (wpa_supplicant_mesh_init(wpa_s, ssid, ¶ms->freq)) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh");
wpa_drv_leave_mesh(wpa_s);
ret = -1;
goto out;
}
- if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
- wpa_s->pairwise_cipher = wpa_s->mesh_rsn->pairwise_cipher;
- wpa_s->group_cipher = wpa_s->mesh_rsn->group_cipher;
- wpa_s->mgmt_group_cipher = wpa_s->mesh_rsn->mgmt_group_cipher;
- }
-
- if (wpa_s->ifmsh) {
- params.ies = wpa_s->ifmsh->mconf->rsn_ie;
- params.ie_len = wpa_s->ifmsh->mconf->rsn_ie_len;
- params.basic_rates = wpa_s->ifmsh->basic_rates;
- params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE;
- params.conf.ht_opmode = wpa_s->ifmsh->bss[0]->iface->ht_op_mode;
- }
-
- wpa_msg(wpa_s, MSG_INFO, "joining mesh %s",
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
- ret = wpa_drv_join_mesh(wpa_s, ¶ms);
- if (ret)
- wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d", ret);
-
- /* hostapd sets the interface down until we associate */
- wpa_drv_set_operstate(wpa_s, 1);
-
- if (!ret)
- wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
-
+ ret = wpas_mesh_complete(wpa_s);
out:
return ret;
}
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index bc3cc5e..9d6ab8d 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -12,6 +12,7 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/hw_features_common.h"
+#include "common/ocv.h"
#include "ap/hostapd.h"
#include "ap/sta_info.h"
#include "ap/ieee802_11.h"
@@ -188,7 +189,7 @@
do {
if (os_get_random((u8 *) &llid, sizeof(llid)) < 0)
- continue;
+ llid = 0; /* continue */
} while (!llid || llid_in_use(wpa_s, llid));
sta->my_lid = llid;
@@ -222,13 +223,14 @@
if (!sta)
return;
- buf_len = 2 + /* capability info */
+ buf_len = 2 + /* Category and Action */
+ 2 + /* capability info */
2 + /* AID */
2 + 8 + /* supported rates */
2 + (32 - 8) +
2 + 32 + /* mesh ID */
2 + 7 + /* mesh config */
- 2 + 23 + /* peering management */
+ 2 + 24 + /* peering management */
2 + 96 + /* AMPE */
2 + 16; /* MIC */
#ifdef CONFIG_IEEE80211N
@@ -245,6 +247,11 @@
#endif /* CONFIG_IEEE80211AC */
if (type != PLINK_CLOSE)
buf_len += conf->rsn_ie_len; /* RSN IE */
+#ifdef CONFIG_OCV
+ /* OCI is included even when the other STA doesn't support OCV */
+ if (type != PLINK_CLOSE && conf->ocv)
+ buf_len += OCV_OCI_EXTENDED_LEN;
+#endif /* CONFIG_OCV */
buf = wpabuf_alloc(buf_len);
if (!buf)
@@ -356,6 +363,22 @@
}
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_OCV
+ if (type != PLINK_CLOSE && conf->ocv) {
+ struct wpa_channel_info ci;
+
+ if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Mesh MPM: Failed to get channel info for OCI element");
+ goto fail;
+ }
+
+ pos = wpabuf_put(buf, OCV_OCI_EXTENDED_LEN);
+ if (ocv_insert_extended_oci(&ci, pos) < 0)
+ goto fail;
+ }
+#endif /* CONFIG_OCV */
+
if (ampe && mesh_rsn_protect_frame(wpa_s->mesh_rsn, sta, cat, buf)) {
wpa_msg(wpa_s, MSG_INFO,
"Mesh MPM: failed to add AMPE and MIC IE");
@@ -437,7 +460,7 @@
break;
}
reason = WLAN_REASON_MESH_MAX_RETRIES;
- /* fall through on else */
+ /* fall through */
case PLINK_CNF_RCVD:
/* confirm timer */
@@ -698,6 +721,7 @@
#ifdef CONFIG_IEEE80211AC
copy_sta_vht_capab(data, sta, elems->vht_capabilities);
+ copy_sta_vht_oper(data, sta, elems->vht_operation);
set_sta_vht_opmode(data, sta, elems->vht_opmode_notif);
#endif /* CONFIG_IEEE80211AC */
@@ -1195,6 +1219,56 @@
}
return;
}
+
+#ifdef CONFIG_OCV
+ if (action_field == PLINK_OPEN && elems.rsn_ie) {
+ struct wpa_state_machine *sm = sta->wpa_sm;
+ struct wpa_ie_data data;
+
+ res = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2,
+ elems.rsn_ie_len + 2,
+ &data);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to parse RSN IE (res=%d)",
+ res);
+ wpa_hexdump(MSG_DEBUG, "RSN IE", elems.rsn_ie,
+ elems.rsn_ie_len);
+ return;
+ }
+
+ wpa_auth_set_ocv(sm, mconf->ocv &&
+ (data.capabilities &
+ WPA_CAPABILITY_OCVC));
+ }
+
+ if (action_field != PLINK_CLOSE &&
+ wpa_auth_uses_ocv(sta->wpa_sm)) {
+ struct wpa_channel_info ci;
+ int tx_chanwidth;
+ int tx_seg1_idx;
+
+ if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "MPM: Failed to get channel info to validate received OCI in MPM Confirm");
+ return;
+ }
+
+ if (get_tx_parameters(
+ sta, channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx, &tx_chanwidth,
+ &tx_seg1_idx) < 0)
+ return;
+
+ if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx) !=
+ 0) {
+ wpa_printf(MSG_WARNING, "MPM: %s",
+ ocv_errorstr);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
}
if (sta->plink_state == PLINK_BLOCKED) {
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index 25dcde5..4b8d6c4 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -76,7 +76,7 @@
static const u8 *auth_get_psk(void *ctx, const u8 *addr,
const u8 *p2p_dev_addr, const u8 *prev_psk,
- size_t *psk_len)
+ size_t *psk_len, int *vlan_id)
{
struct mesh_rsn *mesh_rsn = ctx;
struct hostapd_data *hapd = mesh_rsn->wpa_s->ifmsh->bss[0];
@@ -84,6 +84,8 @@
if (psk_len)
*psk_len = PMK_LEN;
+ if (vlan_id)
+ *vlan_id = 0;
wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
__func__, MAC2STR(addr), prev_psk);
@@ -140,7 +142,7 @@
static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr,
- enum mfp_options ieee80211w)
+ enum mfp_options ieee80211w, int ocv)
{
struct wpa_auth_config conf;
static const struct wpa_auth_callbacks cb = {
@@ -168,6 +170,9 @@
if (ieee80211w != NO_MGMT_FRAME_PROTECTION)
conf.group_mgmt_cipher = rsn->mgmt_group_cipher;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ conf.ocv = ocv;
+#endif /* CONFIG_OCV */
rsn->auth = wpa_init(addr, &conf, &cb, rsn);
if (rsn->auth == NULL) {
@@ -240,7 +245,7 @@
mesh_rsn->mgmt_group_cipher = conf->mgmt_group_cipher;
if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr,
- conf->ieee80211w) < 0) {
+ conf->ieee80211w, conf->ocv) < 0) {
mesh_rsn_deinit(mesh_rsn);
os_free(mesh_rsn);
return NULL;
@@ -332,8 +337,14 @@
return -1;
}
+ if (sta->sae->tmp && !sta->sae->tmp->pw_id && ssid->sae_password_id) {
+ sta->sae->tmp->pw_id = os_strdup(ssid->sae_password_id);
+ if (!sta->sae->tmp->pw_id)
+ return -1;
+ }
return sae_prepare_commit(wpa_s->own_addr, sta->addr,
(u8 *) password, os_strlen(password),
+ ssid->sae_password_id,
sta->sae);
}
@@ -632,7 +643,7 @@
size_t crypt_len;
const u8 *aad[] = { sta->addr, wpa_s->own_addr, cat };
const size_t aad_len[] = { ETH_ALEN, ETH_ALEN,
- (elems->mic - 2) - cat };
+ elems->mic ? (elems->mic - 2) - cat : 0 };
size_t key_len;
if (!sta->sae) {
@@ -646,7 +657,9 @@
mesh_rsn_auth_sae_sta(wpa_s, sta);
}
- if (chosen_pmk && os_memcmp(chosen_pmk, sta->sae->pmkid, PMKID_LEN)) {
+ if (chosen_pmk &&
+ (!sta->sae ||
+ os_memcmp(chosen_pmk, sta->sae->pmkid, PMKID_LEN) != 0)) {
wpa_msg(wpa_s, MSG_DEBUG,
"Mesh RSN: Invalid PMKID (Chosen PMK did not match calculated PMKID)");
return -1;
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 3832a33..41dc334 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -14,7 +14,6 @@
#include "wpa_supplicant_i.h"
#include "wps_supplicant.h"
#include "dbus/dbus_common.h"
-#include "dbus/dbus_old.h"
#include "dbus/dbus_new.h"
#include "rsn_supp/wpa.h"
#include "fst/fst.h"
@@ -27,13 +26,13 @@
int wpas_notify_supplicant_initialized(struct wpa_global *global)
{
-#ifdef CONFIG_DBUS
+#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
if (global->params.dbus_ctrl_interface) {
global->dbus = wpas_dbus_init(global);
if (global->dbus == NULL)
return -1;
}
-#endif /* CONFIG_DBUS */
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
#ifdef CONFIG_HIDL
global->hidl = wpas_hidl_init(global);
@@ -47,10 +46,10 @@
void wpas_notify_supplicant_deinitialized(struct wpa_global *global)
{
-#ifdef CONFIG_DBUS
+#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
if (global->dbus)
wpas_dbus_deinit(global->dbus);
-#endif /* CONFIG_DBUS */
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
#ifdef CONFIG_HIDL
if (global->hidl)
@@ -62,9 +61,6 @@
int wpas_notify_iface_added(struct wpa_supplicant *wpa_s)
{
if (!wpa_s->p2p_mgmt) {
- if (wpas_dbus_register_iface(wpa_s))
- return -1;
-
if (wpas_dbus_register_interface(wpa_s))
return -1;
}
@@ -80,9 +76,6 @@
void wpas_notify_iface_removed(struct wpa_supplicant *wpa_s)
{
if (!wpa_s->p2p_mgmt) {
- /* unregister interface in old DBus ctrl iface */
- wpas_dbus_unregister_iface(wpa_s);
-
/* unregister interface in new DBus ctrl iface */
wpas_dbus_unregister_interface(wpa_s);
}
@@ -99,10 +92,6 @@
if (wpa_s->p2p_mgmt)
return;
- /* notify the old DBus API */
- wpa_supplicant_dbus_notify_state_change(wpa_s, new_state,
- old_state);
-
/* notify the new DBus API */
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATE);
@@ -149,6 +138,15 @@
}
+void wpas_notify_auth_status_code(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_AUTH_STATUS_CODE);
+}
+
+
void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s)
{
if (wpa_s->p2p_mgmt)
@@ -166,6 +164,42 @@
wpas_hidl_notify_auth_timeout(wpa_s);
}
+void wpas_notify_roam_time(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_ROAM_TIME);
+}
+
+
+void wpas_notify_roam_complete(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_ROAM_COMPLETE);
+}
+
+
+void wpas_notify_session_length(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_SESSION_LENGTH);
+}
+
+
+void wpas_notify_bss_tm_status(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSS_TM_STATUS);
+}
+
+
void wpas_notify_network_changed(struct wpa_supplicant *wpa_s)
{
if (wpa_s->p2p_mgmt)
@@ -243,9 +277,6 @@
if (wpa_s->p2p_mgmt)
return;
- /* notify the old DBus API */
- wpa_supplicant_dbus_notify_scanning(wpa_s);
-
/* notify the new DBus API */
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_SCANNING);
}
@@ -265,9 +296,6 @@
if (wpa_s->p2p_mgmt)
return;
- /* notify the old DBus API */
- wpa_supplicant_dbus_notify_scan_results(wpa_s);
-
wpas_wps_notify_scan_results(wpa_s);
}
@@ -279,8 +307,6 @@
return;
#ifdef CONFIG_WPS
- /* notify the old DBus API */
- wpa_supplicant_dbus_notify_wps_cred(wpa_s, cred);
/* notify the new DBus API */
wpas_dbus_signal_wps_cred(wpa_s, cred);
#endif /* CONFIG_WPS */
@@ -788,6 +814,9 @@
wpas_dbus_signal_p2p_peer_joined(wpa_s, p2p_dev_addr);
#endif /* CONFIG_P2P */
+ /* Register the station */
+ wpas_dbus_register_sta(wpa_s, sta);
+
/* Notify listeners a new station has been authorized */
wpas_dbus_signal_sta_authorized(wpa_s, sta);
@@ -811,7 +840,9 @@
/* Notify listeners a station has been deauthorized */
wpas_dbus_signal_sta_deauthorized(wpa_s, sta);
- wpas_hidl_notify_ap_sta_deauthorized(wpa_s, sta, p2p_dev_addr);
+ wpas_hidl_notify_ap_sta_deauthorized(wpa_s, sta, p2p_dev_addr);
+ /* Unregister the station */
+ wpas_dbus_unregister_sta(wpa_s, sta);
}
@@ -859,9 +890,6 @@
"depth=%d %s", depth, altsubject[i]);
}
- /* notify the old DBus API */
- wpa_supplicant_dbus_notify_certification(wpa_s, depth, subject,
- cert_hash, cert);
/* notify the new DBus API */
wpas_dbus_signal_certification(wpa_s, depth, subject, altsubject,
num_altsubject, cert_hash, cert);
@@ -887,6 +915,7 @@
status, parameter);
}
+
void wpas_notify_eap_error(struct wpa_supplicant *wpa_s, int error_code)
{
wpa_dbg(wpa_s, MSG_ERROR,
@@ -894,6 +923,7 @@
wpas_hidl_notify_eap_error(wpa_s, error_code);
}
+
void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
@@ -1024,3 +1054,112 @@
}
#endif /* CONFIG_MESH */
+
+/*
+ * DPP Notifications
+ */
+
+/* DPP Success notifications */
+
+void wpas_notify_dpp_config_received(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_DPP
+ if (!wpa_s)
+ return;
+
+ wpas_hidl_notify_dpp_config_received(wpa_s, ssid);
+#endif /* CONFIG_DPP */
+}
+
+void wpas_notify_dpp_config_sent(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_DPP
+ if (!wpa_s)
+ return;
+
+ wpas_hidl_notify_dpp_config_sent(wpa_s);
+#endif /* CONFIG_DPP */
+}
+
+/* DPP Progress notifications */
+void wpas_notify_dpp_auth_success(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_DPP
+ if (!wpa_s)
+ return;
+
+ wpas_hidl_notify_dpp_auth_success(wpa_s);
+#endif /* CONFIG_DPP */
+}
+
+void wpas_notify_dpp_resp_pending(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_DPP
+ if (!wpa_s)
+ return;
+
+ wpas_hidl_notify_dpp_resp_pending(wpa_s);
+#endif /* CONFIG_DPP */
+}
+
+/* DPP Failure notifications */
+void wpas_notify_dpp_not_compatible(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_DPP
+ if (!wpa_s)
+ return;
+
+ wpas_hidl_notify_dpp_not_compatible(wpa_s);
+#endif /* CONFIG_DPP */
+}
+
+void wpas_notify_dpp_missing_auth(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_DPP
+ if (!wpa_s)
+ return;
+
+ wpas_hidl_notify_dpp_missing_auth(wpa_s);
+#endif /* CONFIG_DPP */
+}
+
+void wpas_notify_dpp_configuration_failure(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_DPP
+ if (!wpa_s)
+ return;
+
+ wpas_hidl_notify_dpp_configuration_failure(wpa_s);
+#endif /* CONFIG_DPP */
+}
+
+void wpas_notify_dpp_timeout(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_DPP
+ if (!wpa_s)
+ return;
+
+ wpas_hidl_notify_dpp_timeout(wpa_s);
+#endif /* CONFIG_DPP */
+}
+
+void wpas_notify_dpp_auth_failure(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_DPP
+ if (!wpa_s)
+ return;
+
+ wpas_hidl_notify_dpp_auth_failure(wpa_s);
+#endif /* CONFIG_DPP */
+}
+
+void wpas_notify_dpp_failure(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_DPP
+ if (!wpa_s)
+ return;
+
+ wpas_hidl_notify_dpp_fail(wpa_s);
+#endif /* CONFIG_DPP */
+}
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index c3ac3d1..2f194ce 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -24,8 +24,13 @@
enum wpa_states new_state,
enum wpa_states old_state);
void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
+void wpas_notify_auth_status_code(struct wpa_supplicant *wpa_s);
void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s);
void wpas_notify_auth_timeout(struct wpa_supplicant *wpa_s);
+void wpas_notify_roam_time(struct wpa_supplicant *wpa_s);
+void wpas_notify_roam_complete(struct wpa_supplicant *wpa_s);
+void wpas_notify_session_length(struct wpa_supplicant *wpa_s);
+void wpas_notify_bss_tm_status(struct wpa_supplicant *wpa_s);
void wpas_notify_network_changed(struct wpa_supplicant *wpa_s);
void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s);
void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s);
@@ -167,4 +172,16 @@
void wpas_notify_hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s,
u8 code, u16 reauth_delay,
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);
+void wpas_notify_dpp_auth_success(struct wpa_supplicant *wpa_s);
+void wpas_notify_dpp_resp_pending(struct wpa_supplicant *wpa_s);
+void wpas_notify_dpp_not_compatible(struct wpa_supplicant *wpa_s);
+void wpas_notify_dpp_missing_auth(struct wpa_supplicant *wpa_s);
+void wpas_notify_dpp_configuration_failure(struct wpa_supplicant *wpa_s);
+void wpas_notify_dpp_timeout(struct wpa_supplicant *wpa_s);
+void wpas_notify_dpp_auth_failure(struct wpa_supplicant *wpa_s);
+void wpas_notify_dpp_failure(struct wpa_supplicant *wpa_s);
+
#endif /* NOTIFY_H */
diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c
index d23b009..947917b 100644
--- a/wpa_supplicant/op_classes.c
+++ b/wpa_supplicant/op_classes.c
@@ -208,17 +208,78 @@
static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
const struct oper_class_map *op_class)
{
int chan;
size_t i;
struct hostapd_hw_modes *mode;
int found;
+ int z;
+ int freq2 = 0;
+ int freq5 = 0;
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode);
if (!mode)
return 0;
+ /* If we are configured to disable certain things, take that into
+ * account here. */
+ if (ssid->freq_list && ssid->freq_list[0]) {
+ for (z = 0; ; z++) {
+ int f = ssid->freq_list[z];
+
+ if (f == 0)
+ break; /* end of list */
+ if (f > 4000 && f < 6000)
+ freq5 = 1;
+ else if (f > 2400 && f < 2500)
+ freq2 = 1;
+ }
+ } else {
+ /* No frequencies specified, can use anything hardware supports.
+ */
+ freq2 = freq5 = 1;
+ }
+
+ if (op_class->op_class >= 115 && op_class->op_class <= 130 && !freq5)
+ return 0;
+ if (op_class->op_class >= 81 && op_class->op_class <= 84 && !freq2)
+ return 0;
+
+#ifdef CONFIG_HT_OVERRIDES
+ if (ssid->disable_ht) {
+ switch (op_class->op_class) {
+ case 83:
+ case 84:
+ case 104:
+ case 105:
+ case 116:
+ case 117:
+ case 119:
+ case 120:
+ case 122:
+ case 123:
+ case 126:
+ case 127:
+ case 128:
+ case 129:
+ case 130:
+ /* Disable >= 40 MHz channels if HT is disabled */
+ return 0;
+ }
+ }
+#endif /* CONFIG_HT_OVERRIDES */
+
+#ifdef CONFIG_VHT_OVERRIDES
+ if (ssid->disable_vht) {
+ if (op_class->op_class >= 128 && op_class->op_class <= 130) {
+ /* Disable >= 80 MHz channels if VHT is disabled */
+ return 0;
+ }
+ }
+#endif /* CONFIG_VHT_OVERRIDES */
+
if (op_class->op_class == 128) {
u8 channels[] = { 42, 58, 106, 122, 138, 155 };
@@ -273,8 +334,9 @@
}
-size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
- size_t len)
+size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ int freq, u8 *pos, size_t len)
{
struct wpabuf *buf;
u8 op, current, chan;
@@ -304,7 +366,7 @@
wpabuf_put_u8(buf, current);
for (op = 0; global_op_class[op].op_class; op++) {
- if (wpas_op_class_supported(wpa_s, &global_op_class[op]))
+ if (wpas_op_class_supported(wpa_s, ssid, &global_op_class[op]))
wpabuf_put_u8(buf, global_op_class[op].op_class);
}
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 0eccd52..70b61d6 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -748,6 +748,7 @@
conncap = P2PS_SETUP_GROUP_OWNER;
goto grp_owner;
}
+ /* fall through */
default:
return P2PS_SETUP_NONE;
@@ -979,6 +980,7 @@
os_free(wpa_s->p2p_group_common_freqs);
wpa_s->p2p_group_common_freqs = NULL;
wpa_s->p2p_group_common_freqs_num = 0;
+ wpa_s->p2p_go_do_acs = 0;
wpa_s->waiting_presence_resp = 0;
@@ -1583,20 +1585,27 @@
static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid, const u8 *buf,
- size_t len, unsigned int wait_time)
+ size_t len, unsigned int wait_time, int *scheduled)
{
struct wpa_supplicant *wpa_s = ctx;
int listen_freq = -1, send_freq = -1;
+ if (scheduled)
+ *scheduled = 0;
if (wpa_s->p2p_listen_work)
listen_freq = wpa_s->p2p_listen_work->freq;
if (wpa_s->p2p_send_action_work)
send_freq = wpa_s->p2p_send_action_work->freq;
if (listen_freq != (int) freq && send_freq != (int) freq) {
- wpa_printf(MSG_DEBUG, "P2P: Schedule new radio work for Action frame TX (listen_freq=%d send_freq=%d)",
- listen_freq, send_freq);
- return wpas_send_action_work(wpa_s, freq, dst, src, bssid, buf,
- len, wait_time);
+ int res;
+
+ wpa_printf(MSG_DEBUG, "P2P: Schedule new radio work for Action frame TX (listen_freq=%d send_freq=%d freq=%u)",
+ listen_freq, send_freq, freq);
+ res = wpas_send_action_work(wpa_s, freq, dst, src, bssid, buf,
+ len, wait_time);
+ if (res == 0 && scheduled)
+ *scheduled = 1;
+ return res;
}
wpa_printf(MSG_DEBUG, "P2P: Use ongoing radio work for Action frame TX");
@@ -1648,7 +1657,7 @@
wpa_supplicant_ap_deinit(wpa_s);
wpas_copy_go_neg_results(wpa_s, res);
if (res->wps_method == WPS_PBC) {
- wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1);
+ wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1, 0);
#ifdef CONFIG_WPS_NFC
} else if (res->wps_method == WPS_NFC) {
wpas_wps_start_nfc(wpa_s, res->peer_device_addr,
@@ -1713,14 +1722,23 @@
static void p2p_go_dump_common_freqs(struct wpa_supplicant *wpa_s)
{
+ char buf[20 + P2P_MAX_CHANNELS * 6];
+ char *pos, *end;
unsigned int i;
+ int res;
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Common group frequencies (len=%u):",
- wpa_s->p2p_group_common_freqs_num);
+ pos = buf;
+ end = pos + sizeof(buf);
+ for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
+ res = os_snprintf(pos, end - pos, " %d",
+ wpa_s->p2p_group_common_freqs[i]);
+ if (os_snprintf_error(end - pos, res))
+ break;
+ pos += res;
+ }
+ *pos = '\0';
- for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++)
- wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d",
- i, wpa_s->p2p_group_common_freqs[i]);
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Common group frequencies:%s", buf);
}
@@ -1902,6 +1920,7 @@
ssid->vht = params->vht;
ssid->max_oper_chwidth = params->max_oper_chwidth;
ssid->vht_center_freq2 = params->vht_center_freq2;
+ ssid->he = params->he;
ssid->ssid = os_zalloc(params->ssid_len + 1);
if (ssid->ssid) {
os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
@@ -2065,6 +2084,13 @@
return -1;
}
+ if (wpa_s->conf->p2p_interface_random_mac_addr) {
+ random_mac_addr(wpa_s->pending_interface_addr);
+ wpa_printf(MSG_DEBUG, "P2P: Generate random MAC address " MACSTR
+ " for the group",
+ MAC2STR(wpa_s->pending_interface_addr));
+ }
+
if (force_ifname[0]) {
wpa_printf(MSG_DEBUG, "P2P: Driver forced interface name %s",
force_ifname);
@@ -2143,6 +2169,29 @@
wpas_p2p_clone_config(group_wpa_s, wpa_s);
+ if (wpa_s->conf->p2p_interface_random_mac_addr) {
+ if (wpa_drv_set_mac_addr(group_wpa_s,
+ wpa_s->pending_interface_addr) < 0) {
+ wpa_msg(group_wpa_s, MSG_INFO,
+ "Failed to set random MAC address");
+ wpa_supplicant_remove_iface(wpa_s->global, group_wpa_s,
+ 0);
+ return NULL;
+ }
+
+ if (wpa_supplicant_update_mac_addr(group_wpa_s) < 0) {
+ wpa_msg(group_wpa_s, MSG_INFO,
+ "Could not update MAC address information");
+ wpa_supplicant_remove_iface(wpa_s->global, group_wpa_s,
+ 0);
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: Using random MAC address " MACSTR
+ " for the group",
+ MAC2STR(wpa_s->pending_interface_addr));
+ }
+
return group_wpa_s;
}
@@ -3048,7 +3097,7 @@
MAC2STR(sa), s->id);
}
wpas_p2p_group_add_persistent(
- wpa_s, s, go, 0, op_freq, 0, 0, 0, 0, NULL,
+ wpa_s, s, go, 0, op_freq, 0, 0, 0, 0, 0, NULL,
go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0,
1);
} else if (bssid) {
@@ -3274,6 +3323,7 @@
wpa_s->p2p_go_vht_center_freq2,
wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht,
wpa_s->p2p_go_max_oper_chwidth,
+ wpa_s->p2p_go_he,
channels,
ssid->mode == WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
@@ -3918,6 +3968,10 @@
/* Remove stale persistent group */
if (s->mode != WPAS_MODE_P2P_GO || s->num_p2p_clients <= 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove stale persistent group id=%d",
+ s->id);
+ wpas_notify_persistent_group_removed(wpa_s, s);
wpa_config_remove_network(wpa_s->conf, s->id);
save_config = 1;
continue;
@@ -4041,6 +4095,11 @@
if (persistent_go && !persistent_go->num_p2p_clients) {
/* remove empty persistent GO */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove empty persistent group id=%d",
+ persistent_go->id);
+ wpas_notify_persistent_group_removed(wpa_s,
+ persistent_go);
wpa_config_remove_network(wpa_s->conf,
persistent_go->id);
}
@@ -4081,6 +4140,10 @@
/* Remove stale persistent group */
if (stale->mode != WPAS_MODE_P2P_GO ||
stale->num_p2p_clients <= 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove stale persistent group id=%d",
+ stale->id);
+ wpas_notify_persistent_group_removed(wpa_s, stale);
wpa_config_remove_network(wpa_s->conf, stale->id);
} else {
size_t i;
@@ -4113,6 +4176,11 @@
if (persistent_go && s != persistent_go &&
!persistent_go->num_p2p_clients) {
/* remove empty persistent GO */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove empty persistent group id=%d",
+ persistent_go->id);
+ wpas_notify_persistent_group_removed(wpa_s,
+ persistent_go);
wpa_config_remove_network(wpa_s->conf,
persistent_go->id);
/* Save config */
@@ -4130,6 +4198,9 @@
return;
}
+ wpa_s->global->pending_p2ps_group = 0;
+ wpa_s->global->pending_p2ps_group_freq = 0;
+
if (conncap == P2PS_SETUP_GROUP_OWNER) {
/*
* We need to copy the interface name. Simply saving a
@@ -4140,8 +4211,10 @@
go_ifname[0] = '\0';
if (!go_wpa_s) {
- wpa_s->global->pending_p2ps_group = 1;
- wpa_s->global->pending_p2ps_group_freq = freq;
+ if (!response_done) {
+ wpa_s->global->pending_p2ps_group = 1;
+ wpa_s->global->pending_p2ps_group_freq = freq;
+ }
if (!wpas_p2p_create_iface(wpa_s))
os_memcpy(go_ifname, wpa_s->ifname,
@@ -4165,13 +4238,14 @@
if (response_done && persistent_go) {
wpas_p2p_group_add_persistent(
wpa_s, persistent_go,
- 0, 0, freq, 0, 0, 0, 0, NULL,
+ 0, 0, freq, 0, 0, 0, 0, 0, NULL,
persistent_go->mode ==
WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
0, 0);
} else if (response_done) {
- wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0);
+ wpas_p2p_group_add(wpa_s, 1, freq,
+ 0, 0, 0, 0, 0);
}
if (passwd_id == DEV_PW_P2PS_DEFAULT) {
@@ -4220,6 +4294,10 @@
if (persistent_go && !persistent_go->num_p2p_clients) {
/* remove empty persistent GO */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove empty persistent group id=%d",
+ persistent_go->id);
+ wpas_notify_persistent_group_removed(wpa_s, persistent_go);
wpa_config_remove_network(wpa_s->conf, persistent_go->id);
}
@@ -4283,11 +4361,11 @@
if (persistent_go) {
wpas_p2p_group_add_persistent(
- wpa_s, persistent_go, 0, 0, 0, 0, 0, 0, 0, NULL,
+ wpa_s, persistent_go, 0, 0, 0, 0, 0, 0, 0, 0, NULL,
persistent_go->mode == WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 0);
} else {
- wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0);
+ wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0);
}
return 1;
@@ -4304,6 +4382,52 @@
WPA_IF_P2P_CLIENT, len, freq_list);
}
+int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s)
+{
+ u8 addr[ETH_ALEN] = {0};
+
+ if (wpa_s->conf->p2p_device_random_mac_addr == 0)
+ return 0;
+
+ if (wpa_s->conf->ssid == NULL) {
+ if (random_mac_addr(addr) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Failed to generate random MAC address");
+ return -EINVAL;
+ }
+
+ /* Store generated MAC address. */
+ os_memcpy(wpa_s->conf->p2p_device_persistent_mac_addr, addr,
+ ETH_ALEN);
+ } else {
+ /* If there are existing saved groups, restore last MAC address.
+ * if there is no last used MAC address, the last one is
+ * factory MAC. */
+ if (is_zero_ether_addr(
+ wpa_s->conf->p2p_device_persistent_mac_addr))
+ return 0;
+ os_memcpy(addr, wpa_s->conf->p2p_device_persistent_mac_addr,
+ ETH_ALEN);
+ wpa_msg(wpa_s, MSG_DEBUG, "Restore last used MAC address.");
+ }
+
+ if (wpa_drv_set_mac_addr(wpa_s, addr) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Failed to set random MAC address");
+ return -EINVAL;
+ }
+
+ if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Could not update MAC address information");
+ return -EINVAL;
+ }
+
+ wpa_msg(wpa_s, MSG_DEBUG, "Using random MAC address " MACSTR,
+ MAC2STR(addr));
+
+ return 0;
+}
/**
* wpas_p2p_init - Initialize P2P module for %wpa_supplicant
@@ -4325,6 +4449,12 @@
if (global->p2p)
return 0;
+ if (wpas_p2p_mac_setup(wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Failed to initialize P2P random MAC address.");
+ return -1;
+ }
+
os_memset(&p2p, 0, sizeof(p2p));
p2p.cb_ctx = wpa_s;
p2p.debug_print = wpas_p2p_debug_print;
@@ -4389,7 +4519,10 @@
* channel.
*/
if (p2p_config_get_random_social(&p2p, &p2p.reg_class,
- &p2p.channel) != 0) {
+ &p2p.channel,
+ &global->p2p_go_avoid_freq,
+ &global->p2p_disallow_freq) !=
+ 0) {
wpa_printf(MSG_INFO,
"P2P: No social channels supported by the driver - do not enable P2P");
return 0;
@@ -4414,10 +4547,14 @@
* other preference is indicated.
*/
if (p2p_config_get_random_social(&p2p, &p2p.op_reg_class,
- &p2p.op_channel) != 0) {
- wpa_printf(MSG_ERROR,
+ &p2p.op_channel, NULL,
+ NULL) != 0) {
+ wpa_printf(MSG_INFO,
"P2P: Failed to select random social channel as operation channel");
- return -1;
+ p2p.op_reg_class = 0;
+ p2p.op_channel = 0;
+ /* This will be overridden during group setup in
+ * p2p_prepare_channel(), so allow setup to continue. */
}
p2p.cfg_op_channel = 0;
wpa_printf(MSG_DEBUG, "P2P: Random operating channel: "
@@ -4810,6 +4947,7 @@
wpa_s->p2p_go_ht40,
wpa_s->p2p_go_vht,
wpa_s->p2p_go_max_oper_chwidth,
+ wpa_s->p2p_go_he,
NULL, 0);
return;
}
@@ -5107,17 +5245,18 @@
os_memcpy(group->p2p_pin, wpa_s->p2p_pin,
sizeof(group->p2p_pin));
group->p2p_wps_method = wpa_s->p2p_wps_method;
- } else {
- /*
- * Need to mark the current interface for p2p_group_formation
- * when a separate group interface is not used. This is needed
- * to allow p2p_cancel stop a pending p2p_connect-join.
- * wpas_p2p_init_group_interface() addresses this for the case
- * where a separate group interface is used.
- */
- wpa_s->global->p2p_group_formation = wpa_s;
}
+ /*
+ * Need to mark the current interface for p2p_group_formation
+ * when a separate group interface is not used. This is needed
+ * to allow p2p_cancel stop a pending p2p_connect-join.
+ * wpas_p2p_init_group_interface() addresses this for the case
+ * where a separate group interface is used.
+ */
+ if (group == wpa_s->parent)
+ wpa_s->global->p2p_group_formation = group;
+
group->p2p_in_provisioning = 1;
group->p2p_fallback_to_go_neg = wpa_s->p2p_fallback_to_go_neg;
@@ -5214,7 +5353,8 @@
ret = p2p_supported_freq_cli(wpa_s->global->p2p, freq);
if (!ret) {
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
- ieee80211_is_dfs(freq)) {
+ ieee80211_is_dfs(freq, wpa_s->hw.modes,
+ wpa_s->hw.num_modes)) {
/*
* If freq is a DFS channel and DFS is offloaded
* to the driver, allow P2P GO to use it.
@@ -5356,7 +5496,7 @@
int persistent_group, int auto_join, int join, int auth,
int go_intent, int freq, unsigned int vht_center_freq2,
int persistent_id, int pd, int ht40, int vht,
- unsigned int vht_chwidth, const u8 *group_ssid,
+ unsigned int vht_chwidth, int he, const u8 *group_ssid,
size_t group_ssid_len)
{
int force_freq = 0, pref_freq = 0;
@@ -5401,6 +5541,7 @@
wpa_s->p2p_go_vht = !!vht;
wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
wpa_s->p2p_go_max_oper_chwidth = vht_chwidth;
+ wpa_s->p2p_go_he = !!he;
if (pin)
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
@@ -5702,7 +5843,8 @@
if (freq > 0 && !p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
- ieee80211_is_dfs(freq)) {
+ ieee80211_is_dfs(freq, wpa_s->hw.modes,
+ wpa_s->hw.num_modes)) {
/*
* If freq is a DFS channel and DFS is offloaded to the
* driver, allow P2P GO to use it.
@@ -5807,10 +5949,23 @@
}
+static int wpas_same_band(int freq1, int freq2)
+{
+ enum hostapd_hw_mode mode1, mode2;
+ u8 chan1, chan2;
+
+ mode1 = ieee80211_freq_to_chan(freq1, &chan1);
+ mode2 = ieee80211_freq_to_chan(freq2, &chan2);
+ if (mode1 == NUM_HOSTAPD_MODES)
+ return 0;
+ return mode1 == mode2;
+}
+
+
static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params,
int freq, int vht_center_freq2, int ht40,
- int vht, int max_oper_chwidth,
+ int vht, int max_oper_chwidth, int he,
const struct p2p_channels *channels)
{
struct wpa_used_freq_data *freqs;
@@ -5823,6 +5978,7 @@
params->role_go = 1;
params->ht40 = ht40;
params->vht = vht;
+ params->he = he;
params->max_oper_chwidth = max_oper_chwidth;
params->vht_center_freq2 = vht_center_freq2;
@@ -5866,7 +6022,8 @@
}
if (!p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
- ieee80211_is_dfs(freq)) {
+ ieee80211_is_dfs(freq, wpa_s->hw.modes,
+ wpa_s->hw.num_modes)) {
/*
* If freq is a DFS channel and DFS is offloaded
* to the driver, allow P2P GO to use it.
@@ -6006,6 +6163,80 @@
goto success;
}
+ /* Try using a channel that allows VHT to be used with 80 MHz */
+ if (wpa_s->hw.modes && wpa_s->p2p_group_common_freqs) {
+ for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
+ enum hostapd_hw_mode mode;
+ struct hostapd_hw_modes *hwmode;
+ u8 chan;
+
+ cand = wpa_s->p2p_group_common_freqs[i];
+ mode = ieee80211_freq_to_chan(cand, &chan);
+ hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ mode);
+ if (!hwmode ||
+ wpas_p2p_verify_channel(wpa_s, hwmode, chan,
+ BW80) != ALLOWED)
+ continue;
+ if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) {
+ params->freq = cand;
+ wpa_printf(MSG_DEBUG,
+ "P2P: Use freq %d MHz common with the peer and allowing VHT80",
+ params->freq);
+ goto success;
+ }
+ }
+ }
+
+ /* Try using a channel that allows HT to be used with 40 MHz on the same
+ * band so that CSA can be used */
+ if (wpa_s->current_ssid && wpa_s->hw.modes &&
+ wpa_s->p2p_group_common_freqs) {
+ for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
+ enum hostapd_hw_mode mode;
+ struct hostapd_hw_modes *hwmode;
+ u8 chan;
+
+ cand = wpa_s->p2p_group_common_freqs[i];
+ mode = ieee80211_freq_to_chan(cand, &chan);
+ hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ mode);
+ if (!wpas_same_band(wpa_s->current_ssid->frequency,
+ cand) ||
+ !hwmode ||
+ (wpas_p2p_verify_channel(wpa_s, hwmode, chan,
+ BW40MINUS) != ALLOWED &&
+ wpas_p2p_verify_channel(wpa_s, hwmode, chan,
+ BW40PLUS) != ALLOWED))
+ continue;
+ if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) {
+ params->freq = cand;
+ wpa_printf(MSG_DEBUG,
+ "P2P: Use freq %d MHz common with the peer, allowing HT40, and maintaining same band",
+ params->freq);
+ goto success;
+ }
+ }
+ }
+
+ /* Try using one of the group common freqs on the same band so that CSA
+ * can be used */
+ if (wpa_s->current_ssid && wpa_s->p2p_group_common_freqs) {
+ for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
+ cand = wpa_s->p2p_group_common_freqs[i];
+ if (!wpas_same_band(wpa_s->current_ssid->frequency,
+ cand))
+ continue;
+ if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) {
+ params->freq = cand;
+ wpa_printf(MSG_DEBUG,
+ "P2P: Use freq %d MHz common with the peer and maintaining same band",
+ params->freq);
+ goto success;
+ }
+ }
+ }
+
/* Try using one of the group common freqs */
if (wpa_s->p2p_group_common_freqs) {
for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++) {
@@ -6075,6 +6306,12 @@
return NULL;
}
+ if (go && wpa_s->p2p_go_do_acs) {
+ group_wpa_s->p2p_go_do_acs = wpa_s->p2p_go_do_acs;
+ group_wpa_s->p2p_go_acs_band = wpa_s->p2p_go_acs_band;
+ wpa_s->p2p_go_do_acs = 0;
+ }
+
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use separate group interface %s",
group_wpa_s->ifname);
group_wpa_s->p2p_first_connection_timeout = 0;
@@ -6098,7 +6335,7 @@
*/
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
int freq, int vht_center_freq2, int ht40, int vht,
- int max_oper_chwidth)
+ int max_oper_chwidth, int he)
{
struct p2p_go_neg_results params;
@@ -6112,12 +6349,14 @@
wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND");
wpas_p2p_stop_find_oper(wpa_s);
- freq = wpas_p2p_select_go_freq(wpa_s, freq);
- if (freq < 0)
- return -1;
+ if (!wpa_s->p2p_go_do_acs) {
+ freq = wpas_p2p_select_go_freq(wpa_s, freq);
+ if (freq < 0)
+ return -1;
+ }
if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, vht_center_freq2,
- ht40, vht, max_oper_chwidth, NULL))
+ ht40, vht, max_oper_chwidth, he, NULL))
return -1;
p2p_go_params(wpa_s->global->p2p, ¶ms);
@@ -6196,7 +6435,7 @@
struct wpa_ssid *ssid, int addr_allocated,
int force_freq, int neg_freq,
int vht_center_freq2, int ht40,
- int vht, int max_oper_chwidth,
+ int vht, int max_oper_chwidth, int he,
const struct p2p_channels *channels,
int connection_timeout, int force_scan)
{
@@ -6272,7 +6511,7 @@
}
if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, vht_center_freq2,
- ht40, vht, max_oper_chwidth, channels))
+ ht40, vht, max_oper_chwidth, he, channels))
return -1;
params.role_go = 1;
@@ -6824,7 +7063,7 @@
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
int vht_center_freq2, int ht40, int vht, int max_chwidth,
- int pref_freq)
+ int pref_freq, int he)
{
enum p2p_invite_role role;
u8 *bssid = NULL;
@@ -6842,6 +7081,7 @@
wpa_s->p2p_persistent_go_freq = freq;
wpa_s->p2p_go_ht40 = !!ht40;
wpa_s->p2p_go_vht = !!vht;
+ wpa_s->p2p_go_he = !!he;
wpa_s->p2p_go_max_oper_chwidth = max_chwidth;
wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
if (ssid->mode == WPAS_MODE_P2P_GO) {
@@ -6988,7 +7228,7 @@
u8 go_dev_addr[ETH_ALEN];
int persistent;
int freq;
- u8 ip[3 * 4];
+ u8 ip[3 * 4], *ip_ptr = NULL;
char ip_addr[100];
if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) {
@@ -7035,6 +7275,7 @@
ip[8], ip[9], ip[10], ip[11]);
if (os_snprintf_error(sizeof(ip_addr), res))
ip_addr[0] = '\0';
+ ip_ptr = ip;
}
wpas_p2p_group_started(wpa_s, 0, ssid, freq,
@@ -7047,7 +7288,7 @@
wpas_p2p_store_persistent_group(wpa_s->p2pdev,
ssid, go_dev_addr);
- wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 1, ip);
+ wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 1, ip_ptr);
}
@@ -7864,7 +8105,8 @@
wpa_s->p2p_pd_before_go_neg,
wpa_s->p2p_go_ht40,
wpa_s->p2p_go_vht,
- wpa_s->p2p_go_max_oper_chwidth, NULL, 0);
+ wpa_s->p2p_go_max_oper_chwidth,
+ wpa_s->p2p_go_he, NULL, 0);
return ret;
}
@@ -8400,6 +8642,7 @@
WPS_NFC, 0, 0, 1, 0, wpa_s->conf->p2p_go_intent,
params->go_freq, wpa_s->p2p_go_vht_center_freq2,
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
+ wpa_s->p2p_go_he,
params->go_ssid_len ? params->go_ssid : NULL,
params->go_ssid_len);
}
@@ -8479,7 +8722,7 @@
WPS_NFC, 0, 0, 0, 0, wpa_s->conf->p2p_go_intent,
forced_freq, wpa_s->p2p_go_vht_center_freq2,
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
- NULL, 0);
+ wpa_s->p2p_go_he, NULL, 0);
}
@@ -8495,7 +8738,7 @@
WPS_NFC, 0, 0, 0, 1, wpa_s->conf->p2p_go_intent,
forced_freq, wpa_s->p2p_go_vht_center_freq2,
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
- NULL, 0);
+ wpa_s->p2p_go_he, NULL, 0);
if (res)
return res;
@@ -8880,7 +9123,7 @@
* TODO: This function may not always work correctly. For example,
* when we have a running GO and a BSS on a DFS channel.
*/
- if (wpas_p2p_init_go_params(wpa_s, ¶ms, 0, 0, 0, 0, 0, NULL)) {
+ if (wpas_p2p_init_go_params(wpa_s, ¶ms, 0, 0, 0, 0, 0, 0, NULL)) {
wpa_dbg(wpa_s, MSG_DEBUG,
"P2P CSA: Failed to select new frequency for GO");
return -1;
@@ -8992,7 +9235,7 @@
wpa_supplicant_ap_deinit(wpa_s);
/* Reselect the GO frequency */
- if (wpas_p2p_init_go_params(wpa_s, ¶ms, 0, 0, 0, 0, 0, NULL)) {
+ if (wpas_p2p_init_go_params(wpa_s, ¶ms, 0, 0, 0, 0, 0, 0, NULL)) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Failed to reselect freq");
wpas_p2p_group_delete(wpa_s,
P2P_GROUP_REMOVAL_GO_LEAVE_CHANNEL);
@@ -9089,7 +9332,7 @@
freq = wpa_s->current_ssid->frequency;
dfs_offload = (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
- ieee80211_is_dfs(freq);
+ ieee80211_is_dfs(freq, wpa_s->hw.modes, wpa_s->hw.num_modes);
for (i = 0, invalid_freq = 0; i < num; i++) {
if (freqs[i].freq == freq) {
flags = freqs[i].flags;
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 63910d1..24ec2ca 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -37,18 +37,18 @@
int persistent_group, int auto_join, int join, int auth,
int go_intent, int freq, unsigned int vht_center_freq2,
int persistent_id, int pd, int ht40, int vht,
- unsigned int vht_chwidth, const u8 *group_ssid,
+ unsigned int vht_chwidth, int he, const u8 *group_ssid,
size_t group_ssid_len);
int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
int freq, struct wpa_ssid *ssid);
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
int freq, int vht_center_freq2, int ht40, int vht,
- int max_oper_chwidth);
+ int max_oper_chwidth, int he);
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
int force_freq, int neg_freq,
int vht_center_freq2, int ht40,
- int vht, int max_oper_chwidth,
+ int vht, int max_oper_chwidth, int he,
const struct p2p_channels *channels,
int connection_timeout, int force_scan);
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
@@ -117,7 +117,7 @@
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
int vht_center_freq2, int ht40, int vht,
- int max_oper_chwidth, int pref_freq);
+ int max_oper_chwidth, int pref_freq, int he);
int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
const u8 *peer_addr, const u8 *go_dev_addr);
int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
@@ -211,6 +211,7 @@
unsigned int period, unsigned int interval,
unsigned int count);
int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s);
+int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s);
#else /* CONFIG_P2P */
diff --git a/wpa_supplicant/p2p_supplicant_sd.c b/wpa_supplicant/p2p_supplicant_sd.c
index f8675e6..fb30584 100644
--- a/wpa_supplicant/p2p_supplicant_sd.c
+++ b/wpa_supplicant/p2p_supplicant_sd.c
@@ -559,9 +559,9 @@
const u8 *query, size_t query_len)
{
struct p2ps_advertisement *adv_data;
- const u8 *svc = &query[1];
+ const u8 *svc;
const u8 *info = NULL;
- size_t svc_len = query[0];
+ size_t svc_len;
size_t info_len = 0;
int prefix = 0;
u8 *count_pos = NULL;
@@ -569,6 +569,15 @@
wpa_hexdump(MSG_DEBUG, "P2P: SD Request for ASP", query, query_len);
+ if (query_len < 1) {
+ wpa_printf(MSG_DEBUG, "P2P: ASP bad request");
+ wpas_sd_add_bad_request(resp, P2P_SERV_P2PS, srv_trans_id);
+ return;
+ }
+
+ svc_len = query[0];
+ svc = &query[1];
+
if (!wpa_s->global->p2p) {
wpa_printf(MSG_DEBUG, "P2P: ASP protocol not available");
wpas_sd_add_proto_not_avail(resp, P2P_SERV_P2PS, srv_trans_id);
diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c
index a213a30..f2fff55 100644
--- a/wpa_supplicant/preauth_test.c
+++ b/wpa_supplicant/preauth_test.c
@@ -348,7 +348,7 @@
ret = -2;
else {
ret = pmksa_cache_set_current(wpa_s.wpa, NULL, bssid, NULL, 0,
- NULL) ? 0 : -3;
+ NULL, 0) ? 0 : -3;
}
test_eapol_clean(&wpa_s);
diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c
index f4fbfa7..cb3c6c9 100644
--- a/wpa_supplicant/rrm.c
+++ b/wpa_supplicant/rrm.c
@@ -392,17 +392,66 @@
}
+static int wpas_rrm_beacon_rep_update_last_frame(u8 *pos, size_t len)
+{
+ struct rrm_measurement_report_element *msr_rep;
+ u8 *end = pos + len;
+ u8 *msr_rep_end;
+ struct rrm_measurement_beacon_report *rep = NULL;
+ u8 *subelem;
+
+ /* Find the last beacon report element */
+ while (end - pos >= (int) sizeof(*msr_rep)) {
+ msr_rep = (struct rrm_measurement_report_element *) pos;
+ msr_rep_end = pos + msr_rep->len + 2;
+
+ if (msr_rep->eid != WLAN_EID_MEASURE_REPORT ||
+ msr_rep_end > end) {
+ /* Should not happen. This indicates a bug. */
+ wpa_printf(MSG_ERROR,
+ "RRM: non-measurement report element in measurement report frame");
+ return -1;
+ }
+
+ if (msr_rep->type == MEASURE_TYPE_BEACON)
+ rep = (struct rrm_measurement_beacon_report *)
+ msr_rep->variable;
+
+ pos += pos[1] + 2;
+ }
+
+ if (!rep)
+ return 0;
+
+ subelem = rep->variable;
+ while (subelem + 2 < msr_rep_end &&
+ subelem[0] != WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION)
+ subelem += 2 + subelem[1];
+
+ if (subelem + 2 < msr_rep_end &&
+ subelem[0] == WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION &&
+ subelem[1] == 1 &&
+ subelem + BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN <= end)
+ subelem[2] = 1;
+
+ return 0;
+}
+
+
static void wpas_rrm_send_msr_report(struct wpa_supplicant *wpa_s,
struct wpabuf *buf)
{
int len = wpabuf_len(buf);
- const u8 *pos = wpabuf_head_u8(buf), *next = pos;
+ u8 *pos = wpabuf_mhead_u8(buf), *next = pos;
#define MPDU_REPORT_LEN (int) (IEEE80211_MAX_MMPDU_SIZE - IEEE80211_HDRLEN - 3)
while (len) {
int send_len = (len > MPDU_REPORT_LEN) ? next - pos : len;
+ if (send_len == len)
+ wpas_rrm_beacon_rep_update_last_frame(pos, len);
+
if (send_len == len ||
(send_len + next[1] + 2) > MPDU_REPORT_LEN) {
wpas_rrm_send_msr_report_mpdu(wpa_s, pos, send_len);
@@ -707,15 +756,17 @@
static int wpas_beacon_rep_add_frame_body(struct bitfield *eids,
enum beacon_report_detail detail,
struct wpa_bss *bss, u8 *buf,
- size_t buf_len)
+ size_t buf_len, u8 **ies_buf,
+ size_t *ie_len, int add_fixed)
{
- u8 *ies = (u8 *) (bss + 1);
- size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
+ u8 *ies = *ies_buf;
+ size_t ies_len = *ie_len;
u8 *pos = buf;
int rem_len;
rem_len = 255 - sizeof(struct rrm_measurement_beacon_report) -
- sizeof(struct rrm_measurement_report_element) - 2;
+ sizeof(struct rrm_measurement_report_element) - 2 -
+ REPORTED_FRAME_BODY_SUBELEM_LEN;
if (detail > BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS) {
wpa_printf(MSG_DEBUG,
@@ -731,18 +782,21 @@
* Minimal frame body subelement size: EID(1) + length(1) + TSF(8) +
* beacon interval(2) + capabilities(2) = 14 bytes
*/
- if (buf_len < 14)
- return 0;
+ if (add_fixed && buf_len < 14)
+ return -1;
*pos++ = WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY;
/* The length will be filled later */
pos++;
- WPA_PUT_LE64(pos, bss->tsf);
- pos += sizeof(bss->tsf);
- WPA_PUT_LE16(pos, bss->beacon_int);
- pos += 2;
- WPA_PUT_LE16(pos, bss->caps);
- pos += 2;
+
+ if (add_fixed) {
+ WPA_PUT_LE64(pos, bss->tsf);
+ pos += sizeof(bss->tsf);
+ WPA_PUT_LE16(pos, bss->beacon_int);
+ pos += 2;
+ WPA_PUT_LE16(pos, bss->caps);
+ pos += 2;
+ }
rem_len -= pos - buf;
@@ -757,15 +811,7 @@
while (ies_len > 2 && 2U + ies[1] <= ies_len && rem_len > 0) {
if (detail == BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS ||
(eids && bitfield_is_set(eids, ies[0]))) {
- u8 eid = ies[0], elen = ies[1];
-
- if ((eid == WLAN_EID_TIM || eid == WLAN_EID_RSN) &&
- elen > 4)
- elen = 4;
- /*
- * TODO: Truncate IBSS DFS element as described in
- * IEEE Std 802.11-2016, 9.4.2.22.7.
- */
+ u8 elen = ies[1];
if (2 + elen > buf + buf_len - pos ||
2 + elen > rem_len)
@@ -782,22 +828,91 @@
ies += 2 + ies[1];
}
+ *ie_len = ies_len;
+ *ies_buf = ies;
+
/* Now the length is known */
buf[1] = pos - buf - 2;
return pos - buf;
}
+static int wpas_add_beacon_rep_elem(struct beacon_rep_data *data,
+ struct wpa_bss *bss,
+ struct wpabuf **wpa_buf,
+ struct rrm_measurement_beacon_report *rep,
+ u8 **ie, size_t *ie_len, u8 idx)
+{
+ int ret;
+ u8 *buf, *pos;
+ u32 subelems_len = REPORTED_FRAME_BODY_SUBELEM_LEN +
+ (data->last_indication ?
+ BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN : 0);
+
+ /* Maximum element length: Beacon Report element + Reported Frame Body
+ * subelement + all IEs of the reported Beacon frame + Reported Frame
+ * Body Fragment ID subelement */
+ buf = os_malloc(sizeof(*rep) + 14 + *ie_len + subelems_len);
+ if (!buf)
+ return -1;
+
+ os_memcpy(buf, rep, sizeof(*rep));
+
+ ret = wpas_beacon_rep_add_frame_body(data->eids, data->report_detail,
+ bss, buf + sizeof(*rep),
+ 14 + *ie_len, ie, ie_len,
+ idx == 0);
+ if (ret < 0)
+ goto out;
+
+ pos = buf + ret + sizeof(*rep);
+ pos[0] = WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY_FRAGMENT_ID;
+ pos[1] = 2;
+
+ /*
+ * Only one Beacon Report Measurement is supported at a time, so
+ * the Beacon Report ID can always be set to 1.
+ */
+ pos[2] = 1;
+
+ /* Fragment ID Number (bits 0..6) and More Frame Body Fragments (bit 7)
+ */
+ pos[3] = idx;
+ if (data->report_detail != BEACON_REPORT_DETAIL_NONE && *ie_len)
+ pos[3] |= REPORTED_FRAME_BODY_MORE_FRAGMENTS;
+ else
+ pos[3] &= ~REPORTED_FRAME_BODY_MORE_FRAGMENTS;
+
+ pos += REPORTED_FRAME_BODY_SUBELEM_LEN;
+
+ if (data->last_indication) {
+ pos[0] = WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION;
+ pos[1] = 1;
+
+ /* This field will be updated later if this is the last frame */
+ pos[2] = 0;
+ }
+
+ ret = wpas_rrm_report_elem(wpa_buf, data->token,
+ MEASUREMENT_REPORT_MODE_ACCEPT,
+ MEASURE_TYPE_BEACON, buf,
+ ret + sizeof(*rep) + subelems_len);
+out:
+ os_free(buf);
+ return ret;
+}
+
+
static int wpas_add_beacon_rep(struct wpa_supplicant *wpa_s,
struct wpabuf **wpa_buf, struct wpa_bss *bss,
u64 start, u64 parent_tsf)
{
struct beacon_rep_data *data = &wpa_s->beacon_rep_data;
- u8 *ie = (u8 *) (bss + 1);
- size_t ie_len = bss->ie_len + bss->beacon_ie_len;
- int ret;
- u8 *buf;
- struct rrm_measurement_beacon_report *rep;
+ u8 *ies = (u8 *) (bss + 1);
+ u8 *pos = ies;
+ size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
+ struct rrm_measurement_beacon_report rep;
+ u8 idx = 0;
if (os_memcmp(data->bssid, broadcast_ether_addr, ETH_ALEN) != 0 &&
os_memcmp(data->bssid, bss->bssid, ETH_ALEN) != 0)
@@ -808,39 +923,29 @@
os_memcmp(data->ssid, bss->ssid, bss->ssid_len) != 0))
return 0;
- /* Maximum element length: beacon report element + reported frame body
- * subelement + all IEs of the reported beacon */
- buf = os_malloc(sizeof(*rep) + 14 + ie_len);
- if (!buf)
- return -1;
+ if (wpas_get_op_chan_phy(bss->freq, ies, ies_len, &rep.op_class,
+ &rep.channel, &rep.report_info) < 0)
+ return 0;
- rep = (struct rrm_measurement_beacon_report *) buf;
- if (wpas_get_op_chan_phy(bss->freq, ie, ie_len, &rep->op_class,
- &rep->channel, &rep->report_info) < 0) {
- ret = 0;
- goto out;
- }
+ rep.start_time = host_to_le64(start);
+ rep.duration = host_to_le16(data->scan_params.duration);
+ rep.rcpi = rssi_to_rcpi(bss->level);
+ rep.rsni = 255; /* 255 indicates that RSNI is not available */
+ os_memcpy(rep.bssid, bss->bssid, ETH_ALEN);
+ rep.antenna_id = 0; /* unknown */
+ rep.parent_tsf = host_to_le32(parent_tsf);
- rep->start_time = host_to_le64(start);
- rep->duration = host_to_le16(data->scan_params.duration);
- rep->rcpi = rssi_to_rcpi(bss->level);
- rep->rsni = 255; /* 255 indicates that RSNI is not available */
- os_memcpy(rep->bssid, bss->bssid, ETH_ALEN);
- rep->antenna_id = 0; /* unknown */
- rep->parent_tsf = host_to_le32(parent_tsf);
+ do {
+ int ret;
- ret = wpas_beacon_rep_add_frame_body(data->eids, data->report_detail,
- bss, rep->variable, 14 + ie_len);
- if (ret < 0)
- goto out;
+ ret = wpas_add_beacon_rep_elem(data, bss, wpa_buf, &rep,
+ &pos, &ies_len, idx++);
+ if (ret)
+ return ret;
+ } while (data->report_detail != BEACON_REPORT_DETAIL_NONE &&
+ ies_len >= 2);
- ret = wpas_rrm_report_elem(wpa_buf, wpa_s->beacon_rep_data.token,
- MEASUREMENT_REPORT_MODE_ACCEPT,
- MEASURE_TYPE_BEACON, buf,
- ret + sizeof(*rep));
-out:
- os_free(buf);
- return ret;
+ return 0;
}
@@ -1006,6 +1111,16 @@
case WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL:
/* Skip - it will be processed when freqs are added */
break;
+ case WLAN_BEACON_REQUEST_SUBELEM_LAST_INDICATION:
+ if (slen != 1) {
+ wpa_printf(MSG_DEBUG,
+ "Beacon request: Invalid last indication request subelement length: %u",
+ slen);
+ return -1;
+ }
+
+ data->last_indication = subelem[0];
+ break;
default:
wpa_printf(MSG_DEBUG,
"Beacon request: Unknown subelement id %u", sid);
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 104b258..7abb028 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Scanning
- * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -455,6 +455,33 @@
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_MBO
+static void wpas_fils_req_param_add_max_channel(struct wpa_supplicant *wpa_s,
+ struct wpabuf **ie)
+{
+ if (wpabuf_resize(ie, 5)) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to allocate space for FILS Request Parameters element");
+ return;
+ }
+
+ /* FILS Request Parameters element */
+ wpabuf_put_u8(*ie, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(*ie, 3); /* FILS Request attribute length */
+ wpabuf_put_u8(*ie, WLAN_EID_EXT_FILS_REQ_PARAMS);
+ /* Parameter control bitmap */
+ wpabuf_put_u8(*ie, 0);
+ /* Max Channel Time field - contains the value of MaxChannelTime
+ * parameter of the MLME-SCAN.request primitive represented in units of
+ * TUs, as an unsigned integer. A Max Channel Time field value of 255
+ * is used to indicate any duration of more than 254 TUs, or an
+ * unspecified or unknown duration. (IEEE Std 802.11ai-2016, 9.4.2.178)
+ */
+ wpabuf_put_u8(*ie, 255);
+}
+#endif /* CONFIG_MBO */
+
+
void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s)
{
struct wpabuf *default_ies = NULL;
@@ -476,6 +503,8 @@
wpabuf_put_data(default_ies, ext_capab, ext_capab_len);
#ifdef CONFIG_MBO
+ if (wpa_s->enable_oce & OCE_STA)
+ wpas_fils_req_param_add_max_channel(wpa_s, &default_ies);
/* Send MBO and OCE capabilities */
if (wpabuf_resize(&default_ies, 12) == 0)
wpas_mbo_scan_ie(wpa_s, default_ies);
@@ -517,6 +546,11 @@
wpas_add_interworking_elements(wpa_s, extra_ie);
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_MBO
+ if (wpa_s->enable_oce & OCE_STA)
+ wpas_fils_req_param_add_max_channel(wpa_s, &extra_ie);
+#endif /* CONFIG_MBO */
+
#ifdef CONFIG_WPS
wps = wpas_wps_in_use(wpa_s, &req_type);
@@ -547,8 +581,8 @@
#endif /* CONFIG_WPS */
#ifdef CONFIG_HS20
- if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 7) == 0)
- wpas_hs20_add_indication(extra_ie, -1);
+ if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 9) == 0)
+ wpas_hs20_add_indication(extra_ie, -1, 0);
#endif /* CONFIG_HS20 */
#ifdef CONFIG_FST
@@ -643,6 +677,87 @@
}
+static void wpa_add_scan_ssid(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params,
+ size_t max_ssids, const u8 *ssid, size_t ssid_len)
+{
+ unsigned int j;
+
+ for (j = 0; j < params->num_ssids; j++) {
+ if (params->ssids[j].ssid_len == ssid_len &&
+ params->ssids[j].ssid &&
+ os_memcmp(params->ssids[j].ssid, ssid, ssid_len) == 0)
+ return; /* already in the list */
+ }
+
+ if (params->num_ssids + 1 > max_ssids) {
+ wpa_printf(MSG_DEBUG, "Over max scan SSIDs for manual request");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "Scan SSID (manual request): %s",
+ wpa_ssid_txt(ssid, ssid_len));
+
+ params->ssids[params->num_ssids].ssid = ssid;
+ params->ssids[params->num_ssids].ssid_len = ssid_len;
+ params->num_ssids++;
+}
+
+
+static void wpa_add_owe_scan_ssid(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params,
+ struct wpa_ssid *ssid, size_t max_ssids)
+{
+#ifdef CONFIG_OWE
+ struct wpa_bss *bss;
+
+ if (!(ssid->key_mgmt & WPA_KEY_MGMT_OWE))
+ return;
+
+ wpa_printf(MSG_DEBUG, "OWE: Look for transition mode AP. ssid=%s",
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ const u8 *owe, *pos, *end;
+ const u8 *owe_ssid;
+ size_t owe_ssid_len;
+
+ if (bss->ssid_len != ssid->ssid_len ||
+ os_memcmp(bss->ssid, ssid->ssid, ssid->ssid_len) != 0)
+ continue;
+
+ owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
+ if (!owe || owe[1] < 4)
+ continue;
+
+ pos = owe + 6;
+ end = owe + 2 + owe[1];
+
+ /* Must include BSSID and ssid_len */
+ if (end - pos < ETH_ALEN + 1)
+ return;
+
+ /* Skip BSSID */
+ pos += ETH_ALEN;
+ owe_ssid_len = *pos++;
+ owe_ssid = pos;
+
+ if ((size_t) (end - pos) < owe_ssid_len ||
+ owe_ssid_len > SSID_MAX_LEN)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "OWE: scan_ssids: transition mode OWE ssid=%s",
+ wpa_ssid_txt(owe_ssid, owe_ssid_len));
+
+ wpa_add_scan_ssid(wpa_s, params, max_ssids,
+ owe_ssid, owe_ssid_len);
+ return;
+ }
+#endif /* CONFIG_OWE */
+}
+
+
static void wpa_set_scan_ssids(struct wpa_supplicant *wpa_s,
struct wpa_driver_scan_params *params,
size_t max_ssids)
@@ -657,33 +772,17 @@
max_ssids = max_ssids > 1 ? max_ssids - 1 : max_ssids;
for (i = 0; i < wpa_s->scan_id_count; i++) {
- unsigned int j;
-
ssid = wpa_config_get_network(wpa_s->conf, wpa_s->scan_id[i]);
- if (!ssid || !ssid->scan_ssid)
+ if (!ssid)
continue;
-
- for (j = 0; j < params->num_ssids; j++) {
- if (params->ssids[j].ssid_len == ssid->ssid_len &&
- params->ssids[j].ssid &&
- os_memcmp(params->ssids[j].ssid, ssid->ssid,
- ssid->ssid_len) == 0)
- break;
- }
- if (j < params->num_ssids)
- continue; /* already in the list */
-
- if (params->num_ssids + 1 > max_ssids) {
- wpa_printf(MSG_DEBUG,
- "Over max scan SSIDs for manual request");
- break;
- }
-
- wpa_printf(MSG_DEBUG, "Scan SSID (manual request): %s",
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
- params->ssids[params->num_ssids].ssid = ssid->ssid;
- params->ssids[params->num_ssids].ssid_len = ssid->ssid_len;
- params->num_ssids++;
+ if (ssid->scan_ssid)
+ wpa_add_scan_ssid(wpa_s, params, max_ssids,
+ ssid->ssid, ssid->ssid_len);
+ /*
+ * Also add the SSID of the OWE BSS, to allow discovery of
+ * transition mode APs more quickly.
+ */
+ wpa_add_owe_scan_ssid(wpa_s, params, ssid, max_ssids);
}
wpa_s->scan_id_count = 0;
@@ -950,6 +1049,17 @@
if (params.num_ssids + 1 >= max_ssids)
break;
}
+
+ if (!wpas_network_disabled(wpa_s, ssid)) {
+ /*
+ * Also add the SSID of the OWE BSS, to allow
+ * discovery of transition mode APs more
+ * quickly.
+ */
+ wpa_add_owe_scan_ssid(wpa_s, ¶ms, ssid,
+ max_ssids);
+ }
+
ssid = ssid->next;
if (ssid == start)
break;
@@ -1077,6 +1187,11 @@
}
}
+#ifdef CONFIG_MBO
+ if (wpa_s->enable_oce & OCE_STA)
+ params.oce_scan = 1;
+#endif /* CONFIG_MBO */
+
params.filter_ssids = wpa_supplicant_build_filter_ssids(
wpa_s->conf, ¶ms.num_filter_ssids);
if (extra_ie) {
@@ -1486,6 +1601,11 @@
int_array_concat(¶ms.freqs, wpa_s->conf->freq_list);
}
+#ifdef CONFIG_MBO
+ if (wpa_s->enable_oce & OCE_STA)
+ params.oce_scan = 1;
+#endif /* CONFIG_MBO */
+
scan_params = ¶ms;
scan:
@@ -1873,7 +1993,8 @@
/* if SNR is close, decide by max rate or frequency band */
if (snr_a && snr_b && abs(snr_b - snr_a) < 7) {
if (wa->est_throughput != wb->est_throughput)
- return wb->est_throughput - wa->est_throughput;
+ return (int) wb->est_throughput -
+ (int) wa->est_throughput;
}
if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) ||
(wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) {
@@ -2401,6 +2522,7 @@
params->low_priority = src->low_priority;
params->duration = src->duration;
params->duration_mandatory = src->duration_mandatory;
+ params->oce_scan = src->oce_scan;
if (src->sched_scan_plans_num > 0) {
params->sched_scan_plans =
@@ -2685,6 +2807,13 @@
{
u8 *tmp = NULL;
+ if ((wpa_s->mac_addr_rand_supported & type) != type ) {
+ wpa_printf(MSG_INFO,
+ "scan: MAC randomization type %u != supported=%u",
+ type, wpa_s->mac_addr_rand_supported);
+ return -1;
+ }
+
wpas_mac_addr_rand_scan_clear(wpa_s, type);
if (addr) {
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index da0e8eb..17a984d 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -12,9 +12,11 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/ocv.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "common/wpa_common.h"
#include "common/sae.h"
+#include "common/dpp.h"
#include "rsn_supp/wpa.h"
#include "rsn_supp/pmksa_cache.h"
#include "config.h"
@@ -56,7 +58,7 @@
static int sme_set_sae_group(struct wpa_supplicant *wpa_s)
{
int *groups = wpa_s->conf->sae_groups;
- int default_groups[] = { 19, 20, 21, 25, 26, 0 };
+ int default_groups[] = { 19, 20, 21, 0 };
if (!groups || groups[0] <= 0)
groups = default_groups;
@@ -72,7 +74,7 @@
if (sae_set_group(&wpa_s->sme.sae, group) == 0) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected SAE group %d",
wpa_s->sme.sae.group);
- return 0;
+ return 0;
}
wpa_s->sme.sae_group_index++;
}
@@ -83,7 +85,8 @@
static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
- const u8 *bssid)
+ const u8 *bssid, int external,
+ int reuse)
{
struct wpabuf *buf;
size_t len;
@@ -95,8 +98,10 @@
buf = wpabuf_alloc(4 + wpabuf_len(wpa_s->sae_commit_override));
if (!buf)
return NULL;
- wpabuf_put_le16(buf, 1); /* Transaction seq# */
- wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ if (!external) {
+ wpabuf_put_le16(buf, 1); /* Transaction seq# */
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ }
wpabuf_put_buf(buf, wpa_s->sae_commit_override);
return buf;
}
@@ -110,6 +115,12 @@
return NULL;
}
+ if (reuse && wpa_s->sme.sae.tmp &&
+ 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");
+ goto reuse_data;
+ }
if (sme_set_sae_group(wpa_s) < 0) {
wpa_printf(MSG_DEBUG, "SAE: Failed to select group");
return NULL;
@@ -117,25 +128,34 @@
if (sae_prepare_commit(wpa_s->own_addr, bssid,
(u8 *) password, os_strlen(password),
+ ssid->sae_password_id,
&wpa_s->sme.sae) < 0) {
wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
return NULL;
}
+ if (wpa_s->sme.sae.tmp)
+ os_memcpy(wpa_s->sme.sae.tmp->bssid, bssid, ETH_ALEN);
+reuse_data:
len = wpa_s->sme.sae_token ? wpabuf_len(wpa_s->sme.sae_token) : 0;
+ if (ssid->sae_password_id)
+ len += 4 + os_strlen(ssid->sae_password_id);
buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + len);
if (buf == NULL)
return NULL;
-
- wpabuf_put_le16(buf, 1); /* Transaction seq# */
- wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
- sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token);
+ if (!external) {
+ wpabuf_put_le16(buf, 1); /* Transaction seq# */
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ }
+ sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token,
+ ssid->sae_password_id);
return buf;
}
-static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s)
+static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s,
+ int external)
{
struct wpabuf *buf;
@@ -143,8 +163,10 @@
if (buf == NULL)
return NULL;
- wpabuf_put_le16(buf, 2); /* Transaction seq# */
- wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ if (!external) {
+ wpabuf_put_le16(buf, 2); /* Transaction seq# */
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ }
sae_write_confirm(&wpa_s->sme.sae, buf);
return buf;
@@ -232,6 +254,11 @@
u8 ext_capab[18];
int ext_capab_len;
int skip_auth;
+ u8 *wpa_ie;
+ size_t wpa_ie_len;
+#ifdef CONFIG_MBO
+ const u8 *mbo_ie;
+#endif /* CONFIG_MBO */
if (bss == NULL) {
wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
@@ -289,6 +316,12 @@
if (!rsn) {
wpa_dbg(wpa_s, MSG_DEBUG,
"SAE enabled, but target BSS does not advertise RSN");
+#ifdef CONFIG_DPP
+ } else if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 &&
+ (ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
+ (ied.key_mgmt & WPA_KEY_MGMT_DPP)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Prefer DPP over SAE when both are enabled");
+#endif /* CONFIG_DPP */
} else if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 &&
wpa_key_mgmt_sae(ied.key_mgmt)) {
wpa_dbg(wpa_s, MSG_DEBUG, "Using SAE auth_alg");
@@ -329,7 +362,8 @@
#endif /* CONFIG_FILS */
if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
wpa_s->current_ssid,
- try_opportunistic, cache_id) == 0)
+ try_opportunistic, cache_id,
+ 0) == 0)
eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
@@ -340,6 +374,20 @@
wpas_connect_work_done(wpa_s);
return;
}
+#ifdef CONFIG_HS20
+ } else if (wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE) &&
+ (ssid->key_mgmt & WPA_KEY_MGMT_OSEN)) {
+ /* No PMKSA caching, but otherwise similar to RSN/WPA */
+ wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
+ if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
+ wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len)) {
+ wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
+ "key management and encryption suites");
+ wpas_connect_work_done(wpa_s);
+ return;
+ }
+#endif /* CONFIG_HS20 */
} else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
/*
@@ -379,18 +427,41 @@
wpa_s->sme.assoc_req_ie_len = 0;
}
+ /* In case the WPA vendor IE is used, it should be placed after all the
+ * non-vendor IEs, as the lower layer expects the IEs to be ordered as
+ * defined in the standard. Store the WPA IE so it can later be
+ * inserted at the correct location.
+ */
+ wpa_ie = NULL;
+ wpa_ie_len = 0;
+ if (wpa_s->wpa_proto == WPA_PROTO_WPA) {
+ wpa_ie = os_memdup(wpa_s->sme.assoc_req_ie,
+ wpa_s->sme.assoc_req_ie_len);
+ if (wpa_ie) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Storing WPA IE");
+
+ wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
+ wpa_s->sme.assoc_req_ie_len = 0;
+ } else {
+ wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed copy WPA IE");
+ wpas_connect_work_done(wpa_s);
+ return;
+ }
+ }
+
#ifdef CONFIG_IEEE80211R
ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
md = ie + 2;
wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
+ if (md && (!wpa_key_mgmt_ft(ssid->key_mgmt) ||
+ !wpa_key_mgmt_ft(wpa_s->key_mgmt)))
+ md = NULL;
if (md) {
/* Prepare for the next transition */
wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
}
- if (md && !wpa_key_mgmt_ft(ssid->key_mgmt))
- md = NULL;
if (md) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: FT mobility domain %02x%02x",
md[0], md[1]);
@@ -409,7 +480,7 @@
wpa_s->sme.assoc_req_ie_len += 5;
}
- if (wpa_s->sme.ft_used &&
+ if (wpa_s->sme.prev_bssid_set && wpa_s->sme.ft_used &&
os_memcmp(md, wpa_s->sme.mobility_domain, 2) == 0 &&
wpa_sm_has_ptk(wpa_s->wpa)) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying to use FT "
@@ -469,7 +540,7 @@
sme_auth_handle_rrm(wpa_s, bss);
wpa_s->sme.assoc_req_ie_len += wpas_supp_op_class_ie(
- wpa_s, bss->freq,
+ wpa_s, ssid, bss->freq,
wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len);
@@ -495,12 +566,14 @@
if (is_hs20_network(wpa_s, ssid, bss)) {
struct wpabuf *hs20;
- hs20 = wpabuf_alloc(20);
+ hs20 = wpabuf_alloc(20 + MAX_ROAMING_CONS_OI_LEN);
if (hs20) {
int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
size_t len;
- wpas_hs20_add_indication(hs20, pps_mo_id);
+ wpas_hs20_add_indication(hs20, pps_mo_id,
+ get_hs20_version(bss));
+ wpas_hs20_add_roam_cons_sel(hs20, ssid);
len = sizeof(wpa_s->sme.assoc_req_ie) -
wpa_s->sme.assoc_req_ie_len;
if (wpabuf_len(hs20) <= len) {
@@ -514,6 +587,26 @@
}
#endif /* CONFIG_HS20 */
+ if (wpa_ie) {
+ size_t len;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Reinsert WPA IE");
+
+ len = sizeof(wpa_s->sme.assoc_req_ie) -
+ wpa_s->sme.assoc_req_ie_len;
+
+ if (len > wpa_ie_len) {
+ os_memcpy(wpa_s->sme.assoc_req_ie +
+ wpa_s->sme.assoc_req_ie_len,
+ wpa_ie, wpa_ie_len);
+ wpa_s->sme.assoc_req_ie_len += wpa_ie_len;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Failed to add WPA IE");
+ }
+
+ os_free(wpa_ie);
+ }
+
if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
size_t len;
@@ -529,13 +622,16 @@
}
#ifdef CONFIG_MBO
- if (wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) {
+ mbo_ie = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
+ if (mbo_ie) {
int len;
len = wpas_mbo_ie(wpa_s, wpa_s->sme.assoc_req_ie +
wpa_s->sme.assoc_req_ie_len,
sizeof(wpa_s->sme.assoc_req_ie) -
- wpa_s->sme.assoc_req_ie_len);
+ wpa_s->sme.assoc_req_ie_len,
+ !!mbo_attr_from_mbo_ie(mbo_ie,
+ OCE_ATTR_ID_CAPA_IND));
if (len >= 0)
wpa_s->sme.assoc_req_ie_len += len;
}
@@ -544,9 +640,13 @@
#ifdef CONFIG_SAE
if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE &&
pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0,
- NULL) == 0) {
+ NULL,
+ wpa_s->key_mgmt == WPA_KEY_MGMT_FT_SAE ?
+ WPA_KEY_MGMT_FT_SAE :
+ WPA_KEY_MGMT_SAE) == 0) {
wpa_dbg(wpa_s, MSG_DEBUG,
"PMKSA cache entry found - try to use PMKSA caching instead of new SAE authentication");
+ wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
params.auth_alg = WPA_AUTH_ALG_OPEN;
wpa_s->sme.sae_pmksa_caching = 1;
}
@@ -554,9 +654,10 @@
if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE) {
if (start)
resp = sme_auth_build_sae_commit(wpa_s, ssid,
- bss->bssid);
+ bss->bssid, 0,
+ start == 2);
else
- resp = sme_auth_build_sae_confirm(wpa_s);
+ resp = sme_auth_build_sae_confirm(wpa_s, 0);
if (resp == NULL) {
wpas_connection_failed(wpa_s, bss->bssid);
return;
@@ -580,6 +681,9 @@
wpa_key_mgmt_fils(ssid->key_mgmt)) {
const u8 *indic;
u16 fils_info;
+ const u8 *realm, *username, *rrk;
+ size_t realm_len, username_len, rrk_len;
+ u16 next_seq_num;
/*
* Check FILS Indication element (FILS Information field) bits
@@ -609,10 +713,23 @@
goto no_fils;
}
+ if (wpa_s->last_con_fail_realm &&
+ eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap,
+ &username, &username_len,
+ &realm, &realm_len, &next_seq_num,
+ &rrk, &rrk_len) == 0 &&
+ realm && realm_len == wpa_s->last_con_fail_realm_len &&
+ os_memcmp(realm, wpa_s->last_con_fail_realm,
+ realm_len) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "SME: FILS authentication for this realm failed last time - try to regenerate ERP key hierarchy");
+ goto no_fils;
+ }
+
if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
ssid, 0,
- wpa_bss_get_fils_cache_id(bss)) ==
- 0)
+ wpa_bss_get_fils_cache_id(bss),
+ 0) == 0)
wpa_printf(MSG_DEBUG,
"SME: Try to use FILS with PMKSA caching");
resp = fils_build_auth(wpa_s->wpa, ssid->fils_dh_group, md);
@@ -789,8 +906,150 @@
#ifdef CONFIG_SAE
+static int sme_external_auth_build_buf(struct wpabuf *buf,
+ struct wpabuf *params,
+ const u8 *sa, const u8 *da,
+ u16 auth_transaction, u16 seq_num)
+{
+ struct ieee80211_mgmt *resp;
+
+ resp = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
+ u.auth.variable));
+
+ resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_AUTH << 4));
+ os_memcpy(resp->da, da, ETH_ALEN);
+ os_memcpy(resp->sa, sa, ETH_ALEN);
+ os_memcpy(resp->bssid, da, ETH_ALEN);
+ resp->u.auth.auth_alg = host_to_le16(WLAN_AUTH_SAE);
+ resp->seq_ctrl = host_to_le16(seq_num << 4);
+ resp->u.auth.auth_transaction = host_to_le16(auth_transaction);
+ resp->u.auth.status_code = host_to_le16(WLAN_STATUS_SUCCESS);
+ if (params)
+ wpabuf_put_buf(buf, params);
+
+ return 0;
+}
+
+
+static void sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s,
+ const u8 *bssid,
+ struct wpa_ssid *ssid)
+{
+ struct wpabuf *resp, *buf;
+
+ resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0);
+ if (!resp)
+ return;
+
+ wpa_s->sme.sae.state = SAE_COMMITTED;
+ buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + wpabuf_len(resp));
+ if (!buf) {
+ wpabuf_free(resp);
+ return;
+ }
+
+ wpa_s->sme.seq_num++;
+ sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
+ bssid, 1, wpa_s->sme.seq_num);
+ wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0);
+ wpabuf_free(resp);
+ wpabuf_free(buf);
+}
+
+
+static void sme_send_external_auth_status(struct wpa_supplicant *wpa_s,
+ u16 status)
+{
+ struct external_auth params;
+
+ os_memset(¶ms, 0, sizeof(params));
+ params.status = status;
+ params.ssid = wpa_s->sme.ext_auth.ssid;
+ params.ssid_len = wpa_s->sme.ext_auth.ssid_len;
+ params.bssid = wpa_s->sme.ext_auth.bssid;
+ wpa_drv_send_external_auth_status(wpa_s, ¶ms);
+}
+
+
+static void sme_handle_external_auth_start(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ struct wpa_ssid *ssid;
+ size_t ssid_str_len = data->external_auth.ssid_len;
+ const u8 *ssid_str = data->external_auth.ssid;
+
+ /* Get the SSID conf from the ssid string obtained */
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (!wpas_network_disabled(wpa_s, ssid) &&
+ ssid_str_len == ssid->ssid_len &&
+ os_memcmp(ssid_str, ssid->ssid, ssid_str_len) == 0 &&
+ (ssid->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE)))
+ break;
+ }
+ if (ssid)
+ sme_external_auth_send_sae_commit(wpa_s,
+ data->external_auth.bssid,
+ ssid);
+ else
+ sme_send_external_auth_status(wpa_s,
+ WLAN_STATUS_UNSPECIFIED_FAILURE);
+}
+
+
+static void sme_external_auth_send_sae_confirm(struct wpa_supplicant *wpa_s,
+ const u8 *da)
+{
+ struct wpabuf *resp, *buf;
+
+ resp = sme_auth_build_sae_confirm(wpa_s, 1);
+ if (!resp) {
+ wpa_printf(MSG_DEBUG, "SAE: Confirm message buf alloc failure");
+ return;
+ }
+
+ wpa_s->sme.sae.state = SAE_CONFIRMED;
+ buf = wpabuf_alloc(4 + SAE_CONFIRM_MAX_LEN + wpabuf_len(resp));
+ if (!buf) {
+ wpa_printf(MSG_DEBUG, "SAE: Auth Confirm buf alloc failure");
+ wpabuf_free(resp);
+ return;
+ }
+ wpa_s->sme.seq_num++;
+ sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
+ da, 2, wpa_s->sme.seq_num);
+ wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0);
+ wpabuf_free(resp);
+ wpabuf_free(buf);
+}
+
+
+void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ if (RSN_SELECTOR_GET(&data->external_auth.key_mgmt_suite) !=
+ RSN_AUTH_KEY_MGMT_SAE)
+ return;
+
+ if (data->external_auth.action == EXT_AUTH_START) {
+ os_memcpy(&wpa_s->sme.ext_auth, data,
+ sizeof(struct external_auth));
+ wpa_s->sme.seq_num = 0;
+ wpa_s->sme.sae.state = SAE_NOTHING;
+ wpa_s->sme.sae.send_confirm = 0;
+ wpa_s->sme.sae_group_index = 0;
+ sme_handle_external_auth_start(wpa_s, data);
+ } else if (data->external_auth.action == EXT_AUTH_ABORT) {
+ /* Report failure to driver for the wrong trigger */
+ sme_send_external_auth_status(wpa_s,
+ WLAN_STATUS_UNSPECIFIED_FAILURE);
+ }
+}
+
+
static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
- u16 status_code, const u8 *data, size_t len)
+ u16 status_code, const u8 *data, size_t len,
+ int external, const u8 *sa)
{
int *groups;
@@ -800,8 +1059,8 @@
if (auth_transaction == 1 &&
status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
wpa_s->sme.sae.state == SAE_COMMITTED &&
- wpa_s->current_bss && wpa_s->current_ssid) {
- int default_groups[] = { 19, 20, 21, 25, 26, 0 };
+ (external || wpa_s->current_bss) && wpa_s->current_ssid) {
+ int default_groups[] = { 19, 20, 21, 0 };
u16 group;
groups = wpa_s->conf->sae_groups;
@@ -827,25 +1086,45 @@
wpabuf_free(wpa_s->sme.sae_token);
wpa_s->sme.sae_token = wpabuf_alloc_copy(data + sizeof(le16),
len - sizeof(le16));
- sme_send_authentication(wpa_s, wpa_s->current_bss,
- wpa_s->current_ssid, 1);
+ if (!external)
+ sme_send_authentication(wpa_s, wpa_s->current_bss,
+ wpa_s->current_ssid, 2);
+ else
+ sme_external_auth_send_sae_commit(
+ wpa_s, wpa_s->sme.ext_auth.bssid,
+ wpa_s->current_ssid);
return 0;
}
if (auth_transaction == 1 &&
status_code == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
wpa_s->sme.sae.state == SAE_COMMITTED &&
- wpa_s->current_bss && wpa_s->current_ssid) {
+ (external || wpa_s->current_bss) && wpa_s->current_ssid) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE group not supported");
wpa_s->sme.sae_group_index++;
if (sme_set_sae_group(wpa_s) < 0)
return -1; /* no other groups enabled */
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Try next enabled SAE group");
- sme_send_authentication(wpa_s, wpa_s->current_bss,
- wpa_s->current_ssid, 1);
+ if (!external)
+ sme_send_authentication(wpa_s, wpa_s->current_bss,
+ wpa_s->current_ssid, 1);
+ else
+ sme_external_auth_send_sae_commit(
+ wpa_s, wpa_s->sme.ext_auth.bssid,
+ wpa_s->current_ssid);
return 0;
}
+ if (auth_transaction == 1 &&
+ status_code == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) {
+ const u8 *bssid = sa ? sa : wpa_s->pending_bssid;
+
+ wpa_msg(wpa_s, MSG_INFO,
+ WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER MACSTR,
+ MAC2STR(bssid));
+ return -1;
+ }
+
if (status_code != WLAN_STATUS_SUCCESS)
return -1;
@@ -855,7 +1134,7 @@
groups = wpa_s->conf->sae_groups;
wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit");
- if (wpa_s->current_bss == NULL ||
+ if ((!external && wpa_s->current_bss == NULL) ||
wpa_s->current_ssid == NULL)
return -1;
if (wpa_s->sme.sae.state != SAE_COMMITTED)
@@ -880,8 +1159,11 @@
wpabuf_free(wpa_s->sme.sae_token);
wpa_s->sme.sae_token = NULL;
- sme_send_authentication(wpa_s, wpa_s->current_bss,
- wpa_s->current_ssid, 0);
+ if (!external)
+ sme_send_authentication(wpa_s, wpa_s->current_bss,
+ wpa_s->current_ssid, 0);
+ else
+ sme_external_auth_send_sae_confirm(wpa_s, sa);
return 0;
} else if (auth_transaction == 2) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm");
@@ -891,11 +1173,60 @@
return -1;
wpa_s->sme.sae.state = SAE_ACCEPTED;
sae_clear_temp_data(&wpa_s->sme.sae);
+
+ if (external) {
+ /* Report success to driver */
+ sme_send_external_auth_status(wpa_s,
+ WLAN_STATUS_SUCCESS);
+ }
+
return 1;
}
return -1;
}
+
+
+void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s,
+ const u8 *auth_frame, size_t len)
+{
+ const struct ieee80211_mgmt *header;
+ size_t auth_length;
+
+ header = (const struct ieee80211_mgmt *) auth_frame;
+ auth_length = IEEE80211_HDRLEN + sizeof(header->u.auth);
+
+ if (len < auth_length) {
+ /* Notify failure to the driver */
+ sme_send_external_auth_status(wpa_s,
+ WLAN_STATUS_UNSPECIFIED_FAILURE);
+ return;
+ }
+
+ if (le_to_host16(header->u.auth.auth_alg) == WLAN_AUTH_SAE) {
+ int res;
+
+ res = sme_sae_auth(
+ wpa_s, le_to_host16(header->u.auth.auth_transaction),
+ le_to_host16(header->u.auth.status_code),
+ header->u.auth.variable,
+ len - auth_length, 1, header->sa);
+ if (res < 0) {
+ /* Notify failure to the driver */
+ sme_send_external_auth_status(
+ wpa_s, WLAN_STATUS_UNSPECIFIED_FAILURE);
+ return;
+ }
+ if (res != 1)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "SME: SAE completed - setting PMK for 4-way handshake");
+ wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN,
+ wpa_s->sme.sae.pmkid, wpa_s->pending_bssid);
+ }
+}
+
#endif /* CONFIG_SAE */
@@ -936,7 +1267,7 @@
int res;
res = sme_sae_auth(wpa_s, data->auth.auth_transaction,
data->auth.status_code, data->auth.ies,
- data->auth.ies_len);
+ data->auth.ies_len, 0, NULL);
if (res < 0) {
wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
@@ -971,6 +1302,12 @@
ie_txt ? ie_txt : "");
os_free(ie_txt);
+#ifdef CONFIG_FILS
+ if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS ||
+ wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS_SK_PFS)
+ fils_connection_failure(wpa_s);
+#endif /* CONFIG_FILS */
+
if (data->auth.status_code !=
WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG ||
wpa_s->sme.auth_alg == data->auth.auth_type ||
@@ -1074,7 +1411,6 @@
}
-#ifdef CONFIG_FILS
#ifdef CONFIG_IEEE80211R
static void remove_ie(u8 *buf, size_t *len, u8 eid)
{
@@ -1089,7 +1425,6 @@
}
}
#endif /* CONFIG_IEEE80211R */
-#endif /* CONFIG_FILS */
void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
@@ -1204,10 +1539,24 @@
if (auth_type == WLAN_AUTH_OPEN &&
wpa_s->key_mgmt == WPA_KEY_MGMT_OWE) {
struct wpabuf *owe_ie;
- u16 group = OWE_DH_GROUP;
+ u16 group;
- if (wpa_s->current_ssid && wpa_s->current_ssid->owe_group)
+ if (wpa_s->current_ssid && wpa_s->current_ssid->owe_group) {
group = wpa_s->current_ssid->owe_group;
+ } else if (wpa_s->assoc_status_code ==
+ WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
+ if (wpa_s->last_owe_group == 19)
+ group = 20;
+ else if (wpa_s->last_owe_group == 20)
+ group = 21;
+ else
+ group = OWE_DH_GROUP;
+ } else {
+ group = OWE_DH_GROUP;
+ }
+
+ wpa_s->last_owe_group = group;
+ wpa_printf(MSG_DEBUG, "OWE: Try to use group %u", group);
owe_ie = owe_build_assoc_req(wpa_s->wpa, group);
if (!owe_ie) {
wpa_printf(MSG_ERROR,
@@ -1228,6 +1577,52 @@
}
#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP2
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && wpa_s->current_ssid &&
+ wpa_s->current_ssid->dpp_netaccesskey) {
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ dpp_pfs_free(wpa_s->dpp_pfs);
+ wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey,
+ ssid->dpp_netaccesskey_len);
+ if (!wpa_s->dpp_pfs) {
+ wpa_printf(MSG_DEBUG, "DPP: Could not initialize PFS");
+ /* Try to continue without PFS */
+ goto pfs_fail;
+ }
+ if (wpa_s->sme.assoc_req_ie_len +
+ wpabuf_len(wpa_s->dpp_pfs->ie) >
+ sizeof(wpa_s->sme.assoc_req_ie)) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Not enough buffer room for own Association Request frame elements");
+ dpp_pfs_free(wpa_s->dpp_pfs);
+ wpa_s->dpp_pfs = NULL;
+ goto pfs_fail;
+ }
+ os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+ wpabuf_head(wpa_s->dpp_pfs->ie),
+ wpabuf_len(wpa_s->dpp_pfs->ie));
+ wpa_s->sme.assoc_req_ie_len += wpabuf_len(wpa_s->dpp_pfs->ie);
+ }
+pfs_fail:
+#endif /* CONFIG_DPP2 */
+
+ if (wpa_s->current_ssid && wpa_s->current_ssid->multi_ap_backhaul_sta) {
+ size_t multi_ap_ie_len;
+
+ multi_ap_ie_len = add_multi_ap_ie(
+ wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+ sizeof(wpa_s->sme.assoc_req_ie) -
+ wpa_s->sme.assoc_req_ie_len,
+ MULTI_AP_BACKHAUL_STA);
+ if (multi_ap_ie_len == 0) {
+ wpa_printf(MSG_ERROR,
+ "Multi-AP: Failed to build Multi-AP IE");
+ return;
+ }
+ wpa_s->sme.assoc_req_ie_len += multi_ap_ie_len;
+ }
+
params.bssid = bssid;
params.ssid = wpa_s->sme.ssid;
params.ssid_len = wpa_s->sme.ssid_len;
@@ -1237,6 +1632,8 @@
params.wpa_ie = wpa_s->sme.assoc_req_ie_len ?
wpa_s->sme.assoc_req_ie : NULL;
params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
+ wpa_hexdump(MSG_DEBUG, "SME: Association Request IEs",
+ params.wpa_ie, params.wpa_ie_len);
params.pairwise_suite = wpa_s->pairwise_cipher;
params.group_suite = wpa_s->group_cipher;
params.mgmt_group_suite = wpa_s->mgmt_group_cipher;
@@ -1257,9 +1654,85 @@
wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, ¶ms);
#endif /* CONFIG_VHT_OVERRIDES */
#ifdef CONFIG_IEEE80211R
- if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) {
+ if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies &&
+ get_ie(wpa_s->sme.ft_ies, wpa_s->sme.ft_ies_len,
+ WLAN_EID_RIC_DATA)) {
+ /* There seems to be a pretty inconvenient bug in the Linux
+ * kernel IE splitting functionality when RIC is used. For now,
+ * skip correct behavior in IE construction here (i.e., drop the
+ * additional non-FT-specific IEs) to avoid kernel issues. This
+ * is fine since RIC is used only for testing purposes in the
+ * current implementation. */
+ wpa_printf(MSG_INFO,
+ "SME: Linux kernel workaround - do not try to include additional IEs with RIC");
params.wpa_ie = wpa_s->sme.ft_ies;
params.wpa_ie_len = wpa_s->sme.ft_ies_len;
+ } else if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) {
+ const u8 *rm_en, *pos, *end;
+ size_t rm_en_len = 0;
+ u8 *rm_en_dup = NULL, *wpos;
+
+ /* Remove RSNE, MDE, FTE to allow them to be overridden with
+ * FT specific values */
+ remove_ie(wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len,
+ WLAN_EID_RSN);
+ remove_ie(wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len,
+ WLAN_EID_MOBILITY_DOMAIN);
+ remove_ie(wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len,
+ WLAN_EID_FAST_BSS_TRANSITION);
+ rm_en = get_ie(wpa_s->sme.assoc_req_ie,
+ wpa_s->sme.assoc_req_ie_len,
+ WLAN_EID_RRM_ENABLED_CAPABILITIES);
+ if (rm_en) {
+ /* Need to remove RM Enabled Capabilities element as
+ * well temporarily, so that it can be placed between
+ * RSNE and MDE. */
+ rm_en_len = 2 + rm_en[1];
+ rm_en_dup = os_memdup(rm_en, rm_en_len);
+ remove_ie(wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len,
+ WLAN_EID_RRM_ENABLED_CAPABILITIES);
+ }
+ wpa_hexdump(MSG_DEBUG,
+ "SME: Association Request IEs after FT IE removal",
+ wpa_s->sme.assoc_req_ie,
+ wpa_s->sme.assoc_req_ie_len);
+ if (wpa_s->sme.assoc_req_ie_len + wpa_s->sme.ft_ies_len +
+ rm_en_len > sizeof(wpa_s->sme.assoc_req_ie)) {
+ wpa_printf(MSG_ERROR,
+ "SME: Not enough buffer room for FT IEs in Association Request frame");
+ os_free(rm_en_dup);
+ return;
+ }
+
+ os_memmove(wpa_s->sme.assoc_req_ie + wpa_s->sme.ft_ies_len +
+ rm_en_len,
+ wpa_s->sme.assoc_req_ie,
+ wpa_s->sme.assoc_req_ie_len);
+ pos = wpa_s->sme.ft_ies;
+ end = pos + wpa_s->sme.ft_ies_len;
+ wpos = wpa_s->sme.assoc_req_ie;
+ if (*pos == WLAN_EID_RSN) {
+ os_memcpy(wpos, pos, 2 + pos[1]);
+ wpos += 2 + pos[1];
+ pos += 2 + pos[1];
+ }
+ if (rm_en_dup) {
+ os_memcpy(wpos, rm_en_dup, rm_en_len);
+ wpos += rm_en_len;
+ os_free(rm_en_dup);
+ }
+ os_memcpy(wpos, pos, end - pos);
+ wpa_s->sme.assoc_req_ie_len += wpa_s->sme.ft_ies_len +
+ rm_en_len;
+ params.wpa_ie = wpa_s->sme.assoc_req_ie;
+ params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
+ wpa_hexdump(MSG_DEBUG,
+ "SME: Association Request IEs after FT override",
+ params.wpa_ie, params.wpa_ie_len);
}
#endif /* CONFIG_IEEE80211R */
params.mode = mode;
@@ -1509,20 +1982,17 @@
sae_clear_data(&wpa_s->sme.sae);
#endif /* CONFIG_SAE */
#ifdef CONFIG_IEEE80211R
- if (wpa_s->sme.ft_ies)
+ if (wpa_s->sme.ft_ies || wpa_s->sme.ft_used)
sme_update_ft_ies(wpa_s, NULL, NULL, 0);
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+ sme_stop_sa_query(wpa_s);
+#endif /* CONFIG_IEEE80211W */
}
void sme_deinit(struct wpa_supplicant *wpa_s)
{
- os_free(wpa_s->sme.ft_ies);
- wpa_s->sme.ft_ies = NULL;
- wpa_s->sme.ft_ies_len = 0;
-#ifdef CONFIG_IEEE80211W
- sme_stop_sa_query(wpa_s);
-#endif /* CONFIG_IEEE80211W */
sme_clear_on_disassoc(wpa_s);
eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
@@ -1816,6 +2286,7 @@
static const unsigned int sa_query_max_timeout = 1000;
static const unsigned int sa_query_retry_timeout = 201;
+static const unsigned int sa_query_ch_switch_max_delay = 5000; /* in usec */
static int sme_check_sa_query_timeout(struct wpa_supplicant *wpa_s)
{
@@ -1839,7 +2310,9 @@
static void sme_send_sa_query_req(struct wpa_supplicant *wpa_s,
const u8 *trans_id)
{
- u8 req[2 + WLAN_SA_QUERY_TR_ID_LEN];
+ u8 req[2 + WLAN_SA_QUERY_TR_ID_LEN + OCV_OCI_EXTENDED_LEN];
+ u8 req_len = 2 + WLAN_SA_QUERY_TR_ID_LEN;
+
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Sending SA Query Request to "
MACSTR, MAC2STR(wpa_s->bssid));
wpa_hexdump(MSG_DEBUG, "SME: SA Query Transaction ID",
@@ -1847,9 +2320,27 @@
req[0] = WLAN_ACTION_SA_QUERY;
req[1] = WLAN_SA_QUERY_REQUEST;
os_memcpy(req + 2, trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(wpa_s->wpa)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in SA Query Request frame");
+ return;
+ }
+
+ if (ocv_insert_extended_oci(&ci, req + req_len) < 0)
+ return;
+
+ req_len += OCV_OCI_EXTENDED_LEN;
+ }
+#endif /* CONFIG_OCV */
+
if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
wpa_s->own_addr, wpa_s->bssid,
- req, sizeof(req), 0) < 0)
+ req, req_len, 0) < 0)
wpa_msg(wpa_s, MSG_INFO, "SME: Failed to send SA Query "
"Request");
}
@@ -1906,6 +2397,8 @@
static void sme_stop_sa_query(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->sme.sa_query_trans_id)
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: Stop SA Query");
eloop_cancel_timeout(sme_sa_query_timer, wpa_s, NULL);
os_free(wpa_s->sme.sa_query_trans_id);
wpa_s->sme.sa_query_trans_id = NULL;
@@ -1944,15 +2437,74 @@
}
-void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
- const u8 *data, size_t len)
+void sme_event_ch_switch(struct wpa_supplicant *wpa_s)
+{
+ unsigned int usec;
+ u32 _rand;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED ||
+ !wpa_sm_ocv_enabled(wpa_s->wpa))
+ return;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SME: Channel switch completed - trigger new SA Query to verify new operating channel");
+ sme_stop_sa_query(wpa_s);
+
+ if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
+ _rand = os_random();
+ usec = _rand % (sa_query_ch_switch_max_delay + 1);
+ eloop_register_timeout(0, usec, sme_sa_query_timer, wpa_s, NULL);
+}
+
+
+static void sme_process_sa_query_request(struct wpa_supplicant *wpa_s,
+ const u8 *sa, const u8 *data,
+ size_t len)
+{
+ u8 resp[2 + WLAN_SA_QUERY_TR_ID_LEN + OCV_OCI_EXTENDED_LEN];
+ u8 resp_len = 2 + WLAN_SA_QUERY_TR_ID_LEN;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: Sending SA Query Response to "
+ MACSTR, MAC2STR(wpa_s->bssid));
+
+ resp[0] = WLAN_ACTION_SA_QUERY;
+ resp[1] = WLAN_SA_QUERY_RESPONSE;
+ os_memcpy(resp + 2, data + 1, WLAN_SA_QUERY_TR_ID_LEN);
+
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(wpa_s->wpa)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in SA Query Response frame");
+ return;
+ }
+
+ if (ocv_insert_extended_oci(&ci, resp + resp_len) < 0)
+ return;
+
+ resp_len += OCV_OCI_EXTENDED_LEN;
+ }
+#endif /* CONFIG_OCV */
+
+ if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ resp, resp_len, 0) < 0)
+ wpa_msg(wpa_s, MSG_INFO,
+ "SME: Failed to send SA Query Response");
+}
+
+
+static void sme_process_sa_query_response(struct wpa_supplicant *wpa_s,
+ const u8 *sa, const u8 *data,
+ size_t len)
{
int i;
- if (wpa_s->sme.sa_query_trans_id == NULL ||
- len < 1 + WLAN_SA_QUERY_TR_ID_LEN ||
- data[0] != WLAN_SA_QUERY_RESPONSE)
+ if (!wpa_s->sme.sa_query_trans_id)
return;
+
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Received SA Query response from "
MACSTR " (trans_id %02x%02x)", MAC2STR(sa), data[1], data[2]);
@@ -1977,4 +2529,48 @@
sme_stop_sa_query(wpa_s);
}
+
+void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
+ const u8 *data, size_t len)
+{
+ if (len < 1 + WLAN_SA_QUERY_TR_ID_LEN)
+ return;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: Received SA Query frame from "
+ MACSTR " (trans_id %02x%02x)", MAC2STR(sa), data[1], data[2]);
+
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(wpa_s->wpa)) {
+ struct ieee802_11_elems elems;
+ struct wpa_channel_info ci;
+
+ if (ieee802_11_parse_elems(data + 1 + WLAN_SA_QUERY_TR_ID_LEN,
+ len - 1 - WLAN_SA_QUERY_TR_ID_LEN,
+ &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "SA Query: Failed to parse elements");
+ return;
+ }
+
+ if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info to validate received OCI in SA Query Action frame");
+ return;
+ }
+
+ 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);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
+ if (data[0] == WLAN_SA_QUERY_REQUEST)
+ sme_process_sa_query_request(wpa_s, sa, data, len);
+ else if (data[0] == WLAN_SA_QUERY_RESPONSE)
+ sme_process_sa_query_response(wpa_s, sa, data, len);
+}
+
#endif /* CONFIG_IEEE80211W */
diff --git a/wpa_supplicant/sme.h b/wpa_supplicant/sme.h
index fd5c3b4..1a7f9e8 100644
--- a/wpa_supplicant/sme.h
+++ b/wpa_supplicant/sme.h
@@ -28,6 +28,7 @@
struct disassoc_info *info);
void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
const u8 *da, u16 reason_code);
+void sme_event_ch_switch(struct wpa_supplicant *wpa_s);
void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
const u8 *data, size_t len);
void sme_state_changed(struct wpa_supplicant *wpa_s);
@@ -38,6 +39,10 @@
int sme_proc_obss_scan(struct wpa_supplicant *wpa_s);
void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable);
+void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data);
+void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s,
+ const u8 *auth_frame, size_t len);
#else /* CONFIG_SME */
@@ -85,6 +90,10 @@
{
}
+static inline void sme_event_ch_switch(struct wpa_supplicant *wpa_s)
+{
+}
+
static inline void sme_state_changed(struct wpa_supplicant *wpa_s)
{
}
@@ -113,6 +122,16 @@
{
}
+static inline void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+}
+
+static inline void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s,
+ const u8 *auth_frame, size_t len)
+{
+}
+
#endif /* CONFIG_SME */
#endif /* SME_H */
diff --git a/wpa_supplicant/systemd/wpa_supplicant.service.in b/wpa_supplicant/systemd/wpa_supplicant.service.in
index bc5d49a..75a37a8 100644
--- a/wpa_supplicant/systemd/wpa_supplicant.service.in
+++ b/wpa_supplicant/systemd/wpa_supplicant.service.in
@@ -5,9 +5,9 @@
[Service]
Type=dbus
-BusName=@DBUS_INTERFACE@
+BusName=fi.w1.wpa_supplicant1
ExecStart=@BINDIR@/wpa_supplicant -u
[Install]
WantedBy=multi-user.target
-Alias=dbus-@DBUS_INTERFACE@.service
+Alias=dbus-fi.w1.wpa_supplicant1.service
diff --git a/wpa_supplicant/utils/log2pcap.py b/wpa_supplicant/utils/log2pcap.py
index 65e2fa1..141aecb 100755
--- a/wpa_supplicant/utils/log2pcap.py
+++ b/wpa_supplicant/utils/log2pcap.py
@@ -28,7 +28,7 @@
input = sys.argv[1]
pcap = sys.argv[2]
except IndexError:
- print "Usage: %s <log file> <pcap file>" % sys.argv[0]
+ print("Usage: %s <log file> <pcap file>" % sys.argv[0])
sys.exit(2)
input_file = open(input, 'r')
diff --git a/wpa_supplicant/wmm_ac.c b/wpa_supplicant/wmm_ac.c
index a88cc46..38800cc 100644
--- a/wpa_supplicant/wmm_ac.c
+++ b/wpa_supplicant/wmm_ac.c
@@ -471,13 +471,8 @@
return -1;
}
- if (!ies) {
- wpa_printf(MSG_ERROR, "WMM AC: Missing IEs");
- return -1;
- }
-
- if (!(wmm_params->info_bitmap & WMM_PARAMS_UAPSD_QUEUES_INFO)) {
- wpa_printf(MSG_DEBUG, "WMM AC: Missing U-APSD configuration");
+ if (!ies || !(wmm_params->info_bitmap & WMM_PARAMS_UAPSD_QUEUES_INFO)) {
+ /* WMM AC not in use for this connection */
return -1;
}
@@ -522,7 +517,7 @@
for (i = 0; i < WMM_AC_NUM; i++)
wmm_ac_del_ts(wpa_s, i, TS_DIR_IDX_ALL);
- /* delete pending add_ts requset */
+ /* delete pending add_ts request */
wmm_ac_del_req(wpa_s, 1);
os_free(wpa_s->wmm_ac_assoc_info);
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 3e27f0c..39cd163 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -12,6 +12,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
+#include "common/ocv.h"
#include "rsn_supp/wpa.h"
#include "config.h"
#include "wpa_supplicant_i.h"
@@ -20,6 +21,7 @@
#include "ctrl_iface.h"
#include "bss.h"
#include "wnm_sta.h"
+#include "notify.h"
#include "hs20_supplicant.h"
#define MAX_TFS_IE_LEN 1024
@@ -58,8 +60,8 @@
int res;
size_t len;
struct wnm_sleep_element *wnmsleep_ie;
- u8 *wnmtfs_ie;
- u8 wnmsleep_ie_len;
+ u8 *wnmtfs_ie, *oci_ie;
+ u8 wnmsleep_ie_len, oci_ie_len;
u16 wnmtfs_ie_len; /* possibly multiple IE(s) */
enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD :
WNM_SLEEP_TFS_REQ_IE_NONE;
@@ -106,7 +108,41 @@
wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element",
(u8 *) wnmtfs_ie, wnmtfs_ie_len);
- mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len);
+ oci_ie = NULL;
+ oci_ie_len = 0;
+#ifdef CONFIG_OCV
+ if (action == WNM_SLEEP_MODE_EXIT && wpa_sm_ocv_enabled(wpa_s->wpa)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in WNM-Sleep Mode frame");
+ os_free(wnmsleep_ie);
+ os_free(wnmtfs_ie);
+ return -1;
+ }
+
+ oci_ie_len = OCV_OCI_EXTENDED_LEN;
+ oci_ie = os_zalloc(oci_ie_len);
+ if (!oci_ie) {
+ wpa_printf(MSG_WARNING,
+ "Failed to allocate buffer for for OCI element in WNM-Sleep Mode frame");
+ os_free(wnmsleep_ie);
+ os_free(wnmtfs_ie);
+ return -1;
+ }
+
+ if (ocv_insert_extended_oci(&ci, oci_ie) < 0) {
+ os_free(wnmsleep_ie);
+ os_free(wnmtfs_ie);
+ os_free(oci_ie);
+ return -1;
+ }
+ }
+#endif /* CONFIG_OCV */
+
+ mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len +
+ oci_ie_len);
if (mgmt == NULL) {
wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
"WNM-Sleep Request action frame");
@@ -131,8 +167,16 @@
wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len);
}
+#ifdef CONFIG_OCV
+ /* copy OCV OCI here */
+ if (oci_ie_len > 0) {
+ os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable +
+ wnmsleep_ie_len + wnmtfs_ie_len, oci_ie, oci_ie_len);
+ }
+#endif /* CONFIG_OCV */
+
len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len +
- wnmtfs_ie_len;
+ wnmtfs_ie_len + oci_ie_len;
res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
wpa_s->own_addr, wpa_s->bssid,
@@ -145,6 +189,7 @@
os_free(wnmsleep_ie);
os_free(wnmtfs_ie);
+ os_free(oci_ie);
os_free(mgmt);
return res;
@@ -256,6 +301,10 @@
/* multiple TFS Resp IE (assuming consecutive) */
const u8 *tfsresp_ie_start = NULL;
const u8 *tfsresp_ie_end = NULL;
+#ifdef CONFIG_OCV
+ const u8 *oci_ie = NULL;
+ u8 oci_ie_len = 0;
+#endif /* CONFIG_OCV */
size_t left;
if (!wpa_s->wnmsleep_used) {
@@ -289,6 +338,12 @@
if (!tfsresp_ie_start)
tfsresp_ie_start = pos;
tfsresp_ie_end = pos;
+#ifdef CONFIG_OCV
+ } else if (*pos == WLAN_EID_EXTENSION && ie_len >= 1 &&
+ pos[2] == WLAN_EID_EXT_OCV_OCI) {
+ oci_ie = pos + 3;
+ oci_ie_len = ie_len - 1;
+#endif /* CONFIG_OCV */
} else
wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos);
pos += ie_len + 2;
@@ -299,6 +354,26 @@
return;
}
+#ifdef CONFIG_OCV
+ if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT &&
+ wpa_sm_ocv_enabled(wpa_s->wpa)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+ wpa_msg(wpa_s, MSG_WARNING,
+ "Failed to get channel info to validate received OCI in WNM-Sleep Mode frame");
+ return;
+ }
+
+ 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);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
wpa_s->wnmsleep_used = 0;
if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT ||
@@ -338,6 +413,9 @@
wpa_s->wnm_num_neighbor_report = 0;
os_free(wpa_s->wnm_neighbor_report_elements);
wpa_s->wnm_neighbor_report_elements = NULL;
+
+ wpabuf_free(wpa_s->coloc_intf_elems);
+ wpa_s->coloc_intf_elems = NULL;
}
@@ -697,7 +775,7 @@
continue;
}
- if (wpa_is_bss_tmp_disallowed(wpa_s, target->bssid)) {
+ if (wpa_is_bss_tmp_disallowed(wpa_s, target)) {
wpa_printf(MSG_DEBUG,
"MBO: Candidate BSS " MACSTR
" retry delay is not over yet",
@@ -942,6 +1020,9 @@
return;
}
+ wpa_s->bss_tm_status = status;
+ wpas_notify_bss_tm_status(wpa_s);
+
wpabuf_put_u8(buf, WLAN_ACTION_WNM);
wpabuf_put_u8(buf, WNM_BSS_TRANS_MGMT_RESP);
wpabuf_put_u8(buf, dialog_token);
@@ -1648,6 +1729,32 @@
pos = next;
continue;
}
+
+ if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 &&
+ WPA_GET_BE24(pos) == OUI_WFA &&
+ pos[3] == HS20_WNM_T_C_ACCEPTANCE) {
+ const u8 *ie_end;
+ u8 url_len;
+ char *url;
+
+ ie_end = pos + ie_len;
+ pos += 4;
+ url_len = *pos++;
+ wpa_printf(MSG_DEBUG,
+ "WNM: HS 2.0 Terms and Conditions Acceptance (URL Length %u)",
+ url_len);
+ if (url_len > ie_end - pos)
+ break;
+ url = os_malloc(url_len + 1);
+ if (!url)
+ break;
+ os_memcpy(url, pos, url_len);
+ url[url_len] = '\0';
+ hs20_rx_t_c_acceptance(wpa_s, url);
+ os_free(url);
+ pos = next;
+ continue;
+ }
#endif /* CONFIG_HS20 */
pos = next;
@@ -1695,6 +1802,46 @@
}
+static void ieee802_11_rx_wnm_coloc_intf_req(struct wpa_supplicant *wpa_s,
+ const u8 *sa, const u8 *frm,
+ int len)
+{
+ u8 dialog_token, req_info, auto_report, timeout;
+
+ if (!wpa_s->conf->coloc_intf_reporting)
+ return;
+
+ /* Dialog Token [1] | Request Info [1] */
+
+ if (len < 2)
+ return;
+ dialog_token = frm[0];
+ req_info = frm[1];
+ auto_report = req_info & 0x03;
+ timeout = req_info >> 2;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WNM: Received Collocated Interference Request (dialog_token %u auto_report %u timeout %u sa " MACSTR ")",
+ dialog_token, auto_report, timeout, MAC2STR(sa));
+
+ if (dialog_token == 0)
+ return; /* only nonzero values are used for request */
+
+ if (wpa_s->wpa_state != WPA_COMPLETED ||
+ os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WNM: Collocated Interference Request frame not from current AP - ignore it");
+ return;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, COLOC_INTF_REQ "%u %u %u",
+ dialog_token, auto_report, timeout);
+ wpa_s->coloc_intf_dialog_token = dialog_token;
+ wpa_s->coloc_intf_auto_report = auto_report;
+ wpa_s->coloc_intf_timeout = timeout;
+}
+
+
void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
const struct ieee80211_mgmt *mgmt, size_t len)
{
@@ -1728,8 +1875,75 @@
case WNM_NOTIFICATION_REQ:
ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos);
break;
+ case WNM_COLLOCATED_INTERFERENCE_REQ:
+ ieee802_11_rx_wnm_coloc_intf_req(wpa_s, mgmt->sa, pos,
+ end - pos);
+ break;
default:
wpa_printf(MSG_ERROR, "WNM: Unknown request");
break;
}
}
+
+
+int wnm_send_coloc_intf_report(struct wpa_supplicant *wpa_s, u8 dialog_token,
+ const struct wpabuf *elems)
+{
+ struct wpabuf *buf;
+ int ret;
+
+ if (wpa_s->wpa_state < WPA_ASSOCIATED || !elems)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "WNM: Send Collocated Interference Report to "
+ MACSTR " (dialog token %u)",
+ MAC2STR(wpa_s->bssid), dialog_token);
+
+ buf = wpabuf_alloc(3 + wpabuf_len(elems));
+ if (!buf)
+ return -1;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_WNM);
+ wpabuf_put_u8(buf, WNM_COLLOCATED_INTERFERENCE_REPORT);
+ wpabuf_put_u8(buf, dialog_token);
+ wpabuf_put_buf(buf, elems);
+
+ ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head_u8(buf), wpabuf_len(buf), 0);
+ wpabuf_free(buf);
+ return ret;
+}
+
+
+void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s,
+ struct wpabuf *elems)
+{
+ wpabuf_free(wpa_s->coloc_intf_elems);
+ if (elems && wpabuf_len(elems) == 0) {
+ wpabuf_free(elems);
+ elems = NULL;
+ }
+ wpa_s->coloc_intf_elems = elems;
+
+ if (wpa_s->conf->coloc_intf_reporting && wpa_s->coloc_intf_elems &&
+ wpa_s->coloc_intf_dialog_token &&
+ (wpa_s->coloc_intf_auto_report == 1 ||
+ wpa_s->coloc_intf_auto_report == 3)) {
+ /* TODO: Check that there has not been less than
+ * wpa_s->coloc_intf_timeout * 200 TU from the last report.
+ */
+ wnm_send_coloc_intf_report(wpa_s,
+ wpa_s->coloc_intf_dialog_token,
+ wpa_s->coloc_intf_elems);
+ }
+}
+
+
+void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_WNM
+ wpa_s->coloc_intf_dialog_token = 0;
+ wpa_s->coloc_intf_auto_report = 0;
+#endif /* CONFIG_WNM */
+}
diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h
index 02cd1cd..29625f8 100644
--- a/wpa_supplicant/wnm_sta.h
+++ b/wpa_supplicant/wnm_sta.h
@@ -65,11 +65,16 @@
int cand_list);
void wnm_deallocate_memory(struct wpa_supplicant *wpa_s);
+int wnm_send_coloc_intf_report(struct wpa_supplicant *wpa_s, u8 dialog_token,
+ const struct wpabuf *elems);
+void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s,
+ struct wpabuf *elems);
#ifdef CONFIG_WNM
int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail);
+void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s);
#else /* CONFIG_WNM */
@@ -79,6 +84,10 @@
return 0;
}
+static inline void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s)
+{
+}
+
#endif /* CONFIG_WNM */
#endif /* WNM_STA_H */
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 6b345af..695fcbe 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - command line interface for wpa_supplicant daemon
- * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -29,7 +29,7 @@
static const char *const wpa_cli_version =
"wpa_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi> and contributors";
#define VENDOR_ELEM_FRAME_ID \
" 0: Probe Req (P2P), 1: Probe Resp (P2P) , 2: Probe Resp (GO), " \
@@ -49,6 +49,7 @@
static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
static const char *client_socket_dir = NULL;
static char *ctrl_ifname = NULL;
+static const char *global = NULL;
static const char *pid_file = NULL;
static const char *action_file = NULL;
static int ping_interval = 5;
@@ -60,6 +61,7 @@
static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */
static DEFINE_DL_LIST(ifnames); /* struct cli_txt_entry */
static DEFINE_DL_LIST(networks); /* struct cli_txt_entry */
+static DEFINE_DL_LIST(creds); /* struct cli_txt_entry */
#ifdef CONFIG_AP
static DEFINE_DL_LIST(stations); /* struct cli_txt_entry */
#endif /* CONFIG_AP */
@@ -70,8 +72,10 @@
static void wpa_cli_close_connection(void);
static char * wpa_cli_get_default_ifname(void);
static char ** wpa_list_cmd_list(void);
+static void update_creds(struct wpa_ctrl *ctrl);
static void update_networks(struct wpa_ctrl *ctrl);
static void update_stations(struct wpa_ctrl *ctrl);
+static void update_ifnames(struct wpa_ctrl *ctrl);
static void usage(void)
@@ -474,7 +478,7 @@
#endif /* CONFIG_P2P */
"country", "bss_max_count", "bss_expiration_age",
"bss_expiration_scan_count", "filter_ssids", "filter_rssi",
- "max_num_sta", "disassoc_low_ack",
+ "max_num_sta", "disassoc_low_ack", "ap_isolate",
#ifdef CONFIG_HS20
"hs20",
#endif /* CONFIG_HS20 */
@@ -571,7 +575,7 @@
#endif /* CONFIG_P2P */
"bss_max_count", "bss_expiration_age",
"bss_expiration_scan_count", "filter_ssids", "filter_rssi",
- "max_num_sta", "disassoc_low_ack",
+ "max_num_sta", "disassoc_low_ack", "ap_isolate",
#ifdef CONFIG_HS20
"hs20",
#endif /* CONFIG_HS20 */
@@ -1201,6 +1205,39 @@
}
+static int wpa_cli_cmd_psk_passphrase(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[256], *pos, *end;
+ int i, ret;
+
+ if (argc < 2) {
+ printf("Invalid PSK_PASSPHRASE command: needs two arguments (network id and PSK/passphrase)\n");
+ return -1;
+ }
+
+ end = cmd + sizeof(cmd);
+ pos = cmd;
+ ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PSK_PASSPHRASE-%s:%s",
+ argv[0], argv[1]);
+ if (os_snprintf_error(end - pos, ret)) {
+ printf("Too long PSK_PASSPHRASE command.\n");
+ return -1;
+ }
+ pos += ret;
+ for (i = 2; i < argc; i++) {
+ ret = os_snprintf(pos, end - pos, " %s", argv[i]);
+ if (os_snprintf_error(end - pos, ret)) {
+ printf("Too long PSK_PASSPHRASE command.\n");
+ return -1;
+ }
+ pos += ret;
+ }
+
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -1374,9 +1411,11 @@
"eap", "identity", "anonymous_identity", "password", "ca_cert",
"ca_path", "client_cert", "private_key", "private_key_passwd",
"dh_file", "subject_match", "altsubject_match",
+ "check_cert_subject",
"domain_suffix_match", "domain_match", "ca_cert2", "ca_path2",
"client_cert2", "private_key2", "private_key2_passwd",
"dh_file2", "subject_match2", "altsubject_match2",
+ "check_cert_subject2",
"domain_suffix_match2", "domain_match2", "phase1", "phase2",
"pcsc", "pin", "engine_id", "key_id", "cert_id", "ca_cert_id",
"pin2", "engine2_id", "key2_id", "cert2_id", "ca_cert2_id",
@@ -1410,7 +1449,7 @@
#ifdef CONFIG_HT_OVERRIDES
"disable_ht", "disable_ht40", "disable_sgi", "disable_ldpc",
"ht40_intolerant", "disable_max_amsdu", "ampdu_factor",
- "ampdu_density", "ht_mcs",
+ "ampdu_density", "ht_mcs", "rx_stbc", "tx_stbc",
#endif /* CONFIG_HT_OVERRIDES */
#ifdef CONFIG_VHT_OVERRIDES
"disable_vht", "vht_capa", "vht_capa_mask", "vht_rx_mcs_nss_1",
@@ -1424,6 +1463,8 @@
#ifdef CONFIG_MACSEC
"macsec_policy",
"macsec_integ_only",
+ "macsec_replay_protect",
+ "macsec_replay_window",
"macsec_port",
"mka_priority",
#endif /* CONFIG_MACSEC */
@@ -1519,14 +1560,56 @@
static int wpa_cli_cmd_add_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- return wpa_ctrl_command(ctrl, "ADD_CRED");
+ int res = wpa_ctrl_command(ctrl, "ADD_CRED");
+ if (interactive)
+ update_creds(ctrl);
+ return res;
}
static int wpa_cli_cmd_remove_cred(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- return wpa_cli_cmd(ctrl, "REMOVE_CRED", 1, argc, argv);
+ int res = wpa_cli_cmd(ctrl, "REMOVE_CRED", 1, argc, argv);
+ if (interactive)
+ update_creds(ctrl);
+ return res;
+}
+
+
+static const char * const cred_fields[] = {
+ "temporary", "priority", "sp_priority", "pcsc", "eap",
+ "update_identifier", "min_dl_bandwidth_home", "min_ul_bandwidth_home",
+ "min_dl_bandwidth_roaming", "min_ul_bandwidth_roaming", "max_bss_load",
+ "req_conn_capab", "ocsp", "sim_num", "realm", "username", "password",
+ "ca_cert", "client_cert", "private_key", "private_key_passwd", "imsi",
+ "milenage", "domain_suffix_match", "domain", "phase1", "phase2",
+ "roaming_consortium", "required_roaming_consortium", "excluded_ssid",
+ "roaming_partner", "provisioning_sp"
+};
+
+
+static char ** wpa_cli_complete_cred(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ int i, num_fields = ARRAY_SIZE(cred_fields);
+ char **res = NULL;
+
+ switch (arg) {
+ case 1:
+ res = cli_txt_list_array(&creds);
+ break;
+ case 2:
+ res = os_calloc(num_fields + 1, sizeof(char *));
+ if (res == NULL)
+ return NULL;
+ for (i = 0; i < num_fields; i++) {
+ res[i] = os_strdup(cred_fields[i]);
+ if (res[i] == NULL)
+ break;
+ }
+ }
+ return res;
}
@@ -2443,6 +2526,8 @@
return wpa_cli_cmd(ctrl, "P2P_REMOVE_CLIENT", 1, argc, argv);
}
+#endif /* CONFIG_P2P */
+
static int wpa_cli_cmd_vendor_elem_add(struct wpa_ctrl *ctrl, int argc,
char *argv[])
@@ -2464,7 +2549,6 @@
return wpa_cli_cmd(ctrl, "VENDOR_ELEM_REMOVE", 2, argc, argv);
}
-#endif /* CONFIG_P2P */
#ifdef CONFIG_WIFI_DISPLAY
@@ -2903,6 +2987,20 @@
}
+static int wpa_cli_cmd_dpp_configurator_get_key(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_CONFIGURATOR_GET_KEY", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_dpp_configurator_sign(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_CONFIGURATOR_SIGN", 1, argc, argv);
+}
+
+
static int wpa_cli_cmd_dpp_pkex_add(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -3032,6 +3130,9 @@
cli_cmd_flag_sensitive,
"<network id> <password> = configure one-time-password for an SSID"
},
+ { "psk_passphrase", wpa_cli_cmd_psk_passphrase,
+ wpa_cli_complete_network_id, cli_cmd_flag_sensitive,
+ "<network id> <PSK/passphrase> = configure PSK/passphrase for an SSID" },
{ "passphrase", wpa_cli_cmd_passphrase, wpa_cli_complete_network_id,
cli_cmd_flag_sensitive,
"<network id> <passphrase> = configure private key passphrase\n"
@@ -3093,10 +3194,10 @@
{ "remove_cred", wpa_cli_cmd_remove_cred, NULL,
cli_cmd_flag_none,
"<cred id> = remove a credential" },
- { "set_cred", wpa_cli_cmd_set_cred, NULL,
+ { "set_cred", wpa_cli_cmd_set_cred, wpa_cli_complete_cred,
cli_cmd_flag_sensitive,
"<cred id> <variable> <value> = set credential variables" },
- { "get_cred", wpa_cli_cmd_get_cred, NULL,
+ { "get_cred", wpa_cli_cmd_get_cred, wpa_cli_complete_cred,
cli_cmd_flag_none,
"<cred id> <variable> = get credential variables" },
{ "save_config", wpa_cli_cmd_save_config, NULL,
@@ -3377,6 +3478,7 @@
{ "p2p_remove_client", wpa_cli_cmd_p2p_remove_client,
wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
"<address|iface=address> = remove a peer from all groups" },
+#endif /* CONFIG_P2P */
{ "vendor_elem_add", wpa_cli_cmd_vendor_elem_add, NULL,
cli_cmd_flag_none,
"<frame id> <hexdump of elem(s)> = add vendor specific IEs to frame(s)\n"
@@ -3389,7 +3491,6 @@
cli_cmd_flag_none,
"<frame id> <hexdump of elem(s)> = remove vendor specific IE(s) in frame(s)\n"
VENDOR_ELEM_FRAME_ID },
-#endif /* CONFIG_P2P */
#ifdef CONFIG_WIFI_DISPLAY
{ "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL,
cli_cmd_flag_none,
@@ -3559,6 +3660,12 @@
{ "dpp_configurator_remove", wpa_cli_cmd_dpp_configurator_remove, NULL,
cli_cmd_flag_none,
"*|<id> = remove DPP configurator" },
+ { "dpp_configurator_get_key", wpa_cli_cmd_dpp_configurator_get_key,
+ NULL, cli_cmd_flag_none,
+ "<id> = Get DPP configurator's private key" },
+ { "dpp_configurator_sign", wpa_cli_cmd_dpp_configurator_sign, NULL,
+ cli_cmd_flag_none,
+ "conf=<role> configurator=<id> = generate self DPP configuration" },
{ "dpp_pkex_add", wpa_cli_cmd_dpp_pkex_add, NULL,
cli_cmd_flag_sensitive,
"add PKEX code" },
@@ -3900,6 +4007,8 @@
wpa_cli_exec(action_file, ifname, pos);
} else if (str_starts(pos, HS20_DEAUTH_IMMINENT_NOTICE)) {
wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, HS20_T_C_ACCEPTANCE)) {
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_starts(pos, WPA_EVENT_TERMINATING)) {
printf("wpa_supplicant is terminating - stop monitoring\n");
wpa_cli_quit = 1;
@@ -3915,10 +4024,46 @@
#endif /* CONFIG_ANSI_C_EXTRA */
+static int wpa_cli_open_global_ctrl(void)
+{
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+ ctrl_conn = wpa_ctrl_open(NULL);
+#else /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+ ctrl_conn = wpa_ctrl_open(global);
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+ if (!ctrl_conn) {
+ fprintf(stderr,
+ "Failed to connect to wpa_supplicant global interface: %s error: %s\n",
+ global, strerror(errno));
+ return -1;
+ }
+
+ if (interactive) {
+ update_ifnames(ctrl_conn);
+ mon_conn = wpa_ctrl_open(global);
+ if (mon_conn) {
+ if (wpa_ctrl_attach(mon_conn) == 0) {
+ wpa_cli_attached = 1;
+ eloop_register_read_sock(
+ wpa_ctrl_get_fd(mon_conn),
+ wpa_cli_mon_receive,
+ NULL, NULL);
+ } else {
+ printf("Failed to open monitor connection through global control interface\n");
+ }
+ }
+ update_stations(ctrl_conn);
+ }
+
+ return 0;
+}
+
+
static void wpa_cli_reconnect(void)
{
wpa_cli_close_connection();
- if (wpa_cli_open_connection(ctrl_ifname, 1) < 0)
+ if ((global && wpa_cli_open_global_ctrl() < 0) ||
+ (!global && wpa_cli_open_connection(ctrl_ifname, 1) < 0))
return;
if (interactive) {
@@ -4206,6 +4351,38 @@
}
+static void update_creds(struct wpa_ctrl *ctrl)
+{
+ char buf[4096];
+ size_t len = sizeof(buf);
+ int ret;
+ const char *cmd = "LIST_CREDS";
+ char *pos, *end;
+ int header = 1;
+
+ cli_txt_list_flush(&creds);
+
+ if (ctrl == NULL)
+ return;
+ ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL);
+ if (ret < 0)
+ return;
+ buf[len] = '\0';
+
+ pos = buf;
+ while (pos) {
+ end = os_strchr(pos, '\n');
+ if (end == NULL)
+ break;
+ *end = '\0';
+ if (!header)
+ cli_txt_list_add_word(&creds, pos, '\t');
+ header = 0;
+ pos = end + 1;
+ }
+}
+
+
static void update_networks(struct wpa_ctrl *ctrl)
{
char buf[4096];
@@ -4279,6 +4456,7 @@
}
update_bssid_list(ctrl_conn);
+ update_creds(ctrl_conn);
update_networks(ctrl_conn);
update_stations(ctrl_conn);
@@ -4302,6 +4480,7 @@
cli_txt_list_flush(&p2p_groups);
cli_txt_list_flush(&bsses);
cli_txt_list_flush(&ifnames);
+ cli_txt_list_flush(&creds);
cli_txt_list_flush(&networks);
if (edit_started)
edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
@@ -4443,7 +4622,6 @@
int c;
int daemonize = 0;
int ret = 0;
- const char *global = NULL;
if (os_program_init())
return -1;
@@ -4498,38 +4676,8 @@
if (eloop_init())
return -1;
- if (global) {
-#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
- ctrl_conn = wpa_ctrl_open(NULL);
-#else /* CONFIG_CTRL_IFACE_NAMED_PIPE */
- ctrl_conn = wpa_ctrl_open(global);
-#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
- if (ctrl_conn == NULL) {
- fprintf(stderr, "Failed to connect to wpa_supplicant "
- "global interface: %s error: %s\n",
- global, strerror(errno));
- return -1;
- }
-
- if (interactive) {
- update_ifnames(ctrl_conn);
- mon_conn = wpa_ctrl_open(global);
- if (mon_conn) {
- if (wpa_ctrl_attach(mon_conn) == 0) {
- wpa_cli_attached = 1;
- eloop_register_read_sock(
- wpa_ctrl_get_fd(mon_conn),
- wpa_cli_mon_receive,
- NULL, NULL);
- } else {
- printf("Failed to open monitor "
- "connection through global "
- "control interface\n");
- }
- }
- update_stations(ctrl_conn);
- }
- }
+ if (global && wpa_cli_open_global_ctrl() < 0)
+ return -1;
eloop_register_signal_terminate(wpa_cli_terminate, NULL);
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index ee5710f..be8efb4 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant
- * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -39,6 +39,7 @@
#include "common/ieee802_11_defs.h"
#include "common/hw_features_common.h"
#include "common/gas_server.h"
+#include "common/dpp.h"
#include "p2p/p2p.h"
#include "fst/fst.h"
#include "blacklist.h"
@@ -68,7 +69,7 @@
const char *const wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi> and contributors";
const char *const wpa_supplicant_license =
"This software may be distributed under the terms of the BSD license.\n"
@@ -244,10 +245,30 @@
wpa_dbg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec "
"%d usec", sec, usec);
eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+ wpa_s->last_auth_timeout_sec = sec;
eloop_register_timeout(sec, usec, wpa_supplicant_timeout, wpa_s, NULL);
}
+/*
+ * wpas_auth_timeout_restart - Restart and change timeout for authentication
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @sec_diff: difference in seconds applied to original timeout value
+ */
+void wpas_auth_timeout_restart(struct wpa_supplicant *wpa_s, int sec_diff)
+{
+ int new_sec = wpa_s->last_auth_timeout_sec + sec_diff;
+
+ if (eloop_is_timeout_registered(wpa_supplicant_timeout, wpa_s, NULL)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Authentication timeout restart: %d sec", new_sec);
+ eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+ eloop_register_timeout(new_sec, 0, wpa_supplicant_timeout,
+ wpa_s, NULL);
+ }
+}
+
+
/**
* wpa_supplicant_cancel_auth_timeout - Cancel authentication timeout
* @wpa_s: Pointer to wpa_supplicant data
@@ -261,6 +282,9 @@
wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout");
eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
wpa_blacklist_del(wpa_s, wpa_s->bssid);
+ os_free(wpa_s->last_con_fail_realm);
+ wpa_s->last_con_fail_realm = NULL;
+ wpa_s->last_con_fail_realm_len = 0;
}
@@ -422,7 +446,7 @@
}
-static void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s)
+void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s)
{
struct wpa_bss_tmp_disallowed *bss, *prev;
@@ -485,6 +509,10 @@
os_free(wpa_s->confanother);
wpa_s->confanother = NULL;
+ os_free(wpa_s->last_con_fail_realm);
+ wpa_s->last_con_fail_realm = NULL;
+ wpa_s->last_con_fail_realm_len = 0;
+
wpa_sm_set_eapol(wpa_s->wpa, NULL);
eapol_sm_deinit(wpa_s->eapol);
wpa_s->eapol = NULL;
@@ -646,6 +674,8 @@
#ifdef CONFIG_DPP
wpas_dpp_deinit(wpa_s);
+ dpp_global_deinit(wpa_s->dpp);
+ wpa_s->dpp = NULL;
#endif /* CONFIG_DPP */
}
@@ -820,6 +850,23 @@
wpa_supplicant_state_txt(wpa_s->wpa_state),
wpa_supplicant_state_txt(state));
+ if (state == WPA_COMPLETED &&
+ os_reltime_initialized(&wpa_s->roam_start)) {
+ os_reltime_age(&wpa_s->roam_start, &wpa_s->roam_time);
+ wpa_s->roam_start.sec = 0;
+ wpa_s->roam_start.usec = 0;
+ wpas_notify_auth_changed(wpa_s);
+ wpas_notify_roam_time(wpa_s);
+ wpas_notify_roam_complete(wpa_s);
+ } else if (state == WPA_DISCONNECTED &&
+ os_reltime_initialized(&wpa_s->roam_start)) {
+ wpa_s->roam_start.sec = 0;
+ wpa_s->roam_start.usec = 0;
+ wpa_s->roam_time.sec = 0;
+ wpa_s->roam_time.usec = 0;
+ wpas_notify_roam_complete(wpa_s);
+ }
+
if (state == WPA_INTERFACE_DISABLED) {
/* Assure normal scan when interface is restored */
wpa_s->normal_scans = 0;
@@ -915,7 +962,7 @@
wpa_supplicant_stop_bgscan(wpa_s);
#endif /* CONFIG_BGSCAN */
- if (state == WPA_AUTHENTICATING)
+ if (state > WPA_SCANNING)
wpa_supplicant_stop_autoscan(wpa_s);
if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
@@ -1011,7 +1058,13 @@
"file '%s' - exiting", wpa_s->confname);
return -1;
}
- wpa_config_read(wpa_s->confanother, conf);
+ if (wpa_s->confanother &&
+ !wpa_config_read(wpa_s->confanother, conf)) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Failed to parse the configuration file '%s' - exiting",
+ wpa_s->confanother);
+ return -1;
+ }
conf->changed_parameters = (unsigned int) -1;
@@ -1140,6 +1193,18 @@
}
+static int matching_ciphers(struct wpa_ssid *ssid, struct wpa_ie_data *ie,
+ int freq)
+{
+ if (!ie->has_group)
+ ie->group_cipher = wpa_default_rsn_cipher(freq);
+ if (!ie->has_pairwise)
+ ie->pairwise_cipher = wpa_default_rsn_cipher(freq);
+ return (ie->group_cipher & ssid->group_cipher) &&
+ (ie->pairwise_cipher & ssid->pairwise_cipher);
+}
+
+
/**
* wpa_supplicant_set_suites - Set authentication and encryption parameters
* @wpa_s: Pointer to wpa_supplicant data
@@ -1171,8 +1236,7 @@
if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
- (ie.group_cipher & ssid->group_cipher) &&
- (ie.pairwise_cipher & ssid->pairwise_cipher) &&
+ matching_ciphers(ssid, &ie, bss->freq) &&
(ie.key_mgmt & ssid->key_mgmt)) {
wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
proto = WPA_PROTO_RSN;
@@ -1184,14 +1248,20 @@
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
proto = WPA_PROTO_WPA;
#ifdef CONFIG_HS20
- } else if (bss_osen && (ssid->proto & WPA_PROTO_OSEN)) {
+ } else if (bss_osen && (ssid->proto & WPA_PROTO_OSEN) &&
+ wpa_parse_wpa_ie(bss_osen, 2 + bss_osen[1], &ie) == 0 &&
+ (ie.group_cipher & ssid->group_cipher) &&
+ (ie.pairwise_cipher & ssid->pairwise_cipher) &&
+ (ie.key_mgmt & ssid->key_mgmt)) {
wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using OSEN");
- /* TODO: parse OSEN element */
- os_memset(&ie, 0, sizeof(ie));
- ie.group_cipher = WPA_CIPHER_CCMP;
- ie.pairwise_cipher = WPA_CIPHER_CCMP;
- ie.key_mgmt = WPA_KEY_MGMT_OSEN;
proto = WPA_PROTO_OSEN;
+ } else if (bss_rsn && (ssid->proto & WPA_PROTO_OSEN) &&
+ wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
+ (ie.group_cipher & ssid->group_cipher) &&
+ (ie.pairwise_cipher & ssid->pairwise_cipher) &&
+ (ie.key_mgmt & ssid->key_mgmt)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using OSEN (within RSN)");
+ proto = WPA_PROTO_RSN;
#endif /* CONFIG_HS20 */
} else if (bss) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN");
@@ -1262,6 +1332,16 @@
WPA_CIPHER_AES_128_CMAC;
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OWE
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+ !ssid->owe_only &&
+ !bss_wpa && !bss_rsn && !bss_osen) {
+ wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+ wpa_s->wpa_proto = 0;
+ *wpa_ie_len = 0;
+ return 0;
+ }
+#endif /* CONFIG_OWE */
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Set cipher suites "
"based on configuration");
} else
@@ -1296,6 +1376,9 @@
wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
#else /* CONFIG_NO_WPA */
sel = ie.group_cipher & ssid->group_cipher;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: AP group 0x%x network profile group 0x%x; available group 0x%x",
+ ie.group_cipher, ssid->group_cipher, sel);
wpa_s->group_cipher = wpa_pick_group_cipher(sel);
if (wpa_s->group_cipher < 0) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select group "
@@ -1306,6 +1389,9 @@
wpa_cipher_txt(wpa_s->group_cipher));
sel = ie.pairwise_cipher & ssid->pairwise_cipher;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: AP pairwise 0x%x network profile pairwise 0x%x; available pairwise 0x%x",
+ ie.pairwise_cipher, ssid->pairwise_cipher, sel);
wpa_s->pairwise_cipher = wpa_pick_pairwise_cipher(sel, 1);
if (wpa_s->pairwise_cipher < 0) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select pairwise "
@@ -1317,11 +1403,29 @@
#endif /* CONFIG_NO_WPA */
sel = ie.key_mgmt & ssid->key_mgmt;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: AP key_mgmt 0x%x network profile key_mgmt 0x%x; available key_mgmt 0x%x",
+ ie.key_mgmt, ssid->key_mgmt, sel);
#ifdef CONFIG_SAE
if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE))
sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
#endif /* CONFIG_SAE */
if (0) {
+#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_SHA384
+ } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: using KEY_MGMT FT/802.1X-SHA384");
+ if (pmksa_cache_get_current(wpa_s->wpa)) {
+ /* PMKSA caching with FT is not fully functional, so
+ * disable the case for now. */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: Disable PMKSA caching for FT/802.1X connection");
+ pmksa_cache_clear_current(wpa_s->wpa);
+ }
+#endif /* CONFIG_SHA384 */
+#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_SUITEB192
} else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
@@ -1354,18 +1458,32 @@
} else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X");
+ if (pmksa_cache_get_current(wpa_s->wpa)) {
+ /* PMKSA caching with FT is not fully functional, so
+ * disable the case for now. */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: Disable PMKSA caching for FT/802.1X connection");
+ pmksa_cache_clear_current(wpa_s->wpa);
+ }
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_DPP
+ } else if (sel & WPA_KEY_MGMT_DPP) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_DPP;
+ wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT DPP");
+#endif /* CONFIG_DPP */
+#ifdef CONFIG_SAE
+ } else if (sel & WPA_KEY_MGMT_FT_SAE) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE;
+ wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT FT/SAE");
+ } else if (sel & WPA_KEY_MGMT_SAE) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_SAE;
+ wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE");
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_IEEE80211R
} else if (sel & WPA_KEY_MGMT_FT_PSK) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_SAE
- } else if (sel & WPA_KEY_MGMT_SAE) {
- wpa_s->key_mgmt = WPA_KEY_MGMT_SAE;
- wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE");
- } else if (sel & WPA_KEY_MGMT_FT_SAE) {
- wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE;
- wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT FT/SAE");
-#endif /* CONFIG_SAE */
#ifdef CONFIG_IEEE80211W
} else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
@@ -1395,11 +1513,6 @@
wpa_s->key_mgmt = WPA_KEY_MGMT_OWE;
wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT OWE");
#endif /* CONFIG_OWE */
-#ifdef CONFIG_DPP
- } else if (sel & WPA_KEY_MGMT_DPP) {
- wpa_s->key_mgmt = WPA_KEY_MGMT_DPP;
- wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT DPP");
-#endif /* CONFIG_DPP */
} else {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select "
"authenticated key management type");
@@ -1418,6 +1531,9 @@
if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION ||
!(ie.capabilities & WPA_CAPABILITY_MFPC))
sel = 0;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: AP mgmt_group_cipher 0x%x network profile mgmt_group_cipher 0x%x; available mgmt_group_cipher 0x%x",
+ ie.mgmt_group_cipher, ssid->group_mgmt_cipher, sel);
if (sel & WPA_CIPHER_AES_128_CMAC) {
wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
@@ -1443,27 +1559,44 @@
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
wpas_get_ssid_pmf(wpa_s, ssid));
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv);
+#endif /* CONFIG_OCV */
if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE");
return -1;
}
- if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
+ if (0) {
+#ifdef CONFIG_DPP
+ } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
+ /* Use PMK from DPP network introduction (PMKSA entry) */
+ wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
+#endif /* CONFIG_DPP */
+ } else if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
int psk_set = 0;
+ int sae_only;
- if (ssid->psk_set) {
+ sae_only = (ssid->key_mgmt & (WPA_KEY_MGMT_PSK |
+ WPA_KEY_MGMT_FT_PSK |
+ WPA_KEY_MGMT_PSK_SHA256)) == 0;
+
+ if (ssid->psk_set && !sae_only) {
+ wpa_hexdump_key(MSG_MSGDUMP, "PSK (set in config)",
+ ssid->psk, PMK_LEN);
wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL,
NULL);
psk_set = 1;
}
- if (wpa_key_mgmt_sae(ssid->key_mgmt) && ssid->sae_password)
+ if (wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ (ssid->sae_password || ssid->passphrase))
psk_set = 1;
#ifndef CONFIG_NO_PBKDF2
if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
- ssid->passphrase) {
+ ssid->passphrase && !sae_only) {
u8 psk[PMK_LEN];
pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len,
4096, psk, PMK_LEN);
@@ -1475,7 +1608,7 @@
}
#endif /* CONFIG_NO_PBKDF2 */
#ifdef CONFIG_EXT_PASSWORD
- if (ssid->ext_psk) {
+ if (ssid->ext_psk && !sae_only) {
struct wpabuf *pw = ext_password_get(wpa_s->ext_pw,
ssid->ext_psk);
char pw_str[64 + 1];
@@ -1521,6 +1654,9 @@
ext_password_free(pw);
return -1;
}
+ wpa_hexdump_key(MSG_MSGDUMP,
+ "PSK (from external PSK)",
+ psk, PMK_LEN);
wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL,
NULL);
psk_set = 1;
@@ -1541,6 +1677,7 @@
if (!psk_set) {
wpa_msg(wpa_s, MSG_INFO,
"No PSK available for association");
+ wpas_auth_failed(wpa_s, "NO_PSK_AVAILABLE");
return -1;
}
#ifdef CONFIG_OWE
@@ -1564,6 +1701,10 @@
case 0: /* Bits 0-7 */
break;
case 1: /* Bits 8-15 */
+ if (wpa_s->conf->coloc_intf_reporting) {
+ /* Bit 13 - Collocated Interference Reporting */
+ *pos |= 0x20;
+ }
break;
case 2: /* Bits 16-23 */
#ifdef CONFIG_WNM
@@ -1582,7 +1723,7 @@
break;
case 4: /* Bits 32-39 */
#ifdef CONFIG_INTERWORKING
- if (wpa_s->drv_flags / WPA_DRIVER_FLAGS_QOS_MAPPING)
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_QOS_MAPPING)
*pos |= 0x01; /* Bit 32 - QoS Map */
#endif /* CONFIG_INTERWORKING */
break;
@@ -1607,7 +1748,8 @@
break;
case 9: /* Bits 72-79 */
#ifdef CONFIG_FILS
- *pos |= 0x01;
+ if (!wpa_s->disable_fils)
+ *pos |= 0x01;
#endif /* CONFIG_FILS */
break;
}
@@ -1816,6 +1958,8 @@
if (wpa_s->current_bss && wpa_s->current_bss == bss) {
wmm_ac_save_tspecs(wpa_s);
wpa_s->reassoc_same_bss = 1;
+ } else if (wpa_s->current_bss && wpa_s->current_bss != bss) {
+ os_get_reltime(&wpa_s->roam_start);
}
}
@@ -2084,9 +2228,14 @@
if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
return;
+ freq->channel = pri_chan->chan;
+
#ifdef CONFIG_HT_OVERRIDES
- if (ssid->disable_ht40)
- return;
+ if (ssid->disable_ht40) {
+ if (ssid->disable_vht)
+ return;
+ goto skip_ht40;
+ }
#endif /* CONFIG_HT_OVERRIDES */
/* Check/setup HT40+/HT40- */
@@ -2111,8 +2260,6 @@
if (sec_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
return;
- freq->channel = pri_chan->chan;
-
if (ht40 == -1) {
if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS))
return;
@@ -2156,6 +2303,9 @@
wpa_scan_results_free(scan_res);
}
+#ifdef CONFIG_HT_OVERRIDES
+skip_ht40:
+#endif /* CONFIG_HT_OVERRIDES */
wpa_printf(MSG_DEBUG,
"IBSS/mesh: setup freq channel %d, sec_channel_offset %d",
freq->channel, freq->sec_channel_offset);
@@ -2245,6 +2395,13 @@
vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
seg0 = 114;
}
+ } else if (ssid->max_oper_chwidth == VHT_CHANWIDTH_USE_HT) {
+ chwidth = VHT_CHANWIDTH_USE_HT;
+ seg0 = vht80[j] + 2;
+#ifdef CONFIG_HT_OVERRIDES
+ if (ssid->disable_ht40)
+ seg0 = 0;
+#endif /* CONFIG_HT_OVERRIDES */
}
if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
@@ -2328,6 +2485,27 @@
return ie_len;
}
+
+
+int wpa_is_fils_supported(struct wpa_supplicant *wpa_s)
+{
+ return (((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS)) ||
+ (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD)));
+}
+
+
+int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_FILS_SK_PFS
+ return (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS);
+#else /* CONFIG_FILS_SK_PFS */
+ return 0;
+#endif /* CONFIG_FILS_SK_PFS */
+}
+
#endif /* CONFIG_FILS */
@@ -2341,6 +2519,12 @@
size_t max_wpa_ie_len = 500;
size_t wpa_ie_len;
int algs = WPA_AUTH_ALG_OPEN;
+#ifdef CONFIG_MBO
+ const u8 *mbo_ie;
+#endif
+#ifdef CONFIG_SAE
+ int sae_pmksa_cached = 0;
+#endif /* CONFIG_SAE */
#ifdef CONFIG_FILS
const u8 *realm, *username, *rrk;
size_t realm_len, username_len, rrk_len;
@@ -2378,8 +2562,12 @@
#endif /* CONFIG_FILS */
if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
ssid, try_opportunistic,
- cache_id) == 0)
+ cache_id, 0) == 0) {
eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
+#ifdef CONFIG_SAE
+ sae_pmksa_cached = 1;
+#endif /* CONFIG_SAE */
+ }
wpa_ie_len = max_wpa_ie_len;
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
wpa_ie, &wpa_ie_len)) {
@@ -2388,6 +2576,19 @@
os_free(wpa_ie);
return NULL;
}
+#ifdef CONFIG_HS20
+ } else if (bss && wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE) &&
+ (ssid->key_mgmt & WPA_KEY_MGMT_OSEN)) {
+ /* No PMKSA caching, but otherwise similar to RSN/WPA */
+ wpa_ie_len = max_wpa_ie_len;
+ if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
+ wpa_ie, &wpa_ie_len)) {
+ wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
+ "key management and encryption suites");
+ os_free(wpa_ie);
+ return NULL;
+ }
+#endif /* CONFIG_HS20 */
} else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss &&
wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
/*
@@ -2449,7 +2650,10 @@
ssid->eap.erp && wpa_key_mgmt_fils(wpa_s->key_mgmt) &&
eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap, &username,
&username_len, &realm, &realm_len,
- &next_seq_num, &rrk, &rrk_len) == 0) {
+ &next_seq_num, &rrk, &rrk_len) == 0 &&
+ (!wpa_s->last_con_fail_realm ||
+ wpa_s->last_con_fail_realm_len != realm_len ||
+ os_memcmp(wpa_s->last_con_fail_realm, realm, realm_len) != 0)) {
algs = WPA_AUTH_ALG_FILS;
params->fils_erp_username = username;
params->fils_erp_username_len = username_len;
@@ -2464,6 +2668,10 @@
}
#endif /* CONFIG_FILS */
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_SAE
+ if (wpa_s->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE))
+ algs = WPA_AUTH_ALG_SAE;
+#endif /* CONFIG_SAE */
wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs);
if (ssid->auth_alg) {
@@ -2472,6 +2680,14 @@
"Overriding auth_alg selection: 0x%x", algs);
}
+#ifdef CONFIG_SAE
+ if (sae_pmksa_cached && algs == WPA_AUTH_ALG_SAE) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SAE: Use WPA_AUTH_ALG_OPEN for PMKSA caching attempt");
+ algs = WPA_AUTH_ALG_OPEN;
+ }
+#endif /* CONFIG_SAE */
+
#ifdef CONFIG_P2P
if (wpa_s->global->p2p) {
u8 *pos;
@@ -2504,7 +2720,7 @@
#endif /* CONFIG_P2P */
if (bss) {
- wpa_ie_len += wpas_supp_op_class_ie(wpa_s, bss->freq,
+ wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss->freq,
wpa_ie + wpa_ie_len,
max_wpa_ie_len -
wpa_ie_len);
@@ -2544,12 +2760,14 @@
if (is_hs20_network(wpa_s, ssid, bss)) {
struct wpabuf *hs20;
- hs20 = wpabuf_alloc(20);
+ hs20 = wpabuf_alloc(20 + MAX_ROAMING_CONS_OI_LEN);
if (hs20) {
int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
size_t len;
- wpas_hs20_add_indication(hs20, pps_mo_id);
+ wpas_hs20_add_indication(hs20, pps_mo_id,
+ get_hs20_version(bss));
+ wpas_hs20_add_roam_cons_sel(hs20, ssid);
len = max_wpa_ie_len - wpa_ie_len;
if (wpabuf_len(hs20) <= len) {
os_memcpy(wpa_ie + wpa_ie_len,
@@ -2588,11 +2806,14 @@
#endif /* CONFIG_FST */
#ifdef CONFIG_MBO
- if (bss && wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) {
+ mbo_ie = bss ? wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE) : NULL;
+ if (mbo_ie) {
int len;
len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
- max_wpa_ie_len - wpa_ie_len);
+ max_wpa_ie_len - wpa_ie_len,
+ !!mbo_attr_from_mbo_ie(mbo_ie,
+ OCE_ATTR_ID_CAPA_IND));
if (len >= 0)
wpa_ie_len += len;
}
@@ -2609,24 +2830,113 @@
#endif /* CONFIG_FILS */
#ifdef CONFIG_OWE
+#ifdef CONFIG_TESTING_OPTIONS
+ if (get_ie_ext(wpa_ie, wpa_ie_len, WLAN_EID_EXT_OWE_DH_PARAM)) {
+ wpa_printf(MSG_INFO, "TESTING: Override OWE DH element");
+ } else
+#endif /* CONFIG_TESTING_OPTIONS */
if (algs == WPA_AUTH_ALG_OPEN &&
ssid->key_mgmt == WPA_KEY_MGMT_OWE) {
struct wpabuf *owe_ie;
- u16 group = OWE_DH_GROUP;
+ u16 group;
- if (ssid->owe_group)
+ if (ssid->owe_group) {
group = ssid->owe_group;
+ } else if (wpa_s->assoc_status_code ==
+ WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
+ if (wpa_s->last_owe_group == 19)
+ group = 20;
+ else if (wpa_s->last_owe_group == 20)
+ group = 21;
+ else
+ group = OWE_DH_GROUP;
+ } else {
+ group = OWE_DH_GROUP;
+ }
+
+ wpa_s->last_owe_group = group;
+ wpa_printf(MSG_DEBUG, "OWE: Try to use group %u", group);
owe_ie = owe_build_assoc_req(wpa_s->wpa, group);
if (owe_ie &&
wpabuf_len(owe_ie) <= max_wpa_ie_len - wpa_ie_len) {
os_memcpy(wpa_ie + wpa_ie_len,
wpabuf_head(owe_ie), wpabuf_len(owe_ie));
wpa_ie_len += wpabuf_len(owe_ie);
- wpabuf_free(owe_ie);
}
+ wpabuf_free(owe_ie);
}
#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP2
+ if (wpa_sm_get_key_mgmt(wpa_s->wpa) == WPA_KEY_MGMT_DPP &&
+ ssid->dpp_netaccesskey) {
+ dpp_pfs_free(wpa_s->dpp_pfs);
+ wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey,
+ ssid->dpp_netaccesskey_len);
+ if (!wpa_s->dpp_pfs) {
+ wpa_printf(MSG_DEBUG, "DPP: Could not initialize PFS");
+ /* Try to continue without PFS */
+ goto pfs_fail;
+ }
+ if (wpabuf_len(wpa_s->dpp_pfs->ie) <=
+ max_wpa_ie_len - wpa_ie_len) {
+ os_memcpy(wpa_ie + wpa_ie_len,
+ wpabuf_head(wpa_s->dpp_pfs->ie),
+ wpabuf_len(wpa_s->dpp_pfs->ie));
+ wpa_ie_len += wpabuf_len(wpa_s->dpp_pfs->ie);
+ }
+ }
+pfs_fail:
+#endif /* CONFIG_DPP2 */
+
+#ifdef CONFIG_IEEE80211R
+ /*
+ * Add MDIE under these conditions: the network profile allows FT,
+ * the AP supports FT, and the mobility domain ID matches.
+ */
+ if (bss && wpa_key_mgmt_ft(wpa_sm_get_key_mgmt(wpa_s->wpa))) {
+ const u8 *mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
+
+ if (mdie && mdie[1] >= MOBILITY_DOMAIN_ID_LEN) {
+ size_t len = 0;
+ const u8 *md = mdie + 2;
+ const u8 *wpa_md = wpa_sm_get_ft_md(wpa_s->wpa);
+
+ if (os_memcmp(md, wpa_md,
+ MOBILITY_DOMAIN_ID_LEN) == 0) {
+ /* Add mobility domain IE */
+ len = wpa_ft_add_mdie(
+ wpa_s->wpa, wpa_ie + wpa_ie_len,
+ max_wpa_ie_len - wpa_ie_len, mdie);
+ wpa_ie_len += len;
+ }
+#ifdef CONFIG_SME
+ if (len > 0 && wpa_s->sme.ft_used &&
+ wpa_sm_has_ptk(wpa_s->wpa)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SME: Trying to use FT over-the-air");
+ algs |= WPA_AUTH_ALG_FT;
+ }
+#endif /* CONFIG_SME */
+ }
+ }
+#endif /* CONFIG_IEEE80211R */
+
+ if (ssid->multi_ap_backhaul_sta) {
+ size_t multi_ap_ie_len;
+
+ multi_ap_ie_len = add_multi_ap_ie(wpa_ie + wpa_ie_len,
+ max_wpa_ie_len - wpa_ie_len,
+ MULTI_AP_BACKHAUL_STA);
+ if (multi_ap_ie_len == 0) {
+ wpa_printf(MSG_ERROR,
+ "Multi-AP: Failed to build Multi-AP IE");
+ os_free(wpa_ie);
+ return NULL;
+ }
+ wpa_ie_len += multi_ap_ie_len;
+ }
+
params->wpa_ie = wpa_ie;
params->wpa_ie_len = wpa_ie_len;
params->auth_alg = algs;
@@ -2665,6 +2975,34 @@
#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+#ifdef CONFIG_MBO
+void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_driver_associate_params params;
+ u8 *wpa_ie;
+
+ /*
+ * Update MBO connect params only in case of change of MBO attributes
+ * when connected, if the AP support MBO.
+ */
+
+ if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid ||
+ !wpa_s->current_bss ||
+ !wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE))
+ return;
+
+ os_memset(¶ms, 0, sizeof(params));
+ wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss,
+ wpa_s->current_ssid, ¶ms, NULL);
+ if (!wpa_ie)
+ return;
+
+ wpa_drv_update_connect_params(wpa_s, ¶ms, WPA_DRV_UPDATE_ASSOC_IES);
+ os_free(wpa_ie);
+}
+#endif /* CONFIG_MBO */
+
+
static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
{
struct wpa_connect_work *cwork = work->ctx;
@@ -2870,7 +3208,7 @@
}
params.wep_tx_keyidx = ssid->wep_tx_keyidx;
- if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
(params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
params.passphrase = ssid->passphrase;
@@ -2878,6 +3216,13 @@
params.psk = ssid->psk;
}
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) &&
+ (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
+ params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
+ params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
+ params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192))
+ params.req_key_mgmt_offload = 1;
+
if (wpa_s->conf->key_mgmt_offload) {
if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
@@ -2910,6 +3255,11 @@
"MFP: require MFP");
params.mgmt_frame_protection =
MGMT_FRAME_PROTECTION_REQUIRED;
+#ifdef CONFIG_OWE
+ } else if (!rsn && (ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+ !ssid->owe_only) {
+ params.mgmt_frame_protection = NO_MGMT_FRAME_PROTECTION;
+#endif /* CONFIG_OWE */
}
}
#endif /* CONFIG_IEEE80211W */
@@ -3100,6 +3450,9 @@
zero_addr = 1;
}
+ if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0)
+ wpa_s->enabled_4addr_mode = 0;
+
#ifdef CONFIG_TDLS
wpa_tdls_teardown_peers(wpa_s->wpa);
#endif /* CONFIG_TDLS */
@@ -3137,6 +3490,7 @@
return;
ssid->disabled = 0;
+ ssid->owe_transition_bss_select_count = 0;
wpas_clear_temp_disabled(wpa_s, ssid, 1);
wpas_notify_network_enabled_changed(wpa_s, ssid);
@@ -3400,6 +3754,9 @@
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
+ wpa_s->last_owe_group = 0;
+ if (ssid)
+ ssid->owe_transition_bss_select_count = 0;
if (wpa_s->connect_without_scan ||
wpa_supplicant_fast_associate(wpa_s) != 1) {
@@ -3687,7 +4044,9 @@
while (entry) {
if (!wpas_network_disabled(wpa_s, entry) &&
((ssid_len == entry->ssid_len &&
- os_memcmp(ssid, entry->ssid, ssid_len) == 0) || wired) &&
+ (!entry->ssid ||
+ os_memcmp(ssid, entry->ssid, ssid_len) == 0)) ||
+ wired) &&
(!entry->bssid_set ||
os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
return entry;
@@ -3865,7 +4224,7 @@
}
if (wpa_s->eapol_received == 0 &&
- (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) ||
+ (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) ||
!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
wpa_s->wpa_state != WPA_COMPLETED) &&
(wpa_s->current_ssid == NULL ||
@@ -3931,7 +4290,7 @@
eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
return;
wpa_drv_poll(wpa_s);
- if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK))
wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
/*
@@ -3957,6 +4316,11 @@
wpa_supplicant_rx_eapol, wpa_s, 0);
if (wpa_s->l2 == NULL)
return -1;
+
+ if (l2_packet_set_packet_filter(wpa_s->l2,
+ L2_PACKET_FILTER_PKTTYPE))
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Failed to attach pkt_type filter");
} else {
const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
if (addr)
@@ -4168,11 +4532,11 @@
{
le16 msk;
- wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled);
-
if (disabled == -1)
return 0;
+ wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled);
+
msk = host_to_le16(HT_CAP_INFO_MAX_AMSDU_SIZE);
htcaps_mask->ht_capabilities_info |= msk;
if (disabled)
@@ -4189,11 +4553,11 @@
struct ieee80211_ht_capabilities *htcaps_mask,
int factor)
{
- wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_factor: %d", factor);
-
if (factor == -1)
return 0;
+ wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_factor: %d", factor);
+
if (factor < 0 || factor > 3) {
wpa_msg(wpa_s, MSG_ERROR, "ampdu_factor: %d out of range. "
"Must be 0-3 or -1", factor);
@@ -4213,11 +4577,11 @@
struct ieee80211_ht_capabilities *htcaps_mask,
int density)
{
- wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_density: %d", density);
-
if (density == -1)
return 0;
+ wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_density: %d", density);
+
if (density < 0 || density > 7) {
wpa_msg(wpa_s, MSG_ERROR,
"ampdu_density: %d out of range. Must be 0-7 or -1.",
@@ -4238,7 +4602,8 @@
struct ieee80211_ht_capabilities *htcaps_mask,
int disabled)
{
- wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
+ if (disabled)
+ wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
set_disable_ht40(htcaps, disabled);
set_disable_ht40(htcaps_mask, 0);
@@ -4256,7 +4621,8 @@
le16 msk = host_to_le16(HT_CAP_INFO_SHORT_GI20MHZ |
HT_CAP_INFO_SHORT_GI40MHZ);
- wpa_msg(wpa_s, MSG_DEBUG, "set_disable_sgi: %d", disabled);
+ if (disabled)
+ wpa_msg(wpa_s, MSG_DEBUG, "set_disable_sgi: %d", disabled);
if (disabled)
htcaps->ht_capabilities_info &= ~msk;
@@ -4277,7 +4643,8 @@
/* Masking these out disables LDPC */
le16 msk = host_to_le16(HT_CAP_INFO_LDPC_CODING_CAP);
- wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ldpc: %d", disabled);
+ if (disabled)
+ wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ldpc: %d", disabled);
if (disabled)
htcaps->ht_capabilities_info &= ~msk;
@@ -4290,6 +4657,58 @@
}
+static int wpa_set_tx_stbc(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int tx_stbc)
+{
+ le16 msk = host_to_le16(HT_CAP_INFO_TX_STBC);
+
+ if (tx_stbc == -1)
+ return 0;
+
+ wpa_msg(wpa_s, MSG_DEBUG, "set_tx_stbc: %d", tx_stbc);
+
+ if (tx_stbc < 0 || tx_stbc > 1) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "tx_stbc: %d out of range. Must be 0-1 or -1", tx_stbc);
+ return -EINVAL;
+ }
+
+ htcaps_mask->ht_capabilities_info |= msk;
+ htcaps->ht_capabilities_info &= ~msk;
+ htcaps->ht_capabilities_info |= (tx_stbc << 7) & msk;
+
+ return 0;
+}
+
+
+static int wpa_set_rx_stbc(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int rx_stbc)
+{
+ le16 msk = host_to_le16(HT_CAP_INFO_RX_STBC_MASK);
+
+ if (rx_stbc == -1)
+ return 0;
+
+ wpa_msg(wpa_s, MSG_DEBUG, "set_rx_stbc: %d", rx_stbc);
+
+ if (rx_stbc < 0 || rx_stbc > 3) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "rx_stbc: %d out of range. Must be 0-3 or -1", rx_stbc);
+ return -EINVAL;
+ }
+
+ htcaps_mask->ht_capabilities_info |= msk;
+ htcaps->ht_capabilities_info &= ~msk;
+ htcaps->ht_capabilities_info |= (rx_stbc << 8) & msk;
+
+ return 0;
+}
+
+
void wpa_supplicant_apply_ht_overrides(
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_driver_associate_params *params)
@@ -4314,6 +4733,8 @@
wpa_set_disable_ht40(wpa_s, htcaps, htcaps_mask, ssid->disable_ht40);
wpa_set_disable_sgi(wpa_s, htcaps, htcaps_mask, ssid->disable_sgi);
wpa_set_disable_ldpc(wpa_s, htcaps, htcaps_mask, ssid->disable_ldpc);
+ wpa_set_rx_stbc(wpa_s, htcaps, htcaps_mask, ssid->rx_stbc);
+ wpa_set_tx_stbc(wpa_s, htcaps, htcaps_mask, ssid->tx_stbc);
if (ssid->ht40_intolerant) {
le16 bit = host_to_le16(HT_CAP_INFO_40MHZ_INTOLERANT);
@@ -4348,6 +4769,16 @@
vhtcaps_mask->vht_capabilities_info = host_to_le32(ssid->vht_capa_mask);
#ifdef CONFIG_HT_OVERRIDES
+ if (ssid->disable_sgi) {
+ vhtcaps_mask->vht_capabilities_info |= (VHT_CAP_SHORT_GI_80 |
+ VHT_CAP_SHORT_GI_160);
+ vhtcaps->vht_capabilities_info &= ~(VHT_CAP_SHORT_GI_80 |
+ VHT_CAP_SHORT_GI_160);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "disable-sgi override specified, vht-caps: 0x%x",
+ vhtcaps->vht_capabilities_info);
+ }
+
/* if max ampdu is <= 3, we have to make the HT cap the same */
if (ssid->vht_capa_mask & VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX) {
int max_ampdu;
@@ -4712,7 +5143,7 @@
if (work->started) {
work->wpa_s->radio->num_active_works--;
wpa_dbg(work->wpa_s, MSG_DEBUG,
- "radio_work_free('%s'@%p: num_active_works --> %u",
+ "radio_work_free('%s'@%p): num_active_works --> %u",
work->type, work,
work->wpa_s->radio->num_active_works);
}
@@ -4919,6 +5350,22 @@
}
+void radio_remove_pending_work(struct wpa_supplicant *wpa_s, void *ctx)
+{
+ struct wpa_radio_work *work;
+ struct wpa_radio *radio = wpa_s->radio;
+
+ dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) {
+ if (work->ctx != ctx)
+ continue;
+ wpa_dbg(wpa_s, MSG_DEBUG, "Free pending radio work '%s'@%p%s",
+ work->type, work, work->started ? " (started)" : "");
+ radio_work_free(work);
+ break;
+ }
+}
+
+
static void radio_remove_interface(struct wpa_supplicant *wpa_s)
{
struct wpa_radio *radio = wpa_s->radio;
@@ -5071,7 +5518,7 @@
static int wpas_init_driver(struct wpa_supplicant *wpa_s,
- struct wpa_interface *iface)
+ const struct wpa_interface *iface)
{
const char *ifname, *driver, *rn;
@@ -5155,7 +5602,7 @@
#endif /* CONFIG_GAS_SERVER */
static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
- struct wpa_interface *iface)
+ const struct wpa_interface *iface)
{
struct wpa_driver_capa capa;
int capa_res;
@@ -5189,7 +5636,13 @@
return -1;
}
wpa_s->confanother = os_rel2abs_path(iface->confanother);
- wpa_config_read(wpa_s->confanother, wpa_s->conf);
+ if (wpa_s->confanother &&
+ !wpa_config_read(wpa_s->confanother, wpa_s->conf)) {
+ wpa_printf(MSG_ERROR,
+ "Failed to read or parse configuration '%s'.",
+ wpa_s->confanother);
+ return -1;
+ }
/*
* Override ctrl_interface and driver_param if set on command
@@ -5339,6 +5792,12 @@
capa.mac_addr_rand_sched_scan_supported)
wpa_s->mac_addr_rand_supported |=
(MAC_ADDR_RAND_SCHED_SCAN | MAC_ADDR_RAND_PNO);
+
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
+ if (wpa_s->extended_capa &&
+ wpa_s->extended_capa_len >= 3 &&
+ wpa_s->extended_capa[2] & 0x40)
+ wpa_s->multi_bss_support = 1;
}
if (wpa_s->max_remain_on_chan == 0)
wpa_s->max_remain_on_chan = 1000;
@@ -5350,8 +5809,6 @@
*/
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)
wpa_s->p2p_mgmt = iface->p2p_mgmt;
- else
- iface->p2p_mgmt = 1;
if (wpa_s->num_multichan_concurrent == 0)
wpa_s->num_multichan_concurrent = 1;
@@ -5360,10 +5817,7 @@
return -1;
#ifdef CONFIG_TDLS
- if ((!iface->p2p_mgmt ||
- !(wpa_s->drv_flags &
- WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
- wpa_tdls_init(wpa_s->wpa))
+ if (!iface->p2p_mgmt && wpa_tdls_init(wpa_s->wpa))
return -1;
#endif /* CONFIG_TDLS */
@@ -5435,7 +5889,9 @@
return -1;
}
- if (iface->p2p_mgmt && wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
+ if ((!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) ||
+ wpa_s->p2p_mgmt) &&
+ wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
return -1;
}
@@ -6258,6 +6714,11 @@
"disconnected state");
return;
}
+ if (wpa_s->auto_reconnect_disabled) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Ignore connection failure "
+ "indication since auto connect is disabled");
+ return;
+ }
/*
* Add the failed BSSID into the blacklist and speed up next scan
@@ -6327,11 +6788,43 @@
* TODO: if more than one possible AP is available in scan results,
* could try the other ones before requesting a new scan.
*/
+
+ /* speed up the connection attempt with normal scan */
+ wpa_s->normal_scans = 0;
wpa_supplicant_req_scan(wpa_s, timeout / 1000,
1000 * (timeout % 1000));
}
+#ifdef CONFIG_FILS
+void fils_connection_failure(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ const u8 *realm, *username, *rrk;
+ size_t realm_len, username_len, rrk_len;
+ u16 next_seq_num;
+
+ if (!ssid || !ssid->eap.erp || !wpa_key_mgmt_fils(ssid->key_mgmt) ||
+ eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap,
+ &username, &username_len,
+ &realm, &realm_len, &next_seq_num,
+ &rrk, &rrk_len) != 0 ||
+ !realm)
+ return;
+
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "FILS: Store last connection failure realm",
+ realm, realm_len);
+ os_free(wpa_s->last_con_fail_realm);
+ wpa_s->last_con_fail_realm = os_malloc(realm_len);
+ if (wpa_s->last_con_fail_realm) {
+ wpa_s->last_con_fail_realm_len = realm_len;
+ os_memcpy(wpa_s->last_con_fail_realm, realm, realm_len);
+ }
+}
+#endif /* CONFIG_FILS */
+
+
int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s)
{
return wpa_s->conf->ap_scan == 2 ||
@@ -6691,6 +7184,7 @@
wpa_s->extra_blacklist_count = 0;
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
+ wpa_s->last_owe_group = 0;
if (wpa_supplicant_fast_associate(wpa_s) != 1)
wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -6717,6 +7211,8 @@
wpa_supplicant_cancel_scan(wpa_s);
wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+ radio_remove_works(wpa_s, "connect", 0);
+ radio_remove_works(wpa_s, "sme-connect", 0);
}
@@ -6971,16 +7467,14 @@
void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
- unsigned int sec)
+ unsigned int sec, int rssi_threshold)
{
struct wpa_bss_tmp_disallowed *bss;
bss = wpas_get_disallowed_bss(wpa_s, bssid);
if (bss) {
eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
- eloop_register_timeout(sec, 0, wpa_bss_tmp_disallow_timeout,
- wpa_s, bss);
- return;
+ goto finish;
}
bss = os_malloc(sizeof(*bss));
@@ -6993,23 +7487,31 @@
os_memcpy(bss->bssid, bssid, ETH_ALEN);
dl_list_add(&wpa_s->bss_tmp_disallowed, &bss->list);
wpa_set_driver_tmp_disallow_list(wpa_s);
+
+finish:
+ bss->rssi_threshold = rssi_threshold;
eloop_register_timeout(sec, 0, wpa_bss_tmp_disallow_timeout,
wpa_s, bss);
}
-int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid)
+int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss)
{
- struct wpa_bss_tmp_disallowed *bss = NULL, *tmp, *prev;
+ struct wpa_bss_tmp_disallowed *disallowed = NULL, *tmp, *prev;
dl_list_for_each_safe(tmp, prev, &wpa_s->bss_tmp_disallowed,
struct wpa_bss_tmp_disallowed, list) {
- if (os_memcmp(bssid, tmp->bssid, ETH_ALEN) == 0) {
- bss = tmp;
+ if (os_memcmp(bss->bssid, tmp->bssid, ETH_ALEN) == 0) {
+ disallowed = tmp;
break;
}
}
- if (!bss)
+ if (!disallowed)
+ return 0;
+
+ if (disallowed->rssi_threshold != 0 &&
+ bss->level > disallowed->rssi_threshold)
return 0;
return 1;
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 61eb38f..a9205f0 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -282,6 +282,14 @@
# to external program(s)
#wps_cred_processing=0
+# Whether to enable SAE (WPA3-Personal transition mode) automatically for
+# WPA2-PSK credentials received using WPS.
+# 0 = only add the explicitly listed WPA2-PSK configuration (default)
+# 1 = add both the WPA2-PSK and SAE configuration and enable PMF so that the
+# station gets configured in WPA3-Personal transition mode (supports both
+# WPA2-Personal (PSK) and WPA3-Personal (SAE) APs).
+#wps_cred_add_sae=0
+
# Vendor attribute in WPS M1, e.g., Windows 7 Vertical Pairing
# The vendor attribute contents to be added in M1 (hex string)
#wps_vendor_ext_m1=000137100100020001
@@ -310,6 +318,15 @@
# of APs when using ap_scan=1 mode.
#bss_max_count=200
+# BSS expiration age in seconds. A BSS will be removed from the local cache
+# if it is not in use and has not been seen for this time. Default is 180.
+#bss_expiration_age=180
+
+# BSS expiration after number of scans. A BSS will be removed from the local
+# cache if it is not seen in this number of scans.
+# Default is 2.
+#bss_expiration_scan_count=2
+
# Automatic scan
# This is an optional set of parameters for automatic scanning
# within an interface in following format:
@@ -377,11 +394,16 @@
# Enabled SAE finite cyclic groups in preference order
# By default (if this parameter is not set), the mandatory group 19 (ECC group
-# defined over a 256-bit prime order field) is preferred, but other groups are
-# also enabled. If this parameter is set, the groups will be tried in the
-# indicated order. The group values are listed in the IANA registry:
+# defined over a 256-bit prime order field, NIST P-256) is preferred and groups
+# 20 (NIST P-384) and 21 (NIST P-521) are also enabled. If this parameter is
+# set, the groups will be tried in the indicated order.
+# The group values are listed in the IANA registry:
# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
-#sae_groups=21 20 19 26 25
+# Note that groups 1, 2, 5, 22, 23, and 24 should not be used in production
+# purposes due limited security (see RFC 8247). Groups that are not as strong as
+# group 19 (ECC, NIST P-256) are unlikely to be useful for production use cases
+# since all implementations are required to support group 19.
+#sae_groups=19 20 21
# Default value for DTIM period (if not overridden in network block)
#dtim_period=2
@@ -597,6 +619,20 @@
# pre-configured with the credential since the NAI Realm information
# may not be available or fetched.
#
+# required_roaming_consortium: Required Roaming Consortium OI
+# If required_roaming_consortium_len is non-zero, this field contains the
+# Roaming Consortium OI that is required to be advertised by the AP for
+# the credential to be considered matching.
+#
+# roaming_consortiums: Roaming Consortium OI(s) memberships
+# This string field contains one or more comma delimited OIs (hexdump)
+# identifying the roaming consortiums of which the provider is a member.
+# The list is sorted from the most preferred one to the least preferred
+# one. A match between the Roaming Consortium OIs advertised by an AP and
+# the OIs in this list indicates that successful authentication is
+# possible.
+# (Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/RoamingConsortiumOI)
+#
# eap: Pre-configured EAP method
# This optional field can be used to specify which EAP method will be
# used with this credential. If not set, the EAP method is selected
@@ -851,6 +887,7 @@
# proto: list of accepted protocols
# WPA = WPA/IEEE 802.11i/D3.0
# RSN = WPA2/IEEE 802.11i (also WPA2 can be used as an alias for RSN)
+# Note that RSN is used also for WPA3.
# If not set, this defaults to: WPA RSN
#
# key_mgmt: list of accepted authenticated key management protocols
@@ -863,11 +900,13 @@
# instead)
# FT-PSK = Fast BSS Transition (IEEE 802.11r) with pre-shared key
# FT-EAP = Fast BSS Transition (IEEE 802.11r) with EAP authentication
+# FT-EAP-SHA384 = Fast BSS Transition (IEEE 802.11r) with EAP authentication
+# and using SHA384
# WPA-PSK-SHA256 = Like WPA-PSK but using stronger SHA256-based algorithms
# WPA-EAP-SHA256 = Like WPA-EAP but using stronger SHA256-based algorithms
# SAE = Simultaneous authentication of equals; pre-shared key/password -based
# authentication with stronger security than WPA-PSK especially when using
-# not that strong password
+# not that strong password; a.k.a. WPA3-Personal
# FT-SAE = SAE with FT
# WPA-EAP-SUITE-B = Suite B 128-bit level
# WPA-EAP-SUITE-B-192 = Suite B 192-bit level
@@ -876,6 +915,8 @@
# FILS-SHA384 = Fast Initial Link Setup with SHA384
# FT-FILS-SHA256 = FT and Fast Initial Link Setup with SHA256
# FT-FILS-SHA384 = FT and Fast Initial Link Setup with SHA384
+# OWE = Opportunistic Wireless Encryption (a.k.a. Enhanced Open)
+# DPP = Device Provisioning Protocol
# If not set, this defaults to: WPA-PSK WPA-EAP
#
# ieee80211w: whether management frame protection is enabled
@@ -888,6 +929,13 @@
# PMF required: ieee80211w=2 and key_mgmt=WPA-EAP-SHA256
# (and similarly for WPA-PSK and WPA-WPSK-SHA256 if WPA2-Personal is used)
#
+# ocv: whether operating channel validation is enabled
+# This is a countermeasure against multi-channel man-in-the-middle attacks.
+# Enabling this automatically also enables ieee80211w, if not yet enabled.
+# 0 = disabled (default)
+# 1 = enabled
+#ocv=1
+#
# auth_alg: list of allowed IEEE 802.11 authentication algorithms
# OPEN = Open System authentication (required for WPA/WPA2)
# SHARED = Shared Key authentication (requires static WEP keys)
@@ -936,9 +984,14 @@
#
# sae_password: SAE password
# This parameter can be used to set a password for SAE. By default, the
-# passphrase value is used if this separate parameter is not used, but
-# passphrase follows the WPA-PSK constraints (8..63 characters) even
-# though SAE passwords do not have such constraints.
+# passphrase from the psk parameter is used if this separate parameter is not
+# used, but psk follows the WPA-PSK constraints (8..63 characters) even though
+# SAE passwords do not have such constraints.
+#
+# sae_password_id: SAE password identifier
+# This parameter can be used to set an identifier for the SAE password. By
+# default, no such identifier is used. If set, the specified identifier value
+# is used by the other peer to select which password to use for authentication.
#
# eapol_flags: IEEE 802.1X/EAPOL options (bit field)
# Dynamic WEP key required for non-WPA mode
@@ -963,6 +1016,22 @@
# 0: Encrypt traffic (default)
# 1: Integrity only
#
+# macsec_replay_protect: IEEE 802.1X/MACsec replay protection
+# This setting applies only when MACsec is in use, i.e.,
+# - macsec_policy is enabled
+# - the key server has decided to enable MACsec
+# 0: Replay protection disabled (default)
+# 1: Replay protection enabled
+#
+# macsec_replay_window: IEEE 802.1X/MACsec replay protection window
+# This determines a window in which replay is tolerated, to allow receipt
+# of frames that have been misordered by the network.
+# This setting applies only when MACsec replay protection active, i.e.,
+# - macsec_replay_protect is enabled
+# - the key server has decided to enable MACsec
+# 0: No replay window, strict check (default)
+# 1..2^32-1: number of packets that could be misordered
+#
# macsec_port: IEEE 802.1X/MACsec port
# Port component of the SCI
# Range: 1-65534 (default: 1)
@@ -971,9 +1040,10 @@
# This allows to configure MACsec with a pre-shared key using a (CAK,CKN) pair.
# In this mode, instances of wpa_supplicant can act as MACsec peers. The peer
# with lower priority will become the key server and start distributing SAKs.
-# mka_cak (CAK = Secure Connectivity Association Key) takes a 16-bytes (128 bit)
-# hex-string (32 hex-digits)
-# mka_ckn (CKN = CAK Name) takes a 32-bytes (256 bit) hex-string (64 hex-digits)
+# mka_cak (CAK = Secure Connectivity Association Key) takes a 16-byte (128-bit)
+# hex-string (32 hex-digits) or a 32-byte (256-bit) hex-string (64 hex-digits)
+# mka_ckn (CKN = CAK Name) takes a 1..32-bytes (8..256 bit) hex-string
+# (2..64 hex-digits)
# mka_priority (Priority of MKA Actor) is in 0..255 range with 255 being
# default priority
#
@@ -1119,6 +1189,12 @@
# certificate may include additional sub-level labels in addition to the
# required labels.
#
+# More than one match string can be provided by using semicolons to
+# separate the strings (e.g., example.org;example.com). When multiple
+# strings are specified, a match with any one of the values is considered
+# a sufficient match for the certificate, i.e., the conditions are ORed
+# together.
+#
# For example, domain_suffix_match=example.com would match
# test.example.com but would not match test-example.com.
# domain_match: Constraint for server domain name
@@ -1131,6 +1207,12 @@
# no subdomains or wildcard matches are allowed. Case-insensitive
# comparison is used, so "Example.com" matches "example.com", but would
# not match "test.Example.com".
+#
+# More than one match string can be provided by using semicolons to
+# separate the strings (e.g., example.org;example.com). When multiple
+# strings are specified, a match with any one of the values is considered
+# a sufficient match for the certificate, i.e., the conditions are ORed
+# together.
# phase1: Phase1 (outer authentication, i.e., TLS tunnel) parameters
# (string with field-value pairs, e.g., "peapver=0" or
# "peapver=1 peaplabel=1")
@@ -1192,10 +1274,19 @@
# For EAP-FAST, this must be set to 0 (or left unconfigured for the
# default value to be used automatically).
# tls_disable_tlsv1_0=1 - disable use of TLSv1.0
+# tls_disable_tlsv1_0=0 - explicitly enable use of TLSv1.0 (this allows
+# systemwide TLS policies to be overridden)
# tls_disable_tlsv1_1=1 - disable use of TLSv1.1 (a workaround for AAA servers
# that have issues interoperating with updated TLS version)
+# tls_disable_tlsv1_1=0 - explicitly enable use of TLSv1.1 (this allows
+# systemwide TLS policies to be overridden)
# tls_disable_tlsv1_2=1 - disable use of TLSv1.2 (a workaround for AAA servers
# that have issues interoperating with updated TLS version)
+# tls_disable_tlsv1_2=0 - explicitly enable use of TLSv1.2 (this allows
+# systemwide TLS policies to be overridden)
+# tls_disable_tlsv1_3=1 - disable use of TLSv1.3 (a workaround for AAA servers
+# that have issues interoperating with updated TLS version)
+# tls_disable_tlsv1_3=0 - enable TLSv1.3 (experimental - disabled by default)
# tls_ext_cert_check=0 - No external server certificate validation (default)
# tls_ext_cert_check=1 - External server certificate validation enabled; this
# requires an external program doing validation of server certificate
@@ -1273,6 +1364,10 @@
# update_identifier: PPS MO ID
# (Hotspot 2.0 PerProviderSubscription/UpdateIdentifier)
+#
+# roaming_consortium_selection: Roaming Consortium Selection
+# The matching Roaming Consortium OI that was used to generate this
+# network profile.
# Station inactivity limit
#
@@ -1351,6 +1446,20 @@
# Treated as hint by the kernel.
# -1 = Do not make any changes.
# 0-3 = Set AMPDU density (aka factor) to specified value.
+#
+# tx_stbc: Allow overriding STBC support for TX streams
+# Value: 0-1, see IEEE Std 802.11-2016, 9.4.2.56.2.
+# -1 = Do not make any changes (default)
+# 0 = Set if not supported
+# 1 = Set if supported
+#
+# rx_stbc: Allow overriding STBC support for RX streams
+# Value: 0-3, see IEEE Std 802.11-2016, 9.4.2.56.2.
+# -1 = Do not make any changes (default)
+# 0 = Set if not supported
+# 1 = Set for support of one spatial stream
+# 2 = Set for support of one and two spatial streams
+# 3 = Set for support of one, two and three spatial streams
# disable_vht: Whether VHT should be disabled.
# 0 = VHT enabled (if AP supports it)
@@ -1366,6 +1475,13 @@
# 2: MCS 0-9
# 3: not supported
+# multi_ap_backhaul_sta: Multi-AP backhaul STA functionality
+# 0 = normal STA (default)
+# 1 = backhaul STA
+# A backhaul STA sends the Multi-AP IE, fails to associate if the AP does not
+# support Multi-AP, and sets 4-address mode if it does. Thus, the netdev can be
+# added to a bridge to allow forwarding frames over this backhaul link.
+
##### Fast Session Transfer (FST) support #####################################
#
# The options in this section are only available when the build configuration
@@ -1765,15 +1881,26 @@
}
-# Example MACsec configuration
-#network={
-# key_mgmt=IEEE8021X
-# eap=TTLS
-# phase2="auth=PAP"
-# anonymous_identity="anonymous@example.com"
-# identity="user@example.com"
-# password="secretr"
-# ca_cert="/etc/cert/ca.pem"
-# eapol_flags=0
-# macsec_policy=1
-#}
+# Example configuration using EAP-TTLS for authentication and key
+# generation for MACsec
+network={
+ key_mgmt=IEEE8021X
+ eap=TTLS
+ phase2="auth=PAP"
+ anonymous_identity="anonymous@example.com"
+ identity="user@example.com"
+ password="secretr"
+ ca_cert="/etc/cert/ca.pem"
+ eapol_flags=0
+ macsec_policy=1
+}
+
+# Example configuration for MACsec with preshared key
+network={
+ key_mgmt=NONE
+ eapol_flags=0
+ macsec_policy=1
+ mka_cak=0123456789ABCDEF0123456789ABCDEF
+ mka_ckn=6162636465666768696A6B6C6D6E6F707172737475767778797A303132333435
+ mka_priority=128
+}
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index acde7c5..a97353f 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -345,6 +345,7 @@
void radio_work_done(struct wpa_radio_work *work);
void radio_remove_works(struct wpa_supplicant *wpa_s,
const char *type, int remove_all);
+void radio_remove_pending_work(struct wpa_supplicant *wpa_s, void *ctx);
void radio_work_check_next(struct wpa_supplicant *wpa_s);
struct wpa_radio_work *
radio_work_pending(struct wpa_supplicant *wpa_s, const char *type);
@@ -450,10 +451,12 @@
struct wpa_bss_tmp_disallowed {
struct dl_list list;
u8 bssid[ETH_ALEN];
+ int rssi_threshold;
};
struct beacon_rep_data {
u8 token;
+ u8 last_indication;
struct wpa_driver_scan_params scan_params;
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
@@ -491,15 +494,16 @@
struct wpa_supplicant *next;
struct l2_packet_data *l2;
struct l2_packet_data *l2_br;
+ struct os_reltime roam_start;
+ struct os_reltime roam_time;
+ struct os_reltime session_start;
+ struct os_reltime session_length;
unsigned char own_addr[ETH_ALEN];
unsigned char perm_addr[ETH_ALEN];
char ifname[100];
#ifdef CONFIG_MATCH_IFACE
int matched;
#endif /* CONFIG_MATCH_IFACE */
-#ifdef CONFIG_CTRL_IFACE_DBUS
- char *dbus_path;
-#endif /* CONFIG_CTRL_IFACE_DBUS */
#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
char *dbus_new_path;
char *dbus_groupobj_path;
@@ -531,6 +535,8 @@
struct wpa_bss *current_bss;
int ap_ies_from_associnfo;
unsigned int assoc_freq;
+ u8 *last_con_fail_realm;
+ size_t last_con_fail_realm_len;
/* Selected configuration (based on Beacon/ProbeResp WPA IE) */
int pairwise_cipher;
@@ -740,6 +746,12 @@
unsigned int mac_addr_changed:1;
unsigned int added_vif:1;
unsigned int wnmsleep_used:1;
+ unsigned int owe_transition_select:1;
+ unsigned int owe_transition_search:1;
+ unsigned int connection_set:1;
+ unsigned int connection_ht:1;
+ unsigned int connection_vht:1;
+ unsigned int connection_he:1;
struct os_reltime last_mac_addr_change;
int last_mac_addr_style;
@@ -751,6 +763,7 @@
int set_ap_uapsd;
int ap_uapsd;
int auth_alg;
+ u16 last_owe_group;
#ifdef CONFIG_SME
struct {
@@ -788,6 +801,8 @@
struct wpabuf *sae_token;
int sae_group_index;
unsigned int sae_pmksa_caching:1;
+ u16 seq_num;
+ struct external_auth ext_auth;
#endif /* CONFIG_SAE */
} sme;
#endif /* CONFIG_SME */
@@ -806,6 +821,7 @@
unsigned int mesh_if_created:1;
unsigned int mesh_ht_enabled:1;
unsigned int mesh_vht_enabled:1;
+ struct wpa_driver_mesh_join_params *mesh_params;
#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
/* struct external_pmksa_cache::list */
struct dl_list mesh_external_pmksa_cache;
@@ -897,11 +913,13 @@
unsigned int p2p_auto_join:1;
unsigned int p2p_auto_pd:1;
+ unsigned int p2p_go_do_acs:1;
unsigned int p2p_persistent_group:1;
unsigned int p2p_fallback_to_go_neg:1;
unsigned int p2p_pd_before_go_neg:1;
unsigned int p2p_go_ht40:1;
unsigned int p2p_go_vht:1;
+ unsigned int p2p_go_he:1;
unsigned int user_initiated_pd:1;
unsigned int p2p_go_group_formation_completed:1;
unsigned int group_formation_reported:1;
@@ -912,6 +930,7 @@
unsigned int p2p_disable_ip_addr_req:1;
unsigned int p2ps_method_config_any:1;
unsigned int p2p_cli_probe:1;
+ enum hostapd_hw_mode p2p_go_acs_band;
int p2p_persistent_go_freq;
int p2p_persistent_id;
int p2p_go_intent;
@@ -1008,6 +1027,10 @@
/* WLAN_REASON_* reason codes. Negative if locally generated. */
int disconnect_reason;
+ /* WLAN_STATUS_* status codes from last received Authentication frame
+ * from the AP. */
+ u16 auth_status_code;
+
/* WLAN_STATUS_* status codes from (Re)Association Response frame. */
u16 assoc_status_code;
/* Indicates if the previous association request timed out. */
@@ -1051,6 +1074,11 @@
struct neighbor_report *wnm_neighbor_report_elements;
struct os_reltime wnm_cand_valid_until;
u8 wnm_cand_from_bss[ETH_ALEN];
+ enum bss_trans_mgmt_status_code bss_tm_status;
+ struct wpabuf *coloc_intf_elems;
+ u8 coloc_intf_dialog_token;
+ u8 coloc_intf_auto_report;
+ u8 coloc_intf_timeout;
#ifdef CONFIG_MBO
unsigned int wnm_mbo_trans_reason_present:1;
u8 wnm_mbo_transition_reason;
@@ -1178,10 +1206,10 @@
/* RIC elements for FT protocol */
struct wpabuf *ric_ies;
+ int last_auth_timeout_sec;
+
#ifdef CONFIG_DPP
- struct dl_list dpp_bootstrap; /* struct dpp_bootstrap_info */
- struct dl_list dpp_configurator; /* struct dpp_configurator */
- int dpp_init_done;
+ struct dpp_global *dpp;
struct dpp_authentication *dpp_auth;
struct wpa_radio_work *dpp_listen_work;
unsigned int dpp_pending_listen_freq;
@@ -1190,7 +1218,9 @@
int dpp_qr_mutual;
int dpp_netrole_ap;
int dpp_auth_ok_on_ack;
+ int dpp_in_response_listen;
int dpp_gas_client;
+ int dpp_gas_dialog_token;
u8 dpp_intro_bssid[ETH_ALEN];
void *dpp_intro_network;
struct dpp_pkex *dpp_pkex;
@@ -1199,6 +1229,16 @@
char *dpp_pkex_identifier;
char *dpp_pkex_auth_cmd;
char *dpp_configurator_params;
+ struct os_reltime dpp_last_init;
+ struct os_reltime dpp_init_iter_start;
+ unsigned int dpp_init_max_tries;
+ unsigned int dpp_init_retry_time;
+ unsigned int dpp_resp_wait_time;
+ unsigned int dpp_resp_max_tries;
+ unsigned int dpp_resp_retry_time;
+#ifdef CONFIG_DPP2
+ struct dpp_pfs *dpp_pfs;
+#endif /* CONFIG_DPP2 */
#ifdef CONFIG_TESTING_OPTIONS
char *dpp_config_obj_override;
char *dpp_discovery_override;
@@ -1206,6 +1246,13 @@
unsigned int dpp_ignore_netaccesskey_mismatch:1;
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_FILS
+ unsigned int disable_fils:1;
+#endif /* CONFIG_FILS */
+ unsigned int ieee80211ac:1;
+ unsigned int enabled_4addr_mode:1;
+ unsigned int multi_bss_support:1;
};
@@ -1238,6 +1285,7 @@
void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr);
void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
int sec, int usec);
+void wpas_auth_timeout_restart(struct wpa_supplicant *wpa_s, int sec_diff);
void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s);
void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
enum wpa_states state);
@@ -1295,6 +1343,7 @@
void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s);
void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s);
void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
+void fils_connection_failure(struct wpa_supplicant *wpa_s);
int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s);
int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s);
void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason);
@@ -1335,8 +1384,12 @@
/* MBO functions */
-int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len);
+int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len,
+ int add_oce_capa);
+const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr);
const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr);
+const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len,
+ enum mbo_attr_id attr);
int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
const char *non_pref_chan);
void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie);
@@ -1351,6 +1404,7 @@
void mbo_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, const u8 *sa,
const u8 *data, size_t slen);
+void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s);
/* op_classes.c */
enum chan_allowed {
@@ -1359,8 +1413,9 @@
enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel,
u8 bw);
-size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
- size_t len);
+size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ int freq, u8 *pos, size_t len);
/**
* wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
@@ -1407,6 +1462,8 @@
struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid **selected_ssid);
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);
/* eap_register.c */
int eap_register_methods(void);
@@ -1459,8 +1516,10 @@
u16 num_modes, enum hostapd_hw_mode mode);
void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
- unsigned int sec);
-int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid);
+ unsigned int sec, int rssi_threshold);
+int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss);
+void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s);
struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
int i, struct wpa_bss *bss,
@@ -1472,4 +1531,7 @@
unsigned int *num,
unsigned int *freq_list);
+int wpa_is_fils_supported(struct wpa_supplicant *wpa_s);
+int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s);
+
#endif /* WPA_SUPPLICANT_I_H */
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index e29f13b..449e04a 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -296,7 +296,7 @@
}
if (result != EAPOL_SUPP_RESULT_SUCCESS ||
- !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X))
return;
if (!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt))
@@ -1037,6 +1037,7 @@
wpas_notify_eap_status(wpa_s, status, parameter);
}
+
static void wpa_supplicant_eap_error_cb(void *ctx, int error_code)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -1044,6 +1045,7 @@
wpas_notify_eap_error(wpa_s, error_code);
}
+
static void wpa_supplicant_set_anon_id(void *ctx, const u8 *id, size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -1181,6 +1183,15 @@
os_free(hex);
}
+
+static int wpa_supplicant_channel_info(void *_wpa_s,
+ struct wpa_channel_info *ci)
+{
+ struct wpa_supplicant *wpa_s = _wpa_s;
+
+ return wpa_drv_channel_info(wpa_s, ci);
+}
+
#endif /* CONFIG_NO_WPA */
@@ -1231,6 +1242,7 @@
ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload;
ctx->key_mgmt_set_pmk = wpa_supplicant_key_mgmt_set_pmk;
ctx->fils_hlp_rx = wpa_supplicant_fils_hlp_rx;
+ ctx->channel_info = wpa_supplicant_channel_info;
wpa_s->wpa = wpa_sm_init(ctx);
if (wpa_s->wpa == NULL) {
diff --git a/wpa_supplicant/wpas_kay.c b/wpa_supplicant/wpas_kay.c
index 587e5c3..41477d5 100644
--- a/wpa_supplicant/wpas_kay.c
+++ b/wpa_supplicant/wpas_kay.c
@@ -5,7 +5,7 @@
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
-#include <openssl/ssl.h>
+
#include "utils/includes.h"
#include "utils/common.h"
@@ -92,6 +92,12 @@
}
+static int wpas_set_receive_lowest_pn(void *wpa_s, struct receive_sa *sa)
+{
+ return wpa_drv_set_receive_lowest_pn(wpa_s, sa);
+}
+
+
static unsigned int conf_offset_val(enum confidentiality_offset co)
{
switch (co) {
@@ -219,6 +225,7 @@
kay_ctx->get_receive_lowest_pn = wpas_get_receive_lowest_pn;
kay_ctx->get_transmit_next_pn = wpas_get_transmit_next_pn;
kay_ctx->set_transmit_next_pn = wpas_set_transmit_next_pn;
+ kay_ctx->set_receive_lowest_pn = wpas_set_receive_lowest_pn;
kay_ctx->create_receive_sc = wpas_create_receive_sc;
kay_ctx->delete_receive_sc = wpas_delete_receive_sc;
kay_ctx->create_receive_sa = wpas_create_receive_sa;
@@ -232,7 +239,8 @@
kay_ctx->enable_transmit_sa = wpas_enable_transmit_sa;
kay_ctx->disable_transmit_sa = wpas_disable_transmit_sa;
- res = ieee802_1x_kay_init(kay_ctx, policy, ssid->macsec_port,
+ res = ieee802_1x_kay_init(kay_ctx, policy, ssid->macsec_replay_protect,
+ ssid->macsec_replay_window, ssid->macsec_port,
ssid->mka_priority, wpa_s->ifname,
wpa_s->own_addr);
/* ieee802_1x_kay_init() frees kay_ctx on failure */
@@ -268,7 +276,7 @@
return -1;
}
- need_len = 1 + 2 * SSL3_RANDOM_SIZE;
+ need_len = 1 + 2 * 32 /* random size */;
if (need_len > id_len) {
wpa_printf(MSG_DEBUG, "EAP Session-Id not long enough");
return -1;
@@ -349,8 +357,8 @@
/* Derive CAK from MSK */
cak->len = DEFAULT_KEY_LEN;
- if (ieee802_1x_cak_128bits_aes_cmac(msk->key, wpa_s->own_addr,
- peer_addr, cak->key)) {
+ if (ieee802_1x_cak_aes_cmac(msk->key, msk->len, wpa_s->own_addr,
+ peer_addr, cak->key, cak->len)) {
wpa_printf(MSG_ERROR,
"IEEE 802.1X: Deriving CAK failed");
goto fail;
@@ -359,9 +367,8 @@
/* Derive CKN from MSK */
ckn->len = DEFAULT_CKN_LEN;
- if (ieee802_1x_ckn_128bits_aes_cmac(msk->key, wpa_s->own_addr,
- peer_addr, sid, sid_len,
- ckn->name)) {
+ if (ieee802_1x_ckn_aes_cmac(msk->key, msk->len, wpa_s->own_addr,
+ peer_addr, sid, sid_len, ckn->name)) {
wpa_printf(MSG_ERROR,
"IEEE 802.1X: Deriving CKN failed");
goto fail;
@@ -392,44 +399,42 @@
{
struct mka_key *cak;
struct mka_key_name *ckn;
- void *res;
+ void *res = NULL;
if ((ssid->mka_psk_set & MKA_PSK_SET) != MKA_PSK_SET)
- return NULL;
-
- if (ieee802_1x_alloc_kay_sm(wpa_s, ssid) < 0)
- return NULL;
-
- if (!wpa_s->kay || wpa_s->kay->policy == DO_NOT_SECURE)
- return NULL;
+ goto end;
ckn = os_zalloc(sizeof(*ckn));
if (!ckn)
- goto dealloc;
+ goto end;
cak = os_zalloc(sizeof(*cak));
if (!cak)
goto free_ckn;
- cak->len = MACSEC_CAK_LEN;
+ if (ieee802_1x_alloc_kay_sm(wpa_s, ssid) < 0 || !wpa_s->kay)
+ goto free_cak;
+
+ if (wpa_s->kay->policy == DO_NOT_SECURE)
+ goto dealloc;
+
+ cak->len = ssid->mka_cak_len;
os_memcpy(cak->key, ssid->mka_cak, cak->len);
- ckn->len = MACSEC_CKN_LEN;
+ ckn->len = ssid->mka_ckn_len;
os_memcpy(ckn->name, ssid->mka_ckn, ckn->len);
res = ieee802_1x_kay_create_mka(wpa_s->kay, ckn, cak, 0, PSK, FALSE);
if (res)
- return res;
+ goto free_cak;
+dealloc:
/* Failed to create MKA */
+ ieee802_1x_dealloc_kay_sm(wpa_s);
+free_cak:
os_free(cak);
-
- /* fallthrough */
-
free_ckn:
os_free(ckn);
-dealloc:
- ieee802_1x_dealloc_kay_sm(wpa_s);
-
- return NULL;
+end:
+ return res;
}
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index bd8af83..2950763 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -203,6 +203,9 @@
if (ssid->ssid == NULL)
return;
bss = wpa_bss_get(wpa_s, cred->mac_addr, ssid->ssid, ssid->ssid_len);
+ if (!bss)
+ bss = wpa_bss_get(wpa_s, wpa_s->bssid,
+ ssid->ssid, ssid->ssid_len);
if (bss == NULL) {
wpa_printf(MSG_DEBUG, "WPS: The AP was not found from BSS "
"table - use credential as-is");
@@ -490,6 +493,16 @@
ssid->pairwise_cipher |= WPA_CIPHER_GCMP;
ssid->group_cipher |= WPA_CIPHER_GCMP;
}
+ if (wpa_s->drv_capa_known &&
+ (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_GCMP_256)) {
+ ssid->pairwise_cipher |= WPA_CIPHER_GCMP_256;
+ ssid->group_cipher |= WPA_CIPHER_GCMP_256;
+ }
+ if (wpa_s->drv_capa_known &&
+ (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_CCMP_256)) {
+ ssid->pairwise_cipher |= WPA_CIPHER_CCMP_256;
+ ssid->group_cipher |= WPA_CIPHER_CCMP_256;
+ }
break;
}
@@ -517,11 +530,18 @@
case WPS_AUTH_WPA2PSK:
ssid->auth_alg = WPA_AUTH_ALG_OPEN;
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
+ if (wpa_s->conf->wps_cred_add_sae &&
+ cred->key_len != 2 * PMK_LEN) {
+ ssid->key_mgmt |= WPA_KEY_MGMT_SAE;
+#ifdef CONFIG_IEEE80211W
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
+#endif /* CONFIG_IEEE80211W */
+ }
ssid->proto = WPA_PROTO_RSN;
break;
}
- if (ssid->key_mgmt == WPA_KEY_MGMT_PSK) {
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
if (cred->key_len == 2 * PMK_LEN) {
if (hexstr2bin((const char *) cred->key, ssid->psk,
PMK_LEN)) {
@@ -1124,9 +1144,10 @@
int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
- int p2p_group)
+ int p2p_group, int multi_ap_backhaul_sta)
{
struct wpa_ssid *ssid;
+ char phase1[32];
#ifdef CONFIG_AP
if (wpa_s->ap_iface) {
@@ -1164,10 +1185,14 @@
}
}
#endif /* CONFIG_P2P */
- if (wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0) < 0)
+ os_snprintf(phase1, sizeof(phase1), "pbc=1%s",
+ multi_ap_backhaul_sta ? " multi_ap=1" : "");
+ if (wpa_config_set_quoted(ssid, "phase1", phase1) < 0)
return -1;
if (wpa_s->wps_fragment_size)
ssid->eap.fragment_size = wpa_s->wps_fragment_size;
+ if (multi_ap_backhaul_sta)
+ ssid->multi_ap_backhaul_sta = 1;
wpa_supplicant_wps_event(wpa_s, WPS_EV_PBC_ACTIVE, NULL);
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
wpa_s, NULL);
diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h
index eb1615a..3a99f2c 100644
--- a/wpa_supplicant/wps_supplicant.h
+++ b/wpa_supplicant/wps_supplicant.h
@@ -30,7 +30,7 @@
int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s);
enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid);
int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
- int p2p_group);
+ int p2p_group, int multi_ap_backhaul_sta);
int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
const char *pin, int p2p_group, u16 dev_pw_id);
void wpas_wps_pbc_overlap(struct wpa_supplicant *wpa_s);