P2P: Fix a corner case in peer addition based on PD Request am: 61dece6d28 am: 3d4eb0e32c am: 45e9e4223b am: 8c2db50b5d
Original change: https://googleplex-android-review.googlesource.com/c/platform/external/wpa_supplicant_8/+/13875752
Change-Id: I11b58bf2b5959cbceb495cbc30f90a0798d8d7f8
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index df3542a..3bde8d5 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -156,6 +156,7 @@
OBJS += src/utils/wpabuf.c
OBJS += src/utils/os_$(CONFIG_OS).c
OBJS += src/utils/ip_addr.c
+OBJS += src/utils/crc32.c
OBJS += src/common/ieee802_11_common.c
OBJS += src/common/wpa_common.c
@@ -216,18 +217,12 @@
L_CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
-ifdef CONFIG_IAPP
-L_CFLAGS += -DCONFIG_IAPP
-OBJS += src/ap/iapp.c
-endif
-
ifdef CONFIG_RSN_PREAUTH
L_CFLAGS += -DCONFIG_RSN_PREAUTH
CONFIG_L2_PACKET=y
endif
ifdef CONFIG_HS20
-NEED_AES_OMAC1=y
CONFIG_PROXYARP=y
endif
@@ -237,8 +232,6 @@
ifdef CONFIG_SUITEB
L_CFLAGS += -DCONFIG_SUITEB
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_SUITEB192
@@ -249,24 +242,14 @@
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
L_CFLAGS += -DCONFIG_IEEE80211R -DCONFIG_IEEE80211R_AP
OBJS += src/ap/wpa_auth_ft.c
-NEED_SHA256=y
-NEED_AES_OMAC1=y
NEED_AES_UNWRAP=y
NEED_AES_SIV=y
NEED_ETH_P_OUI=y
-NEED_SHA256=y
NEED_HMAC_SHA256_KDF=y
endif
@@ -280,6 +263,8 @@
OBJS += src/common/sae.c
NEED_ECC=y
NEED_DH_GROUPS=y
+NEED_HMAC_SHA256_KDF=y
+NEED_DRAGONFLY=y
endif
ifdef CONFIG_OWE
@@ -288,11 +273,14 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
endif
+ifdef CONFIG_WAPI_INTERFACE
+L_CFLAGS += -DCONFIG_WAPI_INTERFACE
+endif
+
ifdef CONFIG_FILS
L_CFLAGS += -DCONFIG_FILS
OBJS += src/ap/fils_hlp.c
@@ -309,10 +297,6 @@
OBJS += src/ap/wnm_ap.c
endif
-ifdef CONFIG_IEEE80211N
-L_CFLAGS += -DCONFIG_IEEE80211N
-endif
-
ifdef CONFIG_IEEE80211AC
L_CFLAGS += -DCONFIG_IEEE80211AC
endif
@@ -341,6 +325,14 @@
endif
endif
+ifdef CONFIG_WEP
+L_CFLAGS += -DCONFIG_WEP
+endif
+
+ifdef CONFIG_NO_TKIP
+L_CFLAGS += -DCONFIG_NO_TKIP
+endif
+
include $(LOCAL_PATH)/src/drivers/drivers.mk
@@ -423,7 +415,6 @@
L_CFLAGS += -DEAP_SERVER_AKA
OBJS += src/eap_server/eap_server_aka.c
CONFIG_EAP_SIM_COMMON=y
-NEED_SHA256=y
NEED_AES_CBC=y
endif
@@ -448,7 +439,6 @@
ifdef CONFIG_EAP_PSK
L_CFLAGS += -DEAP_SERVER_PSK
OBJS += src/eap_server/eap_server_psk.c src/eap_common/eap_psk_common.c
-NEED_AES_OMAC1=y
NEED_AES_ENCBLOCK=y
NEED_AES_EAX=y
endif
@@ -464,15 +454,13 @@
ifdef CONFIG_EAP_GPSK_SHA256
L_CFLAGS += -DEAP_GPSK_SHA256
endif
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_EAP_PWD
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
+NEED_DRAGONFLY=y
endif
ifdef CONFIG_EAP_EKE
@@ -496,6 +484,18 @@
NEED_AES_UNWRAP=y
endif
+ifdef CONFIG_EAP_TEAP
+L_CFLAGS += -DEAP_SERVER_TEAP
+OBJS += src/eap_server/eap_server_teap.c
+OBJS += src/eap_common/eap_teap_common.c
+TLS_FUNCS=y
+NEED_T_PRF=y
+NEED_SHA384=y
+NEED_TLS_PRF_SHA256=y
+NEED_TLS_PRF_SHA384=y
+NEED_AES_UNWRAP=y
+endif
+
ifdef CONFIG_WPS
L_CFLAGS += -DCONFIG_WPS -DEAP_SERVER_WSC
OBJS += src/utils/uuid.c
@@ -510,7 +510,6 @@
OBJS += src/wps/wps_enrollee.c
OBJS += src/wps/wps_registrar.c
NEED_DH_GROUPS=y
-NEED_SHA256=y
NEED_BASE64=y
NEED_AES_CBC=y
NEED_MODEXP=y
@@ -559,12 +558,13 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
+NEED_ECC=y
NEED_JSON=y
NEED_GAS=y
NEED_BASE64=y
+NEED_ASN1=y
ifdef CONFIG_DPP2
L_CFLAGS += -DCONFIG_DPP2
endif
@@ -606,6 +606,10 @@
L_CFLAGS += -DPKCS12_FUNCS
endif
+ifdef NEED_DRAGONFLY
+OBJS += src/common/dragonfly.c
+endif
+
ifdef MS_FUNCS
OBJS += src/crypto/ms_funcs.c
NEED_DES=y
@@ -634,7 +638,6 @@
ifdef CONFIG_TLSV12
L_CFLAGS += -DCONFIG_TLSV12
-NEED_SHA256=y
endif
ifeq ($(CONFIG_TLS), openssl)
@@ -648,7 +651,6 @@
ifdef NEED_FIPS186_2_PRF
OBJS += src/crypto/fips_prf_openssl.c
endif
-NEED_SHA256=y
NEED_TLS_PRF_SHA256=y
LIBS += -lcrypto
LIBS_h += -lcrypto
@@ -700,13 +702,12 @@
OBJS += src/tls/tlsv1_server.c
OBJS += src/tls/tlsv1_server_write.c
OBJS += src/tls/tlsv1_server_read.c
-OBJS += src/tls/asn1.c
OBJS += src/tls/rsa.c
OBJS += src/tls/x509v3.c
OBJS += src/tls/pkcs1.c
OBJS += src/tls/pkcs5.c
OBJS += src/tls/pkcs8.c
-NEED_SHA256=y
+NEED_ASN1=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -801,12 +802,10 @@
ifdef NEED_AES_EAX
AESOBJS += src/crypto/aes-eax.c
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_SIV
AESOBJS += src/crypto/aes-siv.c
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_CTR
AESOBJS += src/crypto/aes-ctr.c
@@ -814,9 +813,7 @@
ifdef NEED_AES_ENCBLOCK
AESOBJS += src/crypto/aes-encblock.c
endif
-ifdef NEED_AES_OMAC1
AESOBJS += src/crypto/aes-omac1.c
-endif
ifdef NEED_AES_UNWRAP
ifneq ($(CONFIG_TLS), openssl)
NEED_AES_DEC=y
@@ -904,7 +901,6 @@
endif
endif
-ifdef NEED_SHA256
L_CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), gnutls)
@@ -918,6 +914,9 @@
ifdef NEED_TLS_PRF_SHA256
OBJS += src/crypto/sha256-tlsprf.c
endif
+ifdef NEED_TLS_PRF_SHA384
+OBJS += src/crypto/sha384-tlsprf.c
+endif
ifdef NEED_HMAC_SHA256_KDF
OBJS += src/crypto/sha256-kdf.c
endif
@@ -927,7 +926,6 @@
ifdef NEED_HMAC_SHA512_KDF
OBJS += src/crypto/sha512-kdf.c
endif
-endif
ifdef NEED_SHA384
L_CFLAGS += -DCONFIG_SHA384
ifneq ($(CONFIG_TLS), openssl)
@@ -959,6 +957,10 @@
OBJS += src/crypto/sha512-internal.c
endif
+ifdef NEED_ASN1
+OBJS += src/tls/asn1.c
+endif
+
ifdef NEED_DH_GROUPS
OBJS += src/crypto/dh_groups.c
endif
@@ -1017,9 +1019,7 @@
OBJS += src/ap/dfs.c
L_CFLAGS += -DNEED_AP_MLME
endif
-ifdef CONFIG_IEEE80211N
OBJS += src/ap/ieee802_11_ht.c
-endif
ifdef CONFIG_IEEE80211AC
OBJS += src/ap/ieee802_11_vht.c
@@ -1128,6 +1128,7 @@
LOCAL_MODULE_TAGS := optional
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_VINTF_FRAGMENTS := android.hardware.wifi.hostapd.xml
ifdef CONFIG_DRIVER_CUSTOM
LOCAL_STATIC_LIBRARIES := libCustomWifi
endif
@@ -1145,7 +1146,8 @@
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_SHARED_LIBRARIES += android.hardware.wifi.hostapd@1.2
+LOCAL_SHARED_LIBRARIES += libbase libhidlbase libutils
LOCAL_STATIC_LIBRARIES += libhostapd_hidl
endif
LOCAL_CFLAGS := $(L_CFLAGS)
@@ -1187,17 +1189,16 @@
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)/hostapd.cpp
LOCAL_SHARED_LIBRARIES := \
android.hardware.wifi.hostapd@1.0 \
android.hardware.wifi.hostapd@1.1 \
+ android.hardware.wifi.hostapd@1.2 \
libbase \
libhidlbase \
- libhidltransport \
- libhwbinder \
libutils \
liblog
LOCAL_EXPORT_C_INCLUDE_DIRS := \
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index f1366b4..6c4410e 100644
--- a/hostapd/ChangeLog
+++ b/hostapd/ChangeLog
@@ -1,5 +1,84 @@
ChangeLog for hostapd
+2019-08-07 - v2.9
+ * SAE changes
+ - disable use of groups using Brainpool curves
+ - improved protection against side channel attacks
+ [https://w1.fi/security/2019-6/]
+ * EAP-pwd changes
+ - disable use of groups using Brainpool curves
+ - improved protection against side channel attacks
+ [https://w1.fi/security/2019-6/]
+ * fixed FT-EAP initial mobility domain association using PMKSA caching
+ * added configuration of airtime policy
+ * fixed FILS to and RSNE into (Re)Association Response frames
+ * fixed DPP bootstrapping URI parser of channel list
+ * added support for regulatory WMM limitation (for ETSI)
+ * added support for MACsec Key Agreement using IEEE 802.1X/PSK
+ * added experimental support for EAP-TEAP server (RFC 7170)
+ * added experimental support for EAP-TLS server with TLS v1.3
+ * added support for two server certificates/keys (RSA/ECC)
+ * added AKMSuiteSelector into "STA <addr>" control interface data to
+ determine with AKM was used for an association
+ * added eap_sim_id parameter to allow EAP-SIM/AKA server pseudonym and
+ fast reauthentication use to be disabled
+ * fixed an ECDH operation corner case with OpenSSL
+
+2019-04-21 - v2.8
+ * SAE changes
+ - added support for SAE Password Identifier
+ - changed default configuration to enable only group 19
+ (i.e., disable groups 20, 21, 25, 26 from default configuration) and
+ disable all unsuitable groups completely based on REVmd changes
+ - improved anti-clogging token mechanism and SAE authentication
+ frame processing during heavy CPU load; this mitigates some issues
+ with potential DoS attacks trying to flood an AP with large number
+ of SAE messages
+ - added Finite Cyclic Group field in status code 77 responses
+ - reject use of unsuitable groups based on new implementation guidance
+ in REVmd (allow only FFC groups with prime >= 3072 bits and ECC
+ groups with prime >= 256)
+ - minimize timing and memory use differences in PWE derivation
+ [https://w1.fi/security/2019-1/] (CVE-2019-9494)
+ - fixed confirm message validation in error cases
+ [https://w1.fi/security/2019-3/] (CVE-2019-9496)
+ * EAP-pwd changes
+ - minimize timing and memory use differences in PWE derivation
+ [https://w1.fi/security/2019-2/] (CVE-2019-9495)
+ - verify peer scalar/element
+ [https://w1.fi/security/2019-4/] (CVE-2019-9497 and CVE-2019-9498)
+ - fix message reassembly issue with unexpected fragment
+ [https://w1.fi/security/2019-5/]
+ - enforce rand,mask generation rules more strictly
+ - fix a memory leak in PWE derivation
+ - disallow ECC groups with a prime under 256 bits (groups 25, 26, and
+ 27)
+ * Hotspot 2.0 changes
+ - added support for release number 3
+ - reject release 2 or newer association without PMF
+ * added support for RSN operating channel validation
+ (CONFIG_OCV=y and configuration parameter ocv=1)
+ * added Multi-AP protocol support
+ * added FTM responder configuration
+ * fixed build with LibreSSL
+ * added FT/RRB workaround for short Ethernet frame padding
+ * fixed KEK2 derivation for FILS+FT
+ * added RSSI-based association rejection from OCE
+ * extended beacon reporting functionality
+ * VLAN changes
+ - allow local VLAN management with remote RADIUS authentication
+ - add WPA/WPA2 passphrase/PSK -based VLAN assignment
+ * OpenSSL: allow systemwide policies to be overridden
+ * extended PEAP to derive EMSK to enable use with ERP/FILS
+ * extended WPS to allow SAE configuration to be added automatically
+ for PSK (wps_cred_add_sae=1)
+ * fixed FT and SA Query Action frame with AP-MLME-in-driver cases
+ * OWE: allow Diffie-Hellman Parameter element to be included with DPP
+ in preparation for DPP protocol extension
+ * RADIUS server: started to accept ERP keyName-NAI as user identity
+ automatically without matching EAP database entry
+ * fixed PTK rekeying with FILS and FT
+
2018-12-02 - v2.7
* fixed WPA packet number reuse with replayed messages and key
reinstallation
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 6e263c5..9c7fc5c 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -121,6 +121,7 @@
LIBS += -lbfd -ldl -liberty -lz
LIBS_c += -lbfd -ldl -liberty -lz
LIBS_h += -lbfd -ldl -liberty -lz
+LIBS_n += -lbfd -ldl -liberty -lz
endif
endif
@@ -157,6 +158,7 @@
OBJS += ../src/utils/wpabuf.o
OBJS += ../src/utils/os_$(CONFIG_OS).o
OBJS += ../src/utils/ip_addr.o
+OBJS += ../src/utils/crc32.o
OBJS += ../src/common/ieee802_11_common.o
OBJS += ../src/common/wpa_common.o
@@ -248,18 +250,12 @@
CFLAGS += -DCONFIG_CTRL_IFACE
endif
-ifdef CONFIG_IAPP
-CFLAGS += -DCONFIG_IAPP
-OBJS += ../src/ap/iapp.o
-endif
-
ifdef CONFIG_RSN_PREAUTH
CFLAGS += -DCONFIG_RSN_PREAUTH
CONFIG_L2_PACKET=y
endif
ifdef CONFIG_HS20
-NEED_AES_OMAC1=y
CONFIG_PROXYARP=y
endif
@@ -269,8 +265,6 @@
ifdef CONFIG_SUITEB
CFLAGS += -DCONFIG_SUITEB
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_SUITEB192
@@ -281,24 +275,14 @@
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
CFLAGS += -DCONFIG_IEEE80211R -DCONFIG_IEEE80211R_AP
OBJS += ../src/ap/wpa_auth_ft.o
-NEED_SHA256=y
-NEED_AES_OMAC1=y
NEED_AES_UNWRAP=y
NEED_AES_SIV=y
NEED_ETH_P_OUI=y
-NEED_SHA256=y
NEED_HMAC_SHA256_KDF=y
endif
@@ -312,7 +296,9 @@
OBJS += ../src/common/sae.o
NEED_ECC=y
NEED_DH_GROUPS=y
+NEED_HMAC_SHA256_KDF=y
NEED_AP_MLME=y
+NEED_DRAGONFLY=y
endif
ifdef CONFIG_OWE
@@ -321,11 +307,19 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
endif
+ifdef CONFIG_WAPI_INTERFACE
+L_CFLAGS += -DCONFIG_WAPI_INTERFACE
+endif
+
+ifdef CONFIG_AIRTIME_POLICY
+CFLAGS += -DCONFIG_AIRTIME_POLICY
+OBJS += ../src/ap/airtime_policy.o
+endif
+
ifdef CONFIG_FILS
CFLAGS += -DCONFIG_FILS
OBJS += ../src/ap/fils_hlp.o
@@ -342,10 +336,6 @@
OBJS += ../src/ap/wnm_ap.o
endif
-ifdef CONFIG_IEEE80211N
-CFLAGS += -DCONFIG_IEEE80211N
-endif
-
ifdef CONFIG_IEEE80211AC
CFLAGS += -DCONFIG_IEEE80211AC
endif
@@ -385,7 +375,6 @@
ifdef CONFIG_ERP
CFLAGS += -DCONFIG_ERP
-NEED_SHA256=y
NEED_HMAC_SHA256_KDF=y
endif
@@ -446,7 +435,6 @@
CFLAGS += -DEAP_SERVER_AKA
OBJS += ../src/eap_server/eap_server_aka.o
CONFIG_EAP_SIM_COMMON=y
-NEED_SHA256=y
NEED_AES_CBC=y
endif
@@ -471,7 +459,6 @@
ifdef CONFIG_EAP_PSK
CFLAGS += -DEAP_SERVER_PSK
OBJS += ../src/eap_server/eap_server_psk.o ../src/eap_common/eap_psk_common.o
-NEED_AES_OMAC1=y
NEED_AES_ENCBLOCK=y
NEED_AES_EAX=y
endif
@@ -487,15 +474,13 @@
ifdef CONFIG_EAP_GPSK_SHA256
CFLAGS += -DEAP_GPSK_SHA256
endif
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_EAP_PWD
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
+NEED_DRAGONFLY=y
endif
ifdef CONFIG_EAP_EKE
@@ -519,6 +504,18 @@
NEED_AES_UNWRAP=y
endif
+ifdef CONFIG_EAP_TEAP
+CFLAGS += -DEAP_SERVER_TEAP
+OBJS += ../src/eap_server/eap_server_teap.o
+OBJS += ../src/eap_common/eap_teap_common.o
+TLS_FUNCS=y
+NEED_T_PRF=y
+NEED_SHA384=y
+NEED_TLS_PRF_SHA256=y
+NEED_TLS_PRF_SHA384=y
+NEED_AES_UNWRAP=y
+endif
+
ifdef CONFIG_WPS
CFLAGS += -DCONFIG_WPS -DEAP_SERVER_WSC
OBJS += ../src/utils/uuid.o
@@ -533,7 +530,6 @@
OBJS += ../src/wps/wps_enrollee.o
OBJS += ../src/wps/wps_registrar.o
NEED_DH_GROUPS=y
-NEED_SHA256=y
NEED_BASE64=y
NEED_AES_CBC=y
NEED_MODEXP=y
@@ -582,12 +578,13 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
+NEED_ECC=y
NEED_JSON=y
NEED_GAS=y
NEED_BASE64=y
+NEED_ASN1=y
ifdef CONFIG_DPP2
CFLAGS += -DCONFIG_DPP2
endif
@@ -613,6 +610,15 @@
endif
endif
+ifdef CONFIG_MACSEC
+CFLAGS += -DCONFIG_MACSEC
+OBJS += ../src/ap/wpa_auth_kay.o
+OBJS += ../src/pae/ieee802_1x_cp.o
+OBJS += ../src/pae/ieee802_1x_kay.o
+OBJS += ../src/pae/ieee802_1x_key.o
+OBJS += ../src/pae/ieee802_1x_secy_ops.o
+endif
+
# Basic EAP functionality is needed for EAPOL
OBJS += eap_register.o
OBJS += ../src/eap_server/eap_server.o
@@ -629,6 +635,10 @@
CFLAGS += -DPKCS12_FUNCS
endif
+ifdef NEED_DRAGONFLY
+OBJS += ../src/common/dragonfly.o
+endif
+
ifdef MS_FUNCS
OBJS += ../src/crypto/ms_funcs.o
NEED_DES=y
@@ -657,7 +667,6 @@
ifdef CONFIG_TLSV12
CFLAGS += -DCONFIG_TLSV12
-NEED_SHA256=y
endif
ifeq ($(CONFIG_TLS), wolfssl)
@@ -671,7 +680,6 @@
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
@@ -693,7 +701,6 @@
ifdef NEED_FIPS186_2_PRF
OBJS += ../src/crypto/fips_prf_openssl.o
endif
-NEED_SHA256=y
NEED_TLS_PRF_SHA256=y
LIBS += -lcrypto
LIBS_h += -lcrypto
@@ -751,13 +758,12 @@
OBJS += ../src/tls/tlsv1_server.o
OBJS += ../src/tls/tlsv1_server_write.o
OBJS += ../src/tls/tlsv1_server_read.o
-OBJS += ../src/tls/asn1.o
OBJS += ../src/tls/rsa.o
OBJS += ../src/tls/x509v3.o
OBJS += ../src/tls/pkcs1.o
OBJS += ../src/tls/pkcs5.o
OBJS += ../src/tls/pkcs8.o
-NEED_SHA256=y
+NEED_ASN1=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -828,13 +834,12 @@
OBJS += ../src/tls/tlsv1_server.o
OBJS += ../src/tls/tlsv1_server_write.o
OBJS += ../src/tls/tlsv1_server_read.o
-OBJS += ../src/tls/asn1.o
OBJS += ../src/tls/rsa.o
OBJS += ../src/tls/x509v3.o
OBJS += ../src/tls/pkcs1.o
OBJS += ../src/tls/pkcs5.o
OBJS += ../src/tls/pkcs8.o
-NEED_SHA256=y
+NEED_ASN1=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -895,12 +900,10 @@
ifdef NEED_AES_EAX
AESOBJS += ../src/crypto/aes-eax.o
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_SIV
AESOBJS += ../src/crypto/aes-siv.o
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_CTR
AESOBJS += ../src/crypto/aes-ctr.o
@@ -908,13 +911,11 @@
ifdef NEED_AES_ENCBLOCK
AESOBJS += ../src/crypto/aes-encblock.o
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)
@@ -1020,7 +1021,6 @@
endif
endif
-ifdef NEED_SHA256
CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
@@ -1038,6 +1038,9 @@
ifdef NEED_TLS_PRF_SHA256
OBJS += ../src/crypto/sha256-tlsprf.o
endif
+ifdef NEED_TLS_PRF_SHA384
+OBJS += ../src/crypto/sha384-tlsprf.o
+endif
ifdef NEED_HMAC_SHA256_KDF
OBJS += ../src/crypto/sha256-kdf.o
endif
@@ -1047,7 +1050,6 @@
ifdef NEED_HMAC_SHA512_KDF
OBJS += ../src/crypto/sha512-kdf.o
endif
-endif
ifdef NEED_SHA384
CFLAGS += -DCONFIG_SHA384
ifneq ($(CONFIG_TLS), openssl)
@@ -1085,6 +1087,10 @@
OBJS += ../src/crypto/sha512-internal.o
endif
+ifdef NEED_ASN1
+OBJS += ../src/tls/asn1.o
+endif
+
ifdef NEED_DH_GROUPS
OBJS += ../src/crypto/dh_groups.o
endif
@@ -1150,9 +1156,7 @@
OBJS += ../src/ap/dfs.o
CFLAGS += -DNEED_AP_MLME
endif
-ifdef CONFIG_IEEE80211N
OBJS += ../src/ap/ieee802_11_ht.o
-endif
ifdef CONFIG_IEEE80211AC
OBJS += ../src/ap/ieee802_11_vht.o
@@ -1239,6 +1243,14 @@
endif
endif
+ifdef CONFIG_WEP
+CFLAGS += -DCONFIG_WEP
+endif
+
+ifdef CONFIG_NO_TKIP
+CFLAGS += -DCONFIG_NO_TKIP
+endif
+
ALL=hostapd hostapd_cli
all: verify_config $(ALL)
@@ -1315,7 +1327,6 @@
NOBJS += ../src/utils/wpabuf.o
ifdef CONFIG_WPA_TRACE
NOBJS += ../src/utils/trace.o
-LIBS_n += -lbfd
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
diff --git a/hostapd/android.config b/hostapd/android.config
index 4502a60..cd54efc 100644
--- a/hostapd/android.config
+++ b/hostapd/android.config
@@ -38,18 +38,9 @@
# Driver interface for no driver (e.g., RADIUS server only)
#CONFIG_DRIVER_NONE=y
-# IEEE 802.11F/IAPP
-#CONFIG_IAPP=y
-
# WPA2/IEEE 802.11i RSN pre-authentication
#CONFIG_RSN_PREAUTH=y
-# IEEE 802.11w (management frame protection)
-# This version is an experimental implementation based on IEEE 802.11w/D1.0
-# draft and is subject to change since the standard has not yet been finalized.
-# Driver support is also needed for IEEE 802.11w.
-CONFIG_IEEE80211W=y
-
# Support Operating Channel Validation
#CONFIG_OCV=y
@@ -134,9 +125,6 @@
# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
#CONFIG_DRIVER_RADIUS_ACL=y
-# IEEE 802.11n (High Throughput) support
-CONFIG_IEEE80211N=y
-
# IEEE 802.11ac (Very High Throughput) support
CONFIG_IEEE80211AC=y
@@ -210,6 +198,11 @@
# Experimental implementation of draft-harkins-owe-07.txt
#CONFIG_OWE=y
+# WLAN Authentication and Privacy Infrastructure (WAPI): interface only.
+# Configure the building of the interface which allows WAPI configuration.
+# Note: does not configure WAPI implementation itself.
+#CONFIG_WAPI_INTERFACE=y
+
# Wpa_supplicant's random pool is not necessary on Android. Randomness is
# already provided by the entropymixer service which ensures sufficient
# entropy is maintained across reboots. Commit b410eb1913 'Initialize
@@ -229,3 +222,12 @@
# WPA3-Personal (SAE)
CONFIG_SAE=y
+
+# Wired equivalent privacy (WEP)
+# WEP is an obsolete cryptographic data confidentiality algorithm that is not
+# considered secure. It should not be used for anything anymore. The
+# functionality needed to use WEP is available in the current hostapd
+# release under this optional build parameter. This functionality is subject to
+# be completely removed in a future release.
+CONFIG_WEP=y
+
diff --git a/hostapd/android.hardware.wifi.hostapd.xml b/hostapd/android.hardware.wifi.hostapd.xml
new file mode 100644
index 0000000..4dc1701
--- /dev/null
+++ b/hostapd/android.hardware.wifi.hostapd.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.wifi.hostapd</name>
+ <transport>hwbinder</transport>
+ <version>1.2</version>
+ <interface>
+ <name>IHostapd</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 42f3b40..cc1855d 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -24,14 +24,6 @@
#include "config_file.h"
-#ifndef CONFIG_NO_RADIUS
-#ifdef EAP_SERVER
-static struct hostapd_radius_attr *
-hostapd_parse_radius_attr(const char *value);
-#endif /* EAP_SERVER */
-#endif /* CONFIG_NO_RADIUS */
-
-
#ifndef CONFIG_NO_VLAN
static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
const char *fname)
@@ -660,75 +652,6 @@
}
-static struct hostapd_radius_attr *
-hostapd_parse_radius_attr(const char *value)
-{
- const char *pos;
- char syntax;
- struct hostapd_radius_attr *attr;
- size_t len;
-
- attr = os_zalloc(sizeof(*attr));
- if (attr == NULL)
- return NULL;
-
- attr->type = atoi(value);
-
- pos = os_strchr(value, ':');
- if (pos == NULL) {
- attr->val = wpabuf_alloc(1);
- if (attr->val == NULL) {
- os_free(attr);
- return NULL;
- }
- wpabuf_put_u8(attr->val, 0);
- return attr;
- }
-
- pos++;
- if (pos[0] == '\0' || pos[1] != ':') {
- os_free(attr);
- return NULL;
- }
- syntax = *pos++;
- pos++;
-
- switch (syntax) {
- case 's':
- attr->val = wpabuf_alloc_copy(pos, os_strlen(pos));
- break;
- case 'x':
- len = os_strlen(pos);
- if (len & 1)
- break;
- len /= 2;
- attr->val = wpabuf_alloc(len);
- if (attr->val == NULL)
- break;
- if (hexstr2bin(pos, wpabuf_put(attr->val, len), len) < 0) {
- wpabuf_free(attr->val);
- os_free(attr);
- return NULL;
- }
- break;
- case 'd':
- attr->val = wpabuf_alloc(4);
- if (attr->val)
- wpabuf_put_be32(attr->val, atoi(pos));
- break;
- default:
- os_free(attr);
- return NULL;
- }
-
- if (attr->val == NULL) {
- os_free(attr);
- return NULL;
- }
-
- return attr;
-}
-
static int hostapd_parse_das_client(struct hostapd_bss_config *bss, char *val)
{
@@ -788,12 +711,10 @@
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)
val |= WPA_KEY_MGMT_PSK_SHA256;
else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
else if (os_strcmp(start, "SAE") == 0)
val |= WPA_KEY_MGMT_SAE;
@@ -872,6 +793,7 @@
}
+#ifdef CONFIG_WEP
static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
char *val)
{
@@ -922,6 +844,7 @@
return 0;
}
+#endif /* CONFIG_WEP */
static int hostapd_parse_chanlist(struct hostapd_config *conf, char *val)
@@ -1230,7 +1153,6 @@
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211N
static int hostapd_config_ht_capab(struct hostapd_config *conf,
const char *capab)
{
@@ -1250,14 +1172,6 @@
}
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;
- }
- if (os_strstr(capab, "[SMPS-DYNAMIC]")) {
- conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
- conf->ht_capab |= HT_CAP_INFO_SMPS_DYNAMIC;
- }
if (os_strstr(capab, "[GF]"))
conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD;
if (os_strstr(capab, "[SHORT-GI-20]"))
@@ -1291,7 +1205,6 @@
return 0;
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
@@ -2313,6 +2226,42 @@
#endif /* EAP_SERVER */
+#ifdef CONFIG_AIRTIME_POLICY
+static int add_airtime_weight(struct hostapd_bss_config *bss, char *value)
+{
+ struct airtime_sta_weight *wt;
+ char *pos, *next;
+
+ wt = os_zalloc(sizeof(*wt));
+ if (!wt)
+ return -1;
+
+ /* 02:01:02:03:04:05 10 */
+ pos = value;
+ next = os_strchr(pos, ' ');
+ if (next)
+ *next++ = '\0';
+ if (!next || hwaddr_aton(pos, wt->addr)) {
+ wpa_printf(MSG_ERROR, "Invalid station address: '%s'", pos);
+ os_free(wt);
+ return -1;
+ }
+
+ pos = next;
+ wt->weight = atoi(pos);
+ if (!wt->weight) {
+ wpa_printf(MSG_ERROR, "Invalid weight: '%s'", pos);
+ os_free(wt);
+ return -1;
+ }
+
+ wt->next = bss->airtime_weight_list;
+ bss->airtime_weight_list = wt;
+ return 0;
+}
+#endif /* CONFIG_AIRTIME_POLICY */
+
+
#ifdef CONFIG_SAE
static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
{
@@ -2376,6 +2325,36 @@
#endif /* CONFIG_SAE */
+#ifdef CONFIG_DPP2
+static int hostapd_dpp_controller_parse(struct hostapd_bss_config *bss,
+ const char *pos)
+{
+ struct dpp_controller_conf *conf;
+ char *val;
+
+ conf = os_zalloc(sizeof(*conf));
+ if (!conf)
+ return -1;
+ val = get_param(pos, "ipaddr=");
+ if (!val || hostapd_parse_ip_addr(val, &conf->ipaddr))
+ goto fail;
+ os_free(val);
+ val = get_param(pos, "pkhash=");
+ if (!val || os_strlen(val) != 2 * SHA256_MAC_LEN ||
+ hexstr2bin(val, conf->pkhash, SHA256_MAC_LEN) < 0)
+ goto fail;
+ os_free(val);
+ conf->next = bss->dpp_controller;
+ bss->dpp_controller = conf;
+ return 0;
+fail:
+ os_free(val);
+ os_free(conf);
+ return -1;
+}
+#endif /* CONFIG_DPP2 */
+
+
static int hostapd_config_fill(struct hostapd_config *conf,
struct hostapd_bss_config *bss,
const char *buf, char *pos, int line)
@@ -2484,6 +2463,13 @@
} else if (os_strcmp(buf, "skip_inactivity_poll") == 0) {
bss->skip_inactivity_poll = atoi(pos);
} else if (os_strcmp(buf, "country_code") == 0) {
+ if (pos[0] < 'A' || pos[0] > 'Z' ||
+ pos[1] < 'A' || pos[1] > 'Z') {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid country_code '%s'",
+ line, pos);
+ return 1;
+ }
os_memcpy(conf->country, pos, 2);
} else if (os_strcmp(buf, "country3") == 0) {
conf->country[2] = strtol(pos, NULL, 16);
@@ -2496,7 +2482,11 @@
} else if (os_strcmp(buf, "eapol_version") == 0) {
int eapol_version = atoi(pos);
+#ifdef CONFIG_MACSEC
+ if (eapol_version < 1 || eapol_version > 3) {
+#else /* CONFIG_MACSEC */
if (eapol_version < 1 || eapol_version > 2) {
+#endif /* CONFIG_MACSEC */
wpa_printf(MSG_ERROR,
"Line %d: invalid EAPOL version (%d): '%s'.",
line, eapol_version, pos);
@@ -2519,12 +2509,21 @@
} else if (os_strcmp(buf, "server_cert") == 0) {
os_free(bss->server_cert);
bss->server_cert = os_strdup(pos);
+ } else if (os_strcmp(buf, "server_cert2") == 0) {
+ os_free(bss->server_cert2);
+ bss->server_cert2 = os_strdup(pos);
} else if (os_strcmp(buf, "private_key") == 0) {
os_free(bss->private_key);
bss->private_key = os_strdup(pos);
+ } else if (os_strcmp(buf, "private_key2") == 0) {
+ os_free(bss->private_key2);
+ bss->private_key2 = os_strdup(pos);
} 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, "private_key_passwd2") == 0) {
+ os_free(bss->private_key_passwd2);
+ bss->private_key_passwd2 = 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'",
@@ -2545,6 +2544,10 @@
bss->tls_session_lifetime = atoi(pos);
} else if (os_strcmp(buf, "tls_flags") == 0) {
bss->tls_flags = parse_tls_flags(pos);
+ } else if (os_strcmp(buf, "max_auth_rounds") == 0) {
+ bss->max_auth_rounds = atoi(pos);
+ } else if (os_strcmp(buf, "max_auth_rounds_short") == 0) {
+ bss->max_auth_rounds_short = atoi(pos);
} else if (os_strcmp(buf, "ocsp_stapling_response") == 0) {
os_free(bss->ocsp_stapling_response);
bss->ocsp_stapling_response = os_strdup(pos);
@@ -2605,6 +2608,24 @@
} else if (os_strcmp(buf, "pac_key_refresh_time") == 0) {
bss->pac_key_refresh_time = atoi(pos);
#endif /* EAP_SERVER_FAST */
+#ifdef EAP_SERVER_TEAP
+ } else if (os_strcmp(buf, "eap_teap_auth") == 0) {
+ int val = atoi(pos);
+
+ if (val < 0 || val > 1) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid eap_teap_auth value",
+ line);
+ return 1;
+ }
+ bss->eap_teap_auth = val;
+ } else if (os_strcmp(buf, "eap_teap_pac_no_inner") == 0) {
+ bss->eap_teap_pac_no_inner = atoi(pos);
+ } else if (os_strcmp(buf, "eap_teap_separate_result") == 0) {
+ bss->eap_teap_separate_result = atoi(pos);
+ } else if (os_strcmp(buf, "eap_teap_id") == 0) {
+ bss->eap_teap_id = atoi(pos);
+#endif /* EAP_SERVER_TEAP */
#ifdef EAP_SERVER_SIM
} else if (os_strcmp(buf, "eap_sim_db") == 0) {
os_free(bss->eap_sim_db);
@@ -2613,6 +2634,8 @@
bss->eap_sim_db_timeout = atoi(pos);
} else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) {
bss->eap_sim_aka_result_ind = atoi(pos);
+ } else if (os_strcmp(buf, "eap_sim_id") == 0) {
+ bss->eap_sim_id = atoi(pos);
#endif /* EAP_SERVER_SIM */
#ifdef EAP_SERVER_TNC
} else if (os_strcmp(buf, "tnc") == 0) {
@@ -2650,6 +2673,7 @@
} else if (os_strcmp(buf, "erp_domain") == 0) {
os_free(bss->erp_domain);
bss->erp_domain = os_strdup(pos);
+#ifdef CONFIG_WEP
} else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
int val = atoi(pos);
@@ -2677,6 +2701,7 @@
line, bss->wep_rekeying_period);
return 1;
}
+#endif /* CONFIG_WEP */
} else if (os_strcmp(buf, "eap_reauth_period") == 0) {
bss->eap_reauth_period = atoi(pos);
if (bss->eap_reauth_period < 0) {
@@ -2688,8 +2713,7 @@
bss->eapol_key_index_workaround = atoi(pos);
#ifdef CONFIG_IAPP
} else if (os_strcmp(buf, "iapp_interface") == 0) {
- bss->ieee802_11f = 1;
- os_strlcpy(bss->iapp_iface, pos, sizeof(bss->iapp_iface));
+ wpa_printf(MSG_INFO, "DEPRECATED: iapp_interface not used");
#endif /* CONFIG_IAPP */
} else if (os_strcmp(buf, "own_ip_addr") == 0) {
if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) {
@@ -2816,6 +2840,9 @@
a = a->next;
a->next = attr;
}
+ } else if (os_strcmp(buf, "radius_req_attr_sqlite") == 0) {
+ os_free(bss->radius_req_attr_sqlite);
+ bss->radius_req_attr_sqlite = os_strdup(pos);
} else if (os_strcmp(buf, "radius_das_port") == 0) {
bss->radius_das_port = atoi(pos);
} else if (os_strcmp(buf, "radius_das_client") == 0) {
@@ -2849,6 +2876,16 @@
}
} else if (os_strcmp(buf, "wpa") == 0) {
bss->wpa = atoi(pos);
+ } else if (os_strcmp(buf, "extended_key_id") == 0) {
+ int val = atoi(pos);
+
+ if (val < 0 || val > 2) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid extended_key_id=%d; allowed range 0..2",
+ line, val);
+ return 1;
+ }
+ bss->extended_key_id = val;
} else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
bss->wpa_group_rekey = atoi(pos);
bss->wpa_group_rekey_set = 1;
@@ -2858,6 +2895,15 @@
bss->wpa_gmk_rekey = atoi(pos);
} else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
bss->wpa_ptk_rekey = atoi(pos);
+ } else if (os_strcmp(buf, "wpa_deny_ptk0_rekey") == 0) {
+ bss->wpa_deny_ptk0_rekey = atoi(pos);
+ if (bss->wpa_deny_ptk0_rekey < 0 ||
+ bss->wpa_deny_ptk0_rekey > 2) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid wpa_deny_ptk0_rekey=%d; allowed range 0..2",
+ line, bss->wpa_deny_ptk0_rekey);
+ return 1;
+ }
} else if (os_strcmp(buf, "wpa_group_update_count") == 0) {
char *endp;
unsigned long val = strtoul(pos, &endp, 0);
@@ -3110,6 +3156,8 @@
}
} else if (os_strcmp(buf, "acs_exclude_dfs") == 0) {
conf->acs_exclude_dfs = atoi(pos);
+ } else if (os_strcmp(buf, "op_class") == 0) {
+ conf->op_class = atoi(pos);
} else if (os_strcmp(buf, "channel") == 0) {
if (os_strcmp(pos, "acs_survey") == 0) {
#ifndef CONFIG_ACS
@@ -3124,12 +3172,25 @@
conf->channel = atoi(pos);
conf->acs = conf->channel == 0;
}
+ } else if (os_strcmp(buf, "edmg_channel") == 0) {
+ conf->edmg_channel = atoi(pos);
+ } else if (os_strcmp(buf, "enable_edmg") == 0) {
+ conf->enable_edmg = atoi(pos);
} else if (os_strcmp(buf, "chanlist") == 0) {
if (hostapd_parse_chanlist(conf, pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid channel list",
line);
return 1;
}
+ } else if (os_strcmp(buf, "freqlist") == 0) {
+ if (freq_range_list_parse(&conf->acs_freq_list, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid frequency list",
+ line);
+ return 1;
+ }
+ conf->acs_freq_list_present = 1;
+ } else if (os_strcmp(buf, "acs_exclude_6ghz_non_psc") == 0) {
+ conf->acs_exclude_6ghz_non_psc = atoi(pos);
} else if (os_strcmp(buf, "beacon_int") == 0) {
int val = atoi(pos);
/* MIB defines range as 1..65535, but very small values
@@ -3271,6 +3332,7 @@
bss->ignore_broadcast_ssid = atoi(pos);
} else if (os_strcmp(buf, "no_probe_resp_if_max_sta") == 0) {
bss->no_probe_resp_if_max_sta = atoi(pos);
+#ifdef CONFIG_WEP
} else if (os_strcmp(buf, "wep_default_key") == 0) {
bss->ssid.wep.idx = atoi(pos);
if (bss->ssid.wep.idx > 3) {
@@ -3289,6 +3351,7 @@
line, buf);
return 1;
}
+#endif /* CONFIG_WEP */
#ifndef CONFIG_NO_VLAN
} else if (os_strcmp(buf, "dynamic_vlan") == 0) {
bss->ssid.dynamic_vlan = atoi(pos);
@@ -3351,7 +3414,6 @@
}
} else if (os_strcmp(buf, "use_driver_iface_addr") == 0) {
conf->use_driver_iface_addr = atoi(pos);
-#ifdef CONFIG_IEEE80211W
} else if (os_strcmp(buf, "ieee80211w") == 0) {
bss->ieee80211w = atoi(pos);
} else if (os_strcmp(buf, "group_mgmt_cipher") == 0) {
@@ -3368,6 +3430,8 @@
line, pos);
return 1;
}
+ } else if (os_strcmp(buf, "beacon_prot") == 0) {
+ bss->beacon_prot = atoi(pos);
} else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) {
bss->assoc_sa_query_max_timeout = atoi(pos);
if (bss->assoc_sa_query_max_timeout == 0) {
@@ -3382,14 +3446,12 @@
line);
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);
} else if (os_strcmp(buf, "ht_capab") == 0) {
@@ -3402,7 +3464,6 @@
conf->require_ht = atoi(pos);
} else if (os_strcmp(buf, "obss_interval") == 0) {
conf->obss_interval = atoi(pos);
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
} else if (os_strcmp(buf, "ieee80211ac") == 0) {
conf->ieee80211ac = atoi(pos);
@@ -3435,13 +3496,18 @@
} else if (os_strcmp(buf, "he_mu_beamformer") == 0) {
conf->he_phy_capab.he_mu_beamformer = atoi(pos);
} else if (os_strcmp(buf, "he_bss_color") == 0) {
- conf->he_op.he_bss_color = atoi(pos);
+ conf->he_op.he_bss_color = atoi(pos) & 0x3f;
+ conf->he_op.he_bss_color_disabled = 0;
+ } else if (os_strcmp(buf, "he_bss_color_partial") == 0) {
+ conf->he_op.he_bss_color_partial = atoi(pos);
} else if (os_strcmp(buf, "he_default_pe_duration") == 0) {
conf->he_op.he_default_pe_duration = atoi(pos);
} else if (os_strcmp(buf, "he_twt_required") == 0) {
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_basic_mcs_nss_set") == 0) {
+ conf->he_op.he_basic_mcs_nss_set = 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);
@@ -3526,6 +3592,20 @@
} 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;
+ } else if (os_strcmp(buf, "he_spr_sr_control") == 0) {
+ conf->spr.sr_control = atoi(pos) & 0xff;
+ } else if (os_strcmp(buf, "he_spr_non_srg_obss_pd_max_offset") == 0) {
+ conf->spr.non_srg_obss_pd_max_offset = atoi(pos);
+ } else if (os_strcmp(buf, "he_spr_srg_obss_pd_min_offset") == 0) {
+ conf->spr.srg_obss_pd_min_offset = atoi(pos);
+ } else if (os_strcmp(buf, "he_spr_srg_obss_pd_max_offset") == 0) {
+ conf->spr.srg_obss_pd_max_offset = atoi(pos);
+ } else if (os_strcmp(buf, "he_oper_chwidth") == 0) {
+ conf->he_oper_chwidth = atoi(pos);
+ } else if (os_strcmp(buf, "he_oper_centr_freq_seg0_idx") == 0) {
+ conf->he_oper_centr_freq_seg0_idx = atoi(pos);
+ } else if (os_strcmp(buf, "he_oper_centr_freq_seg1_idx") == 0) {
+ conf->he_oper_centr_freq_seg1_idx = atoi(pos);
#endif /* CONFIG_IEEE80211AX */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
@@ -3707,6 +3787,9 @@
} else if (os_strcmp(buf, "server_id") == 0) {
os_free(bss->server_id);
bss->server_id = os_strdup(pos);
+ } else if (os_strcmp(buf, "wps_application_ext") == 0) {
+ wpabuf_free(bss->wps_application_ext);
+ bss->wps_application_ext = wpabuf_parse_bin(pos);
#ifdef CONFIG_WPS_NFC
} else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) {
bss->wps_nfc_dev_pw_id = atoi(pos);
@@ -4110,6 +4193,30 @@
} 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, "rsne_override_eapol") == 0) {
+ wpabuf_free(bss->rsne_override_eapol);
+ bss->rsne_override_eapol = wpabuf_parse_bin(pos);
+ } else if (os_strcmp(buf, "rsnxe_override_eapol") == 0) {
+ wpabuf_free(bss->rsnxe_override_eapol);
+ bss->rsnxe_override_eapol = wpabuf_parse_bin(pos);
+ } else if (os_strcmp(buf, "rsne_override_ft") == 0) {
+ wpabuf_free(bss->rsne_override_ft);
+ bss->rsne_override_ft = wpabuf_parse_bin(pos);
+ } else if (os_strcmp(buf, "rsnxe_override_ft") == 0) {
+ wpabuf_free(bss->rsnxe_override_ft);
+ bss->rsnxe_override_ft = wpabuf_parse_bin(pos);
+ } else if (os_strcmp(buf, "gtk_rsc_override") == 0) {
+ wpabuf_free(bss->gtk_rsc_override);
+ bss->gtk_rsc_override = wpabuf_parse_bin(pos);
+ } else if (os_strcmp(buf, "igtk_rsc_override") == 0) {
+ wpabuf_free(bss->igtk_rsc_override);
+ bss->igtk_rsc_override = wpabuf_parse_bin(pos);
+ } else if (os_strcmp(buf, "no_beacon_rsnxe") == 0) {
+ bss->no_beacon_rsnxe = atoi(pos);
+ } else if (os_strcmp(buf, "skip_prune_assoc") == 0) {
+ bss->skip_prune_assoc = atoi(pos);
+ } else if (os_strcmp(buf, "ft_rsnxe_used") == 0) {
+ bss->ft_rsnxe_used = atoi(pos);
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_SAE
} else if (os_strcmp(buf, "sae_password") == 0) {
@@ -4138,6 +4245,10 @@
}
} else if (os_strcmp(buf, "sae_require_mfp") == 0) {
bss->sae_require_mfp = atoi(pos);
+ } else if (os_strcmp(buf, "sae_confirm_immediate") == 0) {
+ bss->sae_confirm_immediate = atoi(pos);
+ } else if (os_strcmp(buf, "sae_pwe") == 0) {
+ bss->sae_pwe = atoi(pos);
} else if (os_strcmp(buf, "local_pwr_constraint") == 0) {
int val = atoi(pos);
if (val < 0 || val > 255) {
@@ -4287,6 +4398,12 @@
} else if (os_strcmp(buf, "broadcast_deauth") == 0) {
bss->broadcast_deauth = atoi(pos);
#ifdef CONFIG_DPP
+ } else if (os_strcmp(buf, "dpp_name") == 0) {
+ os_free(bss->dpp_name);
+ bss->dpp_name = os_strdup(pos);
+ } else if (os_strcmp(buf, "dpp_mud_url") == 0) {
+ os_free(bss->dpp_mud_url);
+ bss->dpp_mud_url = os_strdup(pos);
} else if (os_strcmp(buf, "dpp_connector") == 0) {
os_free(bss->dpp_connector);
bss->dpp_connector = os_strdup(pos);
@@ -4298,6 +4415,23 @@
} else if (os_strcmp(buf, "dpp_csign") == 0) {
if (parse_wpabuf_hex(line, buf, &bss->dpp_csign, pos))
return 1;
+#ifdef CONFIG_DPP2
+ } else if (os_strcmp(buf, "dpp_controller") == 0) {
+ if (hostapd_dpp_controller_parse(bss, pos))
+ return 1;
+ } else if (os_strcmp(buf, "dpp_configurator_connectivity") == 0) {
+ bss->dpp_configurator_connectivity = atoi(pos);
+ } else if (os_strcmp(buf, "dpp_pfs") == 0) {
+ int val = atoi(pos);
+
+ if (val < 0 || val > 2) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid dpp_pfs value '%s'",
+ line, pos);
+ return -1;
+ }
+ bss->dpp_pfs = val;
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
#ifdef CONFIG_OWE
} else if (os_strcmp(buf, "owe_transition_bssid") == 0) {
@@ -4330,9 +4464,11 @@
line, pos);
return 1;
}
+ } else if (os_strcmp(buf, "owe_ptk_workaround") == 0) {
+ bss->owe_ptk_workaround = atoi(pos);
+#endif /* CONFIG_OWE */
} 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);
@@ -4349,6 +4485,123 @@
conf->rssi_reject_assoc_timeout = atoi(pos);
} else if (os_strcmp(buf, "pbss") == 0) {
bss->pbss = atoi(pos);
+ } else if (os_strcmp(buf, "transition_disable") == 0) {
+ bss->transition_disable = strtol(pos, NULL, 16);
+#ifdef CONFIG_AIRTIME_POLICY
+ } else if (os_strcmp(buf, "airtime_mode") == 0) {
+ int val = atoi(pos);
+
+ if (val < 0 || val > AIRTIME_MODE_MAX) {
+ wpa_printf(MSG_ERROR, "Line %d: Unknown airtime_mode",
+ line);
+ return 1;
+ }
+ conf->airtime_mode = val;
+ } else if (os_strcmp(buf, "airtime_update_interval") == 0) {
+ conf->airtime_update_interval = atoi(pos);
+ } else if (os_strcmp(buf, "airtime_bss_weight") == 0) {
+ bss->airtime_weight = atoi(pos);
+ } else if (os_strcmp(buf, "airtime_bss_limit") == 0) {
+ int val = atoi(pos);
+
+ if (val < 0 || val > 1) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid airtime_bss_limit (must be 0 or 1)",
+ line);
+ return 1;
+ }
+ bss->airtime_limit = val;
+ } else if (os_strcmp(buf, "airtime_sta_weight") == 0) {
+ if (add_airtime_weight(bss, pos) < 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid airtime weight '%s'",
+ line, pos);
+ return 1;
+ }
+#endif /* CONFIG_AIRTIME_POLICY */
+#ifdef CONFIG_MACSEC
+ } else if (os_strcmp(buf, "macsec_policy") == 0) {
+ int macsec_policy = atoi(pos);
+
+ if (macsec_policy < 0 || macsec_policy > 1) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid macsec_policy (%d): '%s'.",
+ line, macsec_policy, pos);
+ return 1;
+ }
+ bss->macsec_policy = macsec_policy;
+ } else if (os_strcmp(buf, "macsec_integ_only") == 0) {
+ int macsec_integ_only = atoi(pos);
+
+ if (macsec_integ_only < 0 || macsec_integ_only > 1) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid macsec_integ_only (%d): '%s'.",
+ line, macsec_integ_only, pos);
+ return 1;
+ }
+ bss->macsec_integ_only = macsec_integ_only;
+ } else if (os_strcmp(buf, "macsec_replay_protect") == 0) {
+ int macsec_replay_protect = atoi(pos);
+
+ if (macsec_replay_protect < 0 || macsec_replay_protect > 1) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid macsec_replay_protect (%d): '%s'.",
+ line, macsec_replay_protect, pos);
+ return 1;
+ }
+ bss->macsec_replay_protect = macsec_replay_protect;
+ } else if (os_strcmp(buf, "macsec_replay_window") == 0) {
+ bss->macsec_replay_window = atoi(pos);
+ } else if (os_strcmp(buf, "macsec_port") == 0) {
+ int macsec_port = atoi(pos);
+
+ if (macsec_port < 1 || macsec_port > 65534) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid macsec_port (%d): '%s'.",
+ line, macsec_port, pos);
+ return 1;
+ }
+ bss->macsec_port = macsec_port;
+ } else if (os_strcmp(buf, "mka_priority") == 0) {
+ int mka_priority = atoi(pos);
+
+ if (mka_priority < 0 || mka_priority > 255) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid mka_priority (%d): '%s'.",
+ line, mka_priority, pos);
+ return 1;
+ }
+ bss->mka_priority = mka_priority;
+ } else if (os_strcmp(buf, "mka_cak") == 0) {
+ size_t len = os_strlen(pos);
+
+ if (len > 2 * MACSEC_CAK_MAX_LEN ||
+ (len != 2 * 16 && len != 2 * 32) ||
+ hexstr2bin(pos, bss->mka_cak, len / 2)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CAK '%s'.",
+ line, pos);
+ return 1;
+ }
+ bss->mka_cak_len = len / 2;
+ bss->mka_psk_set |= MKA_PSK_SET_CAK;
+ } else if (os_strcmp(buf, "mka_ckn") == 0) {
+ size_t len = os_strlen(pos);
+
+ 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, pos);
+ return 1;
+ }
+ bss->mka_ckn_len = len / 2;
+ if (hexstr2bin(pos, bss->mka_ckn, bss->mka_ckn_len)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.",
+ line, pos);
+ return -1;
+ }
+ bss->mka_psk_set |= MKA_PSK_SET_CKN;
+#endif /* CONFIG_MACSEC */
} else {
wpa_printf(MSG_ERROR,
"Line %d: unknown configuration item '%s'",
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index e4b16e6..6e8352f 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -11,7 +11,11 @@
#ifndef CONFIG_NATIVE_WINDOWS
#ifdef CONFIG_TESTING_OPTIONS
+#ifdef __NetBSD__
+#include <net/if_ether.h>
+#else
#include <net/ethernet.h>
+#endif
#include <netinet/ip.h>
#endif /* CONFIG_TESTING_OPTIONS */
@@ -55,6 +59,7 @@
#include "ap/neighbor_db.h"
#include "ap/rrm.h"
#include "ap/dpp_hostapd.h"
+#include "ap/dfs.h"
#include "wps/wps_defs.h"
#include "wps/wps.h"
#include "fst/fst_ctrl_iface.h"
@@ -65,9 +70,6 @@
#define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
#ifdef CONFIG_CTRL_IFACE_UDP
-#define COOKIE_LEN 8
-static unsigned char cookie[COOKIE_LEN];
-static unsigned char gcookie[COOKIE_LEN];
#define HOSTAPD_CTRL_IFACE_PORT 8877
#define HOSTAPD_CTRL_IFACE_PORT_LIMIT 50
#define HOSTAPD_GLOBAL_CTRL_IFACE_PORT 8878
@@ -130,7 +132,6 @@
}
-#ifdef CONFIG_IEEE80211W
#ifdef NEED_AP_MLME
static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
const char *txtaddr)
@@ -149,7 +150,6 @@
return 0;
}
#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
@@ -1098,7 +1098,6 @@
}
#endif /* CONFIG_FILS */
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
if (os_snprintf_error(end - pos, ret))
@@ -1111,7 +1110,6 @@
return pos - buf;
pos += ret;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
ret = os_snprintf(pos, end - pos, "SAE ");
@@ -1290,6 +1288,22 @@
pos += ret;
}
+ if (hapd->conf->wpa && hapd->conf->wpa_deny_ptk0_rekey) {
+ ret = os_snprintf(pos, end - pos, "wpa_deny_ptk0_rekey=%d\n",
+ hapd->conf->wpa_deny_ptk0_rekey);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->extended_key_id) {
+ ret = os_snprintf(pos, end - pos, "extended_key_id=%d\n",
+ hapd->conf->extended_key_id);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
return pos - buf;
}
@@ -1330,6 +1344,33 @@
}
}
+
+static int hostapd_ctrl_iface_set_band(struct hostapd_data *hapd,
+ const char *band)
+{
+ union wpa_event_data event;
+ enum set_band setband;
+
+ if (os_strcmp(band, "AUTO") == 0)
+ setband = WPA_SETBAND_AUTO;
+ else if (os_strcmp(band, "5G") == 0)
+ setband = WPA_SETBAND_5G;
+ else if (os_strcmp(band, "2G") == 0)
+ setband = WPA_SETBAND_2G;
+ else
+ return -1;
+
+ if (hostapd_drv_set_band(hapd, setband) == 0) {
+ os_memset(&event, 0, sizeof(event));
+ event.channel_list_changed.initiator = REGDOM_SET_BY_USER;
+ event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN;
+ wpa_supplicant_event(hapd, EVENT_CHANNEL_LIST_CHANGED, &event);
+ }
+
+ return 0;
+}
+
+
static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
{
char *value;
@@ -1413,6 +1454,8 @@
os_free(hapd->dpp_configurator_params);
hapd->dpp_configurator_params = os_strdup(value);
#endif /* CONFIG_DPP */
+ } else if (os_strcasecmp(cmd, "setband") == 0) {
+ ret = hostapd_ctrl_iface_set_band(hapd, value);
} else {
ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
if (ret)
@@ -1428,7 +1471,18 @@
if (ieee802_11_update_beacons(hapd->iface))
wpa_printf(MSG_DEBUG,
"Failed to update beacons with WMM parameters");
+ } else if (os_strcmp(cmd, "wpa_passphrase") == 0 ||
+ os_strcmp(cmd, "sae_password") == 0 ||
+ os_strcmp(cmd, "sae_pwe") == 0) {
+ if (hapd->started)
+ hostapd_setup_sae_pt(hapd->conf);
}
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (os_strcmp(cmd, "ft_rsnxe_used") == 0)
+ wpa_auth_set_ft_rsnxe_used(hapd->wpa_auth,
+ hapd->conf->ft_rsnxe_used);
+#endif /* CONFIG_TESTING_OPTIONS */
}
return ret;
@@ -1628,7 +1682,7 @@
return -1;
}
- res = hostapd_drv_send_mlme(hapd, buf, len, 0);
+ res = hostapd_drv_send_mlme(hapd, buf, len, 0, NULL, 0, 0);
os_free(buf);
return res;
}
@@ -1827,29 +1881,43 @@
{
struct hostapd_data *hapd = ctx;
const struct ether_header *eth;
- struct iphdr ip;
+ struct ip 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)
+ if (ip.ip_hl != 5 || ip.ip_v != 4 ||
+ ntohs(ip.ip_len) > HWSIM_IP_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "test data: RX - ignore unexpect IP header");
return;
+ }
- for (i = 0; i < HWSIM_IP_LEN - sizeof(ip); i++) {
- if (*pos != (u8) i)
+ for (i = 0; i < ntohs(ip.ip_len) - sizeof(ip); i++) {
+ if (*pos != (u8) i) {
+ wpa_printf(MSG_DEBUG,
+ "test data: RX - ignore mismatching payload");
return;
+ }
pos++;
}
- wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
- MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
+ extra[0] = '\0';
+ if (ntohs(ip.ip_len) != HWSIM_IP_LEN)
+ os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.ip_len));
+ wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s",
+ MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra);
}
@@ -1894,20 +1962,21 @@
static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
{
u8 dst[ETH_ALEN], src[ETH_ALEN];
- char *pos;
+ char *pos, *pos2;
int used;
long int val;
u8 tos;
u8 buf[2 + HWSIM_PACKETLEN];
struct ether_header *eth;
- struct iphdr *ip;
+ struct ip *ip;
u8 *dpos;
unsigned int i;
+ size_t send_len = HWSIM_IP_LEN;
if (hapd->l2_test == NULL)
return -1;
- /* format: <dst> <src> <tos> */
+ /* format: <dst> <src> <tos> [len=<length>] */
pos = cmd;
used = hwaddr_aton2(pos, dst);
@@ -1921,32 +1990,40 @@
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);
eth->ether_type = htons(ETHERTYPE_IP);
- ip = (struct iphdr *) (eth + 1);
+ ip = (struct ip *) (eth + 1);
os_memset(ip, 0, sizeof(*ip));
- ip->ihl = 5;
- ip->version = 4;
- ip->ttl = 64;
- ip->tos = tos;
- ip->tot_len = htons(HWSIM_IP_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));
+ ip->ip_hl = 5;
+ ip->ip_v = 4;
+ ip->ip_ttl = 64;
+ ip->ip_tos = tos;
+ ip->ip_len = htons(send_len);
+ ip->ip_p = 1;
+ ip->ip_src.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
+ ip->ip_dst.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
+ ip->ip_sum = 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(hapd->l2_test, dst, ETHERTYPE_IP, &buf[2],
- HWSIM_PACKETLEN) < 0)
+ sizeof(struct ether_header) + send_len) < 0)
return -1;
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX dst=" MACSTR
@@ -2086,7 +2163,6 @@
if (hwaddr_aton(cmd, addr))
return -1;
-#ifdef CONFIG_IEEE80211W
if (is_broadcast_ether_addr(addr) && os_strstr(cmd, "IGTK")) {
if (hapd->last_igtk_alg == WPA_ALG_NONE)
return -1;
@@ -2098,19 +2174,20 @@
if (hostapd_drv_set_key(hapd->conf->iface, hapd,
hapd->last_igtk_alg,
broadcast_ether_addr,
- hapd->last_igtk_key_idx, 1, NULL, 0,
- zero, hapd->last_igtk_len) < 0)
+ hapd->last_igtk_key_idx, 0, 1, NULL, 0,
+ zero, hapd->last_igtk_len,
+ KEY_FLAG_GROUP_TX_DEFAULT) < 0)
return -1;
/* Set the previously configured key to reset its TSC */
return hostapd_drv_set_key(hapd->conf->iface, hapd,
hapd->last_igtk_alg,
broadcast_ether_addr,
- hapd->last_igtk_key_idx, 1, NULL, 0,
- hapd->last_igtk,
- hapd->last_igtk_len);
+ hapd->last_igtk_key_idx, 0, 1, NULL,
+ 0, hapd->last_igtk,
+ hapd->last_igtk_len,
+ KEY_FLAG_GROUP_TX_DEFAULT);
}
-#endif /* CONFIG_IEEE80211W */
if (is_broadcast_ether_addr(addr)) {
if (hapd->last_gtk_alg == WPA_ALG_NONE)
@@ -2123,16 +2200,19 @@
if (hostapd_drv_set_key(hapd->conf->iface, hapd,
hapd->last_gtk_alg,
broadcast_ether_addr,
- hapd->last_gtk_key_idx, 1, NULL, 0,
- zero, hapd->last_gtk_len) < 0)
+ hapd->last_gtk_key_idx, 0, 1, NULL, 0,
+ zero, hapd->last_gtk_len,
+ KEY_FLAG_GROUP_TX_DEFAULT) < 0)
return -1;
/* Set the previously configured key to reset its TSC */
return hostapd_drv_set_key(hapd->conf->iface, hapd,
hapd->last_gtk_alg,
broadcast_ether_addr,
- hapd->last_gtk_key_idx, 1, NULL, 0,
- hapd->last_gtk, hapd->last_gtk_len);
+ hapd->last_gtk_key_idx, 0, 1, NULL,
+ 0, hapd->last_gtk,
+ hapd->last_gtk_len,
+ KEY_FLAG_GROUP_TX_DEFAULT);
}
sta = ap_get_sta(hapd, addr);
@@ -2148,14 +2228,16 @@
/* First, use a zero key to avoid any possible duplicate key avoidance
* in the driver. */
if (hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
- sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
- zero, sta->last_tk_len) < 0)
+ sta->addr, sta->last_tk_key_idx, 0, 1, NULL, 0,
+ zero, sta->last_tk_len,
+ KEY_FLAG_PAIRWISE_RX_TX) < 0)
return -1;
/* Set the previously configured key to reset its TSC/RSC */
return hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
- sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
- sta->last_tk, sta->last_tk_len);
+ sta->addr, sta->last_tk_key_idx, 0, 1, NULL,
+ 0, sta->last_tk, sta->last_tk_len,
+ KEY_FLAG_PAIRWISE_RX_TX);
}
@@ -2164,11 +2246,12 @@
u8 addr[ETH_ALEN];
const char *pos = cmd;
enum wpa_alg alg;
+ enum key_flag key_flag;
int idx, set_tx;
u8 seq[6], key[WPA_TK_MAX_LEN];
size_t key_len;
- /* parameters: alg addr idx set_tx seq key */
+ /* parameters: alg addr idx set_tx seq key key_flag */
alg = atoi(pos);
pos = os_strchr(pos, ' ');
@@ -2197,13 +2280,24 @@
if (*pos != ' ')
return -1;
pos++;
- key_len = os_strlen(pos) / 2;
+ if (!os_strchr(pos, ' '))
+ return -1;
+ key_len = (os_strchr(pos, ' ') - pos) / 2;
if (hexstr2bin(pos, key, key_len) < 0)
return -1;
+ pos += 2 * key_len;
+ if (*pos != ' ')
+ return -1;
+
+ pos++;
+ key_flag = atoi(pos);
+ pos = os_strchr(pos, ' ');
+ if (pos)
+ return -1;
wpa_printf(MSG_INFO, "TESTING: Set key");
- return hostapd_drv_set_key(hapd->conf->iface, hapd, alg, addr, idx,
- set_tx, seq, 6, key, key_len);
+ return hostapd_drv_set_key(hapd->conf->iface, hapd, alg, addr, idx, 0,
+ set_tx, seq, 6, key, key_len, key_flag);
}
@@ -2218,8 +2312,9 @@
* in replay protection issues for now since there is no clean way of
* preventing encryption of a single EAPOL frame. */
hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
- sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
- sta->last_tk, sta->last_tk_len);
+ sta->addr, sta->last_tk_key_idx, 0, 1, NULL, 0,
+ sta->last_tk, sta->last_tk_len,
+ KEY_FLAG_PAIRWISE_RX_TX);
}
@@ -2242,8 +2337,8 @@
wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
MAC2STR(sta->addr));
hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
- sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
- NULL, 0);
+ sta->addr, sta->last_tk_key_idx, 0, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_PAIRWISE);
}
wpa_printf(MSG_INFO, "TESTING: Send M1 to " MACSTR, MAC2STR(sta->addr));
@@ -2272,8 +2367,8 @@
wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
MAC2STR(sta->addr));
hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
- sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
- NULL, 0);
+ sta->addr, sta->last_tk_key_idx, 0, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_PAIRWISE);
}
wpa_printf(MSG_INFO, "TESTING: Send M3 to " MACSTR, MAC2STR(sta->addr));
@@ -2302,8 +2397,8 @@
wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
MAC2STR(sta->addr));
hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
- sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
- NULL, 0);
+ sta->addr, sta->last_tk_key_idx, 0, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_PAIRWISE);
}
wpa_printf(MSG_INFO,
@@ -2313,21 +2408,206 @@
plain ? restore_tk : NULL, hapd, sta);
}
+
+static int hostapd_ctrl_get_pmk(struct hostapd_data *hapd, const char *cmd,
+ char *buf, size_t buflen)
+{
+ struct sta_info *sta;
+ u8 addr[ETH_ALEN];
+ const u8 *pmk;
+ int pmk_len;
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta || !sta->wpa_sm) {
+ wpa_printf(MSG_DEBUG, "No STA WPA state machine for " MACSTR,
+ MAC2STR(addr));
+ return -1;
+ }
+ pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
+ if (!pmk) {
+ wpa_printf(MSG_DEBUG, "No PMK stored for " MACSTR,
+ MAC2STR(addr));
+ return -1;
+ }
+
+ return wpa_snprintf_hex(buf, buflen, pmk, pmk_len);
+}
+
#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef NEED_AP_MLME
+static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params)
+{
+ switch (params->bandwidth) {
+ case 0:
+ /* bandwidth not specified: use 20 MHz by default */
+ /* fall-through */
+ case 20:
+ if (params->center_freq1 &&
+ params->center_freq1 != params->freq)
+ return -1;
+
+ if (params->center_freq2 || params->sec_channel_offset)
+ return -1;
+ break;
+ case 40:
+ if (params->center_freq2 || !params->sec_channel_offset)
+ return -1;
+
+ if (!params->center_freq1)
+ break;
+ switch (params->sec_channel_offset) {
+ case 1:
+ if (params->freq + 10 != params->center_freq1)
+ return -1;
+ break;
+ case -1:
+ if (params->freq - 10 != params->center_freq1)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ case 80:
+ if (!params->center_freq1 || !params->sec_channel_offset)
+ return 1;
+
+ switch (params->sec_channel_offset) {
+ case 1:
+ if (params->freq - 10 != params->center_freq1 &&
+ params->freq + 30 != params->center_freq1)
+ return 1;
+ break;
+ case -1:
+ if (params->freq + 10 != params->center_freq1 &&
+ params->freq - 30 != params->center_freq1)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+
+ /* Adjacent and overlapped are not allowed for 80+80 */
+ if (params->center_freq2 &&
+ params->center_freq1 - params->center_freq2 <= 80 &&
+ params->center_freq2 - params->center_freq1 <= 80)
+ return 1;
+ break;
+ case 160:
+ if (!params->center_freq1 || params->center_freq2 ||
+ !params->sec_channel_offset)
+ return -1;
+
+ switch (params->sec_channel_offset) {
+ case 1:
+ if (params->freq + 70 != params->center_freq1 &&
+ params->freq + 30 != params->center_freq1 &&
+ params->freq - 10 != params->center_freq1 &&
+ params->freq - 50 != params->center_freq1)
+ return -1;
+ break;
+ case -1:
+ if (params->freq + 50 != params->center_freq1 &&
+ params->freq + 10 != params->center_freq1 &&
+ params->freq - 30 != params->center_freq1 &&
+ params->freq - 70 != params->center_freq1)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+#endif /* NEED_AP_MLME */
+
+
static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
char *pos)
{
#ifdef NEED_AP_MLME
struct csa_settings settings;
int ret;
+ int dfs_range = 0;
unsigned int i;
+ int bandwidth;
+ u8 chan;
ret = hostapd_parse_csa_settings(pos, &settings);
if (ret)
return ret;
+ ret = hostapd_ctrl_check_freq_params(&settings.freq_params);
+ if (ret) {
+ wpa_printf(MSG_INFO,
+ "chanswitch: invalid frequency settings provided");
+ return ret;
+ }
+
+ switch (settings.freq_params.bandwidth) {
+ case 40:
+ bandwidth = CHAN_WIDTH_40;
+ break;
+ case 80:
+ if (settings.freq_params.center_freq2)
+ bandwidth = CHAN_WIDTH_80P80;
+ else
+ bandwidth = CHAN_WIDTH_80;
+ break;
+ case 160:
+ bandwidth = CHAN_WIDTH_160;
+ break;
+ default:
+ bandwidth = CHAN_WIDTH_20;
+ break;
+ }
+
+ if (settings.freq_params.center_freq1)
+ dfs_range += hostapd_is_dfs_overlap(
+ iface, bandwidth, settings.freq_params.center_freq1);
+ else
+ dfs_range += hostapd_is_dfs_overlap(
+ iface, bandwidth, settings.freq_params.freq);
+
+ if (settings.freq_params.center_freq2)
+ dfs_range += hostapd_is_dfs_overlap(
+ iface, bandwidth, settings.freq_params.center_freq2);
+
+ if (dfs_range) {
+ ret = ieee80211_freq_to_chan(settings.freq_params.freq, &chan);
+ if (ret == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_ERROR,
+ "Failed to get channel for (freq=%d, sec_channel_offset=%d, bw=%d)",
+ settings.freq_params.freq,
+ settings.freq_params.sec_channel_offset,
+ settings.freq_params.bandwidth);
+ return -1;
+ }
+
+ settings.freq_params.channel = chan;
+
+ wpa_printf(MSG_DEBUG,
+ "DFS/CAC to (channel=%u, freq=%d, sec_channel_offset=%d, bw=%d, center_freq1=%d)",
+ settings.freq_params.channel,
+ settings.freq_params.freq,
+ settings.freq_params.sec_channel_offset,
+ settings.freq_params.bandwidth,
+ settings.freq_params.center_freq1);
+
+ /* Perform CAC and switch channel */
+ hostapd_switch_channel_fallback(iface, &settings.freq_params);
+ return 0;
+ }
+
for (i = 0; i < iface->num_bss; i++) {
/* Save CHAN_SWITCH VHT config */
@@ -2656,6 +2936,20 @@
}
+static int hostapd_ctrl_iface_show_neighbor(struct hostapd_data *hapd,
+ char *buf, size_t buflen)
+{
+ if (!(hapd->conf->radio_measurements[0] &
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SHOW_NEIGHBOR: Neighbor report is not enabled");
+ return -1;
+ }
+
+ return hostapd_neighbor_show(hapd, buf, buflen);
+}
+
+
static int hostapd_ctrl_iface_set_neighbor(struct hostapd_data *hapd, char *buf)
{
struct wpa_ssid_value ssid;
@@ -2762,6 +3056,7 @@
char *buf)
{
struct wpa_ssid_value ssid;
+ struct wpa_ssid_value *ssidp = NULL;
u8 bssid[ETH_ALEN];
char *tmp;
@@ -2771,13 +3066,16 @@
}
tmp = os_strstr(buf, "ssid=");
- if (!tmp || ssid_parse(tmp + 5, &ssid)) {
- wpa_printf(MSG_ERROR,
- "CTRL: REMOVE_NEIGHBORr: Bad or missing SSID");
- return -1;
+ if (tmp) {
+ ssidp = &ssid;
+ if (ssid_parse(tmp + 5, &ssid)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: REMOVE_NEIGHBOR: Bad SSID");
+ return -1;
+ }
}
- return hostapd_neighbor_remove(hapd, bssid, &ssid);
+ return hostapd_neighbor_remove(hapd, bssid, ssidp);
}
@@ -2809,6 +3107,34 @@
}
+static int hostapd_ctrl_driver_flags2(struct hostapd_iface *iface, char *buf,
+ size_t buflen)
+{
+ int ret, i;
+ char *pos, *end;
+
+ ret = os_snprintf(buf, buflen, "%016llX:\n",
+ (long long unsigned) iface->drv_flags2);
+ if (os_snprintf_error(buflen, ret))
+ return -1;
+
+ pos = buf + ret;
+ end = buf + buflen;
+
+ for (i = 0; i < 64; i++) {
+ if (iface->drv_flags2 & (1LLU << i)) {
+ ret = os_snprintf(pos, end - pos, "%s\n",
+ driver_flag2_to_string(1LLU << i));
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ }
+
+ return pos - buf;
+}
+
+
static int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
const char *txtaddr)
{
@@ -3009,13 +3335,11 @@
} else if (os_strcmp(buf, "STOP_AP") == 0) {
if (hostapd_ctrl_iface_stop_ap(hapd))
reply_len = -1;
-#ifdef CONFIG_IEEE80211W
#ifdef NEED_AP_MLME
} else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
reply_len = -1;
#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
@@ -3165,6 +3489,9 @@
} else if (os_strcmp(buf, "REKEY_GTK") == 0) {
if (wpa_auth_rekey_gtk(hapd->wpa_auth) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "GET_PMK ", 8) == 0) {
+ reply_len = hostapd_ctrl_get_pmk(hapd, buf + 8, reply,
+ reply_size);
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
@@ -3202,6 +3529,9 @@
} else if (os_strncmp(buf, "SET_NEIGHBOR ", 13) == 0) {
if (hostapd_ctrl_iface_set_neighbor(hapd, buf + 13))
reply_len = -1;
+ } else if (os_strcmp(buf, "SHOW_NEIGHBOR") == 0) {
+ reply_len = hostapd_ctrl_iface_show_neighbor(hapd, reply,
+ reply_size);
} else if (os_strncmp(buf, "REMOVE_NEIGHBOR ", 16) == 0) {
if (hostapd_ctrl_iface_remove_neighbor(hapd, buf + 16))
reply_len = -1;
@@ -3217,6 +3547,9 @@
} else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply,
reply_size);
+ } else if (os_strcmp(buf, "DRIVER_FLAGS2") == 0) {
+ reply_len = hostapd_ctrl_driver_flags2(hapd->iface, reply,
+ reply_size);
} else if (os_strcmp(buf, "TERMINATE") == 0) {
eloop_terminate();
} else if (os_strncmp(buf, "ACCEPT_ACL ", 11) == 0) {
@@ -3269,6 +3602,33 @@
if (os_snprintf_error(reply_size, reply_len))
reply_len = -1;
}
+ } else if (os_strncmp(buf, "DPP_NFC_URI ", 12) == 0) {
+ res = hostapd_dpp_nfc_uri(hapd, buf + 12);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_REQ ", 21) == 0) {
+ res = hostapd_dpp_nfc_handover_req(hapd, buf + 20);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_SEL ", 21) == 0) {
+ res = hostapd_dpp_nfc_handover_sel(hapd, buf + 20);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) {
res = dpp_bootstrap_gen(hapd->iface->interfaces->dpp, buf + 18);
if (res < 0) {
@@ -3298,6 +3658,11 @@
reply_len = dpp_bootstrap_info(hapd->iface->interfaces->dpp,
atoi(buf + 19),
reply, reply_size);
+ } else if (os_strncmp(buf, "DPP_BOOTSTRAP_SET ", 18) == 0) {
+ if (dpp_bootstrap_set(hapd->iface->interfaces->dpp,
+ atoi(buf + 18),
+ os_strchr(buf + 18, ' ')) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
if (hostapd_dpp_auth_init(hapd, buf + 13) < 0)
reply_len = -1;
@@ -3377,7 +3742,7 @@
int reply_len;
int level = MSG_DEBUG;
#ifdef CONFIG_CTRL_IFACE_UDP
- unsigned char lcookie[COOKIE_LEN];
+ unsigned char lcookie[CTRL_IFACE_COOKIE_LEN];
#endif /* CONFIG_CTRL_IFACE_UDP */
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
@@ -3402,28 +3767,30 @@
#ifdef CONFIG_CTRL_IFACE_UDP
if (os_strcmp(buf, "GET_COOKIE") == 0) {
os_memcpy(reply, "COOKIE=", 7);
- wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
- cookie, COOKIE_LEN);
- reply_len = 7 + 2 * COOKIE_LEN;
+ wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1,
+ hapd->ctrl_iface_cookie,
+ CTRL_IFACE_COOKIE_LEN);
+ reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN;
goto done;
}
if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
- hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
+ hexstr2bin(buf + 7, lcookie, CTRL_IFACE_COOKIE_LEN) < 0) {
wpa_printf(MSG_DEBUG,
"CTRL: No cookie in the request - drop request");
os_free(reply);
return;
}
- if (os_memcmp(cookie, lcookie, COOKIE_LEN) != 0) {
+ if (os_memcmp(hapd->ctrl_iface_cookie, lcookie,
+ CTRL_IFACE_COOKIE_LEN) != 0) {
wpa_printf(MSG_DEBUG,
"CTRL: Invalid cookie in the request - drop request");
os_free(reply);
return;
}
- pos = buf + 7 + 2 * COOKIE_LEN;
+ pos = buf + 7 + 2 * CTRL_IFACE_COOKIE_LEN;
while (*pos == ' ')
pos++;
#endif /* CONFIG_CTRL_IFACE_UDP */
@@ -3512,7 +3879,7 @@
dl_list_init(&hapd->ctrl_dst);
hapd->ctrl_sock = -1;
- os_get_random(cookie, COOKIE_LEN);
+ os_get_random(hapd->ctrl_iface_cookie, CTRL_IFACE_COOKIE_LEN);
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
hints.ai_flags = AI_PASSIVE;
@@ -4091,7 +4458,7 @@
static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
- void *interfaces = eloop_ctx;
+ struct hapd_interfaces *interfaces = eloop_ctx;
char buffer[256], *buf = buffer;
int res;
struct sockaddr_storage from;
@@ -4100,7 +4467,7 @@
int reply_len;
const int reply_size = 4096;
#ifdef CONFIG_CTRL_IFACE_UDP
- unsigned char lcookie[COOKIE_LEN];
+ unsigned char lcookie[CTRL_IFACE_COOKIE_LEN];
#endif /* CONFIG_CTRL_IFACE_UDP */
res = recvfrom(sock, buffer, sizeof(buffer) - 1, 0,
@@ -4129,28 +4496,30 @@
#ifdef CONFIG_CTRL_IFACE_UDP
if (os_strcmp(buf, "GET_COOKIE") == 0) {
os_memcpy(reply, "COOKIE=", 7);
- wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
- gcookie, COOKIE_LEN);
- reply_len = 7 + 2 * COOKIE_LEN;
+ wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1,
+ interfaces->ctrl_iface_cookie,
+ CTRL_IFACE_COOKIE_LEN);
+ reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN;
goto send_reply;
}
if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
- hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
+ hexstr2bin(buf + 7, lcookie, CTRL_IFACE_COOKIE_LEN) < 0) {
wpa_printf(MSG_DEBUG,
"CTRL: No cookie in the request - drop request");
os_free(reply);
return;
}
- if (os_memcmp(gcookie, lcookie, COOKIE_LEN) != 0) {
+ if (os_memcmp(interfaces->ctrl_iface_cookie, lcookie,
+ CTRL_IFACE_COOKIE_LEN) != 0) {
wpa_printf(MSG_DEBUG,
"CTRL: Invalid cookie in the request - drop request");
os_free(reply);
return;
}
- buf += 7 + 2 * COOKIE_LEN;
+ buf += 7 + 2 * CTRL_IFACE_COOKIE_LEN;
while (*buf == ' ')
buf++;
#endif /* CONFIG_CTRL_IFACE_UDP */
@@ -4294,7 +4663,7 @@
}
}
- os_get_random(gcookie, COOKIE_LEN);
+ os_get_random(interface->ctrl_iface_cookie, CTRL_IFACE_COOKIE_LEN);
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
hints.ai_flags = AI_PASSIVE;
@@ -4344,6 +4713,8 @@
return -1;
}
+ wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
+
return 0;
fail:
@@ -4446,6 +4817,8 @@
eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
interface, NULL);
+ wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
+
return 0;
fail:
@@ -4515,37 +4888,43 @@
}
-static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
- enum wpa_msg_type type,
- const char *buf, size_t len)
+static void hostapd_ctrl_iface_send_internal(int sock, struct dl_list *ctrl_dst,
+ const char *ifname, int level,
+ const char *buf, size_t len)
{
struct wpa_ctrl_dst *dst, *next;
- struct dl_list *ctrl_dst;
struct msghdr msg;
- int idx;
- struct iovec io[2];
+ int idx, res;
+ struct iovec io[5];
char levelstr[10];
- int s;
- if (type != WPA_MSG_ONLY_GLOBAL) {
- s = hapd->ctrl_sock;
- ctrl_dst = &hapd->ctrl_dst;
- } else {
- s = hapd->iface->interfaces->global_ctrl_sock;
- ctrl_dst = &hapd->iface->interfaces->global_ctrl_dst;
- }
-
- if (s < 0 || dl_list_empty(ctrl_dst))
+ if (sock < 0 || dl_list_empty(ctrl_dst))
return;
- os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
- io[0].iov_base = levelstr;
- io[0].iov_len = os_strlen(levelstr);
- io[1].iov_base = (char *) buf;
- io[1].iov_len = len;
+ res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
+ if (os_snprintf_error(sizeof(levelstr), res))
+ return;
+ idx = 0;
+ if (ifname) {
+ io[idx].iov_base = "IFNAME=";
+ io[idx].iov_len = 7;
+ idx++;
+ io[idx].iov_base = (char *) ifname;
+ io[idx].iov_len = os_strlen(ifname);
+ idx++;
+ io[idx].iov_base = " ";
+ io[idx].iov_len = 1;
+ idx++;
+ }
+ io[idx].iov_base = levelstr;
+ io[idx].iov_len = os_strlen(levelstr);
+ idx++;
+ io[idx].iov_base = (char *) buf;
+ io[idx].iov_len = len;
+ idx++;
os_memset(&msg, 0, sizeof(msg));
msg.msg_iov = io;
- msg.msg_iovlen = 2;
+ msg.msg_iovlen = idx;
idx = 0;
dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
@@ -4555,22 +4934,16 @@
&dst->addr, dst->addrlen);
msg.msg_name = &dst->addr;
msg.msg_namelen = dst->addrlen;
- if (sendmsg(s, &msg, 0) < 0) {
+ if (sendmsg(sock, &msg, 0) < 0) {
int _errno = errno;
wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
"%d - %s",
idx, errno, strerror(errno));
dst->errors++;
if (dst->errors > 10 || _errno == ENOENT) {
- if (type != WPA_MSG_ONLY_GLOBAL)
- hostapd_ctrl_iface_detach(
- hapd, &dst->addr,
- dst->addrlen);
- else
- hostapd_global_ctrl_iface_detach(
- hapd->iface->interfaces,
- &dst->addr,
- dst->addrlen);
+ ctrl_iface_detach(ctrl_dst,
+ &dst->addr,
+ dst->addrlen);
}
} else
dst->errors = 0;
@@ -4579,4 +4952,25 @@
}
}
+
+static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
+ enum wpa_msg_type type,
+ const char *buf, size_t len)
+{
+ if (type != WPA_MSG_NO_GLOBAL) {
+ hostapd_ctrl_iface_send_internal(
+ hapd->iface->interfaces->global_ctrl_sock,
+ &hapd->iface->interfaces->global_ctrl_dst,
+ type != WPA_MSG_PER_INTERFACE ?
+ NULL : hapd->conf->iface,
+ level, buf, len);
+ }
+
+ if (type != WPA_MSG_ONLY_GLOBAL) {
+ hostapd_ctrl_iface_send_internal(
+ hapd->ctrl_sock, &hapd->ctrl_dst,
+ NULL, level, buf, len);
+ }
+}
+
#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/hostapd/defconfig b/hostapd/defconfig
index ea5e2c9..2341765 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -44,15 +44,9 @@
# Driver interface for no driver (e.g., RADIUS server only)
#CONFIG_DRIVER_NONE=y
-# IEEE 802.11F/IAPP
-CONFIG_IAPP=y
-
# WPA2/IEEE 802.11i RSN pre-authentication
CONFIG_RSN_PREAUTH=y
-# IEEE 802.11w (management frame protection)
-CONFIG_IEEE80211W=y
-
# Support Operating Channel Validation
#CONFIG_OCV=y
@@ -108,11 +102,18 @@
#CONFIG_EAP_GPSK_SHA256=y
# EAP-FAST for the integrated EAP server
-# 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-TEAP for the integrated EAP server
+# Note: The current EAP-TEAP implementation is experimental and should not be
+# enabled for production use. The IETF RFC 7170 that defines EAP-TEAP has number
+# of conflicting statements and missing details and the implementation has
+# vendor specific workarounds for those and as such, may not interoperate with
+# any other implementation. This should not be used for anything else than
+# experimentation and interoperability testing until those issues has been
+# resolved.
+#CONFIG_EAP_TEAP=y
+
# Wi-Fi Protected Setup (WPS)
#CONFIG_WPS=y
# Enable UPnP support for external WPS Registrars
@@ -147,9 +148,6 @@
# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
#CONFIG_DRIVER_RADIUS_ACL=y
-# IEEE 802.11n (High Throughput) support
-#CONFIG_IEEE80211N=y
-
# Wireless Network Management (IEEE Std 802.11v-2011)
# Note: This is experimental and not complete implementation.
#CONFIG_WNM=y
@@ -376,6 +374,29 @@
# Experimental implementation of draft-harkins-owe-07.txt
#CONFIG_OWE=y
+# WLAN Authentication and Privacy Infrastructure (WAPI): interface only.
+# Configure the building of the interface which allows WAPI configuration.
+# Note: does not configure WAPI implementation itself.
+#CONFIG_WAPI_INTERFACE=y
+
+# Airtime policy support
+#CONFIG_AIRTIME_POLICY=y
+
# Override default value for the wpa_disable_eapol_key_retries configuration
# parameter. See that parameter in hostapd.conf for more details.
#CFLAGS += -DDEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES=1
+
+# Wired equivalent privacy (WEP)
+# WEP is an obsolete cryptographic data confidentiality algorithm that is not
+# considered secure. It should not be used for anything anymore. The
+# functionality needed to use WEP is available in the current hostapd
+# release under this optional build parameter. This functionality is subject to
+# be completely removed in a future release.
+#CONFIG_WEP=y
+
+# Remove all TKIP functionality
+# TKIP is an old cryptographic data confidentiality algorithm that is not
+# considered secure. It should not be used anymore. For now, the default hostapd
+# build includes this to allow mixed mode WPA+WPA2 networks to be enabled, but
+# that functionality is subject to be removed in the future.
+#CONFIG_NO_TKIP=y
diff --git a/hostapd/eap_register.c b/hostapd/eap_register.c
index 8477c21..3e870c7 100644
--- a/hostapd/eap_register.c
+++ b/hostapd/eap_register.c
@@ -121,6 +121,11 @@
ret = eap_server_fast_register();
#endif /* EAP_SERVER_FAST */
+#ifdef EAP_SERVER_TEAP
+ if (ret == 0)
+ ret = eap_server_teap_register();
+#endif /* EAP_SERVER_TEAP */
+
#ifdef EAP_SERVER_WSC
if (ret == 0)
ret = eap_server_wsc_register();
diff --git a/hostapd/hidl/1.1/hostapd.cpp b/hostapd/hidl/1.1/hostapd.cpp
deleted file mode 100644
index 0298537..0000000
--- a/hostapd/hidl/1.1/hostapd.cpp
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * hidl interface for wpa_hostapd daemon
- * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2018, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-#include <iomanip>
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-
-#include "hostapd.h"
-#include "hidl_return_util.h"
-
-extern "C"
-{
-#include "utils/eloop.h"
-}
-
-// The HIDL implementation for hostapd creates a hostapd.conf dynamically for
-// each interface. This file can then be used to hook onto the normal config
-// file parsing logic in hostapd code. Helps us to avoid duplication of code
-// in the HIDL interface.
-// TOOD(b/71872409): Add unit tests for this.
-namespace {
-constexpr char kConfFileNameFmt[] = "/data/vendor/wifi/hostapd/hostapd_%s.conf";
-
-using android::base::RemoveFileIfExists;
-using android::base::StringPrintf;
-using android::base::WriteStringToFile;
-using android::hardware::wifi::hostapd::V1_1::IHostapd;
-
-std::string WriteHostapdConfig(
- const std::string& interface_name, const std::string& config)
-{
- const std::string file_path =
- StringPrintf(kConfFileNameFmt, interface_name.c_str());
- if (WriteStringToFile(
- config, file_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
- getuid(), getgid())) {
- return file_path;
- }
- // Diagnose failure
- int error = errno;
- wpa_printf(
- MSG_ERROR, "Cannot write hostapd config to %s, error: %s",
- file_path.c_str(), strerror(error));
- struct stat st;
- int result = stat(file_path.c_str(), &st);
- if (result == 0) {
- wpa_printf(
- MSG_ERROR, "hostapd config file uid: %d, gid: %d, mode: %d",
- st.st_uid, st.st_gid, st.st_mode);
- } else {
- wpa_printf(
- MSG_ERROR,
- "Error calling stat() on hostapd config file: %s",
- strerror(errno));
- }
- return "";
-}
-
-std::string CreateHostapdConfig(
- const IHostapd::IfaceParams& iface_params,
- const IHostapd::NetworkParams& nw_params)
-{
- if (nw_params.ssid.size() >
- static_cast<uint32_t>(
- IHostapd::ParamSizeLimits::SSID_MAX_LEN_IN_BYTES)) {
- wpa_printf(
- MSG_ERROR, "Invalid SSID size: %zu", nw_params.ssid.size());
- return "";
- }
- if ((nw_params.encryptionType != IHostapd::EncryptionType::NONE) &&
- (nw_params.pskPassphrase.size() <
- static_cast<uint32_t>(
- IHostapd::ParamSizeLimits::
- WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES) ||
- nw_params.pskPassphrase.size() >
- static_cast<uint32_t>(
- IHostapd::ParamSizeLimits::
- WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES))) {
- wpa_printf(
- MSG_ERROR, "Invalid psk passphrase size: %zu",
- nw_params.pskPassphrase.size());
- return "";
- }
-
- // SSID string
- std::stringstream ss;
- ss << std::hex;
- ss << std::setfill('0');
- for (uint8_t b : nw_params.ssid) {
- ss << std::setw(2) << static_cast<unsigned int>(b);
- }
- const std::string ssid_as_string = ss.str();
-
- // Encryption config string
- std::string encryption_config_as_string;
- switch (nw_params.encryptionType) {
- case IHostapd::EncryptionType::NONE:
- // no security params
- break;
- case IHostapd::EncryptionType::WPA:
- encryption_config_as_string = StringPrintf(
- "wpa=3\n"
- "wpa_pairwise=TKIP CCMP\n"
- "wpa_passphrase=%s",
- nw_params.pskPassphrase.c_str());
- break;
- case IHostapd::EncryptionType::WPA2:
- encryption_config_as_string = StringPrintf(
- "wpa=2\n"
- "rsn_pairwise=CCMP\n"
- "wpa_passphrase=%s",
- nw_params.pskPassphrase.c_str());
- break;
- default:
- wpa_printf(MSG_ERROR, "Unknown encryption type");
- return "";
- }
-
- std::string channel_config_as_string;
- 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\n"
- "chanlist=%s",
- iface_params.V1_0.channelParams.acsShouldExcludeDfs,
- chanlist_as_string.c_str());
- } else {
- channel_config_as_string = StringPrintf(
- "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.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.V1_0.channelParams.enableAcs) {
- ht_cap_vht_oper_chwidth_as_string =
- "ht_capab=[HT40+]\n"
- "vht_oper_chwidth=1";
- }
- break;
- case IHostapd::Band::BAND_ANY:
- hw_mode_as_string = "hw_mode=any";
- if (iface_params.V1_0.channelParams.enableAcs) {
- ht_cap_vht_oper_chwidth_as_string =
- "ht_capab=[HT40+]\n"
- "vht_oper_chwidth=1";
- }
- break;
- default:
- wpa_printf(MSG_ERROR, "Invalid band");
- return "";
- }
-
- return StringPrintf(
- "interface=%s\n"
- "driver=nl80211\n"
- "ctrl_interface=/data/vendor/wifi/hostapd/ctrl\n"
- // ssid2 signals to hostapd that the value is not a literal value
- // for use as a SSID. In this case, we're giving it a hex
- // std::string and hostapd needs to expect that.
- "ssid2=%s\n"
- "%s\n"
- "ieee80211n=%d\n"
- "ieee80211ac=%d\n"
- "%s\n"
- "%s\n"
- "ignore_broadcast_ssid=%d\n"
- "wowlan_triggers=any\n"
- "%s\n",
- iface_params.V1_0.ifaceName.c_str(), ssid_as_string.c_str(),
- channel_config_as_string.c_str(),
- 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_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_1_1, _hidl_cb, iface_params,
- nw_params);
-}
-
-Return<void> Hostapd::removeAccessPoint(
- const hidl_string& iface_name, removeAccessPoint_cb _hidl_cb)
-{
- return call(
- this, &Hostapd::removeAccessPointInternal, _hidl_cb, iface_name);
-}
-
-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.V1_0.ifaceName.c_str())) {
- wpa_printf(
- MSG_ERROR, "Interface %s already present",
- iface_params.V1_0.ifaceName.c_str());
- return {HostapdStatusCode::FAILURE_IFACE_EXISTS, ""};
- }
- const auto conf_params = CreateHostapdConfig(iface_params, nw_params);
- if (conf_params.empty()) {
- wpa_printf(MSG_ERROR, "Failed to create config params");
- return {HostapdStatusCode::FAILURE_ARGS_INVALID, ""};
- }
- const auto conf_file_path =
- 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.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);
- if (hostapd_add_iface(interfaces_, add_iface_param_vec.data()) < 0) {
- wpa_printf(
- MSG_ERROR, "Adding interface %s failed",
- add_iface_param_str.c_str());
- return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
- }
- struct hostapd_data* iface_hapd =
- 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.V1_0.ifaceName.c_str());
- return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {HostapdStatusCode::SUCCESS, ""};
-}
-
-HostapdStatus Hostapd::removeAccessPointInternal(const std::string& iface_name)
-{
- std::vector<char> remove_iface_param_vec(
- iface_name.begin(), iface_name.end() + 1);
- if (hostapd_remove_iface(interfaces_, remove_iface_param_vec.data()) <
- 0) {
- wpa_printf(
- MSG_ERROR, "Removing interface %s failed",
- iface_name.c_str());
- return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
- }
- return {HostapdStatusCode::SUCCESS, ""};
-}
-
-HostapdStatus Hostapd::registerCallbackInternal(
- const sp<IHostapdCallback>& callback)
-{
- callbacks_.push_back(callback);
- return {HostapdStatusCode::SUCCESS, ""};
-}
-
-} // namespace implementation
-} // namespace V1_1
-} // namespace hostapd
-} // namespace wifi
-} // namespace hardware
-} // namespace android
diff --git a/hostapd/hidl/1.1/hostapd.h b/hostapd/hidl/1.1/hostapd.h
deleted file mode 100644
index e2b4ba8..0000000
--- a/hostapd/hidl/1.1/hostapd.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * hidl interface for wpa_hostapd daemon
- * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2018, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef HOSTAPD_HIDL_SUPPLICANT_H
-#define HOSTAPD_HIDL_SUPPLICANT_H
-
-#include <string>
-
-#include <android-base/macros.h>
-
-#include <android/hardware/wifi/hostapd/1.1/IHostapd.h>
-#include <android/hardware/wifi/hostapd/1.1/IHostapdCallback.h>
-
-extern "C"
-{
-#include "utils/common.h"
-#include "utils/includes.h"
-#include "utils/wpa_debug.h"
-#include "ap/hostapd.h"
-}
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace hostapd {
-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_1::IHostapd
-{
-public:
- Hostapd(hapd_interfaces* interfaces);
- ~Hostapd() override = default;
-
- // 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 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_1
-} // namespace hostapd
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-
-#endif // HOSTAPD_HIDL_SUPPLICANT_H
diff --git a/hostapd/hidl/1.1/hidl.cpp b/hostapd/hidl/1.2/hidl.cpp
similarity index 93%
rename from hostapd/hidl/1.1/hidl.cpp
rename to hostapd/hidl/1.2/hidl.cpp
index 2051e7b..4bde312 100644
--- a/hostapd/hidl/1.1/hidl.cpp
+++ b/hostapd/hidl/1.2/hidl.cpp
@@ -22,8 +22,8 @@
using android::hardware::configureRpcThreadpool;
using android::hardware::IPCThreadState;
-using android::hardware::wifi::hostapd::V1_1::IHostapd;
-using android::hardware::wifi::hostapd::V1_1::implementation::Hostapd;
+using android::hardware::wifi::hostapd::V1_2::IHostapd;
+using android::hardware::wifi::hostapd::V1_2::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.1/hidl.h b/hostapd/hidl/1.2/hidl.h
similarity index 100%
rename from hostapd/hidl/1.1/hidl.h
rename to hostapd/hidl/1.2/hidl.h
diff --git a/hostapd/hidl/1.1/hidl_return_util.h b/hostapd/hidl/1.2/hidl_return_util.h
similarity index 83%
rename from hostapd/hidl/1.1/hidl_return_util.h
rename to hostapd/hidl/1.2/hidl_return_util.h
index d914ee2..81742f8 100644
--- a/hostapd/hidl/1.1/hidl_return_util.h
+++ b/hostapd/hidl/1.2/hidl_return_util.h
@@ -16,7 +16,7 @@
namespace hardware {
namespace wifi {
namespace hostapd {
-namespace V1_1 {
+namespace V1_2 {
namespace implementation {
namespace hidl_return_util {
@@ -25,18 +25,17 @@
* HIDL interface object.
*/
// Use for HIDL methods which return only an instance of HostapdStatus.
-template <typename ObjT, typename WorkFuncT, typename... Args>
+template <typename ObjT, typename WorkFuncT, typename StatusT, typename... Args>
Return<void> call(
ObjT* obj, WorkFuncT&& work,
- const std::function<void(const HostapdStatus&)>& hidl_cb, Args&&... args)
+ const std::function<void(const StatusT&)>& hidl_cb, Args&&... args)
{
hidl_cb((obj->*work)(std::forward<Args>(args)...));
return Void();
}
-
} // namespace hidl_return_util
} // namespace implementation
-} // namespace V1_1
+} // namespace V1_2
} // namespace hostapd
} // namespace wifi
} // namespace hardware
diff --git a/hostapd/hidl/1.2/hostapd.cpp b/hostapd/hidl/1.2/hostapd.cpp
new file mode 100644
index 0000000..537353a
--- /dev/null
+++ b/hostapd/hidl/1.2/hostapd.cpp
@@ -0,0 +1,645 @@
+/*
+ * hidl interface for wpa_hostapd daemon
+ * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2018, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+#include <iomanip>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+
+#include "hostapd.h"
+#include "hidl_return_util.h"
+
+extern "C"
+{
+#include "utils/eloop.h"
+}
+
+// The HIDL implementation for hostapd creates a hostapd.conf dynamically for
+// each interface. This file can then be used to hook onto the normal config
+// file parsing logic in hostapd code. Helps us to avoid duplication of code
+// in the HIDL interface.
+// TOOD(b/71872409): Add unit tests for this.
+namespace {
+constexpr char kConfFileNameFmt[] = "/data/vendor/wifi/hostapd/hostapd_%s.conf";
+
+using android::base::RemoveFileIfExists;
+using android::base::StringPrintf;
+using android::base::WriteStringToFile;
+using android::hardware::wifi::hostapd::V1_2::IHostapd;
+
+std::string WriteHostapdConfig(
+ const std::string& interface_name, const std::string& config)
+{
+ const std::string file_path =
+ StringPrintf(kConfFileNameFmt, interface_name.c_str());
+ if (WriteStringToFile(
+ config, file_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
+ getuid(), getgid())) {
+ return file_path;
+ }
+ // Diagnose failure
+ int error = errno;
+ wpa_printf(
+ MSG_ERROR, "Cannot write hostapd config to %s, error: %s",
+ file_path.c_str(), strerror(error));
+ struct stat st;
+ int result = stat(file_path.c_str(), &st);
+ if (result == 0) {
+ wpa_printf(
+ MSG_ERROR, "hostapd config file uid: %d, gid: %d, mode: %d",
+ st.st_uid, st.st_gid, st.st_mode);
+ } else {
+ wpa_printf(
+ MSG_ERROR,
+ "Error calling stat() on hostapd config file: %s",
+ strerror(errno));
+ }
+ return "";
+}
+
+/*
+ * Get the op_class for a channel/band
+ * The logic here is based on Table E-4 in the 802.11 Specification
+ */
+int getOpClassForChannel(int channel, int band, bool support11n, bool support11ac) {
+ // 2GHz Band
+ if ((band & IHostapd::BandMask::BAND_2_GHZ) != 0) {
+ if (channel == 14) {
+ return 82;
+ }
+ if (channel >= 1 && channel <= 13) {
+ if (!support11n) {
+ //20MHz channel
+ return 81;
+ }
+ if (channel <= 9) {
+ // HT40 with secondary channel above primary
+ return 83;
+ }
+ // HT40 with secondary channel below primary
+ return 84;
+ }
+ // Error
+ return 0;
+ }
+
+ // 5GHz Band
+ if ((band & IHostapd::BandMask::BAND_5_GHZ) != 0) {
+ if (support11ac) {
+ switch (channel) {
+ case 42:
+ case 58:
+ case 106:
+ case 122:
+ case 138:
+ case 155:
+ // 80MHz channel
+ return 128;
+ case 50:
+ case 114:
+ // 160MHz channel
+ return 129;
+ }
+ }
+
+ if (!support11n) {
+ if (channel >= 36 && channel <= 48) {
+ return 115;
+ }
+ if (channel >= 52 && channel <= 64) {
+ return 118;
+ }
+ if (channel >= 100 && channel <= 144) {
+ return 121;
+ }
+ if (channel >= 149 && channel <= 161) {
+ return 124;
+ }
+ if (channel >= 165 && channel <= 169) {
+ return 125;
+ }
+ } else {
+ switch (channel) {
+ case 36:
+ case 44:
+ // HT40 with secondary channel above primary
+ return 116;
+ case 40:
+ case 48:
+ // HT40 with secondary channel below primary
+ return 117;
+ case 52:
+ case 60:
+ // HT40 with secondary channel above primary
+ return 119;
+ case 56:
+ case 64:
+ // HT40 with secondary channel below primary
+ return 120;
+ case 100:
+ case 108:
+ case 116:
+ case 124:
+ case 132:
+ case 140:
+ // HT40 with secondary channel above primary
+ return 122;
+ case 104:
+ case 112:
+ case 120:
+ case 128:
+ case 136:
+ case 144:
+ // HT40 with secondary channel below primary
+ return 123;
+ case 149:
+ case 157:
+ // HT40 with secondary channel above primary
+ return 126;
+ case 153:
+ case 161:
+ // HT40 with secondary channel below primary
+ return 127;
+ }
+ }
+ // Error
+ return 0;
+ }
+
+ // 6GHz Band
+ if ((band & IHostapd::BandMask::BAND_6_GHZ) != 0) {
+ // Channels 1, 5. 9, 13, ...
+ if ((channel & 0x03) == 0x01) {
+ // 20MHz channel
+ return 131;
+ }
+ // Channels 3, 11, 19, 27, ...
+ if ((channel & 0x07) == 0x03) {
+ // 40MHz channel
+ return 132;
+ }
+ // Channels 7, 23, 39, 55, ...
+ if ((channel & 0x0F) == 0x07) {
+ // 80MHz channel
+ return 133;
+ }
+ // Channels 15, 47, 69, ...
+ if ((channel & 0x1F) == 0x0F) {
+ // 160MHz channel
+ return 134;
+ }
+ // Error
+ return 0;
+ }
+
+ return 0;
+}
+
+bool validatePassphrase(int passphrase_len, int min_len, int max_len)
+{
+ if (min_len != -1 && passphrase_len < min_len) return false;
+ if (max_len != -1 && passphrase_len > max_len) return false;
+ return true;
+}
+
+std::string CreateHostapdConfig(
+ const IHostapd::IfaceParams& iface_params,
+ const IHostapd::NetworkParams& nw_params)
+{
+ if (nw_params.V1_0.ssid.size() >
+ static_cast<uint32_t>(
+ IHostapd::ParamSizeLimits::SSID_MAX_LEN_IN_BYTES)) {
+ wpa_printf(
+ MSG_ERROR, "Invalid SSID size: %zu", nw_params.V1_0.ssid.size());
+ return "";
+ }
+
+ // SSID string
+ std::stringstream ss;
+ ss << std::hex;
+ ss << std::setfill('0');
+ for (uint8_t b : nw_params.V1_0.ssid) {
+ ss << std::setw(2) << static_cast<unsigned int>(b);
+ }
+ const std::string ssid_as_string = ss.str();
+
+ // Encryption config string
+ std::string encryption_config_as_string;
+ switch (nw_params.encryptionType) {
+ case IHostapd::EncryptionType::NONE:
+ // no security params
+ break;
+ case IHostapd::EncryptionType::WPA:
+ if (!validatePassphrase(
+ nw_params.passphrase.size(),
+ static_cast<uint32_t>(IHostapd::ParamSizeLimits::
+ WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES),
+ static_cast<uint32_t>(IHostapd::ParamSizeLimits::
+ WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES))) {
+ return "";
+ }
+ encryption_config_as_string = StringPrintf(
+ "wpa=3\n"
+ "wpa_pairwise=TKIP CCMP\n"
+ "wpa_passphrase=%s",
+ nw_params.passphrase.c_str());
+ break;
+ case IHostapd::EncryptionType::WPA2:
+ if (!validatePassphrase(
+ nw_params.passphrase.size(),
+ static_cast<uint32_t>(IHostapd::ParamSizeLimits::
+ WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES),
+ static_cast<uint32_t>(IHostapd::ParamSizeLimits::
+ WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES))) {
+ return "";
+ }
+ encryption_config_as_string = StringPrintf(
+ "wpa=2\n"
+ "rsn_pairwise=CCMP\n"
+ "wpa_passphrase=%s",
+ nw_params.passphrase.c_str());
+ break;
+ case IHostapd::EncryptionType::WPA3_SAE_TRANSITION:
+ if (!validatePassphrase(
+ nw_params.passphrase.size(),
+ static_cast<uint32_t>(IHostapd::ParamSizeLimits::
+ WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES),
+ static_cast<uint32_t>(IHostapd::ParamSizeLimits::
+ WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES))) {
+ return "";
+ }
+ encryption_config_as_string = StringPrintf(
+ "wpa=2\n"
+ "rsn_pairwise=CCMP\n"
+ "wpa_key_mgmt=WPA-PSK SAE\n"
+ "ieee80211w=1\n"
+ "sae_require_mfp=1\n"
+ "wpa_passphrase=%s\n"
+ "sae_password=%s",
+ nw_params.passphrase.c_str(),
+ nw_params.passphrase.c_str());
+ break;
+ case IHostapd::EncryptionType::WPA3_SAE:
+ if (!validatePassphrase(nw_params.passphrase.size(), 1, -1)) {
+ return "";
+ }
+ encryption_config_as_string = StringPrintf(
+ "wpa=2\n"
+ "rsn_pairwise=CCMP\n"
+ "wpa_key_mgmt=SAE\n"
+ "ieee80211w=2\n"
+ "sae_require_mfp=2\n"
+ "sae_password=%s",
+ nw_params.passphrase.c_str());
+ break;
+ default:
+ wpa_printf(MSG_ERROR, "Unknown encryption type");
+ return "";
+ }
+
+ unsigned int band = 0;
+ band |= iface_params.channelParams.bandMask;
+
+ std::string channel_config_as_string;
+ bool isFirst = true;
+ if (iface_params.V1_1.V1_0.channelParams.enableAcs) {
+ std::string freqList_as_string;
+ for (const auto &range :
+ iface_params.channelParams.acsChannelFreqRangesMhz) {
+ if (!isFirst) {
+ freqList_as_string += ",";
+ }
+ isFirst = false;
+
+ if (range.start != range.end) {
+ freqList_as_string +=
+ StringPrintf("%d-%d", range.start, range.end);
+ } else {
+ freqList_as_string += StringPrintf("%d", range.start);
+ }
+ }
+ channel_config_as_string = StringPrintf(
+ "channel=0\n"
+ "acs_exclude_dfs=%d\n"
+ "freqlist=%s",
+ iface_params.V1_1.V1_0.channelParams.acsShouldExcludeDfs,
+ freqList_as_string.c_str());
+ } else {
+ int op_class = getOpClassForChannel(
+ iface_params.V1_1.V1_0.channelParams.channel,
+ band,
+ iface_params.V1_1.V1_0.hwModeParams.enable80211N,
+ iface_params.V1_1.V1_0.hwModeParams.enable80211AC);
+ channel_config_as_string = StringPrintf(
+ "channel=%d\n"
+ "op_class=%d",
+ iface_params.V1_1.V1_0.channelParams.channel, op_class);
+ }
+
+ std::string hw_mode_as_string;
+ std::string ht_cap_vht_oper_chwidth_as_string;
+
+ if ((band & IHostapd::BandMask::BAND_2_GHZ) != 0) {
+ if (((band & IHostapd::BandMask::BAND_5_GHZ) != 0)
+ || ((band & IHostapd::BandMask::BAND_6_GHZ) != 0)) {
+ hw_mode_as_string = "hw_mode=any";
+ if (iface_params.V1_1.V1_0.channelParams.enableAcs) {
+ ht_cap_vht_oper_chwidth_as_string =
+ "ht_capab=[HT40+]\n"
+ "vht_oper_chwidth=1";
+ }
+ } else {
+ hw_mode_as_string = "hw_mode=g";
+ }
+ } else {
+ if (((band & IHostapd::BandMask::BAND_5_GHZ) != 0)
+ || ((band & IHostapd::BandMask::BAND_6_GHZ) != 0)) {
+ hw_mode_as_string = "hw_mode=a";
+ if (iface_params.V1_1.V1_0.channelParams.enableAcs) {
+ ht_cap_vht_oper_chwidth_as_string =
+ "ht_capab=[HT40+]\n"
+ "vht_oper_chwidth=1";
+ }
+ } else {
+ wpa_printf(MSG_ERROR, "Invalid band");
+ return "";
+ }
+ }
+
+ std::string he_params_as_string;
+#ifdef CONFIG_IEEE80211AX
+ if (iface_params.hwModeParams.enable80211AX) {
+ he_params_as_string = StringPrintf(
+ "ieee80211ax=1\n"
+ "he_su_beamformer=%d\n"
+ "he_su_beamformee=%d\n"
+ "he_mu_beamformer=%d\n"
+ "he_twt_required=%d\n",
+ iface_params.hwModeParams.enableHeSingleUserBeamformer ? 1 : 0,
+ iface_params.hwModeParams.enableHeSingleUserBeamformee ? 1 : 0,
+ iface_params.hwModeParams.enableHeMultiUserBeamformer ? 1 : 0,
+ iface_params.hwModeParams.enableHeTargetWakeTime ? 1 : 0);
+ } else {
+ he_params_as_string = "ieee80211ax=0";
+ }
+#endif /* CONFIG_IEEE80211AX */
+
+ return StringPrintf(
+ "interface=%s\n"
+ "driver=nl80211\n"
+ "ctrl_interface=/data/vendor/wifi/hostapd/ctrl\n"
+ // ssid2 signals to hostapd that the value is not a literal value
+ // for use as a SSID. In this case, we're giving it a hex
+ // std::string and hostapd needs to expect that.
+ "ssid2=%s\n"
+ "%s\n"
+ "ieee80211n=%d\n"
+ "ieee80211ac=%d\n"
+ "%s\n"
+ "%s\n"
+ "%s\n"
+ "ignore_broadcast_ssid=%d\n"
+ "wowlan_triggers=any\n"
+ "%s\n",
+ iface_params.V1_1.V1_0.ifaceName.c_str(), ssid_as_string.c_str(),
+ channel_config_as_string.c_str(),
+ iface_params.V1_1.V1_0.hwModeParams.enable80211N ? 1 : 0,
+ iface_params.V1_1.V1_0.hwModeParams.enable80211AC ? 1 : 0,
+ he_params_as_string.c_str(),
+ hw_mode_as_string.c_str(), ht_cap_vht_oper_chwidth_as_string.c_str(),
+ nw_params.V1_0.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_2 {
+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 V1_0::IHostapd::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 V1_1::IHostapd::IfaceParams& iface_params,
+ const V1_0::IHostapd::NetworkParams& nw_params, addAccessPoint_cb _hidl_cb)
+{
+ return call(
+ this, &Hostapd::addAccessPointInternal_1_1, _hidl_cb, iface_params,
+ nw_params);
+}
+
+Return<void> Hostapd::addAccessPoint_1_2(
+ const IfaceParams& iface_params, const NetworkParams& nw_params,
+ addAccessPoint_1_2_cb _hidl_cb)
+{
+ return call(
+ this, &Hostapd::addAccessPointInternal_1_2, _hidl_cb, iface_params,
+ nw_params);
+}
+
+Return<void> Hostapd::removeAccessPoint(
+ const hidl_string& iface_name, removeAccessPoint_cb _hidl_cb)
+{
+ return call(
+ this, &Hostapd::removeAccessPointInternal, _hidl_cb, iface_name);
+}
+
+Return<void> Hostapd::terminate()
+{
+ wpa_printf(MSG_INFO, "Terminating...");
+ eloop_terminate();
+ return Void();
+}
+
+Return<void> Hostapd::registerCallback(
+ const sp<V1_1::IHostapdCallback>& callback, registerCallback_cb _hidl_cb)
+{
+ return call(
+ this, &Hostapd::registerCallbackInternal, _hidl_cb, callback);
+}
+
+Return<void> Hostapd::forceClientDisconnect(
+ const hidl_string& iface_name, const hidl_array<uint8_t, 6>& client_address,
+ V1_2::Ieee80211ReasonCode reason_code, forceClientDisconnect_cb _hidl_cb)
+{
+ return call(
+ this, &Hostapd::forceClientDisconnectInternal, _hidl_cb, iface_name,
+ client_address, reason_code);
+}
+
+Return<void> Hostapd::setDebugParams(
+ DebugLevel level, setDebugParams_cb _hidl_cb)
+{
+ return call(
+ this, &Hostapd::setDebugParamsInternal, _hidl_cb, level);
+}
+
+V1_0::HostapdStatus Hostapd::addAccessPointInternal(
+ const V1_0::IHostapd::IfaceParams& iface_params,
+ const V1_0::IHostapd::NetworkParams& nw_params)
+{
+ return {V1_0::HostapdStatusCode::FAILURE_UNKNOWN, ""};
+}
+
+V1_0::HostapdStatus Hostapd::addAccessPointInternal_1_1(
+ const V1_1::IHostapd::IfaceParams& iface_params,
+ const V1_1::IHostapd::NetworkParams& nw_params)
+{
+ return {V1_0::HostapdStatusCode::FAILURE_UNKNOWN, ""};
+}
+
+HostapdStatus Hostapd::addAccessPointInternal_1_2(
+ const IfaceParams& iface_params, const NetworkParams& nw_params)
+{
+ if (hostapd_get_iface(interfaces_, iface_params.V1_1.V1_0.ifaceName.c_str())) {
+ wpa_printf(
+ MSG_ERROR, "Interface %s already present",
+ iface_params.V1_1.V1_0.ifaceName.c_str());
+ return {HostapdStatusCode::FAILURE_IFACE_EXISTS, ""};
+ }
+ const auto conf_params = CreateHostapdConfig(iface_params, nw_params);
+ if (conf_params.empty()) {
+ wpa_printf(MSG_ERROR, "Failed to create config params");
+ return {HostapdStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ const auto conf_file_path =
+ WriteHostapdConfig(iface_params.V1_1.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.V1_1.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);
+ if (hostapd_add_iface(interfaces_, add_iface_param_vec.data()) < 0) {
+ wpa_printf(
+ MSG_ERROR, "Adding interface %s failed",
+ add_iface_param_str.c_str());
+ return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ struct hostapd_data* iface_hapd =
+ hostapd_get_iface(interfaces_, iface_params.V1_1.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.V1_1.V1_0.ifaceName.c_str());
+ return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {HostapdStatusCode::SUCCESS, ""};
+}
+
+V1_0::HostapdStatus Hostapd::removeAccessPointInternal(const std::string& iface_name)
+{
+ std::vector<char> remove_iface_param_vec(
+ iface_name.begin(), iface_name.end() + 1);
+ if (hostapd_remove_iface(interfaces_, remove_iface_param_vec.data()) <
+ 0) {
+ wpa_printf(
+ MSG_ERROR, "Removing interface %s failed",
+ iface_name.c_str());
+ return {V1_0::HostapdStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {V1_0::HostapdStatusCode::SUCCESS, ""};
+}
+
+V1_0::HostapdStatus Hostapd::registerCallbackInternal(
+ const sp<V1_1::IHostapdCallback>& callback)
+{
+ callbacks_.push_back(callback);
+ return {V1_0::HostapdStatusCode::SUCCESS, ""};
+}
+
+V1_2::HostapdStatus Hostapd::forceClientDisconnectInternal(const std::string& iface_name,
+ const std::array<uint8_t, 6>& client_address, V1_2::Ieee80211ReasonCode reason_code)
+{
+ struct hostapd_data *hapd = hostapd_get_iface(interfaces_, iface_name.c_str());
+ struct sta_info *sta;
+ if (!hapd) {
+ wpa_printf(MSG_ERROR, "Interface %s doesn't exist", iface_name.c_str());
+ return {V1_2::HostapdStatusCode::FAILURE_IFACE_UNKNOWN, ""};
+ }
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ int res;
+ res = memcmp(sta->addr, client_address.data(), ETH_ALEN);
+ if (res == 0) {
+ wpa_printf(MSG_INFO, "Force client:" MACSTR " disconnect with reason: %d",
+ MAC2STR(client_address.data()), (uint16_t) reason_code);
+ ap_sta_disconnect(hapd, sta, sta->addr, (uint16_t) reason_code);
+ return {V1_2::HostapdStatusCode::SUCCESS, ""};
+ }
+ }
+ return {V1_2::HostapdStatusCode::FAILURE_CLIENT_UNKNOWN, ""};
+}
+
+V1_2::HostapdStatus Hostapd::setDebugParamsInternal(DebugLevel level)
+{
+ wpa_debug_level = static_cast<uint32_t>(level);
+ return {V1_2::HostapdStatusCode::SUCCESS, ""};
+}
+
+} // namespace implementation
+} // namespace V1_2
+} // namespace hostapd
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/hostapd/hidl/1.2/hostapd.h b/hostapd/hidl/1.2/hostapd.h
new file mode 100644
index 0000000..ca6c32e
--- /dev/null
+++ b/hostapd/hidl/1.2/hostapd.h
@@ -0,0 +1,103 @@
+/*
+ * hidl interface for wpa_hostapd daemon
+ * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2018, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HOSTAPD_HIDL_SUPPLICANT_H
+#define HOSTAPD_HIDL_SUPPLICANT_H
+
+#include <string>
+
+#include <android-base/macros.h>
+
+#include <android/hardware/wifi/hostapd/1.2/IHostapd.h>
+#include <android/hardware/wifi/hostapd/1.1/IHostapdCallback.h>
+
+extern "C"
+{
+#include "utils/common.h"
+#include "utils/includes.h"
+#include "utils/wpa_debug.h"
+#include "ap/hostapd.h"
+#include "ap/sta_info.h"
+}
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace hostapd {
+namespace V1_2 {
+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_2::IHostapd
+{
+public:
+ Hostapd(hapd_interfaces* interfaces);
+ ~Hostapd() override = default;
+
+ // Hidl methods exposed.
+ Return<void> addAccessPoint(
+ const V1_0::IHostapd::IfaceParams& iface_params,
+ const V1_0::IHostapd::NetworkParams& nw_params, addAccessPoint_cb _hidl_cb) override;
+ Return<void> addAccessPoint_1_1(
+ const V1_1::IHostapd::IfaceParams& iface_params,
+ const V1_0::IHostapd::NetworkParams& nw_params, addAccessPoint_cb _hidl_cb) override;
+ Return<void> addAccessPoint_1_2(
+ const V1_2::IHostapd::IfaceParams& iface_params, const NetworkParams& nw_params,
+ addAccessPoint_1_2_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<V1_1::IHostapdCallback>& callback,
+ registerCallback_cb _hidl_cb) override;
+ Return<void>forceClientDisconnect(
+ const hidl_string& iface_name,
+ const hidl_array<uint8_t, 6>& client_address,
+ V1_2::Ieee80211ReasonCode reason_code, forceClientDisconnect_cb _hidl_cb) override;
+ Return<void> setDebugParams(
+ DebugLevel level, setDebugParams_cb _hidl_cb) override;
+private:
+ // Corresponding worker functions for the HIDL methods.
+ V1_0::HostapdStatus addAccessPointInternal(
+ const V1_0::IHostapd::IfaceParams& iface_params,
+ const V1_0::IHostapd::NetworkParams& nw_params);
+ V1_0::HostapdStatus addAccessPointInternal_1_1(
+ const V1_1::IHostapd::IfaceParams& IfaceParams,
+ const V1_0::IHostapd::NetworkParams& nw_params);
+ V1_2::HostapdStatus addAccessPointInternal_1_2(
+ const V1_2::IHostapd::IfaceParams& IfaceParams,
+ const V1_2::IHostapd::NetworkParams& nw_params);
+ V1_0::HostapdStatus removeAccessPointInternal(const std::string& iface_name);
+ V1_0::HostapdStatus registerCallbackInternal(
+ const sp<V1_1::IHostapdCallback>& callback);
+ V1_2::HostapdStatus forceClientDisconnectInternal(
+ const std::string& iface_name,
+ const std::array<uint8_t, 6>& client_address,
+ V1_2::Ieee80211ReasonCode reason_code);
+ V1_2::HostapdStatus setDebugParamsInternal(DebugLevel level);
+ // Raw pointer to the global structure maintained by the core.
+ struct hapd_interfaces* interfaces_;
+ // Callbacks registered.
+ std::vector<sp<V1_1::IHostapdCallback>> callbacks_;
+ DISALLOW_COPY_AND_ASSIGN(Hostapd);
+};
+} // namespace implementation
+} // namespace V1_2
+} // namespace hostapd
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+
+#endif // HOSTAPD_HIDL_SUPPLICANT_H
diff --git a/hostapd/hostapd.android.rc b/hostapd/hostapd.android.rc
index c8792d6..512ca0d 100644
--- a/hostapd/hostapd.android.rc
+++ b/hostapd/hostapd.android.rc
@@ -14,6 +14,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
+ interface android.hardware.wifi.hostapd@1.2::IHostapd default
class main
capabilities NET_ADMIN NET_RAW
user wifi
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index f8caa56..812c09a 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -41,7 +41,6 @@
# bit 2 (4) = RADIUS
# bit 3 (8) = WPA
# bit 4 (16) = driver interface
-# bit 5 (32) = IAPP
# bit 6 (64) = MLME
#
# Levels (minimum value for logged events):
@@ -73,7 +72,7 @@
# run as non-root users. However, since the control interface can be used to
# change the network configuration, this access needs to be protected in many
# cases. By default, hostapd is configured to use gid 0 (root). If you
-# want to allow non-root users to use the contron interface, add a new group
+# want to allow non-root users to use the control interface, add a new group
# and change this value to match with that group. Add users that should have
# control interface access to this group.
#
@@ -147,7 +146,8 @@
# Operation mode (a = IEEE 802.11a (5 GHz), b = IEEE 802.11b (2.4 GHz),
# g = IEEE 802.11g (2.4 GHz), ad = IEEE 802.11ad (60 GHz); a/g options are used
# with IEEE 802.11n (HT), too, to specify band). For IEEE 802.11ac (VHT), this
-# needs to be set to hw_mode=a. When using ACS (see channel parameter), a
+# needs to be set to hw_mode=a. For IEEE 802.11ax (HE) on 6 GHz this needs
+# to be set to hw_mode=a. When using ACS (see channel parameter), a
# special value "any" can be used to indicate that any support band can be used.
# This special case is currently supported only with drivers with which
# offloaded ACS is used.
@@ -164,6 +164,12 @@
# which will enable the ACS survey based algorithm.
channel=1
+# Global operating class (IEEE 802.11, Annex E, Table E-4)
+# This option allows hostapd to specify the operating class of the channel
+# configured with the channel parameter. channel and op_class together can
+# uniquely identify channels across different bands, including the 6 GHz band.
+#op_class=131
+
# ACS tuning - Automatic Channel Selection
# See: http://wireless.kernel.org/en/users/Documentation/acs
#
@@ -199,11 +205,26 @@
#chanlist=100 104 108 112 116
#chanlist=1 6 11-13
+# Frequency list restriction. This option allows hostapd to select one of the
+# provided frequencies when a frequency should be automatically selected.
+# Frequency list can be provided as range using hyphen ('-') or individual
+# frequencies can be specified by comma (',') separated values
+# Default: all frequencies allowed in selected hw_mode
+#freqlist=2437,5945,5965
+#freqlist=2437,5985-6105
+
# Exclude DFS channels from ACS
# This option can be used to exclude all DFS channels from the ACS channel list
# in cases where the driver supports DFS channels.
#acs_exclude_dfs=1
+# Include only preferred scan channels from 6 GHz band for ACS
+# This option can be used to include only preferred scan channels in the 6 GHz
+# band. This can be useful in particular for devices that operate only a 6 GHz
+# BSS without a collocated 2.4/5 GHz BSS.
+# Default behavior is to include all PSC and non-PSC channels.
+#acs_exclude_6ghz_non_psc=1
+
# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
beacon_int=100
@@ -577,8 +598,6 @@
# channels if needed or creation of 40 MHz channel maybe rejected based
# on overlapping BSSes. These changes are done automatically when hostapd
# is setting up the 40 MHz channel.
-# Spatial Multiplexing (SM) Power Save: [SMPS-STATIC] or [SMPS-DYNAMIC]
-# (SMPS disabled if neither is set)
# HT-greenfield: [GF] (disabled if not set)
# Short GI for 20 MHz: [SHORT-GI-20] (disabled if not set)
# Short GI for 40 MHz: [SHORT-GI-40] (disabled if not set)
@@ -782,10 +801,11 @@
# 1 = supported
#he_mu_beamformer=1
-# he_bss_color: BSS color
-# 0 = no BSS color (default)
-# unsigned integer = BSS color
-#he_bss_color=0
+# he_bss_color: BSS color (1-63)
+#he_bss_color=1
+
+# he_bss_color_partial: BSS color AID equation
+#he_bss_color_partial=0
#he_default_pe_duration: The duration of PE field in an HE PPDU in us
# Possible values are 0 us (default), 4 us, 8 us, 12 us, and 16 us
@@ -801,6 +821,22 @@
# unsigned integer = duration in units of 16 us
#he_rts_threshold=0
+# HE operating channel information; see matching vht_* parameters for details.
+# On the 6 GHz band the center freq calculation starts from 5.940 GHz offset.
+# For example idx=3 would result in 5955 MHz center frequency. In addition,
+# he_oper_chwidth is ignored, and the channel width is derived from the
+# configured operating class or center frequency indexes (see
+# IEEE P802.11ax/D4.3 Annex E, Table E-4).
+#he_oper_chwidth
+#he_oper_centr_freq_seg0_idx
+#he_oper_centr_freq_seg1_idx
+
+#he_basic_mcs_nss_set: Basic NSS/MCS set
+# 16-bit combination of 2-bit values of Max HE-MCS For 1..8 SS; each 2-bit
+# value having following meaning:
+# 0 = HE-MCS 0-7, 1 = HE-MCS 0-9, 2 = HE-MCS 0-11, 3 = not supported
+#he_basic_mcs_nss_set
+
#he_mu_edca_qos_info_param_count
#he_mu_edca_qos_info_q_ack
#he_mu_edca_qos_info_queue_request=1
@@ -825,6 +861,12 @@
#he_mu_edca_ac_vo_ecwmax=15
#he_mu_edca_ac_vo_timer=255
+# Spatial Reuse Parameter Set
+#he_spr_sr_control
+#he_spr_non_srg_obss_pd_max_offset
+#he_spr_srg_obss_pd_min_offset
+#he_spr_srg_obss_pd_max_offset
+
##### IEEE 802.1X-2004 related configuration ##################################
# Require IEEE 802.1X authorization
@@ -836,6 +878,8 @@
# the new version number correctly (they seem to drop the frames completely).
# In order to make hostapd interoperate with these clients, the version number
# can be set to the older version (1) with this configuration value.
+# Note: When using MACsec, eapol_version shall be set to 3, which is
+# defined in IEEE Std 802.1X-2010.
#eapol_version=2
# Optional displayable message sent with EAP Request-Identity. The first \0
@@ -860,6 +904,8 @@
# EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable
# reauthentication).
+# Note: Reauthentications may enforce a disconnection, check the related
+# parameter wpa_deny_ptk0_rekey for details.
#eap_reauth_period=3600
# Use PAE group address (01:80:c2:00:00:03) instead of individual target
@@ -879,6 +925,54 @@
# ERP is enabled (eap_server_erp=1).
#erp_domain=example.com
+##### MACsec ##################################################################
+
+# macsec_policy: IEEE 802.1X/MACsec options
+# This determines how sessions are secured with MACsec (only for MACsec
+# drivers).
+# 0: MACsec not in use (default)
+# 1: MACsec enabled - Should secure, accept key server's advice to
+# determine whether to use a secure session or not.
+#
+# macsec_integ_only: IEEE 802.1X/MACsec transmit mode
+# This setting applies only when MACsec is in use, i.e.,
+# - macsec_policy is enabled
+# - the key server has decided to enable MACsec
+# 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)
+#
+# mka_priority (Priority of MKA Actor)
+# Range: 0..255 (default: 255)
+#
+# mka_cak, mka_ckn, and mka_priority: IEEE 802.1X/MACsec pre-shared key mode
+# This allows to configure MACsec with a pre-shared key using a (CAK,CKN) pair.
+# In this mode, instances of hostapd 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-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)
+
##### Integrated EAP server ###################################################
# Optionally, hostapd can be configured to use an integrated EAP server
@@ -912,6 +1006,23 @@
# Passphrase for private key
#private_key_passwd=secret passphrase
+# An alternative server certificate and private key can be configured with the
+# following parameters (with values just like the parameters above without the
+# '2' suffix). The ca_cert file (in PEM encoding) is used to add the trust roots
+# for both server certificates and/or client certificates).
+#
+# The main use case for this alternative server certificate configuration is to
+# enable both RSA and ECC public keys. The server will pick which one to use
+# based on the client preferences for the cipher suite (in the TLS ClientHello
+# message). It should be noted that number of deployed EAP peer implementations
+# do not filter out the cipher suite list based on their local configuration and
+# as such, configuration of alternative types of certificates on the server may
+# result in interoperability issues.
+#server_cert2=/etc/hostapd.server-ecc.pem
+#private_key2=/etc/hostapd.server-ecc.prv
+#private_key_passwd2=secret passphrase
+
+
# Server identity
# EAP methods that provide mechanism for authenticated server identity delivery
# use this value. If not set, "hostapd" is used as a default.
@@ -930,7 +1041,7 @@
#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.
+# errors X509_V_ERR_CRL_HAS_EXPIRED and X509_V_ERR_CRL_NOT_YET_VALID.
#
# 0 = ignore errors
# 1 = do not ignore errors (default)
@@ -999,6 +1110,12 @@
# [ENABLE-TLSv1.3] = enable TLSv1.3 (experimental - disabled by default)
#tls_flags=[flag1][flag2]...
+# Maximum number of EAP message rounds with data (default: 100)
+#max_auth_rounds=100
+
+# Maximum number of short EAP message rounds (default: 50)
+#max_auth_rounds_short=50
+
# 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.
@@ -1109,10 +1226,41 @@
# (or fewer) of the lifetime remains.
#pac_key_refresh_time=86400
+# EAP-TEAP authentication type
+# 0 = inner EAP (default)
+# 1 = Basic-Password-Auth
+#eap_teap_auth=0
+
+# EAP-TEAP authentication behavior when using PAC
+# 0 = perform inner authentication (default)
+# 1 = skip inner authentication (inner EAP/Basic-Password-Auth)
+#eap_teap_pac_no_inner=0
+
+# EAP-TEAP behavior with Result TLV
+# 0 = include with Intermediate-Result TLV (default)
+# 1 = send in a separate message (for testing purposes)
+#eap_teap_separate_result=0
+
+# EAP-TEAP identities
+# 0 = allow any identity type (default)
+# 1 = require user identity
+# 2 = require machine identity
+# 3 = request user identity; accept either user or machine identity
+# 4 = request machine identity; accept either user or machine identity
+# 5 = require both user and machine identity
+#eap_teap_id=0
+
# EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND
# (default: 0 = disabled).
#eap_sim_aka_result_ind=1
+# EAP-SIM and EAP-AKA identity options
+# 0 = do not use pseudonyms or fast reauthentication
+# 1 = use pseudonyms, but not fast reauthentication
+# 2 = do not use pseudonyms, but use fast reauthentication
+# 3 = use pseudonyms and use fast reauthentication (default)
+#eap_sim_id=3
+
# Trusted Network Connect (TNC)
# If enabled, TNC validation will be required before the peer is allowed to
# connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other
@@ -1124,11 +1272,6 @@
# Whether to enable ERP on the EAP server.
#eap_server_erp=1
-##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) #######################
-
-# Interface to be used for IAPP broadcast packets
-#iapp_interface=eth0
-
##### RADIUS client configuration #############################################
# for IEEE 802.1X with external Authentication Server, IEEE 802.11
@@ -1292,6 +1435,17 @@
# Operator-Name = "Operator"
#radius_acct_req_attr=126:s:Operator
+# If SQLite support is included, path to a database from which additional
+# RADIUS request attributes are extracted based on the station MAC address.
+#
+# The schema for the radius_attributes table is:
+# id | sta | reqtype | attr : multi-key (sta, reqtype)
+# id = autonumber
+# sta = station MAC address in `11:22:33:44:55:66` format.
+# type = `auth` | `acct` | NULL (match any)
+# attr = existing config file format, e.g. `126:s:Test Operator`
+#radius_req_attr_sqlite=radius_attr.sqlite
+
# Dynamic Authorization Extensions (RFC 5176)
# This mechanism can be used to allow dynamic changes to user session based on
# commands from a RADIUS server (or some other disconnect client that has the
@@ -1356,6 +1510,17 @@
# wpa_key_mgmt=SAE for WPA3-Personal instead of wpa_key_mgmt=WPA-PSK).
#wpa=2
+# Extended Key ID support for Individually Addressed frames
+#
+# Extended Key ID allows to rekey PTK keys without the impacts the "normal"
+# PTK rekeying with only a single Key ID 0 has. It can only be used when the
+# driver supports it and RSN/WPA2 is used with a CCMP/GCMP pairwise cipher.
+#
+# 0 = force off, i.e., use only Key ID 0 (default)
+# 1 = enable and use Extended Key ID support when possible
+# 2 = identical to 1 but start with Key ID 1 when possible
+#extended_key_id=0
+
# 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
# (8..63 characters) that will be converted to PSK. This conversion uses SSID
@@ -1456,8 +1621,26 @@
# Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of
# PTK to mitigate some attacks against TKIP deficiencies.
+# Warning: PTK rekeying is buggy with many drivers/devices and with such
+# devices, the only secure method to rekey the PTK without Extended Key ID
+# support requires a disconnection. Check the related parameter
+# wpa_deny_ptk0_rekey for details.
#wpa_ptk_rekey=600
+# Workaround for PTK rekey issues
+#
+# PTK0 rekeys (rekeying the PTK without "Extended Key ID for Individually
+# Addressed Frames") can degrade the security and stability with some cards.
+# To avoid such issues hostapd can replace those PTK rekeys (including EAP
+# reauthentications) with disconnects.
+#
+# Available options:
+# 0 = always rekey when configured/instructed (default)
+# 1 = only rekey when the local driver is explicitly indicating it can perform
+# this operation without issues
+# 2 = never allow PTK0 rekeys
+#wpa_deny_ptk0_rekey=0
+
# The number of times EAPOL-Key Message 1/4 and Message 3/4 in the RSN 4-Way
# Handshake are retried per 4-Way Handshake attempt.
# (dot11RSNAConfigPairwiseUpdateCount)
@@ -1508,6 +1691,12 @@
# 1 = optional
# 2 = required
#ieee80211w=0
+# The most common configuration options for this based on the PMF (protected
+# management frames) certification program are:
+# PMF enabled: ieee80211w=1 and wpa_key_mgmt=WPA-EAP WPA-EAP-SHA256
+# PMF required: ieee80211w=2 and wpa_key_mgmt=WPA-EAP-SHA256
+# (and similarly for WPA-PSK and WPA-PSK-SHA256 if WPA2-Personal is used)
+# WPA3-Personal-only mode: ieee80211w=2 and wpa_key_mgmt=SAE
# Group management cipher suite
# Default: AES-128-CMAC (BIP)
@@ -1520,6 +1709,12 @@
# available in deployed devices.
#group_mgmt_cipher=AES-128-CMAC
+# Beacon Protection (management frame protection for Beacon frames)
+# This depends on management frame protection being enabled (ieee80211w != 0).
+# 0 = disabled (default)
+# 1 = enabled
+#beacon_prot=0
+
# Association SA Query maximum timeout (in TU = 1.024 ms; for MFP)
# (maximum time to wait for a SA Query response)
# dot11AssociationSAQueryMaximumTimeout, 1...4294967295
@@ -1594,7 +1789,7 @@
#sae_anti_clogging_threshold=5
# Maximum number of SAE synchronization errors (dot11RSNASAESync)
-# The offending SAe peer will be disconnected if more than this many
+# The offending SAE peer will be disconnected if more than this many
# synchronization errors happen.
#sae_sync=5
@@ -1619,6 +1814,23 @@
# MFP while SAE stations are required to negotiate MFP if sae_require_mfp=1.
#sae_require_mfp=0
+# SAE Confirm behavior
+# By default, AP will send out only SAE Commit message in response to a received
+# SAE Commit message. This parameter can be set to 1 to override that behavior
+# to send both SAE Commit and SAE Confirm messages without waiting for the STA
+# to send its SAE Confirm message first.
+#sae_confirm_immediate=0
+
+# SAE mechanism for PWE derivation
+# 0 = hunting-and-pecking loop only (default without password identifier)
+# 1 = hash-to-element only (default with password identifier)
+# 2 = both hunting-and-pecking loop and hash-to-element enabled
+# Note: The default value is likely to change from 0 to 2 once the new
+# hash-to-element mechanism has received more interoperability testing.
+# When using SAE password identifier, the hash-to-element mechanism is used
+# regardless of the sae_pwe parameter value.
+#sae_pwe=0
+
# FILS Cache Identifier (16-bit value in hexdump format)
#fils_cache_id=0011
@@ -1643,6 +1855,19 @@
# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10
#owe_groups=19 20 21
+# OWE PTK derivation workaround
+# Initial OWE implementation used SHA256 when deriving the PTK for all OWE
+# groups. This was supposed to change to SHA384 for group 20 and SHA512 for
+# group 21. This parameter can be used to enable workaround for interoperability
+# with stations that use SHA256 with groups 20 and 21. By default (0) only the
+# appropriate hash function is accepted. When workaround is enabled (1), the
+# appropriate hash function is tried first and if that fails, SHA256-based PTK
+# derivation is attempted. This workaround can result in reduced security for
+# groups 20 and 21, but is required for interoperability with older
+# implementations. There is no impact to group 19 behavior. The workaround is
+# disabled by default and can be enabled by uncommenting the following line.
+#owe_ptk_workaround=1
+
# OWE transition mode configuration
# Pointer to the matching open/OWE BSS
#owe_transition_bssid=<bssid>
@@ -1680,6 +1905,23 @@
# default: 30 TUs (= 30.72 milliseconds)
#fils_hlp_wait_time=30
+# Transition Disable indication
+# The AP can notify authenticated stations to disable transition mode in their
+# network profiles when the network has completed transition steps, i.e., once
+# sufficiently large number of APs in the ESS have been updated to support the
+# more secure alternative. When this indication is used, the stations are
+# expected to automatically disable transition mode and less secure security
+# options. This includes use of WEP, TKIP (including use of TKIP as the group
+# cipher), and connections without PMF.
+# Bitmap bits:
+# bit 0 (0x01): WPA3-Personal (i.e., disable WPA2-Personal = WPA-PSK and only
+# allow SAE to be used)
+# bit 1 (0x02): SAE-PK (disable SAE without use of SAE-PK)
+# bit 2 (0x04): WPA3-Enterprise (move to requiring PMF)
+# bit 3 (0x08): Enhanced Open (disable use of open network; require OWE)
+# (default: 0 = do not include Transition Disable KDE)
+#transition_disable=0x01
+
##### IEEE 802.11r configuration ##############################################
# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
@@ -2033,6 +2275,13 @@
#wps_nfc_dh_privkey: Hexdump of DH Private Key
#wps_nfc_dev_pw: Hexdump of Device Password
+# Application Extension attribute for Beacon and Probe Response frames
+# This parameter can be used to add application extension into WPS IE. The
+# contents of this parameter starts with 16-octet (32 hexdump characters) of
+# UUID to identify the specific application and that is followed by the actual
+# application specific data.
+#wps_application_ext=<hexdump>
+
##### Wi-Fi Direct (P2P) ######################################################
# Enable P2P Device management
@@ -2041,6 +2290,31 @@
# Allow cross connection
#allow_cross_connection=1
+##### Device Provisioning Protocol (DPP) ######################################
+
+# Name for Enrollee's DPP Configuration Request
+#dpp_name=Test
+
+# MUD URL for Enrollee's DPP Configuration Request (optional)
+#dpp_mud_url=https://example.com/mud
+
+#dpp_connector
+#dpp_netaccesskey
+#dpp_netaccesskey_expiry
+#dpp_csign
+#dpp_controller
+
+# Configurator Connectivity indication
+# 0: no Configurator is currently connected (default)
+# 1: advertise that a Configurator is available
+#dpp_configurator_connectivity=0
+
+# DPP PFS
+# 0: allow PFS to be used or not used (default)
+# 1: require PFS to be used (note: not compatible with DPP R1)
+# 2: do not allow PFS to be used
+#dpp_pfs=0
+
#### TDLS (IEEE 802.11z-2010) #################################################
# Prohibit use of TDLS in this BSS
@@ -2421,7 +2695,7 @@
# Default is 0 = OCE disabled
#oce=0
-# RSSI-based assocition rejection
+# RSSI-based association rejection
#
# Reject STA association if RSSI is below given threshold (in dBm)
# Allowed range: -60 to -90 dBm; default = 0 (rejection disabled)
@@ -2492,6 +2766,55 @@
# that allows sending of such data. Default: 0.
#stationary_ap=0
+##### Airtime policy configuration ###########################################
+
+# Set the airtime policy operating mode:
+# 0 = disabled (default)
+# 1 = static config
+# 2 = per-BSS dynamic config
+# 3 = per-BSS limit mode
+#airtime_mode=0
+
+# Interval (in milliseconds) to poll the kernel for updated station activity in
+# dynamic and limit modes
+#airtime_update_interval=200
+
+# Static configuration of station weights (when airtime_mode=1). Kernel default
+# weight is 256; set higher for larger airtime share, lower for smaller share.
+# Each entry is a MAC address followed by a weight.
+#airtime_sta_weight=02:01:02:03:04:05 256
+#airtime_sta_weight=02:01:02:03:04:06 512
+
+# Per-BSS airtime weight. In multi-BSS mode, set for each BSS and hostapd will
+# configure station weights to enforce the correct ratio between BSS weights
+# depending on the number of active stations. The *ratios* between different
+# BSSes is what's important, not the absolute numbers.
+# Must be set for all BSSes if airtime_mode=2 or 3, has no effect otherwise.
+#airtime_bss_weight=1
+
+# Whether the current BSS should be limited (when airtime_mode=3).
+#
+# If set, the BSS weight ratio will be applied in the case where the current BSS
+# would exceed the share defined by the BSS weight ratio. E.g., if two BSSes are
+# set to the same weights, and one is set to limited, the limited BSS will get
+# no more than half the available airtime, but if the non-limited BSS has more
+# stations active, that *will* be allowed to exceed its half of the available
+# airtime.
+#airtime_bss_limit=1
+
+##### EDMG support ############################################################
+#
+# Enable EDMG capability for AP mode in the 60 GHz band. Default value is false.
+# To configure channel bonding for an EDMG AP use edmg_channel below.
+# If enable_edmg is set and edmg_channel is not set, EDMG CB1 will be
+# configured.
+#enable_edmg=1
+#
+# Configure channel bonding for AP mode in the 60 GHz band.
+# This parameter is relevant only if enable_edmg is set.
+# Default value is 0 (no channel bonding).
+#edmg_channel=9
+
##### TESTING OPTIONS #########################################################
#
# The options in this section are only available when the build configuration
diff --git a/hostapd/hostapd.wpa_psk b/hostapd/hostapd.wpa_psk
index 166e59e..2ce5ff2 100644
--- a/hostapd/hostapd.wpa_psk
+++ b/hostapd/hostapd.wpa_psk
@@ -7,9 +7,15 @@
# keyid=<keyid_string>
# An optional VLAN ID can be specified by prefixing the line with
# vlanid=<VLAN ID>.
+# An optional WPS tag can be added by prefixing the line with
+# wps=<0/1> (default: 0). Any matching entry with that tag will be used when
+# generating a PSK for a WPS Enrollee instead of generating a new random
+# per-Enrollee PSK.
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
+wps=1 00:00:00:00:00:00 passphrase for WPS
+wps=1 11:22:33:44:55:00 dev-specific passphrase for WPS
00:00:00:00:00:00 another passphrase for all STAs
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 23c592a..440664e 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -54,7 +54,7 @@
fprintf(stderr, "%s\n", hostapd_cli_version);
fprintf(stderr,
"\n"
- "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
+ "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvBr] "
"[-a<path>] \\\n"
" [-P<pid file>] [-G<ping interval>] [command..]\n"
"\n"
@@ -68,6 +68,9 @@
" -a<file> run in daemon mode executing the action file "
"based on events\n"
" from hostapd\n"
+ " -r try to reconnect when client socket is "
+ "disconnected.\n"
+ " This is useful only when used with -a.\n"
" -B run a daemon in the background\n"
" -i<ifname> Interface to listen on (default: first "
"interface found in the\n"
@@ -401,7 +404,6 @@
#endif /* CONFIG_TAXONOMY */
-#ifdef CONFIG_IEEE80211W
static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -414,7 +416,6 @@
snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
return wpa_ctrl_command(ctrl, buf);
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
@@ -1214,6 +1215,13 @@
}
+static int hostapd_cli_cmd_update_beacon(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "UPDATE_BEACON");
+}
+
+
static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
@@ -1304,24 +1312,17 @@
}
+static int hostapd_cli_cmd_show_neighbor(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "SHOW_NEIGHBOR");
+}
+
+
static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[400];
- int res;
-
- if (argc != 2) {
- printf("Invalid remove_neighbor command: needs 2 arguments\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NEIGHBOR %s %s",
- argv[0], argv[1]);
- if (os_snprintf_error(sizeof(cmd), res)) {
- printf("Too long REMOVE_NEIGHBOR command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return hostapd_cli_cmd(ctrl, "REMOVE_NEIGHBOR", 1, argc, argv);
}
@@ -1535,10 +1536,8 @@
{ "signature", hostapd_cli_cmd_signature, hostapd_complete_stations,
"<addr> = get taxonomy signature for a station" },
#endif /* CONFIG_TAXONOMY */
-#ifdef CONFIG_IEEE80211W
{ "sa_query", hostapd_cli_cmd_sa_query, hostapd_complete_stations,
"<addr> = send SA Query to a station" },
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
{ "wps_pin", hostapd_cli_cmd_wps_pin, NULL,
"<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" },
@@ -1617,6 +1616,8 @@
"= reload configuration for current interface" },
{ "disable", hostapd_cli_cmd_disable, NULL,
"= disable hostapd on current interface" },
+ { "update_beacon", hostapd_cli_cmd_update_beacon, NULL,
+ "= update Beacon frame contents\n"},
{ "erp_flush", hostapd_cli_cmd_erp_flush, NULL,
"= drop all ERP keys"},
{ "log_level", hostapd_cli_cmd_log_level, NULL,
@@ -1628,8 +1629,10 @@
{ "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL,
"<addr> <ssid=> <nr=> [lci=] [civic=] [stat]\n"
" = add AP to neighbor database" },
+ { "show_neighbor", hostapd_cli_cmd_show_neighbor, NULL,
+ " = show neighbor database entries" },
{ "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL,
- "<addr> <ssid=> = remove AP from neighbor database" },
+ "<addr> [ssid=<hex>] = remove AP from neighbor database" },
{ "req_lci", hostapd_cli_cmd_req_lci, hostapd_complete_stations,
"<addr> = send LCI request to a station"},
{ "req_range", hostapd_cli_cmd_req_range, NULL,
@@ -2002,12 +2005,13 @@
int warning_displayed = 0;
int c;
int daemonize = 0;
+ int reconnect = 0;
if (os_program_init())
return -1;
for (;;) {
- c = getopt(argc, argv, "a:BhG:i:p:P:s:v");
+ c = getopt(argc, argv, "a:BhG:i:p:P:rs:v");
if (c < 0)
break;
switch (c) {
@@ -2036,6 +2040,9 @@
case 'P':
pid_file = optarg;
break;
+ case 'r':
+ reconnect = 1;
+ break;
case 's':
client_socket_dir = optarg;
break;
@@ -2078,8 +2085,7 @@
printf("Connection established.\n");
break;
}
-
- if (!interactive) {
+ if (!interactive && !reconnect) {
perror("Failed to connect to hostapd - "
"wpa_ctrl_open");
return -1;
@@ -2097,8 +2103,14 @@
return -1;
if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
return -1;
-
- if (interactive)
+ if (reconnect && action_file && ctrl_ifname) {
+ while (!hostapd_cli_quit) {
+ if (ctrl_conn)
+ hostapd_cli_action(ctrl_conn);
+ os_sleep(1, 0);
+ hostapd_cli_reconnect(ctrl_ifname);
+ }
+ } else if (interactive)
hostapd_cli_interactive();
else if (action_file)
hostapd_cli_action(ctrl_conn);
diff --git a/hostapd/main.c b/hostapd/main.c
index b9df584..3ce8126 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -83,9 +83,6 @@
case HOSTAPD_MODULE_DRIVER:
module_str = "DRIVER";
break;
- case HOSTAPD_MODULE_IAPP:
- module_str = "IAPP";
- break;
case HOSTAPD_MODULE_MLME:
module_str = "MLME";
break;
@@ -223,7 +220,7 @@
struct wowlan_triggers *triggs;
iface->drv_flags = capa.flags;
- iface->smps_modes = capa.smps_modes;
+ iface->drv_flags2 = capa.flags2;
iface->probe_resp_offloads = capa.probe_resp_offloads;
/*
* Use default extended capa values from per-radio information
@@ -265,7 +262,7 @@
struct hostapd_iface *iface;
int k;
- wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
+ wpa_printf(MSG_DEBUG, "Configuration file: %s", config_fname);
iface = hostapd_init(interfaces, config_fname);
if (!iface)
return NULL;
@@ -456,11 +453,12 @@
static void show_version(void)
{
fprintf(stderr,
- "hostapd v" VERSION_STR "\n"
+ "hostapd v%s\n"
"User space daemon for IEEE 802.11 AP management,\n"
"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
"Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> "
- "and contributors\n");
+ "and contributors\n",
+ VERSION_STR);
}
@@ -655,6 +653,9 @@
int start_ifaces_in_sync = 0;
char **if_names = NULL;
size_t if_names_size = 0;
+#ifdef CONFIG_DPP
+ struct dpp_global_config dpp_conf;
+#endif /* CONFIG_DPP */
if (os_program_init())
return -1;
@@ -674,7 +675,9 @@
dl_list_init(&interfaces.eth_p_oui);
#endif /* CONFIG_ETH_P_OUI */
#ifdef CONFIG_DPP
- interfaces.dpp = dpp_global_init();
+ os_memset(&dpp_conf, 0, sizeof(dpp_conf));
+ /* TODO: dpp_conf.msg_ctx? */
+ interfaces.dpp = dpp_global_init(&dpp_conf);
if (!interfaces.dpp)
return -1;
#endif /* CONFIG_DPP */
@@ -770,7 +773,7 @@
if (log_file)
wpa_debug_open_file(log_file);
- else
+ if (!log_file && !wpa_debug_syslog)
wpa_debug_setup_stdout();
#ifdef CONFIG_DEBUG_SYSLOG
if (wpa_debug_syslog)
diff --git a/hs20/client/.gitignore b/hs20/client/.gitignore
index d2fd60f..f6c13d3 100644
--- a/hs20/client/.gitignore
+++ b/hs20/client/.gitignore
@@ -1 +1,4 @@
hs20-osu-client
+SP
+osu-ca.pem
+spp.xsd
diff --git a/hs20/client/Makefile b/hs20/client/Makefile
index 67f6f55..cc2af03 100644
--- a/hs20/client/Makefile
+++ b/hs20/client/Makefile
@@ -30,8 +30,17 @@
ifndef CONFIG_NO_BROWSER
ifndef CONFIG_BROWSER_SYSTEM
+TEST_WK := $(shell pkg-config --silence-errors --cflags webkitgtk-3.0)
+ifeq ($(TEST_WK),)
+# Try webkit2
+GTKCFLAGS := $(shell pkg-config --cflags gtk+-3.0 webkit2gtk-4.0)
+GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkit2gtk-4.0)
+CFLAGS += -DUSE_WEBKIT2
+else
GTKCFLAGS := $(shell pkg-config --cflags gtk+-3.0 webkitgtk-3.0)
GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkitgtk-3.0)
+endif
+
CFLAGS += $(GTKCFLAGS)
LIBS += $(GTKLIBS)
endif
diff --git a/hs20/client/est.c b/hs20/client/est.c
index db65334..97f9132 100644
--- a/hs20/client/est.c
+++ b/hs20/client/est.c
@@ -158,7 +158,7 @@
return -1;
}
- pkcs7 = base64_decode((unsigned char *) resp, resp_len, &pkcs7_len);
+ pkcs7 = base64_decode(resp, resp_len, &pkcs7_len);
if (pkcs7 && pkcs7_len < resp_len / 2) {
wpa_printf(MSG_INFO, "Too short base64 decode (%u bytes; downloaded %u bytes) - assume this was binary",
(unsigned int) pkcs7_len, (unsigned int) resp_len);
@@ -639,8 +639,7 @@
return -1;
}
- attrs = base64_decode((unsigned char *) resp, resp_len,
- &attrs_len);
+ attrs = base64_decode(resp, resp_len, &attrs_len);
os_free(resp);
if (attrs == NULL) {
@@ -734,7 +733,7 @@
}
wpa_printf(MSG_DEBUG, "EST simpleenroll response: %s", resp);
- pkcs7 = base64_decode((unsigned char *) resp, resp_len, &pkcs7_len);
+ pkcs7 = base64_decode(resp, resp_len, &pkcs7_len);
if (pkcs7 == NULL) {
wpa_printf(MSG_INFO, "EST workaround - Could not decode base64, assume this is DER encoded PKCS7");
pkcs7 = os_malloc(resp_len);
diff --git a/hs20/client/oma_dm_client.c b/hs20/client/oma_dm_client.c
index d75c845..bcd68b8 100644
--- a/hs20/client/oma_dm_client.c
+++ b/hs20/client/oma_dm_client.c
@@ -407,7 +407,7 @@
wpa_printf(MSG_INFO, "Data: %s", data);
wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data);
write_summary(ctx, "Launch browser to URI '%s'", data);
- res = hs20_web_browser(data);
+ res = hs20_web_browser(data, 1);
xml_node_get_text_free(ctx->xml, data);
if (res > 0) {
wpa_printf(MSG_INFO, "User response in browser completed successfully");
diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c
index 1f594ce..11bf0db 100644
--- a/hs20/client/osu_client.c
+++ b/hs20/client/osu_client.c
@@ -310,7 +310,7 @@
size_t len;
u8 digest1[SHA256_MAC_LEN], digest2[SHA256_MAC_LEN];
int res;
- unsigned char *b64;
+ char *b64;
FILE *f;
url_node = get_node(ctx->xml, params, "CertURL");
@@ -364,7 +364,7 @@
return -1;
}
- b64 = base64_encode((unsigned char *) cert, len, NULL);
+ b64 = base64_encode(cert, len, NULL);
os_free(cert);
if (b64 == NULL)
return -1;
@@ -1588,6 +1588,7 @@
xml_node_t *node, const char *fqdn)
{
char buf[200], dir[200];
+ int res;
wpa_printf(MSG_INFO, "- Credential/DigitalCertificate");
@@ -1599,14 +1600,20 @@
wpa_printf(MSG_INFO, "Failed to set username");
}
- snprintf(buf, sizeof(buf), "%s/SP/%s/client-cert.pem", dir, fqdn);
+ res = os_snprintf(buf, sizeof(buf), "%s/SP/%s/client-cert.pem", dir,
+ fqdn);
+ if (os_snprintf_error(sizeof(buf), res))
+ return;
if (os_file_exists(buf)) {
if (set_cred_quoted(ctx->ifname, id, "client_cert", buf) < 0) {
wpa_printf(MSG_INFO, "Failed to set client_cert");
}
}
- snprintf(buf, sizeof(buf), "%s/SP/%s/client-key.pem", dir, fqdn);
+ res = os_snprintf(buf, sizeof(buf), "%s/SP/%s/client-key.pem", dir,
+ fqdn);
+ if (os_snprintf_error(sizeof(buf), res))
+ return;
if (os_file_exists(buf)) {
if (set_cred_quoted(ctx->ifname, id, "private_key", buf) < 0) {
wpa_printf(MSG_INFO, "Failed to set private_key");
@@ -1620,6 +1627,7 @@
{
char *str = xml_node_get_text(ctx->xml, node);
char buf[200], dir[200];
+ int res;
if (str == NULL)
return;
@@ -1634,7 +1642,9 @@
if (getcwd(dir, sizeof(dir)) == NULL)
return;
- snprintf(buf, sizeof(buf), "%s/SP/%s/aaa-ca.pem", dir, fqdn);
+ res = os_snprintf(buf, sizeof(buf), "%s/SP/%s/aaa-ca.pem", dir, fqdn);
+ if (os_snprintf_error(sizeof(buf), res))
+ return;
if (os_file_exists(buf)) {
if (set_cred_quoted(ctx->ifname, id, "ca_cert", buf) < 0) {
wpa_printf(MSG_INFO, "Failed to set CA cert");
@@ -2223,7 +2233,7 @@
wpa_ctrl_close(mon);
if (res < 0) {
- wpa_printf(MSG_INFO, "Could not connect");
+ wpa_printf(MSG_INFO, "Could not connect to OSU network");
write_summary(ctx, "Could not connect to OSU network");
wpa_printf(MSG_INFO, "Remove OSU network connection");
snprintf(buf, sizeof(buf), "REMOVE_NETWORK %d", id);
@@ -2396,7 +2406,7 @@
snprintf(fname, sizeof(fname), "file://%s/osu-providers.html", dir);
write_summary(ctx, "Start web browser with OSU provider selection page");
- ret = hs20_web_browser(fname);
+ ret = hs20_web_browser(fname, 0);
selected:
if (ret > 0 && (size_t) ret <= osu_count) {
@@ -2717,6 +2727,8 @@
if (!pps_fname) {
char buf[256];
+ int res;
+
wpa_printf(MSG_INFO, "Determining PPS file based on Home SP information");
if (address && os_strncmp(address, "fqdn=", 5) == 0) {
wpa_printf(MSG_INFO, "Use requested FQDN from command line");
@@ -2737,8 +2749,13 @@
"SP/%s/pps.xml", ctx->fqdn);
pps_fname = pps_fname_buf;
- os_snprintf(ca_fname_buf, sizeof(ca_fname_buf), "SP/%s/ca.pem",
- buf);
+ res = os_snprintf(ca_fname_buf, sizeof(ca_fname_buf),
+ "SP/%s/ca.pem", buf);
+ if (os_snprintf_error(sizeof(ca_fname_buf), res)) {
+ os_free(ctx->fqdn);
+ ctx->fqdn = NULL;
+ return -1;
+ }
ca_fname = ca_fname_buf;
}
@@ -2890,7 +2907,7 @@
static int osu_cert_cb(void *_ctx, struct http_cert *cert)
{
struct hs20_osu_client *ctx = _ctx;
- unsigned int i, j;
+ size_t i, j;
int found;
char *host = NULL;
@@ -2985,7 +3002,7 @@
size_t name_len = os_strlen(name);
wpa_printf(MSG_INFO,
- "[%i] Looking for icon file name '%s' match",
+ "[%zu] Looking for icon file name '%s' match",
j, name);
for (i = 0; i < cert->num_logo; i++) {
struct http_logo *logo = &cert->logo[i];
@@ -2993,7 +3010,7 @@
char *pos;
wpa_printf(MSG_INFO,
- "[%i] Comparing to '%s' uri_len=%d name_len=%d",
+ "[%zu] Comparing to '%s' uri_len=%d name_len=%d",
i, logo->uri, (int) uri_len, (int) name_len);
if (uri_len < 1 + name_len) {
wpa_printf(MSG_INFO, "URI Length is too short");
@@ -3027,7 +3044,7 @@
if (logo->hash_len != 32) {
wpa_printf(MSG_INFO,
- "[%i][%i] Icon hash length invalid (should be 32): %d",
+ "[%zu][%zu] Icon hash length invalid (should be 32): %d",
j, i, (int) logo->hash_len);
continue;
}
@@ -3037,7 +3054,7 @@
}
wpa_printf(MSG_DEBUG,
- "[%u][%u] Icon hash did not match", j, i);
+ "[%zu][%zu] Icon hash did not match", j, i);
wpa_hexdump_ascii(MSG_DEBUG, "logo->hash",
logo->hash, 32);
wpa_hexdump_ascii(MSG_DEBUG, "ctx->icon_hash[j]",
@@ -3135,7 +3152,7 @@
static void usage(void)
{
- printf("usage: hs20-osu-client [-dddqqKt] [-S<station ifname>] \\\n"
+ printf("usage: hs20-osu-client [-dddqqKtT] [-S<station ifname>] \\\n"
" [-w<wpa_supplicant ctrl_iface dir>] "
"[-r<result file>] [-f<debug file>] \\\n"
" [-s<summary file>] \\\n"
@@ -3181,7 +3198,7 @@
return -1;
for (;;) {
- c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tw:x:");
+ c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tTw:x:");
if (c < 0)
break;
switch (c) {
@@ -3219,6 +3236,9 @@
case 't':
wpa_debug_timestamp++;
break;
+ case 'T':
+ ctx.ignore_tls = 1;
+ break;
case 'w':
wpas_ctrl_path = optarg;
break;
@@ -3386,7 +3406,7 @@
wpa_printf(MSG_INFO, "Launch web browser to URL %s",
argv[optind + 1]);
- ret = hs20_web_browser(argv[optind + 1]);
+ ret = hs20_web_browser(argv[optind + 1], ctx.ignore_tls);
wpa_printf(MSG_INFO, "Web browser result: %d", ret);
} else if (strcmp(argv[optind], "parse_cert") == 0) {
if (argc - optind < 2) {
diff --git a/hs20/client/osu_client.h b/hs20/client/osu_client.h
index 5c8e6d0..9b45b03 100644
--- a/hs20/client/osu_client.h
+++ b/hs20/client/osu_client.h
@@ -50,6 +50,8 @@
const char *osu_ssid; /* Enforced OSU_SSID for testing purposes */
#define WORKAROUND_OCSP_OPTIONAL 0x00000001
unsigned long int workarounds;
+ int ignore_tls; /* whether to ignore TLS validation issues with HTTPS
+ * server certificate */
};
diff --git a/hs20/client/spp_client.c b/hs20/client/spp_client.c
index c619541..39d10e0 100644
--- a/hs20/client/spp_client.c
+++ b/hs20/client/spp_client.c
@@ -547,7 +547,7 @@
}
wpa_printf(MSG_INFO, "Launch browser to URI '%s'", uri);
write_summary(ctx, "Launch browser to URI '%s'", uri);
- res = hs20_web_browser(uri);
+ res = hs20_web_browser(uri, 1);
xml_node_get_text_free(ctx->xml, uri);
if (res > 0) {
wpa_printf(MSG_INFO, "User response in browser completed successfully - sessionid='%s'",
diff --git a/hs20/server/ca/ocsp-responder.sh b/hs20/server/ca/ocsp-responder.sh
index 8cebd74..620947d 100644
--- a/hs20/server/ca/ocsp-responder.sh
+++ b/hs20/server/ca/ocsp-responder.sh
@@ -1,3 +1,3 @@
#!/bin/sh
-openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner ocsp.pem -rkey ocsp.key -CA demoCA/cacert.pem -text
+openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner ocsp.pem -rkey ocsp.key -CA demoCA/cacert.pem -text -ignore_err
diff --git a/hs20/server/ca/ocsp-update-cache.sh b/hs20/server/ca/ocsp-update-cache.sh
index 8ddef9b..f2b2325 100644
--- a/hs20/server/ca/ocsp-update-cache.sh
+++ b/hs20/server/ca/ocsp-update-cache.sh
@@ -1,5 +1,6 @@
#!/bin/sh
+# NOTE: You may need to replace 'localhost' with your OCSP server hostname.
openssl ocsp \
-no_nonce \
-CAfile ca.pem \
diff --git a/hs20/server/hs20_spp_server.c b/hs20/server/hs20_spp_server.c
index 6c74f54..347c40a 100644
--- a/hs20/server/hs20_spp_server.c
+++ b/hs20/server/hs20_spp_server.c
@@ -176,7 +176,7 @@
ctx.root_dir = optarg;
break;
case 'v':
- printf("hs20_spp_server v" VERSION_STR "\n");
+ printf("hs20_spp_server v%s\n", VERSION_STR);
return 0;
default:
usage();
diff --git a/hs20/server/spp_server.c b/hs20/server/spp_server.c
index 4bef0ff..a50e907 100644
--- a/hs20/server/spp_server.c
+++ b/hs20/server/spp_server.c
@@ -633,7 +633,7 @@
add_text_node(ctx, node, "Username", user);
- b64 = (char *) base64_encode((unsigned char *) pw, strlen(pw), NULL);
+ b64 = base64_encode(pw, strlen(pw), NULL);
if (b64 == NULL)
return NULL;
len = os_strlen(b64);
@@ -1602,8 +1602,7 @@
xml_node_create_text(ctx->xml, enroll, ns, "estUserID", user);
- b64 = (char *) base64_encode((unsigned char *) password,
- strlen(password), NULL);
+ b64 = base64_encode(password, strlen(password), NULL);
if (b64 == NULL) {
xml_node_free(ctx->xml, spp_node);
return NULL;
diff --git a/src/ap/Makefile b/src/ap/Makefile
index 9b07ee1..54e48a0 100644
--- a/src/ap/Makefile
+++ b/src/ap/Makefile
@@ -15,11 +15,10 @@
CFLAGS += -DCONFIG_INTERWORKING
CFLAGS += -DCONFIG_IEEE80211R
CFLAGS += -DCONFIG_IEEE80211R_AP
-CFLAGS += -DCONFIG_IEEE80211W
CFLAGS += -DCONFIG_WPS
CFLAGS += -DCONFIG_PROXYARP
CFLAGS += -DCONFIG_IPV6
-CFLAGS += -DCONFIG_IAPP
+CFLAGS += -DCONFIG_AIRTIME_POLICY
LIB_OBJS= \
accounting.o \
@@ -27,6 +26,7 @@
ap_drv_ops.o \
ap_list.o \
ap_mlme.o \
+ airtime_policy.o \
authsrv.o \
beacon.o \
bss_load.o \
@@ -40,7 +40,6 @@
hostapd.o \
hs20.o \
hw_features.o \
- iapp.o \
ieee802_11_auth.o \
ieee802_11.o \
ieee802_11_ht.o \
diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index 0aacc3c..9fc1886 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -97,6 +97,9 @@
msg) < 0)
goto fail;
+ if (sta && add_sqlite_radius_attr(hapd, sta, msg, 1) < 0)
+ goto fail;
+
if (sta) {
for (i = 0; ; i++) {
val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
diff --git a/src/ap/acs.c b/src/ap/acs.c
index 3b45075..5c01610 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -261,13 +261,13 @@
}
-void acs_cleanup(struct hostapd_iface *iface)
+static void acs_cleanup_mode(struct hostapd_hw_modes *mode)
{
int i;
struct hostapd_channel_data *chan;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED)
acs_clean_chan_surveys(chan);
@@ -276,6 +276,15 @@
chan->flag |= HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED;
chan->min_nf = 0;
}
+}
+
+
+void acs_cleanup(struct hostapd_iface *iface)
+{
+ int i;
+
+ for (i = 0; i < iface->num_hw_features; i++)
+ acs_cleanup_mode(&iface->hw_features[i]);
iface->chans_surveyed = 0;
iface->acs_num_completed_scans = 0;
@@ -453,21 +462,35 @@
}
-static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
+static int acs_surveys_are_sufficient_mode(struct hostapd_hw_modes *mode)
{
int i;
struct hostapd_channel_data *chan;
- int valid = 0;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
acs_survey_list_is_sufficient(chan))
- valid++;
+ return 1;
}
- /* We need at least survey data for one channel */
- return !!valid;
+ return 0;
+}
+
+
+static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
+{
+ int i;
+ struct hostapd_hw_modes *mode;
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode) &&
+ acs_surveys_are_sufficient_mode(mode))
+ return 1;
+ }
+
+ return 0;
}
@@ -489,14 +512,14 @@
}
-static void acs_survey_all_chans_intereference_factor(
- struct hostapd_iface *iface)
+static void acs_survey_mode_interference_factor(
+ struct hostapd_iface *iface, struct hostapd_hw_modes *mode)
{
int i;
struct hostapd_channel_data *chan;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
if (!acs_usable_chan(chan))
continue;
@@ -515,14 +538,28 @@
}
-static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface,
- int freq)
+static void acs_survey_all_chans_interference_factor(
+ struct hostapd_iface *iface)
+{
+ int i;
+ struct hostapd_hw_modes *mode;
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode))
+ acs_survey_mode_interference_factor(iface, mode);
+ }
+}
+
+
+static struct hostapd_channel_data *
+acs_find_chan_mode(struct hostapd_hw_modes *mode, int freq)
{
struct hostapd_channel_data *chan;
int i;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
@@ -535,6 +572,26 @@
}
+static struct hostapd_channel_data *
+acs_find_chan(struct hostapd_iface *iface, int freq)
+{
+ int i;
+ struct hostapd_hw_modes *mode;
+ struct hostapd_channel_data *chan;
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode)) {
+ chan = acs_find_chan_mode(mode, freq);
+ if (chan)
+ return chan;
+ }
+ }
+
+ return NULL;
+}
+
+
static int is_24ghz_mode(enum hostapd_hw_mode mode)
{
return mode == HOSTAPD_MODE_IEEE80211B ||
@@ -565,58 +622,24 @@
#define ACS_24GHZ_PREFER_1_6_11 0.8
#endif /* ACS_24GHZ_PREFER_1_6_11 */
-/*
- * At this point it's assumed chan->interface_factor has been computed.
- * This function should be reusable regardless of interference computation
- * option (survey, BSS, spectral, ...). chan->interference factor must be
- * summable (i.e., must be always greater than zero).
- */
-static struct hostapd_channel_data *
-acs_find_ideal_chan(struct hostapd_iface *iface)
+static void
+acs_find_ideal_chan_mode(struct hostapd_iface *iface,
+ struct hostapd_hw_modes *mode,
+ int n_chans, u32 bw,
+ struct hostapd_channel_data **rand_chan,
+ struct hostapd_channel_data **ideal_chan,
+ long double *ideal_factor)
{
- struct hostapd_channel_data *chan, *adj_chan, *ideal_chan = NULL,
- *rand_chan = NULL;
- long double factor, ideal_factor = 0;
+ struct hostapd_channel_data *chan, *adj_chan = NULL;
+ long double factor;
int i, j;
- int n_chans = 1;
- u32 bw;
unsigned int k;
- /* TODO: HT40- support */
-
- if (iface->conf->ieee80211n &&
- iface->conf->secondary_channel == -1) {
- wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+");
- return NULL;
- }
-
- if (iface->conf->ieee80211n &&
- iface->conf->secondary_channel)
- n_chans = 2;
-
- 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;
- }
- }
-
- bw = num_chan_to_bw(n_chans);
-
- /* 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++) {
+ for (i = 0; i < mode->num_channels; i++) {
double total_weight;
struct acs_bias *bias, tmp_bias;
- chan = &iface->current_mode->channels[i];
+ chan = &mode->channels[i];
/* Since in the current ACS implementation the first channel is
* always a primary channel, skip channels not available as
@@ -637,7 +660,7 @@
/* HT40 on 5 GHz has a limited set of primary channels as per
* 11n Annex J */
- if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
+ if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
iface->conf->ieee80211n &&
iface->conf->secondary_channel &&
!acs_usable_ht40_chan(chan)) {
@@ -646,10 +669,10 @@
continue;
}
- if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
- iface->conf->ieee80211ac) {
- if (iface->conf->vht_oper_chwidth ==
- VHT_CHANWIDTH_80MHZ &&
+ if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
+ (iface->conf->ieee80211ac || iface->conf->ieee80211ax)) {
+ if (hostapd_get_oper_chwidth(iface->conf) ==
+ CHANWIDTH_80MHZ &&
!acs_usable_vht80_chan(chan)) {
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: not allowed as primary channel for VHT80",
@@ -657,8 +680,8 @@
continue;
}
- if (iface->conf->vht_oper_chwidth ==
- VHT_CHANWIDTH_160MHZ &&
+ if (hostapd_get_oper_chwidth(iface->conf) ==
+ CHANWIDTH_160MHZ &&
!acs_usable_vht160_chan(chan)) {
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: not allowed as primary channel for VHT160",
@@ -698,7 +721,7 @@
/* 2.4 GHz has overlapping 20 MHz channels. Include adjacent
* channel interference factor. */
- if (is_24ghz_mode(iface->current_mode->mode)) {
+ if (is_24ghz_mode(mode->mode)) {
for (j = 0; j < n_chans; j++) {
adj_chan = acs_find_chan(iface, chan->freq +
(j * 20) - 5);
@@ -744,7 +767,7 @@
break;
bias = NULL;
}
- } else if (is_24ghz_mode(iface->current_mode->mode) &&
+ } else if (is_24ghz_mode(mode->mode) &&
is_common_24ghz_chan(chan->chan)) {
tmp_bias.channel = chan->chan;
tmp_bias.bias = ACS_24GHZ_PREFER_1_6_11;
@@ -763,14 +786,71 @@
}
if (acs_usable_chan(chan) &&
- (!ideal_chan || factor < ideal_factor)) {
- ideal_factor = factor;
- ideal_chan = chan;
+ (!*ideal_chan || factor < *ideal_factor)) {
+ *ideal_factor = factor;
+ *ideal_chan = chan;
}
/* This channel would at least be usable */
- if (!rand_chan)
- rand_chan = chan;
+ if (!(*rand_chan))
+ *rand_chan = chan;
+ }
+}
+
+
+/*
+ * At this point it's assumed chan->interference_factor has been computed.
+ * This function should be reusable regardless of interference computation
+ * option (survey, BSS, spectral, ...). chan->interference factor must be
+ * summable (i.e., must be always greater than zero).
+ */
+static struct hostapd_channel_data *
+acs_find_ideal_chan(struct hostapd_iface *iface)
+{
+ struct hostapd_channel_data *ideal_chan = NULL,
+ *rand_chan = NULL;
+ long double ideal_factor = 0;
+ int i;
+ int n_chans = 1;
+ u32 bw;
+ struct hostapd_hw_modes *mode;
+
+ /* TODO: HT40- support */
+
+ if (iface->conf->ieee80211n &&
+ iface->conf->secondary_channel == -1) {
+ wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+");
+ return NULL;
+ }
+
+ if (iface->conf->ieee80211n &&
+ iface->conf->secondary_channel)
+ n_chans = 2;
+
+ if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
+ switch (hostapd_get_oper_chwidth(iface->conf)) {
+ case CHANWIDTH_80MHZ:
+ n_chans = 4;
+ break;
+ case CHANWIDTH_160MHZ:
+ n_chans = 8;
+ break;
+ }
+ }
+
+ bw = num_chan_to_bw(n_chans);
+
+ /* TODO: VHT/HE80+80. Update acs_adjust_center_freq() too. */
+
+ wpa_printf(MSG_DEBUG,
+ "ACS: Survey analysis for selected bandwidth %d MHz", bw);
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode))
+ acs_find_ideal_chan_mode(iface, mode, n_chans, bw,
+ &rand_chan, &ideal_chan,
+ &ideal_factor);
}
if (ideal_chan) {
@@ -783,20 +863,20 @@
}
-static void acs_adjust_vht_center_freq(struct hostapd_iface *iface)
+static void acs_adjust_center_freq(struct hostapd_iface *iface)
{
int offset;
wpa_printf(MSG_DEBUG, "ACS: Adjusting VHT center frequency");
- switch (iface->conf->vht_oper_chwidth) {
- case VHT_CHANWIDTH_USE_HT:
+ switch (hostapd_get_oper_chwidth(iface->conf)) {
+ case CHANWIDTH_USE_HT:
offset = 2 * iface->conf->secondary_channel;
break;
- case VHT_CHANWIDTH_80MHZ:
+ case CHANWIDTH_80MHZ:
offset = 6;
break;
- case VHT_CHANWIDTH_160MHZ:
+ case CHANWIDTH_160MHZ:
offset = 14;
break;
default:
@@ -807,8 +887,8 @@
return;
}
- iface->conf->vht_oper_centr_freq_seg0_idx =
- iface->conf->channel + offset;
+ hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
+ iface->conf->channel + offset);
}
@@ -826,7 +906,7 @@
return -1;
}
- acs_survey_all_chans_intereference_factor(iface);
+ acs_survey_all_chans_interference_factor(iface);
return 0;
}
@@ -862,9 +942,10 @@
}
iface->conf->channel = ideal_chan->chan;
+ iface->freq = ideal_chan->freq;
- if (iface->conf->ieee80211ac)
- acs_adjust_vht_center_freq(iface);
+ if (iface->conf->ieee80211ac || iface->conf->ieee80211ax)
+ acs_adjust_center_freq(iface);
err = 0;
fail:
@@ -917,21 +998,15 @@
}
-static int acs_request_scan(struct hostapd_iface *iface)
+static int * acs_request_scan_add_freqs(struct hostapd_iface *iface,
+ struct hostapd_hw_modes *mode,
+ int *freq)
{
- struct wpa_driver_scan_params params;
struct hostapd_channel_data *chan;
- int i, *freq;
+ int i;
- os_memset(¶ms, 0, sizeof(params));
- params.freqs = os_calloc(iface->current_mode->num_channels + 1,
- sizeof(params.freqs[0]));
- if (params.freqs == NULL)
- return -1;
-
- freq = params.freqs;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
@@ -940,8 +1015,47 @@
*freq++ = chan->freq;
}
+
+ return freq;
+}
+
+
+static int acs_request_scan(struct hostapd_iface *iface)
+{
+ struct wpa_driver_scan_params params;
+ int i, *freq;
+ int num_channels;
+ struct hostapd_hw_modes *mode;
+
+ os_memset(¶ms, 0, sizeof(params));
+
+ num_channels = 0;
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode))
+ num_channels += mode->num_channels;
+ }
+
+ params.freqs = os_calloc(num_channels + 1, sizeof(params.freqs[0]));
+ if (params.freqs == NULL)
+ return -1;
+
+ freq = params.freqs;
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode))
+ freq = acs_request_scan_add_freqs(iface, mode, freq);
+ }
+
*freq = 0;
+ if (params.freqs == freq) {
+ wpa_printf(MSG_ERROR, "ACS: No available channels found");
+ os_free(params.freqs);
+ return -1;
+ }
+
iface->scan_cb = acs_scan_complete;
wpa_printf(MSG_DEBUG, "ACS: Scanning %d / %d",
@@ -971,7 +1085,8 @@
return HOSTAPD_CHAN_ACS;
}
- if (!iface->current_mode)
+ if (!iface->current_mode &&
+ iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)
return HOSTAPD_CHAN_INVALID;
acs_cleanup(iface);
diff --git a/src/ap/airtime_policy.c b/src/ap/airtime_policy.c
new file mode 100644
index 0000000..1e67f0d
--- /dev/null
+++ b/src/ap/airtime_policy.c
@@ -0,0 +1,269 @@
+/*
+ * Airtime policy configuration
+ * Copyright (c) 2018-2019, Toke Høiland-Jørgensen <toke@toke.dk>
+ *
+ * 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 "hostapd.h"
+#include "ap_drv_ops.h"
+#include "sta_info.h"
+#include "airtime_policy.h"
+
+/* Idea:
+ * Two modes of airtime enforcement:
+ * 1. Static weights: specify weights per MAC address with a per-BSS default
+ * 2. Per-BSS limits: Dynamically calculate weights of backlogged stations to
+ * enforce relative total shares between BSSes.
+ *
+ * - Periodic per-station callback to update queue status.
+ *
+ * Copy accounting_sta_update_stats() to get TXQ info and airtime weights and
+ * keep them updated in sta_info.
+ *
+ * - Separate periodic per-bss (or per-iface?) callback to update weights.
+ *
+ * Just need to loop through all interfaces, count sum the active stations (or
+ * should the per-STA callback just adjust that for the BSS?) and calculate new
+ * weights.
+ */
+
+static int get_airtime_policy_update_timeout(struct hostapd_iface *iface,
+ unsigned int *sec,
+ unsigned int *usec)
+{
+ unsigned int update_int = iface->conf->airtime_update_interval;
+
+ if (!update_int) {
+ wpa_printf(MSG_ERROR,
+ "Airtime policy: Invalid airtime policy update interval %u",
+ update_int);
+ return -1;
+ }
+
+ *sec = update_int / 1000;
+ *usec = (update_int % 1000) * 1000;
+
+ return 0;
+}
+
+
+static void set_new_backlog_time(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct os_reltime *now)
+{
+ sta->backlogged_until = *now;
+ sta->backlogged_until.usec += hapd->iconf->airtime_update_interval *
+ AIRTIME_BACKLOG_EXPIRY_FACTOR;
+ while (sta->backlogged_until.usec >= 1000000) {
+ sta->backlogged_until.sec++;
+ sta->backlogged_until.usec -= 1000000;
+ }
+}
+
+
+static void count_backlogged_sta(struct hostapd_data *hapd)
+{
+ struct sta_info *sta;
+ struct hostap_sta_driver_data data = {};
+ unsigned int num_backlogged = 0;
+ struct os_reltime now;
+
+ os_get_reltime(&now);
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (hostapd_drv_read_sta_data(hapd, &data, sta->addr))
+ continue;
+
+ if (data.backlog_bytes > 0)
+ set_new_backlog_time(hapd, sta, &now);
+ if (os_reltime_before(&now, &sta->backlogged_until))
+ num_backlogged++;
+ }
+ hapd->num_backlogged_sta = num_backlogged;
+}
+
+
+static int sta_set_airtime_weight(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ unsigned int weight)
+{
+ int ret = 0;
+
+ if (weight != sta->airtime_weight &&
+ (ret = hostapd_sta_set_airtime_weight(hapd, sta->addr, weight)))
+ return ret;
+
+ sta->airtime_weight = weight;
+ return ret;
+}
+
+
+static void set_sta_weights(struct hostapd_data *hapd, unsigned int weight)
+{
+ struct sta_info *sta;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next)
+ sta_set_airtime_weight(hapd, sta, weight);
+}
+
+
+static unsigned int get_airtime_quantum(unsigned int max_wt)
+{
+ unsigned int quantum = AIRTIME_QUANTUM_TARGET / max_wt;
+
+ if (quantum < AIRTIME_QUANTUM_MIN)
+ quantum = AIRTIME_QUANTUM_MIN;
+ else if (quantum > AIRTIME_QUANTUM_MAX)
+ quantum = AIRTIME_QUANTUM_MAX;
+
+ return quantum;
+}
+
+
+static void update_airtime_weights(void *eloop_data, void *user_data)
+{
+ struct hostapd_iface *iface = eloop_data;
+ struct hostapd_data *bss;
+ unsigned int sec, usec;
+ unsigned int num_sta_min = 0, num_sta_prod = 1, num_sta_sum = 0,
+ wt_sum = 0;
+ unsigned int quantum;
+ bool all_div_min = true;
+ bool apply_limit = iface->conf->airtime_mode == AIRTIME_MODE_DYNAMIC;
+ int wt, num_bss = 0, max_wt = 0;
+ size_t i;
+
+ for (i = 0; i < iface->num_bss; i++) {
+ bss = iface->bss[i];
+ if (!bss->started || !bss->conf->airtime_weight)
+ continue;
+
+ count_backlogged_sta(bss);
+ if (!bss->num_backlogged_sta)
+ continue;
+
+ if (!num_sta_min || bss->num_backlogged_sta < num_sta_min)
+ num_sta_min = bss->num_backlogged_sta;
+
+ num_sta_prod *= bss->num_backlogged_sta;
+ num_sta_sum += bss->num_backlogged_sta;
+ wt_sum += bss->conf->airtime_weight;
+ num_bss++;
+ }
+
+ if (num_sta_min) {
+ for (i = 0; i < iface->num_bss; i++) {
+ bss = iface->bss[i];
+ if (!bss->started || !bss->conf->airtime_weight)
+ continue;
+
+ /* Check if we can divide all sta numbers by the
+ * smallest number to keep weights as small as possible.
+ * This is a lazy way to avoid having to factor
+ * integers. */
+ if (bss->num_backlogged_sta &&
+ bss->num_backlogged_sta % num_sta_min > 0)
+ all_div_min = false;
+
+ /* If we're in LIMIT mode, we only apply the weight
+ * scaling when the BSS(es) marked as limited would a
+ * larger share than the relative BSS weights indicates
+ * it should. */
+ if (!apply_limit && bss->conf->airtime_limit) {
+ if (bss->num_backlogged_sta * wt_sum >
+ bss->conf->airtime_weight * num_sta_sum)
+ apply_limit = true;
+ }
+ }
+ if (all_div_min)
+ num_sta_prod /= num_sta_min;
+ }
+
+ for (i = 0; i < iface->num_bss; i++) {
+ bss = iface->bss[i];
+ if (!bss->started || !bss->conf->airtime_weight)
+ continue;
+
+ /* We only set the calculated weight if the BSS has active
+ * stations and there are other active interfaces as well -
+ * otherwise we just set a unit weight. This ensures that
+ * the weights are set reasonably when stations transition from
+ * inactive to active. */
+ if (apply_limit && bss->num_backlogged_sta && num_bss > 1)
+ wt = bss->conf->airtime_weight * num_sta_prod /
+ bss->num_backlogged_sta;
+ else
+ wt = 1;
+
+ bss->airtime_weight = wt;
+ if (wt > max_wt)
+ max_wt = wt;
+ }
+
+ quantum = get_airtime_quantum(max_wt);
+
+ for (i = 0; i < iface->num_bss; i++) {
+ bss = iface->bss[i];
+ if (!bss->started || !bss->conf->airtime_weight)
+ continue;
+ set_sta_weights(bss, bss->airtime_weight * quantum);
+ }
+
+ if (get_airtime_policy_update_timeout(iface, &sec, &usec) < 0)
+ return;
+
+ eloop_register_timeout(sec, usec, update_airtime_weights, iface,
+ NULL);
+}
+
+
+static int get_weight_for_sta(struct hostapd_data *hapd, const u8 *sta)
+{
+ struct airtime_sta_weight *wt;
+
+ wt = hapd->conf->airtime_weight_list;
+ while (wt && os_memcmp(wt->addr, sta, ETH_ALEN) != 0)
+ wt = wt->next;
+
+ return wt ? wt->weight : hapd->conf->airtime_weight;
+}
+
+
+int airtime_policy_new_sta(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ unsigned int weight;
+
+ if (hapd->iconf->airtime_mode == AIRTIME_MODE_STATIC) {
+ weight = get_weight_for_sta(hapd, sta->addr);
+ if (weight)
+ return sta_set_airtime_weight(hapd, sta, weight);
+ }
+ return 0;
+}
+
+
+int airtime_policy_update_init(struct hostapd_iface *iface)
+{
+ unsigned int sec, usec;
+
+ if (iface->conf->airtime_mode < AIRTIME_MODE_DYNAMIC)
+ return 0;
+
+ if (get_airtime_policy_update_timeout(iface, &sec, &usec) < 0)
+ return -1;
+
+ eloop_register_timeout(sec, usec, update_airtime_weights, iface, NULL);
+ return 0;
+}
+
+
+void airtime_policy_update_deinit(struct hostapd_iface *iface)
+{
+ eloop_cancel_timeout(update_airtime_weights, iface, NULL);
+}
diff --git a/src/ap/airtime_policy.h b/src/ap/airtime_policy.h
new file mode 100644
index 0000000..c2a9b00
--- /dev/null
+++ b/src/ap/airtime_policy.h
@@ -0,0 +1,48 @@
+/*
+ * Airtime policy configuration
+ * Copyright (c) 2018-2019, Toke Høiland-Jørgensen <toke@toke.dk>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AIRTIME_POLICY_H
+#define AIRTIME_POLICY_H
+
+struct hostapd_iface;
+
+#ifdef CONFIG_AIRTIME_POLICY
+
+#define AIRTIME_DEFAULT_UPDATE_INTERVAL 200 /* ms */
+#define AIRTIME_BACKLOG_EXPIRY_FACTOR 2500 /* 2.5 intervals + convert to usec */
+
+/* scale quantum so this becomes the effective quantum after applying the max
+ * weight, but never go below min or above max */
+#define AIRTIME_QUANTUM_MIN 8 /* usec */
+#define AIRTIME_QUANTUM_MAX 256 /* usec */
+#define AIRTIME_QUANTUM_TARGET 1024 /* usec */
+
+int airtime_policy_new_sta(struct hostapd_data *hapd, struct sta_info *sta);
+int airtime_policy_update_init(struct hostapd_iface *iface);
+void airtime_policy_update_deinit(struct hostapd_iface *iface);
+
+#else /* CONFIG_AIRTIME_POLICY */
+
+static inline int airtime_policy_new_sta(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ return -1;
+}
+
+static inline int airtime_policy_update_init(struct hostapd_iface *iface)
+{
+ return -1;
+}
+
+static inline void airtime_policy_update_deinit(struct hostapd_iface *iface)
+{
+}
+
+#endif /* CONFIG_AIRTIME_POLICY */
+
+#endif /* AIRTIME_POLICY_H */
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index e640e99..35a32a1 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -13,12 +13,15 @@
#include "crypto/tls.h"
#include "radius/radius_client.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_1x_defs.h"
#include "common/eapol_common.h"
#include "common/dhcp.h"
+#include "common/sae.h"
#include "eap_common/eap_wsc_common.h"
#include "eap_server/eap.h"
#include "wpa_auth.h"
#include "sta_info.h"
+#include "airtime_policy.h"
#include "ap_config.h"
@@ -51,23 +54,33 @@
bss->logger_syslog = (unsigned int) -1;
bss->logger_stdout = (unsigned int) -1;
+#ifdef CONFIG_WEP
bss->auth_algs = WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED;
bss->wep_rekeying_period = 300;
/* use key0 in individual key and key1 in broadcast key */
bss->broadcast_key_idx_min = 1;
bss->broadcast_key_idx_max = 2;
+#else /* CONFIG_WEP */
+ bss->auth_algs = WPA_AUTH_ALG_OPEN;
+#endif /* CONFIG_WEP */
bss->eap_reauth_period = 3600;
bss->wpa_group_rekey = 600;
bss->wpa_gmk_rekey = 86400;
+ bss->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS;
bss->wpa_group_update_count = 4;
bss->wpa_pairwise_update_count = 4;
bss->wpa_disable_eapol_key_retries =
DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES;
bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+#ifdef CONFIG_NO_TKIP
+ bss->wpa_pairwise = WPA_CIPHER_CCMP;
+ bss->wpa_group = WPA_CIPHER_CCMP;
+#else /* CONFIG_NO_TKIP */
bss->wpa_pairwise = WPA_CIPHER_TKIP;
bss->wpa_group = WPA_CIPHER_TKIP;
+#endif /* CONFIG_NO_TKIP */
bss->rsn_pairwise = 0;
bss->max_num_sta = MAX_STA_COUNT;
@@ -76,6 +89,7 @@
bss->radius_server_auth_port = 1812;
bss->eap_sim_db_timeout = 1;
+ bss->eap_sim_id = 3;
bss->ap_max_inactivity = AP_MAX_INACTIVITY;
bss->eapol_version = EAPOL_VERSION;
@@ -83,11 +97,9 @@
bss->pwd_group = 19; /* ECC: GF(p=256) */
-#ifdef CONFIG_IEEE80211W
bss->assoc_sa_query_max_timeout = 1000;
bss->assoc_sa_query_retry_timeout = 201;
bss->group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC;
-#endif /* CONFIG_IEEE80211W */
#ifdef EAP_SERVER_FAST
/* both anonymous and authenticated provisioning */
bss->eap_fast_prov = 3;
@@ -132,12 +144,20 @@
* completed and tested with other implementations. */
bss->tls_flags = TLS_CONN_DISABLE_TLSv1_3;
+ bss->max_auth_rounds = 100;
+ bss->max_auth_rounds_short = 50;
+
bss->send_probe_response = 1;
#ifdef CONFIG_HS20
bss->hs20_release = (HS20_VERSION >> 4) + 1;
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MACSEC
+ bss->mka_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
+ bss->macsec_port = 1;
+#endif /* CONFIG_MACSEC */
+
/* Default to strict CRL checking. */
bss->check_crl_strict = 1;
}
@@ -236,6 +256,16 @@
conf->acs_num_scans = 5;
#endif /* CONFIG_ACS */
+#ifdef CONFIG_IEEE80211AX
+ conf->he_op.he_rts_threshold = HE_OPERATION_RTS_THRESHOLD_MASK >>
+ HE_OPERATION_RTS_THRESHOLD_OFFSET;
+ /* Set default basic MCS/NSS set to single stream MCS 0-7 */
+ conf->he_op.he_basic_mcs_nss_set = 0xfffc;
+ conf->he_op.he_bss_color_disabled = 1;
+ conf->he_op.he_bss_color_partial = 0;
+ conf->he_op.he_bss_color = 1;
+#endif /* CONFIG_IEEE80211AX */
+
/* The third octet of the country string uses an ASCII space character
* by default to indicate that the regulations encompass all
* environments for the current frequency band in the country. */
@@ -244,6 +274,10 @@
conf->rssi_reject_assoc_rssi = 0;
conf->rssi_reject_assoc_timeout = 30;
+#ifdef CONFIG_AIRTIME_POLICY
+ conf->airtime_update_interval = AIRTIME_DEFAULT_UPDATE_INTERVAL;
+#endif /* CONFIG_AIRTIME_POLICY */
+
return conf;
}
@@ -280,6 +314,7 @@
while (fgets(buf, sizeof(buf), f)) {
int vlan_id = 0;
+ int wps = 0;
line++;
@@ -310,6 +345,8 @@
value = "";
if (!os_strcmp(name, "keyid")) {
keyid = value;
+ } else if (!os_strcmp(name, "wps")) {
+ wps = atoi(value);
} else if (!os_strcmp(name, "vlanid")) {
vlan_id = atoi(value);
} else {
@@ -327,8 +364,9 @@
if (!token)
token = "";
if (hwaddr_aton(token, addr)) {
- wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on "
- "line %d in '%s'", token, line, fname);
+ wpa_printf(MSG_ERROR,
+ "Invalid MAC address '%s' on line %d in '%s'",
+ token, line, fname);
ret = -1;
break;
}
@@ -356,16 +394,17 @@
ok = 0;
len = os_strlen(pos);
- if (len == 64 && hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
+ if (len == 2 * PMK_LEN &&
+ hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
ok = 1;
- else if (len >= 8 && len < 64) {
- pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
- 4096, psk->psk, PMK_LEN);
+ else if (len >= 8 && len < 64 &&
+ pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
+ 4096, psk->psk, PMK_LEN) == 0)
ok = 1;
- }
if (!ok) {
- wpa_printf(MSG_ERROR, "Invalid PSK '%s' on line %d in "
- "'%s'", pos, line, fname);
+ wpa_printf(MSG_ERROR,
+ "Invalid PSK '%s' on line %d in '%s'",
+ pos, line, fname);
os_free(psk);
ret = -1;
break;
@@ -383,6 +422,8 @@
}
}
+ psk->wps = wps;
+
psk->next = ssid->wpa_psk;
ssid->wpa_psk = psk;
}
@@ -414,10 +455,52 @@
}
+int hostapd_setup_sae_pt(struct hostapd_bss_config *conf)
+{
+#ifdef CONFIG_SAE
+ struct hostapd_ssid *ssid = &conf->ssid;
+ struct sae_password_entry *pw;
+
+ if ((conf->sae_pwe == 0 && !hostapd_sae_pw_id_in_use(conf)) ||
+ conf->sae_pwe == 3 ||
+ !wpa_key_mgmt_sae(conf->wpa_key_mgmt))
+ return 0; /* PT not needed */
+
+ sae_deinit_pt(ssid->pt);
+ ssid->pt = NULL;
+ if (ssid->wpa_passphrase) {
+ ssid->pt = sae_derive_pt(conf->sae_groups, ssid->ssid,
+ ssid->ssid_len,
+ (const u8 *) ssid->wpa_passphrase,
+ os_strlen(ssid->wpa_passphrase),
+ NULL);
+ if (!ssid->pt)
+ return -1;
+ }
+
+ for (pw = conf->sae_passwords; pw; pw = pw->next) {
+ sae_deinit_pt(pw->pt);
+ pw->pt = sae_derive_pt(conf->sae_groups, ssid->ssid,
+ ssid->ssid_len,
+ (const u8 *) pw->password,
+ os_strlen(pw->password),
+ pw->identifier);
+ if (!pw->pt)
+ return -1;
+ }
+#endif /* CONFIG_SAE */
+
+ return 0;
+}
+
+
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
{
struct hostapd_ssid *ssid = &conf->ssid;
+ if (hostapd_setup_sae_pt(conf) < 0)
+ return -1;
+
if (ssid->wpa_passphrase != NULL) {
if (ssid->wpa_psk != NULL) {
wpa_printf(MSG_DEBUG, "Using pre-configured WPA PSK "
@@ -458,7 +541,76 @@
}
-static void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
+struct hostapd_radius_attr * hostapd_parse_radius_attr(const char *value)
+{
+ const char *pos;
+ char syntax;
+ struct hostapd_radius_attr *attr;
+ size_t len;
+
+ attr = os_zalloc(sizeof(*attr));
+ if (!attr)
+ return NULL;
+
+ attr->type = atoi(value);
+
+ pos = os_strchr(value, ':');
+ if (!pos) {
+ attr->val = wpabuf_alloc(1);
+ if (!attr->val) {
+ os_free(attr);
+ return NULL;
+ }
+ wpabuf_put_u8(attr->val, 0);
+ return attr;
+ }
+
+ pos++;
+ if (pos[0] == '\0' || pos[1] != ':') {
+ os_free(attr);
+ return NULL;
+ }
+ syntax = *pos++;
+ pos++;
+
+ switch (syntax) {
+ case 's':
+ attr->val = wpabuf_alloc_copy(pos, os_strlen(pos));
+ break;
+ case 'x':
+ len = os_strlen(pos);
+ if (len & 1)
+ break;
+ len /= 2;
+ attr->val = wpabuf_alloc(len);
+ if (!attr->val)
+ break;
+ if (hexstr2bin(pos, wpabuf_put(attr->val, len), len) < 0) {
+ wpabuf_free(attr->val);
+ os_free(attr);
+ return NULL;
+ }
+ break;
+ case 'd':
+ attr->val = wpabuf_alloc(4);
+ if (attr->val)
+ wpabuf_put_be32(attr->val, atoi(pos));
+ break;
+ default:
+ os_free(attr);
+ return NULL;
+ }
+
+ if (!attr->val) {
+ os_free(attr);
+ return NULL;
+ }
+
+ return attr;
+}
+
+
+void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
{
struct hostapd_radius_attr *prev;
@@ -493,6 +645,7 @@
}
+#ifdef CONFIG_WEP
static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
{
int i;
@@ -501,6 +654,7 @@
keys->key[i] = NULL;
}
}
+#endif /* CONFIG_WEP */
void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l)
@@ -554,13 +708,34 @@
pw = pw->next;
str_clear_free(tmp->password);
os_free(tmp->identifier);
+#ifdef CONFIG_SAE
+ sae_deinit_pt(tmp->pt);
+#endif /* CONFIG_SAE */
os_free(tmp);
}
}
+#ifdef CONFIG_DPP2
+static void hostapd_dpp_controller_conf_free(struct dpp_controller_conf *conf)
+{
+ struct dpp_controller_conf *prev;
+
+ while (conf) {
+ prev = conf;
+ conf = conf->next;
+ os_free(prev);
+ }
+}
+#endif /* CONFIG_DPP2 */
+
+
void hostapd_config_free_bss(struct hostapd_bss_config *conf)
{
+#if defined(CONFIG_WPS) || defined(CONFIG_HS20)
+ size_t i;
+#endif
+
if (conf == NULL)
return;
@@ -568,10 +743,15 @@
str_clear_free(conf->ssid.wpa_passphrase);
os_free(conf->ssid.wpa_psk_file);
+#ifdef CONFIG_WEP
hostapd_config_free_wep(&conf->ssid.wep);
+#endif /* CONFIG_WEP */
#ifdef CONFIG_FULL_DYNAMIC_VLAN
os_free(conf->ssid.vlan_tagged_interface);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+#ifdef CONFIG_SAE
+ sae_deinit_pt(conf->ssid.pt);
+#endif /* CONFIG_SAE */
hostapd_config_free_eap_users(conf->eap_user);
os_free(conf->eap_user_sqlite);
@@ -589,12 +769,16 @@
}
hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
+ os_free(conf->radius_req_attr_sqlite);
os_free(conf->rsn_preauth_interfaces);
os_free(conf->ctrl_interface);
os_free(conf->ca_cert);
os_free(conf->server_cert);
+ os_free(conf->server_cert2);
os_free(conf->private_key);
+ os_free(conf->private_key2);
os_free(conf->private_key_passwd);
+ os_free(conf->private_key_passwd2);
os_free(conf->check_cert_subject);
os_free(conf->ocsp_stapling_response);
os_free(conf->ocsp_stapling_response_multi);
@@ -653,12 +837,9 @@
os_free(conf->model_description);
os_free(conf->model_url);
os_free(conf->upc);
- {
- unsigned int i;
-
- for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
- wpabuf_free(conf->wps_vendor_ext[i]);
- }
+ for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
+ wpabuf_free(conf->wps_vendor_ext[i]);
+ wpabuf_free(conf->wps_application_ext);
wpabuf_free(conf->wps_nfc_dh_pubkey);
wpabuf_free(conf->wps_nfc_dh_privkey);
wpabuf_free(conf->wps_nfc_dev_pw);
@@ -684,7 +865,6 @@
os_free(conf->hs20_operating_class);
os_free(conf->hs20_icons);
if (conf->hs20_osu_providers) {
- size_t i;
for (i = 0; i < conf->hs20_osu_providers_count; i++) {
struct hs20_osu_provider *p;
size_t j;
@@ -702,8 +882,6 @@
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);
@@ -729,6 +907,12 @@
#ifdef CONFIG_TESTING_OPTIONS
wpabuf_free(conf->own_ie_override);
wpabuf_free(conf->sae_commit_override);
+ wpabuf_free(conf->rsne_override_eapol);
+ wpabuf_free(conf->rsnxe_override_eapol);
+ wpabuf_free(conf->rsne_override_ft);
+ wpabuf_free(conf->rsnxe_override_ft);
+ wpabuf_free(conf->gtk_rsc_override);
+ wpabuf_free(conf->igtk_rsc_override);
#endif /* CONFIG_TESTING_OPTIONS */
os_free(conf->no_probe_resp_if_seen_on);
@@ -737,13 +921,32 @@
hostapd_config_free_fils_realms(conf);
#ifdef CONFIG_DPP
+ os_free(conf->dpp_name);
+ os_free(conf->dpp_mud_url);
os_free(conf->dpp_connector);
wpabuf_free(conf->dpp_netaccesskey);
wpabuf_free(conf->dpp_csign);
+#ifdef CONFIG_DPP2
+ hostapd_dpp_controller_conf_free(conf->dpp_controller);
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
hostapd_config_free_sae_passwords(conf);
+#ifdef CONFIG_AIRTIME_POLICY
+ {
+ struct airtime_sta_weight *wt, *wt_prev;
+
+ wt = conf->airtime_weight_list;
+ conf->airtime_weight_list = NULL;
+ while (wt) {
+ wt_prev = wt;
+ wt = wt->next;
+ os_free(wt_prev);
+ }
+ }
+#endif /* CONFIG_AIRTIME_POLICY */
+
os_free(conf);
}
@@ -765,6 +968,7 @@
os_free(conf->supported_rates);
os_free(conf->basic_rates);
os_free(conf->acs_ch_list.range);
+ os_free(conf->acs_freq_list.range);
os_free(conf->driver_params);
#ifdef CONFIG_ACS
os_free(conf->acs_chan_bias);
@@ -918,6 +1122,7 @@
return -1;
}
+#ifdef CONFIG_WEP
if (bss->wpa) {
int wep, i;
@@ -935,6 +1140,7 @@
return -1;
}
}
+#endif /* CONFIG_WEP */
if (full_config && bss->wpa &&
bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
@@ -982,7 +1188,6 @@
}
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211N
if (full_config && conf->ieee80211n &&
conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
bss->disable_11n = 1;
@@ -990,12 +1195,14 @@
"allowed, disabling HT capabilities");
}
+#ifdef CONFIG_WEP
if (full_config && conf->ieee80211n &&
bss->ssid.security_policy == SECURITY_STATIC_WEP) {
bss->disable_11n = 1;
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
"allowed, disabling HT capabilities");
}
+#endif /* CONFIG_WEP */
if (full_config && conf->ieee80211n && bss->wpa &&
!(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
@@ -1007,15 +1214,16 @@
"requires CCMP/GCMP to be enabled, disabling HT "
"capabilities");
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
+#ifdef CONFIG_WEP
if (full_config && conf->ieee80211ac &&
bss->ssid.security_policy == SECURITY_STATIC_WEP) {
bss->disable_11ac = 1;
wpa_printf(MSG_ERROR,
"VHT (IEEE 802.11ac) with WEP is not allowed, disabling VHT capabilities");
}
+#endif /* CONFIG_WEP */
if (full_config && conf->ieee80211ac && bss->wpa &&
!(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
@@ -1035,12 +1243,14 @@
bss->wps_state = 0;
}
+#ifdef CONFIG_WEP
if (full_config && bss->wps_state &&
bss->ssid.wep.keys_set && bss->wpa == 0) {
wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
"disabled");
bss->wps_state = 0;
}
+#endif /* CONFIG_WEP */
if (full_config && bss->wps_state && bss->wpa &&
(!(bss->wpa & 2) ||
@@ -1140,6 +1350,13 @@
return -1;
}
+#ifdef CONFIG_AIRTIME_POLICY
+ if (full_config && conf->airtime_mode > AIRTIME_MODE_STATIC &&
+ !conf->airtime_update_interval) {
+ wpa_printf(MSG_ERROR, "Airtime update interval cannot be zero");
+ return -1;
+ }
+#endif /* CONFIG_AIRTIME_POLICY */
for (i = 0; i < NUM_TX_QUEUES; i++) {
if (hostapd_config_check_cw(conf, i))
return -1;
@@ -1157,11 +1374,13 @@
void hostapd_set_security_params(struct hostapd_bss_config *bss,
int full_config)
{
+#ifdef CONFIG_WEP
if (bss->individual_wep_key_len == 0) {
/* individual keys are not use; can use key idx0 for
* broadcast keys */
bss->broadcast_key_idx_min = 0;
}
+#endif /* CONFIG_WEP */
if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
bss->rsn_pairwise = bss->wpa_pairwise;
@@ -1187,6 +1406,7 @@
} else if (bss->ieee802_1x) {
int cipher = WPA_CIPHER_NONE;
bss->ssid.security_policy = SECURITY_IEEE_802_1X;
+#ifdef CONFIG_WEP
bss->ssid.wep.default_len = bss->default_wep_key_len;
if (full_config && bss->default_wep_key_len) {
cipher = bss->default_wep_key_len >= 13 ?
@@ -1197,11 +1417,13 @@
else
cipher = WPA_CIPHER_WEP40;
}
+#endif /* CONFIG_WEP */
bss->wpa_group = cipher;
bss->wpa_pairwise = cipher;
bss->rsn_pairwise = cipher;
if (full_config)
bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
+#ifdef CONFIG_WEP
} else if (bss->ssid.wep.keys_set) {
int cipher = WPA_CIPHER_WEP40;
if (bss->ssid.wep.len[0] >= 13)
@@ -1212,6 +1434,7 @@
bss->rsn_pairwise = cipher;
if (full_config)
bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE;
+#endif /* CONFIG_WEP */
} else if (bss->osen) {
bss->ssid.security_policy = SECURITY_OSEN;
bss->wpa_group = WPA_CIPHER_CCMP;
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 509677a..cffa636 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -15,6 +15,7 @@
#include "common/wpa_common.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "crypto/sha256.h"
#include "wps/wps.h"
#include "fst/fst.h"
#include "vlan.h"
@@ -66,6 +67,7 @@
struct ft_remote_r0kh;
struct ft_remote_r1kh;
+#ifdef CONFIG_WEP
#define NUM_WEP_KEYS 4
struct hostapd_wep_keys {
u8 idx;
@@ -74,10 +76,13 @@
int keys_set;
size_t default_len; /* key length used for dynamic key generation */
};
+#endif /* CONFIG_WEP */
typedef enum hostap_security_policy {
SECURITY_PLAINTEXT = 0,
+#ifdef CONFIG_WEP
SECURITY_STATIC_WEP = 1,
+#endif /* CONFIG_WEP */
SECURITY_IEEE_802_1X = 2,
SECURITY_WPA_PSK = 3,
SECURITY_WPA = 4,
@@ -87,6 +92,7 @@
struct hostapd_ssid {
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
+ u32 short_ssid;
unsigned int ssid_set:1;
unsigned int utf8_ssid:1;
unsigned int wpa_passphrase_set:1;
@@ -98,8 +104,11 @@
struct hostapd_wpa_psk *wpa_psk;
char *wpa_passphrase;
char *wpa_psk_file;
+ struct sae_pt *pt;
+#ifdef CONFIG_WEP
struct hostapd_wep_keys wep;
+#endif /* CONFIG_WEP */
#define DYNAMIC_VLAN_DISABLED 0
#define DYNAMIC_VLAN_OPTIONAL 1
@@ -149,6 +158,7 @@
struct hostapd_wpa_psk *next;
int group;
char keyid[KEYID_LEN];
+ int wps;
u8 psk[PMK_LEN];
u8 addr[ETH_ALEN];
u8 p2p_dev_addr[ETH_ALEN];
@@ -250,6 +260,19 @@
char *identifier;
u8 peer_addr[ETH_ALEN];
int vlan_id;
+ struct sae_pt *pt;
+};
+
+struct dpp_controller_conf {
+ struct dpp_controller_conf *next;
+ u8 pkhash[SHA256_MAC_LEN];
+ struct hostapd_ip_addr ipaddr;
+};
+
+struct airtime_sta_weight {
+ struct airtime_sta_weight *next;
+ unsigned int weight;
+ u8 addr[ETH_ALEN];
};
/**
@@ -288,6 +311,7 @@
int radius_request_cui;
struct hostapd_radius_attr *radius_auth_req_attr;
struct hostapd_radius_attr *radius_acct_req_attr;
+ char *radius_req_attr_sqlite;
int radius_das_port;
unsigned int radius_das_time_window;
int radius_das_require_event_timestamp;
@@ -303,18 +327,16 @@
size_t eap_req_id_text_len;
int eapol_key_index_workaround;
+#ifdef CONFIG_WEP
size_t default_wep_key_len;
int individual_wep_key_len;
int wep_rekeying_period;
int broadcast_key_idx_min, broadcast_key_idx_max;
+#endif /* CONFIG_WEP */
int eap_reauth_period;
int erp_send_reauth_start;
char *erp_domain;
- int ieee802_11f; /* use IEEE 802.11f (IAPP) */
- char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
- * frames */
-
enum macaddr_acl {
ACCEPT_UNLESS_DENIED = 0,
DENY_UNLESS_ACCEPTED = 1,
@@ -332,15 +354,15 @@
* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
+ int extended_key_id;
int wpa_key_mgmt;
-#ifdef CONFIG_IEEE80211W
enum mfp_options ieee80211w;
int group_mgmt_cipher;
+ int beacon_prot;
/* dot11AssociationSAQueryMaximumTimeout (in TUs) */
unsigned int assoc_sa_query_max_timeout;
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
int assoc_sa_query_retry_timeout;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
int ocv; /* Operating Channel Validation */
#endif /* CONFIG_OCV */
@@ -357,6 +379,7 @@
int wpa_strict_rekey;
int wpa_gmk_rekey;
int wpa_ptk_rekey;
+ enum ptk0_rekey_handling wpa_deny_ptk0_rekey;
u32 wpa_group_update_count;
u32 wpa_pairwise_update_count;
int wpa_disable_eapol_key_retries;
@@ -390,14 +413,19 @@
char *ca_cert;
char *server_cert;
+ char *server_cert2;
char *private_key;
+ char *private_key2;
char *private_key_passwd;
+ char *private_key_passwd2;
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;
+ unsigned int max_auth_rounds;
+ unsigned int max_auth_rounds_short;
char *ocsp_stapling_response;
char *ocsp_stapling_response_multi;
char *dh_file;
@@ -410,7 +438,12 @@
int eap_fast_prov;
int pac_key_lifetime;
int pac_key_refresh_time;
+ int eap_teap_auth;
+ int eap_teap_pac_no_inner;
+ int eap_teap_separate_result;
+ int eap_teap_id;
int eap_sim_aka_result_ind;
+ int eap_sim_id;
int tnc;
int fragment_size;
u16 pwd_group;
@@ -477,6 +510,7 @@
char *model_url;
char *upc;
struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+ struct wpabuf *wps_application_ext;
int wps_nfc_pw_from_config;
int wps_nfc_dev_pw_id;
struct wpabuf *wps_nfc_dh_pubkey;
@@ -570,6 +604,7 @@
int osen;
int proxy_arp;
int na_mcast_to_ucast;
+
#ifdef CONFIG_HS20
int hs20;
int hs20_release;
@@ -630,6 +665,8 @@
unsigned int sae_anti_clogging_threshold;
unsigned int sae_sync;
int sae_require_mfp;
+ int sae_confirm_immediate;
+ int sae_pwe;
int *sae_groups;
struct sae_password_entry *sae_passwords;
@@ -641,6 +678,15 @@
struct wpabuf *own_ie_override;
int sae_reflection_attack;
struct wpabuf *sae_commit_override;
+ struct wpabuf *rsne_override_eapol;
+ struct wpabuf *rsnxe_override_eapol;
+ struct wpabuf *rsne_override_ft;
+ struct wpabuf *rsnxe_override_ft;
+ struct wpabuf *gtk_rsc_override;
+ struct wpabuf *igtk_rsc_override;
+ int no_beacon_rsnxe;
+ int skip_prune_assoc;
+ int ft_rsnxe_used;
#endif /* CONFIG_TESTING_OPTIONS */
#define MESH_ENABLED BIT(0)
@@ -688,10 +734,17 @@
int broadcast_deauth;
#ifdef CONFIG_DPP
+ char *dpp_name;
+ char *dpp_mud_url;
char *dpp_connector;
struct wpabuf *dpp_netaccesskey;
unsigned int dpp_netaccesskey_expiry;
struct wpabuf *dpp_csign;
+#ifdef CONFIG_DPP2
+ struct dpp_controller_conf *dpp_controller;
+ int dpp_configurator_connectivity;
+ int dpp_pfs;
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
#ifdef CONFIG_OWE
@@ -700,24 +753,121 @@
size_t owe_transition_ssid_len;
char owe_transition_ifname[IFNAMSIZ + 1];
int *owe_groups;
+ int owe_ptk_workaround;
#endif /* CONFIG_OWE */
int coloc_intf_reporting;
u8 send_probe_response;
+ u8 transition_disable;
+
#define BACKHAUL_BSS 1
#define FRONTHAUL_BSS 2
int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */
+
+#ifdef CONFIG_AIRTIME_POLICY
+ unsigned int airtime_weight;
+ int airtime_limit;
+ struct airtime_sta_weight *airtime_weight_list;
+#endif /* CONFIG_AIRTIME_POLICY */
+
+#ifdef CONFIG_MACSEC
+ /**
+ * macsec_policy - Determines the policy for MACsec secure session
+ *
+ * 0: MACsec not in use (default)
+ * 1: MACsec enabled - Should secure, accept key server's advice to
+ * determine whether to use a secure session or not.
+ */
+ int macsec_policy;
+
+ /**
+ * macsec_integ_only - Determines how MACsec are transmitted
+ *
+ * This setting applies only when MACsec is in use, i.e.,
+ * - macsec_policy is enabled
+ * - the key server has decided to enable MACsec
+ *
+ * 0: Encrypt traffic (default)
+ * 1: Integrity only
+ */
+ 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.
+ *
+ * Range: 1-65534 (default: 1)
+ */
+ int macsec_port;
+
+ /**
+ * mka_priority - Priority of MKA Actor
+ *
+ * Range: 0-255 (default: 255)
+ */
+ int mka_priority;
+
+ /**
+ * mka_ckn - MKA pre-shared CKN
+ */
+#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_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)
+#define MKA_PSK_SET (MKA_PSK_SET_CKN | MKA_PSK_SET_CAK)
+ /**
+ * mka_psk_set - Whether mka_ckn and mka_cak are set
+ */
+ u8 mka_psk_set;
+#endif /* CONFIG_MACSEC */
};
/**
* struct he_phy_capabilities_info - HE PHY capabilities
*/
struct he_phy_capabilities_info {
- Boolean he_su_beamformer;
- Boolean he_su_beamformee;
- Boolean he_mu_beamformer;
+ bool he_su_beamformer;
+ bool he_su_beamformee;
+ bool he_mu_beamformer;
};
/**
@@ -725,9 +875,24 @@
*/
struct he_operation {
u8 he_bss_color;
+ u8 he_bss_color_disabled;
+ u8 he_bss_color_partial;
u8 he_default_pe_duration;
u8 he_twt_required;
- u8 he_rts_threshold;
+ u16 he_rts_threshold;
+ u16 he_basic_mcs_nss_set;
+};
+
+/**
+ * struct spatial_reuse - Spatial reuse
+ */
+struct spatial_reuse {
+ u8 sr_control;
+ u8 non_srg_obss_pd_max_offset;
+ u8 srg_obss_pd_min_offset;
+ u8 srg_obss_pd_max_offset;
+ u8 srg_obss_color_bitmap;
+ u8 srg_obss_color_partial_bitmap;
};
/**
@@ -740,11 +905,17 @@
u16 beacon_int;
int rts_threshold;
int fragm_threshold;
+ u8 op_class;
u8 channel;
+ int enable_edmg;
+ u8 edmg_channel;
u8 acs;
struct wpa_freq_range_list acs_ch_list;
+ struct wpa_freq_range_list acs_freq_list;
+ u8 acs_freq_list_present;
int acs_exclude_dfs;
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
+ int acs_exclude_6ghz_non_psc;
enum {
LONG_PREAMBLE = 0,
SHORT_PREAMBLE = 1
@@ -852,6 +1023,10 @@
struct he_phy_capabilities_info he_phy_capab;
struct he_operation he_op;
struct ieee80211_he_mu_edca_parameter_set he_mu_edca;
+ struct spatial_reuse spr;
+ u8 he_oper_chwidth;
+ u8 he_oper_centr_freq_seg0_idx;
+ u8 he_oper_centr_freq_seg1_idx;
#endif /* CONFIG_IEEE80211AX */
/* VHT enable/disable config from CHAN_SWITCH */
@@ -861,12 +1036,87 @@
int rssi_reject_assoc_rssi;
int rssi_reject_assoc_timeout;
+
+#ifdef CONFIG_AIRTIME_POLICY
+ enum {
+ AIRTIME_MODE_OFF = 0,
+ AIRTIME_MODE_STATIC = 1,
+ AIRTIME_MODE_DYNAMIC = 2,
+ AIRTIME_MODE_LIMIT = 3,
+ __AIRTIME_MODE_MAX,
+ } airtime_mode;
+ unsigned int airtime_update_interval;
+#define AIRTIME_MODE_MAX (__AIRTIME_MODE_MAX - 1)
+#endif /* CONFIG_AIRTIME_POLICY */
};
+static inline u8 hostapd_get_oper_chwidth(struct hostapd_config *conf)
+{
+#ifdef CONFIG_IEEE80211AX
+ if (conf->ieee80211ax)
+ return conf->he_oper_chwidth;
+#endif /* CONFIG_IEEE80211AX */
+ return conf->vht_oper_chwidth;
+}
+
+static inline void
+hostapd_set_oper_chwidth(struct hostapd_config *conf, u8 oper_chwidth)
+{
+#ifdef CONFIG_IEEE80211AX
+ if (conf->ieee80211ax)
+ conf->he_oper_chwidth = oper_chwidth;
+#endif /* CONFIG_IEEE80211AX */
+ conf->vht_oper_chwidth = oper_chwidth;
+}
+
+static inline u8
+hostapd_get_oper_centr_freq_seg0_idx(struct hostapd_config *conf)
+{
+#ifdef CONFIG_IEEE80211AX
+ if (conf->ieee80211ax)
+ return conf->he_oper_centr_freq_seg0_idx;
+#endif /* CONFIG_IEEE80211AX */
+ return conf->vht_oper_centr_freq_seg0_idx;
+}
+
+static inline void
+hostapd_set_oper_centr_freq_seg0_idx(struct hostapd_config *conf,
+ u8 oper_centr_freq_seg0_idx)
+{
+#ifdef CONFIG_IEEE80211AX
+ if (conf->ieee80211ax)
+ conf->he_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
+#endif /* CONFIG_IEEE80211AX */
+ conf->vht_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
+}
+
+static inline u8
+hostapd_get_oper_centr_freq_seg1_idx(struct hostapd_config *conf)
+{
+#ifdef CONFIG_IEEE80211AX
+ if (conf->ieee80211ax)
+ return conf->he_oper_centr_freq_seg1_idx;
+#endif /* CONFIG_IEEE80211AX */
+ return conf->vht_oper_centr_freq_seg1_idx;
+}
+
+static inline void
+hostapd_set_oper_centr_freq_seg1_idx(struct hostapd_config *conf,
+ u8 oper_centr_freq_seg1_idx)
+{
+#ifdef CONFIG_IEEE80211AX
+ if (conf->ieee80211ax)
+ conf->he_oper_centr_freq_seg1_idx = oper_centr_freq_seg1_idx;
+#endif /* CONFIG_IEEE80211AX */
+ conf->vht_oper_centr_freq_seg1_idx = oper_centr_freq_seg1_idx;
+}
+
+
int hostapd_mac_comp(const void *a, const void *b);
struct hostapd_config * hostapd_config_defaults(void);
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
+void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr);
void hostapd_config_free_eap_user(struct hostapd_eap_user *user);
void hostapd_config_free_eap_users(struct hostapd_eap_user *user);
void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p);
@@ -885,9 +1135,11 @@
int vlan_id);
struct hostapd_radius_attr *
hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
+struct hostapd_radius_attr * hostapd_parse_radius_attr(const char *value);
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);
+int hostapd_setup_sae_pt(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 067cf86..1f284f0 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -10,6 +10,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
#include "common/hw_features_common.h"
#include "wps/wps.h"
#include "p2p/p2p.h"
@@ -107,6 +108,10 @@
goto fail;
#endif /* CONFIG_FILS */
+ pos = hostapd_eid_rsnxe(hapd, buf, sizeof(buf));
+ if (add_buf_data(&assocresp, buf, pos - buf) < 0)
+ goto fail;
+
if (add_buf(&beacon, hapd->wps_beacon_ie) < 0 ||
add_buf(&proberesp, hapd->wps_probe_resp_ie) < 0)
goto fail;
@@ -305,9 +310,7 @@
params.wpa_pairwise = hapd->conf->wpa_pairwise;
params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt;
params.rsn_preauth = hapd->conf->rsn_preauth;
-#ifdef CONFIG_IEEE80211W
params.ieee80211w = hapd->conf->ieee80211w;
-#endif /* CONFIG_IEEE80211W */
}
return hostapd_set_ieee8021x(hapd, ¶ms);
}
@@ -348,7 +351,7 @@
u16 auth_alg)
{
if (hapd->driver == NULL || hapd->driver->add_sta_node == NULL)
- return 0;
+ return -EOPNOTSUPP;
return hapd->driver->add_sta_node(hapd->drv_priv, addr, auth_alg);
}
@@ -413,6 +416,8 @@
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
+ const struct ieee80211_he_capabilities *he_capab,
+ size_t he_capab_len,
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
int set)
{
@@ -432,6 +437,8 @@
params.listen_interval = listen_interval;
params.ht_capabilities = ht_capab;
params.vht_capabilities = vht_capab;
+ params.he_capab = he_capab;
+ params.he_capab_len = he_capab_len;
params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
params.vht_opmode = vht_opmode;
params.flags = hostapd_sta_flags_to_drv(flags);
@@ -536,18 +543,23 @@
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
- int freq, int channel, int ht_enabled, int vht_enabled,
- int sec_channel_offset, int vht_oper_chwidth,
+ int freq, int channel, int edmg, u8 edmg_channel,
+ int ht_enabled, int vht_enabled,
+ int he_enabled,
+ int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1)
{
struct hostapd_freq_params data;
+ struct hostapd_hw_modes *cmode = hapd->iface->current_mode;
- if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
- vht_enabled, sec_channel_offset,
- vht_oper_chwidth,
+ if (hostapd_set_freq_params(&data, mode, freq, channel, edmg,
+ edmg_channel, ht_enabled,
+ vht_enabled, he_enabled, sec_channel_offset,
+ oper_chwidth,
center_segment0, center_segment1,
- hapd->iface->current_mode ?
- hapd->iface->current_mode->vht_capab : 0))
+ cmode ? cmode->vht_capab : 0,
+ cmode ?
+ &cmode->he_capab[IEEE80211_MODE_AP] : NULL))
return -1;
if (hapd->driver == NULL)
@@ -576,13 +588,23 @@
int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
int total_flags, int flags_or, int flags_and)
{
- if (hapd->driver == NULL || hapd->driver->sta_set_flags == NULL)
+ if (!hapd->driver || !hapd->drv_priv || !hapd->driver->sta_set_flags)
return 0;
return hapd->driver->sta_set_flags(hapd->drv_priv, addr, total_flags,
flags_or, flags_and);
}
+int hostapd_sta_set_airtime_weight(struct hostapd_data *hapd, const u8 *addr,
+ unsigned int weight)
+{
+ if (!hapd->driver || !hapd->driver->sta_set_airtime_weight)
+ return 0;
+ return hapd->driver->sta_set_airtime_weight(hapd->drv_priv, addr,
+ weight);
+}
+
+
int hostapd_set_country(struct hostapd_data *hapd, const char *country)
{
if (hapd->driver == NULL ||
@@ -658,36 +680,41 @@
int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
enum wpa_alg alg, const u8 *addr,
- int key_idx, int set_tx,
+ int key_idx, int vlan_id, int set_tx,
const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
+ const u8 *key, size_t key_len, enum key_flag key_flag)
{
+ struct wpa_driver_set_key_params params;
+
if (hapd->driver == NULL || hapd->driver->set_key == NULL)
return 0;
- return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr,
- key_idx, set_tx, seq, seq_len, key,
- key_len);
+
+ os_memset(¶ms, 0, sizeof(params));
+ params.ifname = ifname;
+ params.alg = alg;
+ params.addr = addr;
+ params.key_idx = key_idx;
+ params.set_tx = set_tx;
+ params.seq = seq;
+ params.seq_len = seq_len;
+ params.key = key;
+ params.key_len = key_len;
+ params.vlan_id = vlan_id;
+ params.key_flag = key_flag;
+
+ return hapd->driver->set_key(hapd->drv_priv, ¶ms);
}
int hostapd_drv_send_mlme(struct hostapd_data *hapd,
- const void *msg, size_t len, int noack)
+ const void *msg, size_t len, int noack,
+ const u16 *csa_offs, size_t csa_offs_len,
+ int no_encrypt)
{
if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv)
return 0;
return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
- NULL, 0);
-}
-
-
-int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
- const void *msg, size_t len, int noack,
- const u16 *csa_offs, size_t csa_offs_len)
-{
- if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
- return 0;
- return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
- csa_offs, csa_offs_len);
+ csa_offs, csa_offs_len, no_encrypt, 0);
}
@@ -775,14 +802,16 @@
int hostapd_start_dfs_cac(struct hostapd_iface *iface,
enum hostapd_hw_mode mode, int freq,
int channel, int ht_enabled, int vht_enabled,
- int sec_channel_offset, int vht_oper_chwidth,
+ int he_enabled,
+ int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1)
{
struct hostapd_data *hapd = iface->bss[0];
struct hostapd_freq_params data;
int res;
+ struct hostapd_hw_modes *cmode = iface->current_mode;
- if (!hapd->driver || !hapd->driver->start_dfs_cac)
+ if (!hapd->driver || !hapd->driver->start_dfs_cac || !cmode)
return 0;
if (!iface->conf->ieee80211h) {
@@ -791,11 +820,13 @@
return -1;
}
- if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
- vht_enabled, sec_channel_offset,
- vht_oper_chwidth, center_segment0,
+ if (hostapd_set_freq_params(&data, mode, freq, channel, 0, 0,
+ ht_enabled,
+ vht_enabled, he_enabled, sec_channel_offset,
+ oper_chwidth, center_segment0,
center_segment1,
- iface->current_mode->vht_capab)) {
+ cmode->vht_capab,
+ &cmode->he_capab[IEEE80211_MODE_AP])) {
wpa_printf(MSG_ERROR, "Can't set freq params");
return -1;
}
@@ -830,10 +861,24 @@
for (i = 0; i < mode->num_channels; i++) {
struct hostapd_channel_data *chan = &mode->channels[i];
- if ((acs_ch_list_all ||
- freq_range_list_includes(&hapd->iface->conf->acs_ch_list,
- chan->chan)) &&
- !(chan->flag & HOSTAPD_CHAN_DISABLED) &&
+ if (!acs_ch_list_all &&
+ (hapd->iface->conf->acs_freq_list.num &&
+ !freq_range_list_includes(
+ &hapd->iface->conf->acs_freq_list,
+ chan->freq)))
+ continue;
+ if (!acs_ch_list_all &&
+ (!hapd->iface->conf->acs_freq_list_present &&
+ hapd->iface->conf->acs_ch_list.num &&
+ !freq_range_list_includes(
+ &hapd->iface->conf->acs_ch_list,
+ chan->chan)))
+ continue;
+ if (is_6ghz_freq(chan->freq) &&
+ hapd->iface->conf->acs_exclude_6ghz_non_psc &&
+ !is_6ghz_psc_frequency(chan->freq))
+ continue;
+ if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
!(hapd->iface->conf->acs_exclude_dfs &&
(chan->flag & HOSTAPD_CHAN_RADAR)))
int_array_add_unique(freq_list, chan->freq);
@@ -859,10 +904,9 @@
{
struct drv_acs_params params;
int ret, i, acs_ch_list_all = 0;
- u8 *channels = NULL;
- unsigned int num_channels = 0;
struct hostapd_hw_modes *mode;
int *freq_list = NULL;
+ enum hostapd_hw_mode selected_mode;
if (hapd->driver == NULL || hapd->driver->do_acs == NULL)
return 0;
@@ -874,42 +918,27 @@
* If no chanlist config parameter is provided, include all enabled
* channels of the selected hw_mode.
*/
- if (!hapd->iface->conf->acs_ch_list.num)
- acs_ch_list_all = 1;
+ if (hapd->iface->conf->acs_freq_list_present)
+ acs_ch_list_all = !hapd->iface->conf->acs_freq_list.num;
+ else
+ acs_ch_list_all = !hapd->iface->conf->acs_ch_list.num;
- mode = hapd->iface->current_mode;
- if (mode) {
- channels = os_malloc(mode->num_channels);
- if (channels == NULL)
- return -1;
+ if (hapd->iface->current_mode)
+ selected_mode = hapd->iface->current_mode->mode;
+ else
+ selected_mode = HOSTAPD_MODE_IEEE80211ANY;
- for (i = 0; i < mode->num_channels; i++) {
- struct hostapd_channel_data *chan = &mode->channels[i];
- if (!acs_ch_list_all &&
- !freq_range_list_includes(
- &hapd->iface->conf->acs_ch_list,
- chan->chan))
- continue;
- if (hapd->iface->conf->acs_exclude_dfs &&
- (chan->flag & HOSTAPD_CHAN_RADAR))
- continue;
- if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) {
- channels[num_channels++] = chan->chan;
- int_array_add_unique(&freq_list, chan->freq);
- }
- }
- } else {
- for (i = 0; i < hapd->iface->num_hw_features; i++) {
- mode = &hapd->iface->hw_features[i];
- hostapd_get_hw_mode_any_channels(hapd, mode,
- acs_ch_list_all,
- &freq_list);
- }
+ for (i = 0; i < hapd->iface->num_hw_features; i++) {
+ mode = &hapd->iface->hw_features[i];
+ if (selected_mode != HOSTAPD_MODE_IEEE80211ANY &&
+ selected_mode != mode->mode)
+ continue;
+ hostapd_get_hw_mode_any_channels(hapd, mode, acs_ch_list_all,
+ &freq_list);
}
- params.ch_list = channels;
- params.ch_list_len = num_channels;
params.freq_list = freq_list;
+ params.edmg_enabled = hapd->iface->conf->enable_edmg;
params.ht_enabled = !!(hapd->iface->conf->ieee80211n);
params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
@@ -919,20 +948,35 @@
if (hapd->iface->conf->ieee80211n && params.ht40_enabled)
params.ch_width = 40;
- /* Note: VHT20 is defined by combination of ht_capab & vht_oper_chwidth
+ /* Note: VHT20 is defined by combination of ht_capab & oper_chwidth
*/
- if (hapd->iface->conf->ieee80211ac && params.ht40_enabled) {
- if (hapd->iface->conf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
+ if ((hapd->iface->conf->ieee80211ax ||
+ hapd->iface->conf->ieee80211ac) &&
+ params.ht40_enabled) {
+ u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iface->conf);
+
+ if (oper_chwidth == CHANWIDTH_80MHZ)
params.ch_width = 80;
- else if (hapd->iface->conf->vht_oper_chwidth ==
- VHT_CHANWIDTH_160MHZ ||
- hapd->iface->conf->vht_oper_chwidth ==
- VHT_CHANWIDTH_80P80MHZ)
+ else if (oper_chwidth == CHANWIDTH_160MHZ ||
+ oper_chwidth == CHANWIDTH_80P80MHZ)
params.ch_width = 160;
}
+ if (hapd->iface->conf->op_class)
+ params.ch_width = op_class_to_bandwidth(
+ hapd->iface->conf->op_class);
ret = hapd->driver->do_acs(hapd->drv_priv, ¶ms);
- os_free(channels);
+ os_free(freq_list);
return ret;
}
+
+
+int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
+ u16 reason_code, const u8 *ie, size_t ielen)
+{
+ if (!hapd->driver || !hapd->driver->update_dh_ie || !hapd->drv_priv)
+ return 0;
+ return hapd->driver->update_dh_ie(hapd->drv_priv, peer, reason_code,
+ ie, ielen);
+}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index de40171..56d1ad8 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -41,6 +41,8 @@
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
+ const struct ieee80211_he_capabilities *he_capab,
+ size_t he_capab_len,
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
int set);
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
@@ -60,13 +62,16 @@
const u8 *addr, int idx, u8 *seq);
int hostapd_flush(struct hostapd_data *hapd);
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
- int freq, int channel, int ht_enabled, int vht_enabled,
- int sec_channel_offset, int vht_oper_chwidth,
+ int freq, int channel, int edmg, u8 edmg_channel,
+ int ht_enabled, int vht_enabled,
+ int he_enabled, int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1);
int hostapd_set_rts(struct hostapd_data *hapd, int rts);
int hostapd_set_frag(struct hostapd_data *hapd, int frag);
int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
int total_flags, int flags_or, int flags_and);
+int hostapd_sta_set_airtime_weight(struct hostapd_data *hapd, const u8 *addr,
+ unsigned int weight);
int hostapd_set_country(struct hostapd_data *hapd, const char *country);
int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
int cw_min, int cw_max, int burst_time);
@@ -84,14 +89,13 @@
int hostapd_drv_set_key(const char *ifname,
struct hostapd_data *hapd,
enum wpa_alg alg, const u8 *addr,
- int key_idx, int set_tx,
+ int key_idx, int vlan_id, int set_tx,
const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len);
+ const u8 *key, size_t key_len, enum key_flag key_flag);
int hostapd_drv_send_mlme(struct hostapd_data *hapd,
- const void *msg, size_t len, int noack);
-int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
- const void *msg, size_t len, int noack,
- const u16 *csa_offs, size_t csa_offs_len);
+ const void *msg, size_t len, int noack,
+ const u16 *csa_offs, size_t csa_offs_len,
+ int no_encrypt);
int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
const u8 *addr, int reason);
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
@@ -122,9 +126,12 @@
int hostapd_start_dfs_cac(struct hostapd_iface *iface,
enum hostapd_hw_mode mode, int freq,
int channel, int ht_enabled, int vht_enabled,
- int sec_channel_offset, int vht_oper_chwidth,
+ int he_enabled,
+ int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1);
int hostapd_drv_do_acs(struct hostapd_data *hapd);
+int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
+ u16 reason_code, const u8 *ie, size_t ielen);
#include "drivers/driver.h"
@@ -374,4 +381,12 @@
return hapd->driver->send_external_auth_status(hapd->drv_priv, params);
}
+static inline int
+hostapd_drv_set_band(struct hostapd_data *hapd, enum set_band band)
+{
+ if (!hapd->driver || !hapd->drv_priv || !hapd->driver->set_band)
+ return -1;
+ return hapd->driver->set_band(hapd->drv_priv, band);
+}
+
#endif /* AP_DRV_OPS */
diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c
index 8bf6dde..20be7f8 100644
--- a/src/ap/ap_list.c
+++ b/src/ap/ap_list.c
@@ -228,7 +228,6 @@
set_beacon++;
}
-#ifdef CONFIG_IEEE80211N
if (!iface->olbc_ht && !ap->ht_support &&
(ap->channel == 0 ||
ap->channel == iface->conf->channel ||
@@ -241,7 +240,6 @@
MAC2STR(ap->addr), ap->channel);
set_beacon++;
}
-#endif /* CONFIG_IEEE80211N */
if (set_beacon)
ieee802_11_update_beacons(iface);
@@ -285,14 +283,12 @@
iface->olbc = 0;
set_beacon++;
}
-#ifdef CONFIG_IEEE80211N
if (!olbc_ht && iface->olbc_ht) {
wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore");
iface->olbc_ht = 0;
hostapd_ht_operation_update(iface);
set_beacon++;
}
-#endif /* CONFIG_IEEE80211N */
}
if (set_beacon)
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index eced6c7..8e12daf 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -110,25 +110,10 @@
srv.auth_port = conf->radius_server_auth_port;
srv.acct_port = conf->radius_server_acct_port;
srv.conf_ctx = hapd;
- srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
- srv.ssl_ctx = hapd->ssl_ctx;
- srv.msg_ctx = hapd->msg_ctx;
- srv.pac_opaque_encr_key = conf->pac_opaque_encr_key;
- srv.eap_fast_a_id = conf->eap_fast_a_id;
- srv.eap_fast_a_id_len = conf->eap_fast_a_id_len;
- srv.eap_fast_a_id_info = conf->eap_fast_a_id_info;
- srv.eap_fast_prov = conf->eap_fast_prov;
- srv.pac_key_lifetime = conf->pac_key_lifetime;
- srv.pac_key_refresh_time = conf->pac_key_refresh_time;
- srv.eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
- srv.tnc = conf->tnc;
- srv.wps = hapd->wps;
srv.ipv6 = conf->radius_server_ipv6;
srv.get_eap_user = hostapd_radius_get_eap_user;
srv.eap_req_id_text = conf->eap_req_id_text;
srv.eap_req_id_text_len = conf->eap_req_id_text_len;
- srv.pwd_group = conf->pwd_group;
- srv.server_id = conf->server_id ? conf->server_id : "hostapd";
srv.sqlite_file = conf->eap_user_sqlite;
#ifdef CONFIG_RADIUS_TEST
srv.dump_msk_file = conf->dump_msk_file;
@@ -139,10 +124,8 @@
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;
- srv.tls_session_lifetime = conf->tls_session_lifetime;
- srv.tls_flags = conf->tls_flags;
+ srv.eap_cfg = hapd->eap_cfg;
hapd->radius_srv = radius_server_init(&srv);
if (hapd->radius_srv == NULL) {
@@ -190,12 +173,67 @@
#endif /* EAP_TLS_FUNCS */
+static struct eap_config * authsrv_eap_config(struct hostapd_data *hapd)
+{
+ struct eap_config *cfg;
+
+ cfg = os_zalloc(sizeof(*cfg));
+ if (!cfg)
+ return NULL;
+
+ cfg->eap_server = hapd->conf->eap_server;
+ cfg->ssl_ctx = hapd->ssl_ctx;
+ cfg->msg_ctx = hapd->msg_ctx;
+ cfg->eap_sim_db_priv = hapd->eap_sim_db_priv;
+ cfg->tls_session_lifetime = hapd->conf->tls_session_lifetime;
+ cfg->tls_flags = hapd->conf->tls_flags;
+ cfg->max_auth_rounds = hapd->conf->max_auth_rounds;
+ cfg->max_auth_rounds_short = hapd->conf->max_auth_rounds_short;
+ if (hapd->conf->pac_opaque_encr_key)
+ cfg->pac_opaque_encr_key =
+ os_memdup(hapd->conf->pac_opaque_encr_key, 16);
+ if (hapd->conf->eap_fast_a_id) {
+ cfg->eap_fast_a_id = os_memdup(hapd->conf->eap_fast_a_id,
+ hapd->conf->eap_fast_a_id_len);
+ cfg->eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
+ }
+ if (hapd->conf->eap_fast_a_id_info)
+ cfg->eap_fast_a_id_info =
+ os_strdup(hapd->conf->eap_fast_a_id_info);
+ cfg->eap_fast_prov = hapd->conf->eap_fast_prov;
+ cfg->pac_key_lifetime = hapd->conf->pac_key_lifetime;
+ cfg->pac_key_refresh_time = hapd->conf->pac_key_refresh_time;
+ cfg->eap_teap_auth = hapd->conf->eap_teap_auth;
+ cfg->eap_teap_pac_no_inner = hapd->conf->eap_teap_pac_no_inner;
+ cfg->eap_teap_separate_result = hapd->conf->eap_teap_separate_result;
+ cfg->eap_teap_id = hapd->conf->eap_teap_id;
+ cfg->eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
+ cfg->eap_sim_id = hapd->conf->eap_sim_id;
+ cfg->tnc = hapd->conf->tnc;
+ cfg->wps = hapd->wps;
+ cfg->fragment_size = hapd->conf->fragment_size;
+ cfg->pwd_group = hapd->conf->pwd_group;
+ cfg->pbc_in_m1 = hapd->conf->pbc_in_m1;
+ if (hapd->conf->server_id) {
+ cfg->server_id = (u8 *) os_strdup(hapd->conf->server_id);
+ cfg->server_id_len = os_strlen(hapd->conf->server_id);
+ } else {
+ cfg->server_id = (u8 *) os_strdup("hostapd");
+ cfg->server_id_len = 7;
+ }
+ cfg->erp = hapd->conf->eap_server_erp;
+
+ return cfg;
+}
+
+
int authsrv_init(struct hostapd_data *hapd)
{
#ifdef EAP_TLS_FUNCS
if (hapd->conf->eap_server &&
(hapd->conf->ca_cert || hapd->conf->server_cert ||
- hapd->conf->private_key || hapd->conf->dh_file)) {
+ hapd->conf->private_key || hapd->conf->dh_file ||
+ hapd->conf->server_cert2 || hapd->conf->private_key2)) {
struct tls_config conf;
struct tls_connection_params params;
@@ -224,8 +262,11 @@
os_memset(¶ms, 0, sizeof(params));
params.ca_cert = hapd->conf->ca_cert;
params.client_cert = hapd->conf->server_cert;
+ params.client_cert2 = hapd->conf->server_cert2;
params.private_key = hapd->conf->private_key;
+ params.private_key2 = hapd->conf->private_key2;
params.private_key_passwd = hapd->conf->private_key_passwd;
+ params.private_key_passwd2 = hapd->conf->private_key_passwd2;
params.dh_file = hapd->conf->dh_file;
params.openssl_ciphers = hapd->conf->openssl_ciphers;
params.openssl_ecdh_curves = hapd->conf->openssl_ecdh_curves;
@@ -266,6 +307,14 @@
}
#endif /* EAP_SIM_DB */
+ hapd->eap_cfg = authsrv_eap_config(hapd);
+ if (!hapd->eap_cfg) {
+ wpa_printf(MSG_ERROR,
+ "Failed to build EAP server configuration");
+ authsrv_deinit(hapd);
+ return -1;
+ }
+
#ifdef RADIUS_SERVER
if (hapd->conf->radius_server_clients &&
hostapd_setup_radius_srv(hapd))
@@ -296,4 +345,7 @@
hapd->eap_sim_db_priv = NULL;
}
#endif /* EAP_SIM_DB */
+
+ eap_server_config_free(hapd->eap_cfg);
+ hapd->eap_cfg = NULL;
}
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 3e62991..47ced9a 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -36,27 +36,6 @@
#ifdef NEED_AP_MLME
-static u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
- size_t len)
-{
- size_t i;
-
- for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
- if (hapd->conf->radio_measurements[i])
- break;
- }
-
- if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
- return eid;
-
- *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
- *eid++ = RRM_CAPABILITIES_IE_LEN;
- os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
-
- return eid + RRM_CAPABILITIES_IE_LEN;
-}
-
-
static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len)
{
if (len < 2 + 5)
@@ -287,17 +266,101 @@
}
-static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
+static const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid)
+{
+ const u8 *ies;
+ size_t ies_len;
+
+ ies = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ies_len);
+ if (!ies)
+ return NULL;
+
+ return get_ie(ies, ies_len, eid);
+}
+
+
+static const u8 * hostapd_vendor_wpa_ie(struct hostapd_data *hapd,
+ u32 vendor_type)
+{
+ const u8 *ies;
+ size_t ies_len;
+
+ ies = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ies_len);
+ if (!ies)
+ return NULL;
+
+ return get_vendor_ie(ies, ies_len, vendor_type);
+}
+
+
+static u8 * hostapd_get_rsne(struct hostapd_data *hapd, u8 *pos, size_t len)
{
const u8 *ie;
- size_t ielen;
- ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
- if (ie == NULL || ielen > len)
- return eid;
+ ie = hostapd_wpa_ie(hapd, WLAN_EID_RSN);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
- os_memcpy(eid, ie, ielen);
- return eid + ielen;
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_mde(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+ const u8 *ie;
+
+ ie = hostapd_wpa_ie(hapd, WLAN_EID_MOBILITY_DOMAIN);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
+
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_rsnxe(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+ const u8 *ie;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->no_beacon_rsnxe) {
+ wpa_printf(MSG_INFO, "TESTING: Do not add RSNXE into Beacon");
+ return pos;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
+
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_wpa_ie(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+ const u8 *ie;
+
+ ie = hostapd_vendor_wpa_ie(hapd, WPA_IE_VENDOR_TYPE);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
+
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_osen_ie(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+ const u8 *ie;
+
+ ie = hostapd_vendor_wpa_ie(hapd, OSEN_IE_VENDOR_TYPE);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
+
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
}
@@ -347,7 +410,7 @@
if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
hapd->iconf->secondary_channel,
- hapd->iconf->vht_oper_chwidth,
+ hostapd_get_oper_chwidth(hapd->iconf),
&op_class, &channel) ==
NUM_HOSTAPD_MODES)
return eid;
@@ -398,12 +461,14 @@
if (hapd->iconf->ieee80211ax) {
buflen += 3 + sizeof(struct ieee80211_he_capabilities) +
3 + sizeof(struct ieee80211_he_operation) +
- 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set);
+ 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
+ 3 + sizeof(struct ieee80211_spatial_reuse);
}
#endif /* CONFIG_IEEE80211AX */
buflen += hostapd_mbo_ie_len(hapd);
buflen += hostapd_eid_owe_trans_len(hapd);
+ buflen += hostapd_eid_dpp_cc_len(hapd);
resp = os_zalloc(buflen);
if (resp == NULL)
@@ -454,13 +519,10 @@
/* Extended supported rates */
pos = hostapd_eid_ext_supp_rates(hapd, pos);
- /* RSN, MDIE */
- if (hapd->conf->wpa != WPA_PROTO_WPA)
- pos = hostapd_eid_wpa(hapd, pos, epos - pos);
-
+ pos = hostapd_get_rsne(hapd, pos, epos - pos);
pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
-
pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos);
+ pos = hostapd_get_mde(hapd, pos, epos - pos);
/* eCSA IE */
csa_pos = hostapd_eid_ecsa(hapd, pos);
@@ -469,15 +531,8 @@
pos = csa_pos;
pos = hostapd_eid_supported_op_classes(hapd, pos);
-
-#ifdef CONFIG_IEEE80211N
- /* Secondary Channel Offset element */
- /* TODO: The standard doesn't specify a position for this element. */
- pos = hostapd_eid_secondary_channel(hapd, pos);
-
pos = hostapd_eid_ht_capabilities(hapd, pos);
pos = hostapd_eid_ht_operation(hapd, pos);
-#endif /* CONFIG_IEEE80211N */
pos = hostapd_eid_ext_capab(hapd, pos);
@@ -497,7 +552,8 @@
#endif /* CONFIG_FST */
#ifdef CONFIG_IEEE80211AC
- if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
+ !is_6ghz_op_class(hapd->iconf->op_class)) {
pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
pos = hostapd_eid_vht_operation(hapd, pos);
pos = hostapd_eid_txpower_envelope(hapd, pos);
@@ -506,11 +562,13 @@
#endif /* CONFIG_IEEE80211AC */
pos = hostapd_eid_fils_indic(hapd, pos, 0);
+ pos = hostapd_get_rsnxe(hapd, pos, epos - pos);
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) {
- pos = hostapd_eid_he_capab(hapd, pos);
+ pos = hostapd_eid_he_capab(hapd, pos, IEEE80211_MODE_AP);
pos = hostapd_eid_he_operation(hapd, pos);
+ pos = hostapd_eid_spatial_reuse(hapd, pos);
pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
}
#endif /* CONFIG_IEEE80211AX */
@@ -520,9 +578,9 @@
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);
+ /* WPA / OSEN */
+ pos = hostapd_get_wpa_ie(hapd, pos, epos - pos);
+ pos = hostapd_get_osen_ie(hapd, pos, epos - pos);
/* Wi-Fi Alliance WMM */
pos = hostapd_eid_wmm(hapd, pos);
@@ -551,11 +609,11 @@
#ifdef CONFIG_HS20
pos = hostapd_eid_hs20_indication(hapd, pos);
- pos = hostapd_eid_osen(hapd, pos);
#endif /* CONFIG_HS20 */
pos = hostapd_eid_mbo(hapd, pos, (u8 *) resp + buflen - pos);
pos = hostapd_eid_owe_trans(hapd, pos, (u8 *) resp + buflen - pos);
+ pos = hostapd_eid_dpp_cc(hapd, pos, (u8 *) resp + buflen - pos);
if (hapd->conf->vendor_elements) {
os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
@@ -577,7 +635,9 @@
static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
const u8 *ssid, size_t ssid_len,
const u8 *ssid_list,
- size_t ssid_list_len)
+ size_t ssid_list_len,
+ const u8 *short_ssid_list,
+ size_t short_ssid_list_len)
{
const u8 *pos, *end;
int wildcard = 0;
@@ -588,20 +648,30 @@
os_memcmp(ssid, hapd->conf->ssid.ssid, ssid_len) == 0)
return EXACT_SSID_MATCH;
- if (ssid_list == NULL)
- return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
+ if (ssid_list) {
+ pos = ssid_list;
+ end = ssid_list + ssid_list_len;
+ while (end - pos >= 2) {
+ if (2 + pos[1] > end - pos)
+ break;
+ if (pos[1] == 0)
+ wildcard = 1;
+ if (pos[1] == hapd->conf->ssid.ssid_len &&
+ os_memcmp(pos + 2, hapd->conf->ssid.ssid,
+ pos[1]) == 0)
+ return EXACT_SSID_MATCH;
+ pos += 2 + pos[1];
+ }
+ }
- pos = ssid_list;
- end = ssid_list + ssid_list_len;
- while (end - pos >= 1) {
- if (2 + pos[1] > end - pos)
- break;
- if (pos[1] == 0)
- wildcard = 1;
- if (pos[1] == hapd->conf->ssid.ssid_len &&
- os_memcmp(pos + 2, hapd->conf->ssid.ssid, pos[1]) == 0)
- return EXACT_SSID_MATCH;
- pos += 2 + pos[1];
+ if (short_ssid_list) {
+ pos = short_ssid_list;
+ end = short_ssid_list + short_ssid_list_len;
+ while (end - pos >= 4) {
+ if (hapd->conf->ssid.short_ssid == WPA_GET_LE32(pos))
+ return EXACT_SSID_MATCH;
+ pos += 4;
+ }
}
return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
@@ -739,11 +809,7 @@
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;
+ struct radius_sta rad_info;
if (len < IEEE80211_HDRLEN)
return;
@@ -752,10 +818,8 @@
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);
+ ret = hostapd_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
+ &rad_info, 1);
if (ret == HOSTAPD_ACL_REJECT) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Ignore Probe Request frame from " MACSTR
@@ -834,7 +898,7 @@
#endif /* CONFIG_P2P */
if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0 &&
- elems.ssid_list_len == 0) {
+ elems.ssid_list_len == 0 && elems.short_ssid_list_len == 0) {
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
"broadcast SSID ignored", MAC2STR(mgmt->sa));
return;
@@ -866,7 +930,8 @@
#endif /* CONFIG_TAXONOMY */
res = ssid_match(hapd, elems.ssid, elems.ssid_len,
- elems.ssid_list, elems.ssid_list_len);
+ elems.ssid_list, elems.ssid_list_len,
+ elems.short_ssid_list, elems.short_ssid_list_len);
if (res == NO_SSID_MATCH) {
if (!(mgmt->da[0] & 0x01)) {
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
@@ -879,6 +944,12 @@
return;
}
+ if (hapd->conf->ignore_broadcast_ssid && res == WILDCARD_SSID_MATCH) {
+ wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
+ "broadcast SSID ignored", MAC2STR(mgmt->sa));
+ return;
+ }
+
#ifdef CONFIG_INTERWORKING
if (hapd->conf->interworking &&
elems.interworking && elems.interworking_len >= 1) {
@@ -983,9 +1054,9 @@
hapd->cs_c_off_ecsa_proberesp;
}
- ret = hostapd_drv_send_mlme_csa(hapd, resp, resp_len, noack,
- csa_offs_len ? csa_offs : NULL,
- csa_offs_len);
+ ret = hostapd_drv_send_mlme(hapd, resp, resp_len, noack,
+ csa_offs_len ? csa_offs : NULL,
+ csa_offs_len, 0);
if (ret < 0)
wpa_printf(MSG_INFO, "handle_probe_req: send failed");
@@ -1056,7 +1127,7 @@
size_t resp_len = 0;
#ifdef NEED_AP_MLME
u16 capab_info;
- u8 *pos, *tailpos, *csa_pos;
+ u8 *pos, *tailpos, *tailend, *csa_pos;
#define BEACON_HEAD_BUF_SIZE 256
#define BEACON_TAIL_BUF_SIZE 512
@@ -1088,12 +1159,14 @@
if (hapd->iconf->ieee80211ax) {
tail_len += 3 + sizeof(struct ieee80211_he_capabilities) +
3 + sizeof(struct ieee80211_he_operation) +
- 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set);
+ 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
+ 3 + sizeof(struct ieee80211_spatial_reuse);
}
#endif /* CONFIG_IEEE80211AX */
tail_len += hostapd_mbo_ie_len(hapd);
tail_len += hostapd_eid_owe_trans_len(hapd);
+ tail_len += hostapd_eid_dpp_cc_len(hapd);
tailpos = tail = os_malloc(tail_len);
if (head == NULL || tail == NULL) {
@@ -1102,6 +1175,7 @@
os_free(tail);
return -1;
}
+ tailend = tail + tail_len;
head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_BEACON);
@@ -1142,8 +1216,7 @@
head_len = pos - (u8 *) head;
- tailpos = hostapd_eid_country(hapd, tailpos,
- tail + BEACON_TAIL_BUF_SIZE - tailpos);
+ tailpos = hostapd_eid_country(hapd, tailpos, tailend - tailpos);
/* Power Constraint element */
tailpos = hostapd_eid_pwr_constraint(hapd, tailpos);
@@ -1160,18 +1233,11 @@
/* Extended supported rates */
tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
- /* RSN, MDIE */
- if (hapd->conf->wpa != WPA_PROTO_WPA)
- tailpos = hostapd_eid_wpa(hapd, tailpos,
- tail + BEACON_TAIL_BUF_SIZE -
- tailpos);
-
+ tailpos = hostapd_get_rsne(hapd, tailpos, tailend - tailpos);
+ tailpos = hostapd_eid_bss_load(hapd, tailpos, tailend - tailpos);
tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos,
- tail + BEACON_TAIL_BUF_SIZE -
- tailpos);
-
- tailpos = hostapd_eid_bss_load(hapd, tailpos,
- tail + BEACON_TAIL_BUF_SIZE - tailpos);
+ tailend - tailpos);
+ tailpos = hostapd_get_mde(hapd, tailpos, tailend - tailpos);
/* eCSA IE */
csa_pos = hostapd_eid_ecsa(hapd, tailpos);
@@ -1180,15 +1246,8 @@
tailpos = csa_pos;
tailpos = hostapd_eid_supported_op_classes(hapd, tailpos);
-
-#ifdef CONFIG_IEEE80211N
- /* Secondary Channel Offset element */
- /* TODO: The standard doesn't specify a position for this element. */
- tailpos = hostapd_eid_secondary_channel(hapd, tailpos);
-
tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
tailpos = hostapd_eid_ht_operation(hapd, tailpos);
-#endif /* CONFIG_IEEE80211N */
tailpos = hostapd_eid_ext_capab(hapd, tailpos);
@@ -1220,11 +1279,14 @@
#endif /* CONFIG_IEEE80211AC */
tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
+ tailpos = hostapd_get_rsnxe(hapd, tailpos, tailend - tailpos);
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) {
- tailpos = hostapd_eid_he_capab(hapd, tailpos);
+ tailpos = hostapd_eid_he_capab(hapd, tailpos,
+ IEEE80211_MODE_AP);
tailpos = hostapd_eid_he_operation(hapd, tailpos);
+ tailpos = hostapd_eid_spatial_reuse(hapd, tailpos);
tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
}
#endif /* CONFIG_IEEE80211AX */
@@ -1234,11 +1296,9 @@
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);
+ /* WPA / OSEN */
+ tailpos = hostapd_get_wpa_ie(hapd, tailpos, tailend - tailpos);
+ tailpos = hostapd_get_osen_ie(hapd, tailpos, tailend - tailpos);
/* Wi-Fi Alliance WMM */
tailpos = hostapd_eid_wmm(hapd, tailpos);
@@ -1266,12 +1326,12 @@
#ifdef CONFIG_HS20
tailpos = hostapd_eid_hs20_indication(hapd, tailpos);
- tailpos = hostapd_eid_osen(hapd, tailpos);
#endif /* CONFIG_HS20 */
tailpos = hostapd_eid_mbo(hapd, tailpos, tail + tail_len - tailpos);
tailpos = hostapd_eid_owe_trans(hapd, tailpos,
tail + tail_len - tailpos);
+ tailpos = hostapd_eid_dpp_cc(hapd, tailpos, tail + tail_len - tailpos);
if (hapd->conf->vendor_elements) {
os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
@@ -1310,10 +1370,13 @@
params->key_mgmt_suites = hapd->conf->wpa_key_mgmt;
params->auth_algs = hapd->conf->auth_algs;
params->wpa_version = hapd->conf->wpa;
- params->privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
+ params->privacy = hapd->conf->wpa;
+#ifdef CONFIG_WEP
+ params->privacy |= hapd->conf->ssid.wep.keys_set ||
(hapd->conf->ieee802_1x &&
(hapd->conf->default_wep_key_len ||
hapd->conf->individual_wep_key_len));
+#endif /* CONFIG_WEP */
switch (hapd->conf->ignore_broadcast_ssid) {
case 0:
params->hide_ssid = NO_SSID_HIDING;
@@ -1326,7 +1389,6 @@
break;
}
params->isolate = hapd->conf->isolate;
- params->smps_mode = hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_MASK;
#ifdef NEED_AP_MLME
params->cts_protect = !!(ieee802_11_erp_info(hapd) &
ERP_INFO_USE_PROTECTION);
@@ -1394,6 +1456,7 @@
struct hostapd_freq_params freq;
struct hostapd_iface *iface = hapd->iface;
struct hostapd_config *iconf = iface->conf;
+ struct hostapd_hw_modes *cmode = iface->current_mode;
struct wpabuf *beacon, *proberesp, *assocresp;
int res, ret = -1;
@@ -1415,17 +1478,33 @@
params.proberesp_ies = proberesp;
params.assocresp_ies = assocresp;
params.reenable = hapd->reenable_beacon;
+#ifdef CONFIG_IEEE80211AX
+ params.he_spr = !!hapd->iface->conf->spr.sr_control;
+ params.he_spr_srg_obss_pd_min_offset =
+ hapd->iface->conf->spr.srg_obss_pd_min_offset;
+ params.he_spr_srg_obss_pd_max_offset =
+ hapd->iface->conf->spr.srg_obss_pd_max_offset;
+ params.he_bss_color_disabled =
+ hapd->iface->conf->he_op.he_bss_color_disabled;
+ params.he_bss_color_partial =
+ hapd->iface->conf->he_op.he_bss_color_partial;
+ params.he_bss_color = hapd->iface->conf->he_op.he_bss_color;
+ params.twt_responder = hostapd_get_he_twt_responder(hapd,
+ IEEE80211_MODE_AP);
+#endif /* CONFIG_IEEE80211AX */
hapd->reenable_beacon = 0;
- if (iface->current_mode &&
+ if (cmode &&
hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
- iconf->channel, iconf->ieee80211n,
- iconf->ieee80211ac,
+ iconf->channel, iconf->enable_edmg,
+ iconf->edmg_channel, iconf->ieee80211n,
+ iconf->ieee80211ac, iconf->ieee80211ax,
iconf->secondary_channel,
- iconf->vht_oper_chwidth,
- iconf->vht_oper_centr_freq_seg0_idx,
- iconf->vht_oper_centr_freq_seg1_idx,
- iface->current_mode->vht_capab) == 0)
+ hostapd_get_oper_chwidth(iconf),
+ hostapd_get_oper_centr_freq_seg0_idx(iconf),
+ hostapd_get_oper_centr_freq_seg1_idx(iconf),
+ cmode->vht_capab,
+ &cmode->he_capab[IEEE80211_MODE_AP]) == 0)
params.freq = &freq;
res = hostapd_drv_set_ap(hapd, ¶ms);
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index c693715..ef53a82 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -273,6 +273,36 @@
if (!os_snprintf_error(buflen - len, res))
len += res;
}
+
+ if (sta->sae && sta->sae->tmp) {
+ const u8 *pos;
+ unsigned int j, count;
+ struct wpabuf *groups = sta->sae->tmp->peer_rejected_groups;
+
+ res = os_snprintf(buf + len, buflen - len,
+ "sae_rejected_groups=");
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+
+ if (groups) {
+ pos = wpabuf_head(groups);
+ count = wpabuf_len(groups) / 2;
+ } else {
+ pos = NULL;
+ count = 0;
+ }
+ for (j = 0; pos && j < count; j++) {
+ res = os_snprintf(buf + len, buflen - len, "%s%d",
+ j == 0 ? "" : " ", WPA_GET_LE16(pos));
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+ pos += 2;
+ }
+
+ res = os_snprintf(buf + len, buflen - len, "\n");
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+ }
#endif /* CONFIG_SAE */
if (sta->vlan_id > 0) {
@@ -315,7 +345,6 @@
}
#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",
@@ -324,7 +353,6 @@
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])) {
@@ -432,9 +460,6 @@
int ret;
u8 *pos;
- if (!hapd->drv_priv || !hapd->driver->send_frame)
- return -1;
-
mgmt = os_zalloc(sizeof(*mgmt) + 100);
if (mgmt == NULL)
return -1;
@@ -468,8 +493,8 @@
pos += 2;
*pos++ = minor_reason_code;
- ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
- pos - (u8 *) mgmt, 1);
+ ret = hostapd_drv_send_mlme(hapd, mgmt, pos - (u8 *) mgmt, 0, NULL, 0,
+ 0);
os_free(mgmt);
return ret < 0 ? -1 : 0;
@@ -499,8 +524,7 @@
if (pos) {
struct ieee80211_mgmt mgmt;
int encrypt;
- if (!hapd->drv_priv || !hapd->driver->send_frame)
- return -1;
+
pos += 6;
encrypt = atoi(pos);
os_memset(&mgmt, 0, sizeof(mgmt));
@@ -510,10 +534,10 @@
os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
mgmt.u.deauth.reason_code = host_to_le16(reason);
- if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
- IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth),
- encrypt) < 0)
+ if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
+ IEEE80211_HDRLEN +
+ sizeof(mgmt.u.deauth),
+ 0, NULL, 0, !encrypt) < 0)
return -1;
return 0;
}
@@ -562,8 +586,7 @@
if (pos) {
struct ieee80211_mgmt mgmt;
int encrypt;
- if (!hapd->drv_priv || !hapd->driver->send_frame)
- return -1;
+
pos += 6;
encrypt = atoi(pos);
os_memset(&mgmt, 0, sizeof(mgmt));
@@ -573,10 +596,10 @@
os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
mgmt.u.disassoc.reason_code = host_to_le16(reason);
- if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
- IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth),
- encrypt) < 0)
+ if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
+ IEEE80211_HDRLEN +
+ sizeof(mgmt.u.deauth),
+ 0, NULL, 0, !encrypt) < 0)
return -1;
return 0;
}
@@ -709,22 +732,44 @@
ret = os_snprintf(buf + len, buflen - len,
"channel=%u\n"
+ "edmg_enable=%d\n"
+ "edmg_channel=%d\n"
"secondary_channel=%d\n"
"ieee80211n=%d\n"
"ieee80211ac=%d\n"
+ "ieee80211ax=%d\n"
"beacon_int=%u\n"
"dtim_period=%d\n",
iface->conf->channel,
+ iface->conf->enable_edmg,
+ iface->conf->edmg_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,
+ iface->conf->ieee80211ax,
iface->conf->beacon_int,
hapd->conf->dtim_period);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
+
+#ifdef CONFIG_IEEE80211AX
+ if (iface->conf->ieee80211ax) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "he_oper_chwidth=%d\n"
+ "he_oper_centr_freq_seg0_idx=%d\n"
+ "he_oper_centr_freq_seg1_idx=%d\n",
+ iface->conf->he_oper_chwidth,
+ iface->conf->he_oper_centr_freq_seg0_idx,
+ iface->conf->he_oper_centr_freq_seg1_idx);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+#endif /* CONFIG_IEEE80211AX */
+
if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
ret = os_snprintf(buf + len, buflen - len,
"vht_oper_chwidth=%d\n"
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 79cd00f..3c078b9 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -28,17 +28,17 @@
if (iface->conf->ieee80211n && iface->conf->secondary_channel)
n_chans = 2;
- if (iface->conf->ieee80211ac) {
- switch (iface->conf->vht_oper_chwidth) {
- case VHT_CHANWIDTH_USE_HT:
+ if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
+ switch (hostapd_get_oper_chwidth(iface->conf)) {
+ case CHANWIDTH_USE_HT:
break;
- case VHT_CHANWIDTH_80MHZ:
+ case CHANWIDTH_80MHZ:
n_chans = 4;
break;
- case VHT_CHANWIDTH_160MHZ:
+ case CHANWIDTH_160MHZ:
n_chans = 8;
break;
- case VHT_CHANWIDTH_80P80MHZ:
+ case CHANWIDTH_80P80MHZ:
n_chans = 4;
*seg1 = 4;
break;
@@ -144,30 +144,44 @@
int i;
u32 bw = num_chan_to_bw(num_chans);
- if (first_chan_idx + num_chans > mode->num_channels)
+ if (first_chan_idx + num_chans > mode->num_channels) {
+ wpa_printf(MSG_DEBUG,
+ "DFS: some channels in range not defined");
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))
+ if (!chan_pri_allowed(first_chan)) {
+ wpa_printf(MSG_DEBUG, "DFS: primary chanenl not allowed");
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)
+ if (!chan) {
+ wpa_printf(MSG_DEBUG, "DFS: no channel data for %d",
+ first_chan->freq + i * 20);
return 0;
+ }
/* HT 40 MHz secondary channel availability checked only for
* primary channel */
- if (!chan_bw_allowed(chan, bw, 1, !i))
+ if (!chan_bw_allowed(chan, bw, 1, !i)) {
+ wpa_printf(MSG_DEBUG, "DFS: bw now allowed for %d",
+ first_chan->freq + i * 20);
return 0;
+ }
- if (!dfs_channel_available(chan, skip_radar))
+ if (!dfs_channel_available(chan, skip_radar)) {
+ wpa_printf(MSG_DEBUG, "DFS: channel not available %d",
+ first_chan->freq + i * 20);
return 0;
+ }
}
return 1;
@@ -188,8 +202,8 @@
* The function assumes HT40+ operation.
* Make sure to adjust the following variables after calling this:
* - hapd->secondary_channel
- * - hapd->vht_oper_centr_freq_seg0_idx
- * - hapd->vht_oper_centr_freq_seg1_idx
+ * - hapd->vht/he_oper_centr_freq_seg0_idx
+ * - hapd->vht/he_oper_centr_freq_seg1_idx
*/
static int dfs_find_channel(struct hostapd_iface *iface,
struct hostapd_channel_data **ret_chan,
@@ -210,66 +224,87 @@
if (iface->conf->ieee80211n &&
iface->conf->secondary_channel &&
(!dfs_is_chan_allowed(chan, n_chans) ||
- !(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)))
+ !(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))) {
+ wpa_printf(MSG_DEBUG,
+ "DFS: channel %d (%d) is incompatible",
+ chan->freq, chan->chan);
continue;
+ }
/* Skip incompatible chandefs */
- if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
+ if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) {
+ wpa_printf(MSG_DEBUG,
+ "DFS: range not available for %d (%d)",
+ chan->freq, chan->chan);
continue;
+ }
- if (!is_in_chanlist(iface, chan))
+ if (!is_in_chanlist(iface, chan)) {
+ wpa_printf(MSG_DEBUG,
+ "DFS: channel %d (%d) not in chanlist",
+ chan->freq, chan->chan);
continue;
+ }
if (ret_chan && idx == channel_idx) {
- wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
+ wpa_printf(MSG_DEBUG, "Selected channel %d (%d)",
+ chan->freq, chan->chan);
*ret_chan = chan;
return idx;
}
- wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan);
+ wpa_printf(MSG_DEBUG, "Adding channel %d (%d)",
+ chan->freq, chan->chan);
channel_idx++;
}
return channel_idx;
}
-static void dfs_adjust_vht_center_freq(struct hostapd_iface *iface,
- struct hostapd_channel_data *chan,
- int secondary_channel,
- u8 *vht_oper_centr_freq_seg0_idx,
- u8 *vht_oper_centr_freq_seg1_idx)
+static void dfs_adjust_center_freq(struct hostapd_iface *iface,
+ struct hostapd_channel_data *chan,
+ int secondary_channel,
+ int sec_chan_idx_80p80,
+ u8 *oper_centr_freq_seg0_idx,
+ u8 *oper_centr_freq_seg1_idx)
{
- if (!iface->conf->ieee80211ac)
+ if (!iface->conf->ieee80211ac && !iface->conf->ieee80211ax)
return;
if (!chan)
return;
- *vht_oper_centr_freq_seg1_idx = 0;
+ *oper_centr_freq_seg1_idx = 0;
- switch (iface->conf->vht_oper_chwidth) {
- case VHT_CHANWIDTH_USE_HT:
+ switch (hostapd_get_oper_chwidth(iface->conf)) {
+ case CHANWIDTH_USE_HT:
if (secondary_channel == 1)
- *vht_oper_centr_freq_seg0_idx = chan->chan + 2;
+ *oper_centr_freq_seg0_idx = chan->chan + 2;
else if (secondary_channel == -1)
- *vht_oper_centr_freq_seg0_idx = chan->chan - 2;
+ *oper_centr_freq_seg0_idx = chan->chan - 2;
else
- *vht_oper_centr_freq_seg0_idx = chan->chan;
+ *oper_centr_freq_seg0_idx = chan->chan;
break;
- case VHT_CHANWIDTH_80MHZ:
- *vht_oper_centr_freq_seg0_idx = chan->chan + 6;
+ case CHANWIDTH_80MHZ:
+ *oper_centr_freq_seg0_idx = chan->chan + 6;
break;
- case VHT_CHANWIDTH_160MHZ:
- *vht_oper_centr_freq_seg0_idx = chan->chan + 14;
+ case CHANWIDTH_160MHZ:
+ *oper_centr_freq_seg0_idx = chan->chan + 14;
break;
+ case CHANWIDTH_80P80MHZ:
+ *oper_centr_freq_seg0_idx = chan->chan + 6;
+ *oper_centr_freq_seg1_idx = sec_chan_idx_80p80 + 6;
+ break;
+
default:
- wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
- *vht_oper_centr_freq_seg0_idx = 0;
+ wpa_printf(MSG_INFO,
+ "DFS: Unsupported channel width configuration");
+ *oper_centr_freq_seg0_idx = 0;
break;
}
wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
- *vht_oper_centr_freq_seg0_idx,
- *vht_oper_centr_freq_seg1_idx);
+ *oper_centr_freq_seg0_idx,
+ *oper_centr_freq_seg1_idx);
}
@@ -288,24 +323,24 @@
if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
channel_no -= 4;
- /* VHT */
- if (iface->conf->ieee80211ac) {
- switch (iface->conf->vht_oper_chwidth) {
- case VHT_CHANWIDTH_USE_HT:
+ /* VHT/HE */
+ if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
+ switch (hostapd_get_oper_chwidth(iface->conf)) {
+ case CHANWIDTH_USE_HT:
break;
- case VHT_CHANWIDTH_80MHZ:
- channel_no =
- iface->conf->vht_oper_centr_freq_seg0_idx - 6;
+ case CHANWIDTH_80MHZ:
+ channel_no = hostapd_get_oper_centr_freq_seg0_idx(
+ iface->conf) - 6;
break;
- case VHT_CHANWIDTH_160MHZ:
- channel_no =
- iface->conf->vht_oper_centr_freq_seg0_idx - 14;
+ case CHANWIDTH_160MHZ:
+ channel_no = hostapd_get_oper_centr_freq_seg0_idx(
+ iface->conf) - 14;
break;
- case VHT_CHANWIDTH_80P80MHZ:
- channel_no =
- iface->conf->vht_oper_centr_freq_seg0_idx - 6;
- chan_seg1 =
- iface->conf->vht_oper_centr_freq_seg1_idx - 6;
+ case CHANWIDTH_80P80MHZ:
+ channel_no = hostapd_get_oper_centr_freq_seg0_idx(
+ iface->conf) - 6;
+ chan_seg1 = hostapd_get_oper_centr_freq_seg1_idx(
+ iface->conf) - 6;
break;
default:
wpa_printf(MSG_INFO,
@@ -348,7 +383,7 @@
mode->num_channels, channel_no, iface->conf->channel,
iface->conf->ieee80211n,
iface->conf->secondary_channel,
- iface->conf->vht_oper_chwidth);
+ hostapd_get_oper_chwidth(iface->conf));
for (i = 0; i < mode->num_channels; i++) {
wpa_printf(MSG_DEBUG, "Available channel: %d",
@@ -435,20 +470,23 @@
static struct hostapd_channel_data *
dfs_get_valid_channel(struct hostapd_iface *iface,
int *secondary_channel,
- u8 *vht_oper_centr_freq_seg0_idx,
- u8 *vht_oper_centr_freq_seg1_idx,
+ u8 *oper_centr_freq_seg0_idx,
+ u8 *oper_centr_freq_seg1_idx,
int skip_radar)
{
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan = NULL;
+ struct hostapd_channel_data *chan2 = NULL;
int num_available_chandefs;
- int chan_idx;
+ int chan_idx, chan_idx2;
+ int sec_chan_idx_80p80 = -1;
+ int i;
u32 _rand;
wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
*secondary_channel = 0;
- *vht_oper_centr_freq_seg0_idx = 0;
- *vht_oper_centr_freq_seg1_idx = 0;
+ *oper_centr_freq_seg0_idx = 0;
+ *oper_centr_freq_seg1_idx = 0;
if (iface->current_mode == NULL)
return NULL;
@@ -459,6 +497,8 @@
/* Get the count first */
num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
+ wpa_printf(MSG_DEBUG, "DFS: num_available_chandefs=%d",
+ num_available_chandefs);
if (num_available_chandefs == 0)
return NULL;
@@ -466,6 +506,12 @@
return NULL;
chan_idx = _rand % num_available_chandefs;
dfs_find_channel(iface, &chan, chan_idx, skip_radar);
+ if (!chan) {
+ wpa_printf(MSG_DEBUG, "DFS: no random channel found");
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "DFS: got random channel %d (%d)",
+ chan->freq, chan->chan);
/* dfs_find_channel() calculations assume HT40+ */
if (iface->conf->secondary_channel)
@@ -473,10 +519,47 @@
else
*secondary_channel = 0;
- dfs_adjust_vht_center_freq(iface, chan,
- *secondary_channel,
- vht_oper_centr_freq_seg0_idx,
- vht_oper_centr_freq_seg1_idx);
+ /* Get secondary channel for HT80P80 */
+ if (hostapd_get_oper_chwidth(iface->conf) == CHANWIDTH_80P80MHZ) {
+ if (num_available_chandefs <= 1) {
+ wpa_printf(MSG_ERROR,
+ "only 1 valid chan, can't support 80+80");
+ return NULL;
+ }
+
+ /*
+ * Loop all channels except channel1 to find a valid channel2
+ * that is not adjacent to channel1.
+ */
+ for (i = 0; i < num_available_chandefs - 1; i++) {
+ /* start from chan_idx + 1, end when chan_idx - 1 */
+ chan_idx2 = (chan_idx + 1 + i) % num_available_chandefs;
+ dfs_find_channel(iface, &chan2, chan_idx2, skip_radar);
+ if (chan2 && abs(chan2->chan - chan->chan) > 12) {
+ /* two channels are not adjacent */
+ sec_chan_idx_80p80 = chan2->chan;
+ wpa_printf(MSG_DEBUG,
+ "DFS: got second chan: %d (%d)",
+ chan2->freq, chan2->chan);
+ break;
+ }
+ }
+
+ /* Check if we got a valid secondary channel which is not
+ * adjacent to the first channel.
+ */
+ if (sec_chan_idx_80p80 == -1) {
+ wpa_printf(MSG_INFO,
+ "DFS: failed to get chan2 for 80+80");
+ return NULL;
+ }
+ }
+
+ dfs_adjust_center_freq(iface, chan,
+ *secondary_channel,
+ sec_chan_idx_80p80,
+ oper_centr_freq_seg0_idx,
+ oper_centr_freq_seg1_idx);
return chan;
}
@@ -515,6 +598,7 @@
int n_chans = 1, i;
struct hostapd_hw_modes *mode;
int frequency = freq;
+ int frequency2 = 0;
int ret = 0;
mode = iface->current_mode;
@@ -542,6 +626,11 @@
n_chans = 4;
frequency = cf1 - 30;
break;
+ case CHAN_WIDTH_80P80:
+ n_chans = 4;
+ frequency = cf1 - 30;
+ frequency2 = cf2 - 30;
+ break;
case CHAN_WIDTH_160:
n_chans = 8;
frequency = cf1 - 70;
@@ -557,6 +646,11 @@
for (i = 0; i < n_chans; i++) {
ret += set_dfs_state_freq(iface, frequency, state);
frequency = frequency + 20;
+
+ if (chan_width == CHAN_WIDTH_80P80) {
+ ret += set_dfs_state_freq(iface, frequency2, state);
+ frequency2 = frequency2 + 20;
+ }
}
return ret;
@@ -662,6 +756,9 @@
int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
int skip_radar = 0;
+ if (is_6ghz_freq(iface->freq))
+ return 1;
+
if (!iface->current_mode) {
/*
* This can happen with drivers that do not provide mode
@@ -724,8 +821,8 @@
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
iface->conf->secondary_channel = sec;
- iface->conf->vht_oper_centr_freq_seg0_idx = cf1;
- iface->conf->vht_oper_centr_freq_seg1_idx = cf2;
+ hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1);
+ hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2);
}
} while (res);
@@ -736,20 +833,19 @@
"freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
iface->freq,
iface->conf->channel, iface->conf->secondary_channel,
- iface->conf->vht_oper_chwidth,
- iface->conf->vht_oper_centr_freq_seg0_idx,
- iface->conf->vht_oper_centr_freq_seg1_idx,
+ hostapd_get_oper_chwidth(iface->conf),
+ hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
+ hostapd_get_oper_centr_freq_seg1_idx(iface->conf),
iface->dfs_cac_ms / 1000);
- res = hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
- iface->freq,
- iface->conf->channel,
- iface->conf->ieee80211n,
- iface->conf->ieee80211ac,
- iface->conf->secondary_channel,
- iface->conf->vht_oper_chwidth,
- iface->conf->vht_oper_centr_freq_seg0_idx,
- iface->conf->vht_oper_centr_freq_seg1_idx);
+ res = hostapd_start_dfs_cac(
+ iface, iface->conf->hw_mode, iface->freq, iface->conf->channel,
+ iface->conf->ieee80211n, iface->conf->ieee80211ac,
+ iface->conf->ieee80211ax,
+ iface->conf->secondary_channel,
+ hostapd_get_oper_chwidth(iface->conf),
+ hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
+ hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
if (res) {
wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
@@ -760,7 +856,7 @@
}
-static int hostapd_config_dfs_chan_available(struct hostapd_iface *iface)
+int hostapd_is_dfs_chan_available(struct hostapd_iface *iface)
{
int n_chans, n_chans1, start_chan_idx, start_chan_idx1;
@@ -808,7 +904,7 @@
* another radio.
*/
if (iface->state != HAPD_IFACE_ENABLED &&
- hostapd_config_dfs_chan_available(iface)) {
+ hostapd_is_dfs_chan_available(iface)) {
hostapd_setup_interface_complete(iface, 0);
iface->cac_started = 0;
}
@@ -838,25 +934,66 @@
}
+static struct hostapd_channel_data *
+dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
+ u8 *oper_centr_freq_seg0_idx,
+ u8 *oper_centr_freq_seg1_idx, int *skip_radar)
+{
+ struct hostapd_channel_data *channel;
+
+ for (;;) {
+ channel = dfs_get_valid_channel(iface, secondary_channel,
+ oper_centr_freq_seg0_idx,
+ oper_centr_freq_seg1_idx,
+ *skip_radar);
+ if (channel) {
+ wpa_printf(MSG_DEBUG, "DFS: Selected channel: %d",
+ channel->chan);
+ return channel;
+ }
+
+ if (*skip_radar) {
+ *skip_radar = 0;
+ } else {
+ if (iface->conf->vht_oper_chwidth == CHANWIDTH_USE_HT)
+ break;
+ *skip_radar = 1;
+ iface->conf->vht_oper_chwidth--;
+ }
+ }
+
+ wpa_printf(MSG_INFO,
+ "%s: no DFS channels left, waiting for NOP to finish",
+ __func__);
+ return NULL;
+}
+
+
static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
{
struct hostapd_channel_data *channel;
int secondary_channel;
- u8 vht_oper_centr_freq_seg0_idx = 0;
- u8 vht_oper_centr_freq_seg1_idx = 0;
+ u8 oper_centr_freq_seg0_idx = 0;
+ u8 oper_centr_freq_seg1_idx = 0;
int skip_radar = 0;
int err = 1;
/* Radar detected during active CAC */
iface->cac_started = 0;
channel = dfs_get_valid_channel(iface, &secondary_channel,
- &vht_oper_centr_freq_seg0_idx,
- &vht_oper_centr_freq_seg1_idx,
+ &oper_centr_freq_seg0_idx,
+ &oper_centr_freq_seg1_idx,
skip_radar);
if (!channel) {
- wpa_printf(MSG_ERROR, "No valid channel available");
- return err;
+ channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
+ &oper_centr_freq_seg0_idx,
+ &oper_centr_freq_seg1_idx,
+ &skip_radar);
+ if (!channel) {
+ wpa_printf(MSG_ERROR, "No valid channel available");
+ return err;
+ }
}
wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
@@ -868,10 +1005,10 @@
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
iface->conf->secondary_channel = secondary_channel;
- iface->conf->vht_oper_centr_freq_seg0_idx =
- vht_oper_centr_freq_seg0_idx;
- iface->conf->vht_oper_centr_freq_seg1_idx =
- vht_oper_centr_freq_seg1_idx;
+ hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
+ oper_centr_freq_seg0_idx);
+ hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
+ oper_centr_freq_seg1_idx);
err = 0;
hostapd_setup_interface_complete(iface, err);
@@ -883,12 +1020,15 @@
{
struct hostapd_channel_data *channel;
int secondary_channel;
- u8 vht_oper_centr_freq_seg0_idx;
- u8 vht_oper_centr_freq_seg1_idx;
+ u8 oper_centr_freq_seg0_idx;
+ u8 oper_centr_freq_seg1_idx;
+ u8 new_vht_oper_chwidth;
int skip_radar = 1;
struct csa_settings csa_settings;
unsigned int i;
int err = 1;
+ struct hostapd_hw_modes *cmode = iface->current_mode;
+ u8 current_vht_oper_chwidth = iface->conf->vht_oper_chwidth;
wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
__func__, iface->cac_started ? "yes" : "no",
@@ -911,8 +1051,8 @@
/* Perform channel switch/CSA */
channel = dfs_get_valid_channel(iface, &secondary_channel,
- &vht_oper_centr_freq_seg0_idx,
- &vht_oper_centr_freq_seg1_idx,
+ &oper_centr_freq_seg0_idx,
+ &oper_centr_freq_seg1_idx,
skip_radar);
if (!channel) {
@@ -922,28 +1062,25 @@
* requires to perform a CAC first.
*/
skip_radar = 0;
- channel = dfs_get_valid_channel(iface, &secondary_channel,
- &vht_oper_centr_freq_seg0_idx,
- &vht_oper_centr_freq_seg1_idx,
- skip_radar);
- if (!channel) {
- wpa_printf(MSG_INFO,
- "%s: no DFS channels left, waiting for NOP to finish",
- __func__);
+ channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
+ &oper_centr_freq_seg0_idx,
+ &oper_centr_freq_seg1_idx,
+ &skip_radar);
+ if (!channel)
return err;
+ if (!skip_radar) {
+ iface->freq = channel->freq;
+ iface->conf->channel = channel->chan;
+ iface->conf->secondary_channel = secondary_channel;
+ hostapd_set_oper_centr_freq_seg0_idx(
+ iface->conf, oper_centr_freq_seg0_idx);
+ hostapd_set_oper_centr_freq_seg1_idx(
+ iface->conf, oper_centr_freq_seg1_idx);
+
+ hostapd_disable_iface(iface);
+ hostapd_enable_iface(iface);
+ return 0;
}
-
- iface->freq = channel->freq;
- iface->conf->channel = channel->chan;
- iface->conf->secondary_channel = secondary_channel;
- iface->conf->vht_oper_centr_freq_seg0_idx =
- vht_oper_centr_freq_seg0_idx;
- iface->conf->vht_oper_centr_freq_seg1_idx =
- vht_oper_centr_freq_seg1_idx;
-
- hostapd_disable_iface(iface);
- hostapd_enable_iface(iface);
- return 0;
}
wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
@@ -952,6 +1089,9 @@
"freq=%d chan=%d sec_chan=%d", channel->freq,
channel->chan, secondary_channel);
+ new_vht_oper_chwidth = iface->conf->vht_oper_chwidth;
+ iface->conf->vht_oper_chwidth = current_vht_oper_chwidth;
+
/* Setup CSA request */
os_memset(&csa_settings, 0, sizeof(csa_settings));
csa_settings.cs_count = 5;
@@ -960,13 +1100,17 @@
iface->conf->hw_mode,
channel->freq,
channel->chan,
+ iface->conf->enable_edmg,
+ iface->conf->edmg_channel,
iface->conf->ieee80211n,
iface->conf->ieee80211ac,
+ iface->conf->ieee80211ax,
secondary_channel,
- iface->conf->vht_oper_chwidth,
- vht_oper_centr_freq_seg0_idx,
- vht_oper_centr_freq_seg1_idx,
- iface->current_mode->vht_capab);
+ new_vht_oper_chwidth,
+ oper_centr_freq_seg0_idx,
+ oper_centr_freq_seg1_idx,
+ cmode->vht_capab,
+ &cmode->he_capab[IEEE80211_MODE_AP]);
if (err) {
wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
@@ -986,10 +1130,11 @@
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
iface->conf->secondary_channel = secondary_channel;
- iface->conf->vht_oper_centr_freq_seg0_idx =
- vht_oper_centr_freq_seg0_idx;
- iface->conf->vht_oper_centr_freq_seg1_idx =
- vht_oper_centr_freq_seg1_idx;
+ iface->conf->vht_oper_chwidth = new_vht_oper_chwidth;
+ hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
+ oper_centr_freq_seg0_idx);
+ hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
+ oper_centr_freq_seg1_idx);
hostapd_disable_iface(iface);
hostapd_enable_iface(iface);
@@ -1022,8 +1167,10 @@
return 0;
/* mark radar frequency as invalid */
- set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
- cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
+ res = set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
+ cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
+ if (!res)
+ return 0;
/* Skip if reported radar event not overlapped our channels */
res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
@@ -1091,11 +1238,18 @@
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2)
{
+ /* This is called when the driver indicates that an offloaded DFS has
+ * started CAC. */
+ hostapd_set_state(iface, HAPD_IFACE_DFS);
+ /* TODO: How to check CAC time for ETSI weather channels? */
+ iface->dfs_cac_ms = 60000;
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
"freq=%d chan=%d chan_offset=%d width=%d seg0=%d "
"seg1=%d cac_time=%ds",
- freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2, 60);
+ freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2,
+ iface->dfs_cac_ms / 1000);
iface->cac_started = 1;
+ os_get_reltime(&iface->dfs_cac_start);
return 0;
}
@@ -1136,3 +1290,56 @@
__func__, iface->freq);
return 2;
}
+
+
+int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
+ int center_freq)
+{
+ struct hostapd_channel_data *chan;
+ struct hostapd_hw_modes *mode = iface->current_mode;
+ int half_width;
+ int res = 0;
+ int i;
+
+ if (!iface->conf->ieee80211h || !mode ||
+ mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return 0;
+
+ switch (width) {
+ case CHAN_WIDTH_20_NOHT:
+ case CHAN_WIDTH_20:
+ half_width = 10;
+ break;
+ case CHAN_WIDTH_40:
+ half_width = 20;
+ break;
+ case CHAN_WIDTH_80:
+ case CHAN_WIDTH_80P80:
+ half_width = 40;
+ break;
+ case CHAN_WIDTH_160:
+ half_width = 80;
+ break;
+ default:
+ wpa_printf(MSG_WARNING, "DFS chanwidth %d not supported",
+ width);
+ return 0;
+ }
+
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
+
+ if (!(chan->flag & HOSTAPD_CHAN_RADAR))
+ continue;
+
+ if (center_freq - chan->freq < half_width &&
+ chan->freq - center_freq < half_width)
+ res++;
+ }
+
+ wpa_printf(MSG_DEBUG, "DFS: (%d, %d): in range: %s",
+ center_freq - half_width, center_freq + half_width,
+ res ? "yes" : "no");
+
+ return res;
+}
diff --git a/src/ap/dfs.h b/src/ap/dfs.h
index f0fa6f6..606c1b3 100644
--- a/src/ap/dfs.h
+++ b/src/ap/dfs.h
@@ -25,9 +25,12 @@
int ht_enabled,
int chan_offset, int chan_width, int cf1, int cf2);
int hostapd_is_dfs_required(struct hostapd_iface *iface);
+int hostapd_is_dfs_chan_available(struct hostapd_iface *iface);
int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2);
int hostapd_handle_dfs_offload(struct hostapd_iface *iface);
+int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
+ int center_freq);
#endif /* DFS_H */
diff --git a/src/ap/dhcp_snoop.c b/src/ap/dhcp_snoop.c
index ed37fc8..edc77da 100644
--- a/src/ap/dhcp_snoop.c
+++ b/src/ap/dhcp_snoop.c
@@ -39,22 +39,22 @@
const u8 *end, *pos;
int res, msgtype = 0, prefixlen = 32;
u32 subnet_mask = 0;
- u16 tot_len;
+ u16 ip_len;
exten_len = len - ETH_HLEN - (sizeof(*b) - sizeof(b->exten));
if (exten_len < 4)
return;
b = (const struct bootp_pkt *) &buf[ETH_HLEN];
- tot_len = ntohs(b->iph.tot_len);
- if (tot_len > (unsigned int) (len - ETH_HLEN))
+ ip_len = ntohs(b->iph.ip_len);
+ if (ip_len > (unsigned int) (len - ETH_HLEN))
return;
if (WPA_GET_BE32(b->exten) != DHCP_MAGIC)
return;
/* Parse DHCP options */
- end = (const u8 *) b + tot_len;
+ end = (const u8 *) b + ip_len;
pos = &b->exten[4];
while (pos < end && *pos != DHCP_OPT_END) {
const u8 *opt = pos++;
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index 75edbc9..c86f01b 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -1,6 +1,7 @@
/*
* hostapd / DPP integration
* Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -16,6 +17,7 @@
#include "hostapd.h"
#include "ap_drv_ops.h"
#include "gas_query_ap.h"
+#include "gas_serv.h"
#include "wpa_auth.h"
#include "dpp_hostapd.h"
@@ -61,6 +63,89 @@
}
+/**
+ * hostapd_dpp_nfc_uri - Parse and add DPP bootstrapping info from NFC Tag (URI)
+ * @hapd: Pointer to hostapd_data
+ * @cmd: DPP URI read from a NFC Tag (URI NDEF message)
+ * Returns: Identifier of the stored info or -1 on failure
+ */
+int hostapd_dpp_nfc_uri(struct hostapd_data *hapd, const char *cmd)
+{
+ struct dpp_bootstrap_info *bi;
+
+ bi = dpp_add_nfc_uri(hapd->iface->interfaces->dpp, cmd);
+ if (!bi)
+ return -1;
+
+ return bi->id;
+}
+
+
+int hostapd_dpp_nfc_handover_req(struct hostapd_data *hapd, const char *cmd)
+{
+ const char *pos;
+ struct dpp_bootstrap_info *peer_bi, *own_bi;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
+ if (!own_bi)
+ return -1;
+
+ pos = os_strstr(cmd, " uri=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ peer_bi = dpp_add_nfc_uri(hapd->iface->interfaces->dpp, pos);
+ if (!peer_bi) {
+ wpa_printf(MSG_INFO,
+ "DPP: Failed to parse URI from NFC Handover Request");
+ return -1;
+ }
+
+ if (dpp_nfc_update_bi(own_bi, peer_bi) < 0)
+ return -1;
+
+ return peer_bi->id;
+}
+
+
+int hostapd_dpp_nfc_handover_sel(struct hostapd_data *hapd, const char *cmd)
+{
+ const char *pos;
+ struct dpp_bootstrap_info *peer_bi, *own_bi;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
+ if (!own_bi)
+ return -1;
+
+ pos = os_strstr(cmd, " uri=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ peer_bi = dpp_add_nfc_uri(hapd->iface->interfaces->dpp, pos);
+ if (!peer_bi) {
+ wpa_printf(MSG_INFO,
+ "DPP: Failed to parse URI from NFC Handover Select");
+ return -1;
+ }
+
+ if (peer_bi->curve != own_bi->curve) {
+ wpa_printf(MSG_INFO,
+ "DPP: Peer (NFC Handover Selector) used different curve");
+ return -1;
+ }
+
+ return peer_bi->id;
+}
+
+
static void hostapd_dpp_auth_resp_retry_timeout(void *eloop_ctx,
void *timeout_ctx)
{
@@ -458,15 +543,15 @@
dpp_auth_deinit(hapd->dpp_auth);
}
- hapd->dpp_auth = dpp_auth_init(hapd->msg_ctx, peer_bi, own_bi,
+ hapd->dpp_auth = dpp_auth_init(hapd->iface->interfaces->dpp,
+ hapd->msg_ctx, peer_bi, own_bi,
allowed_roles, neg_freq,
hapd->iface->hw_features,
hapd->iface->num_hw_features);
if (!hapd->dpp_auth)
goto fail;
hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
- if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
- hapd->dpp_auth, cmd) < 0) {
+ if (dpp_set_configurator(hapd->dpp_auth, cmd) < 0) {
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
goto fail;
@@ -557,6 +642,14 @@
* received hash values */
dpp_bootstrap_find_pair(hapd->iface->interfaces->dpp, i_bootstrap,
r_bootstrap, &own_bi, &peer_bi);
+#ifdef CONFIG_DPP2
+ if (!own_bi) {
+ if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
+ src, hdr, buf, len, freq, i_bootstrap,
+ r_bootstrap) == 0)
+ return;
+ }
+#endif /* CONFIG_DPP2 */
if (!own_bi) {
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
"No matching own bootstrapping key found - ignore message");
@@ -570,7 +663,8 @@
}
hapd->dpp_auth_ok_on_ack = 0;
- hapd->dpp_auth = dpp_auth_req_rx(hapd->msg_ctx, hapd->dpp_allowed_roles,
+ hapd->dpp_auth = dpp_auth_req_rx(hapd->iface->interfaces->dpp,
+ hapd->msg_ctx, hapd->dpp_allowed_roles,
hapd->dpp_qr_mutual,
peer_bi, own_bi, freq, hdr, buf, len);
if (!hapd->dpp_auth) {
@@ -578,8 +672,7 @@
return;
}
hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
- if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
- hapd->dpp_auth,
+ if (dpp_set_configurator(hapd->dpp_auth,
hapd->dpp_configurator_params) < 0) {
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
@@ -598,47 +691,49 @@
static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
- struct dpp_authentication *auth)
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
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)
+ dpp_akm_str(conf->akm));
+ if (conf->ssid_len)
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
- wpa_ssid_txt(auth->ssid, auth->ssid_len));
- if (auth->connector) {
+ wpa_ssid_txt(conf->ssid, conf->ssid_len));
+ if (conf->connector) {
/* TODO: Save the Connector and consider using a command
* to fetch the value instead of sending an event with
* it. The Connector could end up being larger than what
* most clients are ready to receive as an event
* message. */
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
- auth->connector);
- } else if (auth->passphrase[0]) {
+ conf->connector);
+ }
+ if (conf->passphrase[0]) {
char hex[64 * 2 + 1];
wpa_snprintf_hex(hex, sizeof(hex),
- (const u8 *) auth->passphrase,
- os_strlen(auth->passphrase));
+ (const u8 *) conf->passphrase,
+ os_strlen(conf->passphrase));
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_PASS "%s",
hex);
- } else if (auth->psk_set) {
+ } else if (conf->psk_set) {
char hex[PMK_LEN * 2 + 1];
- wpa_snprintf_hex(hex, sizeof(hex), auth->psk, PMK_LEN);
+ wpa_snprintf_hex(hex, sizeof(hex), conf->psk, PMK_LEN);
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_PSK "%s",
hex);
}
- if (auth->c_sign_key) {
+ if (conf->c_sign_key) {
char *hex;
size_t hexlen;
- hexlen = 2 * wpabuf_len(auth->c_sign_key) + 1;
+ hexlen = 2 * wpabuf_len(conf->c_sign_key) + 1;
hex = os_malloc(hexlen);
if (hex) {
wpa_snprintf_hex(hex, hexlen,
- wpabuf_head(auth->c_sign_key),
- wpabuf_len(auth->c_sign_key));
+ wpabuf_head(conf->c_sign_key),
+ wpabuf_len(conf->c_sign_key));
wpa_msg(hapd->msg_ctx, MSG_INFO,
DPP_EVENT_C_SIGN_KEY "%s", hex);
os_free(hex);
@@ -668,6 +763,33 @@
}
+static int hostapd_dpp_handle_key_pkg(struct hostapd_data *hapd,
+ struct dpp_asymmetric_key *key)
+{
+#ifdef CONFIG_DPP2
+ int res;
+
+ if (!key)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "DPP: Received Configurator backup");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
+
+ while (key) {
+ res = dpp_configurator_from_backup(
+ hapd->iface->interfaces->dpp, key);
+ if (res < 0)
+ return -1;
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFIGURATOR_ID "%d",
+ res);
+ key = key->next;
+ }
+#endif /* CONFIG_DPP2 */
+
+ return 0;
+}
+
+
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,
@@ -711,7 +833,10 @@
goto fail;
}
- hostapd_dpp_handle_config_obj(hapd, auth);
+ hostapd_dpp_handle_config_obj(hapd, auth, &auth->conf_obj[0]);
+ if (hostapd_dpp_handle_key_pkg(hapd, auth->conf_key_pkg) < 0)
+ goto fail;
+
status = DPP_STATUS_OK;
#ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_REJECT_CONFIG) {
@@ -756,18 +881,11 @@
{
struct dpp_authentication *auth = hapd->dpp_auth;
struct wpabuf *buf;
- char json[100];
int res;
- int netrole_ap = 1;
- os_snprintf(json, sizeof(json),
- "{\"name\":\"Test\","
- "\"wi-fi_tech\":\"infra\","
- "\"netRole\":\"%s\"}",
- netrole_ap ? "ap" : "sta");
- wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
-
- buf = dpp_build_conf_req(auth, json);
+ buf = dpp_build_conf_req_helper(auth, hapd->conf->dpp_name,
+ DPP_NETROLE_AP,
+ hapd->conf->dpp_mud_url, NULL);
if (!buf) {
wpa_printf(MSG_DEBUG,
"DPP: No configuration request data available");
@@ -913,6 +1031,24 @@
}
+static void hostapd_dpp_conn_status_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 Connection Status Result");
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ DPP_EVENT_CONN_STATUS_RESULT "timeout");
+ 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)
{
@@ -936,6 +1072,20 @@
status = dpp_conf_result_rx(auth, hdr, buf, len);
+ if (status == DPP_STATUS_OK && auth->send_conn_status) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ DPP_EVENT_CONF_SENT "wait_conn_status=1");
+ wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
+ eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout,
+ hapd, NULL);
+ eloop_cancel_timeout(
+ hostapd_dpp_conn_status_result_wait_timeout,
+ hapd, NULL);
+ eloop_register_timeout(
+ 16, 0, hostapd_dpp_conn_status_result_wait_timeout,
+ hapd, NULL);
+ return;
+ }
hostapd_drv_send_action_cancel_wait(hapd);
hostapd_dpp_listen_stop(hapd);
if (status == DPP_STATUS_OK)
@@ -948,6 +1098,105 @@
NULL);
}
+
+static void hostapd_dpp_rx_conn_status_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;
+ u8 ssid[SSID_MAX_LEN];
+ size_t ssid_len = 0;
+ char *channel_list = NULL;
+
+ wpa_printf(MSG_DEBUG, "DPP: Connection Status Result");
+
+ if (!auth || !auth->waiting_conn_status_result) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for connection status result - drop");
+ return;
+ }
+
+ status = dpp_conn_status_result_rx(auth, hdr, buf, len,
+ ssid, &ssid_len, &channel_list);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT
+ "result=%d ssid=%s channel_list=%s",
+ status, wpa_ssid_txt(ssid, ssid_len),
+ channel_list ? channel_list : "N/A");
+ os_free(channel_list);
+ hostapd_drv_send_action_cancel_wait(hapd);
+ hostapd_dpp_listen_stop(hapd);
+ dpp_auth_deinit(auth);
+ hapd->dpp_auth = NULL;
+ eloop_cancel_timeout(hostapd_dpp_conn_status_result_wait_timeout,
+ hapd, NULL);
+}
+
+
+static void
+hostapd_dpp_rx_presence_announcement(struct hostapd_data *hapd, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ const u8 *r_bootstrap;
+ u16 r_bootstrap_len;
+ struct dpp_bootstrap_info *peer_bi;
+ struct dpp_authentication *auth;
+
+ wpa_printf(MSG_DEBUG, "DPP: Presence Announcement from " MACSTR,
+ MAC2STR(src));
+
+ r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_bootstrap_len);
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_msg(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",
+ r_bootstrap, r_bootstrap_len);
+ peer_bi = dpp_bootstrap_find_chirp(hapd->iface->interfaces->dpp,
+ r_bootstrap);
+ if (!peer_bi) {
+ if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
+ src, hdr, buf, len, freq, NULL,
+ r_bootstrap) == 0)
+ return;
+ wpa_printf(MSG_DEBUG,
+ "DPP: No matching bootstrapping information found");
+ return;
+ }
+
+ if (hapd->dpp_auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore Presence Announcement during ongoing Authentication");
+ return;
+ }
+
+ auth = dpp_auth_init(hapd->iface->interfaces->dpp, hapd->msg_ctx,
+ peer_bi, NULL, DPP_CAPAB_CONFIGURATOR, freq, NULL,
+ 0);
+ if (!auth)
+ return;
+ hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
+ if (dpp_set_configurator(hapd->dpp_auth,
+ hapd->dpp_configurator_params) < 0) {
+ dpp_auth_deinit(auth);
+ return;
+ }
+
+ auth->neg_freq = freq;
+
+ if (!is_zero_ether_addr(peer_bi->mac_addr))
+ os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
+
+ hapd->dpp_auth = auth;
+ if (hostapd_dpp_auth_init_next(hapd) < 0) {
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ }
+}
+
#endif /* CONFIG_DPP2 */
@@ -1357,6 +1606,12 @@
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
" freq=%u type=%d", MAC2STR(src), freq, type);
+#ifdef CONFIG_DPP2
+ if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
+ src, hdr, buf, len, freq, NULL, NULL) == 0)
+ return;
+#endif /* CONFIG_DPP2 */
+
switch (type) {
case DPP_PA_AUTHENTICATION_REQ:
hostapd_dpp_rx_auth_req(hapd, src, hdr, buf, len, freq);
@@ -1388,6 +1643,13 @@
case DPP_PA_CONFIGURATION_RESULT:
hostapd_dpp_rx_conf_result(hapd, src, hdr, buf, len);
break;
+ case DPP_PA_CONNECTION_STATUS_RESULT:
+ hostapd_dpp_rx_conn_status_result(hapd, src, hdr, buf, len);
+ break;
+ case DPP_PA_PRESENCE_ANNOUNCEMENT:
+ hostapd_dpp_rx_presence_announcement(hapd, src, hdr, buf, len,
+ freq);
+ break;
#endif /* CONFIG_DPP2 */
default:
wpa_printf(MSG_DEBUG,
@@ -1410,7 +1672,8 @@
struct wpabuf *
hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
- const u8 *query, size_t query_len)
+ const u8 *query, size_t query_len,
+ const u8 *data, size_t data_len)
{
struct dpp_authentication *auth = hapd->dpp_auth;
struct wpabuf *resp;
@@ -1418,6 +1681,13 @@
wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR, MAC2STR(sa));
if (!auth || !auth->auth_success ||
os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
+#ifdef CONFIG_DPP2
+ if (dpp_relay_rx_gas_req(hapd->iface->interfaces->dpp, sa, data,
+ data_len) == 0) {
+ /* Response will be forwarded once received over TCP */
+ return NULL;
+ }
+#endif /* CONFIG_DPP2 */
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
return NULL;
}
@@ -1474,16 +1744,15 @@
int ret = -1;
char *curve = NULL;
- auth = os_zalloc(sizeof(*auth));
+ auth = dpp_alloc_auth(hapd->iface->interfaces->dpp, hapd->msg_ctx);
if (!auth)
return -1;
curve = get_param(cmd, " curve=");
hostapd_dpp_set_testing_options(hapd, auth);
- if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
- auth, cmd) == 0 &&
+ if (dpp_set_configurator(auth, cmd) == 0 &&
dpp_configurator_own_config(auth, curve, 1) == 0) {
- hostapd_dpp_handle_config_obj(hapd, auth);
+ hostapd_dpp_handle_config_obj(hapd, auth, &auth->conf_obj[0]);
ret = 0;
}
@@ -1609,11 +1878,67 @@
}
+#ifdef CONFIG_DPP2
+
+static void hostapd_dpp_relay_tx(void *ctx, const u8 *addr, unsigned int freq,
+ const u8 *msg, size_t len)
+{
+ struct hostapd_data *hapd = ctx;
+ u8 *buf;
+
+ wpa_printf(MSG_DEBUG, "DPP: Send action frame dst=" MACSTR " freq=%u",
+ MAC2STR(addr), freq);
+ buf = os_malloc(2 + len);
+ if (!buf)
+ return;
+ buf[0] = WLAN_ACTION_PUBLIC;
+ buf[1] = WLAN_PA_VENDOR_SPECIFIC;
+ os_memcpy(buf + 2, msg, len);
+ hostapd_drv_send_action(hapd, freq, 0, addr, buf, 2 + len);
+ os_free(buf);
+}
+
+
+static void hostapd_dpp_relay_gas_resp_tx(void *ctx, const u8 *addr,
+ u8 dialog_token, int prot,
+ struct wpabuf *buf)
+{
+ struct hostapd_data *hapd = ctx;
+
+ gas_serv_req_dpp_processing(hapd, addr, dialog_token, prot, buf);
+}
+
+#endif /* CONFIG_DPP2 */
+
+
+static int hostapd_dpp_add_controllers(struct hostapd_data *hapd)
+{
+#ifdef CONFIG_DPP2
+ struct dpp_controller_conf *ctrl;
+ struct dpp_relay_config config;
+
+ os_memset(&config, 0, sizeof(config));
+ config.cb_ctx = hapd;
+ config.tx = hostapd_dpp_relay_tx;
+ config.gas_resp_tx = hostapd_dpp_relay_gas_resp_tx;
+ for (ctrl = hapd->conf->dpp_controller; ctrl; ctrl = ctrl->next) {
+ config.ipaddr = &ctrl->ipaddr;
+ config.pkhash = ctrl->pkhash;
+ if (dpp_relay_add_controller(hapd->iface->interfaces->dpp,
+ &config) < 0)
+ return -1;
+ }
+#endif /* CONFIG_DPP2 */
+
+ return 0;
+}
+
+
int hostapd_dpp_init(struct hostapd_data *hapd)
{
hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE;
hapd->dpp_init_done = 1;
- return 0;
+ return hostapd_dpp_add_controllers(hapd);
}
@@ -1636,6 +1961,8 @@
#ifdef CONFIG_DPP2
eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
NULL);
+ eloop_cancel_timeout(hostapd_dpp_conn_status_result_wait_timeout, hapd,
+ NULL);
#endif /* CONFIG_DPP2 */
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
diff --git a/src/ap/dpp_hostapd.h b/src/ap/dpp_hostapd.h
index 449ca16..b1fa99e 100644
--- a/src/ap/dpp_hostapd.h
+++ b/src/ap/dpp_hostapd.h
@@ -1,6 +1,7 @@
/*
* hostapd / DPP integration
* Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +11,9 @@
#define DPP_HOSTAPD_H
int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_nfc_uri(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_nfc_handover_req(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_nfc_handover_sel(struct hostapd_data *hapd, const char *cmd);
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);
@@ -19,7 +23,8 @@
const u8 *data, size_t data_len, int ok);
struct wpabuf *
hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
- const u8 *query, size_t query_len);
+ const u8 *query, size_t query_len,
+ const u8 *data, size_t data_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);
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index e3844d9..524a151 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -16,6 +16,8 @@
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "common/dpp.h"
+#include "common/sae.h"
+#include "common/hw_features_common.h"
#include "crypto/random.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
@@ -107,16 +109,15 @@
const u8 *req_ies, size_t req_ies_len, int reassoc)
{
struct sta_info *sta;
- int new_assoc, res;
+ int new_assoc;
+ enum wpa_validate_result res;
struct ieee802_11_elems elems;
const u8 *ie;
size_t ielen;
-#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 || CONFIG_OWE */
u16 reason = WLAN_REASON_UNSPECIFIED;
- u16 status = WLAN_STATUS_SUCCESS;
+ int status = WLAN_STATUS_SUCCESS;
const u8 *p2p_dev_addr = NULL;
if (addr == NULL) {
@@ -220,7 +221,6 @@
}
#endif /* CONFIG_P2P */
-#ifdef CONFIG_IEEE80211N
#ifdef NEED_AP_MLME
if (elems.ht_capabilities &&
(hapd->iface->conf->ht_capab &
@@ -234,7 +234,6 @@
ht40_intolerant_add(hapd->iface, sta);
}
#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_INTERWORKING
if (elems.ext_capab && elems.ext_capab_len > 4) {
@@ -321,39 +320,74 @@
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq,
ie, ielen,
+ elems.rsnxe ? elems.rsnxe - 2 : NULL,
+ elems.rsnxe ? elems.rsnxe_len + 2 : 0,
elems.mdie, elems.mdie_len,
elems.owe_dh, elems.owe_dh_len);
- if (res != WPA_IE_OK) {
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ switch (res) {
+ case WPA_IE_OK:
+ reason = WLAN_REASON_UNSPECIFIED;
+ status = WLAN_STATUS_SUCCESS;
+ break;
+ case WPA_INVALID_IE:
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ break;
+ case WPA_INVALID_GROUP:
+ reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
+ status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+ break;
+ case WPA_INVALID_PAIRWISE:
+ reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
+ status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+ break;
+ case WPA_INVALID_AKMP:
+ reason = WLAN_REASON_AKMP_NOT_VALID;
+ status = WLAN_STATUS_AKMP_NOT_VALID;
+ break;
+ case WPA_NOT_ENABLED:
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ break;
+ case WPA_ALLOC_FAIL:
+ reason = WLAN_REASON_UNSPECIFIED;
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ break;
+ case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ break;
+ case WPA_INVALID_MGMT_GROUP_CIPHER:
+ reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
+ status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
+ break;
+ case WPA_INVALID_MDIE:
+ reason = WLAN_REASON_INVALID_MDE;
+ status = WLAN_STATUS_INVALID_MDIE;
+ break;
+ case WPA_INVALID_PROTO:
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ break;
+ case WPA_INVALID_PMKID:
+ reason = WLAN_REASON_INVALID_PMKID;
+ status = WLAN_STATUS_INVALID_PMKID;
+ break;
+ case WPA_DENIED_OTHER_REASON:
+ reason = WLAN_REASON_UNSPECIFIED;
+ status = WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+ break;
+ }
+ if (status != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_DEBUG,
"WPA/RSN information element rejected? (res %u)",
res);
wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
- if (res == WPA_INVALID_GROUP) {
- reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
- status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
- } else if (res == WPA_INVALID_PAIRWISE) {
- reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
- status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
- } else if (res == WPA_INVALID_AKMP) {
- reason = WLAN_REASON_AKMP_NOT_VALID;
- status = WLAN_STATUS_AKMP_NOT_VALID;
- }
-#ifdef CONFIG_IEEE80211W
- else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
- reason = WLAN_REASON_INVALID_IE;
- status = WLAN_STATUS_INVALID_IE;
- } else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
- reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
- status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
- }
-#endif /* CONFIG_IEEE80211W */
- else {
- reason = WLAN_REASON_INVALID_IE;
- status = WLAN_STATUS_INVALID_IE;
- }
goto fail;
}
-#ifdef CONFIG_IEEE80211W
+
if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
(WLAN_STA_ASSOC | WLAN_STA_MFP) &&
!sta->sa_query_timed_out &&
@@ -386,7 +420,6 @@
sta->flags |= WLAN_STA_MFP;
else
sta->flags &= ~WLAN_STA_MFP;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R_AP
if (sta->auth_alg == WLAN_AUTH_FT) {
@@ -403,6 +436,20 @@
}
}
#endif /* CONFIG_IEEE80211R_AP */
+#ifdef CONFIG_SAE
+ if (hapd->conf->sae_pwe == 2 &&
+ sta->auth_alg == WLAN_AUTH_SAE &&
+ sta->sae && sta->sae->tmp && !sta->sae->tmp->h2e &&
+ elems.rsnxe && elems.rsnxe_len >= 1 &&
+ (elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
+ wpa_printf(MSG_INFO, "SAE: " MACSTR
+ " indicates support for SAE H2E, but did not use it",
+ MAC2STR(sta->addr));
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ reason = WLAN_REASON_UNSPECIFIED;
+ goto fail;
+ }
+#endif /* CONFIG_SAE */
} else if (hapd->conf->wps_state) {
#ifdef CONFIG_WPS
struct wpabuf *wps;
@@ -455,6 +502,9 @@
return WLAN_STATUS_INVALID_IE;
#endif /* CONFIG_HS20 */
}
+#ifdef CONFIG_WPS
+skip_wpa_check:
+#endif /* CONFIG_WPS */
#ifdef CONFIG_MBO
if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
@@ -466,13 +516,10 @@
}
#endif /* CONFIG_MBO */
-#ifdef CONFIG_WPS
-skip_wpa_check:
-#endif /* CONFIG_WPS */
-
#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);
+ sta->auth_alg, req_ies, req_ies_len,
+ !elems.rsnxe);
if (!p) {
wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -559,22 +606,24 @@
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
elems.owe_dh) {
u8 *npos;
+ u16 ret_status;
npos = owe_assoc_req_process(hapd, sta,
elems.owe_dh, elems.owe_dh_len,
p, sizeof(buf) - (p - buf),
- &reason);
+ &ret_status);
+ status = ret_status;
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,
+ status == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
+ hostapd_sta_assoc(hapd, addr, reassoc, ret_status, buf,
p - buf);
return 0;
}
- if (!npos || reason != WLAN_STATUS_SUCCESS)
+ if (!npos || status != WLAN_STATUS_SUCCESS)
goto fail;
}
#endif /* CONFIG_OWE */
@@ -611,6 +660,11 @@
pfs_fail:
#endif /* CONFIG_DPP2 */
+ if (elems.rrm_enabled &&
+ elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
+ os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled,
+ sizeof(sta->rrm_enabled_capa));
+
#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
@@ -657,7 +711,8 @@
fail:
#ifdef CONFIG_IEEE80211R_AP
- hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
+ if (status >= 0)
+ hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
#endif /* CONFIG_IEEE80211R_AP */
hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
ap_free_sta(hapd, sta);
@@ -695,6 +750,7 @@
ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ hostapd_set_sta_flags(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
@@ -785,7 +841,8 @@
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
- int offset, int width, int cf1, int cf2)
+ int offset, int width, int cf1, int cf2,
+ int finished)
{
/* TODO: If OCV is enabled deauth STAs that don't perform a SA Query */
@@ -796,7 +853,8 @@
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
- "driver had channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
+ "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
+ finished ? "had" : "starting",
freq, ht, hapd->iconf->ch_switch_vht_config, offset,
width, channel_width_to_string(width), cf1, cf2);
@@ -819,19 +877,19 @@
switch (width) {
case CHAN_WIDTH_80:
- chwidth = VHT_CHANWIDTH_80MHZ;
+ chwidth = CHANWIDTH_80MHZ;
break;
case CHAN_WIDTH_80P80:
- chwidth = VHT_CHANWIDTH_80P80MHZ;
+ chwidth = CHANWIDTH_80P80MHZ;
break;
case CHAN_WIDTH_160:
- chwidth = VHT_CHANWIDTH_160MHZ;
+ chwidth = CHANWIDTH_160MHZ;
break;
case CHAN_WIDTH_20_NOHT:
case CHAN_WIDTH_20:
case CHAN_WIDTH_40:
default:
- chwidth = VHT_CHANWIDTH_USE_HT;
+ chwidth = CHANWIDTH_USE_HT;
break;
}
@@ -864,13 +922,22 @@
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;
+ hostapd_set_oper_chwidth(hapd->iconf, chwidth);
+ hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, seg0_idx);
+ hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, seg1_idx);
is_dfs = ieee80211_is_dfs(freq, hapd->iface->hw_features,
hapd->iface->num_hw_features);
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ "%sfreq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d dfs=%d",
+ finished ? WPA_EVENT_CHANNEL_SWITCH :
+ WPA_EVENT_CHANNEL_SWITCH_STARTED,
+ freq, ht, offset, channel_width_to_string(width),
+ cf1, cf2, is_dfs);
+ if (!finished)
+ return;
+
if (hapd->csa_in_progress &&
freq == hapd->cs_freq_params.freq) {
hostapd_cleanup_cs_params(hapd);
@@ -881,6 +948,12 @@
} else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
"freq=%d dfs=%d", freq, is_dfs);
+ } else if (is_dfs &&
+ hostapd_is_dfs_required(hapd->iface) &&
+ !hostapd_is_dfs_chan_available(hapd->iface) &&
+ !hapd->iface->cac_started) {
+ hostapd_disable_iface(hapd->iface);
+ hostapd_enable_iface(hapd->iface);
}
for (i = 0; i < hapd->iface->num_bss; i++)
@@ -911,6 +984,7 @@
{
int ret, i;
int err = 0;
+ struct hostapd_channel_data *pri_chan;
if (hapd->iconf->channel) {
wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
@@ -918,12 +992,20 @@
return;
}
+ hapd->iface->freq = acs_res->pri_freq;
+
if (!hapd->iface->current_mode) {
for (i = 0; i < hapd->iface->num_hw_features; i++) {
struct hostapd_hw_modes *mode =
&hapd->iface->hw_features[i];
if (mode->mode == acs_res->hw_mode) {
+ if (hapd->iface->freq > 0 &&
+ !hw_get_chan(mode->mode,
+ hapd->iface->freq,
+ hapd->iface->hw_features,
+ hapd->iface->num_hw_features))
+ continue;
hapd->iface->current_mode = mode;
break;
}
@@ -937,24 +1019,33 @@
}
}
- hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel);
-
- if (!acs_res->pri_channel) {
+ if (!acs_res->pri_freq) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"driver switched to bad channel");
err = 1;
goto out;
}
+ pri_chan = hw_get_channel_freq(hapd->iface->current_mode->mode,
+ acs_res->pri_freq, NULL,
+ hapd->iface->hw_features,
+ hapd->iface->num_hw_features);
+ if (!pri_chan) {
+ wpa_printf(MSG_ERROR,
+ "ACS: Could not determine primary channel number from pri_freq %u",
+ acs_res->pri_freq);
+ err = 1;
+ goto out;
+ }
- hapd->iconf->channel = acs_res->pri_channel;
+ hapd->iconf->channel = pri_chan->chan;
hapd->iconf->acs = 1;
- if (acs_res->sec_channel == 0)
+ if (acs_res->sec_freq == 0)
hapd->iconf->secondary_channel = 0;
- else if (acs_res->sec_channel < acs_res->pri_channel)
+ else if (acs_res->sec_freq < acs_res->pri_freq)
hapd->iconf->secondary_channel = -1;
- else if (acs_res->sec_channel > acs_res->pri_channel)
+ else if (acs_res->sec_freq > acs_res->pri_freq)
hapd->iconf->secondary_channel = 1;
else {
wpa_printf(MSG_ERROR, "Invalid secondary channel!");
@@ -962,29 +1053,35 @@
goto out;
}
- if (hapd->iface->conf->ieee80211ac) {
+ hapd->iconf->edmg_channel = acs_res->edmg_channel;
+
+ if (hapd->iface->conf->ieee80211ac || hapd->iface->conf->ieee80211ax) {
/* set defaults for backwards compatibility */
- hapd->iconf->vht_oper_centr_freq_seg1_idx = 0;
- hapd->iconf->vht_oper_centr_freq_seg0_idx = 0;
- hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
- if (acs_res->ch_width == 80) {
- hapd->iconf->vht_oper_centr_freq_seg0_idx =
- acs_res->vht_seg0_center_ch;
- hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
- } else if (acs_res->ch_width == 160) {
+ hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0);
+ hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, 0);
+ hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_USE_HT);
+ if (acs_res->ch_width == 40) {
+ if (is_6ghz_freq(acs_res->pri_freq))
+ hostapd_set_oper_centr_freq_seg0_idx(
+ hapd->iconf,
+ acs_res->vht_seg0_center_ch);
+ } else if (acs_res->ch_width == 80) {
+ hostapd_set_oper_centr_freq_seg0_idx(
+ hapd->iconf, acs_res->vht_seg0_center_ch);
if (acs_res->vht_seg1_center_ch == 0) {
- hapd->iconf->vht_oper_centr_freq_seg0_idx =
- acs_res->vht_seg0_center_ch;
- hapd->iconf->vht_oper_chwidth =
- VHT_CHANWIDTH_160MHZ;
+ hostapd_set_oper_chwidth(hapd->iconf,
+ CHANWIDTH_80MHZ);
} else {
- hapd->iconf->vht_oper_centr_freq_seg0_idx =
- acs_res->vht_seg0_center_ch;
- hapd->iconf->vht_oper_centr_freq_seg1_idx =
- acs_res->vht_seg1_center_ch;
- hapd->iconf->vht_oper_chwidth =
- VHT_CHANWIDTH_80P80MHZ;
+ hostapd_set_oper_chwidth(hapd->iconf,
+ CHANWIDTH_80P80MHZ);
+ hostapd_set_oper_centr_freq_seg1_idx(
+ hapd->iconf,
+ acs_res->vht_seg1_center_ch);
}
+ } else if (acs_res->ch_width == 160) {
+ hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_160MHZ);
+ hostapd_set_oper_centr_freq_seg0_idx(
+ hapd->iconf, acs_res->vht_seg1_center_ch);
}
}
@@ -1163,12 +1260,10 @@
return;
}
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
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);
@@ -1382,15 +1477,33 @@
#endif /* HOSTAPD */
+static struct hostapd_channel_data *
+hostapd_get_mode_chan(struct hostapd_hw_modes *mode, unsigned int freq)
+{
+ int i;
+ struct hostapd_channel_data *chan;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
+ if ((unsigned int) chan->freq == freq)
+ return chan;
+ }
+
+ return NULL;
+}
+
+
static struct hostapd_channel_data * hostapd_get_mode_channel(
struct hostapd_iface *iface, unsigned int freq)
{
int i;
struct hostapd_channel_data *chan;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
- if ((unsigned int) chan->freq == freq)
+ for (i = 0; i < iface->num_hw_features; i++) {
+ if (hostapd_hw_skip_mode(iface, &iface->hw_features[i]))
+ continue;
+ chan = hostapd_get_mode_chan(&iface->hw_features[i], freq);
+ if (chan)
return chan;
}
@@ -1588,6 +1701,73 @@
}
+#ifdef CONFIG_OWE
+static int hostapd_notif_update_dh_ie(struct hostapd_data *hapd,
+ const u8 *peer, const u8 *ie,
+ size_t ie_len)
+{
+ u16 status;
+ struct sta_info *sta;
+ struct ieee802_11_elems elems;
+
+ if (!hapd || !hapd->wpa_auth) {
+ wpa_printf(MSG_DEBUG, "OWE: Invalid hapd context");
+ return -1;
+ }
+ if (!peer) {
+ wpa_printf(MSG_DEBUG, "OWE: Peer unknown");
+ return -1;
+ }
+ if (!(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE)) {
+ wpa_printf(MSG_DEBUG, "OWE: No OWE AKM configured");
+ status = WLAN_STATUS_AKMP_NOT_VALID;
+ goto err;
+ }
+ if (ieee802_11_parse_elems(ie, ie_len, &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG, "OWE: Failed to parse OWE IE for "
+ MACSTR, MAC2STR(peer));
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto err;
+ }
+ status = owe_validate_request(hapd, peer, elems.rsn_ie,
+ elems.rsn_ie_len,
+ elems.owe_dh, elems.owe_dh_len);
+ if (status != WLAN_STATUS_SUCCESS)
+ goto err;
+
+ sta = ap_get_sta(hapd, peer);
+ if (sta) {
+ ap_sta_no_session_timeout(hapd, sta);
+ accounting_sta_stop(hapd, sta);
+
+ /*
+ * Make sure that the previously registered inactivity timer
+ * will not remove the STA immediately.
+ */
+ sta->timeout_next = STA_NULLFUNC;
+ } else {
+ sta = ap_sta_add(hapd, peer);
+ if (!sta) {
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto err;
+ }
+ }
+ sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
+
+ status = owe_process_rsn_ie(hapd, sta, elems.rsn_ie,
+ elems.rsn_ie_len, elems.owe_dh,
+ elems.owe_dh_len);
+ if (status != WLAN_STATUS_SUCCESS)
+ ap_free_sta(hapd, sta);
+
+ return 0;
+err:
+ hostapd_drv_update_dh_ie(hapd, peer, status, NULL, 0);
+ return 0;
+}
+#endif /* CONFIG_OWE */
+
+
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
@@ -1693,6 +1873,15 @@
data->assoc_info.req_ies_len,
data->assoc_info.reassoc);
break;
+#ifdef CONFIG_OWE
+ case EVENT_UPDATE_DH:
+ if (!data)
+ return;
+ hostapd_notif_update_dh_ie(hapd, data->update_dh.peer,
+ data->update_dh.ie,
+ data->update_dh.ie_len);
+ break;
+#endif /* CONFIG_OWE */
case EVENT_DISASSOC:
if (data)
hostapd_notif_disassoc(hapd, data->disassoc_info.addr);
@@ -1709,6 +1898,7 @@
case EVENT_AUTH:
hostapd_notif_auth(hapd, &data->auth);
break;
+ case EVENT_CH_SWITCH_STARTED:
case EVENT_CH_SWITCH:
if (!data)
break;
@@ -1717,7 +1907,8 @@
data->ch_switch.ch_offset,
data->ch_switch.ch_width,
data->ch_switch.cf1,
- data->ch_switch.cf2);
+ data->ch_switch.cf2,
+ event == EVENT_CH_SWITCH);
break;
case EVENT_CONNECT_FAILED_REASON:
if (!data)
diff --git a/src/ap/fils_hlp.c b/src/ap/fils_hlp.c
index 6da514a..0310aab 100644
--- a/src/ap/fils_hlp.c
+++ b/src/ap/fils_hlp.c
@@ -158,7 +158,7 @@
ssize_t res;
u8 msgtype = 0;
int rapid_commit = 0;
- struct iphdr *iph;
+ struct ip *iph;
struct udphdr *udph;
struct wpabuf *resp;
const u8 *rpos;
@@ -259,14 +259,14 @@
wpabuf_put_data(resp, "\xaa\xaa\x03\x00\x00\x00", 6);
wpabuf_put_be16(resp, ETH_P_IP);
iph = wpabuf_put(resp, sizeof(*iph));
- iph->version = 4;
- iph->ihl = sizeof(*iph) / 4;
- iph->tot_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos));
- iph->ttl = 1;
- iph->protocol = 17; /* UDP */
- iph->saddr = hapd->conf->dhcp_server.u.v4.s_addr;
- iph->daddr = dhcp->client_ip;
- iph->check = ip_checksum(iph, sizeof(*iph));
+ iph->ip_v = 4;
+ iph->ip_hl = sizeof(*iph) / 4;
+ iph->ip_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos));
+ iph->ip_ttl = 1;
+ iph->ip_p = 17; /* UDP */
+ iph->ip_src.s_addr = hapd->conf->dhcp_server.u.v4.s_addr;
+ iph->ip_dst.s_addr = dhcp->client_ip;
+ iph->ip_sum = ip_checksum(iph, sizeof(*iph));
udph = wpabuf_put(resp, sizeof(*udph));
udph->uh_sport = htons(DHCP_SERVER_PORT);
udph->uh_dport = htons(DHCP_CLIENT_PORT);
@@ -479,13 +479,13 @@
struct sta_info *sta, const u8 *dst,
const u8 *pos, size_t len)
{
- const struct iphdr *iph;
+ const struct ip *iph;
const struct udphdr *udph;
u16 sport, dport, ulen;
if (len < sizeof(*iph) + sizeof(*udph))
return 0;
- iph = (const struct iphdr *) pos;
+ iph = (const struct ip *) pos;
udph = (const struct udphdr *) (iph + 1);
sport = ntohs(udph->uh_sport);
dport = ntohs(udph->uh_dport);
@@ -510,24 +510,24 @@
struct sta_info *sta, const u8 *dst,
const u8 *pos, size_t len)
{
- const struct iphdr *iph;
- u16 tot_len;
+ const struct ip *iph;
+ uint16_t ip_len;
if (len < sizeof(*iph))
return 0;
- iph = (const struct iphdr *) pos;
+ iph = (const struct ip *) pos;
if (ip_checksum(iph, sizeof(*iph)) != 0) {
wpa_printf(MSG_DEBUG,
"FILS: HLP request IPv4 packet had invalid header checksum - dropped");
return 0;
}
- tot_len = ntohs(iph->tot_len);
- if (tot_len > len)
+ ip_len = ntohs(iph->ip_len);
+ if (ip_len > len)
return 0;
wpa_printf(MSG_DEBUG,
"FILS: HLP request IPv4: saddr=%08x daddr=%08x protocol=%u",
- iph->saddr, iph->daddr, iph->protocol);
- switch (iph->protocol) {
+ iph->ip_src.s_addr, iph->ip_dst.s_addr, iph->ip_p);
+ switch (iph->ip_p) {
case 17:
return fils_process_hlp_udp(hapd, sta, dst, pos, len);
}
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index a7df810..9567e20 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -1522,9 +1522,9 @@
#ifdef CONFIG_DPP
-static void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
- const u8 *sa, u8 dialog_token,
- int prot, struct wpabuf *buf)
+void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
+ const u8 *sa, u8 dialog_token,
+ int prot, struct wpabuf *buf)
{
struct wpabuf *tx_buf;
@@ -1681,7 +1681,8 @@
if (dpp) {
struct wpabuf *msg;
- msg = hostapd_dpp_gas_req_handler(hapd, sa, pos, slen);
+ msg = hostapd_dpp_gas_req_handler(hapd, sa, pos, slen,
+ data, len);
if (!msg)
return;
gas_serv_req_dpp_processing(hapd, sa, dialog_token, prot, msg);
diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h
index 2cf1817..1528af4 100644
--- a/src/ap/gas_serv.h
+++ b/src/ap/gas_serv.h
@@ -88,4 +88,8 @@
int gas_serv_init(struct hostapd_data *hapd);
void gas_serv_deinit(struct hostapd_data *hapd);
+void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
+ const u8 *sa, u8 dialog_token,
+ int prot, struct wpabuf *buf);
+
#endif /* GAS_SERV_H */
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 0bd6892..5515ab3 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -7,9 +7,13 @@
*/
#include "utils/includes.h"
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
#include "utils/common.h"
#include "utils/eloop.h"
+#include "utils/crc32.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
#include "common/hw_features_common.h"
@@ -25,7 +29,6 @@
#include "accounting.h"
#include "ap_list.h"
#include "beacon.h"
-#include "iapp.h"
#include "ieee802_1x.h"
#include "ieee802_11_auth.h"
#include "vlan_init.h"
@@ -50,11 +53,15 @@
#include "fils_hlp.h"
#include "acs.h"
#include "hs20.h"
+#include "airtime_policy.h"
+#include "wpa_auth_kay.h"
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
+#ifdef CONFIG_WEP
static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
+#endif /* CONFIG_WEP */
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,
@@ -84,7 +91,9 @@
return;
hostapd_set_privacy(hapd, 0);
+#ifdef CONFIG_WEP
hostapd_setup_encryption(hapd->conf->iface, hapd);
+#endif /* CONFIG_WEP */
}
@@ -137,7 +146,9 @@
wpa_deinit(hapd->wpa_auth);
hapd->wpa_auth = NULL;
hostapd_set_privacy(hapd, 0);
+#ifdef CONFIG_WEP
hostapd_setup_encryption(hapd->conf->iface, hapd);
+#endif /* CONFIG_WEP */
hostapd_set_generic_elem(hapd, (u8 *) "", 0);
}
@@ -165,7 +176,9 @@
for (j = 0; j < iface->num_bss; j++) {
hostapd_flush_old_stations(iface->bss[j],
WLAN_REASON_PREV_AUTH_NOT_VALID);
+#ifdef CONFIG_WEP
hostapd_broadcast_wep_clear(iface->bss[j]);
+#endif /* CONFIG_WEP */
#ifndef CONFIG_NO_RADIUS
/* TODO: update dynamic data based on changed configuration
@@ -260,11 +273,14 @@
hapd->iconf->ieee80211ac = oldconf->ieee80211ac;
hapd->iconf->ht_capab = oldconf->ht_capab;
hapd->iconf->vht_capab = oldconf->vht_capab;
- hapd->iconf->vht_oper_chwidth = oldconf->vht_oper_chwidth;
- hapd->iconf->vht_oper_centr_freq_seg0_idx =
- oldconf->vht_oper_centr_freq_seg0_idx;
- hapd->iconf->vht_oper_centr_freq_seg1_idx =
- oldconf->vht_oper_centr_freq_seg1_idx;
+ hostapd_set_oper_chwidth(hapd->iconf,
+ hostapd_get_oper_chwidth(oldconf));
+ hostapd_set_oper_centr_freq_seg0_idx(
+ hapd->iconf,
+ hostapd_get_oper_centr_freq_seg0_idx(oldconf));
+ hostapd_set_oper_centr_freq_seg1_idx(
+ hapd->iconf,
+ hostapd_get_oper_centr_freq_seg1_idx(oldconf));
hapd->conf = newconf->bss[j];
hostapd_reload_bss(hapd);
}
@@ -276,6 +292,8 @@
}
+#ifdef CONFIG_WEP
+
static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
const char *ifname)
{
@@ -284,26 +302,24 @@
if (!ifname || !hapd->drv_priv)
return;
for (i = 0; i < NUM_WEP_KEYS; i++) {
- if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
- 0, NULL, 0, NULL, 0)) {
+ if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i, 0,
+ 0, NULL, 0, NULL, 0, KEY_FLAG_GROUP)) {
wpa_printf(MSG_DEBUG, "Failed to clear default "
"encryption keys (ifname=%s keyidx=%d)",
ifname, i);
}
}
-#ifdef CONFIG_IEEE80211W
if (hapd->conf->ieee80211w) {
for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) {
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE,
- NULL, i, 0, NULL,
- 0, NULL, 0)) {
+ NULL, i, 0, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_GROUP)) {
wpa_printf(MSG_DEBUG, "Failed to clear "
"default mgmt encryption keys "
"(ifname=%s keyidx=%d)", ifname, i);
}
}
}
-#endif /* CONFIG_IEEE80211W */
}
@@ -320,11 +336,12 @@
struct hostapd_ssid *ssid = &hapd->conf->ssid;
idx = ssid->wep.idx;
- if (ssid->wep.default_len &&
+ if (ssid->wep.default_len && ssid->wep.key[idx] &&
hostapd_drv_set_key(hapd->conf->iface,
- hapd, WPA_ALG_WEP, broadcast_ether_addr, idx,
+ hapd, WPA_ALG_WEP, broadcast_ether_addr, idx, 0,
1, NULL, 0, ssid->wep.key[idx],
- ssid->wep.len[idx])) {
+ ssid->wep.len[idx],
+ KEY_FLAG_GROUP_RX_TX_DEFAULT)) {
wpa_printf(MSG_WARNING, "Could not set WEP encryption.");
errors++;
}
@@ -332,6 +349,8 @@
return errors;
}
+#endif /* CONFIG_WEP */
+
static void hostapd_free_hapd_data(struct hostapd_data *hapd)
{
@@ -355,8 +374,6 @@
hapd->beacon_set_done = 0;
wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
- iapp_deinit(hapd->iapp);
- hapd->iapp = NULL;
accounting_deinit(hapd);
hostapd_deinit_wpa(hapd);
vlan_deinit(hapd);
@@ -369,6 +386,7 @@
#endif /* CONFIG_NO_RADIUS */
hostapd_deinit_wps(hapd);
+ ieee802_1x_dealloc_kay_sm_hapd(hapd);
#ifdef CONFIG_DPP
hostapd_dpp_deinit(hapd);
gas_query_ap_deinit(hapd->gas);
@@ -475,11 +493,9 @@
static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
{
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
-#ifdef CONFIG_IEEE80211N
#ifdef NEED_AP_MLME
hostapd_stop_setup_timers(iface);
#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211N */
if (iface->current_mode)
acs_cleanup(iface);
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
@@ -491,6 +507,7 @@
iface->basic_rates = NULL;
ap_list_deinit(iface);
sta_track_deinit(iface);
+ airtime_policy_update_deinit(iface);
}
@@ -519,6 +536,8 @@
}
+#ifdef CONFIG_WEP
+
static void hostapd_clear_wep(struct hostapd_data *hapd)
{
if (hapd->drv_priv && !hapd->iface->driver_ap_teardown && hapd->conf) {
@@ -547,10 +566,13 @@
for (i = 0; i < 4; i++) {
if (hapd->conf->ssid.wep.key[i] &&
- hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i,
+ hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i, 0,
i == hapd->conf->ssid.wep.idx, NULL, 0,
hapd->conf->ssid.wep.key[i],
- hapd->conf->ssid.wep.len[i])) {
+ hapd->conf->ssid.wep.len[i],
+ i == hapd->conf->ssid.wep.idx ?
+ KEY_FLAG_GROUP_RX_TX_DEFAULT :
+ KEY_FLAG_GROUP_RX_TX)) {
wpa_printf(MSG_WARNING, "Could not set WEP "
"encryption.");
return -1;
@@ -563,6 +585,8 @@
return 0;
}
+#endif /* CONFIG_WEP */
+
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
{
@@ -598,7 +622,9 @@
{
hostapd_free_stas(hapd);
hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
+#ifdef CONFIG_WEP
hostapd_clear_wep(hapd);
+#endif /* CONFIG_WEP */
}
@@ -1018,6 +1044,43 @@
#define hostapd_das_coa NULL
#endif /* CONFIG_HS20 */
+
+#ifdef CONFIG_SQLITE
+
+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_radius_attributes(sqlite3 *db)
+{
+ char *err = NULL;
+ const char *sql =
+ "CREATE TABLE radius_attributes("
+ " id INTEGER PRIMARY KEY,"
+ " sta TEXT,"
+ " reqtype TEXT,"
+ " attr TEXT"
+ ");"
+ "CREATE INDEX idx_sta_reqtype ON radius_attributes(sta,reqtype);";
+
+ wpa_printf(MSG_DEBUG,
+ "Adding database table for RADIUS attribute information");
+ if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
+ wpa_printf(MSG_ERROR, "SQLite error: %s", err);
+ sqlite3_free(err);
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_SQLITE */
+
#endif /* CONFIG_NO_RADIUS */
@@ -1116,9 +1179,11 @@
WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_set_privacy(hapd, 0);
+#ifdef CONFIG_WEP
hostapd_broadcast_wep_clear(hapd);
if (hostapd_setup_encryption(conf->iface, hapd))
return -1;
+#endif /* CONFIG_WEP */
/*
* Fetch the SSID from the system and use it or,
@@ -1148,8 +1213,14 @@
os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len);
}
+ /*
+ * Short SSID calculation is identical to FCS and it is defined in
+ * IEEE P802.11-REVmd/D3.0, 9.4.2.170.3 (Calculating the Short-SSID).
+ */
+ conf->ssid.short_ssid = crc32(conf->ssid.ssid, conf->ssid.ssid_len);
+
if (!hostapd_drv_none(hapd)) {
- wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR
+ wpa_printf(MSG_DEBUG, "Using interface %s with hwaddr " MACSTR
" and ssid \"%s\"",
conf->iface, MAC2STR(hapd->own_addr),
wpa_ssid_txt(conf->ssid.ssid, conf->ssid.ssid_len));
@@ -1171,6 +1242,24 @@
if (wpa_debug_level <= MSG_MSGDUMP)
conf->radius->msg_dumps = 1;
#ifndef CONFIG_NO_RADIUS
+
+#ifdef CONFIG_SQLITE
+ if (conf->radius_req_attr_sqlite) {
+ if (sqlite3_open(conf->radius_req_attr_sqlite,
+ &hapd->rad_attr_db)) {
+ wpa_printf(MSG_ERROR, "Could not open SQLite file '%s'",
+ conf->radius_req_attr_sqlite);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "Opening RADIUS attribute database: %s",
+ conf->radius_req_attr_sqlite);
+ if (!db_table_exists(hapd->rad_attr_db, "radius_attributes") &&
+ db_table_create_radius_attributes(hapd->rad_attr_db) < 0)
+ return -1;
+ }
+#endif /* CONFIG_SQLITE */
+
hapd->radius = radius_client_init(hapd, conf->radius);
if (hapd->radius == NULL) {
wpa_printf(MSG_ERROR, "RADIUS client initialization failed.");
@@ -1233,13 +1322,6 @@
return -1;
}
- if (conf->ieee802_11f &&
- (hapd->iapp = iapp_init(hapd, conf->iapp_iface)) == NULL) {
- wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization "
- "failed.");
- return -1;
- }
-
#ifdef CONFIG_INTERWORKING
if (gas_serv_init(hapd)) {
wpa_printf(MSG_ERROR, "GAS server initialization failed");
@@ -1519,6 +1601,51 @@
}
+static int configured_fixed_chan_to_freq(struct hostapd_iface *iface)
+{
+ int freq, i, j;
+
+ if (!iface->conf->channel)
+ return 0;
+ if (iface->conf->op_class) {
+ freq = ieee80211_chan_to_freq(NULL, iface->conf->op_class,
+ iface->conf->channel);
+ if (freq < 0) {
+ wpa_printf(MSG_INFO,
+ "Could not convert op_class %u channel %u to operating frequency",
+ iface->conf->op_class, iface->conf->channel);
+ return -1;
+ }
+ iface->freq = freq;
+ return 0;
+ }
+
+ /* Old configurations using only 2.4/5/60 GHz bands may not specify the
+ * op_class parameter. Select a matching channel from the configured
+ * mode using the channel parameter for these cases.
+ */
+ for (j = 0; j < iface->num_hw_features; j++) {
+ struct hostapd_hw_modes *mode = &iface->hw_features[j];
+
+ if (iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY &&
+ iface->conf->hw_mode != mode->mode)
+ continue;
+ for (i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *chan = &mode->channels[i];
+
+ if (chan->chan == iface->conf->channel &&
+ !is_6ghz_freq(chan->freq)) {
+ iface->freq = chan->freq;
+ return 0;
+ }
+ }
+ }
+
+ wpa_printf(MSG_INFO, "Could not determine operating frequency");
+ return -1;
+}
+
+
static int setup_interface2(struct hostapd_iface *iface)
{
iface->wait_channel_update = 0;
@@ -1527,7 +1654,20 @@
/* Not all drivers support this yet, so continue without hw
* feature data. */
} else {
- int ret = hostapd_select_hw_mode(iface);
+ int ret;
+
+ ret = configured_fixed_chan_to_freq(iface);
+ if (ret < 0)
+ goto fail;
+
+ if (iface->conf->op_class) {
+ int ch_width;
+
+ ch_width = op_class_to_ch_width(iface->conf->op_class);
+ hostapd_set_oper_chwidth(iface->conf, ch_width);
+ }
+
+ ret = hostapd_select_hw_mode(iface);
if (ret < 0) {
wpa_printf(MSG_ERROR, "Could not select hw_mode and "
"channel. (%d)", ret);
@@ -1537,6 +1677,9 @@
wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback (ACS)");
return 0;
}
+ ret = hostapd_check_edmg_capab(iface);
+ if (ret < 0)
+ goto fail;
ret = hostapd_check_ht_capab(iface);
if (ret < 0)
goto fail;
@@ -1629,7 +1772,7 @@
static const u8 * fst_hostapd_get_sta(struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+ bool mb_only)
{
struct sta_info *s = (struct sta_info *) *get_ctx;
@@ -1651,7 +1794,7 @@
static const u8 * fst_hostapd_get_peer_first(void *ctx,
struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+ bool mb_only)
{
struct hostapd_data *hapd = ctx;
@@ -1663,7 +1806,7 @@
static const u8 * fst_hostapd_get_peer_next(void *ctx,
struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+ bool mb_only)
{
return fst_hostapd_get_sta(get_ctx, mb_only);
}
@@ -1808,12 +1951,11 @@
goto fail;
wpa_printf(MSG_DEBUG, "Completing interface initialization");
- if (iface->conf->channel) {
+ if (iface->freq) {
#ifdef NEED_AP_MLME
int res;
#endif /* NEED_AP_MLME */
- iface->freq = hostapd_hw_get_freq(hapd, iface->conf->channel);
wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d "
"Frequency: %d MHz",
hostapd_hw_mode_txt(iface->conf->hw_mode),
@@ -1861,12 +2003,17 @@
if (!delay_apply_cfg &&
hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
hapd->iconf->channel,
+ hapd->iconf->enable_edmg,
+ hapd->iconf->edmg_channel,
hapd->iconf->ieee80211n,
hapd->iconf->ieee80211ac,
+ hapd->iconf->ieee80211ax,
hapd->iconf->secondary_channel,
- hapd->iconf->vht_oper_chwidth,
- hapd->iconf->vht_oper_centr_freq_seg0_idx,
- hapd->iconf->vht_oper_centr_freq_seg1_idx)) {
+ hostapd_get_oper_chwidth(hapd->iconf),
+ hostapd_get_oper_centr_freq_seg0_idx(
+ hapd->iconf),
+ hostapd_get_oper_centr_freq_seg1_idx(
+ hapd->iconf))) {
wpa_printf(MSG_ERROR, "Could not set channel for "
"kernel driver");
goto fail;
@@ -1976,6 +2123,7 @@
hostapd_set_state(iface, HAPD_IFACE_ENABLED);
hostapd_owe_update_trans(iface);
+ airtime_policy_update_init(iface);
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
if (hapd->setup_complete_cb)
hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
@@ -2183,6 +2331,12 @@
hapd->conf ? hapd->conf->iface : "N/A");
hostapd_bss_deinit_no_free(hapd);
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
+#ifdef CONFIG_SQLITE
+ if (hapd->rad_attr_db) {
+ sqlite3_close(hapd->rad_attr_db);
+ hapd->rad_attr_db = NULL;
+ }
+#endif /* CONFIG_SQLITE */
hostapd_cleanup(hapd);
}
@@ -2213,12 +2367,10 @@
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 */
}
@@ -2983,10 +3135,6 @@
hostapd_prune_associations(hapd, sta->addr);
ap_sta_clear_disconnect_timeouts(hapd, sta);
- /* IEEE 802.11F (IAPP) */
- if (hapd->conf->ieee802_11f)
- iapp_new_station(hapd->iapp, sta);
-
#ifdef CONFIG_P2P
if (sta->p2p_ie == NULL && !sta->no_p2p_set) {
sta->no_p2p_set = 1;
@@ -2996,6 +3144,8 @@
}
#endif /* CONFIG_P2P */
+ airtime_policy_new_sta(hapd, sta);
+
/* Start accounting here, if IEEE 802.1X and WPA are not used.
* IEEE 802.1X/WPA code will start accounting after the station has
* been authorized. */
@@ -3036,6 +3186,14 @@
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
ap_handle_timer, hapd, sta);
}
+
+#ifdef CONFIG_MACSEC
+ if (hapd->conf->wpa_key_mgmt == WPA_KEY_MGMT_NONE &&
+ hapd->conf->mka_psk_set)
+ ieee802_1x_create_preshared_mka_hapd(hapd, sta);
+ else
+ ieee802_1x_alloc_kay_sm_hapd(hapd, sta);
+#endif /* CONFIG_MACSEC */
}
@@ -3195,6 +3353,8 @@
struct hostapd_freq_params *old_params)
{
int channel;
+ u8 seg0, seg1;
+ struct hostapd_hw_modes *mode;
if (!params->channel) {
/* check if the new channel is supported by hw */
@@ -3205,33 +3365,38 @@
if (!channel)
return -1;
+ mode = hapd->iface->current_mode;
+
/* if a pointer to old_params is provided we save previous state */
if (old_params &&
hostapd_set_freq_params(old_params, conf->hw_mode,
hostapd_hw_get_freq(hapd, conf->channel),
- conf->channel, conf->ieee80211n,
- conf->ieee80211ac,
+ conf->channel, conf->enable_edmg,
+ conf->edmg_channel, conf->ieee80211n,
+ conf->ieee80211ac, conf->ieee80211ax,
conf->secondary_channel,
- conf->vht_oper_chwidth,
- conf->vht_oper_centr_freq_seg0_idx,
- conf->vht_oper_centr_freq_seg1_idx,
- conf->vht_capab))
+ hostapd_get_oper_chwidth(conf),
+ hostapd_get_oper_centr_freq_seg0_idx(conf),
+ hostapd_get_oper_centr_freq_seg1_idx(conf),
+ conf->vht_capab,
+ mode ? &mode->he_capab[IEEE80211_MODE_AP] :
+ NULL))
return -1;
switch (params->bandwidth) {
case 0:
case 20:
case 40:
- conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
+ hostapd_set_oper_chwidth(conf, CHANWIDTH_USE_HT);
break;
case 80:
if (params->center_freq2)
- conf->vht_oper_chwidth = VHT_CHANWIDTH_80P80MHZ;
+ hostapd_set_oper_chwidth(conf, CHANWIDTH_80P80MHZ);
else
- conf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
+ hostapd_set_oper_chwidth(conf, CHANWIDTH_80MHZ);
break;
case 160:
- conf->vht_oper_chwidth = VHT_CHANWIDTH_160MHZ;
+ hostapd_set_oper_chwidth(conf, CHANWIDTH_160MHZ);
break;
default:
return -1;
@@ -3241,9 +3406,11 @@
conf->ieee80211n = params->ht_enabled;
conf->secondary_channel = params->sec_channel_offset;
ieee80211_freq_to_chan(params->center_freq1,
- &conf->vht_oper_centr_freq_seg0_idx);
+ &seg0);
ieee80211_freq_to_chan(params->center_freq2,
- &conf->vht_oper_centr_freq_seg1_idx);
+ &seg1);
+ hostapd_set_oper_centr_freq_seg0_idx(conf, seg0);
+ hostapd_set_oper_centr_freq_seg1_idx(conf, seg1);
/* TODO: maybe call here hostapd_config_check here? */
@@ -3257,7 +3424,7 @@
struct hostapd_iface *iface = hapd->iface;
struct hostapd_freq_params old_freq;
int ret;
- u8 chan, vht_bandwidth;
+ u8 chan, bandwidth;
os_memset(&old_freq, 0, sizeof(old_freq));
if (!iface || !iface->freq || hapd->csa_in_progress)
@@ -3266,29 +3433,30 @@
switch (settings->freq_params.bandwidth) {
case 80:
if (settings->freq_params.center_freq2)
- vht_bandwidth = VHT_CHANWIDTH_80P80MHZ;
+ bandwidth = CHANWIDTH_80P80MHZ;
else
- vht_bandwidth = VHT_CHANWIDTH_80MHZ;
+ bandwidth = CHANWIDTH_80MHZ;
break;
case 160:
- vht_bandwidth = VHT_CHANWIDTH_160MHZ;
+ bandwidth = CHANWIDTH_160MHZ;
break;
default:
- vht_bandwidth = VHT_CHANWIDTH_USE_HT;
+ bandwidth = CHANWIDTH_USE_HT;
break;
}
if (ieee80211_freq_to_channel_ext(
settings->freq_params.freq,
settings->freq_params.sec_channel_offset,
- vht_bandwidth,
+ bandwidth,
&hapd->iface->cs_oper_class,
&chan) == NUM_HOSTAPD_MODES) {
wpa_printf(MSG_DEBUG,
- "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d)",
+ "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d, he_enabled=%d)",
settings->freq_params.freq,
settings->freq_params.sec_channel_offset,
- settings->freq_params.vht_enabled);
+ settings->freq_params.vht_enabled,
+ settings->freq_params.he_enabled);
return -1;
}
@@ -3388,29 +3556,29 @@
hostapd_switch_channel_fallback(struct hostapd_iface *iface,
const struct hostapd_freq_params *freq_params)
{
- int vht_seg0_idx = 0, vht_seg1_idx = 0, vht_bw = VHT_CHANWIDTH_USE_HT;
+ int seg0_idx = 0, seg1_idx = 0, bw = CHANWIDTH_USE_HT;
wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes");
if (freq_params->center_freq1)
- vht_seg0_idx = 36 + (freq_params->center_freq1 - 5180) / 5;
+ seg0_idx = 36 + (freq_params->center_freq1 - 5180) / 5;
if (freq_params->center_freq2)
- vht_seg1_idx = 36 + (freq_params->center_freq2 - 5180) / 5;
+ seg1_idx = 36 + (freq_params->center_freq2 - 5180) / 5;
switch (freq_params->bandwidth) {
case 0:
case 20:
case 40:
- vht_bw = VHT_CHANWIDTH_USE_HT;
+ bw = CHANWIDTH_USE_HT;
break;
case 80:
if (freq_params->center_freq2)
- vht_bw = VHT_CHANWIDTH_80P80MHZ;
+ bw = CHANWIDTH_80P80MHZ;
else
- vht_bw = VHT_CHANWIDTH_80MHZ;
+ bw = CHANWIDTH_80MHZ;
break;
case 160:
- vht_bw = VHT_CHANWIDTH_160MHZ;
+ bw = CHANWIDTH_160MHZ;
break;
default:
wpa_printf(MSG_WARNING, "Unknown CSA bandwidth: %d",
@@ -3421,11 +3589,12 @@
iface->freq = freq_params->freq;
iface->conf->channel = freq_params->channel;
iface->conf->secondary_channel = freq_params->sec_channel_offset;
- iface->conf->vht_oper_centr_freq_seg0_idx = vht_seg0_idx;
- iface->conf->vht_oper_centr_freq_seg1_idx = vht_seg1_idx;
- iface->conf->vht_oper_chwidth = vht_bw;
+ hostapd_set_oper_centr_freq_seg0_idx(iface->conf, seg0_idx);
+ hostapd_set_oper_centr_freq_seg1_idx(iface->conf, seg1_idx);
+ hostapd_set_oper_chwidth(iface->conf, bw);
iface->conf->ieee80211n = freq_params->ht_enabled;
iface->conf->ieee80211ac = freq_params->vht_enabled;
+ iface->conf->ieee80211ax = freq_params->he_enabled;
/*
* cs_params must not be cleared earlier because the freq_params
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 607bb95..c8f691e 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -9,6 +9,10 @@
#ifndef HOSTAPD_H
#define HOSTAPD_H
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
+
#include "common/defs.h"
#include "utils/list.h"
#include "ap_config.h"
@@ -34,6 +38,10 @@
struct mesh_conf;
#endif /* CONFIG_MESH */
+#ifdef CONFIG_CTRL_IFACE_UDP
+#define CTRL_IFACE_COOKIE_LEN 8
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
struct hostapd_iface;
struct hapd_interfaces {
@@ -68,6 +76,11 @@
#ifdef CONFIG_DPP
struct dpp_global *dpp;
#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+ unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
};
enum hostapd_chan_status {
@@ -175,13 +188,12 @@
u64 acct_session_id;
struct radius_das_data *radius_das;
- struct iapp_data *iapp;
-
struct hostapd_cached_radius_acl *acl_cache;
struct hostapd_acl_query_data *acl_queries;
struct wpa_authenticator *wpa_auth;
struct eapol_authenticator *eapol_auth;
+ struct eap_config *eap_cfg;
struct rsn_preauth_interface *preauth_iface;
struct os_reltime michael_mic_failure;
@@ -232,6 +244,10 @@
struct wps_stat wps_stats;
#endif /* CONFIG_WPS */
+#ifdef CONFIG_MACSEC
+ struct ieee802_1x_kay *kay;
+#endif /* CONFIG_MACSEC */
+
struct hostapd_probereq_cb *probereq_cb;
size_t num_probereq_cb;
@@ -329,12 +345,10 @@
u8 last_gtk[WPA_GTK_MAX_LEN];
size_t last_gtk_len;
-#ifdef CONFIG_IEEE80211W
enum wpa_alg last_igtk_alg;
int last_igtk_key_idx;
u8 last_igtk[WPA_IGTK_MAX_LEN];
size_t last_igtk_len;
-#endif /* CONFIG_IEEE80211W */
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_MBO
@@ -379,6 +393,21 @@
unsigned int dpp_ignore_netaccesskey_mismatch:1;
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_AIRTIME_POLICY
+ unsigned int num_backlogged_sta;
+ unsigned int airtime_weight;
+#endif /* CONFIG_AIRTIME_POLICY */
+
+ u8 last_1x_eapol_key_replay_counter[8];
+
+#ifdef CONFIG_SQLITE
+ sqlite3 *rad_attr_db;
+#endif /* CONFIG_SQLITE */
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+ unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
+#endif /* CONFIG_CTRL_IFACE_UDP */
};
@@ -447,9 +476,7 @@
struct ap_info *ap_hash[STA_HASH_SIZE];
u64 drv_flags;
-
- /* SMPS modes supported by the driver (WPA_DRIVER_SMPS_MODE_*) */
- unsigned int smps_modes;
+ u64 drv_flags2;
/*
* A bitmap of supported protocols for probe response offload. See
@@ -542,6 +569,12 @@
unsigned int num_sta_seen;
u8 dfs_domain;
+#ifdef CONFIG_AIRTIME_POLICY
+ unsigned int airtime_quantum;
+#endif /* CONFIG_AIRTIME_POLICY */
+
+ /* Previous WMM element information */
+ struct hostapd_wmm_ac_params prev_wmm[WMM_AC_NUM];
};
/* hostapd.c */
@@ -608,7 +641,8 @@
const u8 *bssid, const u8 *ie, size_t ie_len,
int ssi_signal);
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
- int offset, int width, int cf1, int cf2);
+ int offset, int width, int cf1, int cf2,
+ int finished);
struct survey_results;
void hostapd_event_get_survey(struct hostapd_iface *iface,
struct survey_results *survey_results);
diff --git a/src/ap/hs20.c b/src/ap/hs20.c
index 532580e..543fa33 100644
--- a/src/ap/hs20.c
+++ b/src/ap/hs20.c
@@ -80,13 +80,11 @@
/* 4 PTKSA replay counters when using WMM */
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
}
-#ifdef CONFIG_IEEE80211W
if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
capab |= WPA_CAPABILITY_MFPC;
if (hapd->conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
capab |= WPA_CAPABILITY_MFPR;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
if (hapd->conf->ocv)
capab |= WPA_CAPABILITY_OCVC;
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 8ac33bb..f6e6903 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -224,16 +224,27 @@
}
-#ifdef CONFIG_IEEE80211N
static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
{
- int pri_chan, sec_chan;
+ int pri_freq, sec_freq;
+ struct hostapd_channel_data *p_chan, *s_chan;
- pri_chan = iface->conf->channel;
- sec_chan = pri_chan + iface->conf->secondary_channel * 4;
+ pri_freq = iface->freq;
+ sec_freq = pri_freq + iface->conf->secondary_channel * 20;
- return allowed_ht40_channel_pair(iface->current_mode, pri_chan,
- sec_chan);
+ if (!iface->current_mode)
+ return 0;
+
+ p_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq, NULL,
+ iface->hw_features,
+ iface->num_hw_features);
+
+ s_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq, NULL,
+ iface->hw_features,
+ iface->num_hw_features);
+
+ return allowed_ht40_channel_pair(iface->current_mode->mode,
+ p_chan, s_chan);
}
@@ -241,9 +252,11 @@
{
if (iface->conf->secondary_channel > 0) {
iface->conf->channel += 4;
+ iface->freq += 20;
iface->conf->secondary_channel = -1;
} else {
iface->conf->channel -= 4;
+ iface->freq -= 20;
iface->conf->secondary_channel = 1;
}
}
@@ -252,13 +265,23 @@
static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
struct wpa_scan_results *scan_res)
{
- int pri_chan, sec_chan;
+ unsigned int pri_freq, sec_freq;
int res;
+ struct hostapd_channel_data *pri_chan, *sec_chan;
- pri_chan = iface->conf->channel;
- sec_chan = pri_chan + iface->conf->secondary_channel * 4;
+ pri_freq = iface->freq;
+ sec_freq = pri_freq + iface->conf->secondary_channel * 20;
- res = check_40mhz_5g(iface->current_mode, scan_res, pri_chan, sec_chan);
+ if (!iface->current_mode)
+ return 0;
+ pri_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq,
+ NULL, iface->hw_features,
+ iface->num_hw_features);
+ sec_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq,
+ NULL, iface->hw_features,
+ iface->num_hw_features);
+
+ res = check_40mhz_5g(scan_res, pri_chan, sec_chan);
if (res == 2) {
if (iface->conf->no_pri_sec_switch) {
@@ -329,9 +352,9 @@
res = ieee80211n_allowed_ht40_channel_pair(iface);
if (!res) {
iface->conf->secondary_channel = 0;
- iface->conf->vht_oper_centr_freq_seg0_idx = 0;
- iface->conf->vht_oper_centr_freq_seg1_idx = 0;
- iface->conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
+ hostapd_set_oper_centr_freq_seg0_idx(iface->conf, 0);
+ hostapd_set_oper_centr_freq_seg1_idx(iface->conf, 0);
+ hostapd_set_oper_chwidth(iface->conf, CHANWIDTH_USE_HT);
res = 1;
wpa_printf(MSG_INFO, "Fallback to 20 MHz");
}
@@ -352,7 +375,7 @@
if (iface->current_mode == NULL)
return;
- pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+ pri_freq = iface->freq;
if (iface->conf->secondary_channel > 0)
sec_freq = pri_freq + 20;
else
@@ -397,7 +420,7 @@
if (iface->current_mode == NULL)
return;
- pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+ pri_freq = iface->freq;
if (iface->conf->secondary_channel > 0) {
affected_start = pri_freq - 10;
affected_end = pri_freq + 30;
@@ -537,26 +560,6 @@
return 0;
}
- switch (conf & HT_CAP_INFO_SMPS_MASK) {
- case HT_CAP_INFO_SMPS_STATIC:
- if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_STATIC)) {
- wpa_printf(MSG_ERROR,
- "Driver does not support configured HT capability [SMPS-STATIC]");
- return 0;
- }
- break;
- case HT_CAP_INFO_SMPS_DYNAMIC:
- if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_DYNAMIC)) {
- wpa_printf(MSG_ERROR,
- "Driver does not support configured HT capability [SMPS-DYNAMIC]");
- return 0;
- }
- break;
- case HT_CAP_INFO_SMPS_DISABLED:
- default:
- break;
- }
-
if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
!(hw & HT_CAP_INFO_GREEN_FIELD)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
@@ -655,13 +658,21 @@
}
#endif /* CONFIG_IEEE80211AC */
-#endif /* CONFIG_IEEE80211N */
+
+#ifdef CONFIG_IEEE80211AX
+static int ieee80211ax_supported_he_capab(struct hostapd_iface *iface)
+{
+ return 1;
+}
+#endif /* CONFIG_IEEE80211AX */
int hostapd_check_ht_capab(struct hostapd_iface *iface)
{
-#ifdef CONFIG_IEEE80211N
int ret;
+
+ if (is_6ghz_freq(iface->freq))
+ return 0;
if (!iface->conf->ieee80211n)
return 0;
@@ -675,6 +686,11 @@
if (!ieee80211n_supported_ht_capab(iface))
return -1;
+#ifdef CONFIG_IEEE80211AX
+ if (iface->conf->ieee80211ax &&
+ !ieee80211ax_supported_he_capab(iface))
+ return -1;
+#endif /* CONFIG_IEEE80211AX */
#ifdef CONFIG_IEEE80211AC
if (iface->conf->ieee80211ac &&
!ieee80211ac_supported_vht_capab(iface))
@@ -685,21 +701,47 @@
return ret;
if (!ieee80211n_allowed_ht40_channel_pair(iface))
return -1;
-#endif /* CONFIG_IEEE80211N */
return 0;
}
+int hostapd_check_edmg_capab(struct hostapd_iface *iface)
+{
+ struct hostapd_hw_modes *mode = iface->hw_features;
+ struct ieee80211_edmg_config edmg;
+
+ if (!iface->conf->enable_edmg)
+ return 0;
+
+ hostapd_encode_edmg_chan(iface->conf->enable_edmg,
+ iface->conf->edmg_channel,
+ iface->conf->channel,
+ &edmg);
+
+ if (mode->edmg.channels && ieee802_edmg_is_allowed(mode->edmg, edmg))
+ return 0;
+
+ wpa_printf(MSG_WARNING, "Requested EDMG configuration is not valid");
+ wpa_printf(MSG_INFO, "EDMG capab: channels 0x%x, bw_config %d",
+ mode->edmg.channels, mode->edmg.bw_config);
+ wpa_printf(MSG_INFO,
+ "Requested EDMG configuration: channels 0x%x, bw_config %d",
+ edmg.channels, edmg.bw_config);
+ return -1;
+}
+
+
static int hostapd_is_usable_chan(struct hostapd_iface *iface,
- int channel, int primary)
+ int frequency, int primary)
{
struct hostapd_channel_data *chan;
if (!iface->current_mode)
return 0;
- chan = hw_get_channel_chan(iface->current_mode, channel, NULL);
+ chan = hw_get_channel_freq(iface->current_mode->mode, frequency, NULL,
+ iface->hw_features, iface->num_hw_features);
if (!chan)
return 0;
@@ -708,8 +750,8 @@
return 1;
wpa_printf(MSG_INFO,
- "Channel %d (%s) not allowed for AP mode, flags: 0x%x%s%s",
- channel, primary ? "primary" : "secondary",
+ "Frequency %d (%s) not allowed for AP mode, flags: 0x%x%s%s",
+ frequency, primary ? "primary" : "secondary",
chan->flag,
chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
@@ -717,37 +759,117 @@
}
-static int hostapd_is_usable_chans(struct hostapd_iface *iface)
+static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
{
- int secondary_chan;
+ int i, contiguous = 0;
+ int num_of_enabled = 0;
+ int max_contiguous = 0;
+ struct ieee80211_edmg_config edmg;
struct hostapd_channel_data *pri_chan;
- pri_chan = hw_get_channel_chan(iface->current_mode,
- iface->conf->channel, NULL);
- if (!pri_chan)
+ if (!iface->conf->enable_edmg)
+ return 1;
+
+ if (!iface->current_mode)
+ return 0;
+ pri_chan = hw_get_channel_freq(iface->current_mode->mode,
+ iface->freq, NULL,
+ iface->hw_features,
+ iface->num_hw_features);
+ hostapd_encode_edmg_chan(iface->conf->enable_edmg,
+ iface->conf->edmg_channel,
+ pri_chan->chan,
+ &edmg);
+ if (!(edmg.channels & BIT(pri_chan->chan - 1)))
return 0;
- if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1))
+ /* 60 GHz channels 1..6 */
+ for (i = 0; i < 6; i++) {
+ int freq = 56160 + 2160 * (i + 1);
+
+ if (edmg.channels & BIT(i)) {
+ contiguous++;
+ num_of_enabled++;
+ } else {
+ contiguous = 0;
+ continue;
+ }
+
+ /* P802.11ay defines that the total number of subfields
+ * set to one does not exceed 4.
+ */
+ if (num_of_enabled > 4)
+ return 0;
+
+ if (!hostapd_is_usable_chan(iface, freq, 1))
+ return 0;
+
+ if (contiguous > max_contiguous)
+ max_contiguous = contiguous;
+ }
+
+ /* Check if the EDMG configuration is valid under the limitations
+ * of P802.11ay.
+ */
+ /* check bw_config against contiguous EDMG channels */
+ switch (edmg.bw_config) {
+ case EDMG_BW_CONFIG_4:
+ if (!max_contiguous)
+ return 0;
+ break;
+ case EDMG_BW_CONFIG_5:
+ if (max_contiguous < 2)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int hostapd_is_usable_chans(struct hostapd_iface *iface)
+{
+ int secondary_freq;
+ struct hostapd_channel_data *pri_chan;
+
+ if (!iface->current_mode)
+ return 0;
+ pri_chan = hw_get_channel_freq(iface->current_mode->mode,
+ iface->freq, NULL,
+ iface->hw_features,
+ iface->num_hw_features);
+ if (!pri_chan) {
+ wpa_printf(MSG_ERROR, "Primary frequency not present");
+ return 0;
+ }
+ if (!hostapd_is_usable_chan(iface, pri_chan->freq, 1)) {
+ wpa_printf(MSG_ERROR, "Primary frequency not allowed");
+ return 0;
+ }
+ if (!hostapd_is_usable_edmg(iface))
return 0;
if (!iface->conf->secondary_channel)
return 1;
+ if (hostapd_is_usable_chan(iface, iface->freq +
+ iface->conf->secondary_channel * 20, 0))
+ return 1;
if (!iface->conf->ht40_plus_minus_allowed)
- return hostapd_is_usable_chan(
- iface, iface->conf->channel +
- iface->conf->secondary_channel * 4, 0);
+ return 0;
/* 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) &&
+ secondary_freq = iface->freq + 20;
+ if (hostapd_is_usable_chan(iface, secondary_freq, 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) &&
+ secondary_freq = iface->freq - 20;
+ if (hostapd_is_usable_chan(iface, secondary_freq, 0) &&
(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) {
iface->conf->secondary_channel = -1;
return 1;
@@ -757,10 +879,43 @@
}
+static void hostapd_determine_mode(struct hostapd_iface *iface)
+{
+ int i;
+ enum hostapd_hw_mode target_mode;
+
+ if (iface->current_mode ||
+ iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)
+ return;
+
+ if (iface->freq < 4000)
+ target_mode = HOSTAPD_MODE_IEEE80211G;
+ else if (iface->freq > 50000)
+ target_mode = HOSTAPD_MODE_IEEE80211AD;
+ else
+ target_mode = HOSTAPD_MODE_IEEE80211A;
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ struct hostapd_hw_modes *mode;
+
+ mode = &iface->hw_features[i];
+ if (mode->mode == target_mode) {
+ iface->current_mode = mode;
+ iface->conf->hw_mode = mode->mode;
+ break;
+ }
+ }
+
+ if (!iface->current_mode)
+ wpa_printf(MSG_ERROR, "ACS: Cannot decide mode");
+}
+
+
static enum hostapd_chan_status
hostapd_check_chans(struct hostapd_iface *iface)
{
- if (iface->conf->channel) {
+ if (iface->freq) {
+ hostapd_determine_mode(iface);
if (hostapd_is_usable_chans(iface))
return HOSTAPD_CHAN_VALID;
else
@@ -794,9 +949,9 @@
hostapd_logger(iface->bss[0], NULL,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
- "Configured channel (%d) not found from the "
- "channel list of current mode (%d) %s",
+ "Configured channel (%d) or frequency (%d) not found from the channel list of the current mode (%d) %s",
iface->conf->channel,
+ iface->freq,
iface->current_mode->mode,
hostapd_hw_mode_txt(iface->current_mode->mode));
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
@@ -816,9 +971,7 @@
case HOSTAPD_CHAN_VALID:
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
ACS_EVENT_COMPLETED "freq=%d channel=%d",
- hostapd_hw_get_freq(iface->bss[0],
- iface->conf->channel),
- iface->conf->channel);
+ iface->freq, iface->conf->channel);
break;
case HOSTAPD_CHAN_ACS:
wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available");
@@ -863,27 +1016,40 @@
return -1;
if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G ||
- iface->conf->ieee80211n || iface->conf->ieee80211ac) &&
+ iface->conf->ieee80211n || iface->conf->ieee80211ac ||
+ iface->conf->ieee80211ax) &&
iface->conf->channel == 14) {
- wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT on channel 14");
+ wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT/HE on channel 14");
iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
iface->conf->ieee80211n = 0;
iface->conf->ieee80211ac = 0;
+ iface->conf->ieee80211ax = 0;
}
iface->current_mode = NULL;
for (i = 0; i < iface->num_hw_features; i++) {
struct hostapd_hw_modes *mode = &iface->hw_features[i];
if (mode->mode == iface->conf->hw_mode) {
+ if (iface->freq > 0 &&
+ !hw_get_chan(mode->mode, iface->freq,
+ iface->hw_features,
+ iface->num_hw_features))
+ continue;
iface->current_mode = mode;
break;
}
}
if (iface->current_mode == NULL) {
- if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) ||
- !(iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY))
- {
+ if ((iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) &&
+ (iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY)) {
+ wpa_printf(MSG_DEBUG,
+ "Using offloaded hw_mode=any ACS");
+ } else if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) &&
+ iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211ANY) {
+ wpa_printf(MSG_DEBUG,
+ "Using internal ACS for hw_mode=any");
+ } else {
wpa_printf(MSG_ERROR,
"Hardware does not support configured mode");
hostapd_logger(iface->bss[0], NULL,
@@ -937,7 +1103,9 @@
struct hostapd_hw_modes *mode;
if (hapd->iface->current_mode) {
- channel = hw_get_chan(hapd->iface->current_mode, freq);
+ channel = hw_get_chan(hapd->iface->current_mode->mode, freq,
+ hapd->iface->hw_features,
+ hapd->iface->num_hw_features);
if (channel)
return channel;
}
@@ -948,9 +1116,28 @@
return 0;
for (i = 0; i < hapd->iface->num_hw_features; i++) {
mode = &hapd->iface->hw_features[i];
- channel = hw_get_chan(mode, freq);
+ channel = hw_get_chan(mode->mode, freq,
+ hapd->iface->hw_features,
+ hapd->iface->num_hw_features);
if (channel)
return channel;
}
return 0;
}
+
+
+int hostapd_hw_skip_mode(struct hostapd_iface *iface,
+ struct hostapd_hw_modes *mode)
+{
+ int i;
+
+ if (iface->current_mode)
+ return mode != iface->current_mode;
+ if (mode->mode != HOSTAPD_MODE_IEEE80211B)
+ return 0;
+ for (i = 0; i < iface->num_hw_features; i++) {
+ if (iface->hw_features[i].mode == HOSTAPD_MODE_IEEE80211G)
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index ca7f22b..dd24f95 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -21,9 +21,12 @@
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
int hostapd_check_ht_capab(struct hostapd_iface *iface);
+int hostapd_check_edmg_capab(struct hostapd_iface *iface);
int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode);
void hostapd_stop_setup_timers(struct hostapd_iface *iface);
+int hostapd_hw_skip_mode(struct hostapd_iface *iface,
+ struct hostapd_hw_modes *mode);
#else /* NEED_AP_MLME */
static inline void
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
@@ -48,7 +51,7 @@
static inline const char * hostapd_hw_mode_txt(int mode)
{
- return NULL;
+ return "UNKNOWN";
}
static inline int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
@@ -61,6 +64,11 @@
return 0;
}
+static inline int hostapd_check_edmg_capab(struct hostapd_iface *iface)
+{
+ return 0;
+}
+
static inline int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode)
{
@@ -71,6 +79,12 @@
{
}
+static inline int hostapd_hw_skip_mode(struct hostapd_iface *iface,
+ struct hostapd_hw_modes *mode)
+{
+ return 0;
+}
+
#endif /* NEED_AP_MLME */
#endif /* HW_FEATURES_H */
diff --git a/src/ap/iapp.c b/src/ap/iapp.c
deleted file mode 100644
index 2556da3..0000000
--- a/src/ap/iapp.c
+++ /dev/null
@@ -1,542 +0,0 @@
-/*
- * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
- * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- *
- * Note: IEEE 802.11F-2003 was a experimental use specification. It has expired
- * and IEEE has withdrawn it. In other words, it is likely better to look at
- * using some other mechanism for AP-to-AP communication than extending the
- * implementation here.
- */
-
-/* TODO:
- * Level 1: no administrative or security support
- * (e.g., static BSSID to IP address mapping in each AP)
- * Level 2: support for dynamic mapping of BSSID to IP address
- * Level 3: support for encryption and authentication of IAPP messages
- * - add support for MOVE-notify and MOVE-response (this requires support for
- * finding out IP address for previous AP using RADIUS)
- * - add support for Send- and ACK-Security-Block to speedup IEEE 802.1X during
- * reassociation to another AP
- * - implement counters etc. for IAPP MIB
- * - verify endianness of fields in IAPP messages; are they big-endian as
- * used here?
- * - RADIUS connection for AP registration and BSSID to IP address mapping
- * - TCP connection for IAPP MOVE, CACHE
- * - broadcast ESP for IAPP ADD-notify
- * - ESP for IAPP MOVE messages
- * - security block sending/processing
- * - IEEE 802.11 context transfer
- */
-
-#include "utils/includes.h"
-#include <net/if.h>
-#include <sys/ioctl.h>
-#include <netpacket/packet.h>
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "hostapd.h"
-#include "ap_config.h"
-#include "ieee802_11.h"
-#include "sta_info.h"
-#include "iapp.h"
-
-
-#define IAPP_MULTICAST "224.0.1.178"
-#define IAPP_UDP_PORT 3517
-#define IAPP_TCP_PORT 3517
-
-struct iapp_hdr {
- u8 version;
- u8 command;
- be16 identifier;
- be16 length;
- /* followed by length-6 octets of data */
-} __attribute__ ((packed));
-
-#define IAPP_VERSION 0
-
-enum IAPP_COMMAND {
- IAPP_CMD_ADD_notify = 0,
- IAPP_CMD_MOVE_notify = 1,
- IAPP_CMD_MOVE_response = 2,
- IAPP_CMD_Send_Security_Block = 3,
- IAPP_CMD_ACK_Security_Block = 4,
- IAPP_CMD_CACHE_notify = 5,
- IAPP_CMD_CACHE_response = 6,
-};
-
-
-/* ADD-notify - multicast UDP on the local LAN */
-struct iapp_add_notify {
- u8 addr_len; /* ETH_ALEN */
- u8 reserved;
- u8 mac_addr[ETH_ALEN];
- be16 seq_num;
-} __attribute__ ((packed));
-
-
-/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
-struct iapp_layer2_update {
- u8 da[ETH_ALEN]; /* broadcast */
- u8 sa[ETH_ALEN]; /* STA addr */
- be16 len; /* 6 */
- u8 dsap; /* null DSAP address */
- u8 ssap; /* null SSAP address, CR=Response */
- u8 control;
- u8 xid_info[3];
-} __attribute__ ((packed));
-
-
-/* MOVE-notify - unicast TCP */
-struct iapp_move_notify {
- u8 addr_len; /* ETH_ALEN */
- u8 reserved;
- u8 mac_addr[ETH_ALEN];
- u16 seq_num;
- u16 ctx_block_len;
- /* followed by ctx_block_len bytes */
-} __attribute__ ((packed));
-
-
-/* MOVE-response - unicast TCP */
-struct iapp_move_response {
- u8 addr_len; /* ETH_ALEN */
- u8 status;
- u8 mac_addr[ETH_ALEN];
- u16 seq_num;
- u16 ctx_block_len;
- /* followed by ctx_block_len bytes */
-} __attribute__ ((packed));
-
-enum {
- IAPP_MOVE_SUCCESSFUL = 0,
- IAPP_MOVE_DENIED = 1,
- IAPP_MOVE_STALE_MOVE = 2,
-};
-
-
-/* CACHE-notify */
-struct iapp_cache_notify {
- u8 addr_len; /* ETH_ALEN */
- u8 reserved;
- u8 mac_addr[ETH_ALEN];
- u16 seq_num;
- u8 current_ap[ETH_ALEN];
- u16 ctx_block_len;
- /* ctx_block_len bytes of context block followed by 16-bit context
- * timeout */
-} __attribute__ ((packed));
-
-
-/* CACHE-response - unicast TCP */
-struct iapp_cache_response {
- u8 addr_len; /* ETH_ALEN */
- u8 status;
- u8 mac_addr[ETH_ALEN];
- u16 seq_num;
-} __attribute__ ((packed));
-
-enum {
- IAPP_CACHE_SUCCESSFUL = 0,
- IAPP_CACHE_STALE_CACHE = 1,
-};
-
-
-/* Send-Security-Block - unicast TCP */
-struct iapp_send_security_block {
- u8 iv[8];
- u16 sec_block_len;
- /* followed by sec_block_len bytes of security block */
-} __attribute__ ((packed));
-
-
-/* ACK-Security-Block - unicast TCP */
-struct iapp_ack_security_block {
- u8 iv[8];
- u8 new_ap_ack_authenticator[48];
-} __attribute__ ((packed));
-
-
-struct iapp_data {
- struct hostapd_data *hapd;
- u16 identifier; /* next IAPP identifier */
- struct in_addr own, multicast;
- int udp_sock;
- int packet_sock;
-};
-
-
-static void iapp_send_add(struct iapp_data *iapp, u8 *mac_addr, u16 seq_num)
-{
- char buf[128];
- struct iapp_hdr *hdr;
- struct iapp_add_notify *add;
- struct sockaddr_in addr;
-
- /* Send IAPP ADD-notify to remove possible association from other APs
- */
-
- hdr = (struct iapp_hdr *) buf;
- hdr->version = IAPP_VERSION;
- hdr->command = IAPP_CMD_ADD_notify;
- hdr->identifier = host_to_be16(iapp->identifier++);
- hdr->length = host_to_be16(sizeof(*hdr) + sizeof(*add));
-
- add = (struct iapp_add_notify *) (hdr + 1);
- add->addr_len = ETH_ALEN;
- add->reserved = 0;
- os_memcpy(add->mac_addr, mac_addr, ETH_ALEN);
-
- add->seq_num = host_to_be16(seq_num);
-
- os_memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = iapp->multicast.s_addr;
- addr.sin_port = htons(IAPP_UDP_PORT);
- if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0,
- (struct sockaddr *) &addr, sizeof(addr)) < 0)
- wpa_printf(MSG_INFO, "sendto[IAPP-ADD]: %s", strerror(errno));
-}
-
-
-static void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr)
-{
- struct iapp_layer2_update msg;
-
- /* Send Level 2 Update Frame to update forwarding tables in layer 2
- * bridge devices */
-
- /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
- * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
-
- os_memset(msg.da, 0xff, ETH_ALEN);
- os_memcpy(msg.sa, addr, ETH_ALEN);
- msg.len = host_to_be16(6);
- msg.dsap = 0; /* NULL DSAP address */
- msg.ssap = 0x01; /* NULL SSAP address, CR Bit: Response */
- msg.control = 0xaf; /* XID response lsb.1111F101.
- * F=0 (no poll command; unsolicited frame) */
- msg.xid_info[0] = 0x81; /* XID format identifier */
- msg.xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
- msg.xid_info[2] = 1 << 1; /* XID sender's receive window size (RW)
- * FIX: what is correct RW with 802.11? */
-
- if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0)
- wpa_printf(MSG_INFO, "send[L2 Update]: %s", strerror(errno));
-}
-
-
-/**
- * iapp_new_station - IAPP processing for a new STA
- * @iapp: IAPP data
- * @sta: The associated station
- */
-void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta)
-{
- u16 seq = 0; /* TODO */
-
- if (iapp == NULL)
- return;
-
- /* IAPP-ADD.request(MAC Address, Sequence Number, Timeout) */
- hostapd_logger(iapp->hapd, sta->addr, HOSTAPD_MODULE_IAPP,
- HOSTAPD_LEVEL_DEBUG, "IAPP-ADD.request(seq=%d)", seq);
- iapp_send_layer2_update(iapp, sta->addr);
- iapp_send_add(iapp, sta->addr, seq);
-
- /* TODO: If this was reassociation:
- * IAPP-MOVE.request(MAC Address, Sequence Number, Old AP,
- * Context Block, Timeout)
- * TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to
- * IP address */
-}
-
-
-static void iapp_process_add_notify(struct iapp_data *iapp,
- struct sockaddr_in *from,
- struct iapp_hdr *hdr, int len)
-{
- struct iapp_add_notify *add = (struct iapp_add_notify *) (hdr + 1);
- struct sta_info *sta;
-
- if (len != sizeof(*add)) {
- wpa_printf(MSG_INFO, "Invalid IAPP-ADD packet length %d (expected %lu)",
- len, (unsigned long) sizeof(*add));
- return;
- }
-
- sta = ap_get_sta(iapp->hapd, add->mac_addr);
-
- /* IAPP-ADD.indication(MAC Address, Sequence Number) */
- hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
- HOSTAPD_LEVEL_INFO,
- "Received IAPP ADD-notify (seq# %d) from %s:%d%s",
- be_to_host16(add->seq_num),
- inet_ntoa(from->sin_addr), ntohs(from->sin_port),
- sta ? "" : " (STA not found)");
-
- if (!sta)
- return;
-
- /* TODO: could use seq_num to try to determine whether last association
- * to this AP is newer than the one advertised in IAPP-ADD. Although,
- * this is not really a reliable verification. */
-
- hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
- HOSTAPD_LEVEL_DEBUG,
- "Removing STA due to IAPP ADD-notify");
- ap_sta_disconnect(iapp->hapd, sta, NULL, 0);
-}
-
-
-/**
- * iapp_receive_udp - Process IAPP UDP frames
- * @sock: File descriptor for the socket
- * @eloop_ctx: IAPP data (struct iapp_data *)
- * @sock_ctx: Not used
- */
-static void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx)
-{
- struct iapp_data *iapp = eloop_ctx;
- int len, hlen;
- unsigned char buf[128];
- struct sockaddr_in from;
- socklen_t fromlen;
- struct iapp_hdr *hdr;
-
- /* Handle incoming IAPP frames (over UDP/IP) */
-
- fromlen = sizeof(from);
- len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0,
- (struct sockaddr *) &from, &fromlen);
- if (len < 0) {
- wpa_printf(MSG_INFO, "iapp_receive_udp - recvfrom: %s",
- strerror(errno));
- return;
- }
-
- if (from.sin_addr.s_addr == iapp->own.s_addr)
- return; /* ignore own IAPP messages */
-
- hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
- HOSTAPD_LEVEL_DEBUG,
- "Received %d byte IAPP frame from %s%s\n",
- len, inet_ntoa(from.sin_addr),
- len < (int) sizeof(*hdr) ? " (too short)" : "");
-
- if (len < (int) sizeof(*hdr))
- return;
-
- hdr = (struct iapp_hdr *) buf;
- hlen = be_to_host16(hdr->length);
- hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
- HOSTAPD_LEVEL_DEBUG,
- "RX: version=%d command=%d id=%d len=%d\n",
- hdr->version, hdr->command,
- be_to_host16(hdr->identifier), hlen);
- if (hdr->version != IAPP_VERSION) {
- wpa_printf(MSG_INFO, "Dropping IAPP frame with unknown version %d",
- hdr->version);
- return;
- }
- if (hlen > len) {
- wpa_printf(MSG_INFO, "Underflow IAPP frame (hlen=%d len=%d)",
- hlen, len);
- return;
- }
- if (hlen < len) {
- wpa_printf(MSG_INFO, "Ignoring %d extra bytes from IAPP frame",
- len - hlen);
- len = hlen;
- }
-
- switch (hdr->command) {
- case IAPP_CMD_ADD_notify:
- iapp_process_add_notify(iapp, &from, hdr, len - sizeof(*hdr));
- break;
- case IAPP_CMD_MOVE_notify:
- /* TODO: MOVE is using TCP; so move this to TCP handler once it
- * is implemented.. */
- /* IAPP-MOVE.indication(MAC Address, New BSSID,
- * Sequence Number, AP Address, Context Block) */
- /* TODO: process */
- break;
- default:
- wpa_printf(MSG_INFO, "Unknown IAPP command %d", hdr->command);
- break;
- }
-}
-
-
-struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
-{
- struct ifreq ifr;
- struct sockaddr_ll addr;
- int ifindex;
- struct sockaddr_in *paddr, uaddr;
- struct iapp_data *iapp;
- struct ip_mreqn mreq;
- int reuseaddr = 1;
-
- iapp = os_zalloc(sizeof(*iapp));
- if (iapp == NULL)
- return NULL;
- iapp->hapd = hapd;
- iapp->udp_sock = iapp->packet_sock = -1;
-
- /* TODO:
- * open socket for sending and receiving IAPP frames over TCP
- */
-
- iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
- if (iapp->udp_sock < 0) {
- wpa_printf(MSG_INFO, "iapp_init - socket[PF_INET,SOCK_DGRAM]: %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
- if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) {
- wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFINDEX): %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
- ifindex = ifr.ifr_ifindex;
-
- if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) {
- wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFADDR): %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
- paddr = (struct sockaddr_in *) &ifr.ifr_addr;
- if (paddr->sin_family != AF_INET) {
- wpa_printf(MSG_INFO, "IAPP: Invalid address family %i (SIOCGIFADDR)",
- paddr->sin_family);
- iapp_deinit(iapp);
- return NULL;
- }
- iapp->own.s_addr = paddr->sin_addr.s_addr;
-
- if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) {
- wpa_printf(MSG_INFO, "iapp_init - ioctl(SIOCGIFBRDADDR): %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
- paddr = (struct sockaddr_in *) &ifr.ifr_addr;
- if (paddr->sin_family != AF_INET) {
- wpa_printf(MSG_INFO, "Invalid address family %i (SIOCGIFBRDADDR)",
- paddr->sin_family);
- iapp_deinit(iapp);
- return NULL;
- }
- inet_aton(IAPP_MULTICAST, &iapp->multicast);
-
- os_memset(&uaddr, 0, sizeof(uaddr));
- uaddr.sin_family = AF_INET;
- uaddr.sin_port = htons(IAPP_UDP_PORT);
-
- if (setsockopt(iapp->udp_sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
- sizeof(reuseaddr)) < 0) {
- wpa_printf(MSG_INFO,
- "iapp_init - setsockopt[UDP,SO_REUSEADDR]: %s",
- strerror(errno));
- /*
- * Ignore this and try to continue. This is fine for single
- * BSS cases, but may fail if multiple BSSes enable IAPP.
- */
- }
-
- if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
- sizeof(uaddr)) < 0) {
- wpa_printf(MSG_INFO, "iapp_init - bind[UDP]: %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
-
- os_memset(&mreq, 0, sizeof(mreq));
- mreq.imr_multiaddr = iapp->multicast;
- mreq.imr_address.s_addr = INADDR_ANY;
- mreq.imr_ifindex = 0;
- if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
- sizeof(mreq)) < 0) {
- wpa_printf(MSG_INFO, "iapp_init - setsockopt[UDP,IP_ADD_MEMBERSHIP]: %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
-
- iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
- if (iapp->packet_sock < 0) {
- wpa_printf(MSG_INFO, "iapp_init - socket[PF_PACKET,SOCK_RAW]: %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
-
- os_memset(&addr, 0, sizeof(addr));
- addr.sll_family = AF_PACKET;
- addr.sll_ifindex = ifindex;
- if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
- sizeof(addr)) < 0) {
- wpa_printf(MSG_INFO, "iapp_init - bind[PACKET]: %s",
- strerror(errno));
- iapp_deinit(iapp);
- return NULL;
- }
-
- if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
- iapp, NULL)) {
- wpa_printf(MSG_INFO, "Could not register read socket for IAPP");
- iapp_deinit(iapp);
- return NULL;
- }
-
- wpa_printf(MSG_INFO, "IEEE 802.11F (IAPP) using interface %s", iface);
-
- /* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive
- * RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually
- * be openned only after receiving Initiate-Accept. If Initiate-Reject
- * is received, IAPP is not started. */
-
- return iapp;
-}
-
-
-void iapp_deinit(struct iapp_data *iapp)
-{
- struct ip_mreqn mreq;
-
- if (iapp == NULL)
- return;
-
- if (iapp->udp_sock >= 0) {
- os_memset(&mreq, 0, sizeof(mreq));
- mreq.imr_multiaddr = iapp->multicast;
- mreq.imr_address.s_addr = INADDR_ANY;
- mreq.imr_ifindex = 0;
- if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP,
- &mreq, sizeof(mreq)) < 0) {
- wpa_printf(MSG_INFO, "iapp_deinit - setsockopt[UDP,IP_DEL_MEMBERSHIP]: %s",
- strerror(errno));
- }
-
- eloop_unregister_read_sock(iapp->udp_sock);
- close(iapp->udp_sock);
- }
- if (iapp->packet_sock >= 0) {
- eloop_unregister_read_sock(iapp->packet_sock);
- close(iapp->packet_sock);
- }
- os_free(iapp);
-}
diff --git a/src/ap/iapp.h b/src/ap/iapp.h
deleted file mode 100644
index c221183..0000000
--- a/src/ap/iapp.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
- * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef IAPP_H
-#define IAPP_H
-
-struct iapp_data;
-
-#ifdef CONFIG_IAPP
-
-void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta);
-struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface);
-void iapp_deinit(struct iapp_data *iapp);
-
-#else /* CONFIG_IAPP */
-
-static inline void iapp_new_station(struct iapp_data *iapp,
- struct sta_info *sta)
-{
-}
-
-static inline struct iapp_data * iapp_init(struct hostapd_data *hapd,
- const char *iface)
-{
- return NULL;
-}
-
-static inline void iapp_deinit(struct iapp_data *iapp)
-{
-}
-
-#endif /* CONFIG_IAPP */
-
-#endif /* IAPP_H */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 36161c2..e6aa83d 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -23,6 +23,7 @@
#include "common/sae.h"
#include "common/dpp.h"
#include "common/ocv.h"
+#include "common/wpa_common.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "p2p/p2p.h"
@@ -87,6 +88,7 @@
{
u8 *pos = eid;
int i, num, count;
+ int h2e_required;
if (hapd->iface->current_rates == NULL)
return eid;
@@ -97,6 +99,12 @@
num++;
if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
num++;
+ h2e_required = (hapd->conf->sae_pwe == 1 ||
+ hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
+ hapd->conf->sae_pwe != 3 &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
+ if (h2e_required)
+ num++;
if (num > 8) {
/* rest of the rates are encoded in Extended supported
* rates element */
@@ -123,6 +131,11 @@
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
}
+ if (h2e_required && count < 8) {
+ count++;
+ *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
+ }
+
return pos;
}
@@ -131,6 +144,7 @@
{
u8 *pos = eid;
int i, num, count;
+ int h2e_required;
if (hapd->iface->current_rates == NULL)
return eid;
@@ -140,6 +154,12 @@
num++;
if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
num++;
+ h2e_required = (hapd->conf->sae_pwe == 1 ||
+ hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
+ hapd->conf->sae_pwe != 3 &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
+ if (h2e_required)
+ num++;
if (num <= 8)
return eid;
num -= 8;
@@ -169,14 +189,41 @@
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
}
+ if (h2e_required) {
+ count++;
+ if (count > 8)
+ *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
+ }
+
return pos;
}
+u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
+ size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
+ if (hapd->conf->radio_measurements[i])
+ break;
+ }
+
+ if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
+ return eid;
+
+ *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
+ *eid++ = RRM_CAPABILITIES_IE_LEN;
+ os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
+
+ return eid + RRM_CAPABILITIES_IE_LEN;
+}
+
+
u16 hostapd_own_capab_info(struct hostapd_data *hapd)
{
int capab = WLAN_CAPABILITY_ESS;
- int privacy;
+ int privacy = 0;
int dfs;
int i;
@@ -192,12 +239,14 @@
hapd->iconf->preamble == SHORT_PREAMBLE)
capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
+#ifdef CONFIG_WEP
privacy = hapd->conf->ssid.wep.keys_set;
if (hapd->conf->ieee802_1x &&
(hapd->conf->default_wep_key_len ||
hapd->conf->individual_wep_key_len))
privacy = 1;
+#endif /* CONFIG_WEP */
if (hapd->conf->wpa)
privacy = 1;
@@ -237,6 +286,7 @@
}
+#ifdef CONFIG_WEP
#ifndef CONFIG_NO_RC4
static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
u16 auth_transaction, const u8 *challenge,
@@ -293,9 +343,10 @@
return 0;
}
#endif /* CONFIG_NO_RC4 */
+#endif /* CONFIG_WEP */
-static int send_auth_reply(struct hostapd_data *hapd,
+static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *dst, const u8 *bssid,
u16 auth_alg, u16 auth_transaction, u16 resp,
const u8 *ies, size_t ies_len, const char *dbg)
@@ -328,7 +379,37 @@
" auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)",
MAC2STR(dst), auth_alg, auth_transaction,
resp, (unsigned long) ies_len, dbg);
- if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
+#ifdef CONFIG_TESTING_OPTIONS
+#ifdef CONFIG_SAE
+ if (hapd->conf->sae_confirm_immediate == 2 &&
+ auth_alg == WLAN_AUTH_SAE) {
+ if (auth_transaction == 1 && sta &&
+ (resp == WLAN_STATUS_SUCCESS ||
+ resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT)) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Postpone SAE Commit transmission until Confirm is ready");
+ os_free(sta->sae_postponed_commit);
+ sta->sae_postponed_commit = buf;
+ sta->sae_postponed_commit_len = rlen;
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ if (auth_transaction == 2 && sta && sta->sae_postponed_commit) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Send postponed SAE Commit first, immediately followed by SAE Confirm");
+ if (hostapd_drv_send_mlme(hapd,
+ sta->sae_postponed_commit,
+ sta->sae_postponed_commit_len,
+ 0, NULL, 0, 0) < 0)
+ wpa_printf(MSG_INFO, "send_auth_reply: send failed");
+ os_free(sta->sae_postponed_commit);
+ sta->sae_postponed_commit = NULL;
+ sta->sae_postponed_commit_len = 0;
+ }
+ }
+#endif /* CONFIG_SAE */
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (hostapd_drv_send_mlme(hapd, reply, rlen, 0, NULL, 0, 0) < 0)
wpa_printf(MSG_INFO, "send_auth_reply: send failed");
else
reply_res = WLAN_STATUS_SUCCESS;
@@ -348,7 +429,7 @@
struct sta_info *sta;
int reply_res;
- reply_res = send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT,
+ reply_res = send_auth_reply(hapd, NULL, dst, bssid, WLAN_AUTH_FT,
auth_transaction, status, ies, ies_len,
"auth-ft-finish");
@@ -387,15 +468,27 @@
static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
- struct sta_info *sta, int update)
+ struct sta_info *sta, int update,
+ int status_code)
{
struct wpabuf *buf;
const char *password = NULL;
struct sae_password_entry *pw;
const char *rx_id = NULL;
+ int use_pt = 0;
+ struct sae_pt *pt = NULL;
- if (sta->sae->tmp)
+ if (sta->sae->tmp) {
rx_id = sta->sae->tmp->pw_id;
+ use_pt = sta->sae->tmp->h2e;
+ }
+
+ if (rx_id && hapd->conf->sae_pwe != 3)
+ use_pt = 1;
+ else if (status_code == WLAN_STATUS_SUCCESS)
+ use_pt = 0;
+ else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)
+ use_pt = 1;
for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
if (!is_broadcast_ether_addr(pw->peer_addr) &&
@@ -407,16 +500,24 @@
os_strcmp(rx_id, pw->identifier) != 0)
continue;
password = pw->password;
+ pt = pw->pt;
break;
}
- if (!password)
- password = hapd->conf->ssid.wpa_passphrase;
if (!password) {
+ password = hapd->conf->ssid.wpa_passphrase;
+ pt = hapd->conf->ssid.pt;
+ }
+ if (!password || (use_pt && !pt)) {
wpa_printf(MSG_DEBUG, "SAE: No password available");
return NULL;
}
- if (update &&
+ if (update && use_pt &&
+ sae_prepare_commit_pt(sta->sae, pt, hapd->own_addr, sta->addr,
+ NULL) < 0)
+ return NULL;
+
+ if (update && !use_pt &&
sae_prepare_commit(hapd->own_addr, sta->addr,
(u8 *) password, os_strlen(password), rx_id,
sta->sae) < 0) {
@@ -435,10 +536,13 @@
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, rx_id);
+ if (buf &&
+ sae_write_commit(sta->sae, buf, sta->sae->tmp ?
+ sta->sae->tmp->anti_clogging_token : NULL,
+ rx_id) < 0) {
+ wpabuf_free(buf);
+ buf = NULL;
+ }
return buf;
}
@@ -461,19 +565,23 @@
static int auth_sae_send_commit(struct hostapd_data *hapd,
struct sta_info *sta,
- const u8 *bssid, int update)
+ const u8 *bssid, int update, int status_code)
{
struct wpabuf *data;
int reply_res;
+ u16 status;
- data = auth_build_sae_commit(hapd, sta, update);
+ data = auth_build_sae_commit(hapd, sta, update, status_code);
if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
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),
+ status = (sta->sae->tmp && sta->sae->tmp->h2e) ?
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT : WLAN_STATUS_SUCCESS;
+ reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
+ WLAN_AUTH_SAE, 1,
+ status, wpabuf_head(data),
wpabuf_len(data), "sae-send-commit");
wpabuf_free(data);
@@ -493,7 +601,8 @@
if (data == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 2,
+ reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
+ WLAN_AUTH_SAE, 2,
WLAN_STATUS_SUCCESS, wpabuf_head(data),
wpabuf_len(data), "sae-send-confirm");
@@ -533,13 +642,15 @@
}
-static u8 sae_token_hash(struct hostapd_data *hapd, const u8 *addr)
+static int sae_token_hash(struct hostapd_data *hapd, const u8 *addr, u8 *idx)
{
u8 hash[SHA256_MAC_LEN];
- hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
- addr, ETH_ALEN, hash);
- return hash[0];
+ if (hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+ addr, ETH_ALEN, hash) < 0)
+ return -1;
+ *idx = hash[0];
+ return 0;
}
@@ -552,9 +663,8 @@
u16 token_idx;
u8 idx;
- if (token_len != SHA256_MAC_LEN)
+ if (token_len != SHA256_MAC_LEN || sae_token_hash(hapd, addr, &idx) < 0)
return -1;
- 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 "
@@ -579,7 +689,7 @@
static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
- int group, const u8 *addr)
+ int group, const u8 *addr, int h2e)
{
struct wpabuf *buf;
u8 *token;
@@ -605,13 +715,23 @@
sizeof(hapd->sae_pending_token_idx));
}
- buf = wpabuf_alloc(sizeof(le16) + SHA256_MAC_LEN);
+ buf = wpabuf_alloc(sizeof(le16) + 3 + SHA256_MAC_LEN);
if (buf == NULL)
return NULL;
wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
- p_idx = sae_token_hash(hapd, addr);
+ if (h2e) {
+ /* Encapsulate Anti-clogging Token field in a container IE */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + SHA256_MAC_LEN);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
+ }
+
+ if (sae_token_hash(hapd, addr, &p_idx) < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
token_idx = hapd->sae_pending_token_idx[p_idx];
if (!token_idx) {
hapd->sae_token_idx++;
@@ -662,7 +782,7 @@
switch (sta->sae->state) {
case SAE_COMMITTED:
- ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+ ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
eloop_register_timeout(0,
hapd->dot11RSNASAERetransPeriod * 1000,
auth_sae_retransmit_timer, hapd, sta);
@@ -709,7 +829,8 @@
os_memset(¶ms, 0, sizeof(params));
params.status = status;
params.bssid = sta->addr;
- if (status == WLAN_STATUS_SUCCESS && sta->sae)
+ if (status == WLAN_STATUS_SUCCESS && sta->sae &&
+ !hapd->conf->disable_pmksa_caching)
params.pmkid = sta->sae->pmkid;
hostapd_drv_send_external_auth_status(hapd, ¶ms);
@@ -752,6 +873,9 @@
mlme_authenticate_indication(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm");
+ crypto_bignum_deinit(sta->sae->peer_commit_scalar_accepted, 0);
+ sta->sae->peer_commit_scalar_accepted = sta->sae->peer_commit_scalar;
+ sta->sae->peer_commit_scalar = NULL;
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);
@@ -759,8 +883,8 @@
static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *bssid, u8 auth_transaction, int allow_reuse,
- int *sta_removed)
+ const u8 *bssid, u16 auth_transaction, u16 status_code,
+ int allow_reuse, int *sta_removed)
{
int ret;
@@ -775,8 +899,11 @@
switch (sta->sae->state) {
case SAE_NOTHING:
if (auth_transaction == 1) {
+ if (sta->sae->tmp)
+ sta->sae->tmp->h2e = status_code ==
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT;
ret = auth_sae_send_commit(hapd, sta, bssid,
- !allow_reuse);
+ !allow_reuse, status_code);
if (ret)
return ret;
sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
@@ -785,14 +912,17 @@
return WLAN_STATUS_UNSPECIFIED_FAILURE;
/*
- * In mesh case, both Commit and Confirm can be sent
- * immediately. In infrastructure BSS, only a single
- * Authentication frame (Commit) is expected from the AP
- * here and the second one (Confirm) will be sent once
- * the STA has sent its second Authentication frame
- * (Confirm).
+ * In mesh case, both Commit and Confirm are sent
+ * immediately. In infrastructure BSS, by default, only
+ * a single Authentication frame (Commit) is expected
+ * from the AP here and the second one (Confirm) will
+ * be sent once the STA has sent its second
+ * Authentication frame (Confirm). This behavior can be
+ * overridden with explicit configuration so that the
+ * infrastructure BSS case sends both frames together.
*/
- if (hapd->conf->mesh & MESH_ENABLED) {
+ if ((hapd->conf->mesh & MESH_ENABLED) ||
+ hapd->conf->sae_confirm_immediate) {
/*
* Send both Commit and Confirm immediately
* based on SAE finite state machine
@@ -843,7 +973,8 @@
return WLAN_STATUS_SUCCESS;
sta->sae->sync++;
- ret = auth_sae_send_commit(hapd, sta, bssid, 0);
+ ret = auth_sae_send_commit(hapd, sta, bssid, 0,
+ status_code);
if (ret)
return ret;
@@ -866,7 +997,7 @@
* additional events.
*/
return sae_sm_step(hapd, sta, bssid, auth_transaction,
- 0, sta_removed);
+ WLAN_STATUS_SUCCESS, 0, sta_removed);
}
break;
case SAE_CONFIRMED:
@@ -876,7 +1007,8 @@
return WLAN_STATUS_SUCCESS;
sta->sae->sync++;
- ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+ ret = auth_sae_send_commit(hapd, sta, bssid, 1,
+ status_code);
if (ret)
return ret;
@@ -904,7 +1036,8 @@
*sta_removed = 1;
} else if (auth_transaction == 1) {
wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
- ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+ ret = auth_sae_send_commit(hapd, sta, bssid, 1,
+ status_code);
if (ret)
return ret;
sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
@@ -974,6 +1107,73 @@
}
+static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
+{
+ int sae_pwe = hapd->conf->sae_pwe;
+ int id_in_use;
+
+ id_in_use = hostapd_sae_pw_id_in_use(hapd->conf);
+ if (id_in_use == 2 && sae_pwe != 3)
+ sae_pwe = 1;
+ else if (id_in_use == 1 && sae_pwe == 0)
+ sae_pwe = 2;
+
+ return ((sae_pwe == 0 || sae_pwe == 3) &&
+ status_code == WLAN_STATUS_SUCCESS) ||
+ (sae_pwe == 1 &&
+ status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) ||
+ (sae_pwe == 2 &&
+ (status_code == WLAN_STATUS_SUCCESS ||
+ status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT));
+}
+
+
+static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
+{
+ int *groups = hapd->conf->sae_groups;
+ int default_groups[] = { 19, 0 };
+ int i;
+
+ if (!groups)
+ groups = default_groups;
+
+ for (i = 0; groups[i] > 0; i++) {
+ if (groups[i] == group)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int check_sae_rejected_groups(struct hostapd_data *hapd,
+ const struct wpabuf *groups)
+{
+ size_t i, count;
+ const u8 *pos;
+
+ if (!groups)
+ return 0;
+
+ pos = wpabuf_head(groups);
+ count = wpabuf_len(groups) / 2;
+ for (i = 0; i < count; i++) {
+ int enabled;
+ u16 group;
+
+ group = WPA_GET_LE16(pos);
+ pos += 2;
+ enabled = sae_is_group_enabled(hapd, group);
+ wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
+ group, enabled ? "enabled" : "disabled");
+ if (enabled)
+ return 1;
+ }
+
+ return 0;
+}
+
+
static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
const struct ieee80211_mgmt *mgmt, size_t len,
u16 auth_transaction, u16 status_code)
@@ -993,7 +1193,7 @@
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,
+ send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
auth_transaction, resp, pos, end - pos,
"auth-sae-reflection-attack");
goto remove_sta;
@@ -1001,7 +1201,7 @@
if (hapd->conf->sae_commit_override && auth_transaction == 1) {
wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override");
- send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+ send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
auth_transaction, resp,
wpabuf_head(hapd->conf->sae_commit_override),
wpabuf_len(hapd->conf->sae_commit_override),
@@ -1011,9 +1211,11 @@
#endif /* CONFIG_TESTING_OPTIONS */
if (!sta->sae) {
if (auth_transaction != 1 ||
- status_code != WLAN_STATUS_SUCCESS) {
- resp = -1;
- goto remove_sta;
+ !sae_status_success(hapd, status_code)) {
+ wpa_printf(MSG_DEBUG, "SAE: Unexpected Status Code %u",
+ status_code);
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto reply;
}
sta->sae = os_zalloc(sizeof(*sta->sae));
if (!sta->sae) {
@@ -1038,8 +1240,8 @@
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
- "start SAE authentication (RX commit, status=%u)",
- status_code);
+ "start SAE authentication (RX commit, status=%u (%s))",
+ status_code, status2str(status_code));
if ((hapd->conf->mesh & MESH_ENABLED) &&
status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
@@ -1078,7 +1280,8 @@
* Authentication frame, and the commit-scalar and
* COMMIT-ELEMENT previously sent.
*/
- resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0);
+ resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0,
+ status_code);
if (resp != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_ERROR,
"SAE: Failed to send commit message");
@@ -1101,7 +1304,7 @@
goto remove_sta;
}
- if (status_code != WLAN_STATUS_SUCCESS)
+ if (!sae_status_success(hapd, status_code))
goto remove_sta;
if (!(hapd->conf->mesh & MESH_ENABLED) &&
@@ -1134,7 +1337,8 @@
resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
((const u8 *) mgmt) + len -
mgmt->u.auth.variable, &token,
- &token_len, groups);
+ &token_len, groups, status_code ==
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT);
if (resp == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message from " MACSTR " due to reflection attack",
@@ -1164,12 +1368,25 @@
if (resp != WLAN_STATUS_SUCCESS)
goto reply;
+ if (sta->sae->tmp &&
+ check_sae_rejected_groups(
+ hapd, sta->sae->tmp->peer_rejected_groups)) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto reply;
+ }
+
if (!token && use_sae_anti_clogging(hapd) && !allow_reuse) {
+ int h2e = 0;
+
wpa_printf(MSG_DEBUG,
"SAE: Request anti-clogging token from "
MACSTR, MAC2STR(sta->addr));
+ if (sta->sae->tmp)
+ h2e = sta->sae->tmp->h2e;
+ if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)
+ h2e = 1;
data = auth_build_token_req(hapd, sta->sae->group,
- sta->addr);
+ sta->addr, h2e);
resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
if (hapd->conf->mesh & MESH_ENABLED)
sae_set_state(sta, SAE_NOTHING,
@@ -1178,12 +1395,12 @@
}
resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
- allow_reuse, &sta_removed);
+ status_code, allow_reuse, &sta_removed);
} else if (auth_transaction == 2) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
- "SAE authentication (RX confirm, status=%u)",
- status_code);
+ "SAE authentication (RX confirm, status=%u (%s))",
+ status_code, status2str(status_code));
if (status_code != WLAN_STATUS_SUCCESS)
goto remove_sta;
if (sta->sae->state >= SAE_CONFIRMED ||
@@ -1219,13 +1436,14 @@
}
sta->sae->rc = peer_send_confirm;
}
- resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction, 0,
- &sta_removed);
+ resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
+ status_code, 0, &sta_removed);
} else {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
- "unexpected SAE authentication transaction %u (status=%u)",
- auth_transaction, status_code);
+ "unexpected SAE authentication transaction %u (status=%u (%s))",
+ auth_transaction, status_code,
+ status2str(status_code));
if (status_code != WLAN_STATUS_SUCCESS)
goto remove_sta;
resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
@@ -1243,7 +1461,7 @@
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,
+ send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
auth_transaction, resp,
data ? wpabuf_head(data) : (u8 *) "",
data ? wpabuf_len(data) : 0, "auth-sae");
@@ -1280,7 +1498,7 @@
if (sta->sae->state != SAE_NOTHING)
return -1;
- ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+ ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
if (ret)
return -1;
@@ -1393,29 +1611,37 @@
#endif /* CONFIG_SAE */
-static u16 wpa_res_to_status_code(int res)
+static u16 wpa_res_to_status_code(enum wpa_validate_result res)
{
- if (res == WPA_INVALID_GROUP)
- return WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
- if (res == WPA_INVALID_PAIRWISE)
- return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
- if (res == WPA_INVALID_AKMP)
- return WLAN_STATUS_AKMP_NOT_VALID;
- if (res == WPA_ALLOC_FAIL)
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
-#ifdef CONFIG_IEEE80211W
- 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_CIPHER_REJECTED_PER_POLICY;
-#endif /* CONFIG_IEEE80211W */
- if (res == WPA_INVALID_MDIE)
- return WLAN_STATUS_INVALID_MDIE;
- if (res == WPA_INVALID_PMKID)
- return WLAN_STATUS_INVALID_PMKID;
- if (res != WPA_IE_OK)
+ switch (res) {
+ case WPA_IE_OK:
+ return WLAN_STATUS_SUCCESS;
+ case WPA_INVALID_IE:
return WLAN_STATUS_INVALID_IE;
- return WLAN_STATUS_SUCCESS;
+ case WPA_INVALID_GROUP:
+ return WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+ case WPA_INVALID_PAIRWISE:
+ return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+ case WPA_INVALID_AKMP:
+ return WLAN_STATUS_AKMP_NOT_VALID;
+ case WPA_NOT_ENABLED:
+ return WLAN_STATUS_INVALID_IE;
+ case WPA_ALLOC_FAIL:
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
+ return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
+ case WPA_INVALID_MGMT_GROUP_CIPHER:
+ return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
+ case WPA_INVALID_MDIE:
+ return WLAN_STATUS_INVALID_MDIE;
+ case WPA_INVALID_PROTO:
+ return WLAN_STATUS_INVALID_IE;
+ case WPA_INVALID_PMKID:
+ return WLAN_STATUS_INVALID_PMKID;
+ case WPA_DENIED_OTHER_REASON:
+ return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+ }
+ return WLAN_STATUS_INVALID_IE;
}
@@ -1435,7 +1661,7 @@
u16 resp = WLAN_STATUS_SUCCESS;
const u8 *end;
struct ieee802_11_elems elems;
- int res;
+ enum wpa_validate_result res;
struct wpa_ie_data rsn;
struct rsn_pmksa_cache_entry *pmksa = NULL;
@@ -1551,6 +1777,8 @@
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq,
elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ elems.rsnxe ? elems.rsnxe - 2 : NULL,
+ elems.rsnxe ? elems.rsnxe_len + 2 : 0,
elems.mdie, elems.mdie_len, NULL, 0);
resp = wpa_res_to_status_code(res);
if (resp != WLAN_STATUS_SUCCESS)
@@ -1609,11 +1837,11 @@
FILS_SESSION_LEN);
os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN);
- /* FILS Wrapped Data */
- if (elems.fils_wrapped_data) {
+ /* Wrapped Data */
+ if (elems.wrapped_data) {
wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
- elems.fils_wrapped_data,
- elems.fils_wrapped_data_len);
+ elems.wrapped_data,
+ elems.wrapped_data_len);
if (!pmksa) {
#ifndef CONFIG_NO_RADIUS
if (!sta->eapol_sm) {
@@ -1623,8 +1851,8 @@
wpa_printf(MSG_DEBUG,
"FILS: Forward EAP-Initiate/Re-auth to authentication server");
ieee802_1x_encapsulate_radius(
- hapd, sta, elems.fils_wrapped_data,
- elems.fils_wrapped_data_len);
+ hapd, sta, elems.wrapped_data,
+ elems.wrapped_data_len);
sta->fils_pending_cb = cb;
wpa_printf(MSG_DEBUG,
"FILS: Will send Authentication frame once the response from authentication server is available");
@@ -1633,8 +1861,8 @@
* to maintain a copy of the EAP-Initiate/Reauth
* message. */
if (fils_pmkid_erp(wpa_auth_sta_key_mgmt(sta->wpa_sm),
- elems.fils_wrapped_data,
- elems.fils_wrapped_data_len,
+ elems.wrapped_data,
+ elems.wrapped_data_len,
sta->fils_erp_pmkid) == 0)
sta->fils_erp_pmkid_set = 1;
return;
@@ -1777,12 +2005,12 @@
wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION);
wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN);
- /* FILS Wrapped Data */
+ /* Wrapped Data */
if (!pmksa && erp_resp) {
wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */
/* Element ID Extension */
- wpabuf_put_u8(data, WLAN_EID_EXT_FILS_WRAPPED_DATA);
+ wpabuf_put_u8(data, WLAN_EID_EXT_WRAPPED_DATA);
wpabuf_put_buf(data, erp_resp);
if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm),
@@ -1821,6 +2049,8 @@
}
sta->fils_erp_pmkid_set = 0;
+ wpa_auth_add_fils_pmk_pmkid(sta->wpa_sm, pmk, pmk_len,
+ sta->fils_erp_pmkid);
if (!hapd->conf->disable_pmksa_caching &&
wpa_auth_pmksa_add2(
hapd->wpa_auth, sta->addr,
@@ -1882,7 +2112,7 @@
auth_alg = (pub ||
resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ?
WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
- send_auth_reply(hapd, sta->addr, hapd->own_addr, auth_alg, 2, resp,
+ send_auth_reply(hapd, sta, sta->addr, hapd->own_addr, auth_alg, 2, resp,
data ? wpabuf_head(data) : (u8 *) "",
data ? wpabuf_len(data) : 0, "auth-fils-finish");
wpabuf_free(data);
@@ -1926,28 +2156,18 @@
#endif /* CONFIG_FILS */
-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)
+static int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *msg, size_t len,
+ struct radius_sta *info)
{
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,
- is_probe_req);
+ res = hostapd_allowed_address(hapd, addr, msg, len, info, 0);
if (res == HOSTAPD_ACL_REJECT) {
- if (!is_probe_req)
- wpa_printf(MSG_DEBUG,
- "Station " MACSTR
- " not allowed to authenticate",
- MAC2STR(addr));
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not allowed to authenticate",
+ MAC2STR(addr));
return HOSTAPD_ACL_REJECT;
}
@@ -1967,12 +2187,15 @@
static int
ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
- int res, 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 res, struct radius_sta *info)
{
+ u32 session_timeout = info->session_timeout;
+ u32 acct_interim_interval = info->acct_interim_interval;
+ struct vlan_description *vlan_id = &info->vlan_id;
+ struct hostapd_sta_wpa_psk_short *psk = info->psk;
+ char *identity = info->identity;
+ char *radius_cui = info->radius_cui;
+
if (vlan_id->notempty &&
!hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
@@ -1989,20 +2212,22 @@
HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
hostapd_free_psk_list(sta->psk);
- if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
- sta->psk = *psk;
- *psk = NULL;
- } else {
+ if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED)
+ hostapd_copy_psk_list(&sta->psk, psk);
+ else
sta->psk = NULL;
- }
os_free(sta->identity);
- sta->identity = *identity;
- *identity = NULL;
+ if (identity)
+ sta->identity = os_strdup(identity);
+ else
+ sta->identity = NULL;
os_free(sta->radius_cui);
- sta->radius_cui = *radius_cui;
- *radius_cui = NULL;
+ if (radius_cui)
+ sta->radius_cui = os_strdup(radius_cui);
+ else
+ sta->radius_cui = NULL;
if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
sta->acct_interim_interval = acct_interim_interval;
@@ -2030,14 +2255,10 @@
int res, reply_res;
u16 fc;
const u8 *challenge = NULL;
- u32 session_timeout, acct_interim_interval;
- struct vlan_description vlan_id;
- struct hostapd_sta_wpa_psk_short *psk = NULL;
u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
size_t resp_ies_len = 0;
- char *identity = NULL;
- char *radius_cui = NULL;
u16 seq_ctrl;
+ struct radius_sta rad_info;
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
@@ -2188,10 +2409,8 @@
}
}
- res = ieee802_11_allowed_address(
- hapd, mgmt->sa, (const u8 *) mgmt, len, &session_timeout,
- &acct_interim_interval, &vlan_id, &psk, &identity, &radius_cui,
- 0);
+ res = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
+ &rad_info);
if (res == HOSTAPD_ACL_REJECT) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Ignore Authentication frame from " MACSTR
@@ -2274,9 +2493,7 @@
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);
+ res = ieee802_11_set_radius_info(hapd, sta, res, &rad_info);
if (res) {
wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed");
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -2309,29 +2526,10 @@
(!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
!(hapd->conf->mesh & MESH_ENABLED) &&
!(sta->added_unassoc)) {
- /*
- * If a station that is already associated to the AP, is trying
- * to authenticate again, remove the STA entry, in order to make
- * sure the STA PS state gets cleared and configuration gets
- * 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);
-
- if (hostapd_sta_add(hapd, sta->addr, 0, 0, NULL, 0, 0,
- NULL, NULL, sta->flags, 0, 0, 0, 0)) {
- hostapd_logger(hapd, sta->addr,
- HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_NOTICE,
- "Could not add STA to kernel driver");
+ if (ap_sta_re_add(hapd, sta) < 0) {
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
goto fail;
}
-
- sta->added_unassoc = 1;
}
switch (auth_alg) {
@@ -2344,6 +2542,7 @@
sta->auth_alg = WLAN_AUTH_OPEN;
mlme_authenticate_indication(hapd, sta);
break;
+#ifdef CONFIG_WEP
#ifndef CONFIG_NO_RC4
case WLAN_AUTH_SHARED_KEY:
resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
@@ -2362,6 +2561,7 @@
}
break;
#endif /* CONFIG_NO_RC4 */
+#endif /* CONFIG_WEP */
#ifdef CONFIG_IEEE80211R_AP
case WLAN_AUTH_FT:
sta->auth_alg = WLAN_AUTH_FT;
@@ -2415,11 +2615,7 @@
}
fail:
- os_free(identity);
- os_free(radius_cui);
- hostapd_free_psk_list(psk);
-
- reply_res = send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
+ reply_res = send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, auth_alg,
auth_transaction + 1, resp, resp_ies,
resp_ies_len, "handle-auth");
@@ -2788,14 +2984,131 @@
return WLAN_STATUS_SUCCESS;
}
+
+u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
+ const u8 *rsn_ie, size_t rsn_ie_len,
+ const u8 *owe_dh, size_t owe_dh_len)
+{
+ struct wpa_ie_data data;
+ int res;
+
+ if (!rsn_ie || rsn_ie_len < 2) {
+ wpa_printf(MSG_DEBUG, "OWE: Invalid RSNE from " MACSTR,
+ MAC2STR(peer));
+ return WLAN_STATUS_INVALID_IE;
+ }
+ rsn_ie -= 2;
+ rsn_ie_len += 2;
+
+ res = wpa_parse_wpa_ie_rsn(rsn_ie, rsn_ie_len, &data);
+ if (res) {
+ wpa_printf(MSG_DEBUG, "Failed to parse RSNE from " MACSTR
+ " (res=%d)", MAC2STR(peer), res);
+ wpa_hexdump(MSG_DEBUG, "RSNE", rsn_ie, rsn_ie_len);
+ return wpa_res_to_status_code(res);
+ }
+ if (!(data.key_mgmt & WPA_KEY_MGMT_OWE)) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: Unexpected key mgmt 0x%x from " MACSTR,
+ (unsigned int) data.key_mgmt, MAC2STR(peer));
+ return WLAN_STATUS_AKMP_NOT_VALID;
+ }
+ if (!owe_dh) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: No Diffie-Hellman Parameter element from "
+ MACSTR, MAC2STR(peer));
+ return WLAN_STATUS_AKMP_NOT_VALID;
+ }
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+u16 owe_process_rsn_ie(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *rsn_ie, size_t rsn_ie_len,
+ const u8 *owe_dh, size_t owe_dh_len)
+{
+ u16 status;
+ u8 *owe_buf, ie[256 * 2];
+ size_t ie_len = 0;
+ enum wpa_validate_result res;
+
+ if (!rsn_ie || rsn_ie_len < 2) {
+ wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq");
+ status = WLAN_STATUS_INVALID_IE;
+ goto end;
+ }
+
+ if (!sta->wpa_sm)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
+ NULL);
+ if (!sta->wpa_sm) {
+ wpa_printf(MSG_WARNING,
+ "OWE: Failed to initialize WPA state machine");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto end;
+ }
+ rsn_ie -= 2;
+ rsn_ie_len += 2;
+ res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+ hapd->iface->freq, rsn_ie, rsn_ie_len,
+ NULL, 0, NULL, 0, owe_dh, owe_dh_len);
+ status = wpa_res_to_status_code(res);
+ if (status != WLAN_STATUS_SUCCESS)
+ goto end;
+ status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
+ if (status != WLAN_STATUS_SUCCESS)
+ goto end;
+ owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, ie, sizeof(ie),
+ NULL, 0);
+ if (!owe_buf) {
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto end;
+ }
+
+ if (sta->owe_ecdh) {
+ struct wpabuf *pub;
+
+ pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
+ if (!pub) {
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto end;
+ }
+
+ /* 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);
+ sta->external_dh_updated = 1;
+ }
+ ie_len = owe_buf - ie;
+
+end:
+ wpa_printf(MSG_DEBUG, "OWE: Update status %d, ie len %d for peer "
+ MACSTR, status, (unsigned int) ie_len,
+ MAC2STR(sta->addr));
+ hostapd_drv_update_dh_ie(hapd, sta->addr, status,
+ status == WLAN_STATUS_SUCCESS ? ie : NULL,
+ ie_len);
+
+ return status;
+}
+
#endif /* CONFIG_OWE */
-static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
+static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ies, size_t ies_len, int reassoc)
{
struct ieee802_11_elems elems;
- u16 resp;
+ int resp;
const u8 *wpa_ie;
size_t wpa_ie_len;
const u8 *p2p_dev_addr = NULL;
@@ -2824,7 +3137,6 @@
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)
return resp;
@@ -2835,7 +3147,6 @@
"mandatory HT PHY - reject association");
return WLAN_STATUS_ASSOC_DENIED_NO_HT;
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac) {
@@ -2843,10 +3154,6 @@
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;
@@ -2867,6 +3174,15 @@
return resp;
}
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax) {
+ resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
+ elems.he_capabilities,
+ elems.he_capabilities_len);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+ }
+#endif /* CONFIG_IEEE80211AX */
#ifdef CONFIG_P2P
if (elems.p2p) {
@@ -2927,7 +3243,8 @@
}
if (hapd->conf->wpa && wpa_ie) {
- int res;
+ enum wpa_validate_result res;
+
wpa_ie -= 2;
wpa_ie_len += 2;
if (sta->wpa_sm == NULL)
@@ -2943,12 +3260,13 @@
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq,
wpa_ie, wpa_ie_len,
+ elems.rsnxe ? elems.rsnxe - 2 : NULL,
+ elems.rsnxe ? elems.rsnxe_len + 2 : 0,
elems.mdie, elems.mdie_len,
elems.owe_dh, elems.owe_dh_len);
resp = wpa_res_to_status_code(res);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
-#ifdef CONFIG_IEEE80211W
if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
(WLAN_STA_ASSOC | WLAN_STA_MFP) &&
!sta->sa_query_timed_out &&
@@ -2975,7 +3293,6 @@
sta->flags |= WLAN_STA_MFP;
else
sta->flags &= ~WLAN_STA_MFP;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R_AP
if (sta->auth_alg == WLAN_AUTH_FT) {
@@ -3020,6 +3337,17 @@
MAC2STR(sta->addr), sta->auth_alg);
return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
}
+
+ if (hapd->conf->sae_pwe == 2 &&
+ sta->auth_alg == WLAN_AUTH_SAE &&
+ sta->sae && sta->sae->tmp && !sta->sae->tmp->h2e &&
+ elems.rsnxe && elems.rsnxe_len >= 1 &&
+ (elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
+ wpa_printf(MSG_INFO, "SAE: " MACSTR
+ " indicates support for SAE H2E, but did not use it",
+ MAC2STR(sta->addr));
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
#endif /* CONFIG_SAE */
#ifdef CONFIG_OWE
@@ -3064,7 +3392,6 @@
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) {
hostapd_logger(hapd, sta->addr,
@@ -3074,7 +3401,6 @@
"association");
return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_HS20
} else if (hapd->conf->osen) {
if (elems.osen == NULL) {
@@ -3113,7 +3439,8 @@
sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
elems.hs20_len - 4);
release = ((elems.hs20[4] >> 4) & 0x0f) + 1;
- if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm)) {
+ if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm) &&
+ hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
wpa_printf(MSG_DEBUG,
"HS 2.0: PMF not negotiated by release %d station "
MACSTR, release, MAC2STR(sta->addr));
@@ -3218,7 +3545,7 @@
send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
reply.u.deauth.reason_code = host_to_le16(reason_code);
- if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0) < 0)
+ if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0, NULL, 0, 0) < 0)
wpa_printf(MSG_INFO, "Failed to send deauth: %s",
strerror(errno));
}
@@ -3229,6 +3556,7 @@
{
struct ieee80211_ht_capabilities ht_cap;
struct ieee80211_vht_capabilities vht_cap;
+ struct ieee80211_he_capabilities he_cap;
int set = 1;
/*
@@ -3273,14 +3601,18 @@
sta->ft_over_ds = 0;
}
-#ifdef CONFIG_IEEE80211N
if (sta->flags & WLAN_STA_HT)
hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
if (sta->flags & WLAN_STA_VHT)
hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ if (sta->flags & WLAN_STA_HE) {
+ hostapd_get_he_capab(hapd, sta->he_capab, &he_cap,
+ sta->he_capab_len);
+ }
+#endif /* CONFIG_IEEE80211AX */
/*
* Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
@@ -3292,6 +3624,8 @@
sta->listen_interval,
sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
+ sta->flags & WLAN_STA_HE ? &he_cap : NULL,
+ sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
sta->vht_opmode, sta->p2p_ie ? 1 : 0,
set)) {
@@ -3316,7 +3650,8 @@
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, int rssi)
+ const u8 *ies, size_t ies_len, int rssi,
+ int omit_rsnxe)
{
int send_len;
u8 *buf;
@@ -3329,6 +3664,8 @@
#ifdef CONFIG_FILS
if (sta && sta->fils_hlp_resp)
buflen += wpabuf_len(sta->fils_hlp_resp);
+ if (sta)
+ buflen += 150;
#endif /* CONFIG_FILS */
#ifdef CONFIG_OWE
if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
@@ -3365,6 +3702,9 @@
/* Extended supported rates */
p = hostapd_eid_ext_supp_rates(hapd, p);
+ /* Radio measurement capabilities */
+ p = hostapd_eid_rm_enabled_capab(hapd, p, buf + buflen - p);
+
#ifdef CONFIG_MBO
if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
rssi != 0) {
@@ -3381,7 +3721,8 @@
* Transition Information, RSN, [RIC Response] */
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
buf + buflen - p,
- sta->auth_alg, ies, ies_len);
+ sta->auth_alg, ies, ies_len,
+ omit_rsnxe);
if (!p) {
wpa_printf(MSG_DEBUG,
"FT: Failed to write AssocResp IEs");
@@ -3390,6 +3731,15 @@
}
}
#endif /* CONFIG_IEEE80211R_AP */
+#ifdef CONFIG_FILS
+ if (sta && status_code == WLAN_STATUS_SUCCESS &&
+ (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sta->auth_alg == WLAN_AUTH_FILS_PK))
+ p = wpa_auth_write_assoc_resp_fils(sta->wpa_sm, p,
+ buf + buflen - p,
+ ies, ies_len);
+#endif /* CONFIG_FILS */
#ifdef CONFIG_OWE
if (sta && status_code == WLAN_STATUS_SUCCESS &&
@@ -3399,18 +3749,15 @@
ies, ies_len);
#endif /* CONFIG_OWE */
-#ifdef CONFIG_IEEE80211W
if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211N
p = hostapd_eid_ht_capabilities(hapd, p);
p = hostapd_eid_ht_operation(hapd, p);
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
- if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
+ !is_6ghz_op_class(hapd->iconf->op_class)) {
u32 nsts = 0, sta_nsts;
if (sta && hapd->conf->use_sta_nsts && sta->vht_capabilities) {
@@ -3432,6 +3779,15 @@
}
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax) {
+ p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
+ p = hostapd_eid_he_operation(hapd, p);
+ p = hostapd_eid_spatial_reuse(hapd, p);
+ p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
+ }
+#endif /* CONFIG_IEEE80211AX */
+
p = hostapd_eid_ext_capab(hapd, p);
p = hostapd_eid_bss_max_idle_period(hapd, p);
if (sta && sta->qos_map_enabled)
@@ -3445,6 +3801,24 @@
}
#endif /* CONFIG_FST */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->rsnxe_override_ft &&
+ buf + buflen - p >=
+ (long int) wpabuf_len(hapd->conf->rsnxe_override_ft) &&
+ sta && sta->auth_alg == WLAN_AUTH_FT) {
+ wpa_printf(MSG_DEBUG, "TESTING: RSNXE FT override");
+ os_memcpy(p, wpabuf_head(hapd->conf->rsnxe_override_ft),
+ wpabuf_len(hapd->conf->rsnxe_override_ft));
+ p += wpabuf_len(hapd->conf->rsnxe_override_ft);
+ goto rsnxe_done;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (!omit_rsnxe)
+ p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
+#ifdef CONFIG_TESTING_OPTIONS
+rsnxe_done:
+#endif /* CONFIG_TESTING_OPTIONS */
+
#ifdef CONFIG_OWE
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
@@ -3574,7 +3948,7 @@
}
#endif /* CONFIG_FILS */
- if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, reply, send_len, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
strerror(errno));
res = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -3589,12 +3963,12 @@
#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)
+ u8 *owe_buf, size_t owe_buf_len, u16 *status)
{
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->conf->own_ie_override) {
wpa_printf(MSG_DEBUG, "OWE: Using IE override");
- *reason = WLAN_STATUS_SUCCESS;
+ *status = WLAN_STATUS_SUCCESS;
return wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
owe_buf_len, NULL, 0);
}
@@ -3604,12 +3978,18 @@
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;
+ *status = WLAN_STATUS_SUCCESS;
return owe_buf;
}
- *reason = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
- if (*reason != WLAN_STATUS_SUCCESS)
+ if (sta->owe_pmk && sta->external_dh_updated) {
+ wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK");
+ *status = WLAN_STATUS_SUCCESS;
+ return owe_buf;
+ }
+
+ *status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
+ if (*status != WLAN_STATUS_SUCCESS)
return NULL;
owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
@@ -3620,7 +4000,7 @@
pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
if (!pub) {
- *reason = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ *status = WLAN_STATUS_UNSPECIFIED_FAILURE;
return owe_buf;
}
@@ -3655,7 +4035,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, 0);
+ sta->fils_pending_assoc_req_len, 0, 0);
os_free(sta->fils_pending_assoc_req);
sta->fils_pending_assoc_req = NULL;
sta->fils_pending_assoc_req_len = 0;
@@ -3695,17 +4075,16 @@
int reassoc, int rssi)
{
u16 capab_info, listen_interval, seq_ctrl, fc;
- u16 resp = WLAN_STATUS_SUCCESS, reply_res;
+ int resp = WLAN_STATUS_SUCCESS;
+ u16 reply_res;
const u8 *pos;
int left, i;
struct sta_info *sta;
u8 *tmp = NULL;
- struct hostapd_sta_wpa_psk_short *psk = NULL;
- char *identity = NULL;
- char *radius_cui = NULL;
#ifdef CONFIG_FILS
int delay_assoc = 0;
#endif /* CONFIG_FILS */
+ int omit_rsnxe = 0;
if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
sizeof(mgmt->u.assoc_req))) {
@@ -3782,13 +4161,11 @@
hapd->iface->current_mode->mode ==
HOSTAPD_MODE_IEEE80211AD) {
int acl_res;
- u32 session_timeout, acct_interim_interval;
- struct vlan_description vlan_id;
+ struct radius_sta info;
- acl_res = ieee802_11_allowed_address(
- hapd, mgmt->sa, (const u8 *) mgmt, len,
- &session_timeout, &acct_interim_interval,
- &vlan_id, &psk, &identity, &radius_cui, 0);
+ acl_res = ieee802_11_allowed_address(hapd, mgmt->sa,
+ (const u8 *) mgmt,
+ len, &info);
if (acl_res == HOSTAPD_ACL_REJECT) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Ignore Association Request frame from "
@@ -3813,9 +4190,7 @@
}
acl_res = ieee802_11_set_radius_info(
- hapd, sta, acl_res, session_timeout,
- acct_interim_interval, &vlan_id, &psk,
- &identity, &radius_cui);
+ hapd, sta, acl_res, &info);
if (acl_res) {
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
@@ -3922,6 +4297,7 @@
resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
if (resp != WLAN_STATUS_SUCCESS)
goto fail;
+ omit_rsnxe = !get_ie(pos, left, WLAN_EID_RSNX);
if (hostapd_get_aid(hapd, sta) < 0) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -3974,9 +4350,7 @@
ieee802_11_set_beacons(hapd->iface);
}
-#ifdef CONFIG_IEEE80211N
update_ht_state(hapd, sta);
-#endif /* CONFIG_IEEE80211N */
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -3985,7 +4359,6 @@
*/
sta->flags |= WLAN_STA_ASSOC_REQ_OK;
-#ifdef CONFIG_IEEE80211W
if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) {
wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out "
"SA Query procedure", reassoc ? "re" : "");
@@ -3996,7 +4369,6 @@
* trying to associate.
*/
}
-#endif /* CONFIG_IEEE80211W */
/* Make sure that the previously registered inactivity timer will not
* remove the STA immediately. */
@@ -4018,9 +4390,6 @@
#endif /* CONFIG_FILS */
fail:
- os_free(identity);
- os_free(radius_cui);
- hostapd_free_psk_list(psk);
/*
* In case of a successful response, add the station to the driver.
@@ -4081,8 +4450,9 @@
}
#endif /* CONFIG_FILS */
- reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc, pos,
- left, rssi);
+ if (resp >= 0)
+ reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc,
+ pos, left, rssi, omit_rsnxe);
os_free(tmp);
/*
@@ -4123,6 +4493,7 @@
ap_sta_set_authorized(hapd, sta, 0);
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
+ hostapd_set_sta_flags(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "disassociated");
@@ -4189,6 +4560,7 @@
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
WLAN_STA_ASSOC_REQ_OK);
+ hostapd_set_sta_flags(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "deauthenticated");
@@ -4221,13 +4593,11 @@
}
-#ifdef CONFIG_IEEE80211W
static int robust_action_frame(u8 category)
{
return category != WLAN_ACTION_PUBLIC &&
category != WLAN_ACTION_HT;
}
-#endif /* CONFIG_IEEE80211W */
static int handle_action(struct hostapd_data *hapd,
@@ -4261,7 +4631,6 @@
return 0;
}
-#ifdef CONFIG_IEEE80211W
if (sta && (sta->flags & WLAN_STA_MFP) &&
!(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP)) &&
robust_action_frame(mgmt->u.action.category)) {
@@ -4271,7 +4640,6 @@
"an MFP STA");
return 0;
}
-#endif /* CONFIG_IEEE80211W */
if (sta) {
u16 fc = le_to_host16(mgmt->frame_control);
@@ -4305,11 +4673,9 @@
case WLAN_ACTION_WMM:
hostapd_wmm_action(hapd, mgmt, len);
return 1;
-#ifdef CONFIG_IEEE80211W
case WLAN_ACTION_SA_QUERY:
ieee802_11_sa_query_action(hapd, mgmt, len);
return 1;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WNM_AP
case WLAN_ACTION_WNM:
ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
@@ -4326,14 +4692,12 @@
#endif /* CONFIG_FST */
case WLAN_ACTION_PUBLIC:
case WLAN_ACTION_PROTECTED_DUAL:
-#ifdef CONFIG_IEEE80211N
if (len >= IEEE80211_HDRLEN + 2 &&
mgmt->u.action.u.public_action.action ==
WLAN_PA_20_40_BSS_COEX) {
hostapd_2040_coex_action(hapd, mgmt, len);
return 1;
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_DPP
if (len >= IEEE80211_HDRLEN + 6 &&
mgmt->u.action.u.vs_public_action.action ==
@@ -4416,7 +4780,7 @@
os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
resp->u.action.category |= 0x80;
- if (hostapd_drv_send_mlme(hapd, resp, len, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, resp, len, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send "
"Action frame");
}
@@ -4614,6 +4978,7 @@
struct sta_info *sta,
char *ifname_wds)
{
+#ifdef CONFIG_WEP
int i;
struct hostapd_ssid *ssid = &hapd->conf->ssid;
@@ -4623,14 +4988,18 @@
for (i = 0; i < 4; i++) {
if (ssid->wep.key[i] &&
hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i,
- i == ssid->wep.idx, NULL, 0,
- ssid->wep.key[i], ssid->wep.len[i])) {
+ 0, i == ssid->wep.idx, NULL, 0,
+ ssid->wep.key[i], ssid->wep.len[i],
+ i == ssid->wep.idx ?
+ KEY_FLAG_GROUP_RX_TX_DEFAULT :
+ KEY_FLAG_GROUP_RX_TX)) {
wpa_printf(MSG_WARNING,
"Could not set WEP keys for WDS interface; %s",
ifname_wds);
break;
}
}
+#endif /* CONFIG_WEP */
}
@@ -4709,9 +5078,7 @@
else
mlme_associate_indication(hapd, sta);
-#ifdef CONFIG_IEEE80211W
sta->sa_query_timed_out = 0;
-#endif /* CONFIG_IEEE80211W */
if (sta->eapol_sm == NULL) {
/*
@@ -5104,8 +5471,10 @@
wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
MACSTR, MAC2STR(src));
- if (is_multicast_ether_addr(src)) {
- /* Broadcast bit set in SA?! Ignore the frame silently. */
+ if (is_multicast_ether_addr(src) || is_zero_ether_addr(src) ||
+ os_memcmp(src, hapd->own_addr, ETH_ALEN) == 0) {
+ /* Broadcast bit set in SA or unexpected SA?! Ignore the frame
+ * silently. */
return;
}
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index db7badc..c7bdb4b 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -16,8 +16,8 @@
struct ieee80211_ht_capabilities;
struct ieee80211_vht_capabilities;
struct ieee80211_mgmt;
-struct vlan_description;
-struct hostapd_sta_wpa_psk_short;
+struct radius_sta;
+enum ieee80211_op_mode;
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
struct hostapd_frame_info *fi);
@@ -49,17 +49,20 @@
u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
+ size_t len);
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
-u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts);
u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid);
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_capab(struct hostapd_data *hapd, u8 *eid,
+ enum ieee80211_op_mode opmode);
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);
+u8 * hostapd_eid_spatial_reuse(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,
@@ -70,6 +73,10 @@
void hostapd_get_vht_capab(struct hostapd_data *hapd,
struct ieee80211_vht_capabilities *vht_cap,
struct ieee80211_vht_capabilities *neg_vht_cap);
+void hostapd_get_he_capab(struct hostapd_data *hapd,
+ const struct ieee80211_he_capabilities *he_cap,
+ struct ieee80211_he_capabilities *neg_he_cap,
+ size_t he_capab_len);
int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta);
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab);
@@ -85,6 +92,11 @@
const u8 *vht_oper);
u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_opmode);
+u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ enum ieee80211_op_mode opmode, const u8 *he_capab,
+ size_t he_capab_len);
+int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
+ enum ieee80211_op_mode mode);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
const u8 *buf, size_t len, int ack);
void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
@@ -152,7 +164,13 @@
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);
+ u8 *owe_buf, size_t owe_buf_len, u16 *status);
+u16 owe_process_rsn_ie(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *rsn_ie, size_t rsn_ie_len,
+ const u8 *owe_dh, size_t owe_dh_len);
+u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
+ const u8 *rsn_ie, size_t rsn_ie_len,
+ const u8 *owe_dh, size_t owe_dh_len);
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,
@@ -164,17 +182,14 @@
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);
+
+size_t hostapd_eid_dpp_cc_len(struct hostapd_data *hapd);
+u8 * hostapd_eid_dpp_cc(struct hostapd_data *hapd, u8 *eid, size_t len);
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);
+u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len);
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 931d4d0..783ee6d 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -32,12 +32,7 @@
macaddr addr;
int accepted; /* HOSTAPD_ACL_* */
struct hostapd_cached_radius_acl *next;
- u32 session_timeout;
- u32 acct_interim_interval;
- struct vlan_description vlan_id;
- struct hostapd_sta_wpa_psk_short *psk;
- char *identity;
- char *radius_cui;
+ struct radius_sta info;
};
@@ -54,9 +49,9 @@
#ifndef CONFIG_NO_RADIUS
static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
{
- os_free(e->identity);
- os_free(e->radius_cui);
- hostapd_free_psk_list(e->psk);
+ os_free(e->info.identity);
+ os_free(e->info.radius_cui);
+ hostapd_free_psk_list(e->info.psk);
os_free(e);
}
@@ -73,25 +68,8 @@
}
-static void copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
- struct hostapd_sta_wpa_psk_short *src)
-{
- if (!psk)
- return;
-
- if (src)
- src->ref++;
-
- *psk = src;
-}
-
-
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
- u32 *session_timeout,
- u32 *acct_interim_interval,
- struct vlan_description *vlan_id,
- struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui)
+ struct radius_sta *out)
{
struct hostapd_cached_radius_acl *entry;
struct os_reltime now;
@@ -105,27 +83,8 @@
if (os_reltime_expired(&now, &entry->timestamp,
RADIUS_ACL_TIMEOUT))
return -1; /* entry has expired */
- if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
- if (session_timeout)
- *session_timeout = entry->session_timeout;
- if (acct_interim_interval)
- *acct_interim_interval =
- entry->acct_interim_interval;
- if (vlan_id)
- *vlan_id = entry->vlan_id;
- copy_psk_list(psk, entry->psk);
- if (identity) {
- if (entry->identity)
- *identity = os_strdup(entry->identity);
- else
- *identity = NULL;
- }
- if (radius_cui) {
- if (entry->radius_cui)
- *radius_cui = os_strdup(entry->radius_cui);
- else
- *radius_cui = NULL;
- }
+ *out = entry->info;
+
return entry->accepted;
}
@@ -238,42 +197,28 @@
* @addr: MAC address of the STA
* @msg: Authentication message
* @len: Length of msg in octets
- * @session_timeout: Buffer for returning session timeout (from RADIUS)
- * @acct_interim_interval: Buffer for returning account interval (from RADIUS)
- * @vlan_id: Buffer for returning VLAN ID
- * @psk: Linked list buffer for returning WPA PSK
- * @identity: Buffer for returning identity (from RADIUS)
- * @radius_cui: Buffer for returning CUI (from RADIUS)
+ * @out.session_timeout: Buffer for returning session timeout (from RADIUS)
+ * @out.acct_interim_interval: Buffer for returning account interval (from
+ * RADIUS)
+ * @out.vlan_id: Buffer for returning VLAN ID
+ * @out.psk: Linked list buffer for returning WPA PSK
+ * @out.identity: Buffer for returning identity (from RADIUS)
+ * @out.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
- * values with os_free().
+ * The caller is responsible for properly cloning the returned out->identity and
+ * out->radius_cui and out->psk values.
*/
int hostapd_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,
+ const u8 *msg, size_t len, struct radius_sta *out,
int is_probe_req)
{
int res;
- if (session_timeout)
- *session_timeout = 0;
- if (acct_interim_interval)
- *acct_interim_interval = 0;
- if (vlan_id)
- os_memset(vlan_id, 0, sizeof(*vlan_id));
- if (psk)
- *psk = NULL;
- if (identity)
- *identity = NULL;
- if (radius_cui)
- *radius_cui = NULL;
+ os_memset(out, 0, sizeof(*out));
- res = hostapd_check_acl(hapd, addr, vlan_id);
+ res = hostapd_check_acl(hapd, addr, &out->vlan_id);
if (res != HOSTAPD_ACL_PENDING)
return res;
@@ -290,12 +235,10 @@
};
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
- vlan_id = NULL;
+ os_memset(&out->vlan_id, 0, sizeof(out->vlan_id));
/* 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,
- identity, radius_cui);
+ res = hostapd_acl_cache_get(hapd, addr, out);
if (res == HOSTAPD_ACL_ACCEPT ||
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
return res;
@@ -307,14 +250,6 @@
if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
/* pending query in RADIUS retransmit queue;
* do not generate a new one */
- if (identity) {
- os_free(*identity);
- *identity = NULL;
- }
- if (radius_cui) {
- os_free(*radius_cui);
- *radius_cui = NULL;
- }
return HOSTAPD_ACL_PENDING;
}
query = query->next;
@@ -488,8 +423,8 @@
passphraselen);
psk->is_passphrase = 1;
}
- psk->next = cache->psk;
- cache->psk = psk;
+ psk->next = cache->info.psk;
+ cache->info.psk = psk;
psk = NULL;
}
skip:
@@ -518,6 +453,7 @@
struct hostapd_data *hapd = data;
struct hostapd_acl_query_data *query, *prev;
struct hostapd_cached_radius_acl *cache;
+ struct radius_sta *info;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
query = hapd->acl_queries;
@@ -555,65 +491,66 @@
}
os_get_reltime(&cache->timestamp);
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
+ info = &cache->info;
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
u8 *buf;
size_t len;
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
- &cache->session_timeout) == 0)
+ &info->session_timeout) == 0)
cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
else
cache->accepted = HOSTAPD_ACL_ACCEPT;
if (radius_msg_get_attr_int32(
msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
- &cache->acct_interim_interval) == 0 &&
- cache->acct_interim_interval < 60) {
+ &info->acct_interim_interval) == 0 &&
+ info->acct_interim_interval < 60) {
wpa_printf(MSG_DEBUG, "Ignored too small "
"Acct-Interim-Interval %d for STA " MACSTR,
- cache->acct_interim_interval,
+ info->acct_interim_interval,
MAC2STR(query->addr));
- cache->acct_interim_interval = 0;
+ info->acct_interim_interval = 0;
}
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);
+ info->vlan_id.notempty = !!radius_msg_get_vlanid(
+ msg, &info->vlan_id.untagged,
+ MAX_NUM_TAGGED_VLAN, info->vlan_id.tagged);
decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
msg, req, cache);
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
&buf, &len, NULL) == 0) {
- cache->identity = os_zalloc(len + 1);
- if (cache->identity)
- os_memcpy(cache->identity, buf, len);
+ info->identity = os_zalloc(len + 1);
+ if (info->identity)
+ os_memcpy(info->identity, buf, len);
}
if (radius_msg_get_attr_ptr(
msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
&buf, &len, NULL) == 0) {
- cache->radius_cui = os_zalloc(len + 1);
- if (cache->radius_cui)
- os_memcpy(cache->radius_cui, buf, len);
+ info->radius_cui = os_zalloc(len + 1);
+ if (info->radius_cui)
+ os_memcpy(info->radius_cui, buf, len);
}
if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
- !cache->psk)
+ !info->psk)
cache->accepted = HOSTAPD_ACL_REJECT;
- if (cache->vlan_id.notempty &&
- !hostapd_vlan_valid(hapd->conf->vlan, &cache->vlan_id)) {
+ if (info->vlan_id.notempty &&
+ !hostapd_vlan_valid(hapd->conf->vlan, &info->vlan_id)) {
hostapd_logger(hapd, query->addr,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"Invalid VLAN %d%s received from RADIUS server",
- cache->vlan_id.untagged,
- cache->vlan_id.tagged[0] ? "+" : "");
- os_memset(&cache->vlan_id, 0, sizeof(cache->vlan_id));
+ info->vlan_id.untagged,
+ info->vlan_id.tagged[0] ? "+" : "");
+ os_memset(&info->vlan_id, 0, sizeof(info->vlan_id));
}
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
- !cache->vlan_id.notempty)
+ !info->vlan_id.notempty)
cache->accepted = HOSTAPD_ACL_REJECT;
} else
cache->accepted = HOSTAPD_ACL_REJECT;
@@ -622,7 +559,7 @@
#ifdef CONFIG_DRIVER_RADIUS_ACL
hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted,
- cache->session_timeout);
+ info->session_timeout);
#else /* CONFIG_DRIVER_RADIUS_ACL */
#ifdef NEED_AP_MLME
/* Re-send original authentication frame for 802.11 processing */
@@ -685,6 +622,19 @@
}
+void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
+ struct hostapd_sta_wpa_psk_short *src)
+{
+ if (!psk)
+ return;
+
+ if (src)
+ src->ref++;
+
+ *psk = src;
+}
+
+
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
{
if (psk && psk->ref) {
diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h
index 5aece51..9410f55 100644
--- a/src/ap/ieee802_11_auth.h
+++ b/src/ap/ieee802_11_auth.h
@@ -16,18 +16,25 @@
HOSTAPD_ACL_ACCEPT_TIMEOUT = 3
};
+struct radius_sta {
+ 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 hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
struct vlan_description *vlan_id);
int hostapd_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,
+ const u8 *msg, size_t len, struct radius_sta *out,
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);
void hostapd_acl_expire(struct hostapd_data *hapd);
+void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
+ struct hostapd_sta_wpa_psk_short *src);
#endif /* IEEE802_11_AUTH_H */
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index 0721358..57c6b18 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -1,6 +1,7 @@
/*
* hostapd / IEEE 802.11ax HE
* Copyright (c) 2016-2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2019 John Crispin <john@phrozen.org>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,40 +11,151 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
#include "hostapd.h"
#include "ap_config.h"
#include "beacon.h"
+#include "sta_info.h"
#include "ieee802_11.h"
#include "dfs.h"
-u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid)
+static u8 ieee80211_he_ppet_size(u8 ppe_thres_hdr, const u8 *phy_cap_info)
+{
+ u8 sz = 0, ru;
+
+ if ((phy_cap_info[HE_PHYCAP_PPE_THRESHOLD_PRESENT_IDX] &
+ HE_PHYCAP_PPE_THRESHOLD_PRESENT) == 0)
+ return 0;
+
+ ru = (ppe_thres_hdr >> HE_PPE_THRES_RU_INDEX_BITMASK_SHIFT) &
+ HE_PPE_THRES_RU_INDEX_BITMASK_MASK;
+ while (ru) {
+ if (ru & 0x1)
+ sz++;
+ ru >>= 1;
+ }
+
+ sz *= 1 + (ppe_thres_hdr & HE_PPE_THRES_NSS_MASK);
+ sz = (sz * 6) + 7;
+ if (sz % 8)
+ sz += 8;
+ sz /= 8;
+
+ return sz;
+}
+
+
+static u8 ieee80211_he_mcs_set_size(const u8 *phy_cap_info)
+{
+ u8 sz = 4;
+
+ if (phy_cap_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)
+ sz += 4;
+ if (phy_cap_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
+ sz += 4;
+
+ return sz;
+}
+
+
+static int ieee80211_invalid_he_cap_size(const u8 *buf, size_t len)
{
struct ieee80211_he_capabilities *cap;
- u8 *pos = eid;
+ size_t cap_len;
- if (!hapd->iface->current_mode)
+ cap = (struct ieee80211_he_capabilities *) buf;
+ cap_len = sizeof(*cap) - sizeof(cap->optional);
+ if (len < cap_len)
+ return 1;
+
+ cap_len += ieee80211_he_mcs_set_size(cap->he_phy_capab_info);
+ if (len < cap_len)
+ return 1;
+
+ cap_len += ieee80211_he_ppet_size(buf[cap_len], cap->he_phy_capab_info);
+
+ return len != cap_len;
+}
+
+
+u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
+ enum ieee80211_op_mode opmode)
+{
+ struct ieee80211_he_capabilities *cap;
+ struct hostapd_hw_modes *mode = hapd->iface->current_mode;
+ u8 he_oper_chwidth = ~HE_PHYCAP_CHANNEL_WIDTH_MASK;
+ u8 *pos = eid;
+ u8 ie_size = 0, mcs_nss_size = 4, ppet_size = 0;
+
+ if (!mode)
return eid;
+ ie_size = sizeof(*cap) - sizeof(cap->optional);
+ ppet_size = ieee80211_he_ppet_size(mode->he_capab[opmode].ppet[0],
+ mode->he_capab[opmode].phy_cap);
+
+ switch (hapd->iface->conf->he_oper_chwidth) {
+ case CHANWIDTH_80P80MHZ:
+ he_oper_chwidth |=
+ HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G;
+ mcs_nss_size += 4;
+ /* fall through */
+ case CHANWIDTH_160MHZ:
+ he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
+ mcs_nss_size += 4;
+ /* fall through */
+ case CHANWIDTH_80MHZ:
+ case CHANWIDTH_USE_HT:
+ he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
+ HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
+ break;
+ }
+
+ ie_size += mcs_nss_size + ppet_size;
+
*pos++ = WLAN_EID_EXTENSION;
- *pos++ = 1 + sizeof(struct ieee80211_he_capabilities);
+ *pos++ = 1 + ie_size;
*pos++ = WLAN_EID_EXT_HE_CAPABILITIES;
cap = (struct ieee80211_he_capabilities *) pos;
os_memset(cap, 0, sizeof(*cap));
+ os_memcpy(cap->he_mac_capab_info, mode->he_capab[opmode].mac_cap,
+ HE_MAX_MAC_CAPAB_SIZE);
+ os_memcpy(cap->he_phy_capab_info, mode->he_capab[opmode].phy_cap,
+ HE_MAX_PHY_CAPAB_SIZE);
+ os_memcpy(cap->optional, mode->he_capab[opmode].mcs, mcs_nss_size);
+ if (ppet_size)
+ os_memcpy(&cap->optional[mcs_nss_size],
+ mode->he_capab[opmode].ppet, ppet_size);
+
if (hapd->iface->conf->he_phy_capab.he_su_beamformer)
cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] |=
HE_PHYCAP_SU_BEAMFORMER_CAPAB;
+ else
+ cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] &=
+ ~HE_PHYCAP_SU_BEAMFORMER_CAPAB;
if (hapd->iface->conf->he_phy_capab.he_su_beamformee)
cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX] |=
HE_PHYCAP_SU_BEAMFORMEE_CAPAB;
+ else
+ cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX] &=
+ ~HE_PHYCAP_SU_BEAMFORMEE_CAPAB;
if (hapd->iface->conf->he_phy_capab.he_mu_beamformer)
cap->he_phy_capab_info[HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX] |=
HE_PHYCAP_MU_BEAMFORMER_CAPAB;
+ else
+ cap->he_phy_capab_info[HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX] &=
+ ~HE_PHYCAP_MU_BEAMFORMER_CAPAB;
- pos += sizeof(*cap);
+ cap->he_phy_capab_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &=
+ he_oper_chwidth;
+
+ pos += ie_size;
return pos;
}
@@ -53,36 +165,74 @@
{
struct ieee80211_he_operation *oper;
u8 *pos = eid;
+ int oper_size = 6;
+ u32 params = 0;
if (!hapd->iface->current_mode)
return eid;
+ if (is_6ghz_op_class(hapd->iconf->op_class))
+ oper_size += 5;
+
*pos++ = WLAN_EID_EXTENSION;
- *pos++ = 1 + sizeof(struct ieee80211_he_operation);
+ *pos++ = 1 + oper_size;
*pos++ = WLAN_EID_EXT_HE_OPERATION;
oper = (struct ieee80211_he_operation *) pos;
os_memset(oper, 0, sizeof(*oper));
- if (hapd->iface->conf->he_op.he_bss_color)
- oper->he_oper_params |= hapd->iface->conf->he_op.he_bss_color;
-
if (hapd->iface->conf->he_op.he_default_pe_duration)
- oper->he_oper_params |=
- (hapd->iface->conf->he_op.he_default_pe_duration <<
- HE_OPERATION_DFLT_PE_DURATION_OFFSET);
+ params |= (hapd->iface->conf->he_op.he_default_pe_duration <<
+ HE_OPERATION_DFLT_PE_DURATION_OFFSET);
if (hapd->iface->conf->he_op.he_twt_required)
- oper->he_oper_params |= HE_OPERATION_TWT_REQUIRED;
+ params |= HE_OPERATION_TWT_REQUIRED;
if (hapd->iface->conf->he_op.he_rts_threshold)
- oper->he_oper_params |=
- (hapd->iface->conf->he_op.he_rts_threshold <<
- HE_OPERATION_RTS_THRESHOLD_OFFSET);
+ params |= (hapd->iface->conf->he_op.he_rts_threshold <<
+ HE_OPERATION_RTS_THRESHOLD_OFFSET);
+
+ if (hapd->iface->conf->he_op.he_bss_color_disabled)
+ params |= HE_OPERATION_BSS_COLOR_DISABLED;
+ if (hapd->iface->conf->he_op.he_bss_color_partial)
+ params |= HE_OPERATION_BSS_COLOR_PARTIAL;
+ params |= hapd->iface->conf->he_op.he_bss_color <<
+ HE_OPERATION_BSS_COLOR_OFFSET;
+
+ /* HE minimum required basic MCS and NSS for STAs */
+ oper->he_mcs_nss_set =
+ host_to_le16(hapd->iface->conf->he_op.he_basic_mcs_nss_set);
/* TODO: conditional MaxBSSID Indicator subfield */
- pos += sizeof(*oper);
+ pos += 6; /* skip the fixed part */
+
+ if (is_6ghz_op_class(hapd->iconf->op_class)) {
+ u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf);
+ u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
+
+ if (!seg0)
+ seg0 = hapd->iconf->channel;
+
+ params |= HE_OPERATION_6GHZ_OPER_INFO;
+
+ /* 6 GHz Operation Information field */
+ *pos++ = hapd->iconf->channel; /* Primary Channel */
+
+ /* Control: Channel Width */
+ if (seg1)
+ *pos++ = 3;
+ else
+ *pos++ = center_idx_to_bw_6ghz(seg0);
+
+ /* Channel Center Freq Seg0/Seg1 */
+ *pos++ = seg0;
+ *pos++ = seg1;
+ /* Minimum Rate */
+ *pos++ = 6; /* TODO: what should be set here? */
+ }
+
+ oper->he_oper_params = host_to_le32(params);
return pos;
}
@@ -117,3 +267,164 @@
return pos;
}
+
+
+u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid)
+{
+ struct ieee80211_spatial_reuse *spr;
+ u8 *pos = eid, *spr_param;
+ u8 sz = 1;
+
+ if (!hapd->iface->conf->spr.sr_control)
+ return eid;
+
+ if (hapd->iface->conf->spr.sr_control &
+ SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT)
+ sz++;
+
+ if (hapd->iface->conf->spr.sr_control &
+ SPATIAL_REUSE_SRG_INFORMATION_PRESENT)
+ sz += 18;
+
+ *pos++ = WLAN_EID_EXTENSION;
+ *pos++ = 1 + sz;
+ *pos++ = WLAN_EID_EXT_SPATIAL_REUSE;
+
+ spr = (struct ieee80211_spatial_reuse *) pos;
+ os_memset(spr, 0, sizeof(*spr));
+
+ spr->sr_ctrl = hapd->iface->conf->spr.sr_control;
+ pos++;
+ spr_param = spr->params;
+ if (spr->sr_ctrl & SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT) {
+ *spr_param++ =
+ hapd->iface->conf->spr.non_srg_obss_pd_max_offset;
+ pos++;
+ }
+ if (spr->sr_ctrl & SPATIAL_REUSE_SRG_INFORMATION_PRESENT) {
+ *spr_param++ = hapd->iface->conf->spr.srg_obss_pd_min_offset;
+ *spr_param++ = hapd->iface->conf->spr.srg_obss_pd_max_offset;
+ pos += 18;
+ }
+
+ return pos;
+}
+
+
+void hostapd_get_he_capab(struct hostapd_data *hapd,
+ const struct ieee80211_he_capabilities *he_cap,
+ struct ieee80211_he_capabilities *neg_he_cap,
+ size_t he_capab_len)
+{
+ if (!he_cap)
+ return;
+
+ if (he_capab_len > sizeof(*neg_he_cap))
+ he_capab_len = sizeof(*neg_he_cap);
+ /* TODO: mask out unsupported features */
+
+ os_memcpy(neg_he_cap, he_cap, he_capab_len);
+}
+
+
+static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab,
+ enum ieee80211_op_mode opmode)
+{
+ u16 sta_rx_mcs_set, ap_tx_mcs_set;
+ u8 mcs_count = 0;
+ const u16 *ap_mcs_set, *sta_mcs_set;
+ int i;
+
+ if (!hapd->iface->current_mode)
+ return 1;
+ ap_mcs_set = (u16 *) hapd->iface->current_mode->he_capab[opmode].mcs;
+ sta_mcs_set = (u16 *) ((const struct ieee80211_he_capabilities *)
+ sta_he_capab)->optional;
+
+ /*
+ * Disable HE capabilities for STAs for which there is not even a single
+ * allowed MCS in any supported number of streams, i.e., STA is
+ * advertising 3 (not supported) as HE MCS rates for all supported
+ * band/stream cases.
+ */
+ switch (hapd->iface->conf->he_oper_chwidth) {
+ case CHANWIDTH_80P80MHZ:
+ mcs_count = 3;
+ break;
+ case CHANWIDTH_160MHZ:
+ mcs_count = 2;
+ break;
+ default:
+ mcs_count = 1;
+ break;
+ }
+
+ for (i = 0; i < mcs_count; i++) {
+ int j;
+
+ /* AP Tx MCS map vs. STA Rx MCS map */
+ sta_rx_mcs_set = WPA_GET_LE16((const u8 *) &sta_mcs_set[i * 2]);
+ ap_tx_mcs_set = WPA_GET_LE16((const u8 *)
+ &ap_mcs_set[(i * 2) + 1]);
+
+ for (j = 0; j < HE_NSS_MAX_STREAMS; j++) {
+ if (((ap_tx_mcs_set >> (j * 2)) & 0x3) == 3)
+ continue;
+
+ if (((sta_rx_mcs_set >> (j * 2)) & 0x3) == 3)
+ continue;
+
+ return 1;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "No matching HE MCS found between AP TX and STA RX");
+
+ return 0;
+}
+
+
+u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ enum ieee80211_op_mode opmode, const u8 *he_capab,
+ size_t he_capab_len)
+{
+ if (!he_capab || !hapd->iconf->ieee80211ax ||
+ !check_valid_he_mcs(hapd, he_capab, opmode) ||
+ ieee80211_invalid_he_cap_size(he_capab, he_capab_len) ||
+ he_capab_len > sizeof(struct ieee80211_he_capabilities)) {
+ sta->flags &= ~WLAN_STA_HE;
+ os_free(sta->he_capab);
+ sta->he_capab = NULL;
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ if (!sta->he_capab) {
+ sta->he_capab =
+ os_zalloc(sizeof(struct ieee80211_he_capabilities));
+ if (!sta->he_capab)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ sta->flags |= WLAN_STA_HE;
+ os_memset(sta->he_capab, 0, sizeof(struct ieee80211_he_capabilities));
+ os_memcpy(sta->he_capab, he_capab, he_capab_len);
+ sta->he_capab_len = he_capab_len;
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
+ enum ieee80211_op_mode mode)
+{
+ u8 *mac_cap;
+
+ if (!hapd->iface->current_mode ||
+ !hapd->iface->current_mode->he_capab[mode].he_supported)
+ return 0;
+
+ mac_cap = hapd->iface->current_mode->he_capab[mode].mac_cap;
+
+ return !!(mac_cap[HE_MAC_CAPAB_0] & HE_MACCAP_TWT_RESPONDER);
+}
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 214855d..59ecbdc 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -27,7 +27,7 @@
u8 *pos = eid;
if (!hapd->iconf->ieee80211n || !hapd->iface->current_mode ||
- hapd->conf->disable_11n)
+ hapd->conf->disable_11n || is_6ghz_op_class(hapd->iconf->op_class))
return eid;
*pos++ = WLAN_EID_HT_CAP;
@@ -84,7 +84,8 @@
struct ieee80211_ht_operation *oper;
u8 *pos = eid;
- if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
+ if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n ||
+ is_6ghz_op_class(hapd->iconf->op_class))
return eid;
*pos++ = WLAN_EID_HT_OPERATION;
@@ -108,32 +109,9 @@
}
-u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid)
-{
- u8 sec_ch;
-
- if (!hapd->cs_freq_params.channel ||
- !hapd->cs_freq_params.sec_channel_offset)
- return eid;
-
- if (hapd->cs_freq_params.sec_channel_offset == -1)
- sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW;
- else if (hapd->cs_freq_params.sec_channel_offset == 1)
- sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE;
- else
- return eid;
-
- *eid++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET;
- *eid++ = 1;
- *eid++ = sec_ch;
-
- return eid;
-}
-
-
/*
op_mode
-Set to 0 (HT pure) under the followign conditions
+Set to 0 (HT pure) under the following conditions
- all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
- all STAs in the BSS are 20 MHz HT in 20 MHz BSS
Set to 1 (HT non-member protection) if there may be non-HT STAs
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 707381f..113b4ef 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -19,8 +19,6 @@
#include "ieee802_11.h"
-#ifdef CONFIG_IEEE80211W
-
u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
struct sta_info *sta, u8 *eid)
{
@@ -114,7 +112,8 @@
end += oci_ie_len;
}
#endif /* CONFIG_OCV */
- if (hostapd_drv_send_mlme(hapd, mgmt, end - (u8 *) mgmt, 0) < 0)
+ if (hostapd_drv_send_mlme(hapd, mgmt, end - (u8 *) mgmt, 0, NULL, 0, 0)
+ < 0)
wpa_printf(MSG_INFO, "ieee802_11_send_sa_query_req: send failed");
os_free(mgmt);
@@ -195,7 +194,8 @@
end += oci_ie_len;
}
#endif /* CONFIG_OCV */
- if (hostapd_drv_send_mlme(hapd, resp, end - (u8 *) resp, 0) < 0)
+ if (hostapd_drv_send_mlme(hapd, resp, end - (u8 *) resp, 0, NULL, 0, 0)
+ < 0)
wpa_printf(MSG_INFO, "ieee80211_mgmt_sa_query_request: send failed");
os_free(resp);
@@ -304,8 +304,6 @@
ap_sta_stop_sa_query(hapd, sta);
}
-#endif /* CONFIG_IEEE80211W */
-
static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
{
@@ -379,6 +377,11 @@
wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt))
*pos |= 0x01;
#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax &&
+ hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP))
+ *pos |= 0x40; /* Bit 78 - TWT responder */
+#endif /* CONFIG_IEEE80211AX */
break;
case 10: /* Bits 80-87 */
#ifdef CONFIG_SAE
@@ -394,6 +397,8 @@
* Identifiers Used Exclusively */
}
#endif /* CONFIG_SAE */
+ if (hapd->conf->beacon_prot)
+ *pos |= 0x10; /* Bit 84 - Beacon Protection Enabled */
break;
}
}
@@ -404,14 +409,22 @@
u8 *pos = eid;
u8 len = 0, i;
- if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
+ if (hapd->conf->qos_map_set_len ||
+ (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH)))
len = 5;
- if (len < 4 && hapd->conf->interworking)
+ if (len < 4 &&
+ (hapd->conf->time_advertisement == 2 || hapd->conf->interworking))
len = 4;
- if (len < 3 && hapd->conf->wnm_sleep_mode)
+ if (len < 3 &&
+ (hapd->conf->wnm_sleep_mode || hapd->conf->bss_transition))
len = 3;
- if (len < 1 && hapd->iconf->obss_interval)
+ if (len < 1 &&
+ (hapd->iconf->obss_interval ||
+ (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)))
len = 1;
+ if (len < 2 &&
+ (hapd->conf->proxy_arp || hapd->conf->coloc_intf_reporting))
+ len = 2;
if (len < 7 && hapd->conf->ssid.utf8_ssid)
len = 7;
if (len < 9 &&
@@ -434,12 +447,19 @@
!wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) && len < 10)
len = 10;
#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211AX
+ if (len < 10 && hapd->iconf->ieee80211ax &&
+ hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP))
+ len = 10;
+#endif /* CONFIG_IEEE80211AX */
#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 < 11 && hapd->conf->beacon_prot)
+ len = 11;
if (len < hapd->iface->extended_capa_len)
len = hapd->iface->extended_capa_len;
if (len == 0)
@@ -854,6 +874,36 @@
}
+size_t hostapd_eid_dpp_cc_len(struct hostapd_data *hapd)
+{
+#ifdef CONFIG_DPP2
+ if (hapd->conf->dpp_configurator_connectivity)
+ return 6;
+#endif /* CONFIG_DPP2 */
+ return 0;
+}
+
+
+u8 * hostapd_eid_dpp_cc(struct hostapd_data *hapd, u8 *eid, size_t len)
+{
+#ifdef CONFIG_DPP2
+ u8 *pos = eid;
+
+ if (!hapd->conf->dpp_configurator_connectivity || len < 6)
+ return pos;
+
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 4;
+ WPA_PUT_BE24(pos, OUI_WFA);
+ pos += 3;
+ *pos++ = DPP_CC_OUI_TYPE;
+
+ return pos;
+#endif /* CONFIG_DPP2 */
+ return eid;
+}
+
+
void ap_copy_sta_supp_op_classes(struct sta_info *sta,
const u8 *supp_op_classes,
size_t supp_op_classes_len)
@@ -1000,3 +1050,25 @@
return 0;
}
#endif /* CONFIG_OCV */
+
+
+u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
+{
+ u8 *pos = eid;
+
+ if (!(hapd->conf->wpa & WPA_PROTO_RSN) ||
+ !wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) ||
+ (hapd->conf->sae_pwe != 1 && hapd->conf->sae_pwe != 2 &&
+ !hostapd_sae_pw_id_in_use(hapd->conf)) ||
+ hapd->conf->sae_pwe == 3 ||
+ len < 3)
+ return pos;
+
+ *pos++ = WLAN_EID_RSNX;
+ *pos++ = 1;
+ /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
+ * used for now */
+ *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+
+ return pos;
+}
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 54ee080..f50f142 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -26,7 +26,7 @@
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
u8 *pos = eid;
- if (!mode)
+ if (!mode || is_6ghz_op_class(hapd->iconf->op_class))
return eid;
if (mode->mode == HOSTAPD_MODE_IEEE80211G && hapd->conf->vendor_vht &&
@@ -76,6 +76,9 @@
struct ieee80211_vht_operation *oper;
u8 *pos = eid;
+ if (is_6ghz_op_class(hapd->iconf->op_class))
+ return eid;
+
*pos++ = WLAN_EID_VHT_OPERATION;
*pos++ = sizeof(*oper);
@@ -242,7 +245,7 @@
return eid;
switch (iface->conf->vht_oper_chwidth) {
- case VHT_CHANWIDTH_USE_HT:
+ case CHANWIDTH_USE_HT:
if (iconf->secondary_channel == 0) {
/* Max Transmit Power count = 0 (20 MHz) */
tx_pwr_count = 0;
@@ -251,12 +254,12 @@
tx_pwr_count = 1;
}
break;
- case VHT_CHANWIDTH_80MHZ:
+ case CHANWIDTH_80MHZ:
/* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
tx_pwr_count = 2;
break;
- case VHT_CHANWIDTH_80P80MHZ:
- case VHT_CHANWIDTH_160MHZ:
+ case CHANWIDTH_80P80MHZ:
+ case CHANWIDTH_160MHZ:
/* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
tx_pwr_count = 3;
break;
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 870329a..ee095f6 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -7,6 +7,9 @@
*/
#include "utils/includes.h"
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
#include "utils/common.h"
#include "utils/eloop.h"
@@ -34,6 +37,7 @@
/* FIX: Not really a good thing to require ieee802_11.h here.. (FILS) */
#include "ieee802_11.h"
#include "ieee802_1x.h"
+#include "wpa_auth_kay.h"
#ifdef CONFIG_HS20
@@ -54,15 +58,18 @@
len = sizeof(*xhdr) + datalen;
buf = os_zalloc(len);
- if (buf == NULL) {
- wpa_printf(MSG_ERROR, "malloc() failed for "
- "ieee802_1x_send(len=%lu)",
- (unsigned long) len);
+ if (!buf) {
+ wpa_printf(MSG_ERROR, "malloc() failed for %s(len=%lu)",
+ __func__, (unsigned long) len);
return;
}
xhdr = (struct ieee802_1x_hdr *) buf;
xhdr->version = hapd->conf->eapol_version;
+#ifdef CONFIG_MACSEC
+ if (xhdr->version > 2 && hapd->conf->macsec_policy == 0)
+ xhdr->version = 2;
+#endif /* CONFIG_MACSEC */
xhdr->type = type;
xhdr->length = host_to_be16(datalen);
@@ -130,6 +137,7 @@
}
+#ifdef CONFIG_WEP
#ifndef CONFIG_FIPS
#ifndef CONFIG_NO_RC4
@@ -144,12 +152,12 @@
size_t len, ekey_len;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+ if (!sm)
return;
len = sizeof(*key) + key_len;
buf = os_zalloc(sizeof(*hdr) + len);
- if (buf == NULL)
+ if (!buf)
return;
hdr = (struct ieee802_1x_hdr *) buf;
@@ -157,6 +165,21 @@
key->type = EAPOL_KEY_TYPE_RC4;
WPA_PUT_BE16(key->key_length, key_len);
wpa_get_ntp_timestamp(key->replay_counter);
+ if (os_memcmp(key->replay_counter,
+ hapd->last_1x_eapol_key_replay_counter,
+ IEEE8021X_REPLAY_COUNTER_LEN) <= 0) {
+ /* NTP timestamp did not increment from last EAPOL-Key frame;
+ * use previously used value + 1 instead. */
+ inc_byte_array(hapd->last_1x_eapol_key_replay_counter,
+ IEEE8021X_REPLAY_COUNTER_LEN);
+ os_memcpy(key->replay_counter,
+ hapd->last_1x_eapol_key_replay_counter,
+ IEEE8021X_REPLAY_COUNTER_LEN);
+ } else {
+ os_memcpy(hapd->last_1x_eapol_key_replay_counter,
+ key->replay_counter,
+ IEEE8021X_REPLAY_COUNTER_LEN);
+ }
if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) {
wpa_printf(MSG_ERROR, "Could not get random numbers");
@@ -175,16 +198,16 @@
/* Key is encrypted using "Key-IV + MSK[0..31]" as the RC4-key and
* MSK[32..63] is used to sign the message. */
- if (sm->eap_if->eapKeyData == NULL || sm->eap_if->eapKeyDataLen < 64) {
- wpa_printf(MSG_ERROR, "No eapKeyData available for encrypting "
- "and signing EAPOL-Key");
+ if (!sm->eap_if->eapKeyData || sm->eap_if->eapKeyDataLen < 64) {
+ wpa_printf(MSG_ERROR,
+ "No eapKeyData available for encrypting and signing EAPOL-Key");
os_free(buf);
return;
}
os_memcpy((u8 *) (key + 1), key_data, key_len);
ekey_len = sizeof(key->key_iv) + 32;
ekey = os_malloc(ekey_len);
- if (ekey == NULL) {
+ if (!ekey) {
wpa_printf(MSG_ERROR, "Could not encrypt key");
os_free(buf);
return;
@@ -197,6 +220,10 @@
/* This header is needed here for HMAC-MD5, but it will be regenerated
* in ieee802_1x_send() */
hdr->version = hapd->conf->eapol_version;
+#ifdef CONFIG_MACSEC
+ if (hdr->version > 2)
+ hdr->version = 2;
+#endif /* CONFIG_MACSEC */
hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
hdr->length = host_to_be16(len);
hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len,
@@ -217,7 +244,7 @@
struct eapol_authenticator *eapol = hapd->eapol_auth;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL || !sm->eap_if->eapKeyData)
+ if (!sm || !sm->eap_if->eapKeyData)
return;
wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR,
@@ -238,12 +265,13 @@
if (hapd->conf->individual_wep_key_len > 0) {
u8 *ikey;
+
ikey = os_malloc(hapd->conf->individual_wep_key_len);
- if (ikey == NULL ||
+ if (!ikey ||
random_get_bytes(ikey, hapd->conf->individual_wep_key_len))
{
- wpa_printf(MSG_ERROR, "Could not generate random "
- "individual WEP key.");
+ wpa_printf(MSG_ERROR,
+ "Could not generate random individual WEP key");
os_free(ikey);
return;
}
@@ -257,10 +285,11 @@
/* TODO: set encryption in TX callback, i.e., only after STA
* has ACKed EAPOL-Key frame */
if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
- sta->addr, 0, 1, NULL, 0, ikey,
- hapd->conf->individual_wep_key_len)) {
- wpa_printf(MSG_ERROR, "Could not set individual WEP "
- "encryption.");
+ sta->addr, 0, 0, 1, NULL, 0, ikey,
+ hapd->conf->individual_wep_key_len,
+ KEY_FLAG_PAIRWISE_RX_TX)) {
+ wpa_printf(MSG_ERROR,
+ "Could not set individual WEP encryption");
}
os_free(ikey);
@@ -269,6 +298,7 @@
#endif /* CONFIG_NO_RC4 */
#endif /* CONFIG_FIPS */
+#endif /* CONFIG_WEP */
const char *radius_mode_txt(struct hostapd_data *hapd)
@@ -320,13 +350,13 @@
eap_erp_update_identity(sm->eap, eap, len);
identity = eap_get_identity(sm->eap, &identity_len);
- if (identity == NULL)
+ if (!identity)
return;
/* Save station identity for future RADIUS packets */
os_free(sm->identity);
sm->identity = (u8 *) dup_binstr(identity, identity_len);
- if (sm->identity == NULL) {
+ if (!sm->identity) {
sm->identity_len = 0;
return;
}
@@ -381,7 +411,6 @@
return -1;
}
-#ifdef CONFIG_IEEE80211W
if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
suite = wpa_cipher_to_suite(WPA_PROTO_RSN,
hapd->conf->group_mgmt_cipher);
@@ -394,7 +423,6 @@
return -1;
}
}
-#endif /* CONFIG_IEEE80211W */
return 0;
}
@@ -581,8 +609,7 @@
if (!radius_msg_add_attr(msg, attr->type,
wpabuf_head(attr->val),
wpabuf_len(attr->val))) {
- wpa_printf(MSG_ERROR, "Could not add RADIUS "
- "attribute");
+ wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
return -1;
}
}
@@ -591,6 +618,63 @@
}
+int add_sqlite_radius_attr(struct hostapd_data *hapd, struct sta_info *sta,
+ struct radius_msg *msg, int acct)
+{
+#ifdef CONFIG_SQLITE
+ const char *attrtxt;
+ char addrtxt[3 * ETH_ALEN];
+ char *sql;
+ sqlite3_stmt *stmt = NULL;
+
+ if (!hapd->rad_attr_db)
+ return 0;
+
+ os_snprintf(addrtxt, sizeof(addrtxt), MACSTR, MAC2STR(sta->addr));
+
+ sql = "SELECT attr FROM radius_attributes WHERE sta=? AND (reqtype=? OR reqtype IS NULL);";
+ if (sqlite3_prepare_v2(hapd->rad_attr_db, sql, os_strlen(sql), &stmt,
+ NULL) != SQLITE_OK) {
+ wpa_printf(MSG_ERROR, "DB: Failed to prepare SQL statement: %s",
+ sqlite3_errmsg(hapd->rad_attr_db));
+ return -1;
+ }
+ sqlite3_bind_text(stmt, 1, addrtxt, os_strlen(addrtxt), SQLITE_STATIC);
+ sqlite3_bind_text(stmt, 2, acct ? "acct" : "auth", 4, SQLITE_STATIC);
+ while (sqlite3_step(stmt) == SQLITE_ROW) {
+ struct hostapd_radius_attr *attr;
+ struct radius_attr_hdr *hdr;
+
+ attrtxt = (const char *) sqlite3_column_text(stmt, 0);
+ attr = hostapd_parse_radius_attr(attrtxt);
+ if (!attr) {
+ wpa_printf(MSG_ERROR,
+ "Skipping invalid attribute from SQL: %s",
+ attrtxt);
+ continue;
+ }
+ wpa_printf(MSG_DEBUG, "Adding RADIUS attribute from SQL: %s",
+ attrtxt);
+ hdr = radius_msg_add_attr(msg, attr->type,
+ wpabuf_head(attr->val),
+ wpabuf_len(attr->val));
+ hostapd_config_free_radius_attr(attr);
+ if (!hdr) {
+ wpa_printf(MSG_ERROR,
+ "Could not add RADIUS attribute from SQL");
+ continue;
+ }
+ }
+
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+#endif /* CONFIG_SQLITE */
+
+ return 0;
+}
+
+
void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
struct sta_info *sta,
const u8 *eap, size_t len)
@@ -598,18 +682,17 @@
struct radius_msg *msg;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+ if (!sm)
return;
ieee802_1x_learn_identity(hapd, sm, eap, len);
- wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS "
- "packet");
+ wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS packet");
sm->radius_identifier = radius_client_get_id(hapd->radius);
msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
sm->radius_identifier);
- if (msg == NULL) {
+ if (!msg) {
wpa_printf(MSG_INFO, "Could not create new RADIUS packet");
return;
}
@@ -630,6 +713,9 @@
msg) < 0)
goto fail;
+ if (sta && add_sqlite_radius_attr(hapd, sta, msg, 0) < 0)
+ goto fail;
+
/* TODO: should probably check MTU from driver config; 2304 is max for
* IEEE 802.11, but use 1400 to avoid problems with too large packets
*/
@@ -653,12 +739,12 @@
int res = radius_msg_copy_attr(msg, sm->last_recv_radius,
RADIUS_ATTR_STATE);
if (res < 0) {
- wpa_printf(MSG_INFO, "Could not copy State attribute from previous Access-Challenge");
+ wpa_printf(MSG_INFO,
+ "Could not copy State attribute from previous Access-Challenge");
goto fail;
}
- if (res > 0) {
+ if (res > 0)
wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute");
- }
}
if (hapd->conf->radius_request_cui) {
@@ -687,8 +773,8 @@
if (!radius_msg_add_wfa(
msg, RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION,
&ver, 1)) {
- wpa_printf(MSG_ERROR, "Could not add HS 2.0 AP "
- "version");
+ wpa_printf(MSG_ERROR,
+ "Could not add HS 2.0 AP version");
goto fail;
}
@@ -696,6 +782,7 @@
const u8 *pos;
u8 buf[3];
u16 id;
+
pos = wpabuf_head_u8(sta->hs20_ie);
buf[0] = (*pos) >> 4;
if (((*pos) & HS20_PPS_MO_ID_PRESENT) &&
@@ -708,8 +795,8 @@
msg,
RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION,
buf, sizeof(buf))) {
- wpa_printf(MSG_ERROR, "Could not add HS 2.0 "
- "STA version");
+ wpa_printf(MSG_ERROR,
+ "Could not add HS 2.0 STA version");
goto fail;
}
}
@@ -768,13 +855,14 @@
{
u8 type, *data;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+
+ if (!sm)
return;
data = (u8 *) (eap + 1);
if (len < sizeof(*eap) + 1) {
- wpa_printf(MSG_INFO, "handle_eap_response: too short response data");
+ wpa_printf(MSG_INFO, "%s: too short response data", __func__);
return;
}
@@ -790,7 +878,7 @@
wpabuf_free(sm->eap_if->eapRespData);
sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len);
- sm->eapolEap = TRUE;
+ sm->eapolEap = true;
}
@@ -802,12 +890,11 @@
u8 type, *data;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+ if (!sm)
return;
if (len < sizeof(*eap) + 1) {
- wpa_printf(MSG_INFO,
- "handle_eap_initiate: too short response data");
+ wpa_printf(MSG_INFO, "%s: too short response data", __func__);
return;
}
@@ -815,18 +902,41 @@
type = data[0];
hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d "
- "id=%d len=%d) from STA: EAP Initiate type %u",
+ HOSTAPD_LEVEL_DEBUG,
+ "received EAP packet (code=%d id=%d len=%d) from STA: EAP Initiate type %u",
eap->code, eap->identifier, be_to_host16(eap->length),
type);
wpabuf_free(sm->eap_if->eapRespData);
sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len);
- sm->eapolEap = TRUE;
+ sm->eapolEap = true;
#endif /* CONFIG_ERP */
}
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static const char * eap_code_str(u8 code)
+{
+ switch (code) {
+ case EAP_CODE_REQUEST:
+ return "request";
+ case EAP_CODE_RESPONSE:
+ return "response";
+ case EAP_CODE_SUCCESS:
+ return "success";
+ case EAP_CODE_FAILURE:
+ return "failure";
+ case EAP_CODE_INITIATE:
+ return "initiate";
+ case EAP_CODE_FINISH:
+ return "finish";
+ default:
+ return "unknown";
+ }
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
/* Process incoming EAP packet from Supplicant */
static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta,
u8 *buf, size_t len)
@@ -842,44 +952,29 @@
eap = (struct eap_hdr *) buf;
eap_len = be_to_host16(eap->length);
- wpa_printf(MSG_DEBUG, "EAP: code=%d identifier=%d length=%d",
- eap->code, eap->identifier, eap_len);
+ wpa_printf(MSG_DEBUG, "EAP: code=%d (%s) identifier=%d length=%d",
+ eap->code, eap_code_str(eap->code), eap->identifier,
+ eap_len);
if (eap_len < sizeof(*eap)) {
wpa_printf(MSG_DEBUG, " Invalid EAP length");
return;
} else if (eap_len > len) {
- wpa_printf(MSG_DEBUG, " Too short frame to contain this EAP "
- "packet");
+ wpa_printf(MSG_DEBUG,
+ " Too short frame to contain this EAP packet");
return;
} else if (eap_len < len) {
- wpa_printf(MSG_DEBUG, " Ignoring %lu extra bytes after EAP "
- "packet", (unsigned long) len - eap_len);
+ wpa_printf(MSG_DEBUG,
+ " Ignoring %lu extra bytes after EAP packet",
+ (unsigned long) len - eap_len);
}
switch (eap->code) {
- case EAP_CODE_REQUEST:
- wpa_printf(MSG_DEBUG, " (request)");
- return;
case EAP_CODE_RESPONSE:
- wpa_printf(MSG_DEBUG, " (response)");
handle_eap_response(hapd, sta, eap, eap_len);
break;
- case EAP_CODE_SUCCESS:
- wpa_printf(MSG_DEBUG, " (success)");
- return;
- case EAP_CODE_FAILURE:
- wpa_printf(MSG_DEBUG, " (failure)");
- return;
case EAP_CODE_INITIATE:
- wpa_printf(MSG_DEBUG, " (initiate)");
handle_eap_initiate(hapd, sta, eap, eap_len);
break;
- case EAP_CODE_FINISH:
- wpa_printf(MSG_DEBUG, " (finish)");
- break;
- default:
- wpa_printf(MSG_DEBUG, " (unknown code)");
- return;
}
}
@@ -888,6 +983,7 @@
ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
{
int flags = 0;
+
if (sta->flags & WLAN_STA_PREAUTH)
flags |= EAPOL_SM_PREAUTH;
if (sta->wpa_sm) {
@@ -952,8 +1048,8 @@
sta = ap_get_sta(hapd, sa);
if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) &&
!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
- wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
- "associated/Pre-authenticating STA");
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X data frame from not associated/Pre-authenticating STA");
if (sta && (sta->flags & WLAN_STA_AUTH)) {
wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR
@@ -975,14 +1071,15 @@
hdr->version, hdr->type, datalen);
if (len - sizeof(*hdr) < datalen) {
- wpa_printf(MSG_INFO, " frame too short for this IEEE 802.1X packet");
+ wpa_printf(MSG_INFO,
+ " frame too short for this IEEE 802.1X packet");
if (sta->eapol_sm)
sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++;
return;
}
if (len - sizeof(*hdr) > datalen) {
- wpa_printf(MSG_DEBUG, " ignoring %lu extra octets after "
- "IEEE 802.1X packet",
+ wpa_printf(MSG_DEBUG,
+ " ignoring %lu extra octets after IEEE 802.1X packet",
(unsigned long) len - sizeof(*hdr) - datalen);
}
@@ -1003,8 +1100,8 @@
if (!hapd->conf->ieee802_1x && !hapd->conf->osen &&
!(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
- "802.1X not enabled and WPS not used");
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Ignore EAPOL message - 802.1X not enabled and WPS not used");
return;
}
@@ -1012,8 +1109,8 @@
if (key_mgmt != -1 &&
(wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE ||
key_mgmt == WPA_KEY_MGMT_DPP)) {
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
- "STA is using PSK");
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Ignore EAPOL message - STA is using PSK");
return;
}
@@ -1036,15 +1133,14 @@
* skipped if the STA is known to support WPS
* 2.0.
*/
- wpa_printf(MSG_DEBUG, "WPS: Do not start "
- "EAPOL until EAPOL-Start is "
- "received");
+ wpa_printf(MSG_DEBUG,
+ "WPS: Do not start EAPOL until EAPOL-Start is received");
sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
}
}
#endif /* CONFIG_WPS */
- sta->eapol_sm->eap_if->portEnabled = TRUE;
+ sta->eapol_sm->eap_if->portEnabled = true;
}
/* since we support version 1, we can ignore version field and proceed
@@ -1061,18 +1157,17 @@
case IEEE802_1X_TYPE_EAPOL_START:
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "received EAPOL-Start "
- "from STA");
+ HOSTAPD_LEVEL_DEBUG,
+ "received EAPOL-Start from STA");
sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
if (pmksa) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
- HOSTAPD_LEVEL_DEBUG, "cached PMKSA "
- "available - ignore it since "
- "STA sent EAPOL-Start");
+ HOSTAPD_LEVEL_DEBUG,
+ "cached PMKSA available - ignore it since STA sent EAPOL-Start");
wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa);
}
- sta->eapol_sm->eapolStart = TRUE;
+ sta->eapol_sm->eapolStart = true;
sta->eapol_sm->dot1xAuthEapolStartFramesRx++;
eap_server_clear_identity(sta->eapol_sm->eap);
wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL);
@@ -1080,12 +1175,12 @@
case IEEE802_1X_TYPE_EAPOL_LOGOFF:
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "received EAPOL-Logoff "
- "from STA");
+ HOSTAPD_LEVEL_DEBUG,
+ "received EAPOL-Logoff from STA");
sta->acct_terminate_cause =
RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
accounting_sta_stop(hapd, sta);
- sta->eapol_sm->eapolLogoff = TRUE;
+ sta->eapol_sm->eapolLogoff = true;
sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++;
eap_server_clear_identity(sta->eapol_sm->eap);
break;
@@ -1093,8 +1188,8 @@
case IEEE802_1X_TYPE_EAPOL_KEY:
wpa_printf(MSG_DEBUG, " EAPOL-Key");
if (!ap_sta_is_authorized(sta)) {
- wpa_printf(MSG_DEBUG, " Dropped key data from "
- "unauthorized Supplicant");
+ wpa_printf(MSG_DEBUG,
+ " Dropped key data from unauthorized Supplicant");
break;
}
break;
@@ -1104,6 +1199,13 @@
/* TODO: implement support for this; show data */
break;
+#ifdef CONFIG_MACSEC
+ case IEEE802_1X_TYPE_EAPOL_MKA:
+ wpa_printf(MSG_EXCESSIVE,
+ "EAPOL type %d will be handled by MKA", hdr->type);
+ break;
+#endif /* CONFIG_MACSEC */
+
default:
wpa_printf(MSG_DEBUG, " unknown IEEE 802.1X packet type");
sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++;
@@ -1143,8 +1245,8 @@
#endif /* CONFIG_WPS */
if (!force_1x && !hapd->conf->ieee802_1x && !hapd->conf->osen) {
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - "
- "802.1X not enabled or forced for WPS");
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Ignore STA - 802.1X not enabled or forced for WPS");
/*
* Clear any possible EAPOL authenticator state to support
* reassociation change from WPS to PSK.
@@ -1166,11 +1268,11 @@
return;
}
- if (sta->eapol_sm == NULL) {
+ if (!sta->eapol_sm) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG, "start authentication");
sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
- if (sta->eapol_sm == NULL) {
+ if (!sta->eapol_sm) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_INFO,
@@ -1189,13 +1291,13 @@
* initiates the handshake with EAPOL-Start. Only allow the
* wait to be skipped if the STA is known to support WPS 2.0.
*/
- wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until "
- "EAPOL-Start is received");
+ wpa_printf(MSG_DEBUG,
+ "WPS: Do not start EAPOL until EAPOL-Start is received");
sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
}
#endif /* CONFIG_WPS */
- sta->eapol_sm->eap_if->portEnabled = TRUE;
+ sta->eapol_sm->eap_if->portEnabled = true;
#ifdef CONFIG_IEEE80211R_AP
if (sta->auth_alg == WLAN_AUTH_FT) {
@@ -1204,13 +1306,13 @@
"PMK from FT - skip IEEE 802.1X/EAP");
/* Setup EAPOL state machines to already authenticated state
* because of existing FT information from R0KH. */
- sta->eapol_sm->keyRun = TRUE;
- sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+ sta->eapol_sm->keyRun = true;
+ sta->eapol_sm->eap_if->eapKeyAvailable = true;
sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
- sta->eapol_sm->authSuccess = TRUE;
- sta->eapol_sm->authFail = FALSE;
- sta->eapol_sm->portValid = TRUE;
+ sta->eapol_sm->authSuccess = true;
+ sta->eapol_sm->authFail = false;
+ sta->eapol_sm->portValid = true;
if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap);
ap_sta_bind_vlan(hapd, sta);
@@ -1227,15 +1329,16 @@
"PMK from FILS - skip IEEE 802.1X/EAP");
/* Setup EAPOL state machines to already authenticated state
* because of existing FILS information. */
- sta->eapol_sm->keyRun = TRUE;
- sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+ sta->eapol_sm->keyRun = true;
+ sta->eapol_sm->eap_if->eapKeyAvailable = true;
sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
- sta->eapol_sm->authSuccess = TRUE;
- sta->eapol_sm->authFail = FALSE;
- sta->eapol_sm->portValid = TRUE;
+ sta->eapol_sm->authSuccess = true;
+ sta->eapol_sm->authFail = false;
+ sta->eapol_sm->portValid = true;
if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap);
+ wpa_auth_set_ptk_rekey_timer(sta->wpa_sm);
return;
}
#endif /* CONFIG_FILS */
@@ -1247,12 +1350,12 @@
"PMK from PMKSA cache - skip IEEE 802.1X/EAP");
/* Setup EAPOL state machines to already authenticated state
* because of existing PMKSA information in the cache. */
- sta->eapol_sm->keyRun = TRUE;
- sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+ sta->eapol_sm->keyRun = true;
+ sta->eapol_sm->eap_if->eapKeyAvailable = true;
sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
- sta->eapol_sm->authSuccess = TRUE;
- sta->eapol_sm->authFail = FALSE;
+ sta->eapol_sm->authSuccess = true;
+ sta->eapol_sm->authFail = false;
if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap);
pmksa_cache_to_eapol_data(hapd, pmksa, sta->eapol_sm);
@@ -1264,7 +1367,7 @@
* re-authentication without having to wait for the
* Supplicant to send EAPOL-Start.
*/
- sta->eapol_sm->reAuthenticate = TRUE;
+ sta->eapol_sm->reAuthenticate = true;
}
eapol_auth_step(sta->eapol_sm);
}
@@ -1285,7 +1388,7 @@
sta->pending_eapol_rx = NULL;
}
- if (sm == NULL)
+ if (!sm)
return;
sta->eapol_sm = NULL;
@@ -1310,32 +1413,32 @@
struct radius_msg *msg;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL || sm->last_recv_radius == NULL) {
+ if (!sm || !sm->last_recv_radius) {
if (sm)
- sm->eap_if->aaaEapNoReq = TRUE;
+ sm->eap_if->aaaEapNoReq = true;
return;
}
msg = sm->last_recv_radius;
eap = radius_msg_get_eap(msg);
- if (eap == NULL) {
+ if (!eap) {
/* RFC 3579, Chap. 2.6.3:
* RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
* attribute */
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_WARNING, "could not extract "
- "EAP-Message from RADIUS message");
- sm->eap_if->aaaEapNoReq = TRUE;
+ HOSTAPD_LEVEL_WARNING,
+ "could not extract EAP-Message from RADIUS message");
+ sm->eap_if->aaaEapNoReq = true;
return;
}
if (wpabuf_len(eap) < sizeof(*hdr)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_WARNING, "too short EAP packet "
- "received from authentication server");
+ HOSTAPD_LEVEL_WARNING,
+ "too short EAP packet received from authentication server");
wpabuf_free(eap);
- sm->eap_if->aaaEapNoReq = TRUE;
+ sm->eap_if->aaaEapNoReq = true;
return;
}
@@ -1366,11 +1469,11 @@
}
buf[sizeof(buf) - 1] = '\0';
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "decapsulated EAP packet (code=%d "
- "id=%d len=%d) from RADIUS server: %s",
+ HOSTAPD_LEVEL_DEBUG,
+ "decapsulated EAP packet (code=%d id=%d len=%d) from RADIUS server: %s",
hdr->code, hdr->identifier, be_to_host16(hdr->length),
buf);
- sm->eap_if->aaaEapReq = TRUE;
+ sm->eap_if->aaaEapReq = true;
wpabuf_free(sm->eap_if->aaaEapReqData);
sm->eap_if->aaaEapReqData = eap;
@@ -1384,15 +1487,18 @@
size_t shared_secret_len)
{
struct radius_ms_mppe_keys *keys;
+ u8 *buf;
+ size_t len;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+
+ if (!sm)
return;
keys = radius_msg_get_ms_keys(msg, req, shared_secret,
shared_secret_len);
if (keys && keys->send && keys->recv) {
- size_t len = keys->send_len + keys->recv_len;
+ len = keys->send_len + keys->recv_len;
wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key",
keys->send, keys->send_len);
wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key",
@@ -1406,7 +1512,7 @@
os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len,
keys->send, keys->send_len);
sm->eap_if->aaaEapKeyDataLen = len;
- sm->eap_if->aaaEapKeyAvailable = TRUE;
+ sm->eap_if->aaaEapKeyAvailable = true;
}
} else {
wpa_printf(MSG_DEBUG,
@@ -1420,6 +1526,20 @@
os_free(keys->recv);
os_free(keys);
}
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_EAP_KEY_NAME, &buf, &len,
+ NULL) == 0) {
+ os_free(sm->eap_if->eapSessionId);
+ sm->eap_if->eapSessionId = os_memdup(buf, len);
+ if (sm->eap_if->eapSessionId) {
+ sm->eap_if->eapSessionIdLen = len;
+ wpa_hexdump(MSG_DEBUG, "EAP-Key Name",
+ sm->eap_if->eapSessionId,
+ sm->eap_if->eapSessionIdLen);
+ }
+ } else {
+ sm->eap_if->eapSessionIdLen = 0;
+ }
}
@@ -1434,8 +1554,7 @@
struct radius_attr_data *nclass;
size_t nclass_count;
- if (!hapd->conf->radius->acct_server || hapd->radius == NULL ||
- sm == NULL)
+ if (!hapd->conf->radius->acct_server || !hapd->radius || !sm)
return;
radius_free_class(&sm->radius_class);
@@ -1444,7 +1563,7 @@
return;
nclass = os_calloc(count, sizeof(struct radius_attr_data));
- if (nclass == NULL)
+ if (!nclass)
return;
nclass_count = 0;
@@ -1461,7 +1580,7 @@
} while (class_len < 1);
nclass[nclass_count].data = os_memdup(attr_class, class_len);
- if (nclass[nclass_count].data == NULL)
+ if (!nclass[nclass_count].data)
break;
nclass[nclass_count].len = class_len;
@@ -1470,8 +1589,9 @@
sm->radius_class.attr = nclass;
sm->radius_class.count = nclass_count;
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Stored %lu RADIUS Class "
- "attributes for " MACSTR,
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Stored %lu RADIUS Class attributes for "
+ MACSTR,
(unsigned long) sm->radius_class.count,
MAC2STR(sta->addr));
}
@@ -1486,7 +1606,7 @@
size_t len;
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+ if (!sm)
return;
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len,
@@ -1494,12 +1614,12 @@
return;
identity = (u8 *) dup_binstr(buf, len);
- if (identity == NULL)
+ if (!identity)
return;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with "
- "User-Name from Access-Accept '%s'",
+ HOSTAPD_LEVEL_DEBUG,
+ "old identity '%s' updated with User-Name from Access-Accept '%s'",
sm->identity ? (char *) sm->identity : "N/A",
(char *) identity);
@@ -1519,7 +1639,7 @@
u8 *buf;
size_t len;
- if (sm == NULL)
+ if (!sm)
return;
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
@@ -1527,7 +1647,7 @@
return;
cui = wpabuf_alloc_copy(buf, len);
- if (cui == NULL)
+ if (!cui)
return;
wpabuf_free(sm->radius_cui);
@@ -1548,14 +1668,16 @@
sta->remediation_method = pos[0];
os_memcpy(sta->remediation_url, pos + 1, len - 1);
sta->remediation_url[len - 1] = '\0';
- wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed "
- "for " MACSTR " - server method %u URL %s",
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Subscription remediation needed for "
+ MACSTR " - server method %u URL %s",
MAC2STR(sta->addr), sta->remediation_method,
sta->remediation_url);
} else {
sta->remediation_url = NULL;
- wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed "
- "for " MACSTR, MAC2STR(sta->addr));
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Subscription remediation needed for "
+ MACSTR, MAC2STR(sta->addr));
}
/* TODO: assign the STA into remediation VLAN or add filtering */
}
@@ -1568,8 +1690,8 @@
if (len < 3)
return; /* Malformed information */
sta->hs20_deauth_requested = 1;
- wpa_printf(MSG_DEBUG, "HS 2.0: Deauthentication request - Code %u "
- "Re-auth Delay %u",
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Deauthentication request - Code %u Re-auth Delay %u",
*pos, WPA_GET_LE16(pos + 1));
wpabuf_free(sta->hs20_deauth_req);
sta->hs20_deauth_req = wpabuf_alloc(len + 1);
@@ -1593,16 +1715,17 @@
return; /* Malformed information */
os_free(sta->hs20_session_info_url);
sta->hs20_session_info_url = os_malloc(len);
- if (sta->hs20_session_info_url == NULL)
+ if (!sta->hs20_session_info_url)
return;
swt = pos[0];
os_memcpy(sta->hs20_session_info_url, pos + 1, len - 1);
sta->hs20_session_info_url[len - 1] = '\0';
- wpa_printf(MSG_DEBUG, "HS 2.0: Session Information URL='%s' SWT=%u "
- "(session_timeout=%d)",
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Session Information URL='%s' SWT=%u (session_timeout=%d)",
sta->hs20_session_info_url, swt, session_timeout);
if (session_timeout < 0) {
- wpa_printf(MSG_DEBUG, "HS 2.0: No Session-Timeout set - ignore session info URL");
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: No Session-Timeout set - ignore session info URL");
return;
}
if (swt == 255)
@@ -1735,6 +1858,7 @@
ieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier)
{
struct sta_id_search id_search;
+
id_search.identifier = identifier;
id_search.sm = NULL;
ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search);
@@ -1756,7 +1880,7 @@
if (vlan_desc.notempty &&
!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
- sta->eapol_sm->authFail = TRUE;
+ sta->eapol_sm->authFail = true;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"Invalid VLAN %d%s received from RADIUS server",
@@ -1769,7 +1893,7 @@
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
!vlan_desc.notempty) {
- sta->eapol_sm->authFail = TRUE;
+ 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");
@@ -1805,9 +1929,9 @@
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier);
- if (sm == NULL) {
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not find matching "
- "station for this RADIUS message");
+ if (!sm) {
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Could not find matching station for this RADIUS message");
return RADIUS_RX_UNKNOWN;
}
sta = sm->sta;
@@ -1818,12 +1942,12 @@
radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL,
0) < 0 &&
radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) {
- wpa_printf(MSG_DEBUG, "Allowing RADIUS Access-Reject without "
- "Message-Authenticator since it does not include "
- "EAP-Message");
+ wpa_printf(MSG_DEBUG,
+ "Allowing RADIUS Access-Reject without Message-Authenticator since it does not include EAP-Message");
} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
req, 1)) {
- wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Message-Authenticator - dropped");
+ wpa_printf(MSG_INFO,
+ "Incoming RADIUS packet did not have correct Message-Authenticator - dropped");
return RADIUS_RX_INVALID_AUTHENTICATOR;
}
@@ -1856,8 +1980,7 @@
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_INFO,
- "ignored too small "
- "Acct-Interim-Interval %d",
+ "ignored too small Acct-Interim-Interval %d",
acct_interim_interval);
} else
sta->acct_interim_interval = acct_interim_interval;
@@ -1896,7 +2019,7 @@
else
ap_sta_no_session_timeout(hapd, sta);
- sm->eap_if->aaaSuccess = TRUE;
+ sm->eap_if->aaaSuccess = true;
override_eapReq = 1;
ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret,
shared_secret_len);
@@ -1908,7 +2031,7 @@
(int) session_timeout : -1);
break;
case RADIUS_CODE_ACCESS_REJECT:
- sm->eap_if->aaaFail = TRUE;
+ sm->eap_if->aaaFail = true;
override_eapReq = 1;
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE,
&reason_code) == 0) {
@@ -1919,15 +2042,14 @@
}
break;
case RADIUS_CODE_ACCESS_CHALLENGE:
- sm->eap_if->aaaEapReq = TRUE;
+ sm->eap_if->aaaEapReq = true;
if (session_timeout_set) {
/* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */
sm->eap_if->aaaMethodTimeout = session_timeout;
hostapd_logger(hapd, sm->addr,
HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG,
- "using EAP timeout of %d seconds (from "
- "RADIUS)",
+ "using EAP timeout of %d seconds (from RADIUS)",
sm->eap_if->aaaMethodTimeout);
} else {
/*
@@ -1941,7 +2063,7 @@
ieee802_1x_decapsulate_radius(hapd, sta);
if (override_eapReq)
- sm->eap_if->aaaEapReq = FALSE;
+ sm->eap_if->aaaEapReq = false;
#ifdef CONFIG_FILS
#ifdef NEED_AP_MLME
@@ -1966,7 +2088,8 @@
void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
{
struct eapol_state_machine *sm = sta->eapol_sm;
- if (sm == NULL)
+
+ if (!sm)
return;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
@@ -1986,13 +2109,15 @@
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR,
MAC2STR(sta->addr));
- sm->eap_if->portEnabled = FALSE;
+ sm->eap_if->portEnabled = false;
ap_sta_disconnect(hapd, sta, sta->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
}
}
+#ifdef CONFIG_WEP
+
static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd)
{
struct eapol_authenticator *eapol = hapd->eapol_auth;
@@ -2002,7 +2127,7 @@
os_free(eapol->default_wep_key);
eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len);
- if (eapol->default_wep_key == NULL ||
+ if (!eapol->default_wep_key ||
random_get_bytes(eapol->default_wep_key,
hapd->conf->default_wep_key_len)) {
wpa_printf(MSG_INFO, "Could not generate random WEP key");
@@ -2023,7 +2148,7 @@
struct sta_info *sta, void *ctx)
{
if (sta->eapol_sm) {
- sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+ sta->eapol_sm->eap_if->eapKeyAvailable = true;
eapol_auth_step(sta->eapol_sm);
}
return 0;
@@ -2046,8 +2171,8 @@
if (ieee802_1x_rekey_broadcast(hapd)) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_WARNING, "failed to generate a "
- "new broadcast key");
+ HOSTAPD_LEVEL_WARNING,
+ "failed to generate a new broadcast key");
os_free(eapol->default_wep_key);
eapol->default_wep_key = NULL;
return;
@@ -2057,12 +2182,13 @@
* after new broadcast key has been sent to all stations. */
if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
broadcast_ether_addr,
- eapol->default_wep_key_idx, 1, NULL, 0,
+ eapol->default_wep_key_idx, 0, 1, NULL, 0,
eapol->default_wep_key,
- hapd->conf->default_wep_key_len)) {
+ hapd->conf->default_wep_key_len,
+ KEY_FLAG_GROUP_RX_TX_DEFAULT)) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_WARNING, "failed to configure a "
- "new broadcast key");
+ HOSTAPD_LEVEL_WARNING,
+ "failed to configure a new broadcast key");
os_free(eapol->default_wep_key);
eapol->default_wep_key = NULL;
return;
@@ -2076,6 +2202,8 @@
}
}
+#endif /* CONFIG_WEP */
+
static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type,
const u8 *data, size_t datalen)
@@ -2097,8 +2225,8 @@
(identity_len == WSC_ID_REGISTRAR_LEN &&
os_memcmp(identity, WSC_ID_REGISTRAR,
WSC_ID_REGISTRAR_LEN) == 0))) {
- wpa_printf(MSG_DEBUG, "WPS: WLAN_STA_MAYBE_WPS -> "
- "WLAN_STA_WPS");
+ wpa_printf(MSG_DEBUG,
+ "WPS: WLAN_STA_MAYBE_WPS -> WLAN_STA_WPS");
sta->flags |= WLAN_STA_WPS;
}
}
@@ -2125,6 +2253,7 @@
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
+
if (preauth)
rsn_preauth_finished(hapd, sta, success);
else
@@ -2142,7 +2271,7 @@
int rv = -1;
eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2);
- if (eap_user == NULL)
+ if (!eap_user)
goto out;
os_memset(user, 0, sizeof(*user));
@@ -2155,7 +2284,7 @@
if (eap_user->password) {
user->password = os_memdup(eap_user->password,
eap_user->password_len);
- if (user->password == NULL)
+ if (!user->password)
goto out;
user->password_len = eap_user->password_len;
user->password_hash = eap_user->password_hash;
@@ -2185,8 +2314,9 @@
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
+
sta = ap_get_sta(hapd, addr);
- if (sta == NULL || sta->eapol_sm == NULL)
+ if (!sta || !sta->eapol_sm)
return 0;
return 1;
}
@@ -2223,6 +2353,7 @@
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
+
ieee802_1x_set_sta_authorized(hapd, sta, authorized);
}
@@ -2231,20 +2362,24 @@
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
+
ieee802_1x_abort_auth(hapd, sta);
}
+#ifdef CONFIG_WEP
static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx)
{
#ifndef CONFIG_FIPS
#ifndef CONFIG_NO_RC4
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
+
ieee802_1x_tx_key(hapd, sta);
#endif /* CONFIG_NO_RC4 */
#endif /* CONFIG_FIPS */
}
+#endif /* CONFIG_WEP */
static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx,
@@ -2252,6 +2387,7 @@
{
/* struct hostapd_data *hapd = ctx; */
struct sta_info *sta = sta_ctx;
+
switch (type) {
case EAPOL_AUTH_SM_CHANGE:
wpa_auth_sm_notify(sta->wpa_sm);
@@ -2294,48 +2430,23 @@
int ieee802_1x_init(struct hostapd_data *hapd)
{
- int i;
struct eapol_auth_config conf;
struct eapol_auth_cb cb;
dl_list_init(&hapd->erp_keys);
os_memset(&conf, 0, sizeof(conf));
+ conf.eap_cfg = hapd->eap_cfg;
conf.ctx = hapd;
conf.eap_reauth_period = hapd->conf->eap_reauth_period;
conf.wpa = hapd->conf->wpa;
+#ifdef CONFIG_WEP
conf.individual_wep_key_len = hapd->conf->individual_wep_key_len;
- conf.eap_server = hapd->conf->eap_server;
- conf.ssl_ctx = hapd->ssl_ctx;
- conf.msg_ctx = hapd->msg_ctx;
- conf.eap_sim_db_priv = hapd->eap_sim_db_priv;
+#endif /* CONFIG_WEP */
conf.eap_req_id_text = hapd->conf->eap_req_id_text;
conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start;
conf.erp_domain = hapd->conf->erp_domain;
- conf.erp = hapd->conf->eap_server_erp;
- conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
- conf.tls_flags = hapd->conf->tls_flags;
- conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key;
- conf.eap_fast_a_id = hapd->conf->eap_fast_a_id;
- conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
- conf.eap_fast_a_id_info = hapd->conf->eap_fast_a_id_info;
- conf.eap_fast_prov = hapd->conf->eap_fast_prov;
- conf.pac_key_lifetime = hapd->conf->pac_key_lifetime;
- conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time;
- conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
- conf.tnc = hapd->conf->tnc;
- conf.wps = hapd->wps;
- conf.fragment_size = hapd->conf->fragment_size;
- conf.pwd_group = hapd->conf->pwd_group;
- conf.pbc_in_m1 = hapd->conf->pbc_in_m1;
- if (hapd->conf->server_id) {
- conf.server_id = (const u8 *) hapd->conf->server_id;
- conf.server_id_len = os_strlen(hapd->conf->server_id);
- } else {
- conf.server_id = (const u8 *) "hostapd";
- conf.server_id_len = 7;
- }
os_memset(&cb, 0, sizeof(cb));
cb.eapol_send = ieee802_1x_eapol_send;
@@ -2346,7 +2457,9 @@
cb.logger = ieee802_1x_logger;
cb.set_port_authorized = ieee802_1x_set_port_authorized;
cb.abort_auth = _ieee802_1x_abort_auth;
+#ifdef CONFIG_WEP
cb.tx_key = _ieee802_1x_tx_key;
+#endif /* CONFIG_WEP */
cb.eapol_event = ieee802_1x_eapol_event;
#ifdef CONFIG_ERP
cb.erp_get_key = ieee802_1x_erp_get_key;
@@ -2354,7 +2467,7 @@
#endif /* CONFIG_ERP */
hapd->eapol_auth = eapol_auth_init(&conf, &cb);
- if (hapd->eapol_auth == NULL)
+ if (!hapd->eapol_auth)
return -1;
if ((hapd->conf->ieee802_1x || hapd->conf->wpa) &&
@@ -2367,17 +2480,21 @@
return -1;
#endif /* CONFIG_NO_RADIUS */
+#ifdef CONFIG_WEP
if (hapd->conf->default_wep_key_len) {
+ int i;
+
for (i = 0; i < 4; i++)
hostapd_drv_set_key(hapd->conf->iface, hapd,
- WPA_ALG_NONE, NULL, i, 0, NULL, 0,
- NULL, 0);
+ WPA_ALG_NONE, NULL, i, 0, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_GROUP);
ieee802_1x_rekey(hapd, NULL);
- if (hapd->eapol_auth->default_wep_key == NULL)
+ if (!hapd->eapol_auth->default_wep_key)
return -1;
}
+#endif /* CONFIG_WEP */
return 0;
}
@@ -2397,7 +2514,9 @@
void ieee802_1x_deinit(struct hostapd_data *hapd)
{
+#ifdef CONFIG_WEP
eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
+#endif /* CONFIG_WEP */
if (hapd->driver && hapd->drv_priv &&
(hapd->conf->ieee802_1x || hapd->conf->wpa))
@@ -2418,7 +2537,7 @@
const unsigned char rfc1042_hdr[ETH_ALEN] =
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
- if (sta == NULL)
+ if (!sta)
return -1;
if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2)
return 0;
@@ -2447,8 +2566,8 @@
if (len < (int) sizeof(*xhdr))
return 0;
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d "
- "type=%d length=%d - ack=%d",
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
+ " TX status - version=%d type=%d length=%d - ack=%d",
MAC2STR(sta->addr), xhdr->version, xhdr->type,
be_to_host16(xhdr->length), ack);
@@ -2467,6 +2586,7 @@
if (pos + sizeof(struct wpa_eapol_key) <= buf + len) {
const struct wpa_eapol_key *wpa;
+
wpa = (const struct wpa_eapol_key *) pos;
if (wpa->type == EAPOL_KEY_TYPE_RSN ||
wpa->type == EAPOL_KEY_TYPE_WPA)
@@ -2482,8 +2602,8 @@
if (!ack && pos + sizeof(*key) <= buf + len) {
key = (struct ieee802_1x_eapol_key *) pos;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key "
- "frame (%scast index=%d)",
+ HOSTAPD_LEVEL_DEBUG,
+ "did not Ack EAPOL-Key frame (%scast index=%d)",
key->key_index & BIT(7) ? "uni" : "broad",
key->key_index & ~BIT(7));
/* TODO: re-send EAPOL-Key couple of times (with short delay
@@ -2503,7 +2623,7 @@
u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len)
{
- if (sm == NULL || sm->identity == NULL)
+ if (!sm || !sm->identity)
return NULL;
*len = sm->identity_len;
@@ -2514,7 +2634,7 @@
u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
int idx)
{
- if (sm == NULL || sm->radius_class.attr == NULL ||
+ if (!sm || !sm->radius_class.attr ||
idx >= (int) sm->radius_class.count)
return NULL;
@@ -2525,7 +2645,7 @@
struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return NULL;
return sm->radius_cui;
}
@@ -2534,7 +2654,7 @@
const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
{
*len = 0;
- if (sm == NULL)
+ if (!sm)
return NULL;
*len = sm->eap_if->eapKeyDataLen;
@@ -2542,29 +2662,42 @@
}
+#ifdef CONFIG_MACSEC
+const u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm,
+ size_t *len)
+{
+ *len = 0;
+ if (!sm || !sm->eap_if)
+ return NULL;
+
+ *len = sm->eap_if->eapSessionIdLen;
+ return sm->eap_if->eapSessionId;
+}
+#endif /* CONFIG_MACSEC */
+
+
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
- int enabled)
+ bool enabled)
{
- if (sm == NULL)
+ if (!sm)
return;
- sm->eap_if->portEnabled = enabled ? TRUE : FALSE;
+ sm->eap_if->portEnabled = enabled;
eapol_auth_step(sm);
}
-void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
- int valid)
+void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, bool valid)
{
- if (sm == NULL)
+ if (!sm)
return;
- sm->portValid = valid ? TRUE : FALSE;
+ sm->portValid = valid;
eapol_auth_step(sm);
}
-void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth)
+void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, bool pre_auth)
{
- if (sm == NULL)
+ if (!sm)
return;
if (pre_auth)
sm->flags |= EAPOL_SM_PREAUTH;
@@ -2573,7 +2706,7 @@
}
-static const char * bool_txt(Boolean val)
+static const char * bool_txt(bool val)
{
return val ? "TRUE" : "FALSE";
}
@@ -2596,7 +2729,7 @@
const char *name2;
char *identity_buf = NULL;
- if (sm == NULL)
+ if (!sm)
return 0;
ret = os_snprintf(buf + len, buflen - len,
@@ -2832,6 +2965,10 @@
}
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MACSEC
+ ieee802_1x_notify_create_actor_hapd(hapd, sta);
+#endif /* CONFIG_MACSEC */
+
key = ieee802_1x_get_key(sta->eapol_sm, &len);
if (sta->session_timeout_set) {
os_get_reltime(&now);
diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
index 9594661..70dc11a 100644
--- a/src/ap/ieee802_1x.h
+++ b/src/ap/ieee802_1x.h
@@ -39,11 +39,12 @@
int idx);
struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm);
const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len);
+const u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm,
+ size_t *len);
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
- int enabled);
-void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
- int valid);
-void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth);
+ bool enabled);
+void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, bool valid);
+void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, bool pre_auth);
int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
char *buf, size_t buflen);
@@ -57,6 +58,8 @@
struct hostapd_radius_attr *req_attr,
struct sta_info *sta,
struct radius_msg *msg);
+int add_sqlite_radius_attr(struct hostapd_data *hapd, struct sta_info *sta,
+ struct radius_msg *msg, int acct);
void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
struct sta_info *sta,
const u8 *eap, size_t len);
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
index 2b6f727..01bf886 100644
--- a/src/ap/neighbor_db.c
+++ b/src/ap/neighbor_db.c
@@ -34,6 +34,60 @@
}
+int hostapd_neighbor_show(struct hostapd_data *hapd, char *buf, size_t buflen)
+{
+ struct hostapd_neighbor_entry *nr;
+ char *pos, *end;
+
+ pos = buf;
+ end = buf + buflen;
+
+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
+ list) {
+ int ret;
+ char nrie[2 * 255 + 1];
+ char lci[2 * 255 + 1];
+ char civic[2 * 255 + 1];
+ char ssid[SSID_MAX_LEN * 2 + 1];
+
+ ssid[0] = '\0';
+ wpa_snprintf_hex(ssid, sizeof(ssid), nr->ssid.ssid,
+ nr->ssid.ssid_len);
+
+ nrie[0] = '\0';
+ if (nr->nr)
+ wpa_snprintf_hex(nrie, sizeof(nrie),
+ wpabuf_head(nr->nr),
+ wpabuf_len(nr->nr));
+
+ lci[0] = '\0';
+ if (nr->lci)
+ wpa_snprintf_hex(lci, sizeof(lci),
+ wpabuf_head(nr->lci),
+ wpabuf_len(nr->lci));
+
+ civic[0] = '\0';
+ if (nr->civic)
+ wpa_snprintf_hex(civic, sizeof(civic),
+ wpabuf_head(nr->civic),
+ wpabuf_len(nr->civic));
+
+ ret = os_snprintf(pos, end - pos, MACSTR
+ " ssid=%s%s%s%s%s%s%s%s\n",
+ MAC2STR(nr->bssid), ssid,
+ nr->nr ? " nr=" : "", nrie,
+ nr->lci ? " lci=" : "", lci,
+ nr->civic ? " civic=" : "", civic,
+ nr->stationary ? " stat" : "");
+ if (os_snprintf_error(end - pos, ret))
+ break;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
+
static void hostapd_neighbor_clear_entry(struct hostapd_neighbor_entry *nr)
{
wpabuf_free(nr->nr);
@@ -139,19 +193,21 @@
#ifdef NEED_AP_MLME
static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd,
- int ht, int vht)
+ int ht, int vht, int he)
{
- if (!ht && !vht)
+ u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iconf);
+
+ if (!ht && !vht && !he)
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)
+ if ((!vht && !he) || oper_chwidth == CHANWIDTH_USE_HT)
return NR_CHAN_WIDTH_40;
- if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
+ if (oper_chwidth == CHANWIDTH_80MHZ)
return NR_CHAN_WIDTH_80;
- if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_160MHZ)
+ if (oper_chwidth == CHANWIDTH_160MHZ)
return NR_CHAN_WIDTH_160;
- if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ)
+ if (oper_chwidth == CHANWIDTH_80P80MHZ)
return NR_CHAN_WIDTH_80P80;
return NR_CHAN_WIDTH_20;
}
@@ -164,6 +220,7 @@
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;
+ int he = hapd->iconf->ieee80211ax;
struct wpa_ssid_value ssid;
u8 channel, op_class;
u8 center_freq1_idx = 0, center_freq2_idx = 0;
@@ -199,22 +256,26 @@
/* VHT bit added in IEEE P802.11-REVmc/D4.3 */
if (vht)
bssid_info |= NEI_REP_BSSID_INFO_VHT;
+ if (he)
+ bssid_info |= NEI_REP_BSSID_INFO_HE;
}
/* 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,
+ hostapd_get_oper_chwidth(hapd->iconf),
&op_class, &channel) ==
NUM_HOSTAPD_MODES)
return;
- width = hostapd_get_nr_chan_width(hapd, ht, vht);
+ width = hostapd_get_nr_chan_width(hapd, ht, vht, he);
if (vht) {
- center_freq1_idx = hapd->iconf->vht_oper_centr_freq_seg0_idx;
+ center_freq1_idx = hostapd_get_oper_centr_freq_seg0_idx(
+ hapd->iconf);
if (width == NR_CHAN_WIDTH_80P80)
center_freq2_idx =
- hapd->iconf->vht_oper_centr_freq_seg1_idx;
+ hostapd_get_oper_centr_freq_seg1_idx(
+ hapd->iconf);
} else if (ht) {
ieee80211_freq_to_chan(hapd->iface->freq +
10 * hapd->iconf->secondary_channel,
diff --git a/src/ap/neighbor_db.h b/src/ap/neighbor_db.h
index 9c8f4f2..bed0a2f 100644
--- a/src/ap/neighbor_db.h
+++ b/src/ap/neighbor_db.h
@@ -13,6 +13,7 @@
struct hostapd_neighbor_entry *
hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
const struct wpa_ssid_value *ssid);
+int hostapd_neighbor_show(struct hostapd_data *hapd, char *buf, size_t buflen);
int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
const struct wpa_ssid_value *ssid,
const struct wpabuf *nr, const struct wpabuf *lci,
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index 15e2c49..fe5f817 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -516,6 +516,11 @@
for (entry = pmksa->pmksa; entry; entry = entry->next) {
if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
continue;
+ if (wpa_key_mgmt_sae(entry->akmp)) {
+ if (os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)
+ return entry;
+ continue;
+ }
rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
entry->akmp);
if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
diff --git a/src/ap/preauth_auth.c b/src/ap/preauth_auth.c
index 3e0c800..2ff1861 100644
--- a/src/ap/preauth_auth.c
+++ b/src/ap/preauth_auth.c
@@ -82,7 +82,7 @@
sta = NULL;
} else {
sta->eapol_sm->radius_identifier = -1;
- sta->eapol_sm->portValid = TRUE;
+ sta->eapol_sm->portValid = true;
sta->eapol_sm->flags |= EAPOL_SM_PREAUTH;
}
}
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 71f9f21..93f1f0c 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -46,9 +46,7 @@
static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx);
static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx);
static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
-#ifdef CONFIG_IEEE80211W
static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
-#endif /* CONFIG_IEEE80211W */
static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx);
@@ -166,6 +164,7 @@
/* just in case */
ap_sta_set_authorized(hapd, sta, 0);
+ hostapd_set_sta_flags(hapd, sta);
if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP))
hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
@@ -235,9 +234,7 @@
sta->assoc_ie_taxonomy = NULL;
#endif /* CONFIG_TAXONOMY */
-#ifdef CONFIG_IEEE80211N
ht40_intolerant_remove(hapd->iface, sta);
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_P2P
if (sta->no_p2p_set) {
@@ -248,10 +245,10 @@
}
#endif /* CONFIG_P2P */
-#if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N)
+#ifdef NEED_AP_MLME
if (hostapd_ht_operation_update(hapd->iface) > 0)
set_beacon++;
-#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */
+#endif /* NEED_AP_MLME */
#ifdef CONFIG_MESH
if (hapd->mesh_sta_free_cb)
@@ -301,10 +298,8 @@
os_free(sta->challenge);
-#ifdef CONFIG_IEEE80211W
os_free(sta->sa_query_trans_id);
eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_P2P
p2p_group_notif_disassoc(hapd->p2p_group, sta->addr);
@@ -330,6 +325,7 @@
os_free(sta->ht_capabilities);
os_free(sta->vht_capabilities);
os_free(sta->vht_operation);
+ os_free(sta->he_capab);
hostapd_free_psk_list(sta->psk);
os_free(sta->identity);
os_free(sta->radius_cui);
@@ -376,6 +372,10 @@
os_free(sta->ifname_wds);
+#ifdef CONFIG_TESTING_OPTIONS
+ os_free(sta->sae_postponed_commit);
+#endif /* CONFIG_TESTING_OPTIONS */
+
os_free(sta);
}
@@ -545,6 +545,7 @@
case STA_DISASSOC_FROM_CLI:
ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~WLAN_STA_ASSOC;
+ hostapd_set_sta_flags(hapd, sta);
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
if (!sta->acct_terminate_cause)
sta->acct_terminate_cause =
@@ -589,7 +590,8 @@
wpa_printf(MSG_DEBUG, "%s: Session timer for STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
- if (!(sta->flags & WLAN_STA_AUTH)) {
+ if (!(sta->flags & (WLAN_STA_AUTH | WLAN_STA_ASSOC |
+ WLAN_STA_AUTHORIZED))) {
if (sta->flags & WLAN_STA_GAS) {
wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA "
"entry " MACSTR, MAC2STR(sta->addr));
@@ -670,6 +672,7 @@
struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
{
struct sta_info *sta;
+ int i;
sta = ap_get_sta(hapd, addr);
if (sta)
@@ -694,6 +697,15 @@
return NULL;
}
+ for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
+ if (!hapd->iface->basic_rates)
+ break;
+ if (hapd->iface->basic_rates[i] < 0)
+ break;
+ sta->supported_rates[i] = hapd->iface->basic_rates[i] / 5;
+ }
+ sta->supported_rates_len = i;
+
if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
"for " MACSTR " (%d seconds - ap_max_inactivity)",
@@ -802,6 +814,7 @@
sta->timeout_next = STA_DEAUTH;
}
ap_sta_set_authorized(hapd, sta, 0);
+ hostapd_set_sta_flags(hapd, sta);
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - "
"AP_MAX_INACTIVITY_AFTER_DISASSOC)",
@@ -812,6 +825,8 @@
ap_handle_timer, hapd, sta);
accounting_sta_stop(hapd, sta);
ieee802_1x_free_station(hapd, sta);
+ wpa_auth_sta_deinit(sta->wpa_sm);
+ sta->wpa_sm = NULL;
sta->disassoc_reason = reason;
sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
@@ -850,6 +865,7 @@
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
ap_sta_set_authorized(hapd, sta, 0);
+ hostapd_set_sta_flags(hapd, sta);
sta->timeout_next = STA_REMOVE;
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - "
@@ -1015,6 +1031,13 @@
int ret;
int old_vlanid = sta->vlan_id_bound;
+ if ((sta->flags & WLAN_STA_WDS) && sta->vlan_id == 0) {
+ wpa_printf(MSG_DEBUG,
+ "Do not override WDS VLAN assignment for STA "
+ MACSTR, MAC2STR(sta->addr));
+ return 0;
+ }
+
iface = hapd->conf->iface;
if (hapd->conf->ssid.vlan[0])
iface = hapd->conf->ssid.vlan;
@@ -1036,7 +1059,8 @@
if (sta->vlan_id == old_vlanid)
goto skip_counting;
- if (sta->vlan_id > 0 && vlan == NULL) {
+ if (sta->vlan_id > 0 && !vlan &&
+ !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
"binding station to (vlan_id=%d)",
@@ -1082,8 +1106,6 @@
}
-#ifdef CONFIG_IEEE80211W
-
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
{
u32 tu;
@@ -1122,6 +1144,8 @@
if (sta->sa_query_count > 0 &&
ap_check_sa_query_timeout(hapd, sta))
return;
+ if (sta->sa_query_count >= 1000)
+ return;
nbuf = os_realloc_array(sta->sa_query_trans_id,
sta->sa_query_count + 1,
@@ -1173,8 +1197,6 @@
sta->sa_query_count = 0;
}
-#endif /* CONFIG_IEEE80211W */
-
const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
struct sta_info *sta)
@@ -1311,9 +1333,10 @@
if (sta == NULL)
return;
ap_sta_set_authorized(hapd, sta, 0);
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ hostapd_set_sta_flags(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
- sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
wpa_printf(MSG_DEBUG, "%s: %s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - "
"AP_MAX_INACTIVITY_AFTER_DEAUTH)",
@@ -1401,7 +1424,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%s",
+ res = os_snprintf(buf, buflen, "%s%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]" : ""),
@@ -1420,6 +1443,7 @@
(flags & WLAN_STA_GAS ? "[GAS]" : ""),
(flags & WLAN_STA_HT ? "[HT]" : ""),
(flags & WLAN_STA_VHT ? "[VHT]" : ""),
+ (flags & WLAN_STA_HE ? "[HE]" : ""),
(flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
(flags & WLAN_STA_WNM_SLEEP_MODE ?
"[WNM_SLEEP_MODE]" : ""));
@@ -1473,3 +1497,33 @@
return eloop_is_timeout_registered(ap_sta_delayed_1x_auth_fail_cb,
hapd, sta);
}
+
+
+int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ /*
+ * If a station that is already associated to the AP, is trying to
+ * authenticate again, remove the STA entry, in order to make sure the
+ * STA PS state gets cleared and configuration gets 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);
+
+ if (hostapd_sta_add(hapd, sta->addr, 0, 0,
+ sta->supported_rates,
+ sta->supported_rates_len,
+ 0, NULL, NULL, NULL, 0,
+ sta->flags, 0, 0, 0, 0)) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_NOTICE,
+ "Could not add STA to kernel driver");
+ return -1;
+ }
+
+ sta->added_unassoc = 1;
+ return 0;
+}
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index ece0c60..308aa29 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -37,6 +37,7 @@
#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_HE BIT(24)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -119,6 +120,7 @@
unsigned int agreed_to_steer:1;
unsigned int hs20_t_c_filtering:1;
unsigned int ft_over_ds:1;
+ unsigned int external_dh_updated:1;
u16 auth_alg;
@@ -166,8 +168,9 @@
struct ieee80211_vht_capabilities *vht_capabilities;
struct ieee80211_vht_operation *vht_operation;
u8 vht_opmode;
+ struct ieee80211_he_capabilities *he_capab;
+ size_t he_capab_len;
-#ifdef CONFIG_IEEE80211W
int sa_query_count; /* number of pending SA Query requests;
* 0 = no SA Query in progress */
int sa_query_timed_out;
@@ -175,7 +178,6 @@
* sa_query_count octets of pending SA Query
* transaction identifiers */
struct os_reltime sa_query_start;
-#endif /* CONFIG_IEEE80211W */
#if defined(CONFIG_INTERWORKING) || defined(CONFIG_DPP)
#define GAS_DIALOG_MAX 8 /* Max concurrent dialog number */
@@ -274,7 +276,13 @@
int last_tk_key_idx;
u8 last_tk[WPA_TK_MAX_LEN];
size_t last_tk_len;
+ u8 *sae_postponed_commit;
+ size_t sae_postponed_commit_len;
#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_AIRTIME_POLICY
+ unsigned int airtime_weight;
+ struct os_reltime backlogged_until;
+#endif /* CONFIG_AIRTIME_POLICY */
};
@@ -350,5 +358,6 @@
struct sta_info *sta);
int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
struct sta_info *sta);
+int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta);
#endif /* STA_INFO_H */
diff --git a/src/ap/utils.c b/src/ap/utils.c
index fcb371b..bedad6e 100644
--- a/src/ap/utils.c
+++ b/src/ap/utils.c
@@ -56,6 +56,10 @@
ohapd = iface->bss[j];
if (ohapd == data->hapd)
continue;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (ohapd->conf->skip_prune_assoc)
+ continue;
+#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_FST
/* Don't prune STAs belong to same FST */
if (ohapd->iface->fst &&
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index e293a00..53eacfb 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -22,7 +22,9 @@
static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
int existsok)
{
- int ret, i;
+ int ret;
+#ifdef CONFIG_WEP
+ int i;
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (!hapd->conf->ssid.wep.key[i])
@@ -32,6 +34,7 @@
vlan->ifname);
return -1;
}
+#endif /* CONFIG_WEP */
if (!iface_exists(vlan->ifname))
ret = hostapd_vlan_if_add(hapd, vlan->ifname);
diff --git a/src/ap/wmm.c b/src/ap/wmm.c
index 8054c5d..9ebb01e 100644
--- a/src/ap/wmm.c
+++ b/src/ap/wmm.c
@@ -20,6 +20,13 @@
#include "ap_drv_ops.h"
#include "wmm.h"
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+
static inline u8 wmm_aci_aifsn(int aifsn, int acm, int aci)
{
@@ -39,6 +46,62 @@
}
+static void
+wmm_set_regulatory_limit(const struct hostapd_wmm_ac_params *wmm_conf,
+ struct hostapd_wmm_ac_params *wmm,
+ const struct hostapd_wmm_rule *wmm_reg)
+{
+ int ac;
+
+ for (ac = 0; ac < WMM_AC_NUM; ac++) {
+ wmm[ac].cwmin = MAX(wmm_conf[ac].cwmin, wmm_reg[ac].min_cwmin);
+ wmm[ac].cwmax = MAX(wmm_conf[ac].cwmax, wmm_reg[ac].min_cwmax);
+ wmm[ac].aifs = MAX(wmm_conf[ac].aifs, wmm_reg[ac].min_aifs);
+ wmm[ac].txop_limit =
+ MIN(wmm_conf[ac].txop_limit, wmm_reg[ac].max_txop);
+ wmm[ac].admission_control_mandatory =
+ wmm_conf[ac].admission_control_mandatory;
+ }
+}
+
+
+/*
+ * Calculate WMM regulatory limit if any.
+ */
+static void wmm_calc_regulatory_limit(struct hostapd_data *hapd,
+ struct hostapd_wmm_ac_params *acp)
+{
+ struct hostapd_hw_modes *mode = hapd->iface->current_mode;
+ int c;
+
+ os_memcpy(acp, hapd->iconf->wmm_ac_params,
+ sizeof(hapd->iconf->wmm_ac_params));
+
+ for (c = 0; mode && c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+
+ if (chan->freq != hapd->iface->freq)
+ continue;
+
+ if (chan->wmm_rules_valid)
+ wmm_set_regulatory_limit(hapd->iconf->wmm_ac_params,
+ acp, chan->wmm_rules);
+ break;
+ }
+
+ /*
+ * Check if we need to update set count. Since both were initialized to
+ * zero we can compare the whole array in one shot.
+ */
+ if (os_memcmp(acp, hapd->iface->prev_wmm,
+ sizeof(hapd->iconf->wmm_ac_params)) != 0) {
+ os_memcpy(hapd->iface->prev_wmm, acp,
+ sizeof(hapd->iconf->wmm_ac_params));
+ hapd->parameter_set_count++;
+ }
+}
+
+
/*
* Add WMM Parameter Element to Beacon, Probe Response, and (Re)Association
* Response frames.
@@ -48,10 +111,14 @@
u8 *pos = eid;
struct wmm_parameter_element *wmm =
(struct wmm_parameter_element *) (pos + 2);
+ struct hostapd_wmm_ac_params wmmp[WMM_AC_NUM];
int e;
+ os_memset(wmmp, 0, sizeof(wmmp));
+
if (!hapd->conf->wmm_enabled)
return eid;
+ wmm_calc_regulatory_limit(hapd, wmmp);
eid[0] = WLAN_EID_VENDOR_SPECIFIC;
wmm->oui[0] = 0x00;
wmm->oui[1] = 0x50;
@@ -70,8 +137,7 @@
/* fill in a parameter set record for each AC */
for (e = 0; e < 4; e++) {
struct wmm_ac_parameter *ac = &wmm->ac[e];
- struct hostapd_wmm_ac_params *acp =
- &hapd->iconf->wmm_ac_params[e];
+ struct hostapd_wmm_ac_params *acp = &wmmp[e];
ac->aci_aifsn = wmm_aci_aifsn(acp->aifs,
acp->admission_control_mandatory,
@@ -145,7 +211,7 @@
os_memcpy(t, tspec, sizeof(struct wmm_tspec_element));
len = ((u8 *) (t + 1)) - buf;
- if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0)
+ if (hostapd_drv_send_mlme(hapd, m, len, 0, NULL, 0, 0) < 0)
wpa_printf(MSG_INFO, "wmm_send_action: send failed");
}
@@ -227,10 +293,11 @@
static void wmm_addts_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt,
- struct wmm_tspec_element *tspec, size_t len)
+ const struct wmm_tspec_element *tspec, size_t len)
{
const u8 *end = ((const u8 *) mgmt) + len;
int res;
+ struct wmm_tspec_element tspec_resp;
if ((const u8 *) (tspec + 1) > end) {
wpa_printf(MSG_DEBUG, "WMM: TSPEC overflow in ADDTS Request");
@@ -242,10 +309,11 @@
mgmt->u.action.u.wmm_action.dialog_token,
MAC2STR(mgmt->sa));
- res = wmm_process_tspec(tspec);
+ os_memcpy(&tspec_resp, tspec, sizeof(struct wmm_tspec_element));
+ res = wmm_process_tspec(&tspec_resp);
wpa_printf(MSG_DEBUG, "WMM: ADDTS processing result: %d", res);
- wmm_send_action(hapd, mgmt->sa, tspec, WMM_ACTION_CODE_ADDTS_RESP,
+ wmm_send_action(hapd, mgmt->sa, &tspec_resp, WMM_ACTION_CODE_ADDTS_RESP,
mgmt->u.action.u.wmm_action.dialog_token, res);
}
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index 27c69d3..67281b3 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -54,6 +54,7 @@
size_t len;
size_t gtk_elem_len = 0;
size_t igtk_elem_len = 0;
+ size_t bigtk_elem_len = 0;
struct wnm_sleep_element wnmsleep_ie;
u8 *wnmtfs_ie, *oci_ie;
u8 wnmsleep_ie_len, oci_ie_len;
@@ -122,8 +123,10 @@
#define MAX_GTK_SUBELEM_LEN 45
#define MAX_IGTK_SUBELEM_LEN 26
+#define MAX_BIGTK_SUBELEM_LEN 26
mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len +
MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN +
+ MAX_BIGTK_SUBELEM_LEN +
oci_ie_len);
if (mgmt == NULL) {
wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
@@ -150,7 +153,6 @@
pos += gtk_elem_len;
wpa_printf(MSG_DEBUG, "Pass 4, gtk_len = %d",
(int) gtk_elem_len);
-#ifdef CONFIG_IEEE80211W
res = wpa_wnmsleep_igtk_subelem(sta->wpa_sm, pos);
if (res < 0)
goto fail;
@@ -158,11 +160,19 @@
pos += igtk_elem_len;
wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
(int) igtk_elem_len);
-#endif /* CONFIG_IEEE80211W */
+ if (hapd->conf->beacon_prot) {
+ res = wpa_wnmsleep_bigtk_subelem(sta->wpa_sm, pos);
+ if (res < 0)
+ goto fail;
+ bigtk_elem_len = res;
+ pos += bigtk_elem_len;
+ wpa_printf(MSG_DEBUG, "Pass 4 bigtk_len = %d",
+ (int) bigtk_elem_len);
+ }
WPA_PUT_LE16((u8 *)
&mgmt->u.action.u.wnm_sleep_resp.keydata_len,
- gtk_elem_len + igtk_elem_len);
+ gtk_elem_len + igtk_elem_len + bigtk_elem_len);
}
os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
/* copy TFS IE here */
@@ -178,7 +188,8 @@
#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 + oci_ie_len;
+ igtk_elem_len + bigtk_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 */
@@ -191,8 +202,8 @@
/* when entering wnmsleep
* 1. pause the node in driver
- * 2. mark the node so that AP won't update GTK/IGTK during
- * WNM Sleep
+ * 2. mark the node so that AP won't update GTK/IGTK/BIGTK
+ * during WNM Sleep
*/
if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) {
@@ -203,7 +214,7 @@
}
/* when exiting wnmsleep
* 1. unmark the node
- * 2. start GTK/IGTK update if MFP is not used
+ * 2. start GTK/IGTK/BIGTK update if MFP is not used
* 3. unpause the node in driver
*/
if ((wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT ||
@@ -223,6 +234,7 @@
#undef MAX_GTK_SUBELEM_LEN
#undef MAX_IGTK_SUBELEM_LEN
+#undef MAX_BIGTK_SUBELEM_LEN
fail:
os_free(wnmtfs_ie);
os_free(oci_ie);
@@ -510,6 +522,30 @@
}
+static void wnm_beacon_protection_failure(struct hostapd_data *hapd,
+ const u8 *addr)
+{
+ struct sta_info *sta;
+
+ if (!hapd->conf->beacon_prot)
+ return;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for received WNM-Notification Request",
+ MAC2STR(addr));
+ return;
+ }
+
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Beacon protection failure reported");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPA_EVENT_UNPROT_BEACON "reporter="
+ MACSTR, MAC2STR(addr));
+}
+
+
static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd,
const u8 *addr, const u8 *buf,
size_t len)
@@ -528,8 +564,14 @@
MAC2STR(addr), dialog_token, type);
wpa_hexdump(MSG_MSGDUMP, "WNM: Notification Request subelements",
buf, len);
- if (type == WLAN_EID_VENDOR_SPECIFIC)
+ switch (type) {
+ case WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE:
+ wnm_beacon_protection_failure(hapd, addr);
+ break;
+ case WNM_NOTIF_TYPE_VENDOR_SPECIFIC:
mbo_ap_wnm_notification_req(hapd, addr, buf, len);
+ break;
+ }
}
@@ -643,7 +685,7 @@
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request frame to indicate imminent disassociation (disassoc_timer=%d) to "
MACSTR, disassoc_timer, MAC2STR(sta->addr));
- if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
"Management Request frame");
return -1;
@@ -716,7 +758,7 @@
os_memcpy(pos, url, url_len);
pos += url_len;
- if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
"Management Request frame");
return -1;
@@ -792,7 +834,7 @@
mbo_len);
}
- if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_DEBUG,
"Failed to send BSS Transition Management Request frame");
os_free(buf);
@@ -836,7 +878,7 @@
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) {
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_DEBUG,
"WNM: Failed to send Collocated Interference Request frame");
return -1;
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index e89a716..30e7258 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -56,13 +56,14 @@
struct wpa_group *group);
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
const u8 *pmk, unsigned int pmk_len,
- struct wpa_ptk *ptk);
+ struct wpa_ptk *ptk, int force_sha256);
static void wpa_group_free(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static void wpa_group_get(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static void wpa_group_put(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
+static int ieee80211w_kde_len(struct wpa_state_machine *sm);
static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos);
static const u32 eapol_key_timeout_first = 100; /* ms */
@@ -105,7 +106,7 @@
static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth,
const u8 *addr, wpa_eapol_variable var)
{
- if (wpa_auth->cb->get_eapol == NULL)
+ if (!wpa_auth->cb->get_eapol)
return -1;
return wpa_auth->cb->get_eapol(wpa_auth->cb_ctx, addr, var);
}
@@ -117,7 +118,7 @@
const u8 *prev_psk, size_t *psk_len,
int *vlan_id)
{
- if (wpa_auth->cb->get_psk == NULL)
+ if (!wpa_auth->cb->get_psk)
return NULL;
return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
prev_psk, psk_len, vlan_id);
@@ -127,7 +128,7 @@
static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,
const u8 *addr, u8 *msk, size_t *len)
{
- if (wpa_auth->cb->get_msk == NULL)
+ if (!wpa_auth->cb->get_msk)
return -1;
return wpa_auth->cb->get_msk(wpa_auth->cb_ctx, addr, msk, len);
}
@@ -136,21 +137,46 @@
static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
int vlan_id,
enum wpa_alg alg, const u8 *addr, int idx,
- u8 *key, size_t key_len)
+ u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
- if (wpa_auth->cb->set_key == NULL)
+ if (!wpa_auth->cb->set_key)
return -1;
return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
- key, key_len);
+ key, key_len, key_flag);
}
static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
const u8 *addr, int idx, u8 *seq)
{
- if (wpa_auth->cb->get_seqnum == NULL)
+ int res;
+
+ if (!wpa_auth->cb->get_seqnum)
return -1;
- return wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq);
+ res = wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (!addr && idx < 4 && wpa_auth->conf.gtk_rsc_override_set) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Override GTK RSC %016llx --> %016llx",
+ (long long unsigned) WPA_GET_LE64(seq),
+ (long long unsigned)
+ WPA_GET_LE64(wpa_auth->conf.gtk_rsc_override));
+ os_memcpy(seq, wpa_auth->conf.gtk_rsc_override,
+ WPA_KEY_RSC_LEN);
+ }
+ if (!addr && idx >= 4 && idx <= 5 &&
+ wpa_auth->conf.igtk_rsc_override_set) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Override IGTK RSC %016llx --> %016llx",
+ (long long unsigned) WPA_GET_LE64(seq),
+ (long long unsigned)
+ WPA_GET_LE64(wpa_auth->conf.igtk_rsc_override));
+ os_memcpy(seq, wpa_auth->conf.igtk_rsc_override,
+ WPA_KEY_RSC_LEN);
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ return res;
}
@@ -158,7 +184,7 @@
wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *data, size_t data_len, int encrypt)
{
- if (wpa_auth->cb->send_eapol == NULL)
+ if (!wpa_auth->cb->send_eapol)
return -1;
return wpa_auth->cb->send_eapol(wpa_auth->cb_ctx, addr, data, data_len,
encrypt);
@@ -169,7 +195,7 @@
static inline int wpa_auth_start_ampe(struct wpa_authenticator *wpa_auth,
const u8 *addr)
{
- if (wpa_auth->cb->start_ampe == NULL)
+ if (!wpa_auth->cb->start_ampe)
return -1;
return wpa_auth->cb->start_ampe(wpa_auth->cb_ctx, addr);
}
@@ -180,7 +206,7 @@
int (*cb)(struct wpa_state_machine *sm, void *ctx),
void *cb_ctx)
{
- if (wpa_auth->cb->for_each_sta == NULL)
+ if (!wpa_auth->cb->for_each_sta)
return 0;
return wpa_auth->cb->for_each_sta(wpa_auth->cb_ctx, cb, cb_ctx);
}
@@ -190,7 +216,7 @@
int (*cb)(struct wpa_authenticator *a, void *ctx),
void *cb_ctx)
{
- if (wpa_auth->cb->for_each_auth == NULL)
+ if (!wpa_auth->cb->for_each_auth)
return 0;
return wpa_auth->cb->for_each_auth(wpa_auth->cb_ctx, cb, cb_ctx);
}
@@ -199,7 +225,7 @@
void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
logger_level level, const char *txt)
{
- if (wpa_auth->cb->logger == NULL)
+ if (!wpa_auth->cb->logger)
return;
wpa_auth->cb->logger(wpa_auth->cb_ctx, addr, level, txt);
}
@@ -212,7 +238,7 @@
int maxlen;
va_list ap;
- if (wpa_auth->cb->logger == NULL)
+ if (!wpa_auth->cb->logger)
return;
maxlen = os_strlen(fmt) + 100;
@@ -233,7 +259,7 @@
static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
const u8 *addr, u16 reason)
{
- if (wpa_auth->cb->disconnect == NULL)
+ if (!wpa_auth->cb->disconnect)
return;
wpa_printf(MSG_DEBUG, "wpa_sta_disconnect STA " MACSTR " (reason %u)",
MAC2STR(addr), reason);
@@ -266,8 +292,8 @@
struct wpa_authenticator *wpa_auth = eloop_ctx;
if (random_get_bytes(wpa_auth->group->GMK, WPA_GMK_LEN)) {
- wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
- "initialization.");
+ wpa_printf(MSG_ERROR,
+ "Failed to get random data for WPA initialization.");
} else {
wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "GMK rekeyd");
wpa_hexdump_key(MSG_DEBUG, "GMK",
@@ -291,9 +317,9 @@
while (group) {
wpa_group_get(wpa_auth, group);
- group->GTKReKey = TRUE;
+ group->GTKReKey = true;
do {
- group->changed = FALSE;
+ group->changed = false;
wpa_group_sm_step(wpa_auth, group);
} while (group->changed);
@@ -320,6 +346,19 @@
}
+void wpa_auth_set_ptk_rekey_timer(struct wpa_state_machine *sm)
+{
+ if (sm && sm->wpa_auth->conf.wpa_ptk_rekey) {
+ wpa_printf(MSG_DEBUG, "WPA: Start PTK rekeying timer for "
+ MACSTR " (%d seconds)", MAC2STR(sm->addr),
+ sm->wpa_auth->conf.wpa_ptk_rekey);
+ eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
+ eloop_register_timeout(sm->wpa_auth->conf.wpa_ptk_rekey, 0,
+ wpa_rekey_ptk, sm->wpa_auth, sm);
+ }
+}
+
+
static int wpa_auth_pmksa_clear_cb(struct wpa_state_machine *sm, void *ctx)
{
if (sm->pmksa == ctx)
@@ -378,17 +417,16 @@
struct wpa_group *group;
group = os_zalloc(sizeof(struct wpa_group));
- if (group == NULL)
+ if (!group)
return NULL;
- group->GTKAuthenticator = TRUE;
+ group->GTKAuthenticator = true;
group->vlan_id = vlan_id;
group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
if (random_pool_ready() != 1) {
- wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
- "for secure operations - update keys later when "
- "the first station connects");
+ wpa_printf(MSG_INFO,
+ "WPA: Not enough entropy in random pool for secure operations - update keys later when the first station connects");
}
/*
@@ -398,20 +436,20 @@
* on embedded devices.
*/
if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0) {
- wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
- "initialization.");
+ wpa_printf(MSG_ERROR,
+ "Failed to get random data for WPA initialization.");
os_free(group);
return NULL;
}
- group->GInit = TRUE;
+ group->GInit = true;
if (delay_init) {
- wpa_printf(MSG_DEBUG, "WPA: Delay group state machine start "
- "until Beacon frames have been configured");
+ wpa_printf(MSG_DEBUG,
+ "WPA: Delay group state machine start until Beacon frames have been configured");
/* Initialization is completed in wpa_init_keys(). */
} else {
wpa_group_sm_step(wpa_auth, group);
- group->GInit = FALSE;
+ group->GInit = false;
wpa_group_sm_step(wpa_auth, group);
}
@@ -434,7 +472,7 @@
struct wpa_authenticator *wpa_auth;
wpa_auth = os_zalloc(sizeof(struct wpa_authenticator));
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return NULL;
os_memcpy(wpa_auth->addr, addr, ETH_ALEN);
os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
@@ -448,7 +486,7 @@
}
wpa_auth->group = wpa_group_init(wpa_auth, 0, 1);
- if (wpa_auth->group == NULL) {
+ if (!wpa_auth->group) {
os_free(wpa_auth->wpa_ie);
os_free(wpa_auth);
return NULL;
@@ -456,7 +494,7 @@
wpa_auth->pmksa = pmksa_cache_auth_init(wpa_auth_pmksa_free_cb,
wpa_auth);
- if (wpa_auth->pmksa == NULL) {
+ if (!wpa_auth->pmksa) {
wpa_printf(MSG_ERROR, "PMKSA cache initialization failed.");
os_free(wpa_auth->group);
os_free(wpa_auth->wpa_ie);
@@ -466,7 +504,7 @@
#ifdef CONFIG_IEEE80211R_AP
wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init();
- if (wpa_auth->ft_pmk_cache == NULL) {
+ if (!wpa_auth->ft_pmk_cache) {
wpa_printf(MSG_ERROR, "FT PMK cache initialization failed.");
os_free(wpa_auth->group);
os_free(wpa_auth->wpa_ie);
@@ -505,10 +543,10 @@
{
struct wpa_group *group = wpa_auth->group;
- wpa_printf(MSG_DEBUG, "WPA: Start group state machine to set initial "
- "keys");
+ wpa_printf(MSG_DEBUG,
+ "WPA: Start group state machine to set initial keys");
wpa_group_sm_step(wpa_auth, group);
- group->GInit = FALSE;
+ group->GInit = false;
wpa_group_sm_step(wpa_auth, group);
if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
return -1;
@@ -562,7 +600,8 @@
struct wpa_auth_config *conf)
{
struct wpa_group *group;
- if (wpa_auth == NULL)
+
+ if (!wpa_auth)
return 0;
os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
@@ -577,9 +616,9 @@
*/
group = wpa_auth->group;
group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
- group->GInit = TRUE;
+ group->GInit = true;
wpa_group_sm_step(wpa_auth, group);
- group->GInit = FALSE;
+ group->GInit = false;
wpa_group_sm_step(wpa_auth, group);
return 0;
@@ -596,7 +635,7 @@
return NULL;
sm = os_zalloc(sizeof(struct wpa_state_machine));
- if (sm == NULL)
+ if (!sm)
return NULL;
os_memcpy(sm->addr, addr, ETH_ALEN);
if (p2p_dev_addr)
@@ -613,17 +652,16 @@
int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm)
{
- if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
+ if (!wpa_auth || !wpa_auth->conf.wpa || !sm)
return -1;
#ifdef CONFIG_IEEE80211R_AP
if (sm->ft_completed) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "FT authentication already completed - do not "
- "start 4-way handshake");
+ "FT authentication already completed - do not start 4-way handshake");
/* Go to PTKINITDONE state to allow GTK rekeying */
sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
- sm->Pair = TRUE;
+ sm->Pair = true;
return 0;
}
#endif /* CONFIG_IEEE80211R_AP */
@@ -634,14 +672,14 @@
"FILS authentication already completed - do not start 4-way handshake");
/* Go to PTKINITDONE state to allow GTK rekeying */
sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
- sm->Pair = TRUE;
+ sm->Pair = true;
return 0;
}
#endif /* CONFIG_FILS */
if (sm->started) {
os_memset(&sm->key_replay, 0, sizeof(sm->key_replay));
- sm->ReAuthenticationRequest = TRUE;
+ sm->ReAuthenticationRequest = true;
return wpa_sm_step(sm);
}
@@ -649,11 +687,11 @@
"start authentication");
sm->started = 1;
- sm->Init = TRUE;
+ sm->Init = true;
if (wpa_sm_step(sm) == 1)
return 1; /* should not really happen */
- sm->Init = FALSE;
- sm->AuthenticationRequest = TRUE;
+ sm->Init = false;
+ sm->AuthenticationRequest = true;
return wpa_sm_step(sm);
}
@@ -663,7 +701,7 @@
/* WPA/RSN was not used - clear WPA state. This is needed if the STA
* reassociates back to the same AP while the previous entry for the
* STA has not yet been removed. */
- if (sm == NULL)
+ if (!sm)
return;
sm->wpa_key_mgmt = 0;
@@ -675,8 +713,9 @@
#ifdef CONFIG_P2P
if (WPA_GET_BE32(sm->ip_addr)) {
u32 start;
- wpa_printf(MSG_DEBUG, "P2P: Free assigned IP "
- "address %u.%u.%u.%u from " MACSTR,
+ wpa_printf(MSG_DEBUG,
+ "P2P: Free assigned IP address %u.%u.%u.%u from "
+ MACSTR,
sm->ip_addr[0], sm->ip_addr[1],
sm->ip_addr[2], sm->ip_addr[3],
MAC2STR(sm->addr));
@@ -687,7 +726,7 @@
#endif /* CONFIG_P2P */
if (sm->GUpdateStationKeys) {
sm->group->GKeyDoneStations--;
- sm->GUpdateStationKeys = FALSE;
+ sm->GUpdateStationKeys = false;
}
#ifdef CONFIG_IEEE80211R_AP
os_free(sm->assoc_resp_ftie);
@@ -695,6 +734,7 @@
#endif /* CONFIG_IEEE80211R_AP */
os_free(sm->last_rx_eapol_key);
os_free(sm->wpa_ie);
+ os_free(sm->rsnxe);
wpa_group_put(sm->wpa_auth, sm->group);
#ifdef CONFIG_DPP2
wpabuf_clear_free(sm->dpp_z);
@@ -705,31 +745,34 @@
void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ struct wpa_authenticator *wpa_auth;
+
+ if (!sm)
return;
- if (sm->wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "strict rekeying - force GTK rekey since STA "
- "is leaving");
+ wpa_auth = sm->wpa_auth;
+ if (wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "strict rekeying - force GTK rekey since STA is leaving");
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);
+ wpa_auth, NULL) == -1)
+ eloop_register_timeout(0, 500000, wpa_rekey_gtk,
+ wpa_auth, NULL);
}
- eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
+ eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
sm->pending_1_of_4_timeout = 0;
eloop_cancel_timeout(wpa_sm_call_step, sm, NULL);
- eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
+ eloop_cancel_timeout(wpa_rekey_ptk, wpa_auth, sm);
#ifdef CONFIG_IEEE80211R_AP
wpa_ft_sta_deinit(sm);
#endif /* CONFIG_IEEE80211R_AP */
if (sm->in_step_loop) {
/* Must not free state machine while wpa_sm_step() is running.
* Freeing will be completed in the end of wpa_sm_step(). */
- wpa_printf(MSG_DEBUG, "WPA: Registering pending STA state "
- "machine deinit for " MACSTR, MAC2STR(sm->addr));
+ wpa_printf(MSG_DEBUG,
+ "WPA: Registering pending STA state machine deinit for "
+ MACSTR, MAC2STR(sm->addr));
sm->pending_deinit = 1;
} else
wpa_free_sta_sm(sm);
@@ -738,11 +781,23 @@
static void wpa_request_new_ptk(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return;
- sm->PTKRequest = TRUE;
- sm->PTK_valid = 0;
+ if (!sm->use_ext_key_id && sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
+ wpa_printf(MSG_INFO,
+ "WPA: PTK0 rekey not allowed, disconnect " MACSTR,
+ MAC2STR(sm->addr));
+ sm->Disconnect = true;
+ /* Try to encourage the STA to reconnect */
+ sm->disconnect_reason =
+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
+ } else {
+ if (sm->use_ext_key_id)
+ sm->keyidx_active ^= 1; /* flip Key ID */
+ sm->PTKRequest = true;
+ sm->PTK_valid = 0;
+ }
}
@@ -767,10 +822,10 @@
int i;
for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
if (ctr[i].valid &&
- (replay_counter == NULL ||
+ (!replay_counter ||
os_memcmp(replay_counter, ctr[i].counter,
WPA_REPLAY_COUNTER_LEN) == 0))
- ctr[i].valid = FALSE;
+ ctr[i].valid = false;
}
}
@@ -784,9 +839,9 @@
struct rsn_mdie *mdie;
if (wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0 ||
- ie.num_pmkid != 1 || ie.pmkid == NULL) {
- wpa_printf(MSG_DEBUG, "FT: No PMKR1Name in "
- "FT 4-way handshake message 2/4");
+ ie.num_pmkid != 1 || !ie.pmkid) {
+ wpa_printf(MSG_DEBUG,
+ "FT: No PMKR1Name in FT 4-way handshake message 2/4");
return -1;
}
@@ -795,8 +850,9 @@
sm->sup_pmk_r1_name, PMKID_LEN);
if (!kde->mdie || !kde->ftie) {
- wpa_printf(MSG_DEBUG, "FT: No %s in FT 4-way handshake "
- "message 2/4", kde->mdie ? "FTIE" : "MDIE");
+ wpa_printf(MSG_DEBUG,
+ "FT: No %s in FT 4-way handshake message 2/4",
+ kde->mdie ? "FTIE" : "MDIE");
return -1;
}
@@ -830,18 +886,15 @@
{
/* Supplicant reported a Michael MIC error */
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key Error Request "
- "(STA detected Michael MIC failure (group=%d))",
+ "received EAPOL-Key Error Request (STA detected Michael MIC failure (group=%d))",
group);
if (group && wpa_auth->conf.wpa_group != WPA_CIPHER_TKIP) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "ignore Michael MIC failure report since "
- "group cipher is not TKIP");
+ "ignore Michael MIC failure report since group cipher is not TKIP");
} else if (!group && sm->pairwise != WPA_CIPHER_TKIP) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "ignore Michael MIC failure report since "
- "pairwise cipher is not TKIP");
+ "ignore Michael MIC failure report since pairwise cipher is not TKIP");
} else {
if (wpa_auth_mic_failure_report(wpa_auth, sm->addr) > 0)
return 1; /* STA entry was removed */
@@ -874,7 +927,7 @@
pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
sm->p2p_dev_addr, pmk, &pmk_len,
&vlan_id);
- if (pmk == NULL)
+ if (!pmk)
break;
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
@@ -887,7 +940,8 @@
pmk_len = sm->pmk_len;
}
- if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK) < 0)
+ if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK, 0) <
+ 0)
break;
if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
@@ -921,7 +975,8 @@
os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN);
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
- sm->PTK_valid = TRUE;
+ forced_memzero(&PTK, sizeof(PTK));
+ sm->PTK_valid = true;
return 0;
}
@@ -941,7 +996,7 @@
size_t keyhdrlen, mic_len;
u8 *mic;
- if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
+ if (!wpa_auth || !wpa_auth->conf.wpa || !sm)
return;
wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL data", data, data_len);
@@ -960,20 +1015,19 @@
key_data = mic + mic_len + 2;
key_data_length = WPA_GET_BE16(mic + mic_len);
wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
- " key_info=0x%x type=%u mic_len=%u key_data_length=%u",
+ " key_info=0x%x type=%u mic_len=%zu key_data_length=%u",
MAC2STR(sm->addr), key_info, key->type,
- (unsigned int) mic_len, key_data_length);
+ mic_len, key_data_length);
wpa_hexdump(MSG_MSGDUMP,
"WPA: EAPOL-Key header (ending before Key MIC)",
key, sizeof(*key));
wpa_hexdump(MSG_MSGDUMP, "WPA: EAPOL-Key Key MIC",
mic, mic_len);
if (key_data_length > data_len - sizeof(*hdr) - keyhdrlen) {
- wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
- "key_data overflow (%d > %lu)",
+ wpa_printf(MSG_INFO,
+ "WPA: Invalid EAPOL-Key frame - key_data overflow (%d > %zu)",
key_data_length,
- (unsigned long) (data_len - sizeof(*hdr) -
- keyhdrlen));
+ data_len - sizeof(*hdr) - keyhdrlen);
return;
}
@@ -983,18 +1037,18 @@
* Some deployed station implementations seem to send
* msg 4/4 with incorrect type value in WPA2 mode.
*/
- wpa_printf(MSG_DEBUG, "Workaround: Allow EAPOL-Key "
- "with unexpected WPA type in RSN mode");
+ wpa_printf(MSG_DEBUG,
+ "Workaround: Allow EAPOL-Key with unexpected WPA type in RSN mode");
} else if (key->type != EAPOL_KEY_TYPE_RSN) {
- wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
- "unexpected type %d in RSN mode",
+ wpa_printf(MSG_DEBUG,
+ "Ignore EAPOL-Key with unexpected type %d in RSN mode",
key->type);
return;
}
} else {
if (key->type != EAPOL_KEY_TYPE_WPA) {
- wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
- "unexpected type %d in WPA mode",
+ wpa_printf(MSG_DEBUG,
+ "Ignore EAPOL-Key with unexpected type %d in WPA mode",
key->type);
return;
}
@@ -1039,9 +1093,7 @@
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
- "advertised support for "
- "AES-128-CMAC, but did not "
- "use it");
+ "advertised support for AES-128-CMAC, but did not use it");
return;
}
@@ -1050,8 +1102,7 @@
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
- "did not use HMAC-SHA1-AES "
- "with CCMP/GCMP");
+ "did not use HMAC-SHA1-AES with CCMP/GCMP");
return;
}
}
@@ -1069,8 +1120,7 @@
os_memcmp(key->replay_counter, sm->req_replay_counter,
WPA_REPLAY_COUNTER_LEN) <= 0) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
- "received EAPOL-Key request with "
- "replayed counter");
+ "received EAPOL-Key request with replayed counter");
return;
}
}
@@ -1093,12 +1143,10 @@
* even if we have already sent out EAPOL-Key 3/4.
*/
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "Process SNonce update from STA "
- "based on retransmitted EAPOL-Key "
- "1/4");
+ "Process SNonce update from STA based on retransmitted EAPOL-Key 1/4");
sm->update_snonce = 1;
os_memcpy(sm->alt_SNonce, sm->SNonce, WPA_NONCE_LEN);
- sm->alt_snonce_valid = TRUE;
+ sm->alt_snonce_valid = true;
os_memcpy(sm->alt_replay_counter,
sm->key_replay[0].counter,
WPA_REPLAY_COUNTER_LEN);
@@ -1124,12 +1172,12 @@
key->replay_counter) &&
sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "ignore retransmitted EAPOL-Key %s - "
- "SNonce did not change", msgtxt);
+ "ignore retransmitted EAPOL-Key %s - SNonce did not change",
+ msgtxt);
} else {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "received EAPOL-Key %s with "
- "unexpected replay counter", msgtxt);
+ "received EAPOL-Key %s with unexpected replay counter",
+ msgtxt);
}
for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
if (!sm->key_replay[i].valid)
@@ -1160,8 +1208,7 @@
(!sm->update_snonce ||
sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING)) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key msg 2/4 in "
- "invalid state (%d) - dropped",
+ "received EAPOL-Key msg 2/4 in invalid state (%d) - dropped",
sm->wpa_ptk_state);
return;
}
@@ -1176,9 +1223,8 @@
* Counter update and the station will be allowed to
* continue.
*/
- wpa_printf(MSG_DEBUG, "WPA: Reject 4-way handshake to "
- "collect more entropy for random number "
- "generation");
+ wpa_printf(MSG_DEBUG,
+ "WPA: Reject 4-way handshake to collect more entropy for random number generation");
random_mark_pool_ready();
wpa_sta_disconnect(wpa_auth, sm->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
@@ -1189,8 +1235,7 @@
if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING ||
!sm->PTK_valid) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key msg 4/4 in "
- "invalid state (%d) - dropped",
+ "received EAPOL-Key msg 4/4 in invalid state (%d) - dropped",
sm->wpa_ptk_state);
return;
}
@@ -1199,8 +1244,7 @@
if (sm->wpa_ptk_group_state != WPA_PTK_GROUP_REKEYNEGOTIATING
|| !sm->PTK_valid) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key msg 2/2 in "
- "invalid state (%d) - dropped",
+ "received EAPOL-Key msg 2/2 in invalid state (%d) - dropped",
sm->wpa_ptk_group_state);
return;
}
@@ -1234,7 +1278,7 @@
}
#endif /* CONFIG_FILS */
- sm->MICVerified = FALSE;
+ sm->MICVerified = false;
if (sm->PTK_valid && !sm->update_snonce) {
if (mic_len &&
wpa_verify_key_mic(sm->wpa_key_mgmt, sm->pmk_len, &sm->PTK,
@@ -1267,7 +1311,7 @@
#ifdef TEST_FUZZ
continue_fuzz:
#endif /* TEST_FUZZ */
- sm->MICVerified = TRUE;
+ sm->MICVerified = true;
eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
sm->pending_1_of_4_timeout = 0;
}
@@ -1279,8 +1323,7 @@
WPA_REPLAY_COUNTER_LEN);
} else {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key request with "
- "invalid MIC");
+ "received EAPOL-Key request with invalid MIC");
return;
}
@@ -1296,8 +1339,7 @@
return; /* STA entry was removed */
} else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key Request for new "
- "4-Way Handshake");
+ "received EAPOL-Key Request for new 4-Way Handshake");
wpa_request_new_ptk(sm);
} else if (key_data_length > 0 &&
wpa_parse_kde_ies(key_data, key_data_length,
@@ -1305,8 +1347,7 @@
kde.mac_addr) {
} else {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key Request for GTK "
- "rekeying");
+ "received EAPOL-Key Request for GTK rekeying");
eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
wpa_rekey_gtk(wpa_auth, NULL);
}
@@ -1339,12 +1380,12 @@
os_free(sm->last_rx_eapol_key);
sm->last_rx_eapol_key = os_memdup(data, data_len);
- if (sm->last_rx_eapol_key == NULL)
+ if (!sm->last_rx_eapol_key)
return;
sm->last_rx_eapol_key_len = data_len;
sm->rx_eapol_key_secure = !!(key_info & WPA_KEY_INFO_SECURE);
- sm->EAPOLKeyReceived = TRUE;
+ sm->EAPOLKeyReceived = true;
sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST);
os_memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN);
@@ -1394,6 +1435,8 @@
#endif /* CONFIG_SHA256 */
#endif /* CONFIG_SHA384 */
+ forced_memzero(data, sizeof(data));
+
return ret;
}
@@ -1405,7 +1448,7 @@
sm->pending_1_of_4_timeout = 0;
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "EAPOL-Key timeout");
- sm->TimeoutEvt = TRUE;
+ sm->TimeoutEvt = true;
wpa_sm_step(sm);
}
@@ -1416,6 +1459,7 @@
const u8 *kde, size_t kde_len,
int keyidx, int encr, int force_version)
{
+ struct wpa_auth_config *conf = &wpa_auth->conf;
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
size_t len, mic_len, keyhdrlen;
@@ -1444,15 +1488,14 @@
pairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
- wpa_printf(MSG_DEBUG, "WPA: Send EAPOL(version=%d secure=%d mic=%d "
- "ack=%d install=%d pairwise=%d kde_len=%lu keyidx=%d "
- "encr=%d)",
+ wpa_printf(MSG_DEBUG,
+ "WPA: Send EAPOL(version=%d secure=%d mic=%d ack=%d install=%d pairwise=%d kde_len=%zu keyidx=%d encr=%d)",
version,
(key_info & WPA_KEY_INFO_SECURE) ? 1 : 0,
(key_info & WPA_KEY_INFO_MIC) ? 1 : 0,
(key_info & WPA_KEY_INFO_ACK) ? 1 : 0,
(key_info & WPA_KEY_INFO_INSTALL) ? 1 : 0,
- pairwise, (unsigned long) kde_len, keyidx, encr);
+ pairwise, kde_len, keyidx, encr);
key_data_len = kde_len;
@@ -1470,9 +1513,9 @@
len += AES_BLOCK_SIZE;
hdr = os_zalloc(len);
- if (hdr == NULL)
+ if (!hdr)
return;
- hdr->version = wpa_auth->conf.eapol_version;
+ hdr->version = conf->eapol_version;
hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
hdr->length = host_to_be16(len - sizeof(*hdr));
key = (struct wpa_eapol_key *) (hdr + 1);
@@ -1488,7 +1531,7 @@
key_info |= keyidx << WPA_KEY_INFO_KEY_INDEX_SHIFT;
WPA_PUT_BE16(key->key_info, key_info);
- alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group;
+ alg = pairwise ? sm->pairwise : conf->wpa_group;
if (sm->wpa == WPA_VERSION_WPA2 && !pairwise)
WPA_PUT_BE16(key->key_length, 0);
else
@@ -1505,7 +1548,7 @@
WPA_REPLAY_COUNTER_LEN);
wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter",
key->replay_counter, WPA_REPLAY_COUNTER_LEN);
- sm->key_replay[0].valid = TRUE;
+ sm->key_replay[0].valid = true;
if (nonce)
os_memcpy(key->key_nonce, nonce, WPA_NONCE_LEN);
@@ -1542,7 +1585,7 @@
#endif /* CONFIG_FILS */
} else if (encr && kde) {
buf = os_zalloc(key_data_len);
- if (buf == NULL) {
+ if (!buf) {
os_free(hdr);
return;
}
@@ -1559,8 +1602,8 @@
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)",
- (unsigned int) sm->PTK.kek_len);
+ "WPA: Encrypt Key Data using AES-WRAP (KEK length %zu)",
+ sm->PTK.kek_len);
if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len,
(key_data_len - 8) / 8, buf, key_data)) {
os_free(hdr);
@@ -1594,8 +1637,7 @@
if (key_info & WPA_KEY_INFO_MIC) {
if (!sm->PTK_valid || !mic_len) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "PTK not valid when sending EAPOL-Key "
- "frame");
+ "PTK not valid when sending EAPOL-Key frame");
os_free(hdr);
return;
}
@@ -1608,9 +1650,8 @@
}
#ifdef CONFIG_TESTING_OPTIONS
if (!pairwise &&
- wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 &&
- drand48() <
- wpa_auth->conf.corrupt_gtk_rekey_mic_probability) {
+ conf->corrupt_gtk_rekey_mic_probability > 0.0 &&
+ drand48() < conf->corrupt_gtk_rekey_mic_probability) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"Corrupting group EAPOL-Key Key MIC");
key_mic[0]++;
@@ -1618,8 +1659,7 @@
#endif /* CONFIG_TESTING_OPTIONS */
}
- wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx,
- 1);
+ wpa_auth_set_eapol(wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx, 1);
wpa_auth_send_eapol(wpa_auth, sm->addr, (u8 *) hdr, len,
sm->pairwise_set);
os_free(hdr);
@@ -1636,7 +1676,7 @@
int pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
u32 ctr;
- if (sm == NULL)
+ if (!sm)
return;
__wpa_send_eapol(wpa_auth, sm, key_info, key_rsc, nonce, kde, kde_len,
@@ -1656,8 +1696,9 @@
#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);
+ 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,
wpa_send_eapol_timeout, wpa_auth, sm);
}
@@ -1694,13 +1735,18 @@
void wpa_remove_ptk(struct wpa_state_machine *sm)
{
- sm->PTK_valid = FALSE;
+ sm->PTK_valid = false;
os_memset(&sm->PTK, 0, sizeof(sm->PTK));
if (wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL,
- 0))
+ 0, KEY_FLAG_PAIRWISE))
wpa_printf(MSG_DEBUG,
"RSN: PTK removal from the driver failed");
- sm->pairwise_set = FALSE;
+ if (sm->use_ext_key_id &&
+ wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 1, NULL,
+ 0, KEY_FLAG_PAIRWISE))
+ wpa_printf(MSG_DEBUG,
+ "RSN: PTK Key ID 1 removal from the driver failed");
+ sm->pairwise_set = false;
eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
}
@@ -1709,7 +1755,7 @@
{
int remove_ptk = 1;
- if (sm == NULL)
+ if (!sm)
return -1;
wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
@@ -1729,12 +1775,14 @@
break;
case WPA_DEAUTH:
case WPA_DISASSOC:
- sm->DeauthenticationRequest = TRUE;
+ 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;
+ os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1));
+ sm->pmk_r1_len = 0;
#endif /* CONFIG_IEEE80211R_AP */
break;
case WPA_REAUTH:
@@ -1747,35 +1795,52 @@
* sure that the WPA state machines gets initialized
* properly at this point.
*/
- wpa_printf(MSG_DEBUG, "WPA state machine had not been "
- "started - initialize now");
+ wpa_printf(MSG_DEBUG,
+ "WPA state machine had not been started - initialize now");
sm->started = 1;
- sm->Init = TRUE;
+ sm->Init = true;
if (wpa_sm_step(sm) == 1)
return 1; /* should not really happen */
- sm->Init = FALSE;
- sm->AuthenticationRequest = TRUE;
+ sm->Init = false;
+ sm->AuthenticationRequest = true;
break;
}
+
+ if (!sm->use_ext_key_id &&
+ sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
+ wpa_printf(MSG_INFO,
+ "WPA: PTK0 rekey not allowed, disconnect "
+ MACSTR, MAC2STR(sm->addr));
+ sm->Disconnect = true;
+ /* Try to encourage the STA to reconnect */
+ sm->disconnect_reason =
+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
+ break;
+ }
+
+ if (sm->use_ext_key_id)
+ sm->keyidx_active ^= 1; /* flip Key ID */
+
if (sm->GUpdateStationKeys) {
/*
* Reauthentication cancels the pending group key
* update for this STA.
*/
sm->group->GKeyDoneStations--;
- sm->GUpdateStationKeys = FALSE;
- sm->PtkGroupInit = TRUE;
+ sm->GUpdateStationKeys = false;
+ sm->PtkGroupInit = true;
}
- sm->ReAuthenticationRequest = TRUE;
+ sm->ReAuthenticationRequest = true;
break;
case WPA_ASSOC_FT:
#ifdef CONFIG_IEEE80211R_AP
- wpa_printf(MSG_DEBUG, "FT: Retry PTK configuration "
- "after association");
- wpa_ft_install_ptk(sm);
+ wpa_printf(MSG_DEBUG,
+ "FT: Retry PTK configuration after association");
+ wpa_ft_install_ptk(sm, 1);
/* Using FT protocol, not WPA auth state machine */
sm->ft_completed = 1;
+ wpa_auth_set_ptk_rekey_timer(sm);
return 0;
#else /* CONFIG_IEEE80211R_AP */
break;
@@ -1791,7 +1856,7 @@
break;
#endif /* CONFIG_FILS */
case WPA_DRV_STA_REMOVED:
- sm->tk_already_set = FALSE;
+ sm->tk_already_set = false;
return 0;
}
@@ -1799,10 +1864,8 @@
sm->ft_completed = 0;
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
if (sm->mgmt_frame_prot && event == WPA_AUTH)
remove_ptk = 0;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_FILS
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
(event == WPA_AUTH || event == WPA_ASSOC))
@@ -1810,7 +1873,7 @@
#endif /* CONFIG_FILS */
if (remove_ptk) {
- sm->PTK_valid = FALSE;
+ sm->PTK_valid = false;
os_memset(&sm->PTK, 0, sizeof(sm->PTK));
if (event != WPA_REAUTH_EAPOL)
@@ -1822,7 +1885,7 @@
* wpa_sm_step() is already running - avoid recursive call to
* it by making the existing loop process the new update.
*/
- sm->changed = TRUE;
+ sm->changed = true;
return 0;
}
return wpa_sm_step(sm);
@@ -1835,18 +1898,18 @@
if (sm->Init) {
/* Init flag is not cleared here, so avoid busy
* loop by claiming nothing changed. */
- sm->changed = FALSE;
+ sm->changed = false;
}
sm->keycount = 0;
if (sm->GUpdateStationKeys)
sm->group->GKeyDoneStations--;
- sm->GUpdateStationKeys = FALSE;
+ sm->GUpdateStationKeys = false;
if (sm->wpa == WPA_VERSION_WPA)
- sm->PInitAKeys = FALSE;
+ sm->PInitAKeys = false;
if (1 /* Unicast cipher supported AND (ESS OR ((IBSS or WDS) and
* Local AA > Remote AA)) */) {
- sm->Pair = TRUE;
+ sm->Pair = true;
}
wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 0);
wpa_remove_ptk(sm);
@@ -1866,7 +1929,7 @@
u16 reason = sm->disconnect_reason;
SM_ENTRY_MA(WPA_PTK, DISCONNECT, wpa_ptk);
- sm->Disconnect = FALSE;
+ sm->Disconnect = false;
sm->disconnect_reason = 0;
if (!reason)
reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
@@ -1877,7 +1940,7 @@
SM_STATE(WPA_PTK, DISCONNECTED)
{
SM_ENTRY_MA(WPA_PTK, DISCONNECTED, wpa_ptk);
- sm->DeauthenticationRequest = FALSE;
+ sm->DeauthenticationRequest = false;
}
@@ -1885,11 +1948,11 @@
{
SM_ENTRY_MA(WPA_PTK, AUTHENTICATION, wpa_ptk);
os_memset(&sm->PTK, 0, sizeof(sm->PTK));
- sm->PTK_valid = FALSE;
+ sm->PTK_valid = false;
wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portControl_Auto,
1);
wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 1);
- sm->AuthenticationRequest = FALSE;
+ sm->AuthenticationRequest = false;
}
@@ -1905,23 +1968,23 @@
* GMK and Counter here to improve their strength if there was not
* enough entropy available immediately after system startup.
*/
- wpa_printf(MSG_DEBUG, "WPA: Re-initialize GMK/Counter on first "
- "station");
+ wpa_printf(MSG_DEBUG,
+ "WPA: Re-initialize GMK/Counter on first station");
if (random_pool_ready() != 1) {
- wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
- "to proceed - reject first 4-way handshake");
- group->reject_4way_hs_for_entropy = TRUE;
+ wpa_printf(MSG_INFO,
+ "WPA: Not enough entropy in random pool to proceed - reject first 4-way handshake");
+ group->reject_4way_hs_for_entropy = true;
} else {
- group->first_sta_seen = TRUE;
- group->reject_4way_hs_for_entropy = FALSE;
+ group->first_sta_seen = true;
+ group->reject_4way_hs_for_entropy = false;
}
if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0 ||
wpa_gtk_update(wpa_auth, group) < 0 ||
wpa_group_config_group_keys(wpa_auth, group) < 0) {
wpa_printf(MSG_INFO, "WPA: GMK/GTK setup failed");
- group->first_sta_seen = FALSE;
- group->reject_4way_hs_for_entropy = TRUE;
+ group->first_sta_seen = false;
+ group->reject_4way_hs_for_entropy = true;
}
}
@@ -1931,7 +1994,7 @@
SM_ENTRY_MA(WPA_PTK, AUTHENTICATION2, wpa_ptk);
wpa_group_ensure_init(sm->wpa_auth, sm->group);
- sm->ReAuthenticationRequest = FALSE;
+ sm->ReAuthenticationRequest = false;
/*
* Definition of ANonce selection in IEEE Std 802.11i-2004 is somewhat
@@ -1943,9 +2006,9 @@
* stronger protection against potential precomputation attacks.
*/
if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
- wpa_printf(MSG_ERROR, "WPA: Failed to get random data for "
- "ANonce.");
- sm->Disconnect = TRUE;
+ wpa_printf(MSG_ERROR,
+ "WPA: Failed to get random data for ANonce.");
+ sm->Disconnect = true;
return;
}
wpa_hexdump(MSG_DEBUG, "WPA: Assign ANonce", sm->ANonce,
@@ -1963,7 +2026,7 @@
if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
wpa_printf(MSG_ERROR,
"WPA: Failed to get random data for ANonce");
- sm->Disconnect = TRUE;
+ sm->Disconnect = true;
return -1;
}
wpa_hexdump(MSG_DEBUG, "WPA: Assign new ANonce", sm->ANonce,
@@ -1990,7 +2053,7 @@
} else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP) {
wpa_printf(MSG_DEBUG,
"DPP: No PMKSA cache entry for STA - reject connection");
- sm->Disconnect = TRUE;
+ sm->Disconnect = true;
sm->disconnect_reason = WLAN_REASON_INVALID_PMKID;
return;
#endif /* CONFIG_DPP */
@@ -2001,14 +2064,14 @@
pmk_len = PMK_LEN_SUITE_B_192;
else
pmk_len = PMK_LEN;
- wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine "
- "(MSK len=%lu PMK len=%u)", (unsigned long) len,
- pmk_len);
+ wpa_printf(MSG_DEBUG,
+ "WPA: PMK from EAPOL state machine (MSK len=%zu PMK len=%u)",
+ len, pmk_len);
if (len < pmk_len) {
wpa_printf(MSG_DEBUG,
- "WPA: MSK not long enough (%u) to create PMK (%u)",
- (unsigned int) len, (unsigned int) pmk_len);
- sm->Disconnect = TRUE;
+ "WPA: MSK not long enough (%zu) to create PMK (%u)",
+ len, pmk_len);
+ sm->Disconnect = true;
return;
}
os_memcpy(sm->PMK, msk, pmk_len);
@@ -2027,21 +2090,21 @@
} else {
wpa_printf(MSG_DEBUG, "WPA: Could not get PMK, get_msk: %p",
sm->wpa_auth->cb->get_msk);
- sm->Disconnect = TRUE;
+ sm->Disconnect = true;
return;
}
- os_memset(msk, 0, sizeof(msk));
+ forced_memzero(msk, sizeof(msk));
sm->req_replay_counter_used = 0;
- /* IEEE 802.11i does not set keyRun to FALSE, but not doing this
+ /* IEEE 802.11i does not set keyRun to false, but not doing this
* will break reauthentication since EAPOL state machines may not be
* get into AUTHENTICATING state that clears keyRun before WPA state
* machine enters AUTHENTICATION2 state and goes immediately to INITPMK
* state and takes PMK from the previously used AAA Key. This will
* eventually fail in 4-Way Handshake because Supplicant uses PMK
- * derived from the new AAA Key. Setting keyRun = FALSE here seems to
+ * derived from the new AAA Key. Setting keyRun = false here seems to
* be good workaround for this issue. */
- wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyRun, 0);
+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyRun, false);
}
@@ -2082,9 +2145,9 @@
size_t pmkid_len = 0;
SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk);
- sm->PTKRequest = FALSE;
- sm->TimeoutEvt = FALSE;
- sm->alt_snonce_valid = FALSE;
+ sm->PTKRequest = false;
+ sm->TimeoutEvt = false;
+ sm->alt_snonce_valid = false;
sm->TimeoutCtr++;
if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
@@ -2130,6 +2193,28 @@
wpa_printf(MSG_DEBUG,
"RSN: No KCK available to derive PMKID for message 1/4");
pmkid = NULL;
+#ifdef CONFIG_FILS
+ } else if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+ if (sm->pmkid_set) {
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: Message 1/4 PMKID from FILS/ERP",
+ 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 FILS/ERP PMKID available for message 1/4");
+ pmkid = NULL;
+ }
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R_AP
+ } else if (wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
+ sm->ft_completed) {
+ wpa_printf(MSG_DEBUG,
+ "FT: No PMKID in message 1/4 when using FT protocol");
+ pmkid = NULL;
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_SAE
} else if (wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
if (sm->pmkid_set) {
@@ -2158,6 +2243,8 @@
&pmkid[2 + RSN_SELECTOR_LEN], PMKID_LEN);
}
}
+ if (!pmkid)
+ pmkid_len = 0;
wpa_send_eapol(sm->wpa_auth, sm,
WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL,
sm->ANonce, pmkid, pmkid_len, 0, 0);
@@ -2166,14 +2253,27 @@
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
const u8 *pmk, unsigned int pmk_len,
- struct wpa_ptk *ptk)
+ struct wpa_ptk *ptk, int force_sha256)
{
const u8 *z = NULL;
size_t z_len = 0;
+ int akmp;
#ifdef CONFIG_IEEE80211R_AP
- if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
- return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
+ if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
+ if (sm->ft_completed) {
+ u8 ptk_name[WPA_PMK_NAME_LEN];
+
+ return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->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);
+ }
+ return wpa_auth_derive_ptk_ft(sm, ptk);
+ }
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_DPP2
@@ -2183,9 +2283,12 @@
}
#endif /* CONFIG_DPP2 */
+ akmp = sm->wpa_key_mgmt;
+ if (force_sha256)
+ akmp |= WPA_KEY_MGMT_PSK_SHA256;
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, z, z_len);
+ ptk, akmp, sm->pairwise, z, z_len);
}
@@ -2209,8 +2312,8 @@
fils_ft, &fils_ft_len);
if (res < 0)
return res;
- sm->PTK_valid = TRUE;
- sm->tk_already_set = FALSE;
+ sm->PTK_valid = true;
+ sm->tk_already_set = false;
#ifdef CONFIG_IEEE80211R_AP
if (fils_ft_len) {
@@ -2234,12 +2337,12 @@
wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR0Name",
pmk_r0_name, WPA_PMK_NAME_LEN);
wpa_ft_store_pmk_fils(sm, pmk_r0, pmk_r0_name);
- os_memset(fils_ft, 0, sizeof(fils_ft));
+ forced_memzero(fils_ft, 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);
+ forced_memzero(pmk_r0, PMK_LEN_MAX);
if (res < 0)
return -1;
wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR1Name", sm->pmk_r1_name,
@@ -2257,7 +2360,7 @@
sm->wpa_key_mgmt, sm->fils_key_auth_sta,
sm->fils_key_auth_ap,
&sm->fils_key_auth_len);
- os_memset(ick, 0, sizeof(ick));
+ forced_memzero(ick, sizeof(ick));
/* Store nonces for (Re)Association Request/Response frame processing */
os_memcpy(sm->SNonce, snonce, FILS_NONCE_LEN);
@@ -2399,9 +2502,9 @@
if (elems.fils_key_confirm_len != sm->fils_key_auth_len) {
wpa_printf(MSG_DEBUG,
- "FILS: Unexpected Key-Auth length %d (expected %d)",
+ "FILS: Unexpected Key-Auth length %d (expected %zu)",
elems.fils_key_confirm_len,
- (int) sm->fils_key_auth_len);
+ sm->fils_key_auth_len);
return -1;
}
@@ -2559,7 +2662,7 @@
if (pos + wpabuf_len(plain) + AES_BLOCK_SIZE > end) {
wpa_printf(MSG_DEBUG,
"FILS: Not enough room for FILS elements");
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
return -1;
}
@@ -2569,7 +2672,7 @@
if (aes_siv_encrypt(sm->PTK.kek, sm->PTK.kek_len,
wpabuf_head(plain), wpabuf_len(plain),
5, aad, aad_len, pos) < 0) {
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
return -1;
}
@@ -2577,7 +2680,7 @@
"FILS: Encrypted Association Response elements",
pos, AES_BLOCK_SIZE + wpabuf_len(plain));
current_len += wpabuf_len(plain) + AES_BLOCK_SIZE;
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
sm->fils_completed = 1;
@@ -2594,8 +2697,13 @@
u8 *gtk, dummy_gtk[32];
size_t gtk_len;
struct wpa_group *gsm;
+ size_t plain_len;
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
- plain = wpabuf_alloc(1000);
+ plain_len = 1000 + ieee80211w_kde_len(sm);
+ if (conf->transition_disable)
+ plain_len += 2 + RSN_SELECTOR_LEN + 1;
+ plain = wpabuf_alloc(plain_len);
if (!plain)
return NULL;
@@ -2624,14 +2732,13 @@
/* GTK KDE */
gtk = gsm->GTK[gsm->GN - 1];
gtk_len = gsm->GTK_len;
- if (sm->wpa_auth->conf.disable_gtk ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
/*
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
*/
if (random_get_bytes(dummy_gtk, gtk_len) < 0) {
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
return NULL;
}
gtk = dummy_gtk;
@@ -2643,11 +2750,18 @@
gtk, gtk_len);
wpabuf_put(plain, tmp2 - tmp);
- /* IGTK KDE */
+ /* IGTK KDE and BIGTK KDE */
tmp = wpabuf_put(plain, 0);
tmp2 = ieee80211w_kde_add(sm, tmp);
wpabuf_put(plain, tmp2 - tmp);
+ if (conf->transition_disable) {
+ tmp = wpabuf_put(plain, 0);
+ tmp2 = wpa_add_kde(tmp, WFA_KEY_DATA_TRANSITION_DISABLE,
+ &conf->transition_disable, 1, NULL, 0);
+ wpabuf_put(plain, tmp2 - tmp);
+ }
+
*len = (u8 *) wpabuf_put(plain, 0) - len - 1;
#ifdef CONFIG_OCV
@@ -2658,13 +2772,13 @@
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);
+ wpabuf_clear_free(plain);
return NULL;
}
pos = wpabuf_put(plain, OCV_OCI_EXTENDED_LEN);
if (ocv_insert_extended_oci(&ci, pos) < 0) {
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
return NULL;
}
}
@@ -2693,11 +2807,11 @@
wpa_printf(MSG_DEBUG, "FILS: Configure TK to the driver");
if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
- sm->PTK.tk, klen)) {
+ sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX)) {
wpa_printf(MSG_DEBUG, "FILS: Failed to set TK to the driver");
return -1;
}
- sm->tk_already_set = TRUE;
+ sm->tk_already_set = true;
return 0;
}
@@ -2725,9 +2839,9 @@
os_memcpy(pos, wpabuf_head(plain), wpabuf_len(plain));
pos += wpabuf_len(plain);
- wpa_printf(MSG_DEBUG, "%s: plain buf_len: %u", __func__,
- (unsigned int) wpabuf_len(plain));
- wpabuf_free(plain);
+ wpa_printf(MSG_DEBUG, "%s: plain buf_len: %zu", __func__,
+ wpabuf_len(plain));
+ wpabuf_clear_free(plain);
sm->fils_completed = 1;
return pos;
}
@@ -2765,10 +2879,11 @@
struct wpa_eapol_key *key;
struct wpa_eapol_ie_parse kde;
int vlan_id = 0;
+ int owe_ptk_workaround = !!wpa_auth->conf.owe_ptk_workaround;
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
- sm->EAPOLKeyReceived = FALSE;
- sm->update_snonce = FALSE;
+ sm->EAPOLKeyReceived = false;
+ sm->update_snonce = false;
os_memset(&PTK, 0, sizeof(PTK));
mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
@@ -2782,7 +2897,7 @@
pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
sm->p2p_dev_addr, pmk, &pmk_len,
&vlan_id);
- if (pmk == NULL)
+ if (!pmk)
break;
psk_found = 1;
#ifdef CONFIG_IEEE80211R_AP
@@ -2796,7 +2911,14 @@
pmk_len = sm->pmk_len;
}
- if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK) < 0)
+ if ((!pmk || !pmk_len) && sm->pmksa) {
+ wpa_printf(MSG_DEBUG, "WPA: Use PMK from PMKSA cache");
+ pmk = sm->pmksa->pmk;
+ pmk_len = sm->pmksa->pmk_len;
+ }
+
+ if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK,
+ owe_ptk_workaround == 2) < 0)
break;
if (mic_len &&
@@ -2820,6 +2942,16 @@
}
#endif /* CONFIG_FILS */
+#ifdef CONFIG_OWE
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && pmk_len > 32 &&
+ owe_ptk_workaround == 1) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: Try PTK derivation workaround with SHA256");
+ owe_ptk_workaround = 2;
+ continue;
+ }
+#endif /* CONFIG_OWE */
+
if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
wpa_key_mgmt_sae(sm->wpa_key_mgmt))
break;
@@ -2862,7 +2994,7 @@
eapol_key_ie_len = kde.wpa_ie_len;
}
ft = sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt);
- if (sm->wpa_ie == NULL ||
+ if (!sm->wpa_ie ||
wpa_compare_rsn_ie(ft, sm->wpa_ie, sm->wpa_ie_len,
eapol_key_ie, eapol_key_ie_len)) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -2878,6 +3010,22 @@
WLAN_REASON_PREV_AUTH_NOT_VALID);
return;
}
+ if ((!sm->rsnxe && kde.rsnxe) ||
+ (sm->rsnxe && !kde.rsnxe) ||
+ (sm->rsnxe && kde.rsnxe &&
+ (sm->rsnxe_len != kde.rsnxe_len ||
+ os_memcmp(sm->rsnxe, kde.rsnxe, sm->rsnxe_len) != 0))) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "RSNXE from (Re)AssocReq did not match the one in EAPOL-Key msg 2/4");
+ wpa_hexdump(MSG_DEBUG, "RSNXE in AssocReq",
+ sm->rsnxe, sm->rsnxe_len);
+ wpa_hexdump(MSG_DEBUG, "RSNXE in EAPOL-Key msg 2/4",
+ kde.rsnxe, kde.rsnxe_len);
+ /* MLME-DEAUTHENTICATE.request */
+ wpa_sta_disconnect(wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ return;
+ }
#ifdef CONFIG_OCV
if (wpa_auth_uses_ocv(sm)) {
struct wpa_channel_info ci;
@@ -2940,10 +3088,9 @@
if (os_memcmp_const(sm->sup_pmk_r1_name, sm->pmk_r1_name,
WPA_PMK_NAME_LEN) != 0) {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "PMKR1Name mismatch in FT 4-way "
- "handshake");
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from "
- "Supplicant",
+ "PMKR1Name mismatch in FT 4-way handshake");
+ wpa_hexdump(MSG_DEBUG,
+ "FT: PMKR1Name from Supplicant",
sm->sup_pmk_r1_name, WPA_PMK_NAME_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name",
sm->pmk_r1_name, WPA_PMK_NAME_LEN);
@@ -2970,10 +3117,11 @@
sm->pmk_len = PMK_LEN;
}
- sm->MICVerified = TRUE;
+ sm->MICVerified = true;
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
- sm->PTK_valid = TRUE;
+ forced_memzero(&PTK, sizeof(PTK));
+ sm->PTK_valid = true;
}
@@ -2984,26 +3132,31 @@
}
-#ifdef CONFIG_IEEE80211W
-
static int ieee80211w_kde_len(struct wpa_state_machine *sm)
{
+ size_t len = 0;
+
if (sm->mgmt_frame_prot) {
- size_t len;
- len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
- return 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN + len;
+ len += 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN;
+ len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+ }
+ if (sm->mgmt_frame_prot && sm->wpa_auth->conf.beacon_prot) {
+ len += 2 + RSN_SELECTOR_LEN + WPA_BIGTK_KDE_PREFIX_LEN;
+ len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
}
- return 0;
+ return len;
}
static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
{
struct wpa_igtk_kde igtk;
+ struct wpa_bigtk_kde bigtk;
struct wpa_group *gsm = sm->group;
u8 rsc[WPA_KEY_RSC_LEN];
- size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
+ size_t len = wpa_cipher_key_len(conf->group_mgmt_cipher);
if (!sm->mgmt_frame_prot)
return pos;
@@ -3016,8 +3169,7 @@
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 ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
/*
* Provide unique random IGTK to each STA to prevent use of
* IGTK in the BSS.
@@ -3029,24 +3181,24 @@
(const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len,
NULL, 0);
+ if (!conf->beacon_prot)
+ return pos;
+
+ bigtk.keyid[0] = gsm->GN_bigtk;
+ bigtk.keyid[1] = 0;
+ if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
+ wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, rsc) < 0)
+ os_memset(bigtk.pn, 0, sizeof(bigtk.pn));
+ else
+ os_memcpy(bigtk.pn, rsc, sizeof(bigtk.pn));
+ os_memcpy(bigtk.bigtk, gsm->BIGTK[gsm->GN_bigtk - 6], len);
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_BIGTK,
+ (const u8 *) &bigtk, WPA_BIGTK_KDE_PREFIX_LEN + len,
+ NULL, 0);
+
return pos;
}
-#else /* CONFIG_IEEE80211W */
-
-static int ieee80211w_kde_len(struct wpa_state_machine *sm)
-{
- return 0;
-}
-
-
-static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
-{
- return pos;
-}
-
-#endif /* CONFIG_IEEE80211W */
-
static int ocv_oci_len(struct wpa_state_machine *sm)
{
@@ -3078,64 +3230,129 @@
}
+#ifdef CONFIG_TESTING_OPTIONS
+static u8 * replace_ie(const char *name, const u8 *old_buf, size_t *len, u8 eid,
+ const u8 *ie, size_t ie_len)
+{
+ const u8 *elem;
+ u8 *buf;
+
+ wpa_printf(MSG_DEBUG, "TESTING: %s EAPOL override", name);
+ wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie before override",
+ old_buf, *len);
+ buf = os_malloc(*len + ie_len);
+ if (!buf)
+ return NULL;
+ os_memcpy(buf, old_buf, *len);
+ elem = get_ie(buf, *len, eid);
+ if (elem) {
+ u8 elem_len = 2 + elem[1];
+
+ os_memmove((void *) elem, elem + elem_len,
+ *len - (elem - buf) - elem_len);
+ *len -= elem_len;
+ }
+ os_memcpy(buf + *len, ie, ie_len);
+ *len += ie_len;
+ wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie after EAPOL override",
+ buf, *len);
+
+ return buf;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
{
- u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32];
- size_t gtk_len, kde_len;
+ u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde = NULL, *pos, dummy_gtk[32];
+ size_t gtk_len, kde_len, wpa_ie_len;
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
- int wpa_ie_len, secure, keyidx, encr = 0;
+ int secure, gtkidx, encr = 0;
+ u8 *wpa_ie_buf = NULL, *wpa_ie_buf2 = NULL;
+ u8 hdr[2];
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk);
- sm->TimeoutEvt = FALSE;
+ sm->TimeoutEvt = false;
sm->TimeoutCtr++;
- if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
- sm->TimeoutCtr > 1) {
+ if (conf->wpa_disable_eapol_key_retries && sm->TimeoutCtr > 1) {
/* Do not allow retransmission of EAPOL-Key msg 3/4 */
return;
}
- if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
+ if (sm->TimeoutCtr > conf->wpa_pairwise_update_count) {
/* No point in sending the EAPOL-Key - we will disconnect
* immediately following this. */
return;
}
/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
- GTK[GN], IGTK, [FTIE], [TIE * 2])
+ GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
*/
os_memset(rsc, 0, WPA_KEY_RSC_LEN);
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
/* If FT is used, wpa_auth->wpa_ie includes both RSNIE and MDIE */
wpa_ie = sm->wpa_auth->wpa_ie;
wpa_ie_len = sm->wpa_auth->wpa_ie_len;
- if (sm->wpa == WPA_VERSION_WPA &&
- (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
- wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
+ if (sm->wpa == WPA_VERSION_WPA && (conf->wpa & WPA_PROTO_RSN) &&
+ wpa_ie_len > wpa_ie[1] + 2U && wpa_ie[0] == WLAN_EID_RSN) {
/* WPA-only STA, remove RSN IE and possible MDIE */
wpa_ie = wpa_ie + wpa_ie[1] + 2;
if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN)
wpa_ie = wpa_ie + wpa_ie[1] + 2;
wpa_ie_len = wpa_ie[1] + 2;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conf->rsne_override_eapol_set) {
+ wpa_ie_buf2 = replace_ie(
+ "RSNE", wpa_ie, &wpa_ie_len, WLAN_EID_RSN,
+ conf->rsne_override_eapol,
+ conf->rsne_override_eapol_len);
+ if (!wpa_ie_buf2)
+ goto done;
+ wpa_ie = wpa_ie_buf2;
+ }
+ if (conf->rsnxe_override_eapol_set) {
+ wpa_ie_buf = replace_ie(
+ "RSNXE", wpa_ie, &wpa_ie_len, WLAN_EID_RSNX,
+ conf->rsnxe_override_eapol,
+ conf->rsnxe_override_eapol_len);
+ if (!wpa_ie_buf)
+ goto done;
+ wpa_ie = wpa_ie_buf;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"sending 3/4 msg of 4-Way Handshake");
if (sm->wpa == WPA_VERSION_WPA2) {
+ if (sm->use_ext_key_id && sm->TimeoutCtr == 1 &&
+ wpa_auth_set_key(sm->wpa_auth, 0,
+ wpa_cipher_to_alg(sm->pairwise),
+ sm->addr,
+ sm->keyidx_active, sm->PTK.tk,
+ wpa_cipher_key_len(sm->pairwise),
+ KEY_FLAG_PAIRWISE_RX)) {
+ wpa_sta_disconnect(sm->wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ return;
+ }
+
/* WPA2 send GTK in the 4-way handshake */
secure = 1;
gtk = gsm->GTK[gsm->GN - 1];
gtk_len = gsm->GTK_len;
- if (sm->wpa_auth->conf.disable_gtk ||
+ if (conf->disable_gtk ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
/*
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
*/
if (random_get_bytes(dummy_gtk, gtk_len) < 0)
- return;
+ goto done;
gtk = dummy_gtk;
}
- keyidx = gsm->GN;
+ gtkidx = gsm->GN;
_rsc = rsc;
encr = 1;
} else {
@@ -3143,7 +3360,6 @@
secure = 0;
gtk = NULL;
gtk_len = 0;
- keyidx = 0;
_rsc = NULL;
if (sm->rx_eapol_key_secure) {
/*
@@ -3155,13 +3371,16 @@
* WPA if the supplicant used it first.
*/
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "STA used Secure bit in WPA msg 2/4 - "
- "set Secure for 3/4 as workaround");
+ "STA used Secure bit in WPA msg 2/4 - set Secure for 3/4 as workaround");
secure = 1;
}
}
kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
+
+ if (sm->use_ext_key_id)
+ kde_len += 2 + RSN_SELECTOR_LEN + 2;
+
if (gtk)
kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
#ifdef CONFIG_IEEE80211R_AP
@@ -3174,9 +3393,13 @@
if (WPA_GET_BE32(sm->ip_addr) > 0)
kde_len += 2 + RSN_SELECTOR_LEN + 3 * 4;
#endif /* CONFIG_P2P */
+
+ if (conf->transition_disable)
+ kde_len += 2 + RSN_SELECTOR_LEN + 1;
+
kde = os_malloc(kde_len);
- if (kde == NULL)
- return;
+ if (!kde)
+ goto done;
pos = kde;
os_memcpy(pos, wpa_ie, wpa_ie_len);
@@ -3189,34 +3412,34 @@
elen = pos - kde;
res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name);
if (res < 0) {
- wpa_printf(MSG_ERROR, "FT: Failed to insert "
- "PMKR1Name into RSN IE in EAPOL-Key data");
- os_free(kde);
- return;
+ wpa_printf(MSG_ERROR,
+ "FT: Failed to insert PMKR1Name into RSN IE in EAPOL-Key data");
+ goto done;
}
pos -= wpa_ie_len;
pos += elen;
}
#endif /* CONFIG_IEEE80211R_AP */
+ hdr[1] = 0;
+
+ if (sm->use_ext_key_id) {
+ hdr[0] = sm->keyidx_active & 0x01;
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0);
+ }
+
if (gtk) {
- u8 hdr[2];
- hdr[0] = keyidx & 0x03;
- hdr[1] = 0;
+ hdr[0] = gtkidx & 0x03;
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gtk_len);
}
pos = ieee80211w_kde_add(sm, pos);
- if (ocv_oci_add(sm, &pos) < 0) {
- os_free(kde);
- return;
- }
+ if (ocv_oci_add(sm, &pos) < 0)
+ goto done;
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
int res;
- struct wpa_auth_config *conf;
- conf = &sm->wpa_auth->conf;
if (sm->assoc_resp_ftie &&
kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) {
os_memcpy(pos, sm->assoc_resp_ftie,
@@ -3230,13 +3453,12 @@
conf->r0_key_holder_len,
NULL, NULL, pos,
kde + kde_len - pos,
- NULL, 0);
+ NULL, 0, 0);
}
if (res < 0) {
- wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
- "into EAPOL-Key Key Data");
- os_free(kde);
- return;
+ wpa_printf(MSG_ERROR,
+ "FT: Failed to insert FTIE into EAPOL-Key Key Data");
+ goto done;
}
pos += res;
@@ -3259,46 +3481,57 @@
if (WPA_GET_BE32(sm->ip_addr) > 0) {
u8 addr[3 * 4];
os_memcpy(addr, sm->ip_addr, 4);
- os_memcpy(addr + 4, sm->wpa_auth->conf.ip_addr_mask, 4);
- os_memcpy(addr + 8, sm->wpa_auth->conf.ip_addr_go, 4);
+ os_memcpy(addr + 4, conf->ip_addr_mask, 4);
+ os_memcpy(addr + 8, conf->ip_addr_go, 4);
pos = wpa_add_kde(pos, WFA_KEY_DATA_IP_ADDR_ALLOC,
addr, sizeof(addr), NULL, 0);
}
#endif /* CONFIG_P2P */
+ if (conf->transition_disable)
+ pos = wpa_add_kde(pos, WFA_KEY_DATA_TRANSITION_DISABLE,
+ &conf->transition_disable, 1, NULL, 0);
+
wpa_send_eapol(sm->wpa_auth, sm,
(secure ? WPA_KEY_INFO_SECURE : 0) |
(wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ?
WPA_KEY_INFO_MIC : 0) |
WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
WPA_KEY_INFO_KEY_TYPE,
- _rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
+ _rsc, sm->ANonce, kde, pos - kde, 0, encr);
+done:
os_free(kde);
+ os_free(wpa_ie_buf);
+ os_free(wpa_ie_buf2);
}
SM_STATE(WPA_PTK, PTKINITDONE)
{
SM_ENTRY_MA(WPA_PTK, PTKINITDONE, wpa_ptk);
- sm->EAPOLKeyReceived = FALSE;
+ sm->EAPOLKeyReceived = false;
if (sm->Pair) {
enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise);
int klen = wpa_cipher_key_len(sm->pairwise);
- if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
- sm->PTK.tk, klen)) {
+ int res;
+
+ if (sm->use_ext_key_id)
+ res = wpa_auth_set_key(sm->wpa_auth, 0, 0, sm->addr,
+ sm->keyidx_active, NULL, 0,
+ KEY_FLAG_PAIRWISE_RX_TX_MODIFY);
+ else
+ res = wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr,
+ 0, sm->PTK.tk, klen,
+ KEY_FLAG_PAIRWISE_RX_TX);
+ if (res) {
wpa_sta_disconnect(sm->wpa_auth, sm->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
return;
}
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
- sm->pairwise_set = TRUE;
+ sm->pairwise_set = true;
- if (sm->wpa_auth->conf.wpa_ptk_rekey) {
- eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
- eloop_register_timeout(sm->wpa_auth->conf.
- wpa_ptk_rekey, 0, wpa_rekey_ptk,
- sm->wpa_auth, sm);
- }
+ wpa_auth_set_ptk_rekey_timer(sm);
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
@@ -3318,12 +3551,13 @@
wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid,
1);
}
- wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyAvailable, 0);
- wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyDone, 1);
+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyAvailable,
+ false);
+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyDone, true);
if (sm->wpa == WPA_VERSION_WPA)
- sm->PInitAKeys = TRUE;
+ sm->PInitAKeys = true;
else
- sm->has_GTK = TRUE;
+ sm->has_GTK = true;
wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
"pairwise key handshake completed (%s)",
sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
@@ -3337,6 +3571,7 @@
SM_STEP(WPA_PTK)
{
struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+ struct wpa_auth_config *conf = &wpa_auth->conf;
if (sm->Init)
SM_ENTER(WPA_PTK, INITIALIZE);
@@ -3371,8 +3606,8 @@
break;
case WPA_PTK_AUTHENTICATION2:
if (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
- wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
- WPA_EAPOL_keyRun) > 0)
+ wpa_auth_get_eapol(wpa_auth, sm->addr,
+ WPA_EAPOL_keyRun))
SM_ENTER(WPA_PTK, INITPMK);
else if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE
@@ -3382,8 +3617,8 @@
SM_ENTER(WPA_PTK, INITPMK);
break;
case WPA_PTK_INITPMK:
- if (wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
- WPA_EAPOL_keyAvailable) > 0) {
+ if (wpa_auth_get_eapol(wpa_auth, sm->addr,
+ WPA_EAPOL_keyAvailable)) {
SM_ENTER(WPA_PTK, PTKSTART);
#ifdef CONFIG_DPP
} else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && sm->pmksa) {
@@ -3391,13 +3626,13 @@
#endif /* CONFIG_DPP */
} else {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"INITPMK - keyAvailable = false");
SM_ENTER(WPA_PTK, DISCONNECT);
}
break;
case WPA_PTK_INITPSK:
- if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr,
+ if (wpa_auth_get_psk(wpa_auth, sm->addr, sm->p2p_dev_addr,
NULL, NULL, NULL)) {
SM_ENTER(WPA_PTK, PTKSTART);
#ifdef CONFIG_SAE
@@ -3405,7 +3640,7 @@
SM_ENTER(WPA_PTK, PTKSTART);
#endif /* CONFIG_SAE */
} else {
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"no PSK configured for the STA");
wpa_auth->dot11RSNA4WayHandshakeFailures++;
SM_ENTER(WPA_PTK, DISCONNECT);
@@ -3415,13 +3650,13 @@
if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
sm->EAPOLKeyPairwise)
SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
- else if (sm->TimeoutCtr >
- sm->wpa_auth->conf.wpa_pairwise_update_count) {
+ else if (sm->TimeoutCtr > conf->wpa_pairwise_update_count) {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
- wpa_auth_vlogger(
- sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "PTKSTART: Retry limit %u reached",
- sm->wpa_auth->conf.wpa_pairwise_update_count);
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "PTKSTART: Retry limit %u reached",
+ conf->wpa_pairwise_update_count);
+ sm->disconnect_reason =
+ WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT;
SM_ENTER(WPA_PTK, DISCONNECT);
} else if (sm->TimeoutEvt)
SM_ENTER(WPA_PTK, PTKSTART);
@@ -3445,14 +3680,15 @@
sm->EAPOLKeyPairwise && sm->MICVerified)
SM_ENTER(WPA_PTK, PTKINITDONE);
else if (sm->TimeoutCtr >
- sm->wpa_auth->conf.wpa_pairwise_update_count ||
- (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
+ conf->wpa_pairwise_update_count ||
+ (conf->wpa_disable_eapol_key_retries &&
sm->TimeoutCtr > 1)) {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
- wpa_auth_vlogger(
- sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "PTKINITNEGOTIATING: Retry limit %u reached",
- sm->wpa_auth->conf.wpa_pairwise_update_count);
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "PTKINITNEGOTIATING: Retry limit %u reached",
+ conf->wpa_pairwise_update_count);
+ sm->disconnect_reason =
+ WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT;
SM_ENTER(WPA_PTK, DISCONNECT);
} else if (sm->TimeoutEvt)
SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
@@ -3469,7 +3705,7 @@
if (sm->Init) {
/* Init flag is not cleared here, so avoid busy
* loop by claiming nothing changed. */
- sm->changed = FALSE;
+ sm->changed = false;
}
sm->GTimeoutCtr = 0;
}
@@ -3483,24 +3719,24 @@
u8 *kde_buf = NULL, *pos, hdr[2];
size_t kde_len;
u8 *gtk, dummy_gtk[32];
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
sm->GTimeoutCtr++;
- if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
- sm->GTimeoutCtr > 1) {
+ if (conf->wpa_disable_eapol_key_retries && sm->GTimeoutCtr > 1) {
/* Do not allow retransmission of EAPOL-Key group msg 1/2 */
return;
}
- if (sm->GTimeoutCtr > sm->wpa_auth->conf.wpa_group_update_count) {
+ if (sm->GTimeoutCtr > conf->wpa_group_update_count) {
/* No point in sending the EAPOL-Key - we will disconnect
* immediately following this. */
return;
}
if (sm->wpa == WPA_VERSION_WPA)
- sm->PInitAKeys = FALSE;
- sm->TimeoutEvt = FALSE;
+ sm->PInitAKeys = false;
+ sm->TimeoutEvt = false;
/* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */
os_memset(rsc, 0, WPA_KEY_RSC_LEN);
if (gsm->wpa_group_state == WPA_GROUP_SETKEYSDONE)
@@ -3509,8 +3745,7 @@
"sending 1/2 msg of Group Key Handshake");
gtk = gsm->GTK[gsm->GN - 1];
- if (sm->wpa_auth->conf.disable_gtk ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
/*
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
@@ -3523,7 +3758,7 @@
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
ieee80211w_kde_len(sm) + ocv_oci_len(sm);
kde_buf = os_malloc(kde_len);
- if (kde_buf == NULL)
+ if (!kde_buf)
return;
kde = pos = kde_buf;
@@ -3556,8 +3791,8 @@
SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
{
-#ifdef CONFIG_OCV
struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+#ifdef CONFIG_OCV
const u8 *key_data, *mic;
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
@@ -3567,7 +3802,7 @@
#endif /* CONFIG_OCV */
SM_ENTRY_MA(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group);
- sm->EAPOLKeyReceived = FALSE;
+ sm->EAPOLKeyReceived = false;
#ifdef CONFIG_OCV
mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
@@ -3619,13 +3854,13 @@
if (sm->GUpdateStationKeys)
sm->group->GKeyDoneStations--;
- sm->GUpdateStationKeys = FALSE;
+ sm->GUpdateStationKeys = false;
sm->GTimeoutCtr = 0;
/* FIX: MLME.SetProtection.Request(TA, Tx_Rx) */
- wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
"group key handshake completed (%s)",
sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
- sm->has_GTK = TRUE;
+ sm->has_GTK = true;
}
@@ -3634,8 +3869,9 @@
SM_ENTRY_MA(WPA_PTK_GROUP, KEYERROR, wpa_ptk_group);
if (sm->GUpdateStationKeys)
sm->group->GKeyDoneStations--;
- sm->GUpdateStationKeys = FALSE;
- sm->Disconnect = TRUE;
+ sm->GUpdateStationKeys = false;
+ sm->Disconnect = true;
+ sm->disconnect_reason = WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT;
wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
"group key handshake failed (%s) after %u tries",
sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN",
@@ -3647,7 +3883,7 @@
{
if (sm->Init || sm->PtkGroupInit) {
SM_ENTER(WPA_PTK_GROUP, IDLE);
- sm->PtkGroupInit = FALSE;
+ sm->PtkGroupInit = false;
} else switch (sm->wpa_ptk_group_state) {
case WPA_PTK_GROUP_IDLE:
if (sm->GUpdateStationKeys ||
@@ -3679,7 +3915,9 @@
static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
+ struct wpa_auth_config *conf = &wpa_auth->conf;
int ret = 0;
+ size_t len;
os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
inc_byte_array(group->Counter, WPA_NONCE_LEN);
@@ -3690,10 +3928,8 @@
wpa_hexdump_key(MSG_DEBUG, "GTK",
group->GTK[group->GN - 1], group->GTK_len);
-#ifdef CONFIG_IEEE80211W
- if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
- size_t len;
- len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ len = wpa_cipher_key_len(conf->group_mgmt_cipher);
os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
inc_byte_array(group->Counter, WPA_NONCE_LEN);
if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion",
@@ -3703,7 +3939,19 @@
wpa_hexdump_key(MSG_DEBUG, "IGTK",
group->IGTK[group->GN_igtk - 4], len);
}
-#endif /* CONFIG_IEEE80211W */
+
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION &&
+ conf->beacon_prot) {
+ len = wpa_cipher_key_len(conf->group_mgmt_cipher);
+ os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
+ inc_byte_array(group->Counter, WPA_NONCE_LEN);
+ if (wpa_gmk_to_gtk(group->GMK, "BIGTK key expansion",
+ wpa_auth->addr, group->GNonce,
+ group->BIGTK[group->GN_bigtk - 6], len) < 0)
+ ret = -1;
+ wpa_hexdump_key(MSG_DEBUG, "BIGTK",
+ group->BIGTK[group->GN_bigtk - 6], len);
+ }
return ret;
}
@@ -3712,19 +3960,20 @@
static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
- wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
- "GTK_INIT (VLAN-ID %d)", group->vlan_id);
- group->changed = FALSE; /* GInit is not cleared here; avoid loop */
+ wpa_printf(MSG_DEBUG,
+ "WPA: group state machine entering state GTK_INIT (VLAN-ID %d)",
+ group->vlan_id);
+ group->changed = false; /* GInit is not cleared here; avoid loop */
group->wpa_group_state = WPA_GROUP_GTK_INIT;
/* GTK[0..N] = 0 */
os_memset(group->GTK, 0, sizeof(group->GTK));
group->GN = 1;
group->GM = 2;
-#ifdef CONFIG_IEEE80211W
group->GN_igtk = 4;
group->GM_igtk = 5;
-#endif /* CONFIG_IEEE80211W */
+ group->GN_bigtk = 6;
+ group->GM_bigtk = 7;
/* GTK[GN] = CalcGTK() */
wpa_gtk_update(wpa_auth, group);
}
@@ -3738,7 +3987,7 @@
if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"Not in PTKINITDONE; skip Group Key update");
- sm->GUpdateStationKeys = FALSE;
+ sm->GUpdateStationKeys = false;
return 0;
}
if (sm->GUpdateStationKeys) {
@@ -3748,8 +3997,7 @@
* station needs to be counted here anyway.
*/
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "GUpdateStationKeys was already set when "
- "marking station for GTK rekeying");
+ "GUpdateStationKeys was already set when marking station for GTK rekeying");
}
/* Do not rekey GTK/IGTK when STA is in WNM-Sleep Mode */
@@ -3757,7 +4005,7 @@
return 0;
sm->group->GKeyDoneStations++;
- sm->GUpdateStationKeys = TRUE;
+ sm->GUpdateStationKeys = true;
wpa_sm_step(sm);
return 0;
@@ -3768,7 +4016,7 @@
/* update GTK when exiting WNM-Sleep Mode */
void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
{
- if (sm == NULL || sm->is_wnmsleep)
+ if (!sm || sm->is_wnmsleep)
return;
wpa_group_update_sta(sm, NULL);
@@ -3813,7 +4061,6 @@
}
-#ifdef CONFIG_IEEE80211W
int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
{
struct wpa_group *gsm = sm->group;
@@ -3842,7 +4089,37 @@
return pos - start;
}
-#endif /* CONFIG_IEEE80211W */
+
+
+int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos)
+{
+ struct wpa_group *gsm = sm->group;
+ u8 *start = pos;
+ size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+
+ /*
+ * BIGTK subelement:
+ * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
+ */
+ *pos++ = WNM_SLEEP_SUBELEM_BIGTK;
+ *pos++ = 2 + 6 + len;
+ WPA_PUT_LE16(pos, gsm->GN_bigtk);
+ pos += 2;
+ if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos) != 0)
+ return 0;
+ pos += 6;
+
+ os_memcpy(pos, gsm->BIGTK[gsm->GN_bigtk - 6], len);
+ pos += len;
+
+ wpa_printf(MSG_DEBUG, "WNM: BIGTK Key ID %u in WNM-Sleep Mode exit",
+ gsm->GN_bigtk);
+ wpa_hexdump_key(MSG_DEBUG, "WNM: BIGTK in WNM-Sleep Mode exit",
+ gsm->IGTK[gsm->GN_bigtk - 6], len);
+
+ return pos - start;
+}
+
#endif /* CONFIG_WNM_AP */
@@ -3851,27 +4128,29 @@
{
int tmp;
- wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
- "SETKEYS (VLAN-ID %d)", group->vlan_id);
- group->changed = TRUE;
+ wpa_printf(MSG_DEBUG,
+ "WPA: group state machine entering state SETKEYS (VLAN-ID %d)",
+ group->vlan_id);
+ group->changed = true;
group->wpa_group_state = WPA_GROUP_SETKEYS;
- group->GTKReKey = FALSE;
+ group->GTKReKey = false;
tmp = group->GM;
group->GM = group->GN;
group->GN = tmp;
-#ifdef CONFIG_IEEE80211W
tmp = group->GM_igtk;
group->GM_igtk = group->GN_igtk;
group->GN_igtk = tmp;
-#endif /* CONFIG_IEEE80211W */
+ tmp = group->GM_bigtk;
+ group->GM_bigtk = group->GN_bigtk;
+ group->GN_bigtk = tmp;
/* "GKeyDoneStations = GNoStations" is done in more robust way by
* counting the STAs that are marked with GUpdateStationKeys instead of
* including all STAs that could be in not-yet-completed state. */
wpa_gtk_update(wpa_auth, group);
if (group->GKeyDoneStations) {
- wpa_printf(MSG_DEBUG, "wpa_group_setkeys: Unexpected "
- "GKeyDoneStations=%d when starting new GTK rekey",
+ wpa_printf(MSG_DEBUG,
+ "wpa_group_setkeys: Unexpected GKeyDoneStations=%d when starting new GTK rekey",
group->GKeyDoneStations);
group->GKeyDoneStations = 0;
}
@@ -3884,29 +4163,37 @@
static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
+ struct wpa_auth_config *conf = &wpa_auth->conf;
int ret = 0;
if (wpa_auth_set_key(wpa_auth, group->vlan_id,
- wpa_cipher_to_alg(wpa_auth->conf.wpa_group),
+ wpa_cipher_to_alg(conf->wpa_group),
broadcast_ether_addr, group->GN,
- group->GTK[group->GN - 1], group->GTK_len) < 0)
+ group->GTK[group->GN - 1], group->GTK_len,
+ KEY_FLAG_GROUP_TX_DEFAULT) < 0)
ret = -1;
-#ifdef CONFIG_IEEE80211W
- if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
enum wpa_alg alg;
size_t len;
- alg = wpa_cipher_to_alg(wpa_auth->conf.group_mgmt_cipher);
- len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
+ alg = wpa_cipher_to_alg(conf->group_mgmt_cipher);
+ len = wpa_cipher_key_len(conf->group_mgmt_cipher);
if (ret == 0 &&
wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
broadcast_ether_addr, group->GN_igtk,
- group->IGTK[group->GN_igtk - 4], len) < 0)
+ group->IGTK[group->GN_igtk - 4], len,
+ KEY_FLAG_GROUP_TX_DEFAULT) < 0)
+ ret = -1;
+
+ if (ret == 0 && conf->beacon_prot &&
+ wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
+ broadcast_ether_addr, group->GN_bigtk,
+ group->BIGTK[group->GN_bigtk - 6], len,
+ KEY_FLAG_GROUP_TX_DEFAULT) < 0)
ret = -1;
}
-#endif /* CONFIG_IEEE80211W */
return ret;
}
@@ -3916,9 +4203,9 @@
{
if (sm->group == ctx) {
wpa_printf(MSG_DEBUG, "WPA: Mark STA " MACSTR
- " for discconnection due to fatal failure",
+ " for disconnection due to fatal failure",
MAC2STR(sm->addr));
- sm->Disconnect = TRUE;
+ sm->Disconnect = true;
}
return 0;
@@ -3928,8 +4215,9 @@
static void wpa_group_fatal_failure(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
- wpa_printf(MSG_DEBUG, "WPA: group state machine entering state FATAL_FAILURE");
- group->changed = TRUE;
+ wpa_printf(MSG_DEBUG,
+ "WPA: group state machine entering state FATAL_FAILURE");
+ group->changed = true;
group->wpa_group_state = WPA_GROUP_FATAL_FAILURE;
wpa_auth_for_each_sta(wpa_auth, wpa_group_disconnect_cb, group);
}
@@ -3938,9 +4226,10 @@
static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
- wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
- "SETKEYSDONE (VLAN-ID %d)", group->vlan_id);
- group->changed = TRUE;
+ wpa_printf(MSG_DEBUG,
+ "WPA: group state machine entering state SETKEYSDONE (VLAN-ID %d)",
+ group->vlan_id);
+ group->changed = true;
group->wpa_group_state = WPA_GROUP_SETKEYSDONE;
if (wpa_group_config_group_keys(wpa_auth, group) < 0) {
@@ -3976,7 +4265,7 @@
static int wpa_sm_step(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return 0;
if (sm->in_step_loop) {
@@ -3992,8 +4281,8 @@
if (sm->pending_deinit)
break;
- sm->changed = FALSE;
- sm->wpa_auth->group->changed = FALSE;
+ sm->changed = false;
+ sm->wpa_auth->group->changed = false;
SM_STEP_RUN(WPA_PTK);
if (sm->pending_deinit)
@@ -4006,8 +4295,9 @@
sm->in_step_loop = 0;
if (sm->pending_deinit) {
- wpa_printf(MSG_DEBUG, "WPA: Completing pending STA state "
- "machine deinit for " MACSTR, MAC2STR(sm->addr));
+ wpa_printf(MSG_DEBUG,
+ "WPA: Completing pending STA state machine deinit for "
+ MACSTR, MAC2STR(sm->addr));
wpa_free_sta_sm(sm);
return 1;
}
@@ -4024,7 +4314,7 @@
void wpa_auth_sm_notify(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return;
eloop_register_timeout(0, 0, wpa_sm_call_step, sm, NULL);
}
@@ -4035,7 +4325,7 @@
int tmp, i;
struct wpa_group *group;
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return;
group = wpa_auth->group;
@@ -4044,11 +4334,12 @@
tmp = group->GM;
group->GM = group->GN;
group->GN = tmp;
-#ifdef CONFIG_IEEE80211W
tmp = group->GM_igtk;
group->GM_igtk = group->GN_igtk;
group->GN_igtk = tmp;
-#endif /* CONFIG_IEEE80211W */
+ tmp = group->GM_bigtk;
+ group->GM_bigtk = group->GN_bigtk;
+ group->GN_bigtk = tmp;
wpa_gtk_update(wpa_auth, group);
wpa_group_config_group_keys(wpa_auth, group);
}
@@ -4067,6 +4358,7 @@
int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
{
+ struct wpa_auth_config *conf;
int len = 0, ret;
char pmkid_txt[PMKID_LEN * 2 + 1];
#ifdef CONFIG_RSN_PREAUTH
@@ -4075,8 +4367,9 @@
const int preauth = 0;
#endif /* CONFIG_RSN_PREAUTH */
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return len;
+ conf = &wpa_auth->conf;
ret = os_snprintf(buf + len, buflen - len,
"dot11RSNAOptionImplemented=TRUE\n"
@@ -4084,8 +4377,8 @@
"dot11RSNAEnabled=%s\n"
"dot11RSNAPreauthenticationEnabled=%s\n",
wpa_bool_txt(preauth),
- wpa_bool_txt(wpa_auth->conf.wpa & WPA_PROTO_RSN),
- wpa_bool_txt(wpa_auth->conf.rsn_preauth));
+ wpa_bool_txt(conf->wpa & WPA_PROTO_RSN),
+ wpa_bool_txt(conf->rsn_preauth));
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -4120,10 +4413,10 @@
"dot11RSNA4WayHandshakeFailures=%u\n"
"dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n",
RSN_VERSION,
- !!wpa_auth->conf.wpa_strict_rekey,
- wpa_auth->conf.wpa_group_update_count,
- wpa_auth->conf.wpa_pairwise_update_count,
- wpa_cipher_key_len(wpa_auth->conf.wpa_group) * 8,
+ !!conf->wpa_strict_rekey,
+ conf->wpa_group_update_count,
+ conf->wpa_pairwise_update_count,
+ wpa_cipher_key_len(conf->wpa_group) * 8,
dot11RSNAConfigPMKLifetime,
dot11RSNAConfigPMKReauthThreshold,
dot11RSNAConfigSATimeout,
@@ -4159,7 +4452,7 @@
int len = 0, ret;
u32 pairwise = 0;
- if (sm == NULL)
+ if (!sm)
return 0;
/* TODO: FF-FF-FF-FF-FF-FF entry for broadcast/multicast stats */
@@ -4194,8 +4487,12 @@
/* Private MIB */
ret = os_snprintf(buf + len, buflen - len,
+ "wpa=%d\n"
+ "AKMSuiteSelector=" RSN_SUITE "\n"
"hostapdWPAPTKState=%d\n"
"hostapdWPAPTKGroupState=%d\n",
+ sm->wpa,
+ RSN_SUITE_ARG(wpa_akm_to_suite(sm->wpa_key_mgmt)),
sm->wpa_ptk_state,
sm->wpa_ptk_group_state);
if (os_snprintf_error(buflen - len, ret))
@@ -4236,7 +4533,7 @@
int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return -1;
return sm->wpa_key_mgmt;
}
@@ -4244,7 +4541,7 @@
int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return 0;
return sm->wpa;
}
@@ -4269,7 +4566,7 @@
int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
struct rsn_pmksa_cache_entry *entry)
{
- if (sm == NULL || sm->pmksa != entry)
+ if (!sm || sm->pmksa != entry)
return -1;
sm->pmksa = NULL;
return 0;
@@ -4292,7 +4589,7 @@
const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, size_t *len)
{
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return NULL;
*len = wpa_auth->wpa_ie_len;
return wpa_auth->wpa_ie;
@@ -4303,10 +4600,19 @@
unsigned int pmk_len,
int session_timeout, struct eapol_state_machine *eapol)
{
- if (sm == NULL || sm->wpa != WPA_VERSION_WPA2 ||
+ if (!sm || sm->wpa != WPA_VERSION_WPA2 ||
sm->wpa_auth->conf.disable_pmksa_caching)
return -1;
+#ifdef CONFIG_IEEE80211R_AP
+ if (pmk_len >= 2 * PMK_LEN && wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
+ wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
+ !wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
+ /* Cache MPMK/XXKey instead of initial part from MSK */
+ pmk = pmk + PMK_LEN;
+ pmk_len = PMK_LEN;
+ } else
+#endif /* CONFIG_IEEE80211R_AP */
if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
if (pmk_len > PMK_LEN_SUITE_B_192)
pmk_len = PMK_LEN_SUITE_B_192;
@@ -4314,6 +4620,7 @@
pmk_len = PMK_LEN;
}
+ wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK", pmk, pmk_len);
if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, pmk_len, NULL,
sm->PTK.kck, sm->PTK.kck_len,
sm->wpa_auth->addr, sm->addr, session_timeout,
@@ -4329,9 +4636,10 @@
int session_timeout,
struct eapol_state_machine *eapol)
{
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return -1;
+ wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from preauth", pmk, len);
if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, NULL,
NULL, 0,
wpa_auth->addr,
@@ -4349,6 +4657,7 @@
if (wpa_auth->conf.disable_pmksa_caching)
return -1;
+ wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from SAE", pmk, PMK_LEN);
if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN, pmkid,
NULL, 0,
wpa_auth->addr, addr, 0, NULL,
@@ -4373,6 +4682,7 @@
if (wpa_auth->conf.disable_pmksa_caching)
return -1;
+ wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK (2)", pmk, PMK_LEN);
if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, pmk_len, pmkid,
NULL, 0, wpa_auth->addr, addr, session_timeout,
NULL, akmp))
@@ -4387,7 +4697,7 @@
{
struct rsn_pmksa_cache_entry *pmksa;
- if (wpa_auth == NULL || wpa_auth->pmksa == NULL)
+ if (!wpa_auth || !wpa_auth->pmksa)
return;
pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL);
if (pmksa) {
@@ -4553,13 +4863,13 @@
{
struct wpa_group *group;
- if (wpa_auth == NULL || wpa_auth->group == NULL)
+ if (!wpa_auth || !wpa_auth->group)
return NULL;
wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d",
vlan_id);
group = wpa_group_init(wpa_auth, vlan_id, 0);
- if (group == NULL)
+ if (!group)
return NULL;
group->next = wpa_auth->group->next;
@@ -4579,7 +4889,7 @@
{
struct wpa_group *group;
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return 0;
group = wpa_auth->group;
@@ -4589,9 +4899,9 @@
group = group->next;
}
- if (group == NULL) {
+ if (!group) {
group = wpa_auth_add_group(wpa_auth, vlan_id);
- if (group == NULL)
+ if (!group)
return -1;
}
@@ -4620,7 +4930,7 @@
struct wpa_group *group;
int ret = 0;
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return 0;
group = wpa_auth->group;
@@ -4630,7 +4940,7 @@
group = group->next;
}
- if (group == NULL)
+ if (!group)
return -1;
wpa_printf(MSG_DEBUG,
@@ -4665,7 +4975,7 @@
{
struct wpa_group *group;
- if (sm == NULL || sm->wpa_auth == NULL)
+ if (!sm || !sm->wpa_auth)
return 0;
group = sm->wpa_auth->group;
@@ -4675,9 +4985,9 @@
group = group->next;
}
- if (group == NULL) {
+ if (!group) {
group = wpa_auth_add_group(sm->wpa_auth, vlan_id);
- if (group == NULL)
+ if (!group)
return -1;
}
@@ -4687,8 +4997,9 @@
if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
return -1;
- wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state "
- "machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id);
+ wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR
+ " to use group state machine for VLAN ID %d",
+ MAC2STR(sm->addr), vlan_id);
wpa_group_get(sm->wpa_auth, group);
wpa_group_put(sm->wpa_auth, sm->group);
@@ -4701,7 +5012,7 @@
void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int ack)
{
- if (wpa_auth == NULL || sm == NULL)
+ if (!wpa_auth || !sm)
return;
wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key TX status for STA " MACSTR
" ack=%d", MAC2STR(sm->addr), ack);
@@ -4717,8 +5028,8 @@
* the station has received the frame.
*/
int timeout_ms = eapol_key_timeout_subseq;
- wpa_printf(MSG_DEBUG, "WPA: Increase initial EAPOL-Key 1/4 "
- "timeout by %u ms because of acknowledged frame",
+ wpa_printf(MSG_DEBUG,
+ "WPA: Increase initial EAPOL-Key 1/4 timeout by %u ms because of acknowledged frame",
timeout_ms);
eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
eloop_register_timeout(timeout_ms / 1000,
@@ -4738,7 +5049,7 @@
int wpa_auth_uses_sae(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return 0;
return wpa_key_mgmt_sae(sm->wpa_key_mgmt);
}
@@ -4746,7 +5057,7 @@
int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return 0;
return sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE;
}
@@ -4755,7 +5066,7 @@
#ifdef CONFIG_P2P
int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr)
{
- if (sm == NULL || WPA_GET_BE32(sm->ip_addr) == 0)
+ if (!sm || WPA_GET_BE32(sm->ip_addr) == 0)
return -1;
os_memcpy(addr, sm->ip_addr, 4);
return 0;
@@ -4831,7 +5142,7 @@
return wpa_write_ftie(conf, use_sha384, conf->r0_key_holder,
conf->r0_key_holder_len,
- NULL, NULL, buf, len, NULL, 0);
+ NULL, NULL, buf, len, NULL, 0, 0);
}
#endif /* CONFIG_IEEE80211R_AP */
@@ -4846,6 +5157,16 @@
*fils_kek_len = sm->PTK.kek_len;
}
+
+void wpa_auth_add_fils_pmk_pmkid(struct wpa_state_machine *sm, const u8 *pmk,
+ size_t pmk_len, const u8 *pmkid)
+{
+ os_memcpy(sm->PMK, pmk, pmk_len);
+ sm->pmk_len = pmk_len;
+ os_memcpy(sm->pmkid, pmkid, PMKID_LEN);
+ sm->pmkid_set = 1;
+}
+
#endif /* CONFIG_FILS */
@@ -4896,16 +5217,15 @@
void *ctx1, void *ctx2)
{
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;
- int wpa_ie_len, secure, keyidx, encr = 0;
+ int wpa_ie_len, secure, gtkidx, encr = 0;
+ u8 hdr[2];
/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
- GTK[GN], IGTK, [FTIE], [TIE * 2])
+ GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
*/
/* Use 0 RSC */
@@ -4929,7 +5249,7 @@
secure = 1;
gtk = gsm->GTK[gsm->GN - 1];
gtk_len = gsm->GTK_len;
- keyidx = gsm->GN;
+ gtkidx = gsm->GN;
_rsc = rsc;
encr = 1;
} else {
@@ -4937,7 +5257,6 @@
secure = 0;
gtk = NULL;
gtk_len = 0;
- keyidx = 0;
_rsc = NULL;
if (sm->rx_eapol_key_secure) {
/*
@@ -4949,13 +5268,16 @@
* WPA if the supplicant used it first.
*/
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "STA used Secure bit in WPA msg 2/4 - "
- "set Secure for 3/4 as workaround");
+ "STA used Secure bit in WPA msg 2/4 - set Secure for 3/4 as workaround");
secure = 1;
}
}
kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
+
+ if (sm->use_ext_key_id)
+ kde_len += 2 + RSN_SELECTOR_LEN + 2;
+
if (gtk)
kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
#ifdef CONFIG_IEEE80211R_AP
@@ -4965,7 +5287,7 @@
}
#endif /* CONFIG_IEEE80211R_AP */
kde = os_malloc(kde_len);
- if (kde == NULL)
+ if (!kde)
return -1;
pos = kde;
@@ -4979,8 +5301,8 @@
elen = pos - kde;
res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name);
if (res < 0) {
- wpa_printf(MSG_ERROR, "FT: Failed to insert "
- "PMKR1Name into RSN IE in EAPOL-Key data");
+ wpa_printf(MSG_ERROR,
+ "FT: Failed to insert PMKR1Name into RSN IE in EAPOL-Key data");
os_free(kde);
return -1;
}
@@ -4988,14 +5310,18 @@
pos += elen;
}
#endif /* CONFIG_IEEE80211R_AP */
+ hdr[1] = 0;
+
+ if (sm->use_ext_key_id) {
+ hdr[0] = sm->keyidx_active & 0x01;
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0);
+ }
+
if (gtk) {
- u8 hdr[2];
- hdr[0] = keyidx & 0x03;
- hdr[1] = 0;
+ hdr[0] = gtkidx & 0x03;
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 >= 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN) {
@@ -5003,7 +5329,6 @@
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;
@@ -5028,11 +5353,11 @@
conf->r0_key_holder_len,
NULL, NULL, pos,
kde + kde_len - pos,
- NULL, 0);
+ NULL, 0, 0);
}
if (res < 0) {
- wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
- "into EAPOL-Key Key Data");
+ wpa_printf(MSG_ERROR,
+ "FT: Failed to insert FTIE into EAPOL-Key Key Data");
os_free(kde);
return -1;
}
@@ -5060,7 +5385,7 @@
WPA_KEY_INFO_MIC : 0) |
WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
WPA_KEY_INFO_KEY_TYPE,
- _rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
+ _rsc, sm->ANonce, kde, pos - kde, 0, encr);
os_free(kde);
return 0;
}
@@ -5074,9 +5399,7 @@
struct wpa_group *gsm = sm->group;
const u8 *kde;
u8 *kde_buf = NULL, *pos, hdr[2];
-#ifdef CONFIG_IEEE80211W
u8 *opos;
-#endif /* CONFIG_IEEE80211W */
size_t kde_len;
u8 *gtk;
@@ -5091,7 +5414,7 @@
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
ieee80211w_kde_len(sm) + ocv_oci_len(sm);
kde_buf = os_malloc(kde_len);
- if (kde_buf == NULL)
+ if (!kde_buf)
return -1;
kde = pos = kde_buf;
@@ -5099,7 +5422,6 @@
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 >=
@@ -5108,7 +5430,6 @@
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;
@@ -5144,4 +5465,11 @@
return eloop_register_timeout(0, 0, wpa_rekey_gtk, wpa_auth, NULL);
}
+
+void wpa_auth_set_ft_rsnxe_used(struct wpa_authenticator *wpa_auth, int val)
+{
+ if (wpa_auth)
+ wpa_auth->conf.ft_rsnxe_used = val;
+}
+
#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 484e1e5..1ea067b 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -169,6 +169,7 @@
struct wpa_auth_config {
int wpa;
+ int extended_key_id;
int wpa_key_mgmt;
int wpa_pairwise;
int wpa_group;
@@ -176,6 +177,7 @@
int wpa_strict_rekey;
int wpa_gmk_rekey;
int wpa_ptk_rekey;
+ int wpa_deny_ptk0_rekey;
u32 wpa_group_update_count;
u32 wpa_pairwise_update_count;
int wpa_disable_eapol_key_retries;
@@ -187,11 +189,10 @@
int disable_pmksa_caching;
int okc;
int tx_status;
-#ifdef CONFIG_IEEE80211W
enum mfp_options ieee80211w;
+ int beacon_prot;
int group_mgmt_cipher;
int sae_require_mfp;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
int ocv; /* Operating Channel Validation */
#endif /* CONFIG_OCV */
@@ -221,6 +222,23 @@
double corrupt_gtk_rekey_mic_probability;
u8 own_ie_override[MAX_OWN_IE_OVERRIDE];
size_t own_ie_override_len;
+ u8 rsne_override_eapol[MAX_OWN_IE_OVERRIDE];
+ size_t rsne_override_eapol_len;
+ u8 rsnxe_override_eapol[MAX_OWN_IE_OVERRIDE];
+ size_t rsnxe_override_eapol_len;
+ u8 rsne_override_ft[MAX_OWN_IE_OVERRIDE];
+ size_t rsne_override_ft_len;
+ u8 rsnxe_override_ft[MAX_OWN_IE_OVERRIDE];
+ size_t rsnxe_override_ft_len;
+ u8 gtk_rsc_override[WPA_KEY_RSC_LEN];
+ u8 igtk_rsc_override[WPA_KEY_RSC_LEN];
+ unsigned int rsne_override_eapol_set:1;
+ unsigned int rsnxe_override_eapol_set:1;
+ unsigned int rsne_override_ft_set:1;
+ unsigned int rsnxe_override_ft_set:1;
+ unsigned int gtk_rsc_override_set:1;
+ unsigned int igtk_rsc_override_set:1;
+ int ft_rsnxe_used;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_P2P
u8 ip_addr_go[4];
@@ -232,6 +250,12 @@
unsigned int fils_cache_id_set:1;
u8 fils_cache_id[FILS_CACHE_ID_LEN];
#endif /* CONFIG_FILS */
+ int sae_pwe;
+ int owe_ptk_workaround;
+ u8 transition_disable;
+#ifdef CONFIG_DPP2
+ int dpp_pfs;
+#endif /* CONFIG_DPP2 */
};
typedef enum {
@@ -258,7 +282,8 @@
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);
+ const u8 *addr, int idx, u8 *key, size_t key_len,
+ enum key_flag key_flag);
int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq);
int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data,
size_t data_len, int encrypt);
@@ -277,6 +302,7 @@
int *bandwidth, int *seg1_idx);
#ifdef CONFIG_IEEE80211R_AP
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
+ int (*add_sta_ft)(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,
@@ -310,18 +336,21 @@
int wpa_reconfig(struct wpa_authenticator *wpa_auth,
struct wpa_auth_config *conf);
-enum {
+enum wpa_validate_result {
WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,
WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,
WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER,
- WPA_INVALID_MDIE, WPA_INVALID_PROTO, WPA_INVALID_PMKID
+ WPA_INVALID_MDIE, WPA_INVALID_PROTO, WPA_INVALID_PMKID,
+ WPA_DENIED_OTHER_REASON
};
-int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
- 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);
+enum wpa_validate_result
+wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm, int freq,
+ const u8 *wpa_ie, size_t wpa_ie_len,
+ const u8 *rsnxe, size_t rsnxe_len,
+ const u8 *mdie, size_t mdie_len,
+ const u8 *owe_dh, size_t owe_dh_len);
int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
const u8 *osen_ie, size_t osen_ie_len);
@@ -405,14 +434,15 @@
#ifdef CONFIG_IEEE80211R_AP
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
size_t max_len, int auth_alg,
- const u8 *req_ies, size_t req_ies_len);
+ const u8 *req_ies, size_t req_ies_len,
+ int omit_rsnxe);
void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
u16 auth_transaction, const u8 *ies, size_t ies_len,
void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
u16 auth_transaction, u16 resp,
const u8 *ies, size_t ies_len),
void *ctx);
-u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
+int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
size_t ies_len);
int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len);
int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
@@ -429,6 +459,7 @@
void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag);
int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos);
int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos);
+int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos);
int wpa_auth_uses_sae(struct wpa_state_machine *sm);
int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm);
@@ -470,9 +501,14 @@
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);
+void wpa_auth_add_fils_pmk_pmkid(struct wpa_state_machine *sm, const u8 *pmk,
+ size_t pmk_len, const u8 *pmkid);
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);
+u8 * wpa_auth_write_assoc_resp_fils(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);
@@ -486,5 +522,7 @@
void (*cb)(void *ctx1, void *ctx2),
void *ctx1, void *ctx2);
int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth);
+void wpa_auth_set_ptk_rekey_timer(struct wpa_state_machine *sm);
+void wpa_auth_set_ft_rsnxe_used(struct wpa_authenticator *wpa_auth, int val);
#endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index fdb7eba..5af65aa 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -25,6 +25,7 @@
#include "wmm.h"
#include "wpa_auth.h"
#include "wpa_auth_i.h"
+#include "pmksa_cache_auth.h"
#ifdef CONFIG_IEEE80211R_AP
@@ -807,7 +808,7 @@
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)
+ size_t subelem_len, int rsnxe_used)
{
u8 *pos = buf, *ielen;
size_t hdrlen = use_sha384 ? sizeof(struct rsn_ftie_sha384) :
@@ -825,7 +826,7 @@
os_memset(hdr, 0, sizeof(*hdr));
pos += sizeof(*hdr);
- WPA_PUT_LE16(hdr->mic_control, 0);
+ WPA_PUT_LE16(hdr->mic_control, !!rsnxe_used);
if (anonce)
os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
if (snonce)
@@ -835,7 +836,7 @@
os_memset(hdr, 0, sizeof(*hdr));
pos += sizeof(*hdr);
- WPA_PUT_LE16(hdr->mic_control, 0);
+ WPA_PUT_LE16(hdr->mic_control, !!rsnxe_used);
if (anonce)
os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
if (snonce)
@@ -950,8 +951,9 @@
goto err;
}
- wpa_printf(MSG_DEBUG, "FT: Send out sequence number request to " MACSTR,
- MAC2STR(src_addr));
+ wpa_printf(MSG_DEBUG, "FT: Send sequence number request from " MACSTR
+ " to " MACSTR,
+ MAC2STR(wpa_auth->addr), MAC2STR(src_addr));
item = os_zalloc(sizeof(*item));
if (!item)
goto err;
@@ -1996,9 +1998,6 @@
key = r0kh->key;
key_len = sizeof(r0kh->key);
- wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH "
- "address " MACSTR, MAC2STR(r0kh->addr));
-
if (r0kh->seq->rx.num_last == 0) {
/* A sequence request will be sent out anyway when pull
* response is received. Send it out now to avoid one RTT. */
@@ -2007,6 +2006,10 @@
key_len, NULL, 0, NULL, 0, NULL);
}
+ wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request from " MACSTR
+ " to remote R0KH address " MACSTR,
+ MAC2STR(sm->wpa_auth->addr), MAC2STR(r0kh->addr));
+
if (first &&
random_get_bytes(sm->ft_pending_pull_nonce, FT_RRB_NONCE_LEN) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
@@ -2074,8 +2077,7 @@
}
-int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
- struct wpa_ptk *ptk)
+int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
{
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) ?
@@ -2095,8 +2097,16 @@
const u8 *identity, *radius_cui;
size_t identity_len, radius_cui_len;
int session_timeout;
+ const u8 *mpmk;
+ size_t mpmk_len;
- if (sm->xxkey_len == 0) {
+ if (sm->xxkey_len > 0) {
+ mpmk = sm->xxkey;
+ mpmk_len = sm->xxkey_len;
+ } else if (sm->pmksa) {
+ mpmk = sm->pmksa->pmk;
+ mpmk_len = sm->pmksa->pmk_len;
+ } else {
wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
"derivation");
return -1;
@@ -2113,7 +2123,7 @@
&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,
+ if (wpa_derive_pmk_r0(mpmk, mpmk_len, ssid, ssid_len, mdid,
r0kh, r0kh_len, sm->addr,
pmk_r0, pmk_r0_name,
wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) < 0)
@@ -2218,12 +2228,12 @@
return NULL;
}
+ forced_memzero(keybuf, sizeof(keybuf));
*len = subelem_len;
return subelem;
}
-#ifdef CONFIG_IEEE80211W
static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
{
u8 *subelem, *pos;
@@ -2270,7 +2280,54 @@
*len = subelem_len;
return subelem;
}
-#endif /* CONFIG_IEEE80211W */
+
+
+static u8 * wpa_ft_bigtk_subelem(struct wpa_state_machine *sm, size_t *len)
+{
+ u8 *subelem, *pos;
+ struct wpa_group *gsm = sm->group;
+ size_t subelem_len;
+ const u8 *kek;
+ size_t kek_len;
+ size_t bigtk_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;
+ }
+
+ bigtk_len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+
+ /* Sub-elem ID[1] | Length[1] | KeyID[2] | BIPN[6] | Key Length[1] |
+ * Key[16+8] */
+ subelem_len = 1 + 1 + 2 + 6 + 1 + bigtk_len + 8;
+ subelem = os_zalloc(subelem_len);
+ if (subelem == NULL)
+ return NULL;
+
+ pos = subelem;
+ *pos++ = FTIE_SUBELEM_BIGTK;
+ *pos++ = subelem_len - 2;
+ WPA_PUT_LE16(pos, gsm->GN_bigtk);
+ pos += 2;
+ wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos);
+ pos += 6;
+ *pos++ = bigtk_len;
+ if (aes_wrap(kek, kek_len, bigtk_len / 8,
+ gsm->IGTK[gsm->GN_bigtk - 6], pos)) {
+ wpa_printf(MSG_DEBUG,
+ "FT: BIGTK subelem encryption failed: kek_len=%d",
+ (int) kek_len);
+ os_free(subelem);
+ return NULL;
+ }
+
+ *len = subelem_len;
+ return subelem;
+}
static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
@@ -2406,11 +2463,15 @@
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
size_t max_len, int auth_alg,
- const u8 *req_ies, size_t req_ies_len)
+ const u8 *req_ies, size_t req_ies_len,
+ int omit_rsnxe)
{
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;
+ u8 rsnxe_buf[10], *rsnxe = rsnxe_buf;
+ size_t rsnxe_len;
+ int rsnxe_used;
int res;
struct wpa_auth_config *conf;
struct wpa_ft_ies parse;
@@ -2431,6 +2492,32 @@
end = pos + max_len;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (auth_alg == WLAN_AUTH_FT &&
+ sm->wpa_auth->conf.rsne_override_ft_set) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: RSNE FT override for MIC calculation");
+ rsnie = sm->wpa_auth->conf.rsne_override_ft;
+ rsnie_len = sm->wpa_auth->conf.rsne_override_ft_len;
+ if (end - pos < (long int) rsnie_len)
+ return pos;
+ os_memcpy(pos, rsnie, rsnie_len);
+ rsnie = pos;
+ pos += rsnie_len;
+ if (rsnie_len > PMKID_LEN && sm->pmk_r1_name_valid) {
+ int idx;
+
+ /* Replace all 0xff PMKID with the valid PMKR1Name */
+ for (idx = 0; idx < PMKID_LEN; idx++) {
+ if (rsnie[rsnie_len - 1 - idx] != 0xff)
+ break;
+ }
+ if (idx == PMKID_LEN)
+ os_memcpy(&rsnie[rsnie_len - PMKID_LEN],
+ sm->pmk_r1_name, WPA_PMK_NAME_LEN);
+ }
+ } else
+#endif /* CONFIG_TESTING_OPTIONS */
if (auth_alg == WLAN_AUTH_FT ||
((auth_alg == WLAN_AUTH_FILS_SK ||
auth_alg == WLAN_AUTH_FILS_SK_PFS ||
@@ -2478,7 +2565,6 @@
r0kh_id_len = sm->r0kh_id_len;
anonce = sm->ANonce;
snonce = sm->SNonce;
-#ifdef CONFIG_IEEE80211W
if (sm->mgmt_frame_prot) {
u8 *igtk;
size_t igtk_len;
@@ -2501,7 +2587,29 @@
subelem_len += igtk_len;
os_free(igtk);
}
-#endif /* CONFIG_IEEE80211W */
+ if (sm->mgmt_frame_prot && conf->beacon_prot) {
+ u8 *bigtk;
+ size_t bigtk_len;
+ u8 *nbuf;
+
+ bigtk = wpa_ft_bigtk_subelem(sm, &bigtk_len);
+ if (!bigtk) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Failed to add BIGTK subelement");
+ os_free(subelem);
+ return NULL;
+ }
+ nbuf = os_realloc(subelem, subelem_len + bigtk_len);
+ if (!nbuf) {
+ os_free(subelem);
+ os_free(bigtk);
+ return NULL;
+ }
+ subelem = nbuf;
+ os_memcpy(subelem + subelem_len, bigtk, bigtk_len);
+ subelem_len += bigtk_len;
+ os_free(bigtk);
+ }
#ifdef CONFIG_OCV
if (wpa_auth_uses_ocv(sm)) {
struct wpa_channel_info ci;
@@ -2537,9 +2645,18 @@
anonce = NULL;
snonce = NULL;
}
+ rsnxe_used = (auth_alg == WLAN_AUTH_FT) &&
+ (conf->sae_pwe == 1 || conf->sae_pwe == 2);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->wpa_auth->conf.ft_rsnxe_used) {
+ rsnxe_used = sm->wpa_auth->conf.ft_rsnxe_used == 1;
+ wpa_printf(MSG_DEBUG, "TESTING: FT: Force RSNXE Used %d",
+ rsnxe_used);
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
res = wpa_write_ftie(conf, use_sha384, r0kh_id, r0kh_id_len,
anonce, snonce, pos, end - pos,
- subelem, subelem_len);
+ subelem, subelem_len, rsnxe_used);
os_free(subelem);
if (res < 0)
return NULL;
@@ -2575,6 +2692,27 @@
if (ric_start == pos)
ric_start = NULL;
+ if (omit_rsnxe) {
+ rsnxe_len = 0;
+ } else {
+ res = wpa_write_rsnxe(&sm->wpa_auth->conf, rsnxe,
+ sizeof(rsnxe_buf));
+ if (res < 0)
+ return NULL;
+ rsnxe_len = res;
+ }
+#ifdef CONFIG_TESTING_OPTIONS
+ if (auth_alg == WLAN_AUTH_FT &&
+ sm->wpa_auth->conf.rsnxe_override_ft_set) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: RSNXE FT override for MIC calculation");
+ rsnxe = sm->wpa_auth->conf.rsnxe_override_ft;
+ rsnxe_len = sm->wpa_auth->conf.rsnxe_override_ft_len;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (auth_alg == WLAN_AUTH_FT && rsnxe_len)
+ *elem_count += 1;
+
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
kck = sm->PTK.kck2;
kck_len = sm->PTK.kck2_len;
@@ -2587,6 +2725,7 @@
mdie, mdie_len, ftie, ftie_len,
rsnie, rsnie_len,
ric_start, ric_start ? pos - ric_start : 0,
+ rsnxe_len ? rsnxe : NULL, rsnxe_len,
fte_mic) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
return NULL;
@@ -2605,16 +2744,26 @@
static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
int vlan_id,
enum wpa_alg alg, const u8 *addr, int idx,
- u8 *key, size_t key_len)
+ u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
if (wpa_auth->cb->set_key == NULL)
return -1;
return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
- key, key_len);
+ key, key_len, key_flag);
}
-void wpa_ft_install_ptk(struct wpa_state_machine *sm)
+static inline int wpa_auth_add_sta_ft(struct wpa_authenticator *wpa_auth,
+ const u8 *addr)
+{
+ if (!wpa_auth->cb->add_sta_ft)
+ return -1;
+ return wpa_auth->cb->add_sta_ft(wpa_auth->cb_ctx, addr);
+}
+
+
+void wpa_ft_install_ptk(struct wpa_state_machine *sm, int retry)
{
enum wpa_alg alg;
int klen;
@@ -2636,19 +2785,22 @@
return;
}
+ if (!retry)
+ wpa_auth_add_sta_ft(sm->wpa_auth, sm->addr);
+
/* FIX: add STA entry to kernel/driver here? The set_key will fail
* most likely without this.. At the moment, STA entry is added only
* after association has been completed. This function will be called
* again after association to get the PTK configured, but that could be
* optimized by adding the STA entry earlier.
*/
- if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
- sm->PTK.tk, klen))
+ if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, sm->keyidx_active,
+ sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX))
return;
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
- sm->pairwise_set = TRUE;
- sm->tk_already_set = TRUE;
+ sm->pairwise_set = true;
+ sm->tk_already_set = true;
}
@@ -2984,6 +3136,8 @@
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);
+ os_memcpy(sm->pmk_r1, pmk_r1, pmk_r1_len);
+ sm->pmk_r1_len = pmk_r1_len;
if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
@@ -3003,9 +3157,9 @@
return WLAN_STATUS_UNSPECIFIED_FAILURE;
sm->pairwise = pairwise;
- sm->PTK_valid = TRUE;
- sm->tk_already_set = FALSE;
- wpa_ft_install_ptk(sm);
+ sm->PTK_valid = true;
+ sm->tk_already_set = false;
+ wpa_ft_install_ptk(sm, 0);
if (wpa_ft_set_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to configure VLAN");
@@ -3040,7 +3194,8 @@
pos += ret;
ret = wpa_write_ftie(conf, use_sha384, parse.r0kh_id, parse.r0kh_id_len,
- sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0);
+ sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0,
+ 0);
if (ret < 0)
goto fail;
pos += ret;
@@ -3089,8 +3244,9 @@
status = res;
wpa_printf(MSG_DEBUG, "FT: FT authentication response: dst=" MACSTR
- " auth_transaction=%d status=%d",
- MAC2STR(sm->addr), auth_transaction + 1, status);
+ " auth_transaction=%d status=%u (%s)",
+ MAC2STR(sm->addr), auth_transaction + 1, status,
+ status2str(status));
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
cb(ctx, sm->addr, bssid, auth_transaction + 1, status,
resp_ies, resp_ies_len);
@@ -3098,7 +3254,7 @@
}
-u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
+int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
size_t ies_len)
{
struct wpa_ft_ies parse;
@@ -3111,10 +3267,13 @@
int use_sha384;
const u8 *anonce, *snonce, *fte_mic;
u8 fte_elem_count;
+ int rsnxe_used;
+ struct wpa_auth_config *conf;
if (sm == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ conf = &sm->wpa_auth->conf;
use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len);
@@ -3143,8 +3302,7 @@
mdie = (struct rsn_mdie *) parse.mdie;
if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
- os_memcmp(mdie->mobility_domain,
- sm->wpa_auth->conf.mobility_domain,
+ os_memcmp(mdie->mobility_domain, conf->mobility_domain,
MOBILITY_DOMAIN_ID_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
return WLAN_STATUS_INVALID_MDIE;
@@ -3161,6 +3319,7 @@
anonce = ftie->anonce;
snonce = ftie->snonce;
+ rsnxe_used = ftie->mic_control[0] & 0x01;
fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic;
} else {
@@ -3174,6 +3333,7 @@
anonce = ftie->anonce;
snonce = ftie->snonce;
+ rsnxe_used = ftie->mic_control[0] & 0x01;
fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic;
}
@@ -3219,14 +3379,14 @@
return WLAN_STATUS_INVALID_FTIE;
}
- if (os_memcmp_const(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder,
+ if (os_memcmp_const(parse.r1kh_id, conf->r1_key_holder,
FT_R1KH_ID_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
"ReassocReq");
wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE",
parse.r1kh_id, FT_R1KH_ID_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected R1KH-ID",
- sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
+ conf->r1_key_holder, FT_R1KH_ID_LEN);
return WLAN_STATUS_INVALID_FTIE;
}
@@ -3241,6 +3401,8 @@
count = 3;
if (parse.ric)
count += ieee802_11_ie_count(parse.ric, parse.ric_len);
+ if (parse.rsnxe)
+ count++;
if (fte_elem_count != count) {
wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
"Control: received %u expected %u",
@@ -3260,6 +3422,8 @@
parse.ftie - 2, parse.ftie_len + 2,
parse.rsn - 2, parse.rsn_len + 2,
parse.ric, parse.ric_len,
+ parse.rsnxe ? parse.rsnxe - 2 : NULL,
+ parse.rsnxe ? parse.rsnxe_len + 2 : 0,
mic) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -3278,9 +3442,19 @@
parse.ftie - 2, parse.ftie_len + 2);
wpa_hexdump(MSG_MSGDUMP, "FT: RSN",
parse.rsn - 2, parse.rsn_len + 2);
+ wpa_hexdump(MSG_MSGDUMP, "FT: RSNXE",
+ parse.rsnxe ? parse.rsnxe - 2 : NULL,
+ parse.rsnxe ? parse.rsnxe_len + 2 : 0);
return WLAN_STATUS_INVALID_FTIE;
}
+ if (rsnxe_used && (conf->sae_pwe == 1 || conf->sae_pwe == 2) &&
+ !parse.rsnxe) {
+ wpa_printf(MSG_INFO,
+ "FT: FTE indicated that STA uses RSNXE, but RSNXE was not included");
+ return -1; /* discard request */
+ }
+
#ifdef CONFIG_OCV
if (wpa_auth_uses_ocv(sm)) {
struct wpa_channel_info ci;
@@ -3448,8 +3622,9 @@
u8 *pos;
wpa_printf(MSG_DEBUG, "FT: RRB authentication response: STA=" MACSTR
- " CurrentAP=" MACSTR " status=%d",
- MAC2STR(sm->addr), MAC2STR(current_ap), status);
+ " CurrentAP=" MACSTR " status=%u (%s)",
+ MAC2STR(sm->addr), MAC2STR(current_ap), status,
+ status2str(status));
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
/* RRB - Forward action frame response to the Current AP */
@@ -3555,7 +3730,7 @@
pmk_r0->vlan, src_addr, type,
packet, packet_len);
- os_memset(pmk_r1, 0, sizeof(pmk_r1));
+ forced_memzero(pmk_r1, sizeof(pmk_r1));
return ret;
}
@@ -3661,6 +3836,10 @@
goto out;
}
+ wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull response from " MACSTR
+ " to " MACSTR,
+ MAC2STR(wpa_auth->addr), MAC2STR(src_addr));
+
resp[0].type = FT_RRB_S1KH_ID;
resp[0].len = f_s1kh_id_len;
resp[0].data = f_s1kh_id;
@@ -3881,10 +4060,7 @@
ret = 0;
out:
- if (plain) {
- os_memset(plain, 0, plain_len);
- os_free(plain);
- }
+ bin_clear_free(plain, plain_len);
return ret;
@@ -4170,6 +4346,10 @@
goto out;
}
+ wpa_printf(MSG_DEBUG, "FT: Send sequence number response from " MACSTR
+ " to " MACSTR,
+ MAC2STR(wpa_auth->addr), MAC2STR(src_addr));
+
seq_resp_auth[0].type = FT_RRB_NONCE;
seq_resp_auth[0].len = f_nonce_len;
seq_resp_auth[0].data = f_nonce;
@@ -4399,7 +4579,6 @@
return -1;
}
status_code = WPA_GET_LE16(pos);
- pos += 2;
wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Response "
"(status_code=%d)", status_code);
@@ -4412,11 +4591,6 @@
return -1;
}
- if (end > pos) {
- wpa_hexdump(MSG_DEBUG, "FT: Ignore extra data in end",
- pos, end - pos);
- }
-
return 0;
}
@@ -4429,9 +4603,11 @@
size_t alen, elen;
int no_defer = 0;
- 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_printf(MSG_DEBUG, "FT: RRB-OUI(" MACSTR
+ ") received frame from remote AP "
+ MACSTR " oui_suffix=%u dst=" MACSTR,
+ MAC2STR(wpa_auth->addr), MAC2STR(src_addr), oui_suffix,
+ MAC2STR(dst_addr));
wpa_hexdump(MSG_MSGDUMP, "FT: RRB frame payload", data, data_len);
if (is_multicast_ether_addr(src_addr)) {
@@ -4441,13 +4617,8 @@
return;
}
- if (is_multicast_ether_addr(dst_addr)) {
- wpa_printf(MSG_DEBUG,
- "FT: RRB-OUI received frame from remote AP " MACSTR
- " to multicast address " MACSTR,
- MAC2STR(src_addr), MAC2STR(dst_addr));
+ if (is_multicast_ether_addr(dst_addr))
no_defer = 1;
- }
if (data_len < sizeof(u16)) {
wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame too short");
@@ -4522,6 +4693,10 @@
return -1;
}
+ wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 push from " MACSTR
+ " to remote R0KH address " MACSTR,
+ MAC2STR(wpa_auth->addr), MAC2STR(r1kh->addr));
+
if (wpa_ft_rrb_build_r0(r1kh->key, sizeof(r1kh->key), push, pmk_r0,
r1kh->id, s1kh_id, push_auth, wpa_auth->addr,
FT_PACKET_R0KH_R1KH_PUSH,
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 45172c6..44ab830 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -37,8 +37,11 @@
struct hostapd_config *iconf,
struct wpa_auth_config *wconf)
{
+ int sae_pw_id;
+
os_memset(wconf, 0, sizeof(*wconf));
wconf->wpa = conf->wpa;
+ wconf->extended_key_id = conf->extended_key_id;
wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
wconf->wpa_pairwise = conf->wpa_pairwise;
wconf->wpa_group = conf->wpa_group;
@@ -53,6 +56,10 @@
wconf->rsn_pairwise = conf->rsn_pairwise;
wconf->rsn_preauth = conf->rsn_preauth;
wconf->eapol_version = conf->eapol_version;
+#ifdef CONFIG_MACSEC
+ if (wconf->eapol_version > 2)
+ wconf->eapol_version = 2;
+#endif /* CONFIG_MACSEC */
wconf->wmm_enabled = conf->wmm_enabled;
wconf->wmm_uapsd = conf->wmm_uapsd;
wconf->disable_pmksa_caching = conf->disable_pmksa_caching;
@@ -60,11 +67,10 @@
wconf->ocv = conf->ocv;
#endif /* CONFIG_OCV */
wconf->okc = conf->okc;
-#ifdef CONFIG_IEEE80211W
wconf->ieee80211w = conf->ieee80211w;
+ wconf->beacon_prot = conf->beacon_prot;
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;
if (wconf->ssid_len > SSID_MAX_LEN)
@@ -103,9 +109,7 @@
wconf->rsn_pairwise = WPA_CIPHER_CCMP;
wconf->rsn_preauth = 0;
wconf->disable_pmksa_caching = 1;
-#ifdef CONFIG_IEEE80211W
wconf->ieee80211w = 1;
-#endif /* CONFIG_IEEE80211W */
}
#endif /* CONFIG_HS20 */
#ifdef CONFIG_TESTING_OPTIONS
@@ -118,6 +122,59 @@
wpabuf_head(conf->own_ie_override),
wconf->own_ie_override_len);
}
+ if (conf->rsne_override_eapol &&
+ wpabuf_len(conf->rsne_override_eapol) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->rsne_override_eapol_set = 1;
+ wconf->rsne_override_eapol_len =
+ wpabuf_len(conf->rsne_override_eapol);
+ os_memcpy(wconf->rsne_override_eapol,
+ wpabuf_head(conf->rsne_override_eapol),
+ wconf->rsne_override_eapol_len);
+ }
+ if (conf->rsnxe_override_eapol &&
+ wpabuf_len(conf->rsnxe_override_eapol) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->rsnxe_override_eapol_set = 1;
+ wconf->rsnxe_override_eapol_len =
+ wpabuf_len(conf->rsnxe_override_eapol);
+ os_memcpy(wconf->rsnxe_override_eapol,
+ wpabuf_head(conf->rsnxe_override_eapol),
+ wconf->rsnxe_override_eapol_len);
+ }
+ if (conf->rsne_override_ft &&
+ wpabuf_len(conf->rsne_override_ft) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->rsne_override_ft_set = 1;
+ wconf->rsne_override_ft_len =
+ wpabuf_len(conf->rsne_override_ft);
+ os_memcpy(wconf->rsne_override_ft,
+ wpabuf_head(conf->rsne_override_ft),
+ wconf->rsne_override_ft_len);
+ }
+ if (conf->rsnxe_override_ft &&
+ wpabuf_len(conf->rsnxe_override_ft) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->rsnxe_override_ft_set = 1;
+ wconf->rsnxe_override_ft_len =
+ wpabuf_len(conf->rsnxe_override_ft);
+ os_memcpy(wconf->rsnxe_override_ft,
+ wpabuf_head(conf->rsnxe_override_ft),
+ wconf->rsnxe_override_ft_len);
+ }
+ if (conf->gtk_rsc_override &&
+ wpabuf_len(conf->gtk_rsc_override) > 0 &&
+ wpabuf_len(conf->gtk_rsc_override) <= WPA_KEY_RSC_LEN) {
+ os_memcpy(wconf->gtk_rsc_override,
+ wpabuf_head(conf->gtk_rsc_override),
+ wpabuf_len(conf->gtk_rsc_override));
+ wconf->gtk_rsc_override_set = 1;
+ }
+ if (conf->igtk_rsc_override &&
+ wpabuf_len(conf->igtk_rsc_override) > 0 &&
+ wpabuf_len(conf->igtk_rsc_override) <= WPA_KEY_RSC_LEN) {
+ os_memcpy(wconf->igtk_rsc_override,
+ wpabuf_head(conf->igtk_rsc_override),
+ wpabuf_len(conf->igtk_rsc_override));
+ wconf->igtk_rsc_override_set = 1;
+ }
+ wconf->ft_rsnxe_used = conf->ft_rsnxe_used;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_P2P
os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4);
@@ -130,6 +187,19 @@
os_memcpy(wconf->fils_cache_id, conf->fils_cache_id,
FILS_CACHE_ID_LEN);
#endif /* CONFIG_FILS */
+ wconf->sae_pwe = conf->sae_pwe;
+ sae_pw_id = hostapd_sae_pw_id_in_use(conf);
+ if (sae_pw_id == 2 && wconf->sae_pwe != 3)
+ wconf->sae_pwe = 1;
+ else if (sae_pw_id == 1 && wconf->sae_pwe == 0)
+ wconf->sae_pwe = 2;
+#ifdef CONFIG_OWE
+ wconf->owe_ptk_workaround = conf->owe_ptk_workaround;
+#endif /* CONFIG_OWE */
+ wconf->transition_disable = conf->transition_disable;
+#ifdef CONFIG_DPP2
+ wconf->dpp_pfs = conf->dpp_pfs;
+#endif /* CONFIG_DPP2 */
}
@@ -207,16 +277,15 @@
break;
case WPA_EAPOL_keyRun:
if (sta->eapol_sm)
- sta->eapol_sm->keyRun = value ? TRUE : FALSE;
+ sta->eapol_sm->keyRun = value;
break;
case WPA_EAPOL_keyAvailable:
if (sta->eapol_sm)
- sta->eapol_sm->eap_if->eapKeyAvailable =
- value ? TRUE : FALSE;
+ sta->eapol_sm->eap_if->eapKeyAvailable = value;
break;
case WPA_EAPOL_keyDone:
if (sta->eapol_sm)
- sta->eapol_sm->keyDone = value ? TRUE : FALSE;
+ sta->eapol_sm->keyDone = value;
break;
case WPA_EAPOL_inc_EapolFramesTx:
if (sta->eapol_sm)
@@ -353,19 +422,27 @@
static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
const u8 *addr, int idx, u8 *key,
- size_t key_len)
+ size_t key_len, enum key_flag key_flag)
{
struct hostapd_data *hapd = ctx;
const char *ifname = hapd->conf->iface;
if (vlan_id > 0) {
ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);
- if (ifname == NULL)
- return -1;
+ if (!ifname) {
+ if (!(hapd->iface->drv_flags &
+ WPA_DRIVER_FLAGS_VLAN_OFFLOAD))
+ return -1;
+ ifname = hapd->conf->iface;
+ }
}
#ifdef CONFIG_TESTING_OPTIONS
- if (addr && !is_broadcast_ether_addr(addr)) {
+ if (key_flag & KEY_FLAG_MODIFY) {
+ /* We are updating an already installed key. Don't overwrite
+ * the already stored key information with zeros.
+ */
+ } else if (addr && !is_broadcast_ether_addr(addr)) {
struct sta_info *sta;
sta = ap_get_sta(hapd, addr);
@@ -376,7 +453,6 @@
os_memcpy(sta->last_tk, key, key_len);
sta->last_tk_len = key_len;
}
-#ifdef CONFIG_IEEE80211W
} else if (alg == WPA_ALG_IGTK ||
alg == WPA_ALG_BIP_GMAC_128 ||
alg == WPA_ALG_BIP_GMAC_256 ||
@@ -386,7 +462,6 @@
if (key)
os_memcpy(hapd->last_igtk, key, key_len);
hapd->last_igtk_len = key_len;
-#endif /* CONFIG_IEEE80211W */
} else {
hapd->last_gtk_alg = alg;
hapd->last_gtk_key_idx = idx;
@@ -395,8 +470,8 @@
hapd->last_gtk_len = key_len;
}
#endif /* CONFIG_TESTING_OPTIONS */
- return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0,
- key, key_len);
+ return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, vlan_id, 1,
+ NULL, 0, key, key_len, key_flag);
}
@@ -616,10 +691,6 @@
}
#endif /* CONFIG_IEEE80211R_AP */
- if (hapd->driver && hapd->driver->send_ether)
- return hapd->driver->send_ether(hapd->drv_priv, dst,
- hapd->own_addr, proto,
- data, data_len);
if (hapd->l2 == NULL)
return -1;
@@ -681,6 +752,12 @@
dl_list_for_each_safe(data, n, &hapd->l2_oui_queue,
struct oui_deliver_later_data, list) {
oui_ctx = hostapd_wpa_get_oui(hapd, data->oui_suffix);
+ wpa_printf(MSG_DEBUG, "RRB(%s): %s src=" MACSTR " dst=" MACSTR
+ " oui_suffix=%u data_len=%u data=%p",
+ hapd->conf->iface, __func__,
+ MAC2STR(data->src_addr), MAC2STR(data->dst_addr),
+ data->oui_suffix, (unsigned int) data->data_len,
+ data);
if (hapd->wpa_auth && oui_ctx) {
eth_p_oui_deliver(oui_ctx, data->src_addr,
data->dst_addr,
@@ -705,16 +782,26 @@
{
struct wpa_auth_oui_iface_iter_data *idata = ctx;
struct oui_deliver_later_data *data;
- struct hostapd_data *hapd;
+ struct hostapd_data *hapd, *src_hapd = idata->src_hapd;
size_t j;
for (j = 0; j < iface->num_bss; j++) {
hapd = iface->bss[j];
- if (hapd == idata->src_hapd)
- continue;
+ if (hapd == src_hapd)
+ continue; /* don't deliver back to same interface */
+ if (!wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) ||
+ hapd->conf->ssid.ssid_len !=
+ src_hapd->conf->ssid.ssid_len ||
+ os_memcmp(hapd->conf->ssid.ssid,
+ src_hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len) != 0 ||
+ os_memcmp(hapd->conf->mobility_domain,
+ src_hapd->conf->mobility_domain,
+ MOBILITY_DOMAIN_ID_LEN) != 0)
+ continue; /* no matching FT SSID/mobility domain */
if (!is_multicast_ether_addr(idata->dst_addr) &&
os_memcmp(hapd->own_addr, idata->dst_addr, ETH_ALEN) != 0)
- continue;
+ continue; /* destination address does not match */
/* defer eth_p_oui_deliver until next eloop step as this is
* when it would be triggerd from reading from sock
@@ -726,14 +813,20 @@
data = os_zalloc(sizeof(*data) + idata->data_len);
if (!data)
return 1;
+ wpa_printf(MSG_DEBUG,
+ "RRB(%s): local delivery to %s dst=" MACSTR
+ " oui_suffix=%u data_len=%u data=%p",
+ src_hapd->conf->iface, hapd->conf->iface,
+ MAC2STR(idata->dst_addr), idata->oui_suffix,
+ (unsigned int) idata->data_len, data);
- os_memcpy(data->src_addr, idata->src_hapd->own_addr, ETH_ALEN);
+ os_memcpy(data->src_addr, src_hapd->own_addr, ETH_ALEN);
os_memcpy(data->dst_addr, idata->dst_addr, ETH_ALEN);
os_memcpy(data + 1, idata->data, idata->data_len);
data->data_len = idata->data_len;
data->oui_suffix = idata->oui_suffix;
- dl_list_add(&hapd->l2_oui_queue, &data->list);
+ dl_list_add_tail(&hapd->l2_oui_queue, &data->list);
if (!eloop_is_timeout_registered(hostapd_oui_deliver_later,
hapd, NULL))
@@ -741,7 +834,11 @@
hostapd_oui_deliver_later,
hapd, NULL);
- return 1;
+ /* If dst_addr is a multicast address, do not return any
+ * non-zero value here. Otherwise, the iteration of
+ * for_each_interface() will be stopped. */
+ if (!is_multicast_ether_addr(idata->dst_addr))
+ return 1;
}
return 0;
@@ -757,6 +854,10 @@
struct hostapd_data *hapd = ctx;
struct eth_p_oui_ctx *oui_ctx;
+ wpa_printf(MSG_DEBUG, "RRB(%s): send to dst=" MACSTR
+ " oui_suffix=%u data_len=%u",
+ hapd->conf->iface, MAC2STR(dst), oui_suffix,
+ (unsigned int) data_len);
#ifdef CONFIG_IEEE80211R_AP
if (hapd->iface->interfaces &&
hapd->iface->interfaces->for_each_interface) {
@@ -800,26 +901,32 @@
#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 (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
+ struct vlan_description vlan_desc;
- 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;
+ 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;
+ }
+ } else {
+ sta->vlan_id = vlan_id;
}
wpa_printf(MSG_INFO,
@@ -881,7 +988,7 @@
os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
os_memcpy(&m->u, data, data_len);
- res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0);
+ res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0, NULL, 0, 0);
os_free(m);
return res;
}
@@ -892,18 +999,28 @@
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
+ int ret;
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)
+ ret = hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT);
+
+ /*
+ * The expected return values from hostapd_add_sta_node() are
+ * 0: successfully added STA entry
+ * -EOPNOTSUPP: driver or driver wrapper does not support/need this
+ * operations
+ * any other negative value: error in adding the STA entry */
+ if (ret < 0 && ret != -EOPNOTSUPP)
return NULL;
sta = ap_sta_add(hapd, sta_addr);
if (sta == NULL)
return NULL;
- if (hapd->driver && hapd->driver->add_sta_node)
+ if (ret == 0)
sta->added_unassoc = 1;
+
sta->ft_over_ds = 1;
if (sta->wpa_sm) {
sta->auth_alg = WLAN_AUTH_FT;
@@ -921,6 +1038,34 @@
}
+static int hostapd_wpa_auth_add_sta_ft(void *ctx, const u8 *sta_addr)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, sta_addr);
+ if (!sta)
+ return -1;
+
+ if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
+ (sta->flags & WLAN_STA_MFP) && ap_sta_is_authorized(sta) &&
+ !(hapd->conf->mesh & MESH_ENABLED) && !(sta->added_unassoc)) {
+ /* We could not do this in handle_auth() since there was a
+ * PMF-enabled association for the STA and the new
+ * authentication attempt was not yet fully processed. Now that
+ * we are ready to configure the TK to the driver,
+ * authentication has succeeded and we can clean up the driver
+ * STA entry to avoid issues with any maintained state from the
+ * previous association. */
+ wpa_printf(MSG_DEBUG,
+ "FT: Remove and re-add driver STA entry after successful FT authentication");
+ return ap_sta_re_add(hapd, sta);
+ }
+
+ return 0;
+}
+
+
static int hostapd_wpa_auth_set_vlan(void *ctx, const u8 *sta_addr,
struct vlan_description *vlan)
{
@@ -1282,6 +1427,7 @@
#ifdef CONFIG_IEEE80211R_AP
.send_ft_action = hostapd_wpa_auth_send_ft_action,
.add_sta = hostapd_wpa_auth_add_sta,
+ .add_sta_ft = hostapd_wpa_auth_add_sta_ft,
.add_tspec = hostapd_wpa_auth_add_tspec,
.set_vlan = hostapd_wpa_auth_set_vlan,
.get_vlan = hostapd_wpa_auth_get_vlan,
@@ -1301,6 +1447,22 @@
_conf.tx_status = 1;
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
_conf.ap_mlme = 1;
+
+ if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) &&
+ (hapd->conf->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_NEVER ||
+ (hapd->conf->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_LOCAL_OK &&
+ !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS)))) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ "Disable PTK0 rekey support - replaced with disconnect");
+ _conf.wpa_deny_ptk0_rekey = 1;
+ }
+
+ if (_conf.extended_key_id &&
+ (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID))
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Extended Key ID supported");
+ else
+ _conf.extended_key_id = 0;
+
hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd);
if (hapd->wpa_auth == NULL) {
wpa_printf(MSG_ERROR, "WPA initialization failed.");
@@ -1335,9 +1497,7 @@
hapd->conf->iface;
hapd->l2 = l2_packet_init(ft_iface, NULL, ETH_P_RRB,
hostapd_rrb_receive, hapd, 1);
- if (hapd->l2 == NULL &&
- (hapd->driver == NULL ||
- hapd->driver->send_ether == NULL)) {
+ if (!hapd->l2) {
wpa_printf(MSG_ERROR, "Failed to open l2_packet "
"interface");
return -1;
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 3dcf77a..af0aaca 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -39,20 +39,20 @@
WPA_PTK_GROUP_KEYERROR
} wpa_ptk_group_state;
- Boolean Init;
- Boolean DeauthenticationRequest;
- Boolean AuthenticationRequest;
- Boolean ReAuthenticationRequest;
- Boolean Disconnect;
+ bool Init;
+ bool DeauthenticationRequest;
+ bool AuthenticationRequest;
+ bool ReAuthenticationRequest;
+ bool Disconnect;
u16 disconnect_reason; /* specific reason code to use with Disconnect */
u32 TimeoutCtr;
u32 GTimeoutCtr;
- Boolean TimeoutEvt;
- Boolean EAPOLKeyReceived;
- Boolean EAPOLKeyPairwise;
- Boolean EAPOLKeyRequest;
- Boolean MICVerified;
- Boolean GUpdateStationKeys;
+ bool TimeoutEvt;
+ bool EAPOLKeyReceived;
+ bool EAPOLKeyPairwise;
+ bool EAPOLKeyRequest;
+ bool MICVerified;
+ bool GUpdateStationKeys;
u8 ANonce[WPA_NONCE_LEN];
u8 SNonce[WPA_NONCE_LEN];
u8 alt_SNonce[WPA_NONCE_LEN];
@@ -61,20 +61,22 @@
unsigned int pmk_len;
u8 pmkid[PMKID_LEN]; /* valid if pmkid_set == 1 */
struct wpa_ptk PTK;
- Boolean PTK_valid;
- Boolean pairwise_set;
- Boolean tk_already_set;
+ u8 keyidx_active;
+ bool use_ext_key_id;
+ bool PTK_valid;
+ bool pairwise_set;
+ bool tk_already_set;
int keycount;
- Boolean Pair;
+ bool Pair;
struct wpa_key_replay_counter {
u8 counter[WPA_REPLAY_COUNTER_LEN];
- Boolean valid;
+ bool valid;
} key_replay[RSNA_MAX_EAPOL_RETRIES],
prev_key_replay[RSNA_MAX_EAPOL_RETRIES];
- Boolean PInitAKeys; /* WPA only, not in IEEE 802.11i */
- Boolean PTKRequest; /* not in IEEE 802.11i state machine */
- Boolean has_GTK;
- Boolean PtkGroupInit; /* init request for PTK Group state machine */
+ bool PInitAKeys; /* WPA only, not in IEEE 802.11i */
+ bool PTKRequest; /* not in IEEE 802.11i state machine */
+ bool has_GTK;
+ bool PtkGroupInit; /* init request for PTK Group state machine */
u8 *last_rx_eapol_key; /* starting from IEEE 802.1X header */
size_t last_rx_eapol_key_len;
@@ -102,6 +104,8 @@
u8 *wpa_ie;
size_t wpa_ie_len;
+ u8 *rsnxe;
+ size_t rsnxe_len;
enum {
WPA_VERSION_NO_WPA = 0 /* WPA not used */,
@@ -119,6 +123,8 @@
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[PMK_LEN_MAX];
+ unsigned int pmk_r1_len;
u8 pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name derived from FT Auth
* Request */
u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; /* R0KH-ID from FT Auth Request */
@@ -168,12 +174,12 @@
struct wpa_group *next;
int vlan_id;
- Boolean GInit;
+ bool GInit;
int GKeyDoneStations;
- Boolean GTKReKey;
+ bool GTKReKey;
int GTK_len;
int GN, GM;
- Boolean GTKAuthenticator;
+ bool GTKAuthenticator;
u8 Counter[WPA_NONCE_LEN];
enum {
@@ -185,13 +191,13 @@
u8 GMK[WPA_GMK_LEN];
u8 GTK[2][WPA_GTK_MAX_LEN];
u8 GNonce[WPA_NONCE_LEN];
- Boolean changed;
- Boolean first_sta_seen;
- Boolean reject_4way_hs_for_entropy;
-#ifdef CONFIG_IEEE80211W
+ bool changed;
+ bool first_sta_seen;
+ bool reject_4way_hs_for_entropy;
u8 IGTK[2][WPA_IGTK_MAX_LEN];
+ u8 BIGTK[2][WPA_IGTK_MAX_LEN];
int GN_igtk, GM_igtk;
-#endif /* CONFIG_IEEE80211W */
+ int GN_bigtk, GM_bigtk;
/* Number of references except those in struct wpa_group->next */
unsigned int references;
unsigned int num_setup_iface;
@@ -267,6 +273,7 @@
int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
const u8 *pmkid);
+int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len);
void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
logger_level level, const char *txt);
void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
@@ -289,12 +296,11 @@
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);
-int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
- struct wpa_ptk *ptk);
+ size_t subelem_len, int rsnxe_used);
+int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk);
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);
+void wpa_ft_install_ptk(struct wpa_state_machine *sm, int retry);
int wpa_ft_store_pmk_fils(struct wpa_state_machine *sm, const u8 *pmk_r0,
const u8 *pmk_r0_name);
#endif /* CONFIG_IEEE80211R_AP */
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 8580a5a..8dfd657 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -183,7 +183,6 @@
num_suites++;
}
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
pos += RSN_SELECTOR_LEN;
@@ -194,7 +193,6 @@
pos += RSN_SELECTOR_LEN;
num_suites++;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
@@ -286,13 +284,11 @@
/* 4 PTKSA replay counters when using WMM */
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
}
-#ifdef CONFIG_IEEE80211W
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
capab |= WPA_CAPABILITY_MFPC;
if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
capab |= WPA_CAPABILITY_MFPR;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
if (conf->ocv)
capab |= WPA_CAPABILITY_OCVC;
@@ -301,6 +297,8 @@
if (rsn_testing)
capab |= BIT(8) | BIT(15);
#endif /* CONFIG_RSN_TESTING */
+ if (conf->extended_key_id)
+ capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
WPA_PUT_LE16(pos, capab);
pos += 2;
@@ -314,7 +312,6 @@
pos += PMKID_LEN;
}
-#ifdef CONFIG_IEEE80211W
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION &&
conf->group_mgmt_cipher != WPA_CIPHER_AES_128_CMAC) {
if (2 + 4 > buf + len - pos)
@@ -347,7 +344,6 @@
}
pos += RSN_SELECTOR_LEN;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
@@ -378,6 +374,26 @@
}
+int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
+{
+ u8 *pos = buf;
+
+ if (conf->sae_pwe != 1 && conf->sae_pwe != 2)
+ return 0; /* no supported extended RSN capabilities */
+
+ if (len < 3)
+ return -1;
+
+ *pos++ = WLAN_EID_RSNX;
+ *pos++ = 1;
+ /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
+ * used for now */
+ *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+
+ return pos - buf;
+}
+
+
static u8 * wpa_write_osen(struct wpa_auth_config *conf, u8 *eid)
{
u8 *len;
@@ -411,13 +427,11 @@
/* 4 PTKSA replay counters when using WMM */
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
}
-#ifdef CONFIG_IEEE80211W
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
capab |= WPA_CAPABILITY_MFPC;
if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
capab |= WPA_CAPABILITY_MFPR;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
if (conf->ocv)
capab |= WPA_CAPABILITY_OCVC;
@@ -464,6 +478,11 @@
if (res < 0)
return res;
pos += res;
+ res = wpa_write_rsnxe(&wpa_auth->conf, pos,
+ buf + sizeof(buf) - pos);
+ if (res < 0)
+ return res;
+ pos += res;
}
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) {
@@ -529,12 +548,15 @@
}
-int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
- 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)
+enum wpa_validate_result
+wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm, int freq,
+ const u8 *wpa_ie, size_t wpa_ie_len,
+ const u8 *rsnxe, size_t rsnxe_len,
+ const u8 *mdie, size_t mdie_len,
+ const u8 *owe_dh, size_t owe_dh_len)
{
+ struct wpa_auth_config *conf = &wpa_auth->conf;
struct wpa_ie_data data;
int ciphers, key_mgmt, res, version;
u32 selector;
@@ -607,12 +629,10 @@
else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
selector = RSN_AUTH_KEY_MGMT_FT_PSK;
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
selector = RSN_AUTH_KEY_MGMT_PSK_SHA256;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
else if (data.key_mgmt & WPA_KEY_MGMT_SAE)
selector = RSN_AUTH_KEY_MGMT_SAE;
@@ -717,12 +737,10 @@
else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211W
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
else if (key_mgmt & WPA_KEY_MGMT_SAE)
sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE;
@@ -758,7 +776,6 @@
return WPA_INVALID_PAIRWISE;
}
-#ifdef CONFIG_IEEE80211W
if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
if (!(data.capabilities & WPA_CAPABILITY_MFPC)) {
wpa_printf(MSG_DEBUG, "Management frame protection "
@@ -807,7 +824,6 @@
"Management frame protection cannot use TKIP");
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
@@ -835,19 +851,18 @@
"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");
- return WPA_INVALID_AKMP;
- }
#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP2
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP &&
+ ((conf->dpp_pfs == 1 && !owe_dh) ||
+ (conf->dpp_pfs == 2 && owe_dh))) {
+ wpa_printf(MSG_DEBUG, "DPP: PFS %s",
+ conf->dpp_pfs == 1 ? "required" : "not allowed");
+ return WPA_DENIED_OTHER_REASON;
+ }
+#endif /* CONFIG_DPP2 */
+
sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0);
if (sm->pairwise < 0)
return WPA_INVALID_PAIRWISE;
@@ -932,6 +947,23 @@
}
#endif /* CONFIG_DPP */
+ if (conf->extended_key_id && sm->wpa == WPA_VERSION_WPA2 &&
+ sm->pairwise != WPA_CIPHER_TKIP &&
+ (data.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) {
+ sm->use_ext_key_id = true;
+ if (conf->extended_key_id == 2 &&
+ !wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
+ !wpa_key_mgmt_fils(sm->wpa_key_mgmt))
+ sm->keyidx_active = 1;
+ else
+ sm->keyidx_active = 0;
+ wpa_printf(MSG_DEBUG,
+ "RSN: Extended Key ID supported (start with %d)",
+ sm->keyidx_active);
+ } else {
+ sm->use_ext_key_id = false;
+ }
+
if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
os_free(sm->wpa_ie);
sm->wpa_ie = os_malloc(wpa_ie_len);
@@ -941,6 +973,21 @@
os_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len);
sm->wpa_ie_len = wpa_ie_len;
+ if (rsnxe && rsnxe_len) {
+ if (!sm->rsnxe || sm->rsnxe_len < rsnxe_len) {
+ os_free(sm->rsnxe);
+ sm->rsnxe = os_malloc(rsnxe_len);
+ if (!sm->rsnxe)
+ return WPA_ALLOC_FAIL;
+ }
+ os_memcpy(sm->rsnxe, rsnxe, rsnxe_len);
+ sm->rsnxe_len = rsnxe_len;
+ } else {
+ os_free(sm->rsnxe);
+ sm->rsnxe = NULL;
+ sm->rsnxe_len = 0;
+ }
+
return WPA_IE_OK;
}
@@ -975,153 +1022,6 @@
#endif /* CONFIG_HS20 */
-/**
- * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
- * @pos: Pointer to the IE header
- * @end: Pointer to the end of the Key Data buffer
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, 1 if end mark is found, -1 on failure
- */
-static int wpa_parse_generic(const u8 *pos, const u8 *end,
- struct wpa_eapol_ie_parse *ie)
-{
- if (pos[1] == 0)
- return 1;
-
- if (pos[1] >= 6 &&
- RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
- pos[2 + WPA_SELECTOR_LEN] == 1 &&
- pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
- ie->wpa_ie = pos;
- ie->wpa_ie_len = pos[1] + 2;
- return 0;
- }
-
- if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) {
- ie->osen = pos;
- ie->osen_len = pos[1] + 2;
- return 0;
- }
-
- if (1 + RSN_SELECTOR_LEN < end - pos &&
- pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
- ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
- ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
- ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
- ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
- return 0;
- }
-
-#ifdef CONFIG_IEEE80211W
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
- ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
- return 0;
- }
-#endif /* CONFIG_IEEE80211W */
-
-#ifdef CONFIG_P2P
- if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
- ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
- ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
- return 0;
- }
-
- if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
- ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG,
- "WPA: IP Address Allocation in EAPOL-Key",
- ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
- return 0;
- }
-#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;
-}
-
-
-/**
- * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs
- * @buf: Pointer to the Key Data buffer
- * @len: Key Data Length
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, -1 on failure
- */
-int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
-{
- const u8 *pos, *end;
- int ret = 0;
-
- os_memset(ie, 0, sizeof(*ie));
- for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) {
- if (pos[0] == 0xdd &&
- ((pos == buf + len - 1) || pos[1] == 0)) {
- /* Ignore padding */
- break;
- }
- if (2 + pos[1] > end - pos) {
- wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
- "underflow (ie=%d len=%d pos=%d)",
- pos[0], pos[1], (int) (pos - buf));
- wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
- buf, len);
- ret = -1;
- break;
- }
- if (*pos == WLAN_EID_RSN) {
- ie->rsn_ie = pos;
- ie->rsn_ie_len = pos[1] + 2;
-#ifdef CONFIG_IEEE80211R_AP
- } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
- ie->mdie = pos;
- ie->mdie_len = pos[1] + 2;
- } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
- ie->ftie = pos;
- ie->ftie_len = pos[1] + 2;
-#endif /* CONFIG_IEEE80211R_AP */
- } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
- ret = wpa_parse_generic(pos, end, ie);
- if (ret < 0)
- break;
- if (ret > 0) {
- ret = 0;
- break;
- }
- } else {
- wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
- "Key Data IE", pos, 2 + pos[1]);
- }
- }
-
- return ret;
-}
-
-
int wpa_auth_uses_mfp(struct wpa_state_machine *sm)
{
return sm ? sm->mgmt_frame_prot : 0;
@@ -1176,3 +1076,23 @@
return pos + res;
}
#endif /* CONFIG_OWE */
+
+
+#ifdef CONFIG_FILS
+u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
+ u8 *pos, size_t max_len,
+ const u8 *req_ies, size_t req_ies_len)
+{
+ int res;
+
+ if (!sm ||
+ sm->wpa_key_mgmt & (WPA_KEY_MGMT_FT_FILS_SHA256 |
+ WPA_KEY_MGMT_FT_FILS_SHA384))
+ return pos;
+
+ res = wpa_write_rsn_ie(&sm->wpa_auth->conf, pos, max_len, NULL);
+ if (res < 0)
+ return pos;
+ return pos + res;
+}
+#endif /* CONFIG_FILS */
diff --git a/src/ap/wpa_auth_ie.h b/src/ap/wpa_auth_ie.h
index a38b206..dd44b9e 100644
--- a/src/ap/wpa_auth_ie.h
+++ b/src/ap/wpa_auth_ie.h
@@ -9,41 +9,6 @@
#ifndef WPA_AUTH_IE_H
#define WPA_AUTH_IE_H
-struct wpa_eapol_ie_parse {
- const u8 *wpa_ie;
- size_t wpa_ie_len;
- const u8 *rsn_ie;
- size_t rsn_ie_len;
- const u8 *pmkid;
- const u8 *gtk;
- size_t gtk_len;
- const u8 *mac_addr;
- size_t mac_addr_len;
-#ifdef CONFIG_IEEE80211W
- const u8 *igtk;
- size_t igtk_len;
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R_AP
- const u8 *mdie;
- size_t mdie_len;
- const u8 *ftie;
- size_t ftie_len;
-#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_P2P
- 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;
-};
-
-int wpa_parse_kde_ies(const u8 *buf, size_t len,
- struct wpa_eapol_ie_parse *ie);
u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
const u8 *data2, size_t data2_len);
int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth);
diff --git a/src/ap/wpa_auth_kay.c b/src/ap/wpa_auth_kay.c
new file mode 100644
index 0000000..46d94b4
--- /dev/null
+++ b/src/ap/wpa_auth_kay.c
@@ -0,0 +1,523 @@
+/*
+ * IEEE 802.1X-2010 KaY Interface
+ * Copyright (c) 2019, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "pae/ieee802_1x_key.h"
+#include "pae/ieee802_1x_kay.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "wpa_auth_kay.h"
+#include "ieee802_1x.h"
+
+
+#define DEFAULT_KEY_LEN 16
+/* secure Connectivity Association Key Name (CKN) */
+#define DEFAULT_CKN_LEN 16
+
+
+static int hapd_macsec_init(void *priv, struct macsec_init_params *params)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->macsec_init)
+ return -1;
+ return hapd->driver->macsec_init(hapd->drv_priv, params);
+}
+
+
+static int hapd_macsec_deinit(void *priv)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->macsec_deinit)
+ return -1;
+ return hapd->driver->macsec_deinit(hapd->drv_priv);
+}
+
+
+static int hapd_macsec_get_capability(void *priv, enum macsec_cap *cap)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->macsec_get_capability)
+ return -1;
+ return hapd->driver->macsec_get_capability(hapd->drv_priv, cap);
+}
+
+
+static int hapd_enable_protect_frames(void *priv, bool enabled)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->enable_protect_frames)
+ return -1;
+ return hapd->driver->enable_protect_frames(hapd->drv_priv, enabled);
+}
+
+
+static int hapd_enable_encrypt(void *priv, bool enabled)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->enable_encrypt)
+ return -1;
+ return hapd->driver->enable_encrypt(hapd->drv_priv, enabled);
+}
+
+
+static int hapd_set_replay_protect(void *priv, bool enabled, u32 window)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->set_replay_protect)
+ return -1;
+ return hapd->driver->set_replay_protect(hapd->drv_priv, enabled,
+ window);
+}
+
+
+static int hapd_set_current_cipher_suite(void *priv, u64 cs)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->set_current_cipher_suite)
+ return -1;
+ return hapd->driver->set_current_cipher_suite(hapd->drv_priv, cs);
+}
+
+
+static int hapd_enable_controlled_port(void *priv, bool enabled)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->enable_controlled_port)
+ return -1;
+ return hapd->driver->enable_controlled_port(hapd->drv_priv, enabled);
+}
+
+
+static int hapd_get_receive_lowest_pn(void *priv, struct receive_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->get_receive_lowest_pn)
+ return -1;
+ return hapd->driver->get_receive_lowest_pn(hapd->drv_priv, sa);
+}
+
+
+static int hapd_get_transmit_next_pn(void *priv, struct transmit_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->get_transmit_next_pn)
+ return -1;
+ return hapd->driver->get_transmit_next_pn(hapd->drv_priv, sa);
+}
+
+
+static int hapd_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->set_transmit_next_pn)
+ return -1;
+ return hapd->driver->set_transmit_next_pn(hapd->drv_priv, sa);
+}
+
+
+static unsigned int conf_offset_val(enum confidentiality_offset co)
+{
+ switch (co) {
+ case CONFIDENTIALITY_OFFSET_30:
+ return 30;
+ break;
+ case CONFIDENTIALITY_OFFSET_50:
+ return 50;
+ default:
+ return 0;
+ }
+}
+
+
+static int hapd_create_receive_sc(void *priv, struct receive_sc *sc,
+ enum validate_frames vf,
+ enum confidentiality_offset co)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->create_receive_sc)
+ return -1;
+ return hapd->driver->create_receive_sc(hapd->drv_priv, sc,
+ conf_offset_val(co), vf);
+}
+
+
+static int hapd_delete_receive_sc(void *priv, struct receive_sc *sc)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->delete_receive_sc)
+ return -1;
+ return hapd->driver->delete_receive_sc(hapd->drv_priv, sc);
+}
+
+
+static int hapd_create_receive_sa(void *priv, struct receive_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->create_receive_sa)
+ return -1;
+ return hapd->driver->create_receive_sa(hapd->drv_priv, sa);
+}
+
+
+static int hapd_delete_receive_sa(void *priv, struct receive_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->delete_receive_sa)
+ return -1;
+ return hapd->driver->delete_receive_sa(hapd->drv_priv, sa);
+}
+
+
+static int hapd_enable_receive_sa(void *priv, struct receive_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->enable_receive_sa)
+ return -1;
+ return hapd->driver->enable_receive_sa(hapd->drv_priv, sa);
+}
+
+
+static int hapd_disable_receive_sa(void *priv, struct receive_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->disable_receive_sa)
+ return -1;
+ return hapd->driver->disable_receive_sa(hapd->drv_priv, sa);
+}
+
+
+static int
+hapd_create_transmit_sc(void *priv, struct transmit_sc *sc,
+ enum confidentiality_offset co)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->create_transmit_sc)
+ return -1;
+ return hapd->driver->create_transmit_sc(hapd->drv_priv, sc,
+ conf_offset_val(co));
+}
+
+
+static int hapd_delete_transmit_sc(void *priv, struct transmit_sc *sc)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->delete_transmit_sc)
+ return -1;
+ return hapd->driver->delete_transmit_sc(hapd->drv_priv, sc);
+}
+
+
+static int hapd_create_transmit_sa(void *priv, struct transmit_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->create_transmit_sa)
+ return -1;
+ return hapd->driver->create_transmit_sa(hapd->drv_priv, sa);
+}
+
+
+static int hapd_delete_transmit_sa(void *priv, struct transmit_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->delete_transmit_sa)
+ return -1;
+ return hapd->driver->delete_transmit_sa(hapd->drv_priv, sa);
+}
+
+
+static int hapd_enable_transmit_sa(void *priv, struct transmit_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->enable_transmit_sa)
+ return -1;
+ return hapd->driver->enable_transmit_sa(hapd->drv_priv, sa);
+}
+
+
+static int hapd_disable_transmit_sa(void *priv, struct transmit_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->disable_transmit_sa)
+ return -1;
+ return hapd->driver->disable_transmit_sa(hapd->drv_priv, sa);
+}
+
+
+int ieee802_1x_alloc_kay_sm_hapd(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct ieee802_1x_kay_ctx *kay_ctx;
+ struct ieee802_1x_kay *res = NULL;
+ enum macsec_policy policy;
+
+ ieee802_1x_dealloc_kay_sm_hapd(hapd);
+
+ if (!hapd->conf || hapd->conf->macsec_policy == 0)
+ return 0;
+
+ if (hapd->conf->macsec_policy == 1) {
+ if (hapd->conf->macsec_integ_only == 1)
+ policy = SHOULD_SECURE;
+ else
+ policy = SHOULD_ENCRYPT;
+ } else {
+ policy = DO_NOT_SECURE;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: if_name=%s", __func__, hapd->conf->iface);
+ kay_ctx = os_zalloc(sizeof(*kay_ctx));
+ if (!kay_ctx)
+ return -1;
+
+ kay_ctx->ctx = hapd;
+
+ kay_ctx->macsec_init = hapd_macsec_init;
+ kay_ctx->macsec_deinit = hapd_macsec_deinit;
+ kay_ctx->macsec_get_capability = hapd_macsec_get_capability;
+ kay_ctx->enable_protect_frames = hapd_enable_protect_frames;
+ kay_ctx->enable_encrypt = hapd_enable_encrypt;
+ kay_ctx->set_replay_protect = hapd_set_replay_protect;
+ kay_ctx->set_current_cipher_suite = hapd_set_current_cipher_suite;
+ kay_ctx->enable_controlled_port = hapd_enable_controlled_port;
+ kay_ctx->get_receive_lowest_pn = hapd_get_receive_lowest_pn;
+ kay_ctx->get_transmit_next_pn = hapd_get_transmit_next_pn;
+ kay_ctx->set_transmit_next_pn = hapd_set_transmit_next_pn;
+ kay_ctx->create_receive_sc = hapd_create_receive_sc;
+ kay_ctx->delete_receive_sc = hapd_delete_receive_sc;
+ kay_ctx->create_receive_sa = hapd_create_receive_sa;
+ kay_ctx->delete_receive_sa = hapd_delete_receive_sa;
+ kay_ctx->enable_receive_sa = hapd_enable_receive_sa;
+ kay_ctx->disable_receive_sa = hapd_disable_receive_sa;
+ kay_ctx->create_transmit_sc = hapd_create_transmit_sc;
+ kay_ctx->delete_transmit_sc = hapd_delete_transmit_sc;
+ kay_ctx->create_transmit_sa = hapd_create_transmit_sa;
+ kay_ctx->delete_transmit_sa = hapd_delete_transmit_sa;
+ kay_ctx->enable_transmit_sa = hapd_enable_transmit_sa;
+ kay_ctx->disable_transmit_sa = hapd_disable_transmit_sa;
+
+ res = ieee802_1x_kay_init(kay_ctx, policy,
+ hapd->conf->macsec_replay_protect,
+ hapd->conf->macsec_replay_window,
+ hapd->conf->macsec_port,
+ hapd->conf->mka_priority, hapd->conf->iface,
+ hapd->own_addr);
+ /* ieee802_1x_kay_init() frees kay_ctx on failure */
+ if (!res)
+ return -1;
+
+ hapd->kay = res;
+
+ return 0;
+}
+
+
+void ieee802_1x_dealloc_kay_sm_hapd(struct hostapd_data *hapd)
+{
+ if (!hapd->kay)
+ return;
+
+ ieee802_1x_kay_deinit(hapd->kay);
+ hapd->kay = NULL;
+}
+
+
+static int ieee802_1x_auth_get_session_id(struct hostapd_data *hapd,
+ struct sta_info *sta, u8 *sid,
+ size_t *len)
+{
+ const u8 *session_id;
+ size_t id_len, need_len;
+
+ session_id = ieee802_1x_get_session_id(sta->eapol_sm, &id_len);
+ if (!session_id) {
+ wpa_printf(MSG_DEBUG,
+ "MACsec: Failed to get SessionID from EAPOL state machines");
+ return -1;
+ }
+
+ need_len = 1 + 2 * 32 /* random size */;
+ if (need_len > id_len) {
+ wpa_printf(MSG_DEBUG, "EAP Session-Id not long enough");
+ return -1;
+ }
+
+ os_memcpy(sid, session_id, need_len);
+ *len = need_len;
+
+ return 0;
+}
+
+
+static int ieee802_1x_auth_get_msk(struct hostapd_data *hapd,
+ struct sta_info *sta, u8 *msk, size_t *len)
+{
+ const u8 *key;
+ size_t keylen;
+
+ if (!sta->eapol_sm)
+ return -1;
+
+ key = ieee802_1x_get_key(sta->eapol_sm, &keylen);
+ if (key == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "MACsec: Failed to get MSK from EAPOL state machines");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "MACsec: Successfully fetched key (len=%lu)",
+ (unsigned long) keylen);
+ wpa_hexdump_key(MSG_DEBUG, "MSK: ", key, keylen);
+
+ if (keylen > *len)
+ keylen = *len;
+ os_memcpy(msk, key, keylen);
+ *len = keylen;
+
+ return 0;
+}
+
+
+void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ u8 *sid;
+ size_t sid_len = 128;
+ struct mka_key_name *ckn;
+ struct mka_key *cak;
+ struct mka_key *msk;
+ void *res = NULL;
+
+ if (!hapd->kay || hapd->kay->policy == DO_NOT_SECURE)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: External notification - Create MKA for "
+ MACSTR, MAC2STR(sta->addr));
+
+ msk = os_zalloc(sizeof(*msk));
+ sid = os_zalloc(sid_len);
+ ckn = os_zalloc(sizeof(*ckn));
+ cak = os_zalloc(sizeof(*cak));
+ if (!msk || !sid || !ckn || !cak)
+ goto fail;
+
+ msk->len = DEFAULT_KEY_LEN;
+ if (ieee802_1x_auth_get_msk(hapd, sta, msk->key, &msk->len)) {
+ wpa_printf(MSG_ERROR, "IEEE 802.1X: Could not get MSK");
+ goto fail;
+ }
+
+ if (ieee802_1x_auth_get_session_id(hapd, sta, sid, &sid_len))
+ {
+ wpa_printf(MSG_ERROR,
+ "IEEE 802.1X: Could not get EAP Session Id");
+ goto fail;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "own_addr", hapd->own_addr, ETH_ALEN);
+ wpa_hexdump(MSG_DEBUG, "sta_addr", sta->addr, ETH_ALEN);
+
+ /* Derive CAK from MSK */
+ cak->len = DEFAULT_KEY_LEN;
+ if (ieee802_1x_cak_aes_cmac(msk->key, msk->len, hapd->own_addr,
+ sta->addr, cak->key, cak->len)) {
+ wpa_printf(MSG_ERROR, "IEEE 802.1X: Deriving CAK failed");
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "Derived CAK", cak->key, cak->len);
+
+ /* Derive CKN from MSK */
+ ckn->len = DEFAULT_CKN_LEN;
+ if (ieee802_1x_ckn_aes_cmac(msk->key, msk->len, hapd->own_addr,
+ sta->addr, sid, sid_len, ckn->name)) {
+ wpa_printf(MSG_ERROR, "IEEE 802.1X: Deriving CKN failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "Derived CKN", ckn->name, ckn->len);
+
+ res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, EAP_EXCHANGE,
+ true);
+
+fail:
+ bin_clear_free(msk, sizeof(*msk));
+ os_free(sid);
+ os_free(ckn);
+ bin_clear_free(cak, sizeof(*cak));
+
+ return res;
+}
+
+
+void * ieee802_1x_create_preshared_mka_hapd(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct mka_key *cak;
+ struct mka_key_name *ckn;
+ void *res = NULL;
+
+ if ((hapd->conf->mka_psk_set & MKA_PSK_SET) != MKA_PSK_SET)
+ goto end;
+
+ ckn = os_zalloc(sizeof(*ckn));
+ if (!ckn)
+ goto end;
+
+ cak = os_zalloc(sizeof(*cak));
+ if (!cak)
+ goto free_ckn;
+
+ if (ieee802_1x_alloc_kay_sm_hapd(hapd, sta) < 0 || !hapd->kay)
+ goto free_cak;
+
+ if (hapd->kay->policy == DO_NOT_SECURE)
+ goto dealloc;
+
+ cak->len = hapd->conf->mka_cak_len;
+ os_memcpy(cak->key, hapd->conf->mka_cak, cak->len);
+
+ ckn->len = hapd->conf->mka_ckn_len;;
+ os_memcpy(ckn->name, hapd->conf->mka_ckn, ckn->len);
+
+ res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, PSK, true);
+ if (res)
+ goto free_cak;
+
+dealloc:
+ /* Failed to create MKA */
+ ieee802_1x_dealloc_kay_sm_hapd(hapd);
+free_cak:
+ os_free(cak);
+free_ckn:
+ os_free(ckn);
+end:
+ return res;
+}
diff --git a/src/ap/wpa_auth_kay.h b/src/ap/wpa_auth_kay.h
new file mode 100644
index 0000000..0dd7e41
--- /dev/null
+++ b/src/ap/wpa_auth_kay.h
@@ -0,0 +1,51 @@
+/*
+ * IEEE 802.1X-2010 KaY Interface
+ * Copyright (c) 2019, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_AUTH_KAY_H
+#define WPA_AUTH_KAY_H
+
+#ifdef CONFIG_MACSEC
+
+int ieee802_1x_alloc_kay_sm_hapd(struct hostapd_data *hapd,
+ struct sta_info *sta);
+void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
+ struct sta_info *sta);
+void ieee802_1x_dealloc_kay_sm_hapd(struct hostapd_data *hapd);
+
+void * ieee802_1x_create_preshared_mka_hapd(struct hostapd_data *hapd,
+ struct sta_info *sta);
+
+#else /* CONFIG_MACSEC */
+
+static inline int ieee802_1x_alloc_kay_sm_hapd(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ return 0;
+}
+
+static inline void *
+ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ return NULL;
+}
+
+static inline void ieee802_1x_dealloc_kay_sm_hapd(struct hostapd_data *hapd)
+{
+}
+
+static inline void *
+ieee802_1x_create_preshared_mka_hapd(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ return NULL;
+}
+
+#endif /* CONFIG_MACSEC */
+
+#endif /* WPA_AUTH_KAY_H */
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 6161cdb..dc8aa8f 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -125,6 +125,7 @@
os_memcpy(p->addr, mac_addr, ETH_ALEN);
os_memcpy(p->p2p_dev_addr, p2p_dev_addr, ETH_ALEN);
os_memcpy(p->psk, psk, PMK_LEN);
+ p->wps = 1;
if (hapd->new_psk_cb) {
hapd->new_psk_cb(hapd->new_psk_cb_ctx, mac_addr, p2p_dev_addr,
@@ -137,16 +138,17 @@
if (ssid->wpa_psk_file) {
FILE *f;
char hex[PMK_LEN * 2 + 1];
+
/* Add the new PSK to PSK list file */
f = fopen(ssid->wpa_psk_file, "a");
- if (f == NULL) {
- wpa_printf(MSG_DEBUG, "Failed to add the PSK to "
- "'%s'", ssid->wpa_psk_file);
+ if (!f) {
+ wpa_printf(MSG_DEBUG, "Failed to add the PSK to '%s'",
+ ssid->wpa_psk_file);
return -1;
}
wpa_snprintf_hex(hex, sizeof(hex), psk, psk_len);
- fprintf(f, MACSTR " %s\n", MAC2STR(mac_addr), hex);
+ fprintf(f, "wps=1 " MACSTR " %s\n", MAC2STR(mac_addr), hex);
fclose(f);
}
@@ -269,6 +271,44 @@
}
+static int hostapd_wps_lookup_pskfile_cb(void *ctx, const u8 *mac_addr,
+ const u8 **psk)
+{
+ const struct hostapd_data *hapd = ctx;
+ const struct hostapd_wpa_psk *wpa_psk;
+ const u8 *any_psk = NULL;
+ const u8 *dev_psk = NULL;
+
+ for (wpa_psk = hapd->conf->ssid.wpa_psk; wpa_psk;
+ wpa_psk = wpa_psk->next) {
+ if (!wpa_psk->wps)
+ continue;
+
+ if (!any_psk && is_zero_ether_addr(wpa_psk->addr))
+ any_psk = wpa_psk->psk;
+
+ if (mac_addr && !dev_psk &&
+ os_memcmp(mac_addr, wpa_psk->addr, ETH_ALEN) == 0) {
+ dev_psk = wpa_psk->psk;
+ break;
+ }
+ }
+
+ if (dev_psk) {
+ *psk = dev_psk;
+ } else if (any_psk) {
+ *psk = any_psk;
+ } else {
+ *psk = NULL;
+ wpa_printf(MSG_DEBUG,
+ "WPS: No appropriate PSK in wpa_psk_file");
+ return 0;
+ }
+
+ return 1;
+}
+
+
static void wps_reload_config(void *eloop_data, void *user_ctx)
{
struct hostapd_iface *iface = eloop_data;
@@ -324,6 +364,13 @@
bss->ssid.ssid_set = 1;
}
+#ifdef CONFIG_NO_TKIP
+ if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK |
+ WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
+ bss->wpa = 2;
+ else
+ bss->wpa = 0;
+#else /* CONFIG_NO_TKIP */
if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
(cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
bss->wpa = 3;
@@ -333,6 +380,7 @@
bss->wpa = 1;
else
bss->wpa = 0;
+#endif /* CONFIG_NO_TKIP */
if (bss->wpa) {
if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA))
@@ -347,8 +395,10 @@
else
bss->wpa_pairwise |= WPA_CIPHER_CCMP;
}
+#ifndef CONFIG_NO_TKIP
if (cred->encr_type & WPS_ENCR_TKIP)
bss->wpa_pairwise |= WPA_CIPHER_TKIP;
+#endif /* CONFIG_NO_TKIP */
bss->rsn_pairwise = bss->wpa_pairwise;
bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa,
bss->wpa_pairwise,
@@ -358,12 +408,10 @@
(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) {
@@ -521,6 +569,13 @@
fprintf(nconf, "\n");
}
+#ifdef CONFIG_NO_TKIP
+ if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK |
+ WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
+ wpa = 2;
+ else
+ wpa = 0;
+#else /* CONFIG_NO_TKIP */
if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
(cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
wpa = 3;
@@ -530,12 +585,11 @@
wpa = 1;
else
wpa = 0;
+#endif /* CONFIG_NO_TKIP */
if (wpa) {
char *prefix;
-#ifdef CONFIG_IEEE80211W
int sae = 0;
-#endif /* CONFIG_IEEE80211W */
fprintf(nconf, "wpa=%d\n", wpa);
@@ -553,13 +607,10 @@
(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);
@@ -567,7 +618,6 @@
}
if (sae)
fprintf(nconf, "sae_require_mfp=1\n");
-#endif /* CONFIG_IEEE80211W */
fprintf(nconf, "wpa_pairwise=");
prefix = "";
@@ -579,9 +629,11 @@
prefix = " ";
}
+#ifndef CONFIG_NO_TKIP
if (cred->encr_type & WPS_ENCR_TKIP) {
fprintf(nconf, "%sTKIP", prefix);
}
+#endif /* CONFIG_NO_TKIP */
fprintf(nconf, "\n");
if (cred->key_len >= 8 && cred->key_len < 64) {
@@ -619,8 +671,10 @@
(str_starts(buf, "ssid=") ||
str_starts(buf, "ssid2=") ||
str_starts(buf, "auth_algs=") ||
+#ifdef CONFIG_WEP
str_starts(buf, "wep_default_key=") ||
str_starts(buf, "wep_key") ||
+#endif /* CONFIG_WEP */
str_starts(buf, "wps_state=") ||
(pmf_changed && str_starts(buf, "ieee80211w=")) ||
str_starts(buf, "wpa=") ||
@@ -993,6 +1047,21 @@
}
+static int hostapd_wps_set_application_ext(struct hostapd_data *hapd,
+ struct wps_context *wps)
+{
+ wpabuf_free(wps->dev.application_ext);
+
+ if (!hapd->conf->wps_application_ext) {
+ wps->dev.application_ext = NULL;
+ return 0;
+ }
+
+ wps->dev.application_ext = wpabuf_dup(hapd->conf->wps_application_ext);
+ return wps->dev.application_ext ? 0 : -1;
+}
+
+
static void hostapd_free_wps(struct wps_context *wps)
{
int i;
@@ -1082,7 +1151,8 @@
os_memcpy(wps->dev.pri_dev_type, hapd->conf->device_type,
WPS_DEV_TYPE_LEN);
- if (hostapd_wps_set_vendor_ext(hapd, wps) < 0)
+ if (hostapd_wps_set_vendor_ext(hapd, wps) < 0 ||
+ hostapd_wps_set_application_ext(hapd, wps) < 0)
goto fail;
wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
@@ -1110,12 +1180,24 @@
wps->encr_types_rsn |= WPS_ENCR_AES;
}
if (conf->rsn_pairwise & WPA_CIPHER_TKIP) {
+#ifdef CONFIG_NO_TKIP
+ wpa_printf(MSG_INFO, "WPS: TKIP not supported");
+ goto fail;
+#else /* CONFIG_NO_TKIP */
wps->encr_types |= WPS_ENCR_TKIP;
wps->encr_types_rsn |= WPS_ENCR_TKIP;
+#endif /* CONFIG_NO_TKIP */
}
}
if (conf->wpa & WPA_PROTO_WPA) {
+#ifdef CONFIG_NO_TKIP
+ if (!(conf->wpa & WPA_PROTO_RSN)) {
+ wpa_printf(MSG_INFO, "WPS: WPA(v1) not supported");
+ goto fail;
+ }
+ conf->wpa &= ~WPA_PROTO_WPA;
+#else /* CONFIG_NO_TKIP */
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
wps->auth_types |= WPS_AUTH_WPAPSK;
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
@@ -1129,6 +1211,7 @@
wps->encr_types |= WPS_ENCR_TKIP;
wps->encr_types_wpa |= WPS_ENCR_TKIP;
}
+#endif /* CONFIG_NO_TKIP */
}
if (conf->ssid.security_policy == SECURITY_PLAINTEXT) {
@@ -1148,6 +1231,7 @@
wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
conf->ssid.wpa_psk->psk, PMK_LEN);
wps->network_key_len = 2 * PMK_LEN;
+#ifdef CONFIG_WEP
} else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
wps->network_key = os_malloc(conf->ssid.wep.len[0]);
if (wps->network_key == NULL)
@@ -1155,6 +1239,7 @@
os_memcpy(wps->network_key, conf->ssid.wep.key[0],
conf->ssid.wep.len[0]);
wps->network_key_len = conf->ssid.wep.len[0];
+#endif /* CONFIG_WEP */
}
if (conf->ssid.wpa_psk) {
@@ -1166,10 +1251,17 @@
wps->ap_encr_type = wps->encr_types;
if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) {
/* Override parameters to enable security by default */
+#ifdef CONFIG_NO_TKIP
+ wps->auth_types = WPS_AUTH_WPA2PSK;
+ wps->encr_types = WPS_ENCR_AES;
+ wps->encr_types_rsn = WPS_ENCR_AES;
+ wps->encr_types_wpa = WPS_ENCR_AES;
+#else /* CONFIG_NO_TKIP */
wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
wps->encr_types_rsn = WPS_ENCR_AES | WPS_ENCR_TKIP;
wps->encr_types_wpa = WPS_ENCR_AES | WPS_ENCR_TKIP;
+#endif /* CONFIG_NO_TKIP */
}
if ((hapd->conf->multi_ap & FRONTHAUL_BSS) &&
@@ -1205,14 +1297,13 @@
cfg.pin_needed_cb = hostapd_wps_pin_needed_cb;
cfg.reg_success_cb = hostapd_wps_reg_success_cb;
cfg.enrollee_seen_cb = hostapd_wps_enrollee_seen_cb;
+ cfg.lookup_pskfile_cb = hostapd_wps_lookup_pskfile_cb;
cfg.cb_ctx = hapd;
cfg.skip_cred_build = conf->skip_cred_build;
cfg.extra_cred = conf->extra_cred;
cfg.extra_cred_len = conf->extra_cred_len;
cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) &&
conf->skip_cred_build;
- if (conf->ssid.security_policy == SECURITY_STATIC_WEP)
- cfg.static_wep_only = 1;
cfg.dualband = interface_count(hapd->iface) > 1;
if ((wps->dev.rf_bands & (WPS_RF_50GHZ | WPS_RF_24GHZ)) ==
(WPS_RF_50GHZ | WPS_RF_24GHZ))
@@ -1319,6 +1410,7 @@
#endif /* CONFIG_WPS_UPNP */
hostapd_wps_set_vendor_ext(hapd, hapd->wps);
+ hostapd_wps_set_application_ext(hapd, hapd->wps);
if (hapd->conf->wps_state)
wps_registrar_update_ie(hapd->wps->registrar);
@@ -1425,6 +1517,7 @@
data->count++;
wps_registrar_wps_cancel(hapd->wps->registrar);
ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_CANCEL);
}
return 0;
@@ -1748,8 +1841,10 @@
if (os_strncmp(auth, "OPEN", 4) == 0)
cred.auth_type = WPS_AUTH_OPEN;
+#ifndef CONFIG_NO_TKIP
else if (os_strncmp(auth, "WPAPSK", 6) == 0)
cred.auth_type = WPS_AUTH_WPAPSK;
+#endif /* CONFIG_NO_TKIP */
else if (os_strncmp(auth, "WPA2PSK", 7) == 0)
cred.auth_type = WPS_AUTH_WPA2PSK;
else
@@ -1758,8 +1853,10 @@
if (encr) {
if (os_strncmp(encr, "NONE", 4) == 0)
cred.encr_type = WPS_ENCR_NONE;
+#ifndef CONFIG_NO_TKIP
else if (os_strncmp(encr, "TKIP", 4) == 0)
cred.encr_type = WPS_ENCR_TKIP;
+#endif /* CONFIG_NO_TKIP */
else if (os_strncmp(encr, "CCMP", 4) == 0)
cred.encr_type = WPS_ENCR_AES;
else
diff --git a/src/common/Makefile b/src/common/Makefile
index e703630..ccb280e 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -9,7 +9,6 @@
include ../lib.rules
CFLAGS += -DCONFIG_IEEE80211R
-CFLAGS += -DCONFIG_IEEE80211W
CFLAGS += -DCONFIG_HS20
CFLAGS += -DCONFIG_SAE
CFLAGS += -DCONFIG_SUITE
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
index 30c5247..a58bf66 100644
--- a/src/common/common_module_tests.c
+++ b/src/common/common_module_tests.c
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "utils/module_tests.h"
#include "crypto/crypto.h"
+#include "crypto/dh_groups.h"
#include "ieee802_11_common.h"
#include "ieee802_11_defs.h"
#include "gas.h"
@@ -258,6 +259,7 @@
/* 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 *ssid = "byteme";
const char *pw = "mekmitasdigoat";
const char *pwid = "psk4internet";
const u8 local_rand[] = {
@@ -338,6 +340,72 @@
};
struct wpabuf *buf = NULL;
struct crypto_bignum *mask = NULL;
+ const u8 pwe_19_x[32] = {
+ 0xc9, 0x30, 0x49, 0xb9, 0xe6, 0x40, 0x00, 0xf8,
+ 0x48, 0x20, 0x16, 0x49, 0xe9, 0x99, 0xf2, 0xb5,
+ 0xc2, 0x2d, 0xea, 0x69, 0xb5, 0x63, 0x2c, 0x9d,
+ 0xf4, 0xd6, 0x33, 0xb8, 0xaa, 0x1f, 0x6c, 0x1e
+ };
+ const u8 pwe_19_y[32] = {
+ 0x73, 0x63, 0x4e, 0x94, 0xb5, 0x3d, 0x82, 0xe7,
+ 0x38, 0x3a, 0x8d, 0x25, 0x81, 0x99, 0xd9, 0xdc,
+ 0x1a, 0x5e, 0xe8, 0x26, 0x9d, 0x06, 0x03, 0x82,
+ 0xcc, 0xbf, 0x33, 0xe6, 0x14, 0xff, 0x59, 0xa0
+ };
+ const u8 pwe_15[384] = {
+ 0x69, 0x68, 0x73, 0x65, 0x8f, 0x65, 0x31, 0x42,
+ 0x9f, 0x97, 0x39, 0x6f, 0xb8, 0x5f, 0x89, 0xe1,
+ 0xfc, 0xd2, 0xf6, 0x92, 0x19, 0xa9, 0x0e, 0x82,
+ 0x2f, 0xf7, 0xf4, 0xbc, 0x0b, 0xd8, 0xa7, 0x9f,
+ 0xf0, 0x80, 0x35, 0x31, 0x6f, 0xca, 0xe1, 0xa5,
+ 0x39, 0x77, 0xdc, 0x11, 0x2b, 0x0b, 0xfe, 0x2e,
+ 0x6f, 0x65, 0x6d, 0xc7, 0xd4, 0xa4, 0x5b, 0x08,
+ 0x1f, 0xd9, 0xbb, 0xe2, 0x22, 0x85, 0x31, 0x81,
+ 0x79, 0x70, 0xbe, 0xa1, 0x66, 0x58, 0x4a, 0x09,
+ 0x3c, 0x57, 0x34, 0x3c, 0x9d, 0x57, 0x8f, 0x42,
+ 0x58, 0xd0, 0x39, 0x81, 0xdb, 0x8f, 0x79, 0xa2,
+ 0x1b, 0x01, 0xcd, 0x27, 0xc9, 0xae, 0xcf, 0xcb,
+ 0x9c, 0xdb, 0x1f, 0x84, 0xb8, 0x88, 0x4e, 0x8f,
+ 0x50, 0x66, 0xb4, 0x29, 0x83, 0x1e, 0xb9, 0x89,
+ 0x0c, 0xa5, 0x47, 0x21, 0xba, 0x10, 0xd5, 0xaa,
+ 0x1a, 0x80, 0xce, 0xf1, 0x4c, 0xad, 0x16, 0xda,
+ 0x57, 0xb2, 0x41, 0x8a, 0xbe, 0x4b, 0x8c, 0xb0,
+ 0xb2, 0xeb, 0xf7, 0xa8, 0x0e, 0x3e, 0xcf, 0x22,
+ 0x8f, 0xd8, 0xb6, 0xdb, 0x79, 0x9c, 0x9b, 0x80,
+ 0xaf, 0xd7, 0x14, 0xad, 0x51, 0x82, 0xf4, 0x64,
+ 0xb6, 0x3f, 0x4c, 0x6c, 0xe5, 0x3f, 0xaa, 0x6f,
+ 0xbf, 0x3d, 0xc2, 0x3f, 0x77, 0xfd, 0xcb, 0xe1,
+ 0x9c, 0xe3, 0x1e, 0x8a, 0x0e, 0x97, 0xe2, 0x2b,
+ 0xe2, 0xdd, 0x37, 0x39, 0x88, 0xc2, 0x8e, 0xbe,
+ 0xfa, 0xac, 0x3d, 0x5b, 0x62, 0x2e, 0x1e, 0x74,
+ 0xa0, 0x9a, 0xf8, 0xed, 0xfa, 0xe1, 0xce, 0x9c,
+ 0xab, 0xbb, 0xdc, 0x36, 0xb1, 0x28, 0x46, 0x3c,
+ 0x7e, 0xa8, 0xbd, 0xb9, 0x36, 0x4c, 0x26, 0x75,
+ 0xe0, 0x17, 0x73, 0x1f, 0xe0, 0xfe, 0xf6, 0x49,
+ 0xfa, 0xa0, 0x45, 0xf4, 0x44, 0x05, 0x20, 0x27,
+ 0x25, 0xc2, 0x99, 0xde, 0x27, 0x8b, 0x70, 0xdc,
+ 0x54, 0x60, 0x90, 0x02, 0x1e, 0x29, 0x97, 0x9a,
+ 0xc4, 0xe7, 0xb6, 0xf5, 0x8b, 0xae, 0x7c, 0x34,
+ 0xaa, 0xef, 0x9b, 0xc6, 0x30, 0xf2, 0x80, 0x8d,
+ 0x80, 0x78, 0xc2, 0x55, 0x63, 0xa0, 0xa1, 0x38,
+ 0x70, 0xfb, 0xf4, 0x74, 0x8d, 0xcd, 0x87, 0x90,
+ 0xb4, 0x54, 0xc3, 0x75, 0xdf, 0x10, 0xc5, 0xb6,
+ 0xb2, 0x08, 0x59, 0x61, 0xe6, 0x68, 0xa5, 0x82,
+ 0xf8, 0x8f, 0x47, 0x30, 0x43, 0xb4, 0xdc, 0x31,
+ 0xfc, 0xbc, 0x69, 0xe7, 0xb4, 0x94, 0xb0, 0x6a,
+ 0x60, 0x59, 0x80, 0x2e, 0xd3, 0xa4, 0xe8, 0x97,
+ 0xa2, 0xa3, 0xc9, 0x08, 0x4b, 0x27, 0x6c, 0xc1,
+ 0x37, 0xe8, 0xfc, 0x5c, 0xe2, 0x54, 0x30, 0x3e,
+ 0xf8, 0xfe, 0xa2, 0xfc, 0xbb, 0xbd, 0x88, 0x6c,
+ 0x92, 0xa3, 0x2a, 0x40, 0x7a, 0x2c, 0x22, 0x38,
+ 0x8c, 0x86, 0x86, 0xfe, 0xb9, 0xd4, 0x6b, 0xd6,
+ 0x47, 0x88, 0xa7, 0xf6, 0x8e, 0x0f, 0x14, 0xad,
+ 0x1e, 0xac, 0xcf, 0x33, 0x01, 0x99, 0xc1, 0x62
+ };
+ int pt_groups[] = { 19, 20, 21, 25, 26, 28, 29, 30, 15, 0 };
+ struct sae_pt *pt_info, *pt;
+ const u8 addr1b[ETH_ALEN] = { 0x00, 0x09, 0x5b, 0x66, 0xec, 0x1e };
+ const u8 addr2b[ETH_ALEN] = { 0x00, 0x0b, 0x6b, 0xd9, 0x02, 0x46 };
os_memset(&sae, 0, sizeof(sae));
buf = wpabuf_alloc(1000);
@@ -366,7 +434,8 @@
goto fail;
/* Check that output matches the test vector */
- sae_write_commit(&sae, buf, NULL, pwid);
+ if (sae_write_commit(&sae, buf, NULL, pwid) < 0)
+ goto fail;
wpa_hexdump_buf(MSG_DEBUG, "SAE: Commit message", buf);
if (wpabuf_len(buf) != sizeof(local_commit) ||
@@ -377,7 +446,7 @@
}
if (sae_parse_commit(&sae, peer_commit, sizeof(peer_commit), NULL, NULL,
- NULL) != 0 ||
+ NULL, 0) != 0 ||
sae_process_commit(&sae) < 0)
goto fail;
@@ -411,6 +480,62 @@
if (sae_check_confirm(&sae, peer_confirm, sizeof(peer_confirm)) < 0)
goto fail;
+ pt_info = sae_derive_pt(pt_groups,
+ (const u8 *) ssid, os_strlen(ssid),
+ (const u8 *) pw, os_strlen(pw), pwid);
+ if (!pt_info)
+ goto fail;
+
+ for (pt = pt_info; pt; pt = pt->next) {
+ if (pt->group == 19) {
+ struct crypto_ec_point *pwe;
+ u8 bin[SAE_MAX_ECC_PRIME_LEN * 2];
+ size_t prime_len = sizeof(pwe_19_x);
+
+ pwe = sae_derive_pwe_from_pt_ecc(pt, addr1b, addr2b);
+ if (!pwe) {
+ sae_deinit_pt(pt);
+ goto fail;
+ }
+ if (crypto_ec_point_to_bin(pt->ec, pwe, bin,
+ bin + prime_len) < 0 ||
+ os_memcmp(pwe_19_x, bin, prime_len) != 0 ||
+ os_memcmp(pwe_19_y, bin + prime_len,
+ prime_len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "SAE: PT/PWE test vector mismatch");
+ crypto_ec_point_deinit(pwe, 1);
+ sae_deinit_pt(pt);
+ goto fail;
+ }
+ crypto_ec_point_deinit(pwe, 1);
+ }
+
+ if (pt->group == 15) {
+ struct crypto_bignum *pwe;
+ u8 bin[SAE_MAX_PRIME_LEN];
+ size_t prime_len = sizeof(pwe_15);
+
+ pwe = sae_derive_pwe_from_pt_ffc(pt, addr1b, addr2b);
+ if (!pwe) {
+ sae_deinit_pt(pt);
+ goto fail;
+ }
+ if (crypto_bignum_to_bin(pwe, bin, sizeof(bin),
+ prime_len) < 0 ||
+ os_memcmp(pwe_15, bin, prime_len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "SAE: PT/PWE test vector mismatch");
+ crypto_bignum_deinit(pwe, 1);
+ sae_deinit_pt(pt);
+ goto fail;
+ }
+ crypto_bignum_deinit(pwe, 1);
+ }
+ }
+
+ sae_deinit_pt(pt_info);
+
ret = 0;
fail:
sae_clear_data(&sae);
diff --git a/src/common/defs.h b/src/common/defs.h
index 4faf1c8..bcf6f54 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -9,15 +9,6 @@
#ifndef DEFS_H
#define DEFS_H
-#ifdef FALSE
-#undef FALSE
-#endif
-#ifdef TRUE
-#undef TRUE
-#endif
-typedef enum { FALSE = 0, TRUE = 1 } Boolean;
-
-
#define WPA_CIPHER_NONE BIT(0)
#define WPA_CIPHER_WEP40 BIT(1)
#define WPA_CIPHER_WEP104 BIT(2)
@@ -82,6 +73,13 @@
WPA_KEY_MGMT_FT_FILS_SHA384));
}
+static inline int wpa_key_mgmt_wpa_psk_no_sae(int akm)
+{
+ return !!(akm & (WPA_KEY_MGMT_PSK |
+ WPA_KEY_MGMT_FT_PSK |
+ WPA_KEY_MGMT_PSK_SHA256));
+}
+
static inline int wpa_key_mgmt_wpa_psk(int akm)
{
return !!(akm & (WPA_KEY_MGMT_PSK |
@@ -193,7 +191,6 @@
WPA_ALG_TKIP,
WPA_ALG_CCMP,
WPA_ALG_IGTK,
- WPA_ALG_PMK,
WPA_ALG_GCMP,
WPA_ALG_SMS4,
WPA_ALG_KRK,
@@ -416,7 +413,54 @@
CHAN_WIDTH_80,
CHAN_WIDTH_80P80,
CHAN_WIDTH_160,
+ CHAN_WIDTH_2160,
+ CHAN_WIDTH_4320,
+ CHAN_WIDTH_6480,
+ CHAN_WIDTH_8640,
CHAN_WIDTH_UNKNOWN
};
+enum key_flag {
+ KEY_FLAG_MODIFY = BIT(0),
+ KEY_FLAG_DEFAULT = BIT(1),
+ KEY_FLAG_RX = BIT(2),
+ KEY_FLAG_TX = BIT(3),
+ KEY_FLAG_GROUP = BIT(4),
+ KEY_FLAG_PAIRWISE = BIT(5),
+ KEY_FLAG_PMK = BIT(6),
+ /* Used flag combinations */
+ KEY_FLAG_RX_TX = KEY_FLAG_RX | KEY_FLAG_TX,
+ KEY_FLAG_GROUP_RX_TX = KEY_FLAG_GROUP | KEY_FLAG_RX_TX,
+ KEY_FLAG_GROUP_RX_TX_DEFAULT = KEY_FLAG_GROUP_RX_TX |
+ KEY_FLAG_DEFAULT,
+ KEY_FLAG_GROUP_RX = KEY_FLAG_GROUP | KEY_FLAG_RX,
+ KEY_FLAG_GROUP_TX_DEFAULT = KEY_FLAG_GROUP | KEY_FLAG_TX |
+ KEY_FLAG_DEFAULT,
+ KEY_FLAG_PAIRWISE_RX_TX = KEY_FLAG_PAIRWISE | KEY_FLAG_RX_TX,
+ KEY_FLAG_PAIRWISE_RX = KEY_FLAG_PAIRWISE | KEY_FLAG_RX,
+ KEY_FLAG_PAIRWISE_RX_TX_MODIFY = KEY_FLAG_PAIRWISE_RX_TX |
+ KEY_FLAG_MODIFY,
+ /* Max allowed flags for each key type */
+ KEY_FLAG_PAIRWISE_MASK = KEY_FLAG_PAIRWISE_RX_TX_MODIFY,
+ KEY_FLAG_GROUP_MASK = KEY_FLAG_GROUP_RX_TX_DEFAULT,
+ KEY_FLAG_PMK_MASK = KEY_FLAG_PMK,
+};
+
+static inline int check_key_flag(enum key_flag key_flag)
+{
+ return !!(!key_flag ||
+ ((key_flag & (KEY_FLAG_PAIRWISE | KEY_FLAG_MODIFY)) &&
+ (key_flag & ~KEY_FLAG_PAIRWISE_MASK)) ||
+ ((key_flag & KEY_FLAG_GROUP) &&
+ (key_flag & ~KEY_FLAG_GROUP_MASK)) ||
+ ((key_flag & KEY_FLAG_PMK) &&
+ (key_flag & ~KEY_FLAG_PMK_MASK)));
+}
+
+enum ptk0_rekey_handling {
+ PTK0_REKEY_ALLOW_ALWAYS,
+ PTK0_REKEY_ALLOW_LOCAL_OK,
+ PTK0_REKEY_ALLOW_NEVER
+};
+
#endif /* DEFS_H */
diff --git a/src/common/dhcp.h b/src/common/dhcp.h
index e38512c..7dc67d5 100644
--- a/src/common/dhcp.h
+++ b/src/common/dhcp.h
@@ -39,7 +39,7 @@
} STRUCT_PACKED;
struct bootp_pkt {
- struct iphdr iph;
+ struct ip iph;
struct udphdr udph;
u8 op;
u8 htype;
diff --git a/src/common/dpp.c b/src/common/dpp.c
index 49de476..b33ab15 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -1,13 +1,14 @@
/*
* DPP functionality shared between hostapd and wpa_supplicant
* Copyright (c) 2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
+#include <fcntl.h>
#include <openssl/opensslv.h>
#include <openssl/err.h>
#include <openssl/asn1.h>
@@ -16,6 +17,8 @@
#include "utils/common.h"
#include "utils/base64.h"
#include "utils/json.h"
+#include "utils/ip_addr.h"
+#include "utils/eloop.h"
#include "common/ieee802_11_common.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
@@ -26,10 +29,13 @@
#include "crypto/aes_siv.h"
#include "crypto/sha384.h"
#include "crypto/sha512.h"
+#include "tls/asn1.h"
#include "drivers/driver.h"
#include "dpp.h"
+static const char * dpp_netrole_str(enum dpp_netrole netrole);
+
#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 };
@@ -67,12 +73,76 @@
*ps = sig->s;
}
+
+#ifdef CONFIG_DPP2
+static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
+{
+ if (pkey->type != EVP_PKEY_EC)
+ return NULL;
+ return pkey->pkey.ec;
+}
+#endif /* CONFIG_DPP2 */
+
#endif
+struct dpp_connection {
+ struct dl_list list;
+ struct dpp_controller *ctrl;
+ struct dpp_relay_controller *relay;
+ struct dpp_global *global;
+ struct dpp_authentication *auth;
+ int sock;
+ u8 mac_addr[ETH_ALEN];
+ unsigned int freq;
+ u8 msg_len[4];
+ size_t msg_len_octets;
+ struct wpabuf *msg;
+ struct wpabuf *msg_out;
+ size_t msg_out_pos;
+ unsigned int read_eloop:1;
+ unsigned int write_eloop:1;
+ unsigned int on_tcp_tx_complete_gas_done:1;
+ unsigned int on_tcp_tx_complete_remove:1;
+ unsigned int on_tcp_tx_complete_auth_ok:1;
+};
+
+/* Remote Controller */
+struct dpp_relay_controller {
+ struct dl_list list;
+ struct dpp_global *global;
+ u8 pkhash[SHA256_MAC_LEN];
+ struct hostapd_ip_addr ipaddr;
+ void *cb_ctx;
+ void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg,
+ size_t len);
+ void (*gas_resp_tx)(void *ctx, const u8 *addr, u8 dialog_token,
+ int prot, struct wpabuf *buf);
+ struct dl_list conn; /* struct dpp_connection */
+};
+
+/* Local Controller */
+struct dpp_controller {
+ struct dpp_global *global;
+ u8 allowed_roles;
+ int qr_mutual;
+ int sock;
+ struct dl_list conn; /* struct dpp_connection */
+ char *configurator_params;
+};
+
struct dpp_global {
+ void *msg_ctx;
struct dl_list bootstrap; /* struct dpp_bootstrap_info */
struct dl_list configurator; /* struct dpp_configurator */
+#ifdef CONFIG_DPP2
+ struct dl_list controllers; /* struct dpp_relay_controller */
+ struct dpp_controller *controller;
+ struct dl_list tcp_init; /* struct dpp_connection */
+ void *cb_ctx;
+ int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
+ void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
+#endif /* CONFIG_DPP2 */
};
static const struct dpp_curve_params dpp_curves[] = {
@@ -395,6 +465,76 @@
}
+#ifdef CONFIG_DPP2
+
+static int dpp_pbkdf2_f(size_t hash_len,
+ const u8 *password, size_t password_len,
+ const u8 *salt, size_t salt_len,
+ unsigned int iterations, unsigned int count, u8 *digest)
+{
+ unsigned char tmp[DPP_MAX_HASH_LEN], tmp2[DPP_MAX_HASH_LEN];
+ unsigned int i;
+ size_t j;
+ u8 count_buf[4];
+ const u8 *addr[2];
+ size_t len[2];
+
+ addr[0] = salt;
+ len[0] = salt_len;
+ addr[1] = count_buf;
+ len[1] = 4;
+
+ /* F(P, S, c, i) = U1 xor U2 xor ... Uc
+ * U1 = PRF(P, S || i)
+ * U2 = PRF(P, U1)
+ * Uc = PRF(P, Uc-1)
+ */
+
+ WPA_PUT_BE32(count_buf, count);
+ if (dpp_hmac_vector(hash_len, password, password_len, 2, addr, len,
+ tmp))
+ return -1;
+ os_memcpy(digest, tmp, hash_len);
+
+ for (i = 1; i < iterations; i++) {
+ if (dpp_hmac(hash_len, password, password_len, tmp, hash_len,
+ tmp2))
+ return -1;
+ os_memcpy(tmp, tmp2, hash_len);
+ for (j = 0; j < hash_len; j++)
+ digest[j] ^= tmp2[j];
+ }
+
+ return 0;
+}
+
+
+static int dpp_pbkdf2(size_t hash_len, const u8 *password, size_t password_len,
+ const u8 *salt, size_t salt_len, unsigned int iterations,
+ u8 *buf, size_t buflen)
+{
+ unsigned int count = 0;
+ unsigned char *pos = buf;
+ size_t left = buflen, plen;
+ unsigned char digest[DPP_MAX_HASH_LEN];
+
+ while (left > 0) {
+ count++;
+ if (dpp_pbkdf2_f(hash_len, password, password_len,
+ salt, salt_len, iterations, count, digest))
+ return -1;
+ plen = left > hash_len ? hash_len : left;
+ os_memcpy(pos, digest, plen);
+ pos += plen;
+ left -= plen;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_DPP2 */
+
+
static int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
{
int num_bytes, offset;
@@ -554,6 +694,91 @@
}
+static int dpp_ecdh(EVP_PKEY *own, EVP_PKEY *peer,
+ u8 *secret, size_t *secret_len)
+{
+ EVP_PKEY_CTX *ctx;
+ int ret = -1;
+
+ ERR_clear_error();
+ *secret_len = 0;
+
+ ctx = EVP_PKEY_CTX_new(own, NULL);
+ if (!ctx) {
+ wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_CTX_new failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+
+ if (EVP_PKEY_derive_init(ctx) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive_init failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (EVP_PKEY_derive_set_peer(ctx, peer) != 1) {
+ wpa_printf(MSG_ERROR,
+ "DPP: EVP_PKEY_derive_set_peet failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (EVP_PKEY_derive(ctx, NULL, secret_len) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive(NULL) failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
+ u8 buf[200];
+ int level = *secret_len > 200 ? MSG_ERROR : MSG_DEBUG;
+
+ /* It looks like OpenSSL can return unexpectedly large buffer
+ * need for shared secret from EVP_PKEY_derive(NULL) in some
+ * cases. For example, group 19 has shown cases where secret_len
+ * is set to 72 even though the actual length ends up being
+ * updated to 32 when EVP_PKEY_derive() is called with a buffer
+ * for the value. Work around this by trying to fetch the value
+ * and continue if it is within supported range even when the
+ * initial buffer need is claimed to be larger. */
+ wpa_printf(level,
+ "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
+ (int) *secret_len);
+ if (*secret_len > 200)
+ goto fail;
+ if (EVP_PKEY_derive(ctx, buf, secret_len) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
+ (int) *secret_len);
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "DPP: Unexpected secret_len change",
+ buf, *secret_len);
+ os_memcpy(secret, buf, *secret_len);
+ forced_memzero(buf, sizeof(buf));
+ goto done;
+ }
+
+ if (EVP_PKEY_derive(ctx, secret, secret_len) != 1) {
+ wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+done:
+ ret = 0;
+
+fail:
+ EVP_PKEY_CTX_free(ctx);
+ return ret;
+}
+
+
static void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
{
wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
@@ -601,6 +826,34 @@
}
+static const u8 * dpp_get_attr_next(const u8 *prev, const u8 *buf, size_t len,
+ u16 req_id, u16 *ret_len)
+{
+ u16 id, alen;
+ const u8 *pos, *end = buf + len;
+
+ if (!prev)
+ pos = buf;
+ else
+ pos = prev + WPA_GET_LE16(prev - 2);
+ while (end - pos >= 4) {
+ id = WPA_GET_LE16(pos);
+ pos += 2;
+ alen = WPA_GET_LE16(pos);
+ pos += 2;
+ if (alen > end - pos)
+ return NULL;
+ if (id == req_id) {
+ *ret_len = alen;
+ return pos;
+ }
+ pos += alen;
+ }
+
+ return NULL;
+}
+
+
int dpp_check_attrs(const u8 *buf, size_t len)
{
const u8 *pos, *end;
@@ -649,7 +902,10 @@
return;
os_free(info->uri);
os_free(info->info);
+ os_free(info->chan);
+ os_free(info->pk);
EVP_PKEY_free(info->pubkey);
+ str_clear_free(info->configurator_params);
os_free(info);
}
@@ -661,6 +917,8 @@
return "QRCODE";
case DPP_BOOTSTRAP_PKEX:
return "PKEX";
+ case DPP_BOOTSTRAP_NFC_URI:
+ return "NFC-URI";
}
return "??";
}
@@ -689,17 +947,19 @@
int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
const char *chan_list)
{
- const char *pos = chan_list;
- int opclass, channel, freq;
+ const char *pos = chan_list, *pos2;
+ int opclass = -1, channel, freq;
while (pos && *pos && *pos != ';') {
- opclass = atoi(pos);
+ pos2 = pos;
+ while (*pos2 >= '0' && *pos2 <= '9')
+ pos2++;
+ if (*pos2 == '/') {
+ opclass = atoi(pos);
+ pos = pos2 + 1;
+ }
if (opclass <= 0)
goto fail;
- pos = os_strchr(pos, '/');
- if (!pos)
- goto fail;
- pos++;
channel = atoi(pos);
if (channel <= 0)
goto fail;
@@ -807,6 +1067,32 @@
}
+static int dpp_bi_pubkey_hash(struct dpp_bootstrap_info *bi,
+ const u8 *data, size_t data_len)
+{
+ const u8 *addr[2];
+ size_t len[2];
+
+ addr[0] = data;
+ len[0] = data_len;
+ if (sha256_vector(1, addr, len, bi->pubkey_hash) < 0)
+ return -1;
+ wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
+ bi->pubkey_hash, SHA256_MAC_LEN);
+
+ addr[0] = (const u8 *) "chirp";
+ len[0] = 5;
+ addr[1] = data;
+ len[1] = data_len;
+ if (sha256_vector(2, addr, len, bi->pubkey_hash_chirp) < 0)
+ return -1;
+ wpa_hexdump(MSG_DEBUG, "DPP: Public key hash (chirp)",
+ bi->pubkey_hash_chirp, SHA256_MAC_LEN);
+
+ return 0;
+}
+
+
static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
{
const char *end;
@@ -836,8 +1122,7 @@
if (!end)
return -1;
- data = base64_decode((const unsigned char *) info, end - info,
- &data_len);
+ data = base64_decode(info, end - info, &data_len);
if (!data) {
wpa_printf(MSG_DEBUG,
"DPP: Invalid base64 encoding on URI public-key");
@@ -846,14 +1131,11 @@
wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
data, data_len);
- if (sha256_vector(1, (const u8 **) &data, &data_len,
- bi->pubkey_hash) < 0) {
+ if (dpp_bi_pubkey_hash(bi, data, data_len) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
os_free(data);
return -1;
}
- wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
- bi->pubkey_hash, SHA256_MAC_LEN);
/* DER encoded ASN.1 SubjectPublicKeyInfo
*
@@ -1011,17 +1293,6 @@
}
-struct dpp_bootstrap_info * dpp_parse_qr_code(const char *uri)
-{
- struct dpp_bootstrap_info *bi;
-
- bi = dpp_parse_uri(uri);
- if (bi)
- bi->type = DPP_BOOTSTRAP_QR_CODE;
- return bi;
-}
-
-
static void dpp_debug_print_key(const char *title, EVP_PKEY *key)
{
EC_KEY *eckey;
@@ -1079,7 +1350,7 @@
static EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve)
{
EVP_PKEY_CTX *kctx = NULL;
- EC_KEY *ec_params;
+ EC_KEY *ec_params = NULL;
EVP_PKEY *params = NULL, *key = NULL;
int nid;
@@ -1110,19 +1381,18 @@
EVP_PKEY_keygen_init(kctx) != 1 ||
EVP_PKEY_keygen(kctx, &key) != 1) {
wpa_printf(MSG_ERROR, "DPP: Failed to generate EC key");
+ key = NULL;
goto fail;
}
if (wpa_debug_show_keys)
dpp_debug_print_key("Own generated key", key);
+fail:
+ EC_KEY_free(ec_params);
EVP_PKEY_free(params);
EVP_PKEY_CTX_free(kctx);
return key;
-fail:
- EVP_PKEY_CTX_free(kctx);
- EVP_PKEY_free(params);
- return NULL;
}
@@ -1283,41 +1553,31 @@
}
-int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
+static 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);
+ res = dpp_bi_pubkey_hash(bi, wpabuf_head(der), wpabuf_len(der));
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;
}
-char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
- const u8 *privkey, size_t privkey_len)
+static int dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
+ const u8 *privkey, size_t privkey_len)
{
- unsigned char *base64 = NULL;
+ char *base64 = NULL;
char *pos, *end;
size_t len;
struct wpabuf *der = NULL;
- const u8 *addr[1];
- int res;
if (!curve) {
bi->curve = &dpp_curves[0];
@@ -1326,7 +1586,7 @@
if (!bi->curve) {
wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
curve);
- return NULL;
+ return -1;
}
}
if (privkey)
@@ -1343,22 +1603,17 @@
wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
der);
- addr[0] = wpabuf_head(der);
- len = wpabuf_len(der);
- res = sha256_vector(1, addr, &len, bi->pubkey_hash);
- if (res < 0) {
+ if (dpp_bi_pubkey_hash(bi, wpabuf_head(der), wpabuf_len(der)) < 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(wpabuf_head(der), wpabuf_len(der), &len);
wpabuf_free(der);
der = NULL;
if (!base64)
goto fail;
- pos = (char *) base64;
+ pos = base64;
end = pos + len;
for (;;) {
pos = os_strchr(pos, '\n');
@@ -1366,11 +1621,13 @@
break;
os_memmove(pos, pos + 1, end - pos);
}
- return (char *) base64;
+ os_free(bi->pk);
+ bi->pk = base64;
+ return 0;
fail:
os_free(base64);
wpabuf_free(der);
- return NULL;
+ return -1;
}
@@ -1754,9 +2011,11 @@
#ifdef CONFIG_DPP2
/* Protocol Version */
- wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
- wpabuf_put_le16(msg, 1);
- wpabuf_put_u8(msg, 2);
+ if (auth->peer_version >= 2) {
+ 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);
@@ -1997,6 +2256,7 @@
static int dpp_prepare_channel_list(struct dpp_authentication *auth,
+ unsigned int neg_freq,
struct hostapd_hw_modes *own_modes,
u16 num_modes)
{
@@ -2004,6 +2264,14 @@
char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
unsigned int i;
+ if (!own_modes) {
+ if (!neg_freq)
+ return -1;
+ auth->num_freq = 1;
+ auth->freq[0] = neg_freq;
+ return 0;
+ }
+
if (auth->peer_bi->num_freq > 0)
res = dpp_channel_intersect(auth, own_modes, num_modes);
else
@@ -2036,11 +2304,42 @@
}
+static int dpp_gen_uri(struct dpp_bootstrap_info *bi)
+{
+ char macstr[ETH_ALEN * 2 + 10];
+ size_t len;
+
+ len = 4; /* "DPP:" */
+ if (bi->chan)
+ len += 3 + os_strlen(bi->chan); /* C:...; */
+ if (is_zero_ether_addr(bi->mac_addr))
+ macstr[0] = '\0';
+ else
+ os_snprintf(macstr, sizeof(macstr), "M:" COMPACT_MACSTR ";",
+ MAC2STR(bi->mac_addr));
+ len += os_strlen(macstr); /* M:...; */
+ if (bi->info)
+ len += 3 + os_strlen(bi->info); /* I:...; */
+ len += 4 + os_strlen(bi->pk); /* K:...;; */
+
+ os_free(bi->uri);
+ bi->uri = os_malloc(len + 1);
+ if (!bi->uri)
+ return -1;
+ os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%sK:%s;;",
+ bi->chan ? "C:" : "", bi->chan ? bi->chan : "",
+ bi->chan ? ";" : "",
+ macstr,
+ bi->info ? "I:" : "", bi->info ? bi->info : "",
+ bi->info ? ";" : "",
+ bi->pk);
+ 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 */
@@ -2049,33 +2348,38 @@
if (!bi)
return -1;
bi->type = DPP_BOOTSTRAP_QR_CODE;
- pk = dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0);
- if (!pk)
+ if (dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0) < 0 ||
+ dpp_gen_uri(bi) < 0)
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_authentication *
+dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx)
+{
+ struct dpp_authentication *auth;
+
+ auth = os_zalloc(sizeof(*auth));
+ if (!auth)
+ return NULL;
+ auth->global = dpp;
+ auth->msg_ctx = msg_ctx;
+ auth->conf_resp_status = 255;
+ return auth;
+}
+
+
+struct dpp_authentication * dpp_auth_init(struct dpp_global *dpp, void *msg_ctx,
struct dpp_bootstrap_info *peer_bi,
struct dpp_bootstrap_info *own_bi,
u8 dpp_allowed_roles,
@@ -2085,7 +2389,6 @@
{
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;
@@ -2093,10 +2396,12 @@
u8 test_hash[SHA256_MAC_LEN];
#endif /* CONFIG_TESTING_OPTIONS */
- auth = os_zalloc(sizeof(*auth));
+ auth = dpp_alloc_auth(dpp, msg_ctx);
if (!auth)
return NULL;
- auth->msg_ctx = msg_ctx;
+ if (peer_bi->configurator_params &&
+ dpp_set_configurator(auth, peer_bi->configurator_params) < 0)
+ goto fail;
auth->initiator = 1;
auth->waiting_auth_resp = 1;
auth->allowed_roles = dpp_allowed_roles;
@@ -2106,7 +2411,7 @@
auth->curve = peer_bi->curve;
if (dpp_autogen_bootstrap_key(auth) < 0 ||
- dpp_prepare_channel_list(auth, own_modes, num_modes) < 0)
+ dpp_prepare_channel_list(auth, neg_freq, own_modes, num_modes) < 0)
goto fail;
#ifdef CONFIG_TESTING_OPTIONS
@@ -2154,21 +2459,10 @@
goto fail;
/* ECDH: M = pI * BR */
- ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, auth->peer_bi->pubkey) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
- secret_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(auth->own_protocol_key, auth->peer_bi->pubkey,
+ auth->Mx, &secret_len) < 0)
goto fail;
- }
auth->secret_len = secret_len;
- EVP_PKEY_CTX_free(ctx);
- ctx = NULL;
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
auth->Mx, auth->secret_len);
@@ -2213,6 +2507,8 @@
}
#endif /* CONFIG_TESTING_OPTIONS */
+ if (neg_freq && auth->num_freq == 1 && auth->freq[0] == neg_freq)
+ neg_freq = 0;
auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash,
i_pubkey_hash, neg_freq);
if (!auth->req_msg)
@@ -2220,7 +2516,6 @@
out:
wpabuf_free(pi);
- EVP_PKEY_CTX_free(ctx);
return auth;
fail:
dpp_auth_deinit(auth);
@@ -2247,7 +2542,7 @@
}
wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
json_len = os_strlen(json);
- wpa_hexdump_ascii(MSG_DEBUG, "DPP: configAttr JSON", json, json_len);
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: configRequest JSON", json, json_len);
/* { E-nonce, configAttrib }ke */
clear_len = 4 + nonce_len + 4 + json_len;
@@ -2383,6 +2678,66 @@
}
+struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
+ const char *name,
+ enum dpp_netrole netrole,
+ const char *mud_url, int *opclasses)
+{
+ size_t len, name_len;
+ const char *tech = "infra";
+ const char *dpp_name;
+ struct wpabuf *buf, *json;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
+ static const char *bogus_tech = "knfra";
+
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
+ tech = bogus_tech;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ dpp_name = name ? name : "Test";
+ name_len = os_strlen(dpp_name);
+
+ len = 100 + name_len * 6 + 1 + int_array_len(opclasses) * 4;
+ if (mud_url && mud_url[0])
+ len += 10 + os_strlen(mud_url);
+ json = wpabuf_alloc(len);
+ if (!json)
+ return NULL;
+
+ json_start_object(json, NULL);
+ if (json_add_string_escape(json, "name", dpp_name, name_len) < 0) {
+ wpabuf_free(json);
+ return NULL;
+ }
+ json_value_sep(json);
+ json_add_string(json, "wi-fi_tech", tech);
+ json_value_sep(json);
+ json_add_string(json, "netRole", dpp_netrole_str(netrole));
+ if (mud_url && mud_url[0]) {
+ json_value_sep(json);
+ json_add_string(json, "mudurl", mud_url);
+ }
+ if (opclasses) {
+ int i;
+
+ json_value_sep(json);
+ json_start_array(json, "bandSupport");
+ for (i = 0; opclasses[i]; i++)
+ wpabuf_printf(json, "%s%u", i ? "," : "", opclasses[i]);
+ json_end_array(json);
+ }
+ json_end_object(json);
+
+ buf = dpp_build_conf_req(auth, wpabuf_head(json));
+ wpabuf_free(json);
+
+ return buf;
+}
+
+
static void dpp_auth_success(struct dpp_authentication *auth)
{
wpa_printf(MSG_DEBUG,
@@ -2693,7 +3048,6 @@
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];
@@ -2732,6 +3086,7 @@
#endif /* CONFIG_TESTING_OPTIONS */
wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", auth->r_nonce, nonce_len);
+ EVP_PKEY_free(auth->own_protocol_key);
#ifdef CONFIG_TESTING_OPTIONS
if (dpp_protocol_key_override_len) {
const struct dpp_curve_params *tmp_curve;
@@ -2755,20 +3110,9 @@
goto fail;
/* ECDH: N = pR * PI */
- ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, auth->peer_protocol_key) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
- secret_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(auth->own_protocol_key, auth->peer_protocol_key,
+ auth->Nx, &secret_len) < 0)
goto fail;
- }
- EVP_PKEY_CTX_free(ctx);
- ctx = NULL;
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
auth->Nx, auth->secret_len);
@@ -2951,8 +3295,8 @@
struct dpp_authentication *
-dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
- struct dpp_bootstrap_info *peer_bi,
+dpp_auth_req_rx(struct dpp_global *dpp, 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,
size_t attr_len)
@@ -2993,10 +3337,12 @@
wrapped_data, wrapped_data_len);
attr_len = wrapped_data - 4 - attr_start;
- auth = os_zalloc(sizeof(*auth));
+ auth = dpp_alloc_auth(dpp, msg_ctx);
if (!auth)
goto fail;
- auth->msg_ctx = msg_ctx;
+ if (peer_bi && peer_bi->configurator_params &&
+ dpp_set_configurator(auth, peer_bi->configurator_params) < 0)
+ goto fail;
auth->peer_bi = peer_bi;
auth->own_bi = own_bi;
auth->curve = own_bi->curve;
@@ -3064,22 +3410,9 @@
}
dpp_debug_print_key("Peer (Initiator) Protocol Key", pi);
- ctx = EVP_PKEY_CTX_new(own_bi->pubkey, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pi) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
- secret_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) {
- 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");
+ if (dpp_ecdh(own_bi->pubkey, pi, auth->Mx, &secret_len) < 0)
goto fail;
- }
auth->secret_len = secret_len;
- EVP_PKEY_CTX_free(ctx);
- ctx = NULL;
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
auth->Mx, auth->secret_len);
@@ -3533,7 +3866,6 @@
const u8 *attr_start, size_t attr_len)
{
EVP_PKEY *pr;
- EVP_PKEY_CTX *ctx = NULL;
size_t secret_len;
const u8 *addr[2];
size_t len[2];
@@ -3622,6 +3954,14 @@
dpp_auth_fail(auth,
"Missing Initiator Bootstrapping Key Hash attribute");
return NULL;
+ } else if (auth->own_bi &&
+ auth->own_bi->type == DPP_BOOTSTRAP_NFC_URI &&
+ auth->own_bi->nfc_negotiated) {
+ /* NFC negotiated connection handover 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 */
@@ -3683,21 +4023,11 @@
}
dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
- ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pr) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
- secret_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(auth->own_protocol_key, pr, auth->Nx, &secret_len) < 0) {
dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
goto fail;
}
- EVP_PKEY_CTX_free(ctx);
- ctx = NULL;
+ EVP_PKEY_free(auth->peer_protocol_key);
auth->peer_protocol_key = pr;
pr = NULL;
@@ -3868,7 +4198,6 @@
bin_clear_free(unwrapped, unwrapped_len);
bin_clear_free(unwrapped2, unwrapped2_len);
EVP_PKEY_free(pr);
- EVP_PKEY_CTX_free(ctx);
return NULL;
}
@@ -3964,7 +4293,11 @@
}
#endif /* CONFIG_TESTING_OPTIONS */
- if (auth->initiator || !auth->own_bi) {
+ if (auth->initiator || !auth->own_bi || !auth->waiting_auth_conf) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: initiator=%d own_bi=%d waiting_auth_conf=%d",
+ auth->initiator, !!auth->own_bi,
+ auth->waiting_auth_conf);
dpp_auth_fail(auth, "Unexpected Authentication Confirm");
return -1;
}
@@ -4206,8 +4539,8 @@
}
-static int dpp_configuration_parse(struct dpp_authentication *auth,
- const char *cmd)
+static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
+ const char *cmd, int idx)
{
const char *pos, *end;
struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
@@ -4218,6 +4551,7 @@
conf_sta = dpp_configuration_alloc(pos + 10);
if (!conf_sta)
goto fail;
+ conf_sta->netrole = DPP_NETROLE_STA;
conf = conf_sta;
}
@@ -4226,9 +4560,14 @@
conf_ap = dpp_configuration_alloc(pos + 9);
if (!conf_ap)
goto fail;
+ conf_ap->netrole = DPP_NETROLE_AP;
conf = conf_ap;
}
+ pos = os_strstr(cmd, " conf=configurator");
+ if (pos)
+ auth->provision_configurator = 1;
+
if (!conf)
return 0;
@@ -4251,6 +4590,16 @@
#endif /* CONFIG_TESTING_OPTIONS */
}
+ pos = os_strstr(cmd, " ssid_charset=");
+ if (pos) {
+ if (conf_ap) {
+ wpa_printf(MSG_INFO,
+ "DPP: ssid64 option (ssid_charset param) not allowed for AP enrollee");
+ goto fail;
+ }
+ conf->ssid_charset = atoi(pos + 14);
+ }
+
pos = os_strstr(cmd, " pass=");
if (pos) {
size_t pass_len;
@@ -4303,8 +4652,15 @@
if (!dpp_configuration_valid(conf))
goto fail;
- auth->conf_sta = conf_sta;
- auth->conf_ap = conf_ap;
+ if (idx == 0) {
+ auth->conf_sta = conf_sta;
+ auth->conf_ap = conf_ap;
+ } else if (idx == 1) {
+ auth->conf2_sta = conf_sta;
+ auth->conf2_ap = conf_ap;
+ } else {
+ goto fail;
+ }
return 0;
fail:
@@ -4314,6 +4670,41 @@
}
+static int dpp_configuration_parse(struct dpp_authentication *auth,
+ const char *cmd)
+{
+ const char *pos;
+ char *tmp;
+ size_t len;
+ int res;
+
+ pos = os_strstr(cmd, " @CONF-OBJ-SEP@ ");
+ if (!pos)
+ return dpp_configuration_parse_helper(auth, cmd, 0);
+
+ len = pos - cmd;
+ tmp = os_malloc(len + 1);
+ if (!tmp)
+ goto fail;
+ os_memcpy(tmp, cmd, len);
+ tmp[len] = '\0';
+ res = dpp_configuration_parse_helper(auth, cmd, 0);
+ str_clear_free(tmp);
+ if (res)
+ goto fail;
+ res = dpp_configuration_parse_helper(auth, cmd + len, 1);
+ if (res)
+ goto fail;
+ return 0;
+fail:
+ dpp_configuration_free(auth->conf_sta);
+ dpp_configuration_free(auth->conf2_sta);
+ dpp_configuration_free(auth->conf_ap);
+ dpp_configuration_free(auth->conf2_ap);
+ return -1;
+}
+
+
static struct dpp_configurator *
dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
{
@@ -4331,51 +4722,102 @@
}
-int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
- struct dpp_authentication *auth,
- const char *cmd)
+int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd)
{
const char *pos;
+ char *tmp = NULL;
+ int ret = -1;
- if (!cmd)
+ if (!cmd || auth->configurator_set)
return 0;
+ auth->configurator_set = 1;
+
+ if (cmd[0] != ' ') {
+ size_t len;
+
+ len = os_strlen(cmd);
+ tmp = os_malloc(len + 2);
+ if (!tmp)
+ goto fail;
+ tmp[0] = ' ';
+ os_memcpy(tmp + 1, cmd, len + 1);
+ cmd = tmp;
+ }
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));
+ auth->conf = dpp_configurator_get_id(auth->global, atoi(pos));
if (!auth->conf) {
wpa_printf(MSG_INFO,
"DPP: Could not find the specified configurator");
- return -1;
+ goto fail;
}
}
- if (dpp_configuration_parse(auth, cmd) < 0) {
- wpa_msg(msg_ctx, MSG_INFO,
- "DPP: Failed to set configurator parameters");
- return -1;
+ pos = os_strstr(cmd, " conn_status=");
+ if (pos) {
+ pos += 13;
+ auth->send_conn_status = atoi(pos);
}
- return 0;
+
+ pos = os_strstr(cmd, " akm_use_selector=");
+ if (pos) {
+ pos += 18;
+ auth->akm_use_selector = atoi(pos);
+ }
+
+ if (dpp_configuration_parse(auth, cmd) < 0) {
+ wpa_msg(auth->msg_ctx, MSG_INFO,
+ "DPP: Failed to set configurator parameters");
+ goto fail;
+ }
+ ret = 0;
+fail:
+ os_free(tmp);
+ return ret;
+}
+
+
+static void dpp_free_asymmetric_key(struct dpp_asymmetric_key *key)
+{
+ while (key) {
+ struct dpp_asymmetric_key *next = key->next;
+
+ EVP_PKEY_free(key->csign);
+ str_clear_free(key->config_template);
+ str_clear_free(key->connector_template);
+ os_free(key);
+ key = next;
+ }
}
void dpp_auth_deinit(struct dpp_authentication *auth)
{
+ unsigned int i;
+
if (!auth)
return;
dpp_configuration_free(auth->conf_ap);
+ dpp_configuration_free(auth->conf2_ap);
dpp_configuration_free(auth->conf_sta);
+ dpp_configuration_free(auth->conf2_sta);
EVP_PKEY_free(auth->own_protocol_key);
EVP_PKEY_free(auth->peer_protocol_key);
wpabuf_free(auth->req_msg);
wpabuf_free(auth->resp_msg);
wpabuf_free(auth->conf_req);
- os_free(auth->connector);
+ for (i = 0; i < auth->num_conf_obj; i++) {
+ struct dpp_config_obj *conf = &auth->conf_obj[i];
+
+ os_free(conf->connector);
+ wpabuf_free(conf->c_sign_key);
+ }
+ dpp_free_asymmetric_key(auth->conf_key_pkg);
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);
@@ -4391,7 +4833,6 @@
struct dpp_configuration *conf, size_t tailroom)
{
struct wpabuf *buf;
- char ssid[6 * sizeof(conf->ssid) + 1];
#ifdef CONFIG_TESTING_OPTIONS
if (auth->discovery_override)
@@ -4401,21 +4842,35 @@
buf = wpabuf_alloc(200 + tailroom);
if (!buf)
return NULL;
- wpabuf_put_str(buf, "{\"wi-fi_tech\":\"infra\",\"discovery\":");
+ json_start_object(buf, NULL);
+ json_add_string(buf, "wi-fi_tech", "infra");
+ json_value_sep(buf);
#ifdef CONFIG_TESTING_OPTIONS
if (auth->discovery_override) {
wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'",
auth->discovery_override);
+ wpabuf_put_str(buf, "\"discovery\":");
wpabuf_put_str(buf, auth->discovery_override);
- wpabuf_put_u8(buf, ',');
+ json_value_sep(buf);
return buf;
}
#endif /* CONFIG_TESTING_OPTIONS */
- wpabuf_put_str(buf, "{\"ssid\":\"");
- json_escape_string(ssid, sizeof(ssid),
- (const char *) conf->ssid, conf->ssid_len);
- wpabuf_put_str(buf, ssid);
- wpabuf_put_str(buf, "\"},");
+ json_start_object(buf, "discovery");
+ if (((!conf->ssid_charset || auth->peer_version < 2) &&
+ json_add_string_escape(buf, "ssid", conf->ssid,
+ conf->ssid_len) < 0) ||
+ ((conf->ssid_charset && auth->peer_version >= 2) &&
+ json_add_base64url(buf, "ssid64", conf->ssid,
+ conf->ssid_len) < 0)) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+ if (conf->ssid_charset > 0) {
+ json_value_sep(buf);
+ json_add_int(buf, "ssid_charset", conf->ssid_charset);
+ }
+ json_end_object(buf);
+ json_value_sep(buf);
return buf;
}
@@ -4426,37 +4881,32 @@
{
struct wpabuf *pub;
const u8 *pos;
- char *x = NULL, *y = NULL;
int ret = -1;
pub = dpp_get_pubkey_point(key, 0);
if (!pub)
goto fail;
- pos = wpabuf_head(pub);
- x = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0);
- pos += curve->prime_len;
- y = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0);
- if (!x || !y)
- goto fail;
- wpabuf_put_str(buf, "\"");
- wpabuf_put_str(buf, name);
- wpabuf_put_str(buf, "\":{\"kty\":\"EC\",\"crv\":\"");
- wpabuf_put_str(buf, curve->jwk_crv);
- wpabuf_put_str(buf, "\",\"x\":\"");
- wpabuf_put_str(buf, x);
- wpabuf_put_str(buf, "\",\"y\":\"");
- wpabuf_put_str(buf, y);
+ json_start_object(buf, name);
+ json_add_string(buf, "kty", "EC");
+ json_value_sep(buf);
+ json_add_string(buf, "crv", curve->jwk_crv);
+ json_value_sep(buf);
+ pos = wpabuf_head(pub);
+ if (json_add_base64url(buf, "x", pos, curve->prime_len) < 0)
+ goto fail;
+ json_value_sep(buf);
+ pos += curve->prime_len;
+ if (json_add_base64url(buf, "y", pos, curve->prime_len) < 0)
+ goto fail;
if (kid) {
- wpabuf_put_str(buf, "\",\"kid\":\"");
- wpabuf_put_str(buf, kid);
+ json_value_sep(buf);
+ json_add_string(buf, "kid", kid);
}
- wpabuf_put_str(buf, "\"}");
+ json_end_object(buf);
ret = 0;
fail:
wpabuf_free(pub);
- os_free(x);
- os_free(y);
return ret;
}
@@ -4465,36 +4915,43 @@
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));
+ json_add_string_escape(buf, "pass", conf->passphrase,
+ os_strlen(conf->passphrase));
} 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));
+ json_add_string(buf, "psk_hex", psk);
+ forced_memzero(psk, sizeof(psk));
+ }
+}
+
+
+static const char * dpp_netrole_str(enum dpp_netrole netrole)
+{
+ switch (netrole) {
+ case DPP_NETROLE_STA:
+ return "sta";
+ case DPP_NETROLE_AP:
+ return "ap";
+ case DPP_NETROLE_CONFIGURATOR:
+ return "configurator";
+ default:
+ return "??";
}
}
static struct wpabuf *
-dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
+dpp_build_conf_obj_dpp(struct dpp_authentication *auth,
struct dpp_configuration *conf)
{
struct wpabuf *buf = NULL;
char *signed1 = NULL, *signed2 = NULL, *signed3 = NULL;
size_t tailroom;
const struct dpp_curve_params *curve;
- char jws_prot_hdr[100];
+ struct wpabuf *jws_prot_hdr;
size_t signed1_len, signed2_len, signed3_len;
struct wpabuf *dppcon = NULL;
unsigned char *signature = NULL;
@@ -4508,6 +4965,7 @@
size_t extra_len = 1000;
int incl_legacy;
enum dpp_akm akm;
+ const char *akm_str;
if (!auth->conf) {
wpa_printf(MSG_INFO,
@@ -4554,14 +5012,21 @@
auth->groups_override);
wpabuf_put_str(dppcon, "\"groups\":");
wpabuf_put_str(dppcon, auth->groups_override);
- wpabuf_put_u8(dppcon, ',');
+ json_value_sep(dppcon);
}
goto skip_groups;
}
#endif /* CONFIG_TESTING_OPTIONS */
- wpabuf_printf(dppcon, "{\"groups\":[{\"groupId\":\"%s\",",
- conf->group_id ? conf->group_id : "*");
- wpabuf_printf(dppcon, "\"netRole\":\"%s\"}],", ap ? "ap" : "sta");
+ json_start_object(dppcon, NULL);
+ json_start_array(dppcon, "groups");
+ json_start_object(dppcon, NULL);
+ json_add_string(dppcon, "groupId",
+ conf->group_id ? conf->group_id : "*");
+ json_value_sep(dppcon);
+ json_add_string(dppcon, "netRole", dpp_netrole_str(conf->netrole));
+ json_end_object(dppcon);
+ json_end_array(dppcon);
+ json_value_sep(dppcon);
#ifdef CONFIG_TESTING_OPTIONS
skip_groups:
#endif /* CONFIG_TESTING_OPTIONS */
@@ -4572,30 +5037,40 @@
}
if (conf->netaccesskey_expiry) {
struct os_tm tm;
+ char expiry[30];
if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
wpa_printf(MSG_DEBUG,
"DPP: Failed to generate expiry string");
goto fail;
}
- wpabuf_printf(dppcon,
- ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
- tm.year, tm.month, tm.day,
- tm.hour, tm.min, tm.sec);
+ os_snprintf(expiry, sizeof(expiry),
+ "%04u-%02u-%02uT%02u:%02u:%02uZ",
+ tm.year, tm.month, tm.day,
+ tm.hour, tm.min, tm.sec);
+ json_value_sep(dppcon);
+ json_add_string(dppcon, "expiry", expiry);
}
- wpabuf_put_u8(dppcon, '}');
+ json_end_object(dppcon);
wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
(const char *) wpabuf_head(dppcon));
- os_snprintf(jws_prot_hdr, sizeof(jws_prot_hdr),
- "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}",
- auth->conf->kid, curve->jws_alg);
- signed1 = (char *) base64_url_encode((unsigned char *) jws_prot_hdr,
- os_strlen(jws_prot_hdr),
- &signed1_len, 0);
- signed2 = (char *) base64_url_encode(wpabuf_head(dppcon),
- wpabuf_len(dppcon),
- &signed2_len, 0);
+ jws_prot_hdr = wpabuf_alloc(100);
+ if (!jws_prot_hdr)
+ goto fail;
+ json_start_object(jws_prot_hdr, NULL);
+ json_add_string(jws_prot_hdr, "typ", "dppCon");
+ json_value_sep(jws_prot_hdr);
+ json_add_string(jws_prot_hdr, "kid", auth->conf->kid);
+ json_value_sep(jws_prot_hdr);
+ json_add_string(jws_prot_hdr, "alg", curve->jws_alg);
+ json_end_object(jws_prot_hdr);
+ signed1 = base64_url_encode(wpabuf_head(jws_prot_hdr),
+ wpabuf_len(jws_prot_hdr),
+ &signed1_len);
+ wpabuf_free(jws_prot_hdr);
+ signed2 = base64_url_encode(wpabuf_head(dppcon), wpabuf_len(dppcon),
+ &signed2_len);
if (!signed1 || !signed2)
goto fail;
@@ -4645,8 +5120,7 @@
signature_len = 2 * curve->prime_len;
wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)",
signature, signature_len);
- signed3 = (char *) base64_url_encode(signature, signature_len,
- &signed3_len, 0);
+ signed3 = base64_url_encode(signature, signature_len, &signed3_len);
if (!signed3)
goto fail;
@@ -4660,10 +5134,16 @@
if (!buf)
goto fail;
- wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(akm));
+ if (auth->akm_use_selector && dpp_akm_ver2(akm))
+ akm_str = dpp_akm_selector_str(akm);
+ else
+ akm_str = dpp_akm_str(akm);
+ json_start_object(buf, "cred");
+ json_add_string(buf, "akm", akm_str);
+ json_value_sep(buf);
if (incl_legacy) {
dpp_build_legacy_cred_params(buf, conf);
- wpabuf_put_str(buf, ",");
+ json_value_sep(buf);
}
wpabuf_put_str(buf, "\"signedConnector\":\"");
wpabuf_put_str(buf, signed1);
@@ -4671,14 +5151,16 @@
wpabuf_put_str(buf, signed2);
wpabuf_put_u8(buf, '.');
wpabuf_put_str(buf, signed3);
- wpabuf_put_str(buf, "\",");
+ wpabuf_put_str(buf, "\"");
+ json_value_sep(buf);
if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
curve) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
goto fail;
}
- wpabuf_put_str(buf, "}}");
+ json_end_object(buf);
+ json_end_object(buf);
wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
wpabuf_head(buf), wpabuf_len(buf));
@@ -4701,18 +5183,26 @@
static struct wpabuf *
-dpp_build_conf_obj_legacy(struct dpp_authentication *auth, int ap,
+dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
struct dpp_configuration *conf)
{
struct wpabuf *buf;
+ const char *akm_str;
buf = dpp_build_conf_start(auth, conf, 1000);
if (!buf)
return NULL;
- wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(conf->akm));
+ if (auth->akm_use_selector && dpp_akm_ver2(conf->akm))
+ akm_str = dpp_akm_selector_str(conf->akm);
+ else
+ akm_str = dpp_akm_str(conf->akm);
+ json_start_object(buf, "cred");
+ json_add_string(buf, "akm", akm_str);
+ json_value_sep(buf);
dpp_build_legacy_cred_params(buf, conf);
- wpabuf_put_str(buf, "}}");
+ json_end_object(buf);
+ json_end_object(buf);
wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
wpabuf_head(buf), wpabuf_len(buf));
@@ -4722,37 +5212,533 @@
static struct wpabuf *
-dpp_build_conf_obj(struct dpp_authentication *auth, int ap)
+dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
+ int idx)
{
- struct dpp_configuration *conf;
+ struct dpp_configuration *conf = NULL;
#ifdef CONFIG_TESTING_OPTIONS
if (auth->config_obj_override) {
+ if (idx != 0)
+ return NULL;
wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
return wpabuf_alloc_copy(auth->config_obj_override,
os_strlen(auth->config_obj_override));
}
#endif /* CONFIG_TESTING_OPTIONS */
- conf = ap ? auth->conf_ap : auth->conf_sta;
+ if (idx == 0) {
+ if (netrole == DPP_NETROLE_STA)
+ conf = auth->conf_sta;
+ else if (netrole == DPP_NETROLE_AP)
+ conf = auth->conf_ap;
+ } else if (idx == 1) {
+ if (netrole == DPP_NETROLE_STA)
+ conf = auth->conf2_sta;
+ else if (netrole == DPP_NETROLE_AP)
+ conf = auth->conf2_ap;
+ }
if (!conf) {
- wpa_printf(MSG_DEBUG,
- "DPP: No configuration available for Enrollee(%s) - reject configuration request",
- ap ? "ap" : "sta");
+ if (idx == 0)
+ wpa_printf(MSG_DEBUG,
+ "DPP: No configuration available for Enrollee(%s) - reject configuration request",
+ dpp_netrole_str(netrole));
return NULL;
}
- if (dpp_akm_dpp(conf->akm))
- return dpp_build_conf_obj_dpp(auth, ap, conf);
- return dpp_build_conf_obj_legacy(auth, ap, conf);
+ if (dpp_akm_dpp(conf->akm) || (auth->peer_version >= 2 && auth->conf))
+ return dpp_build_conf_obj_dpp(auth, conf);
+ return dpp_build_conf_obj_legacy(auth, conf);
+}
+
+
+#ifdef CONFIG_DPP2
+
+static struct wpabuf * dpp_build_conf_params(void)
+{
+ struct wpabuf *buf;
+ size_t len;
+ /* TODO: proper template values */
+ const char *conf_template = "{\"wi-fi_tech\":\"infra\",\"discovery\":{\"ssid\":\"test\"},\"cred\":{\"akm\":\"dpp\"}}";
+ const char *connector_template = NULL;
+
+ len = 100 + os_strlen(conf_template);
+ if (connector_template)
+ len += os_strlen(connector_template);
+ buf = wpabuf_alloc(len);
+ if (!buf)
+ return NULL;
+
+ /*
+ * DPPConfigurationParameters ::= SEQUENCE {
+ * configurationTemplate UTF8String,
+ * connectorTemplate UTF8String OPTIONAL}
+ */
+
+ asn1_put_utf8string(buf, conf_template);
+ if (connector_template)
+ asn1_put_utf8string(buf, connector_template);
+ return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+static struct wpabuf * dpp_build_attribute(void)
+{
+ struct wpabuf *conf_params, *attr;
+
+ /*
+ * aa-DPPConfigurationParameters ATTRIBUTE ::=
+ * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
+ *
+ * Attribute ::= SEQUENCE {
+ * type OBJECT IDENTIFIER,
+ * values SET SIZE(1..MAX) OF Type
+ */
+ conf_params = dpp_build_conf_params();
+ conf_params = asn1_encaps(conf_params, ASN1_CLASS_UNIVERSAL,
+ ASN1_TAG_SET);
+ if (!conf_params)
+ return NULL;
+
+ attr = wpabuf_alloc(100 + wpabuf_len(conf_params));
+ if (!attr) {
+ wpabuf_clear_free(conf_params);
+ return NULL;
+ }
+
+ asn1_put_oid(attr, &asn1_dpp_config_params_oid);
+ wpabuf_put_buf(attr, conf_params);
+ wpabuf_clear_free(conf_params);
+
+ return asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+static struct wpabuf * dpp_build_key_alg(const struct dpp_curve_params *curve)
+{
+ const struct asn1_oid *oid;
+ struct wpabuf *params, *res;
+
+ switch (curve->ike_group) {
+ case 19:
+ oid = &asn1_prime256v1_oid;
+ break;
+ case 20:
+ oid = &asn1_secp384r1_oid;
+ break;
+ case 21:
+ oid = &asn1_secp521r1_oid;
+ break;
+ case 28:
+ oid = &asn1_brainpoolP256r1_oid;
+ break;
+ case 29:
+ oid = &asn1_brainpoolP384r1_oid;
+ break;
+ case 30:
+ oid = &asn1_brainpoolP512r1_oid;
+ break;
+ default:
+ return NULL;
+ }
+
+ params = wpabuf_alloc(20);
+ if (!params)
+ return NULL;
+ asn1_put_oid(params, oid); /* namedCurve */
+
+ res = asn1_build_alg_id(&asn1_ec_public_key_oid, params);
+ wpabuf_free(params);
+ return res;
+}
+
+
+static struct wpabuf * dpp_build_key_pkg(struct dpp_authentication *auth)
+{
+ struct wpabuf *key = NULL, *attr, *alg, *priv_key = NULL;
+ EC_KEY *eckey;
+ unsigned char *der = NULL;
+ int der_len;
+
+ eckey = EVP_PKEY_get0_EC_KEY(auth->conf->csign);
+ if (!eckey)
+ return NULL;
+
+ EC_KEY_set_enc_flags(eckey, EC_PKEY_NO_PUBKEY);
+ der_len = i2d_ECPrivateKey(eckey, &der);
+ if (der_len > 0)
+ priv_key = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
+
+ alg = dpp_build_key_alg(auth->conf->curve);
+
+ /* Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } */
+ attr = dpp_build_attribute();
+ attr = asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SET);
+ if (!priv_key || !attr || !alg)
+ goto fail;
+
+ /*
+ * OneAsymmetricKey ::= SEQUENCE {
+ * version Version,
+ * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ * privateKey PrivateKey,
+ * attributes [0] Attributes OPTIONAL,
+ * ...,
+ * [[2: publicKey [1] BIT STRING OPTIONAL ]],
+ * ...
+ * }
+ */
+
+ key = wpabuf_alloc(100 + wpabuf_len(alg) + wpabuf_len(priv_key) +
+ wpabuf_len(attr));
+ if (!key)
+ goto fail;
+
+ asn1_put_integer(key, 1); /* version = v2(1) */
+
+ /* PrivateKeyAlgorithmIdentifier */
+ wpabuf_put_buf(key, alg);
+
+ /* PrivateKey ::= OCTET STRING */
+ asn1_put_octet_string(key, priv_key);
+
+ /* [0] Attributes OPTIONAL */
+ asn1_put_hdr(key, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0, wpabuf_len(attr));
+ wpabuf_put_buf(key, attr);
+
+fail:
+ wpabuf_clear_free(attr);
+ wpabuf_clear_free(priv_key);
+ wpabuf_free(alg);
+
+ /*
+ * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
+ *
+ * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
+ *
+ * OneAsymmetricKey ::= SEQUENCE
+ */
+ return asn1_encaps(asn1_encaps(key,
+ ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE),
+ ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+static struct wpabuf * dpp_build_pbkdf2_alg_id(const struct wpabuf *salt,
+ size_t hash_len)
+{
+ struct wpabuf *params = NULL, *buf = NULL, *prf = NULL;
+ const struct asn1_oid *oid;
+
+ /*
+ * PBKDF2-params ::= SEQUENCE {
+ * salt CHOICE {
+ * specified OCTET STRING,
+ * otherSource AlgorithmIdentifier}
+ * iterationCount INTEGER (1..MAX),
+ * keyLength INTEGER (1..MAX),
+ * prf AlgorithmIdentifier}
+ *
+ * salt is an 64 octet value, iterationCount is 1000, keyLength is based
+ * on Configurator signing key length, prf is
+ * id-hmacWithSHA{256,384,512} based on Configurator signing key.
+ */
+
+ if (hash_len == 32)
+ oid = &asn1_pbkdf2_hmac_sha256_oid;
+ else if (hash_len == 48)
+ oid = &asn1_pbkdf2_hmac_sha384_oid;
+ else if (hash_len == 64)
+ oid = &asn1_pbkdf2_hmac_sha512_oid;
+ else
+ goto fail;
+ prf = asn1_build_alg_id(oid, NULL);
+ if (!prf)
+ goto fail;
+ params = wpabuf_alloc(100 + wpabuf_len(salt) + wpabuf_len(prf));
+ if (!params)
+ goto fail;
+ asn1_put_octet_string(params, salt); /* salt.specified */
+ asn1_put_integer(params, 1000); /* iterationCount */
+ asn1_put_integer(params, hash_len); /* keyLength */
+ wpabuf_put_buf(params, prf);
+ params = asn1_encaps(params, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+ if (!params)
+ goto fail;
+ buf = asn1_build_alg_id(&asn1_pbkdf2_oid, params);
+fail:
+ wpabuf_free(params);
+ wpabuf_free(prf);
+ return buf;
}
static struct wpabuf *
-dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
- u16 e_nonce_len, int ap)
+dpp_build_pw_recipient_info(struct dpp_authentication *auth, size_t hash_len,
+ const struct wpabuf *cont_enc_key)
{
- struct wpabuf *conf;
+ struct wpabuf *pwri = NULL, *enc_key = NULL, *key_der_alg = NULL,
+ *key_enc_alg = NULL, *salt;
+ u8 kek[DPP_MAX_HASH_LEN];
+ const u8 *key;
+ size_t key_len;
+
+ salt = wpabuf_alloc(64);
+ if (!salt || os_get_random(wpabuf_put(salt, 64), 64) < 0)
+ goto fail;
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: PBKDF2 salt", salt);
+
+ /* TODO: For initial testing, use ke as the key. Replace this with a
+ * new key once that has been defined. */
+ key = auth->ke;
+ key_len = auth->curve->hash_len;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
+
+ if (dpp_pbkdf2(hash_len, key, key_len, wpabuf_head(salt), 64, 1000,
+ kek, hash_len)) {
+ wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed");
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2",
+ kek, hash_len);
+
+ enc_key = wpabuf_alloc(hash_len + AES_BLOCK_SIZE);
+ if (!enc_key ||
+ aes_siv_encrypt(kek, hash_len, wpabuf_head(cont_enc_key),
+ wpabuf_len(cont_enc_key), 0, NULL, NULL,
+ wpabuf_put(enc_key, hash_len + AES_BLOCK_SIZE)) < 0)
+ goto fail;
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: encryptedKey", enc_key);
+
+ /*
+ * PasswordRecipientInfo ::= SEQUENCE {
+ * version CMSVersion,
+ * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
+ * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+ * encryptedKey EncryptedKey}
+ *
+ * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
+ * parameters contains PBKDF2-params SEQUENCE.
+ */
+
+ key_der_alg = dpp_build_pbkdf2_alg_id(salt, hash_len);
+ key_enc_alg = asn1_build_alg_id(&asn1_aes_siv_cmac_aead_256_oid, NULL);
+ if (!key_der_alg || !key_enc_alg)
+ goto fail;
+ pwri = wpabuf_alloc(100 + wpabuf_len(key_der_alg) +
+ wpabuf_len(key_enc_alg) + wpabuf_len(enc_key));
+ if (!pwri)
+ goto fail;
+
+ /* version = 0 */
+ asn1_put_integer(pwri, 0);
+
+ /* [0] KeyDerivationAlgorithmIdentifier */
+ asn1_put_hdr(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0,
+ wpabuf_len(key_der_alg));
+ wpabuf_put_buf(pwri, key_der_alg);
+
+ /* KeyEncryptionAlgorithmIdentifier */
+ wpabuf_put_buf(pwri, key_enc_alg);
+
+ /* EncryptedKey ::= OCTET STRING */
+ asn1_put_octet_string(pwri, enc_key);
+
+fail:
+ wpabuf_clear_free(key_der_alg);
+ wpabuf_free(key_enc_alg);
+ wpabuf_free(enc_key);
+ wpabuf_free(salt);
+ forced_memzero(kek, sizeof(kek));
+ return asn1_encaps(pwri, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+static struct wpabuf *
+dpp_build_recipient_info(struct dpp_authentication *auth, size_t hash_len,
+ const struct wpabuf *cont_enc_key)
+{
+ struct wpabuf *pwri;
+
+ /*
+ * RecipientInfo ::= CHOICE {
+ * ktri KeyTransRecipientInfo,
+ * kari [1] KeyAgreeRecipientInfo,
+ * kekri [2] KEKRecipientInfo,
+ * pwri [3] PasswordRecipientInfo,
+ * ori [4] OtherRecipientInfo}
+ *
+ * Shall always use the pwri CHOICE.
+ */
+
+ pwri = dpp_build_pw_recipient_info(auth, hash_len, cont_enc_key);
+ return asn1_encaps(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 3);
+}
+
+
+static struct wpabuf *
+dpp_build_enc_cont_info(struct dpp_authentication *auth, size_t hash_len,
+ const struct wpabuf *cont_enc_key)
+{
+ struct wpabuf *key_pkg, *enc_cont_info = NULL, *enc_cont = NULL,
+ *enc_alg;
+ const struct asn1_oid *oid;
+ size_t enc_cont_len;
+
+ /*
+ * EncryptedContentInfo ::= SEQUENCE {
+ * contentType ContentType,
+ * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+ * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL}
+ */
+
+ if (hash_len == 32)
+ oid = &asn1_aes_siv_cmac_aead_256_oid;
+ else if (hash_len == 48)
+ oid = &asn1_aes_siv_cmac_aead_384_oid;
+ else if (hash_len == 64)
+ oid = &asn1_aes_siv_cmac_aead_512_oid;
+ else
+ return NULL;
+
+ key_pkg = dpp_build_key_pkg(auth);
+ enc_alg = asn1_build_alg_id(oid, NULL);
+ if (!key_pkg || !enc_alg)
+ goto fail;
+
+ wpa_hexdump_buf_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage",
+ key_pkg);
+
+ enc_cont_len = wpabuf_len(key_pkg) + AES_BLOCK_SIZE;
+ enc_cont = wpabuf_alloc(enc_cont_len);
+ if (!enc_cont ||
+ aes_siv_encrypt(wpabuf_head(cont_enc_key), wpabuf_len(cont_enc_key),
+ wpabuf_head(key_pkg), wpabuf_len(key_pkg),
+ 0, NULL, NULL,
+ wpabuf_put(enc_cont, enc_cont_len)) < 0)
+ goto fail;
+
+ enc_cont_info = wpabuf_alloc(100 + wpabuf_len(enc_alg) +
+ wpabuf_len(enc_cont));
+ if (!enc_cont_info)
+ goto fail;
+
+ /* ContentType ::= OBJECT IDENTIFIER */
+ asn1_put_oid(enc_cont_info, &asn1_dpp_asymmetric_key_package_oid);
+
+ /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
+ wpabuf_put_buf(enc_cont_info, enc_alg);
+
+ /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+ * EncryptedContent ::= OCTET STRING */
+ asn1_put_hdr(enc_cont_info, ASN1_CLASS_CONTEXT_SPECIFIC, 0, 0,
+ wpabuf_len(enc_cont));
+ wpabuf_put_buf(enc_cont_info, enc_cont);
+
+fail:
+ wpabuf_clear_free(key_pkg);
+ wpabuf_free(enc_cont);
+ wpabuf_free(enc_alg);
+ return enc_cont_info;
+}
+
+
+static struct wpabuf * dpp_gen_random(size_t len)
+{
+ struct wpabuf *key;
+
+ key = wpabuf_alloc(len);
+ if (!key || os_get_random(wpabuf_put(key, len), len) < 0) {
+ wpabuf_free(key);
+ key = NULL;
+ }
+ wpa_hexdump_buf_key(MSG_DEBUG, "DPP: content-encryption key", key);
+ return key;
+}
+
+
+static struct wpabuf * dpp_build_enveloped_data(struct dpp_authentication *auth)
+{
+ struct wpabuf *env = NULL;
+ struct wpabuf *recipient_info = NULL, *enc_cont_info = NULL;
+ struct wpabuf *cont_enc_key = NULL;
+ size_t hash_len;
+
+ if (!auth->conf) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No Configurator instance selected for the session - cannot build DPPEnvelopedData");
+ return NULL;
+ }
+
+ if (!auth->provision_configurator) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Configurator provisioning not allowed");
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Building DPPEnvelopedData");
+
+ hash_len = auth->conf->curve->hash_len;
+ cont_enc_key = dpp_gen_random(hash_len);
+ if (!cont_enc_key)
+ goto fail;
+ recipient_info = dpp_build_recipient_info(auth, hash_len, cont_enc_key);
+ enc_cont_info = dpp_build_enc_cont_info(auth, hash_len, cont_enc_key);
+ if (!recipient_info || !enc_cont_info)
+ goto fail;
+
+ env = wpabuf_alloc(wpabuf_len(recipient_info) +
+ wpabuf_len(enc_cont_info) +
+ 100);
+ if (!env)
+ goto fail;
+
+ /*
+ * DPPEnvelopedData ::= EnvelopedData
+ *
+ * EnvelopedData ::= SEQUENCE {
+ * version CMSVersion,
+ * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+ * recipientInfos RecipientInfos,
+ * encryptedContentInfo EncryptedContentInfo,
+ * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL}
+ *
+ * For DPP, version is 3, both originatorInfo and
+ * unprotectedAttrs are omitted, and recipientInfos contains a single
+ * RecipientInfo.
+ */
+
+ /* EnvelopedData.version = 3 */
+ asn1_put_integer(env, 3);
+
+ /* RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo */
+ asn1_put_set(env, recipient_info);
+
+ /* EncryptedContentInfo ::= SEQUENCE */
+ asn1_put_sequence(env, enc_cont_info);
+
+ env = asn1_encaps(env, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: DPPEnvelopedData", env);
+out:
+ wpabuf_clear_free(cont_enc_key);
+ wpabuf_clear_free(recipient_info);
+ wpabuf_free(enc_cont_info);
+ return env;
+fail:
+ wpabuf_free(env);
+ env = NULL;
+ goto out;
+}
+
+#endif /* CONFIG_DPP2 */
+
+
+static struct wpabuf *
+dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
+ u16 e_nonce_len, enum dpp_netrole netrole)
+{
+ struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL;
size_t clear_len, attr_len;
struct wpabuf *clear = NULL, *msg = NULL;
u8 *wrapped;
@@ -4760,18 +5746,34 @@
size_t len[1];
enum dpp_status_error status;
- conf = dpp_build_conf_obj(auth, ap);
- if (conf) {
- wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
- wpabuf_head(conf), wpabuf_len(conf));
+ if (netrole == DPP_NETROLE_CONFIGURATOR) {
+#ifdef CONFIG_DPP2
+ env_data = dpp_build_enveloped_data(auth);
+#endif /* CONFIG_DPP2 */
+ } else {
+ conf = dpp_build_conf_obj(auth, netrole, 0);
+ if (conf) {
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "DPP: configurationObject JSON",
+ wpabuf_head(conf), wpabuf_len(conf));
+ conf2 = dpp_build_conf_obj(auth, netrole, 1);
+ }
}
- status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE;
+ status = (conf || env_data) ? DPP_STATUS_OK :
+ DPP_STATUS_CONFIGURE_FAILURE;
auth->conf_resp_status = status;
- /* { E-nonce, configurationObject}ke */
+ /* { E-nonce, configurationObject[, sendConnStatus]}ke */
clear_len = 4 + e_nonce_len;
if (conf)
clear_len += 4 + wpabuf_len(conf);
+ if (conf2)
+ clear_len += 4 + wpabuf_len(conf2);
+ if (env_data)
+ clear_len += 4 + wpabuf_len(env_data);
+ if (auth->peer_version >= 2 && auth->send_conn_status &&
+ netrole == DPP_NETROLE_STA)
+ clear_len += 4;
clear = wpabuf_alloc(clear_len);
attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
#ifdef CONFIG_TESTING_OPTIONS
@@ -4819,6 +5821,26 @@
wpabuf_put_le16(clear, wpabuf_len(conf));
wpabuf_put_buf(clear, conf);
}
+ if (auth->peer_version >= 2 && conf2) {
+ wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
+ wpabuf_put_le16(clear, wpabuf_len(conf2));
+ wpabuf_put_buf(clear, conf2);
+ } else if (conf2) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Second Config Object available, but peer does not support more than one");
+ }
+ if (env_data) {
+ wpabuf_put_le16(clear, DPP_ATTR_ENVELOPED_DATA);
+ wpabuf_put_le16(clear, wpabuf_len(env_data));
+ wpabuf_put_buf(clear, env_data);
+ }
+
+ if (auth->peer_version >= 2 && auth->send_conn_status &&
+ netrole == DPP_NETROLE_STA) {
+ wpa_printf(MSG_DEBUG, "DPP: sendConnStatus");
+ wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS);
+ wpabuf_put_le16(clear, 0);
+ }
#ifdef CONFIG_TESTING_OPTIONS
skip_config_obj:
@@ -4866,8 +5888,10 @@
wpa_hexdump_buf(MSG_DEBUG,
"DPP: Configuration Response attributes", msg);
out:
- wpabuf_free(conf);
- wpabuf_free(clear);
+ wpabuf_clear_free(conf);
+ wpabuf_clear_free(conf2);
+ wpabuf_clear_free(env_data);
+ wpabuf_clear_free(clear);
return msg;
fail:
@@ -4887,7 +5911,7 @@
size_t unwrapped_len = 0;
struct wpabuf *resp = NULL;
struct json_token *root = NULL, *token;
- int ap;
+ enum dpp_netrole netrole;
#ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
@@ -4985,9 +6009,11 @@
}
wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
if (os_strcmp(token->string, "sta") == 0) {
- ap = 0;
+ netrole = DPP_NETROLE_STA;
} else if (os_strcmp(token->string, "ap") == 0) {
- ap = 1;
+ netrole = DPP_NETROLE_AP;
+ } else if (os_strcmp(token->string, "configurator") == 0) {
+ netrole = DPP_NETROLE_CONFIGURATOR;
} else {
wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
token->string);
@@ -4995,7 +6021,33 @@
goto fail;
}
- resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, ap);
+ token = json_get_member(root, "mudurl");
+ if (token && token->type == JSON_STRING)
+ wpa_printf(MSG_DEBUG, "DPP: mudurl = '%s'", token->string);
+
+ token = json_get_member(root, "bandSupport");
+ auth->band_list_size = 0;
+ if (token && token->type == JSON_ARRAY) {
+ memset(auth->band_list, 0, sizeof(auth->band_list));
+ wpa_printf(MSG_DEBUG, "DPP: bandSupport");
+ token = token->child;
+ while (token) {
+ if (token->type != JSON_NUMBER) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Invalid bandSupport array member type");
+ } else {
+ if (auth->band_list_size < DPP_MAX_CHANNELS) {
+ auth->band_list[auth->band_list_size++] = token->number;
+ }
+ wpa_printf(MSG_DEBUG,
+ "DPP: Supported global operating class: %d",
+ token->number);
+ }
+ token = token->sibling;
+ }
+ }
+
+ resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole);
fail:
json_free(root);
@@ -5084,7 +6136,7 @@
}
-static int dpp_parse_cred_legacy(struct dpp_authentication *auth,
+static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
struct json_token *cred)
{
struct json_token *pass, *psk_hex;
@@ -5101,28 +6153,28 @@
pass->string, len);
if (len < 8 || len > 63)
return -1;
- os_strlcpy(auth->passphrase, pass->string,
- sizeof(auth->passphrase));
+ os_strlcpy(conf->passphrase, pass->string,
+ sizeof(conf->passphrase));
} else if (psk_hex && psk_hex->type == JSON_STRING) {
- if (dpp_akm_sae(auth->akm) && !dpp_akm_psk(auth->akm)) {
+ if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->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) {
+ hexstr2bin(psk_hex->string, conf->psk, PMK_LEN) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
return -1;
}
wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
- auth->psk, PMK_LEN);
- auth->psk_set = 1;
+ conf->psk, PMK_LEN);
+ conf->psk_set = 1;
} else {
wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
return -1;
}
- if (dpp_akm_sae(auth->akm) && !auth->passphrase[0]) {
+ if (dpp_akm_sae(conf->akm) && !conf->passphrase[0]) {
wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
return -1;
}
@@ -5199,6 +6251,7 @@
pkey = dpp_set_pubkey_point_group(group, wpabuf_head(x), wpabuf_head(y),
wpabuf_len(x));
+ EC_GROUP_free(group);
*key_curve = curve;
fail:
@@ -5289,6 +6342,7 @@
static int dpp_parse_connector(struct dpp_authentication *auth,
+ struct dpp_config_obj *conf,
const unsigned char *payload,
u16 payload_len)
{
@@ -5416,7 +6470,7 @@
}
-static void dpp_copy_csign(struct dpp_authentication *auth, EVP_PKEY *csign)
+static void dpp_copy_csign(struct dpp_config_obj *conf, EVP_PKEY *csign)
{
unsigned char *der = NULL;
int der_len;
@@ -5424,13 +6478,14 @@
der_len = i2d_PUBKEY(csign, &der);
if (der_len <= 0)
return;
- wpabuf_free(auth->c_sign_key);
- auth->c_sign_key = wpabuf_alloc_copy(der, der_len);
+ wpabuf_free(conf->c_sign_key);
+ conf->c_sign_key = wpabuf_alloc_copy(der, der_len);
OPENSSL_free(der);
}
-static void dpp_copy_netaccesskey(struct dpp_authentication *auth)
+static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
unsigned char *der = NULL;
int der_len;
@@ -5498,8 +6553,7 @@
ret = DPP_STATUS_INVALID_CONNECTOR;
goto fail;
}
- prot_hdr = base64_url_decode((const unsigned char *) pos,
- end - pos, &prot_hdr_len);
+ prot_hdr = base64_url_decode(pos, end - pos, &prot_hdr_len);
if (!prot_hdr) {
wpa_printf(MSG_DEBUG,
"DPP: Failed to base64url decode signedConnector JWS Protected Header");
@@ -5531,8 +6585,7 @@
goto fail;
}
signed_end = end - 1;
- info->payload = base64_url_decode((const unsigned char *) pos,
- end - pos, &info->payload_len);
+ info->payload = base64_url_decode(pos, end - pos, &info->payload_len);
if (!info->payload) {
wpa_printf(MSG_DEBUG,
"DPP: Failed to base64url decode signedConnector JWS Payload");
@@ -5543,8 +6596,7 @@
"DPP: signedConnector - JWS Payload",
info->payload, info->payload_len);
pos = end + 1;
- signature = base64_url_decode((const unsigned char *) pos,
- os_strlen(pos), &signature_len);
+ signature = base64_url_decode(pos, os_strlen(pos), &signature_len);
if (!signature) {
wpa_printf(MSG_DEBUG,
"DPP: Failed to base64url decode signedConnector signature");
@@ -5624,6 +6676,7 @@
static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
+ struct dpp_config_obj *conf,
struct json_token *cred)
{
struct dpp_signed_connector_info info;
@@ -5635,10 +6688,10 @@
os_memset(&info, 0, sizeof(info));
- if (dpp_akm_psk(auth->akm) || dpp_akm_sae(auth->akm)) {
+ if (dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) {
wpa_printf(MSG_DEBUG,
"DPP: Legacy credential included in Connector credential");
- if (dpp_parse_cred_legacy(auth, cred) < 0)
+ if (dpp_parse_cred_legacy(conf, cred) < 0)
return -1;
}
@@ -5677,16 +6730,18 @@
signed_connector) != DPP_STATUS_OK)
goto fail;
- if (dpp_parse_connector(auth, info.payload, info.payload_len) < 0) {
+ if (dpp_parse_connector(auth, conf,
+ info.payload, info.payload_len) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
goto fail;
}
- os_free(auth->connector);
- auth->connector = os_strdup(signed_connector);
+ os_free(conf->connector);
+ conf->connector = os_strdup(signed_connector);
- dpp_copy_csign(auth, csign_pub);
- dpp_copy_netaccesskey(auth);
+ dpp_copy_csign(conf, csign_pub);
+ if (dpp_akm_dpp(conf->akm) || auth->peer_version >= 2)
+ dpp_copy_netaccesskey(auth, conf);
ret = 0;
fail:
@@ -5717,8 +6772,32 @@
}
+const char * dpp_akm_selector_str(enum dpp_akm akm)
+{
+ switch (akm) {
+ case DPP_AKM_DPP:
+ return "506F9A02";
+ case DPP_AKM_PSK:
+ return "000FAC02+000FAC06";
+ case DPP_AKM_SAE:
+ return "000FAC08";
+ case DPP_AKM_PSK_SAE:
+ return "000FAC02+000FAC06+000FAC08";
+ case DPP_AKM_SAE_DPP:
+ return "506F9A02+000FAC08";
+ case DPP_AKM_PSK_SAE_DPP:
+ return "506F9A02+000FAC08+000FAC02+000FAC06";
+ default:
+ return "??";
+ }
+}
+
+
static enum dpp_akm dpp_akm_from_str(const char *akm)
{
+ const char *pos;
+ int dpp = 0, psk = 0, sae = 0;
+
if (os_strcmp(akm, "psk") == 0)
return DPP_AKM_PSK;
if (os_strcmp(akm, "sae") == 0)
@@ -5731,6 +6810,38 @@
return DPP_AKM_SAE_DPP;
if (os_strcmp(akm, "dpp+psk+sae") == 0)
return DPP_AKM_PSK_SAE_DPP;
+
+ pos = akm;
+ while (*pos) {
+ if (os_strlen(pos) < 8)
+ break;
+ if (os_strncasecmp(pos, "506F9A02", 8) == 0)
+ dpp = 1;
+ else if (os_strncasecmp(pos, "000FAC02", 8) == 0)
+ psk = 1;
+ else if (os_strncasecmp(pos, "000FAC06", 8) == 0)
+ psk = 1;
+ else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
+ sae = 1;
+ pos += 8;
+ if (*pos != '+')
+ break;
+ pos++;
+ }
+
+ if (dpp && psk && sae)
+ return DPP_AKM_PSK_SAE_DPP;
+ if (dpp && sae)
+ return DPP_AKM_SAE_DPP;
+ if (dpp)
+ return DPP_AKM_DPP;
+ if (psk && sae)
+ return DPP_AKM_PSK_SAE;
+ if (sae)
+ return DPP_AKM_SAE;
+ if (psk)
+ return DPP_AKM_PSK;
+
return DPP_AKM_UNKNOWN;
}
@@ -5740,6 +6851,9 @@
{
int ret = -1;
struct json_token *root, *token, *discovery, *cred;
+ struct dpp_config_obj *conf;
+ struct wpabuf *ssid64 = NULL;
+ int legacy;
root = json_parse((const char *) conf_obj, conf_obj_len);
if (!root)
@@ -5767,19 +6881,52 @@
goto fail;
}
- token = json_get_member(discovery, "ssid");
- if (!token || token->type != JSON_STRING) {
- dpp_auth_fail(auth, "No discovery::ssid string value found");
+ ssid64 = json_get_member_base64url(discovery, "ssid64");
+ if (ssid64) {
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid64",
+ wpabuf_head(ssid64), wpabuf_len(ssid64));
+ if (wpabuf_len(ssid64) > SSID_MAX_LEN) {
+ dpp_auth_fail(auth, "Too long discovery::ssid64 value");
+ goto fail;
+ }
+ } else {
+ token = json_get_member(discovery, "ssid");
+ if (!token || token->type != JSON_STRING) {
+ 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) {
+ dpp_auth_fail(auth,
+ "Too long discovery::ssid string value");
+ goto fail;
+ }
+ }
+
+ if (auth->num_conf_obj == DPP_MAX_CONF_OBJ) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No room for this many Config Objects - ignore this one");
+ ret = 0;
goto fail;
}
- wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
- token->string, os_strlen(token->string));
- if (os_strlen(token->string) > SSID_MAX_LEN) {
- dpp_auth_fail(auth, "Too long discovery::ssid string value");
- goto fail;
+ conf = &auth->conf_obj[auth->num_conf_obj++];
+
+ if (ssid64) {
+ conf->ssid_len = wpabuf_len(ssid64);
+ os_memcpy(conf->ssid, wpabuf_head(ssid64), conf->ssid_len);
+ } else {
+ conf->ssid_len = os_strlen(token->string);
+ os_memcpy(conf->ssid, token->string, conf->ssid_len);
}
- auth->ssid_len = os_strlen(token->string);
- os_memcpy(auth->ssid, token->string, auth->ssid_len);
+
+ token = json_get_member(discovery, "ssid_charset");
+ if (token && token->type == JSON_NUMBER) {
+ conf->ssid_charset = token->number;
+ wpa_printf(MSG_DEBUG, "DPP: ssid_charset=%d",
+ conf->ssid_charset);
+ }
cred = json_get_member(root, "cred");
if (!cred || cred->type != JSON_OBJECT) {
@@ -5792,13 +6939,24 @@
dpp_auth_fail(auth, "No cred::akm string value found");
goto fail;
}
- auth->akm = dpp_akm_from_str(token->string);
+ conf->akm = dpp_akm_from_str(token->string);
- if (dpp_akm_legacy(auth->akm)) {
- if (dpp_parse_cred_legacy(auth, cred) < 0)
+ legacy = dpp_akm_legacy(conf->akm);
+ if (legacy && auth->peer_version >= 2) {
+ struct json_token *csign, *s_conn;
+
+ csign = json_get_member(cred, "csign");
+ s_conn = json_get_member(cred, "signedConnector");
+ if (csign && csign->type == JSON_OBJECT &&
+ s_conn && s_conn->type == JSON_STRING)
+ legacy = 0;
+ }
+ if (legacy) {
+ if (dpp_parse_cred_legacy(conf, cred) < 0)
goto fail;
- } else if (dpp_akm_dpp(auth->akm)) {
- if (dpp_parse_cred_dpp(auth, cred) < 0)
+ } else if (dpp_akm_dpp(conf->akm) ||
+ (auth->peer_version >= 2 && dpp_akm_legacy(conf->akm))) {
+ if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
goto fail;
} else {
wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
@@ -5810,16 +6968,722 @@
wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
ret = 0;
fail:
+ wpabuf_free(ssid64);
json_free(root);
return ret;
}
+#ifdef CONFIG_DPP2
+
+struct dpp_enveloped_data {
+ const u8 *enc_cont;
+ size_t enc_cont_len;
+ const u8 *enc_key;
+ size_t enc_key_len;
+ const u8 *salt;
+ size_t pbkdf2_key_len;
+ size_t prf_hash_len;
+};
+
+
+static int dpp_parse_recipient_infos(const u8 *pos, size_t len,
+ struct dpp_enveloped_data *data)
+{
+ struct asn1_hdr hdr;
+ const u8 *end = pos + len;
+ const u8 *next, *e_end;
+ struct asn1_oid oid;
+ int val;
+ const u8 *params;
+ size_t params_len;
+
+ wpa_hexdump(MSG_MSGDUMP, "DPP: RecipientInfos", pos, len);
+
+ /*
+ * RecipientInfo ::= CHOICE {
+ * ktri KeyTransRecipientInfo,
+ * kari [1] KeyAgreeRecipientInfo,
+ * kekri [2] KEKRecipientInfo,
+ * pwri [3] PasswordRecipientInfo,
+ * ori [4] OtherRecipientInfo}
+ *
+ * Shall always use the pwri CHOICE.
+ */
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 3) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected CHOICE [3] (pwri) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: PasswordRecipientInfo",
+ hdr.payload, hdr.length);
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ /*
+ * PasswordRecipientInfo ::= SEQUENCE {
+ * version CMSVersion,
+ * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
+ * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+ * encryptedKey EncryptedKey}
+ *
+ * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
+ * parameters contains PBKDF2-params SEQUENCE.
+ */
+
+ if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0)
+ return -1;
+ pos = hdr.payload;
+
+ if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
+ return -1;
+ if (val != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: pwri.version != 0");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Remaining PasswordRecipientInfo after version",
+ pos, end - pos);
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected keyDerivationAlgorithm [0] - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ pos = hdr.payload;
+ e_end = pos + hdr.length;
+
+ /* KeyDerivationAlgorithmIdentifier ::= AlgorithmIdentifier */
+ if (asn1_get_alg_id(pos, e_end - pos, &oid, ¶ms, ¶ms_len,
+ &next) < 0)
+ return -1;
+ if (!asn1_oid_equal(&oid, &asn1_pbkdf2_oid)) {
+ char buf[80];
+
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected KeyDerivationAlgorithmIdentifier %s",
+ buf);
+ return -1;
+ }
+
+ /*
+ * PBKDF2-params ::= SEQUENCE {
+ * salt CHOICE {
+ * specified OCTET STRING,
+ * otherSource AlgorithmIdentifier}
+ * iterationCount INTEGER (1..MAX),
+ * keyLength INTEGER (1..MAX),
+ * prf AlgorithmIdentifier}
+ *
+ * salt is an 64 octet value, iterationCount is 1000, keyLength is based
+ * on Configurator signing key length, prf is
+ * id-hmacWithSHA{256,384,512} based on Configurator signing key.
+ */
+ if (!params ||
+ asn1_get_sequence(params, params_len, &hdr, &e_end) < 0)
+ return -1;
+ pos = hdr.payload;
+
+ if (asn1_get_next(pos, e_end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected OCTETSTRING (salt.specified) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: salt.specified",
+ hdr.payload, hdr.length);
+ if (hdr.length != 64) {
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected salt length %u",
+ hdr.length);
+ return -1;
+ }
+ data->salt = hdr.payload;
+ pos = hdr.payload + hdr.length;
+
+ if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0)
+ return -1;
+ if (val != 1000) {
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected iterationCount %d", val);
+ return -1;
+ }
+
+ if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0)
+ return -1;
+ if (val != 32 && val != 48 && val != 64) {
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected keyLength %d", val);
+ return -1;
+ }
+ data->pbkdf2_key_len = val;
+
+ if (asn1_get_sequence(pos, e_end - pos, &hdr, NULL) < 0 ||
+ asn1_get_oid(hdr.payload, hdr.length, &oid, &pos) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Could not parse prf");
+ return -1;
+ }
+ if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha256_oid)) {
+ data->prf_hash_len = 32;
+ } else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha384_oid)) {
+ data->prf_hash_len = 48;
+ } else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha512_oid)) {
+ data->prf_hash_len = 64;
+ } else {
+ char buf[80];
+
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected PBKDF2-params.prf %s",
+ buf);
+ return -1;
+ }
+
+ pos = next;
+
+ /* keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier
+ *
+ * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * id-alg-AES-SIV-CMAC-aed-256, id-alg-AES-SIV-CMAC-aed-384, or
+ * id-alg-AES-SIV-CMAC-aed-512. */
+ if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0)
+ return -1;
+ if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) &&
+ !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) &&
+ !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) {
+ char buf[80];
+
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected KeyEncryptionAlgorithmIdentifier %s",
+ buf);
+ return -1;
+ }
+
+ /*
+ * encryptedKey EncryptedKey
+ *
+ * EncryptedKey ::= OCTET STRING
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected OCTETSTRING (pwri.encryptedKey) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: pwri.encryptedKey",
+ hdr.payload, hdr.length);
+ data->enc_key = hdr.payload;
+ data->enc_key_len = hdr.length;
+
+ return 0;
+}
+
+
+static int dpp_parse_encrypted_content_info(const u8 *pos, const u8 *end,
+ struct dpp_enveloped_data *data)
+{
+ struct asn1_hdr hdr;
+ struct asn1_oid oid;
+
+ /*
+ * EncryptedContentInfo ::= SEQUENCE {
+ * contentType ContentType,
+ * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+ * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL}
+ */
+ if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
+ return -1;
+ wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContentInfo",
+ hdr.payload, hdr.length);
+ if (pos < end) {
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Unexpected extra data after EncryptedContentInfo",
+ pos, end - pos);
+ return -1;
+ }
+
+ end = pos;
+ pos = hdr.payload;
+
+ /* ContentType ::= OBJECT IDENTIFIER */
+ if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Could not parse ContentType");
+ return -1;
+ }
+ if (!asn1_oid_equal(&oid, &asn1_dpp_asymmetric_key_package_oid)) {
+ char buf[80];
+
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected ContentType %s", buf);
+ return -1;
+ }
+
+ /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
+ if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0)
+ return -1;
+ if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) &&
+ !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) &&
+ !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) {
+ char buf[80];
+
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected ContentEncryptionAlgorithmIdentifier %s",
+ buf);
+ return -1;
+ }
+ /* ignore optional parameters */
+
+ /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+ * EncryptedContent ::= OCTET STRING */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected [0] IMPLICIT (EncryptedContent) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContent",
+ hdr.payload, hdr.length);
+ data->enc_cont = hdr.payload;
+ data->enc_cont_len = hdr.length;
+ return 0;
+}
+
+
+static int dpp_parse_enveloped_data(const u8 *env_data, size_t env_data_len,
+ struct dpp_enveloped_data *data)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos, *end;
+ int val;
+
+ os_memset(data, 0, sizeof(*data));
+
+ /*
+ * DPPEnvelopedData ::= EnvelopedData
+ *
+ * EnvelopedData ::= SEQUENCE {
+ * version CMSVersion,
+ * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+ * recipientInfos RecipientInfos,
+ * encryptedContentInfo EncryptedContentInfo,
+ * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL}
+ *
+ * CMSVersion ::= INTEGER
+ *
+ * RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo
+ *
+ * For DPP, version is 3, both originatorInfo and
+ * unprotectedAttrs are omitted, and recipientInfos contains a single
+ * RecipientInfo.
+ */
+ if (asn1_get_sequence(env_data, env_data_len, &hdr, &end) < 0)
+ return -1;
+ pos = hdr.payload;
+ if (end < env_data + env_data_len) {
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Unexpected extra data after DPPEnvelopedData",
+ end, env_data + env_data_len - end);
+ return -1;
+ }
+
+ if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
+ return -1;
+ if (val != 3) {
+ wpa_printf(MSG_DEBUG, "DPP: EnvelopedData.version != 3");
+ return -1;
+ }
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected SET (RecipientInfos) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ if (dpp_parse_recipient_infos(hdr.payload, hdr.length, data) < 0)
+ return -1;
+ return dpp_parse_encrypted_content_info(hdr.payload + hdr.length, end,
+ data);
+}
+
+
+static struct dpp_asymmetric_key *
+dpp_parse_one_asymmetric_key(const u8 *buf, size_t len)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos = buf, *end = buf + len, *next;
+ int val;
+ const u8 *params;
+ size_t params_len;
+ struct asn1_oid oid;
+ char txt[80];
+ struct dpp_asymmetric_key *key;
+ EC_KEY *eckey;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "DPP: OneAsymmetricKey", buf, len);
+
+ key = os_zalloc(sizeof(*key));
+ if (!key)
+ return NULL;
+
+ /*
+ * OneAsymmetricKey ::= SEQUENCE {
+ * version Version,
+ * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ * privateKey PrivateKey,
+ * attributes [0] Attributes OPTIONAL,
+ * ...,
+ * [[2: publicKey [1] BIT STRING OPTIONAL ]],
+ * ...
+ * }
+ */
+ if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0)
+ goto fail;
+ pos = hdr.payload;
+
+ /* Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2) */
+ if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
+ goto fail;
+ if (val != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unsupported DPPAsymmetricKeyPackage version %d",
+ val);
+ goto fail;
+ }
+
+ /* PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier */
+ if (asn1_get_alg_id(pos, end - pos, &oid, ¶ms, ¶ms_len,
+ &pos) < 0)
+ goto fail;
+ if (!asn1_oid_equal(&oid, &asn1_ec_public_key_oid)) {
+ asn1_oid_to_str(&oid, txt, sizeof(txt));
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unsupported PrivateKeyAlgorithmIdentifier %s",
+ txt);
+ goto fail;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: PrivateKeyAlgorithmIdentifier params",
+ params, params_len);
+ /*
+ * ECParameters ::= CHOICE {
+ * namedCurve OBJECT IDENTIFIER
+ * -- implicitCurve NULL
+ * -- specifiedCurve SpecifiedECDomain}
+ */
+ if (!params || asn1_get_oid(params, params_len, &oid, &next) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not parse ECParameters.namedCurve");
+ goto fail;
+ }
+ asn1_oid_to_str(&oid, txt, sizeof(txt));
+ wpa_printf(MSG_MSGDUMP, "DPP: namedCurve %s", txt);
+ /* Assume the curve is identified within ECPrivateKey, so that this
+ * separate indication is not really needed. */
+
+ /*
+ * PrivateKey ::= OCTET STRING
+ * (Contains DER encoding of ECPrivateKey)
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected OCTETSTRING (PrivateKey) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "DPP: PrivateKey",
+ hdr.payload, hdr.length);
+ pos = hdr.payload + hdr.length;
+ eckey = d2i_ECPrivateKey(NULL, &hdr.payload, hdr.length);
+ if (!eckey) {
+ wpa_printf(MSG_INFO,
+ "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ key->csign = EVP_PKEY_new();
+ if (!key->csign || EVP_PKEY_assign_EC_KEY(key->csign, eckey) != 1) {
+ EC_KEY_free(eckey);
+ goto fail;
+ }
+ if (wpa_debug_show_keys)
+ dpp_debug_print_key("DPP: Received c-sign-key", key->csign);
+
+ /*
+ * Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } }
+ *
+ * Exactly one instance of type Attribute in OneAsymmetricKey.
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected [0] Attributes - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "DPP: Attributes",
+ hdr.payload, hdr.length);
+ if (hdr.payload + hdr.length < end) {
+ wpa_hexdump_key(MSG_MSGDUMP,
+ "DPP: Ignore additional data at the end of OneAsymmetricKey",
+ hdr.payload + hdr.length,
+ end - (hdr.payload + hdr.length));
+ }
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected SET (Attributes) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ goto fail;
+ }
+ if (hdr.payload + hdr.length < end) {
+ wpa_hexdump_key(MSG_MSGDUMP,
+ "DPP: Ignore additional data at the end of OneAsymmetricKey (after SET)",
+ hdr.payload + hdr.length,
+ end - (hdr.payload + hdr.length));
+ }
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ /*
+ * OneAsymmetricKeyAttributes ATTRIBUTE ::= {
+ * aa-DPPConfigurationParameters,
+ * ... -- For local profiles
+ * }
+ *
+ * aa-DPPConfigurationParameters ATTRIBUTE ::=
+ * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
+ *
+ * Attribute ::= SEQUENCE {
+ * type OBJECT IDENTIFIER,
+ * values SET SIZE(1..MAX) OF Type
+ *
+ * Exactly one instance of ATTRIBUTE in attrValues.
+ */
+ if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
+ goto fail;
+ if (pos < end) {
+ wpa_hexdump_key(MSG_MSGDUMP,
+ "DPP: Ignore additional data at the end of ATTRIBUTE",
+ pos, end - pos);
+ }
+ end = pos;
+ pos = hdr.payload;
+
+ if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0)
+ goto fail;
+ if (!asn1_oid_equal(&oid, &asn1_dpp_config_params_oid)) {
+ asn1_oid_to_str(&oid, txt, sizeof(txt));
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected Attribute identifier %s", txt);
+ goto fail;
+ }
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected SET (Attribute) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ goto fail;
+ }
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ /*
+ * DPPConfigurationParameters ::= SEQUENCE {
+ * configurationTemplate UTF8String,
+ * connectorTemplate UTF8String OPTIONAL}
+ */
+
+ wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPConfigurationParameters",
+ pos, end - pos);
+ if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
+ goto fail;
+ if (pos < end) {
+ wpa_hexdump_key(MSG_MSGDUMP,
+ "DPP: Ignore additional data after DPPConfigurationParameters",
+ pos, end - pos);
+ }
+ end = pos;
+ pos = hdr.payload;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_UTF8STRING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected UTF8STRING (configurationTemplate) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ goto fail;
+ }
+ wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: configurationTemplate",
+ hdr.payload, hdr.length);
+ key->config_template = os_zalloc(hdr.length + 1);
+ if (!key->config_template)
+ goto fail;
+ os_memcpy(key->config_template, hdr.payload, hdr.length);
+
+ pos = hdr.payload + hdr.length;
+
+ if (pos < end) {
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_UTF8STRING) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Expected UTF8STRING (connectorTemplate) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ goto fail;
+ }
+ wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: connectorTemplate",
+ hdr.payload, hdr.length);
+ key->connector_template = os_zalloc(hdr.length + 1);
+ if (!key->connector_template)
+ goto fail;
+ os_memcpy(key->connector_template, hdr.payload, hdr.length);
+ }
+
+ return key;
+fail:
+ wpa_printf(MSG_DEBUG, "DPP: Failed to parse OneAsymmetricKey");
+ dpp_free_asymmetric_key(key);
+ return NULL;
+}
+
+
+static struct dpp_asymmetric_key *
+dpp_parse_dpp_asymmetric_key_package(const u8 *key_pkg, size_t key_pkg_len)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos = key_pkg, *end = key_pkg + key_pkg_len;
+ struct dpp_asymmetric_key *first = NULL, *last = NULL, *key;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage",
+ key_pkg, key_pkg_len);
+
+ /*
+ * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
+ *
+ * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
+ */
+ while (pos < end) {
+ if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0 ||
+ !(key = dpp_parse_one_asymmetric_key(hdr.payload,
+ hdr.length))) {
+ dpp_free_asymmetric_key(first);
+ return NULL;
+ }
+ if (!last) {
+ first = last = key;
+ } else {
+ last->next = key;
+ last = key;
+ }
+ }
+
+ return first;
+}
+
+
+static int dpp_conf_resp_env_data(struct dpp_authentication *auth,
+ const u8 *env_data, size_t env_data_len)
+{
+ const u8 *key;
+ size_t key_len;
+ u8 kek[DPP_MAX_HASH_LEN];
+ u8 cont_encr_key[DPP_MAX_HASH_LEN];
+ size_t cont_encr_key_len;
+ int res;
+ u8 *key_pkg;
+ size_t key_pkg_len;
+ struct dpp_enveloped_data data;
+ struct dpp_asymmetric_key *keys;
+
+ wpa_hexdump(MSG_DEBUG, "DPP: DPPEnvelopedData", env_data, env_data_len);
+
+ if (dpp_parse_enveloped_data(env_data, env_data_len, &data) < 0)
+ return -1;
+
+ /* TODO: For initial testing, use ke as the key. Replace this with a
+ * new key once that has been defined. */
+ key = auth->ke;
+ key_len = auth->curve->hash_len;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
+
+ if (dpp_pbkdf2(data.prf_hash_len, key, key_len, data.salt, 64, 1000,
+ kek, data.pbkdf2_key_len)) {
+ wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed");
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2",
+ kek, data.pbkdf2_key_len);
+
+ if (data.enc_key_len < AES_BLOCK_SIZE ||
+ data.enc_key_len > sizeof(cont_encr_key) + AES_BLOCK_SIZE) {
+ wpa_printf(MSG_DEBUG, "DPP: Invalid encryptedKey length");
+ return -1;
+ }
+ res = aes_siv_decrypt(kek, data.pbkdf2_key_len,
+ data.enc_key, data.enc_key_len,
+ 0, NULL, NULL, cont_encr_key);
+ forced_memzero(kek, data.pbkdf2_key_len);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: AES-SIV decryption of encryptedKey failed");
+ return -1;
+ }
+ cont_encr_key_len = data.enc_key_len - AES_BLOCK_SIZE;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: content-encryption key",
+ cont_encr_key, cont_encr_key_len);
+
+ if (data.enc_cont_len < AES_BLOCK_SIZE)
+ return -1;
+ key_pkg_len = data.enc_cont_len - AES_BLOCK_SIZE;
+ key_pkg = os_malloc(key_pkg_len);
+ if (!key_pkg)
+ return -1;
+ res = aes_siv_decrypt(cont_encr_key, cont_encr_key_len,
+ data.enc_cont, data.enc_cont_len,
+ 0, NULL, NULL, key_pkg);
+ forced_memzero(cont_encr_key, cont_encr_key_len);
+ if (res < 0) {
+ bin_clear_free(key_pkg, key_pkg_len);
+ wpa_printf(MSG_DEBUG,
+ "DPP: AES-SIV decryption of encryptedContent failed");
+ return -1;
+ }
+
+ keys = dpp_parse_dpp_asymmetric_key_package(key_pkg, key_pkg_len);
+ bin_clear_free(key_pkg, key_pkg_len);
+ dpp_free_asymmetric_key(auth->conf_key_pkg);
+ auth->conf_key_pkg = keys;
+
+ return keys != NULL;;
+}
+
+#endif /* CONFIG_DPP2 */
+
+
int dpp_conf_resp_rx(struct dpp_authentication *auth,
const struct wpabuf *resp)
{
const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
+ const u8 *env_data;
+ u16 env_data_len;
const u8 *addr[1];
size_t len[1];
u8 *unwrapped = NULL;
@@ -5895,17 +7759,40 @@
goto fail;
}
- conf_obj = dpp_get_attr(unwrapped, unwrapped_len,
- DPP_ATTR_CONFIG_OBJ, &conf_obj_len);
- if (!conf_obj) {
+ env_data = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_ENVELOPED_DATA, &env_data_len);
+#ifdef CONFIG_DPP2
+ if (env_data &&
+ dpp_conf_resp_env_data(auth, env_data, env_data_len) < 0)
+ goto fail;
+#endif /* CONFIG_DPP2 */
+
+ conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
+ &conf_obj_len);
+ if (!conf_obj && !env_data) {
dpp_auth_fail(auth,
"Missing required Configuration Object attribute");
goto fail;
}
- wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
- conf_obj, conf_obj_len);
- if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
- goto fail;
+ while (conf_obj) {
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
+ conf_obj, conf_obj_len);
+ if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
+ goto fail;
+ conf_obj = dpp_get_attr_next(conf_obj, unwrapped, unwrapped_len,
+ DPP_ATTR_CONFIG_OBJ,
+ &conf_obj_len);
+ }
+
+#ifdef CONFIG_DPP2
+ status = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_SEND_CONN_STATUS, &status_len);
+ if (status) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Configurator requested connection status result");
+ auth->conn_status_requested = 1;
+ }
+#endif /* CONFIG_DPP2 */
ret = 0;
@@ -5916,6 +7803,7 @@
#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)
@@ -5996,7 +7884,6 @@
bin_clear_free(unwrapped, unwrapped_len);
return ret;
}
-#endif /* CONFIG_DPP2 */
struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
@@ -6014,7 +7901,7 @@
clear = wpabuf_alloc(clear_len);
msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
if (!clear || !msg)
- return NULL;
+ goto fail;
/* DPP Status */
dpp_build_attr_status(clear, status);
@@ -6055,6 +7942,219 @@
}
+static int valid_channel_list(const char *val)
+{
+ while (*val) {
+ if (!((*val >= '0' && *val <= '9') ||
+ *val == '/' || *val == ','))
+ return 0;
+ val++;
+ }
+
+ return 1;
+}
+
+
+enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
+ const u8 *hdr,
+ const u8 *attr_start,
+ size_t attr_len,
+ u8 *ssid, size_t *ssid_len,
+ char **channel_list)
+{
+ 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;
+ struct json_token *root = NULL, *token;
+ struct wpabuf *ssid64;
+
+ *ssid_len = 0;
+ *channel_list = 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) {
+ 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_CONN_STATUS,
+ &status_len);
+ if (!status) {
+ dpp_auth_fail(auth,
+ "Missing required DPP Connection Status attribute");
+ goto fail;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
+ status, status_len);
+
+ root = json_parse((const char *) status, status_len);
+ if (!root) {
+ dpp_auth_fail(auth, "Could not parse connStatus");
+ goto fail;
+ }
+
+ ssid64 = json_get_member_base64url(root, "ssid64");
+ if (ssid64 && wpabuf_len(ssid64) <= SSID_MAX_LEN) {
+ *ssid_len = wpabuf_len(ssid64);
+ os_memcpy(ssid, wpabuf_head(ssid64), *ssid_len);
+ }
+ wpabuf_free(ssid64);
+
+ token = json_get_member(root, "channelList");
+ if (token && token->type == JSON_STRING &&
+ valid_channel_list(token->string))
+ *channel_list = os_strdup(token->string);
+
+ token = json_get_member(root, "result");
+ if (!token || token->type != JSON_NUMBER) {
+ dpp_auth_fail(auth, "No connStatus - result");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: result %d", token->number);
+ ret = token->number;
+
+fail:
+ json_free(root);
+ bin_clear_free(unwrapped, unwrapped_len);
+ return ret;
+}
+
+
+struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
+ enum dpp_status_error result,
+ const u8 *ssid, size_t ssid_len,
+ const char *channel_list)
+{
+ struct wpabuf *msg = NULL, *clear = NULL, *json;
+ size_t nonce_len, clear_len, attr_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *wrapped;
+
+ json = wpabuf_alloc(1000);
+ if (!json)
+ return NULL;
+ json_start_object(json, NULL);
+ json_add_int(json, "result", result);
+ if (ssid) {
+ json_value_sep(json);
+ if (json_add_base64url(json, "ssid64", ssid, ssid_len) < 0)
+ goto fail;
+ }
+ if (channel_list) {
+ json_value_sep(json);
+ json_add_string(json, "channelList", channel_list);
+ }
+ json_end_object(json);
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
+ wpabuf_head(json), wpabuf_len(json));
+
+ nonce_len = auth->curve->nonce_len;
+ clear_len = 5 + 4 + nonce_len + 4 + wpabuf_len(json);
+ attr_len = 4 + clear_len + AES_BLOCK_SIZE;
+ clear = wpabuf_alloc(clear_len);
+ msg = dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT, attr_len);
+ if (!clear || !msg)
+ goto fail;
+
+ /* 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);
+
+ /* DPP Connection Status */
+ wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
+ wpabuf_put_le16(clear, wpabuf_len(json));
+ wpabuf_put_buf(clear, json);
+
+ /* 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: Connection Status Result attributes",
+ msg);
+ wpabuf_free(json);
+ wpabuf_free(clear);
+ return msg;
+fail:
+ wpabuf_free(json);
+ wpabuf_free(clear);
+ wpabuf_free(msg);
+ return NULL;
+}
+
+#endif /* CONFIG_DPP2 */
+
+
void dpp_configurator_free(struct dpp_configurator *conf)
{
if (!conf)
@@ -6089,15 +8189,41 @@
}
+static int dpp_configurator_gen_kid(struct dpp_configurator *conf)
+{
+ struct wpabuf *csign_pub = NULL;
+ u8 kid_hash[SHA256_MAC_LEN];
+ const u8 *addr[1];
+ size_t len[1];
+ int res;
+
+ csign_pub = dpp_get_pubkey_point(conf->csign, 1);
+ if (!csign_pub) {
+ wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
+ return -1;
+ }
+
+ /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
+ addr[0] = wpabuf_head(csign_pub);
+ len[0] = wpabuf_len(csign_pub);
+ res = sha256_vector(1, addr, len, kid_hash);
+ wpabuf_free(csign_pub);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to derive kid for C-sign-key");
+ return -1;
+ }
+
+ conf->kid = base64_url_encode(kid_hash, sizeof(kid_hash), NULL);
+ return conf->kid ? 0 : -1;
+}
+
+
struct dpp_configurator *
dpp_keygen_configurator(const char *curve, const u8 *privkey,
size_t privkey_len)
{
struct dpp_configurator *conf;
- struct wpabuf *csign_pub = NULL;
- u8 kid_hash[SHA256_MAC_LEN];
- const u8 *addr[1];
- size_t len[1];
conf = os_zalloc(sizeof(*conf));
if (!conf)
@@ -6123,32 +8249,12 @@
goto fail;
conf->own = 1;
- csign_pub = dpp_get_pubkey_point(conf->csign, 1);
- if (!csign_pub) {
- wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
+ if (dpp_configurator_gen_kid(conf) < 0)
goto fail;
- }
-
- /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
- addr[0] = wpabuf_head(csign_pub);
- len[0] = wpabuf_len(csign_pub);
- if (sha256_vector(1, addr, len, kid_hash) < 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Failed to derive kid for C-sign-key");
- goto fail;
- }
-
- conf->kid = (char *) base64_url_encode(kid_hash, sizeof(kid_hash),
- NULL, 0);
- if (!conf->kid)
- goto fail;
-out:
- wpabuf_free(csign_pub);
return conf;
fail:
dpp_configurator_free(conf);
- conf = NULL;
- goto out;
+ return NULL;
}
@@ -6180,13 +8286,16 @@
auth->own_protocol_key = dpp_gen_keypair(auth->curve);
if (!auth->own_protocol_key)
return -1;
- dpp_copy_netaccesskey(auth);
+ dpp_copy_netaccesskey(auth, &auth->conf_obj[0]);
auth->peer_protocol_key = auth->own_protocol_key;
- dpp_copy_csign(auth, auth->conf->csign);
+ dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
- conf_obj = dpp_build_conf_obj(auth, ap);
- if (!conf_obj)
+ conf_obj = dpp_build_conf_obj(auth, ap, 0);
+ if (!conf_obj) {
+ wpabuf_free(auth->conf_obj[0].c_sign_key);
+ auth->conf_obj[0].c_sign_key = NULL;
goto fail;
+ }
ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
wpabuf_len(conf_obj));
fail:
@@ -6367,7 +8476,6 @@
const char *pos, *end;
unsigned char *own_conn = NULL;
size_t own_conn_len;
- EVP_PKEY_CTX *ctx = NULL;
size_t Nx_len;
u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
@@ -6402,8 +8510,7 @@
wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
goto fail;
}
- own_conn = base64_url_decode((const unsigned char *) pos,
- end - pos, &own_conn_len);
+ own_conn = base64_url_decode(pos, end - pos, &own_conn_len);
if (!own_conn) {
wpa_printf(MSG_DEBUG,
"DPP: Failed to base64url decode own signedConnector JWS Payload");
@@ -6481,18 +8588,8 @@
}
/* ECDH: N = nk * PK */
- ctx = EVP_PKEY_CTX_new(own_key, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, peer_key) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &Nx_len) != 1 ||
- Nx_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, Nx, &Nx_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(own_key, peer_key, Nx, &Nx_len) < 0)
goto fail;
- }
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
Nx, Nx_len);
@@ -6515,7 +8612,6 @@
if (ret != DPP_STATUS_OK)
os_memset(intro, 0, sizeof(*intro));
os_memset(Nx, 0, sizeof(Nx));
- EVP_PKEY_CTX_free(ctx);
os_free(own_conn);
os_free(signed_connector);
os_free(info.payload);
@@ -6535,6 +8631,7 @@
EC_GROUP *group;
size_t len = curve->prime_len;
const u8 *x, *y;
+ EVP_PKEY *res;
switch (curve->ike_group) {
case 19:
@@ -6568,14 +8665,16 @@
group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
if (!group)
return NULL;
- return dpp_set_pubkey_point_group(group, x, y, len);
+ res = dpp_set_pubkey_point_group(group, x, y, len);
+ EC_GROUP_free(group);
+ return res;
}
static EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
const u8 *mac_init, const char *code,
const char *identifier, BN_CTX *bnctx,
- const EC_GROUP **ret_group)
+ EC_GROUP **ret_group)
{
u8 hash[DPP_MAX_HASH_LEN];
const u8 *addr[3];
@@ -6644,8 +8743,10 @@
EC_KEY_free(Pi_ec);
EVP_PKEY_free(Pi);
BN_clear_free(hash_bn);
- if (ret_group)
+ if (ret_group && Qi)
*ret_group = group2;
+ else
+ EC_GROUP_free(group2);
return Qi;
fail:
EC_POINT_free(Qi);
@@ -6657,7 +8758,7 @@
static EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
const u8 *mac_resp, const char *code,
const char *identifier, BN_CTX *bnctx,
- const EC_GROUP **ret_group)
+ EC_GROUP **ret_group)
{
u8 hash[DPP_MAX_HASH_LEN];
const u8 *addr[3];
@@ -6726,8 +8827,10 @@
EC_KEY_free(Pr_ec);
EVP_PKEY_free(Pr);
BN_clear_free(hash_bn);
- if (ret_group)
+ if (ret_group && Qr)
*ret_group = group2;
+ else
+ EC_GROUP_free(group2);
return Qr;
fail:
EC_POINT_free(Qr);
@@ -6796,6 +8899,7 @@
BN_free(y);
EC_POINT_free(point);
BN_CTX_free(ctx);
+ EC_GROUP_free(group);
return ret;
}
@@ -6807,7 +8911,7 @@
EC_KEY *X_ec = NULL;
const EC_POINT *X_point;
BN_CTX *bnctx = NULL;
- const EC_GROUP *group;
+ EC_GROUP *group = NULL;
EC_POINT *Qi = NULL, *M = NULL;
struct wpabuf *M_buf = NULL;
BIGNUM *Mx = NULL, *My = NULL;
@@ -6929,6 +9033,7 @@
BN_clear_free(Mx);
BN_clear_free(My);
BN_CTX_free(bnctx);
+ EC_GROUP_free(group);
return msg;
fail:
wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
@@ -7173,7 +9278,7 @@
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;
+ EC_GROUP *group = NULL;
BIGNUM *Mx = NULL, *My = NULL;
EC_KEY *Y_ec = NULL, *X_ec = NULL;;
const EC_POINT *Y_point;
@@ -7181,7 +9286,6 @@
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
@@ -7348,18 +9452,8 @@
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));
+ if (dpp_ecdh(pkex->y, pkex->x, Kx, &Kx_len) < 0)
goto fail;
- }
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
Kx, Kx_len);
@@ -7377,7 +9471,6 @@
pkex->exchange_done = 1;
out:
- EVP_PKEY_CTX_free(ctx);
BN_CTX_free(bnctx);
EC_POINT_free(Qi);
EC_POINT_free(Qr);
@@ -7390,6 +9483,7 @@
EC_POINT_free(X);
EC_KEY_free(X_ec);
EC_KEY_free(Y_ec);
+ EC_GROUP_free(group);
return pkex;
fail:
wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
@@ -7518,13 +9612,12 @@
{
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;
+ EC_GROUP *group = NULL;
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;
BIGNUM *Nx = NULL, *Ny = NULL;
- EVP_PKEY_CTX *ctx = NULL;
EC_KEY *Y_ec = NULL;
size_t Jx_len, Kx_len;
u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
@@ -7636,18 +9729,8 @@
if (!pkex->y ||
EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1)
goto fail;
- ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pkex->y) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 ||
- Jx_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0)
goto fail;
- }
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
Jx, Jx_len);
@@ -7671,19 +9754,8 @@
wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
/* K = x * Y’ */
- EVP_PKEY_CTX_free(ctx);
- ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pkex->y) != 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));
+ if (dpp_ecdh(pkex->x, pkex->y, Kx, &Kx_len) < 0)
goto fail;
- }
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
Kx, Kx_len);
@@ -7713,8 +9785,8 @@
BN_free(Nx);
BN_free(Ny);
EC_KEY_free(Y_ec);
- EVP_PKEY_CTX_free(ctx);
BN_CTX_free(bnctx);
+ EC_GROUP_free(group);
return msg;
fail:
wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
@@ -7840,7 +9912,6 @@
const u8 *buf, size_t buflen)
{
const struct dpp_curve_params *curve = pkex->own_bi->curve;
- 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];
@@ -7924,18 +9995,8 @@
pkex->peer_bootstrap_key);
/* ECDH: J' = y * A' */
- ctx = EVP_PKEY_CTX_new(pkex->y, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 ||
- Jx_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(pkex->y, pkex->peer_bootstrap_key, Jx, &Jx_len) < 0)
goto fail;
- }
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
Jx, Jx_len);
@@ -7971,19 +10032,8 @@
wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
/* ECDH: L = b * X' */
- EVP_PKEY_CTX_free(ctx);
- ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 ||
- Lx_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(pkex->own_bi->pubkey, pkex->x, Lx, &Lx_len) < 0)
goto fail;
- }
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
Lx, Lx_len);
@@ -8009,7 +10059,6 @@
goto fail;
out:
- EVP_PKEY_CTX_free(ctx);
os_free(unwrapped);
wpabuf_free(A_pub);
wpabuf_free(B_pub);
@@ -8038,7 +10087,6 @@
u8 v[DPP_MAX_HASH_LEN];
size_t Lx_len;
u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
- EVP_PKEY_CTX *ctx = NULL;
struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
#ifdef CONFIG_TESTING_OPTIONS
@@ -8109,18 +10157,8 @@
pkex->peer_bootstrap_key);
/* ECDH: L' = x * B' */
- ctx = EVP_PKEY_CTX_new(pkex->x, NULL);
- if (!ctx ||
- EVP_PKEY_derive_init(ctx) != 1 ||
- EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 ||
- EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 ||
- Lx_len > DPP_MAX_SHARED_SECRET_LEN ||
- EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to derive ECDH shared secret: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (dpp_ecdh(pkex->x, pkex->peer_bootstrap_key, Lx, &Lx_len) < 0)
goto fail;
- }
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
Lx, Lx_len);
@@ -8160,7 +10198,6 @@
wpabuf_free(B_pub);
wpabuf_free(X_pub);
wpabuf_free(Y_pub);
- EVP_PKEY_CTX_free(ctx);
os_free(unwrapped);
return ret;
fail:
@@ -8207,8 +10244,7 @@
wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s",
pos);
- signature = base64_url_decode((const unsigned char *) pos,
- os_strlen(pos), &signature_len);
+ signature = base64_url_decode(pos, os_strlen(pos), &signature_len);
if (!signature || signature_len == 0)
goto fail;
wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature",
@@ -8216,8 +10252,7 @@
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);
+ signed3 = base64_url_encode(signature, signature_len, &signed3_len);
if (!signed3)
goto fail;
os_memcpy(pos, signed3, signed3_len);
@@ -8347,6 +10382,10 @@
if (id && bi->id != id)
continue;
found = 1;
+#ifdef CONFIG_DPP2
+ if (dpp->remove_bi)
+ dpp->remove_bi(dpp->cb_ctx, bi);
+#endif /* CONFIG_DPP2 */
dl_list_del(&bi->list);
dpp_bootstrap_info_free(bi);
}
@@ -8365,10 +10404,30 @@
if (!dpp)
return NULL;
- bi = dpp_parse_qr_code(uri);
+ bi = dpp_parse_uri(uri);
if (!bi)
return NULL;
+ bi->type = DPP_BOOTSTRAP_QR_CODE;
+ bi->id = dpp_next_id(dpp);
+ dl_list_add(&dpp->bootstrap, &bi->list);
+ return bi;
+}
+
+
+struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
+ const char *uri)
+{
+ struct dpp_bootstrap_info *bi;
+
+ if (!dpp)
+ return NULL;
+
+ bi = dpp_parse_uri(uri);
+ if (!bi)
+ return NULL;
+
+ bi->type = DPP_BOOTSTRAP_NFC_URI;
bi->id = dpp_next_id(dpp);
dl_list_add(&dpp->bootstrap, &bi->list);
return bi;
@@ -8377,11 +10436,10 @@
int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
{
- char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL;
+ char *mac = NULL, *info = 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;
@@ -8396,10 +10454,12 @@
bi->type = DPP_BOOTSTRAP_QR_CODE;
else if (os_strstr(cmd, "type=pkex"))
bi->type = DPP_BOOTSTRAP_PKEX;
+ else if (os_strstr(cmd, "type=nfc-uri"))
+ bi->type = DPP_BOOTSTRAP_NFC_URI;
else
goto fail;
- chan = get_param(cmd, " chan=");
+ bi->chan = get_param(cmd, " chan=");
mac = get_param(cmd, " mac=");
info = get_param(cmd, " info=");
curve = get_param(cmd, " curve=");
@@ -8413,43 +10473,19 @@
goto fail;
}
- pk = dpp_keygen(bi, curve, privkey, privkey_len);
- if (!pk)
+ if (dpp_keygen(bi, curve, privkey, privkey_len) < 0 ||
+ dpp_parse_uri_chan_list(bi, bi->chan) < 0 ||
+ dpp_parse_uri_mac(bi, mac) < 0 ||
+ dpp_parse_uri_info(bi, info) < 0 ||
+ dpp_gen_uri(bi) < 0)
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);
@@ -8533,20 +10569,47 @@
char *reply, int reply_size)
{
struct dpp_bootstrap_info *bi;
+ char pkhash[2 * SHA256_MAC_LEN + 1];
bi = dpp_bootstrap_get_id(dpp, id);
if (!bi)
return -1;
+ wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash,
+ SHA256_MAC_LEN);
return os_snprintf(reply, reply_size, "type=%s\n"
"mac_addr=" MACSTR "\n"
"info=%s\n"
"num_freq=%u\n"
- "curve=%s\n",
+ "use_freq=%u\n"
+ "curve=%s\n"
+ "pkhash=%s\n",
dpp_bootstrap_type_txt(bi->type),
MAC2STR(bi->mac_addr),
bi->info ? bi->info : "",
bi->num_freq,
- bi->curve->name);
+ bi->num_freq == 1 ? bi->freq[0] : 0,
+ bi->curve->name,
+ pkhash);
+}
+
+
+int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params)
+{
+ struct dpp_bootstrap_info *bi;
+
+ bi = dpp_bootstrap_get_id(dpp, id);
+ if (!bi)
+ return -1;
+
+ str_clear_free(bi->configurator_params);
+
+ if (params) {
+ bi->configurator_params = os_strdup(params);
+ return bi->configurator_params ? 0 : -1;
+ }
+
+ bi->configurator_params = NULL;
+ return 0;
}
@@ -8582,7 +10645,108 @@
if (*own_bi && *peer_bi)
break;
}
+}
+
+#ifdef CONFIG_DPP2
+struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
+ const u8 *hash)
+{
+ struct dpp_bootstrap_info *bi;
+
+ if (!dpp)
+ return NULL;
+
+ dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
+ if (!bi->own && os_memcmp(bi->pubkey_hash_chirp, hash,
+ SHA256_MAC_LEN) == 0)
+ return bi;
+ }
+
+ return NULL;
+}
+#endif /* CONFIG_DPP2 */
+
+
+static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info *own_bi,
+ struct dpp_bootstrap_info *peer_bi)
+{
+ unsigned int i, freq = 0;
+ enum hostapd_hw_mode mode;
+ u8 op_class, channel;
+ char chan[20];
+
+ if (peer_bi->num_freq == 0)
+ return 0; /* no channel preference/constraint */
+
+ for (i = 0; i < peer_bi->num_freq; i++) {
+ if (own_bi->num_freq == 0 ||
+ freq_included(own_bi->freq, own_bi->num_freq,
+ peer_bi->freq[i])) {
+ freq = peer_bi->freq[i];
+ break;
+ }
+ }
+ if (!freq) {
+ wpa_printf(MSG_DEBUG, "DPP: No common channel found");
+ return -1;
+ }
+
+ mode = ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, &channel);
+ if (mode == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not determine operating class or channel number for %u MHz",
+ freq);
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover",
+ freq, op_class, channel);
+ os_snprintf(chan, sizeof(chan), "%u/%u", op_class, channel);
+ os_free(own_bi->chan);
+ own_bi->chan = os_strdup(chan);
+ own_bi->freq[0] = freq;
+ own_bi->num_freq = 1;
+ os_free(peer_bi->chan);
+ peer_bi->chan = os_strdup(chan);
+ peer_bi->freq[0] = freq;
+ peer_bi->num_freq = 1;
+
+ return dpp_gen_uri(own_bi);
+}
+
+
+static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info *own_bi,
+ struct dpp_bootstrap_info *peer_bi)
+{
+ if (peer_bi->curve == own_bi->curve)
+ return 0;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Update own bootstrapping key to match peer curve from NFC handover");
+
+ EVP_PKEY_free(own_bi->pubkey);
+ own_bi->pubkey = NULL;
+
+ if (dpp_keygen(own_bi, peer_bi->curve->name, NULL, 0) < 0 ||
+ dpp_gen_uri(own_bi) < 0)
+ goto fail;
+
+ return 0;
+fail:
+ dl_list_del(&own_bi->list);
+ dpp_bootstrap_info_free(own_bi);
+ return -1;
+}
+
+
+int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
+ struct dpp_bootstrap_info *peer_bi)
+{
+ if (dpp_nfc_update_bi_channel(own_bi, peer_bi) < 0 ||
+ dpp_nfc_update_bi_key(own_bi, peer_bi) < 0)
+ return -1;
+ return 0;
}
@@ -8689,16 +10853,137 @@
}
-struct dpp_global * dpp_global_init(void)
+#ifdef CONFIG_DPP2
+
+int dpp_configurator_from_backup(struct dpp_global *dpp,
+ struct dpp_asymmetric_key *key)
+{
+ struct dpp_configurator *conf;
+ const EC_KEY *eckey;
+ const EC_GROUP *group;
+ int nid;
+ const struct dpp_curve_params *curve;
+
+ if (!key->csign)
+ return -1;
+ eckey = EVP_PKEY_get0_EC_KEY(key->csign);
+ if (!eckey)
+ return -1;
+ group = EC_KEY_get0_group(eckey);
+ if (!group)
+ return -1;
+ nid = EC_GROUP_get_curve_name(group);
+ curve = dpp_get_curve_nid(nid);
+ if (!curve) {
+ wpa_printf(MSG_INFO, "DPP: Unsupported group in c-sign-key");
+ return -1;
+ }
+
+ conf = os_zalloc(sizeof(*conf));
+ if (!conf)
+ return -1;
+ conf->curve = curve;
+ conf->csign = key->csign;
+ key->csign = NULL;
+ conf->own = 1;
+ if (dpp_configurator_gen_kid(conf) < 0) {
+ dpp_configurator_free(conf);
+ return -1;
+ }
+
+ conf->id = dpp_next_configurator_id(dpp);
+ dl_list_add(&dpp->configurator, &conf->list);
+ return conf->id;
+}
+
+
+static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx);
+
+
+static void dpp_connection_free(struct dpp_connection *conn)
+{
+ if (conn->sock >= 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Close Controller socket %d",
+ conn->sock);
+ eloop_unregister_sock(conn->sock, EVENT_TYPE_READ);
+ eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
+ close(conn->sock);
+ }
+ eloop_cancel_timeout(dpp_controller_conn_status_result_wait_timeout,
+ conn, NULL);
+ wpabuf_free(conn->msg);
+ wpabuf_free(conn->msg_out);
+ dpp_auth_deinit(conn->auth);
+ os_free(conn);
+}
+
+
+static void dpp_connection_remove(struct dpp_connection *conn)
+{
+ dl_list_del(&conn->list);
+ dpp_connection_free(conn);
+}
+
+
+static void dpp_tcp_init_flush(struct dpp_global *dpp)
+{
+ struct dpp_connection *conn, *tmp;
+
+ dl_list_for_each_safe(conn, tmp, &dpp->tcp_init, struct dpp_connection,
+ list)
+ dpp_connection_remove(conn);
+}
+
+
+static void dpp_relay_controller_free(struct dpp_relay_controller *ctrl)
+{
+ struct dpp_connection *conn, *tmp;
+
+ dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection,
+ list)
+ dpp_connection_remove(conn);
+ os_free(ctrl);
+}
+
+
+static void dpp_relay_flush_controllers(struct dpp_global *dpp)
+{
+ struct dpp_relay_controller *ctrl, *tmp;
+
+ if (!dpp)
+ return;
+
+ dl_list_for_each_safe(ctrl, tmp, &dpp->controllers,
+ struct dpp_relay_controller, list) {
+ dl_list_del(&ctrl->list);
+ dpp_relay_controller_free(ctrl);
+ }
+}
+
+#endif /* CONFIG_DPP2 */
+
+
+struct dpp_global * dpp_global_init(struct dpp_global_config *config)
{
struct dpp_global *dpp;
dpp = os_zalloc(sizeof(*dpp));
if (!dpp)
return NULL;
+ dpp->msg_ctx = config->msg_ctx;
+#ifdef CONFIG_DPP2
+ dpp->cb_ctx = config->cb_ctx;
+ dpp->process_conf_obj = config->process_conf_obj;
+ dpp->remove_bi = config->remove_bi;
+#endif /* CONFIG_DPP2 */
dl_list_init(&dpp->bootstrap);
dl_list_init(&dpp->configurator);
+#ifdef CONFIG_DPP2
+ dl_list_init(&dpp->controllers);
+ dl_list_init(&dpp->tcp_init);
+#endif /* CONFIG_DPP2 */
return dpp;
}
@@ -8711,6 +10996,11 @@
dpp_bootstrap_del(dpp, 0);
dpp_configurator_del(dpp, 0);
+#ifdef CONFIG_DPP2
+ dpp_tcp_init_flush(dpp);
+ dpp_relay_flush_controllers(dpp);
+ dpp_controller_stop(dpp);
+#endif /* CONFIG_DPP2 */
}
@@ -8719,3 +11009,1319 @@
dpp_global_clear(dpp);
os_free(dpp);
}
+
+
+#ifdef CONFIG_DPP2
+
+static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx);
+static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx);
+static void dpp_controller_auth_success(struct dpp_connection *conn,
+ int initiator);
+
+
+int dpp_relay_add_controller(struct dpp_global *dpp,
+ struct dpp_relay_config *config)
+{
+ struct dpp_relay_controller *ctrl;
+
+ if (!dpp)
+ return -1;
+
+ ctrl = os_zalloc(sizeof(*ctrl));
+ if (!ctrl)
+ return -1;
+ dl_list_init(&ctrl->conn);
+ ctrl->global = dpp;
+ os_memcpy(&ctrl->ipaddr, config->ipaddr, sizeof(*config->ipaddr));
+ os_memcpy(ctrl->pkhash, config->pkhash, SHA256_MAC_LEN);
+ ctrl->cb_ctx = config->cb_ctx;
+ ctrl->tx = config->tx;
+ ctrl->gas_resp_tx = config->gas_resp_tx;
+ dl_list_add(&dpp->controllers, &ctrl->list);
+ return 0;
+}
+
+
+static struct dpp_relay_controller *
+dpp_relay_controller_get(struct dpp_global *dpp, const u8 *pkhash)
+{
+ struct dpp_relay_controller *ctrl;
+
+ if (!dpp)
+ return NULL;
+
+ dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller,
+ list) {
+ if (os_memcmp(pkhash, ctrl->pkhash, SHA256_MAC_LEN) == 0)
+ return ctrl;
+ }
+
+ return NULL;
+}
+
+
+static void dpp_controller_gas_done(struct dpp_connection *conn)
+{
+ struct dpp_authentication *auth = conn->auth;
+
+ if (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;
+ return;
+ }
+
+ wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
+ dpp_connection_remove(conn);
+}
+
+
+static int dpp_tcp_send(struct dpp_connection *conn)
+{
+ int res;
+
+ if (!conn->msg_out) {
+ eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
+ conn->write_eloop = 0;
+ return -1;
+ }
+ res = send(conn->sock,
+ wpabuf_head_u8(conn->msg_out) + conn->msg_out_pos,
+ wpabuf_len(conn->msg_out) - conn->msg_out_pos, 0);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to send buffer: %s",
+ strerror(errno));
+ dpp_connection_remove(conn);
+ return -1;
+ }
+
+ conn->msg_out_pos += res;
+ if (wpabuf_len(conn->msg_out) > conn->msg_out_pos) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: %u/%u bytes of message sent to Controller",
+ (unsigned int) conn->msg_out_pos,
+ (unsigned int) wpabuf_len(conn->msg_out));
+ if (!conn->write_eloop &&
+ eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
+ dpp_conn_tx_ready, conn, NULL) == 0)
+ conn->write_eloop = 1;
+ return 1;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Full message sent over TCP");
+ wpabuf_free(conn->msg_out);
+ conn->msg_out = NULL;
+ conn->msg_out_pos = 0;
+ eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
+ conn->write_eloop = 0;
+ if (!conn->read_eloop &&
+ eloop_register_sock(conn->sock, EVENT_TYPE_READ,
+ dpp_controller_rx, conn, NULL) == 0)
+ conn->read_eloop = 1;
+ if (conn->on_tcp_tx_complete_remove) {
+ dpp_connection_remove(conn);
+ } else if (conn->ctrl && conn->on_tcp_tx_complete_gas_done &&
+ conn->auth) {
+ dpp_controller_gas_done(conn);
+ } else if (conn->on_tcp_tx_complete_auth_ok) {
+ conn->on_tcp_tx_complete_auth_ok = 0;
+ dpp_controller_auth_success(conn, 1);
+ }
+
+ return 0;
+}
+
+
+static int dpp_tcp_send_msg(struct dpp_connection *conn,
+ const struct wpabuf *msg)
+{
+ wpabuf_free(conn->msg_out);
+ conn->msg_out_pos = 0;
+ conn->msg_out = wpabuf_alloc(4 + wpabuf_len(msg) - 1);
+ if (!conn->msg_out)
+ return -1;
+ wpabuf_put_be32(conn->msg_out, wpabuf_len(msg) - 1);
+ wpabuf_put_data(conn->msg_out, wpabuf_head_u8(msg) + 1,
+ wpabuf_len(msg) - 1);
+
+ if (dpp_tcp_send(conn) == 1) {
+ if (!conn->write_eloop) {
+ if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
+ dpp_conn_tx_ready,
+ conn, NULL) < 0)
+ return -1;
+ conn->write_eloop = 1;
+ }
+ }
+
+ return 0;
+}
+
+
+static void dpp_controller_start_gas_client(struct dpp_connection *conn)
+{
+ struct dpp_authentication *auth = conn->auth;
+ struct wpabuf *buf;
+ int netrole_ap = 0; /* TODO: make this configurable */
+
+ buf = dpp_build_conf_req_helper(auth, "Test", netrole_ap, NULL, NULL);
+ if (!buf) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No configuration request data available");
+ return;
+ }
+
+ dpp_tcp_send_msg(conn, buf);
+ wpabuf_free(buf);
+}
+
+
+static void dpp_controller_auth_success(struct dpp_connection *conn,
+ int initiator)
+{
+ struct dpp_authentication *auth = conn->auth;
+
+ if (!auth)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
+ wpa_msg(conn->global->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 (auth->configurator) {
+ /* Prevent GAS response */
+ auth->auth_success = 0;
+ }
+ return;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (!auth->configurator)
+ dpp_controller_start_gas_client(conn);
+}
+
+
+static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct dpp_connection *conn = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "DPP: TCP socket %d ready for TX", sock);
+ dpp_tcp_send(conn);
+}
+
+
+static int dpp_ipaddr_to_sockaddr(struct sockaddr *addr, socklen_t *addrlen,
+ const struct hostapd_ip_addr *ipaddr,
+ int port)
+{
+ struct sockaddr_in *dst;
+#ifdef CONFIG_IPV6
+ struct sockaddr_in6 *dst6;
+#endif /* CONFIG_IPV6 */
+
+ switch (ipaddr->af) {
+ case AF_INET:
+ dst = (struct sockaddr_in *) addr;
+ os_memset(dst, 0, sizeof(*dst));
+ dst->sin_family = AF_INET;
+ dst->sin_addr.s_addr = ipaddr->u.v4.s_addr;
+ dst->sin_port = htons(port);
+ *addrlen = sizeof(*dst);
+ break;
+#ifdef CONFIG_IPV6
+ case AF_INET6:
+ dst6 = (struct sockaddr_in6 *) addr;
+ os_memset(dst6, 0, sizeof(*dst6));
+ dst6->sin6_family = AF_INET6;
+ os_memcpy(&dst6->sin6_addr, &ipaddr->u.v6,
+ sizeof(struct in6_addr));
+ dst6->sin6_port = htons(port);
+ *addrlen = sizeof(*dst6);
+ break;
+#endif /* CONFIG_IPV6 */
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static struct dpp_connection *
+dpp_relay_new_conn(struct dpp_relay_controller *ctrl, const u8 *src,
+ unsigned int freq)
+{
+ struct dpp_connection *conn;
+ struct sockaddr_storage addr;
+ socklen_t addrlen;
+ char txt[100];
+
+ if (dl_list_len(&ctrl->conn) >= 15) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one");
+ return NULL;
+ }
+
+ if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &addr, &addrlen,
+ &ctrl->ipaddr, DPP_TCP_PORT) < 0)
+ return NULL;
+
+ conn = os_zalloc(sizeof(*conn));
+ if (!conn)
+ return NULL;
+
+ conn->global = ctrl->global;
+ conn->relay = ctrl;
+ os_memcpy(conn->mac_addr, src, ETH_ALEN);
+ conn->freq = freq;
+
+ conn->sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (conn->sock < 0)
+ goto fail;
+ wpa_printf(MSG_DEBUG, "DPP: TCP relay socket %d connection to %s",
+ conn->sock, hostapd_ip_txt(&ctrl->ipaddr, txt, sizeof(txt)));
+
+ if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
+ strerror(errno));
+ goto fail;
+ }
+
+ if (connect(conn->sock, (struct sockaddr *) &addr, addrlen) < 0) {
+ if (errno != EINPROGRESS) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s",
+ strerror(errno));
+ goto fail;
+ }
+
+ /*
+ * Continue connecting in the background; eloop will call us
+ * once the connection is ready (or failed).
+ */
+ }
+
+ if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
+ dpp_conn_tx_ready, conn, NULL) < 0)
+ goto fail;
+ conn->write_eloop = 1;
+
+ /* TODO: eloop timeout to clear a connection if it does not complete
+ * properly */
+
+ dl_list_add(&ctrl->conn, &conn->list);
+ return conn;
+fail:
+ dpp_connection_free(conn);
+ return NULL;
+}
+
+
+static struct wpabuf * dpp_tcp_encaps(const u8 *hdr, const u8 *buf, size_t len)
+{
+ struct wpabuf *msg;
+
+ msg = wpabuf_alloc(4 + 1 + DPP_HDR_LEN + len);
+ if (!msg)
+ return NULL;
+ wpabuf_put_be32(msg, 1 + DPP_HDR_LEN + len);
+ wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
+ wpabuf_put_data(msg, hdr, DPP_HDR_LEN);
+ wpabuf_put_data(msg, buf, len);
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg);
+ return msg;
+}
+
+
+static int dpp_relay_tx(struct dpp_connection *conn, const u8 *hdr,
+ const u8 *buf, size_t len)
+{
+ u8 type = hdr[DPP_HDR_LEN - 1];
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Continue already established Relay/Controller connection for this session");
+ wpabuf_free(conn->msg_out);
+ conn->msg_out_pos = 0;
+ conn->msg_out = dpp_tcp_encaps(hdr, buf, len);
+ if (!conn->msg_out) {
+ dpp_connection_remove(conn);
+ return -1;
+ }
+
+ /* TODO: for proto ver 1, need to do remove connection based on GAS Resp
+ * TX status */
+ if (type == DPP_PA_CONFIGURATION_RESULT)
+ conn->on_tcp_tx_complete_remove = 1;
+ dpp_tcp_send(conn);
+ return 0;
+}
+
+
+int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
+ const u8 *buf, size_t len, unsigned int freq,
+ const u8 *i_bootstrap, const u8 *r_bootstrap)
+{
+ struct dpp_relay_controller *ctrl;
+ struct dpp_connection *conn;
+ u8 type = hdr[DPP_HDR_LEN - 1];
+
+ /* Check if there is an already started session for this peer and if so,
+ * continue that session (send this over TCP) and return 0.
+ */
+ if (type != DPP_PA_PEER_DISCOVERY_REQ &&
+ type != DPP_PA_PEER_DISCOVERY_RESP &&
+ type != DPP_PA_PRESENCE_ANNOUNCEMENT) {
+ dl_list_for_each(ctrl, &dpp->controllers,
+ struct dpp_relay_controller, list) {
+ dl_list_for_each(conn, &ctrl->conn,
+ struct dpp_connection, list) {
+ if (os_memcmp(src, conn->mac_addr,
+ ETH_ALEN) == 0)
+ return dpp_relay_tx(conn, hdr, buf, len);
+ }
+ }
+ }
+
+ if (!r_bootstrap)
+ return -1;
+
+ if (type == DPP_PA_PRESENCE_ANNOUNCEMENT) {
+ /* TODO: Could send this to all configured Controllers. For now,
+ * only the first Controller is supported. */
+ ctrl = dl_list_first(&dpp->controllers,
+ struct dpp_relay_controller, list);
+ } else {
+ ctrl = dpp_relay_controller_get(dpp, r_bootstrap);
+ }
+ if (!ctrl)
+ return -1;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Authentication Request for a configured Controller");
+ conn = dpp_relay_new_conn(ctrl, src, freq);
+ if (!conn)
+ return -1;
+
+ conn->msg_out = dpp_tcp_encaps(hdr, buf, len);
+ if (!conn->msg_out) {
+ dpp_connection_remove(conn);
+ return -1;
+ }
+ /* Message will be sent in dpp_conn_tx_ready() */
+
+ return 0;
+}
+
+
+int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data,
+ size_t data_len)
+{
+ struct dpp_relay_controller *ctrl;
+ struct dpp_connection *conn, *found = NULL;
+ struct wpabuf *msg;
+
+ /* Check if there is a successfully completed authentication for this
+ * and if so, continue that session (send this over TCP) and return 0.
+ */
+ dl_list_for_each(ctrl, &dpp->controllers,
+ struct dpp_relay_controller, list) {
+ if (found)
+ break;
+ dl_list_for_each(conn, &ctrl->conn,
+ struct dpp_connection, list) {
+ if (os_memcmp(src, conn->mac_addr,
+ ETH_ALEN) == 0) {
+ found = conn;
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ return -1;
+
+ msg = wpabuf_alloc(4 + 1 + data_len);
+ if (!msg)
+ return -1;
+ wpabuf_put_be32(msg, 1 + data_len);
+ wpabuf_put_u8(msg, WLAN_PA_GAS_INITIAL_REQ);
+ wpabuf_put_data(msg, data, data_len);
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg);
+
+ wpabuf_free(conn->msg_out);
+ conn->msg_out_pos = 0;
+ conn->msg_out = msg;
+ dpp_tcp_send(conn);
+ return 0;
+}
+
+
+static void dpp_controller_free(struct dpp_controller *ctrl)
+{
+ struct dpp_connection *conn, *tmp;
+
+ if (!ctrl)
+ return;
+
+ dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection,
+ list)
+ dpp_connection_remove(conn);
+
+ if (ctrl->sock >= 0) {
+ close(ctrl->sock);
+ eloop_unregister_sock(ctrl->sock, EVENT_TYPE_READ);
+ }
+ os_free(ctrl->configurator_params);
+ os_free(ctrl);
+}
+
+
+static int dpp_controller_rx_auth_req(struct dpp_connection *conn,
+ const u8 *hdr, const u8 *buf, size_t len)
+{
+ const u8 *r_bootstrap, *i_bootstrap;
+ u16 r_bootstrap_len, i_bootstrap_len;
+ struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
+
+ if (!conn->ctrl)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "DPP: Authentication Request");
+
+ r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_bootstrap_len);
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_printf(MSG_INFO,
+ "Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
+ r_bootstrap, r_bootstrap_len);
+
+ i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
+ &i_bootstrap_len);
+ if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_printf(MSG_INFO,
+ "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
+ i_bootstrap, i_bootstrap_len);
+
+ /* Try to find own and peer bootstrapping key matches based on the
+ * received hash values */
+ dpp_bootstrap_find_pair(conn->ctrl->global, i_bootstrap, r_bootstrap,
+ &own_bi, &peer_bi);
+ if (!own_bi) {
+ wpa_printf(MSG_INFO,
+ "No matching own bootstrapping key found - ignore message");
+ return -1;
+ }
+
+ if (conn->auth) {
+ wpa_printf(MSG_INFO,
+ "Already in DPP authentication exchange - ignore new one");
+ return 0;
+ }
+
+ conn->auth = dpp_auth_req_rx(conn->ctrl->global,
+ conn->ctrl->global->msg_ctx,
+ conn->ctrl->allowed_roles,
+ conn->ctrl->qr_mutual,
+ peer_bi, own_bi, -1, hdr, buf, len);
+ if (!conn->auth) {
+ wpa_printf(MSG_DEBUG, "DPP: No response generated");
+ return -1;
+ }
+
+ if (dpp_set_configurator(conn->auth,
+ conn->ctrl->configurator_params) < 0) {
+ dpp_connection_remove(conn);
+ return -1;
+ }
+
+ return dpp_tcp_send_msg(conn, conn->auth->resp_msg);
+}
+
+
+static int dpp_controller_rx_auth_resp(struct dpp_connection *conn,
+ const u8 *hdr, const u8 *buf, size_t len)
+{
+ struct dpp_authentication *auth = conn->auth;
+ struct wpabuf *msg;
+ int res;
+
+ if (!auth)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "DPP: Authentication Response");
+
+ 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");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
+ dpp_connection_remove(conn);
+ return -1;
+ }
+
+ conn->on_tcp_tx_complete_auth_ok = 1;
+ res = dpp_tcp_send_msg(conn, msg);
+ wpabuf_free(msg);
+ return res;
+}
+
+
+static int dpp_controller_rx_auth_conf(struct dpp_connection *conn,
+ const u8 *hdr, const u8 *buf, size_t len)
+{
+ struct dpp_authentication *auth = conn->auth;
+
+ wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation");
+
+ if (!auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Authentication in progress - drop");
+ return -1;
+ }
+
+ if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
+ return -1;
+ }
+
+ dpp_controller_auth_success(conn, 0);
+ return 0;
+}
+
+
+static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct dpp_connection *conn = eloop_ctx;
+
+ if (!conn->auth->waiting_conf_result)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Timeout while waiting for Connection Status Result");
+ wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
+ DPP_EVENT_CONN_STATUS_RESULT "timeout");
+ dpp_connection_remove(conn);
+}
+
+
+static int dpp_controller_rx_conf_result(struct dpp_connection *conn,
+ const u8 *hdr, const u8 *buf,
+ size_t len)
+{
+ struct dpp_authentication *auth = conn->auth;
+ enum dpp_status_error status;
+
+ if (!conn->ctrl)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "DPP: Configuration Result");
+
+ if (!auth || !auth->waiting_conf_result) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for result - drop");
+ return -1;
+ }
+
+ status = dpp_conf_result_rx(auth, hdr, buf, len);
+ if (status == DPP_STATUS_OK && auth->send_conn_status) {
+ wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
+ DPP_EVENT_CONF_SENT "wait_conn_status=1");
+ wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
+ eloop_cancel_timeout(
+ dpp_controller_conn_status_result_wait_timeout,
+ conn, NULL);
+ eloop_register_timeout(
+ 16, 0, dpp_controller_conn_status_result_wait_timeout,
+ conn, NULL);
+ return 0;
+ }
+ if (status == DPP_STATUS_OK)
+ wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
+ DPP_EVENT_CONF_SENT);
+ else
+ wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
+ DPP_EVENT_CONF_FAILED);
+ return -1; /* to remove the completed connection */
+}
+
+
+static int dpp_controller_rx_conn_status_result(struct dpp_connection *conn,
+ const u8 *hdr, const u8 *buf,
+ size_t len)
+{
+ struct dpp_authentication *auth = conn->auth;
+ enum dpp_status_error status;
+ u8 ssid[SSID_MAX_LEN];
+ size_t ssid_len = 0;
+ char *channel_list = NULL;
+
+ if (!conn->ctrl)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "DPP: Connection Status Result");
+
+ if (!auth || !auth->waiting_conn_status_result) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for connection status result - drop");
+ return -1;
+ }
+
+ status = dpp_conn_status_result_rx(auth, hdr, buf, len,
+ ssid, &ssid_len, &channel_list);
+ wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
+ DPP_EVENT_CONN_STATUS_RESULT
+ "result=%d ssid=%s channel_list=%s",
+ status, wpa_ssid_txt(ssid, ssid_len),
+ channel_list ? channel_list : "N/A");
+ os_free(channel_list);
+ return -1; /* to remove the completed connection */
+}
+
+
+static int dpp_controller_rx_presence_announcement(struct dpp_connection *conn,
+ const u8 *hdr, const u8 *buf,
+ size_t len)
+{
+ const u8 *r_bootstrap;
+ u16 r_bootstrap_len;
+ struct dpp_bootstrap_info *peer_bi;
+ struct dpp_authentication *auth;
+ struct dpp_global *dpp = conn->ctrl->global;
+
+ if (conn->auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore Presence Announcement during ongoing Authentication");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Presence Announcement");
+
+ r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_bootstrap_len);
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_msg(dpp->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
+ r_bootstrap, r_bootstrap_len);
+ peer_bi = dpp_bootstrap_find_chirp(dpp, r_bootstrap);
+ if (!peer_bi) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No matching bootstrapping information found");
+ return -1;
+ }
+
+ auth = dpp_auth_init(dpp, dpp->msg_ctx, peer_bi, NULL,
+ DPP_CAPAB_CONFIGURATOR, -1, NULL, 0);
+ if (!auth)
+ return -1;
+ if (dpp_set_configurator(conn->auth,
+ conn->ctrl->configurator_params) < 0) {
+ dpp_auth_deinit(auth);
+ dpp_connection_remove(conn);
+ return -1;
+ }
+
+ conn->auth = auth;
+ return dpp_tcp_send_msg(conn, conn->auth->req_msg);
+}
+
+
+static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg,
+ size_t len)
+{
+ const u8 *pos, *end;
+ u8 type;
+
+ wpa_printf(MSG_DEBUG, "DPP: Received DPP Action frame over TCP");
+ pos = msg;
+ end = msg + len;
+
+ if (end - pos < DPP_HDR_LEN ||
+ WPA_GET_BE24(pos) != OUI_WFA ||
+ pos[3] != DPP_OUI_TYPE) {
+ wpa_printf(MSG_DEBUG, "DPP: Unrecognized header");
+ return -1;
+ }
+
+ if (pos[4] != 1) {
+ wpa_printf(MSG_DEBUG, "DPP: Unsupported Crypto Suite %u",
+ pos[4]);
+ return -1;
+ }
+ type = pos[5];
+ wpa_printf(MSG_DEBUG, "DPP: Received message type %u", type);
+ pos += DPP_HDR_LEN;
+
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes",
+ pos, end - pos);
+ if (dpp_check_attrs(pos, end - pos) < 0)
+ return -1;
+
+ if (conn->relay) {
+ wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN");
+ conn->relay->tx(conn->relay->cb_ctx, conn->mac_addr,
+ conn->freq, msg, len);
+ return 0;
+ }
+
+ switch (type) {
+ case DPP_PA_AUTHENTICATION_REQ:
+ return dpp_controller_rx_auth_req(conn, msg, pos, end - pos);
+ case DPP_PA_AUTHENTICATION_RESP:
+ return dpp_controller_rx_auth_resp(conn, msg, pos, end - pos);
+ case DPP_PA_AUTHENTICATION_CONF:
+ return dpp_controller_rx_auth_conf(conn, msg, pos, end - pos);
+ case DPP_PA_CONFIGURATION_RESULT:
+ return dpp_controller_rx_conf_result(conn, msg, pos, end - pos);
+ case DPP_PA_CONNECTION_STATUS_RESULT:
+ return dpp_controller_rx_conn_status_result(conn, msg, pos,
+ end - pos);
+ case DPP_PA_PRESENCE_ANNOUNCEMENT:
+ return dpp_controller_rx_presence_announcement(conn, msg, pos,
+ end - pos);
+ default:
+ /* TODO: missing messages types */
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unsupported frame subtype %d", type);
+ return -1;
+ }
+}
+
+
+static int dpp_controller_rx_gas_req(struct dpp_connection *conn, const u8 *msg,
+ size_t len)
+{
+ const u8 *pos, *end, *next;
+ u8 dialog_token;
+ const u8 *adv_proto;
+ u16 slen;
+ struct wpabuf *resp, *buf;
+ struct dpp_authentication *auth = conn->auth;
+
+ if (len < 1 + 2)
+ return -1;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Received DPP Configuration Request over TCP");
+
+ if (!conn->ctrl || !auth || !auth->auth_success) {
+ wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
+ return -1;
+ }
+
+ pos = msg;
+ end = msg + len;
+
+ dialog_token = *pos++;
+ adv_proto = pos++;
+ slen = *pos++;
+ if (*adv_proto != WLAN_EID_ADV_PROTO ||
+ slen > end - pos || slen < 2)
+ return -1;
+
+ next = pos + slen;
+ pos++; /* skip QueryRespLenLimit and PAME-BI */
+
+ if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC ||
+ pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA ||
+ pos[5] != DPP_OUI_TYPE || pos[6] != 0x01)
+ return -1;
+
+ pos = next;
+ /* Query Request */
+ if (end - pos < 2)
+ return -1;
+ slen = WPA_GET_LE16(pos);
+ pos += 2;
+ if (slen > end - pos)
+ return -1;
+
+ resp = dpp_conf_req_rx(auth, pos, slen);
+ if (!resp)
+ return -1;
+
+ buf = wpabuf_alloc(4 + 18 + wpabuf_len(resp));
+ if (!buf) {
+ wpabuf_free(resp);
+ return -1;
+ }
+
+ wpabuf_put_be32(buf, 18 + wpabuf_len(resp));
+
+ wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_RESP);
+ wpabuf_put_u8(buf, dialog_token);
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ wpabuf_put_le16(buf, 0); /* GAS Comeback Delay */
+
+ dpp_write_adv_proto(buf);
+ dpp_write_gas_query(buf, resp);
+ wpabuf_free(resp);
+
+ /* Send Config Response over TCP; GAS fragmentation is taken care of by
+ * the Relay */
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", buf);
+ wpabuf_free(conn->msg_out);
+ conn->msg_out_pos = 0;
+ conn->msg_out = buf;
+ conn->on_tcp_tx_complete_gas_done = 1;
+ dpp_tcp_send(conn);
+ return 0;
+}
+
+
+static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp)
+{
+ struct dpp_authentication *auth = conn->auth;
+ int res;
+ struct wpabuf *msg;
+ enum dpp_status_error status;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Configuration Response for local stack from TCP");
+
+ res = dpp_conf_resp_rx(auth, resp);
+ wpabuf_free(resp);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
+ return -1;
+ }
+
+ if (conn->global->process_conf_obj)
+ res = conn->global->process_conf_obj(conn->global->cb_ctx,
+ auth);
+ else
+ res = 0;
+
+ if (auth->peer_version < 2 || auth->conf_resp_status != DPP_STATUS_OK)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
+ status = res < 0 ? DPP_STATUS_CONFIG_REJECTED : DPP_STATUS_OK;
+ msg = dpp_build_conf_result(auth, status);
+ if (!msg)
+ return -1;
+
+ conn->on_tcp_tx_complete_remove = 1;
+ res = dpp_tcp_send_msg(conn, msg);
+ wpabuf_free(msg);
+
+ /* This exchange will be terminated in the TX status handler */
+
+ return res;
+}
+
+
+static int dpp_rx_gas_resp(struct dpp_connection *conn, const u8 *msg,
+ size_t len)
+{
+ struct wpabuf *buf;
+ u8 dialog_token;
+ const u8 *pos, *end, *next, *adv_proto;
+ u16 status, slen;
+
+ if (len < 5 + 2)
+ return -1;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Received DPP Configuration Response over TCP");
+
+ pos = msg;
+ end = msg + len;
+
+ dialog_token = *pos++;
+ status = WPA_GET_LE16(pos);
+ if (status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected Status Code %u", status);
+ return -1;
+ }
+ pos += 2;
+ pos += 2; /* ignore GAS Comeback Delay */
+
+ adv_proto = pos++;
+ slen = *pos++;
+ if (*adv_proto != WLAN_EID_ADV_PROTO ||
+ slen > end - pos || slen < 2)
+ return -1;
+
+ next = pos + slen;
+ pos++; /* skip QueryRespLenLimit and PAME-BI */
+
+ if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC ||
+ pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA ||
+ pos[5] != DPP_OUI_TYPE || pos[6] != 0x01)
+ return -1;
+
+ pos = next;
+ /* Query Response */
+ if (end - pos < 2)
+ return -1;
+ slen = WPA_GET_LE16(pos);
+ pos += 2;
+ if (slen > end - pos)
+ return -1;
+
+ buf = wpabuf_alloc(slen);
+ if (!buf)
+ return -1;
+ wpabuf_put_data(buf, pos, slen);
+
+ if (!conn->relay && !conn->ctrl)
+ return dpp_tcp_rx_gas_resp(conn, buf);
+
+ if (!conn->relay) {
+ wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
+ wpabuf_free(buf);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN");
+ conn->relay->gas_resp_tx(conn->relay->cb_ctx, conn->mac_addr,
+ dialog_token, 0, buf);
+
+ return 0;
+}
+
+
+static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx)
+{
+ struct dpp_connection *conn = eloop_ctx;
+ int res;
+ const u8 *pos;
+
+ wpa_printf(MSG_DEBUG, "DPP: TCP data available for reading (sock %d)",
+ sd);
+
+ if (conn->msg_len_octets < 4) {
+ u32 msglen;
+
+ res = recv(sd, &conn->msg_len[conn->msg_len_octets],
+ 4 - conn->msg_len_octets, 0);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: recv failed: %s",
+ strerror(errno));
+ dpp_connection_remove(conn);
+ return;
+ }
+ if (res == 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No more data available over TCP");
+ dpp_connection_remove(conn);
+ return;
+ }
+ wpa_printf(MSG_DEBUG,
+ "DPP: Received %d/%d octet(s) of message length field",
+ res, (int) (4 - conn->msg_len_octets));
+ conn->msg_len_octets += res;
+
+ if (conn->msg_len_octets < 4) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Need %d more octets of message length field",
+ (int) (4 - conn->msg_len_octets));
+ return;
+ }
+
+ msglen = WPA_GET_BE32(conn->msg_len);
+ wpa_printf(MSG_DEBUG, "DPP: Message length: %u", msglen);
+ if (msglen > 65535) {
+ wpa_printf(MSG_INFO, "DPP: Unexpectedly long message");
+ dpp_connection_remove(conn);
+ return;
+ }
+
+ wpabuf_free(conn->msg);
+ conn->msg = wpabuf_alloc(msglen);
+ }
+
+ if (!conn->msg) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No buffer available for receiving the message");
+ dpp_connection_remove(conn);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Need %u more octets of message payload",
+ (unsigned int) wpabuf_tailroom(conn->msg));
+
+ res = recv(sd, wpabuf_put(conn->msg, 0), wpabuf_tailroom(conn->msg), 0);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: recv failed: %s", strerror(errno));
+ dpp_connection_remove(conn);
+ return;
+ }
+ if (res == 0) {
+ wpa_printf(MSG_DEBUG, "DPP: No more data available over TCP");
+ dpp_connection_remove(conn);
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Received %d octets", res);
+ wpabuf_put(conn->msg, res);
+
+ if (wpabuf_tailroom(conn->msg) > 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Need %u more octets of message payload",
+ (unsigned int) wpabuf_tailroom(conn->msg));
+ return;
+ }
+
+ conn->msg_len_octets = 0;
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Received TCP message", conn->msg);
+ if (wpabuf_len(conn->msg) < 1) {
+ dpp_connection_remove(conn);
+ return;
+ }
+
+ pos = wpabuf_head(conn->msg);
+ switch (*pos) {
+ case WLAN_PA_VENDOR_SPECIFIC:
+ if (dpp_controller_rx_action(conn, pos + 1,
+ wpabuf_len(conn->msg) - 1) < 0)
+ dpp_connection_remove(conn);
+ break;
+ case WLAN_PA_GAS_INITIAL_REQ:
+ if (dpp_controller_rx_gas_req(conn, pos + 1,
+ wpabuf_len(conn->msg) - 1) < 0)
+ dpp_connection_remove(conn);
+ break;
+ case WLAN_PA_GAS_INITIAL_RESP:
+ if (dpp_rx_gas_resp(conn, pos + 1,
+ wpabuf_len(conn->msg) - 1) < 0)
+ dpp_connection_remove(conn);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "DPP: Ignore unsupported message type %u",
+ *pos);
+ break;
+ }
+}
+
+
+static void dpp_controller_tcp_cb(int sd, void *eloop_ctx, void *sock_ctx)
+{
+ struct dpp_controller *ctrl = eloop_ctx;
+ struct sockaddr_in addr;
+ socklen_t addr_len = sizeof(addr);
+ int fd;
+ struct dpp_connection *conn;
+
+ wpa_printf(MSG_DEBUG, "DPP: New TCP connection");
+
+ fd = accept(ctrl->sock, (struct sockaddr *) &addr, &addr_len);
+ if (fd < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to accept new connection: %s",
+ strerror(errno));
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Connection from %s:%d",
+ inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
+
+ conn = os_zalloc(sizeof(*conn));
+ if (!conn)
+ goto fail;
+
+ conn->global = ctrl->global;
+ conn->ctrl = ctrl;
+ conn->sock = fd;
+
+ if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
+ strerror(errno));
+ goto fail;
+ }
+
+ if (eloop_register_sock(conn->sock, EVENT_TYPE_READ,
+ dpp_controller_rx, conn, NULL) < 0)
+ goto fail;
+ conn->read_eloop = 1;
+
+ /* TODO: eloop timeout to expire connections that do not complete in
+ * reasonable time */
+ dl_list_add(&ctrl->conn, &conn->list);
+ return;
+
+fail:
+ close(fd);
+ os_free(conn);
+}
+
+
+int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
+ const struct hostapd_ip_addr *addr, int port)
+{
+ struct dpp_connection *conn;
+ struct sockaddr_storage saddr;
+ socklen_t addrlen;
+ const u8 *hdr, *pos, *end;
+ char txt[100];
+
+ wpa_printf(MSG_DEBUG, "DPP: Initialize TCP connection to %s port %d",
+ hostapd_ip_txt(addr, txt, sizeof(txt)), port);
+ if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &saddr, &addrlen,
+ addr, port) < 0) {
+ dpp_auth_deinit(auth);
+ return -1;
+ }
+
+ conn = os_zalloc(sizeof(*conn));
+ if (!conn) {
+ dpp_auth_deinit(auth);
+ return -1;
+ }
+
+ conn->global = dpp;
+ conn->auth = auth;
+ conn->sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (conn->sock < 0)
+ goto fail;
+
+ if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
+ strerror(errno));
+ goto fail;
+ }
+
+ if (connect(conn->sock, (struct sockaddr *) &saddr, addrlen) < 0) {
+ if (errno != EINPROGRESS) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s",
+ strerror(errno));
+ goto fail;
+ }
+
+ /*
+ * Continue connecting in the background; eloop will call us
+ * once the connection is ready (or failed).
+ */
+ }
+
+ if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
+ dpp_conn_tx_ready, conn, NULL) < 0)
+ goto fail;
+ conn->write_eloop = 1;
+
+ hdr = wpabuf_head(auth->req_msg);
+ end = hdr + wpabuf_len(auth->req_msg);
+ hdr += 2; /* skip Category and Actiom */
+ pos = hdr + DPP_HDR_LEN;
+ conn->msg_out = dpp_tcp_encaps(hdr, pos, end - pos);
+ if (!conn->msg_out)
+ goto fail;
+ /* Message will be sent in dpp_conn_tx_ready() */
+
+ /* TODO: eloop timeout to clear a connection if it does not complete
+ * properly */
+ dl_list_add(&dpp->tcp_init, &conn->list);
+ return 0;
+fail:
+ dpp_connection_free(conn);
+ return -1;
+}
+
+
+int dpp_controller_start(struct dpp_global *dpp,
+ struct dpp_controller_config *config)
+{
+ struct dpp_controller *ctrl;
+ int on = 1;
+ struct sockaddr_in sin;
+ int port;
+
+ if (!dpp || dpp->controller)
+ return -1;
+
+ ctrl = os_zalloc(sizeof(*ctrl));
+ if (!ctrl)
+ return -1;
+ ctrl->global = dpp;
+ if (config->configurator_params)
+ ctrl->configurator_params =
+ os_strdup(config->configurator_params);
+ dl_list_init(&ctrl->conn);
+ /* TODO: configure these somehow */
+ ctrl->allowed_roles = DPP_CAPAB_ENROLLEE | DPP_CAPAB_CONFIGURATOR;
+ ctrl->qr_mutual = 0;
+
+ ctrl->sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (ctrl->sock < 0)
+ goto fail;
+
+ if (setsockopt(ctrl->sock, SOL_SOCKET, SO_REUSEADDR,
+ &on, sizeof(on)) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: setsockopt(SO_REUSEADDR) failed: %s",
+ strerror(errno));
+ /* try to continue anyway */
+ }
+
+ if (fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0) {
+ wpa_printf(MSG_INFO, "DPP: fnctl(O_NONBLOCK) failed: %s",
+ strerror(errno));
+ goto fail;
+ }
+
+ /* TODO: IPv6 */
+ os_memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = INADDR_ANY;
+ port = config->tcp_port ? config->tcp_port : DPP_TCP_PORT;
+ sin.sin_port = htons(port);
+ if (bind(ctrl->sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
+ wpa_printf(MSG_INFO,
+ "DPP: Failed to bind Controller TCP port: %s",
+ strerror(errno));
+ goto fail;
+ }
+ if (listen(ctrl->sock, 10 /* max backlog */) < 0 ||
+ fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0 ||
+ eloop_register_sock(ctrl->sock, EVENT_TYPE_READ,
+ dpp_controller_tcp_cb, ctrl, NULL))
+ goto fail;
+
+ dpp->controller = ctrl;
+ wpa_printf(MSG_DEBUG, "DPP: Controller started on TCP port %d", port);
+ return 0;
+fail:
+ dpp_controller_free(ctrl);
+ return -1;
+}
+
+
+void dpp_controller_stop(struct dpp_global *dpp)
+{
+ if (dpp) {
+ dpp_controller_free(dpp->controller);
+ dpp->controller = NULL;
+ }
+}
+
+
+struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi)
+{
+ struct wpabuf *msg;
+
+ wpa_printf(MSG_DEBUG, "DPP: Build Presence Announcement frame");
+
+ msg = dpp_alloc_msg(DPP_PA_PRESENCE_ANNOUNCEMENT, 4 + SHA256_MAC_LEN);
+ if (!msg)
+ return NULL;
+
+ /* Responder Bootstrapping Key Hash */
+ dpp_build_attr_r_bootstrap_key_hash(msg, bi->pubkey_hash_chirp);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "DPP: Presence Announcement frame attributes", msg);
+ return msg;
+}
+
+#endif /* CONFIG_DPP2 */
diff --git a/src/common/dpp.h b/src/common/dpp.h
index 5a6d8cc..585d398 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -1,7 +1,7 @@
/*
* DPP functionality shared between hostapd and wpa_supplicant
* Copyright (c) 2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -18,9 +18,11 @@
#include "crypto/sha256.h"
struct crypto_ecdh;
+struct hostapd_ip_addr;
struct dpp_global;
#define DPP_HDR_LEN (4 + 2) /* OUI, OUI Type, Crypto Suite, DPP frame type */
+#define DPP_TCP_PORT 7871
enum dpp_public_action_frame_type {
DPP_PA_AUTHENTICATION_REQ = 0,
@@ -33,6 +35,12 @@
DPP_PA_PKEX_COMMIT_REVEAL_REQ = 9,
DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10,
DPP_PA_CONFIGURATION_RESULT = 11,
+ DPP_PA_CONNECTION_STATUS_RESULT = 12,
+ DPP_PA_PRESENCE_ANNOUNCEMENT = 13,
+ DPP_PA_RECONFIG_ANNOUNCEMENT = 14,
+ DPP_PA_RECONFIG_AUTH_REQ = 15,
+ DPP_PA_RECONFIG_AUTH_RESP = 16,
+ DPP_PA_RECONFIG_AUTH_CONF = 17,
};
enum dpp_attribute_id {
@@ -62,6 +70,11 @@
DPP_ATTR_CHANNEL = 0x1018,
DPP_ATTR_PROTOCOL_VERSION = 0x1019,
DPP_ATTR_ENVELOPED_DATA = 0x101A,
+ DPP_ATTR_SEND_CONN_STATUS = 0x101B,
+ DPP_ATTR_CONN_STATUS = 0x101C,
+ DPP_ATTR_RECONFIG_FLAGS = 0x101D,
+ DPP_ATTR_C_SIGN_KEY_HASH = 0x101E,
+ DPP_ATTR_CSR_ATTR_REQ = 0x101F,
};
enum dpp_status_error {
@@ -75,6 +88,10 @@
DPP_STATUS_INVALID_CONNECTOR = 7,
DPP_STATUS_NO_MATCH = 8,
DPP_STATUS_CONFIG_REJECTED = 9,
+ DPP_STATUS_NO_AP = 10,
+ DPP_STATUS_CONFIGURE_PENDING = 11,
+ DPP_STATUS_CSR_NEEDED = 12,
+ DPP_STATUS_CSR_BAD = 13,
};
#define DPP_CAPAB_ENROLLEE BIT(0)
@@ -100,6 +117,7 @@
enum dpp_bootstrap_type {
DPP_BOOTSTRAP_QR_CODE,
DPP_BOOTSTRAP_PKEX,
+ DPP_BOOTSTRAP_NFC_URI,
};
struct dpp_bootstrap_info {
@@ -108,15 +126,21 @@
enum dpp_bootstrap_type type;
char *uri;
u8 mac_addr[ETH_ALEN];
+ char *chan;
char *info;
+ char *pk;
unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
unsigned int num_freq;
int own;
EVP_PKEY *pubkey;
u8 pubkey_hash[SHA256_MAC_LEN];
+ u8 pubkey_hash_chirp[SHA256_MAC_LEN];
const struct dpp_curve_params *curve;
unsigned int pkex_t; /* number of failures before dpp_pkex
* instantiation */
+ int nfc_negotiated; /* whether this has been used in NFC negotiated
+ * connection handover */
+ char *configurator_params;
};
#define PKEX_COUNTER_T_LIMIT 5
@@ -155,10 +179,18 @@
DPP_AKM_PSK_SAE_DPP,
};
+enum dpp_netrole {
+ DPP_NETROLE_STA,
+ DPP_NETROLE_AP,
+ DPP_NETROLE_CONFIGURATOR,
+};
+
struct dpp_configuration {
u8 ssid[32];
size_t ssid_len;
+ int ssid_charset;
enum dpp_akm akm;
+ enum dpp_netrole netrole;
/* For DPP configuration (connector) */
os_time_t netaccesskey_expiry;
@@ -172,7 +204,18 @@
int psk_set;
};
+struct dpp_asymmetric_key {
+ struct dpp_asymmetric_key *next;
+ EVP_PKEY *csign;
+ char *config_template;
+ char *connector_template;
+};
+
+#define DPP_MAX_CONF_OBJ 10
+#define DPP_MAX_CHANNELS 32
+
struct dpp_authentication {
+ struct dpp_global *global;
void *msg_ctx;
u8 peer_version;
const struct dpp_curve_params *curve;
@@ -220,28 +263,43 @@
int remove_on_tx_status;
int connect_on_tx_status;
int waiting_conf_result;
+ int waiting_conn_status_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 *conf2_ap;
struct dpp_configuration *conf_sta;
+ struct dpp_configuration *conf2_sta;
+ int provision_configurator;
struct dpp_configurator *conf;
- char *connector; /* received signedConnector */
- u8 ssid[SSID_MAX_LEN];
- u8 ssid_len;
- char passphrase[64];
- u8 psk[PMK_LEN];
- int psk_set;
- enum dpp_akm akm;
+ struct dpp_config_obj {
+ char *connector; /* received signedConnector */
+ u8 ssid[SSID_MAX_LEN];
+ u8 ssid_len;
+ int ssid_charset;
+ char passphrase[64];
+ u8 psk[PMK_LEN];
+ int psk_set;
+ enum dpp_akm akm;
+ struct wpabuf *c_sign_key;
+ } conf_obj[DPP_MAX_CONF_OBJ];
+ unsigned int num_conf_obj;
+ struct dpp_asymmetric_key *conf_key_pkg;
struct wpabuf *net_access_key;
os_time_t net_access_key_expiry;
- struct wpabuf *c_sign_key;
+ int send_conn_status;
+ int conn_status_requested;
+ int akm_use_selector;
+ int configurator_set;
#ifdef CONFIG_TESTING_OPTIONS
char *config_obj_override;
char *discovery_override;
char *groups_override;
unsigned int ignore_netaccesskey_mismatch:1;
#endif /* CONFIG_TESTING_OPTIONS */
+ unsigned short band_list[DPP_MAX_CHANNELS];
+ int band_list_size;
};
struct dpp_configurator {
@@ -259,6 +317,22 @@
size_t pmk_len;
};
+struct dpp_relay_config {
+ const struct hostapd_ip_addr *ipaddr;
+ const u8 *pkhash;
+
+ void *cb_ctx;
+ void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg,
+ size_t len);
+ void (*gas_resp_tx)(void *ctx, const u8 *addr, u8 dialog_token, int prot,
+ struct wpabuf *buf);
+};
+
+struct dpp_controller_config {
+ const char *configurator_params;
+ int tcp_port;
+};
+
#ifdef CONFIG_TESTING_OPTIONS
enum dpp_test_behavior {
DPP_TEST_DISABLED = 0,
@@ -368,16 +442,16 @@
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);
int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
const char *chan_list);
int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac);
int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info);
-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);
+int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
+ struct dpp_bootstrap_info *peer_bi);
+struct dpp_authentication *
+dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx);
struct hostapd_hw_modes;
-struct dpp_authentication * dpp_auth_init(void *msg_ctx,
+struct dpp_authentication * dpp_auth_init(struct dpp_global *dpp, void *msg_ctx,
struct dpp_bootstrap_info *peer_bi,
struct dpp_bootstrap_info *own_bi,
u8 dpp_allowed_roles,
@@ -385,8 +459,8 @@
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,
+dpp_auth_req_rx(struct dpp_global *dpp, 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,
size_t attr_len);
@@ -395,6 +469,10 @@
const u8 *attr_start, size_t attr_len);
struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
const char *json);
+struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
+ const char *name,
+ enum dpp_netrole netrole,
+ const char *mud_url, int *opclasses);
int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
const u8 *attr_start, size_t attr_len);
int dpp_notify_new_qr_code(struct dpp_authentication *auth,
@@ -407,9 +485,7 @@
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);
+int dpp_set_configurator(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,
@@ -421,12 +497,23 @@
const u8 *attr_start, size_t attr_len);
struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
enum dpp_status_error status);
+enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
+ const u8 *hdr,
+ const u8 *attr_start,
+ size_t attr_len,
+ u8 *ssid, size_t *ssid_len,
+ char **channel_list);
+struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
+ enum dpp_status_error result,
+ const u8 *ssid, size_t ssid_len,
+ const char *channel_list);
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);
+const char * dpp_akm_selector_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);
@@ -479,6 +566,8 @@
struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
const char *uri);
+struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
+ 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);
@@ -489,15 +578,41 @@
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);
+int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params);
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 * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
+ const u8 *hash);
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);
+int dpp_configurator_from_backup(struct dpp_global *dpp,
+ struct dpp_asymmetric_key *key);
+int dpp_relay_add_controller(struct dpp_global *dpp,
+ struct dpp_relay_config *config);
+int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
+ const u8 *buf, size_t len, unsigned int freq,
+ const u8 *i_bootstrap, const u8 *r_bootstrap);
+int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data,
+ size_t data_len);
+int dpp_controller_start(struct dpp_global *dpp,
+ struct dpp_controller_config *config);
+void dpp_controller_stop(struct dpp_global *dpp);
+int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
+ const struct hostapd_ip_addr *addr, int port);
+struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi);
+
+struct dpp_global_config {
+ void *msg_ctx;
+ void *cb_ctx;
+ int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
+ void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
+};
+
+struct dpp_global * dpp_global_init(struct dpp_global_config *config);
void dpp_global_clear(struct dpp_global *dpp);
void dpp_global_deinit(struct dpp_global *dpp);
diff --git a/src/common/dragonfly.c b/src/common/dragonfly.c
new file mode 100644
index 0000000..547be66
--- /dev/null
+++ b/src/common/dragonfly.c
@@ -0,0 +1,215 @@
+/*
+ * Shared Dragonfly functionality
+ * Copyright (c) 2012-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2019, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/const_time.h"
+#include "crypto/crypto.h"
+#include "dragonfly.h"
+
+
+int dragonfly_suitable_group(int group, int ecc_only)
+{
+ /* 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. Disable
+ * groups that use Brainpool curves as well for now since they leak more
+ * timing information due to the prime not being close to a power of
+ * two. */
+ return group == 19 || group == 20 || group == 21 ||
+ (!ecc_only &&
+ (group == 15 || group == 16 || group == 17 || group == 18));
+}
+
+
+unsigned int dragonfly_min_pwe_loop_iter(int group)
+{
+ if (group == 22 || group == 23 || group == 24) {
+ /* FFC groups for which pwd-value is likely to be >= p
+ * frequently */
+ return 40;
+ }
+
+ if (group == 1 || group == 2 || group == 5 || group == 14 ||
+ group == 15 || group == 16 || group == 17 || group == 18) {
+ /* FFC groups that have prime that is close to a power of two */
+ return 1;
+ }
+
+ /* Default to 40 (this covers most ECC groups) */
+ return 40;
+}
+
+
+int dragonfly_get_random_qr_qnr(const struct crypto_bignum *prime,
+ struct crypto_bignum **qr,
+ struct crypto_bignum **qnr)
+{
+ *qr = *qnr = NULL;
+
+ while (!(*qr) || !(*qnr)) {
+ struct crypto_bignum *tmp;
+ int res;
+
+ tmp = crypto_bignum_init();
+ if (!tmp || crypto_bignum_rand(tmp, prime) < 0) {
+ crypto_bignum_deinit(tmp, 0);
+ break;
+ }
+
+ res = crypto_bignum_legendre(tmp, prime);
+ if (res == 1 && !(*qr))
+ *qr = tmp;
+ else if (res == -1 && !(*qnr))
+ *qnr = tmp;
+ else
+ crypto_bignum_deinit(tmp, 0);
+ }
+
+ if (*qr && *qnr)
+ return 0;
+ crypto_bignum_deinit(*qr, 0);
+ crypto_bignum_deinit(*qnr, 0);
+ *qr = *qnr = NULL;
+ return -1;
+}
+
+
+static struct crypto_bignum *
+dragonfly_get_rand_1_to_p_1(const struct crypto_bignum *prime)
+{
+ struct crypto_bignum *tmp, *pm1, *one;
+
+ tmp = crypto_bignum_init();
+ pm1 = crypto_bignum_init();
+ one = crypto_bignum_init_set((const u8 *) "\x01", 1);
+ if (!tmp || !pm1 || !one ||
+ crypto_bignum_sub(prime, one, pm1) < 0 ||
+ crypto_bignum_rand(tmp, pm1) < 0 ||
+ crypto_bignum_add(tmp, one, tmp) < 0) {
+ crypto_bignum_deinit(tmp, 0);
+ tmp = NULL;
+ }
+
+ crypto_bignum_deinit(pm1, 0);
+ crypto_bignum_deinit(one, 0);
+ return tmp;
+}
+
+
+int dragonfly_is_quadratic_residue_blind(struct crypto_ec *ec,
+ const u8 *qr, const u8 *qnr,
+ const struct crypto_bignum *val)
+{
+ struct crypto_bignum *r, *num, *qr_or_qnr = NULL;
+ int check, res = -1;
+ u8 qr_or_qnr_bin[DRAGONFLY_MAX_ECC_PRIME_LEN];
+ const struct crypto_bignum *prime;
+ size_t prime_len;
+ unsigned int mask;
+
+ prime = crypto_ec_get_prime(ec);
+ prime_len = crypto_ec_prime_len(ec);
+
+ /*
+ * Use a blinding technique to mask val while determining whether it is
+ * a quadratic residue modulo p to avoid leaking timing information
+ * while determining the Legendre symbol.
+ *
+ * v = val
+ * r = a random number between 1 and p-1, inclusive
+ * num = (v * r * r) modulo p
+ */
+ r = dragonfly_get_rand_1_to_p_1(prime);
+ if (!r)
+ return -1;
+
+ num = crypto_bignum_init();
+ if (!num ||
+ crypto_bignum_mulmod(val, r, prime, num) < 0 ||
+ crypto_bignum_mulmod(num, r, prime, num) < 0)
+ goto fail;
+
+ /*
+ * Need to minimize differences in handling different cases, so try to
+ * avoid branches and timing differences.
+ *
+ * If r is 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 is set to !odd(r)
+ */
+ mask = const_time_is_zero(crypto_bignum_is_odd(r));
+ 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, prime, num) < 0)
+ goto fail;
+ /* branchless version of check = odd(r) ? 1 : -1, */
+ check = const_time_select_int(mask, -1, 1);
+
+ /* Determine the Legendre symbol on the masked value */
+ res = crypto_bignum_legendre(num, prime);
+ if (res == -2) {
+ res = -1;
+ goto fail;
+ }
+ /* 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 dragonfly_get_rand_2_to_r_1(struct crypto_bignum *val,
+ const struct crypto_bignum *order)
+{
+ return crypto_bignum_rand(val, order) == 0 &&
+ !crypto_bignum_is_zero(val) &&
+ !crypto_bignum_is_one(val);
+}
+
+
+int dragonfly_generate_scalar(const struct crypto_bignum *order,
+ struct crypto_bignum *_rand,
+ struct crypto_bignum *_mask,
+ struct crypto_bignum *scalar)
+{
+ int count;
+
+ /* 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 (dragonfly_get_rand_2_to_r_1(_rand, order) &&
+ dragonfly_get_rand_2_to_r_1(_mask, order) &&
+ 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;
+ }
+
+ /* This should not be reachable in practice if the random number
+ * generation is working. */
+ wpa_printf(MSG_INFO,
+ "dragonfly: Unable to get randomness for own scalar");
+ return -1;
+}
diff --git a/src/common/dragonfly.h b/src/common/dragonfly.h
new file mode 100644
index 0000000..ec3dd59
--- /dev/null
+++ b/src/common/dragonfly.h
@@ -0,0 +1,31 @@
+/*
+ * Shared Dragonfly functionality
+ * Copyright (c) 2012-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2019, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DRAGONFLY_H
+#define DRAGONFLY_H
+
+#define DRAGONFLY_MAX_ECC_PRIME_LEN 66
+
+struct crypto_bignum;
+struct crypto_ec;
+
+int dragonfly_suitable_group(int group, int ecc_only);
+unsigned int dragonfly_min_pwe_loop_iter(int group);
+int dragonfly_get_random_qr_qnr(const struct crypto_bignum *prime,
+ struct crypto_bignum **qr,
+ struct crypto_bignum **qnr);
+int dragonfly_is_quadratic_residue_blind(struct crypto_ec *ec,
+ const u8 *qr, const u8 *qnr,
+ const struct crypto_bignum *val);
+int dragonfly_generate_scalar(const struct crypto_bignum *order,
+ struct crypto_bignum *_rand,
+ struct crypto_bignum *_mask,
+ struct crypto_bignum *scalar);
+
+#endif /* DRAGONFLY_H */
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index 49ed806..f6c67a3 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -40,23 +40,32 @@
}
-struct hostapd_channel_data * hw_get_channel_freq(struct hostapd_hw_modes *mode,
- int freq, int *chan)
+struct hostapd_channel_data *
+hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int *chan,
+ struct hostapd_hw_modes *hw_features, int num_hw_features)
{
- int i;
+ int i, j;
if (chan)
*chan = 0;
- if (!mode)
+ if (!hw_features)
return NULL;
- for (i = 0; i < mode->num_channels; i++) {
- struct hostapd_channel_data *ch = &mode->channels[i];
- if (ch->freq == freq) {
- if (chan)
- *chan = ch->chan;
- return ch;
+ for (j = 0; j < num_hw_features; j++) {
+ struct hostapd_hw_modes *curr_mode = &hw_features[j];
+
+ if (curr_mode->mode != mode)
+ continue;
+ for (i = 0; i < curr_mode->num_channels; i++) {
+ struct hostapd_channel_data *ch =
+ &curr_mode->channels[i];
+
+ if (ch->freq == freq) {
+ if (chan)
+ *chan = ch->chan;
+ return ch;
+ }
}
}
@@ -74,29 +83,33 @@
}
-int hw_get_chan(struct hostapd_hw_modes *mode, int freq)
+int hw_get_chan(enum hostapd_hw_mode mode, int freq,
+ struct hostapd_hw_modes *hw_features, int num_hw_features)
{
int chan;
- hw_get_channel_freq(mode, freq, &chan);
+ hw_get_channel_freq(mode, freq, &chan, hw_features, num_hw_features);
return chan;
}
-int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
- int sec_chan)
+int allowed_ht40_channel_pair(enum hostapd_hw_mode mode,
+ struct hostapd_channel_data *p_chan,
+ struct hostapd_channel_data *s_chan)
{
int ok, first;
int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 140,
149, 157, 165, 184, 192 };
size_t k;
- struct hostapd_channel_data *p_chan, *s_chan;
- const int ht40_plus = pri_chan < sec_chan;
+ int ht40_plus, pri_chan, sec_chan;
- p_chan = hw_get_channel_chan(mode, pri_chan, NULL);
- if (!p_chan)
+ if (!p_chan || !s_chan)
return 0;
+ pri_chan = p_chan->chan;
+ sec_chan = s_chan->chan;
+
+ ht40_plus = pri_chan < sec_chan;
if (pri_chan == sec_chan || !sec_chan) {
if (chan_pri_allowed(p_chan))
@@ -107,13 +120,9 @@
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",
- pri_chan, sec_chan);
+ "HT40: control channel: %d (%d MHz), secondary channel: %d (%d MHz)",
+ pri_chan, p_chan->freq, sec_chan, s_chan->freq);
/* Verify that HT40 secondary channel is an allowed 20 MHz
* channel */
@@ -131,7 +140,7 @@
* 2.4 GHz rules allow all cases where the secondary channel fits into
* the list of allowed channels (already checked above).
*/
- if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+ if (mode != HOSTAPD_MODE_IEEE80211A)
return 1;
first = pri_chan < sec_chan ? pri_chan : sec_chan;
@@ -176,22 +185,19 @@
}
-int check_40mhz_5g(struct hostapd_hw_modes *mode,
- struct wpa_scan_results *scan_res, int pri_chan,
- int sec_chan)
+int check_40mhz_5g(struct wpa_scan_results *scan_res,
+ struct hostapd_channel_data *pri_chan,
+ struct hostapd_channel_data *sec_chan)
{
- int pri_freq, sec_freq, pri_bss, sec_bss;
+ int pri_bss, sec_bss;
int bss_pri_chan, bss_sec_chan;
size_t i;
int match;
- if (!mode || !scan_res || !pri_chan || !sec_chan ||
- pri_chan == sec_chan)
+ if (!scan_res || !pri_chan || !sec_chan ||
+ pri_chan->freq == sec_chan->freq)
return 0;
- pri_freq = hw_get_freq(mode, pri_chan);
- sec_freq = hw_get_freq(mode, sec_chan);
-
/*
* Switch PRI/SEC channels if Beacons were detected on selected SEC
* channel, but not on selected PRI channel.
@@ -199,9 +205,9 @@
pri_bss = sec_bss = 0;
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *bss = scan_res->res[i];
- if (bss->freq == pri_freq)
+ if (bss->freq == pri_chan->freq)
pri_bss++;
- else if (bss->freq == sec_freq)
+ else if (bss->freq == sec_chan->freq)
sec_bss++;
}
if (sec_bss && !pri_bss) {
@@ -219,8 +225,8 @@
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *bss = scan_res->res[i];
get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
- if (pri_chan == bss_pri_chan &&
- sec_chan == bss_sec_chan) {
+ if (pri_chan->chan == bss_pri_chan &&
+ sec_chan->chan == bss_sec_chan) {
match = 1;
break;
}
@@ -229,8 +235,8 @@
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *bss = scan_res->res[i];
get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
- if (pri_chan == bss_sec_chan &&
- sec_chan == bss_pri_chan) {
+ if (pri_chan->chan == bss_sec_chan &&
+ sec_chan->chan == bss_pri_chan) {
wpa_printf(MSG_INFO, "Switch own primary and "
"secondary channel due to BSS "
"overlap with " MACSTR,
@@ -273,12 +279,87 @@
}
+/*
+ * Returns:
+ * 0: no impact
+ * 1: overlapping BSS
+ * 2: overlapping BSS with 40 MHz intolerant advertisement
+ */
+int check_bss_coex_40mhz(struct wpa_scan_res *bss, int pri_freq, int sec_freq)
+{
+ int affected_start, affected_end;
+ struct ieee802_11_elems elems;
+ int pri_chan, sec_chan;
+ int pri = bss->freq;
+ int sec = pri;
+
+ if (pri_freq == sec_freq)
+ return 1;
+
+ affected_start = (pri_freq + sec_freq) / 2 - 25;
+ affected_end = (pri_freq + sec_freq) / 2 + 25;
+
+ /* Check for overlapping 20 MHz BSS */
+ if (check_20mhz_bss(bss, pri_freq, affected_start, affected_end)) {
+ wpa_printf(MSG_DEBUG, "Overlapping 20 MHz BSS is found");
+ return 1;
+ }
+
+ get_pri_sec_chan(bss, &pri_chan, &sec_chan);
+
+ if (sec_chan) {
+ if (sec_chan < pri_chan)
+ sec = pri - 20;
+ else
+ sec = pri + 20;
+ }
+
+ if ((pri < affected_start || pri > affected_end) &&
+ (sec < affected_start || sec > affected_end))
+ return 0; /* not within affected channel range */
+
+ wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
+ " freq=%d pri=%d sec=%d",
+ MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
+
+ if (sec_chan) {
+ if (pri_freq != pri || sec_freq != sec) {
+ wpa_printf(MSG_DEBUG,
+ "40 MHz pri/sec mismatch with BSS "
+ MACSTR
+ " <%d,%d> (chan=%d%c) vs. <%d,%d>",
+ MAC2STR(bss->bssid),
+ pri, sec, pri_chan,
+ sec > pri ? '+' : '-',
+ pri_freq, sec_freq);
+ return 1;
+ }
+ }
+
+ ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
+ if (elems.ht_capabilities) {
+ struct ieee80211_ht_capabilities *ht_cap =
+ (struct ieee80211_ht_capabilities *)
+ elems.ht_capabilities;
+
+ if (le_to_host16(ht_cap->ht_capabilities_info) &
+ HT_CAP_INFO_40MHZ_INTOLERANT) {
+ wpa_printf(MSG_DEBUG,
+ "40 MHz Intolerant is set on channel %d in BSS "
+ MACSTR, pri, MAC2STR(bss->bssid));
+ return 2;
+ }
+ }
+
+ return 0;
+}
+
+
int check_40mhz_2g4(struct hostapd_hw_modes *mode,
struct wpa_scan_results *scan_res, int pri_chan,
int sec_chan)
{
int pri_freq, sec_freq;
- int affected_start, affected_end;
size_t i;
if (!mode || !scan_res || !pri_chan || !sec_chan ||
@@ -288,70 +369,12 @@
pri_freq = hw_get_freq(mode, pri_chan);
sec_freq = hw_get_freq(mode, sec_chan);
- affected_start = (pri_freq + sec_freq) / 2 - 25;
- affected_end = (pri_freq + sec_freq) / 2 + 25;
wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
- affected_start, affected_end);
+ (pri_freq + sec_freq) / 2 - 25,
+ (pri_freq + sec_freq) / 2 + 25);
for (i = 0; i < scan_res->num; i++) {
- struct wpa_scan_res *bss = scan_res->res[i];
- int pri = bss->freq;
- int sec = pri;
- struct ieee802_11_elems elems;
-
- /* Check for overlapping 20 MHz BSS */
- if (check_20mhz_bss(bss, pri_freq, affected_start,
- affected_end)) {
- wpa_printf(MSG_DEBUG,
- "Overlapping 20 MHz BSS is found");
+ if (check_bss_coex_40mhz(scan_res->res[i], pri_freq, sec_freq))
return 0;
- }
-
- get_pri_sec_chan(bss, &pri_chan, &sec_chan);
-
- if (sec_chan) {
- if (sec_chan < pri_chan)
- sec = pri - 20;
- else
- sec = pri + 20;
- }
-
- if ((pri < affected_start || pri > affected_end) &&
- (sec < affected_start || sec > affected_end))
- continue; /* not within affected channel range */
-
- wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
- " freq=%d pri=%d sec=%d",
- MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
-
- if (sec_chan) {
- if (pri_freq != pri || sec_freq != sec) {
- wpa_printf(MSG_DEBUG,
- "40 MHz pri/sec mismatch with BSS "
- MACSTR
- " <%d,%d> (chan=%d%c) vs. <%d,%d>",
- MAC2STR(bss->bssid),
- pri, sec, pri_chan,
- sec > pri ? '+' : '-',
- pri_freq, sec_freq);
- return 0;
- }
- }
-
- ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems,
- 0);
- if (elems.ht_capabilities) {
- struct ieee80211_ht_capabilities *ht_cap =
- (struct ieee80211_ht_capabilities *)
- elems.ht_capabilities;
-
- if (le_to_host16(ht_cap->ht_capabilities_info) &
- HT_CAP_INFO_40MHZ_INTOLERANT) {
- wpa_printf(MSG_DEBUG,
- "40 MHz Intolerant is set on channel %d in BSS "
- MACSTR, pri, MAC2STR(bss->bssid));
- return 0;
- }
- }
}
return 1;
@@ -360,46 +383,177 @@
int hostapd_set_freq_params(struct hostapd_freq_params *data,
enum hostapd_hw_mode mode,
- int freq, int channel, int ht_enabled,
- int vht_enabled, int sec_channel_offset,
- int vht_oper_chwidth, int center_segment0,
- int center_segment1, u32 vht_caps)
+ int freq, int channel, int enable_edmg,
+ u8 edmg_channel, int ht_enabled,
+ int vht_enabled, int he_enabled,
+ int sec_channel_offset,
+ int oper_chwidth, int center_segment0,
+ int center_segment1, u32 vht_caps,
+ struct he_capabilities *he_cap)
{
+ if (!he_cap)
+ he_enabled = 0;
os_memset(data, 0, sizeof(*data));
data->mode = mode;
data->freq = freq;
data->channel = channel;
data->ht_enabled = ht_enabled;
data->vht_enabled = vht_enabled;
+ data->he_enabled = he_enabled;
data->sec_channel_offset = sec_channel_offset;
data->center_freq1 = freq + sec_channel_offset * 10;
data->center_freq2 = 0;
data->bandwidth = sec_channel_offset ? 40 : 20;
- if (data->vht_enabled) switch (vht_oper_chwidth) {
- case VHT_CHANWIDTH_USE_HT:
+ hostapd_encode_edmg_chan(enable_edmg, edmg_channel, channel,
+ &data->edmg);
+
+ if (is_6ghz_freq(freq)) {
+ if (!data->he_enabled) {
+ wpa_printf(MSG_ERROR,
+ "Can't set 6 GHz mode - HE isn't enabled");
+ return -1;
+ }
+
+ if (center_idx_to_bw_6ghz(channel) != 0) {
+ wpa_printf(MSG_ERROR,
+ "Invalid control channel for 6 GHz band");
+ return -1;
+ }
+
+ if (!center_segment0) {
+ if (center_segment1) {
+ wpa_printf(MSG_ERROR,
+ "Segment 0 center frequency isn't set");
+ return -1;
+ }
+
+ data->center_freq1 = data->freq;
+ data->bandwidth = 20;
+ } else {
+ int freq1, freq2 = 0;
+ int bw = center_idx_to_bw_6ghz(center_segment0);
+
+ if (bw < 0) {
+ wpa_printf(MSG_ERROR,
+ "Invalid center frequency index for 6 GHz");
+ return -1;
+ }
+
+ freq1 = ieee80211_chan_to_freq(NULL, 131,
+ center_segment0);
+ if (freq1 < 0) {
+ wpa_printf(MSG_ERROR,
+ "Invalid segment 0 center frequency for 6 GHz");
+ return -1;
+ }
+
+ if (center_segment1) {
+ if (center_idx_to_bw_6ghz(center_segment1) != 2 ||
+ bw != 2) {
+ wpa_printf(MSG_ERROR,
+ "6 GHz 80+80 MHz configuration doesn't use valid 80 MHz channels");
+ return -1;
+ }
+
+ freq2 = ieee80211_chan_to_freq(NULL, 131,
+ center_segment1);
+ if (freq2 < 0) {
+ wpa_printf(MSG_ERROR,
+ "Invalid segment 1 center frequency for UHB");
+ return -1;
+ }
+ }
+
+ data->bandwidth = (1 << (u8) bw) * 20;
+ data->center_freq1 = freq1;
+ data->center_freq2 = freq2;
+ }
+ data->ht_enabled = 0;
+ data->vht_enabled = 0;
+
+ return 0;
+ }
+
+ if (data->he_enabled) switch (oper_chwidth) {
+ case CHANWIDTH_USE_HT:
+ if (mode == HOSTAPD_MODE_IEEE80211G && sec_channel_offset) {
+ if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G)) {
+ wpa_printf(MSG_ERROR,
+ "40 MHz channel width is not supported in 2.4 GHz");
+ return -1;
+ }
+ break;
+ }
+ /* fall through */
+ case CHANWIDTH_80MHZ:
+ if (mode == HOSTAPD_MODE_IEEE80211A) {
+ if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) {
+ wpa_printf(MSG_ERROR,
+ "40/80 MHz channel width is not supported in 5/6 GHz");
+ return -1;
+ }
+ }
+ break;
+ case CHANWIDTH_80P80MHZ:
+ if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) {
+ wpa_printf(MSG_ERROR,
+ "80+80 MHz channel width is not supported in 5/6 GHz");
+ return -1;
+ }
+ break;
+ case CHANWIDTH_160MHZ:
+ if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G)) {
+ wpa_printf(MSG_ERROR,
+ "160 MHz channel width is not supported in 5 / 6GHz");
+ return -1;
+ }
+ break;
+ } else if (data->vht_enabled) switch (oper_chwidth) {
+ case CHANWIDTH_USE_HT:
+ break;
+ case CHANWIDTH_80P80MHZ:
+ if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
+ wpa_printf(MSG_ERROR,
+ "80+80 channel width is not supported!");
+ return -1;
+ }
+ /* fall through */
+ case CHANWIDTH_80MHZ:
+ break;
+ case CHANWIDTH_160MHZ:
+ if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
+ VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
+ wpa_printf(MSG_ERROR,
+ "160 MHz channel width is not supported!");
+ return -1;
+ }
+ break;
+ }
+
+ if (data->he_enabled || data->vht_enabled) switch (oper_chwidth) {
+ case CHANWIDTH_USE_HT:
if (center_segment1 ||
(center_segment0 != 0 &&
5000 + center_segment0 * 5 != data->center_freq1 &&
2407 + center_segment0 * 5 != data->center_freq1))
return -1;
break;
- case VHT_CHANWIDTH_80P80MHZ:
- if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
- wpa_printf(MSG_ERROR,
- "80+80 channel width is not supported!");
- return -1;
- }
+ case CHANWIDTH_80P80MHZ:
if (center_segment1 == center_segment0 + 4 ||
center_segment1 == center_segment0 - 4)
return -1;
data->center_freq2 = 5000 + center_segment1 * 5;
/* fall through */
- case VHT_CHANWIDTH_80MHZ:
+ case CHANWIDTH_80MHZ:
data->bandwidth = 80;
- if ((vht_oper_chwidth == VHT_CHANWIDTH_80MHZ &&
+ if ((oper_chwidth == CHANWIDTH_80MHZ &&
center_segment1) ||
- (vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ &&
+ (oper_chwidth == CHANWIDTH_80P80MHZ &&
!center_segment1) ||
!sec_channel_offset)
return -1;
@@ -432,14 +586,8 @@
return -1;
}
break;
- case VHT_CHANWIDTH_160MHZ:
+ case CHANWIDTH_160MHZ:
data->bandwidth = 160;
- if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
- VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
- wpa_printf(MSG_ERROR,
- "160MHZ channel width is not supported!");
- return -1;
- }
if (center_segment1)
return -1;
if (!sec_channel_offset)
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index eb1f1c5..e57a8d6 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -14,27 +14,34 @@
struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
int chan, int *freq);
-struct hostapd_channel_data * hw_get_channel_freq(struct hostapd_hw_modes *mode,
- int freq, int *chan);
+struct hostapd_channel_data *
+hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int *chan,
+ struct hostapd_hw_modes *hw_features, int num_hw_features);
int hw_get_freq(struct hostapd_hw_modes *mode, int chan);
-int hw_get_chan(struct hostapd_hw_modes *mode, int freq);
+int hw_get_chan(enum hostapd_hw_mode mode, int freq,
+ struct hostapd_hw_modes *hw_features, int num_hw_features);
-int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
- int sec_chan);
+int allowed_ht40_channel_pair(enum hostapd_hw_mode mode,
+ struct hostapd_channel_data *p_chan,
+ struct hostapd_channel_data *s_chan);
void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan);
-int check_40mhz_5g(struct hostapd_hw_modes *mode,
- struct wpa_scan_results *scan_res, int pri_chan,
- int sec_chan);
+int check_40mhz_5g(struct wpa_scan_results *scan_res,
+ struct hostapd_channel_data *pri_chan,
+ struct hostapd_channel_data *sec_chan);
+int check_bss_coex_40mhz(struct wpa_scan_res *bss, int pri_freq, int sec_freq);
int check_40mhz_2g4(struct hostapd_hw_modes *mode,
struct wpa_scan_results *scan_res, int pri_chan,
int sec_chan);
int hostapd_set_freq_params(struct hostapd_freq_params *data,
enum hostapd_hw_mode mode,
- int freq, int channel, int ht_enabled,
- int vht_enabled, int sec_channel_offset,
- int vht_oper_chwidth, int center_segment0,
- int center_segment1, u32 vht_caps);
+ int freq, int channel, int edmg, u8 edmg_channel,
+ int ht_enabled,
+ int vht_enabled, int he_enabled,
+ int sec_channel_offset,
+ int oper_chwidth, int center_segment0,
+ int center_segment1, u32 vht_caps,
+ struct he_capabilities *he_caps);
void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps,
int disabled);
int ieee80211ac_cap_check(u32 hw, u32 conf);
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index f886551..71c54ba 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -130,6 +130,12 @@
elems->multi_ap = pos;
elems->multi_ap_len = elen;
break;
+ case OWE_OUI_TYPE:
+ /* OWE Transition Mode element */
+ break;
+ case DPP_CC_OUI_TYPE:
+ /* DPP Configurator Connectivity element */
+ break;
default:
wpa_printf(MSG_MSGDUMP, "Unknown WFA "
"information element ignored "
@@ -206,6 +212,8 @@
ext_id = *pos++;
elen--;
+ elems->frag_ies.last_eid_ext = 0;
+
switch (ext_id) {
case WLAN_EID_EXT_ASSOC_DELAY_INFO:
if (elen != 1)
@@ -245,9 +253,9 @@
elems->key_delivery = pos;
elems->key_delivery_len = elen;
break;
- case WLAN_EID_EXT_FILS_WRAPPED_DATA:
- elems->fils_wrapped_data = pos;
- elems->fils_wrapped_data_len = elen;
+ case WLAN_EID_EXT_WRAPPED_DATA:
+ elems->wrapped_data = pos;
+ elems->wrapped_data_len = elen;
break;
case WLAN_EID_EXT_FILS_PUBLIC_KEY:
if (elen < 1)
@@ -271,13 +279,25 @@
elems->password_id_len = elen;
break;
case WLAN_EID_EXT_HE_CAPABILITIES:
+ if (elen < HE_CAPABILITIES_IE_MIN_LEN)
+ break;
elems->he_capabilities = pos;
elems->he_capabilities_len = elen;
break;
+ case WLAN_EID_EXT_HE_OPERATION:
+ if (elen < HE_OPERATION_IE_MIN_LEN)
+ break;
+ elems->he_operation = pos;
+ elems->he_operation_len = elen;
+ break;
case WLAN_EID_EXT_OCV_OCI:
elems->oci = pos;
elems->oci_len = elen;
break;
+ case WLAN_EID_EXT_SHORT_SSID_LIST:
+ elems->short_ssid_list = pos;
+ elems->short_ssid_list_len = elen;
+ break;
default:
if (show_errors) {
wpa_printf(MSG_MSGDUMP,
@@ -287,10 +307,39 @@
return -1;
}
+ if (elen == 254)
+ elems->frag_ies.last_eid_ext = ext_id;
+
return 0;
}
+static void ieee802_11_parse_fragment(struct frag_ies_info *frag_ies,
+ const u8 *pos, u8 elen)
+{
+ if (frag_ies->n_frags >= MAX_NUM_FRAG_IES_SUPPORTED) {
+ wpa_printf(MSG_MSGDUMP, "Too many element fragments - skip");
+ return;
+ }
+
+ /*
+ * Note: while EID == 0 is a valid ID (SSID IE), it should not be
+ * fragmented.
+ */
+ if (!frag_ies->last_eid) {
+ wpa_printf(MSG_MSGDUMP,
+ "Fragment without a valid last element - skip");
+ return;
+ }
+
+ frag_ies->frags[frag_ies->n_frags].ie = pos;
+ frag_ies->frags[frag_ies->n_frags].ie_len = elen;
+ frag_ies->frags[frag_ies->n_frags].eid = frag_ies->last_eid;
+ frag_ies->frags[frag_ies->n_frags].eid_ext = frag_ies->last_eid_ext;
+ frag_ies->n_frags++;
+}
+
+
/**
* ieee802_11_parse_elems - Parse information elements in management frames
* @start: Pointer to the start of IEs
@@ -323,6 +372,11 @@
elen);
break;
}
+ if (elems->ssid) {
+ wpa_printf(MSG_MSGDUMP,
+ "Ignored duplicated SSID element");
+ break;
+ }
elems->ssid = pos;
elems->ssid_len = elen;
break;
@@ -361,6 +415,10 @@
elems->rsn_ie = pos;
elems->rsn_ie_len = elen;
break;
+ case WLAN_EID_RSNX:
+ elems->rsnxe = pos;
+ elems->rsnxe_len = elen;
+ break;
case WLAN_EID_PWR_CAPABILITY:
if (elen < 2)
break;
@@ -504,7 +562,7 @@
elems->dils_len = elen;
break;
case WLAN_EID_FRAGMENT:
- /* TODO */
+ ieee802_11_parse_fragment(&elems->frag_ies, pos, elen);
break;
case WLAN_EID_EXTENSION:
if (ieee802_11_parse_extension(pos, elen, elems,
@@ -520,6 +578,12 @@
id, elen);
break;
}
+
+ if (id != WLAN_EID_FRAGMENT && elen == 255)
+ elems->frag_ies.last_eid = id;
+
+ if (id == WLAN_EID_EXTENSION && !elems->frag_ies.last_eid_ext)
+ elems->frag_ies.last_eid = 0;
}
if (!for_each_element_completed(elem, start, len)) {
@@ -704,7 +768,7 @@
{
u8 op_class;
- return ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT,
+ return ieee80211_freq_to_channel_ext(freq, 0, CHANWIDTH_USE_HT,
&op_class, channel);
}
@@ -714,13 +778,14 @@
* for HT40 and VHT. DFS channels are not covered.
* @freq: Frequency (MHz) to convert
* @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below
- * @vht: VHT channel width (VHT_CHANWIDTH_*)
+ * @chanwidth: VHT/EDMG channel width (CHANWIDTH_*)
* @op_class: Buffer for returning operating class
* @channel: Buffer for returning channel number
* Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure
*/
enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
- int sec_channel, int vht,
+ int sec_channel,
+ int chanwidth,
u8 *op_class, u8 *channel)
{
u8 vht_opclass;
@@ -734,7 +799,7 @@
if ((freq - 2407) % 5)
return NUM_HOSTAPD_MODES;
- if (vht)
+ if (chanwidth)
return NUM_HOSTAPD_MODES;
/* 2.407 GHz, channels 1..13 */
@@ -751,7 +816,7 @@
}
if (freq == 2484) {
- if (sec_channel || vht)
+ if (sec_channel || chanwidth)
return NUM_HOSTAPD_MODES;
*op_class = 82; /* channel 14 */
@@ -768,14 +833,14 @@
return HOSTAPD_MODE_IEEE80211A;
}
- switch (vht) {
- case VHT_CHANWIDTH_80MHZ:
+ switch (chanwidth) {
+ case CHANWIDTH_80MHZ:
vht_opclass = 128;
break;
- case VHT_CHANWIDTH_160MHZ:
+ case CHANWIDTH_160MHZ:
vht_opclass = 129;
break;
- case VHT_CHANWIDTH_80P80MHZ:
+ case CHANWIDTH_80P80MHZ:
vht_opclass = 130;
break;
default:
@@ -869,13 +934,57 @@
return HOSTAPD_MODE_IEEE80211A;
}
- /* 56.16 GHz, channel 1..4 */
- if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
- if (sec_channel || vht)
+ if (freq > 5940 && freq <= 7105) {
+ int bw;
+ u8 idx = (freq - 5940) / 5;
+
+ bw = center_idx_to_bw_6ghz(idx);
+ if (bw < 0)
return NUM_HOSTAPD_MODES;
- *channel = (freq - 56160) / 2160;
- *op_class = 180;
+ *channel = idx;
+ *op_class = 131 + bw;
+ return HOSTAPD_MODE_IEEE80211A;
+ }
+
+ /* 56.16 GHz, channel 1..6 */
+ if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 6) {
+ if (sec_channel)
+ return NUM_HOSTAPD_MODES;
+
+ switch (chanwidth) {
+ case CHANWIDTH_USE_HT:
+ case CHANWIDTH_2160MHZ:
+ *channel = (freq - 56160) / 2160;
+ *op_class = 180;
+ break;
+ case CHANWIDTH_4320MHZ:
+ /* EDMG channels 9 - 13 */
+ if (freq > 56160 + 2160 * 5)
+ return NUM_HOSTAPD_MODES;
+
+ *channel = (freq - 56160) / 2160 + 8;
+ *op_class = 181;
+ break;
+ case CHANWIDTH_6480MHZ:
+ /* EDMG channels 17 - 20 */
+ if (freq > 56160 + 2160 * 4)
+ return NUM_HOSTAPD_MODES;
+
+ *channel = (freq - 56160) / 2160 + 16;
+ *op_class = 182;
+ break;
+ case CHANWIDTH_8640MHZ:
+ /* EDMG channels 25 - 27 */
+ if (freq > 56160 + 2160 * 3)
+ return NUM_HOSTAPD_MODES;
+
+ *channel = (freq - 56160) / 2160 + 24;
+ *op_class = 183;
+ break;
+ default:
+ return NUM_HOSTAPD_MODES;
+ }
return HOSTAPD_MODE_IEEE80211AD;
}
@@ -887,27 +996,39 @@
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;
+ int cw = 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;
+ cw = CHANWIDTH_USE_HT;
break;
case CHAN_WIDTH_80:
- vht = VHT_CHANWIDTH_80MHZ;
+ cw = CHANWIDTH_80MHZ;
break;
case CHAN_WIDTH_80P80:
- vht = VHT_CHANWIDTH_80P80MHZ;
+ cw = CHANWIDTH_80P80MHZ;
break;
case CHAN_WIDTH_160:
- vht = VHT_CHANWIDTH_160MHZ;
+ cw = CHANWIDTH_160MHZ;
+ break;
+ case CHAN_WIDTH_2160:
+ cw = CHANWIDTH_2160MHZ;
+ break;
+ case CHAN_WIDTH_4320:
+ cw = CHANWIDTH_4320MHZ;
+ break;
+ case CHAN_WIDTH_6480:
+ cw = CHANWIDTH_6480MHZ;
+ break;
+ case CHAN_WIDTH_8640:
+ cw = CHANWIDTH_8640MHZ;
break;
}
- if (ieee80211_freq_to_channel_ext(freq, sec_channel, vht, op_class,
+ if (ieee80211_freq_to_channel_ext(freq, sec_channel, cw, op_class,
channel) == NUM_HOSTAPD_MODES) {
wpa_printf(MSG_WARNING,
"Cannot determine operating class and channel (freq=%u chanwidth=%d sec_channel=%d)",
@@ -989,10 +1110,22 @@
if (chan < 149 || chan > 165)
return -1;
return 5000 + 5 * chan;
- case 34: /* 60 GHz band, channels 1..3 */
- if (chan < 1 || chan > 3)
+ case 34: /* 60 GHz band, channels 1..8 */
+ if (chan < 1 || chan > 8)
return -1;
return 56160 + 2160 * chan;
+ case 37: /* 60 GHz band, EDMG CB2, channels 9..15 */
+ if (chan < 9 || chan > 15)
+ return -1;
+ return 56160 + 2160 * (chan - 8);
+ case 38: /* 60 GHz band, EDMG CB3, channels 17..22 */
+ if (chan < 17 || chan > 22)
+ return -1;
+ return 56160 + 2160 * (chan - 16);
+ case 39: /* 60 GHz band, EDMG CB4, channels 25..29 */
+ if (chan < 25 || chan > 29)
+ return -1;
+ return 56160 + 2160 * (chan - 24);
}
return -1;
}
@@ -1027,10 +1160,22 @@
if (chan < 149 || chan > 169)
return -1;
return 5000 + 5 * chan;
- case 18: /* 60 GHz band, channels 1..4 */
- if (chan < 1 || chan > 4)
+ case 18: /* 60 GHz band, channels 1..6 */
+ if (chan < 1 || chan > 6)
return -1;
return 56160 + 2160 * chan;
+ case 21: /* 60 GHz band, EDMG CB2, channels 9..11 */
+ if (chan < 9 || chan > 11)
+ return -1;
+ return 56160 + 2160 * (chan - 8);
+ case 22: /* 60 GHz band, EDMG CB3, channels 17..18 */
+ if (chan < 17 || chan > 18)
+ return -1;
+ return 56160 + 2160 * (chan - 16);
+ case 23: /* 60 GHz band, EDMG CB4, channels 25 */
+ if (chan != 25)
+ return -1;
+ return 56160 + 2160 * (chan - 24);
}
return -1;
}
@@ -1071,10 +1216,22 @@
if (chan < 100 || chan > 140)
return -1;
return 5000 + 5 * chan;
- case 59: /* 60 GHz band, channels 1..4 */
- if (chan < 1 || chan > 3)
+ case 59: /* 60 GHz band, channels 1..6 */
+ if (chan < 1 || chan > 6)
return -1;
return 56160 + 2160 * chan;
+ case 62: /* 60 GHz band, EDMG CB2, channels 9..11 */
+ if (chan < 9 || chan > 11)
+ return -1;
+ return 56160 + 2160 * (chan - 8);
+ case 63: /* 60 GHz band, EDMG CB3, channels 17..18 */
+ if (chan < 17 || chan > 18)
+ return -1;
+ return 56160 + 2160 * (chan - 16);
+ case 64: /* 60 GHz band, EDMG CB4, channel 25 */
+ if (chan != 25)
+ return -1;
+ return 56160 + 2160 * (chan - 24);
}
return -1;
}
@@ -1159,10 +1316,30 @@
if (chan < 36 || chan > 128)
return -1;
return 5000 + 5 * chan;
- case 180: /* 60 GHz band, channels 1..4 */
- if (chan < 1 || chan > 4)
+ case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
+ case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */
+ case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
+ case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
+ case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
+ if (chan < 1 || chan > 233)
+ return -1;
+ return 5940 + chan * 5;
+ case 180: /* 60 GHz band, channels 1..8 */
+ if (chan < 1 || chan > 8)
return -1;
return 56160 + 2160 * chan;
+ case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
+ if (chan < 9 || chan > 15)
+ return -1;
+ return 56160 + 2160 * (chan - 8);
+ case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */
+ if (chan < 17 || chan > 22)
+ return -1;
+ return 56160 + 2160 * (chan - 16);
+ case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */
+ if (chan < 25 || chan > 29)
+ return -1;
+ return 56160 + 2160 * (chan - 24);
}
return -1;
}
@@ -1317,6 +1494,186 @@
}
+const char * reason2str(u16 reason)
+{
+#define R2S(r) case WLAN_REASON_ ## r: return #r;
+ switch (reason) {
+ R2S(UNSPECIFIED)
+ R2S(PREV_AUTH_NOT_VALID)
+ R2S(DEAUTH_LEAVING)
+ R2S(DISASSOC_DUE_TO_INACTIVITY)
+ R2S(DISASSOC_AP_BUSY)
+ R2S(CLASS2_FRAME_FROM_NONAUTH_STA)
+ R2S(CLASS3_FRAME_FROM_NONASSOC_STA)
+ R2S(DISASSOC_STA_HAS_LEFT)
+ R2S(STA_REQ_ASSOC_WITHOUT_AUTH)
+ R2S(PWR_CAPABILITY_NOT_VALID)
+ R2S(SUPPORTED_CHANNEL_NOT_VALID)
+ R2S(BSS_TRANSITION_DISASSOC)
+ R2S(INVALID_IE)
+ R2S(MICHAEL_MIC_FAILURE)
+ R2S(4WAY_HANDSHAKE_TIMEOUT)
+ R2S(GROUP_KEY_UPDATE_TIMEOUT)
+ R2S(IE_IN_4WAY_DIFFERS)
+ R2S(GROUP_CIPHER_NOT_VALID)
+ R2S(PAIRWISE_CIPHER_NOT_VALID)
+ R2S(AKMP_NOT_VALID)
+ R2S(UNSUPPORTED_RSN_IE_VERSION)
+ R2S(INVALID_RSN_IE_CAPAB)
+ R2S(IEEE_802_1X_AUTH_FAILED)
+ R2S(CIPHER_SUITE_REJECTED)
+ R2S(TDLS_TEARDOWN_UNREACHABLE)
+ R2S(TDLS_TEARDOWN_UNSPECIFIED)
+ R2S(SSP_REQUESTED_DISASSOC)
+ R2S(NO_SSP_ROAMING_AGREEMENT)
+ R2S(BAD_CIPHER_OR_AKM)
+ R2S(NOT_AUTHORIZED_THIS_LOCATION)
+ R2S(SERVICE_CHANGE_PRECLUDES_TS)
+ R2S(UNSPECIFIED_QOS_REASON)
+ R2S(NOT_ENOUGH_BANDWIDTH)
+ R2S(DISASSOC_LOW_ACK)
+ R2S(EXCEEDED_TXOP)
+ R2S(STA_LEAVING)
+ R2S(END_TS_BA_DLS)
+ R2S(UNKNOWN_TS_BA)
+ R2S(TIMEOUT)
+ R2S(PEERKEY_MISMATCH)
+ R2S(AUTHORIZED_ACCESS_LIMIT_REACHED)
+ R2S(EXTERNAL_SERVICE_REQUIREMENTS)
+ R2S(INVALID_FT_ACTION_FRAME_COUNT)
+ R2S(INVALID_PMKID)
+ R2S(INVALID_MDE)
+ R2S(INVALID_FTE)
+ R2S(MESH_PEERING_CANCELLED)
+ R2S(MESH_MAX_PEERS)
+ R2S(MESH_CONFIG_POLICY_VIOLATION)
+ R2S(MESH_CLOSE_RCVD)
+ R2S(MESH_MAX_RETRIES)
+ R2S(MESH_CONFIRM_TIMEOUT)
+ R2S(MESH_INVALID_GTK)
+ R2S(MESH_INCONSISTENT_PARAMS)
+ R2S(MESH_INVALID_SECURITY_CAP)
+ R2S(MESH_PATH_ERROR_NO_PROXY_INFO)
+ R2S(MESH_PATH_ERROR_NO_FORWARDING_INFO)
+ R2S(MESH_PATH_ERROR_DEST_UNREACHABLE)
+ R2S(MAC_ADDRESS_ALREADY_EXISTS_IN_MBSS)
+ R2S(MESH_CHANNEL_SWITCH_REGULATORY_REQ)
+ R2S(MESH_CHANNEL_SWITCH_UNSPECIFIED)
+ }
+ return "UNKNOWN";
+#undef R2S
+}
+
+
+const char * status2str(u16 status)
+{
+#define S2S(s) case WLAN_STATUS_ ## s: return #s;
+ switch (status) {
+ S2S(SUCCESS)
+ S2S(UNSPECIFIED_FAILURE)
+ S2S(TDLS_WAKEUP_ALTERNATE)
+ S2S(TDLS_WAKEUP_REJECT)
+ S2S(SECURITY_DISABLED)
+ S2S(UNACCEPTABLE_LIFETIME)
+ S2S(NOT_IN_SAME_BSS)
+ S2S(CAPS_UNSUPPORTED)
+ S2S(REASSOC_NO_ASSOC)
+ S2S(ASSOC_DENIED_UNSPEC)
+ S2S(NOT_SUPPORTED_AUTH_ALG)
+ S2S(UNKNOWN_AUTH_TRANSACTION)
+ S2S(CHALLENGE_FAIL)
+ S2S(AUTH_TIMEOUT)
+ S2S(AP_UNABLE_TO_HANDLE_NEW_STA)
+ S2S(ASSOC_DENIED_RATES)
+ S2S(ASSOC_DENIED_NOSHORT)
+ S2S(SPEC_MGMT_REQUIRED)
+ S2S(PWR_CAPABILITY_NOT_VALID)
+ S2S(SUPPORTED_CHANNEL_NOT_VALID)
+ S2S(ASSOC_DENIED_NO_SHORT_SLOT_TIME)
+ S2S(ASSOC_DENIED_NO_HT)
+ S2S(R0KH_UNREACHABLE)
+ S2S(ASSOC_DENIED_NO_PCO)
+ S2S(ASSOC_REJECTED_TEMPORARILY)
+ S2S(ROBUST_MGMT_FRAME_POLICY_VIOLATION)
+ S2S(UNSPECIFIED_QOS_FAILURE)
+ S2S(DENIED_INSUFFICIENT_BANDWIDTH)
+ S2S(DENIED_POOR_CHANNEL_CONDITIONS)
+ S2S(DENIED_QOS_NOT_SUPPORTED)
+ S2S(REQUEST_DECLINED)
+ S2S(INVALID_PARAMETERS)
+ S2S(REJECTED_WITH_SUGGESTED_CHANGES)
+ S2S(INVALID_IE)
+ S2S(GROUP_CIPHER_NOT_VALID)
+ S2S(PAIRWISE_CIPHER_NOT_VALID)
+ S2S(AKMP_NOT_VALID)
+ S2S(UNSUPPORTED_RSN_IE_VERSION)
+ S2S(INVALID_RSN_IE_CAPAB)
+ S2S(CIPHER_REJECTED_PER_POLICY)
+ S2S(TS_NOT_CREATED)
+ S2S(DIRECT_LINK_NOT_ALLOWED)
+ S2S(DEST_STA_NOT_PRESENT)
+ S2S(DEST_STA_NOT_QOS_STA)
+ S2S(ASSOC_DENIED_LISTEN_INT_TOO_LARGE)
+ S2S(INVALID_FT_ACTION_FRAME_COUNT)
+ S2S(INVALID_PMKID)
+ S2S(INVALID_MDIE)
+ S2S(INVALID_FTIE)
+ S2S(REQUESTED_TCLAS_NOT_SUPPORTED)
+ S2S(INSUFFICIENT_TCLAS_PROCESSING_RESOURCES)
+ S2S(TRY_ANOTHER_BSS)
+ S2S(GAS_ADV_PROTO_NOT_SUPPORTED)
+ S2S(NO_OUTSTANDING_GAS_REQ)
+ S2S(GAS_RESP_NOT_RECEIVED)
+ S2S(STA_TIMED_OUT_WAITING_FOR_GAS_RESP)
+ S2S(GAS_RESP_LARGER_THAN_LIMIT)
+ S2S(REQ_REFUSED_HOME)
+ S2S(ADV_SRV_UNREACHABLE)
+ S2S(REQ_REFUSED_SSPN)
+ S2S(REQ_REFUSED_UNAUTH_ACCESS)
+ S2S(INVALID_RSNIE)
+ S2S(U_APSD_COEX_NOT_SUPPORTED)
+ S2S(U_APSD_COEX_MODE_NOT_SUPPORTED)
+ S2S(BAD_INTERVAL_WITH_U_APSD_COEX)
+ S2S(ANTI_CLOGGING_TOKEN_REQ)
+ S2S(FINITE_CYCLIC_GROUP_NOT_SUPPORTED)
+ S2S(CANNOT_FIND_ALT_TBTT)
+ S2S(TRANSMISSION_FAILURE)
+ S2S(REQ_TCLAS_NOT_SUPPORTED)
+ S2S(TCLAS_RESOURCES_EXCHAUSTED)
+ S2S(REJECTED_WITH_SUGGESTED_BSS_TRANSITION)
+ S2S(REJECT_WITH_SCHEDULE)
+ S2S(REJECT_NO_WAKEUP_SPECIFIED)
+ S2S(SUCCESS_POWER_SAVE_MODE)
+ S2S(PENDING_ADMITTING_FST_SESSION)
+ S2S(PERFORMING_FST_NOW)
+ S2S(PENDING_GAP_IN_BA_WINDOW)
+ S2S(REJECT_U_PID_SETTING)
+ S2S(REFUSED_EXTERNAL_REASON)
+ S2S(REFUSED_AP_OUT_OF_MEMORY)
+ S2S(REJECTED_EMERGENCY_SERVICE_NOT_SUPPORTED)
+ S2S(QUERY_RESP_OUTSTANDING)
+ S2S(REJECT_DSE_BAND)
+ S2S(TCLAS_PROCESSING_TERMINATED)
+ S2S(TS_SCHEDULE_CONFLICT)
+ S2S(DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL)
+ S2S(MCCAOP_RESERVATION_CONFLICT)
+ S2S(MAF_LIMIT_EXCEEDED)
+ S2S(MCCA_TRACK_LIMIT_EXCEEDED)
+ S2S(DENIED_DUE_TO_SPECTRUM_MANAGEMENT)
+ S2S(ASSOC_DENIED_NO_VHT)
+ S2S(ENABLEMENT_DENIED)
+ S2S(RESTRICTION_FROM_AUTHORIZED_GDB)
+ S2S(AUTHORIZATION_DEENABLED)
+ S2S(FILS_AUTHENTICATION_FAILURE)
+ S2S(UNKNOWN_AUTHENTICATION_SERVER)
+ S2S(UNKNOWN_PASSWORD_IDENTIFIER)
+ S2S(SAE_HASH_TO_ELEMENT)
+ }
+ return "UNKNOWN";
+#undef S2S
+}
+
+
int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
size_t ies_len)
{
@@ -1409,7 +1766,17 @@
{ HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 130, 36, 161, 4, BW80P80, P2P_SUPP },
- { HOSTAPD_MODE_IEEE80211AD, 180, 1, 4, 1, BW2160, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, P2P_SUPP },
+
+ /*
+ * IEEE Std 802.11ad-2012 and P802.ay/D5.0 60 GHz operating classes.
+ * Class 180 has the legacy channels 1-6. Classes 181-183 include
+ * channels which implement channel bonding features.
+ */
+ { HOSTAPD_MODE_IEEE80211AD, 180, 1, 6, 1, BW2160, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211AD, 181, 9, 13, 1, BW4320, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211AD, 182, 17, 20, 1, BW6480, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211AD, 183, 25, 27, 1, BW8640, P2P_SUPP },
{ -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP }
};
@@ -1723,6 +2090,63 @@
}
+int center_idx_to_bw_6ghz(u8 idx)
+{
+ /* channels: 1, 5, 9, 13... */
+ if ((idx & 0x3) == 0x1)
+ return 0; /* 20 MHz */
+ /* channels 3, 11, 19... */
+ if ((idx & 0x7) == 0x3)
+ return 1; /* 40 MHz */
+ /* channels 7, 23, 39.. */
+ if ((idx & 0xf) == 0x7)
+ return 2; /* 80 MHz */
+ /* channels 15, 47, 79...*/
+ if ((idx & 0x1f) == 0xf)
+ return 3; /* 160 MHz */
+
+ return -1;
+}
+
+
+int is_6ghz_freq(int freq)
+{
+ if (freq < 5940 || freq > 7105)
+ return 0;
+
+ if (center_idx_to_bw_6ghz((freq - 5940) / 5) < 0)
+ return 0;
+
+ return 1;
+}
+
+
+int is_6ghz_op_class(u8 op_class)
+{
+ return op_class >= 131 && op_class <= 135;
+}
+
+
+int is_6ghz_psc_frequency(int freq)
+{
+ int i;
+
+ if (!is_6ghz_freq(freq))
+ return 0;
+ if ((((freq - 5940) / 5) & 0x3) != 0x1)
+ return 0;
+
+ i = (freq - 5940 + 55) % 80;
+ if (i == 0)
+ i = (freq - 5940 + 55) / 80;
+
+ if (i >= 1 && i <= 15)
+ return 1;
+
+ return 0;
+}
+
+
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
size_t nei_rep_len)
{
@@ -1831,3 +2255,537 @@
return 0;
return !!(ie[2 + capab / 8] & BIT(capab % 8));
}
+
+
+void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel,
+ int primary_channel,
+ struct ieee80211_edmg_config *edmg)
+{
+ if (!edmg_enable) {
+ edmg->channels = 0;
+ edmg->bw_config = 0;
+ return;
+ }
+
+ /* Only EDMG CB1 and EDMG CB2 contiguous channels supported for now */
+ switch (edmg_channel) {
+ case EDMG_CHANNEL_9:
+ edmg->channels = EDMG_CHANNEL_9_SUBCHANNELS;
+ edmg->bw_config = EDMG_BW_CONFIG_5;
+ return;
+ case EDMG_CHANNEL_10:
+ edmg->channels = EDMG_CHANNEL_10_SUBCHANNELS;
+ edmg->bw_config = EDMG_BW_CONFIG_5;
+ return;
+ case EDMG_CHANNEL_11:
+ edmg->channels = EDMG_CHANNEL_11_SUBCHANNELS;
+ edmg->bw_config = EDMG_BW_CONFIG_5;
+ return;
+ case EDMG_CHANNEL_12:
+ edmg->channels = EDMG_CHANNEL_12_SUBCHANNELS;
+ edmg->bw_config = EDMG_BW_CONFIG_5;
+ return;
+ case EDMG_CHANNEL_13:
+ edmg->channels = EDMG_CHANNEL_13_SUBCHANNELS;
+ edmg->bw_config = EDMG_BW_CONFIG_5;
+ return;
+ default:
+ if (primary_channel > 0 && primary_channel < 7) {
+ edmg->channels = BIT(primary_channel - 1);
+ edmg->bw_config = EDMG_BW_CONFIG_4;
+ } else {
+ edmg->channels = 0;
+ edmg->bw_config = 0;
+ }
+ break;
+ }
+}
+
+
+/* Check if the requested EDMG configuration is a subset of the allowed
+ * EDMG configuration. */
+int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,
+ struct ieee80211_edmg_config requested)
+{
+ /*
+ * The validation check if the requested EDMG configuration
+ * is a subset of the allowed EDMG configuration:
+ * 1. Check that the requested channels are part (set) of the allowed
+ * channels.
+ * 2. P802.11ay defines the values of bw_config between 4 and 15.
+ * (bw config % 4) will give us 4 groups inside bw_config definition,
+ * inside each group we can check the subset just by comparing the
+ * bw_config value.
+ * Between this 4 groups, there is no subset relation - as a result of
+ * the P802.11ay definition.
+ * bw_config defined by IEEE P802.11ay/D4.0, 9.4.2.251, Table 13.
+ */
+ if (((requested.channels & allowed.channels) != requested.channels) ||
+ ((requested.bw_config % 4) > (allowed.bw_config % 4)) ||
+ requested.bw_config > allowed.bw_config)
+ return 0;
+
+ return 1;
+}
+
+
+int op_class_to_bandwidth(u8 op_class)
+{
+ switch (op_class) {
+ case 81:
+ case 82:
+ return 20;
+ case 83: /* channels 1..9; 40 MHz */
+ case 84: /* channels 5..13; 40 MHz */
+ return 40;
+ case 115: /* channels 36,40,44,48; indoor only */
+ return 20;
+ case 116: /* channels 36,44; 40 MHz; indoor only */
+ case 117: /* channels 40,48; 40 MHz; indoor only */
+ return 40;
+ case 118: /* channels 52,56,60,64; dfs */
+ return 20;
+ case 119: /* channels 52,60; 40 MHz; dfs */
+ case 120: /* channels 56,64; 40 MHz; dfs */
+ return 40;
+ case 121: /* channels 100-140 */
+ return 20;
+ case 122: /* channels 100-142; 40 MHz */
+ case 123: /* channels 104-136; 40 MHz */
+ return 40;
+ case 124: /* channels 149,153,157,161 */
+ case 125: /* channels 149,153,157,161,165,169 */
+ return 20;
+ case 126: /* channels 149,157; 40 MHz */
+ case 127: /* channels 153,161; 40 MHz */
+ return 40;
+ case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
+ return 80;
+ case 129: /* center freqs 50, 114; 160 MHz */
+ return 160;
+ case 130: /* center freqs 42, 58, 106, 122, 138, 155; 80+80 MHz */
+ return 80;
+ case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
+ return 20;
+ case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */
+ return 40;
+ case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
+ return 80;
+ case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
+ case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
+ return 160;
+ case 180: /* 60 GHz band, channels 1..8 */
+ return 2160;
+ case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
+ return 4320;
+ case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */
+ return 6480;
+ case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */
+ return 8640;
+ }
+
+ return 20;
+}
+
+
+int op_class_to_ch_width(u8 op_class)
+{
+ switch (op_class) {
+ case 81:
+ case 82:
+ return CHANWIDTH_USE_HT;
+ case 83: /* channels 1..9; 40 MHz */
+ case 84: /* channels 5..13; 40 MHz */
+ return CHANWIDTH_USE_HT;
+ case 115: /* channels 36,40,44,48; indoor only */
+ return CHANWIDTH_USE_HT;
+ case 116: /* channels 36,44; 40 MHz; indoor only */
+ case 117: /* channels 40,48; 40 MHz; indoor only */
+ return CHANWIDTH_USE_HT;
+ case 118: /* channels 52,56,60,64; dfs */
+ return CHANWIDTH_USE_HT;
+ case 119: /* channels 52,60; 40 MHz; dfs */
+ case 120: /* channels 56,64; 40 MHz; dfs */
+ return CHANWIDTH_USE_HT;
+ case 121: /* channels 100-140 */
+ return CHANWIDTH_USE_HT;
+ case 122: /* channels 100-142; 40 MHz */
+ case 123: /* channels 104-136; 40 MHz */
+ return CHANWIDTH_USE_HT;
+ case 124: /* channels 149,153,157,161 */
+ case 125: /* channels 149,153,157,161,165,169 */
+ return CHANWIDTH_USE_HT;
+ case 126: /* channels 149,157; 40 MHz */
+ case 127: /* channels 153,161; 40 MHz */
+ return CHANWIDTH_USE_HT;
+ case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
+ return CHANWIDTH_80MHZ;
+ case 129: /* center freqs 50, 114; 160 MHz */
+ return CHANWIDTH_160MHZ;
+ case 130: /* center freqs 42, 58, 106, 122, 138, 155; 80+80 MHz */
+ return CHANWIDTH_80P80MHZ;
+ case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
+ return CHANWIDTH_USE_HT;
+ case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */
+ return CHANWIDTH_USE_HT;
+ case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
+ return CHANWIDTH_80MHZ;
+ case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
+ return CHANWIDTH_160MHZ;
+ case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
+ return CHANWIDTH_80P80MHZ;
+ case 180: /* 60 GHz band, channels 1..8 */
+ return CHANWIDTH_2160MHZ;
+ case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
+ return CHANWIDTH_4320MHZ;
+ case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */
+ return CHANWIDTH_6480MHZ;
+ case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */
+ return CHANWIDTH_8640MHZ;
+ }
+ return CHANWIDTH_USE_HT;
+}
+
+struct wpabuf * ieee802_11_defrag_data(struct ieee802_11_elems *elems,
+ u8 eid, u8 eid_ext,
+ const u8 *data, u8 len)
+{
+ struct frag_ies_info *frag_ies = &elems->frag_ies;
+ struct wpabuf *buf;
+ unsigned int i;
+
+ if (!elems || !data || !len)
+ return NULL;
+
+ buf = wpabuf_alloc_copy(data, len);
+ if (!buf)
+ return NULL;
+
+ for (i = 0; i < frag_ies->n_frags; i++) {
+ int ret;
+
+ if (frag_ies->frags[i].eid != eid ||
+ frag_ies->frags[i].eid_ext != eid_ext)
+ continue;
+
+ ret = wpabuf_resize(&buf, frag_ies->frags[i].ie_len);
+ if (ret < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ /* Copy only the fragment data (without the EID and length) */
+ wpabuf_put_data(buf, frag_ies->frags[i].ie,
+ frag_ies->frags[i].ie_len);
+ }
+
+ return buf;
+}
+
+
+struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems,
+ u8 eid, u8 eid_ext)
+{
+ const u8 *data;
+ u8 len;
+
+ /*
+ * TODO: Defragmentation mechanism can be supported for all IEs. For now
+ * handle only those that are used (or use ieee802_11_defrag_data()).
+ */
+ switch (eid) {
+ case WLAN_EID_EXTENSION:
+ switch (eid_ext) {
+ case WLAN_EID_EXT_FILS_HLP_CONTAINER:
+ data = elems->fils_hlp;
+ len = elems->fils_hlp_len;
+ break;
+ case WLAN_EID_EXT_WRAPPED_DATA:
+ data = elems->wrapped_data;
+ len = elems->wrapped_data_len;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "Defragmentation not supported. eid_ext=%u",
+ eid_ext);
+ return NULL;
+ }
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "Defragmentation not supported. eid=%u", eid);
+ return NULL;
+ }
+
+ return ieee802_11_defrag_data(elems, eid, eid_ext, data, len);
+}
+
+/* Parse HT capabilities to get maximum number of supported spatial streams */
+static int parse_ht_mcs_set_for_max_nss(
+ struct ieee80211_ht_capabilities *htcaps,
+ u8 parse_for_rx)
+{
+ int max_nss_rx = 1;
+ if (htcaps == NULL)
+ return max_nss_rx;
+ int i;
+ for (i = 4; i >= 1; i--) {
+ if (htcaps->supported_mcs_set[i - 1] > 0) {
+ max_nss_rx = i;
+ break;
+ }
+ }
+ if (parse_for_rx)
+ return max_nss_rx;
+ u8 supported_tx_mcs_set = htcaps->supported_mcs_set[12];
+ u8 tx_mcs_set_defined = supported_tx_mcs_set & 0x1;
+ u8 tx_rx_mcs_set_not_equal = (supported_tx_mcs_set >> 1) & 0x1;
+ if (tx_mcs_set_defined && tx_rx_mcs_set_not_equal) {
+ int max_nss_tx_field_value = (supported_tx_mcs_set >> 2) & 0x3;
+ // The maximum number of Tx streams is 1 more than the field value.
+ return max_nss_tx_field_value + 1;
+ }
+ return max_nss_rx;
+}
+
+
+/* Parse MCS map to get maximum number of supported spatial streams */
+static int parse_mcs_map_for_max_nss (u16 mcs_map, int max_streams_allowed)
+{
+ int max_nss = 1;
+ int i;
+ for (i = max_streams_allowed; i >= 1; i--) {
+ int stream_map = (mcs_map >> ((i - 1) * 2)) & 0x3;
+ // 3 means unsupported
+ if (stream_map != 3) {
+ max_nss = i;
+ break;
+ }
+ }
+ return max_nss;
+}
+
+
+/* Parse capabilities IEs to get maximum number of supported spatial streams */
+int get_max_nss_capability(struct ieee802_11_elems *elems, int parse_for_rx)
+{
+ int max_nss = 1;
+ struct ieee80211_ht_capabilities *htcaps =
+ (struct ieee80211_ht_capabilities *) elems->ht_capabilities;
+ struct ieee80211_vht_capabilities *vhtcaps =
+ (struct ieee80211_vht_capabilities *) elems->vht_capabilities;
+ struct ieee80211_he_capabilities *hecaps =
+ (struct ieee80211_he_capabilities *) elems->he_capabilities;
+ if (htcaps) {
+ int max_nss_ht = parse_ht_mcs_set_for_max_nss(htcaps, parse_for_rx);
+ if (max_nss_ht > max_nss)
+ max_nss = max_nss_ht;
+ }
+ le16 mcs_map;
+ if (vhtcaps) {
+ mcs_map = (parse_for_rx) ? vhtcaps->vht_supported_mcs_set.rx_map :
+ vhtcaps->vht_supported_mcs_set.tx_map;
+ int max_nss_vht = parse_mcs_map_for_max_nss(
+ le_to_host16(mcs_map), VHT_RX_NSS_MAX_STREAMS);
+ if (max_nss_vht > max_nss)
+ max_nss = max_nss_vht;
+ }
+ if (hecaps) {
+ mcs_map = (parse_for_rx) ? hecaps->he_basic_supported_mcs_set.rx_map :
+ hecaps->he_basic_supported_mcs_set.tx_map;
+ int max_nss_he = parse_mcs_map_for_max_nss(
+ le_to_host16(mcs_map), HE_NSS_MAX_STREAMS);
+ if (max_nss_he > max_nss)
+ max_nss = max_nss_he;
+ }
+ return max_nss;
+}
+
+
+/* Parse VHT/HE capabilities IEs to get supported channel width */
+struct supported_chan_width get_supported_channel_width(
+ struct ieee802_11_elems *elems)
+{
+ struct supported_chan_width supported_width;
+ supported_width.is_160_supported = 0;
+ supported_width.is_80p80_supported = 0;
+ if (elems == NULL)
+ return supported_width;
+
+ struct ieee80211_vht_capabilities *vhtcaps =
+ (struct ieee80211_vht_capabilities *) elems->vht_capabilities;
+ struct ieee80211_he_capabilities *hecaps =
+ (struct ieee80211_he_capabilities *) elems->he_capabilities;
+
+ if (vhtcaps) {
+ le32 vht_capabilities_info =
+ le_to_host32(vhtcaps->vht_capabilities_info);
+ if (vht_capabilities_info & VHT_CAP_SUPP_CHAN_WIDTH_160MHZ)
+ supported_width.is_160_supported = 1;
+ if (vht_capabilities_info & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
+ supported_width.is_80p80_supported = 1;
+ }
+ if (hecaps) {
+ u8 channel_width_set =
+ hecaps->he_phy_capab_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX];
+ if (channel_width_set & HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
+ supported_width.is_160_supported = 1;
+ if (channel_width_set & HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)
+ supported_width.is_80p80_supported = 1;
+ }
+ wpa_printf(MSG_DEBUG, " IE indicate 160 supported: %u, 80+80 supported: %u",
+ supported_width.is_160_supported, supported_width.is_80p80_supported);
+ return supported_width;
+}
+
+/*
+ * Parse VHT operation info fields to get operation channel width
+ * note that VHT operation info fields could come from VHT operation IE
+ * or from HE operation IE
+ */
+static enum chan_width get_vht_operation_channel_width(
+ struct ieee80211_vht_operation_info *vht_oper_info)
+{
+ enum chan_width channel_width = CHAN_WIDTH_UNKNOWN;
+ u8 seg0, seg1;
+ switch (vht_oper_info->vht_op_info_chwidth) {
+ case 1:
+ seg0 = vht_oper_info->vht_op_info_chan_center_freq_seg0_idx;
+ seg1 = vht_oper_info->vht_op_info_chan_center_freq_seg1_idx;
+ if (seg1 && abs(seg1 - seg0) == 8)
+ channel_width = CHAN_WIDTH_160;
+ else if (seg1)
+ channel_width = CHAN_WIDTH_80P80;
+ else
+ channel_width = CHAN_WIDTH_80;
+ break;
+ case 2:
+ channel_width = CHAN_WIDTH_160;
+ break;
+ case 3:
+ channel_width = CHAN_WIDTH_80P80;
+ break;
+ default:
+ break;
+ }
+ wpa_printf(MSG_DEBUG, " VHT operation CBW: %u", channel_width);
+ return channel_width;
+}
+
+/* Parse 6GHz operation info fields to get operation channel width */
+static enum chan_width get_6ghz_operation_channel_width(
+ struct ieee80211_6ghz_operation_info * six_ghz_oper_info)
+{
+ enum chan_width channel_width = CHAN_WIDTH_UNKNOWN;
+ u8 seg0, seg1;
+ switch (six_ghz_oper_info->control & SIX_GHZ_CONTROL_CHANNEL_WIDTH_MASK) {
+ case 0:
+ channel_width = CHAN_WIDTH_20;
+ break;
+ case 1:
+ channel_width = CHAN_WIDTH_40;
+ break;
+ case 2:
+ channel_width = CHAN_WIDTH_80;
+ break;
+ case 3:
+ seg0 = six_ghz_oper_info->chan_center_freq_seg0_idx;
+ seg1 = six_ghz_oper_info->chan_center_freq_seg1_idx;
+ if (abs(seg1 - seg0) == 8)
+ channel_width = CHAN_WIDTH_160;
+ else
+ channel_width = CHAN_WIDTH_80P80;
+ break;
+ default:
+ break;
+ }
+ wpa_printf(MSG_DEBUG, " 6GHz operation CBW: %u", channel_width);
+ return channel_width;
+}
+
+
+/* Parse HE operation IE to get HE operation channel width */
+static enum chan_width get_he_operation_channel_width(
+ struct ieee80211_he_operation *he_oper,
+ int he_oper_len)
+{
+ enum chan_width channel_width = CHAN_WIDTH_UNKNOWN;
+ u8 is_6ghz_info_present =
+ (he_oper->he_oper_params & HE_OPERATION_6GHZ_OPER_INFO) ? 1 : 0;
+ u8 is_vht_info_present =
+ (he_oper->he_oper_params & HE_OPERATION_VHT_OPER_INFO) ? 1 : 0;
+ u8 is_cohosted_bss_present =
+ (he_oper->he_oper_params & HE_OPERATION_COHOSTED_BSS) ? 1 : 0;
+ int expected_len = HE_OPERATION_IE_MIN_LEN
+ + (is_6ghz_info_present ? HE_OPERATION_6GHZ_OPER_INFO_LEN : 0)
+ + (is_vht_info_present ? HE_OPERATION_VHT_OPER_INFO_LEN : 0)
+ + (is_cohosted_bss_present
+ ? HE_OPERATION_COHOSTED_BSSID_INDICATOR_LEN : 0);
+ if (he_oper_len < expected_len)
+ return channel_width;
+
+ const u8 *he_oper_u8 = (const u8 *) he_oper;
+ if (is_6ghz_info_present) {
+ struct ieee80211_6ghz_operation_info *six_ghz_oper_info =
+ (struct ieee80211_6ghz_operation_info *)
+ (he_oper_u8 + HE_OPERATION_IE_MIN_LEN
+ + (is_vht_info_present ? HE_OPERATION_VHT_OPER_INFO_LEN : 0)
+ + (is_cohosted_bss_present
+ ? HE_OPERATION_COHOSTED_BSSID_INDICATOR_LEN : 0));
+ channel_width = get_6ghz_operation_channel_width(six_ghz_oper_info);
+ }
+ if (channel_width == CHAN_WIDTH_UNKNOWN && is_vht_info_present) {
+ struct ieee80211_vht_operation_info *vht_oper_info =
+ (struct ieee80211_vht_operation_info *)
+ (he_oper_u8 + HE_OPERATION_IE_MIN_LEN);
+ channel_width = get_vht_operation_channel_width(vht_oper_info);
+ }
+ wpa_printf(MSG_DEBUG, " HE operation CBW: %u", channel_width);
+ return channel_width;
+}
+
+/* Parse HT/VHT/HE operation IEs to get operation channel width */
+enum chan_width get_operation_channel_width(struct ieee802_11_elems *elems)
+{
+ enum chan_width channel_width = CHAN_WIDTH_UNKNOWN;
+ if (elems == NULL)
+ return channel_width;
+
+ struct ieee80211_ht_operation *ht_oper =
+ (struct ieee80211_ht_operation *) elems->ht_operation;
+ struct ieee80211_vht_operation_info *vht_oper_info =
+ (struct ieee80211_vht_operation_info *) elems->vht_operation;
+ struct ieee80211_he_operation *he_oper =
+ (struct ieee80211_he_operation *) elems->he_operation;
+ if (he_oper)
+ channel_width = get_he_operation_channel_width(
+ he_oper, elems->he_operation_len);
+
+ if (channel_width == CHAN_WIDTH_UNKNOWN && vht_oper_info)
+ channel_width = get_vht_operation_channel_width(vht_oper_info);
+
+ if (channel_width == CHAN_WIDTH_UNKNOWN && ht_oper) {
+ u8 sec_chan_offset =
+ ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
+ channel_width = (sec_chan_offset == 0) ? CHAN_WIDTH_20 : CHAN_WIDTH_40;
+ }
+ wpa_printf(MSG_DEBUG, " overall operation CBW: %u", channel_width);
+ return channel_width;
+}
+
+/*
+ * Get STA operation channel width from AP's operation channel width and
+ * STA's supported channel width
+ */
+enum chan_width get_sta_operation_chan_width(
+ enum chan_width ap_operation_chan_width,
+ struct supported_chan_width sta_supported_chan_width)
+{
+ if (ap_operation_chan_width == CHAN_WIDTH_160)
+ return (sta_supported_chan_width.is_160_supported)
+ ? CHAN_WIDTH_160 : CHAN_WIDTH_80;
+ if (ap_operation_chan_width == CHAN_WIDTH_80P80)
+ return (sta_supported_chan_width.is_80p80_supported)
+ ? CHAN_WIDTH_80P80 : CHAN_WIDTH_80;
+ return ap_operation_chan_width;
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index d41bd39..e395769 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -21,6 +21,7 @@
struct hostapd_hw_modes;
#define MAX_NOF_MB_IES_SUPPORTED 5
+#define MAX_NUM_FRAG_IES_SUPPORTED 3
struct mb_ies_info {
struct {
@@ -30,6 +31,21 @@
u8 nof_ies;
};
+struct frag_ies_info {
+ struct {
+ u8 eid;
+ u8 eid_ext;
+ const u8 *ie;
+ u8 ie_len;
+ } frags[MAX_NUM_FRAG_IES_SUPPORTED];
+
+ u8 n_frags;
+
+ /* the last parsed element ID and element extension ID */
+ u8 last_eid;
+ u8 last_eid_ext;
+};
+
/* Parsed Information Elements */
struct ieee802_11_elems {
const u8 *ssid;
@@ -40,6 +56,7 @@
const u8 *ext_supp_rates;
const u8 *wpa_ie;
const u8 *rsn_ie;
+ const u8 *rsnxe;
const u8 *wmm; /* WMM Information or Parameter Element */
const u8 *wmm_tspec;
const u8 *wps_ie;
@@ -84,7 +101,7 @@
const u8 *fils_hlp;
const u8 *fils_ip_addr_assign;
const u8 *key_delivery;
- const u8 *fils_wrapped_data;
+ const u8 *wrapped_data;
const u8 *fils_pk;
const u8 *fils_nonce;
const u8 *owe_dh;
@@ -94,6 +111,8 @@
const u8 *oci;
const u8 *multi_ap;
const u8 *he_capabilities;
+ const u8 *he_operation;
+ const u8 *short_ssid_list;
u8 ssid_len;
u8 supp_rates_len;
@@ -101,6 +120,7 @@
u8 ext_supp_rates_len;
u8 wpa_ie_len;
u8 rsn_ie_len;
+ u8 rsnxe_len;
u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */
u8 wmm_tspec_len;
u8 wps_ie_len;
@@ -134,7 +154,7 @@
u8 fils_hlp_len;
u8 fils_ip_addr_assign_len;
u8 key_delivery_len;
- u8 fils_wrapped_data_len;
+ u8 wrapped_data_len;
u8 fils_pk_len;
u8 owe_dh_len;
u8 power_capab_len;
@@ -143,8 +163,11 @@
u8 oci_len;
u8 multi_ap_len;
u8 he_capabilities_len;
+ u8 he_operation_len;
+ u8 short_ssid_list_len;
struct mb_ies_info mb_ies;
+ struct frag_ies_info frag_ies;
};
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
@@ -185,6 +208,8 @@
struct wpabuf * mb_ies_by_info(struct mb_ies_info *info);
const char * fc2str(u16 fc);
+const char * reason2str(u16 reason);
+const char * status2str(u16 status);
struct oper_class_map {
enum hostapd_hw_mode mode;
@@ -192,7 +217,8 @@
u8 min_chan;
u8 max_chan;
u8 inc;
- enum { BW20, BW40PLUS, BW40MINUS, BW80, BW2160, BW160, BW80P80 } bw;
+ enum { BW20, BW40PLUS, BW40MINUS, BW80, BW2160, BW160, BW80P80, BW4320,
+ BW6480, BW8640} bw;
enum { P2P_SUPP, NO_P2P_SUPP } p2p;
};
@@ -216,11 +242,17 @@
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 center_idx_to_bw_6ghz(u8 idx);
+int is_6ghz_freq(int freq);
+int is_6ghz_op_class(u8 op_class);
+int is_6ghz_psc_frequency(int freq);
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);
+int op_class_to_bandwidth(u8 op_class);
+int op_class_to_ch_width(u8 op_class);
/* element iteration helpers */
#define for_each_element(_elem, _data, _datalen) \
@@ -269,4 +301,33 @@
return (const u8 *) element == (const u8 *) data + datalen;
}
+struct ieee80211_edmg_config;
+
+void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel,
+ int primary_channel,
+ struct ieee80211_edmg_config *edmg);
+
+int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,
+ struct ieee80211_edmg_config requested);
+
+struct wpabuf * ieee802_11_defrag_data(struct ieee802_11_elems *elems,
+ u8 eid, u8 eid_ext,
+ const u8 *data, u8 len);
+struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems,
+ u8 eid, u8 eid_ext);
+
+int get_max_nss_capability(struct ieee802_11_elems *elems, int parse_for_rx);
+
+struct supported_chan_width {
+ u8 is_160_supported;
+ u8 is_80p80_supported;
+};
+
+struct supported_chan_width get_supported_channel_width(struct ieee802_11_elems *elems);
+
+enum chan_width get_operation_channel_width(struct ieee802_11_elems *elems);
+
+enum chan_width get_sta_operation_chan_width(enum chan_width ap_operation_chan_width,
+ struct supported_chan_width sta_supported_width);
+
#endif /* IEEE802_11_COMMON_H */
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index adaa893..4a5eb16 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -204,6 +204,7 @@
#define WLAN_STATUS_FILS_AUTHENTICATION_FAILURE 112
#define WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER 113
#define WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER 123
+#define WLAN_STATUS_SAE_HASH_TO_ELEMENT 126
/* Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45) */
#define WLAN_REASON_UNSPECIFIED 1
@@ -446,6 +447,7 @@
#define WLAN_EID_FILS_INDICATION 240
#define WLAN_EID_DILS 241
#define WLAN_EID_FRAGMENT 242
+#define WLAN_EID_RSNX 244
#define WLAN_EID_EXTENSION 255
/* Element ID Extension (EID 255) values */
@@ -456,7 +458,7 @@
#define WLAN_EID_EXT_FILS_HLP_CONTAINER 5
#define WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN 6
#define WLAN_EID_EXT_KEY_DELIVERY 7
-#define WLAN_EID_EXT_FILS_WRAPPED_DATA 8
+#define WLAN_EID_EXT_WRAPPED_DATA 8
#define WLAN_EID_EXT_FTM_SYNC_INFO 9
#define WLAN_EID_EXT_EXTENDED_REQUEST 10
#define WLAN_EID_EXT_ESTIMATED_SERVICE_PARAMS 11
@@ -468,7 +470,13 @@
#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_SPATIAL_REUSE 39
#define WLAN_EID_EXT_OCV_OCI 54
+#define WLAN_EID_EXT_SHORT_SSID_LIST 58
+#define WLAN_EID_EXT_EDMG_CAPABILITIES 61
+#define WLAN_EID_EXT_EDMG_OPERATION 62
+#define WLAN_EID_EXT_REJECTED_GROUPS 92
+#define WLAN_EID_EXT_ANTI_CLOGGING_TOKEN 93
/* Extended Capabilities field */
#define WLAN_EXT_CAPAB_20_40_COEX 0
@@ -550,6 +558,12 @@
#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
+#define WLAN_EXT_CAPAB_BEACON_PROTECTION 84
+
+/* Extended RSN Capabilities */
+/* bits 0-3: Field length (n-1) */
+#define WLAN_RSNX_CAPAB_PROTECTED_TWT 4
+#define WLAN_RSNX_CAPAB_SAE_H2E 5
/* Action frame categories (IEEE Std 802.11-2016, 9.4.1.11, Table 9-76) */
#define WLAN_ACTION_SPECTRUM_MGMT 0
@@ -1091,6 +1105,12 @@
le16 vht_basic_mcs_set;
} STRUCT_PACKED;
+struct ieee80211_vht_operation_info {
+ u8 vht_op_info_chwidth;
+ u8 vht_op_info_chan_center_freq_seg0_idx;
+ u8 vht_op_info_chan_center_freq_seg1_idx;
+} STRUCT_PACKED;
+
struct ieee80211_ampe_ie {
u8 selected_pairwise_suite[4];
u8 local_nonce[32];
@@ -1216,6 +1236,7 @@
#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
+#define BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY 123
/* VHT Defines */
#define VHT_CAP_MAX_MPDU_LENGTH_7991 ((u32) BIT(0))
@@ -1273,11 +1294,17 @@
#define VHT_RX_NSS_MAX_STREAMS 8
-/* VHT channel widths */
-#define VHT_CHANWIDTH_USE_HT 0
-#define VHT_CHANWIDTH_80MHZ 1
-#define VHT_CHANWIDTH_160MHZ 2
-#define VHT_CHANWIDTH_80P80MHZ 3
+/* VHT/EDMG channel widths */
+#define CHANWIDTH_USE_HT 0
+#define CHANWIDTH_80MHZ 1
+#define CHANWIDTH_160MHZ 2
+#define CHANWIDTH_80P80MHZ 3
+#define CHANWIDTH_2160MHZ 4
+#define CHANWIDTH_4320MHZ 5
+#define CHANWIDTH_6480MHZ 6
+#define CHANWIDTH_8640MHZ 7
+
+#define HE_NSS_MAX_STREAMS 8
#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
* 00:50:F2 */
@@ -1295,6 +1322,8 @@
#define OWE_IE_VENDOR_TYPE 0x506f9a1c
#define OWE_OUI_TYPE 28
#define MULTI_AP_OUI_TYPE 0x1B
+#define DPP_CC_IE_VENDOR_TYPE 0x506f9a1e
+#define DPP_CC_OUI_TYPE 0x1e
#define MULTI_AP_SUB_ELEM_TYPE 0x06
#define MULTI_AP_TEAR_DOWN BIT(4)
@@ -1854,7 +1883,15 @@
/* WNM-Sleep Mode subelement IDs */
enum wnm_sleep_mode_subelement_id {
WNM_SLEEP_SUBELEM_GTK = 0,
- WNM_SLEEP_SUBELEM_IGTK = 1
+ WNM_SLEEP_SUBELEM_IGTK = 1,
+ WNM_SLEEP_SUBELEM_BIGTK = 2,
+};
+
+/* WNM notification type (IEEE P802.11-REVmd/D3.0, Table 9-430) */
+enum wnm_notification_Type {
+ WNM_NOTIF_TYPE_FIRMWARE_UPDATE = 0,
+ WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE = 2,
+ WNM_NOTIF_TYPE_VENDOR_SPECIFIC = 221,
};
/* Channel Switch modes (802.11h) */
@@ -2070,7 +2107,7 @@
PHY_TYPE_VHT = 9,
};
-/* IEEE P802.11-REVmc/D5.0, 9.4.2.37 - Neighbor Report element */
+/* IEEE P802.11-REVmd/D3.0, 9.4.2.36 - Neighbor Report element */
/* BSSID Information Field */
#define NEI_REP_BSSID_INFO_AP_NOT_REACH BIT(0)
#define NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH BIT(1)
@@ -2087,11 +2124,12 @@
#define NEI_REP_BSSID_INFO_HT BIT(11)
#define NEI_REP_BSSID_INFO_VHT BIT(12)
#define NEI_REP_BSSID_INFO_FTM BIT(13)
+#define NEI_REP_BSSID_INFO_HE BIT(14)
/*
* IEEE P802.11-REVmc/D5.0 Table 9-152 - HT/VHT Operation Information
* subfields.
- * Note: These definitions are not the same as other VHT_CHANWIDTH_*.
+ * Note: These definitions are not the same as other CHANWIDTH_*.
*/
enum nr_chan_width {
NR_CHAN_WIDTH_20 = 0,
@@ -2104,21 +2142,60 @@
struct ieee80211_he_capabilities {
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 {
+ le16 rx_map;
+ le16 tx_map;
+ } he_basic_supported_mcs_set;
+ /* Followed by 0, 4, or 8 octets of optional supported HE-MCS And NSS Set field
+ * and optional variable length PPE Thresholds field. */
+ u8 optional[33];
} STRUCT_PACKED;
struct ieee80211_he_operation {
- u32 he_oper_params; /* HE Operation Parameters[3] and
- * BSS Color Information[1] */
- u8 he_mcs_nss_set[2];
+ le32 he_oper_params; /* HE Operation Parameters[3] and
+ * BSS Color Information[1] */
+ le16 he_mcs_nss_set;
u8 vht_op_info_chwidth;
u8 vht_op_info_chan_center_freq_seg0_idx;
u8 vht_op_info_chan_center_freq_seg1_idx;
/* Followed by conditional MaxBSSID Indicator subfield (u8) */
} STRUCT_PACKED;
+/*
+ * IEEE P802.11ax/D4.0, 9.4.2.246 Spatial Reuse Parameter Set element
+ */
+struct ieee80211_spatial_reuse {
+ u8 sr_ctrl; /* SR Control */
+ /* Up to 19 octets of parameters:
+ * Non-SRG OBSS PD Max Offset[0 or 1]
+ * SRG OBSS PD Min Offset[0 or 1]
+ * SRG OBSS PD Max Offset[0 or 1]
+ * SRG BSS Color Bitmap[0 or 8]
+ * SRG Partial BSSID Bitmap[0 or 8]
+ */
+ u8 params[19];
+} STRUCT_PACKED;
+
+struct ieee80211_6ghz_operation_info {
+ u8 primary_chan;
+ u8 control;
+ u8 chan_center_freq_seg0_idx;
+ u8 chan_center_freq_seg1_idx;
+ u8 minimum_rate;
+} STRUCT_PACKED;
+
+#define HE_CAPABILITIES_IE_MIN_LEN 21
+
/* HE Capabilities Information defines */
+#define HE_MACCAP_TWT_RESPONDER ((u8) BIT(2))
+#define HE_PHYCAP_CHANNEL_WIDTH_SET_IDX 0
+#define HE_PHYCAP_CHANNEL_WIDTH_MASK ((u8) (BIT(1) | BIT(2) | \
+ BIT(3) | BIT(4)))
+#define HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G ((u8) BIT(1))
+#define HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G ((u8) BIT(2))
+#define HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G ((u8) BIT(3))
+#define HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G ((u8) BIT(4))
+
#define HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX 3
#define HE_PHYCAP_SU_BEAMFORMER_CAPAB ((u8) BIT(7))
#define HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX 4
@@ -2126,23 +2203,53 @@
#define HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX 4
#define HE_PHYCAP_MU_BEAMFORMER_CAPAB ((u8) BIT(1))
+#define HE_PHYCAP_PPE_THRESHOLD_PRESENT_IDX 6
+#define HE_PHYCAP_PPE_THRESHOLD_PRESENT ((u8) BIT(7))
+
+/* HE PPE Threshold define */
+#define HE_PPE_THRES_RU_INDEX_BITMASK_MASK 0xf
+#define HE_PPE_THRES_RU_INDEX_BITMASK_SHIFT 3
+#define HE_PPE_THRES_NSS_MASK 0x7
+
/* 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_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) | \
- BIT(20) | BIT(21)))
-#define HE_OPERATION_RTS_THRESHOLD_OFFSET 12
+#define HE_OPERATION_DFLT_PE_DURATION_MASK ((u32) (BIT(0) | BIT(1) | \
+ BIT(2)))
+#define HE_OPERATION_DFLT_PE_DURATION_OFFSET 0
+#define HE_OPERATION_TWT_REQUIRED ((u32) BIT(3))
+#define HE_OPERATION_RTS_THRESHOLD_MASK ((u32) (BIT(4) | BIT(5) | \
+ BIT(6) | BIT(7) | \
+ BIT(8) | BIT(9) | \
+ BIT(10) | BIT(11) | \
+ BIT(12) | BIT(13)))
+#define HE_OPERATION_RTS_THRESHOLD_OFFSET 4
+#define HE_OPERATION_VHT_OPER_INFO ((u32) BIT(14))
+#define HE_OPERATION_COHOSTED_BSS ((u32) BIT(15))
+#define HE_OPERATION_ER_SU_DISABLE ((u32) BIT(16))
+#define HE_OPERATION_6GHZ_OPER_INFO ((u32) BIT(17))
+#define HE_OPERATION_BSS_COLOR_MASK ((u32) (BIT(24) | BIT(25) | \
+ BIT(26) | BIT(27) | \
+ BIT(28) | BIT(29)))
+#define HE_OPERATION_BSS_COLOR_PARTIAL ((u32) BIT(30))
+#define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(31))
+#define HE_OPERATION_BSS_COLOR_OFFSET 24
+
+/* HE operation fields length*/
+#define HE_OPERATION_IE_MIN_LEN 6
+#define HE_OPERATION_VHT_OPER_INFO_LEN 3
+#define HE_OPERATION_COHOSTED_BSSID_INDICATOR_LEN 1
+#define HE_OPERATION_6GHZ_OPER_INFO_LEN 5
+
+/* Spatial Reuse defines */
+#define SPATIAL_REUSE_SRP_DISALLOWED BIT(0)
+#define SPATIAL_REUSE_NON_SRG_OBSS_PD_SR_DISALLOWED BIT(1)
+#define SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT BIT(2)
+#define SPATIAL_REUSE_SRG_INFORMATION_PRESENT BIT(3)
+#define SPATIAL_REUSE_HESIGA_SR_VAL15_ALLOWED BIT(4)
+
+/* 6GHz operation control field defines*/
+#define SIX_GHZ_CONTROL_CHANNEL_WIDTH_MASK ((u8) BIT(0) | BIT(1))
+#define SIX_GHZ_CONTROL_DUPLICATE_BEACON BIT(2)
struct ieee80211_he_mu_edca_parameter_set {
u8 he_qos_info;
@@ -2177,6 +2284,39 @@
/* 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)))
+/* IEEE P802.11ay/D4.0, 9.4.2.251 - EDMG Operation element */
+#define EDMG_BSS_OPERATING_CHANNELS_OFFSET 6
+#define EDMG_OPERATING_CHANNEL_WIDTH_OFFSET 7
+
+/* IEEE P802.11ay/D4.0, 29.3.4 - Channelization */
+enum edmg_channel {
+ EDMG_CHANNEL_9 = 9,
+ EDMG_CHANNEL_10 = 10,
+ EDMG_CHANNEL_11 = 11,
+ EDMG_CHANNEL_12 = 12,
+ EDMG_CHANNEL_13 = 13,
+};
+
+/* Represent CB2 contiguous channels */
+#define EDMG_CHANNEL_9_SUBCHANNELS (BIT(0) | BIT(1)) /* channels 1 and 2 */
+#define EDMG_CHANNEL_10_SUBCHANNELS (BIT(1) | BIT(2)) /* channels 2 and 3 */
+#define EDMG_CHANNEL_11_SUBCHANNELS (BIT(2) | BIT(3)) /* channels 3 and 4 */
+#define EDMG_CHANNEL_12_SUBCHANNELS (BIT(3) | BIT(4)) /* channels 4 and 5 */
+#define EDMG_CHANNEL_13_SUBCHANNELS (BIT(4) | BIT(5)) /* channels 5 and 6 */
+
+/**
+ * enum edmg_bw_config - Allowed channel bandwidth configurations
+ * @EDMG_BW_CONFIG_4: 2.16 GHz
+ * @EDMG_BW_CONFIG_5: 2.16 GHz and 4.32 GHz
+ *
+ * IEEE P802.11ay/D4.0, 9.4.2.251 (EDMG Operation element),
+ * Table 13 (Channel BW Configuration subfield definition)
+ */
+enum edmg_bw_config {
+ EDMG_BW_CONFIG_4 = 4,
+ EDMG_BW_CONFIG_5 = 5,
+};
+
/* DPP Public Action frame identifiers - OUI_WFA */
#define DPP_OUI_TYPE 0x1A
diff --git a/src/common/privsep_commands.h b/src/common/privsep_commands.h
index b85c6c3..d2c4bbd 100644
--- a/src/common/privsep_commands.h
+++ b/src/common/privsep_commands.h
@@ -82,6 +82,7 @@
size_t seq_len;
u8 key[32];
size_t key_len;
+ enum key_flag key_flag;
};
enum privsep_event {
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index c34a3bc..e599b8d 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -1,7 +1,7 @@
/*
* Qualcomm Atheros OUI and vendor specific assignments
* Copyright (c) 2014-2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018, The Linux Foundation
+ * Copyright (c) 2018-2019, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -19,6 +19,10 @@
#define OUI_QCA 0x001374
+#ifndef BIT
+#define BIT(x) (1U << (x))
+#endif
+
/**
* enum qca_radiotap_vendor_ids - QCA radiotap vendor namespace IDs
*/
@@ -72,7 +76,7 @@
*
* @QCA_NL80211_VENDOR_SUBCMD_DO_ACS: ACS command/event which is used to
* invoke the ACS function in device and pass selected channels to
- * hostapd.
+ * hostapd. Uses enum qca_wlan_vendor_attr_acs_offload attributes.
*
* @QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES: Command to get the features
* supported by the driver. enum qca_wlan_vendor_features defines
@@ -98,6 +102,9 @@
* which supports DFS offloading, to indicate a radar pattern has been
* detected. The channel is now unusable.
*
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO: Get information from the driver.
+ * Attributes defined in enum qca_wlan_vendor_attr_get_wifi_info.
+ *
* @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.
@@ -167,6 +174,11 @@
* 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_ACS_POLICY: This command is used to configure
+ * DFS policy and channel hint for ACS operation. This command uses the
+ * attributes defined in enum qca_wlan_vendor_attr_acs_config and
+ * enum qca_acs_dfs_mode.
+ *
* @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
@@ -373,7 +385,9 @@
* @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_START: Start spectral scan. The scan
* parameters are specified by enum qca_wlan_vendor_attr_spectral_scan.
* This returns a cookie (%QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COOKIE)
- * identifying the operation in success case.
+ * identifying the operation in success case. In failure cases an
+ * error code (%QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_ERROR_CODE)
+ * describing the reason for the failure is returned.
*
* @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_STOP: Stop spectral scan. This uses
* a cookie (%QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COOKIE) from
@@ -524,6 +538,114 @@
* 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.
+ * @QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING: This sub command is used to
+ * implement Beacon frame reporting feature.
+ *
+ * Userspace can request the driver/firmware to periodically report
+ * received Beacon frames whose BSSID is same as the current connected
+ * BSS's MAC address.
+ *
+ * In case the STA seamlessly (without sending disconnect indication to
+ * userspace) roams to a different BSS, Beacon frame reporting will be
+ * automatically enabled for the Beacon frames whose BSSID is same as the
+ * MAC address of the new BSS. Beacon reporting will be stopped when the
+ * STA is disconnected (when the disconnect indication is sent to
+ * userspace) and need to be explicitly enabled by userspace for next
+ * connection.
+ *
+ * When a Beacon frame matching configured conditions is received, and if
+ * userspace has requested to send asynchronous beacon reports, the
+ * driver/firmware will encapsulate the details of the Beacon frame in an
+ * event and send it to userspace along with updating the BSS information
+ * in cfg80211 scan cache, otherwise driver will only update the cfg80211
+ * scan cache with the information from the received Beacon frame but will
+ * not send any active report to userspace.
+ *
+ * The userspace can request the driver/firmware to stop reporting Beacon
+ * frames. If the driver/firmware is not able to receive Beacon frames due
+ * to other Wi-Fi operations such as off-channel activities, etc., the
+ * driver/firmware will send a pause event to userspace and stop reporting
+ * Beacon frames. Whether the beacon reporting will be automatically
+ * resumed or not by the driver/firmware later will be reported to
+ * userspace using the QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_AUTO_RESUMES
+ * flag. The beacon reporting shall be resumed for all the cases except
+ * either when userspace sets
+ * QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_DO_NOT_RESUME flag in the command
+ * which triggered the current beacon reporting or during any disconnection
+ * case as indicated by setting
+ * QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PAUSE_REASON to
+ * QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_DISCONNECTED by the
+ * driver.
+ *
+ * After QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_PAUSE event is received
+ * by userspace with QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_AUTO_RESUMES
+ * flag not set, the next first
+ * QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO event from the driver
+ * shall be considered as un-pause event.
+ *
+ * All the attributes used with this command are defined in
+ * enum qca_wlan_vendor_attr_beacon_reporting_params.
+ * @QCA_NL80211_VENDOR_SUBCMD_INTEROP_ISSUES_AP: In practice, some APs have
+ * interop issues with the DUT. This sub command is used to transfer the
+ * AP info between the driver and user space. This works both as a command
+ * and an event. As a command, it configures the stored list of APs from
+ * user space to firmware; as an event, it indicates the AP info detected
+ * by the firmware to user space for persistent storage. The attributes
+ * defined in enum qca_vendor_attr_interop_issues_ap are used to deliver
+ * the parameters.
+ * @QCA_NL80211_VENDOR_SUBCMD_OEM_DATA: This command/event is used to
+ * send/receive OEM data binary blobs to/from application/service to/from
+ * firmware. The attributes defined in enum
+ * qca_wlan_vendor_attr_oem_data_params are used to deliver the
+ * parameters.
+ * @QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_EXT: This command/event is used
+ * to send/receive avoid frequency data using
+ * enum qca_wlan_vendor_attr_avoid_frequency_ext.
+ * This new command is alternative to existing command
+ * QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY since existing command/event
+ * is using stream of bytes instead of structured data using vendor
+ * attributes.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE: This vendor subcommand is used to
+ * add the STA node details in driver/firmware. Attributes for this event
+ * are specified in enum qca_wlan_vendor_attr_add_sta_node_params.
+ * @QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE: This command is used to set BT
+ * coex chain mode from application/service.
+ * The attributes defined in enum qca_vendor_attr_btc_chain_mode are used
+ * to deliver the parameters.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO: This vendor subcommand is used to
+ * get information of a station from driver to userspace. This command can
+ * be used in both STA and AP modes. For STA mode, it provides information
+ * of the current association when in connected state or the last
+ * association when in disconnected state. For AP mode, only information
+ * of the currently connected stations is available. This command uses
+ * attributes defined in enum qca_wlan_vendor_attr_get_sta_info.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_REQUEST_SAR_LIMITS_EVENT: This acts as an event.
+ * Host drivers can request the user space entity to set the SAR power
+ * limits with this event. Accordingly, the user space entity is expected
+ * to set the SAR power limits. Host drivers can retry this event to the
+ * user space for the SAR power limits configuration from user space. If
+ * the driver does not get the SAR power limits from user space for all
+ * the retried attempts, it can configure a default SAR power limit.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO: This acts as a vendor event and
+ * is used to update the information about the station from the driver to
+ * userspace. Uses attributes from enum
+ * qca_wlan_vendor_attr_update_sta_info.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DRIVER_DISCONNECT_REASON: This acts as an event.
+ * The host driver initiates the disconnection for scenarios such as beacon
+ * miss, NUD failure, peer kick out, etc. The disconnection indication
+ * through cfg80211_disconnected() expects the reason codes from enum
+ * ieee80211_reasoncode which does not signify these various reasons why
+ * the driver has triggered the disconnection. This event will be used to
+ * send the driver specific reason codes by the host driver to userspace.
+ * Host drivers should trigger this event and pass the respective reason
+ * code immediately prior to triggering cfg80211_disconnected(). The
+ * attributes used with this event are defined in enum
+ * qca_wlan_vendor_attr_driver_disconnect_reason.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -623,7 +745,8 @@
QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE = 109,
/* 110..114 - reserved for QCA */
QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_DECR_DB = 115,
- /* 116..117 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_ACS_POLICY = 116,
+ /* 117 - reserved for QCA */
QCA_NL80211_VENDOR_SUBCMD_SET_SAP_CONFIG = 118,
QCA_NL80211_VENDOR_SUBCMD_TSF = 119,
QCA_NL80211_VENDOR_SUBCMD_WISA = 120,
@@ -692,6 +815,16 @@
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,
+ QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING = 180,
+ QCA_NL80211_VENDOR_SUBCMD_INTEROP_ISSUES_AP = 181,
+ QCA_NL80211_VENDOR_SUBCMD_OEM_DATA = 182,
+ QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_EXT = 183,
+ QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE = 184,
+ QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE = 185,
+ QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO = 186,
+ QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS_EVENT = 187,
+ QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO = 188,
+ QCA_NL80211_VENDOR_SUBCMD_DRIVER_DISCONNECT_REASON = 189,
};
enum qca_wlan_vendor_attr {
@@ -1028,31 +1161,178 @@
QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_AFTER_LAST - 1
};
+/**
+ * enum qca_wlan_vendor_attr_acs_offload - Defines attributes to be used with
+ * vendor command/event QCA_NL80211_VENDOR_SUBCMD_DO_ACS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL: Required (u8).
+ * Used with event to notify the primary channel number selected in ACS
+ * operation.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL is deprecated; use
+ * QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY instead.
+ * To maintain backward compatibility, QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL: Required (u8).
+ * Used with event to notify the secondary channel number selected in ACS
+ * operation.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL is deprecated; use
+ * QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY instead.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL is still used if either of
+ * the driver or user space application doesn't support 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE: Required (u8).
+ * (a) Used with command to configure hw_mode from
+ * enum qca_wlan_vendor_acs_hw_mode for ACS operation.
+ * (b) Also used with event to notify the hw_mode of selected primary channel
+ * in ACS operation.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED: Flag attribute.
+ * Used with command to configure ACS operation for HT mode.
+ * Disable (flag attribute not present) - HT disabled and
+ * Enable (flag attribute present) - HT enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED: Flag attribute.
+ * Used with command to configure ACS operation for HT40 mode.
+ * Disable (flag attribute not present) - HT40 disabled and
+ * Enable (flag attribute present) - HT40 enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED: Flag attribute.
+ * Used with command to configure ACS operation for VHT mode.
+ * Disable (flag attribute not present) - VHT disabled and
+ * Enable (flag attribute present) - VHT enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH: Optional (u16) with command and
+ * mandatory with event.
+ * If specified in command path, ACS operation is configured with the given
+ * channel width (in MHz).
+ * In event path, specifies the channel width of the primary channel selected.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST: Required and type is NLA_UNSPEC.
+ * Used with command to configure channel list using an array of
+ * channel numbers (u8).
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * the driver mandates use of QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST whereas
+ * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL: Required (u8).
+ * Used with event to notify the VHT segment 0 center channel number selected in
+ * ACS operation. The value is the index of the channel center frequency for
+ * 20 MHz, 40 MHz, and 80 MHz channels. The value is the center frequency index
+ * of the primary 80 MHz segment for 160 MHz and 80+80 MHz channels.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL is deprecated; use
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY instead.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL is still used if either of
+ * the driver or user space application doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL: Required (u8).
+ * Used with event to notify the VHT segment 1 center channel number selected in
+ * ACS operation. The value is zero for 20 MHz, 40 MHz, and 80 MHz channels.
+ * The value is the index of the channel center frequency for 160 MHz channels
+ * and the center frequency index of the secondary 80 MHz segment for 80+80 MHz
+ * channels.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL is deprecated; use
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY instead.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL is still used if either of
+ * the driver or user space application doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST: Required and type is NLA_UNSPEC.
+ * Used with command to configure the channel list using an array of channel
+ * center frequencies in MHz (u32).
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * the driver first parses the frequency list and if it fails to get a frequency
+ * list, parses the channel list specified using
+ * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST (considers only 2 GHz and 5 GHz channels in
+ * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST).
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY: Required (u32).
+ * Used with event to notify the primary channel center frequency (MHz) selected
+ * in ACS operation.
+ * Note: If the driver supports the 6 GHz band, the event sent from the driver
+ * includes this attribute along with QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY: Required (u32).
+ * Used with event to notify the secondary channel center frequency (MHz)
+ * selected in ACS operation.
+ * Note: If the driver supports the 6 GHz band, the event sent from the driver
+ * includes this attribute along with
+ * QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY: Required (u32).
+ * Used with event to notify the VHT segment 0 center channel frequency (MHz)
+ * selected in ACS operation.
+ * Note: If the driver supports the 6 GHz band, the event sent from the driver
+ * includes this attribute along with
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY: Required (u32).
+ * Used with event to notify the VHT segment 1 center channel frequency (MHz)
+ * selected in ACS operation.
+ * Note: If the driver supports the 6 GHz band, the event sent from the driver
+ * includes this attribute along with
+ * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED: Flag attribute.
+ * Used with command to notify the driver of EDMG request for ACS
+ * operation.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL: Optional (u8).
+ * Used with event to notify the EDMG channel number selected in ACS
+ * operation.
+ * EDMG primary channel is indicated by QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL
+ */
enum qca_wlan_vendor_attr_acs_offload {
QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
- QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL,
- QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL,
- QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE,
- QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED,
- QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED,
- QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED,
- QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
- QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST,
- QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL,
- QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL,
- QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST,
+ QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL = 1,
+ QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL = 2,
+ QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE = 3,
+ QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED = 4,
+ QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED = 5,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED = 6,
+ QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH = 7,
+ QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST = 8,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL = 9,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL = 10,
+ QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST = 11,
+ QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY = 12,
+ QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY = 13,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY = 14,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY = 15,
+ QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED = 16,
+ QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL = 17,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_ACS_MAX =
QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST - 1
};
+/**
+ * enum qca_wlan_vendor_acs_hw_mode - Defines HW mode to be used with the
+ * vendor command/event QCA_NL80211_VENDOR_SUBCMD_DO_ACS.
+ *
+ * @QCA_ACS_MODE_IEEE80211B: 802.11b mode
+ * @QCA_ACS_MODE_IEEE80211G: 802.11g mode
+ * @QCA_ACS_MODE_IEEE80211A: 802.11a mode
+ * @QCA_ACS_MODE_IEEE80211AD: 802.11ad mode
+ * @QCA_ACS_MODE_IEEE80211ANY: all modes
+ * @QCA_ACS_MODE_IEEE80211AX: 802.11ax mode
+ */
enum qca_wlan_vendor_acs_hw_mode {
QCA_ACS_MODE_IEEE80211B,
QCA_ACS_MODE_IEEE80211G,
QCA_ACS_MODE_IEEE80211A,
QCA_ACS_MODE_IEEE80211AD,
QCA_ACS_MODE_IEEE80211ANY,
+ QCA_ACS_MODE_IEEE80211AX,
};
/**
@@ -1084,6 +1364,13 @@
* @QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY: Device supports self
* managed regulatory.
* @QCA_WLAN_VENDOR_FEATURE_TWT: Device supports TWT (Target Wake Time).
+ * @QCA_WLAN_VENDOR_FEATURE_11AX: Device supports 802.11ax (HE)
+ * @QCA_WLAN_VENDOR_FEATURE_6GHZ_SUPPORT: Device supports 6 GHz band operation
+ * @QCA_WLAN_VENDOR_FEATURE_THERMAL_CONFIG: Device is capable of receiving
+ * and applying thermal configuration through
+ * %QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL and
+ * %QCA_WLAN_VENDOR_ATTR_THERMAL_COMPLETION_WINDOW attributes from
+ * userspace.
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
*/
enum qca_wlan_vendor_features {
@@ -1096,6 +1383,9 @@
QCA_WLAN_VENDOR_FEATURE_OCE_STA_CFON = 6,
QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY = 7,
QCA_WLAN_VENDOR_FEATURE_TWT = 8,
+ QCA_WLAN_VENDOR_FEATURE_11AX = 9,
+ QCA_WLAN_VENDOR_FEATURE_6GHZ_SUPPORT = 10,
+ QCA_WLAN_VENDOR_FEATURE_THERMAL_CONFIG = 11,
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
@@ -1437,6 +1727,9 @@
* randomisation
* @QCA_WLAN_VENDOR_ATTR_SCAN_BSSID: 6-byte MAC address representing the
* specific BSSID to scan for.
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_DWELL_TIME: Unsigned 64-bit dwell time in
+ * microseconds. This is a common value which applies across all
+ * frequencies specified by QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES.
*/
enum qca_wlan_vendor_attr_scan {
QCA_WLAN_VENDOR_ATTR_SCAN_INVALID_PARAM = 0,
@@ -1451,6 +1744,7 @@
QCA_WLAN_VENDOR_ATTR_SCAN_MAC = 9,
QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK = 10,
QCA_WLAN_VENDOR_ATTR_SCAN_BSSID = 11,
+ QCA_WLAN_VENDOR_ATTR_SCAN_DWELL_TIME = 12,
QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SCAN_MAX =
QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST - 1
@@ -1788,18 +2082,77 @@
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_GTX = 57,
+ /* Attribute to configure disconnect IEs to the driver.
+ * This carries an array of unsigned 8-bit characters.
+ *
+ * If this is configured, driver shall fill the IEs in disassoc/deauth
+ * frame.
+ * These IEs are expected to be considered only for the next
+ * immediate disconnection (disassoc/deauth frame) originated by
+ * the DUT, irrespective of the entity (user space/driver/firmware)
+ * triggering the disconnection.
+ * The host drivers are not expected to use the IEs set through
+ * this interface for further disconnections after the first immediate
+ * disconnection initiated post the configuration.
+ * If the IEs are also updated through cfg80211 interface (after the
+ * enhancement to cfg80211_disconnect), host driver is expected to
+ * take the union of IEs from both of these interfaces and send in
+ * further disassoc/deauth frames.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_DISCONNECT_IES = 58,
+
+ /* 8-bit unsigned value for ELNA bypass.
+ * 1-Enable, 0-Disable
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS = 59,
+
+ /* 8-bit unsigned value. This attribute enables/disables the host driver
+ * to send the Beacon Report Response with failure reason for the
+ * scenarios where STA cannot honor the Beacon Report Request from AP.
+ * 1-Enable, 0-Disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_REPORT_FAIL = 60,
+
+ /* 8-bit unsigned value. This attribute enables/disables the host driver
+ * to send roam reason information in the Reassociation Request frame to
+ * the target AP when roaming within the same ESS.
+ * 1-Enable, 0-Disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ROAM_REASON = 61,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST - 1,
};
+/* Compatibility defines for previously used incorrect enum
+ * qca_wlan_vendor_attr_config names. These values should not be used in any
+ * new implementation. */
+#define QCA_WLAN_VENDOR_ATTR_DISCONNECT_IES \
+ QCA_WLAN_VENDOR_ATTR_CONFIG_DISCONNECT_IES
+#define QCA_WLAN_VENDOR_ATTR_BEACON_REPORT_FAIL \
+ QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_REPORT_FAIL
+
/**
* enum qca_wlan_vendor_attr_sap_config - Parameters for AP configuration
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL: Optional (u8)
+ * Channel number on which Access Point should restart.
+ * Note: If both the driver and user space application supports the 6 GHz band,
+ * this attribute is deprecated and QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_FREQUENCY
+ * should be used.
+ * To maintain backward compatibility, QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_FREQUENCY: Optional (u32)
+ * Channel center frequency (MHz) on which the access point should restart.
*/
enum qca_wlan_vendor_attr_sap_config {
QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_INVALID = 0,
- /* 1 - reserved for QCA */
+ QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL = 1,
+
/* List of frequencies on which AP is expected to operate.
* This is irrespective of ACS configuration. This list is a priority
* based one and is looked for before the AP is created to ensure the
@@ -1807,6 +2160,7 @@
* the system.
*/
QCA_WLAN_VENDOR_ATTR_SAP_MANDATORY_FREQUENCY_LIST = 2,
+ QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_FREQUENCY = 3,
QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_MAX =
@@ -1886,6 +2240,54 @@
};
/**
+ * enum qca_acs_dfs_mode - Defines different types of DFS channel
+ * configurations for ACS operation.
+ *
+ * @QCA_ACS_DFS_MODE_NONE: Refer to invalid DFS mode
+ * @QCA_ACS_DFS_MODE_ENABLE: Consider DFS channels in ACS operation
+ * @QCA_ACS_DFS_MODE_DISABLE: Do not consider DFS channels in ACS operation
+ * @QCA_ACS_DFS_MODE_DEPRIORITIZE: Deprioritize DFS channels in ACS operation
+ */
+enum qca_acs_dfs_mode {
+ QCA_ACS_DFS_MODE_NONE = 0,
+ QCA_ACS_DFS_MODE_ENABLE = 1,
+ QCA_ACS_DFS_MODE_DISABLE = 2,
+ QCA_ACS_DFS_MODE_DEPRIORITIZE = 3,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_acs_config - Defines Configuration attributes
+ * used by the vendor command QCA_NL80211_VENDOR_SUBCMD_ACS_POLICY.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_DFS_MODE: Required (u8)
+ * DFS mode for ACS operation from enum qca_acs_dfs_mode.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT: Required (u8)
+ * channel number hint for ACS operation, if valid channel is specified then
+ * ACS operation gives priority to this channel.
+ * Note: If both the driver and user space application supports the 6 GHz band,
+ * this attribute is deprecated and QCA_WLAN_VENDOR_ATTR_ACS_FREQUENCY_HINT
+ * should be used.
+ * To maintain backward compatibility, QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_FREQUENCY_HINT: Required (u32).
+ * Channel center frequency (MHz) hint for ACS operation, if a valid center
+ * frequency is specified, ACS operation gives priority to this channel.
+ */
+enum qca_wlan_vendor_attr_acs_config {
+ QCA_WLAN_VENDOR_ATTR_ACS_MODE_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_ACS_DFS_MODE = 1,
+ QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT = 2,
+ QCA_WLAN_VENDOR_ATTR_ACS_FREQUENCY_HINT = 3,
+
+ QCA_WLAN_VENDOR_ATTR_ACS_DFS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ACS_DFS_MAX =
+ QCA_WLAN_VENDOR_ATTR_ACS_DFS_AFTER_LAST - 1,
+};
+
+/**
* enum qca_wlan_vendor_attr_get_hw_capability - Wi-Fi hardware capability
*/
enum qca_wlan_vendor_attr_get_hw_capability {
@@ -3204,11 +3606,28 @@
/**
* enum qca_wlan_vendor_attr_get_wifi_info: Attributes for data used by
* QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO sub command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION: In a request this attribute
+ * should be set to any U8 value to indicate that the driver version
+ * should be returned. When enabled in this manner, in a response this
+ * attribute will contain a string representation of the driver version.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION: In a request this attribute
+ * should be set to any U8 value to indicate that the firmware version
+ * should be returned. When enabled in this manner, in a response this
+ * attribute will contain a string representation of the firmware version.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_WIFI_INFO_RADIO_INDEX: In a request this attribute
+ * should be set to any U32 value to indicate that the current radio
+ * index should be returned. When enabled in this manner, in a response
+ * this attribute will contain a U32 radio index value.
+ *
*/
enum qca_wlan_vendor_attr_get_wifi_info {
QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION = 1,
QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION = 2,
+ QCA_WLAN_VENDOR_ATTR_WIFI_INFO_RADIO_INDEX = 3,
/* keep last */
QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_AFTER_LAST,
@@ -3251,6 +3670,345 @@
QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_AFTER_LAST - 1,
};
+/**
+ * enum qca_scan_freq_list_type: Frequency list types
+ *
+ * @QCA_PREFERRED_SCAN_FREQ_LIST: The driver shall use the scan frequency list
+ * specified with attribute QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST as
+ * a preferred frequency list for roaming.
+ *
+ * @QCA_SPECIFIC_SCAN_FREQ_LIST: The driver shall use the frequency list
+ * specified with attribute QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST as
+ * a specific frequency list for roaming.
+ */
+enum qca_scan_freq_list_type {
+ QCA_PREFERRED_SCAN_FREQ_LIST = 1,
+ QCA_SPECIFIC_SCAN_FREQ_LIST = 2,
+};
+
+/**
+ * enum qca_vendor_attr_scan_freq_list_scheme: Frequency list scheme
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST: Nested attribute of u32 values
+ * List of frequencies in MHz to be considered for a roam scan.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_TYPE: Unsigned 32-bit value.
+ * Type of frequency list scheme being configured/gotten as defined by the
+ * enum qca_scan_freq_list_type.
+ */
+enum qca_vendor_attr_scan_freq_list_scheme {
+ QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST = 1,
+ QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_TYPE = 2,
+
+ /* keep last */
+ QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_SCHEME_AFTER_LAST,
+ QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_SCHEME_MAX =
+ QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_SCHEME_AFTER_LAST - 1,
+};
+
+/*
+ * enum qca_vendor_roam_triggers: Bitmap of roaming triggers
+ *
+ * @QCA_ROAM_TRIGGER_REASON_PER: Set if the roam has to be triggered based on
+ * a bad packet error rates (PER).
+ * @QCA_ROAM_TRIGGER_REASON_BEACON_MISS: Set if the roam has to be triggered
+ * based on beacon misses from the connected AP.
+ * @QCA_ROAM_TRIGGER_REASON_POOR_RSSI: Set if the roam has to be triggered
+ * due to poor RSSI of the connected AP.
+ * @QCA_ROAM_TRIGGER_REASON_BETTER_RSSI: Set if the roam has to be triggered
+ * upon finding a BSSID with a better RSSI than the connected BSSID.
+ * Here the RSSI of the current BSSID need not be poor.
+ * @QCA_ROAM_TRIGGER_REASON_PERIODIC: Set if the roam has to be triggered
+ * by triggering a periodic scan to find a better AP to roam.
+ * @QCA_ROAM_TRIGGER_REASON_DENSE: Set if the roam has to be triggered
+ * when the connected channel environment is too noisy/congested.
+ * @QCA_ROAM_TRIGGER_REASON_BTM: Set if the roam has to be triggered
+ * when BTM Request frame is received from the connected AP.
+ * @QCA_ROAM_TRIGGER_REASON_BSS_LOAD: Set if the roam has to be triggered
+ * when the channel utilization is goes above the configured threshold.
+ *
+ * Set the corresponding roam trigger reason bit to consider it for roam
+ * trigger.
+ * Userspace can set multiple bits and send to the driver. The driver shall
+ * consider all of them to trigger/initiate a roam scan.
+ */
+enum qca_vendor_roam_triggers {
+ QCA_ROAM_TRIGGER_REASON_PER = 1 << 0,
+ QCA_ROAM_TRIGGER_REASON_BEACON_MISS = 1 << 1,
+ QCA_ROAM_TRIGGER_REASON_POOR_RSSI = 1 << 2,
+ QCA_ROAM_TRIGGER_REASON_BETTER_RSSI = 1 << 3,
+ QCA_ROAM_TRIGGER_REASON_PERIODIC = 1 << 4,
+ QCA_ROAM_TRIGGER_REASON_DENSE = 1 << 5,
+ QCA_ROAM_TRIGGER_REASON_BTM = 1 << 6,
+ QCA_ROAM_TRIGGER_REASON_BSS_LOAD = 1 << 7,
+};
+
+/**
+ * enum qca_vendor_attr_roam_candidate_selection_criteria:
+ *
+ * Each attribute carries a weightage in percentage (%).
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_RSSI: Unsigned 8-bit value.
+ * Represents the weightage to be given for the RSSI selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE: Unsigned 8-bit value.
+ * Represents the weightage to be given for the rate selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BW: Unsigned 8-bit value.
+ * Represents the weightage to be given for the band width selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BAND: Unsigned 8-bit value.
+ * Represents the weightage to be given for the band selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_NSS: Unsigned 8-bit value.
+ * Represents the weightage to be given for the NSS selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_CHAN_CONGESTION: Unsigned 8-bit value.
+ * Represents the weightage to be given for the channel congestion
+ * selection criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BEAMFORMING: Unsigned 8-bit value.
+ * Represents the weightage to be given for the beamforming selection
+ * criteria among other parameters.
+ *
+ * @QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_OCE_WAN: Unsigned 8-bit value.
+ * Represents the weightage to be given for the OCE selection
+ * criteria among other parameters.
+ */
+enum qca_vendor_attr_roam_candidate_selection_criteria {
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_RSSI = 1,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE = 2,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BW = 3,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BAND = 4,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_NSS = 5,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_CHAN_CONGESTION = 6,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_BEAMFORMING = 7,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_OCE_WAN = 8,
+
+ /* keep last */
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE_AFTER_LAST,
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE_MAX =
+ QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_vendor_attr_roam_control - Attributes to carry roam configuration
+ * The following attributes are used to set/get/clear the respective
+ * configurations to/from the driver.
+ * For the get, the attribute for the configuration to be queried shall
+ * carry any of its acceptable values to the driver. In return, the driver
+ * shall send the configured values within the same attribute to the user
+ * space.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_ENABLE: Unsigned 8-bit value.
+ * Signifies to enable/disable roam control in driver.
+ * 1-enable, 0-disable
+ * Enable: Mandates the driver to do the further roams using the
+ * configuration parameters set through
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET.
+ * Disable: Disables the driver/firmware roaming triggered through
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET. Further roaming is
+ * expected to continue with the default configurations.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_STATUS: Unsigned 8-bit value.
+ * This is used along with QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_GET.
+ * Roam control status is obtained through this attribute.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_CLEAR_ALL: Flag attribute to indicate the
+ * complete config set through QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET
+ * is to be cleared in the driver.
+ * This is used along with QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR
+ * and shall be ignored if used with other sub commands.
+ * If this attribute is specified along with subcmd
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR, the driver shall ignore
+ * all other attributes, if there are any.
+ * If this attribute is not specified when the subcmd
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR is sent, the driver shall
+ * clear the data corresponding to the attributes specified.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_FREQ_LIST_SCHEME: Nested attribute to carry the
+ * list of frequencies and its type, represented by
+ * enum qca_vendor_attr_scan_freq_list_scheme.
+ * Frequency list and its type are mandatory for this attribute to set
+ * the frequencies.
+ * Frequency type is mandatory for this attribute to get the frequencies
+ * and the frequency list is obtained through
+ * QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST.
+ * Frequency list type is mandatory for this attribute to clear the
+ * frequencies.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_PERIOD: Unsigned 32-bit value.
+ * Carries the value of scan period in seconds to set.
+ * The value of scan period is obtained with the same attribute for get.
+ * Clears the scan period in the driver when specified with clear command.
+ * Scan period is the idle time in seconds between each subsequent
+ * channel scans.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_FULL_SCAN_PERIOD: Unsigned 32-bit value.
+ * Carries the value of full scan period in seconds to set.
+ * The value of full scan period is obtained with the same attribute for
+ * get.
+ * Clears the full scan period in the driver when specified with clear
+ * command. Full scan period is the idle period in seconds between two
+ * successive full channel roam scans.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_TRIGGERS: Unsigned 32-bit value.
+ * Carries a bitmap of the roam triggers specified in
+ * enum qca_vendor_roam_triggers.
+ * The driver shall enable roaming by enabling corresponding roam triggers
+ * based on the trigger bits sent with this attribute.
+ * If this attribute is not configured, the driver shall proceed with
+ * default behavior.
+ * The bitmap configured is obtained with the same attribute for get.
+ * Clears the bitmap configured in driver when specified with clear
+ * command.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SELECTION_CRITERIA: Nested attribute signifying the
+ * weightage in percentage (%) to be given for each selection criteria.
+ * Different roam candidate selection criteria are represented by
+ * enum qca_vendor_attr_roam_candidate_selection_criteria.
+ * The driver shall select the roam candidate based on corresponding
+ * candidate selection scores sent.
+ *
+ * An empty nested attribute is used to indicate that no specific
+ * preference score/criteria is configured (i.e., to disable this mechanism
+ * in the set case and to show that the mechanism is disabled in the get
+ * case).
+ *
+ * Userspace can send multiple attributes out of this enum to the driver.
+ * Since this attribute represents the weight/percentage of preference for
+ * the respective selection criteria, it is preferred to configure 100%
+ * total weightage. The value in each attribute or cumulative weight of the
+ * values in all the nested attributes should not exceed 100%. The driver
+ * shall reject such configuration.
+ *
+ * If the weights configured through this attribute are less than 100%,
+ * the driver shall honor the weights (x%) passed for the corresponding
+ * selection criteria and choose/distribute rest of the weight (100-x)%
+ * for the other selection criteria, based on its internal logic.
+ *
+ * The selection criteria configured is obtained with the same
+ * attribute for get.
+ *
+ * Clears the selection criteria configured in the driver when specified
+ * with clear command.
+ */
+enum qca_vendor_attr_roam_control {
+ QCA_ATTR_ROAM_CONTROL_ENABLE = 1,
+ QCA_ATTR_ROAM_CONTROL_STATUS = 2,
+ QCA_ATTR_ROAM_CONTROL_CLEAR_ALL = 3,
+ QCA_ATTR_ROAM_CONTROL_FREQ_LIST_SCHEME= 4,
+ QCA_ATTR_ROAM_CONTROL_SCAN_PERIOD = 5,
+ QCA_ATTR_ROAM_CONTROL_FULL_SCAN_PERIOD = 6,
+ QCA_ATTR_ROAM_CONTROL_TRIGGERS = 7,
+ QCA_ATTR_ROAM_CONTROL_SELECTION_CRITERIA = 8,
+
+ /* keep last */
+ QCA_ATTR_ROAM_CONTROL_AFTER_LAST,
+ QCA_ATTR_ROAM_CONTROL_MAX =
+ QCA_ATTR_ROAM_CONTROL_AFTER_LAST - 1,
+};
+
+/*
+ * enum qca_wlan_vendor_attr_roaming_config_params: Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_ROAM sub command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD: Unsigned 32-bit value.
+ * Represents the different roam sub commands referred by
+ * enum qca_wlan_vendor_roaming_subcmd.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID: Unsigned 32-bit value.
+ * Represents the Request ID for the specific set of commands.
+ * This also helps to map specific set of commands to the respective
+ * ID / client. e.g., helps to identify the user entity configuring the
+ * Blacklist BSSID and accordingly clear the respective ones with the
+ * matching ID.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS: Unsigned
+ * 32-bit value.Represents the number of whitelist SSIDs configured.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST: Nested attribute
+ * to carry the list of Whitelist SSIDs.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID: SSID (binary attribute,
+ * 0..32 octets). Represents the white list SSID. Whitelist SSIDs
+ * represent the list of SSIDs to which the firmware/driver can consider
+ * to roam to.
+ *
+ * The following PARAM_A_BAND_XX attributes are applied to 5GHz BSSIDs when
+ * comparing with a 2.4GHz BSSID. They are not applied when comparing two
+ * 5GHz BSSIDs.The following attributes are set through the Roaming SUBCMD -
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_GSCAN_ROAM_PARAMS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_THRESHOLD: Signed 32-bit
+ * value, RSSI threshold above which 5GHz RSSI is favored.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_THRESHOLD: Signed 32-bit
+ * value, RSSI threshold below which 5GHz RSSI is penalized.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_FACTOR: Unsigned 32-bit
+ * value, factor by which 5GHz RSSI is boosted.
+ * boost=(RSSI_measured-5GHz_boost_threshold)*5GHz_boost_factor
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_FACTOR: Unsigned 32-bit
+ * value, factor by which 5GHz RSSI is penalized.
+ * penalty=(5GHz_penalty_threshold-RSSI_measured)*5GHz_penalty_factor
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_MAX_BOOST: Unsigned 32-bit
+ * value, maximum boost that can be applied to a 5GHz RSSI.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_LAZY_ROAM_HISTERESYS: Unsigned 32-bit
+ * value, boost applied to current BSSID to ensure the currently
+ * associated BSSID is favored so as to prevent ping-pong situations.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALERT_ROAM_RSSI_TRIGGER: Signed 32-bit
+ * value, RSSI below which "Alert" roam is enabled.
+ * "Alert" mode roaming - firmware is "urgently" hunting for another BSSID
+ * because the RSSI is low, or because many successive beacons have been
+ * lost or other bad link conditions.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE: Unsigned 32-bit
+ * value. 1-Enable, 0-Disable. Represents "Lazy" mode, where
+ * firmware is hunting for a better BSSID or white listed SSID even though
+ * the RSSI of the link is good. The parameters enabling the roaming are
+ * configured through the PARAM_A_BAND_XX attrbutes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS: Nested attribute,
+ * represents the BSSIDs preferred over others while evaluating them
+ * for the roaming.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_NUM_BSSID: Unsigned
+ * 32-bit value. Represents the number of preferred BSSIDs set.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID: 6-byte MAC
+ * address representing the BSSID to be preferred.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER: Signed
+ * 32-bit value, representing the modifier to be applied to the RSSI of
+ * the BSSID for the purpose of comparing it with other roam candidate.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS: Nested attribute,
+ * represents the BSSIDs to get blacklisted for roaming.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID: Unsigned
+ * 32-bit value, represents the number of blacklisted BSSIDs.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID: 6-byte MAC
+ * address representing the Blacklisted BSSID.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_HINT: Flag attribute,
+ * indicates this BSSID blacklist as a hint to the driver. The driver can
+ * select this BSSID in the worst case (when no other BSSIDs are better).
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL: Nested attribute to
+ * set/get/clear the roam control config as
+ * defined @enum qca_vendor_attr_roam_control.
+ */
enum qca_wlan_vendor_attr_roaming_config_params {
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_INVALID = 0,
@@ -3287,6 +4045,8 @@
/* Flag attribute indicates this BSSID blacklist as a hint */
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_HINT = 21,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL = 22,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX =
@@ -3294,22 +4054,63 @@
};
/*
- * enum qca_wlan_vendor_attr_roam_subcmd: Attributes for data used by
- * QCA_NL80211_VENDOR_SUBCMD_ROAM sub command.
+ * enum qca_wlan_vendor_roaming_subcmd: Referred by
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SSID_WHITE_LIST: Sub command to
+ * configure the white list SSIDs. These are configured through
+ * the following attributes.
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS,
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST,
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_GSCAN_ROAM_PARAMS: Sub command to
+ * configure the Roam params. These parameters are evaluated on the GScan
+ * results. Refers the attributes PARAM_A_BAND_XX above to configure the
+ * params.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_LAZY_ROAM: Sets the Lazy roam. Uses
+ * the attribute QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE
+ * to enable/disable Lazy roam.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BSSID_PREFS: Sets the BSSID
+ * preference. Contains the attribute
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS to set the BSSID
+ * preference.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID: Sets the Blacklist
+ * BSSIDs. Refers QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS to
+ * set the same.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET: Command to set the
+ * roam control config to the driver with the attribute
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_GET: Command to obtain the
+ * roam control config from driver with the attribute
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL.
+ * For the get, the attribute for the configuration to be queried shall
+ * carry any of its acceptable value to the driver. In return, the driver
+ * shall send the configured values within the same attribute to the user
+ * space.
+ *
+ * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR: Command to clear the
+ * roam control config in the driver with the attribute
+ * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL.
+ * The driver shall continue with its default roaming behavior when data
+ * corresponding to an attribute is cleared.
*/
-enum qca_wlan_vendor_attr_roam_subcmd {
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_INVALID = 0,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SSID_WHITE_LIST = 1,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_GSCAN_ROAM_PARAMS = 2,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_LAZY_ROAM = 3,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PREFS = 4,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PARAMS = 5,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID = 6,
-
- /* keep last */
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_MAX =
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST - 1,
+enum qca_wlan_vendor_roaming_subcmd {
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_INVALID = 0,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SSID_WHITE_LIST = 1,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_GSCAN_ROAM_PARAMS = 2,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_LAZY_ROAM = 3,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BSSID_PREFS = 4,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BSSID_PARAMS = 5,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID = 6,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET = 7,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_GET = 8,
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR = 9,
};
enum qca_wlan_vendor_attr_gscan_config_params {
@@ -3677,8 +4478,8 @@
/* 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
+ * the vendor command QCA_NL80211_VENDOR_SUBCMD_ROAM with subcmd
+ * QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID and attribute
* QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID.
*/
QCA_WLAN_VENDOR_ATTR_GSCAN_MAX_NUM_BLACKLISTED_BSSID = 46,
@@ -3780,6 +4581,44 @@
QCA_WLAN_VENDOR_ACS_SELECT_REASON_DFS,
/* Represents the reason that LTE co-exist in the current band. */
QCA_WLAN_VENDOR_ACS_SELECT_REASON_LTE_COEX,
+ /* Represents the reason that generic, uncategorized interference has
+ * been found in the current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_GENERIC_INTERFERENCE,
+ /* Represents the reason that excessive 802.11 interference has been
+ * found in the current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_80211_INTERFERENCE,
+ /* Represents the reason that generic Continuous Wave (CW) interference
+ * has been found in the current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_CW_INTERFERENCE,
+ /* Represents the reason that Microwave Oven (MWO) interference has been
+ * found in the current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_MWO_INTERFERENCE,
+ /* Represents the reason that generic Frequency-Hopping Spread Spectrum
+ * (FHSS) interference has been found in the current channel. This may
+ * include 802.11 waveforms.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_FHSS_INTERFERENCE,
+ /* Represents the reason that non-802.11 generic Frequency-Hopping
+ * Spread Spectrum (FHSS) interference has been found in the current
+ * channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_NON_80211_FHSS_INTERFERENCE,
+ /* Represents the reason that generic Wideband (WB) interference has
+ * been found in the current channel. This may include 802.11 waveforms.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_WB_INTERFERENCE,
+ /* Represents the reason that non-802.11 generic Wideband (WB)
+ * interference has been found in the current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_NON_80211_WB_INTERFERENCE,
+ /* Represents the reason that Jammer interference has been found in the
+ * current channel.
+ */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_JAMMER_INTERFERENCE,
};
/**
@@ -3947,6 +4786,46 @@
*/
QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAGS_2 = 11,
+ /*
+ * VHT segment 0 in MHz (u32) and the attribute is mandatory.
+ * Note: Event QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS includes
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0
+ * along with
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_0.
+ *
+ * If both the driver and user-space application supports the 6 GHz
+ * band, QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_0
+ * is deprecated and
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0
+ * should be used.
+ *
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0 = 12,
+
+ /*
+ * VHT segment 1 in MHz (u32) and the attribute is mandatory.
+ * Note: Event QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS includes
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1
+ * along with
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_1.
+ *
+ * If both the driver and user-space application supports the 6 GHz
+ * band, QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_1
+ * is deprecated and
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1
+ * should be considered.
+ *
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1 = 13,
+
/* keep last */
QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_LAST,
QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MAX =
@@ -4047,9 +4926,100 @@
};
/**
- * qca_wlan_vendor_attr_external_acs_channels: Attributes to vendor subcmd
+ * enum qca_wlan_vendor_attr_external_acs_channels: Attributes to vendor subcmd
* QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS. This carries a list of channels
* in priority order as decided after ACS operation in userspace.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_REASON: Required (u8).
+ * One of reason code from enum qca_wlan_vendor_acs_select_reason.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LIST: Required
+ * Array of nested values for each channel with following attributes:
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LIST is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_LIST.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LIST
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY: Required (u8).
+ * Primary channel number
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY
+ * is still used if either of the driver or user space application doesn't
+ * support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY: Required (u8).
+ * Secondary channel number, required only for 160 and 80+80 MHz bandwidths.
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0: Required (u8).
+ * VHT seg0 channel number
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0 is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1: Required (u8).
+ * VHT seg1 channel number
+ * Note: If both the driver and user-space application supports the 6 GHz band,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1 is deprecated and use
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1.
+ * To maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1
+ * is still used if either of the driver or user space application
+ * doesn't support the 6 GHz band.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH: Required (u8).
+ * Takes one of enum nl80211_chan_width values.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_LIST: Required
+ * Array of nested values for each channel with following attributes:
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY in MHz (u32),
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY in MHz (u32),
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0 in MHz (u32),
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1 in MHz (u32),
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH
+ * Note: If user-space application has no support of the 6 GHz band, this
+ * attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY: Required (u32)
+ * Primary channel frequency in MHz
+ * Note: If user-space application has no support of the 6 GHz band, this
+ * attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY: Required (u32)
+ * Secondary channel frequency in MHz used for HT 40 MHz channels.
+ * Note: If user-space application has no support of the 6 GHz band, this
+ * attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0: Required (u32)
+ * VHT seg0 channel frequency in MHz
+ * Note: If user-space application has no support of the 6GHz band, this
+ * attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1: Required (u32)
+ * VHT seg1 channel frequency in MHz
+ * Note: If user-space application has no support of the 6 GHz band, this
+ * attribute is optional.
*/
enum qca_wlan_vendor_attr_external_acs_channels {
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_INVALID = 0,
@@ -4080,6 +5050,12 @@
/* Channel width (u8). Takes one of enum nl80211_chan_width values. */
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH = 8,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_LIST = 9,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY = 10,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY = 11,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0 = 12,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1 = 13,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LAST,
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_MAX =
@@ -4481,6 +5457,62 @@
* qca_wlan_vendor_attr_spectral_scan_request_type.
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE = 23,
+ /* This specifies the frequency span over which spectral
+ * scan would be carried out. Its value depends on the
+ * value of QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_MODE and
+ * the relation is as follows.
+ * QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_NORMAL
+ * Not applicable. Spectral scan would happen in the
+ * operating span.
+ * QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_AGILE
+ * Center frequency (in MHz) of the span of interest or
+ * for convenience, center frequency (in MHz) of any channel
+ * in the span of interest. For 80+80 MHz agile spectral scan
+ * request it represents center frequency (in MHz) of the primary
+ * 80 MHz span or for convenience, center frequency (in MHz) of any
+ * channel in the primary 80 MHz span. If agile spectral scan is
+ * initiated without setting a valid frequency it returns the
+ * error code
+ * (QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_NOT_INITIALIZED).
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FREQUENCY = 24,
+ /* Spectral scan mode. u32 attribute.
+ * It uses values defined in enum qca_wlan_vendor_spectral_scan_mode.
+ * If this attribute is not present, it is assumed to be
+ * normal mode (QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_NORMAL).
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_MODE = 25,
+ /* Spectral scan error code. u32 attribute.
+ * It uses values defined in enum
+ * qca_wlan_vendor_spectral_scan_error_code.
+ * This attribute is included only in failure scenarios.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_ERROR_CODE = 26,
+ /* 8-bit unsigned value to enable/disable debug of the
+ * Spectral DMA ring.
+ * 1-enable, 0-disable
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DMA_RING_DEBUG = 27,
+ /* 8-bit unsigned value to enable/disable debug of the
+ * Spectral DMA buffers.
+ * 1-enable, 0-disable
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DMA_BUFFER_DEBUG = 28,
+ /* This specifies the frequency span over which spectral scan would be
+ * carried out. Its value depends on the value of
+ * QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_MODE and the relation is as
+ * follows.
+ * QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_NORMAL
+ * Not applicable. Spectral scan would happen in the operating span.
+ * QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_AGILE
+ * This attribute is applicable only for agile spectral scan
+ * requests in 80+80 MHz mode. It represents center frequency (in
+ * MHz) of the secondary 80 MHz span or for convenience, center
+ * frequency (in MHz) of any channel in the secondary 80 MHz span.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FREQUENCY_2 = 29,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX =
@@ -4559,6 +5591,38 @@
* u8 attribute.
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_DEFAULT_AGC_MAX_GAIN = 10,
+ /* Flag attribute to indicate agile spectral scan capability
+ * for 20/40/80 MHz modes.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AGILE_SPECTRAL = 11,
+ /* Flag attribute to indicate agile spectral scan capability
+ * for 160 MHz mode.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AGILE_SPECTRAL_160 = 12,
+ /* Flag attribute to indicate agile spectral scan capability
+ * for 80+80 MHz mode.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AGILE_SPECTRAL_80_80 = 13,
+ /* Number of spectral detectors used for scan in 20 MHz.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_NUM_DETECTORS_20_MHZ = 14,
+ /* Number of spectral detectors used for scan in 40 MHz.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_NUM_DETECTORS_40_MHZ = 15,
+ /* Number of spectral detectors used for scan in 80 MHz.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_NUM_DETECTORS_80_MHZ = 16,
+ /* Number of spectral detectors used for scan in 160 MHz.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_NUM_DETECTORS_160_MHZ = 17,
+ /* Number of spectral detectors used for scan in 80+80 MHz.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_NUM_DETECTORS_80P80_MHZ = 18,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_MAX =
@@ -4575,6 +5639,13 @@
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,
+ /* Spectral scan mode. u32 attribute.
+ * It uses values defined in enum qca_wlan_vendor_spectral_scan_mode.
+ * If this attribute is not present, normal mode
+ * (QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_NORMAL is assumed to be
+ * requested.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_MODE = 3,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_MAX =
@@ -4600,6 +5671,43 @@
};
/**
+ * qca_wlan_vendor_spectral_scan_mode: Attribute values for
+ * QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_MODE in the vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_START and
+ * QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_MODE in the vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_STATUS. This represents the
+ * spectral scan modes.
+ * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_NORMAL: Normal spectral scan:
+ * spectral scan in the current operating span.
+ * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_AGILE: Agile spectral scan:
+ * spectral scan in the configured agile span.
+ */
+enum qca_wlan_vendor_spectral_scan_mode {
+ QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_NORMAL = 0,
+ QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_AGILE = 1,
+};
+
+/**
+ * qca_wlan_vendor_spectral_scan_error_code: Attribute values for
+ * QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_ERROR_CODE in the vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_START.
+ * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_UNSUPPORTED: Changing the value
+ * of a parameter is not supported.
+ * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED: Requested spectral scan
+ * mode is not supported.
+ * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE: A parameter
+ * has invalid value.
+ * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_NOT_INITIALIZED: A parameter
+ * is not initialized.
+ */
+enum qca_wlan_vendor_spectral_scan_error_code {
+ QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_UNSUPPORTED = 0,
+ QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED = 1,
+ QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE = 2,
+ QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_NOT_INITIALIZED = 3,
+};
+
+/**
* 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
@@ -4664,6 +5772,39 @@
QCA_WLAN_HANG_DXE_FAILURE = 12,
/* WMI pending commands exceed the maximum count */
QCA_WLAN_HANG_WMI_EXCEED_MAX_PENDING_CMDS = 13,
+ /* Timeout for peer STA connection accept command's response from the
+ * FW in AP mode. This command is triggered when a STA (peer) connects
+ * to AP (DUT).
+ */
+ QCA_WLAN_HANG_AP_STA_CONNECT_REQ_TIMEOUT = 14,
+ /* Timeout for the AP connection accept command's response from the FW
+ * in STA mode. This command is triggered when the STA (DUT) connects
+ * to an AP (peer).
+ */
+ QCA_WLAN_HANG_STA_AP_CONNECT_REQ_TIMEOUT = 15,
+ /* Timeout waiting for the response to the MAC HW mode change command
+ * sent to FW as a part of MAC mode switch among DBS (Dual Band
+ * Simultaneous), SCC (Single Channel Concurrency), and MCC (Multi
+ * Channel Concurrency) mode.
+ */
+ QCA_WLAN_HANG_MAC_HW_MODE_CHANGE_TIMEOUT = 16,
+ /* Timeout waiting for the response from FW to configure the MAC HW's
+ * mode. This operation is to configure the single/two MACs in either
+ * SCC/MCC/DBS mode.
+ */
+ QCA_WLAN_HANG_MAC_HW_MODE_CONFIG_TIMEOUT = 17,
+ /* Timeout waiting for response of VDEV start command from the FW */
+ QCA_WLAN_HANG_VDEV_START_RESPONSE_TIMED_OUT = 18,
+ /* Timeout waiting for response of VDEV restart command from the FW */
+ QCA_WLAN_HANG_VDEV_RESTART_RESPONSE_TIMED_OUT = 19,
+ /* Timeout waiting for response of VDEV stop command from the FW */
+ QCA_WLAN_HANG_VDEV_STOP_RESPONSE_TIMED_OUT = 20,
+ /* Timeout waiting for response of VDEV delete command from the FW */
+ QCA_WLAN_HANG_VDEV_DELETE_RESPONSE_TIMED_OUT = 21,
+ /* Timeout waiting for response of peer all delete request command to
+ * the FW on a specific VDEV.
+ */
+ QCA_WLAN_HANG_VDEV_PEER_DELETE_ALL_RESPONSE_TIMED_OUT = 22,
};
/**
@@ -4676,6 +5817,12 @@
* qca_wlan_vendor_hang_reason.
*/
QCA_WLAN_VENDOR_ATTR_HANG_REASON = 1,
+ /* The binary blob data associated with the hang reason specified by
+ * QCA_WLAN_VENDOR_ATTR_HANG_REASON. This binary data is expected to
+ * contain the required dump to analyze the reason for the hang.
+ * NLA_BINARY attribute, the max size is 1024 bytes.
+ */
+ QCA_WLAN_VENDOR_ATTR_HANG_REASON_DATA = 2,
QCA_WLAN_VENDOR_ATTR_HANG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_HANG_MAX =
@@ -4776,12 +5923,22 @@
enum qca_wlan_vendor_attr_rtplinst {
QCA_WLAN_VENDOR_ATTR_RTPLINST_INVALID = 0,
- /* Primary channel number (u8) */
+ /* Primary channel number (u8).
+ * Note: If both the driver and user space application support the
+ * 6 GHz band, this attribute is deprecated and
+ * QCA_WLAN_VENDOR_ATTR_RTPLINST_PRIMARY_FREQUENCY should be used. To
+ * maintain backward compatibility,
+ * QCA_WLAN_VENDOR_ATTR_RTPLINST_PRIMARY is still used if either the
+ * driver or user space application or both do not support the 6 GHz
+ * band.
+ */
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,
+ /* Primary channel center frequency (u32) in MHz */
+ QCA_WLAN_VENDOR_ATTR_RTPLINST_PRIMARY_FREQUENCY = 4,
QCA_WLAN_VENDOR_ATTR_RTPLINST_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_RTPLINST_MAX =
@@ -5313,6 +6470,29 @@
};
/**
+ * enum qca_wlan_vendor_thermal_level - Defines various thermal levels
+ * configured by userspace to the driver/firmware. The values will be
+ * encapsulated in QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL attribute.
+ * The driver/firmware takes actions requested by userspace such as throttling
+ * wifi TX etc. in order to mitigate high temperature.
+ *
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_NONE: Stop/clear all throttling actions.
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_LIGHT: Throttle TX lightly.
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_MODERATE: Throttle TX moderately.
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_SEVERE: Throttle TX severely.
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_CRITICAL: Critical thermal level reached.
+ * @QCA_WLAN_VENDOR_THERMAL_LEVEL_EMERGENCY: Emergency thermal level reached.
+ */
+enum qca_wlan_vendor_thermal_level {
+ QCA_WLAN_VENDOR_THERMAL_LEVEL_NONE = 0,
+ QCA_WLAN_VENDOR_THERMAL_LEVEL_LIGHT = 1,
+ QCA_WLAN_VENDOR_THERMAL_LEVEL_MODERATE = 2,
+ QCA_WLAN_VENDOR_THERMAL_LEVEL_SEVERE = 3,
+ QCA_WLAN_VENDOR_THERMAL_LEVEL_CRITICAL = 4,
+ QCA_WLAN_VENDOR_THERMAL_LEVEL_EMERGENCY = 5,
+};
+
+/**
* 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.
@@ -5325,6 +6505,21 @@
* u32 attribute.
*/
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE = 1,
+ /* Userspace uses this attribute to configure thermal level to the
+ * driver/firmware. Used in request, u32 attribute, possible values
+ * are defined in enum qca_wlan_vendor_thermal_level.
+ */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL = 2,
+ /* Userspace uses this attribute to configure the time in which the
+ * driver/firmware should complete applying settings it received from
+ * userspace with QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL
+ * command type. Used in request, u32 attribute, value is in
+ * milliseconds. A value of zero indicates to apply the settings
+ * immediately. The driver/firmware can delay applying the configured
+ * thermal settings within the time specified in this attribute if
+ * there is any critical ongoing operation.
+ */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_COMPLETION_WINDOW = 3,
/* keep last */
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_AFTER_LAST,
@@ -5348,12 +6543,15 @@
* suspend action.
* @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_RESUME: Request to execute thermal
* resume action.
+ * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL: Configure thermal level to
+ * the driver/firmware.
*/
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,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL,
};
/**
@@ -6262,10 +7460,42 @@
* 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.
+ * @QCA_WLAN_VENDOR_CFR_METHOD_QOS_NULL: CFR method using QoS Null frame
+ * @QCA_WLAN_VENDOR_CFR_QOS_NULL_WITH_PHASE: CFR method using QoS Null frame
+ * with phase
+ * @QCA_WLAN_VENDOR_CFR_PROBE_RESPONSE: CFR method using Probe Response frame
*/
enum qca_wlan_vendor_cfr_method {
- /* CFR method using QOS Null frame */
QCA_WLAN_VENDOR_CFR_METHOD_QOS_NULL = 0,
+ QCA_WLAN_VENDOR_CFR_QOS_NULL_WITH_PHASE = 1,
+ QCA_WLAN_VENDOR_CFR_PROBE_RESPONSE = 2,
+};
+
+/**
+ * enum qca_wlan_vendor_cfr_capture_type - QCA vendor CFR capture type used by
+ * attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE.
+ * @QCA_WLAN_VENDOR_CFR_DIRECT_FTM: Filter directed FTM ACK frames.
+ * @QCA_WLAN_VENDOR_CFR_ALL_FTM_ACK: Filter all FTM ACK frames.
+ * @QCA_WLAN_VENDOR_CFR_DIRECT_NDPA_NDP: Filter NDPA NDP directed frames.
+ * @QCA_WLAN_VENDOR_CFR_TA_RA: Filter frames based on TA/RA/Subtype which
+ * is provided by one or more of below attributes:
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER
+ * @QCA_WLAN_CFR_ALL_PACKET: Filter all packets.
+ * @QCA_WLAN_VENDOR_CFR_NDPA_NDP_ALL: Filter all NDPA NDP frames.
+ */
+enum qca_wlan_vendor_cfr_capture_type {
+ QCA_WLAN_VENDOR_CFR_DIRECT_FTM = 0,
+ QCA_WLAN_VENDOR_CFR_ALL_FTM_ACK = 1,
+ QCA_WLAN_VENDOR_CFR_DIRECT_NDPA_NDP = 2,
+ QCA_WLAN_VENDOR_CFR_TA_RA = 3,
+ QCA_WLAN_VENDOR_CFR_ALL_PACKET = 4,
+ QCA_WLAN_VENDOR_CFR_NDPA_NDP_ALL = 5,
};
/**
@@ -6273,44 +7503,177 @@
* QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG to configure peer
* Channel Frequency Response capture parameters and enable periodic CFR
* capture.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CFR_PEER_MAC_ADDR: Optional (6-byte MAC address)
+ * MAC address of peer. This is for CFR version 1 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE: Required (flag)
+ * Enable peer CFR capture. 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_BANDWIDTH: Optional (u8)
+ * 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.
+ * This attribute is mandatory for version 1 if attribute
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_PERIODICITY: Optional (u32)
+ * Periodicity of CFR measurement in milliseconds.
+ * Periodicity should be a multiple of Base timer.
+ * Current Base timer value supported is 10 milliseconds (default).
+ * 0 for one shot capture.
+ * This attribute is mandatory for version 1 if attribute
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD: Optional (u8)
+ * Method used to capture Channel Frequency Response.
+ * Attribute uses the values defined in enum qca_wlan_vendor_cfr_method.
+ * This attribute is mandatory for version 1 if attribute
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PERIODIC_CFR_CAPTURE_ENABLE: Optional (flag)
+ * Enable periodic CFR capture.
+ * This attribute is mandatory for version 1 to enable Periodic CFR capture.
+ * If this attribute is not present, periodic CFR capture is disabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_VERSION: Optional (u8)
+ * Value is 1 or 2 since there are two versions of CFR capture. Two versions
+ * can't be enabled at same time. This attribute is mandatory if target
+ * support both versions and use one of them.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE_GROUP_BITMAP: Optional (u32)
+ * This attribute is mandatory for version 2 if
+ * QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY is used.
+ * Bits 15:0 bitfield indicates which group is to be enabled.
+ * Bits 31:16 Reserved for future use.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION: Optional (u32)
+ * CFR capture duration in microsecond. This attribute is mandatory for
+ * version 2 if attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL is used.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL: Optional (u32)
+ * CFR capture interval in microsecond. This attribute is mandatory for
+ * version 2 if attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION is used.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE: Optional (u32)
+ * CFR capture type is defined in enum qca_wlan_vendor_cfr_capture_type.
+ * This attribute is mandatory for version 2.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_UL_MU_MASK: Optional (u64)
+ * Bitfield indicating which user in the current UL MU transmissions are
+ * enabled for CFR capture. Bits 36 to 0 indicate user indexes for 37 users in
+ * a UL MU transmission. If bit 0 is set, the CFR capture will happen for user
+ * index 0 in the current UL MU transmission. If bits 0 and 2 are set, CFR
+ * capture for UL MU TX corresponds to user indices 0 and 2. Bits 63:37 are
+ * reserved for future use. This is for CFR version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_FREEZE_TLV_DELAY_COUNT: Optional (u32)
+ * Indicates the number of consecutive RX frames to be skipped before CFR
+ * capture is enabled again. This is for CFR version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TABLE: Nested attribute containing
+ * one or more %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY attributes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY: Nested attribute containing
+ * the following group attributes:
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER,
+ * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER: Optional (u32)
+ * Target supports multiple groups for some configurations. The group number
+ * can be any value between 0 and 15. This is for CFR version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA: Optional (6-byte MAC address)
+ * Transmitter address which is used to filter frames. This MAC address takes
+ * effect with QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK. This is for CFR
+ * version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA: Optional (6-byte MAC address)
+ * Receiver address which is used to filter frames. This MAC address takes
+ * effect with QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK. This is for CFR
+ * version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK: Optional (6-byte MAC address)
+ * Mask of transmitter address which is used to filter frames. This is for CFR
+ * version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK: Optional (6-byte MAC address)
+ * Mask of receiver address which is used to filter frames. This is for CFR
+ * version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS: Optional (u32)
+ * Indicates frames with a specific NSS will be filtered for CFR capture.
+ * This is for CFR version 2 only. This is a bitmask. Bits 7:0 request CFR
+ * capture to be done for frames matching the NSS specified within this bitmask.
+ * Bits 31:8 are reserved for future use. Bits 7:0 map to NSS:
+ * bit 0 : NSS 1
+ * bit 1 : NSS 2
+ * ...
+ * bit 7 : NSS 8
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW: Optional (u32)
+ * Indicates frames with a specific bandwidth will be filtered for CFR capture.
+ * This is for CFR version 2 only. This is a bitmask. Bits 4:0 request CFR
+ * capture to be done for frames matching the bandwidths specified within this
+ * bitmask. Bits 31:5 are reserved for future use. Bits 4:0 map to bandwidth
+ * numerated in enum nl80211_band (although not all bands may be supported
+ * by a given device).
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER: Optional (u32)
+ * Management frames matching the subtype filter categories will be filtered in
+ * by MAC for CFR capture. This is a bitmask in which each bit represents the
+ * corresponding Management frame subtype value per IEEE Std 802.11-2016,
+ * 9.2.4.1.3 Type and Subtype subfields. For example, Beacon frame control type
+ * is 8 and its value is 1 << 8 = 0x100. This is for CFR version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER: Optional (u32)
+ * Control frames matching the subtype filter categories will be filtered in by
+ * MAC for CFR capture. This is a bitmask in which each bit represents the
+ * corresponding Control frame subtype value per IEEE Std 802.11-2016,
+ * 9.2.4.1.3 Type and Subtype subfields. This is for CFR version 2 only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER: Optional (u32)
+ * Data frames matching the subtype filter categories will be filtered in by
+ * MAC for CFR capture. This is a bitmask in which each bit represents the
+ * corresponding Data frame subtype value per IEEE Std 802.11-2016,
+ * 9.2.4.1.3 Type and Subtype subfields. This is for CFR version 2 only.
*/
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,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_VERSION = 7,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE_GROUP_BITMAP = 8,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION = 9,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL = 10,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE = 11,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_UL_MU_MASK = 12,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_FREEZE_TLV_DELAY_COUNT = 13,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TABLE = 14,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY = 15,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER = 16,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA = 17,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA = 18,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK = 19,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK = 20,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS = 21,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW = 22,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER = 23,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER = 24,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER = 25,
/* Keep last */
QCA_WLAN_VENDOR_ATTR_PEER_CFR_AFTER_LAST,
@@ -6709,4 +8072,773 @@
QCA_MPTA_HELPER_VENDOR_ATTR_AFTER_LAST - 1
};
+/**
+ * enum qca_wlan_vendor_beacon_reporting_op_types - Defines different types of
+ * operations for which %QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING can be used.
+ * Will be used by %QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE.
+ *
+ * @QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START: Sent by userspace to the driver
+ * to request the driver to start reporting Beacon frames.
+ * @QCA_WLAN_VENDOR_BEACON_REPORTING_OP_STOP: Sent by userspace to the driver to
+ * request the driver to stop reporting Beacon frames.
+ * @QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO: Sent by the driver to
+ * userspace to report received Beacon frames.
+ * @QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE: Sent by the driver to userspace
+ * to indicate that the driver is going to pause reporting Beacon frames.
+ */
+enum qca_wlan_vendor_beacon_reporting_op_types {
+ QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START = 0,
+ QCA_WLAN_VENDOR_BEACON_REPORTING_OP_STOP = 1,
+ QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO = 2,
+ QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE = 3,
+};
+
+/**
+ * enum qca_wlan_vendor_beacon_reporting_pause_reasons - Defines different types
+ * of reasons for which the driver is pausing reporting Beacon frames. Will be
+ * used by %QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PAUSE_REASON.
+ *
+ * @QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_UNSPECIFIED: For unspecified
+ * reasons.
+ * @QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_SCAN_STARTED: When the
+ * driver/firmware is starting a scan.
+ * @QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_DISCONNECTED: When the
+ * driver/firmware disconnects from the ESS and indicates the disconnection to
+ * userspace (non-seamless roaming case). This reason code will be used by the
+ * driver/firmware to indicate stopping of beacon report events. Userspace will
+ * need to start beacon reporting again (if desired) by sending vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING with
+ * QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE set to
+ * QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START after the next connection is
+ * completed.
+ */
+enum qca_wlan_vendor_beacon_reporting_pause_reasons {
+ QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_UNSPECIFIED = 0,
+ QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_SCAN_STARTED = 1,
+ QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_DISCONNECTED = 2,
+};
+
+/*
+ * enum qca_wlan_vendor_attr_beacon_reporting_params - List of attributes used
+ * in vendor sub-command QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING.
+ */
+enum qca_wlan_vendor_attr_beacon_reporting_params {
+ QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_INVALID = 0,
+ /* Specifies the type of operation that the vendor command/event is
+ * intended for. Possible values for this attribute are defined in
+ * enum qca_wlan_vendor_beacon_reporting_op_types. u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE = 1,
+ /* Optionally set by userspace to request the driver to report Beacon
+ * frames using asynchronous vendor events when the
+ * QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
+ * QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START. NLA_FLAG attribute.
+ * If this flag is not set, the driver will only update Beacon frames in
+ * cfg80211 scan cache but not send any vendor events.
+ */
+ QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_ACTIVE_REPORTING = 2,
+ /* Optionally used by userspace to request the driver/firmware to report
+ * Beacon frames periodically when the
+ * QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
+ * QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START.
+ * u32 attribute, indicates the period of Beacon frames to be reported
+ * and in the units of beacon interval.
+ * If this attribute is missing in the command, then the default value
+ * of 1 will be assumed by driver, i.e., to report every Beacon frame.
+ * Zero is an invalid value.
+ * If a valid value is received for this attribute, the driver will
+ * update the cfg80211 scan cache periodically as per the value received
+ * in this attribute in addition to updating the cfg80211 scan cache
+ * when there is significant change in Beacon frame IEs.
+ */
+ QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PERIOD = 3,
+ /* Used by the driver to encapsulate the SSID when the
+ * QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
+ * QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO.
+ * u8 array with a maximum size of 32.
+ *
+ * When generating beacon report from non-MBSSID Beacon frame, the SSID
+ * will be taken from the SSID element of the received Beacon frame.
+ *
+ * When generating beacon report from Multiple BSSID Beacon frame and if
+ * the BSSID of the current connected BSS matches the BSSID of the
+ * transmitting BSS, the SSID will be taken from the SSID element of the
+ * received Beacon frame.
+ *
+ * When generating beacon report from Multiple BSSID Beacon frame and if
+ * the BSSID of the current connected BSS matches the BSSID of one of
+ * the* nontransmitting BSSs, the SSID will be taken from the SSID field
+ * included in the nontransmitted BSS profile whose derived BSSID is
+ * same as the BSSID of the current connected BSS. When there is no
+ * nontransmitted BSS profile whose derived BSSID is same as the BSSID
+ * of current connected* BSS, this attribute will not be present.
+ */
+ QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_SSID = 4,
+ /* Used by the driver to encapsulate the BSSID of the AP to which STA is
+ * currently connected to when the
+ * QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
+ * QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO. u8 array with a
+ * fixed size of 6 bytes.
+ *
+ * When generating beacon report from a Multiple BSSID beacon and the
+ * current connected BSSID matches one of the nontransmitted BSSIDs in a
+ * Multiple BSSID set, this BSSID will be that particular nontransmitted
+ * BSSID and not the transmitted BSSID (i.e., the transmitting address
+ * of the Beacon frame).
+ */
+ QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BSSID = 5,
+ /* Used by the driver to encapsulate the frequency in MHz on which
+ * the Beacon frame was received when the
+ * QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is
+ * set to QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_FREQ = 6,
+ /* Used by the driver to encapsulate the Beacon interval
+ * when the QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
+ * QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO.
+ * u16 attribute. The value will be copied from the Beacon frame and the
+ * units are TUs.
+ */
+ QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BI = 7,
+ /* Used by the driver to encapsulate the Timestamp field from the Beacon
+ * frame when the QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set
+ * to QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO.
+ * u64 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_TSF = 8,
+ /* Used by the driver to encapsulate the CLOCK_BOOTTIME when this
+ * Beacon frame is received in the driver when the
+ * QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
+ * QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO. u64 attribute, in
+ * the units of nanoseconds. This value is expected to have accuracy of
+ * about 10 ms.
+ */
+ QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BOOTTIME_WHEN_RECEIVED = 9,
+ /* Used by the driver to encapsulate the IEs of the Beacon frame from
+ * which this event is generated when the
+ * QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
+ * QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO. u8 array.
+ */
+ QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_IES = 10,
+ /* Used by the driver to specify the reason for the driver/firmware to
+ * pause sending beacons to userspace when the
+ * QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
+ * QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE. Possible values are
+ * defined in enum qca_wlan_vendor_beacon_reporting_pause_reasons, u32
+ * attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PAUSE_REASON = 11,
+ /* Used by the driver to specify whether the driver will automatically
+ * resume reporting beacon events to userspace later (for example after
+ * the ongoing off-channel activity is completed etc.) when the
+ * QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
+ * QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE. NLA_FLAG attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_AUTO_RESUMES = 12,
+ /* Optionally set by userspace to request the driver not to resume
+ * beacon reporting after a pause is completed, when the
+ * QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
+ * QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START. NLA_FLAG attribute.
+ * If this flag is set, the driver will not resume beacon reporting
+ * after any pause in beacon reporting is completed. Userspace has to
+ * send QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START command again in order
+ * to initiate beacon reporting again. If this flag is set in the recent
+ * QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START command, then in the
+ * subsequent QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE event (if any)
+ * the QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_AUTO_RESUMES shall not be
+ * set by the driver. Setting this flag until and unless there is a
+ * specific need is not recommended as there is a chance of some beacons
+ * received after pause command and next start command being not
+ * reported.
+ */
+ QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_DO_NOT_RESUME = 13,
+
+ /* Keep last */
+ QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_LAST,
+ QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_MAX =
+ QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_LAST - 1
+};
+
+/**
+ * enum qca_vendor_interop_issues_ap_type - Interop issue types
+ * This enum defines the valid set of values of interop issue types. These
+ * values are used by attribute %QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_TYPE.
+ *
+ * @QCA_VENDOR_INTEROP_ISSUES_AP_ON_STA_PS: The AP has power save interop issue
+ * when the STA's Qpower feature is enabled.
+ */
+enum qca_vendor_interop_issues_ap_type {
+ QCA_VENDOR_INTEROP_ISSUES_AP_INVALID = 0,
+ QCA_VENDOR_INTEROP_ISSUES_AP_ON_STA_PS = 1,
+};
+
+/**
+ * enum qca_vendor_attr_interop_issues_ap - attribute for AP with interop issues
+ * Values are used by %QCA_NL80211_VENDOR_SUBCMD_INTEROP_ISSUES_AP.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_INVALID: Invalid value
+ * @QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_TYPE: Interop issue type
+ * 32-bit unsigned value. The values defined in enum
+ * qca_vendor_interop_issues_ap_type are used.
+ * @QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_LIST: APs' BSSID container
+ * array of nested QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_BSSID attributes.
+ * It is present and mandatory for the command but is not used for the event
+ * since only a single BSSID is reported in an event.
+ * @QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_BSSID: AP's BSSID 6-byte MAC address.
+ * It is used within the nested QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_LIST
+ * attribute in command case and without such encapsulation in the event case.
+ * @QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_AFTER_LAST: last value
+ * @QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_MAX: max value
+ */
+enum qca_vendor_attr_interop_issues_ap {
+ QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_INVALID,
+ QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_TYPE,
+ QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_LIST,
+ QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_BSSID,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_MAX =
+ QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_vendor_oem_device_type - Represents the target device in firmware.
+ * It is used by QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO.
+ *
+ * @QCA_VENDOR_OEM_DEVICE_VIRTUAL: The command is intended for
+ * a virtual device.
+ *
+ * @QCA_VENDOR_OEM_DEVICE_PHYSICAL: The command is intended for
+ * a physical device.
+ */
+enum qca_vendor_oem_device_type {
+ QCA_VENDOR_OEM_DEVICE_VIRTUAL = 0,
+ QCA_VENDOR_OEM_DEVICE_PHYSICAL = 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_oem_data_params - Used by the vendor command/event
+ * QCA_NL80211_VENDOR_SUBCMD_OEM_DATA.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA: The binary blob for the vendor
+ * command/event QCA_NL80211_VENDOR_SUBCMD_OEM_DATA are carried through this
+ * attribute.
+ * NLA_BINARY attribute, the max size is 1024 bytes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO: The binary blob will be routed
+ * based on this field. This optional attribute is included to specify whether
+ * the device type is a virtual device or a physical device for the
+ * command/event. This attribute can be omitted for a virtual device (default)
+ * command/event.
+ * This u8 attribute is used to carry information for the device type using
+ * values defined by enum qca_vendor_oem_device_type.
+ */
+enum qca_wlan_vendor_attr_oem_data_params {
+ QCA_WLAN_VENDOR_ATTR_OEM_DATA_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA = 1,
+ QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX =
+ QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_avoid_frequency_ext - Defines attributes to be
+ * used with vendor command/event QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_EXT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_RANGE: Required
+ * Nested attribute containing multiple ranges with following attributes:
+ * QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START and
+ * QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START: Required (u32)
+ * Starting center frequency in MHz.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END: Required (u32)
+ * Ending center frequency in MHz.
+ */
+enum qca_wlan_vendor_attr_avoid_frequency_ext {
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_RANGE = 1,
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START = 2,
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END = 3,
+
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_MAX =
+ QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_AFTER_LAST - 1
+};
+
+/*
+ * enum qca_wlan_vendor_attr_add_sta_node_params - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE.
+ */
+enum qca_wlan_vendor_attr_add_sta_node_params {
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_INVALID = 0,
+ /* 6 byte MAC address of STA */
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_MAC_ADDR = 1,
+ /* Authentication algorithm used by the station of size u16;
+ * defined in enum nl80211_auth_type.
+ */
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_AUTH_ALGO = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_PARAM_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_PARAM_MAX =
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_PARAM_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_btc_chain_mode - Specifies BT coex chain mode.
+ * This enum defines the valid set of values of BT coex chain mode.
+ * These values are used by attribute %QCA_VENDOR_ATTR_BTC_CHAIN_MODE of
+ * %QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE.
+ *
+ * @QCA_BTC_CHAIN_SHARED: chains of BT and WLAN 2.4G are shared.
+ * @QCA_BTC_CHAIN_SEPARATED: chains of BT and WLAN 2.4G are separated.
+ */
+enum qca_btc_chain_mode {
+ QCA_BTC_CHAIN_SHARED = 0,
+ QCA_BTC_CHAIN_SEPARATED = 1,
+};
+
+/**
+ * enum qca_vendor_attr_btc_chain_mode - Specifies attributes for BT coex
+ * chain mode.
+ * Attributes for data used by QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE.
+ *
+ * @QCA_VENDOR_ATTR_COEX_BTC_CHAIN_MODE: u32 attribute.
+ * Indicates the BT coex chain mode, are 32-bit values from
+ * enum qca_btc_chain_mode. This attribute is mandatory.
+ *
+ * @QCA_VENDOR_ATTR_COEX_BTC_CHAIN_MODE_RESTART: flag attribute.
+ * If set, vdev should be restarted when BT coex chain mode is updated.
+ * This attribute is optional.
+ */
+enum qca_vendor_attr_btc_chain_mode {
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE_INVALID = 0,
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE = 1,
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE_RESTART = 2,
+
+ /* Keep last */
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE_LAST,
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE_MAX =
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE_LAST - 1,
+};
+
+/**
+ * enum qca_vendor_wlan_sta_flags - Station feature flags
+ * Bits will be set to 1 if the corresponding features are enabled.
+ * @QCA_VENDOR_WLAN_STA_FLAG_AMPDU: AMPDU is enabled for the station
+ * @QCA_VENDOR_WLAN_STA_FLAG_TX_STBC: TX Space-time block coding is enabled
+ for the station
+ * @QCA_VENDOR_WLAN_STA_FLAG_RX_STBC: RX Space-time block coding is enabled
+ for the station
+ */
+enum qca_vendor_wlan_sta_flags {
+ QCA_VENDOR_WLAN_STA_FLAG_AMPDU = BIT(0),
+ QCA_VENDOR_WLAN_STA_FLAG_TX_STBC = BIT(1),
+ QCA_VENDOR_WLAN_STA_FLAG_RX_STBC = BIT(2),
+};
+
+/**
+ * enum qca_vendor_wlan_sta_guard_interval - Station guard interval
+ * @QCA_VENDOR_WLAN_STA_GI_800_NS: Legacy normal guard interval
+ * @QCA_VENDOR_WLAN_STA_GI_400_NS: Legacy short guard interval
+ * @QCA_VENDOR_WLAN_STA_GI_1600_NS: Guard interval used by HE
+ * @QCA_VENDOR_WLAN_STA_GI_3200_NS: Guard interval used by HE
+ */
+enum qca_vendor_wlan_sta_guard_interval {
+ QCA_VENDOR_WLAN_STA_GI_800_NS = 0,
+ QCA_VENDOR_WLAN_STA_GI_400_NS = 1,
+ QCA_VENDOR_WLAN_STA_GI_1600_NS = 2,
+ QCA_VENDOR_WLAN_STA_GI_3200_NS = 3,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_get_sta_info - Defines attributes
+ * used by QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAC:
+ * Required attribute in request for AP mode only, 6-byte MAC address,
+ * corresponding to the station's MAC address for which information is
+ * requested. For STA mode this is not required as the info always correspond
+ * to the self STA and the current/last association.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_FLAGS:
+ * Optionally used in response, u32 attribute, contains a bitmap of different
+ * fields defined in enum qca_vendor_wlan_sta_flags, used in AP mode only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_GUARD_INTERVAL:
+ * Optionally used in response, u32 attribute, possible values are defined in
+ * enum qca_vendor_wlan_sta_guard_interval, used in AP mode only.
+ * Guard interval used by the station.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_RETRY_COUNT:
+ * Optionally used in response, u32 attribute, used in AP mode only.
+ * Value indicates the number of data frames received from station with retry
+ * bit set to 1 in FC.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BC_MC_COUNT:
+ * Optionally used in response, u32 attribute, used in AP mode only.
+ * Counter for number of data frames with broadcast or multicast address in
+ * the destination address received from the station.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RETRY_SUCCEED:
+ * Optionally used in response, u32 attribute, used in both STA and AP modes.
+ * Value indicates the number of data frames successfully transmitted only
+ * after retrying the packets and for which the TX status has been updated
+ * back to host from target.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RETRY_EXHAUSTED:
+ * Optionally used in response, u32 attribute, used in both STA and AP mode.
+ * Value indicates the number of data frames not transmitted successfully even
+ * after retrying the packets for the number of times equal to the total number
+ * of retries allowed for that packet and for which the TX status has been
+ * updated back to host from target.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_TOTAL:
+ * Optionally used in response, u32 attribute, used in AP mode only.
+ * Counter in the target for the number of data frames successfully transmitted
+ * to the station.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_RETRY:
+ * Optionally used in response, u32 attribute, used in AP mode only.
+ * Value indicates the number of data frames successfully transmitted only
+ * after retrying the packets.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_RETRY_EXHAUSTED:
+ * Optionally used in response, u32 attribute, used in both STA & AP mode.
+ * Value indicates the number of data frames not transmitted successfully even
+ * after retrying the packets for the number of times equal to the total number
+ * of retries allowed for that packet.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_PROBE_REQ_BMISS_COUNT: u32, used in
+ * the STA mode only. Represent the number of probe requests sent by the STA
+ * while attempting to roam on missing certain number of beacons from the
+ * connected AP. If queried in the disconnected state, this represents the
+ * count for the last connected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_PROBE_RESP_BMISS_COUNT: u32, used in
+ * the STA mode. Represent the number of probe responses received by the station
+ * while attempting to roam on missing certain number of beacons from the
+ * connected AP. When queried in the disconnected state, this represents the
+ * count when in last connected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_ALL_COUNT: u32, used in the
+ * STA mode only. Represents the total number of frames sent out by STA
+ * including Data, ACK, RTS, CTS, Control Management. This data is maintained
+ * only for the connect session. Represents the count of last connected session,
+ * when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RTS_COUNT: u32, used in the STA mode.
+ * Total number of RTS sent out by the STA. This data is maintained per connect
+ * session. Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RTS_RETRY_FAIL_COUNT: u32, used in the
+ * STA mode.Represent the number of RTS transmission failure that reach retry
+ * limit. This data is maintained per connect session. Represents the count of
+ * last connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_DATA_NON_AGGREGATED_COUNT: u32, used in
+ * the STA mode. Represent the total number of non aggregated frames transmitted
+ * by the STA. This data is maintained per connect session. Represents the count
+ * of last connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_DATA_AGGREGATED_COUNT: u32, used in the
+ * STA mode. Represent the total number of aggregated frames transmitted by the
+ * STA. This data is maintained per connect session. Represents the count of
+ * last connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_GOOD_PLCP_COUNT: u32, used in
+ * the STA mode. Represents the number of received frames with a good PLCP. This
+ * data is maintained per connect session. Represents the count of last
+ * connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_INVALID_DELIMITER_COUNT: u32,
+ * used in the STA mode. Represents the number of occasions that no valid
+ * delimiter is detected by A-MPDU parser. This data is maintained per connect
+ * session. Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_CRC_FAIL_COUNT: u32, used in the
+ * STA mode. Represents the number of frames for which CRC check failed in the
+ * MAC. This data is maintained per connect session. Represents the count of
+ * last connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_ACKS_GOOD_FCS_COUNT: u32, used in the
+ * STA mode. Represents the number of unicast ACKs received with good FCS. This
+ * data is maintained per connect session. Represents the count of last
+ * connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BLOCKACK_COUNT: u32, used in the STA
+ * mode. Represents the number of received Block Acks. This data is maintained
+ * per connect session. Represents the count of last connected session, when
+ * queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BEACON_COUNT: u32, used in the STA
+ * mode. Represents the number of beacons received from the connected BSS. This
+ * data is maintained per connect session. Represents the count of last
+ * connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_OTHER_BEACON_COUNT: u32, used in the
+ * STA mode. Represents the number of beacons received by the other BSS when in
+ * connected state (through the probes done by the STA). This data is maintained
+ * per connect session. Represents the count of last connected session, when
+ * queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_UCAST_DATA_GOOD_FCS_COUNT: u64, used in
+ * the STA mode. Represents the number of received DATA frames with good FCS and
+ * matching Receiver Address when in connected state. This data is maintained
+ * per connect session. Represents the count of last connected session, when
+ * queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_DATA_BC_MC_DROP_COUNT: u32, used in the
+ * STA mode. Represents the number of RX Data multicast frames dropped by the HW
+ * when in the connected state. This data is maintained per connect session.
+ * Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_1MBPS: u32, used in the
+ * STA mode. This represents the target power in dBm for the transmissions done
+ * to the AP in 2.4 GHz at 1 Mbps (DSSS) rate. This data is maintained per
+ * connect session. Represents the count of last connected session, when
+ * queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_6MBPS: u32, used in the
+ * STA mode. This represents the Target power in dBm for transmissions done to
+ * the AP in 2.4 GHz at 6 Mbps (OFDM) rate. This data is maintained per connect
+ * session. Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_MCS0: u32, used in the
+ * STA mode. This represents the Target power in dBm for transmissions done to
+ * the AP in 2.4 GHz at MCS0 rate. This data is maintained per connect session.
+ * Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_6MBPS: u32, used in the
+ * STA mode. This represents the Target power in dBm for transmissions done to
+ * the AP in 5 GHz at 6 Mbps (OFDM) rate. This data is maintained per connect
+ * session. Represents the count of last connected session, when queried in
+ * the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_MCS0: u32, used in the
+ * STA mode. This represents the Target power in dBm for for transmissions done
+ * to the AP in 5 GHz at MCS0 rate. This data is maintained per connect session.
+ * Represents the count of last connected session, when queried in the
+ * disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_HW_BUFFERS_OVERFLOW_COUNT: u32, used
+ * in the STA mode. This represents the Nested attribute representing the
+ * overflow counts of each receive buffer allocated to the hardware during the
+ * STA's connection. The number of hw buffers might vary for each WLAN
+ * solution and hence this attribute represents the nested array of all such
+ * HW buffer count. This data is maintained per connect session. Represents
+ * the count of last connected session, when queried in the disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX_TX_POWER: u32, Max TX power (dBm)
+ * allowed as per the regulatory requirements for the current or last connected
+ * session. Used in the STA mode.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_TX_POWER: u32, Latest TX power
+ * (dBm) used by the station in its latest unicast frame while communicating
+ * to the AP in the connected state. When queried in the disconnected state,
+ * this represents the TX power used by the STA with last AP communication
+ * when in connected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ANI_LEVEL: u32, Adaptive noise immunity
+ * level used to adjust the RX sensitivity. Represents the current ANI level
+ * when queried in the connected state. When queried in the disconnected
+ * state, this corresponds to the latest ANI level at the instance of
+ * disconnection.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_IES: Binary attribute containing
+ * the raw information elements from Beacon frames. Represents the Beacon frames
+ * of the current BSS in the connected state. When queried in the disconnected
+ * state, these IEs correspond to the last connected BSSID.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PROBE_RESP_IES: Binary attribute
+ * containing the raw information elements from Probe Response frames.
+ * Represents the Probe Response frames of the current BSS in the connected
+ * state. When queried in the disconnected state, these IEs correspond to the
+ * last connected BSSID.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_DRIVER_DISCONNECT_REASON: u32, Driver
+ * disconnect reason for the last disconnection if the disconnection is
+ * triggered from the host driver. The values are referred from
+ * enum qca_disconnect_reason_codes.
+ */
+enum qca_wlan_vendor_attr_get_sta_info {
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAC = 1,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_FLAGS = 2,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_GUARD_INTERVAL = 3,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_RETRY_COUNT = 4,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BC_MC_COUNT = 5,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RETRY_SUCCEED = 6,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RETRY_EXHAUSTED = 7,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_TOTAL = 8,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_RETRY = 9,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_RETRY_EXHAUSTED = 10,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_PROBE_REQ_BMISS_COUNT = 11,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_PROBE_RESP_BMISS_COUNT = 12,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_ALL_COUNT = 13,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RTS_COUNT = 14,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RTS_RETRY_FAIL_COUNT = 15,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_DATA_NON_AGGREGATED_COUNT = 16,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_DATA_AGGREGATED_COUNT = 17,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_GOOD_PLCP_COUNT = 18,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_INVALID_DELIMITER_COUNT = 19,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_CRC_FAIL_COUNT = 20,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_ACKS_GOOD_FCS_COUNT = 21,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BLOCKACK_COUNT = 22,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BEACON_COUNT = 23,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_OTHER_BEACON_COUNT = 24,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_UCAST_DATA_GOOD_FCS_COUNT = 25,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_DATA_BC_MC_DROP_COUNT = 26,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_1MBPS = 27,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_6MBPS = 28,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_MCS0 = 29,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_6MBPS = 30,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_MCS0 = 31,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_HW_BUFFERS_OVERFLOW_COUNT = 32,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX_TX_POWER = 33,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_TX_POWER = 34,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ANI_LEVEL = 35,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_IES = 36,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PROBE_RESP_IES = 37,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_DRIVER_DISCONNECT_REASON = 38,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX =
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_update_sta_info - Defines attributes
+ * used by QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_CONNECT_CHANNELS: Type is NLA_UNSPEC.
+ * Used in STA mode. This attribute represents the list of channel center
+ * frequencies in MHz (u32) the station has learnt during the last connection
+ * or roaming attempt. This information shall not signify the channels for
+ * an explicit scan request from the user space. Host drivers can update this
+ * information to the user space in both connected and disconnected state.
+ * In the disconnected state this information shall signify the channels
+ * scanned in the last connection/roam attempt that lead to the disconnection.
+ */
+enum qca_wlan_vendor_attr_update_sta_info {
+ QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_CONNECT_CHANNELS = 1,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_MAX =
+ QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_disconnect_reason_codes - Specifies driver disconnect reason codes.
+ * Used when the driver triggers the STA to disconnect from the AP.
+ *
+ * @QCA_DISCONNECT_REASON_UNSPECIFIED: The host driver triggered the
+ * disconnection with the AP due to unspecified reasons.
+ *
+ * @QCA_DISCONNECT_REASON_INTERNAL_ROAM_FAILURE: The host driver triggered the
+ * disconnection with the AP due to a roaming failure. This roaming is triggered
+ * internally (host driver/firmware).
+ *
+ * @QCA_DISCONNECT_REASON_EXTERNAL_ROAM_FAILURE: The driver disconnected from
+ * the AP when the user/external triggered roaming fails.
+ *
+ * @QCA_DISCONNECT_REASON_GATEWAY_REACHABILITY_FAILURE: This reason code is used
+ * by the host driver whenever gateway reachability failure is detected and the
+ * driver disconnects with AP.
+ *
+ * @QCA_DISCONNECT_REASON_UNSUPPORTED_CHANNEL_CSA: The driver disconnected from
+ * the AP on a channel switch announcement from it with an unsupported channel.
+ *
+ * @QCA_DISCONNECT_REASON_OPER_CHANNEL_DISABLED_INDOOR: On a concurrent AP start
+ * with indoor channels disabled and if the STA is connected on one of these
+ * disabled channels, the host driver disconnected the STA with this reason
+ * code.
+ *
+ * @QCA_DISCONNECT_REASON_OPER_CHANNEL_USER_DISABLED: Disconnection due to an
+ * explicit request from the user to disable the current operating channel.
+ *
+ * @QCA_DISCONNECT_REASON_DEVICE_RECOVERY: STA disconnected from the AP due to
+ * the internal host driver/firmware recovery.
+ *
+ * @QCA_DISCONNECT_REASON_KEY_TIMEOUT: The driver triggered the disconnection on
+ * a timeout for the key installations from the user space.
+ *
+ * @QCA_DISCONNECT_REASON_OPER_CHANNEL_BAND_CHANGE: The dDriver disconnected the
+ * STA on a band change request from the user space to a different band from the
+ * current operation channel/band.
+ *
+ * @QCA_DISCONNECT_REASON_IFACE_DOWN: The STA disconnected from the AP on an
+ * interface down trigger from the user space.
+ *
+ * @QCA_DISCONNECT_REASON_PEER_XRETRY_FAIL: The host driver disconnected the
+ * STA on getting continuous transmission failures for multiple Data frames.
+ *
+ * @QCA_DISCONNECT_REASON_PEER_INACTIVITY: The STA does a keep alive
+ * notification to the AP by transmitting NULL/G-ARP frames. This disconnection
+ * represents inactivity from AP on such transmissions.
+
+ * @QCA_DISCONNECT_REASON_SA_QUERY_TIMEOUT: This reason code is used on
+ * disconnection when SA Query times out (AP does not respond to SA Query).
+ *
+ * @QCA_DISCONNECT_REASON_BEACON_MISS_FAILURE: The host driver disconnected the
+ * STA on missing the beacons continuously from the AP.
+ *
+ * @QCA_DISCONNECT_REASON_CHANNEL_SWITCH_FAILURE: Disconnection due to STA not
+ * able to move to the channel mentioned by the AP in CSA.
+ *
+ * @QCA_DISCONNECT_REASON_USER_TRIGGERED: User triggered disconnection.
+ */
+enum qca_disconnect_reason_codes {
+ QCA_DISCONNECT_REASON_UNSPECIFIED = 0,
+ QCA_DISCONNECT_REASON_INTERNAL_ROAM_FAILURE = 1,
+ QCA_DISCONNECT_REASON_EXTERNAL_ROAM_FAILURE = 2,
+ QCA_DISCONNECT_REASON_GATEWAY_REACHABILITY_FAILURE = 3,
+ QCA_DISCONNECT_REASON_UNSUPPORTED_CHANNEL_CSA = 4,
+ QCA_DISCONNECT_REASON_OPER_CHANNEL_DISABLED_INDOOR = 5,
+ QCA_DISCONNECT_REASON_OPER_CHANNEL_USER_DISABLED = 6,
+ QCA_DISCONNECT_REASON_DEVICE_RECOVERY = 7,
+ QCA_DISCONNECT_REASON_KEY_TIMEOUT = 8,
+ QCA_DISCONNECT_REASON_OPER_CHANNEL_BAND_CHANGE = 9,
+ QCA_DISCONNECT_REASON_IFACE_DOWN = 10,
+ QCA_DISCONNECT_REASON_PEER_XRETRY_FAIL = 11,
+ QCA_DISCONNECT_REASON_PEER_INACTIVITY = 12,
+ QCA_DISCONNECT_REASON_SA_QUERY_TIMEOUT = 13,
+ QCA_DISCONNECT_REASON_BEACON_MISS_FAILURE = 14,
+ QCA_DISCONNECT_REASON_CHANNEL_SWITCH_FAILURE = 15,
+ QCA_DISCONNECT_REASON_USER_TRIGGERED = 16,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_driver_disconnect_reason - Defines attributes
+ * used by %QCA_NL80211_VENDOR_SUBCMD_DRIVER_DISCONNECT_REASON vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASCON_CODE: u32 attribute.
+ * This attribute represents the driver specific reason codes (local
+ * driver/firmware initiated reasons for disconnection) defined
+ * in enum qca_disconnect_reason_codes.
+ */
+enum qca_wlan_vendor_attr_driver_disconnect_reason {
+ QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASCON_CODE = 1,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_MAX =
+ QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_AFTER_LAST - 1,
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index 0d56e55..543640d 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -12,38 +12,27 @@
#include "utils/const_time.h"
#include "crypto/crypto.h"
#include "crypto/sha256.h"
+#include "crypto/sha384.h"
+#include "crypto/sha512.h"
#include "crypto/random.h"
#include "crypto/dh_groups.h"
#include "ieee802_11_defs.h"
+#include "dragonfly.h"
#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)) {
+#ifdef CONFIG_TESTING_OPTIONS
+ /* Allow all groups for testing purposes in non-production builds. */
+#else /* CONFIG_TESTING_OPTIONS */
+ if (!dragonfly_suitable_group(group, 0)) {
wpa_printf(MSG_DEBUG, "SAE: Reject unsuitable group %d", group);
return -1;
}
+#endif /* CONFIG_TESTING_OPTIONS */
sae_clear_data(sae);
tmp = sae->tmp = os_zalloc(sizeof(*tmp));
@@ -58,6 +47,7 @@
sae->group = group;
tmp->prime_len = crypto_ec_prime_len(tmp->ec);
tmp->prime = crypto_ec_get_prime(tmp->ec);
+ tmp->order_len = crypto_ec_order_len(tmp->ec);
tmp->order = crypto_ec_get_order(tmp->ec);
return 0;
}
@@ -82,6 +72,7 @@
}
tmp->prime = tmp->prime_buf;
+ tmp->order_len = tmp->dh->order_len;
tmp->order_buf = crypto_bignum_init_set(tmp->dh->order,
tmp->dh->order_len);
if (tmp->order_buf == NULL) {
@@ -118,6 +109,8 @@
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);
+ wpabuf_free(tmp->own_rejected_groups);
+ wpabuf_free(tmp->peer_rejected_groups);
os_free(tmp->pw_id);
bin_clear_free(tmp, sizeof(*tmp));
sae->tmp = NULL;
@@ -130,62 +123,11 @@
return;
sae_clear_temp_data(sae);
crypto_bignum_deinit(sae->peer_commit_scalar, 0);
+ crypto_bignum_deinit(sae->peer_commit_scalar_accepted, 0);
os_memset(sae, 0, sizeof(*sae));
}
-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;
-}
-
-
-static struct crypto_bignum * sae_get_rand(struct sae_data *sae)
-{
- u8 val[SAE_MAX_PRIME_LEN];
- int iter = 0;
- struct crypto_bignum *bn = NULL;
- int order_len_bits = crypto_bignum_bits(sae->tmp->order);
- size_t order_len = (order_len_bits + 7) / 8;
-
- if (order_len > sizeof(val))
- return NULL;
-
- for (;;) {
- if (iter++ > 100 || random_get_bytes(val, order_len) < 0)
- return NULL;
- if (order_len_bits % 8)
- buf_shift_right(val, order_len, 8 - order_len_bits % 8);
- bn = crypto_bignum_init_set(val, order_len);
- if (bn == NULL)
- return NULL;
- if (crypto_bignum_is_zero(bn) ||
- crypto_bignum_is_one(bn) ||
- crypto_bignum_cmp(bn, sae->tmp->order) >= 0) {
- crypto_bignum_deinit(bn, 0);
- continue;
- }
- break;
- }
-
- os_memset(val, 0, order_len);
- return bn;
-}
-
-
-static struct crypto_bignum * sae_get_rand_and_mask(struct sae_data *sae)
-{
- crypto_bignum_deinit(sae->tmp->sae_rand, 1);
- sae->tmp->sae_rand = sae_get_rand(sae);
- if (sae->tmp->sae_rand == NULL)
- return NULL;
- return sae_get_rand(sae);
-}
-
-
static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key)
{
wpa_printf(MSG_DEBUG, "SAE: PWE derivation - addr1=" MACSTR
@@ -200,103 +142,6 @@
}
-static struct crypto_bignum *
-get_rand_1_to_p_1(const u8 *prime, size_t prime_len, size_t prime_bits,
- int *r_odd)
-{
- for (;;) {
- struct crypto_bignum *r;
- u8 tmp[SAE_MAX_ECC_PRIME_LEN];
-
- if (random_get_bytes(tmp, prime_len) < 0)
- break;
- if (prime_bits % 8)
- buf_shift_right(tmp, prime_len, 8 - prime_bits % 8);
- if (os_memcmp(tmp, prime, prime_len) >= 0)
- continue;
- r = crypto_bignum_init_set(tmp, prime_len);
- if (!r)
- break;
- if (crypto_bignum_is_zero(r)) {
- crypto_bignum_deinit(r, 0);
- continue;
- }
-
- *r_odd = tmp[prime_len - 1] & 0x01;
- return r;
- }
-
- return NULL;
-}
-
-
-static int is_quadratic_residue_blind(struct sae_data *sae,
- const u8 *prime, size_t bits,
- const u8 *qr, const u8 *qnr,
- const struct crypto_bignum *y_sqr)
-{
- 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
- * whether it is a quadratic residue modulo p to avoid leaking
- * timing information while determining the Legendre symbol.
- *
- * v = y_sqr
- * r = a random number between 1 and p-1, inclusive
- * num = (v * r * r) modulo p
- */
- r = get_rand_1_to_p_1(prime, prime_len, bits, &r_odd);
- if (!r)
- return -1;
-
- num = crypto_bignum_init();
- if (!num ||
- crypto_bignum_mulmod(y_sqr, r, sae->tmp->prime, num) < 0 ||
- crypto_bignum_mulmod(num, r, sae->tmp->prime, num) < 0)
- goto fail;
-
- /*
- * 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;
- }
- /* 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 u8 *qr, const u8 *qnr,
u8 *pwd_value)
@@ -304,6 +149,8 @@
struct crypto_bignum *y_sqr, *x_cand;
int res;
size_t bits;
+ int cmp_prime;
+ unsigned int in_range;
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
@@ -317,8 +164,13 @@
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
pwd_value, sae->tmp->prime_len);
- if (const_time_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0)
- return 0;
+ cmp_prime = const_time_memcmp(pwd_value, prime, sae->tmp->prime_len);
+ /* Create a const_time mask for selection based on prf result
+ * being smaller than prime. */
+ in_range = const_time_fill_msb((unsigned int) cmp_prime);
+ /* The algorithm description would skip the next steps if
+ * cmp_prime >= 0 (reutnr 0 here), but go through them regardless to
+ * minimize externally observable differences in behavior. */
x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
if (!x_cand)
@@ -328,9 +180,12 @@
if (!y_sqr)
return -1;
- res = is_quadratic_residue_blind(sae, prime, bits, qr, qnr, y_sqr);
+ res = dragonfly_is_quadratic_residue_blind(sae->tmp->ec, qr, qnr,
+ y_sqr);
crypto_bignum_deinit(y_sqr, 1);
- return res;
+ if (res < 0)
+ return res;
+ return const_time_select_int(in_range, res, 0);
}
@@ -423,47 +278,11 @@
}
-static int get_random_qr_qnr(const u8 *prime, size_t prime_len,
- const struct crypto_bignum *prime_bn,
- size_t prime_bits, struct crypto_bignum **qr,
- struct crypto_bignum **qnr)
-{
- *qr = NULL;
- *qnr = NULL;
-
- while (!(*qr) || !(*qnr)) {
- u8 tmp[SAE_MAX_ECC_PRIME_LEN];
- struct crypto_bignum *q;
- int res;
-
- if (random_get_bytes(tmp, prime_len) < 0)
- break;
- if (prime_bits % 8)
- buf_shift_right(tmp, prime_len, 8 - prime_bits % 8);
- if (os_memcmp(tmp, prime, prime_len) >= 0)
- continue;
- q = crypto_bignum_init_set(tmp, prime_len);
- if (!q)
- break;
- res = crypto_bignum_legendre(q, prime_bn);
-
- if (res == 1 && !(*qr))
- *qr = q;
- else if (res == -1 && !(*qnr))
- *qnr = q;
- else
- crypto_bignum_deinit(q, 0);
- }
-
- return (*qr && *qnr) ? 0 : -1;
-}
-
-
static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
const u8 *addr2, const u8 *password,
size_t password_len, const char *identifier)
{
- u8 counter, k = 40;
+ u8 counter, k;
u8 addrs[2 * ETH_ALEN];
const u8 *addr[3];
size_t len[3];
@@ -477,7 +296,6 @@
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 = -1;
u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
* mask */
@@ -494,14 +312,12 @@
if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
prime_len) < 0)
goto fail;
- bits = crypto_ec_prime_len_bits(sae->tmp->ec);
/*
* Create a random quadratic residue (qr) and quadratic non-residue
* (qnr) modulo p for blinding purposes during the loop.
*/
- if (get_random_qr_qnr(prime, prime_len, sae->tmp->prime, bits,
- &qr, &qnr) < 0 ||
+ if (dragonfly_get_random_qr_qnr(sae->tmp->prime, &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;
@@ -537,6 +353,8 @@
* attacks that attempt to determine the number of iterations required
* in the loop.
*/
+ k = dragonfly_min_pwe_loop_iter(sae->group);
+
for (counter = 1; counter <= k || !found; counter++) {
u8 pwd_seed[SHA256_MAC_LEN];
@@ -618,13 +436,6 @@
}
-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, const char *identifier)
@@ -673,7 +484,7 @@
len[num_elem] = sizeof(counter);
num_elem++;
- k = sae_modp_group_require_masking(sae->group) ? 40 : 1;
+ k = dragonfly_min_pwe_loop_iter(sae->group);
for (counter = 1; counter <= k || !found; counter++) {
u8 pwd_seed[SHA256_MAC_LEN];
@@ -719,6 +530,748 @@
}
+static int hkdf_extract(size_t hash_len, const u8 *salt, size_t salt_len,
+ size_t num_elem, const u8 *addr[], const size_t len[],
+ u8 *prk)
+{
+ if (hash_len == 32)
+ return hmac_sha256_vector(salt, salt_len, num_elem, addr, len,
+ prk);
+#ifdef CONFIG_SHA384
+ if (hash_len == 48)
+ return hmac_sha384_vector(salt, salt_len, num_elem, addr, len,
+ prk);
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+ if (hash_len == 64)
+ return hmac_sha512_vector(salt, salt_len, num_elem, addr, len,
+ prk);
+#endif /* CONFIG_SHA512 */
+ return -1;
+}
+
+
+static int hkdf_expand(size_t hash_len, const u8 *prk, size_t prk_len,
+ const char *info, u8 *okm, size_t okm_len)
+{
+ size_t info_len = os_strlen(info);
+
+ if (hash_len == 32)
+ return hmac_sha256_kdf(prk, prk_len, NULL,
+ (const u8 *) info, info_len,
+ okm, okm_len);
+#ifdef CONFIG_SHA384
+ if (hash_len == 48)
+ return hmac_sha384_kdf(prk, prk_len, NULL,
+ (const u8 *) info, info_len,
+ okm, okm_len);
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+ if (hash_len == 64)
+ return hmac_sha512_kdf(prk, prk_len, NULL,
+ (const u8 *) info, info_len,
+ okm, okm_len);
+#endif /* CONFIG_SHA512 */
+ return -1;
+}
+
+
+static int sswu_curve_param(int group, int *z)
+{
+ switch (group) {
+ case 19:
+ *z = -10;
+ return 0;
+ case 20:
+ *z = -12;
+ return 0;
+ case 21:
+ *z = -4;
+ return 0;
+ case 25:
+ case 29:
+ *z = -5;
+ return 0;
+ case 26:
+ *z = 31;
+ return 0;
+ case 28:
+ *z = -2;
+ return 0;
+ case 30:
+ *z = 7;
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static void debug_print_bignum(const char *title, const struct crypto_bignum *a,
+ size_t prime_len)
+{
+ u8 *bin;
+
+ bin = os_malloc(prime_len);
+ if (bin && crypto_bignum_to_bin(a, bin, prime_len, prime_len) >= 0)
+ wpa_hexdump_key(MSG_DEBUG, title, bin, prime_len);
+ else
+ wpa_printf(MSG_DEBUG, "Could not print bignum (%s)", title);
+ bin_clear_free(bin, prime_len);
+}
+
+
+static struct crypto_ec_point * sswu(struct crypto_ec *ec, int group,
+ const struct crypto_bignum *u)
+{
+ int z_int;
+ const struct crypto_bignum *a, *b, *prime;
+ struct crypto_bignum *u2, *t1, *t2, *z, *t, *zero, *one, *two, *three,
+ *x1a, *x1b, *y = NULL;
+ struct crypto_bignum *x1 = NULL, *x2, *gx1, *gx2, *v = NULL;
+ unsigned int m_is_zero, is_qr, is_eq;
+ size_t prime_len;
+ u8 bin[SAE_MAX_ECC_PRIME_LEN];
+ u8 bin1[SAE_MAX_ECC_PRIME_LEN];
+ u8 bin2[SAE_MAX_ECC_PRIME_LEN];
+ u8 x_y[2 * SAE_MAX_ECC_PRIME_LEN];
+ struct crypto_ec_point *p = NULL;
+
+ if (sswu_curve_param(group, &z_int) < 0)
+ return NULL;
+
+ prime = crypto_ec_get_prime(ec);
+ prime_len = crypto_ec_prime_len(ec);
+ a = crypto_ec_get_a(ec);
+ b = crypto_ec_get_b(ec);
+
+ u2 = crypto_bignum_init();
+ t1 = crypto_bignum_init();
+ t2 = crypto_bignum_init();
+ z = crypto_bignum_init_uint(abs(z_int));
+ t = crypto_bignum_init();
+ zero = crypto_bignum_init_uint(0);
+ one = crypto_bignum_init_uint(1);
+ two = crypto_bignum_init_uint(2);
+ three = crypto_bignum_init_uint(3);
+ x1a = crypto_bignum_init();
+ x1b = crypto_bignum_init();
+ x2 = crypto_bignum_init();
+ gx1 = crypto_bignum_init();
+ gx2 = crypto_bignum_init();
+ if (!u2 || !t1 || !t2 || !z || !t || !zero || !one || !two || !three ||
+ !x1a || !x1b || !x2 || !gx1 || !gx2)
+ goto fail;
+
+ if (z_int < 0 && crypto_bignum_sub(prime, z, z) < 0)
+ goto fail;
+
+ /* m = z^2 * u^4 + z * u^2 */
+ /* --> tmp = z * u^2, m = tmp^2 + tmp */
+
+ /* u2 = u^2
+ * t1 = z * u2
+ * t2 = t1^2
+ * m = t1 = t1 + t2 */
+ if (crypto_bignum_sqrmod(u, prime, u2) < 0 ||
+ crypto_bignum_mulmod(z, u2, prime, t1) < 0 ||
+ crypto_bignum_sqrmod(t1, prime, t2) < 0 ||
+ crypto_bignum_addmod(t1, t2, prime, t1) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: m", t1, prime_len);
+
+ /* l = CEQ(m, 0)
+ * t = CSEL(l, 0, inverse(m); where inverse(x) is calculated as
+ * x^(p-2) modulo p which will handle m == 0 case correctly */
+ /* TODO: Make sure crypto_bignum_is_zero() is constant time */
+ m_is_zero = const_time_eq(crypto_bignum_is_zero(t1), 1);
+ /* t = m^(p-2) modulo p */
+ if (crypto_bignum_sub(prime, two, t2) < 0 ||
+ crypto_bignum_exptmod(t1, t2, prime, t) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: t", t, prime_len);
+
+ /* b / (z * a) */
+ if (crypto_bignum_mulmod(z, a, prime, t1) < 0 ||
+ crypto_bignum_inverse(t1, prime, t1) < 0 ||
+ crypto_bignum_mulmod(b, t1, prime, x1a) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: x1a = b / (z * a)", x1a, prime_len);
+
+ /* (-b/a) * (1 + t) */
+ if (crypto_bignum_sub(prime, b, t1) < 0 ||
+ crypto_bignum_inverse(a, prime, t2) < 0 ||
+ crypto_bignum_mulmod(t1, t2, prime, t1) < 0 ||
+ crypto_bignum_addmod(one, t, prime, t2) < 0 ||
+ crypto_bignum_mulmod(t1, t2, prime, x1b) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: x1b = (-b/a) * (1 + t)", x1b, prime_len);
+
+ /* x1 = CSEL(CEQ(m, 0), x1a, x1b) */
+ if (crypto_bignum_to_bin(x1a, bin1, sizeof(bin1), prime_len) < 0 ||
+ crypto_bignum_to_bin(x1b, bin2, sizeof(bin2), prime_len) < 0)
+ goto fail;
+ const_time_select_bin(m_is_zero, bin1, bin2, prime_len, bin);
+ x1 = crypto_bignum_init_set(bin, prime_len);
+ debug_print_bignum("SSWU: x1 = CSEL(l, x1a, x1b)", x1, prime_len);
+
+ /* gx1 = x1^3 + a * x1 + b */
+ if (crypto_bignum_exptmod(x1, three, prime, t1) < 0 ||
+ crypto_bignum_mulmod(a, x1, prime, t2) < 0 ||
+ crypto_bignum_addmod(t1, t2, prime, t1) < 0 ||
+ crypto_bignum_addmod(t1, b, prime, gx1) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: gx1 = x1^3 + a * x1 + b", gx1, prime_len);
+
+ /* x2 = z * u^2 * x1 */
+ if (crypto_bignum_mulmod(z, u2, prime, t1) < 0 ||
+ crypto_bignum_mulmod(t1, x1, prime, x2) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: x2 = z * u^2 * x1", x2, prime_len);
+
+ /* gx2 = x2^3 + a * x2 + b */
+ if (crypto_bignum_exptmod(x2, three, prime, t1) < 0 ||
+ crypto_bignum_mulmod(a, x2, prime, t2) < 0 ||
+ crypto_bignum_addmod(t1, t2, prime, t1) < 0 ||
+ crypto_bignum_addmod(t1, b, prime, gx2) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: gx2 = x2^3 + a * x2 + b", gx2, prime_len);
+
+ /* l = gx1 is a quadratic residue modulo p
+ * --> gx1^((p-1)/2) modulo p is zero or one */
+ if (crypto_bignum_sub(prime, one, t1) < 0 ||
+ crypto_bignum_rshift(t1, 1, t1) < 0 ||
+ crypto_bignum_exptmod(gx1, t1, prime, t1) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: gx1^((p-1)/2) modulo p", t1, prime_len);
+ is_qr = const_time_eq(crypto_bignum_is_zero(t1) |
+ crypto_bignum_is_one(t1), 1);
+
+ /* v = CSEL(l, gx1, gx2) */
+ if (crypto_bignum_to_bin(gx1, bin1, sizeof(bin1), prime_len) < 0 ||
+ crypto_bignum_to_bin(gx2, bin2, sizeof(bin2), prime_len) < 0)
+ goto fail;
+ const_time_select_bin(is_qr, bin1, bin2, prime_len, bin);
+ v = crypto_bignum_init_set(bin, prime_len);
+ debug_print_bignum("SSWU: v = CSEL(l, gx1, gx2)", v, prime_len);
+
+ /* x = CSEL(l, x1, x2) */
+ if (crypto_bignum_to_bin(x1, bin1, sizeof(bin1), prime_len) < 0 ||
+ crypto_bignum_to_bin(x2, bin2, sizeof(bin2), prime_len) < 0)
+ goto fail;
+ const_time_select_bin(is_qr, bin1, bin2, prime_len, x_y);
+ wpa_hexdump_key(MSG_DEBUG, "SSWU: x = CSEL(l, x1, x2)", x_y, prime_len);
+
+ /* y = sqrt(v)
+ * For prime p such that p = 3 mod 4 --> v^((p+1)/4) */
+ if (crypto_bignum_to_bin(prime, bin1, sizeof(bin1), prime_len) < 0)
+ goto fail;
+ if ((bin1[prime_len - 1] & 0x03) != 3) {
+ wpa_printf(MSG_DEBUG, "SSWU: prime does not have p = 3 mod 4");
+ goto fail;
+ }
+ y = crypto_bignum_init();
+ if (!y ||
+ crypto_bignum_add(prime, one, t1) < 0 ||
+ crypto_bignum_rshift(t1, 2, t1) < 0 ||
+ crypto_bignum_exptmod(v, t1, prime, y) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: y = sqrt(v)", y, prime_len);
+
+ /* l = CEQ(LSB(u), LSB(y)) */
+ if (crypto_bignum_to_bin(u, bin1, sizeof(bin1), prime_len) < 0 ||
+ crypto_bignum_to_bin(y, bin2, sizeof(bin2), prime_len) < 0)
+ goto fail;
+ is_eq = const_time_eq(bin1[prime_len - 1] & 0x01,
+ bin2[prime_len - 1] & 0x01);
+
+ /* P = CSEL(l, (x,y), (x, p-y)) */
+ if (crypto_bignum_sub(prime, y, t1) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: p - y", t1, prime_len);
+ if (crypto_bignum_to_bin(y, bin1, sizeof(bin1), prime_len) < 0 ||
+ crypto_bignum_to_bin(t1, bin2, sizeof(bin2), prime_len) < 0)
+ goto fail;
+ const_time_select_bin(is_eq, bin1, bin2, prime_len, &x_y[prime_len]);
+
+ /* output P */
+ wpa_hexdump_key(MSG_DEBUG, "SSWU: P.x", x_y, prime_len);
+ wpa_hexdump_key(MSG_DEBUG, "SSWU: P.y", &x_y[prime_len], prime_len);
+ p = crypto_ec_point_from_bin(ec, x_y);
+
+fail:
+ crypto_bignum_deinit(u2, 1);
+ crypto_bignum_deinit(t1, 1);
+ crypto_bignum_deinit(t2, 1);
+ crypto_bignum_deinit(z, 0);
+ crypto_bignum_deinit(t, 1);
+ crypto_bignum_deinit(x1a, 1);
+ crypto_bignum_deinit(x1b, 1);
+ crypto_bignum_deinit(x1, 1);
+ crypto_bignum_deinit(x2, 1);
+ crypto_bignum_deinit(gx1, 1);
+ crypto_bignum_deinit(gx2, 1);
+ crypto_bignum_deinit(y, 1);
+ crypto_bignum_deinit(v, 1);
+ crypto_bignum_deinit(zero, 0);
+ crypto_bignum_deinit(one, 0);
+ crypto_bignum_deinit(two, 0);
+ crypto_bignum_deinit(three, 0);
+ forced_memzero(bin, sizeof(bin));
+ forced_memzero(bin1, sizeof(bin1));
+ forced_memzero(bin2, sizeof(bin2));
+ forced_memzero(x_y, sizeof(x_y));
+ return p;
+}
+
+
+static int sae_pwd_seed(size_t hash_len, const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier, u8 *pwd_seed)
+{
+ const u8 *addr[2];
+ size_t len[2];
+ size_t num_elem;
+
+ /* pwd-seed = HKDF-Extract(ssid, password [ || identifier ]) */
+ addr[0] = password;
+ len[0] = password_len;
+ num_elem = 1;
+ wpa_hexdump_ascii(MSG_DEBUG, "SAE: SSID", ssid, ssid_len);
+ wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
+ password, password_len);
+ if (identifier) {
+ wpa_printf(MSG_DEBUG, "SAE: password identifier: %s",
+ identifier);
+ addr[num_elem] = (const u8 *) identifier;
+ len[num_elem] = os_strlen(identifier);
+ num_elem++;
+ }
+ if (hkdf_extract(hash_len, ssid, ssid_len, num_elem, addr, len,
+ pwd_seed) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, hash_len);
+ return 0;
+}
+
+
+size_t sae_ecc_prime_len_2_hash_len(size_t prime_len)
+{
+ if (prime_len <= 256 / 8)
+ return 32;
+ if (prime_len <= 384 / 8)
+ return 48;
+ return 64;
+}
+
+
+static struct crypto_ec_point *
+sae_derive_pt_ecc(struct crypto_ec *ec, int group,
+ const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier)
+{
+ u8 pwd_seed[64];
+ u8 pwd_value[SAE_MAX_ECC_PRIME_LEN * 2];
+ size_t pwd_value_len, hash_len, prime_len;
+ const struct crypto_bignum *prime;
+ struct crypto_bignum *bn = NULL;
+ struct crypto_ec_point *p1 = NULL, *p2 = NULL, *pt = NULL;
+
+ prime = crypto_ec_get_prime(ec);
+ prime_len = crypto_ec_prime_len(ec);
+ if (prime_len > SAE_MAX_ECC_PRIME_LEN)
+ goto fail;
+ hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
+
+ /* len = olen(p) + ceil(olen(p)/2) */
+ pwd_value_len = prime_len + (prime_len + 1) / 2;
+
+ if (sae_pwd_seed(hash_len, ssid, ssid_len, password, password_len,
+ identifier, pwd_seed) < 0)
+ goto fail;
+
+ /* pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element u1 P1", len)
+ */
+ if (hkdf_expand(hash_len, pwd_seed, hash_len,
+ "SAE Hash to Element u1 P1", pwd_value, pwd_value_len) <
+ 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value (u1 P1)",
+ pwd_value, pwd_value_len);
+
+ /* u1 = pwd-value modulo p */
+ bn = crypto_bignum_init_set(pwd_value, pwd_value_len);
+ if (!bn || crypto_bignum_mod(bn, prime, bn) < 0 ||
+ crypto_bignum_to_bin(bn, pwd_value, sizeof(pwd_value),
+ prime_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: u1", pwd_value, prime_len);
+
+ /* P1 = SSWU(u1) */
+ p1 = sswu(ec, group, bn);
+ if (!p1)
+ goto fail;
+
+ /* pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element u2 P2", len)
+ */
+ if (hkdf_expand(hash_len, pwd_seed, hash_len,
+ "SAE Hash to Element u2 P2", pwd_value,
+ pwd_value_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value (u2 P2)",
+ pwd_value, pwd_value_len);
+
+ /* u2 = pwd-value modulo p */
+ crypto_bignum_deinit(bn, 1);
+ bn = crypto_bignum_init_set(pwd_value, pwd_value_len);
+ if (!bn || crypto_bignum_mod(bn, prime, bn) < 0 ||
+ crypto_bignum_to_bin(bn, pwd_value, sizeof(pwd_value),
+ prime_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: u2", pwd_value, prime_len);
+
+ /* P2 = SSWU(u2) */
+ p2 = sswu(ec, group, bn);
+ if (!p2)
+ goto fail;
+
+ /* PT = elem-op(P1, P2) */
+ pt = crypto_ec_point_init(ec);
+ if (!pt)
+ goto fail;
+ if (crypto_ec_point_add(ec, p1, p2, pt) < 0) {
+ crypto_ec_point_deinit(pt, 1);
+ pt = NULL;
+ }
+
+fail:
+ forced_memzero(pwd_seed, sizeof(pwd_seed));
+ forced_memzero(pwd_value, sizeof(pwd_value));
+ crypto_bignum_deinit(bn, 1);
+ crypto_ec_point_deinit(p1, 1);
+ crypto_ec_point_deinit(p2, 1);
+ return pt;
+}
+
+
+size_t sae_ffc_prime_len_2_hash_len(size_t prime_len)
+{
+ if (prime_len <= 2048 / 8)
+ return 32;
+ if (prime_len <= 3072 / 8)
+ return 48;
+ return 64;
+}
+
+
+static struct crypto_bignum *
+sae_derive_pt_ffc(const struct dh_group *dh, int group,
+ const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier)
+{
+ size_t hash_len, prime_len, pwd_value_len;
+ struct crypto_bignum *prime, *order;
+ struct crypto_bignum *one = NULL, *two = NULL, *bn = NULL, *tmp = NULL,
+ *pt = NULL;
+ u8 pwd_seed[64];
+ u8 pwd_value[SAE_MAX_PRIME_LEN + SAE_MAX_PRIME_LEN / 2];
+
+ prime = crypto_bignum_init_set(dh->prime, dh->prime_len);
+ order = crypto_bignum_init_set(dh->order, dh->order_len);
+ if (!prime || !order)
+ goto fail;
+ prime_len = dh->prime_len;
+ if (prime_len > SAE_MAX_PRIME_LEN)
+ goto fail;
+ hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
+
+ /* len = olen(p) + ceil(olen(p)/2) */
+ pwd_value_len = prime_len + (prime_len + 1) / 2;
+ if (pwd_value_len > sizeof(pwd_value))
+ goto fail;
+
+ if (sae_pwd_seed(hash_len, ssid, ssid_len, password, password_len,
+ identifier, pwd_seed) < 0)
+ goto fail;
+
+ /* pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element", len) */
+ if (hkdf_expand(hash_len, pwd_seed, hash_len,
+ "SAE Hash to Element", pwd_value, pwd_value_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
+ pwd_value, pwd_value_len);
+
+ /* pwd-value = (pwd-value modulo (p-2)) + 2 */
+ bn = crypto_bignum_init_set(pwd_value, pwd_value_len);
+ one = crypto_bignum_init_uint(1);
+ two = crypto_bignum_init_uint(2);
+ tmp = crypto_bignum_init();
+ if (!bn || !one || !two || !tmp ||
+ crypto_bignum_sub(prime, two, tmp) < 0 ||
+ crypto_bignum_mod(bn, tmp, bn) < 0 ||
+ crypto_bignum_add(bn, two, bn) < 0 ||
+ crypto_bignum_to_bin(bn, pwd_value, sizeof(pwd_value),
+ prime_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value(reduced)",
+ pwd_value, prime_len);
+
+ /* PT = pwd-value^((p-1)/q) modulo p */
+ pt = crypto_bignum_init();
+ if (!pt ||
+ crypto_bignum_sub(prime, one, tmp) < 0 ||
+ crypto_bignum_div(tmp, order, tmp) < 0 ||
+ crypto_bignum_exptmod(bn, tmp, prime, pt) < 0) {
+ crypto_bignum_deinit(pt, 1);
+ pt = NULL;
+ goto fail;
+ }
+ debug_print_bignum("SAE: PT", pt, prime_len);
+
+fail:
+ forced_memzero(pwd_seed, sizeof(pwd_seed));
+ forced_memzero(pwd_value, sizeof(pwd_value));
+ crypto_bignum_deinit(bn, 1);
+ crypto_bignum_deinit(tmp, 1);
+ crypto_bignum_deinit(one, 0);
+ crypto_bignum_deinit(two, 0);
+ crypto_bignum_deinit(prime, 0);
+ crypto_bignum_deinit(order, 0);
+ return pt;
+}
+
+
+static struct sae_pt *
+sae_derive_pt_group(int group, const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier)
+{
+ struct sae_pt *pt;
+
+ wpa_printf(MSG_DEBUG, "SAE: Derive PT - group %d", group);
+
+ pt = os_zalloc(sizeof(*pt));
+ if (!pt)
+ return NULL;
+
+ pt->group = group;
+ pt->ec = crypto_ec_init(group);
+ if (pt->ec) {
+ pt->ecc_pt = sae_derive_pt_ecc(pt->ec, group, ssid, ssid_len,
+ password, password_len,
+ identifier);
+ if (!pt->ecc_pt) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to derive PT");
+ goto fail;
+ }
+
+ return pt;
+ }
+
+ pt->dh = dh_groups_get(group);
+ if (!pt->dh) {
+ wpa_printf(MSG_DEBUG, "SAE: Unsupported group %d", group);
+ goto fail;
+ }
+
+ pt->ffc_pt = sae_derive_pt_ffc(pt->dh, group, ssid, ssid_len,
+ password, password_len, identifier);
+ if (!pt->ffc_pt) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to derive PT");
+ goto fail;
+ }
+
+ return pt;
+fail:
+ sae_deinit_pt(pt);
+ return NULL;
+}
+
+
+struct sae_pt * sae_derive_pt(int *groups, const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier)
+{
+ struct sae_pt *pt = NULL, *last = NULL, *tmp;
+ int default_groups[] = { 19, 0 };
+ int i;
+
+ if (!groups)
+ groups = default_groups;
+ for (i = 0; groups[i] > 0; i++) {
+ tmp = sae_derive_pt_group(groups[i], ssid, ssid_len, password,
+ password_len, identifier);
+ if (!tmp)
+ continue;
+
+ if (last)
+ last->next = tmp;
+ else
+ pt = tmp;
+ last = tmp;
+ }
+
+ return pt;
+}
+
+
+static void sae_max_min_addr(const u8 *addr[], size_t len[],
+ const u8 *addr1, const u8 *addr2)
+{
+ len[0] = ETH_ALEN;
+ len[1] = ETH_ALEN;
+ if (os_memcmp(addr1, addr2, ETH_ALEN) > 0) {
+ addr[0] = addr1;
+ addr[1] = addr2;
+ } else {
+ addr[0] = addr2;
+ addr[1] = addr1;
+ }
+}
+
+
+struct crypto_ec_point *
+sae_derive_pwe_from_pt_ecc(const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2)
+{
+ u8 bin[SAE_MAX_ECC_PRIME_LEN * 2];
+ size_t prime_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 salt[64], hash[64];
+ size_t hash_len;
+ const struct crypto_bignum *order;
+ struct crypto_bignum *tmp = NULL, *val = NULL, *one = NULL;
+ struct crypto_ec_point *pwe = NULL;
+
+ wpa_printf(MSG_DEBUG, "SAE: Derive PWE from PT");
+ prime_len = crypto_ec_prime_len(pt->ec);
+ if (crypto_ec_point_to_bin(pt->ec, pt->ecc_pt,
+ bin, bin + prime_len) < 0)
+ return NULL;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: PT.x", bin, prime_len);
+ wpa_hexdump_key(MSG_DEBUG, "SAE: PT.y", bin + prime_len, prime_len);
+
+ sae_max_min_addr(addr, len, addr1, addr2);
+
+ /* val = H(0^n,
+ * MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC)) */
+ wpa_printf(MSG_DEBUG, "SAE: val = H(0^n, MAX(addrs) || MIN(addrs))");
+ hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
+ os_memset(salt, 0, hash_len);
+ if (hkdf_extract(hash_len, salt, hash_len, 2, addr, len, hash) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "SAE: val", hash, hash_len);
+
+ /* val = val modulo (q - 1) + 1 */
+ order = crypto_ec_get_order(pt->ec);
+ tmp = crypto_bignum_init();
+ val = crypto_bignum_init_set(hash, hash_len);
+ one = crypto_bignum_init_uint(1);
+ if (!tmp || !val || !one ||
+ crypto_bignum_sub(order, one, tmp) < 0 ||
+ crypto_bignum_mod(val, tmp, val) < 0 ||
+ crypto_bignum_add(val, one, val) < 0)
+ goto fail;
+ debug_print_bignum("SAE: val(reduced to 1..q-1)", val, prime_len);
+
+ /* PWE = scalar-op(val, PT) */
+ pwe = crypto_ec_point_init(pt->ec);
+ if (!pwe ||
+ crypto_ec_point_mul(pt->ec, pt->ecc_pt, val, pwe) < 0 ||
+ crypto_ec_point_to_bin(pt->ec, pwe, bin, bin + prime_len) < 0) {
+ crypto_ec_point_deinit(pwe, 1);
+ pwe = NULL;
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "SAE: PWE.x", bin, prime_len);
+ wpa_hexdump_key(MSG_DEBUG, "SAE: PWE.y", bin + prime_len, prime_len);
+
+fail:
+ crypto_bignum_deinit(tmp, 1);
+ crypto_bignum_deinit(val, 1);
+ crypto_bignum_deinit(one, 0);
+ return pwe;
+}
+
+
+struct crypto_bignum *
+sae_derive_pwe_from_pt_ffc(const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2)
+{
+ size_t prime_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 salt[64], hash[64];
+ size_t hash_len;
+ struct crypto_bignum *tmp = NULL, *val = NULL, *one = NULL;
+ struct crypto_bignum *pwe = NULL, *order = NULL, *prime = NULL;
+
+ wpa_printf(MSG_DEBUG, "SAE: Derive PWE from PT");
+ prime = crypto_bignum_init_set(pt->dh->prime, pt->dh->prime_len);
+ order = crypto_bignum_init_set(pt->dh->order, pt->dh->order_len);
+ if (!prime || !order)
+ goto fail;
+ prime_len = pt->dh->prime_len;
+
+ sae_max_min_addr(addr, len, addr1, addr2);
+
+ /* val = H(0^n,
+ * MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC)) */
+ wpa_printf(MSG_DEBUG, "SAE: val = H(0^n, MAX(addrs) || MIN(addrs))");
+ hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
+ os_memset(salt, 0, hash_len);
+ if (hkdf_extract(hash_len, salt, hash_len, 2, addr, len, hash) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "SAE: val", hash, hash_len);
+
+ /* val = val modulo (q - 1) + 1 */
+ tmp = crypto_bignum_init();
+ val = crypto_bignum_init_set(hash, hash_len);
+ one = crypto_bignum_init_uint(1);
+ if (!tmp || !val || !one ||
+ crypto_bignum_sub(order, one, tmp) < 0 ||
+ crypto_bignum_mod(val, tmp, val) < 0 ||
+ crypto_bignum_add(val, one, val) < 0)
+ goto fail;
+ debug_print_bignum("SAE: val(reduced to 1..q-1)", val, prime_len);
+
+ /* PWE = scalar-op(val, PT) */
+ pwe = crypto_bignum_init();
+ if (!pwe || crypto_bignum_exptmod(pt->ffc_pt, val, prime, pwe) < 0) {
+ crypto_bignum_deinit(pwe, 1);
+ pwe = NULL;
+ goto fail;
+ }
+ debug_print_bignum("SAE: PWE", pwe, prime_len);
+
+fail:
+ crypto_bignum_deinit(tmp, 1);
+ crypto_bignum_deinit(val, 1);
+ crypto_bignum_deinit(one, 0);
+ crypto_bignum_deinit(prime, 0);
+ crypto_bignum_deinit(order, 0);
+ return pwe;
+}
+
+
+void sae_deinit_pt(struct sae_pt *pt)
+{
+ struct sae_pt *prev;
+
+ while (pt) {
+ crypto_ec_point_deinit(pt->ecc_pt, 1);
+ crypto_bignum_deinit(pt->ffc_pt, 1);
+ crypto_ec_deinit(pt->ec);
+ prev = pt;
+ pt = pt->next;
+ os_free(prev);
+ }
+}
+
+
static int sae_derive_commit_element_ecc(struct sae_data *sae,
struct crypto_bignum *mask)
{
@@ -768,48 +1321,23 @@
static int sae_derive_commit(struct sae_data *sae)
{
struct crypto_bignum *mask;
- int ret = -1;
- unsigned int counter = 0;
+ int ret;
- do {
- counter++;
- if (counter > 100) {
- /*
- * This cannot really happen in practice if the random
- * number generator is working. Anyway, to avoid even a
- * theoretical infinite loop, break out after 100
- * attemps.
- */
- return -1;
- }
-
- mask = sae_get_rand_and_mask(sae);
- if (mask == NULL) {
- wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask");
- return -1;
- }
-
- /* commit-scalar = (rand + mask) modulo r */
- if (!sae->tmp->own_commit_scalar) {
- sae->tmp->own_commit_scalar = crypto_bignum_init();
- if (!sae->tmp->own_commit_scalar)
- goto fail;
- }
- crypto_bignum_add(sae->tmp->sae_rand, mask,
- sae->tmp->own_commit_scalar);
- crypto_bignum_mod(sae->tmp->own_commit_scalar, sae->tmp->order,
- sae->tmp->own_commit_scalar);
- } while (crypto_bignum_is_zero(sae->tmp->own_commit_scalar) ||
- crypto_bignum_is_one(sae->tmp->own_commit_scalar));
-
- if ((sae->tmp->ec && sae_derive_commit_element_ecc(sae, mask) < 0) ||
- (sae->tmp->dh && sae_derive_commit_element_ffc(sae, mask) < 0))
- goto fail;
-
- ret = 0;
-fail:
+ mask = crypto_bignum_init();
+ if (!sae->tmp->sae_rand)
+ sae->tmp->sae_rand = crypto_bignum_init();
+ if (!sae->tmp->own_commit_scalar)
+ sae->tmp->own_commit_scalar = crypto_bignum_init();
+ ret = !mask || !sae->tmp->sae_rand || !sae->tmp->own_commit_scalar ||
+ dragonfly_generate_scalar(sae->tmp->order, sae->tmp->sae_rand,
+ mask,
+ sae->tmp->own_commit_scalar) < 0 ||
+ (sae->tmp->ec &&
+ sae_derive_commit_element_ecc(sae, mask) < 0) ||
+ (sae->tmp->dh &&
+ sae_derive_commit_element_ffc(sae, mask) < 0);
crypto_bignum_deinit(mask, 1);
- return ret;
+ return ret ? -1 : 0;
}
@@ -823,10 +1351,66 @@
identifier) < 0) ||
(sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
password_len,
- identifier) < 0) ||
- sae_derive_commit(sae) < 0)
+ identifier) < 0))
return -1;
- return 0;
+
+ sae->tmp->h2e = 0;
+ return sae_derive_commit(sae);
+}
+
+
+int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2,
+ int *rejected_groups)
+{
+ if (!sae->tmp)
+ return -1;
+
+ while (pt) {
+ if (pt->group == sae->group)
+ break;
+ pt = pt->next;
+ }
+ if (!pt) {
+ wpa_printf(MSG_INFO, "SAE: Could not find PT for group %u",
+ sae->group);
+ return -1;
+ }
+
+ sae->tmp->own_addr_higher = os_memcmp(addr1, addr2, ETH_ALEN) > 0;
+ wpabuf_free(sae->tmp->own_rejected_groups);
+ sae->tmp->own_rejected_groups = NULL;
+ if (rejected_groups) {
+ int count, i;
+ struct wpabuf *groups;
+
+ count = int_array_len(rejected_groups);
+ groups = wpabuf_alloc(count * 2);
+ if (!groups)
+ return -1;
+ for (i = 0; i < count; i++)
+ wpabuf_put_le16(groups, rejected_groups[i]);
+ sae->tmp->own_rejected_groups = groups;
+ }
+
+ if (pt->ec) {
+ crypto_ec_point_deinit(sae->tmp->pwe_ecc, 1);
+ sae->tmp->pwe_ecc = sae_derive_pwe_from_pt_ecc(pt, addr1,
+ addr2);
+ if (!sae->tmp->pwe_ecc)
+ return -1;
+ }
+
+ if (pt->dh) {
+ crypto_bignum_deinit(sae->tmp->pwe_ffc, 1);
+ sae->tmp->pwe_ffc = sae_derive_pwe_from_pt_ffc(pt, addr1,
+ addr2);
+ if (!sae->tmp->pwe_ffc)
+ return -1;
+ }
+
+ sae->tmp->h2e = 1;
+ return sae_derive_commit(sae);
}
@@ -904,47 +1488,124 @@
}
+static int sae_kdf_hash(size_t hash_len, const u8 *k, const char *label,
+ const u8 *context, size_t context_len,
+ u8 *out, size_t out_len)
+{
+ if (hash_len == 32)
+ return sha256_prf(k, hash_len, label,
+ context, context_len, out, out_len);
+#ifdef CONFIG_SHA384
+ if (hash_len == 48)
+ return sha384_prf(k, hash_len, label,
+ context, context_len, out, out_len);
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+ if (hash_len == 64)
+ return sha512_prf(k, hash_len, label,
+ context, context_len, out, out_len);
+#endif /* CONFIG_SHA512 */
+ return -1;
+}
+
+
static int sae_derive_keys(struct sae_data *sae, const u8 *k)
{
- u8 null_key[SAE_KEYSEED_KEY_LEN], val[SAE_MAX_PRIME_LEN];
- u8 keyseed[SHA256_MAC_LEN];
- u8 keys[SAE_KCK_LEN + SAE_PMK_LEN];
+ u8 zero[SAE_MAX_HASH_LEN], val[SAE_MAX_PRIME_LEN];
+ const u8 *salt;
+ struct wpabuf *rejected_groups = NULL;
+ u8 keyseed[SAE_MAX_HASH_LEN];
+ u8 keys[SAE_MAX_HASH_LEN + SAE_PMK_LEN];
struct crypto_bignum *tmp;
int ret = -1;
+ size_t hash_len, salt_len, prime_len = sae->tmp->prime_len;
+ const u8 *addr[1];
+ size_t len[1];
tmp = crypto_bignum_init();
if (tmp == NULL)
goto fail;
- /* keyseed = H(<0>32, k)
- * KCK || PMK = KDF-512(keyseed, "SAE KCK and PMK",
+ /* keyseed = H(salt, k)
+ * KCK || PMK = KDF-Hash-Length(keyseed, "SAE KCK and PMK",
* (commit-scalar + peer-commit-scalar) modulo r)
* PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128)
*/
+ if (!sae->tmp->h2e)
+ hash_len = SHA256_MAC_LEN;
+ else if (sae->tmp->dh)
+ hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
+ else
+ hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
+ if (sae->tmp->h2e && (sae->tmp->own_rejected_groups ||
+ sae->tmp->peer_rejected_groups)) {
+ struct wpabuf *own, *peer;
- os_memset(null_key, 0, sizeof(null_key));
- hmac_sha256(null_key, sizeof(null_key), k, sae->tmp->prime_len,
- keyseed);
- wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, sizeof(keyseed));
-
- crypto_bignum_add(sae->tmp->own_commit_scalar, sae->peer_commit_scalar,
- tmp);
- crypto_bignum_mod(tmp, sae->tmp->order, tmp);
- crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->prime_len);
- wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
- if (sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
- val, sae->tmp->prime_len, keys, sizeof(keys)) < 0)
+ own = sae->tmp->own_rejected_groups;
+ peer = sae->tmp->peer_rejected_groups;
+ salt_len = 0;
+ if (own)
+ salt_len += wpabuf_len(own);
+ if (peer)
+ salt_len += wpabuf_len(peer);
+ rejected_groups = wpabuf_alloc(salt_len);
+ if (!rejected_groups)
+ goto fail;
+ if (sae->tmp->own_addr_higher) {
+ if (own)
+ wpabuf_put_buf(rejected_groups, own);
+ if (peer)
+ wpabuf_put_buf(rejected_groups, peer);
+ } else {
+ if (peer)
+ wpabuf_put_buf(rejected_groups, peer);
+ if (own)
+ wpabuf_put_buf(rejected_groups, own);
+ }
+ salt = wpabuf_head(rejected_groups);
+ salt_len = wpabuf_len(rejected_groups);
+ } else {
+ os_memset(zero, 0, hash_len);
+ salt = zero;
+ salt_len = hash_len;
+ }
+ wpa_hexdump(MSG_DEBUG, "SAE: salt for keyseed derivation",
+ salt, salt_len);
+ addr[0] = k;
+ len[0] = prime_len;
+ if (hkdf_extract(hash_len, salt, salt_len, 1, addr, len, keyseed) < 0)
goto fail;
- os_memset(keyseed, 0, sizeof(keyseed));
- os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN);
- os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, hash_len);
+
+ if (crypto_bignum_add(sae->tmp->own_commit_scalar,
+ sae->peer_commit_scalar, tmp) < 0 ||
+ crypto_bignum_mod(tmp, sae->tmp->order, tmp) < 0)
+ goto fail;
+ /* IEEE Std 802.11-2016 is not exactly clear on the encoding of the bit
+ * string that is needed for KCK, PMK, and PMKID derivation, but it
+ * seems to make most sense to encode the
+ * (commit-scalar + peer-commit-scalar) mod r part as a bit string by
+ * zero padding it from left to the length of the order (in full
+ * octets). */
+ crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->order_len);
+ wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
+ if (sae_kdf_hash(hash_len, keyseed, "SAE KCK and PMK",
+ val, sae->tmp->order_len,
+ keys, hash_len + SAE_PMK_LEN) < 0)
+ goto fail;
+ forced_memzero(keyseed, sizeof(keyseed));
+ os_memcpy(sae->tmp->kck, keys, hash_len);
+ sae->tmp->kck_len = hash_len;
+ os_memcpy(sae->pmk, keys + hash_len, SAE_PMK_LEN);
os_memcpy(sae->pmkid, val, SAE_PMKID_LEN);
- os_memset(keys, 0, sizeof(keys));
- wpa_hexdump_key(MSG_DEBUG, "SAE: KCK", sae->tmp->kck, SAE_KCK_LEN);
+ forced_memzero(keys, sizeof(keys));
+ wpa_hexdump_key(MSG_DEBUG, "SAE: KCK",
+ sae->tmp->kck, sae->tmp->kck_len);
wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN);
ret = 0;
fail:
+ wpabuf_free(rejected_groups);
crypto_bignum_deinit(tmp, 0);
return ret;
}
@@ -962,38 +1623,42 @@
}
-void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
- const struct wpabuf *token, const char *identifier)
+int sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
+ const struct wpabuf *token, const char *identifier)
{
u8 *pos;
if (sae->tmp == NULL)
- return;
+ return -1;
wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
- if (token) {
+ if (!sae->tmp->h2e && token) {
wpabuf_put_buf(buf, token);
wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token",
wpabuf_head(token), wpabuf_len(token));
}
pos = wpabuf_put(buf, sae->tmp->prime_len);
- crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
- sae->tmp->prime_len, sae->tmp->prime_len);
+ if (crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
+ sae->tmp->prime_len, sae->tmp->prime_len) < 0)
+ return -1;
wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar",
pos, sae->tmp->prime_len);
if (sae->tmp->ec) {
pos = wpabuf_put(buf, 2 * sae->tmp->prime_len);
- crypto_ec_point_to_bin(sae->tmp->ec,
- sae->tmp->own_commit_element_ecc,
- pos, pos + sae->tmp->prime_len);
+ if (crypto_ec_point_to_bin(sae->tmp->ec,
+ sae->tmp->own_commit_element_ecc,
+ pos, pos + sae->tmp->prime_len) < 0)
+ return -1;
wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)",
pos, sae->tmp->prime_len);
wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)",
pos + sae->tmp->prime_len, sae->tmp->prime_len);
} else {
pos = wpabuf_put(buf, sae->tmp->prime_len);
- crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
- sae->tmp->prime_len, sae->tmp->prime_len);
+ if (crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
+ sae->tmp->prime_len,
+ sae->tmp->prime_len) < 0)
+ return -1;
wpa_hexdump(MSG_DEBUG, "SAE: own commit-element",
pos, sae->tmp->prime_len);
}
@@ -1007,6 +1672,28 @@
wpa_printf(MSG_DEBUG, "SAE: own Password Identifier: %s",
identifier);
}
+
+ if (sae->tmp->h2e && sae->tmp->own_rejected_groups) {
+ wpa_hexdump_buf(MSG_DEBUG, "SAE: own Rejected Groups",
+ sae->tmp->own_rejected_groups);
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf,
+ 1 + wpabuf_len(sae->tmp->own_rejected_groups));
+ wpabuf_put_u8(buf, WLAN_EID_EXT_REJECTED_GROUPS);
+ wpabuf_put_buf(buf, sae->tmp->own_rejected_groups);
+ }
+
+ if (sae->tmp->h2e && token) {
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + wpabuf_len(token));
+ wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
+ wpabuf_put_buf(buf, token);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "SAE: Anti-clogging token (in container)",
+ token);
+ }
+
+ return 0;
}
@@ -1062,30 +1749,44 @@
}
+static int sae_is_rejected_groups_elem(const u8 *pos, const u8 *end)
+{
+ return end - pos >= 3 &&
+ pos[0] == WLAN_EID_EXTENSION &&
+ pos[1] >= 2 &&
+ end - pos - 2 >= pos[1] &&
+ pos[2] == WLAN_EID_EXT_REJECTED_GROUPS;
+}
+
+
+static int sae_is_token_container_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_ANTI_CLOGGING_TOKEN;
+}
+
+
static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
const u8 *end, const u8 **token,
- size_t *token_len)
+ size_t *token_len, int h2e)
{
size_t scalar_elem_len, tlen;
- const u8 *elem;
if (token)
*token = NULL;
if (token_len)
*token_len = 0;
+ if (h2e)
+ return; /* No Anti-Clogging Token field outside container IE */
+
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) {
@@ -1095,21 +1796,6 @@
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;
@@ -1119,6 +1805,21 @@
}
+static void sae_parse_token_container(struct sae_data *sae,
+ const u8 *pos, const u8 *end,
+ const u8 **token, size_t *token_len)
+{
+ wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
+ pos, end - pos);
+ if (!sae_is_token_container_elem(pos, end))
+ return;
+ *token = pos + 3;
+ *token_len = pos[1] - 1;
+ wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token (in container)",
+ *token, *token_len);
+}
+
+
static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
const u8 *end)
{
@@ -1139,8 +1840,9 @@
* shall be dropped if the peer-scalar is identical to the one used in
* the existing protocol instance.
*/
- if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar &&
- crypto_bignum_cmp(sae->peer_commit_scalar, peer_scalar) == 0) {
+ if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar_accepted &&
+ crypto_bignum_cmp(sae->peer_commit_scalar_accepted,
+ peer_scalar) == 0) {
wpa_printf(MSG_DEBUG, "SAE: Do not accept re-use of previous "
"peer-commit-scalar");
crypto_bignum_deinit(peer_scalar, 0);
@@ -1274,11 +1976,11 @@
static int sae_parse_password_identifier(struct sae_data *sae,
- const u8 *pos, const u8 *end)
+ 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)) {
+ *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)",
@@ -1291,8 +1993,8 @@
}
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)) {
+ ((*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);
@@ -1300,19 +2002,41 @@
}
os_free(sae->tmp->pw_id);
- sae->tmp->pw_id = os_malloc(pos[1]);
+ 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';
+ 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);
+ sae->tmp->pw_id, (*pos)[1] - 1);
+ *pos = *pos + 2 + (*pos)[1];
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+static int sae_parse_rejected_groups(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_rejected_groups_elem(*pos, end))
+ return WLAN_STATUS_SUCCESS;
+ wpabuf_free(sae->tmp->peer_rejected_groups);
+ sae->tmp->peer_rejected_groups = wpabuf_alloc((*pos)[1] - 1);
+ if (!sae->tmp->peer_rejected_groups)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ wpabuf_put_data(sae->tmp->peer_rejected_groups, (*pos) + 3,
+ (*pos)[1] - 1);
+ wpa_hexdump_buf(MSG_DEBUG, "SAE: Received Rejected Groups list",
+ sae->tmp->peer_rejected_groups);
+ *pos = *pos + 2 + (*pos)[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)
+ const u8 **token, size_t *token_len, int *allowed_groups,
+ int h2e)
{
const u8 *pos = data, *end = data + len;
u16 res;
@@ -1326,7 +2050,7 @@
pos += 2;
/* Optional Anti-Clogging Token */
- sae_parse_commit_token(sae, &pos, end, token, token_len);
+ sae_parse_commit_token(sae, &pos, end, token, token_len, h2e);
/* commit-scalar */
res = sae_parse_commit_scalar(sae, &pos, end);
@@ -1339,10 +2063,21 @@
return res;
/* Optional Password Identifier element */
- res = sae_parse_password_identifier(sae, pos, end);
+ res = sae_parse_password_identifier(sae, &pos, end);
if (res != WLAN_STATUS_SUCCESS)
return res;
+ /* Conditional Rejected Groups element */
+ if (h2e) {
+ res = sae_parse_rejected_groups(sae, &pos, end);
+ if (res != WLAN_STATUS_SUCCESS)
+ return res;
+ }
+
+ /* Optional Anti-Clogging Token Container element */
+ if (h2e)
+ sae_parse_token_container(sae, pos, end, token, token_len);
+
/*
* Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as
* the values we sent which would be evidence of a reflection attack.
@@ -1370,12 +2105,12 @@
}
-static void sae_cn_confirm(struct sae_data *sae, const u8 *sc,
- const struct crypto_bignum *scalar1,
- const u8 *element1, size_t element1_len,
- const struct crypto_bignum *scalar2,
- const u8 *element2, size_t element2_len,
- u8 *confirm)
+static int sae_cn_confirm(struct sae_data *sae, const u8 *sc,
+ const struct crypto_bignum *scalar1,
+ const u8 *element1, size_t element1_len,
+ const struct crypto_bignum *scalar2,
+ const u8 *element2, size_t element2_len,
+ u8 *confirm)
{
const u8 *addr[5];
size_t len[5];
@@ -1389,72 +2124,81 @@
* verifier = CN(KCK, peer-send-confirm, peer-commit-scalar,
* PEER-COMMIT-ELEMENT, commit-scalar, COMMIT-ELEMENT)
*/
+ if (crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1),
+ sae->tmp->prime_len) < 0 ||
+ crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2),
+ sae->tmp->prime_len) < 0)
+ return -1;
addr[0] = sc;
len[0] = 2;
- crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1),
- sae->tmp->prime_len);
addr[1] = scalar_b1;
len[1] = sae->tmp->prime_len;
addr[2] = element1;
len[2] = element1_len;
- crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2),
- sae->tmp->prime_len);
addr[3] = scalar_b2;
len[3] = sae->tmp->prime_len;
addr[4] = element2;
len[4] = element2_len;
- hmac_sha256_vector(sae->tmp->kck, sizeof(sae->tmp->kck), 5, addr, len,
- confirm);
+ return hkdf_extract(sae->tmp->kck_len, sae->tmp->kck, sae->tmp->kck_len,
+ 5, addr, len, confirm);
}
-static void sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc,
- const struct crypto_bignum *scalar1,
- const struct crypto_ec_point *element1,
- const struct crypto_bignum *scalar2,
- const struct crypto_ec_point *element2,
- u8 *confirm)
+static int sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc,
+ const struct crypto_bignum *scalar1,
+ const struct crypto_ec_point *element1,
+ const struct crypto_bignum *scalar2,
+ const struct crypto_ec_point *element2,
+ u8 *confirm)
{
u8 element_b1[2 * SAE_MAX_ECC_PRIME_LEN];
u8 element_b2[2 * SAE_MAX_ECC_PRIME_LEN];
- crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1,
- element_b1 + sae->tmp->prime_len);
- crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2,
- element_b2 + sae->tmp->prime_len);
-
- sae_cn_confirm(sae, sc, scalar1, element_b1, 2 * sae->tmp->prime_len,
- scalar2, element_b2, 2 * sae->tmp->prime_len, confirm);
+ if (crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1,
+ element_b1 + sae->tmp->prime_len) < 0 ||
+ crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2,
+ element_b2 + sae->tmp->prime_len) < 0 ||
+ sae_cn_confirm(sae, sc, scalar1, element_b1,
+ 2 * sae->tmp->prime_len,
+ scalar2, element_b2, 2 * sae->tmp->prime_len,
+ confirm) < 0)
+ return -1;
+ return 0;
}
-static void sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
- const struct crypto_bignum *scalar1,
- const struct crypto_bignum *element1,
- const struct crypto_bignum *scalar2,
- const struct crypto_bignum *element2,
- u8 *confirm)
+static int sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
+ const struct crypto_bignum *scalar1,
+ const struct crypto_bignum *element1,
+ const struct crypto_bignum *scalar2,
+ const struct crypto_bignum *element2,
+ u8 *confirm)
{
u8 element_b1[SAE_MAX_PRIME_LEN];
u8 element_b2[SAE_MAX_PRIME_LEN];
- crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1),
- sae->tmp->prime_len);
- crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2),
- sae->tmp->prime_len);
-
- sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len,
- scalar2, element_b2, sae->tmp->prime_len, confirm);
+ if (crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1),
+ sae->tmp->prime_len) < 0 ||
+ crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2),
+ sae->tmp->prime_len) < 0 ||
+ sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len,
+ scalar2, element_b2, sae->tmp->prime_len,
+ confirm) < 0)
+ return -1;
+ return 0;
}
void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
{
const u8 *sc;
+ size_t hash_len;
if (sae->tmp == NULL)
return;
+ hash_len = sae->tmp->kck_len;
+
/* Send-Confirm */
sc = wpabuf_put(buf, 0);
wpabuf_put_le16(buf, sae->send_confirm);
@@ -1466,59 +2210,63 @@
sae->tmp->own_commit_element_ecc,
sae->peer_commit_scalar,
sae->tmp->peer_commit_element_ecc,
- wpabuf_put(buf, SHA256_MAC_LEN));
+ wpabuf_put(buf, hash_len));
else
sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
sae->tmp->own_commit_element_ffc,
sae->peer_commit_scalar,
sae->tmp->peer_commit_element_ffc,
- wpabuf_put(buf, SHA256_MAC_LEN));
+ wpabuf_put(buf, hash_len));
}
int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
{
- u8 verifier[SHA256_MAC_LEN];
+ u8 verifier[SAE_MAX_HASH_LEN];
+ size_t hash_len;
- if (len < 2 + SHA256_MAC_LEN) {
+ if (!sae->tmp)
+ return -1;
+
+ hash_len = sae->tmp->kck_len;
+ if (len < 2 + hash_len) {
wpa_printf(MSG_DEBUG, "SAE: Too short confirm message");
return -1;
}
wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data));
- if (!sae->tmp || !sae->peer_commit_scalar ||
- !sae->tmp->own_commit_scalar) {
+ if (!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->peer_commit_element_ecc ||
- !sae->tmp->own_commit_element_ecc)
+ !sae->tmp->own_commit_element_ecc ||
+ 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) < 0)
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 {
if (!sae->tmp->peer_commit_element_ffc ||
- !sae->tmp->own_commit_element_ffc)
+ !sae->tmp->own_commit_element_ffc ||
+ 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) < 0)
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) {
+ if (os_memcmp_const(verifier, data + 2, hash_len) != 0) {
wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch");
wpa_hexdump(MSG_DEBUG, "SAE: Received confirm",
- data + 2, SHA256_MAC_LEN);
+ data + 2, hash_len);
wpa_hexdump(MSG_DEBUG, "SAE: Calculated verifier",
- verifier, SHA256_MAC_LEN);
+ verifier, hash_len);
return -1;
}
diff --git a/src/common/sae.h b/src/common/sae.h
index 3eb6e32..7966d70 100644
--- a/src/common/sae.h
+++ b/src/common/sae.h
@@ -12,17 +12,18 @@
#define SAE_KCK_LEN 32
#define SAE_PMK_LEN 32
#define SAE_PMKID_LEN 16
-#define SAE_KEYSEED_KEY_LEN 32
#define SAE_MAX_PRIME_LEN 512
#define SAE_MAX_ECC_PRIME_LEN 66
-#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN)
-#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_PRIME_LEN)
+#define SAE_MAX_HASH_LEN 64
+#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN + 255)
+#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_HASH_LEN)
/* Special value returned by sae_parse_commit() */
#define SAE_SILENTLY_DISCARD 65535
struct sae_temporary_data {
- u8 kck[SAE_KCK_LEN];
+ u8 kck[SAE_MAX_HASH_LEN];
+ size_t kck_len;
struct crypto_bignum *own_commit_scalar;
struct crypto_bignum *own_commit_element_ffc;
struct crypto_ec_point *own_commit_element_ecc;
@@ -33,6 +34,7 @@
struct crypto_bignum *sae_rand;
struct crypto_ec *ec;
int prime_len;
+ int order_len;
const struct dh_group *dh;
const struct crypto_bignum *prime;
const struct crypto_bignum *order;
@@ -42,6 +44,20 @@
char *pw_id;
int vlan_id;
u8 bssid[ETH_ALEN];
+ struct wpabuf *own_rejected_groups;
+ struct wpabuf *peer_rejected_groups;
+ unsigned int h2e:1;
+ unsigned int own_addr_higher:1;
+};
+
+struct sae_pt {
+ struct sae_pt *next;
+ int group;
+ struct crypto_ec *ec;
+ struct crypto_ec_point *ecc_pt;
+
+ const struct dh_group *dh;
+ struct crypto_bignum *ffc_pt;
};
enum sae_state {
@@ -54,6 +70,7 @@
u8 pmk[SAE_PMK_LEN];
u8 pmkid[SAE_PMKID_LEN];
struct crypto_bignum *peer_commit_scalar;
+ struct crypto_bignum *peer_commit_scalar_accepted;
int group;
unsigned int sync; /* protocol instance variable: Sync */
u16 rc; /* protocol instance variable: Rc (received send-confirm) */
@@ -67,14 +84,28 @@
int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
const u8 *password, size_t password_len,
const char *identifier, struct sae_data *sae);
+int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2,
+ int *rejected_groups);
int sae_process_commit(struct sae_data *sae);
-void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
- const struct wpabuf *token, const char *identifier);
+int sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
+ const struct wpabuf *token, const char *identifier);
u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
- const u8 **token, size_t *token_len, int *allowed_groups);
+ const u8 **token, size_t *token_len, int *allowed_groups,
+ int h2e);
void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf);
int sae_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);
+struct sae_pt * sae_derive_pt(int *groups, const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier);
+struct crypto_ec_point *
+sae_derive_pwe_from_pt_ecc(const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2);
+struct crypto_bignum *
+sae_derive_pwe_from_pt_ffc(const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2);
+void sae_deinit_pt(struct sae_pt *pt);
#endif /* SAE_H */
diff --git a/src/common/version.h b/src/common/version.h
index eb4f313..0235c9b 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.8-devel" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
+#define VERSION_STR "2.10-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 ed2d1c2..eb1861a 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -212,11 +212,9 @@
return -1;
os_memcpy(mic, hash, MD5_MAC_LEN);
break;
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
case WPA_KEY_INFO_TYPE_AES_128_CMAC:
wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using AES-CMAC");
return omac1_aes_128(key, buf, len, mic);
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
case WPA_KEY_INFO_TYPE_AKM_DEFINED:
switch (akmp) {
#ifdef CONFIG_SAE
@@ -357,6 +355,14 @@
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;
+#ifdef CONFIG_OWE
+ int owe_ptk_workaround = 0;
+
+ if (akmp == (WPA_KEY_MGMT_OWE | WPA_KEY_MGMT_PSK_SHA256)) {
+ owe_ptk_workaround = 1;
+ akmp = WPA_KEY_MGMT_OWE;
+ }
+#endif /* CONFIG_OWE */
if (pmk_len == 0) {
wpa_printf(MSG_ERROR, "WPA: No PMK set for PTK derivation");
@@ -409,15 +415,33 @@
#else /* CONFIG_SUITEB192 || CONFIG_FILS */
return -1;
#endif /* CONFIG_SUITEB192 || CONFIG_FILS */
- } else if (wpa_key_mgmt_sha256(akmp) || akmp == WPA_KEY_MGMT_OWE) {
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_SAE) || defined(CONFIG_FILS)
+ } else if (wpa_key_mgmt_sha256(akmp)) {
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
if (sha256_prf(pmk, pmk_len, label, data, data_len,
tmp, ptk_len) < 0)
return -1;
-#else /* CONFIG_IEEE80211W or CONFIG_SAE or CONFIG_FILS */
+#ifdef CONFIG_OWE
+ } else if (akmp == WPA_KEY_MGMT_OWE && (pmk_len == 32 ||
+ owe_ptk_workaround)) {
+ wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
+ if (sha256_prf(pmk, pmk_len, label, data, data_len,
+ tmp, ptk_len) < 0)
+ return -1;
+ } else if (akmp == WPA_KEY_MGMT_OWE && pmk_len == 48) {
+ wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)");
+ if (sha384_prf(pmk, pmk_len, label, data, data_len,
+ tmp, ptk_len) < 0)
+ return -1;
+ } else if (akmp == WPA_KEY_MGMT_OWE && pmk_len == 64) {
+ wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA512)");
+ if (sha512_prf(pmk, pmk_len, label, data, data_len,
+ tmp, ptk_len) < 0)
+ return -1;
+ } else if (akmp == WPA_KEY_MGMT_OWE) {
+ wpa_printf(MSG_INFO, "OWE: Unknown PMK length %u",
+ (unsigned int) pmk_len);
return -1;
-#endif /* CONFIG_IEEE80211W or CONFIG_SAE or CONFIG_FILS */
+#endif /* CONFIG_OWE */
#ifdef CONFIG_DPP
} else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 32) {
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
@@ -692,7 +716,7 @@
len[2] = ETH_ALEN;
addr[3] = bssid;
len[3] = ETH_ALEN;
- if (g_sta && g_ap_len && g_ap && g_ap_len) {
+ if (g_sta && g_sta_len && g_ap && g_ap_len) {
addr[4] = g_sta;
len[4] = g_sta_len;
addr[5] = g_ap;
@@ -723,7 +747,7 @@
addr[1] = snonce;
addr[2] = bssid;
addr[3] = sta_addr;
- if (g_sta && g_ap_len && g_ap && g_ap_len) {
+ if (g_sta && g_sta_len && g_ap && g_ap_len) {
addr[4] = g_ap;
len[4] = g_ap_len;
addr[5] = g_sta;
@@ -756,10 +780,12 @@
const u8 *mdie, size_t mdie_len,
const u8 *ftie, size_t ftie_len,
const u8 *rsnie, size_t rsnie_len,
- const u8 *ric, size_t ric_len, u8 *mic)
+ const u8 *ric, size_t ric_len,
+ const u8 *rsnxe, size_t rsnxe_len,
+ u8 *mic)
{
- const u8 *addr[9];
- size_t len[9];
+ const u8 *addr[10];
+ size_t len[10];
size_t i, num_elem = 0;
u8 zero_mic[24];
size_t mic_len, fte_fixed_len;
@@ -826,6 +852,12 @@
num_elem++;
}
+ if (rsnxe) {
+ addr[num_elem] = rsnxe;
+ len[num_elem] = rsnxe_len;
+ num_elem++;
+ }
+
for (i = 0; i < num_elem; i++)
wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", addr[i], len[i]);
#ifdef CONFIG_SHA384
@@ -892,18 +924,20 @@
parse->r0kh_id = pos;
parse->r0kh_id_len = len;
break;
-#ifdef CONFIG_IEEE80211W
case FTIE_SUBELEM_IGTK:
parse->igtk = pos;
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 */
+ case FTIE_SUBELEM_BIGTK:
+ parse->bigtk = pos;
+ parse->bigtk_len = len;
+ break;
default:
wpa_printf(MSG_DEBUG, "FT: Unknown subelem id %u", id);
break;
@@ -958,6 +992,7 @@
"RSN IE: %d", ret);
return -1;
}
+ parse->rsn_capab = data.capabilities;
if (data.num_pmkid == 1 && data.pmkid)
parse->rsn_pmkid = data.pmkid;
parse->key_mgmt = data.key_mgmt;
@@ -968,6 +1003,13 @@
update_use_sha384 = 0;
}
break;
+ case WLAN_EID_RSNX:
+ wpa_hexdump(MSG_DEBUG, "FT: RSNXE", pos, len);
+ if (len < 1)
+ break;
+ parse->rsnxe = pos;
+ parse->rsnxe_len = len;
+ break;
case WLAN_EID_MOBILITY_DOMAIN:
wpa_hexdump(MSG_DEBUG, "FT: MDE", pos, len);
if (len < sizeof(struct rsn_mdie))
@@ -989,9 +1031,11 @@
wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
ftie_sha384->mic,
sizeof(ftie_sha384->mic));
+ parse->fte_anonce = ftie_sha384->anonce;
wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
ftie_sha384->anonce,
WPA_NONCE_LEN);
+ parse->fte_snonce = ftie_sha384->snonce;
wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
ftie_sha384->snonce,
WPA_NONCE_LEN);
@@ -1008,8 +1052,10 @@
ftie->mic_control, 2);
wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
ftie->mic, sizeof(ftie->mic));
+ parse->fte_anonce = ftie->anonce;
wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
ftie->anonce, WPA_NONCE_LEN);
+ parse->fte_snonce = ftie->snonce;
wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
ftie->snonce, WPA_NONCE_LEN);
prot_ie_count = ftie->mic_control[1];
@@ -1046,6 +1092,8 @@
prot_ie_count--;
if (parse->ftie)
prot_ie_count--;
+ if (parse->rsnxe)
+ prot_ie_count--;
if (prot_ie_count < 0) {
wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
"the protected IE count");
@@ -1087,10 +1135,8 @@
return WPA_CIPHER_TKIP;
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
return WPA_CIPHER_CCMP;
-#ifdef CONFIG_IEEE80211W
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
return WPA_CIPHER_AES_128_CMAC;
-#endif /* CONFIG_IEEE80211W */
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP)
return WPA_CIPHER_GCMP;
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP_256)
@@ -1125,12 +1171,10 @@
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)
return WPA_KEY_MGMT_IEEE8021X_SHA256;
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
return WPA_KEY_MGMT_PSK_SHA256;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
return WPA_KEY_MGMT_SAE;
@@ -1170,7 +1214,6 @@
}
-#ifdef CONFIG_IEEE80211W
int wpa_cipher_valid_mgmt_group(int cipher)
{
return cipher == WPA_CIPHER_AES_128_CMAC ||
@@ -1178,7 +1221,6 @@
cipher == WPA_CIPHER_BIP_GMAC_256 ||
cipher == WPA_CIPHER_BIP_CMAC_256;
}
-#endif /* CONFIG_IEEE80211W */
/**
@@ -1203,11 +1245,7 @@
data->capabilities = 0;
data->pmkid = NULL;
data->num_pmkid = 0;
-#ifdef CONFIG_IEEE80211W
data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
-#else /* CONFIG_IEEE80211W */
- data->mgmt_group_cipher = 0;
-#endif /* CONFIG_IEEE80211W */
if (rsn_ie_len == 0) {
/* No RSN IE - fail silently */
@@ -1282,13 +1320,11 @@
pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN;
}
-#ifdef CONFIG_IEEE80211W
if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
"pairwise cipher", __func__);
return -1;
}
-#endif /* CONFIG_IEEE80211W */
} else if (left == 1) {
wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
__func__);
@@ -1340,7 +1376,6 @@
}
}
-#ifdef CONFIG_IEEE80211W
if (left >= 4) {
data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) {
@@ -1353,7 +1388,6 @@
pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN;
}
-#endif /* CONFIG_IEEE80211W */
if (left > 0) {
wpa_hexdump(MSG_DEBUG,
@@ -1852,11 +1886,9 @@
wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-384");
hmac_sha384_vector(pmk, pmk_len, 3, addr, len, hash);
#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");
hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
-#endif /* CONFIG_IEEE80211W || CONFIG_FILS */
} else {
wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-1");
hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
@@ -1942,10 +1974,12 @@
switch (cipher) {
case WPA_CIPHER_NONE:
return "NONE";
+#ifdef CONFIG_WEP
case WPA_CIPHER_WEP40:
return "WEP-40";
case WPA_CIPHER_WEP104:
return "WEP-104";
+#endif /* CONFIG_WEP */
case WPA_CIPHER_TKIP:
return "TKIP";
case WPA_CIPHER_CCMP:
@@ -2007,12 +2041,10 @@
case WPA_KEY_MGMT_FT_PSK:
return "FT-PSK";
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
case WPA_KEY_MGMT_IEEE8021X_SHA256:
return "WPA2-EAP-SHA256";
case WPA_KEY_MGMT_PSK_SHA256:
return "WPA2-PSK-SHA256";
-#endif /* CONFIG_IEEE80211W */
case WPA_KEY_MGMT_WPS:
return "WPS";
case WPA_KEY_MGMT_SAE:
@@ -2075,6 +2107,14 @@
return RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
if (akm & WPA_KEY_MGMT_FT_FILS_SHA384)
return RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
+ if (akm & WPA_KEY_MGMT_SAE)
+ return RSN_AUTH_KEY_MGMT_SAE;
+ if (akm & WPA_KEY_MGMT_FT_SAE)
+ return RSN_AUTH_KEY_MGMT_FT_SAE;
+ if (akm & WPA_KEY_MGMT_OWE)
+ return RSN_AUTH_KEY_MGMT_OWE;
+ if (akm & WPA_KEY_MGMT_DPP)
+ return RSN_AUTH_KEY_MGMT_DPP;
return 0;
}
@@ -2116,7 +2156,6 @@
}
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS)
int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid)
{
u8 *start, *end, *rpos, *rend;
@@ -2131,11 +2170,10 @@
start += 2 + start[1];
}
if (start >= end) {
- wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in "
- "IEs data");
+ wpa_printf(MSG_ERROR, "RSN: Could not find RSNE in IEs data");
return -1;
}
- wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification",
+ wpa_hexdump(MSG_DEBUG, "RSN: RSNE before modification",
start, 2 + start[1]);
/* Find start of PMKID-Count */
@@ -2161,8 +2199,8 @@
/* Skip RSN Capabilities */
rpos += 2;
if (rpos > rend) {
- wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in "
- "IEs data");
+ wpa_printf(MSG_ERROR,
+ "RSN: Could not parse RSNE in IEs data");
return -1;
}
}
@@ -2193,10 +2231,10 @@
* PMKID(s) first before adding the new one.
*/
wpa_printf(MSG_DEBUG,
- "FT: Remove %u old PMKID(s) from RSN IE",
+ "RSN: Remove %u old PMKID(s) from RSNE",
num_pmkid);
after = rpos + 2 + num_pmkid * PMKID_LEN;
- os_memmove(rpos + 2, after, rend - after);
+ os_memmove(rpos + 2, after, end - after);
start[1] -= num_pmkid * PMKID_LEN;
added -= num_pmkid * PMKID_LEN;
}
@@ -2208,14 +2246,13 @@
start[1] += PMKID_LEN;
}
- wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification "
- "(PMKID inserted)", start, 2 + start[1]);
+ wpa_hexdump(MSG_DEBUG, "RSN: RSNE after modification (PMKID inserted)",
+ start, 2 + start[1]);
*ies_len += added;
return 0;
}
-#endif /* CONFIG_IEEE80211R || CONFIG_FILS */
int wpa_cipher_key_len(int cipher)
@@ -2282,11 +2319,18 @@
int wpa_cipher_valid_pairwise(int cipher)
{
+#ifdef CONFIG_NO_TKIP
+ return cipher == WPA_CIPHER_CCMP_256 ||
+ cipher == WPA_CIPHER_GCMP_256 ||
+ cipher == WPA_CIPHER_CCMP ||
+ cipher == WPA_CIPHER_GCMP;
+#else /* CONFIG_NO_TKIP */
return cipher == WPA_CIPHER_CCMP_256 ||
cipher == WPA_CIPHER_GCMP_256 ||
cipher == WPA_CIPHER_CCMP ||
cipher == WPA_CIPHER_GCMP ||
cipher == WPA_CIPHER_TKIP;
+#endif /* CONFIG_NO_TKIP */
}
@@ -2439,12 +2483,16 @@
val |= WPA_CIPHER_CCMP;
else if (os_strcmp(start, "GCMP") == 0)
val |= WPA_CIPHER_GCMP;
+#ifndef CONFIG_NO_TKIP
else if (os_strcmp(start, "TKIP") == 0)
val |= WPA_CIPHER_TKIP;
+#endif /* CONFIG_NO_TKIP */
+#ifdef CONFIG_WEP
else if (os_strcmp(start, "WEP104") == 0)
val |= WPA_CIPHER_WEP104;
else if (os_strcmp(start, "WEP40") == 0)
val |= WPA_CIPHER_WEP40;
+#endif /* CONFIG_WEP */
else if (os_strcmp(start, "NONE") == 0)
val |= WPA_CIPHER_NONE;
else if (os_strcmp(start, "GTK_NOT_USED") == 0)
@@ -2600,3 +2648,286 @@
return 0;
}
#endif /* CONFIG_FILS */
+
+
+/**
+ * wpa_parse_vendor_specific - Parse Vendor Specific IEs
+ * @pos: Pointer to the IE header
+ * @end: Pointer to the end of the Key Data buffer
+ * @ie: Pointer to parsed IE data
+ */
+static void wpa_parse_vendor_specific(const u8 *pos, const u8 *end,
+ struct wpa_eapol_ie_parse *ie)
+{
+ unsigned int oui;
+
+ if (pos[1] < 4) {
+ wpa_printf(MSG_MSGDUMP,
+ "Too short vendor specific IE ignored (len=%u)",
+ pos[1]);
+ return;
+ }
+
+ oui = WPA_GET_BE24(&pos[2]);
+ if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) {
+ if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) {
+ ie->wmm = &pos[2];
+ ie->wmm_len = pos[1];
+ wpa_hexdump(MSG_DEBUG, "WPA: WMM IE",
+ ie->wmm, ie->wmm_len);
+ } else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) {
+ ie->wmm = &pos[2];
+ ie->wmm_len = pos[1];
+ wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element",
+ ie->wmm, ie->wmm_len);
+ }
+ }
+}
+
+
+/**
+ * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
+ * @pos: Pointer to the IE header
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, 1 if end mark is found, 2 if KDE is not recognized
+ */
+static int wpa_parse_generic(const u8 *pos, struct wpa_eapol_ie_parse *ie)
+{
+ if (pos[1] == 0)
+ return 1;
+
+ if (pos[1] >= 6 &&
+ RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
+ pos[2 + WPA_SELECTOR_LEN] == 1 &&
+ pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
+ ie->wpa_ie = pos;
+ ie->wpa_ie_len = pos[1] + 2;
+ wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
+ ie->wpa_ie, ie->wpa_ie_len);
+ return 0;
+ }
+
+ if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) {
+ ie->osen = pos;
+ ie->osen_len = pos[1] + 2;
+ return 0;
+ }
+
+ if (pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
+ ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] >= RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_KEYID) {
+ ie->key_id = pos + 2 + RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: KeyID in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
+ ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
+ ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
+ ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
+ ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
+ ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
+ ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_BIGTK) {
+ ie->bigtk = pos + 2 + RSN_SELECTOR_LEN;
+ ie->bigtk_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: BIGTK in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
+ RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
+ ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
+ ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
+ return 0;
+ }
+
+ if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
+ RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
+ ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG,
+ "WPA: IP Address Allocation in EAPOL-Key",
+ ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
+ return 0;
+ }
+
+ 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;
+ wpa_hexdump(MSG_DEBUG, "WPA: OCI KDE in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
+ RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_TRANSITION_DISABLE) {
+ ie->transition_disable = pos + 2 + RSN_SELECTOR_LEN;
+ ie->transition_disable_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG,
+ "WPA: Transition Disable KDE in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ return 2;
+}
+
+
+/**
+ * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs
+ * @buf: Pointer to the Key Data buffer
+ * @len: Key Data Length
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
+{
+ const u8 *pos, *end;
+ int ret = 0;
+
+ os_memset(ie, 0, sizeof(*ie));
+ for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) {
+ if (pos[0] == 0xdd &&
+ ((pos == buf + len - 1) || pos[1] == 0)) {
+ /* Ignore padding */
+ break;
+ }
+ if (2 + pos[1] > end - pos) {
+ wpa_printf(MSG_DEBUG,
+ "WPA: EAPOL-Key Key Data underflow (ie=%d len=%d pos=%d)",
+ pos[0], pos[1], (int) (pos - buf));
+ wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", buf, len);
+ ret = -1;
+ break;
+ }
+ if (*pos == WLAN_EID_RSN) {
+ ie->rsn_ie = pos;
+ ie->rsn_ie_len = pos[1] + 2;
+ wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
+ ie->rsn_ie, ie->rsn_ie_len);
+ } else if (*pos == WLAN_EID_RSNX) {
+ ie->rsnxe = pos;
+ ie->rsnxe_len = pos[1] + 2;
+ wpa_hexdump(MSG_DEBUG, "WPA: RSNXE in EAPOL-Key",
+ ie->rsnxe, ie->rsnxe_len);
+ } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
+ ie->mdie = pos;
+ ie->mdie_len = pos[1] + 2;
+ wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
+ ie->mdie, ie->mdie_len);
+ } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
+ ie->ftie = pos;
+ ie->ftie_len = pos[1] + 2;
+ wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
+ ie->ftie, ie->ftie_len);
+ } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
+ if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) {
+ ie->reassoc_deadline = pos;
+ wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
+ "in EAPOL-Key",
+ ie->reassoc_deadline, pos[1] + 2);
+ } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
+ ie->key_lifetime = pos;
+ wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
+ "in EAPOL-Key",
+ ie->key_lifetime, pos[1] + 2);
+ } else {
+ wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
+ "EAPOL-Key Key Data IE",
+ pos, 2 + pos[1]);
+ }
+ } else if (*pos == WLAN_EID_LINK_ID) {
+ if (pos[1] >= 18) {
+ ie->lnkid = pos;
+ ie->lnkid_len = pos[1] + 2;
+ }
+ } else if (*pos == WLAN_EID_EXT_CAPAB) {
+ ie->ext_capab = pos;
+ ie->ext_capab_len = pos[1] + 2;
+ } else if (*pos == WLAN_EID_SUPP_RATES) {
+ ie->supp_rates = pos;
+ ie->supp_rates_len = pos[1] + 2;
+ } else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
+ ie->ext_supp_rates = pos;
+ ie->ext_supp_rates_len = pos[1] + 2;
+ } else if (*pos == WLAN_EID_HT_CAP &&
+ pos[1] >= sizeof(struct ieee80211_ht_capabilities)) {
+ ie->ht_capabilities = pos + 2;
+ } else if (*pos == WLAN_EID_VHT_AID) {
+ if (pos[1] >= 2)
+ ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff;
+ } else if (*pos == WLAN_EID_VHT_CAP &&
+ pos[1] >= sizeof(struct ieee80211_vht_capabilities))
+ {
+ ie->vht_capabilities = pos + 2;
+ } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
+ ie->qosinfo = pos[2];
+ } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
+ ie->supp_channels = pos + 2;
+ ie->supp_channels_len = pos[1];
+ } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) {
+ /*
+ * The value of the Length field of the Supported
+ * Operating Classes element is between 2 and 253.
+ * Silently skip invalid elements to avoid interop
+ * issues when trying to use the value.
+ */
+ if (pos[1] >= 2 && pos[1] <= 253) {
+ ie->supp_oper_classes = pos + 2;
+ ie->supp_oper_classes_len = pos[1];
+ }
+ } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
+ ret = wpa_parse_generic(pos, ie);
+ if (ret == 1) {
+ /* end mark found */
+ ret = 0;
+ break;
+ }
+
+ if (ret == 2) {
+ /* not a known KDE */
+ wpa_parse_vendor_specific(pos, end, ie);
+ }
+
+ ret = 0;
+ } else {
+ wpa_hexdump(MSG_DEBUG,
+ "WPA: Unrecognized EAPOL-Key Key Data IE",
+ pos, 2 + pos[1]);
+ }
+ }
+
+ return ret;
+}
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index e83d688..c0ef689 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -22,6 +22,15 @@
#define OWE_DH_GROUP 19
+#ifdef CONFIG_NO_TKIP
+#define WPA_ALLOWED_PAIRWISE_CIPHERS \
+(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_NONE | \
+WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256)
+#define WPA_ALLOWED_GROUP_CIPHERS \
+(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | \
+WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256 | \
+WPA_CIPHER_GTK_NOT_USED)
+#else /* CONFIG_NO_TKIP */
#define WPA_ALLOWED_PAIRWISE_CIPHERS \
(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE | \
WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256)
@@ -29,6 +38,7 @@
(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | \
WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256 | \
WPA_CIPHER_GTK_NOT_USED)
+#endif /* CONFIG_NO_TKIP */
#define WPA_ALLOWED_GROUP_MGMT_CIPHERS \
(WPA_CIPHER_AES_128_CMAC | WPA_CIPHER_BIP_GMAC_128 | WPA_CIPHER_BIP_GMAC_256 | \
WPA_CIPHER_BIP_CMAC_256)
@@ -104,16 +114,16 @@
#endif
#define RSN_KEY_DATA_MAC_ADDR RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
#define RSN_KEY_DATA_PMKID RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
-#ifdef CONFIG_IEEE80211W
#define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
-#endif /* CONFIG_IEEE80211W */
#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 RSN_KEY_DATA_BIGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 14)
#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)
+#define WFA_KEY_DATA_TRANSITION_DISABLE RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x20)
#define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
@@ -130,10 +140,10 @@
#pragma pack(push, 1)
#endif /* _MSC_VER */
-#ifdef CONFIG_IEEE80211W
#define WPA_IGTK_LEN 16
#define WPA_IGTK_MAX_LEN 32
-#endif /* CONFIG_IEEE80211W */
+#define WPA_BIGTK_LEN 16
+#define WPA_BIGTK_MAX_LEN 32
/* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */
@@ -226,12 +236,15 @@
size_t gtk_len;
};
-#ifdef CONFIG_IEEE80211W
struct wpa_igtk {
u8 igtk[WPA_IGTK_MAX_LEN];
size_t igtk_len;
};
-#endif /* CONFIG_IEEE80211W */
+
+struct wpa_bigtk {
+ u8 bigtk[WPA_BIGTK_MAX_LEN];
+ size_t bigtk_len;
+};
/* WPA IE version 1
* 00-50-f2:1 (OUI:OUI type)
@@ -291,14 +304,19 @@
be16 error_type;
} STRUCT_PACKED;
-#ifdef CONFIG_IEEE80211W
#define WPA_IGTK_KDE_PREFIX_LEN (2 + 6)
struct wpa_igtk_kde {
u8 keyid[2];
u8 pn[6];
u8 igtk[WPA_IGTK_MAX_LEN];
} STRUCT_PACKED;
-#endif /* CONFIG_IEEE80211W */
+
+#define WPA_BIGTK_KDE_PREFIX_LEN (2 + 6)
+struct wpa_bigtk_kde {
+ u8 keyid[2];
+ u8 pn[6];
+ u8 bigtk[WPA_BIGTK_MAX_LEN];
+} STRUCT_PACKED;
struct rsn_mdie {
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
@@ -329,6 +347,7 @@
#define FTIE_SUBELEM_R0KH_ID 3
#define FTIE_SUBELEM_IGTK 4
#define FTIE_SUBELEM_OCI 5
+#define FTIE_SUBELEM_BIGTK 6
struct rsn_rdie {
u8 id;
@@ -336,6 +355,12 @@
le16 status_code;
} STRUCT_PACKED;
+/* WFA Transition Disable KDE (using OUI_WFA) */
+/* Transition Disable Bitmap bits */
+#define TRANSITION_DISABLE_WPA3_PERSONAL BIT(0)
+#define TRANSITION_DISABLE_SAE_PK BIT(1)
+#define TRANSITION_DISABLE_WPA3_ENTERPRISE BIT(2)
+#define TRANSITION_DISABLE_ENHANCED_OPEN BIT(3)
#ifdef _MSC_VER
#pragma pack(pop)
@@ -372,7 +397,9 @@
const u8 *mdie, size_t mdie_len,
const u8 *ftie, size_t ftie_len,
const u8 *rsnie, size_t rsnie_len,
- const u8 *ric, size_t ric_len, u8 *mic);
+ const u8 *ric, size_t ric_len,
+ const u8 *rsnxe, size_t rsnxe_len,
+ u8 *mic);
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,
@@ -451,13 +478,18 @@
size_t gtk_len;
const u8 *r0kh_id;
size_t r0kh_id_len;
+ const u8 *fte_anonce;
+ const u8 *fte_snonce;
const u8 *rsn;
size_t rsn_len;
+ u16 rsn_capab;
const u8 *rsn_pmkid;
const u8 *tie;
size_t tie_len;
const u8 *igtk;
size_t igtk_len;
+ const u8 *bigtk;
+ size_t bigtk_len;
#ifdef CONFIG_OCV
const u8 *oci;
size_t oci_len;
@@ -466,11 +498,72 @@
size_t ric_len;
int key_mgmt;
int pairwise_cipher;
+ const u8 *rsnxe;
+ size_t rsnxe_len;
};
int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
int use_sha384);
+struct wpa_eapol_ie_parse {
+ const u8 *wpa_ie;
+ size_t wpa_ie_len;
+ const u8 *rsn_ie;
+ size_t rsn_ie_len;
+ const u8 *pmkid;
+ const u8 *key_id;
+ const u8 *gtk;
+ size_t gtk_len;
+ const u8 *mac_addr;
+ size_t mac_addr_len;
+ const u8 *igtk;
+ size_t igtk_len;
+ const u8 *bigtk;
+ size_t bigtk_len;
+ const u8 *mdie;
+ size_t mdie_len;
+ const u8 *ftie;
+ size_t ftie_len;
+ const u8 *ip_addr_req;
+ const u8 *ip_addr_alloc;
+ const u8 *transition_disable;
+ size_t transition_disable_len;
+ const u8 *oci;
+ size_t oci_len;
+ const u8 *osen;
+ size_t osen_len;
+ const u8 *rsnxe;
+ size_t rsnxe_len;
+ const u8 *reassoc_deadline;
+ const u8 *key_lifetime;
+ const u8 *lnkid;
+ size_t lnkid_len;
+ const u8 *ext_capab;
+ size_t ext_capab_len;
+ const u8 *supp_rates;
+ size_t supp_rates_len;
+ const u8 *ext_supp_rates;
+ size_t ext_supp_rates_len;
+ const u8 *ht_capabilities;
+ const u8 *vht_capabilities;
+ const u8 *supp_channels;
+ size_t supp_channels_len;
+ const u8 *supp_oper_classes;
+ size_t supp_oper_classes_len;
+ u8 qosinfo;
+ u16 aid;
+ const u8 *wmm;
+ size_t wmm_len;
+};
+
+int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie);
+static inline int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
+ struct wpa_eapol_ie_parse *ie)
+{
+ return wpa_parse_kde_ies(buf, len, ie);
+}
+
+
int wpa_cipher_key_len(int cipher);
int wpa_cipher_rsc_len(int cipher);
enum wpa_alg wpa_cipher_to_alg(int cipher);
diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c
index 944b6e3..c1ce68c 100644
--- a/src/common/wpa_ctrl.c
+++ b/src/common/wpa_ctrl.c
@@ -270,7 +270,6 @@
void wpa_ctrl_cleanup(void)
{
DIR *dir;
- struct dirent entry;
struct dirent *result;
size_t dirnamelen;
size_t maxcopy;
@@ -288,8 +287,8 @@
}
namep = pathname + dirnamelen;
maxcopy = PATH_MAX - dirnamelen;
- while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
- if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy)
+ while ((result = readdir(dir)) != NULL) {
+ if (os_strlcpy(namep, result->d_name, maxcopy) < maxcopy)
unlink(pathname);
}
closedir(dir);
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index f65077e..ca1c35f 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -87,11 +87,16 @@
#define WPA_EVENT_BEACON_LOSS "CTRL-EVENT-BEACON-LOSS "
/** Regulatory domain channel */
#define WPA_EVENT_REGDOM_CHANGE "CTRL-EVENT-REGDOM-CHANGE "
+/** Channel switch started (followed by freq=<MHz> and other channel parameters)
+ */
+#define WPA_EVENT_CHANNEL_SWITCH_STARTED "CTRL-EVENT-STARTED-CHANNEL-SWITCH "
/** 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 "
+/** Unprotected Beacon frame dropped */
+#define WPA_EVENT_UNPROT_BEACON "CTRL-EVENT-UNPROT-BEACON "
/** IP subnet status change notification
*
@@ -165,8 +170,10 @@
#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_CONN_STATUS_RESULT "DPP-CONN-STATUS-RESULT "
#define DPP_EVENT_CONFOBJ_AKM "DPP-CONFOBJ-AKM "
#define DPP_EVENT_CONFOBJ_SSID "DPP-CONFOBJ-SSID "
+#define DPP_EVENT_CONFOBJ_SSID_CHARSET "DPP-CONFOBJ-SSID-CHARSET "
#define DPP_EVENT_CONFOBJ_PASS "DPP-CONFOBJ-PASS "
#define DPP_EVENT_CONFOBJ_PSK "DPP-CONFOBJ-PSK "
#define DPP_EVENT_CONNECTOR "DPP-CONNECTOR "
@@ -174,6 +181,7 @@
#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_CONFIGURATOR_ID "DPP-CONFIGURATOR-ID "
#define DPP_EVENT_RX "DPP-RX "
#define DPP_EVENT_TX "DPP-TX "
#define DPP_EVENT_TX_STATUS "DPP-TX-STATUS "
@@ -181,6 +189,7 @@
#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 "
+#define DPP_EVENT_CHIRP_STOPPED "DPP-CHIRP-STOPPED "
/* MESH events */
#define MESH_GROUP_STARTED "MESH-GROUP-STARTED "
@@ -296,6 +305,8 @@
#define WPS_EVENT_AP_SETUP_UNLOCKED "WPS-AP-SETUP-UNLOCKED "
#define WPS_EVENT_AP_PIN_ENABLED "WPS-AP-PIN-ENABLED "
#define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED "
+#define WPS_EVENT_PIN_ACTIVE "WPS-PIN-ACTIVE "
+#define WPS_EVENT_CANCEL "WPS-CANCEL "
#define AP_STA_CONNECTED "AP-STA-CONNECTED "
#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
#define AP_STA_POSSIBLE_PSK_MISMATCH "AP-STA-POSSIBLE-PSK-MISMATCH "
@@ -372,6 +383,13 @@
#define WDS_STA_INTERFACE_ADDED "WDS-STA-INTERFACE-ADDED "
#define WDS_STA_INTERFACE_REMOVED "WDS-STA-INTERFACE-REMOVED "
+/* Transition mode disabled indication - followed by bitmap */
+#define TRANSITION_DISABLE "TRANSITION-DISABLE "
+
+#ifndef BIT
+#define BIT(x) (1U << (x))
+#endif
+
/* BSS command information masks */
#define WPA_BSS_MASK_ALL 0xFFFDFFFF
diff --git a/src/crypto/Makefile b/src/crypto/Makefile
index ab108da..c40e955 100644
--- a/src/crypto/Makefile
+++ b/src/crypto/Makefile
@@ -54,6 +54,8 @@
sha384.o \
sha384-prf.o \
sha384-internal.o \
+ sha512.o \
+ sha512-prf.o \
sha512-internal.o
LIB_OBJS += crypto_internal.o
diff --git a/src/crypto/aes_i.h b/src/crypto/aes_i.h
index 54375cf..b20ec92 100644
--- a/src/crypto/aes_i.h
+++ b/src/crypto/aes_i.h
@@ -65,7 +65,7 @@
#else /* AES_SMALL_TABLES */
-#define RCON(i) (rcons[(i)] << 24)
+#define RCON(i) ((u32) rcons[(i)] << 24)
static inline u32 rotr(u32 val, int bits)
{
@@ -94,10 +94,10 @@
#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8)
#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16)
#define TD3(i) rotr(Td0[(i) & 0xff], 24)
-#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24)
-#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16)
-#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8)
-#define TD44(i) (Td4s[(i) & 0xff])
+#define TD41(i) ((u32) Td4s[((i) >> 24) & 0xff] << 24)
+#define TD42(i) ((u32) Td4s[((i) >> 16) & 0xff] << 16)
+#define TD43(i) ((u32) Td4s[((i) >> 8) & 0xff] << 8)
+#define TD44(i) ((u32) Td4s[(i) & 0xff])
#define TD0_(i) Td0[(i) & 0xff]
#define TD1_(i) rotr(Td0[(i) & 0xff], 8)
#define TD2_(i) rotr(Td0[(i) & 0xff], 16)
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 12109ce..7c7515f 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -519,6 +519,13 @@
struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len);
/**
+ * crypto_bignum_init_set - Allocate memory for bignum and set the value (uint)
+ * @val: Value to set
+ * Returns: Pointer to allocated bignum or %NULL on failure
+ */
+struct crypto_bignum * crypto_bignum_init_uint(unsigned int val);
+
+/**
* crypto_bignum_deinit - Free bignum
* @n: Bignum from crypto_bignum_init() or crypto_bignum_init_set()
* @clear: Whether to clear the value from memory
@@ -613,6 +620,19 @@
struct crypto_bignum *c);
/**
+ * crypto_bignum_addmod - d = a + b (mod c)
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum
+ * @d: Bignum; used to store the result of (a + b) % c
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_addmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d);
+
+/**
* crypto_bignum_mulmod - d = a * b (mod c)
* @a: Bignum
* @b: Bignum
@@ -626,6 +646,17 @@
struct crypto_bignum *d);
/**
+ * crypto_bignum_sqrmod - c = a^2 (mod b)
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result of a^2 % b
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_sqrmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c);
+
+/**
* crypto_bignum_rshift - r = a >> n
* @a: Bignum
* @n: Number of bits
@@ -645,13 +676,6 @@
const struct crypto_bignum *b);
/**
- * crypto_bignum_bits - Get size of a bignum in bits
- * @a: Bignum
- * Returns: Number of bits in the bignum
- */
-int crypto_bignum_bits(const struct crypto_bignum *a);
-
-/**
* crypto_bignum_is_zero - Is the given bignum zero
* @a: Bignum
* Returns: 1 if @a is zero or 0 if not
@@ -738,6 +762,9 @@
*/
const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e);
+const struct crypto_bignum * crypto_ec_get_a(struct crypto_ec *e);
+const struct crypto_bignum * crypto_ec_get_b(struct crypto_ec *e);
+
/**
* struct crypto_ec_point - Elliptic curve point
*
@@ -889,5 +916,6 @@
struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
const u8 *key, size_t len);
void crypto_ecdh_deinit(struct crypto_ecdh *ecdh);
+size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh);
#endif /* CRYPTO_H */
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 1b0c1ec..47b6ebb 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -570,8 +570,8 @@
failed = !q || !ctx || !tmp ||
!BN_mod_exp(tmp, pub, q, p, ctx) ||
!BN_is_one(tmp);
- BN_clear(q);
- BN_clear(tmp);
+ BN_clear_free(q);
+ BN_clear_free(tmp);
BN_CTX_free(ctx);
if (failed)
goto fail;
@@ -580,8 +580,8 @@
res = crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
prime, prime_len, secret, len);
fail:
- BN_clear(pub);
- BN_clear(p);
+ BN_clear_free(pub);
+ BN_clear_free(p);
return res;
}
@@ -1283,6 +1283,24 @@
}
+struct crypto_bignum * crypto_bignum_init_uint(unsigned int val)
+{
+ BIGNUM *bn;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ bn = BN_new();
+ if (!bn)
+ return NULL;
+ if (BN_set_word(bn, val) != 1) {
+ BN_free(bn);
+ return NULL;
+ }
+ return (struct crypto_bignum *) bn;
+}
+
+
void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
{
if (clear)
@@ -1303,6 +1321,18 @@
if (padlen > buflen)
return -1;
+ if (padlen) {
+#ifdef OPENSSL_IS_BORINGSSL
+ if (BN_bn2bin_padded(buf, padlen, (const BIGNUM *) a) == 0)
+ return -1;
+ return padlen;
+#else /* OPENSSL_IS_BORINGSSL */
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+ return BN_bn2binpad((const BIGNUM *) a, buf, padlen);
+#endif
+#endif
+ }
+
num_bytes = BN_num_bytes((const BIGNUM *) a);
if ((size_t) num_bytes > buflen)
return -1;
@@ -1437,6 +1467,28 @@
}
+int crypto_bignum_addmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d)
+{
+ int res;
+ BN_CTX *bnctx;
+
+ if (TEST_FAIL())
+ return -1;
+
+ bnctx = BN_CTX_new();
+ if (!bnctx)
+ return -1;
+ res = BN_mod_add((BIGNUM *) d, (const BIGNUM *) a, (const BIGNUM *) b,
+ (const BIGNUM *) c, bnctx);
+ BN_CTX_free(bnctx);
+
+ return res ? 0 : -1;
+}
+
+
int crypto_bignum_mulmod(const struct crypto_bignum *a,
const struct crypto_bignum *b,
const struct crypto_bignum *c,
@@ -1460,6 +1512,27 @@
}
+int crypto_bignum_sqrmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+{
+ int res;
+ BN_CTX *bnctx;
+
+ if (TEST_FAIL())
+ return -1;
+
+ bnctx = BN_CTX_new();
+ if (!bnctx)
+ return -1;
+ res = BN_mod_sqr((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b,
+ bnctx);
+ BN_CTX_free(bnctx);
+
+ return res ? 0 : -1;
+}
+
+
int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
struct crypto_bignum *r)
{
@@ -1476,12 +1549,6 @@
}
-int crypto_bignum_bits(const struct crypto_bignum *a)
-{
- return BN_num_bits((const BIGNUM *) a);
-}
-
-
int crypto_bignum_is_zero(const struct crypto_bignum *a)
{
return BN_is_zero((const BIGNUM *) a);
@@ -1676,6 +1743,18 @@
}
+const struct crypto_bignum * crypto_ec_get_a(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) e->a;
+}
+
+
+const struct crypto_bignum * crypto_ec_get_b(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) e->b;
+}
+
+
void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
{
if (clear)
@@ -1870,7 +1949,7 @@
{
struct crypto_ecdh *ecdh;
EVP_PKEY *params = NULL;
- EC_KEY *ec_params;
+ EC_KEY *ec_params = NULL;
EVP_PKEY_CTX *kctx = NULL;
ecdh = os_zalloc(sizeof(*ecdh));
@@ -1913,6 +1992,7 @@
}
done:
+ EC_KEY_free(ec_params);
EVP_PKEY_free(params);
EVP_PKEY_CTX_free(kctx);
@@ -2052,13 +2132,17 @@
secret = wpabuf_alloc(secret_len);
if (!secret)
goto fail;
- if (EVP_PKEY_derive(ctx, wpabuf_put(secret, secret_len),
- &secret_len) != 1) {
+ if (EVP_PKEY_derive(ctx, wpabuf_put(secret, 0), &secret_len) != 1) {
wpa_printf(MSG_ERROR,
"OpenSSL: EVP_PKEY_derive(2) failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto fail;
}
+ if (secret->size != secret_len)
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: EVP_PKEY_derive(2) changed secret_len %d -> %d",
+ (int) secret->size, (int) secret_len);
+ wpabuf_put(secret, secret_len);
done:
BN_free(x);
@@ -2084,4 +2168,10 @@
}
}
+
+size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh)
+{
+ return crypto_ec_prime_len(ecdh->ec);
+}
+
#endif /* CONFIG_ECC */
diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c
index 976a008..dc68bd6 100644
--- a/src/crypto/crypto_wolfssl.c
+++ b/src/crypto/crypto_wolfssl.c
@@ -1042,6 +1042,26 @@
}
+struct crypto_bignum * crypto_bignum_init_uint(unsigned int val)
+{
+ mp_int *a;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ a = (mp_int *) crypto_bignum_init();
+ if (!a)
+ return NULL;
+
+ if (mp_set_int(a, val) != MP_OKAY) {
+ os_free(a);
+ a = NULL;
+ }
+
+ return (struct crypto_bignum *) a;
+}
+
+
void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
{
if (!n)
@@ -1151,7 +1171,7 @@
if (TEST_FAIL())
return -1;
- return mp_add((mp_int *) a, (mp_int *) b,
+ return mp_sub((mp_int *) a, (mp_int *) b,
(mp_int *) r) == MP_OKAY ? 0 : -1;
}
@@ -1168,6 +1188,19 @@
}
+int crypto_bignum_addmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_addmod((mp_int *) a, (mp_int *) b, (mp_int *) c,
+ (mp_int *) d) == MP_OKAY ? 0 : -1;
+}
+
+
int crypto_bignum_mulmod(const struct crypto_bignum *a,
const struct crypto_bignum *b,
const struct crypto_bignum *m,
@@ -1181,6 +1214,18 @@
}
+int crypto_bignum_sqrmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_sqrmod((mp_int *) a, (mp_int *) b,
+ (mp_int *) c) == MP_OKAY ? 0 : -1;
+}
+
+
int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
struct crypto_bignum *r)
{
@@ -1198,12 +1243,6 @@
}
-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);
@@ -1392,6 +1431,18 @@
}
+const struct crypto_bignum * crypto_ec_get_a(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) &e->a;
+}
+
+
+const struct crypto_bignum * crypto_ec_get_b(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) &e->b;
+}
+
+
void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
{
ecc_point *point = (ecc_point *) p;
@@ -1783,4 +1834,10 @@
goto done;
}
+
+size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh)
+{
+ return crypto_ec_prime_len(ecdh->ec);
+}
+
#endif /* CONFIG_ECC */
diff --git a/src/crypto/sha1-internal.c b/src/crypto/sha1-internal.c
index a491707..ffa04df 100644
--- a/src/crypto/sha1-internal.c
+++ b/src/crypto/sha1-internal.c
@@ -224,7 +224,7 @@
/* Wipe variables */
a = b = c = d = e = 0;
#ifdef SHA1HANDSOFF
- os_memset(block, 0, 64);
+ forced_memzero(block, 64);
#endif
}
@@ -300,7 +300,7 @@
os_memset(context->buffer, 0, 64);
os_memset(context->state, 0, 20);
os_memset(context->count, 0, 8);
- os_memset(finalcount, 0, 8);
+ forced_memzero(finalcount, sizeof(finalcount));
}
/* ===== end - public domain SHA1 implementation ===== */
diff --git a/src/crypto/sha1-prf.c b/src/crypto/sha1-prf.c
index 4b2d137..1385149 100644
--- a/src/crypto/sha1-prf.c
+++ b/src/crypto/sha1-prf.c
@@ -61,7 +61,7 @@
}
counter++;
}
- os_memset(hash, 0, sizeof(hash));
+ forced_memzero(hash, sizeof(hash));
return 0;
}
diff --git a/src/crypto/sha1-tlsprf.c b/src/crypto/sha1-tlsprf.c
index a11649a..5e8d159 100644
--- a/src/crypto/sha1-tlsprf.c
+++ b/src/crypto/sha1-tlsprf.c
@@ -92,10 +92,10 @@
SHA1_pos++;
}
- os_memset(A_MD5, 0, MD5_MAC_LEN);
- os_memset(P_MD5, 0, MD5_MAC_LEN);
- os_memset(A_SHA1, 0, SHA1_MAC_LEN);
- os_memset(P_SHA1, 0, SHA1_MAC_LEN);
+ forced_memzero(A_MD5, MD5_MAC_LEN);
+ forced_memzero(P_MD5, MD5_MAC_LEN);
+ forced_memzero(A_SHA1, SHA1_MAC_LEN);
+ forced_memzero(P_SHA1, SHA1_MAC_LEN);
return 0;
}
diff --git a/src/crypto/sha1-tprf.c b/src/crypto/sha1-tprf.c
index 562510f..c3acf19 100644
--- a/src/crypto/sha1-tprf.c
+++ b/src/crypto/sha1-tprf.c
@@ -66,7 +66,7 @@
len[0] = SHA1_MAC_LEN;
}
- os_memset(hash, 0, SHA1_MAC_LEN);
+ forced_memzero(hash, SHA1_MAC_LEN);
return 0;
}
diff --git a/src/crypto/sha1.c b/src/crypto/sha1.c
index 8fce139..76d7a68 100644
--- a/src/crypto/sha1.c
+++ b/src/crypto/sha1.c
@@ -86,7 +86,8 @@
_addr[1] = mac;
_len[1] = SHA1_MAC_LEN;
ret = sha1_vector(2, _addr, _len, mac);
- os_memset(k_pad, 0, sizeof(k_pad));
+ forced_memzero(k_pad, sizeof(k_pad));
+ forced_memzero(tk, sizeof(tk));
return ret;
}
diff --git a/src/crypto/sha256-kdf.c b/src/crypto/sha256-kdf.c
index af7d954..5a6b744 100644
--- a/src/crypto/sha256-kdf.c
+++ b/src/crypto/sha256-kdf.c
@@ -69,7 +69,7 @@
if (iter == 255) {
os_memset(out, 0, outlen);
- os_memset(T, 0, SHA256_MAC_LEN);
+ forced_memzero(T, SHA256_MAC_LEN);
return -1;
}
iter++;
@@ -77,11 +77,11 @@
if (hmac_sha256_vector(secret, secret_len, 4, addr, len, T) < 0)
{
os_memset(out, 0, outlen);
- os_memset(T, 0, SHA256_MAC_LEN);
+ forced_memzero(T, SHA256_MAC_LEN);
return -1;
}
}
- os_memset(T, 0, SHA256_MAC_LEN);
+ forced_memzero(T, SHA256_MAC_LEN);
return 0;
}
diff --git a/src/crypto/sha256-prf.c b/src/crypto/sha256-prf.c
index 722cad6..d665a99 100644
--- a/src/crypto/sha256-prf.c
+++ b/src/crypto/sha256-prf.c
@@ -102,7 +102,7 @@
buf[pos - 1] &= mask;
}
- os_memset(hash, 0, sizeof(hash));
+ forced_memzero(hash, sizeof(hash));
return 0;
}
diff --git a/src/crypto/sha256-tlsprf.c b/src/crypto/sha256-tlsprf.c
index 0528dad..9045cd3 100644
--- a/src/crypto/sha256-tlsprf.c
+++ b/src/crypto/sha256-tlsprf.c
@@ -26,8 +26,8 @@
* This function is used to derive new, cryptographically separate keys from a
* given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
*/
-void tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label,
- const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+int tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label,
+ const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
{
size_t clen;
u8 A[SHA256_MAC_LEN];
@@ -50,12 +50,15 @@
* PRF(secret, label, seed) = P_SHA256(secret, label + seed)
*/
- hmac_sha256_vector(secret, secret_len, 2, &addr[1], &len[1], A);
+ if (hmac_sha256_vector(secret, secret_len, 2, &addr[1], &len[1], A) < 0)
+ return -1;
pos = 0;
while (pos < outlen) {
- hmac_sha256_vector(secret, secret_len, 3, addr, len, P);
- hmac_sha256(secret, secret_len, A, SHA256_MAC_LEN, A);
+ if (hmac_sha256_vector(secret, secret_len, 3, addr, len, P) <
+ 0 ||
+ hmac_sha256(secret, secret_len, A, SHA256_MAC_LEN, A) < 0)
+ return -1;
clen = outlen - pos;
if (clen > SHA256_MAC_LEN)
@@ -63,4 +66,6 @@
os_memcpy(out + pos, P, clen);
pos += clen;
}
+
+ return 0;
}
diff --git a/src/crypto/sha256.c b/src/crypto/sha256.c
index b55e976..17af964 100644
--- a/src/crypto/sha256.c
+++ b/src/crypto/sha256.c
@@ -28,10 +28,10 @@
{
unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
unsigned char tk[32];
- const u8 *_addr[6];
- size_t _len[6], i;
+ const u8 *_addr[11];
+ size_t _len[11], i;
- if (num_elem > 5) {
+ if (num_elem > 10) {
/*
* Fixed limit on the number of fragments to avoid having to
* allocate memory (which could fail).
diff --git a/src/crypto/sha256.h b/src/crypto/sha256.h
index 5219022..8054bbe 100644
--- a/src/crypto/sha256.h
+++ b/src/crypto/sha256.h
@@ -20,9 +20,9 @@
int sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf,
size_t buf_len_bits);
-void tls_prf_sha256(const u8 *secret, size_t secret_len,
- const char *label, const u8 *seed, size_t seed_len,
- u8 *out, size_t outlen);
+int tls_prf_sha256(const u8 *secret, size_t secret_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *out, size_t outlen);
int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
const char *label, const u8 *seed, size_t seed_len,
u8 *out, size_t outlen);
diff --git a/src/crypto/sha384-kdf.c b/src/crypto/sha384-kdf.c
index 1d19627..babcb9e 100644
--- a/src/crypto/sha384-kdf.c
+++ b/src/crypto/sha384-kdf.c
@@ -69,7 +69,7 @@
if (iter == 255) {
os_memset(out, 0, outlen);
- os_memset(T, 0, SHA384_MAC_LEN);
+ forced_memzero(T, SHA384_MAC_LEN);
return -1;
}
iter++;
@@ -77,11 +77,11 @@
if (hmac_sha384_vector(secret, secret_len, 4, addr, len, T) < 0)
{
os_memset(out, 0, outlen);
- os_memset(T, 0, SHA384_MAC_LEN);
+ forced_memzero(T, SHA384_MAC_LEN);
return -1;
}
}
- os_memset(T, 0, SHA384_MAC_LEN);
+ forced_memzero(T, SHA384_MAC_LEN);
return 0;
}
diff --git a/src/crypto/sha384-prf.c b/src/crypto/sha384-prf.c
index 03e3cb3..420e78c 100644
--- a/src/crypto/sha384-prf.c
+++ b/src/crypto/sha384-prf.c
@@ -102,7 +102,7 @@
buf[pos - 1] &= mask;
}
- os_memset(hash, 0, sizeof(hash));
+ forced_memzero(hash, sizeof(hash));
return 0;
}
diff --git a/src/crypto/sha384-tlsprf.c b/src/crypto/sha384-tlsprf.c
new file mode 100644
index 0000000..9ff96ac
--- /dev/null
+++ b/src/crypto/sha384-tlsprf.c
@@ -0,0 +1,71 @@
+/*
+ * TLS PRF P_SHA384
+ * Copyright (c) 2011-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 "sha384.h"
+
+
+/**
+ * tls_prf_sha384 - Pseudo-Random Function for TLS v1.2 (P_SHA384, RFC 5246)
+ * @secret: Key for PRF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure.
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key in TLS. This PRF is defined in RFC 5246, Chapter 5.
+ */
+int tls_prf_sha384(const u8 *secret, size_t secret_len, const char *label,
+ const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+{
+ size_t clen;
+ u8 A[SHA384_MAC_LEN];
+ u8 P[SHA384_MAC_LEN];
+ size_t pos;
+ const unsigned char *addr[3];
+ size_t len[3];
+
+ addr[0] = A;
+ len[0] = SHA384_MAC_LEN;
+ addr[1] = (unsigned char *) label;
+ len[1] = os_strlen(label);
+ addr[2] = seed;
+ len[2] = seed_len;
+
+ /*
+ * RFC 5246, Chapter 5
+ * A(0) = seed, A(i) = HMAC(secret, A(i-1))
+ * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
+ * PRF(secret, label, seed) = P_SHA384(secret, label + seed)
+ */
+
+ if (hmac_sha384_vector(secret, secret_len, 2, &addr[1], &len[1], A) < 0)
+ return -1;
+
+ pos = 0;
+ while (pos < outlen) {
+ if (hmac_sha384_vector(secret, secret_len, 3, addr, len, P) <
+ 0 ||
+ hmac_sha384(secret, secret_len, A, SHA384_MAC_LEN, A) < 0)
+ return -1;
+
+ clen = outlen - pos;
+ if (clen > SHA384_MAC_LEN)
+ clen = SHA384_MAC_LEN;
+ os_memcpy(out + pos, P, clen);
+ pos += clen;
+ }
+
+ return 0;
+}
diff --git a/src/crypto/sha384.c b/src/crypto/sha384.c
index ee136ce..fd84b82 100644
--- a/src/crypto/sha384.c
+++ b/src/crypto/sha384.c
@@ -28,10 +28,10 @@
{
unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */
unsigned char tk[48];
- const u8 *_addr[6];
- size_t _len[6], i;
+ const u8 *_addr[11];
+ size_t _len[11], i;
- if (num_elem > 5) {
+ if (num_elem > 10) {
/*
* Fixed limit on the number of fragments to avoid having to
* allocate memory (which could fail).
diff --git a/src/crypto/sha384.h b/src/crypto/sha384.h
index 2241425..d946907 100644
--- a/src/crypto/sha384.h
+++ b/src/crypto/sha384.h
@@ -20,6 +20,9 @@
int sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf,
size_t buf_len_bits);
+int tls_prf_sha384(const u8 *secret, size_t secret_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *out, size_t outlen);
int hmac_sha384_kdf(const u8 *secret, size_t secret_len,
const char *label, const u8 *seed, size_t seed_len,
u8 *out, size_t outlen);
diff --git a/src/crypto/sha512-kdf.c b/src/crypto/sha512-kdf.c
index 8b71f9b..5bde664 100644
--- a/src/crypto/sha512-kdf.c
+++ b/src/crypto/sha512-kdf.c
@@ -69,7 +69,7 @@
if (iter == 255) {
os_memset(out, 0, outlen);
- os_memset(T, 0, SHA512_MAC_LEN);
+ forced_memzero(T, SHA512_MAC_LEN);
return -1;
}
iter++;
@@ -77,11 +77,11 @@
if (hmac_sha512_vector(secret, secret_len, 4, addr, len, T) < 0)
{
os_memset(out, 0, outlen);
- os_memset(T, 0, SHA512_MAC_LEN);
+ forced_memzero(T, SHA512_MAC_LEN);
return -1;
}
}
- os_memset(T, 0, SHA512_MAC_LEN);
+ forced_memzero(T, SHA512_MAC_LEN);
return 0;
}
diff --git a/src/crypto/sha512-prf.c b/src/crypto/sha512-prf.c
index 3b2ad88..e48cf5f 100644
--- a/src/crypto/sha512-prf.c
+++ b/src/crypto/sha512-prf.c
@@ -102,7 +102,7 @@
buf[pos - 1] &= mask;
}
- os_memset(hash, 0, sizeof(hash));
+ forced_memzero(hash, sizeof(hash));
return 0;
}
diff --git a/src/crypto/sha512.c b/src/crypto/sha512.c
index 66311c3..f60a576 100644
--- a/src/crypto/sha512.c
+++ b/src/crypto/sha512.c
@@ -28,10 +28,10 @@
{
unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */
unsigned char tk[64];
- const u8 *_addr[6];
- size_t _len[6], i;
+ const u8 *_addr[11];
+ size_t _len[11], i;
- if (num_elem > 5) {
+ if (num_elem > 10) {
/*
* Fixed limit on the number of fragments to avoid having to
* allocate memory (which could fail).
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 8bdb91f..c8b1a82 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -48,6 +48,18 @@
#define TLS_MAX_ALT_SUBJECT 10
+struct tls_cert_data {
+ int depth;
+ const char *subject;
+ const struct wpabuf *cert;
+ const u8 *hash;
+ size_t hash_len;
+ const char *altsubject[TLS_MAX_ALT_SUBJECT];
+ int num_altsubject;
+ const char *serial_num;
+ int tod;
+};
+
union tls_event_data {
struct {
int depth;
@@ -57,16 +69,7 @@
const struct wpabuf *cert;
} cert_fail;
- struct {
- int depth;
- const char *subject;
- const struct wpabuf *cert;
- const u8 *hash;
- size_t hash_len;
- const char *altsubject[TLS_MAX_ALT_SUBJECT];
- int num_altsubject;
- const char *serial_num;
- } peer_cert;
+ struct tls_cert_data peer_cert;
struct {
int is_local;
@@ -108,6 +111,7 @@
#define TLS_CONN_ENABLE_TLSv1_0 BIT(14)
#define TLS_CONN_ENABLE_TLSv1_1 BIT(15)
#define TLS_CONN_ENABLE_TLSv1_2 BIT(16)
+#define TLS_CONN_TEAP_ANON_DH BIT(17)
/**
* struct tls_connection_params - Parameters for TLS connection
@@ -184,12 +188,15 @@
const char *suffix_match;
const char *domain_match;
const char *client_cert;
+ const char *client_cert2;
const u8 *client_cert_blob;
size_t client_cert_blob_len;
const char *private_key;
+ const char *private_key2;
const u8 *private_key_blob;
size_t private_key_blob_len;
const char *private_key_passwd;
+ const char *private_key_passwd2;
const char *dh_file;
const u8 *dh_blob;
size_t dh_blob_len;
@@ -643,4 +650,24 @@
void tls_connection_remove_session(struct tls_connection *conn);
+/**
+ * tls_get_tls_unique - Fetch "tls-unique" for channel binding
+ * @conn: Connection context data from tls_connection_init()
+ * @buf: Buffer for returning the value
+ * @max_len: Maximum length of the buffer in bytes
+ * Returns: Number of bytes written to buf or -1 on error
+ *
+ * This function can be used to fetch "tls-unique" (RFC 5929, Section 3) which
+ * is the first TLS Finished message sent in the most recent TLS handshake of
+ * the TLS connection.
+ */
+int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len);
+
+/**
+ * tls_connection_get_cipher_suite - Get current TLS cipher suite
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: TLS cipher suite of the current connection or 0 on error
+ */
+u16 tls_connection_get_cipher_suite(struct tls_connection *conn);
+
#endif /* TLS_H */
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 620254a..7ee371a 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -44,6 +44,13 @@
#define OPENSSL_NEED_EAP_FAST_PRF
#endif
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \
+ defined(EAP_SERVER_FAST) || defined(EAP_TEAP) || \
+ defined(EAP_SERVER_TEAP)
+#define EAP_FAST_OR_TEAP
+#endif
+
+
#if defined(OPENSSL_IS_BORINGSSL)
/* stack_index_t is the return type of OpenSSL's sk_XXX_num() functions. */
typedef size_t stack_index_t;
@@ -1085,11 +1092,8 @@
}
#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 */
+ wpa_printf(MSG_DEBUG, "ENGINE: Loading builtin engines");
+ ENGINE_load_builtin_engines();
if (conf &&
(conf->opensc_engine_path || conf->pkcs11_engine_path ||
@@ -1345,6 +1349,8 @@
return "heartbeat";
case 256:
return "TLS header info"; /* pseudo content type */
+ case 257:
+ return "inner content type"; /* pseudo content type */
default:
return "?";
}
@@ -1354,6 +1360,8 @@
static const char * openssl_handshake_type(int content_type, const u8 *buf,
size_t len)
{
+ if (content_type == 257 && buf && len == 1)
+ return openssl_content_type(buf[0]);
if (content_type != 22 || !buf || len == 0)
return "";
switch (buf[0]) {
@@ -1584,6 +1592,11 @@
options |= SSL_OP_NO_COMPRESSION;
#endif /* SSL_OP_NO_COMPRESSION */
SSL_set_options(conn->ssl, options);
+#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT
+ /* Hopefully there is no need for middlebox compatibility mechanisms
+ * when going through EAP authentication. */
+ SSL_clear_options(conn->ssl, SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
+#endif
conn->ssl_in = BIO_new(BIO_s_mem());
if (!conn->ssl_in) {
@@ -2170,6 +2183,37 @@
}
+static int openssl_cert_tod(X509 *cert)
+{
+ CERTIFICATEPOLICIES *ext;
+ stack_index_t i;
+ char buf[100];
+ int res;
+ int tod = 0;
+
+ ext = X509_get_ext_d2i(cert, NID_certificate_policies, NULL, NULL);
+ if (!ext)
+ return 0;
+
+ for (i = 0; i < sk_POLICYINFO_num(ext); i++) {
+ POLICYINFO *policy;
+
+ policy = sk_POLICYINFO_value(ext, i);
+ res = OBJ_obj2txt(buf, sizeof(buf), policy->policyid, 0);
+ if (res < 0 || (size_t) res >= sizeof(buf))
+ continue;
+ wpa_printf(MSG_DEBUG, "OpenSSL: Certificate Policy %s", buf);
+ if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.1") == 0)
+ tod = 1; /* TOD-STRICT */
+ else if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.2") == 0 && !tod)
+ tod = 2; /* TOD-TOFU */
+ }
+ sk_POLICYINFO_pop_free(ext, POLICYINFO_free);
+
+ return tod;
+}
+
+
static void openssl_tls_cert_event(struct tls_connection *conn,
X509 *err_cert, int depth,
const char *subject)
@@ -2262,6 +2306,8 @@
ev.peer_cert.altsubject[alt] = altsubject[alt];
ev.peer_cert.num_altsubject = num_altsubject;
+ ev.peer_cert.tod = openssl_cert_tod(err_cert);
+
context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
wpabuf_free(cert);
for (alt = 0; alt < num_altsubject; alt++)
@@ -2269,6 +2315,38 @@
}
+static void debug_print_cert(X509 *cert, const char *title)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+ BIO *out;
+ size_t rlen;
+ char *txt;
+ int res;
+
+ if (wpa_debug_level > MSG_DEBUG)
+ return;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return;
+
+ X509_print(out, cert);
+ rlen = BIO_ctrl_pending(out);
+ txt = os_malloc(rlen + 1);
+ if (txt) {
+ res = BIO_read(out, txt, rlen);
+ if (res > 0) {
+ txt[res] = '\0';
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s\n%s", title, txt);
+ }
+ os_free(txt);
+ }
+
+ BIO_free(out);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
char buf[256];
@@ -2289,6 +2367,8 @@
depth = X509_STORE_CTX_get_error_depth(x509_ctx);
ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
SSL_get_ex_data_X509_STORE_CTX_idx());
+ os_snprintf(buf, sizeof(buf), "Peer certificate - depth %d", depth);
+ debug_print_cert(err_cert, buf);
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
conn = SSL_get_app_data(ssl);
@@ -2366,7 +2446,30 @@
}
#endif /* CONFIG_SHA256 */
+ openssl_tls_cert_event(conn, err_cert, depth, buf);
+
if (!preverify_ok) {
+ if (depth > 0) {
+ /* Send cert event for the peer certificate so that
+ * the upper layers get information about it even if
+ * validation of a CA certificate fails. */
+ STACK_OF(X509) *chain;
+
+ chain = X509_STORE_CTX_get1_chain(x509_ctx);
+ if (chain && sk_X509_num(chain) > 0) {
+ char buf2[256];
+ X509 *cert;
+
+ cert = sk_X509_value(chain, 0);
+ X509_NAME_oneline(X509_get_subject_name(cert),
+ buf2, sizeof(buf2));
+
+ openssl_tls_cert_event(conn, cert, 0, buf2);
+ }
+ if (chain)
+ sk_X509_pop_free(chain, X509_free);
+ }
+
wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
" error %d (%s) depth %d for '%s'", err, err_str,
depth, buf);
@@ -2422,8 +2525,7 @@
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
"Domain mismatch",
TLS_FAIL_DOMAIN_MISMATCH);
- } else
- openssl_tls_cert_event(conn, err_cert, depth, buf);
+ }
if (conn->cert_probe && preverify_ok && depth == 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate "
@@ -2598,9 +2700,23 @@
(const unsigned char **) &ca_cert_blob,
ca_cert_blob_len);
if (cert == NULL) {
- tls_show_errors(MSG_WARNING, __func__,
- "Failed to parse ca_cert_blob");
- return -1;
+ BIO *bio = BIO_new_mem_buf(ca_cert_blob,
+ ca_cert_blob_len);
+
+ if (bio) {
+ cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+ BIO_free(bio);
+ }
+
+ if (!cert) {
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed to parse ca_cert_blob");
+ return -1;
+ }
+
+ while (ERR_get_error()) {
+ /* Ignore errors from DER conversion. */
+ }
}
if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
@@ -3034,6 +3150,40 @@
}
#endif /* CONFIG_SUITEB */
+ if (flags & TLS_CONN_TEAP_ANON_DH) {
+#ifndef TEAP_DH_ANON_CS
+#define TEAP_DH_ANON_CS \
+ "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:" \
+ "ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:" \
+ "ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:" \
+ "DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:" \
+ "DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:" \
+ "DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:" \
+ "ADH-AES256-GCM-SHA384:ADH-AES128-GCM-SHA256:" \
+ "ADH-AES256-SHA256:ADH-AES128-SHA256:ADH-AES256-SHA:ADH-AES128-SHA"
+#endif
+ static const char *cs = TEAP_DH_ANON_CS;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
+ !defined(LIBRESSL_VERSION_NUMBER) && \
+ !defined(OPENSSL_IS_BORINGSSL)
+ /*
+ * Need to drop to security level 0 to allow anonymous
+ * cipher suites for EAP-TEAP.
+ */
+ SSL_set_security_level(conn->ssl, 0);
+#endif
+
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Enable cipher suites for anonymous EAP-TEAP provisioning: %s",
+ cs);
+ if (SSL_set_cipher_list(conn->ssl, cs) != 1) {
+ tls_show_errors(MSG_INFO, __func__,
+ "Cipher suite configuration failed");
+ return -1;
+ }
+ }
+
return 0;
}
@@ -3916,6 +4066,7 @@
int cipher, digest;
const EVP_CIPHER *c;
const EVP_MD *h;
+ int mac_key_len, enc_key_len, fixed_iv_len;
ssl_cipher = SSL_get_current_cipher(ssl);
if (!ssl_cipher)
@@ -3926,17 +4077,33 @@
cipher, digest);
if (cipher < 0 || digest < 0)
return -1;
- c = EVP_get_cipherbynid(cipher);
- h = EVP_get_digestbynid(digest);
- if (!c || !h)
+ if (cipher == NID_undef) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: no cipher in use?!");
return -1;
+ }
+ c = EVP_get_cipherbynid(cipher);
+ if (!c)
+ return -1;
+ enc_key_len = EVP_CIPHER_key_length(c);
+ if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE ||
+ EVP_CIPHER_mode(c) == EVP_CIPH_CCM_MODE)
+ fixed_iv_len = 4; /* only part of IV from PRF */
+ else
+ fixed_iv_len = EVP_CIPHER_iv_length(c);
+ if (digest == NID_undef) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: no digest in use (e.g., AEAD)");
+ mac_key_len = 0;
+ } else {
+ h = EVP_get_digestbynid(digest);
+ if (!h)
+ return -1;
+ mac_key_len = EVP_MD_size(h);
+ }
wpa_printf(MSG_DEBUG,
- "OpenSSL: keyblock size: key_len=%d MD_size=%d IV_len=%d",
- EVP_CIPHER_key_length(c), EVP_MD_size(h),
- EVP_CIPHER_iv_length(c));
- return 2 * (EVP_CIPHER_key_length(c) + EVP_MD_size(h) +
- EVP_CIPHER_iv_length(c));
+ "OpenSSL: keyblock size: mac_key_len=%d enc_key_len=%d fixed_iv_len=%d",
+ mac_key_len, enc_key_len, fixed_iv_len);
+ return 2 * (mac_key_len + enc_key_len + fixed_iv_len);
#endif
}
#endif /* OPENSSL_NEED_EAP_FAST_PRF */
@@ -4020,7 +4187,7 @@
_out, skip + out_len) == 0) {
ret = 0;
}
- os_memset(master_key, 0, sizeof(master_key));
+ forced_memzero(master_key, sizeof(master_key));
os_free(rnd);
if (ret == 0)
os_memcpy(out, _out + skip, out_len);
@@ -4210,6 +4377,22 @@
wpa_printf(MSG_DEBUG,
"OpenSSL: Handshake finished - resumed=%d",
tls_connection_resumed(conn->ssl_ctx, conn));
+ if (conn->server) {
+ char *buf;
+ size_t buflen = 2000;
+
+ buf = os_malloc(buflen);
+ if (buf) {
+ if (SSL_get_shared_ciphers(conn->ssl, buf,
+ buflen)) {
+ buf[buflen - 1] = '\0';
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Shared ciphers: %s",
+ buf);
+ }
+ os_free(buf);
+ }
+ }
if (appl_data && in_data)
*appl_data = openssl_get_appl_data(conn,
wpabuf_len(in_data));
@@ -4392,11 +4575,15 @@
c++;
}
+ if (!buf[0]) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: No ciphers listed");
+ return -1;
+ }
wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
-#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+#ifdef EAP_FAST_OR_TEAP
if (os_strstr(buf, ":ADH-")) {
/*
* Need to drop to security level 0 to allow anonymous
@@ -4407,7 +4594,7 @@
/* Force at least security level 1 */
SSL_set_security_level(conn->ssl, 1);
}
-#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+#endif /* EAP_FAST_OR_TEAP */
#endif
if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
@@ -4461,7 +4648,7 @@
}
-#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+#ifdef EAP_FAST_OR_TEAP
/* ClientHello TLS extensions require a patch to openssl, so this function is
* commented out unless explicitly needed for EAP-FAST in order to be able to
* build this file with unmodified openssl. */
@@ -4478,7 +4665,7 @@
return 0;
}
-#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+#endif /* EAP_FAST_OR_TEAP */
int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
@@ -4541,41 +4728,6 @@
}
-static void debug_print_cert(X509 *cert, const char *title)
-{
-#ifndef CONFIG_NO_STDOUT_DEBUG
- BIO *out;
- size_t rlen;
- char *txt;
- int res;
-
- if (wpa_debug_level > MSG_DEBUG)
- return;
-
- out = BIO_new(BIO_s_mem());
- if (!out)
- return;
-
- X509_print(out, cert);
- rlen = BIO_ctrl_pending(out);
- txt = os_malloc(rlen + 1);
- if (!txt) {
- BIO_free(out);
- return;
- }
-
- res = BIO_read(out, txt, rlen);
- if (res > 0) {
- txt[res] = '\0';
- wpa_printf(MSG_DEBUG, "OpenSSL: %s\n%s", title, txt);
- }
- os_free(txt);
-
- BIO_free(out);
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-}
-
-
static int ocsp_resp_cb(SSL *s, void *arg)
{
struct tls_connection *conn = arg;
@@ -4687,6 +4839,7 @@
res = OCSP_resp_find_status(basic, id, &status, &reason, &produced_at,
&this_update, &next_update);
if (!res) {
+ OCSP_CERTID_free(id);
id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer);
if (!id) {
wpa_printf(MSG_DEBUG,
@@ -4774,6 +4927,76 @@
#endif /* HAVE_OCSP */
+static size_t max_str_len(const char **lines)
+{
+ const char **p;
+ size_t max_len = 0;
+
+ for (p = lines; *p; p++) {
+ size_t len = os_strlen(*p);
+
+ if (len > max_len)
+ max_len = len;
+ }
+
+ return max_len;
+}
+
+
+static int match_lines_in_file(const char *path, const char **lines)
+{
+ FILE *f;
+ char *buf;
+ size_t bufsize;
+ int found = 0, is_linestart = 1;
+
+ bufsize = max_str_len(lines) + sizeof("\r\n");
+ buf = os_malloc(bufsize);
+ if (!buf)
+ return 0;
+
+ f = fopen(path, "r");
+ if (!f) {
+ os_free(buf);
+ return 0;
+ }
+
+ while (!found && fgets(buf, bufsize, f)) {
+ int is_lineend;
+ size_t len;
+ const char **p;
+
+ len = strcspn(buf, "\r\n");
+ is_lineend = buf[len] != '\0';
+ buf[len] = '\0';
+
+ if (is_linestart && is_lineend) {
+ for (p = lines; !found && *p; p++)
+ found = os_strcmp(buf, *p) == 0;
+ }
+ is_linestart = is_lineend;
+ }
+
+ fclose(f);
+ bin_clear_free(buf, bufsize);
+
+ return found;
+}
+
+
+static int is_tpm2_key(const char *path)
+{
+ /* Check both new and old format of TPM2 PEM guard tag */
+ static const char *tpm2_tags[] = {
+ "-----BEGIN TSS2 PRIVATE KEY-----",
+ "-----BEGIN TSS2 KEY BLOB-----",
+ NULL
+ };
+
+ return match_lines_in_file(path, tpm2_tags);
+}
+
+
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params)
{
@@ -4826,6 +5049,17 @@
if (can_pkcs11 == 2 && !engine_id)
engine_id = "pkcs11";
+ /* If private_key points to a TPM2-wrapped key, automatically enable
+ * tpm2 engine and use it to unwrap the key. */
+ if (params->private_key &&
+ (!engine_id || os_strcmp(engine_id, "tpm2") == 0) &&
+ is_tpm2_key(params->private_key)) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Found TPM2 wrapped key %s",
+ params->private_key);
+ key_id = key_id ? key_id : params->private_key;
+ engine_id = engine_id ? engine_id : "tpm2";
+ }
+
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
if (params->flags & TLS_CONN_EAP_FAST) {
@@ -4857,7 +5091,8 @@
}
if (engine_id) {
- wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
+ wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine %s",
+ engine_id);
ret = tls_engine_init(conn, engine_id, params->pin,
key_id, cert_id, ca_cert_id);
if (ret)
@@ -4997,6 +5232,114 @@
}
+static void openssl_debug_dump_cipher_list(SSL_CTX *ssl_ctx)
+{
+ SSL *ssl;
+ int i;
+
+ ssl = SSL_new(ssl_ctx);
+ if (!ssl)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Enabled cipher suites in priority order");
+ for (i = 0; ; i++) {
+ const char *cipher;
+
+ cipher = SSL_get_cipher_list(ssl, i);
+ if (!cipher)
+ break;
+ wpa_printf(MSG_DEBUG, "Cipher %d: %s", i, cipher);
+ }
+
+ SSL_free(ssl);
+}
+
+
+#if !defined(LIBRESSL_VERSION_NUMBER) && !defined(BORINGSSL_API_VERSION)
+
+static const char * openssl_pkey_type_str(const EVP_PKEY *pkey)
+{
+ if (!pkey)
+ return "NULL";
+ switch (EVP_PKEY_type(EVP_PKEY_id(pkey))) {
+ case EVP_PKEY_RSA:
+ return "RSA";
+ case EVP_PKEY_DSA:
+ return "DSA";
+ case EVP_PKEY_DH:
+ return "DH";
+ case EVP_PKEY_EC:
+ return "EC";
+ }
+ return "?";
+}
+
+
+static void openssl_debug_dump_certificate(int i, X509 *cert)
+{
+ char buf[256];
+ EVP_PKEY *pkey;
+ ASN1_INTEGER *ser;
+ char serial_num[128];
+
+ X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
+
+ ser = X509_get_serialNumber(cert);
+ if (ser)
+ wpa_snprintf_hex_uppercase(serial_num, sizeof(serial_num),
+ ASN1_STRING_get0_data(ser),
+ ASN1_STRING_length(ser));
+ else
+ serial_num[0] = '\0';
+
+ pkey = X509_get_pubkey(cert);
+ wpa_printf(MSG_DEBUG, "%d: %s (%s) %s", i, buf,
+ openssl_pkey_type_str(pkey), serial_num);
+ EVP_PKEY_free(pkey);
+}
+
+
+static void openssl_debug_dump_certificates(SSL_CTX *ssl_ctx)
+{
+ STACK_OF(X509) *certs;
+
+ wpa_printf(MSG_DEBUG, "OpenSSL: Configured certificate chain");
+ if (SSL_CTX_get0_chain_certs(ssl_ctx, &certs) == 1) {
+ int i;
+
+ for (i = sk_X509_num(certs); i > 0; i--)
+ openssl_debug_dump_certificate(i, sk_X509_value(certs,
+ i - 1));
+ }
+ openssl_debug_dump_certificate(0, SSL_CTX_get0_certificate(ssl_ctx));
+}
+
+#endif
+
+
+static void openssl_debug_dump_certificate_chains(SSL_CTX *ssl_ctx)
+{
+#if !defined(LIBRESSL_VERSION_NUMBER) && !defined(BORINGSSL_API_VERSION)
+ int res;
+
+ for (res = SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_FIRST);
+ res == 1;
+ res = SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_NEXT))
+ openssl_debug_dump_certificates(ssl_ctx);
+
+ SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_FIRST);
+#endif
+}
+
+
+static void openssl_debug_dump_ctx(SSL_CTX *ssl_ctx)
+{
+ openssl_debug_dump_cipher_list(ssl_ctx);
+ openssl_debug_dump_certificate_chains(ssl_ctx);
+}
+
+
int tls_global_set_params(void *tls_ctx,
const struct tls_connection_params *params)
{
@@ -5022,6 +5365,9 @@
tls_global_client_cert(data, params->client_cert) ||
tls_global_private_key(data, params->private_key,
params->private_key_passwd) ||
+ tls_global_client_cert(data, params->client_cert2) ||
+ tls_global_private_key(data, params->private_key2,
+ params->private_key_passwd2) ||
tls_global_dh(data, params->dh_file)) {
wpa_printf(MSG_INFO, "TLS: Failed to set global parameters");
return -1;
@@ -5091,11 +5437,13 @@
tls_global->ocsp_stapling_response = NULL;
#endif /* HAVE_OCSP */
+ openssl_debug_dump_ctx(ssl_ctx);
+
return 0;
}
-#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+#ifdef EAP_FAST_OR_TEAP
/* Pre-shared secred requires a patch to openssl, so this function is
* commented out unless explicitly needed for EAP-FAST in order to be able to
* build this file with unmodified openssl. */
@@ -5176,7 +5524,7 @@
return 1;
}
-#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+#endif /* EAP_FAST_OR_TEAP */
int tls_connection_set_session_ticket_cb(void *tls_ctx,
@@ -5184,7 +5532,7 @@
tls_session_ticket_cb cb,
void *ctx)
{
-#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+#ifdef EAP_FAST_OR_TEAP
conn->session_ticket_cb = cb;
conn->session_ticket_cb_ctx = ctx;
@@ -5201,9 +5549,9 @@
}
return 0;
-#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+#else /* EAP_FAST_OR_TEAP */
return -1;
-#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+#endif /* EAP_FAST_OR_TEAP */
}
@@ -5286,3 +5634,36 @@
wpa_printf(MSG_DEBUG,
"OpenSSL: Removed cached session to disable session resumption");
}
+
+
+int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len)
+{
+ size_t len;
+ int reused;
+
+ reused = SSL_session_reused(conn->ssl);
+ if ((conn->server && !reused) || (!conn->server && reused))
+ len = SSL_get_peer_finished(conn->ssl, buf, max_len);
+ else
+ len = SSL_get_finished(conn->ssl, buf, max_len);
+
+ if (len == 0 || len > max_len)
+ return -1;
+
+ return len;
+}
+
+
+u16 tls_connection_get_cipher_suite(struct tls_connection *conn)
+{
+ const SSL_CIPHER *cipher;
+
+ cipher = SSL_get_current_cipher(conn->ssl);
+ if (!cipher)
+ return 0;
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
+ return SSL_CIPHER_get_protocol_id(cipher);
+#else
+ return SSL_CIPHER_get_id(cipher) & 0xFFFF;
+#endif
+}
diff --git a/src/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c
index e9cb425..d222d14 100644
--- a/src/crypto/tls_wolfssl.c
+++ b/src/crypto/tls_wolfssl.c
@@ -141,7 +141,7 @@
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);
+ os_memcpy(buf, wpabuf_head_u8(data->in_data) + data->consumed, get);
data->consumed += get;
if (get == 0)
@@ -2044,7 +2044,7 @@
_out, skip + out_len);
}
- os_memset(master_key, 0, master_key_len);
+ forced_memzero(master_key, master_key_len);
if (ret == 0)
os_memcpy(out, _out + skip, out_len);
bin_clear_free(tmp_out, skip + out_len);
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index e7c8f31..e3b13bc 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -102,6 +102,20 @@
};
/**
+ * struct hostapd_wmm_rule - WMM regulatory rule
+ * @min_cwmin: Lower bound of CW_min value
+ * @min_cwmax: Lower bound of CW_max value
+ * @min_aifs: Lower bound of AIFS value
+ * @max_txop: Upper bound of TXOP, value in units of 32 usec
+ */
+struct hostapd_wmm_rule {
+ int min_cwmin;
+ int min_cwmax;
+ int min_aifs;
+ int max_txop;
+};
+
+/**
* struct hostapd_channel_data - Channel information
*/
struct hostapd_channel_data {
@@ -156,34 +170,67 @@
* dfs_cac_ms - DFS CAC time in milliseconds
*/
unsigned int dfs_cac_ms;
+
+ /**
+ * wmm_rules_valid - Indicates wmm_rules state
+ */
+ int wmm_rules_valid;
+
+ /**
+ * wmm_rules - WMM regulatory rules
+ */
+ struct hostapd_wmm_rule wmm_rules[WMM_AC_NUM];
};
-#define HE_MAX_NUM_SS 8
-#define HE_MAX_PHY_CAPAB_SIZE 3
-
-/**
- * struct he_ppe_threshold - IEEE 802.11ax HE PPE Threshold
- */
-struct he_ppe_threshold {
- u32 numss_m1;
- u32 ru_count;
- u32 ppet16_ppet8_ru3_ru0[HE_MAX_NUM_SS];
-};
+#define HE_MAC_CAPAB_0 0
+#define HE_MAX_MAC_CAPAB_SIZE 6
+#define HE_MAX_PHY_CAPAB_SIZE 11
+#define HE_MAX_MCS_CAPAB_SIZE 12
+#define HE_MAX_PPET_CAPAB_SIZE 25
/**
* struct he_capabilities - IEEE 802.11ax HE capabilities
*/
struct he_capabilities {
u8 he_supported;
- u32 phy_cap[HE_MAX_PHY_CAPAB_SIZE];
- u32 mac_cap;
- u32 mcs;
- struct he_ppe_threshold ppet;
+ u8 phy_cap[HE_MAX_PHY_CAPAB_SIZE];
+ u8 mac_cap[HE_MAX_MAC_CAPAB_SIZE];
+ u8 mcs[HE_MAX_MCS_CAPAB_SIZE];
+ u8 ppet[HE_MAX_PPET_CAPAB_SIZE];
};
#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
#define HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN BIT(1)
+
+enum ieee80211_op_mode {
+ IEEE80211_MODE_INFRA = 0,
+ IEEE80211_MODE_IBSS = 1,
+ IEEE80211_MODE_AP = 2,
+ IEEE80211_MODE_MESH = 5,
+
+ /* only add new entries before IEEE80211_MODE_NUM */
+ IEEE80211_MODE_NUM
+};
+
+/**
+ * struct ieee80211_edmg_config - EDMG configuration
+ *
+ * This structure describes most essential parameters needed
+ * for IEEE 802.11ay EDMG configuration
+ *
+ * @channels: Bitmap that indicates the 2.16 GHz channel(s)
+ * that are allowed to be used for transmissions.
+ * Bit 0 indicates channel 1, bit 1 indicates channel 2, etc.
+ * Set to 0 to indicate EDMG not supported.
+ * @bw_config: Channel BW Configuration subfield encodes
+ * the allowed channel bandwidth configurations
+ */
+struct ieee80211_edmg_config {
+ u8 channels;
+ enum edmg_bw_config bw_config;
+};
+
/**
* struct hostapd_hw_modes - Supported hardware mode information
*/
@@ -243,15 +290,16 @@
/**
* he_capab - HE (IEEE 802.11ax) capabilities
*/
- struct he_capabilities he_capab;
+ struct he_capabilities he_capab[IEEE80211_MODE_NUM];
+
+ /**
+ * This structure describes the most essential parameters needed
+ * for IEEE 802.11ay EDMG configuration.
+ */
+ struct ieee80211_edmg_config edmg;
};
-#define IEEE80211_MODE_INFRA 0
-#define IEEE80211_MODE_IBSS 1
-#define IEEE80211_MODE_AP 2
-#define IEEE80211_MODE_MESH 5
-
#define IEEE80211_CAP_ESS 0x0001
#define IEEE80211_CAP_IBSS 0x0002
#define IEEE80211_CAP_PRIVACY 0x0010
@@ -470,7 +518,7 @@
* mac_addr - MAC address used with randomization. The address cannot be
* a multicast one, i.e., bit 0 of byte 0 should not be set.
*/
- const u8 *mac_addr;
+ u8 *mac_addr;
/**
* mac_addr_mask - MAC address mask used with randomization.
@@ -699,6 +747,11 @@
int vht_enabled;
/**
+ * he_enabled - Whether HE is enabled
+ */
+ int he_enabled;
+
+ /**
* center_freq1 - Segment 0 center frequency in MHz
*
* Valid for both HT and VHT.
@@ -716,6 +769,12 @@
* bandwidth - Channel bandwidth in MHz (20, 40, 80, 160)
*/
int bandwidth;
+
+ /**
+ * This structure describes the most essential parameters needed
+ * for IEEE 802.11ay EDMG configuration.
+ */
+ struct ieee80211_edmg_config edmg;
};
/**
@@ -1037,6 +1096,13 @@
const struct ieee80211_vht_capabilities *vhtcaps_mask;
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ /**
+ * disable_he - Disable HE for this connection
+ */
+ int disable_he;
+#endif /* CONFIG_HE_OVERRIDES */
+
/**
* req_key_mgmt_offload - Request key management offload for connection
*
@@ -1046,6 +1112,14 @@
int req_key_mgmt_offload;
/**
+ * req_handshake_offload - Request EAPOL handshake offload
+ *
+ * Request EAPOL handshake offload for this connection if the device
+ * supports it.
+ */
+ int req_handshake_offload;
+
+ /**
* Flag for indicating whether this association includes support for
* RRM (Radio Resource Measurements)
*/
@@ -1122,6 +1196,11 @@
HIDDEN_SSID_ZERO_CONTENTS
};
+enum ch_switch_state {
+ CH_SW_STARTED,
+ CH_SW_FINISHED
+};
+
struct wowlan_triggers {
u8 any;
u8 disconnect;
@@ -1331,14 +1410,6 @@
u8 p2p_go_ctwindow;
/**
- * smps_mode - SMPS mode
- *
- * SMPS mode to be used by the AP, specified as the relevant bits of
- * ht_capab (i.e. HT_CAP_INFO_SMPS_*).
- */
- unsigned int smps_mode;
-
- /**
* disable_dgaf - Whether group-addressed frames are disabled
*/
int disable_dgaf;
@@ -1401,6 +1472,41 @@
* type 11 as defined in IEEE Std 802.11-2016, 9.4.2.22.13
*/
const struct wpabuf *civic;
+
+ /**
+ * he_spr - Whether Spatial Reuse is enabled
+ */
+ int he_spr;
+
+ /**
+ * he_spr_srg_obss_pd_min_offset - Minimum TX power offset
+ */
+ int he_spr_srg_obss_pd_min_offset;
+
+ /**
+ * he_spr_srg_obss_pd_max_offset - Maximum TX power offset
+ */
+ int he_spr_srg_obss_pd_max_offset;
+
+ /**
+ * he_bss_color - Whether the BSS Color is disabled
+ */
+ int he_bss_color_disabled;
+
+ /**
+ * he_bss_color_partial - The BSS Color AID equation
+ */
+ int he_bss_color_partial;
+
+ /**
+ * he_bss_color - The BSS Color of the AP
+ */
+ int he_bss_color;
+
+ /**
+ * twt_responder - Whether Target Wait Time responder is enabled
+ */
+ int twt_responder;
};
struct wpa_driver_mesh_bss_params {
@@ -1438,6 +1544,120 @@
unsigned int flags;
};
+struct wpa_driver_set_key_params {
+ /**
+ * ifname - Interface name (for multi-SSID/VLAN support) */
+ const char *ifname;
+
+ /**
+ * alg - Encryption algorithm
+ *
+ * (%WPA_ALG_NONE, %WPA_ALG_WEP, %WPA_ALG_TKIP, %WPA_ALG_CCMP,
+ * %WPA_ALG_IGTK, %WPA_ALG_GCMP, %WPA_ALG_GCMP_256, %WPA_ALG_CCMP_256,
+ * %WPA_ALG_BIP_GMAC_128, %WPA_ALG_BIP_GMAC_256, %WPA_ALG_BIP_CMAC_256);
+ * %WPA_ALG_NONE clears the key. */
+ enum wpa_alg alg;
+
+ /**
+ * addr - Address of the peer STA
+ *
+ * (BSSID of the current AP when setting pairwise key in station mode),
+ * ff:ff:ff:ff:ff:ff for broadcast keys, %NULL for default keys that
+ * are used both for broadcast and unicast; when clearing keys, %NULL
+ * is used to indicate that both the broadcast-only and default key of
+ * the specified key index is to be cleared */
+ const u8 *addr;
+
+ /**
+ * key_idx - Key index
+ *
+ * (0..3), usually 0 for unicast keys; 4..5 for IGTK; 6..7 for BIGTK */
+ int key_idx;
+
+ /**
+ * set_tx - Configure this key as the default Tx key
+ *
+ * Only used when driver does not support separate unicast/individual
+ * key */
+ int set_tx;
+
+ /**
+ * seq - Sequence number/packet number
+ *
+ * seq_len octets, the next packet number to be used for in replay
+ * protection; configured for Rx keys (in most cases, this is only used
+ * with broadcast keys and set to zero for unicast keys); %NULL if not
+ * set */
+ const u8 *seq;
+
+ /**
+ * seq_len - Length of the seq, depends on the algorithm
+ *
+ * TKIP: 6 octets, CCMP/GCMP: 6 octets, IGTK: 6 octets */
+ size_t seq_len;
+
+ /**
+ * key - Key buffer
+ *
+ * TKIP: 16-byte temporal key, 8-byte Tx Mic key, 8-byte Rx Mic Key */
+ const u8 *key;
+
+ /**
+ * key_len - Length of the key buffer in octets
+ *
+ * WEP: 5 or 13, TKIP: 32, CCMP/GCMP: 16, IGTK: 16 */
+ size_t key_len;
+
+ /**
+ * vlan_id - VLAN index (0..4095) for VLAN offload cases */
+ int vlan_id;
+
+ /**
+ * key_flag - Additional key flags
+ *
+ * %KEY_FLAG_MODIFY
+ * Set when an already installed key must be updated.
+ * So far the only use-case is changing RX/TX status for
+ * pairwise keys. Must not be set when deleting a key.
+ * %KEY_FLAG_DEFAULT
+ * Set when the key is also a default key. Must not be set when
+ * deleting a key.
+ * %KEY_FLAG_RX
+ * The key is valid for RX. Must not be set when deleting a key.
+ * %KEY_FLAG_TX
+ * The key is valid for TX. Must not be set when deleting a key.
+ * %KEY_FLAG_GROUP
+ * The key is a broadcast or group key.
+ * %KEY_FLAG_PAIRWISE
+ * The key is a pairwise key.
+ * %KEY_FLAG_PMK
+ * The key is a Pairwise Master Key (PMK).
+ *
+ * Valid and pre-defined combinations are:
+ * %KEY_FLAG_GROUP_RX_TX
+ * WEP key not to be installed as default key.
+ * %KEY_FLAG_GROUP_RX_TX_DEFAULT
+ * Default WEP or WPA-NONE key.
+ * %KEY_FLAG_GROUP_RX
+ * GTK key valid for RX only.
+ * %KEY_FLAG_GROUP_TX_DEFAULT
+ * GTK key valid for TX only, immediately taking over TX.
+ * %KEY_FLAG_PAIRWISE_RX_TX
+ * Pairwise key immediately becoming the active pairwise key.
+ * %KEY_FLAG_PAIRWISE_RX
+ * Pairwise key not yet valid for TX. (Only usable when Extended
+ * Key ID is supported by the driver.)
+ * %KEY_FLAG_PAIRWISE_RX_TX_MODIFY
+ * Enable TX for a pairwise key installed with
+ * KEY_FLAG_PAIRWISE_RX.
+ *
+ * Not a valid standalone key type but pre-defined to be combined
+ * with other key_flags:
+ * %KEY_FLAG_RX_TX
+ * RX/TX key. */
+ enum key_flag key_flag;
+};
+
/**
* struct wpa_driver_capa - Driver capability information
*/
@@ -1491,7 +1711,7 @@
/** Driver takes care of all DFS operations */
#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 */
+ * struct wpa_driver_ops::set_key using key_flag = KEY_FLAG_PMK */
#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X 0x00000008
/** Driver is for a wired Ethernet interface */
#define WPA_DRIVER_FLAGS_WIRED 0x00000010
@@ -1618,15 +1838,27 @@
#define WPA_DRIVER_FLAGS_FTM_RESPONDER 0x0100000000000000ULL
/** Driver support 4-way handshake offload for WPA-Personal */
#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK 0x0200000000000000ULL
+/** Driver supports a separate control port TX for EAPOL frames */
+#define WPA_DRIVER_FLAGS_CONTROL_PORT 0x0400000000000000ULL
+/** Driver supports VLAN offload */
+#define WPA_DRIVER_FLAGS_VLAN_OFFLOAD 0x0800000000000000ULL
+/** Driver supports UPDATE_FT_IES command */
+#define WPA_DRIVER_FLAGS_UPDATE_FT_IES 0x1000000000000000ULL
+/** Driver can correctly rekey PTKs without Extended Key ID */
+#define WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS 0x2000000000000000ULL
+/** Driver supports Beacon protection */
+#define WPA_DRIVER_FLAGS_BEACON_PROTECTION 0x4000000000000000ULL
+/** Driver supports Extended Key ID */
+#define WPA_DRIVER_FLAGS_EXTENDED_KEY_ID 0x8000000000000000ULL
u64 flags;
+/** Driver supports a separate control port RX for EAPOL frames */
+#define WPA_DRIVER_FLAGS2_CONTROL_PORT_RX 0x0000000000000001ULL
+ u64 flags2;
+
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
(drv_flags & WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE)
-#define WPA_DRIVER_SMPS_MODE_STATIC 0x00000001
-#define WPA_DRIVER_SMPS_MODE_DYNAMIC 0x00000002
- unsigned int smps_modes;
-
unsigned int wmm_ac_supported:1;
unsigned int mac_addr_rand_scan_supported:1;
@@ -1752,6 +1984,7 @@
struct hostap_sta_driver_data {
unsigned long rx_packets, tx_packets;
unsigned long long rx_bytes, tx_bytes;
+ unsigned long long rx_airtime, tx_airtime;
int bytes_64bit; /* whether 64-bit byte counters are supported */
unsigned long current_tx_rate;
unsigned long current_rx_rate;
@@ -1761,6 +1994,8 @@
unsigned long tx_retry_failed;
unsigned long tx_retry_count;
s8 last_ack_rssi;
+ unsigned long backlog_packets;
+ unsigned long backlog_bytes;
s8 signal;
u8 rx_vhtmcs;
u8 tx_vhtmcs;
@@ -1781,6 +2016,8 @@
const struct ieee80211_vht_capabilities *vht_capabilities;
int vht_opmode_enabled;
u8 vht_opmode;
+ const struct ieee80211_he_capabilities *he_capab;
+ size_t he_capab_len;
u32 flags; /* bitmask of WPA_STA_* flags */
u32 flags_mask; /* unset bits in flags */
#ifdef CONFIG_MESH
@@ -2069,9 +2306,9 @@
#ifdef CONFIG_MACSEC
struct macsec_init_params {
- Boolean always_include_sci;
- Boolean use_es;
- Boolean use_scb;
+ bool always_include_sci;
+ bool use_es;
+ bool use_scb;
};
#endif /* CONFIG_MACSEC */
@@ -2101,10 +2338,11 @@
/* Configured ACS channel width */
u16 ch_width;
- /* ACS channel list info */
- unsigned int ch_list_len;
- const u8 *ch_list;
+ /* ACS frequency list info */
const int *freq_list;
+
+ /* Indicates whether EDMG is enabled */
+ int edmg_enabled;
};
struct wpa_bss_trans_info {
@@ -2130,6 +2368,8 @@
const u8 *pmkid;
const u8 *pmk;
size_t pmk_len;
+ u32 pmk_lifetime;
+ u8 pmk_reauth_threshold;
};
/* Mask used to specify which connection parameters have to be updated */
@@ -2216,35 +2456,8 @@
/**
* set_key - Configure encryption key
- * @ifname: Interface name (for multi-SSID/VLAN support)
* @priv: private driver interface data
- * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
- * %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK,
- * %WPA_ALG_GCMP, %WPA_ALG_GCMP_256, %WPA_ALG_CCMP_256,
- * %WPA_ALG_BIP_GMAC_128, %WPA_ALG_BIP_GMAC_256,
- * %WPA_ALG_BIP_CMAC_256);
- * %WPA_ALG_NONE clears the key.
- * @addr: Address of the peer STA (BSSID of the current AP when setting
- * pairwise key in station mode), ff:ff:ff:ff:ff:ff for
- * broadcast keys, %NULL for default keys that are used both for
- * broadcast and unicast; when clearing keys, %NULL is used to
- * indicate that both the broadcast-only and default key of the
- * specified key index is to be cleared
- * @key_idx: key index (0..3), usually 0 for unicast keys; 0..4095 for
- * IGTK
- * @set_tx: configure this key as the default Tx key (only used when
- * driver does not support separate unicast/individual key
- * @seq: sequence number/packet number, seq_len octets, the next
- * packet number to be used for in replay protection; configured
- * for Rx keys (in most cases, this is only used with broadcast
- * keys and set to zero for unicast keys); %NULL if not set
- * @seq_len: length of the seq, depends on the algorithm:
- * TKIP: 6 octets, CCMP/GCMP: 6 octets, IGTK: 6 octets
- * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
- * 8-byte Rx Mic Key
- * @key_len: length of the key buffer in octets (WEP: 5 or 13,
- * TKIP: 32, CCMP/GCMP: 16, IGTK: 16)
- *
+ * @params: Key parameters
* Returns: 0 on success, -1 on failure
*
* Configure the given key for the kernel driver. If the driver
@@ -2265,10 +2478,7 @@
* in driver_*.c set_key() implementation, see driver_ndis.c for an
* example on how this can be done.
*/
- int (*set_key)(const char *ifname, void *priv, 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);
+ int (*set_key)(void *priv, struct wpa_driver_set_key_params *params);
/**
* init - Initialize driver interface
@@ -2337,7 +2547,7 @@
*
* Returns: 0 on success, -1 on failure
*/
- int (*deauthenticate)(void *priv, const u8 *addr, int reason_code);
+ int (*deauthenticate)(void *priv, const u8 *addr, u16 reason_code);
/**
* associate - Request driver to associate
@@ -2520,11 +2730,15 @@
* driver decide
* @csa_offs: Array of CSA offsets or %NULL
* @csa_offs_len: Number of elements in csa_offs
+ * @no_encrypt: Do not encrypt frame even if appropriate key exists
+ * (used only for testing purposes)
+ * @wait: Time to wait off-channel for a response (in ms), or zero
* Returns: 0 on success, -1 on failure
*/
int (*send_mlme)(void *priv, const u8 *data, size_t data_len,
int noack, unsigned int freq, const u16 *csa_offs,
- size_t csa_offs_len);
+ size_t csa_offs_len, int no_encrypt,
+ unsigned int wait);
/**
* update_ft_ies - Update FT (IEEE 802.11r) IEs
@@ -2779,6 +2993,33 @@
const u8 *addr);
/**
+ * tx_control_port - Send a frame over the 802.1X controlled port
+ * @priv: Private driver interface data
+ * @dest: Destination MAC address
+ * @proto: Ethertype in host byte order
+ * @buf: Frame payload starting from IEEE 802.1X header
+ * @len: Frame payload length
+ * @no_encrypt: Do not encrypt frame
+ *
+ * Returns 0 on success, else an error
+ *
+ * This is like a normal Ethernet send except that the driver is aware
+ * (by other means than the Ethertype) that this frame is special,
+ * and more importantly it gains an ordering between the transmission of
+ * the frame and other driver management operations such as key
+ * installations. This can be used to work around known limitations in
+ * IEEE 802.11 protocols such as race conditions between rekeying 4-way
+ * handshake message 4/4 and a PTK being overwritten.
+ *
+ * This function is only used for a given interface if the driver
+ * instance reports WPA_DRIVER_FLAGS_CONTROL_PORT capability. Otherwise,
+ * API users will fall back to sending the frame via a normal socket.
+ */
+ int (*tx_control_port)(void *priv, const u8 *dest,
+ u16 proto, const u8 *buf, size_t len,
+ int no_encrypt);
+
+ /**
* hapd_send_eapol - Send an EAPOL packet (AP only)
* @priv: private driver interface data
* @addr: Destination MAC address
@@ -2806,7 +3047,7 @@
* a Deauthentication frame to be sent to it.
*/
int (*sta_deauth)(void *priv, const u8 *own_addr, const u8 *addr,
- int reason);
+ u16 reason);
/**
* sta_disassoc - Disassociate a station (AP only)
@@ -2820,7 +3061,7 @@
* a Disassociation frame to be sent to it.
*/
int (*sta_disassoc)(void *priv, const u8 *own_addr, const u8 *addr,
- int reason);
+ u16 reason);
/**
* sta_remove - Remove a station entry (AP only)
@@ -2938,6 +3179,16 @@
unsigned int flags_and);
/**
+ * sta_set_airtime_weight - Set station airtime weight (AP only)
+ * @priv: Private driver interface data
+ * @addr: Station address
+ * @weight: New weight for station airtime assignment
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*sta_set_airtime_weight)(void *priv, const u8 *addr,
+ unsigned int weight);
+
+ /**
* set_tx_queue_params - Set TX queue parameters
* @priv: Private driver interface data
* @queue: Queue number (0 = VO, 1 = VI, 2 = BE, 3 = BK)
@@ -3014,19 +3265,6 @@
int (*commit)(void *priv);
/**
- * send_ether - Send an ethernet packet (AP only)
- * @priv: private driver interface data
- * @dst: Destination MAC address
- * @src: Source MAC address
- * @proto: Ethertype
- * @data: EAPOL packet starting with IEEE 802.1X header
- * @data_len: Length of the EAPOL packet in octets
- * Returns: 0 on success, -1 on failure
- */
- int (*send_ether)(void *priv, const u8 *dst, const u8 *src, u16 proto,
- const u8 *data, size_t data_len);
-
- /**
* set_radius_acl_auth - Notification of RADIUS ACL change
* @priv: Private driver interface data
* @mac: MAC address of the station
@@ -3249,20 +3487,6 @@
int (*signal_monitor)(void *priv, int threshold, int hysteresis);
/**
- * send_frame - Send IEEE 802.11 frame (testing use only)
- * @priv: Private driver interface data
- * @data: IEEE 802.11 frame with IEEE 802.11 header
- * @data_len: Size of the frame
- * @encrypt: Whether to encrypt the frame (if keys are set)
- * Returns: 0 on success, -1 on failure
- *
- * This function is only used for debugging purposes and is not
- * required to be implemented for normal operations.
- */
- int (*send_frame)(void *priv, const u8 *data, size_t data_len,
- int encrypt);
-
- /**
* get_noa - Get current Notice of Absence attribute payload
* @priv: Private driver interface data
* @buf: Buffer for returning NoA
@@ -3414,6 +3638,12 @@
unsigned int val);
/**
+ * get_wowlan - Get wake-on-wireless status
+ * @priv: Private driver interface data
+ */
+ int (*get_wowlan)(void *priv);
+
+ /**
* set_wowlan - Set wake-on-wireless triggers
* @priv: Private driver interface data
* @triggers: wowlan triggers
@@ -3773,30 +4003,30 @@
/**
* enable_protect_frames - Set protect frames status
* @priv: Private driver interface data
- * @enabled: TRUE = protect frames enabled
- * FALSE = protect frames disabled
+ * @enabled: true = protect frames enabled
+ * false = protect frames disabled
* Returns: 0 on success, -1 on failure (or if not supported)
*/
- int (*enable_protect_frames)(void *priv, Boolean enabled);
+ int (*enable_protect_frames)(void *priv, bool enabled);
/**
* enable_encrypt - Set encryption status
* @priv: Private driver interface data
- * @enabled: TRUE = encrypt outgoing traffic
- * FALSE = integrity-only protection on outgoing traffic
+ * @enabled: true = encrypt outgoing traffic
+ * false = integrity-only protection on outgoing traffic
* Returns: 0 on success, -1 on failure (or if not supported)
*/
- int (*enable_encrypt)(void *priv, Boolean enabled);
+ int (*enable_encrypt)(void *priv, bool enabled);
/**
* set_replay_protect - Set replay protect status and window size
* @priv: Private driver interface data
- * @enabled: TRUE = replay protect enabled
- * FALSE = replay protect disabled
+ * @enabled: true = replay protect enabled
+ * false = replay protect disabled
* @window: replay window size, valid only when replay protect enabled
* Returns: 0 on success, -1 on failure (or if not supported)
*/
- int (*set_replay_protect)(void *priv, Boolean enabled, u32 window);
+ int (*set_replay_protect)(void *priv, bool enabled, u32 window);
/**
* set_current_cipher_suite - Set current cipher suite
@@ -3809,11 +4039,11 @@
/**
* enable_controlled_port - Set controlled port status
* @priv: Private driver interface data
- * @enabled: TRUE = controlled port enabled
- * FALSE = controlled port disabled
+ * @enabled: true = controlled port enabled
+ * false = controlled port disabled
* Returns: 0 on success, -1 on failure (or if not supported)
*/
- int (*enable_controlled_port)(void *priv, Boolean enabled);
+ int (*enable_controlled_port)(void *priv, bool enabled);
/**
* get_receive_lowest_pn - Get receive lowest pn
@@ -3975,6 +4205,18 @@
int (*leave_mesh)(void *priv);
/**
+ * probe_mesh_link - Inject a frame over direct mesh link to a given
+ * peer skipping the next_hop lookup from mpath table.
+ * @priv: Private driver interface data
+ * @addr: Peer MAC address
+ * @eth: Ethernet frame to be sent
+ * @len: Ethernet frame lengtn in bytes
+ * Returns 0 on success, -1 on failure
+ */
+ int (*probe_mesh_link)(void *priv, const u8 *addr, const u8 *eth,
+ size_t len);
+
+ /**
* do_acs - Automatically select channel
* @priv: Private driver interface data
* @params: Parameters for ACS
@@ -4167,6 +4409,32 @@
* Returns: 0 on success, < 0 on failure
*/
int (*set_4addr_mode)(void *priv, const char *bridge_ifname, int val);
+
+ /**
+ * update_dh_ie - Update DH IE
+ * @priv: Private driver interface data
+ * @peer_mac: Peer MAC address
+ * @reason_code: Reacon code
+ * @ie: DH IE
+ * @ie_len: DH IE length in bytes
+ * Returns: 0 on success, -1 on failure
+ *
+ * This callback is used to let the driver know the DH processing result
+ * and DH IE for a pending association.
+ */
+ int (*update_dh_ie)(void *priv, const u8 *peer_mac, u16 reason_code,
+ const u8 *ie, size_t ie_len);
+
+ /**
+ * dpp_listen - Notify driver about start/stop of DPP listen
+ * @priv: Private driver interface data
+ * @enable: Whether listen state is enabled (or disabled)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This optional callback can be used to update RX frame filtering to
+ * explicitly allow reception of broadcast Public Action frames.
+ */
+ int (*dpp_listen)(void *priv, bool enable);
};
/**
@@ -4541,6 +4809,15 @@
EVENT_CH_SWITCH,
/**
+ * EVENT_CH_SWITCH_STARTED - AP or GO started to switch channels
+ *
+ * This is a pre-switch event indicating the shortly following switch
+ * of operating channels.
+ *
+ * Described in wpa_event_data.ch_switch
+ */
+ EVENT_CH_SWITCH_STARTED,
+ /**
* EVENT_WNM - Request WNM operation
*
* This event can be used to request a WNM operation to be performed.
@@ -4703,6 +4980,20 @@
* This event is emitted when an interface is added/removed for WDS STA.
*/
EVENT_WDS_STA_INTERFACE_STATUS,
+
+ /**
+ * EVENT_UPDATE_DH - Notification of updated DH information
+ */
+ EVENT_UPDATE_DH,
+
+ /**
+ * EVENT_UNPROT_BEACON - Unprotected Beacon frame received
+ *
+ * This event should be called when a Beacon frame is dropped due to it
+ * not being protected correctly. union wpa_event_data::unprot_beacon
+ * is required to provide more details of the frame.
+ */
+ EVENT_UNPROT_BEACON,
};
@@ -5467,18 +5758,28 @@
/**
* struct acs_selected_channels - Data for EVENT_ACS_CHANNEL_SELECTED
- * @pri_channel: Selected primary channel
- * @sec_channel: Selected secondary channel
+ * @pri_freq: Selected primary frequency
+ * @sec_freq: Selected secondary frequency
+ * @edmg_channel: Selected EDMG channel
* @vht_seg0_center_ch: VHT mode Segment0 center channel
+ * The value is the index of the channel center frequency for
+ * 20 MHz, 40 MHz, and 80 MHz channels. The value is the center
+ * frequency index of the primary 80 MHz segment for 160 MHz and
+ * 80+80 MHz channels.
* @vht_seg1_center_ch: VHT mode Segment1 center channel
+ * The value is zero for 20 MHz, 40 MHz, and 80 MHz channels. The
+ * value is the index of the channel center frequency for 160 MHz
+ * channels and the center frequency index of the secondary 80 MHz
+ * segment for 80+80 MHz channels.
* @ch_width: Selected Channel width by driver. Driver may choose to
* change hostapd configured ACS channel width due driver internal
* channel restrictions.
* hw_mode: Selected band (used with hw_mode=any)
*/
struct acs_selected_channels {
- u8 pri_channel;
- u8 sec_channel;
+ unsigned int pri_freq;
+ unsigned int sec_freq;
+ u8 edmg_channel;
u8 vht_seg0_center_ch;
u8 vht_seg1_center_ch;
u16 ch_width;
@@ -5536,6 +5837,22 @@
INTERFACE_REMOVED
} istatus;
} wds_sta_interface;
+
+ /**
+ * struct update_dh - Data for EVENT_UPDATE_DH
+ */
+ struct update_dh {
+ const u8 *peer;
+ const u8 *ie;
+ size_t ie_len;
+ } update_dh;
+
+ /**
+ * struct unprot_beacon - Data for EVENT_UNPROT_BEACON
+ */
+ struct unprot_beacon {
+ const u8 *sa;
+ } unprot_beacon;
};
/**
@@ -5619,6 +5936,7 @@
const struct wpa_driver_capa *capa);
/* Convert driver flag to string */
const char * driver_flag_to_string(u64 flag);
+const char * driver_flag2_to_string(u64 flag2);
/* NULL terminated array of linked in driver wrappers */
extern const struct wpa_driver_ops *const wpa_drivers[];
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index 807cd94..d630c3d 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -59,10 +59,6 @@
#include "netlink.h"
#include "linux_ioctl.h"
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20) || defined(CONFIG_WNM) || defined(CONFIG_WPS) || defined(CONFIG_FILS)
-#define ATHEROS_USE_RAW_RECEIVE
-#endif
-
struct atheros_driver_data {
struct hostapd_data *hapd; /* back pointer */
@@ -86,7 +82,7 @@
};
static int atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
- int reason_code);
+ u16 reason_code);
static int atheros_set_privacy(void *priv, int enabled);
static const char * athr_get_ioctl_name(int op)
@@ -366,13 +362,11 @@
v = 0;
if (params->rsn_preauth)
v |= BIT(0);
-#ifdef CONFIG_IEEE80211W
if (params->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
v |= BIT(7);
if (params->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
v |= BIT(6);
}
-#endif /* CONFIG_IEEE80211W */
wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", __func__, v);
if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
@@ -498,14 +492,18 @@
}
static int
-atheros_set_key(const char *ifname, void *priv, 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)
+atheros_set_key(void *priv, struct wpa_driver_set_key_params *params)
{
struct atheros_driver_data *drv = priv;
struct ieee80211req_key wk;
u_int8_t cipher;
int ret;
+ enum wpa_alg alg = params->alg;
+ const u8 *addr = params->addr;
+ int key_idx = params->key_idx;
+ int set_tx = params->set_tx;
+ const u8 *key = params->key;
+ size_t key_len = params->key_len;
if (alg == WPA_ALG_NONE)
return atheros_del_key(drv, addr, key_idx);
@@ -534,7 +532,6 @@
cipher = IEEE80211_CIPHER_AES_GCM_256;
break;
#endif /* ATH_GCM_SUPPORT */
-#ifdef CONFIG_IEEE80211W
case WPA_ALG_IGTK:
cipher = IEEE80211_CIPHER_AES_CMAC;
break;
@@ -549,7 +546,6 @@
cipher = IEEE80211_CIPHER_AES_GMAC_256;
break;
#endif /* ATH_GCM_SUPPORT */
-#endif /* CONFIG_IEEE80211W */
default:
wpa_printf(MSG_INFO, "%s: unknown/unsupported algorithm %d",
__func__, alg);
@@ -761,7 +757,7 @@
static int
atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
- int reason_code)
+ u16 reason_code)
{
struct atheros_driver_data *drv = priv;
struct ieee80211req_mlme mlme;
@@ -785,7 +781,7 @@
static int
atheros_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
- int reason_code)
+ u16 reason_code)
{
struct atheros_driver_data *drv = priv;
struct ieee80211req_mlme mlme;
@@ -856,7 +852,7 @@
return 0;
}
-#ifdef ATHEROS_USE_RAW_RECEIVE
+
static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
size_t len)
{
@@ -953,7 +949,7 @@
break;
}
}
-#endif /* ATHEROS_USE_RAW_RECEIVE */
+
static int atheros_receive_pkt(struct atheros_driver_data *drv)
{
@@ -965,11 +961,9 @@
#ifdef CONFIG_WPS
filt.app_filterype |= IEEE80211_FILTER_TYPE_PROBE_REQ;
#endif /* CONFIG_WPS */
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS)
filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ |
IEEE80211_FILTER_TYPE_AUTH |
IEEE80211_FILTER_TYPE_ACTION);
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */
#ifdef CONFIG_WNM
filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
#endif /* CONFIG_WNM */
@@ -1069,7 +1063,6 @@
#define atheros_set_ap_wps_ie NULL
#endif /* CONFIG_WPS */
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
static int
atheros_sta_auth(void *priv, struct wpa_driver_sta_auth_params *params)
{
@@ -1169,7 +1162,7 @@
}
return ret;
}
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */
+
static void
atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
@@ -1315,7 +1308,6 @@
atheros_raw_receive(drv, NULL,
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
#endif /* CONFIG_WPS */
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
} else if (os_strncmp(custom, "Manage.assoc_req ", 17) == 0) {
/* Format: "Manage.assoc_req <frame len>" | zero padding |
* frame */
@@ -1339,8 +1331,6 @@
}
atheros_raw_receive(drv, NULL,
(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) {
/* Format: "Manage.assoc_req <frame len>" | zero padding | frame
*/
@@ -1353,7 +1343,6 @@
}
atheros_raw_receive(drv, NULL,
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
-#endif /* ATHEROS_USE_RAW_RECEIVE */
}
}
@@ -1973,11 +1962,10 @@
}
-#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,
- const u16 *csa_offs, size_t csa_offs_len)
+ const u16 *csa_offs, size_t csa_offs_len,
+ int no_encrypt, unsigned int wait)
{
struct atheros_driver_data *drv = priv;
u8 buf[1510];
@@ -1999,7 +1987,6 @@
return set80211priv(drv, IEEE80211_IOCTL_SEND_MGMT, mgmt_frm,
sizeof(struct ieee80211req_mgmtbuf) + data_len);
}
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */
#ifdef CONFIG_IEEE80211R
@@ -2283,11 +2270,9 @@
.set_ap_wps_ie = atheros_set_ap_wps_ie,
.set_authmode = atheros_set_authmode,
.set_ap = atheros_set_ap,
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
.sta_assoc = atheros_sta_assoc,
.sta_auth = atheros_sta_auth,
.send_mlme = atheros_send_mgmt,
-#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 4675496..b4400d7 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -9,7 +9,6 @@
#include "includes.h"
#include <sys/ioctl.h>
-#include <sys/sysctl.h>
#include "common.h"
#include "driver.h"
@@ -51,22 +50,19 @@
void *ctx;
int sock; /* socket for 802.11 ioctls */
int route; /* routing socket for events */
- char *event_buf;
- size_t event_buf_len;
struct dl_list ifaces; /* list of interfaces */
};
struct bsd_driver_data {
struct dl_list list;
struct bsd_driver_global *global;
- struct hostapd_data *hapd; /* back pointer */
+ void *ctx;
struct l2_packet_data *sock_xmit;/* raw packet xmit socket */
char ifname[IFNAMSIZ+1]; /* interface name */
int flags;
unsigned int ifindex; /* interface index */
int if_removed; /* has the interface been removed? */
- void *ctx;
struct wpa_driver_capa capa; /* driver capability */
int is_ap; /* Access point mode */
int prev_roaming; /* roaming state to restore on deinit */
@@ -90,7 +86,6 @@
return NULL;
}
-#ifndef HOSTAPD
static struct bsd_driver_data *
bsd_get_drvname(void *priv, const char *ifname)
{
@@ -103,7 +98,6 @@
}
return NULL;
}
-#endif /* HOSTAPD */
static int
bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len)
@@ -295,9 +289,8 @@
}
static int
-bsd_ctrl_iface(void *priv, int enable)
+bsd_get_iface_flags(struct bsd_driver_data *drv)
{
- struct bsd_driver_data *drv = priv;
struct ifreq ifr;
os_memset(&ifr, 0, sizeof(ifr));
@@ -309,36 +302,24 @@
return -1;
}
drv->flags = ifr.ifr_flags;
-
- if (enable) {
- if (ifr.ifr_flags & IFF_UP)
- return 0;
- ifr.ifr_flags |= IFF_UP;
- } else {
- if (!(ifr.ifr_flags & IFF_UP))
- return 0;
- ifr.ifr_flags &= ~IFF_UP;
- }
-
- if (ioctl(drv->global->sock, SIOCSIFFLAGS, &ifr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
- strerror(errno));
- return -1;
- }
-
- drv->flags = ifr.ifr_flags;
return 0;
}
static int
-bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
- const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
- size_t seq_len, const u8 *key, size_t key_len)
+bsd_set_key(void *priv, struct wpa_driver_set_key_params *params)
{
struct ieee80211req_key wk;
#ifdef IEEE80211_KEY_NOREPLAY
struct bsd_driver_data *drv = priv;
#endif /* IEEE80211_KEY_NOREPLAY */
+ enum wpa_alg alg = params->alg;
+ const u8 *addr = params->addr;
+ int key_idx = params->key_idx;
+ int set_tx = params->set_tx;
+ const u8 *seq = params->seq;
+ size_t seq_len = params->seq_len;
+ const u8 *key = params->key;
+ size_t key_len = params->key_len;
wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
"seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx,
@@ -540,7 +521,7 @@
__func__);
return -1;
}
- return bsd_ctrl_iface(priv, 1);
+ return 0;
}
static void
@@ -595,17 +576,13 @@
if (channel < 14) {
mode =
-#ifdef CONFIG_IEEE80211N
freq->ht_enabled ? IFM_IEEE80211_11NG :
-#endif /* CONFIG_IEEE80211N */
- IFM_IEEE80211_11G;
+ IFM_IEEE80211_11G;
} else if (channel == 14) {
mode = IFM_IEEE80211_11B;
} else {
mode =
-#ifdef CONFIG_IEEE80211N
freq->ht_enabled ? IFM_IEEE80211_11NA :
-#endif /* CONFIG_IEEE80211N */
IFM_IEEE80211_11A;
}
if (bsd_set_mediaopt(drv, IFM_MMASK, mode) < 0) {
@@ -636,20 +613,152 @@
return 0;
}
-static size_t
-rtbuf_len(void)
+static void
+bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
{
- size_t len;
+ char event_buf[2048]; /* max size of a single route(4) msg */
+ struct bsd_driver_global *global = sock_ctx;
+ struct bsd_driver_data *drv;
+ struct if_announcemsghdr *ifan;
+ struct if_msghdr *ifm;
+ struct rt_msghdr *rtm;
+ union wpa_event_data event;
+ struct ieee80211_michael_event *mic;
+ struct ieee80211_leave_event *leave;
+ struct ieee80211_join_event *join;
+ int n;
- int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0};
-
- if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
- wpa_printf(MSG_WARNING, "%s failed: %s", __func__,
- strerror(errno));
- len = 2048;
+ n = read(sock, event_buf, sizeof(event_buf));
+ if (n < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ wpa_printf(MSG_ERROR, "%s read() failed: %s",
+ __func__, strerror(errno));
+ return;
}
- return len;
+ rtm = (struct rt_msghdr *) event_buf;
+ if (rtm->rtm_version != RTM_VERSION) {
+ wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
+ rtm->rtm_version);
+ return;
+ }
+ os_memset(&event, 0, sizeof(event));
+ switch (rtm->rtm_type) {
+ case RTM_IEEE80211:
+ ifan = (struct if_announcemsghdr *) rtm;
+ drv = bsd_get_drvindex(global, ifan->ifan_index);
+ if (drv == NULL)
+ return;
+ switch (ifan->ifan_what) {
+ case RTM_IEEE80211_ASSOC:
+ case RTM_IEEE80211_REASSOC:
+ if (drv->is_ap)
+ break;
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+ break;
+ case RTM_IEEE80211_DISASSOC:
+ if (drv->is_ap)
+ break;
+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
+ break;
+ case RTM_IEEE80211_SCAN:
+ if (drv->is_ap)
+ break;
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS,
+ NULL);
+ break;
+ case RTM_IEEE80211_LEAVE:
+ leave = (struct ieee80211_leave_event *) &ifan[1];
+ drv_event_disassoc(drv->ctx, leave->iev_addr);
+ break;
+ case RTM_IEEE80211_JOIN:
+#ifdef RTM_IEEE80211_REJOIN
+ case RTM_IEEE80211_REJOIN:
+#endif
+ join = (struct ieee80211_join_event *) &ifan[1];
+ bsd_new_sta(drv, drv->ctx, join->iev_addr);
+ break;
+ case RTM_IEEE80211_REPLAY:
+ /* ignore */
+ break;
+ case RTM_IEEE80211_MICHAEL:
+ mic = (struct ieee80211_michael_event *) &ifan[1];
+ wpa_printf(MSG_DEBUG,
+ "Michael MIC failure wireless event: "
+ "keyix=%u src_addr=" MACSTR, mic->iev_keyix,
+ MAC2STR(mic->iev_src));
+ os_memset(&event, 0, sizeof(event));
+ event.michael_mic_failure.unicast =
+ !IEEE80211_IS_MULTICAST(mic->iev_dst);
+ event.michael_mic_failure.src = mic->iev_src;
+ wpa_supplicant_event(drv->ctx,
+ EVENT_MICHAEL_MIC_FAILURE, &event);
+ break;
+ }
+ break;
+ case RTM_IFANNOUNCE:
+ ifan = (struct if_announcemsghdr *) rtm;
+ switch (ifan->ifan_what) {
+ case IFAN_DEPARTURE:
+ drv = bsd_get_drvindex(global, ifan->ifan_index);
+ if (drv)
+ drv->if_removed = 1;
+ event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+ break;
+ case IFAN_ARRIVAL:
+ drv = bsd_get_drvname(global, ifan->ifan_name);
+ if (drv) {
+ drv->ifindex = ifan->ifan_index;
+ drv->if_removed = 0;
+ }
+ event.interface_status.ievent = EVENT_INTERFACE_ADDED;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: unknown action");
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
+ ifan->ifan_name,
+ ifan->ifan_what == IFAN_DEPARTURE ?
+ "removed" : "added");
+ os_strlcpy(event.interface_status.ifname, ifan->ifan_name,
+ sizeof(event.interface_status.ifname));
+ if (drv) {
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
+ &event);
+ /*
+ * Set ifindex to zero after sending the event as the
+ * event might query the driver to ensure a match.
+ */
+ if (ifan->ifan_what == IFAN_DEPARTURE)
+ drv->ifindex = 0;
+ } else {
+ wpa_supplicant_event_global(global->ctx,
+ EVENT_INTERFACE_STATUS,
+ &event);
+ }
+ break;
+ case RTM_IFINFO:
+ ifm = (struct if_msghdr *) rtm;
+ drv = bsd_get_drvindex(global, ifm->ifm_index);
+ if (drv == NULL)
+ return;
+ if ((ifm->ifm_flags & IFF_UP) == 0 &&
+ (drv->flags & IFF_UP) != 0) {
+ wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
+ drv->ifname);
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED,
+ NULL);
+ } else if ((ifm->ifm_flags & IFF_UP) != 0 &&
+ (drv->flags & IFF_UP) == 0) {
+ wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP",
+ drv->ifname);
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+ NULL);
+ }
+ drv->flags = ifm->ifm_flags;
+ break;
+ }
}
#ifdef HOSTAPD
@@ -663,7 +772,7 @@
#undef WPA_OUI_TYPE
static int bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
- int reason_code);
+ u16 reason_code);
static const char *
ether_sprintf(const u8 *addr)
@@ -755,7 +864,7 @@
}
static int
-bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, int reason_code)
+bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, u16 reason_code)
{
return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code,
addr);
@@ -763,87 +872,17 @@
static int
bsd_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
- int reason_code)
+ u16 reason_code)
{
return bsd_send_mlme_param(priv, IEEE80211_MLME_DISASSOC, reason_code,
addr);
}
static void
-bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
-{
- struct bsd_driver_global *global = sock_ctx;
- struct bsd_driver_data *drv;
- struct if_announcemsghdr *ifan;
- struct rt_msghdr *rtm;
- struct ieee80211_michael_event *mic;
- struct ieee80211_join_event *join;
- struct ieee80211_leave_event *leave;
- int n;
- union wpa_event_data data;
-
- n = read(sock, global->event_buf, global->event_buf_len);
- if (n < 0) {
- if (errno != EINTR && errno != EAGAIN)
- wpa_printf(MSG_ERROR, "%s read() failed: %s",
- __func__, strerror(errno));
- return;
- }
-
- rtm = (struct rt_msghdr *) global->event_buf;
- if (rtm->rtm_version != RTM_VERSION) {
- wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
- rtm->rtm_version);
- return;
- }
- switch (rtm->rtm_type) {
- case RTM_IEEE80211:
- ifan = (struct if_announcemsghdr *) rtm;
- drv = bsd_get_drvindex(global, ifan->ifan_index);
- if (drv == NULL)
- return;
- switch (ifan->ifan_what) {
- case RTM_IEEE80211_ASSOC:
- case RTM_IEEE80211_REASSOC:
- case RTM_IEEE80211_DISASSOC:
- case RTM_IEEE80211_SCAN:
- break;
- case RTM_IEEE80211_LEAVE:
- leave = (struct ieee80211_leave_event *) &ifan[1];
- drv_event_disassoc(drv->hapd, leave->iev_addr);
- break;
- case RTM_IEEE80211_JOIN:
-#ifdef RTM_IEEE80211_REJOIN
- case RTM_IEEE80211_REJOIN:
-#endif
- join = (struct ieee80211_join_event *) &ifan[1];
- bsd_new_sta(drv, drv->hapd, join->iev_addr);
- break;
- case RTM_IEEE80211_REPLAY:
- /* ignore */
- break;
- case RTM_IEEE80211_MICHAEL:
- mic = (struct ieee80211_michael_event *) &ifan[1];
- wpa_printf(MSG_DEBUG,
- "Michael MIC failure wireless event: "
- "keyix=%u src_addr=" MACSTR, mic->iev_keyix,
- MAC2STR(mic->iev_src));
- os_memset(&data, 0, sizeof(data));
- data.michael_mic_failure.unicast = 1;
- data.michael_mic_failure.src = mic->iev_src;
- wpa_supplicant_event(drv->hapd,
- EVENT_MICHAEL_MIC_FAILURE, &data);
- break;
- }
- break;
- }
-}
-
-static void
handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
{
struct bsd_driver_data *drv = ctx;
- drv_event_eapol_rx(drv->hapd, src_addr, buf, len);
+ drv_event_eapol_rx(drv->ctx, src_addr, buf, len);
}
static void *
@@ -864,7 +903,8 @@
goto bad;
}
- drv->hapd = hapd;
+ drv->ctx = hapd;
+ drv->is_ap = 1;
drv->global = params->global_priv;
os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
@@ -875,8 +915,7 @@
if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr))
goto bad;
- /* mark down during setup */
- if (bsd_ctrl_iface(drv, 0) < 0)
+ if (bsd_get_iface_flags(drv) < 0)
goto bad;
if (bsd_set_mediaopt(drv, IFM_OMASK, IFM_IEEE80211_HOSTAP) < 0) {
@@ -901,8 +940,6 @@
{
struct bsd_driver_data *drv = priv;
- if (drv->ifindex != 0)
- bsd_ctrl_iface(drv, 0);
if (drv->sock_xmit != NULL)
l2_packet_deinit(drv->sock_xmit);
os_free(drv);
@@ -910,13 +947,6 @@
static int
-bsd_commit(void *priv)
-{
- return bsd_ctrl_iface(priv, 1);
-}
-
-
-static int
bsd_set_sta_authorized(void *priv, const u8 *addr,
unsigned int total_flags, unsigned int flags_or,
unsigned int flags_and)
@@ -1026,7 +1056,7 @@
}
static int
-wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code)
+wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, u16 reason_code)
{
return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code,
addr);
@@ -1169,8 +1199,11 @@
}
/* NB: interface must be marked UP to do a scan */
- if (bsd_ctrl_iface(drv, 1) < 0)
+ if (!(drv->flags & IFF_UP)) {
+ wpa_printf(MSG_DEBUG, "%s: interface is not up, cannot scan",
+ __func__);
return -1;
+ }
#ifdef IEEE80211_IOC_SCAN_MAX_SSID
os_memset(&sr, 0, sizeof(sr));
@@ -1208,153 +1241,6 @@
}
static void
-wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
-{
- struct bsd_driver_global *global = sock_ctx;
- struct bsd_driver_data *drv;
- struct if_announcemsghdr *ifan;
- struct if_msghdr *ifm;
- struct rt_msghdr *rtm;
- union wpa_event_data event;
- struct ieee80211_michael_event *mic;
- struct ieee80211_leave_event *leave;
- struct ieee80211_join_event *join;
- int n;
-
- n = read(sock, global->event_buf, global->event_buf_len);
- if (n < 0) {
- if (errno != EINTR && errno != EAGAIN)
- wpa_printf(MSG_ERROR, "%s read() failed: %s",
- __func__, strerror(errno));
- return;
- }
-
- rtm = (struct rt_msghdr *) global->event_buf;
- if (rtm->rtm_version != RTM_VERSION) {
- wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
- rtm->rtm_version);
- return;
- }
- os_memset(&event, 0, sizeof(event));
- switch (rtm->rtm_type) {
- case RTM_IFANNOUNCE:
- ifan = (struct if_announcemsghdr *) rtm;
- switch (ifan->ifan_what) {
- case IFAN_DEPARTURE:
- drv = bsd_get_drvindex(global, ifan->ifan_index);
- if (drv)
- drv->if_removed = 1;
- event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
- break;
- case IFAN_ARRIVAL:
- drv = bsd_get_drvname(global, ifan->ifan_name);
- if (drv) {
- drv->ifindex = ifan->ifan_index;
- drv->if_removed = 0;
- }
- event.interface_status.ievent = EVENT_INTERFACE_ADDED;
- break;
- default:
- wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: unknown action");
- return;
- }
- wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
- ifan->ifan_name,
- ifan->ifan_what == IFAN_DEPARTURE ?
- "removed" : "added");
- os_strlcpy(event.interface_status.ifname, ifan->ifan_name,
- sizeof(event.interface_status.ifname));
- if (drv) {
- wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
- &event);
- /*
- * Set ifindex to zero after sending the event as the
- * event might query the driver to ensure a match.
- */
- if (ifan->ifan_what == IFAN_DEPARTURE)
- drv->ifindex = 0;
- } else {
- wpa_supplicant_event_global(global->ctx,
- EVENT_INTERFACE_STATUS,
- &event);
- }
- break;
- case RTM_IEEE80211:
- ifan = (struct if_announcemsghdr *) rtm;
- drv = bsd_get_drvindex(global, ifan->ifan_index);
- if (drv == NULL)
- return;
- switch (ifan->ifan_what) {
- case RTM_IEEE80211_ASSOC:
- case RTM_IEEE80211_REASSOC:
- if (drv->is_ap)
- break;
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
- break;
- case RTM_IEEE80211_DISASSOC:
- if (drv->is_ap)
- break;
- wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
- break;
- case RTM_IEEE80211_SCAN:
- if (drv->is_ap)
- break;
- wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS,
- NULL);
- break;
- case RTM_IEEE80211_LEAVE:
- leave = (struct ieee80211_leave_event *) &ifan[1];
- drv_event_disassoc(drv->ctx, leave->iev_addr);
- break;
- case RTM_IEEE80211_JOIN:
-#ifdef RTM_IEEE80211_REJOIN
- case RTM_IEEE80211_REJOIN:
-#endif
- join = (struct ieee80211_join_event *) &ifan[1];
- bsd_new_sta(drv, drv->ctx, join->iev_addr);
- break;
- case RTM_IEEE80211_REPLAY:
- /* ignore */
- break;
- case RTM_IEEE80211_MICHAEL:
- mic = (struct ieee80211_michael_event *) &ifan[1];
- wpa_printf(MSG_DEBUG,
- "Michael MIC failure wireless event: "
- "keyix=%u src_addr=" MACSTR, mic->iev_keyix,
- MAC2STR(mic->iev_src));
-
- os_memset(&event, 0, sizeof(event));
- event.michael_mic_failure.unicast =
- !IEEE80211_IS_MULTICAST(mic->iev_dst);
- wpa_supplicant_event(drv->ctx,
- EVENT_MICHAEL_MIC_FAILURE, &event);
- break;
- }
- break;
- case RTM_IFINFO:
- ifm = (struct if_msghdr *) rtm;
- drv = bsd_get_drvindex(global, ifm->ifm_index);
- if (drv == NULL)
- return;
- if ((ifm->ifm_flags & IFF_UP) == 0 &&
- (drv->flags & IFF_UP) != 0) {
- wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
- drv->ifname);
- wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED,
- NULL);
- } else if ((ifm->ifm_flags & IFF_UP) != 0 &&
- (drv->flags & IFF_UP) == 0) {
- wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP",
- drv->ifname);
- wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
- NULL);
- }
- drv->flags = ifm->ifm_flags;
- break;
- }
-}
-
-static void
wpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res,
struct ieee80211req_scan_result *sr)
{
@@ -1570,12 +1456,6 @@
if (drv == NULL)
return NULL;
- /*
- * NB: We require the interface name be mappable to an index.
- * This implies we do not support having wpa_supplicant
- * wait for an interface to appear. This seems ok; that
- * doesn't belong here; it's really the job of devd.
- */
drv->ifindex = if_nametoindex(ifname);
if (drv->ifindex == 0) {
wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
@@ -1607,7 +1487,7 @@
goto fail;
/* Down interface during setup. */
- if (bsd_ctrl_iface(drv, 0) < 0)
+ if (bsd_get_iface_flags(drv) < 0)
goto fail;
drv->opmode = get80211opmode(drv);
@@ -1628,9 +1508,6 @@
if (drv->ifindex != 0 && !drv->if_removed) {
wpa_driver_bsd_set_wpa(drv, 0);
- /* NB: mark interface down */
- bsd_ctrl_iface(drv, 0);
-
wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa,
drv->prev_privacy);
@@ -1661,6 +1538,15 @@
bsd_global_init(void *ctx)
{
struct bsd_driver_global *global;
+#if defined(RO_MSGFILTER) || defined(ROUTE_MSGFILTER)
+ unsigned char msgfilter[] = {
+ RTM_IEEE80211,
+ RTM_IFINFO, RTM_IFANNOUNCE,
+ };
+#endif
+#ifdef ROUTE_MSGFILTER
+ unsigned int i, msgfilter_mask;
+#endif
global = os_zalloc(sizeof(*global));
if (global == NULL)
@@ -1683,22 +1569,24 @@
goto fail;
}
- global->event_buf_len = rtbuf_len();
- global->event_buf = os_malloc(global->event_buf_len);
- if (global->event_buf == NULL) {
- wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__);
- goto fail;
- }
+#if defined(RO_MSGFILTER)
+ if (setsockopt(global->route, PF_ROUTE, RO_MSGFILTER,
+ &msgfilter, sizeof(msgfilter)) < 0)
+ wpa_printf(MSG_ERROR, "socket[PF_ROUTE,RO_MSGFILTER]: %s",
+ strerror(errno));
+#elif defined(ROUTE_MSGFILTER)
+ msgfilter_mask = 0;
+ for (i = 0; i < (sizeof(msgfilter) / sizeof(msgfilter[0])); i++)
+ msgfilter_mask |= ROUTE_FILTER(msgfilter[i]);
+ if (setsockopt(global->route, PF_ROUTE, ROUTE_MSGFILTER,
+ &msgfilter_mask, sizeof(msgfilter_mask)) < 0)
+ wpa_printf(MSG_ERROR, "socket[PF_ROUTE,ROUTE_MSGFILTER]: %s",
+ strerror(errno));
+#endif
-#ifdef HOSTAPD
eloop_register_read_sock(global->route, bsd_wireless_event_receive,
NULL, global);
-#else /* HOSTAPD */
- eloop_register_read_sock(global->route, wpa_driver_bsd_event_receive,
- NULL, global);
-#endif /* HOSTAPD */
-
return global;
fail:
@@ -1735,7 +1623,6 @@
.sta_disassoc = bsd_sta_disassoc,
.sta_deauth = bsd_sta_deauth,
.sta_set_flags = bsd_set_sta_authorized,
- .commit = bsd_commit,
#else /* HOSTAPD */
.init2 = wpa_driver_bsd_init,
.deinit = wpa_driver_bsd_deinit,
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index e55e6cd..23a6a42 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -67,6 +67,7 @@
E2S(DRIVER_CLIENT_POLL_OK);
E2S(EAPOL_TX_STATUS);
E2S(CH_SWITCH);
+ E2S(CH_SWITCH_STARTED);
E2S(WNM);
E2S(CONNECT_FAILED_REASON);
E2S(DFS_RADAR_DETECTED);
@@ -87,6 +88,8 @@
E2S(STATION_OPMODE_CHANGED);
E2S(INTERFACE_MAC_CHANGED);
E2S(WDS_STA_INTERFACE_STATUS);
+ E2S(UPDATE_DH);
+ E2S(UNPROT_BEACON);
}
return "UNKNOWN";
@@ -306,6 +309,25 @@
DF2S(OCE_AP);
DF2S(OCE_STA_CFON);
DF2S(MFP_OPTIONAL);
+ DF2S(SELF_MANAGED_REGULATORY);
+ DF2S(FTM_RESPONDER);
+ DF2S(CONTROL_PORT);
+ DF2S(VLAN_OFFLOAD);
+ DF2S(UPDATE_FT_IES);
+ DF2S(SAFE_PTK0_REKEYS);
+ DF2S(BEACON_PROTECTION);
+ DF2S(EXTENDED_KEY_ID);
+ }
+ return "UNKNOWN";
+#undef DF2S
+}
+
+
+const char * driver_flag2_to_string(u64 flag2)
+{
+#define DF2S(x) case WPA_DRIVER_FLAGS2_ ## x: return #x
+ switch (flag2) {
+ DF2S(CONTROL_PORT_RX);
}
return "UNKNOWN";
#undef DF2S
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
index 61b39b1..b9c42e4 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -263,7 +263,8 @@
static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack,
unsigned int freq,
- const u16 *csa_offs, size_t csa_offs_len)
+ const u16 *csa_offs, size_t csa_offs_len,
+ int no_encrypt, unsigned int wait)
{
struct hostap_driver_data *drv = priv;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg;
@@ -312,7 +313,7 @@
pos += 2;
memcpy(pos, data, data_len);
- res = hostap_send_mlme(drv, (u8 *) hdr, len, 0, 0, NULL, 0);
+ res = hostap_send_mlme(drv, (u8 *) hdr, len, 0, 0, NULL, 0, 0, 0);
if (res < 0) {
wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - "
"failed: %d (%s)",
@@ -395,17 +396,20 @@
}
-static int wpa_driver_hostap_set_key(const char *ifname, void *priv,
- 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)
+static int wpa_driver_hostap_set_key(void *priv,
+ struct wpa_driver_set_key_params *params)
{
struct hostap_driver_data *drv = priv;
struct prism2_hostapd_param *param;
u8 *buf;
size_t blen;
int ret = 0;
+ enum wpa_alg alg = params->alg;
+ const u8 *addr = params->addr;
+ int key_idx = params->key_idx;
+ int set_tx = params->set_tx;
+ const u8 *key = params->key;
+ size_t key_len = params->key_len;
blen = sizeof(*param) + key_len;
buf = os_zalloc(blen);
@@ -1028,7 +1032,7 @@
static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
- int reason)
+ u16 reason)
{
struct hostap_driver_data *drv = priv;
struct ieee80211_mgmt mgmt;
@@ -1051,7 +1055,7 @@
memcpy(mgmt.bssid, own_addr, ETH_ALEN);
mgmt.u.deauth.reason_code = host_to_le16(reason);
return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth), 0, 0, NULL, 0);
+ sizeof(mgmt.u.deauth), 0, 0, NULL, 0, 0, 0);
}
@@ -1076,7 +1080,7 @@
static int hostap_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
- int reason)
+ u16 reason)
{
struct hostap_driver_data *drv = priv;
struct ieee80211_mgmt mgmt;
@@ -1089,7 +1093,7 @@
memcpy(mgmt.bssid, own_addr, ETH_ALEN);
mgmt.u.disassoc.reason_code = host_to_le16(reason);
return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
- sizeof(mgmt.u.disassoc), 0, 0, NULL, 0);
+ sizeof(mgmt.u.disassoc), 0, 0, NULL, 0, 0, 0);
}
@@ -1169,7 +1173,7 @@
os_memcpy(hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
os_memcpy(hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
- hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0, 0, NULL, 0);
+ hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0, 0, NULL, 0, 0, 0);
}
diff --git a/src/drivers/driver_macsec_linux.c b/src/drivers/driver_macsec_linux.c
index 9d981bb..36a0757 100644
--- a/src/drivers/driver_macsec_linux.c
+++ b/src/drivers/driver_macsec_linux.c
@@ -1,6 +1,7 @@
/*
* Driver interaction with Linux MACsec kernel module
* Copyright (c) 2016, Sabrina Dubroca <sd@queasysnail.net> and Red Hat, Inc.
+ * Copyright (c) 2019, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -22,6 +23,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
+#include "common/eapol_common.h"
#include "pae/ieee802_1x_kay.h"
#include "driver.h"
#include "driver_wired_common.h"
@@ -52,30 +54,29 @@
struct nl_sock *sk;
struct macsec_genl_ctx ctx;
- struct netlink_data *netlink;
- struct nl_handle *nl;
char ifname[IFNAMSIZ + 1];
int ifi;
int parent_ifi;
+ int use_pae_group_addr;
- Boolean created_link;
+ bool created_link;
- Boolean controlled_port_enabled;
- Boolean controlled_port_enabled_set;
+ bool controlled_port_enabled;
+ bool controlled_port_enabled_set;
- Boolean protect_frames;
- Boolean protect_frames_set;
+ bool protect_frames;
+ bool protect_frames_set;
- Boolean encrypt;
- Boolean encrypt_set;
+ bool encrypt;
+ bool encrypt_set;
- Boolean replay_protect;
- Boolean replay_protect_set;
+ bool replay_protect;
+ bool replay_protect_set;
u32 replay_window;
u8 encoding_sa;
- Boolean encoding_sa_set;
+ bool encoding_sa_set;
};
@@ -196,7 +197,7 @@
rtnl_link_put(change);
- drv->controlled_port_enabled_set = FALSE;
+ drv->controlled_port_enabled_set = false;
}
if (drv->protect_frames_set) {
@@ -235,9 +236,9 @@
if (err < 0)
return err;
- drv->protect_frames_set = FALSE;
- drv->encrypt_set = FALSE;
- drv->replay_protect_set = FALSE;
+ drv->protect_frames_set = false;
+ drv->encrypt_set = false;
+ drv->replay_protect_set = false;
return 0;
}
@@ -318,14 +319,14 @@
if (err < 0) {
wpa_printf(MSG_ERROR, DRV_PREFIX
"Unable to connect NETLINK_ROUTE socket: %s",
- strerror(errno));
+ nl_geterror(err));
goto sock;
}
err = rtnl_link_alloc_cache(drv->sk, AF_UNSPEC, &drv->link_cache);
if (err < 0) {
wpa_printf(MSG_ERROR, DRV_PREFIX "Unable to get link cache: %s",
- strerror(errno));
+ nl_geterror(err));
goto sock;
}
@@ -389,17 +390,17 @@
/**
* macsec_drv_enable_protect_frames - Set protect frames status
* @priv: Private driver interface data
- * @enabled: TRUE = protect frames enabled
- * FALSE = protect frames disabled
+ * @enabled: true = protect frames enabled
+ * false = protect frames disabled
* Returns: 0 on success, -1 on failure (or if not supported)
*/
-static int macsec_drv_enable_protect_frames(void *priv, Boolean enabled)
+static int macsec_drv_enable_protect_frames(void *priv, bool enabled)
{
struct macsec_drv_data *drv = priv;
wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
- drv->protect_frames_set = TRUE;
+ drv->protect_frames_set = true;
drv->protect_frames = enabled;
return try_commit(drv);
@@ -409,17 +410,17 @@
/**
* macsec_drv_enable_encrypt - Set protect frames status
* @priv: Private driver interface data
- * @enabled: TRUE = protect frames enabled
- * FALSE = protect frames disabled
+ * @enabled: true = protect frames enabled
+ * false = protect frames disabled
* Returns: 0 on success, -1 on failure (or if not supported)
*/
-static int macsec_drv_enable_encrypt(void *priv, Boolean enabled)
+static int macsec_drv_enable_encrypt(void *priv, bool enabled)
{
struct macsec_drv_data *drv = priv;
wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
- drv->encrypt_set = TRUE;
+ drv->encrypt_set = true;
drv->encrypt = enabled;
return try_commit(drv);
@@ -429,12 +430,12 @@
/**
* macsec_drv_set_replay_protect - Set replay protect status and window size
* @priv: Private driver interface data
- * @enabled: TRUE = replay protect enabled
- * FALSE = replay protect disabled
+ * @enabled: true = replay protect enabled
+ * false = replay protect disabled
* @window: replay window size, valid only when replay protect enabled
* Returns: 0 on success, -1 on failure (or if not supported)
*/
-static int macsec_drv_set_replay_protect(void *priv, Boolean enabled,
+static int macsec_drv_set_replay_protect(void *priv, bool enabled,
u32 window)
{
struct macsec_drv_data *drv = priv;
@@ -442,7 +443,7 @@
wpa_printf(MSG_DEBUG, "%s -> %s, %u", __func__,
enabled ? "TRUE" : "FALSE", window);
- drv->replay_protect_set = TRUE;
+ drv->replay_protect_set = true;
drv->replay_protect = enabled;
if (enabled)
drv->replay_window = window;
@@ -467,18 +468,18 @@
/**
* macsec_drv_enable_controlled_port - Set controlled port status
* @priv: Private driver interface data
- * @enabled: TRUE = controlled port enabled
- * FALSE = controlled port disabled
+ * @enabled: true = controlled port enabled
+ * false = controlled port disabled
* Returns: 0 on success, -1 on failure (or if not supported)
*/
-static int macsec_drv_enable_controlled_port(void *priv, Boolean enabled)
+static int macsec_drv_enable_controlled_port(void *priv, bool enabled)
{
struct macsec_drv_data *drv = priv;
wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
drv->controlled_port_enabled = enabled;
- drv->controlled_port_enabled_set = TRUE;
+ drv->controlled_port_enabled_set = true;
return try_commit(drv);
}
@@ -985,7 +986,7 @@
static int set_active_rx_sa(const struct macsec_genl_ctx *ctx, int ifindex,
- u64 sci, unsigned char an, Boolean state)
+ u64 sci, unsigned char an, bool state)
{
struct nl_msg *msg;
struct nlattr *nest;
@@ -1035,7 +1036,7 @@
SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
return set_active_rx_sa(ctx, drv->ifi, mka_sci_u64(&sa->sc->sci),
- sa->an, TRUE);
+ sa->an, true);
}
@@ -1055,7 +1056,7 @@
SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
return set_active_rx_sa(ctx, drv->ifi, mka_sci_u64(&sa->sc->sci),
- sa->an, FALSE);
+ sa->an, false);
}
@@ -1116,13 +1117,13 @@
sci = mka_sci_u64(&sc->sci);
rtnl_link_macsec_set_sci(link, sci);
- drv->created_link = TRUE;
+ drv->created_link = true;
err = rtnl_link_add(drv->sk, link, NLM_F_CREATE);
if (err == -NLE_BUSY) {
wpa_printf(MSG_INFO,
DRV_PREFIX "link already exists, using it");
- drv->created_link = FALSE;
+ drv->created_link = false;
} else if (err < 0) {
rtnl_link_put(link);
wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't create link: err %d",
@@ -1295,7 +1296,7 @@
static int set_active_tx_sa(const struct macsec_genl_ctx *ctx, int ifindex,
- unsigned char an, Boolean state)
+ unsigned char an, bool state)
{
struct nl_msg *msg;
struct nlattr *nest;
@@ -1343,13 +1344,13 @@
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);
+ ret = set_active_tx_sa(ctx, drv->ifi, sa->an, true);
if (ret < 0) {
wpa_printf(MSG_ERROR, DRV_PREFIX "failed to enable txsa");
return ret;
}
- drv->encoding_sa_set = TRUE;
+ drv->encoding_sa_set = true;
drv->encoding_sa = sa->an;
return try_commit(drv);
@@ -1371,7 +1372,7 @@
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);
+ return set_active_tx_sa(ctx, drv->ifi, sa->an, false);
}
@@ -1399,6 +1400,214 @@
}
+#ifdef __linux__
+
+static void macsec_drv_handle_data(void *ctx, unsigned char *buf, size_t len)
+{
+#ifdef HOSTAPD
+ struct ieee8023_hdr *hdr;
+ u8 *pos, *sa;
+ size_t left;
+ union wpa_event_data event;
+
+ /* must contain at least ieee8023_hdr 6 byte source, 6 byte dest,
+ * 2 byte ethertype */
+ if (len < 14) {
+ wpa_printf(MSG_MSGDUMP, "%s: too short (%lu)",
+ __func__, (unsigned long) len);
+ return;
+ }
+
+ 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);
+
+ pos = (u8 *) (hdr + 1);
+ left = len - sizeof(*hdr);
+ drv_event_eapol_rx(ctx, sa, pos, left);
+ break;
+
+ default:
+ wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame",
+ ntohs(hdr->ethertype));
+ break;
+ }
+#endif /* HOSTAPD */
+}
+
+
+static void macsec_drv_handle_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ int len;
+ unsigned char buf[3000];
+
+ len = recv(sock, buf, sizeof(buf), 0);
+ if (len < 0) {
+ wpa_printf(MSG_ERROR, "macsec_linux: recv: %s",
+ strerror(errno));
+ return;
+ }
+
+ macsec_drv_handle_data(eloop_ctx, buf, len);
+}
+
+#endif /* __linux__ */
+
+
+static int macsec_drv_init_sockets(struct macsec_drv_data *drv, u8 *own_addr)
+{
+#ifdef __linux__
+ struct ifreq ifr;
+ struct sockaddr_ll addr;
+
+ drv->common.sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
+ if (drv->common.sock < 0) {
+ wpa_printf(MSG_ERROR, "socket[PF_PACKET,SOCK_RAW]: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ if (eloop_register_read_sock(drv->common.sock, macsec_drv_handle_read,
+ drv->common.ctx, NULL)) {
+ wpa_printf(MSG_INFO, "Could not register read socket");
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name));
+ if (ioctl(drv->common.sock, SIOCGIFINDEX, &ifr) != 0) {
+ wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
+ strerror(errno));
+ return -1;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sll_family = AF_PACKET;
+ addr.sll_ifindex = ifr.ifr_ifindex;
+ wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
+ addr.sll_ifindex);
+
+ if (bind(drv->common.sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+ {
+ wpa_printf(MSG_ERROR, "bind: %s", strerror(errno));
+ return -1;
+ }
+
+ /* filter multicast address */
+ if (wired_multicast_membership(drv->common.sock, ifr.ifr_ifindex,
+ pae_group_addr, 1) < 0) {
+ wpa_printf(MSG_ERROR, "wired: Failed to add multicast group "
+ "membership");
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name));
+ if (ioctl(drv->common.sock, SIOCGIFHWADDR, &ifr) != 0) {
+ wpa_printf(MSG_ERROR, "ioctl(SIOCGIFHWADDR): %s",
+ strerror(errno));
+ return -1;
+ }
+
+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ wpa_printf(MSG_INFO, "Invalid HW-addr family 0x%04x",
+ ifr.ifr_hwaddr.sa_family);
+ return -1;
+ }
+ os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ return 0;
+#else /* __linux__ */
+ return -1;
+#endif /* __linux__ */
+}
+
+
+static void * macsec_drv_hapd_init(struct hostapd_data *hapd,
+ struct wpa_init_params *params)
+{
+ struct macsec_drv_data *drv;
+
+ drv = os_zalloc(sizeof(struct macsec_drv_data));
+ if (drv == NULL) {
+ wpa_printf(MSG_INFO,
+ "Could not allocate memory for wired driver data");
+ return NULL;
+ }
+
+ drv->common.ctx = hapd;
+ os_strlcpy(drv->common.ifname, params->ifname,
+ sizeof(drv->common.ifname));
+ drv->use_pae_group_addr = params->use_pae_group_addr;
+
+ if (macsec_drv_init_sockets(drv, params->own_addr)) {
+ os_free(drv);
+ return NULL;
+ }
+
+ return drv;
+}
+
+
+static void macsec_drv_hapd_deinit(void *priv)
+{
+ struct macsec_drv_data *drv = priv;
+
+ if (drv->common.sock >= 0) {
+ eloop_unregister_read_sock(drv->common.sock);
+ close(drv->common.sock);
+ }
+
+ os_free(drv);
+}
+
+
+static int macsec_drv_send_eapol(void *priv, const u8 *addr,
+ const u8 *data, size_t data_len, int encrypt,
+ const u8 *own_addr, u32 flags)
+{
+ struct macsec_drv_data *drv = priv;
+ struct ieee8023_hdr *hdr;
+ size_t len;
+ u8 *pos;
+ int res;
+
+ len = sizeof(*hdr) + data_len;
+ hdr = os_zalloc(len);
+ if (hdr == NULL) {
+ wpa_printf(MSG_INFO,
+ "%s: malloc() failed (len=%lu)",
+ __func__, (unsigned long) len);
+ return -1;
+ }
+
+ os_memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr,
+ ETH_ALEN);
+ os_memcpy(hdr->src, own_addr, ETH_ALEN);
+ hdr->ethertype = htons(ETH_P_PAE);
+
+ pos = (u8 *) (hdr + 1);
+ os_memcpy(pos, data, data_len);
+
+ res = send(drv->common.sock, (u8 *) hdr, len, 0);
+ os_free(hdr);
+
+ if (res < 0) {
+ wpa_printf(MSG_ERROR,
+ "%s: packet len: %lu - failed: send: %s",
+ __func__, (unsigned long) len, strerror(errno));
+ }
+
+ return res;
+}
+
+
const struct wpa_driver_ops wpa_driver_macsec_linux_ops = {
.name = "macsec_linux",
.desc = "MACsec Ethernet driver for Linux",
@@ -1407,6 +1616,9 @@
.get_capa = driver_wired_get_capa,
.init = macsec_drv_wpa_init,
.deinit = macsec_drv_wpa_deinit,
+ .hapd_init = macsec_drv_hapd_init,
+ .hapd_deinit = macsec_drv_hapd_deinit,
+ .hapd_send_eapol = macsec_drv_send_eapol,
.macsec_init = macsec_drv_macsec_init,
.macsec_deinit = macsec_drv_macsec_deinit,
diff --git a/src/drivers/driver_macsec_qca.c b/src/drivers/driver_macsec_qca.c
index 8372393..928f024 100644
--- a/src/drivers/driver_macsec_qca.c
+++ b/src/drivers/driver_macsec_qca.c
@@ -3,6 +3,7 @@
* Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004, Gunter Burchardt <tira@isx.de>
* Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
+ * Copyright (c) 2019, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -29,6 +30,7 @@
#include "utils/eloop.h"
#include "common/defs.h"
#include "common/ieee802_1x_defs.h"
+#include "common/eapol_common.h"
#include "pae/ieee802_1x_kay.h"
#include "driver.h"
#include "driver_wired_common.h"
@@ -64,14 +66,15 @@
struct macsec_qca_data {
struct driver_wired_common_data common;
+ int use_pae_group_addr;
u32 secy_id;
/* shadow */
- Boolean always_include_sci;
- Boolean use_es;
- Boolean use_scb;
- Boolean protect_frames;
- Boolean replay_protect;
+ bool always_include_sci;
+ bool use_es;
+ bool use_scb;
+ bool protect_frames;
+ bool replay_protect;
u32 replay_window;
struct channel_map receive_channel_map[MAXSC];
@@ -88,7 +91,7 @@
wpa_printf(MSG_INFO, "%s: secy_id=%d", __func__, drv->secy_id);
/* Enable Secy and Let EAPoL bypass */
- ret = nss_macsec_secy_en_set(drv->secy_id, TRUE);
+ ret = nss_macsec_secy_en_set(drv->secy_id, true);
if (ret)
wpa_printf(MSG_ERROR, "nss_macsec_secy_en_set: FAIL");
@@ -120,12 +123,140 @@
static void __macsec_drv_deinit(struct macsec_qca_data *drv)
{
- nss_macsec_secy_en_set(drv->secy_id, FALSE);
+ nss_macsec_secy_en_set(drv->secy_id, false);
nss_macsec_secy_rx_sc_del_all(drv->secy_id);
nss_macsec_secy_tx_sc_del_all(drv->secy_id);
}
+#ifdef __linux__
+
+static void macsec_qca_handle_data(void *ctx, unsigned char *buf, size_t len)
+{
+#ifdef HOSTAPD
+ struct ieee8023_hdr *hdr;
+ u8 *pos, *sa;
+ size_t left;
+ union wpa_event_data event;
+
+ /* at least 6 bytes src macaddress, 6 bytes dst macaddress
+ * and 2 bytes ethertype
+ */
+ if (len < 14) {
+ wpa_printf(MSG_MSGDUMP,
+ "macsec_qca_handle_data: too short (%lu)",
+ (unsigned long) len);
+ return;
+ }
+ 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);
+
+ pos = (u8 *) (hdr + 1);
+ left = len - sizeof(*hdr);
+ drv_event_eapol_rx(ctx, sa, pos, left);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame",
+ ntohs(hdr->ethertype));
+ break;
+ }
+#endif /* HOSTAPD */
+}
+
+
+static void macsec_qca_handle_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ int len;
+ unsigned char buf[3000];
+
+ len = recv(sock, buf, sizeof(buf), 0);
+ if (len < 0) {
+ wpa_printf(MSG_ERROR, "macsec_qca: recv: %s", strerror(errno));
+ return;
+ }
+
+ macsec_qca_handle_data(eloop_ctx, buf, len);
+}
+
+#endif /* __linux__ */
+
+
+static int macsec_qca_init_sockets(struct macsec_qca_data *drv, u8 *own_addr)
+{
+#ifdef __linux__
+ struct ifreq ifr;
+ struct sockaddr_ll addr;
+
+ drv->common.sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
+ if (drv->common.sock < 0) {
+ wpa_printf(MSG_ERROR, "socket[PF_PACKET,SOCK_RAW]: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ if (eloop_register_read_sock(drv->common.sock, macsec_qca_handle_read,
+ drv->common.ctx, NULL)) {
+ wpa_printf(MSG_INFO, "Could not register read socket");
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name));
+ if (ioctl(drv->common.sock, SIOCGIFINDEX, &ifr) != 0) {
+ wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
+ strerror(errno));
+ return -1;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sll_family = AF_PACKET;
+ addr.sll_ifindex = ifr.ifr_ifindex;
+ wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
+ addr.sll_ifindex);
+
+ if (bind(drv->common.sock, (struct sockaddr *) &addr,
+ sizeof(addr)) < 0) {
+ wpa_printf(MSG_ERROR, "macsec_qca: bind: %s", strerror(errno));
+ return -1;
+ }
+
+ /* filter multicast address */
+ if (wired_multicast_membership(drv->common.sock, ifr.ifr_ifindex,
+ pae_group_addr, 1) < 0) {
+ wpa_printf(MSG_ERROR,
+ "macsec_qca_init_sockets: Failed to add multicast group membership");
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name));
+ if (ioctl(drv->common.sock, SIOCGIFHWADDR, &ifr) != 0) {
+ wpa_printf(MSG_ERROR, "ioctl(SIOCGIFHWADDR): %s",
+ strerror(errno));
+ return -1;
+ }
+
+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ wpa_printf(MSG_INFO, "Invalid HW-addr family 0x%04x",
+ ifr.ifr_hwaddr.sa_family);
+ return -1;
+ }
+ os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ return 0;
+#else /* __linux__ */
+ return -1;
+#endif /* __linux__ */
+}
+
+
static void * macsec_qca_init(void *ctx, const char *ifname)
{
struct macsec_qca_data *drv;
@@ -160,6 +291,97 @@
}
+static void * macsec_qca_hapd_init(struct hostapd_data *hapd,
+ struct wpa_init_params *params)
+{
+ struct macsec_qca_data *drv;
+
+ drv = os_zalloc(sizeof(struct macsec_qca_data));
+ if (!drv) {
+ wpa_printf(MSG_INFO,
+ "Could not allocate memory for macsec_qca driver data");
+ return NULL;
+ }
+
+ /* Board specific settings */
+ if (os_memcmp("eth2", params->ifname, 4) == 0)
+ drv->secy_id = 1;
+ else if (os_memcmp("eth3", params->ifname, 4) == 0)
+ drv->secy_id = 2;
+ else if (os_memcmp("eth4", params->ifname, 4) == 0)
+ drv->secy_id = 0;
+ else if (os_memcmp("eth5", params->ifname, 4) == 0)
+ drv->secy_id = 1;
+ else
+ drv->secy_id = -1;
+
+ drv->common.ctx = hapd;
+ os_strlcpy(drv->common.ifname, params->ifname,
+ sizeof(drv->common.ifname));
+ drv->use_pae_group_addr = params->use_pae_group_addr;
+
+ if (macsec_qca_init_sockets(drv, params->own_addr)) {
+ os_free(drv);
+ return NULL;
+ }
+
+ return drv;
+}
+
+
+static void macsec_qca_hapd_deinit(void *priv)
+{
+ struct macsec_qca_data *drv = priv;
+
+ if (drv->common.sock >= 0) {
+ eloop_unregister_read_sock(drv->common.sock);
+ close(drv->common.sock);
+ }
+
+ os_free(drv);
+}
+
+
+static int macsec_qca_send_eapol(void *priv, const u8 *addr,
+ const u8 *data, size_t data_len, int encrypt,
+ const u8 *own_addr, u32 flags)
+{
+ struct macsec_qca_data *drv = priv;
+ struct ieee8023_hdr *hdr;
+ size_t len;
+ u8 *pos;
+ int res;
+
+ len = sizeof(*hdr) + data_len;
+ hdr = os_zalloc(len);
+ if (!hdr) {
+ wpa_printf(MSG_INFO,
+ "malloc() failed for macsec_qca_send_eapol(len=%lu)",
+ (unsigned long) len);
+ return -1;
+ }
+
+ os_memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr,
+ ETH_ALEN);
+ os_memcpy(hdr->src, own_addr, ETH_ALEN);
+ hdr->ethertype = htons(ETH_P_PAE);
+
+ pos = (u8 *) (hdr + 1);
+ os_memcpy(pos, data, data_len);
+
+ res = send(drv->common.sock, (u8 *) hdr, len, 0);
+ os_free(hdr);
+
+ if (res < 0) {
+ wpa_printf(MSG_ERROR,
+ "macsec_qca_send_eapol - packet len: %lu - failed: send: %s",
+ (unsigned long) len, strerror(errno));
+ }
+
+ return res;
+}
+
+
static int macsec_qca_macsec_init(void *priv, struct macsec_init_params *params)
{
struct macsec_qca_data *drv = priv;
@@ -200,7 +422,7 @@
}
-static int macsec_qca_enable_protect_frames(void *priv, Boolean enabled)
+static int macsec_qca_enable_protect_frames(void *priv, bool enabled)
{
struct macsec_qca_data *drv = priv;
int ret = 0;
@@ -213,7 +435,7 @@
}
-static int macsec_qca_set_replay_protect(void *priv, Boolean enabled,
+static int macsec_qca_set_replay_protect(void *priv, bool enabled,
unsigned int window)
{
struct macsec_qca_data *drv = priv;
@@ -258,7 +480,7 @@
}
-static int macsec_qca_enable_controlled_port(void *priv, Boolean enabled)
+static int macsec_qca_enable_controlled_port(void *priv, bool enabled)
{
struct macsec_qca_data *drv = priv;
int ret = 0;
@@ -338,7 +560,7 @@
struct macsec_qca_data *drv = priv;
int ret = 0;
u32 next_pn = 0;
- bool enabled = FALSE;
+ bool enabled = false;
u32 win;
u32 channel;
@@ -407,7 +629,7 @@
struct macsec_qca_data *drv = priv;
int ret = 0;
u32 sc_ch = 0;
- bool in_use = FALSE;
+ bool in_use = false;
for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
ret = nss_macsec_secy_rx_sc_in_used_get(drv->secy_id, sc_ch,
@@ -572,7 +794,7 @@
sa->an);
ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
- TRUE);
+ true);
return ret;
}
@@ -592,7 +814,7 @@
sa->an);
ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
- FALSE);
+ false);
return ret;
}
@@ -602,7 +824,7 @@
{
struct macsec_qca_data *drv = priv;
u32 sc_ch = 0;
- bool in_use = FALSE;
+ bool in_use = false;
for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
if (nss_macsec_secy_tx_sc_in_used_get(drv->secy_id, sc_ch,
@@ -766,7 +988,7 @@
sa->an);
ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
- TRUE);
+ true);
return ret;
}
@@ -786,7 +1008,7 @@
sa->an);
ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
- FALSE);
+ false);
return ret;
}
@@ -800,6 +1022,9 @@
.get_capa = driver_wired_get_capa,
.init = macsec_qca_init,
.deinit = macsec_qca_deinit,
+ .hapd_init = macsec_qca_hapd_init,
+ .hapd_deinit = macsec_qca_hapd_deinit,
+ .hapd_send_eapol = macsec_qca_send_eapol,
.macsec_init = macsec_qca_macsec_init,
.macsec_deinit = macsec_qca_macsec_deinit,
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index 614c452..529fc3b 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -719,7 +719,7 @@
static int wpa_driver_ndis_deauthenticate(void *priv, const u8 *addr,
- int reason_code)
+ u16 reason_code)
{
struct wpa_driver_ndis_data *drv = priv;
return wpa_driver_ndis_disconnect(drv);
@@ -1034,6 +1034,18 @@
static int
+wpa_driver_ndis_set_key_wrapper(void *priv,
+ struct wpa_driver_set_key_params *params)
+{
+ return wpa_driver_ndis_set_key(params->ifname, priv,
+ params->alg, params->addr,
+ params->key_idx, params->set_tx,
+ params->seq, params->seq_len,
+ params->key, params->key_len);
+}
+
+
+static int
wpa_driver_ndis_associate(void *priv,
struct wpa_driver_associate_params *params)
{
@@ -3195,7 +3207,7 @@
wpa_driver_ndis_ops.desc = ndis_drv_desc;
wpa_driver_ndis_ops.get_bssid = wpa_driver_ndis_get_bssid;
wpa_driver_ndis_ops.get_ssid = wpa_driver_ndis_get_ssid;
- wpa_driver_ndis_ops.set_key = wpa_driver_ndis_set_key;
+ wpa_driver_ndis_ops.set_key = wpa_driver_ndis_set_key_wrapper;
wpa_driver_ndis_ops.init = wpa_driver_ndis_init;
wpa_driver_ndis_ops.deinit = wpa_driver_ndis_deinit;
wpa_driver_ndis_ops.deauthenticate = wpa_driver_ndis_deauthenticate;
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 21d1398..d48f8cb 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -30,7 +30,6 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_common.h"
-#include "l2_packet/l2_packet.h"
#include "netlink.h"
#include "linux_defines.h"
#include "linux_ioctl.h"
@@ -66,48 +65,6 @@
#define SOL_NETLINK 270
#endif
-#ifndef CONFIG_LIBNL20
-/*
- * libnl 1.1 has a bug, it tries to allocate socket numbers densely
- * but when you free a socket again it will mess up its bitmap and
- * and use the wrong number the next time it needs a socket ID.
- * Therefore, we wrap the handle alloc/destroy and add our own pid
- * accounting.
- */
-static uint32_t port_bitmap[32] = { 0 };
-
-static struct nl_handle *nl80211_handle_alloc(void *cb)
-{
- struct nl_handle *handle;
- uint32_t pid = getpid() & 0x3FFFFF;
- int i;
-
- handle = nl_handle_alloc_cb(cb);
-
- for (i = 0; i < 1024; i++) {
- if (port_bitmap[i / 32] & (1 << (i % 32)))
- continue;
- port_bitmap[i / 32] |= 1 << (i % 32);
- pid += i << 22;
- break;
- }
-
- nl_socket_set_local_port(handle, pid);
-
- return handle;
-}
-
-static void nl80211_handle_destroy(struct nl_handle *handle)
-{
- uint32_t port = nl_socket_get_local_port(handle);
-
- port >>= 22;
- port_bitmap[port / 32] &= ~(1 << (port % 32));
-
- nl_handle_destroy(handle);
-}
-#endif /* CONFIG_LIBNL20 */
-
#ifdef ANDROID
/* system/core/libnl_2 does not include nl_socket_set_nonblocking() */
@@ -117,11 +74,11 @@
#endif /* ANDROID */
-static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg)
+static struct nl_sock * nl_create_handle(struct nl_cb *cb, const char *dbg)
{
- struct nl_handle *handle;
+ struct nl_sock *handle;
- handle = nl80211_handle_alloc(cb);
+ handle = nl_socket_alloc_cb(cb);
if (handle == NULL) {
wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
"callbacks (%s)", dbg);
@@ -131,7 +88,7 @@
if (genl_connect(handle)) {
wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
"netlink (%s)", dbg);
- nl80211_handle_destroy(handle);
+ nl_socket_free(handle);
return NULL;
}
@@ -139,11 +96,11 @@
}
-static void nl_destroy_handles(struct nl_handle **handle)
+static void nl_destroy_handles(struct nl_sock **handle)
{
if (*handle == NULL)
return;
- nl80211_handle_destroy(*handle);
+ nl_socket_free(*handle);
*handle = NULL;
}
@@ -154,11 +111,10 @@
#define ELOOP_SOCKET_INVALID (intptr_t) 0x88888889ULL
#endif
-static void nl80211_register_eloop_read(struct nl_handle **handle,
+static void nl80211_register_eloop_read(struct nl_sock **handle,
eloop_sock_handler handler,
void *eloop_data, int persist)
{
-#ifdef CONFIG_LIBNL20
/*
* libnl uses a pretty small buffer (32 kB that gets converted to 64 kB)
* by default. It is possible to hit that limit in some cases where
@@ -166,13 +122,15 @@
* to hostapd and STA entry deletion. Try to increase the buffer to make
* this less likely to occur.
*/
- if (nl_socket_set_buffer_size(*handle, 262144, 0) < 0) {
+ int err;
+
+ err = nl_socket_set_buffer_size(*handle, 262144, 0);
+ if (err < 0) {
wpa_printf(MSG_DEBUG,
"nl80211: Could not set nl_socket RX buffer size: %s",
- strerror(errno));
+ nl_geterror(err));
/* continue anyway with the default (smaller) buffer */
}
-#endif /* CONFIG_LIBNL20 */
nl_socket_set_nonblocking(*handle);
eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
@@ -183,7 +141,7 @@
}
-static void nl80211_destroy_eloop_handle(struct nl_handle **handle, int persist)
+static void nl80211_destroy_eloop_handle(struct nl_sock **handle, int persist)
{
if (!persist)
*handle = (void *) (((intptr_t) *handle) ^
@@ -206,7 +164,8 @@
const char *driver_params);
static int nl80211_send_frame_cmd(struct i802_bss *bss,
unsigned int freq, unsigned int wait,
- const u8 *buf, size_t buf_len, u64 *cookie,
+ const u8 *buf, size_t buf_len,
+ int save_cookie,
int no_cck, int no_ack, int offchanok,
const u16 *csa_offs, size_t csa_offs_len);
static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
@@ -236,7 +195,7 @@
struct wpa_driver_mesh_bss_params *params);
#endif /* CONFIG_MESH */
static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
- int reason);
+ u16 reason);
/* Converts nl80211_chan_width to a common format */
@@ -391,7 +350,7 @@
static int send_and_recv(struct nl80211_global *global,
- struct nl_handle *nl_handle, struct nl_msg *msg,
+ struct nl_sock *nl_handle, struct nl_msg *msg,
int (*valid_handler)(struct nl_msg *, void *),
void *valid_data)
{
@@ -416,8 +375,16 @@
NETLINK_CAP_ACK, &opt, sizeof(opt));
err = nl_send_auto_complete(nl_handle, msg);
- if (err < 0)
+ if (err < 0) {
+ wpa_printf(MSG_INFO,
+ "nl80211: nl_send_auto_complete() failed: %s",
+ nl_geterror(err));
+ /* Need to convert libnl error code to an errno value. For now,
+ * just hardcode this to EBADF; the real error reason is shown
+ * in that error print above. */
+ err = -EBADF;
goto out;
+ }
err = 1;
@@ -431,10 +398,24 @@
while (err > 0) {
int res = nl_recvmsgs(nl_handle, cb);
- if (res < 0) {
+
+ if (res == -NLE_DUMP_INTR) {
+ /* Most likely one of the nl80211 dump routines hit a
+ * case where internal results changed while the dump
+ * was being sent. The most common known case for this
+ * is scan results fetching while associated were every
+ * received Beacon frame from the AP may end up
+ * incrementing bss_generation. This
+ * NL80211_CMD_GET_SCAN case tries again in the caller;
+ * other cases (of which there are no known common ones)
+ * will stop and return an error. */
+ wpa_printf(MSG_DEBUG, "nl80211: %s; convert to -EAGAIN",
+ nl_geterror(res));
+ err = -EAGAIN;
+ } else if (res < 0) {
wpa_printf(MSG_INFO,
- "nl80211: %s->nl_recvmsgs failed: %d",
- __func__, res);
+ "nl80211: %s->nl_recvmsgs failed: %d (%s)",
+ __func__, res, nl_geterror(res));
}
}
out:
@@ -456,6 +437,52 @@
}
+/* Use this method to mark that it is necessary to own the connection/interface
+ * for this operation.
+ * handle may be set to NULL, to get the same behavior as send_and_recv_msgs().
+ * set_owner can be used to mark this socket for receiving control port frames.
+ */
+static int send_and_recv_msgs_owner(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg,
+ struct nl_sock *handle, int set_owner,
+ int (*valid_handler)(struct nl_msg *,
+ void *),
+ void *valid_data)
+{
+ /* Control port over nl80211 needs the flags and attributes below.
+ *
+ * The Linux kernel has initial checks for them (in nl80211.c) like:
+ * validate_pae_over_nl80211(...)
+ * or final checks like:
+ * dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid
+ *
+ * Final operations (e.g., disassociate) don't need to set these
+ * attributes, but they have to be performed on the socket, which has
+ * the connection owner property set in the kernel.
+ */
+ if ((drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) &&
+ handle && set_owner &&
+ (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_OVER_NL80211) ||
+ nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER) ||
+ nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
+ nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_PREAUTH)))
+ return -1;
+
+ return send_and_recv(drv->global, handle ? handle : drv->global->nl,
+ msg, valid_handler, valid_data);
+}
+
+
+struct nl_sock * get_connect_handle(struct i802_bss *bss)
+{
+ if ((bss->drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) ||
+ bss->use_nl_connect)
+ return bss->nl_connect;
+
+ return NULL;
+}
+
+
struct family_data {
const char *group;
int id;
@@ -1065,7 +1092,7 @@
while (RTA_OK(attr, attrlen)) {
switch (attr->rta_type) {
case IFLA_IFNAME:
- if (RTA_PAYLOAD(attr) >= IFNAMSIZ)
+ if (RTA_PAYLOAD(attr) > IFNAMSIZ)
break;
os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
ifname[RTA_PAYLOAD(attr)] = '\0';
@@ -1240,7 +1267,7 @@
while (RTA_OK(attr, attrlen)) {
switch (attr->rta_type) {
case IFLA_IFNAME:
- if (RTA_PAYLOAD(attr) >= IFNAMSIZ)
+ if (RTA_PAYLOAD(attr) > IFNAMSIZ)
break;
os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
ifname[RTA_PAYLOAD(attr)] = '\0';
@@ -1369,12 +1396,25 @@
struct nl_msg *msg;
int ret;
struct nl80211_get_assoc_freq_arg arg;
+ int count = 0;
+try_again:
msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
os_memset(&arg, 0, sizeof(arg));
arg.drv = drv;
ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
&arg);
+ if (ret == -EAGAIN) {
+ count++;
+ if (count >= 10) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid");
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid - try again");
+ goto try_again;
+ }
+ }
if (ret == 0) {
os_memcpy(ssid, arg.assoc_ssid, arg.assoc_ssid_len);
return arg.assoc_ssid_len;
@@ -1390,12 +1430,25 @@
struct nl_msg *msg;
int ret;
struct nl80211_get_assoc_freq_arg arg;
+ int count = 0;
+try_again:
msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
os_memset(&arg, 0, sizeof(arg));
arg.drv = drv;
ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
&arg);
+ if (ret == -EAGAIN) {
+ count++;
+ if (count >= 10) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Failed to receive consistent scan result dump for get_assoc_freq");
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to receive consistent scan result dump for get_assoc_freq - try again");
+ goto try_again;
+ }
+ }
if (ret == 0) {
unsigned int freq = drv->nlmode == NL80211_IFTYPE_ADHOC ?
arg.ibss_freq : arg.assoc_freq;
@@ -1733,7 +1786,7 @@
if (ret < 0) {
wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
"membership for scan events: %d (%s)",
- ret, strerror(-ret));
+ ret, nl_geterror(ret));
goto err;
}
@@ -1743,7 +1796,7 @@
if (ret < 0) {
wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
"membership for mlme events: %d (%s)",
- ret, strerror(-ret));
+ ret, nl_geterror(ret));
goto err;
}
@@ -1753,7 +1806,7 @@
if (ret < 0) {
wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
"membership for regulatory events: %d (%s)",
- ret, strerror(-ret));
+ ret, nl_geterror(ret));
/* Continue without regulatory events */
}
@@ -1763,7 +1816,7 @@
if (ret < 0) {
wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
"membership for vendor events: %d (%s)",
- ret, strerror(-ret));
+ ret, nl_geterror(ret));
/* Continue without vendor events */
}
@@ -1789,7 +1842,7 @@
static void nl80211_check_global(struct nl80211_global *global)
{
- struct nl_handle *handle;
+ struct nl_sock *handle;
const char *groups[] = { "scan", "mlme", "regulatory", "vendor", NULL };
int ret;
unsigned int i;
@@ -1808,7 +1861,7 @@
if (ret < 0) {
wpa_printf(MSG_INFO,
"nl80211: Could not re-add multicast membership for %s events: %d (%s)",
- groups[i], ret, strerror(-ret));
+ groups[i], ret, nl_geterror(ret));
}
}
}
@@ -1910,6 +1963,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_init_bss(struct i802_bss *bss)
{
bss->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
@@ -1921,6 +1993,8 @@
nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
process_bss_event, bss);
+ nl80211_init_connect_handle(bss);
+
return 0;
}
@@ -1929,6 +2003,9 @@
{
nl_cb_put(bss->nl_cb);
bss->nl_cb = NULL;
+
+ if (bss->nl_connect)
+ nl80211_destroy_eloop_handle(&bss->nl_connect, 1);
}
@@ -2010,9 +2087,8 @@
*/
drv->set_rekey_offload = 1;
- drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
+ drv->num_if_indices = ARRAY_SIZE(drv->default_if_indices);
drv->if_indices = drv->default_if_indices;
- drv->if_indices_reason = drv->default_if_indices_reason;
drv->first_bss = os_zalloc(sizeof(*drv->first_bss));
if (!drv->first_bss) {
@@ -2088,8 +2164,9 @@
static int nl80211_register_frame(struct i802_bss *bss,
- struct nl_handle *nl_handle,
- u16 type, const u8 *match, size_t match_len)
+ struct nl_sock *nl_handle,
+ u16 type, const u8 *match, size_t match_len,
+ bool multicast)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
@@ -2098,10 +2175,12 @@
buf[0] = '\0';
wpa_snprintf_hex(buf, sizeof(buf), match, match_len);
- wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x (%s) nl_handle=%p match=%s",
- type, fc2str(type), nl_handle, buf);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Register frame type=0x%x (%s) nl_handle=%p match=%s multicast=%d",
+ type, fc2str(type), nl_handle, buf, multicast);
- if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REGISTER_ACTION)) ||
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REGISTER_FRAME)) ||
+ (multicast && nla_put_flag(msg, NL80211_ATTR_RECEIVE_MULTICAST)) ||
nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, type) ||
nla_put(msg, NL80211_ATTR_FRAME_MATCH, match_len, match)) {
nlmsg_free(msg);
@@ -2149,32 +2228,14 @@
{
u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
return nl80211_register_frame(bss, bss->nl_mgmt,
- type, match, match_len);
-}
-
-
-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;
+ type, match, match_len, false);
}
static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
+ u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
int ret = 0;
if (nl80211_alloc_mgmt_handle(bss))
@@ -2182,13 +2243,14 @@
wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
"handle %p", bss->nl_mgmt);
- 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);
-
+ if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
/* register for any AUTH message */
- nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0);
+ nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0, false);
+ } else if ((drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
+ !(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
+ /* register for SAE Authentication frames */
+ nl80211_register_frame(bss, bss->nl_mgmt, type,
+ (u8 *) "\x03\x00", 2, false);
}
#ifdef CONFIG_INTERWORKING
@@ -2241,7 +2303,6 @@
6) < 0)
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)
@@ -2250,7 +2311,6 @@
/* SA Query Response */
if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
ret = -1;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_TDLS
if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
/* TDLS Discovery Response */
@@ -2332,7 +2392,7 @@
if (nl80211_register_frame(bss, bss->nl_mgmt,
(WLAN_FC_TYPE_MGMT << 2) |
(WLAN_FC_STYPE_AUTH << 4),
- NULL, 0) < 0)
+ NULL, 0, false) < 0)
ret = -1;
/* Mesh peering open */
@@ -2386,11 +2446,9 @@
/* FT Action frames */
if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
ret = -1;
-#ifdef CONFIG_IEEE80211W
/* SA Query */
if (nl80211_register_action_frame(bss, (u8 *) "\x08", 1) < 0)
ret = -1;
-#endif /* CONFIG_IEEE80211W */
/* Protected Dual of Public Action */
if (nl80211_register_action_frame(bss, (u8 *) "\x09", 1) < 0)
ret = -1;
@@ -2440,7 +2498,7 @@
if (nl80211_register_frame(bss, bss->nl_mgmt,
(WLAN_FC_TYPE_MGMT << 2) |
(stypes[i] << 4),
- NULL, 0) < 0) {
+ NULL, 0, false) < 0) {
goto out_err;
}
}
@@ -2474,8 +2532,8 @@
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)
+ if (nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0,
+ false) < 0)
wpa_printf(MSG_DEBUG,
"nl80211: Failed to subscribe to handle Authentication frames - SAE offload may not work");
}
@@ -2711,8 +2769,6 @@
if (drv->vendor_cmd_test_avail)
qca_vendor_test(drv);
- nl80211_init_connect_handle(bss);
-
return 0;
}
@@ -2762,7 +2818,7 @@
}
if (drv->rtnl_sk)
- nl80211_handle_destroy(drv->rtnl_sk);
+ nl_socket_free(drv->rtnl_sk);
if (bss->added_bridge) {
if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
@@ -2789,9 +2845,6 @@
if (drv->if_indices != drv->default_if_indices)
os_free(drv->if_indices);
- if (drv->if_indices_reason != drv->default_if_indices_reason)
- os_free(drv->if_indices_reason);
-
if (drv->disabled_11b_rates)
nl80211_disable_11b_rates(drv, drv->ifindex, 0);
@@ -2828,9 +2881,6 @@
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);
@@ -2881,7 +2931,6 @@
case WPA_ALG_KRK:
return RSN_CIPHER_SUITE_KRK;
case WPA_ALG_NONE:
- case WPA_ALG_PMK:
wpa_printf(MSG_ERROR, "nl80211: Unexpected encryption algorithm %d",
alg);
return 0;
@@ -2942,6 +2991,40 @@
}
+static int wpa_key_mgmt_to_suites(unsigned int key_mgmt_suites, u32 suites[],
+ int max_suites)
+{
+ int num_suites = 0;
+
+#define __AKM(a, b) \
+ if (num_suites < max_suites && \
+ (key_mgmt_suites & (WPA_KEY_MGMT_ ## a))) \
+ suites[num_suites++] = (RSN_AUTH_KEY_MGMT_ ## b)
+ __AKM(IEEE8021X, UNSPEC_802_1X);
+ __AKM(PSK, PSK_OVER_802_1X);
+ __AKM(FT_IEEE8021X, FT_802_1X);
+ __AKM(FT_PSK, FT_PSK);
+ __AKM(IEEE8021X_SHA256, 802_1X_SHA256);
+ __AKM(PSK_SHA256, PSK_SHA256);
+ __AKM(SAE, SAE);
+ __AKM(FT_SAE, FT_SAE);
+ __AKM(CCKM, CCKM);
+ __AKM(OSEN, OSEN);
+ __AKM(IEEE8021X_SUITE_B, 802_1X_SUITE_B);
+ __AKM(IEEE8021X_SUITE_B_192, 802_1X_SUITE_B_192);
+ __AKM(FILS_SHA256, FILS_SHA256);
+ __AKM(FILS_SHA384, FILS_SHA384);
+ __AKM(FT_FILS_SHA256, FT_FILS_SHA256);
+ __AKM(FT_FILS_SHA384, FT_FILS_SHA384);
+ __AKM(OWE, OWE);
+ __AKM(DPP, DPP);
+ __AKM(FT_IEEE8021X_SHA384, FT_802_1X_SHA384);
+#undef __AKM
+
+ return num_suites;
+}
+
+
#ifdef CONFIG_DRIVER_NL80211_QCA
static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
const u8 *key, size_t key_len)
@@ -3011,17 +3094,26 @@
}
-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,
- const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
+static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
+ struct wpa_driver_set_key_params *params)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
int ifindex;
- struct nl_msg *msg = NULL;
+ struct nl_msg *msg;
+ struct nl_msg *key_msg;
int ret;
- int tdls = 0;
+ int skip_set_key = 1;
+ const char *ifname = params->ifname;
+ enum wpa_alg alg = params->alg;
+ const u8 *addr = params->addr;
+ int key_idx = params->key_idx;
+ int set_tx = params->set_tx;
+ const u8 *seq = params->seq;
+ size_t seq_len = params->seq_len;
+ const u8 *key = params->key;
+ size_t key_len = params->key_len;
+ int vlan_id = params->vlan_id;
+ enum key_flag key_flag = params->key_flag;
/* Ignore for P2P Device */
if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
@@ -3029,18 +3121,17 @@
ifindex = if_nametoindex(ifname);
wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d "
- "set_tx=%d seq_len=%lu key_len=%lu",
+ "set_tx=%d seq_len=%lu key_len=%lu key_flag=0x%x",
__func__, ifindex, ifname, alg, addr, key_idx, set_tx,
- (unsigned long) seq_len, (unsigned long) key_len);
-#ifdef CONFIG_TDLS
- if (key_idx == -1) {
- key_idx = 0;
- tdls = 1;
+ (unsigned long) seq_len, (unsigned long) key_len, key_flag);
+
+ if (check_key_flag(key_flag)) {
+ wpa_printf(MSG_DEBUG, "%s: invalid key_flag", __func__);
+ return -EINVAL;
}
-#endif /* CONFIG_TDLS */
#ifdef CONFIG_DRIVER_NL80211_QCA
- if (alg == WPA_ALG_PMK &&
+ if ((key_flag & KEY_FLAG_PMK) &&
(drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
wpa_printf(MSG_DEBUG, "%s: calling issue_key_mgmt_set_key",
__func__);
@@ -3049,32 +3140,59 @@
}
#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 (key_flag & KEY_FLAG_PMK) {
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)
+ return nl80211_set_pmk(drv, key, key_len, addr);
+ /* The driver does not have any offload mechanism for PMK, so
+ * there is no need to configure this key. */
+ return 0;
+ }
- if (alg == WPA_ALG_NONE) {
+ ret = -ENOBUFS;
+ key_msg = nlmsg_alloc();
+ if (!key_msg)
+ return ret;
+
+ if ((key_flag & KEY_FLAG_PAIRWISE_MASK) ==
+ KEY_FLAG_PAIRWISE_RX_TX_MODIFY) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: SET_KEY (pairwise RX/TX modify)");
+ msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
+ if (!msg)
+ goto fail2;
+ } else if (alg == WPA_ALG_NONE && (key_flag & KEY_FLAG_RX_TX)) {
+ wpa_printf(MSG_DEBUG, "%s: invalid key_flag to delete key",
+ __func__);
+ ret = -EINVAL;
+ goto fail2;
+ } else if (alg == WPA_ALG_NONE) {
+ wpa_printf(MSG_DEBUG, "nl80211: DEL_KEY");
msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
if (!msg)
- return -ENOBUFS;
+ goto fail2;
} else {
u32 suite;
suite = wpa_alg_to_cipher_suite(alg, key_len);
- if (!suite)
- goto fail;
+ if (!suite) {
+ ret = -EINVAL;
+ goto fail2;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: NEW_KEY");
msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY);
- if (!msg ||
- nla_put(msg, NL80211_ATTR_KEY_DATA, key_len, key) ||
- nla_put_u32(msg, NL80211_ATTR_KEY_CIPHER, suite))
+ if (!msg)
+ goto fail2;
+ if (nla_put(key_msg, NL80211_KEY_DATA, key_len, key) ||
+ nla_put_u32(key_msg, NL80211_KEY_CIPHER, suite))
goto fail;
wpa_hexdump_key(MSG_DEBUG, "nl80211: KEY_DATA", key, key_len);
- }
- if (seq && seq_len) {
- if (nla_put(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq))
- goto fail;
- wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ", seq, seq_len);
+ if (seq && seq_len) {
+ if (nla_put(key_msg, NL80211_KEY_SEQ, seq_len, seq))
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ",
+ seq, seq_len);
+ }
}
if (addr && !is_broadcast_ether_addr(addr)) {
@@ -3082,83 +3200,135 @@
if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
goto fail;
- if (alg != WPA_ALG_WEP && key_idx && !set_tx) {
+ if ((key_flag & KEY_FLAG_PAIRWISE_MASK) ==
+ KEY_FLAG_PAIRWISE_RX ||
+ (key_flag & KEY_FLAG_PAIRWISE_MASK) ==
+ KEY_FLAG_PAIRWISE_RX_TX_MODIFY) {
+ if (nla_put_u8(key_msg, NL80211_KEY_MODE,
+ key_flag == KEY_FLAG_PAIRWISE_RX ?
+ NL80211_KEY_NO_TX : NL80211_KEY_SET_TX))
+ goto fail;
+ } else if ((key_flag & KEY_FLAG_GROUP_MASK) ==
+ KEY_FLAG_GROUP_RX) {
wpa_printf(MSG_DEBUG, " RSN IBSS RX GTK");
- if (nla_put_u32(msg, NL80211_ATTR_KEY_TYPE,
+ if (nla_put_u32(key_msg, NL80211_KEY_TYPE,
NL80211_KEYTYPE_GROUP))
goto fail;
- }
- } else if (addr && is_broadcast_ether_addr(addr)) {
- struct nlattr *types;
-
- wpa_printf(MSG_DEBUG, " broadcast key");
-
- types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
- if (!types ||
- nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
+ } else if (!(key_flag & KEY_FLAG_PAIRWISE)) {
+ wpa_printf(MSG_DEBUG,
+ " key_flag missing PAIRWISE when setting a pairwise key");
+ ret = -EINVAL;
goto fail;
- nla_nest_end(msg, types);
- }
- if (nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
+ } else if (alg == WPA_ALG_WEP &&
+ (key_flag & KEY_FLAG_RX_TX) == KEY_FLAG_RX_TX) {
+ wpa_printf(MSG_DEBUG, " unicast WEP key");
+ skip_set_key = 0;
+ } else {
+ wpa_printf(MSG_DEBUG, " pairwise key");
+ }
+ } else if ((key_flag & KEY_FLAG_PAIRWISE) ||
+ !(key_flag & KEY_FLAG_GROUP)) {
+ wpa_printf(MSG_DEBUG,
+ " invalid key_flag for a broadcast key");
+ ret = -EINVAL;
goto fail;
+ } else {
+ wpa_printf(MSG_DEBUG, " broadcast key");
+ if (key_flag & KEY_FLAG_DEFAULT)
+ skip_set_key = 0;
+ }
+ if (nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) ||
+ nla_put_nested(msg, NL80211_ATTR_KEY, key_msg))
+ goto fail;
+ nl80211_nlmsg_clear(key_msg);
+ nlmsg_free(key_msg);
+ key_msg = NULL;
+
+ if (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
+ wpa_printf(MSG_DEBUG, "nl80211: VLAN ID %d", vlan_id);
+ if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id))
+ goto fail;
+ }
ret = send_and_recv_msgs(drv, msg, NULL, key ? (void *) -1 : NULL);
if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
ret = 0;
if (ret)
- wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s)",
+ wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s",
ret, strerror(-ret));
/*
- * If we failed or don't need to set the default TX key (below),
+ * If we failed or don't need to set the key as default (below),
* we're done here.
*/
- if (ret || !set_tx || alg == WPA_ALG_NONE || tdls)
+ if (ret || skip_set_key)
return ret;
- if (is_ap_interface(drv->nlmode) && addr &&
- !is_broadcast_ether_addr(addr))
+ wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_SET_KEY - default key");
+
+ ret = -ENOBUFS;
+ key_msg = nlmsg_alloc();
+ if (!key_msg)
return ret;
msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
- if (!msg ||
- nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx) ||
- nla_put_flag(msg, (alg == WPA_ALG_IGTK ||
- alg == WPA_ALG_BIP_GMAC_128 ||
- alg == WPA_ALG_BIP_GMAC_256 ||
- alg == WPA_ALG_BIP_CMAC_256) ?
- NL80211_ATTR_KEY_DEFAULT_MGMT :
- NL80211_ATTR_KEY_DEFAULT))
+ if (!msg)
+ goto fail2;
+ if (!key_msg ||
+ nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) ||
+ nla_put_flag(key_msg, (alg == WPA_ALG_IGTK ||
+ alg == WPA_ALG_BIP_GMAC_128 ||
+ alg == WPA_ALG_BIP_GMAC_256 ||
+ alg == WPA_ALG_BIP_CMAC_256) ?
+ (key_idx == 6 || key_idx == 7 ?
+ NL80211_KEY_DEFAULT_BEACON :
+ NL80211_KEY_DEFAULT_MGMT) :
+ NL80211_KEY_DEFAULT))
goto fail;
if (addr && is_broadcast_ether_addr(addr)) {
struct nlattr *types;
- types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
+ types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
if (!types ||
- nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
+ nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
goto fail;
- nla_nest_end(msg, types);
+ nla_nest_end(key_msg, types);
} else if (addr) {
struct nlattr *types;
- types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
+ types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES);
if (!types ||
- nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_UNICAST))
+ nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_UNICAST))
goto fail;
- nla_nest_end(msg, types);
+ nla_nest_end(key_msg, types);
+ }
+
+ if (nla_put_nested(msg, NL80211_ATTR_KEY, key_msg))
+ goto fail;
+ nl80211_nlmsg_clear(key_msg);
+ nlmsg_free(key_msg);
+ key_msg = NULL;
+
+ if (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
+ wpa_printf(MSG_DEBUG, "nl80211: set_key default - VLAN ID %d",
+ vlan_id);
+ if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id))
+ goto fail;
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- if (ret == -ENOENT)
- ret = 0;
if (ret)
- wpa_printf(MSG_DEBUG, "nl80211: set_key default failed; "
- "err=%d %s)", ret, strerror(-ret));
+ wpa_printf(MSG_DEBUG,
+ "nl80211: set_key default failed; err=%d %s",
+ ret, strerror(-ret));
return ret;
fail:
nl80211_nlmsg_clear(msg);
nlmsg_free(msg);
- return -ENOBUFS;
+fail2:
+ nl80211_nlmsg_clear(key_msg);
+ nlmsg_free(key_msg);
+ return ret;
}
@@ -3254,7 +3424,7 @@
int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
const u8 *addr, int cmd, u16 reason_code,
int local_state_change,
- struct nl_handle *nl_connect)
+ struct nl_sock *nl_connect)
{
int ret;
struct nl_msg *msg;
@@ -3282,8 +3452,8 @@
static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
- int reason_code,
- struct nl_handle *nl_connect)
+ u16 reason_code,
+ struct nl_sock *nl_connect)
{
int ret;
int drv_associated = drv->associated;
@@ -3304,7 +3474,7 @@
static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
- const u8 *addr, int reason_code)
+ const u8 *addr, u16 reason_code)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret;
@@ -3315,18 +3485,14 @@
return nl80211_leave_ibss(drv, 1);
}
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);
+ get_connect_handle(bss));
}
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, NULL);
+ reason_code, 0, get_connect_handle(bss));
/*
* For locally generated deauthenticate, supplicant already generates a
* DEAUTH event, so ignore the event from NL80211.
@@ -3433,6 +3599,7 @@
enum nl80211_iftype nlmode;
int count = 0;
int is_retry;
+ struct wpa_driver_set_key_params p;
nl80211_unmask_11b_rates(bss);
@@ -3461,14 +3628,20 @@
if (!msg)
goto fail;
+ os_memset(&p, 0, sizeof(p));
+ p.ifname = bss->ifname;
+ p.alg = WPA_ALG_WEP;
for (i = 0; i < 4; i++) {
if (!params->wep_key[i])
continue;
- wpa_driver_nl80211_set_key(bss->ifname, bss, WPA_ALG_WEP,
- NULL, i,
- i == params->wep_tx_keyidx, NULL, 0,
- params->wep_key[i],
- params->wep_key_len[i]);
+ p.key_idx = i;
+ p.set_tx = i == params->wep_tx_keyidx;
+ p.key = params->wep_key[i];
+ p.key_len = params->wep_key_len[i];
+ p.key_flag = i == params->wep_tx_keyidx ?
+ KEY_FLAG_GROUP_RX_TX_DEFAULT :
+ KEY_FLAG_GROUP_RX_TX;
+ wpa_driver_nl80211_set_key(bss, &p);
if (params->wep_tx_keyidx != i)
continue;
if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
@@ -3630,80 +3803,27 @@
}
-static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
- const void *data, size_t len,
- int encrypt, int noack,
- unsigned int freq, int no_cck,
- int offchanok, unsigned int wait_time,
- const u16 *csa_offs,
- size_t csa_offs_len)
-{
- struct wpa_driver_nl80211_data *drv = bss->drv;
- u64 cookie;
- int res;
-
- if (freq == 0 && drv->nlmode == NL80211_IFTYPE_ADHOC) {
- freq = nl80211_get_assoc_freq(drv);
- wpa_printf(MSG_DEBUG,
- "nl80211: send_frame - Use assoc_freq=%u for IBSS",
- freq);
- }
- if (freq == 0) {
- wpa_printf(MSG_DEBUG, "nl80211: send_frame - Use bss->freq=%u",
- bss->freq);
- freq = bss->freq;
- }
-
- if (drv->use_monitor) {
- wpa_printf(MSG_DEBUG, "nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor",
- freq, bss->freq);
- return nl80211_send_monitor(drv, data, len, encrypt, noack);
- }
-
- wpa_printf(MSG_DEBUG, "nl80211: send_frame -> send_frame_cmd");
- res = nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
- &cookie, no_cck, noack, offchanok,
- csa_offs, csa_offs_len);
- if (res == 0 && !noack) {
- const struct ieee80211_mgmt *mgmt;
- u16 fc;
-
- mgmt = (const struct ieee80211_mgmt *) data;
- fc = le_to_host16(mgmt->frame_control);
- if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
- WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
- wpa_printf(MSG_MSGDUMP,
- "nl80211: Update send_action_cookie from 0x%llx to 0x%llx",
- (long long unsigned int)
- drv->send_action_cookie,
- (long long unsigned int) cookie);
- drv->send_action_cookie = cookie;
- }
- }
-
- return res;
-}
-
-
static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
size_t data_len, int noack,
unsigned int freq, int no_cck,
int offchanok,
unsigned int wait_time,
const u16 *csa_offs,
- size_t csa_offs_len)
+ size_t csa_offs_len, int no_encrypt)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
struct ieee80211_mgmt *mgmt;
- int encrypt = 1;
+ int encrypt = !no_encrypt;
u16 fc;
+ int use_cookie = 1;
+ int res;
mgmt = (struct ieee80211_mgmt *) data;
fc = le_to_host16(mgmt->frame_control);
- wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da= " MACSTR
- " noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u fc=0x%x (%s) nlmode=%d",
+ wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da=" MACSTR
+ " noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u no_encrypt=%d fc=0x%x (%s) nlmode=%d",
MAC2STR(mgmt->da), noack, freq, no_cck, offchanok, wait_time,
- fc, fc2str(fc), drv->nlmode);
+ no_encrypt, fc, fc2str(fc), drv->nlmode);
if ((is_sta_interface(drv->nlmode) ||
drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
@@ -3719,9 +3839,11 @@
drv->last_mgmt_freq);
freq = drv->last_mgmt_freq;
}
- return nl80211_send_frame_cmd(bss, freq, 0,
- data, data_len, NULL, 1, noack,
- 1, csa_offs, csa_offs_len);
+ wait_time = 0;
+ use_cookie = 0;
+ no_cck = 1;
+ offchanok = 1;
+ goto send_frame_cmd;
}
if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
@@ -3730,13 +3852,9 @@
bss->freq);
freq = bss->freq;
}
- return nl80211_send_frame_cmd(bss, freq,
- (int) freq == bss->freq ? 0 :
- wait_time,
- data, data_len,
- &drv->send_action_cookie,
- no_cck, noack, offchanok,
- csa_offs, csa_offs_len);
+ if ((int) freq == bss->freq)
+ wait_time = 0;
+ goto send_frame_cmd;
}
if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
@@ -3753,11 +3871,60 @@
encrypt = 0;
}
- wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame");
- return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
- noack, freq, no_cck, offchanok,
- wait_time, csa_offs,
- csa_offs_len);
+ if (freq == 0 && drv->nlmode == NL80211_IFTYPE_STATION &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
+ !(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
+ freq = nl80211_get_assoc_freq(drv);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: send_mlme - Use assoc_freq=%u for external auth",
+ freq);
+ }
+
+ if (freq == 0 && drv->nlmode == NL80211_IFTYPE_ADHOC) {
+ freq = nl80211_get_assoc_freq(drv);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: send_mlme - Use assoc_freq=%u for IBSS",
+ freq);
+ }
+ if (freq == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: send_mlme - Use bss->freq=%u",
+ bss->freq);
+ freq = bss->freq;
+ }
+
+ if (drv->use_monitor) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor",
+ freq, bss->freq);
+ return nl80211_send_monitor(drv, data, data_len, encrypt,
+ noack);
+ }
+
+ if (noack || WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
+ WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
+ use_cookie = 0;
+send_frame_cmd:
+#ifdef CONFIG_TESTING_OPTIONS
+ if (no_encrypt && !encrypt && !drv->use_monitor) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Request to send an unencrypted frame - use a monitor interface for this");
+ if (nl80211_create_monitor_interface(drv) < 0)
+ return -1;
+ res = nl80211_send_monitor(drv, data, data_len, encrypt,
+ noack);
+ nl80211_remove_monitor_interface(drv);
+ return res;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame_cmd");
+ res = nl80211_send_frame_cmd(bss, freq, wait_time, data, data_len,
+ use_cookie, no_cck, noack, offchanok,
+ csa_offs, csa_offs_len);
+
+ return res;
}
@@ -4059,8 +4226,7 @@
int ret = -ENOBUFS;
int beacon_set;
int num_suites;
- int smps_mode;
- u32 suites[10], suite;
+ u32 suites[20], suite;
u32 ver;
#ifdef CONFIG_MESH
struct wpa_driver_mesh_bss_params mesh_params;
@@ -4154,14 +4320,15 @@
wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x",
params->key_mgmt_suites);
- num_suites = 0;
- if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X)
- suites[num_suites++] = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
- if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK)
- suites[num_suites++] = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
- if (num_suites &&
- nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32),
- suites))
+ num_suites = wpa_key_mgmt_to_suites(params->key_mgmt_suites,
+ suites, ARRAY_SIZE(suites));
+ if (num_suites > NL80211_MAX_NR_AKM_SUITES)
+ wpa_printf(MSG_WARNING,
+ "nl80211: Not enough room for all AKM suites (num_suites=%d > NL80211_MAX_NR_AKM_SUITES)",
+ num_suites);
+ else if (num_suites &&
+ nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32),
+ suites))
goto fail;
if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
@@ -4171,8 +4338,10 @@
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);
+ if (drv->device_ap_sme &&
+ (params->key_mgmt_suites & WPA_KEY_MGMT_SAE) &&
+ nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
+ goto fail;
wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
params->pairwise_ciphers);
@@ -4190,27 +4359,6 @@
nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite))
goto fail;
- if (params->ht_opmode != -1) {
- switch (params->smps_mode) {
- case HT_CAP_INFO_SMPS_DYNAMIC:
- wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - dynamic");
- smps_mode = NL80211_SMPS_DYNAMIC;
- break;
- case HT_CAP_INFO_SMPS_STATIC:
- wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - static");
- smps_mode = NL80211_SMPS_STATIC;
- break;
- default:
- /* invalid - fallback to smps off */
- case HT_CAP_INFO_SMPS_DISABLED:
- wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - off");
- smps_mode = NL80211_SMPS_OFF;
- break;
- }
- if (nla_put_u8(msg, NL80211_ATTR_SMPS_MODE, smps_mode))
- goto fail;
- }
-
if (params->beacon_ies) {
wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
params->beacon_ies);
@@ -4288,7 +4436,48 @@
nla_nest_end(msg, ftm);
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+#ifdef CONFIG_IEEE80211AX
+ if (params->he_spr) {
+ struct nlattr *spr;
+
+ spr = nla_nest_start(msg, NL80211_ATTR_HE_OBSS_PD);
+ wpa_printf(MSG_DEBUG, "nl80211: he_spr=%d", params->he_spr);
+
+ if (!spr ||
+ nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
+ params->he_spr_srg_obss_pd_min_offset) ||
+ nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET,
+ params->he_spr_srg_obss_pd_max_offset))
+ goto fail;
+
+ nla_nest_end(msg, spr);
+ }
+
+ if (params->freq && params->freq->he_enabled) {
+ struct nlattr *bss_color;
+
+ bss_color = nla_nest_start(msg, NL80211_ATTR_HE_BSS_COLOR);
+ if (!bss_color ||
+ (params->he_bss_color_disabled &&
+ nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_DISABLED)) ||
+ (params->he_bss_color_partial &&
+ nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_PARTIAL)) ||
+ nla_put_u8(msg, NL80211_HE_BSS_COLOR_ATTR_COLOR,
+ params->he_bss_color))
+ goto fail;
+ nla_nest_end(msg, bss_color);
+ }
+
+ if (params->twt_responder) {
+ wpa_printf(MSG_DEBUG, "nl80211: twt_responder=%d",
+ params->twt_responder);
+ if (nla_put_flag(msg, NL80211_ATTR_TWT_RESPONDER))
+ goto fail;
+ }
+#endif /* CONFIG_IEEE80211AX */
+
+ ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 1,
+ NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
ret, strerror(-ret));
@@ -4346,14 +4535,23 @@
static int nl80211_put_freq_params(struct nl_msg *msg,
const struct hostapd_freq_params *freq)
{
+ enum hostapd_hw_mode hw_mode;
+ int is_24ghz;
+ u8 channel;
+
wpa_printf(MSG_DEBUG, " * freq=%d", freq->freq);
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
return -ENOBUFS;
+ wpa_printf(MSG_DEBUG, " * he_enabled=%d", freq->he_enabled);
wpa_printf(MSG_DEBUG, " * vht_enabled=%d", freq->vht_enabled);
wpa_printf(MSG_DEBUG, " * ht_enabled=%d", freq->ht_enabled);
- if (freq->vht_enabled) {
+ hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
+ is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
+ hw_mode == HOSTAPD_MODE_IEEE80211B;
+
+ if (freq->vht_enabled || (freq->he_enabled && !is_24ghz)) {
enum nl80211_chan_width cw;
wpa_printf(MSG_DEBUG, " * bandwidth=%d", freq->bandwidth);
@@ -4409,6 +4607,15 @@
wpa_printf(MSG_DEBUG, " * channel_type=%d", ct);
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
return -ENOBUFS;
+ } else if (freq->edmg.channels && freq->edmg.bw_config) {
+ wpa_printf(MSG_DEBUG,
+ " * EDMG configuration: channels=0x%x bw_config=%d",
+ freq->edmg.channels, freq->edmg.bw_config);
+ if (nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_CHANNELS,
+ freq->edmg.channels) ||
+ nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
+ freq->edmg.bw_config))
+ return -1;
} else {
wpa_printf(MSG_DEBUG, " * channel_type=%d",
NL80211_CHAN_NO_HT);
@@ -4428,8 +4635,8 @@
int ret;
wpa_printf(MSG_DEBUG,
- "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
- freq->freq, freq->ht_enabled, freq->vht_enabled,
+ "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
+ freq->freq, freq->ht_enabled, freq->vht_enabled, freq->he_enabled,
freq->bandwidth, freq->center_freq1, freq->center_freq2);
msg = nl80211_drv_msg(drv, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
@@ -4561,6 +4768,14 @@
goto fail;
}
+ if (params->he_capab) {
+ wpa_hexdump(MSG_DEBUG, " * he_capab",
+ params->he_capab, params->he_capab_len);
+ if (nla_put(msg, NL80211_ATTR_HE_CAPABILITY,
+ params->he_capab_len, params->he_capab))
+ goto fail;
+ }
+
if (params->ext_capab) {
wpa_hexdump(MSG_DEBUG, " * ext_capab",
params->ext_capab, params->ext_capab_len);
@@ -4693,8 +4908,9 @@
goto fail;
#endif /* CONFIG_MESH */
- if ((!params->set || FULL_AP_CLIENT_STATE_SUPP(drv->capa.flags)) &&
- (params->flags & WPA_STA_WMM)) {
+ if ((!params->set || (params->flags & WPA_STA_TDLS_PEER) ||
+ 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);
@@ -5038,6 +5254,40 @@
}
+static int nl80211_tx_control_port(void *priv, const u8 *dest,
+ u16 proto, const u8 *buf, size_t len,
+ int no_encrypt)
+{
+ struct i802_bss *bss = priv;
+ struct nl_msg *msg;
+ int ret;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Send over control port dest=" MACSTR
+ " proto=0x%04x len=%u no_encrypt=%d",
+ MAC2STR(dest), proto, (unsigned int) len, no_encrypt);
+
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CONTROL_PORT_FRAME);
+ if (!msg ||
+ nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, proto) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dest) ||
+ nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
+ (no_encrypt &&
+ nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG,
+ "nl80211: tx_control_port failed: ret=%d (%s)",
+ ret, strerror(-ret));
+
+ return ret;
+}
+
+
static int nl80211_send_eapol_data(struct i802_bss *bss,
const u8 *addr, const u8 *data,
size_t data_len)
@@ -5080,6 +5330,13 @@
int res;
int qos = flags & WPA_STA_WMM;
+ /* For now, disable EAPOL TX over control port in AP mode by default
+ * since it does not provide TX status notifications. */
+ if (drv->control_port_ap &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_CONTROL_PORT))
+ return nl80211_tx_control_port(bss, addr, ETH_P_EAPOL,
+ data, data_len, !encrypt);
+
if (drv->device_ap_sme || !drv->use_monitor)
return nl80211_send_eapol_data(bss, addr, data, data_len);
@@ -5120,12 +5377,11 @@
pos += 2;
memcpy(pos, data, data_len);
- res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0,
- 0, 0, 0, 0, NULL, 0);
+ res = nl80211_send_monitor(drv, hdr, len, encrypt, 0);
if (res < 0) {
- wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
- "failed: %d (%s)",
- (unsigned long) len, errno, strerror(errno));
+ wpa_printf(MSG_ERROR,
+ "hapd_send_eapol - packet len: %lu - failed",
+ (unsigned long) len);
}
os_free(hdr);
@@ -5185,6 +5441,28 @@
}
+static int driver_nl80211_sta_set_airtime_weight(void *priv, const u8 *addr,
+ unsigned int weight)
+{
+ struct i802_bss *bss = priv;
+ struct nl_msg *msg;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Set STA airtime weight - ifname=%s addr=" MACSTR
+ " weight=%u", bss->ifname, MAC2STR(addr), weight);
+
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ nla_put_u16(msg, NL80211_ATTR_AIRTIME_WEIGHT, weight))
+ goto fail;
+
+ return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+fail:
+ nlmsg_free(msg);
+ return -ENOBUFS;
+}
+
+
static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params)
{
@@ -5222,7 +5500,9 @@
int ret;
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_IBSS);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs_owner(drv, msg,
+ get_connect_handle(drv->first_bss), 1,
+ NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
"(%s)", ret, strerror(-ret));
@@ -5354,7 +5634,9 @@
if (ret < 0)
goto fail;
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs_owner(drv, msg,
+ get_connect_handle(drv->first_bss), 1,
+ NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
@@ -5457,6 +5739,18 @@
return -1;
}
+ if (params->freq.edmg.channels && params->freq.edmg.bw_config) {
+ wpa_printf(MSG_DEBUG,
+ " * EDMG configuration: channels=0x%x bw_config=%d",
+ params->freq.edmg.channels,
+ params->freq.edmg.bw_config);
+ if (nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_CHANNELS,
+ params->freq.edmg.channels) ||
+ nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
+ params->freq.edmg.bw_config))
+ return -1;
+ }
+
if (params->bg_scan_period >= 0) {
wpa_printf(MSG_DEBUG, " * bg scan period=%d",
params->bg_scan_period);
@@ -5603,7 +5897,7 @@
return -1;
}
- if (params->req_key_mgmt_offload &&
+ if (params->req_handshake_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))
@@ -5665,7 +5959,8 @@
nl80211_put_fils_connect_params(drv, params, msg) != 0)
return -1;
- if ((params->auth_alg & WPA_AUTH_ALG_SAE) &&
+ if ((params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE) &&
(!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) &&
nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
return -1;
@@ -5677,7 +5972,7 @@
static int wpa_driver_nl80211_try_connect(
struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params,
- struct nl_handle *nl_connect)
+ struct nl_sock *nl_connect)
{
struct nl_msg *msg;
enum nl80211_auth_type type;
@@ -5742,12 +6037,8 @@
if (ret)
goto fail;
- 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);
-
+ ret = send_and_recv_msgs_owner(drv, msg, nl_connect, 1, NULL,
+ (void *) -1);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
@@ -5768,7 +6059,7 @@
static int wpa_driver_nl80211_connect(
struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params,
- struct nl_handle *nl_connect)
+ struct nl_sock *nl_connect)
{
int ret;
@@ -5816,18 +6107,17 @@
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;
- if (params->auth_alg & WPA_AUTH_ALG_SAE) {
- nl_connect = bss->nl_connect;
+ if (params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE)
bss->use_nl_connect = 1;
- } else {
+ else
bss->use_nl_connect = 0;
- }
- return wpa_driver_nl80211_connect(drv, params, nl_connect);
+ return wpa_driver_nl80211_connect(drv, params,
+ get_connect_handle(bss));
}
nl80211_mark_disconnected(drv);
@@ -5862,7 +6152,9 @@
goto fail;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs_owner(drv, msg,
+ get_connect_handle(drv->first_bss), 1,
+ NULL, NULL);
msg = NULL;
if (ret) {
wpa_dbg(drv->ctx, MSG_DEBUG,
@@ -6264,6 +6556,36 @@
}
+static void get_sta_tid_stats(struct hostap_sta_driver_data *data,
+ struct nlattr *attr)
+{
+ struct nlattr *tid_stats[NL80211_TID_STATS_MAX + 1], *tidattr;
+ struct nlattr *txq_stats[NL80211_TXQ_STATS_MAX + 1];
+ static struct nla_policy txq_stats_policy[NL80211_TXQ_STATS_MAX + 1] = {
+ [NL80211_TXQ_STATS_BACKLOG_BYTES] = { .type = NLA_U32 },
+ [NL80211_TXQ_STATS_BACKLOG_PACKETS] = { .type = NLA_U32 },
+ };
+ int rem;
+
+ nla_for_each_nested(tidattr, attr, rem) {
+ if (nla_parse_nested(tid_stats, NL80211_TID_STATS_MAX,
+ tidattr, NULL) != 0 ||
+ !tid_stats[NL80211_TID_STATS_TXQ_STATS] ||
+ nla_parse_nested(txq_stats, NL80211_TXQ_STATS_MAX,
+ tid_stats[NL80211_TID_STATS_TXQ_STATS],
+ txq_stats_policy) != 0)
+ continue;
+ /* sum the backlogs over all TIDs for station */
+ if (txq_stats[NL80211_TXQ_STATS_BACKLOG_BYTES])
+ data->backlog_bytes += nla_get_u32(
+ txq_stats[NL80211_TXQ_STATS_BACKLOG_BYTES]);
+ if (txq_stats[NL80211_TXQ_STATS_BACKLOG_PACKETS])
+ data->backlog_bytes += nla_get_u32(
+ txq_stats[NL80211_TXQ_STATS_BACKLOG_PACKETS]);
+ }
+}
+
+
static int get_sta_handler(struct nl_msg *msg, void *arg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -6281,6 +6603,8 @@
[NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 },
[NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
[NL80211_STA_INFO_ACK_SIGNAL] = { .type = NLA_U8 },
+ [NL80211_STA_INFO_RX_DURATION] = { .type = NLA_U64 },
+ [NL80211_STA_INFO_TX_DURATION] = { .type = NLA_U64 },
};
struct nlattr *rate[NL80211_RATE_INFO_MAX + 1];
static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
@@ -6338,6 +6662,12 @@
if (stats[NL80211_STA_INFO_TX_PACKETS])
data->tx_packets =
nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
+ if (stats[NL80211_STA_INFO_RX_DURATION])
+ data->rx_airtime =
+ nla_get_u64(stats[NL80211_STA_INFO_RX_DURATION]);
+ if (stats[NL80211_STA_INFO_TX_DURATION])
+ data->tx_airtime =
+ nla_get_u64(stats[NL80211_STA_INFO_TX_DURATION]);
if (stats[NL80211_STA_INFO_TX_FAILED])
data->tx_retry_failed =
nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
@@ -6408,6 +6738,9 @@
}
}
+ if (stats[NL80211_STA_INFO_TID_STATS])
+ get_sta_tid_stats(data, stats[NL80211_STA_INFO_TID_STATS]);
+
return NL_SKIP;
}
@@ -6506,6 +6839,8 @@
MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id);
if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ ((drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD) &&
+ nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id)) ||
nla_put_u32(msg, NL80211_ATTR_STA_VLAN, if_nametoindex(ifname))) {
nlmsg_free(msg);
return -ENOBUFS;
@@ -6548,7 +6883,7 @@
static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
- int reason)
+ u16 reason)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -6578,12 +6913,12 @@
return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
IEEE80211_HDRLEN +
sizeof(mgmt.u.deauth), 0, 0, 0, 0,
- 0, NULL, 0);
+ 0, NULL, 0, 0);
}
static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
- int reason)
+ u16 reason)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -6605,7 +6940,7 @@
return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
IEEE80211_HDRLEN +
sizeof(mgmt.u.disassoc), 0, 0, 0, 0,
- 0, NULL, 0);
+ 0, NULL, 0, 0);
}
@@ -6618,11 +6953,11 @@
end = pos + sizeof(buf);
for (i = 0; i < drv->num_if_indices; i++) {
- if (!drv->if_indices[i])
+ if (!drv->if_indices[i].ifindex)
continue;
res = os_snprintf(pos, end - pos, " %d(%d)",
- drv->if_indices[i],
- drv->if_indices_reason[i]);
+ drv->if_indices[i].ifindex,
+ drv->if_indices[i].reason);
if (os_snprintf_error(end - pos, res))
break;
pos += res;
@@ -6638,7 +6973,7 @@
int ifidx_reason)
{
int i;
- int *old, *old_reason;
+ struct drv_nl80211_if_info *old;
wpa_printf(MSG_DEBUG,
"nl80211: Add own interface ifindex %d (ifidx_reason %d)",
@@ -6649,9 +6984,9 @@
return;
}
for (i = 0; i < drv->num_if_indices; i++) {
- if (drv->if_indices[i] == 0) {
- drv->if_indices[i] = ifidx;
- drv->if_indices_reason[i] = ifidx_reason;
+ if (drv->if_indices[i].ifindex == 0) {
+ drv->if_indices[i].ifindex = ifidx;
+ drv->if_indices[i].reason = ifidx_reason;
dump_ifidx(drv);
return;
}
@@ -6662,29 +6997,13 @@
else
old = NULL;
- if (drv->if_indices_reason != drv->default_if_indices_reason)
- old_reason = drv->if_indices_reason;
- else
- old_reason = NULL;
-
drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1,
- sizeof(int));
- drv->if_indices_reason = os_realloc_array(old_reason,
- drv->num_if_indices + 1,
- sizeof(int));
+ sizeof(*old));
if (!drv->if_indices) {
if (!old)
drv->if_indices = drv->default_if_indices;
else
drv->if_indices = old;
- }
- if (!drv->if_indices_reason) {
- if (!old_reason)
- drv->if_indices_reason = drv->default_if_indices_reason;
- else
- drv->if_indices_reason = old_reason;
- }
- if (!drv->if_indices || !drv->if_indices_reason) {
wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
"interfaces");
wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
@@ -6693,12 +7012,8 @@
if (!old)
os_memcpy(drv->if_indices, drv->default_if_indices,
sizeof(drv->default_if_indices));
- if (!old_reason)
- os_memcpy(drv->if_indices_reason,
- drv->default_if_indices_reason,
- sizeof(drv->default_if_indices_reason));
- drv->if_indices[drv->num_if_indices] = ifidx;
- drv->if_indices_reason[drv->num_if_indices] = ifidx_reason;
+ drv->if_indices[drv->num_if_indices].ifindex = ifidx;
+ drv->if_indices[drv->num_if_indices].reason = ifidx_reason;
drv->num_if_indices++;
dump_ifidx(drv);
}
@@ -6710,10 +7025,12 @@
int i;
for (i = 0; i < drv->num_if_indices; i++) {
- if ((drv->if_indices[i] == ifidx || ifidx == IFIDX_ANY) &&
- (drv->if_indices_reason[i] == ifidx_reason ||
+ if ((drv->if_indices[i].ifindex == ifidx ||
+ ifidx == IFIDX_ANY) &&
+ (drv->if_indices[i].reason == ifidx_reason ||
ifidx_reason == IFIDX_ANY)) {
- drv->if_indices[i] = 0;
+ drv->if_indices[i].ifindex = 0;
+ drv->if_indices[i].reason = 0;
break;
}
}
@@ -6727,8 +7044,8 @@
int i;
for (i = 0; i < drv->num_if_indices; i++)
- if (drv->if_indices[i] == ifidx &&
- (drv->if_indices_reason[i] == ifidx_reason ||
+ if (drv->if_indices[i].ifindex == ifidx &&
+ (drv->if_indices[i].reason == ifidx_reason ||
ifidx_reason == IFIDX_ANY))
return 1;
@@ -6871,10 +7188,14 @@
wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
ifname, brname);
if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to add interface %s "
- "into bridge %s: %s",
+ wpa_printf(MSG_WARNING,
+ "nl80211: Failed to add interface %s into bridge %s: %s",
ifname, brname, strerror(errno));
- return -1;
+ /* Try to continue without the interface being in a bridge. This
+ * may be needed for some cases, e.g., with Open vSwitch, where
+ * an external component will need to handle bridge
+ * configuration. */
+ return 0;
}
bss->added_if_into_bridge = 1;
@@ -6952,20 +7273,29 @@
#ifdef CONFIG_LIBNL3_ROUTE
if (bss->added_if_into_bridge || bss->already_in_bridge) {
+ int err;
+
drv->rtnl_sk = nl_socket_alloc();
if (drv->rtnl_sk == NULL) {
wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock");
goto failed;
}
- if (nl_connect(drv->rtnl_sk, NETLINK_ROUTE)) {
+ err = nl_connect(drv->rtnl_sk, NETLINK_ROUTE);
+ if (err) {
wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s",
- strerror(errno));
+ nl_geterror(err));
goto failed;
}
}
#endif /* CONFIG_LIBNL3_ROUTE */
+ if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Do not open EAPOL RX socket - using control port for RX");
+ goto skip_eapol_sock;
+ }
+
drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
if (drv->eapol_sock < 0) {
wpa_printf(MSG_ERROR, "nl80211: socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE) failed: %s",
@@ -6978,6 +7308,7 @@
wpa_printf(MSG_INFO, "nl80211: Could not register read socket for eapol");
goto failed;
}
+skip_eapol_sock:
if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
params->own_addr))
@@ -7334,7 +7665,7 @@
static int nl80211_send_frame_cmd(struct i802_bss *bss,
unsigned int freq, unsigned int wait,
const u8 *buf, size_t buf_len,
- u64 *cookie_out, int no_cck, int no_ack,
+ int save_cookie, int no_cck, int no_ack,
int offchanok, const u16 *csa_offs,
size_t csa_offs_len)
{
@@ -7373,22 +7704,22 @@
"cookie 0x%llx", no_ack ? " (no ACK)" : "",
(long long unsigned int) cookie);
- if (cookie_out)
- *cookie_out = no_ack ? (u64) -1 : cookie;
+ if (save_cookie)
+ drv->send_frame_cookie = no_ack ? (u64) -1 : cookie;
- if (drv->num_send_action_cookies == MAX_SEND_ACTION_COOKIES) {
+ if (drv->num_send_frame_cookies == MAX_SEND_FRAME_COOKIES) {
wpa_printf(MSG_DEBUG,
- "nl80211: Drop oldest pending send action cookie 0x%llx",
+ "nl80211: Drop oldest pending send frame cookie 0x%llx",
(long long unsigned int)
- drv->send_action_cookies[0]);
- os_memmove(&drv->send_action_cookies[0],
- &drv->send_action_cookies[1],
- (MAX_SEND_ACTION_COOKIES - 1) *
+ drv->send_frame_cookies[0]);
+ os_memmove(&drv->send_frame_cookies[0],
+ &drv->send_frame_cookies[1],
+ (MAX_SEND_FRAME_COOKIES - 1) *
sizeof(u64));
- drv->num_send_action_cookies--;
+ drv->num_send_frame_cookies--;
}
- drv->send_action_cookies[drv->num_send_action_cookies] = cookie;
- drv->num_send_action_cookies++;
+ drv->send_frame_cookies[drv->num_send_frame_cookies] = cookie;
+ drv->num_send_frame_cookies++;
}
fail:
@@ -7409,10 +7740,14 @@
int ret = -1;
u8 *buf;
struct ieee80211_hdr *hdr;
+ int offchanok = 1;
+
+ if (is_ap_interface(drv->nlmode) && (int) freq == bss->freq)
+ offchanok = 0;
wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
- "freq=%u MHz wait=%d ms no_cck=%d)",
- drv->ifindex, freq, wait_time, no_cck);
+ "freq=%u MHz wait=%d ms no_cck=%d offchanok=%d)",
+ drv->ifindex, freq, wait_time, no_cck, offchanok);
buf = os_zalloc(24 + data_len);
if (buf == NULL)
@@ -7438,13 +7773,12 @@
(int) freq == bss->freq || drv->device_ap_sme ||
!drv->use_monitor))
ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
- 0, freq, no_cck, 1,
- wait_time, NULL, 0);
+ 0, freq, no_cck, offchanok,
+ wait_time, NULL, 0, 0);
else
ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
24 + data_len,
- &drv->send_action_cookie,
- no_cck, 0, 1, NULL, 0);
+ 1, no_cck, 0, offchanok, NULL, 0);
os_free(buf);
return ret;
@@ -7480,19 +7814,19 @@
u64 cookie;
/* Cancel the last pending TX cookie */
- nl80211_frame_wait_cancel(bss, drv->send_action_cookie);
+ nl80211_frame_wait_cancel(bss, drv->send_frame_cookie);
/*
* Cancel the other pending TX cookies, if any. This is needed since
* the driver may keep a list of all pending offchannel TX operations
* and free up the radio only once they have expired or cancelled.
*/
- for (i = drv->num_send_action_cookies; i > 0; i--) {
- cookie = drv->send_action_cookies[i - 1];
- if (cookie != drv->send_action_cookie)
+ for (i = drv->num_send_frame_cookies; i > 0; i--) {
+ cookie = drv->send_frame_cookies[i - 1];
+ if (cookie != drv->send_frame_cookie)
nl80211_frame_wait_cancel(bss, cookie);
}
- drv->num_send_action_cookies = 0;
+ drv->num_send_frame_cookies = 0;
}
@@ -7600,7 +7934,7 @@
if (nl80211_register_frame(bss, bss->nl_preq,
(WLAN_FC_TYPE_MGMT << 2) |
(WLAN_FC_STYPE_PROBE_REQ << 4),
- NULL, 0) < 0)
+ NULL, 0, false) < 0)
goto out_err;
nl80211_register_eloop_read(&bss->nl_preq,
@@ -7812,15 +8146,6 @@
}
-static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
- int encrypt)
-{
- struct i802_bss *bss = priv;
- return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0,
- 0, 0, 0, 0, NULL, 0);
-}
-
-
static int nl80211_set_param(void *priv, const char *param)
{
struct i802_bss *bss = priv;
@@ -7855,6 +8180,17 @@
drv->test_use_roc_tx = 1;
}
+ if (os_strstr(param, "control_port=0")) {
+ drv->capa.flags &= ~WPA_DRIVER_FLAGS_CONTROL_PORT;
+ drv->capa.flags2 &= ~WPA_DRIVER_FLAGS2_CONTROL_PORT_RX;
+ }
+
+ if (os_strstr(param, "control_port_ap=1"))
+ drv->control_port_ap = 1;
+
+ if (os_strstr(param, "full_ap_client_state=0"))
+ drv->capa.flags &= ~WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE;
+
return 0;
}
@@ -7955,6 +8291,12 @@
(params->fils_cache_id &&
nla_put(msg, NL80211_ATTR_FILS_CACHE_ID, 2,
params->fils_cache_id)) ||
+ (params->pmk_lifetime &&
+ nla_put_u32(msg, NL80211_ATTR_PMK_LIFETIME,
+ params->pmk_lifetime)) ||
+ (params->pmk_reauth_threshold &&
+ nla_put_u8(msg, NL80211_ATTR_PMK_REAUTH_THRESHOLD,
+ params->pmk_reauth_threshold)) ||
(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))) {
@@ -8275,7 +8617,7 @@
os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0,
- 0, 0, NULL, 0) < 0)
+ 0, 0, NULL, 0, 0) < 0)
wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
"send poll frame");
}
@@ -8370,8 +8712,8 @@
struct nl_msg *msg;
int ret;
- wpa_printf(MSG_DEBUG, "nl80211: Start radar detection (CAC) %d MHz (ht_enabled=%d, vht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
- freq->freq, freq->ht_enabled, freq->vht_enabled,
+ wpa_printf(MSG_DEBUG, "nl80211: Start radar detection (CAC) %d MHz (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
+ freq->freq, freq->ht_enabled, freq->vht_enabled, freq->he_enabled,
freq->bandwidth, freq->center_freq1, freq->center_freq2);
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_RADAR)) {
@@ -8549,15 +8891,12 @@
#endif /* CONFIG TDLS */
-static int driver_nl80211_set_key(const char *ifname, void *priv,
- 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)
+static int driver_nl80211_set_key(void *priv,
+ struct wpa_driver_set_key_params *params)
{
struct i802_bss *bss = priv;
- return wpa_driver_nl80211_set_key(ifname, bss, alg, addr, key_idx,
- set_tx, seq, seq_len, key, key_len);
+
+ return wpa_driver_nl80211_set_key(bss, params);
}
@@ -8583,7 +8922,7 @@
static int driver_nl80211_deauthenticate(void *priv, const u8 *addr,
- int reason_code)
+ u16 reason_code)
{
struct i802_bss *bss = priv;
return wpa_driver_nl80211_deauthenticate(bss, addr, reason_code);
@@ -8616,12 +8955,13 @@
static int driver_nl80211_send_mlme(void *priv, const u8 *data,
size_t data_len, int noack,
unsigned int freq,
- const u16 *csa_offs, size_t csa_offs_len)
+ const u16 *csa_offs, size_t csa_offs_len,
+ int no_encrypt, unsigned int wait)
{
struct i802_bss *bss = priv;
return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
- freq, 0, 0, 0, csa_offs,
- csa_offs_len);
+ freq, 0, 0, wait, csa_offs,
+ csa_offs_len, no_encrypt);
}
@@ -8698,6 +9038,35 @@
}
+static int nl80211_update_dh_ie(void *priv, const u8 *peer_mac,
+ u16 reason_code, const u8 *ie, size_t ie_len)
+{
+ int ret;
+ struct nl_msg *msg;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Updating DH IE peer: " MACSTR
+ " reason %u", MAC2STR(peer_mac), reason_code);
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UPDATE_OWE_INFO)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer_mac) ||
+ nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, reason_code) ||
+ (ie && nla_put(msg, NL80211_ATTR_IE, ie_len, ie))) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: update_dh_ie failed err=%d (%s)",
+ ret, strerror(-ret));
+ }
+
+ return ret;
+}
+
+
static const u8 * wpa_driver_nl80211_get_macaddr(void *priv)
{
struct i802_bss *bss = priv;
@@ -9191,7 +9560,12 @@
if (nlmsg_append(msg, (void *) data, data_len, NLMSG_ALIGNTO) <
0)
goto fail;
- ret = send_and_recv_msgs(drv, msg, cmd_reply_handler, buf);
+ /* This test vendor_cmd can be used with nl80211 commands that
+ * need the connect nl_sock, so use the owner-setting variant
+ * of send_and_recv_msgs(). */
+ ret = send_and_recv_msgs_owner(drv, msg,
+ get_connect_handle(bss), 0,
+ cmd_reply_handler, buf);
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: command failed err=%d",
ret);
@@ -9243,6 +9617,46 @@
}
+static int get_wowlan_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ int *wowlan_enabled = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ *wowlan_enabled = !!tb[NL80211_ATTR_WOWLAN_TRIGGERS];
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_get_wowlan(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int wowlan_enabled;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status");
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_WOWLAN);
+
+ ret = send_and_recv_msgs(drv, msg, get_wowlan_handler, &wowlan_enabled);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status failed");
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: wowlan is %s",
+ wowlan_enabled ? "enabled" : "disabled");
+
+ return wowlan_enabled;
+}
+
+
static int nl80211_set_wowlan(void *priv,
const struct wowlan_triggers *triggers)
{
@@ -9372,7 +9786,7 @@
QCA_NL80211_VENDOR_SUBCMD_ROAM) ||
!(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD,
- QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID) ||
+ QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID) ||
nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID,
WPA_SUPPLICANT_CLIENT_ID) ||
nla_put_u32(msg,
@@ -9407,6 +9821,40 @@
return -1;
}
+
+static int nl80211_add_sta_node(void *priv, const u8 *addr, u16 auth_alg)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *params;
+
+ if (!drv->add_sta_node_vendor_cmd_avail)
+ return -EOPNOTSUPP;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Add STA node");
+
+ 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_ADD_STA_NODE) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ (addr &&
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_MAC_ADDR, ETH_ALEN,
+ addr)) ||
+ nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_AUTH_ALGO,
+ auth_alg)) {
+ nlmsg_free(msg);
+ wpa_printf(MSG_ERROR,
+ "%s: err in adding vendor_cmd and vendor_data",
+ __func__);
+ return -1;
+ }
+ nla_nest_end(msg, params);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
+
#endif /* CONFIG_DRIVER_NL80211_QCA */
@@ -9572,7 +10020,8 @@
if (nl80211_put_mesh_config(msg, ¶ms->conf) < 0)
goto fail;
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 1,
+ NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d (%s)",
@@ -9629,7 +10078,8 @@
wpa_printf(MSG_DEBUG, "nl80211: mesh leave (ifindex=%d)", drv->ifindex);
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_MESH);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 0,
+ NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d (%s)",
ret, strerror(-ret));
@@ -9646,6 +10096,36 @@
return ret;
}
+
+static int nl80211_probe_mesh_link(void *priv, const u8 *addr, const u8 *eth,
+ size_t len)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_PROBE_MESH_LINK);
+ if (!msg ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ nla_put(msg, NL80211_ATTR_FRAME, len, eth)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: mesh link probe to " MACSTR
+ " failed: ret=%d (%s)",
+ MAC2STR(addr), ret, strerror(-ret));
+ } else {
+ wpa_printf(MSG_DEBUG, "nl80211: Mesh link to " MACSTR
+ " probed successfully", MAC2STR(addr));
+ }
+
+ return ret;
+}
+
#endif /* CONFIG_MESH */
@@ -9722,7 +10202,7 @@
if (res) {
wpa_printf(MSG_DEBUG,
"nl80211: Adding bridge ip neigh failed: %s",
- strerror(errno));
+ nl_geterror(res));
}
errout:
if (nl_lladdr)
@@ -9798,7 +10278,7 @@
if (res) {
wpa_printf(MSG_DEBUG,
"nl80211: Deleting bridge ip neigh failed: %s",
- strerror(errno));
+ nl_geterror(res));
}
errout:
if (nl_ipaddr)
@@ -9942,6 +10422,48 @@
}
+static int add_acs_ch_list(struct nl_msg *msg, const int *freq_list)
+{
+ int num_channels = 0, num_freqs;
+ u8 *ch_list;
+ enum hostapd_hw_mode hw_mode;
+ int ret = 0;
+ int i;
+
+ if (!freq_list)
+ return 0;
+
+ num_freqs = int_array_len(freq_list);
+ ch_list = os_malloc(sizeof(u8) * num_freqs);
+ if (!ch_list)
+ return -1;
+
+ for (i = 0; i < num_freqs; i++) {
+ const int freq = freq_list[i];
+
+ if (freq == 0)
+ break;
+ /* Send 2.4 GHz and 5 GHz channels with
+ * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST to maintain backwards
+ * compatibility.
+ */
+ if (!(freq >= 2412 && freq <= 2484) &&
+ !(freq >= 5180 && freq <= 5900))
+ continue;
+ hw_mode = ieee80211_freq_to_chan(freq, &ch_list[num_channels]);
+ if (hw_mode != NUM_HOSTAPD_MODES)
+ num_channels++;
+ }
+
+ if (num_channels)
+ ret = nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST,
+ num_channels, ch_list);
+
+ os_free(ch_list);
+ return ret;
+}
+
+
static int add_acs_freq_list(struct nl_msg *msg, const int *freq_list)
{
int i, len, ret;
@@ -9989,25 +10511,25 @@
nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED)) ||
nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
params->ch_width) ||
- (params->ch_list_len &&
- nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST, params->ch_list_len,
- params->ch_list)) ||
- add_acs_freq_list(msg, params->freq_list)) {
+ add_acs_ch_list(msg, params->freq_list) ||
+ add_acs_freq_list(msg, params->freq_list) ||
+ (params->edmg_enabled &&
+ nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED))) {
nlmsg_free(msg);
return -ENOBUFS;
}
nla_nest_end(msg, data);
wpa_printf(MSG_DEBUG,
- "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d CH_LIST_LEN: %u",
+ "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d EDMG: %d",
params->hw_mode, params->ht_enabled, params->ht40_enabled,
- params->vht_enabled, params->ch_width, params->ch_list_len);
+ params->vht_enabled, params->ch_width, params->edmg_enabled);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG,
"nl80211: Failed to invoke driver ACS function: %s",
- strerror(errno));
+ strerror(-ret));
}
return ret;
}
@@ -10054,7 +10576,7 @@
if (ret) {
wpa_printf(MSG_DEBUG,
"nl80211: Driver setband function failed: %s",
- strerror(errno));
+ strerror(-ret));
}
return ret;
}
@@ -10634,22 +11156,37 @@
{
int fd, len;
char tmp[128];
+ int ret = 0;
fd = open(name, O_RDWR);
if (fd < 0) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to open %s: %s",
+ int level;
+ /*
+ * Flags may not exist on older kernels, or while we're tearing
+ * down a disappearing device.
+ */
+ if (errno == ENOENT) {
+ ret = 0;
+ level = MSG_DEBUG;
+ } else {
+ ret = -1;
+ level = MSG_ERROR;
+ }
+ wpa_printf(level, "nl80211: Failed to open %s: %s",
name, strerror(errno));
- return fd;
+ return ret;
}
len = os_snprintf(tmp, sizeof(tmp), "%u\n", val);
len = write(fd, tmp, len);
- if (len < 0)
+ if (len < 0) {
+ ret = -1;
wpa_printf(MSG_ERROR, "nl80211: Failed to write to %s: %s",
name, strerror(errno));
+ }
close(fd);
- return 0;
+ return ret;
}
@@ -10764,6 +11301,14 @@
int ret = -1;
enum nl80211_auth_type type;
+ /* Update Connection Params is intended for drivers that implement
+ * internal SME and expect these updated connection params from
+ * wpa_supplicant. Do not send this request for the drivers using
+ * SME from wpa_supplicant.
+ */
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME)
+ return 0;
+
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_CONNECT_PARAMS);
if (!msg)
goto fail;
@@ -10813,11 +11358,11 @@
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
+ * internal SME but want to offload authentication processing (e.g.,
+ * SAE) to hostapd/wpa_supplicant. Do not send the status to drivers
* which do not support AP SME or use wpa_supplicant/hostapd SME.
*/
- if (!bss->drv->device_ap_sme ||
+ if ((is_ap_interface(drv->nlmode) && !bss->drv->device_ap_sme) ||
(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
return -1;
@@ -10891,6 +11436,28 @@
}
+#ifdef CONFIG_DPP
+static int nl80211_dpp_listen(void *priv, bool enable)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
+ struct nl_sock *handle;
+
+ if (!drv->multicast_registrations || !bss->nl_mgmt)
+ return 0; /* cannot do more than hope broadcast RX works */
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Update DPP Public Action frame registration (%s multicast RX)",
+ enable ? "enable" : "disable");
+ handle = (void *) (((intptr_t) bss->nl_mgmt) ^ ELOOP_SOCKET_INVALID);
+ return nl80211_register_frame(bss, handle, type,
+ (u8 *) "\x04\x09\x50\x6f\x9a\x1a", 6,
+ enable);
+}
+#endif /* CONFIG_DPP */
+
+
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
@@ -10922,8 +11489,10 @@
.get_hw_feature_data = nl80211_get_hw_feature_data,
.sta_add = wpa_driver_nl80211_sta_add,
.sta_remove = driver_nl80211_sta_remove,
+ .tx_control_port = nl80211_tx_control_port,
.hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
.sta_set_flags = wpa_driver_nl80211_sta_set_flags,
+ .sta_set_airtime_weight = driver_nl80211_sta_set_airtime_weight,
.hapd_init = i802_init,
.hapd_deinit = i802_deinit,
.set_wds_sta = i802_set_wds_sta,
@@ -10951,7 +11520,6 @@
.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,
.add_pmkid = nl80211_add_pmkid,
@@ -10969,6 +11537,7 @@
.tdls_disable_channel_switch = nl80211_tdls_disable_channel_switch,
#endif /* CONFIG_TDLS */
.update_ft_ies = wpa_driver_nl80211_update_ft_ies,
+ .update_dh_ie = nl80211_update_dh_ie,
.get_mac_addr = wpa_driver_nl80211_get_macaddr,
.get_survey = wpa_driver_nl80211_get_survey,
.status = wpa_driver_nl80211_status,
@@ -10985,12 +11554,14 @@
#endif /* ANDROID */
.vendor_cmd = nl80211_vendor_cmd,
.set_qos_map = nl80211_set_qos_map,
+ .get_wowlan = nl80211_get_wowlan,
.set_wowlan = nl80211_set_wowlan,
.set_mac_addr = nl80211_set_mac_addr,
#ifdef CONFIG_MESH
.init_mesh = wpa_driver_nl80211_init_mesh,
.join_mesh = wpa_driver_nl80211_join_mesh,
.leave_mesh = wpa_driver_nl80211_leave_mesh,
+ .probe_mesh_link = nl80211_probe_mesh_link,
#endif /* CONFIG_MESH */
.br_add_ip_neigh = wpa_driver_br_add_ip_neigh,
.br_delete_ip_neigh = wpa_driver_br_delete_ip_neigh,
@@ -11015,10 +11586,14 @@
.ignore_assoc_disallow = nl80211_ignore_assoc_disallow,
#endif /* CONFIG_MBO */
.set_bssid_blacklist = nl80211_set_bssid_blacklist,
+ .add_sta_node = nl80211_add_sta_node,
#endif /* CONFIG_DRIVER_NL80211_QCA */
.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,
+#ifdef CONFIG_DPP
+ .dpp_listen = nl80211_dpp_listen,
+#endif /* CONFIG_DPP */
};
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 1e7fe7a..dc80a17 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -17,12 +17,10 @@
#include "utils/list.h"
#include "driver.h"
-#ifdef CONFIG_LIBNL20
-/* libnl 2.0 compatibility code */
-#define nl_handle nl_sock
-#define nl80211_handle_alloc nl_socket_alloc_cb
-#define nl80211_handle_destroy nl_socket_free
-#endif /* CONFIG_LIBNL20 */
+#ifndef NL_CAPABILITY_VERSION_3_5_0
+#define nla_nest_start(msg, attrtype) \
+ nla_nest_start(msg, NLA_F_NESTED | (attrtype))
+#endif
struct nl80211_global {
void *ctx;
@@ -32,11 +30,11 @@
int if_add_wdevid_set;
struct netlink_data *netlink;
struct nl_cb *nl_cb;
- struct nl_handle *nl;
+ struct nl_sock *nl;
int nl80211_id;
int ioctl_sock; /* socket for ioctl() use */
- struct nl_handle *nl_event;
+ struct nl_sock *nl_event;
};
struct nl80211_wiphy_data {
@@ -44,7 +42,7 @@
struct dl_list bsss;
struct dl_list drvs;
- struct nl_handle *nl_beacons;
+ struct nl_sock *nl_beacons;
struct nl_cb *nl_cb;
int wiphy_idx;
@@ -75,7 +73,7 @@
int if_dynamic;
void *ctx;
- struct nl_handle *nl_preq, *nl_mgmt, *nl_connect;
+ struct nl_sock *nl_preq, *nl_mgmt, *nl_connect;
struct nl_cb *nl_cb;
struct nl80211_wiphy_data *wiphy_data;
@@ -83,6 +81,12 @@
u8 rand_addr[ETH_ALEN];
};
+struct drv_nl80211_if_info {
+ int ifindex;
+ /* the AP/AP_VLAN iface that is in this bridge */
+ int reason;
+};
+
struct wpa_driver_nl80211_data {
struct nl80211_global *global;
struct dl_list list;
@@ -163,17 +167,19 @@
unsigned int scan_vendor_cmd_avail:1;
unsigned int connect_reassoc:1;
unsigned int set_wifi_conf_vendor_cmd_avail:1;
- 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;
+ unsigned int add_sta_node_vendor_cmd_avail:1;
+ unsigned int control_port_ap:1;
+ unsigned int multicast_registrations:1;
u64 vendor_scan_cookie;
u64 remain_on_chan_cookie;
- u64 send_action_cookie;
-#define MAX_SEND_ACTION_COOKIES 20
- u64 send_action_cookies[MAX_SEND_ACTION_COOKIES];
- unsigned int num_send_action_cookies;
+ u64 send_frame_cookie;
+#define MAX_SEND_FRAME_COOKIES 20
+ u64 send_frame_cookies[MAX_SEND_FRAME_COOKIES];
+ unsigned int num_send_frame_cookies;
unsigned int last_mgmt_freq;
@@ -186,13 +192,10 @@
int eapol_sock; /* socket for EAPOL frames */
- struct nl_handle *rtnl_sk; /* nl_sock for NETLINK_ROUTE */
+ struct nl_sock *rtnl_sk; /* nl_sock for NETLINK_ROUTE */
- int default_if_indices[16];
- /* the AP/AP_VLAN iface that is in this bridge */
- int default_if_indices_reason[16];
- int *if_indices;
- int *if_indices_reason;
+ struct drv_nl80211_if_info default_if_indices[16];
+ struct drv_nl80211_if_info *if_indices;
int num_if_indices;
/* From failed authentication command */
@@ -215,8 +218,6 @@
* (NL80211_CMD_VENDOR). 0 if no pending scan request.
*/
int last_scan_cmd;
-
- struct he_capabilities he_capab;
};
struct nl_msg;
@@ -230,6 +231,7 @@
int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg,
int (*valid_handler)(struct nl_msg *, void *),
void *valid_data);
+struct nl_sock * get_connect_handle(struct i802_bss *bss);
int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
const char *ifname, enum nl80211_iftype iftype,
const u8 *addr, int wds,
@@ -255,7 +257,7 @@
int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
const u8 *addr, int cmd, u16 reason_code,
int local_state_change,
- struct nl_handle *nl_connect);
+ struct nl_sock *nl_connect);
int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv);
void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv);
@@ -274,7 +276,7 @@
const char * nl80211_iftype_str(enum nl80211_iftype mode);
#ifdef ANDROID
-int android_nl_socket_set_nonblocking(struct nl_handle *handle);
+int android_nl_socket_set_nonblocking(struct nl_sock *handle);
int android_pno_start(struct i802_bss *bss,
struct wpa_driver_scan_params *params);
int android_pno_stop(struct i802_bss *bss);
diff --git a/src/drivers/driver_nl80211_android.c b/src/drivers/driver_nl80211_android.c
index ba47888..9431a12 100644
--- a/src/drivers/driver_nl80211_android.c
+++ b/src/drivers/driver_nl80211_android.c
@@ -182,9 +182,7 @@
#endif /* ANDROID_P2P */
-int android_nl_socket_set_nonblocking(struct nl_handle *handle)
+int android_nl_socket_set_nonblocking(struct nl_sock *handle)
{
return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK);
}
-
-
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 37eeb5e..f997577 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -78,6 +78,7 @@
unsigned int wmm_ac_supported:1;
unsigned int mac_addr_rand_scan_supported:1;
unsigned int mac_addr_rand_sched_scan_supported:1;
+ unsigned int update_ft_ies_supported:1;
};
@@ -243,6 +244,9 @@
case NL80211_CMD_SET_QOS_MAP:
info->set_qos_map_supported = 1;
break;
+ case NL80211_CMD_UPDATE_FT_IES:
+ info->update_ft_ies_supported = 1;
+ break;
}
}
}
@@ -433,6 +437,33 @@
if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER))
capa->flags |= WPA_DRIVER_FLAGS_FTM_RESPONDER;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211))
+ capa->flags |= WPA_DRIVER_FLAGS_CONTROL_PORT;
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH))
+ capa->flags2 |= WPA_DRIVER_FLAGS2_CONTROL_PORT_RX;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_VLAN_OFFLOAD))
+ capa->flags |= WPA_DRIVER_FLAGS_VLAN_OFFLOAD;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_CAN_REPLACE_PTK0))
+ capa->flags |= WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_BEACON_PROTECTION))
+ capa->flags |= WPA_DRIVER_FLAGS_BEACON_PROTECTION;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_EXT_KEY_ID))
+ capa->flags |= WPA_DRIVER_FLAGS_EXTENDED_KEY_ID;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS))
+ info->drv->multicast_registrations = 1;
}
@@ -479,12 +510,6 @@
if (flags & NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR)
info->mac_addr_rand_sched_scan_supported = 1;
- if (flags & NL80211_FEATURE_STATIC_SMPS)
- capa->smps_modes |= WPA_DRIVER_SMPS_MODE_STATIC;
-
- if (flags & NL80211_FEATURE_DYNAMIC_SMPS)
- capa->smps_modes |= WPA_DRIVER_SMPS_MODE_DYNAMIC;
-
if (flags & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
info->wmm_ac_supported = 1;
@@ -778,9 +803,6 @@
case QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION:
drv->set_wifi_conf_vendor_cmd_avail = 1;
break;
- case QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES:
- drv->he_capab_vendor_cmd_avail = 1;
- break;
case QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS:
drv->fetch_bss_trans_status = 1;
break;
@@ -790,6 +812,9 @@
case QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS:
drv->get_supported_akm_suites_avail = 1;
break;
+ case QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE:
+ drv->add_sta_node_vendor_cmd_avail = 1;
+ break;
#endif /* CONFIG_DRIVER_NL80211_QCA */
}
}
@@ -904,6 +929,9 @@
drv->capa.max_sched_scan_plan_iterations = 0;
}
+ if (info->update_ft_ies_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_UPDATE_FT_IES;
+
return 0;
}
@@ -1082,100 +1110,6 @@
}
-static int qca_nl80211_he_capab_handler(struct nl_msg *msg, void *arg)
-{
- struct nlattr *tb[NL80211_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct he_capabilities *he_capab = arg;
- struct nlattr *nl_vend;
- struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX + 1];
- size_t len;
-
- nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
-
- if (!tb[NL80211_ATTR_VENDOR_DATA])
- return NL_SKIP;
-
- nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
- nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX,
- nla_data(nl_vend), nla_len(nl_vend), NULL);
-
- if (tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED]) {
- u8 he_supported;
-
- he_supported = nla_get_u8(
- tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED]);
- wpa_printf(MSG_DEBUG, "nl80211: HE capabilities supported: %u",
- he_supported);
- he_capab->he_supported = he_supported;
- if (!he_supported)
- return NL_SKIP;
- }
-
- if (tb_vendor[QCA_WLAN_VENDOR_ATTR_PHY_CAPAB]) {
- len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_PHY_CAPAB]);
-
- if (len > sizeof(he_capab->phy_cap))
- len = sizeof(he_capab->phy_cap);
- os_memcpy(he_capab->phy_cap,
- nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_PHY_CAPAB]),
- len);
- }
-
- if (tb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_CAPAB])
- he_capab->mac_cap =
- nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_CAPAB]);
-
- if (tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_MCS])
- he_capab->mcs =
- nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_MCS]);
-
- if (tb_vendor[QCA_WLAN_VENDOR_ATTR_NUM_SS])
- he_capab->ppet.numss_m1 =
- nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_NUM_SS]);
-
- if (tb_vendor[QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK])
- he_capab->ppet.ru_count =
- nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK]);
-
- if (tb_vendor[QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD]) {
- len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD]);
-
- if (len > sizeof(he_capab->ppet.ppet16_ppet8_ru3_ru0))
- len = sizeof(he_capab->ppet.ppet16_ppet8_ru3_ru0);
- os_memcpy(he_capab->ppet.ppet16_ppet8_ru3_ru0,
- nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD]),
- len);
- }
-
- return NL_SKIP;
-}
-
-
-static void qca_nl80211_check_he_capab(struct wpa_driver_nl80211_data *drv)
-{
- struct nl_msg *msg;
- int ret;
-
- if (!drv->he_capab_vendor_cmd_avail)
- return;
-
- 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_HE_CAPABILITIES)) {
- nlmsg_free(msg);
- return;
- }
-
- ret = send_and_recv_msgs(drv, msg, qca_nl80211_he_capab_handler,
- &drv->he_capab);
- if (!ret && drv->he_capab.he_supported)
- drv->capa.flags |= WPA_DRIVER_FLAGS_HE_CAPABILITIES;
-}
-
-
struct features_info {
u8 *flags;
size_t flags_len;
@@ -1299,10 +1233,13 @@
WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK |
WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B |
- WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192 |
WPA_DRIVER_CAPA_KEY_MGMT_OWE |
WPA_DRIVER_CAPA_KEY_MGMT_DPP;
+ if (drv->capa.enc & (WPA_DRIVER_CAPA_ENC_CCMP_256 |
+ WPA_DRIVER_CAPA_ENC_GCMP_256))
+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192;
+
if (drv->capa.flags & WPA_DRIVER_FLAGS_SME)
drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256 |
WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384 |
@@ -1373,7 +1310,6 @@
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);
/*
* To enable offchannel simultaneous support in wpa_supplicant, the
@@ -1386,6 +1322,12 @@
drv->capa.flags &= ~WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS;
#endif /* CONFIG_DRIVER_NL80211_QCA */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: key_mgmt=0x%x enc=0x%x auth=0x%x flags=0x%llx rrm_flags=0x%x probe_resp_offloads=0x%x max_stations=%u max_remain_on_chan=%u max_scan_ssids=%d",
+ drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth,
+ (unsigned long long) drv->capa.flags, drv->capa.rrm_flags,
+ drv->capa.probe_resp_offloads, drv->capa.max_stations,
+ drv->capa.max_remain_on_chan, drv->capa.max_scan_ssids);
return 0;
}
@@ -1435,17 +1377,54 @@
}
+static int phy_info_edmg_capa(struct hostapd_hw_modes *mode,
+ struct nlattr *bw_config,
+ struct nlattr *channels)
+{
+ if (!bw_config || !channels)
+ return NL_OK;
+
+ mode->edmg.bw_config = nla_get_u8(bw_config);
+ mode->edmg.channels = nla_get_u8(channels);
+
+ if (!mode->edmg.channels || !mode->edmg.bw_config)
+ return NL_STOP;
+
+ return NL_OK;
+}
+
+
+static int cw2ecw(unsigned int cw)
+{
+ int bit;
+
+ if (cw == 0)
+ return 0;
+
+ for (bit = 1; cw != 1; bit++)
+ cw >>= 1;
+
+ return bit;
+}
+
+
static void phy_info_freq(struct hostapd_hw_modes *mode,
struct hostapd_channel_data *chan,
struct nlattr *tb_freq[])
{
u8 channel;
+
+ os_memset(chan, 0, sizeof(*chan));
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;
+ else
+ wpa_printf(MSG_DEBUG,
+ "nl80211: No channel number found for frequency %u MHz",
+ chan->freq);
if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
chan->flag |= HOSTAPD_CHAN_DISABLED;
@@ -1492,6 +1471,66 @@
chan->dfs_cac_ms = nla_get_u32(
tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]);
}
+
+ chan->wmm_rules_valid = 0;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_WMM]) {
+ static struct nla_policy wmm_policy[NL80211_WMMR_MAX + 1] = {
+ [NL80211_WMMR_CW_MIN] = { .type = NLA_U16 },
+ [NL80211_WMMR_CW_MAX] = { .type = NLA_U16 },
+ [NL80211_WMMR_AIFSN] = { .type = NLA_U8 },
+ [NL80211_WMMR_TXOP] = { .type = NLA_U16 },
+ };
+ static const u8 wmm_map[4] = {
+ [NL80211_AC_BE] = WMM_AC_BE,
+ [NL80211_AC_BK] = WMM_AC_BK,
+ [NL80211_AC_VI] = WMM_AC_VI,
+ [NL80211_AC_VO] = WMM_AC_VO,
+ };
+ struct nlattr *nl_wmm;
+ struct nlattr *tb_wmm[NL80211_WMMR_MAX + 1];
+ int rem_wmm, ac, count = 0;
+
+ nla_for_each_nested(nl_wmm, tb_freq[NL80211_FREQUENCY_ATTR_WMM],
+ rem_wmm) {
+ if (nla_parse_nested(tb_wmm, NL80211_WMMR_MAX, nl_wmm,
+ wmm_policy)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to parse WMM rules attribute");
+ return;
+ }
+ if (!tb_wmm[NL80211_WMMR_CW_MIN] ||
+ !tb_wmm[NL80211_WMMR_CW_MAX] ||
+ !tb_wmm[NL80211_WMMR_AIFSN] ||
+ !tb_wmm[NL80211_WMMR_TXOP]) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Channel is missing WMM rule attribute");
+ return;
+ }
+ ac = nl_wmm->nla_type;
+ if ((unsigned int) ac >= ARRAY_SIZE(wmm_map)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Invalid AC value %d", ac);
+ return;
+ }
+
+ ac = wmm_map[ac];
+ chan->wmm_rules[ac].min_cwmin =
+ cw2ecw(nla_get_u16(
+ tb_wmm[NL80211_WMMR_CW_MIN]));
+ chan->wmm_rules[ac].min_cwmax =
+ cw2ecw(nla_get_u16(
+ tb_wmm[NL80211_WMMR_CW_MAX]));
+ chan->wmm_rules[ac].min_aifs =
+ nla_get_u8(tb_wmm[NL80211_WMMR_AIFSN]);
+ chan->wmm_rules[ac].max_txop =
+ nla_get_u16(tb_wmm[NL80211_WMMR_TXOP]) / 32;
+ count++;
+ }
+
+ /* Set valid flag if all the AC rules are present */
+ if (count == WMM_AC_NUM)
+ chan->wmm_rules_valid = 1;
+ }
}
@@ -1598,6 +1637,101 @@
}
+static void phy_info_iftype_copy(struct he_capabilities *he_capab,
+ enum ieee80211_op_mode opmode,
+ struct nlattr **tb, struct nlattr **tb_flags)
+{
+ enum nl80211_iftype iftype;
+ size_t len;
+
+ switch (opmode) {
+ case IEEE80211_MODE_INFRA:
+ iftype = NL80211_IFTYPE_STATION;
+ break;
+ case IEEE80211_MODE_IBSS:
+ iftype = NL80211_IFTYPE_ADHOC;
+ break;
+ case IEEE80211_MODE_AP:
+ iftype = NL80211_IFTYPE_AP;
+ break;
+ case IEEE80211_MODE_MESH:
+ iftype = NL80211_IFTYPE_MESH_POINT;
+ break;
+ default:
+ return;
+ }
+
+ if (!nla_get_flag(tb_flags[iftype]))
+ return;
+
+ he_capab->he_supported = 1;
+
+ if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]) {
+ len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]);
+
+ if (len > sizeof(he_capab->phy_cap))
+ len = sizeof(he_capab->phy_cap);
+ os_memcpy(he_capab->phy_cap,
+ nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]),
+ len);
+ }
+
+ if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]) {
+ len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]);
+
+ if (len > sizeof(he_capab->mac_cap))
+ len = sizeof(he_capab->mac_cap);
+ os_memcpy(he_capab->mac_cap,
+ nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]),
+ len);
+ }
+
+ if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET]) {
+ len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET]);
+
+ if (len > sizeof(he_capab->mcs))
+ len = sizeof(he_capab->mcs);
+ os_memcpy(he_capab->mcs,
+ nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET]),
+ len);
+ }
+
+ if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]) {
+ len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]);
+
+ if (len > sizeof(he_capab->ppet))
+ len = sizeof(he_capab->ppet);
+ os_memcpy(&he_capab->ppet,
+ nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]),
+ len);
+ }
+}
+
+
+static int phy_info_iftype(struct hostapd_hw_modes *mode,
+ struct nlattr *nl_iftype)
+{
+ struct nlattr *tb[NL80211_BAND_IFTYPE_ATTR_MAX + 1];
+ struct nlattr *tb_flags[NL80211_IFTYPE_MAX + 1];
+ unsigned int i;
+
+ nla_parse(tb, NL80211_BAND_IFTYPE_ATTR_MAX,
+ nla_data(nl_iftype), nla_len(nl_iftype), NULL);
+
+ if (!tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES])
+ return NL_STOP;
+
+ if (nla_parse_nested(tb_flags, NL80211_IFTYPE_MAX,
+ tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES], NULL))
+ return NL_STOP;
+
+ for (i = 0; i < IEEE80211_MODE_NUM; i++)
+ phy_info_iftype_copy(&mode->he_capab[i], i, tb, tb_flags);
+
+ return NL_OK;
+}
+
+
static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
{
struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
@@ -1646,7 +1780,12 @@
tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA],
tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
- ret = phy_info_freqs(phy_info, mode, tb_band[NL80211_BAND_ATTR_FREQS]);
+ ret = phy_info_edmg_capa(mode,
+ tb_band[NL80211_BAND_ATTR_EDMG_BW_CONFIG],
+ tb_band[NL80211_BAND_ATTR_EDMG_CHANNELS]);
+ if (ret == NL_OK)
+ ret = phy_info_freqs(phy_info, mode,
+ tb_band[NL80211_BAND_ATTR_FREQS]);
if (ret == NL_OK)
ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
if (ret != NL_OK) {
@@ -1654,6 +1793,19 @@
return ret;
}
+ if (tb_band[NL80211_BAND_ATTR_IFTYPE_DATA]) {
+ struct nlattr *nl_iftype;
+ int rem_band;
+
+ nla_for_each_nested(nl_iftype,
+ tb_band[NL80211_BAND_ATTR_IFTYPE_DATA],
+ rem_band) {
+ ret = phy_info_iftype(mode, nl_iftype);
+ if (ret != NL_OK)
+ return ret;
+ }
+ }
+
return NL_OK;
}
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index ee7b4da..1152312 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -136,6 +136,8 @@
C2S(NL80211_CMD_EXTERNAL_AUTH)
C2S(NL80211_CMD_STA_OPMODE_CHANGED)
C2S(NL80211_CMD_CONTROL_PORT_FRAME)
+ C2S(NL80211_CMD_UPDATE_OWE_INFO)
+ C2S(NL80211_CMD_UNPROT_BEACON)
default:
return "NL80211_CMD_UNKNOWN";
}
@@ -523,6 +525,10 @@
break;
case CHAN_WIDTH_UNKNOWN:
case CHAN_WIDTH_80P80:
+ case CHAN_WIDTH_2160:
+ case CHAN_WIDTH_4320:
+ case CHAN_WIDTH_6480:
+ case CHAN_WIDTH_8640:
/* FIXME: implement this */
return 0;
}
@@ -534,7 +540,8 @@
static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
struct nlattr *ifindex, struct nlattr *freq,
struct nlattr *type, struct nlattr *bw,
- struct nlattr *cf1, struct nlattr *cf2)
+ struct nlattr *cf1, struct nlattr *cf2,
+ int finished)
{
struct i802_bss *bss;
union wpa_event_data data;
@@ -542,7 +549,8 @@
int chan_offset = 0;
int ifidx;
- wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
+ wpa_printf(MSG_DEBUG, "nl80211: Channel switch%s event",
+ finished ? "" : " started");
if (!freq)
return;
@@ -593,10 +601,12 @@
if (cf2)
data.ch_switch.cf2 = nla_get_u32(cf2);
- bss->freq = data.ch_switch.freq;
+ if (finished)
+ bss->freq = data.ch_switch.freq;
drv->assoc_freq = data.ch_switch.freq;
- wpa_supplicant_event(bss->ctx, EVENT_CH_SWITCH, &data);
+ wpa_supplicant_event(bss->ctx, finished ?
+ EVENT_CH_SWITCH : EVENT_CH_SWITCH_STARTED, &data);
}
@@ -674,29 +684,42 @@
size_t len, struct nlattr *ack)
{
union wpa_event_data event;
- const struct ieee80211_hdr *hdr;
- u16 fc;
+ const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) frame;
+ u16 fc = le_to_host16(hdr->frame_control);
+ u64 cookie_val = 0;
- wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event");
- if (!is_ap_interface(drv->nlmode)) {
- u64 cookie_val;
+ if (cookie)
+ cookie_val = nla_get_u64(cookie);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Frame TX status event A1=" MACSTR
+ " %sstype=%d cookie=0x%llx%s ack=%d",
+ MAC2STR(hdr->addr1),
+ WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ? "not-mgmt " : "",
+ WLAN_FC_GET_STYPE(fc), (long long unsigned int) cookie_val,
+ cookie ? "" : "(N/A)", ack != NULL);
+ if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
+ return;
+
+ if (!is_ap_interface(drv->nlmode) &&
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
if (!cookie)
return;
- cookie_val = nla_get_u64(cookie);
- wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
- " cookie=0x%llx%s (ack=%d)",
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Frame TX status: cookie=0x%llx%s (ack=%d)",
(long long unsigned int) cookie_val,
- cookie_val == drv->send_action_cookie ?
+ cookie_val == drv->send_frame_cookie ?
" (match)" : " (unknown)", ack != NULL);
- if (cookie_val != drv->send_action_cookie)
+ if (cookie_val != drv->send_frame_cookie)
return;
+ } else if (!is_ap_interface(drv->nlmode) &&
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Authentication frame TX status: ack=%d",
+ !!ack);
}
- hdr = (const struct ieee80211_hdr *) frame;
- 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);
@@ -871,6 +894,23 @@
}
+static void mlme_event_unprot_beacon(struct wpa_driver_nl80211_data *drv,
+ const u8 *frame, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+
+ if (len < 24)
+ return;
+
+ mgmt = (const struct ieee80211_mgmt *) frame;
+
+ os_memset(&event, 0, sizeof(event));
+ event.unprot_beacon.sa = mgmt->sa;
+ wpa_supplicant_event(drv->ctx, EVENT_UNPROT_BEACON, &event);
+}
+
+
static void mlme_event(struct i802_bss *bss,
enum nl80211_commands cmd, struct nlattr *frame,
struct nlattr *addr, struct nlattr *timed_out,
@@ -952,6 +992,9 @@
mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC,
nla_data(frame), nla_len(frame));
break;
+ case NL80211_CMD_UNPROT_BEACON:
+ mlme_event_unprot_beacon(drv, nla_data(frame), nla_len(frame));
+ break;
default:
break;
}
@@ -1101,6 +1144,29 @@
}
+static void mlme_event_dh_event(struct wpa_driver_nl80211_data *drv,
+ struct i802_bss *bss,
+ struct nlattr *tb[])
+{
+ union wpa_event_data data;
+
+ if (!is_ap_interface(drv->nlmode))
+ return;
+ if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_IE])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ data.update_dh.peer = nla_data(tb[NL80211_ATTR_MAC]);
+ data.update_dh.ie = nla_data(tb[NL80211_ATTR_IE]);
+ data.update_dh.ie_len = nla_len(tb[NL80211_ATTR_IE]);
+
+ wpa_printf(MSG_DEBUG, "nl80211: DH event - peer " MACSTR,
+ MAC2STR(data.update_dh.peer));
+
+ wpa_supplicant_event(bss->ctx, EVENT_UPDATE_DH, &data);
+}
+
+
static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
struct nlattr *tb[], int external_scan)
{
@@ -1708,35 +1774,73 @@
}
+static unsigned int chan_to_freq(struct wpa_driver_nl80211_data *drv,
+ u8 chan, enum hostapd_hw_mode hw_mode)
+{
+ if (hw_mode == NUM_HOSTAPD_MODES) {
+ /* For drivers that do not report ACS_HW_MODE */
+ u16 num_modes, flags;
+ struct hostapd_hw_modes *modes;
+ u8 dfs_domain;
+ int i;
+
+ modes = nl80211_get_hw_feature_data(drv->first_bss, &num_modes,
+ &flags, &dfs_domain);
+ if (!modes) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Fetching hardware mode failed");
+ goto try_2_4_or_5;
+ }
+ if (num_modes == 1)
+ hw_mode = modes[0].mode;
+
+ for (i = 0; i < num_modes; i++) {
+ os_free(modes[i].channels);
+ os_free(modes[i].rates);
+ }
+
+ os_free(modes);
+ }
+
+ if (hw_mode == HOSTAPD_MODE_IEEE80211AD) {
+ if (chan >= 1 && chan <= 6)
+ return 56160 + (2160 * chan);
+ return 0;
+ }
+
+try_2_4_or_5:
+ if (chan >= 1 && chan <= 13)
+ return 2407 + 5 * chan;
+ if (chan == 14)
+ return 2484;
+ if (chan >= 36 && chan <= 169)
+ return 5000 + 5 * chan;
+
+ return 0;
+}
+
+
static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
const u8 *data, size_t len)
{
struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ACS_MAX + 1];
union wpa_event_data event;
+ u8 chan;
wpa_printf(MSG_DEBUG,
"nl80211: ACS channel selection vendor event received");
if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACS_MAX,
(struct nlattr *) data, len, NULL) ||
- !tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL] ||
- !tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL])
+ (!tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY] &&
+ !tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]) ||
+ (!tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY] &&
+ !tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]))
return;
os_memset(&event, 0, sizeof(event));
- event.acs_selected_channels.pri_channel =
- nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]);
- event.acs_selected_channels.sec_channel =
- nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]);
- if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
- event.acs_selected_channels.vht_seg0_center_ch =
- nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]);
- if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
- event.acs_selected_channels.vht_seg1_center_ch =
- nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL]);
- if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH])
- event.acs_selected_channels.ch_width =
- nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]);
+ event.acs_selected_channels.hw_mode = NUM_HOSTAPD_MODES;
+
if (tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]) {
u8 hw_mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]);
@@ -1751,14 +1855,48 @@
}
}
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY]) {
+ event.acs_selected_channels.pri_freq = nla_get_u32(
+ tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY]);
+ } else {
+ chan = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]);
+ event.acs_selected_channels.pri_freq =
+ chan_to_freq(drv, chan,
+ event.acs_selected_channels.hw_mode);
+ }
+
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY]) {
+ event.acs_selected_channels.sec_freq = nla_get_u32(
+ tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY]);
+ } else {
+ chan = nla_get_u8(
+ tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]);
+ event.acs_selected_channels.sec_freq =
+ chan_to_freq(drv, chan,
+ event.acs_selected_channels.hw_mode);
+ }
+
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL])
+ event.acs_selected_channels.edmg_channel =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL]);
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
+ event.acs_selected_channels.vht_seg0_center_ch =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]);
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL])
+ event.acs_selected_channels.vht_seg1_center_ch =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL]);
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH])
+ event.acs_selected_channels.ch_width =
+ nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]);
wpa_printf(MSG_INFO,
- "nl80211: ACS Results: PCH: %d SCH: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d",
- event.acs_selected_channels.pri_channel,
- event.acs_selected_channels.sec_channel,
+ "nl80211: ACS Results: PFreq: %d SFreq: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d EDMGCH: %d",
+ event.acs_selected_channels.pri_freq,
+ event.acs_selected_channels.sec_freq,
event.acs_selected_channels.ch_width,
event.acs_selected_channels.vht_seg0_center_ch,
event.acs_selected_channels.vht_seg1_center_ch,
- event.acs_selected_channels.hw_mode);
+ event.acs_selected_channels.hw_mode,
+ event.acs_selected_channels.edmg_channel);
/* Ignore ACS channel list check for backwards compatibility */
@@ -2385,11 +2523,46 @@
}
+static void nl80211_control_port_frame(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ u8 *src_addr;
+ u16 ethertype;
+
+ if (!tb[NL80211_ATTR_MAC] ||
+ !tb[NL80211_ATTR_FRAME] ||
+ !tb[NL80211_ATTR_CONTROL_PORT_ETHERTYPE])
+ return;
+
+ src_addr = nla_data(tb[NL80211_ATTR_MAC]);
+ ethertype = nla_get_u16(tb[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
+
+ switch (ethertype) {
+ case ETH_P_RSN_PREAUTH:
+ wpa_printf(MSG_INFO, "nl80211: Got pre-auth frame from "
+ MACSTR " over control port unexpectedly",
+ MAC2STR(src_addr));
+ break;
+ case ETH_P_PAE:
+ drv_event_eapol_rx(drv->ctx, src_addr,
+ nla_data(tb[NL80211_ATTR_FRAME]),
+ nla_len(tb[NL80211_ATTR_FRAME]));
+ break;
+ default:
+ wpa_printf(MSG_INFO, "nl80211: Unxpected ethertype 0x%04x from "
+ MACSTR " over control port",
+ ethertype, MAC2STR(src_addr));
+ break;
+ }
+}
+
+
static void do_process_drv_event(struct i802_bss *bss, int cmd,
struct nlattr **tb)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
int external_scan_event = 0;
+ struct nlattr *frame = tb[NL80211_ATTR_FRAME];
wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
cmd, nl80211_command_to_string(cmd), bss->ifname);
@@ -2508,6 +2681,16 @@
tb[NL80211_ATTR_PMK],
tb[NL80211_ATTR_PMKID]);
break;
+ case NL80211_CMD_CH_SWITCH_STARTED_NOTIFY:
+ mlme_event_ch_switch(drv,
+ tb[NL80211_ATTR_IFINDEX],
+ tb[NL80211_ATTR_WIPHY_FREQ],
+ tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
+ tb[NL80211_ATTR_CHANNEL_WIDTH],
+ tb[NL80211_ATTR_CENTER_FREQ1],
+ tb[NL80211_ATTR_CENTER_FREQ2],
+ 0);
+ break;
case NL80211_CMD_CH_SWITCH_NOTIFY:
mlme_event_ch_switch(drv,
tb[NL80211_ATTR_IFINDEX],
@@ -2515,7 +2698,8 @@
tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
tb[NL80211_ATTR_CHANNEL_WIDTH],
tb[NL80211_ATTR_CENTER_FREQ1],
- tb[NL80211_ATTR_CENTER_FREQ2]);
+ tb[NL80211_ATTR_CENTER_FREQ2],
+ 1);
break;
case NL80211_CMD_DISCONNECT:
mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
@@ -2586,6 +2770,14 @@
case NL80211_CMD_STA_OPMODE_CHANGED:
nl80211_sta_opmode_change_event(drv, tb);
break;
+ case NL80211_CMD_UPDATE_OWE_INFO:
+ mlme_event_dh_event(drv, bss, tb);
+ break;
+ case NL80211_CMD_UNPROT_BEACON:
+ if (frame)
+ mlme_event_unprot_beacon(drv, nla_data(frame),
+ nla_len(frame));
+ break;
default:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", cmd);
@@ -2634,8 +2826,9 @@
}
}
wpa_printf(MSG_DEBUG,
- "nl80211: Ignored event (cmd=%d) for foreign interface (ifindex %d wdev 0x%llx)",
- gnlh->cmd, ifidx, (long long unsigned int) wdev_id);
+ "nl80211: Ignored event %d (%s) for foreign interface (ifindex %d wdev 0x%llx)",
+ gnlh->cmd, nl80211_command_to_string(gnlh->cmd),
+ ifidx, (long long unsigned int) wdev_id);
}
return NL_SKIP;
@@ -2674,6 +2867,9 @@
case NL80211_CMD_EXTERNAL_AUTH:
nl80211_external_auth(bss->drv, tb);
break;
+ case NL80211_CMD_CONTROL_PORT_FRAME:
+ nl80211_control_port_frame(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 f25cd79..7ff55f1 100644
--- a/src/drivers/driver_nl80211_monitor.c
+++ b/src/drivers/driver_nl80211_monitor.c
@@ -71,6 +71,9 @@
u16 fc;
union wpa_event_data event;
+ if (!drv->use_monitor)
+ return;
+
hdr = (struct ieee80211_hdr *) buf;
fc = le_to_host16(hdr->frame_control);
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index 9afa5b3..17e8b2c 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -236,6 +236,11 @@
params->filter_ssids = NULL;
drv->num_filter_ssids = params->num_filter_ssids;
+ if (!drv->hostapd && is_ap_interface(drv->nlmode)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_AP");
+ scan_flags |= NL80211_SCAN_FLAG_AP;
+ }
+
if (params->only_new_results) {
wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH");
scan_flags |= NL80211_SCAN_FLAG_FLUSH;
@@ -867,7 +872,7 @@
wpa_driver_nl80211_mlme(drv, addr,
NL80211_CMD_DEAUTHENTICATE,
WLAN_REASON_PREV_AUTH_NOT_VALID, 1,
- NULL);
+ get_connect_handle(drv->first_bss));
}
}
@@ -928,7 +933,9 @@
struct wpa_scan_results *res;
int ret;
struct nl80211_bss_info_arg arg;
+ int count = 0;
+try_again:
res = os_zalloc(sizeof(*res));
if (res == NULL)
return NULL;
@@ -941,6 +948,18 @@
arg.drv = drv;
arg.res = res;
ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
+ if (ret == -EAGAIN) {
+ count++;
+ if (count >= 10) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Failed to receive consistent scan result dump");
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to receive consistent scan result dump - try again");
+ wpa_scan_results_free(res);
+ goto try_again;
+ }
+ }
if (ret == 0) {
struct nl80211_noise_info info;
diff --git a/src/drivers/driver_none.c b/src/drivers/driver_none.c
index 6ff3eae..ccd2d9d 100644
--- a/src/drivers/driver_none.c
+++ b/src/drivers/driver_none.c
@@ -43,13 +43,6 @@
}
-static int none_driver_send_ether(void *priv, const u8 *dst, const u8 *src,
- u16 proto, const u8 *data, size_t data_len)
-{
- return 0;
-}
-
-
static void * none_driver_init(void *ctx, const char *ifname)
{
struct none_driver_data *drv;
@@ -79,7 +72,6 @@
.desc = "no driver (RADIUS server/WPS ER)",
.hapd_init = none_driver_hapd_init,
.hapd_deinit = none_driver_hapd_deinit,
- .send_ether = none_driver_send_ether,
.init = none_driver_init,
.deinit = none_driver_deinit,
};
diff --git a/src/drivers/driver_openbsd.c b/src/drivers/driver_openbsd.c
index c06e75c..bfc2311 100644
--- a/src/drivers/driver_openbsd.c
+++ b/src/drivers/driver_openbsd.c
@@ -69,14 +69,16 @@
static int
-wpa_driver_openbsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
- const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
- size_t seq_len, const u8 *key, size_t key_len)
+wpa_driver_openbsd_set_key(void *priv, struct wpa_driver_set_key_params *params)
{
struct openbsd_driver_data *drv = priv;
struct ieee80211_keyavail keyavail;
+ enum key_flag key_flag = params->key_flag;
+ const u8 *key = params->key;
+ size_t key_len = params->key_len;
- if (alg != WPA_ALG_PMK || key_len > IEEE80211_PMK_LEN)
+ if (key_len > IEEE80211_PMK_LEN ||
+ (key_flag & KEY_FLAG_PMK_MASK) != KEY_FLAG_PMK) {
return -1;
memset(&keyavail, 0, sizeof(keyavail));
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index a3f0837..d6735b4 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -205,14 +205,19 @@
}
-static int wpa_driver_privsep_set_key(const char *ifname, void *priv,
- 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)
+static int wpa_driver_privsep_set_key(void *priv,
+ struct wpa_driver_set_key_params *params)
{
struct wpa_driver_privsep_data *drv = priv;
struct privsep_cmd_set_key cmd;
+ enum wpa_alg alg = params->alg;
+ const u8 *addr = params->addr;
+ int key_idx = params->key_idx;
+ int set_tx = params->set_tx;
+ const u8 *seq = params->seq;
+ size_t seq_len = params->seq_len;
+ const u8 *key = params->key;
+ size_t key_len = params->key_len;
wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d",
__func__, priv, alg, key_idx, set_tx);
@@ -225,6 +230,7 @@
os_memset(cmd.addr, 0xff, ETH_ALEN);
cmd.key_idx = key_idx;
cmd.set_tx = set_tx;
+ cmd.key_flag = params->key_flag;
if (seq && seq_len > 0 && seq_len < sizeof(cmd.seq)) {
os_memcpy(cmd.seq, seq, seq_len);
cmd.seq_len = seq_len;
@@ -368,7 +374,7 @@
static int wpa_driver_privsep_deauthenticate(void *priv, const u8 *addr,
- int reason_code)
+ u16 reason_code)
{
//struct wpa_driver_privsep_data *drv = priv;
wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
@@ -791,6 +797,8 @@
capa->extended_capa = NULL;
capa->extended_capa_mask = NULL;
capa->extended_capa_len = 0;
+ /* Control port is not yet supported */
+ capa->flags &= ~WPA_DRIVER_FLAGS_CONTROL_PORT;
return 0;
}
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index f7755cc..978e1cf 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -1712,7 +1712,8 @@
const u8 *addr, int key_idx,
int set_tx, const u8 *seq,
size_t seq_len,
- const u8 *key, size_t key_len)
+ const u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
struct wpa_driver_wext_data *drv = priv;
struct iwreq iwr;
@@ -1751,32 +1752,31 @@
os_memcpy(ext + 1, key, key_len);
ext->key_len = key_len;
}
- switch (alg) {
- case WPA_ALG_NONE:
- ext->alg = IW_ENCODE_ALG_NONE;
- break;
- case WPA_ALG_WEP:
- ext->alg = IW_ENCODE_ALG_WEP;
- break;
- case WPA_ALG_TKIP:
- ext->alg = IW_ENCODE_ALG_TKIP;
- break;
- case WPA_ALG_CCMP:
- ext->alg = IW_ENCODE_ALG_CCMP;
- break;
- case WPA_ALG_PMK:
+ if (key_flag & KEY_FLAG_PMK) {
ext->alg = IW_ENCODE_ALG_PMK;
- break;
-#ifdef CONFIG_IEEE80211W
- case WPA_ALG_IGTK:
- ext->alg = IW_ENCODE_ALG_AES_CMAC;
- break;
-#endif /* CONFIG_IEEE80211W */
- default:
- wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d",
- __FUNCTION__, alg);
- os_free(ext);
- return -1;
+ } else {
+ switch (alg) {
+ case WPA_ALG_NONE:
+ ext->alg = IW_ENCODE_ALG_NONE;
+ break;
+ case WPA_ALG_WEP:
+ ext->alg = IW_ENCODE_ALG_WEP;
+ break;
+ case WPA_ALG_TKIP:
+ ext->alg = IW_ENCODE_ALG_TKIP;
+ break;
+ case WPA_ALG_CCMP:
+ ext->alg = IW_ENCODE_ALG_CCMP;
+ break;
+ case WPA_ALG_IGTK:
+ ext->alg = IW_ENCODE_ALG_AES_CMAC;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d",
+ __FUNCTION__, alg);
+ os_free(ext);
+ return -1;
+ }
}
if (seq && seq_len) {
@@ -1805,37 +1805,27 @@
/**
* wpa_driver_wext_set_key - Configure encryption key
* @priv: Pointer to private wext data from wpa_driver_wext_init()
- * @priv: Private driver interface data
- * @alg: Encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
- * %WPA_ALG_TKIP, %WPA_ALG_CCMP); %WPA_ALG_NONE clears the key.
- * @addr: Address of the peer STA or ff:ff:ff:ff:ff:ff for
- * broadcast/default keys
- * @key_idx: key index (0..3), usually 0 for unicast keys
- * @set_tx: Configure this key as the default Tx key (only used when
- * driver does not support separate unicast/individual key
- * @seq: Sequence number/packet number, seq_len octets, the next
- * packet number to be used for in replay protection; configured
- * for Rx keys (in most cases, this is only used with broadcast
- * keys and set to zero for unicast keys)
- * @seq_len: Length of the seq, depends on the algorithm:
- * TKIP: 6 octets, CCMP: 6 octets
- * @key: Key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
- * 8-byte Rx Mic Key
- * @key_len: Length of the key buffer in octets (WEP: 5 or 13,
- * TKIP: 32, CCMP: 16)
+ * @params: Key parameters
* Returns: 0 on success, -1 on failure
*
* This function uses SIOCSIWENCODEEXT by default, but tries to use
* SIOCSIWENCODE if the extended ioctl fails when configuring a WEP key.
*/
-int wpa_driver_wext_set_key(const char *ifname, void *priv, 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)
+static int wpa_driver_wext_set_key(void *priv,
+ struct wpa_driver_set_key_params *params)
{
struct wpa_driver_wext_data *drv = priv;
struct iwreq iwr;
int ret = 0;
+ enum wpa_alg alg = params->alg;
+ enum key_flag key_flag = params->key_flag;
+ const u8 *addr = params->addr;
+ int key_idx = params->key_idx;
+ int set_tx = params->set_tx;
+ const u8 *seq = params->seq;
+ size_t seq_len = params->seq_len;
+ const u8 *key = params->key;
+ size_t key_len = params->key_len;
wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu "
"key_len=%lu",
@@ -1843,7 +1833,7 @@
(unsigned long) seq_len, (unsigned long) key_len);
ret = wpa_driver_wext_set_key_ext(drv, alg, addr, key_idx, set_tx,
- seq, seq_len, key, key_len);
+ seq, seq_len, key, key_len, key_flag);
if (ret == 0)
return 0;
@@ -1915,7 +1905,7 @@
static int wpa_driver_wext_mlme(struct wpa_driver_wext_data *drv,
- const u8 *addr, int cmd, int reason_code)
+ const u8 *addr, int cmd, u16 reason_code)
{
struct iwreq iwr;
struct iw_mlme mlme;
@@ -1998,7 +1988,7 @@
static int wpa_driver_wext_deauthenticate(void *priv, const u8 *addr,
- int reason_code)
+ u16 reason_code)
{
struct wpa_driver_wext_data *drv = priv;
int ret;
@@ -2201,7 +2191,6 @@
IW_AUTH_RX_UNENCRYPTED_EAPOL,
allow_unencrypted_eapol) < 0)
ret = -1;
-#ifdef CONFIG_IEEE80211W
switch (params->mgmt_frame_protection) {
case NO_MGMT_FRAME_PROTECTION:
value = IW_AUTH_MFP_DISABLED;
@@ -2215,7 +2204,6 @@
};
if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0)
ret = -1;
-#endif /* CONFIG_IEEE80211W */
if (params->freq.freq &&
wpa_driver_wext_set_freq(drv, params->freq.freq) < 0)
ret = -1;
diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h
index b4b5960..6214cdf 100644
--- a/src/drivers/driver_wext.h
+++ b/src/drivers/driver_wext.h
@@ -52,10 +52,6 @@
int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len);
int wpa_driver_wext_set_freq(void *priv, int freq);
int wpa_driver_wext_set_mode(void *priv, int mode);
-int wpa_driver_wext_set_key(const char *ifname, void *priv, 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);
int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params);
struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv);
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index 442c59c..55a98ef 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -140,10 +140,6 @@
DRV_OBJS += ../src/drivers/netlink.o
endif
-ifdef NEED_LINUX_IOCTL
-DRV_OBJS += ../src/drivers/linux_ioctl.o
-endif
-
ifdef NEED_RFKILL
DRV_OBJS += ../src/drivers/rfkill.o
endif
@@ -152,13 +148,18 @@
DRV_OBJS += ../src/utils/radiotap.o
endif
-ifdef CONFIG_VLAN_NETLINK
ifdef CONFIG_FULL_DYNAMIC_VLAN
+NEED_LINUX_IOCTL=y
+ifdef CONFIG_VLAN_NETLINK
NEED_LIBNL=y
CONFIG_LIBNL3_ROUTE=y
endif
endif
+ifdef NEED_LINUX_IOCTL
+DRV_OBJS += ../src/drivers/linux_ioctl.o
+endif
+
ifdef NEED_LIBNL
ifndef CONFIG_LIBNL32
ifndef CONFIG_LIBNL20
@@ -175,7 +176,6 @@
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
@@ -192,14 +192,8 @@
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
endif
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index 599a0b5..5a32a24 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -132,10 +132,6 @@
DRV_OBJS += src/drivers/netlink.c
endif
-ifdef NEED_LINUX_IOCTL
-DRV_OBJS += src/drivers/linux_ioctl.c
-endif
-
ifdef NEED_RFKILL
DRV_OBJS += src/drivers/rfkill.c
endif
@@ -148,18 +144,23 @@
DRV_CFLAGS += -DCONFIG_DRIVER_CUSTOM
endif
-ifdef CONFIG_VLAN_NETLINK
ifdef CONFIG_FULL_DYNAMIC_VLAN
+NEED_LINUX_IOCTL=y
+ifdef CONFIG_VLAN_NETLINK
NEED_LIBNL=y
CONFIG_LIBNL3_ROUTE=y
endif
endif
+ifdef NEED_LINUX_IOCTL
+DRV_OBJS += src/drivers/linux_ioctl.c
+endif
+
ifdef NEED_LIBNL
ifdef CONFIG_LIBNL32
DRV_LIBS += -lnl-3
DRV_LIBS += -lnl-genl-3
- DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
+ DRV_CFLAGS += -I/usr/include/libnl3
ifdef CONFIG_LIBNL3_ROUTE
DRV_LIBS += -lnl-route-3
DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE
@@ -169,13 +170,7 @@
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
+ DRV_LIBS += -lnl-genl
endif
endif
endif
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index dd4f86e..5e500d7 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -11,7 +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
+ * Copyright (C) 2018-2020 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
@@ -52,6 +52,11 @@
#define NL80211_MULTICAST_GROUP_NAN "nan"
#define NL80211_MULTICAST_GROUP_TESTMODE "testmode"
+#define NL80211_EDMG_BW_CONFIG_MIN 4
+#define NL80211_EDMG_BW_CONFIG_MAX 15
+#define NL80211_EDMG_CHANNELS_MIN 1
+#define NL80211_EDMG_CHANNELS_MAX 0x3c /* 0b00111100 */
+
/**
* DOC: Station handling
*
@@ -235,6 +240,54 @@
*/
/**
+ * DOC: SAE authentication offload
+ *
+ * By setting @NL80211_EXT_FEATURE_SAE_OFFLOAD flag drivers can indicate they
+ * support offloading SAE authentication for WPA3-Personal networks. In
+ * %NL80211_CMD_CONNECT the password for SAE should be specified using
+ * %NL80211_ATTR_SAE_PASSWORD.
+ */
+
+/**
+ * DOC: VLAN offload support for setting group keys and binding STAs to VLANs
+ *
+ * By setting @NL80211_EXT_FEATURE_VLAN_OFFLOAD flag drivers can indicate they
+ * support offloading VLAN functionality in a manner where the driver exposes a
+ * single netdev that uses VLAN tagged frames and separate VLAN-specific netdevs
+ * can then be added using RTM_NEWLINK/IFLA_VLAN_ID similarly to the Ethernet
+ * case. Frames received from stations that are not assigned to any VLAN are
+ * delivered on the main netdev and frames to such stations can be sent through
+ * that main netdev.
+ *
+ * %NL80211_CMD_NEW_KEY (for group keys), %NL80211_CMD_NEW_STATION, and
+ * %NL80211_CMD_SET_STATION will optionally specify vlan_id using
+ * %NL80211_ATTR_VLAN_ID.
+ */
+
+/**
+ * DOC: TID configuration
+ *
+ * TID config support can be checked in the %NL80211_ATTR_TID_CONFIG
+ * attribute given in wiphy capabilities.
+ *
+ * The necessary configuration parameters are mentioned in
+ * &enum nl80211_tid_config_attr and it will be passed to the
+ * %NL80211_CMD_SET_TID_CONFIG command in %NL80211_ATTR_TID_CONFIG.
+ *
+ * If the configuration needs to be applied for specific peer then the MAC
+ * address of the peer needs to be passed in %NL80211_ATTR_MAC, otherwise the
+ * configuration will be applied for all the connected peers in the vif except
+ * any peers that have peer specific configuration for the TID by default; if
+ * the %NL80211_TID_CONFIG_ATTR_OVERRIDE flag is set, peer specific values
+ * will be overwritten.
+ *
+ * All this configuration is valid only for STA's current connection
+ * i.e. the configuration will be reset to default when the STA connects back
+ * after disconnection/roaming, and this configuration will be cleared when
+ * the interface goes down.
+ */
+
+/**
* enum nl80211_commands - supported nl80211 commands
*
* @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -557,6 +610,14 @@
* set of BSSID,frequency parameters is used (i.e., either the enforcing
* %NL80211_ATTR_MAC,%NL80211_ATTR_WIPHY_FREQ or the less strict
* %NL80211_ATTR_MAC_HINT and %NL80211_ATTR_WIPHY_FREQ_HINT).
+ * Driver shall not modify the IEs specified through %NL80211_ATTR_IE if
+ * %NL80211_ATTR_MAC is included. However, if %NL80211_ATTR_MAC_HINT is
+ * included, these IEs through %NL80211_ATTR_IE are specified by the user
+ * space based on the best possible BSS selected. Thus, if the driver ends
+ * up selecting a different BSS, it can modify these IEs accordingly (e.g.
+ * userspace asks the driver to perform PMKSA caching with BSS1 and the
+ * driver ends up selecting BSS2 with different PMKSA cache entry; RSNIE
+ * has to get updated with the apt PMKID).
* %NL80211_ATTR_PREV_BSSID can be used to request a reassociation within
* the ESS in case the device is already associated and an association with
* a different BSS is desired.
@@ -626,6 +687,10 @@
* four bytes for vendor frames including the OUI. The registration
* cannot be dropped, but is removed automatically when the netlink
* socket is closed. Multiple registrations can be made.
+ * The %NL80211_ATTR_RECEIVE_MULTICAST flag attribute can be given if
+ * %NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS is available, in which
+ * case the registration can also be modified to include/exclude the
+ * flag, rather than requiring unregistration to change it.
* @NL80211_CMD_REGISTER_ACTION: Alias for @NL80211_CMD_REGISTER_FRAME for
* backward compatibility
* @NL80211_CMD_FRAME: Management frame TX request and RX notification. This
@@ -648,7 +713,9 @@
* is used during CSA period.
* @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this
* command may be used with the corresponding cookie to cancel the wait
- * time if it is known that it is no longer necessary.
+ * time if it is known that it is no longer necessary. This command is
+ * also sent as an event whenever the driver has completed the off-channel
+ * wait time.
* @NL80211_CMD_ACTION: Alias for @NL80211_CMD_FRAME for backward compatibility.
* @NL80211_CMD_FRAME_TX_STATUS: Report TX status of a management frame
* transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies
@@ -1065,6 +1132,34 @@
* indicated by %NL80211_ATTR_WIPHY_FREQ and other attributes
* determining the width and type.
*
+ * @NL80211_CMD_UPDATE_OWE_INFO: This interface allows the host driver to
+ * offload OWE processing to user space. This intends to support
+ * OWE AKM by the host drivers that implement SME but rely
+ * on the user space for the cryptographic/DH IE processing in AP mode.
+ *
+ * @NL80211_CMD_PROBE_MESH_LINK: The requirement for mesh link metric
+ * refreshing, is that from one mesh point we be able to send some data
+ * frames to other mesh points which are not currently selected as a
+ * primary traffic path, but which are only 1 hop away. The absence of
+ * the primary path to the chosen node makes it necessary to apply some
+ * form of marking on a chosen packet stream so that the packets can be
+ * properly steered to the selected node for testing, and not by the
+ * regular mesh path lookup. Further, the packets must be of type data
+ * so that the rate control (often embedded in firmware) is used for
+ * rate selection.
+ *
+ * Here attribute %NL80211_ATTR_MAC is used to specify connected mesh
+ * peer MAC address and %NL80211_ATTR_FRAME is used to specify the frame
+ * content. The frame is ethernet data.
+ *
+ * @NL80211_CMD_SET_TID_CONFIG: Data frame TID specific configuration
+ * is passed using %NL80211_ATTR_TID_CONFIG attribute.
+ *
+ * @NL80211_CMD_UNPROT_BEACON: Unprotected or incorrectly protected Beacon
+ * frame. This event is used to indicate that a received Beacon frame was
+ * dropped because it did not include a valid MME MIC while beacon
+ * protection was enabled (BIGTK configured in station mode).
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1285,6 +1380,14 @@
NL80211_CMD_NOTIFY_RADAR,
+ NL80211_CMD_UPDATE_OWE_INFO,
+
+ NL80211_CMD_PROBE_MESH_LINK,
+
+ NL80211_CMD_SET_TID_CONFIG,
+
+ NL80211_CMD_UNPROT_BEACON,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1540,7 +1643,8 @@
* 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.
+ * flag. When used with %NL80211_ATTR_CONTROL_PORT_NO_PREAUTH, pre-auth
+ * frames are not forwared over the control port.
*
* @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
* We recommend using nested, driver-specific attributes within this.
@@ -2308,6 +2412,78 @@
* @NL80211_ATTR_AIRTIME_WEIGHT: Station's weight when scheduled by the airtime
* scheduler.
*
+ * @NL80211_ATTR_STA_TX_POWER_SETTING: Transmit power setting type (u8) for
+ * station associated with the AP. See &enum nl80211_tx_power_setting for
+ * possible values.
+ * @NL80211_ATTR_STA_TX_POWER: Transmit power level (s16) in dBm units. This
+ * allows to set Tx power for a station. If this attribute is not included,
+ * the default per-interface tx power setting will be overriding. Driver
+ * should be picking up the lowest tx power, either tx power per-interface
+ * or per-station.
+ *
+ * @NL80211_ATTR_SAE_PASSWORD: attribute for passing SAE password material. It
+ * is used with %NL80211_CMD_CONNECT to provide password for offloading
+ * SAE authentication for WPA3-Personal networks.
+ *
+ * @NL80211_ATTR_TWT_RESPONDER: Enable target wait time responder support.
+ *
+ * @NL80211_ATTR_HE_OBSS_PD: nested attribute for OBSS Packet Detection
+ * functionality.
+ *
+ * @NL80211_ATTR_WIPHY_EDMG_CHANNELS: bitmap that indicates the 2.16 GHz
+ * channel(s) that are allowed to be used for EDMG transmissions.
+ * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251. (u8 attribute)
+ * @NL80211_ATTR_WIPHY_EDMG_BW_CONFIG: Channel BW Configuration subfield encodes
+ * the allowed channel bandwidth configurations. (u8 attribute)
+ * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13.
+ *
+ * @NL80211_ATTR_VLAN_ID: VLAN ID (1..4094) for the station and VLAN group key
+ * (u16).
+ *
+ * @NL80211_ATTR_HE_BSS_COLOR: nested attribute for BSS Color Settings.
+ *
+ * @NL80211_ATTR_IFTYPE_AKM_SUITES: nested array attribute, with each entry
+ * using attributes from &enum nl80211_iftype_akm_attributes. This
+ * attribute is sent in a response to %NL80211_CMD_GET_WIPHY indicating
+ * supported AKM suites capability per interface. AKMs advertised in
+ * %NL80211_ATTR_AKM_SUITES are default capabilities if AKM suites not
+ * advertised for a specific interface type.
+ *
+ * @NL80211_ATTR_TID_CONFIG: TID specific configuration in a
+ * nested attribute with &enum nl80211_tid_config_attr sub-attributes;
+ * on output (in wiphy attributes) it contains only the feature sub-
+ * attributes.
+ *
+ * @NL80211_ATTR_CONTROL_PORT_NO_PREAUTH: disable preauth frame rx on control
+ * port in order to forward/receive them as ordinary data frames.
+ *
+ * @NL80211_ATTR_PMK_LIFETIME: Maximum lifetime for PMKSA in seconds (u32,
+ * dot11RSNAConfigPMKReauthThreshold; 0 is not a valid value).
+ * An optional parameter configured through %NL80211_CMD_SET_PMKSA.
+ * Drivers that trigger roaming need to know the lifetime of the
+ * configured PMKSA for triggering the full vs. PMKSA caching based
+ * authentication. This timeout helps authentication methods like SAE,
+ * where PMK gets updated only by going through a full (new SAE)
+ * authentication instead of getting updated during an association for EAP
+ * authentication. No new full authentication within the PMK expiry shall
+ * result in a disassociation at the end of the lifetime.
+ *
+ * @NL80211_ATTR_PMK_REAUTH_THRESHOLD: Reauthentication threshold time, in
+ * terms of percentage of %NL80211_ATTR_PMK_LIFETIME
+ * (u8, dot11RSNAConfigPMKReauthThreshold, 1..100). This is an optional
+ * parameter configured through %NL80211_CMD_SET_PMKSA. Requests the
+ * driver to trigger a full authentication roam (without PMKSA caching)
+ * after the reauthentication threshold time, but before the PMK lifetime
+ * has expired.
+ *
+ * Authentication methods like SAE need to be able to generate a new PMKSA
+ * entry without having to force a disconnection after the PMK timeout. If
+ * no roaming occurs between the reauth threshold and PMK expiration,
+ * disassociation is still forced.
+ *
+ * @NL80211_ATTR_RECEIVE_MULTICAST: multicast flag for the
+ * %NL80211_CMD_REGISTER_FRAME command, see the description there.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2758,6 +2934,32 @@
NL80211_ATTR_PEER_MEASUREMENTS,
NL80211_ATTR_AIRTIME_WEIGHT,
+ NL80211_ATTR_STA_TX_POWER_SETTING,
+ NL80211_ATTR_STA_TX_POWER,
+
+ NL80211_ATTR_SAE_PASSWORD,
+
+ NL80211_ATTR_TWT_RESPONDER,
+
+ NL80211_ATTR_HE_OBSS_PD,
+
+ NL80211_ATTR_WIPHY_EDMG_CHANNELS,
+ NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
+
+ NL80211_ATTR_VLAN_ID,
+
+ NL80211_ATTR_HE_BSS_COLOR,
+
+ NL80211_ATTR_IFTYPE_AKM_SUITES,
+
+ NL80211_ATTR_TID_CONFIG,
+
+ NL80211_ATTR_CONTROL_PORT_NO_PREAUTH,
+
+ NL80211_ATTR_PMK_LIFETIME,
+ NL80211_ATTR_PMK_REAUTH_THRESHOLD,
+
+ NL80211_ATTR_RECEIVE_MULTICAST,
/* add attributes here, update the policy in nl80211.c */
@@ -2802,14 +3004,14 @@
#define NL80211_MAX_SUPP_RATES 32
#define NL80211_MAX_SUPP_HT_RATES 77
-#define NL80211_MAX_SUPP_REG_RULES 64
+#define NL80211_MAX_SUPP_REG_RULES 128
#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0
#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16
#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_HE_MAX_CAPABILITY_LEN 54
#define NL80211_MAX_NR_CIPHER_SUITES 5
#define NL80211_MAX_NR_AKM_SUITES 2
@@ -3139,6 +3341,9 @@
* @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_AIRTIME_LINK_METRIC: airtime link metric for mesh station
+ * @NL80211_STA_INFO_ASSOC_AT_BOOTTIME: Timestamp (CLOCK_BOOTTIME, nanoseconds)
+ * of STA's association
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@@ -3184,6 +3389,8 @@
NL80211_STA_INFO_CONNECTED_TO_GATE,
NL80211_STA_INFO_TX_DURATION,
NL80211_STA_INFO_AIRTIME_WEIGHT,
+ NL80211_STA_INFO_AIRTIME_LINK_METRIC,
+ NL80211_STA_INFO_ASSOC_AT_BOOTTIME,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
@@ -3365,6 +3572,12 @@
* @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_EDMG_CHANNELS: bitmap that indicates the 2.16 GHz
+ * channel(s) that are allowed to be used for EDMG transmissions.
+ * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251.
+ * @NL80211_BAND_ATTR_EDMG_BW_CONFIG: Channel BW Configuration subfield encodes
+ * the allowed channel bandwidth configurations.
+ * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13.
* @NL80211_BAND_ATTR_MAX: highest band attribute currently defined
* @__NL80211_BAND_ATTR_AFTER_LAST: internal use
*/
@@ -3382,6 +3595,9 @@
NL80211_BAND_ATTR_VHT_CAPA,
NL80211_BAND_ATTR_IFTYPE_DATA,
+ NL80211_BAND_ATTR_EDMG_CHANNELS,
+ NL80211_BAND_ATTR_EDMG_BW_CONFIG,
+
/* keep last */
__NL80211_BAND_ATTR_AFTER_LAST,
NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
@@ -3464,6 +3680,8 @@
* @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_NO_HE: HE operation is not allowed on this channel
+ * in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -3493,6 +3711,7 @@
NL80211_FREQUENCY_ATTR_NO_20MHZ,
NL80211_FREQUENCY_ATTR_NO_10MHZ,
NL80211_FREQUENCY_ATTR_WMM,
+ NL80211_FREQUENCY_ATTR_NO_HE,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -3638,6 +3857,14 @@
* 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_PER_BAND_RSSI: Nested attribute that carries the
+ * band specific minimum rssi thresholds for the bands defined in
+ * enum nl80211_band. The minimum rssi threshold value(s32) specific to a
+ * band shall be encapsulated in attribute with type value equals to one
+ * of the NL80211_BAND_* defined in enum nl80211_band. For example, the
+ * minimum rssi threshold value for 2.4GHZ band shall be encapsulated
+ * within an attribute of type NL80211_BAND_2GHZ. And one or more of such
+ * attributes will be nested within this attribute.
* @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
* attribute number currently defined
* @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
@@ -3650,6 +3877,7 @@
NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI,
NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST,
NL80211_SCHED_SCAN_MATCH_ATTR_BSSID,
+ NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI,
/* keep last */
__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
@@ -3681,6 +3909,7 @@
* @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation
* @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed
* @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed
+ * @NL80211_RRF_NO_HE: HE operation not allowed
*/
enum nl80211_reg_rule_flags {
NL80211_RRF_NO_OFDM = 1<<0,
@@ -3698,6 +3927,7 @@
NL80211_RRF_NO_HT40PLUS = 1<<14,
NL80211_RRF_NO_80MHZ = 1<<15,
NL80211_RRF_NO_160MHZ = 1<<16,
+ NL80211_RRF_NO_HE = 1<<17,
};
#define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR
@@ -3771,6 +4001,8 @@
* @NL80211_SURVEY_INFO_TIME_SCAN: time the radio spent for scan
* (on this channel or globally)
* @NL80211_SURVEY_INFO_PAD: attribute used for padding for 64-bit alignment
+ * @NL80211_SURVEY_INFO_TIME_BSS_RX: amount of time the radio spent
+ * receiving frames destined to the local BSS
* @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
* currently defined
* @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
@@ -3787,6 +4019,7 @@
NL80211_SURVEY_INFO_TIME_TX,
NL80211_SURVEY_INFO_TIME_SCAN,
NL80211_SURVEY_INFO_PAD,
+ NL80211_SURVEY_INFO_TIME_BSS_RX,
/* keep last */
__NL80211_SURVEY_INFO_AFTER_LAST,
@@ -4135,6 +4368,27 @@
};
/**
+ * enum nl80211_key_mode - Key mode
+ *
+ * @NL80211_KEY_RX_TX: (Default)
+ * Key can be used for Rx and Tx immediately
+ *
+ * The following modes can only be selected for unicast keys and when the
+ * driver supports @NL80211_EXT_FEATURE_EXT_KEY_ID:
+ *
+ * @NL80211_KEY_NO_TX: Only allowed in combination with @NL80211_CMD_NEW_KEY:
+ * Unicast key can only be used for Rx, Tx not allowed, yet
+ * @NL80211_KEY_SET_TX: Only allowed in combination with @NL80211_CMD_SET_KEY:
+ * The unicast key identified by idx and mac is cleared for Tx and becomes
+ * the preferred Tx key for the station.
+ */
+enum nl80211_key_mode {
+ NL80211_KEY_RX_TX,
+ NL80211_KEY_NO_TX,
+ NL80211_KEY_SET_TX
+};
+
+/**
* enum nl80211_chan_width - channel width definitions
*
* These values are used with the %NL80211_ATTR_CHANNEL_WIDTH
@@ -4339,6 +4593,7 @@
enum nl80211_wpa_versions {
NL80211_WPA_VERSION_1 = 1 << 0,
NL80211_WPA_VERSION_2 = 1 << 1,
+ NL80211_WPA_VERSION_3 = 1 << 2,
};
/**
@@ -4377,6 +4632,10 @@
* @NL80211_KEY_DEFAULT_TYPES: A nested attribute containing flags
* attributes, specifying what a key should be set as default as.
* See &enum nl80211_key_default_types.
+ * @NL80211_KEY_MODE: the mode from enum nl80211_key_mode.
+ * Defaults to @NL80211_KEY_RX_TX.
+ * @NL80211_KEY_DEFAULT_BEACON: flag indicating default Beacon frame key
+ *
* @__NL80211_KEY_AFTER_LAST: internal
* @NL80211_KEY_MAX: highest key attribute
*/
@@ -4390,6 +4649,8 @@
NL80211_KEY_DEFAULT_MGMT,
NL80211_KEY_TYPE,
NL80211_KEY_DEFAULT_TYPES,
+ NL80211_KEY_MODE,
+ NL80211_KEY_DEFAULT_BEACON,
/* keep last */
__NL80211_KEY_AFTER_LAST,
@@ -4445,6 +4706,7 @@
* @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 - 69.12 GHz)
+ * @NL80211_BAND_6GHZ: around 6 GHz band (5.9 - 7.2 GHz)
* @NUM_NL80211_BANDS: number of bands, avoid using this in userspace
* since newer kernel versions may support more bands
*/
@@ -4452,6 +4714,7 @@
NL80211_BAND_2GHZ,
NL80211_BAND_5GHZ,
NL80211_BAND_60GHZ,
+ NL80211_BAND_6GHZ,
NUM_NL80211_BANDS,
};
@@ -4544,6 +4807,69 @@
};
/**
+ * enum nl80211_tid_config - TID config state
+ * @NL80211_TID_CONFIG_ENABLE: Enable config for the TID
+ * @NL80211_TID_CONFIG_DISABLE: Disable config for the TID
+ */
+enum nl80211_tid_config {
+ NL80211_TID_CONFIG_ENABLE,
+ NL80211_TID_CONFIG_DISABLE,
+};
+
+/* enum nl80211_tid_config_attr - TID specific configuration.
+ * @NL80211_TID_CONFIG_ATTR_PAD: pad attribute for 64-bit values
+ * @NL80211_TID_CONFIG_ATTR_VIF_SUPP: a bitmap (u64) of attributes supported
+ * for per-vif configuration; doesn't list the ones that are generic
+ * (%NL80211_TID_CONFIG_ATTR_TIDS, %NL80211_TID_CONFIG_ATTR_OVERRIDE).
+ * @NL80211_TID_CONFIG_ATTR_PEER_SUPP: same as the previous per-vif one, but
+ * per peer instead.
+ * @NL80211_TID_CONFIG_ATTR_OVERRIDE: flag attribute, if no peer
+ * is selected, if set indicates that the new configuration overrides
+ * all previous peer configurations, otherwise previous peer specific
+ * configurations should be left untouched. If peer is selected then
+ * it will reset particular TID configuration of that peer and it will
+ * not accept other TID config attributes along with peer.
+ * @NL80211_TID_CONFIG_ATTR_TIDS: a bitmask value of TIDs (bit 0 to 7)
+ * Its type is u16.
+ * @NL80211_TID_CONFIG_ATTR_NOACK: Configure ack policy for the TID.
+ * specified in %NL80211_TID_CONFIG_ATTR_TID. see %enum nl80211_tid_config.
+ * Its type is u8.
+ * @NL80211_TID_CONFIG_ATTR_RETRY_SHORT: Number of retries used with data frame
+ * transmission, user-space sets this configuration in
+ * &NL80211_CMD_SET_TID_CONFIG. It is u8 type, min value is 1 and
+ * the max value is advertised by the driver in this attribute on
+ * output in wiphy capabilities.
+ * @NL80211_TID_CONFIG_ATTR_RETRY_LONG: Number of retries used with data frame
+ * transmission, user-space sets this configuration in
+ * &NL80211_CMD_SET_TID_CONFIG. Its type is u8, min value is 1 and
+ * the max value is advertised by the driver in this attribute on
+ * output in wiphy capabilities.
+ * @NL80211_TID_CONFIG_ATTR_AMPDU_CTRL: Enable/Disable aggregation for the TIDs
+ * specified in %NL80211_TID_CONFIG_ATTR_TIDS. Its type is u8, using
+ * the values from &nl80211_tid_config.
+ * @NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL: Enable/Disable RTS_CTS for the TIDs
+ * specified in %NL80211_TID_CONFIG_ATTR_TIDS. It is u8 type, using
+ * the values from &nl80211_tid_config.
+ */
+enum nl80211_tid_config_attr {
+ __NL80211_TID_CONFIG_ATTR_INVALID,
+ NL80211_TID_CONFIG_ATTR_PAD,
+ NL80211_TID_CONFIG_ATTR_VIF_SUPP,
+ NL80211_TID_CONFIG_ATTR_PEER_SUPP,
+ NL80211_TID_CONFIG_ATTR_OVERRIDE,
+ NL80211_TID_CONFIG_ATTR_TIDS,
+ NL80211_TID_CONFIG_ATTR_NOACK,
+ NL80211_TID_CONFIG_ATTR_RETRY_SHORT,
+ NL80211_TID_CONFIG_ATTR_RETRY_LONG,
+ NL80211_TID_CONFIG_ATTR_AMPDU_CTRL,
+ NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL,
+
+ /* keep last */
+ __NL80211_TID_CONFIG_ATTR_AFTER_LAST,
+ NL80211_TID_CONFIG_ATTR_MAX = __NL80211_TID_CONFIG_ATTR_AFTER_LAST - 1
+};
+
+/**
* enum nl80211_packet_pattern_attr - packet pattern attribute
* @__NL80211_PKTPAT_INVALID: invalid number for nested attribute
* @NL80211_PKTPAT_PATTERN: the pattern, values where the mask has
@@ -5243,7 +5569,7 @@
NL80211_FEATURE_TDLS_CHANNEL_SWITCH = 1 << 28,
NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR = 1 << 29,
NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR = 1 << 30,
- NL80211_FEATURE_ND_RANDOM_MAC_ADDR = 1 << 31,
+ NL80211_FEATURE_ND_RANDOM_MAC_ADDR = 1U << 31,
};
/**
@@ -5335,6 +5661,8 @@
* 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_EXT_KEY_ID: Driver supports "Extended Key ID for
+ * Individually Addressed Frames" from IEEE802.11-2016.
*
* @NL80211_EXT_FEATURE_AIRTIME_FAIRNESS: Driver supports getting airtime
* fairness for transmitted packets and has enabled airtime fairness
@@ -5343,6 +5671,40 @@
* @NL80211_EXT_FEATURE_AP_PMKSA_CACHING: Driver/device supports PMKSA caching
* (set/del PMKSA operations) in AP mode.
*
+ * @NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD: Driver supports
+ * filtering of sched scan results using band specific RSSI thresholds.
+ *
+ * @NL80211_EXT_FEATURE_STA_TX_PWR: This driver supports controlling tx power
+ * to a station.
+ *
+ * @NL80211_EXT_FEATURE_SAE_OFFLOAD: Device wants to do SAE authentication in
+ * station mode (SAE password is passed as part of the connect command).
+ *
+ * @NL80211_EXT_FEATURE_VLAN_OFFLOAD: The driver supports a single netdev
+ * with VLAN tagged frames and separate VLAN-specific netdevs added using
+ * vconfig similarly to the Ethernet case.
+ *
+ * @NL80211_EXT_FEATURE_AQL: The driver supports the Airtime Queue Limit (AQL)
+ * feature, which prevents bufferbloat by using the expected transmission
+ * time to limit the amount of data buffered in the hardware.
+ *
+ * @NL80211_EXT_FEATURE_BEACON_PROTECTION: The driver supports Beacon protection
+ * and can receive key configuration for BIGTK using key indexes 6 and 7.
+ * @NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT: The driver supports Beacon
+ * protection as a client only and cannot transmit protected beacons.
+ *
+ * @NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH: The driver can disable the
+ * forwarding of preauth frames over the control port. They are then
+ * handled as ordinary data frames.
+ *
+ * @NL80211_EXT_FEATURE_PROTECTED_TWT: Driver supports protected TWT frames
+ *
+ * @NL80211_EXT_FEATURE_DEL_IBSS_STA: The driver supports removing stations
+ * in IBSS mode, essentially by dropping their state.
+ *
+ * @NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS: management frame registrations
+ * are possible for multicast frames and those will be reported properly.
+ *
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@@ -5384,6 +5746,18 @@
NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER,
NL80211_EXT_FEATURE_AIRTIME_FAIRNESS,
NL80211_EXT_FEATURE_AP_PMKSA_CACHING,
+ NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD,
+ NL80211_EXT_FEATURE_EXT_KEY_ID,
+ NL80211_EXT_FEATURE_STA_TX_PWR,
+ NL80211_EXT_FEATURE_SAE_OFFLOAD,
+ NL80211_EXT_FEATURE_VLAN_OFFLOAD,
+ NL80211_EXT_FEATURE_AQL,
+ NL80211_EXT_FEATURE_BEACON_PROTECTION,
+ NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH,
+ NL80211_EXT_FEATURE_PROTECTED_TWT,
+ NL80211_EXT_FEATURE_DEL_IBSS_STA,
+ NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS,
+ NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@@ -6006,12 +6380,14 @@
* @NL80211_PREAMBLE_HT: HT preamble
* @NL80211_PREAMBLE_VHT: VHT preamble
* @NL80211_PREAMBLE_DMG: DMG preamble
+ * @NL80211_PREAMBLE_HE: HE preamble
*/
enum nl80211_preamble {
NL80211_PREAMBLE_LEGACY,
NL80211_PREAMBLE_HT,
NL80211_PREAMBLE_VHT,
NL80211_PREAMBLE_DMG,
+ NL80211_PREAMBLE_HE,
};
/**
@@ -6204,6 +6580,10 @@
* 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)
+ * @NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED: flag attribute indicating if
+ * trigger based ranging measurement is supported
+ * @NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED: flag attribute indicating
+ * if non trigger based ranging measurement is supported
*
* @NUM_NL80211_PMSR_FTM_CAPA_ATTR: internal
* @NL80211_PMSR_FTM_CAPA_ATTR_MAX: highest attribute number
@@ -6219,6 +6599,8 @@
NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS,
NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT,
NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST,
+ NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED,
+ NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED,
/* keep last */
NUM_NL80211_PMSR_FTM_CAPA_ATTR,
@@ -6248,6 +6630,20 @@
* @NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI: request LCI data (flag)
* @NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC: request civic location data
* (flag)
+ * @NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED: request trigger based ranging
+ * measurement (flag).
+ * This attribute and %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED are
+ * mutually exclusive.
+ * if neither %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED nor
+ * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set, EDCA based
+ * ranging will be used.
+ * @NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED: request non trigger based
+ * ranging measurement (flag)
+ * This attribute and %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED are
+ * mutually exclusive.
+ * if neither %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED nor
+ * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set, EDCA based
+ * ranging will be used.
*
* @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal
* @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number
@@ -6264,6 +6660,8 @@
NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES,
NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI,
NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC,
+ NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED,
+ NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED,
/* keep last */
NUM_NL80211_PMSR_FTM_REQ_ATTR,
@@ -6382,4 +6780,72 @@
NL80211_PMSR_FTM_RESP_ATTR_MAX = NUM_NL80211_PMSR_FTM_RESP_ATTR - 1
};
+/**
+ * enum nl80211_obss_pd_attributes - OBSS packet detection attributes
+ * @__NL80211_HE_OBSS_PD_ATTR_INVALID: Invalid
+ *
+ * @NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET: the OBSS PD minimum tx power offset.
+ * @NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET: the OBSS PD maximum tx power offset.
+ *
+ * @__NL80211_HE_OBSS_PD_ATTR_LAST: Internal
+ * @NL80211_HE_OBSS_PD_ATTR_MAX: highest OBSS PD attribute.
+ */
+enum nl80211_obss_pd_attributes {
+ __NL80211_HE_OBSS_PD_ATTR_INVALID,
+
+ NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
+ NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET,
+
+ /* keep last */
+ __NL80211_HE_OBSS_PD_ATTR_LAST,
+ NL80211_HE_OBSS_PD_ATTR_MAX = __NL80211_HE_OBSS_PD_ATTR_LAST - 1,
+};
+
+/**
+ * enum nl80211_bss_color_attributes - BSS Color attributes
+ * @__NL80211_HE_BSS_COLOR_ATTR_INVALID: Invalid
+ *
+ * @NL80211_HE_BSS_COLOR_ATTR_COLOR: the current BSS Color.
+ * @NL80211_HE_BSS_COLOR_ATTR_DISABLED: is BSS coloring disabled.
+ * @NL80211_HE_BSS_COLOR_ATTR_PARTIAL: the AID equation to be used..
+ *
+ * @__NL80211_HE_BSS_COLOR_ATTR_LAST: Internal
+ * @NL80211_HE_BSS_COLOR_ATTR_MAX: highest BSS Color attribute.
+ */
+enum nl80211_bss_color_attributes {
+ __NL80211_HE_BSS_COLOR_ATTR_INVALID,
+
+ NL80211_HE_BSS_COLOR_ATTR_COLOR,
+ NL80211_HE_BSS_COLOR_ATTR_DISABLED,
+ NL80211_HE_BSS_COLOR_ATTR_PARTIAL,
+
+ /* keep last */
+ __NL80211_HE_BSS_COLOR_ATTR_LAST,
+ NL80211_HE_BSS_COLOR_ATTR_MAX = __NL80211_HE_BSS_COLOR_ATTR_LAST - 1,
+};
+
+/**
+ * enum nl80211_iftype_akm_attributes - interface type AKM attributes
+ * @__NL80211_IFTYPE_AKM_ATTR_INVALID: Invalid
+ *
+ * @NL80211_IFTYPE_AKM_ATTR_IFTYPES: nested attribute containing a flag
+ * attribute for each interface type that supports AKM suites specified in
+ * %NL80211_IFTYPE_AKM_ATTR_SUITES
+ * @NL80211_IFTYPE_AKM_ATTR_SUITES: an array of u32. Used to indicate supported
+ * AKM suites for the specified interface types.
+ *
+ * @__NL80211_IFTYPE_AKM_ATTR_LAST: Internal
+ * @NL80211_IFTYPE_AKM_ATTR_MAX: highest interface type AKM attribute.
+ */
+enum nl80211_iftype_akm_attributes {
+ __NL80211_IFTYPE_AKM_ATTR_INVALID,
+
+ NL80211_IFTYPE_AKM_ATTR_IFTYPES,
+ NL80211_IFTYPE_AKM_ATTR_SUITES,
+
+ /* keep last */
+ __NL80211_IFTYPE_AKM_ATTR_LAST,
+ NL80211_IFTYPE_AKM_ATTR_MAX = __NL80211_IFTYPE_AKM_ATTR_LAST - 1,
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/src/eap_common/eap_common.c b/src/eap_common/eap_common.c
index 51a15d7..e27b965 100644
--- a/src/eap_common/eap_common.c
+++ b/src/eap_common/eap_common.c
@@ -63,7 +63,7 @@
* the payload regardless of whether the packet used the expanded EAP header or
* not.
*/
-const u8 * eap_hdr_validate(int vendor, EapType eap_type,
+const u8 * eap_hdr_validate(int vendor, enum eap_type eap_type,
const struct wpabuf *msg, size_t *plen)
{
const struct eap_hdr *hdr;
@@ -125,8 +125,8 @@
* function to allocate the message buffers. The returned buffer has room for
* payload_len bytes and has the EAP header and Type field already filled in.
*/
-struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
- u8 code, u8 identifier)
+struct wpabuf * eap_msg_alloc(int vendor, enum eap_type type,
+ size_t payload_len, u8 code, u8 identifier)
{
struct wpabuf *buf;
struct eap_hdr *hdr;
@@ -196,7 +196,7 @@
* @msg: Buffer starting with an EAP header
* Returns: The EAP Type after the EAP header
*/
-EapType eap_get_type(const struct wpabuf *msg)
+enum eap_type eap_get_type(const struct wpabuf *msg)
{
if (wpabuf_len(msg) < sizeof(struct eap_hdr) + 1)
return EAP_TYPE_NONE;
diff --git a/src/eap_common/eap_common.h b/src/eap_common/eap_common.h
index e62f167..e40cabe 100644
--- a/src/eap_common/eap_common.h
+++ b/src/eap_common/eap_common.h
@@ -20,13 +20,13 @@
};
int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload);
-const u8 * eap_hdr_validate(int vendor, EapType eap_type,
+const u8 * eap_hdr_validate(int vendor, enum eap_type eap_type,
const struct wpabuf *msg, size_t *plen);
-struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
- u8 code, u8 identifier);
+struct wpabuf * eap_msg_alloc(int vendor, enum eap_type type,
+ size_t payload_len, u8 code, u8 identifier);
void eap_update_len(struct wpabuf *msg);
u8 eap_get_id(const struct wpabuf *msg);
-EapType eap_get_type(const struct wpabuf *msg);
+enum eap_type eap_get_type(const struct wpabuf *msg);
int erp_parse_tlvs(const u8 *pos, const u8 *end, struct erp_tlvs *tlvs,
int stop_at_keyname);
diff --git a/src/eap_common/eap_defs.h b/src/eap_common/eap_defs.h
index 54f26ca..70999c4 100644
--- a/src/eap_common/eap_defs.h
+++ b/src/eap_common/eap_defs.h
@@ -64,7 +64,7 @@
* EAP Method Types as allocated by IANA:
* http://www.iana.org/assignments/eap-numbers
*/
-typedef enum {
+enum eap_type {
EAP_TYPE_NONE = 0,
EAP_TYPE_IDENTITY = 1 /* RFC 3748 */,
EAP_TYPE_NOTIFICATION = 2 /* RFC 3748 */,
@@ -92,8 +92,9 @@
EAP_TYPE_GPSK = 51 /* RFC 5433 */,
EAP_TYPE_PWD = 52 /* RFC 5931 */,
EAP_TYPE_EKE = 53 /* RFC 6124 */,
+ EAP_TYPE_TEAP = 55 /* RFC 7170 */,
EAP_TYPE_EXPANDED = 254 /* RFC 3748 */
-} EapType;
+};
/* SMI Network Management Private Enterprise Code for vendor specific types */
diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
index 6ca2c8b..2b2b8ef 100644
--- a/src/eap_common/eap_pwd_common.c
+++ b/src/eap_common/eap_pwd_common.c
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
#include "utils/const_time.h"
+#include "common/dragonfly.h"
#include "crypto/sha256.h"
#include "crypto/crypto.h"
#include "eap_defs.h"
@@ -85,20 +86,11 @@
}
-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)) {
+ if (!dragonfly_suitable_group(num, 1)) {
wpa_printf(MSG_INFO, "EAP-pwd: unsuitable group %u", num);
return NULL;
}
@@ -119,15 +111,6 @@
}
-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.
@@ -138,23 +121,24 @@
const u8 *id_peer, size_t id_peer_len,
const u8 *token)
{
- struct crypto_bignum *qr = NULL, *qnr = NULL, *one = NULL;
- struct crypto_bignum *qr_or_qnr = NULL;
+ struct crypto_bignum *qr = NULL, *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_bignum *tmp2 = NULL;
struct crypto_hash *hash;
unsigned char pwe_digest[SHA256_MAC_LEN], *prfbuf = NULL, ctr;
- int ret = 0, check, res;
+ int ret = 0, 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;
+ u8 found_ctr = 0, is_odd = 0;
+ int cmp_prime;
+ unsigned int in_range;
if (grp->pwe)
return -1;
@@ -168,10 +152,7 @@
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) {
+ if (!grp->pwe) {
wpa_printf(MSG_INFO, "EAP-pwd: unable to create bignums");
goto fail;
}
@@ -181,25 +162,10 @@
"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),
+ if (dragonfly_get_random_qr_qnr(prime, &qr, &qnr) < 0 ||
+ crypto_bignum_to_bin(qr, qr_bin, sizeof(qr_bin),
primebytelen) < 0 ||
crypto_bignum_to_bin(qnr, qnr_bin, sizeof(qnr_bin),
primebytelen) < 0)
@@ -241,8 +207,13 @@
if (primebitlen % 8)
buf_shift_right(prfbuf, primebytelen,
8 - primebitlen % 8);
- if (const_time_memcmp(prfbuf, prime_bin, primebytelen) >= 0)
- continue;
+ cmp_prime = const_time_memcmp(prfbuf, prime_bin, primebytelen);
+ /* Create a const_time mask for selection based on prf result
+ * being smaller than prime. */
+ in_range = const_time_fill_msb((unsigned int) cmp_prime);
+ /* The algorithm description would skip the next steps if
+ * cmp_prime >= 0, but go through them regardless to minimize
+ * externally observable differences in behavior. */
crypto_bignum_deinit(x_candidate, 1);
x_candidate = crypto_bignum_init_set(prfbuf, primebytelen);
@@ -267,46 +238,16 @@
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)
+ res = dragonfly_is_quadratic_residue_blind(grp->group, qr_bin,
+ qnr_bin, tmp2);
+ if (res < 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;
+ /* found is 0 or 0xff here and res is 0 or 1. Bitwise OR of them
+ * (with res converted to 0/0xff and masked with prf being below
+ * prime) handles this in constant time.
+ */
+ found |= (res & in_range) * 0xff;
}
if (found == 0) {
wpa_printf(MSG_INFO,
@@ -347,13 +288,9 @@
}
/* cleanliness and order.... */
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));
@@ -507,25 +444,6 @@
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;
+ return dragonfly_generate_scalar(crypto_ec_get_order(group->group),
+ _rand, _mask, scalar);
}
diff --git a/src/eap_common/eap_sake_common.c b/src/eap_common/eap_sake_common.c
index 8819541..8ee9e32 100644
--- a/src/eap_common/eap_sake_common.c
+++ b/src/eap_common/eap_sake_common.c
@@ -1,6 +1,6 @@
/*
* EAP server/peer: EAP-SAKE shared routines
- * Copyright (c) 2006-2007, 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.
@@ -201,14 +201,15 @@
* @data2_len: Length of the data2
* @buf: Buffer for the generated pseudo-random key
* @buf_len: Number of bytes of key to generate
+ * Returns: 0 on success or -1 on failure
*
* This function is used to derive new, cryptographically separate keys from a
* given key (e.g., SMS). This is identical to the PRF used in IEEE 802.11i.
*/
-static void eap_sake_kdf(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len,
- const u8 *data2, size_t data2_len,
- u8 *buf, size_t buf_len)
+static int eap_sake_kdf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len,
+ const u8 *data2, size_t data2_len,
+ u8 *buf, size_t buf_len)
{
u8 counter = 0;
size_t pos, plen;
@@ -230,17 +231,21 @@
while (pos < buf_len) {
plen = buf_len - pos;
if (plen >= SHA1_MAC_LEN) {
- hmac_sha1_vector(key, key_len, 4, addr, len,
- &buf[pos]);
+ if (hmac_sha1_vector(key, key_len, 4, addr, len,
+ &buf[pos]) < 0)
+ return -1;
pos += SHA1_MAC_LEN;
} else {
- hmac_sha1_vector(key, key_len, 4, addr, len,
- hash);
+ if (hmac_sha1_vector(key, key_len, 4, addr, len,
+ hash) < 0)
+ return -1;
os_memcpy(&buf[pos], hash, plen);
break;
}
counter++;
}
+
+ return 0;
}
@@ -253,12 +258,13 @@
* @tek: Buffer for Temporary EAK Keys (TEK-Auth[16] | TEK-Cipher[16])
* @msk: Buffer for 64-byte MSK
* @emsk: Buffer for 64-byte EMSK
+ * Returns: 0 on success or -1 on failure
*
* This function derives EAP-SAKE keys as defined in RFC 4763, section 3.2.6.
*/
-void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
- const u8 *rand_s, const u8 *rand_p, u8 *tek, u8 *msk,
- u8 *emsk)
+int eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
+ const u8 *rand_s, const u8 *rand_p, u8 *tek, u8 *msk,
+ u8 *emsk)
{
u8 sms_a[EAP_SAKE_SMS_LEN];
u8 sms_b[EAP_SAKE_SMS_LEN];
@@ -268,14 +274,16 @@
wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-A",
root_secret_a, EAP_SAKE_ROOT_SECRET_LEN);
- eap_sake_kdf(root_secret_a, EAP_SAKE_ROOT_SECRET_LEN,
- "SAKE Master Secret A",
- rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
- sms_a, EAP_SAKE_SMS_LEN);
+ if (eap_sake_kdf(root_secret_a, EAP_SAKE_ROOT_SECRET_LEN,
+ "SAKE Master Secret A",
+ rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
+ sms_a, EAP_SAKE_SMS_LEN) < 0)
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-A", sms_a, EAP_SAKE_SMS_LEN);
- eap_sake_kdf(sms_a, EAP_SAKE_SMS_LEN, "Transient EAP Key",
- rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
- tek, EAP_SAKE_TEK_LEN);
+ if (eap_sake_kdf(sms_a, EAP_SAKE_SMS_LEN, "Transient EAP Key",
+ rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
+ tek, EAP_SAKE_TEK_LEN) < 0)
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Auth",
tek, EAP_SAKE_TEK_AUTH_LEN);
wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Cipher",
@@ -283,18 +291,21 @@
wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-B",
root_secret_b, EAP_SAKE_ROOT_SECRET_LEN);
- eap_sake_kdf(root_secret_b, EAP_SAKE_ROOT_SECRET_LEN,
- "SAKE Master Secret B",
- rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
- sms_b, EAP_SAKE_SMS_LEN);
+ if (eap_sake_kdf(root_secret_b, EAP_SAKE_ROOT_SECRET_LEN,
+ "SAKE Master Secret B",
+ rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
+ sms_b, EAP_SAKE_SMS_LEN) < 0)
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-B", sms_b, EAP_SAKE_SMS_LEN);
- eap_sake_kdf(sms_b, EAP_SAKE_SMS_LEN, "Master Session Key",
- rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
- key_buf, sizeof(key_buf));
+ if (eap_sake_kdf(sms_b, EAP_SAKE_SMS_LEN, "Master Session Key",
+ rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
+ key_buf, sizeof(key_buf)) < 0)
+ return -1;
os_memcpy(msk, key_buf, EAP_MSK_LEN);
os_memcpy(emsk, key_buf + EAP_MSK_LEN, EAP_EMSK_LEN);
wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: MSK", msk, EAP_MSK_LEN);
wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: EMSK", emsk, EAP_EMSK_LEN);
+ return 0;
}
@@ -312,6 +323,7 @@
* @eap_len: EAP packet length
* @mic_pos: MIC position in the EAP packet (must be [eap .. eap + eap_len])
* @mic: Buffer for the computed 16-byte MIC
+ * Returns: 0 on success or -1 on failure
*/
int eap_sake_compute_mic(const u8 *tek_auth,
const u8 *rand_s, const u8 *rand_p,
@@ -323,6 +335,7 @@
u8 _rand[2 * EAP_SAKE_RAND_LEN];
u8 *tmp, *pos;
size_t tmplen;
+ int ret;
tmplen = serverid_len + 1 + peerid_len + 1 + eap_len;
tmp = os_malloc(tmplen);
@@ -364,14 +377,14 @@
os_memcpy(pos, eap, eap_len);
os_memset(pos + (mic_pos - eap), 0, EAP_SAKE_MIC_LEN);
- eap_sake_kdf(tek_auth, EAP_SAKE_TEK_AUTH_LEN,
- peer ? "Peer MIC" : "Server MIC",
- _rand, 2 * EAP_SAKE_RAND_LEN, tmp, tmplen,
- mic, EAP_SAKE_MIC_LEN);
+ ret = eap_sake_kdf(tek_auth, EAP_SAKE_TEK_AUTH_LEN,
+ peer ? "Peer MIC" : "Server MIC",
+ _rand, 2 * EAP_SAKE_RAND_LEN, tmp, tmplen,
+ mic, EAP_SAKE_MIC_LEN);
os_free(tmp);
- return 0;
+ return ret;
}
diff --git a/src/eap_common/eap_sake_common.h b/src/eap_common/eap_sake_common.h
index 9e1e757..a817a35 100644
--- a/src/eap_common/eap_sake_common.h
+++ b/src/eap_common/eap_sake_common.h
@@ -1,6 +1,6 @@
/*
* EAP server/peer: EAP-SAKE shared routines
- * Copyright (c) 2006-2007, 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.
@@ -81,9 +81,9 @@
int eap_sake_parse_attributes(const u8 *buf, size_t len,
struct eap_sake_parse_attr *attr);
-void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
- const u8 *rand_s, const u8 *rand_p,
- u8 *tek, u8 *msk, u8 *emsk);
+int eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
+ const u8 *rand_s, const u8 *rand_p,
+ u8 *tek, u8 *msk, u8 *emsk);
int eap_sake_compute_mic(const u8 *tek_auth,
const u8 *rand_s, const u8 *rand_p,
const u8 *serverid, size_t serverid_len,
diff --git a/src/eap_common/eap_sim_common.c b/src/eap_common/eap_sim_common.c
index cfdd1bf..4a93244 100644
--- a/src/eap_common/eap_sim_common.c
+++ b/src/eap_common/eap_sim_common.c
@@ -945,10 +945,15 @@
if (decrypted == NULL)
return NULL;
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Skip AES-128-CBC decryption for fuzz testing");
+#else /* TEST_FUZZ */
if (aes_128_cbc_decrypt(k_encr, iv, decrypted, encr_data_len)) {
os_free(decrypted);
return NULL;
}
+#endif /* TEST_FUZZ */
wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA",
decrypted, encr_data_len);
@@ -1214,6 +1219,10 @@
os_memcmp(id, anonymous_id_prefix, anonymous_id_len) == 0)
return 1; /* 'anonymous@realm' */
+ if (id_len > anonymous_id_len + 1 &&
+ os_memcmp(id + 1, anonymous_id_prefix, anonymous_id_len) == 0)
+ return 1; /* 'Xanonymous@realm' where X is an EAP method code */
+
if (id_len > 1 && id[0] == '@')
return 1; /* '@realm' */
diff --git a/src/eap_common/eap_teap_common.c b/src/eap_common/eap_teap_common.c
new file mode 100644
index 0000000..ffb9a62
--- /dev/null
+++ b/src/eap_common/eap_teap_common.c
@@ -0,0 +1,744 @@
+/*
+ * EAP-TEAP common helper functions (RFC 7170)
+ * Copyright (c) 2008-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/sha1.h"
+#include "crypto/sha256.h"
+#include "crypto/sha384.h"
+#include "crypto/tls.h"
+#include "eap_defs.h"
+#include "eap_teap_common.h"
+
+
+static int tls_cipher_suite_mac_sha384(u16 cs);
+
+
+void eap_teap_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len)
+{
+ struct teap_tlv_hdr hdr;
+
+ hdr.tlv_type = host_to_be16(type);
+ hdr.length = host_to_be16(len);
+ wpabuf_put_data(buf, &hdr, sizeof(hdr));
+}
+
+
+void eap_teap_put_tlv(struct wpabuf *buf, u16 type, const void *data, u16 len)
+{
+ eap_teap_put_tlv_hdr(buf, type, len);
+ wpabuf_put_data(buf, data, len);
+}
+
+
+void eap_teap_put_tlv_buf(struct wpabuf *buf, u16 type,
+ const struct wpabuf *data)
+{
+ eap_teap_put_tlv_hdr(buf, type, wpabuf_len(data));
+ wpabuf_put_buf(buf, data);
+}
+
+
+struct wpabuf * eap_teap_tlv_eap_payload(struct wpabuf *buf)
+{
+ struct wpabuf *e;
+
+ if (!buf)
+ return NULL;
+
+ /* Encapsulate EAP packet in EAP-Payload TLV */
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Add EAP-Payload TLV");
+ e = wpabuf_alloc(sizeof(struct teap_tlv_hdr) + wpabuf_len(buf));
+ if (!e) {
+ wpa_printf(MSG_ERROR,
+ "EAP-TEAP: Failed to allocate memory for TLV encapsulation");
+ wpabuf_free(buf);
+ return NULL;
+ }
+ eap_teap_put_tlv_buf(e, TEAP_TLV_MANDATORY | TEAP_TLV_EAP_PAYLOAD, buf);
+ wpabuf_free(buf);
+
+ /* TODO: followed by optional TLVs associated with the EAP packet */
+
+ return e;
+}
+
+
+static int eap_teap_tls_prf(u16 tls_cs, const u8 *secret, size_t secret_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *out, size_t outlen)
+{
+ /* TODO: TLS-PRF for TLSv1.3 */
+ if (tls_cipher_suite_mac_sha384(tls_cs))
+ return tls_prf_sha384(secret, secret_len, label, seed, seed_len,
+ out, outlen);
+ return tls_prf_sha256(secret, secret_len, label, seed, seed_len,
+ out, outlen);
+}
+
+
+int eap_teap_derive_eap_msk(u16 tls_cs, const u8 *simck, u8 *msk)
+{
+ /*
+ * RFC 7170, Section 5.4: EAP Master Session Key Generation
+ * MSK = TLS-PRF(S-IMCK[j], "Session Key Generating Function", 64)
+ */
+
+ if (eap_teap_tls_prf(tls_cs, simck, EAP_TEAP_SIMCK_LEN,
+ "Session Key Generating Function", (u8 *) "", 0,
+ msk, EAP_TEAP_KEY_LEN) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Derived key (MSK)",
+ msk, EAP_TEAP_KEY_LEN);
+ return 0;
+}
+
+
+int eap_teap_derive_eap_emsk(u16 tls_cs, const u8 *simck, u8 *emsk)
+{
+ /*
+ * RFC 7170, Section 5.4: EAP Master Session Key Generation
+ * EMSK = TLS-PRF(S-IMCK[j],
+ * "Extended Session Key Generating Function", 64)
+ */
+
+ if (eap_teap_tls_prf(tls_cs, simck, EAP_TEAP_SIMCK_LEN,
+ "Extended Session Key Generating Function",
+ (u8 *) "", 0, emsk, EAP_EMSK_LEN) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Derived key (EMSK)",
+ emsk, EAP_EMSK_LEN);
+ return 0;
+}
+
+
+int eap_teap_derive_cmk_basic_pw_auth(u16 tls_cs, const u8 *s_imck_msk, u8 *cmk)
+{
+ u8 imsk[32], imck[EAP_TEAP_IMCK_LEN];
+ int res;
+
+ /* FIX: The Basic-Password-Auth (i.e., no inner EAP) case is
+ * not fully defined in RFC 7170, so this CMK derivation may
+ * need to be changed if a fixed definition is eventually
+ * published. For now, derive CMK[0] based on S-IMCK[0] and
+ * IMSK of 32 octets of zeros. */
+ os_memset(imsk, 0, 32);
+ res = eap_teap_tls_prf(tls_cs, s_imck_msk, EAP_TEAP_SIMCK_LEN,
+ "Inner Methods Compound Keys",
+ imsk, 32, imck, sizeof(imck));
+ if (res < 0)
+ return -1;
+ os_memcpy(cmk, &imck[EAP_TEAP_SIMCK_LEN], EAP_TEAP_CMK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: CMK[no-inner-EAP]",
+ cmk, EAP_TEAP_CMK_LEN);
+ forced_memzero(imck, sizeof(imck));
+ return 0;
+}
+
+
+int eap_teap_derive_imck(u16 tls_cs,
+ const u8 *prev_s_imck_msk, const u8 *prev_s_imck_emsk,
+ const u8 *msk, size_t msk_len,
+ const u8 *emsk, size_t emsk_len,
+ u8 *s_imck_msk, u8 *cmk_msk,
+ u8 *s_imck_emsk, u8 *cmk_emsk)
+{
+ u8 imsk[64], imck[EAP_TEAP_IMCK_LEN];
+ int res;
+
+ /*
+ * RFC 7170, Section 5.2:
+ * IMSK = First 32 octets of TLS-PRF(EMSK, "TEAPbindkey@ietf.org" |
+ * "\0" | 64)
+ * (if EMSK is not available, MSK is used instead; if neither is
+ * available, IMSK is 32 octets of zeros; MSK is truncated to 32 octets
+ * or padded to 32 octets, if needed)
+ * (64 is encoded as a 2-octet field in network byte order)
+ *
+ * S-IMCK[0] = session_key_seed
+ * IMCK[j] = TLS-PRF(S-IMCK[j-1], "Inner Methods Compound Keys",
+ * IMSK[j], 60)
+ * S-IMCK[j] = first 40 octets of IMCK[j]
+ * CMK[j] = last 20 octets of IMCK[j]
+ */
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: MSK[j]", msk, msk_len);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: EMSK[j]", emsk, emsk_len);
+
+ if (emsk && emsk_len > 0) {
+ u8 context[3];
+
+ context[0] = 0;
+ context[1] = 0;
+ context[2] = 64;
+ if (eap_teap_tls_prf(tls_cs, emsk, emsk_len,
+ "TEAPbindkey@ietf.org",
+ context, sizeof(context), imsk, 64) < 0)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: IMSK from EMSK",
+ imsk, 32);
+
+ res = eap_teap_tls_prf(tls_cs,
+ prev_s_imck_emsk, EAP_TEAP_SIMCK_LEN,
+ "Inner Methods Compound Keys",
+ imsk, 32, imck, EAP_TEAP_IMCK_LEN);
+ forced_memzero(imsk, sizeof(imsk));
+ if (res < 0)
+ return -1;
+
+ os_memcpy(s_imck_emsk, imck, EAP_TEAP_SIMCK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: EMSK S-IMCK[j]",
+ s_imck_emsk, EAP_TEAP_SIMCK_LEN);
+ os_memcpy(cmk_emsk, &imck[EAP_TEAP_SIMCK_LEN],
+ EAP_TEAP_CMK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: EMSK CMK[j]",
+ cmk_emsk, EAP_TEAP_CMK_LEN);
+ forced_memzero(imck, EAP_TEAP_IMCK_LEN);
+ }
+
+ if (msk && msk_len > 0) {
+ size_t copy_len = msk_len;
+
+ os_memset(imsk, 0, 32); /* zero pad, if needed */
+ if (copy_len > 32)
+ copy_len = 32;
+ os_memcpy(imsk, msk, copy_len);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: IMSK from MSK", imsk, 32);
+ } else {
+ os_memset(imsk, 0, 32);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Zero IMSK", imsk, 32);
+ }
+
+ res = eap_teap_tls_prf(tls_cs, prev_s_imck_msk, EAP_TEAP_SIMCK_LEN,
+ "Inner Methods Compound Keys",
+ imsk, 32, imck, EAP_TEAP_IMCK_LEN);
+ forced_memzero(imsk, sizeof(imsk));
+ if (res < 0)
+ return -1;
+
+ os_memcpy(s_imck_msk, imck, EAP_TEAP_SIMCK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: MSK S-IMCK[j]",
+ s_imck_msk, EAP_TEAP_SIMCK_LEN);
+ os_memcpy(cmk_msk, &imck[EAP_TEAP_SIMCK_LEN], EAP_TEAP_CMK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: MSK CMK[j]",
+ cmk_msk, EAP_TEAP_CMK_LEN);
+ forced_memzero(imck, EAP_TEAP_IMCK_LEN);
+
+ return 0;
+}
+
+
+static int tls_cipher_suite_match(const u16 *list, size_t count, u16 cs)
+{
+ size_t i;
+
+ for (i = 0; i < count; i++) {
+ if (list[i] == cs)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int tls_cipher_suite_mac_sha1(u16 cs)
+{
+ static const u16 sha1_cs[] = {
+ 0x0005, 0x0007, 0x000a, 0x000d, 0x0010, 0x0013, 0x0016, 0x001b,
+ 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036,
+ 0x0037, 0x0038, 0x0039, 0x003a, 0x0041, 0x0042, 0x0043, 0x0044,
+ 0x0045, 0x0046, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089,
+ 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091,
+ 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099,
+ 0x009a, 0x009b,
+ 0xc002, 0xc003, 0xc004, 0xc005, 0xc007, 0xc008, 0xc009, 0xc009,
+ 0xc00a, 0xc00c, 0xc00d, 0xc00e, 0xc00f, 0xc011, 0xc012, 0xc013,
+ 0xc014, 0xc016, 0xc017, 0xc018, 0xc019, 0xc01a, 0xc01b, 0xc01c,
+ 0xc014, 0xc01e, 0xc01f, 0xc020, 0xc021, 0xc022, 0xc033, 0xc034,
+ 0xc035, 0xc036
+ };
+
+ return tls_cipher_suite_match(sha1_cs, ARRAY_SIZE(sha1_cs), cs);
+}
+
+
+static int tls_cipher_suite_mac_sha256(u16 cs)
+{
+ static const u16 sha256_cs[] = {
+ 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0067, 0x0068, 0x0069,
+ 0x006a, 0x006b, 0x006c, 0x006d, 0x009c, 0x009e, 0x00a0, 0x00a2,
+ 0x00a4, 0x00a6, 0x00a8, 0x00aa, 0x00ac, 0x00ae, 0x00b2, 0x00b6,
+ 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bd, 0x00be, 0x00be,
+ 0x00bf, 0x00bf, 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5,
+ 0x1301, 0x1303, 0x1304, 0x1305,
+ 0xc023, 0xc025, 0xc027, 0xc029, 0xc02b, 0xc02d, 0xc02f, 0xc031,
+ 0xc037, 0xc03c, 0xc03e, 0xc040, 0xc040, 0xc042, 0xc044, 0xc046,
+ 0xc048, 0xc04a, 0xc04c, 0xc04e, 0xc050, 0xc052, 0xc054, 0xc056,
+ 0xc058, 0xc05a, 0xc05c, 0xc05e, 0xc060, 0xc062, 0xc064, 0xc066,
+ 0xc068, 0xc06a, 0xc06c, 0xc06e, 0xc070, 0xc072, 0xc074, 0xc076,
+ 0xc078, 0xc07a, 0xc07c, 0xc07e, 0xc080, 0xc082, 0xc084, 0xc086,
+ 0xc088, 0xc08a, 0xc08c, 0xc08e, 0xc090, 0xc092, 0xc094, 0xc096,
+ 0xc098, 0xc09a, 0xc0b0, 0xc0b2, 0xc0b4,
+ 0xcca8, 0xcca9, 0xccaa, 0xccab, 0xccac, 0xccad, 0xccae,
+ 0xd001, 0xd003, 0xd005
+ };
+
+ return tls_cipher_suite_match(sha256_cs, ARRAY_SIZE(sha256_cs), cs);
+}
+
+
+static int tls_cipher_suite_mac_sha384(u16 cs)
+{
+ static const u16 sha384_cs[] = {
+ 0x009d, 0x009f, 0x00a1, 0x00a3, 0x00a5, 0x00a7, 0x00a9, 0x00ab,
+ 0x00ad, 0x00af, 0x00b3, 0x00b7, 0x1302,
+ 0xc024, 0xc026, 0xc028, 0xc02a, 0xc02c, 0xc02e, 0xc030, 0xc032,
+ 0xc038, 0xc03d, 0xc03f, 0xc041, 0xc043, 0xc045, 0xc047, 0xc049,
+ 0xc04b, 0xc04d, 0xc04f, 0xc051, 0xc053, 0xc055, 0xc057, 0xc059,
+ 0xc05b, 0xc05d, 0xc05f, 0xc061, 0xc063, 0xc065, 0xc067, 0xc069,
+ 0xc06b, 0xc06d, 0xc06f, 0xc071, 0xc073, 0xc075, 0xc077, 0xc079,
+ 0xc07b, 0xc07d, 0xc07f, 0xc081, 0xc083, 0xc085, 0xc087, 0xc089,
+ 0xc08b, 0xc08d, 0xc08f, 0xc091, 0xc093, 0xc095, 0xc097, 0xc099,
+ 0xc09b, 0xc0b1, 0xc0b3, 0xc0b5,
+ 0xd002
+ };
+
+ return tls_cipher_suite_match(sha384_cs, ARRAY_SIZE(sha384_cs), cs);
+}
+
+
+static int eap_teap_tls_mac(u16 tls_cs, const u8 *cmk, size_t cmk_len,
+ const u8 *buffer, size_t buffer_len,
+ u8 *mac, size_t mac_len)
+{
+ int res;
+ u8 tmp[48];
+
+ os_memset(tmp, 0, sizeof(tmp));
+ os_memset(mac, 0, mac_len);
+
+ if (tls_cipher_suite_mac_sha1(tls_cs)) {
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: MAC algorithm: HMAC-SHA1");
+ res = hmac_sha1(cmk, cmk_len, buffer, buffer_len, tmp);
+ } else if (tls_cipher_suite_mac_sha256(tls_cs)) {
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: MAC algorithm: HMAC-SHA256");
+ res = hmac_sha256(cmk, cmk_len, buffer, buffer_len, tmp);
+ } else if (tls_cipher_suite_mac_sha384(tls_cs)) {
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: MAC algorithm: HMAC-SHA384");
+ res = hmac_sha384(cmk, cmk_len, buffer, buffer_len, tmp);
+ } else {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Unsupported TLS cipher suite 0x%04x",
+ tls_cs);
+ res = -1;
+ }
+ if (res < 0)
+ return res;
+
+ /* FIX: RFC 7170 does not describe how to handle truncation of the
+ * Compound MAC or if the fields are supposed to be of variable length
+ * based on the negotiated TLS cipher suite (they are defined as having
+ * fixed size of 20 octets in the TLV description) */
+ if (mac_len > sizeof(tmp))
+ mac_len = sizeof(tmp);
+ os_memcpy(mac, tmp, mac_len);
+ return 0;
+}
+
+
+int eap_teap_compound_mac(u16 tls_cs, const struct teap_tlv_crypto_binding *cb,
+ const struct wpabuf *server_outer_tlvs,
+ const struct wpabuf *peer_outer_tlvs,
+ const u8 *cmk, u8 *compound_mac)
+{
+ u8 *pos, *buffer;
+ size_t bind_len, buffer_len;
+ struct teap_tlv_crypto_binding *tmp_cb;
+ int res;
+
+ /* RFC 7170, Section 5.3 */
+ bind_len = sizeof(struct teap_tlv_hdr) + be_to_host16(cb->length);
+ buffer_len = bind_len + 1;
+ if (server_outer_tlvs)
+ buffer_len += wpabuf_len(server_outer_tlvs);
+ if (peer_outer_tlvs)
+ buffer_len += wpabuf_len(peer_outer_tlvs);
+ buffer = os_malloc(buffer_len);
+ if (!buffer)
+ return -1;
+
+ pos = buffer;
+ /* 1. The entire Crypto-Binding TLV attribute with both the EMSK and MSK
+ * Compound MAC fields zeroed out. */
+ os_memcpy(pos, cb, bind_len);
+ pos += bind_len;
+ tmp_cb = (struct teap_tlv_crypto_binding *) buffer;
+ os_memset(tmp_cb->emsk_compound_mac, 0, EAP_TEAP_COMPOUND_MAC_LEN);
+ os_memset(tmp_cb->msk_compound_mac, 0, EAP_TEAP_COMPOUND_MAC_LEN);
+
+ /* 2. The EAP Type sent by the other party in the first TEAP message. */
+ /* This is supposed to be the EAP Type sent by the other party in the
+ * first TEAP message, but since we cannot get here without having
+ * successfully negotiated use of TEAP, this can only be the fixed EAP
+ * Type of TEAP. */
+ *pos++ = EAP_TYPE_TEAP;
+
+ /* 3. All the Outer TLVs from the first TEAP message sent by EAP server
+ * to peer. */
+ if (server_outer_tlvs) {
+ os_memcpy(pos, wpabuf_head(server_outer_tlvs),
+ wpabuf_len(server_outer_tlvs));
+ pos += wpabuf_len(server_outer_tlvs);
+ }
+
+ /* 4. All the Outer TLVs from the first TEAP message sent by the peer to
+ * the EAP server. */
+ if (peer_outer_tlvs) {
+ os_memcpy(pos, wpabuf_head(peer_outer_tlvs),
+ wpabuf_len(peer_outer_tlvs));
+ pos += wpabuf_len(peer_outer_tlvs);
+ }
+
+ buffer_len = pos - buffer;
+
+ wpa_hexdump_key(MSG_MSGDUMP,
+ "EAP-TEAP: CMK for Compound MAC calculation",
+ cmk, EAP_TEAP_CMK_LEN);
+ wpa_hexdump(MSG_MSGDUMP,
+ "EAP-TEAP: BUFFER for Compound MAC calculation",
+ buffer, buffer_len);
+ res = eap_teap_tls_mac(tls_cs, cmk, EAP_TEAP_CMK_LEN,
+ buffer, buffer_len,
+ compound_mac, EAP_TEAP_COMPOUND_MAC_LEN);
+ os_free(buffer);
+
+ return res;
+}
+
+
+int eap_teap_parse_tlv(struct eap_teap_tlv_parse *tlv,
+ int tlv_type, u8 *pos, size_t len)
+{
+ switch (tlv_type) {
+ case TEAP_TLV_IDENTITY_TYPE:
+ if (len < 2) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Too short Identity-Type TLV");
+ tlv->result = TEAP_STATUS_FAILURE;
+ break;
+ }
+ tlv->identity_type = WPA_GET_BE16(pos);
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Identity-Type: %u",
+ tlv->identity_type);
+ break;
+ case TEAP_TLV_RESULT:
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Result TLV", pos, len);
+ if (tlv->result) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: More than one Result TLV in the message");
+ tlv->result = TEAP_STATUS_FAILURE;
+ return -2;
+ }
+ if (len < 2) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: Too short Result TLV");
+ tlv->result = TEAP_STATUS_FAILURE;
+ break;
+ }
+ tlv->result = WPA_GET_BE16(pos);
+ if (tlv->result != TEAP_STATUS_SUCCESS &&
+ tlv->result != TEAP_STATUS_FAILURE) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: Unknown Result %d",
+ tlv->result);
+ tlv->result = TEAP_STATUS_FAILURE;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Result: %s",
+ tlv->result == TEAP_STATUS_SUCCESS ?
+ "Success" : "Failure");
+ break;
+ case TEAP_TLV_NAK:
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: NAK TLV", pos, len);
+ if (len < 6) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: Too short NAK TLV");
+ tlv->result = TEAP_STATUS_FAILURE;
+ break;
+ }
+ tlv->nak = pos;
+ tlv->nak_len = len;
+ break;
+ case TEAP_TLV_ERROR:
+ if (len < 4) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: Too short Error TLV");
+ tlv->result = TEAP_STATUS_FAILURE;
+ break;
+ }
+ tlv->error_code = WPA_GET_BE32(pos);
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Error: %u", tlv->error_code);
+ break;
+ case TEAP_TLV_REQUEST_ACTION:
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Request-Action TLV",
+ pos, len);
+ if (tlv->request_action) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: More than one Request-Action TLV in the message");
+ tlv->iresult = TEAP_STATUS_FAILURE;
+ return -2;
+ }
+ if (len < 2) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Too short Request-Action TLV");
+ tlv->iresult = TEAP_STATUS_FAILURE;
+ break;
+ }
+ tlv->request_action_status = pos[0];
+ tlv->request_action = pos[1];
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Request-Action: Status=%u Action=%u",
+ tlv->request_action_status, tlv->request_action);
+ break;
+ case TEAP_TLV_EAP_PAYLOAD:
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: EAP-Payload TLV",
+ pos, len);
+ if (tlv->eap_payload_tlv) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: More than one EAP-Payload TLV in the message");
+ tlv->iresult = TEAP_STATUS_FAILURE;
+ return -2;
+ }
+ tlv->eap_payload_tlv = pos;
+ tlv->eap_payload_tlv_len = len;
+ break;
+ case TEAP_TLV_INTERMEDIATE_RESULT:
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Intermediate-Result TLV",
+ pos, len);
+ if (len < 2) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Too short Intermediate-Result TLV");
+ tlv->iresult = TEAP_STATUS_FAILURE;
+ break;
+ }
+ if (tlv->iresult) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: More than one Intermediate-Result TLV in the message");
+ tlv->iresult = TEAP_STATUS_FAILURE;
+ return -2;
+ }
+ tlv->iresult = WPA_GET_BE16(pos);
+ if (tlv->iresult != TEAP_STATUS_SUCCESS &&
+ tlv->iresult != TEAP_STATUS_FAILURE) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Unknown Intermediate Result %d",
+ tlv->iresult);
+ tlv->iresult = TEAP_STATUS_FAILURE;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Intermediate Result: %s",
+ tlv->iresult == TEAP_STATUS_SUCCESS ?
+ "Success" : "Failure");
+ break;
+ case TEAP_TLV_PAC:
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: PAC TLV", pos, len);
+ if (tlv->pac) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: More than one PAC TLV in the message");
+ tlv->iresult = TEAP_STATUS_FAILURE;
+ return -2;
+ }
+ tlv->pac = pos;
+ tlv->pac_len = len;
+ break;
+ case TEAP_TLV_CRYPTO_BINDING:
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Crypto-Binding TLV",
+ pos, len);
+ if (tlv->crypto_binding) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: More than one Crypto-Binding TLV in the message");
+ tlv->iresult = TEAP_STATUS_FAILURE;
+ return -2;
+ }
+ tlv->crypto_binding_len = sizeof(struct teap_tlv_hdr) + len;
+ if (tlv->crypto_binding_len < sizeof(*tlv->crypto_binding)) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Too short Crypto-Binding TLV");
+ tlv->iresult = TEAP_STATUS_FAILURE;
+ return -2;
+ }
+ tlv->crypto_binding = (struct teap_tlv_crypto_binding *)
+ (pos - sizeof(struct teap_tlv_hdr));
+ break;
+ case TEAP_TLV_BASIC_PASSWORD_AUTH_REQ:
+ wpa_hexdump_ascii(MSG_MSGDUMP,
+ "EAP-TEAP: Basic-Password-Auth-Req TLV",
+ pos, len);
+ if (tlv->basic_auth_req) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: More than one Basic-Password-Auth-Req TLV in the message");
+ tlv->iresult = TEAP_STATUS_FAILURE;
+ return -2;
+ }
+ tlv->basic_auth_req = pos;
+ tlv->basic_auth_req_len = len;
+ break;
+ case TEAP_TLV_BASIC_PASSWORD_AUTH_RESP:
+ wpa_hexdump_ascii(MSG_MSGDUMP,
+ "EAP-TEAP: Basic-Password-Auth-Resp TLV",
+ pos, len);
+ if (tlv->basic_auth_resp) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: More than one Basic-Password-Auth-Resp TLV in the message");
+ tlv->iresult = TEAP_STATUS_FAILURE;
+ return -2;
+ }
+ tlv->basic_auth_resp = pos;
+ tlv->basic_auth_resp_len = len;
+ break;
+ default:
+ /* Unknown TLV */
+ return -1;
+ }
+
+ return 0;
+}
+
+
+const char * eap_teap_tlv_type_str(enum teap_tlv_types type)
+{
+ switch (type) {
+ case TEAP_TLV_AUTHORITY_ID:
+ return "Authority-ID";
+ case TEAP_TLV_IDENTITY_TYPE:
+ return "Identity-Type";
+ case TEAP_TLV_RESULT:
+ return "Result";
+ case TEAP_TLV_NAK:
+ return "NAK";
+ case TEAP_TLV_ERROR:
+ return "Error";
+ case TEAP_TLV_CHANNEL_BINDING:
+ return "Channel-Binding";
+ case TEAP_TLV_VENDOR_SPECIFIC:
+ return "Vendor-Specific";
+ case TEAP_TLV_REQUEST_ACTION:
+ return "Request-Action";
+ case TEAP_TLV_EAP_PAYLOAD:
+ return "EAP-Payload";
+ case TEAP_TLV_INTERMEDIATE_RESULT:
+ return "Intermediate-Result";
+ case TEAP_TLV_PAC:
+ return "PAC";
+ case TEAP_TLV_CRYPTO_BINDING:
+ return "Crypto-Binding";
+ case TEAP_TLV_BASIC_PASSWORD_AUTH_REQ:
+ return "Basic-Password-Auth-Req";
+ case TEAP_TLV_BASIC_PASSWORD_AUTH_RESP:
+ return "Basic-Password-Auth-Resp";
+ case TEAP_TLV_PKCS7:
+ return "PKCS#7";
+ case TEAP_TLV_PKCS10:
+ return "PKCS#10";
+ case TEAP_TLV_TRUSTED_SERVER_ROOT:
+ return "Trusted-Server-Root";
+ }
+
+ return "?";
+}
+
+
+struct wpabuf * eap_teap_tlv_result(int status, int intermediate)
+{
+ struct wpabuf *buf;
+ struct teap_tlv_result *result;
+
+ if (status != TEAP_STATUS_FAILURE && status != TEAP_STATUS_SUCCESS)
+ return NULL;
+
+ buf = wpabuf_alloc(sizeof(*result));
+ if (!buf)
+ return NULL;
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Add %sResult TLV(status=%s)",
+ intermediate ? "Intermediate-" : "",
+ status == TEAP_STATUS_SUCCESS ? "Success" : "Failure");
+ result = wpabuf_put(buf, sizeof(*result));
+ result->tlv_type = host_to_be16(TEAP_TLV_MANDATORY |
+ (intermediate ?
+ TEAP_TLV_INTERMEDIATE_RESULT :
+ TEAP_TLV_RESULT));
+ result->length = host_to_be16(2);
+ result->status = host_to_be16(status);
+ return buf;
+}
+
+
+struct wpabuf * eap_teap_tlv_error(enum teap_error_codes error)
+{
+ struct wpabuf *buf;
+
+ buf = wpabuf_alloc(4 + 4);
+ if (!buf)
+ return NULL;
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Add Error TLV(Error Code=%d)",
+ error);
+ wpabuf_put_be16(buf, TEAP_TLV_MANDATORY | TEAP_TLV_ERROR);
+ wpabuf_put_be16(buf, 4);
+ wpabuf_put_be32(buf, error);
+ return buf;
+}
+
+
+struct wpabuf * eap_teap_tlv_identity_type(enum teap_identity_types id)
+{
+ struct wpabuf *buf;
+
+ buf = wpabuf_alloc(4 + 2);
+ if (!buf)
+ return NULL;
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Add Identity-Type TLV(Identity-Type=%d)", id);
+ wpabuf_put_be16(buf, TEAP_TLV_IDENTITY_TYPE);
+ wpabuf_put_be16(buf, 2);
+ wpabuf_put_be16(buf, id);
+ return buf;
+}
+
+
+int eap_teap_allowed_anon_prov_phase2_method(int vendor, enum eap_type type)
+{
+ /* RFC 7170, Section 3.8.3: MUST provide mutual authentication,
+ * provide key generation, and be resistant to dictionary attack.
+ * Section 3.8 also mentions requirement for using EMSK Compound MAC. */
+ return vendor == EAP_VENDOR_IETF &&
+ (type == EAP_TYPE_PWD || type == EAP_TYPE_EKE);
+}
+
+
+int eap_teap_allowed_anon_prov_cipher_suite(u16 cs)
+{
+ /* RFC 7170, Section 3.8.3: anonymous ciphersuites MAY be supported as
+ * long as the TLS pre-master secret is generated form contribution from
+ * both peers. Accept the recommended TLS_DH_anon_WITH_AES_128_CBC_SHA
+ * cipher suite and other ciphersuites that use DH in some form, have
+ * SHA-1 or stronger MAC function, and use reasonable strong cipher. */
+ static const u16 ok_cs[] = {
+ /* DH-anon */
+ 0x0034, 0x003a, 0x006c, 0x006d, 0x00a6, 0x00a7,
+ /* DHE-RSA */
+ 0x0033, 0x0039, 0x0067, 0x006b, 0x009e, 0x009f,
+ /* ECDH-anon */
+ 0xc018, 0xc019,
+ /* ECDH-RSA */
+ 0xc003, 0xc00f, 0xc029, 0xc02a, 0xc031, 0xc032,
+ /* ECDH-ECDSA */
+ 0xc004, 0xc005, 0xc025, 0xc026, 0xc02d, 0xc02e,
+ /* ECDHE-RSA */
+ 0xc013, 0xc014, 0xc027, 0xc028, 0xc02f, 0xc030,
+ /* ECDHE-ECDSA */
+ 0xc009, 0xc00a, 0xc023, 0xc024, 0xc02b, 0xc02c,
+ };
+
+ return tls_cipher_suite_match(ok_cs, ARRAY_SIZE(ok_cs), cs);
+}
diff --git a/src/eap_common/eap_teap_common.h b/src/eap_common/eap_teap_common.h
new file mode 100644
index 0000000..3a25879
--- /dev/null
+++ b/src/eap_common/eap_teap_common.h
@@ -0,0 +1,230 @@
+/*
+ * EAP-TEAP definitions (RFC 7170)
+ * 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.
+ */
+
+#ifndef EAP_TEAP_H
+#define EAP_TEAP_H
+
+#define EAP_TEAP_VERSION 1
+#define EAP_TEAP_KEY_LEN 64
+#define EAP_TEAP_IMCK_LEN 60
+#define EAP_TEAP_SIMCK_LEN 40
+#define EAP_TEAP_CMK_LEN 20
+#define EAP_TEAP_COMPOUND_MAC_LEN 20
+#define EAP_TEAP_NONCE_LEN 32
+
+#define TEAP_TLS_EXPORTER_LABEL_SKS "EXPORTER: teap session key seed"
+
+#define TLS_EXT_PAC_OPAQUE 35
+
+/*
+ * RFC 7170: Section 4.2.12.1 - Formats for PAC Attributes
+ * Note: bit 0x8000 (Mandatory) and bit 0x4000 (Reserved) are also defined
+ * in the general TLV format (Section 4.2.1).
+ */
+#define PAC_TYPE_PAC_KEY 1
+#define PAC_TYPE_PAC_OPAQUE 2
+#define PAC_TYPE_CRED_LIFETIME 3
+#define PAC_TYPE_A_ID 4
+#define PAC_TYPE_I_ID 5
+/* 6 - Reserved */
+#define PAC_TYPE_A_ID_INFO 7
+#define PAC_TYPE_PAC_ACKNOWLEDGEMENT 8
+#define PAC_TYPE_PAC_INFO 9
+#define PAC_TYPE_PAC_TYPE 10
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct pac_attr_hdr {
+ be16 type;
+ be16 len;
+} STRUCT_PACKED;
+
+struct teap_tlv_hdr {
+ be16 tlv_type;
+ be16 length;
+} STRUCT_PACKED;
+
+/* Result TLV and Intermediate-Result TLV */
+struct teap_tlv_result {
+ be16 tlv_type;
+ be16 length;
+ be16 status;
+ /* for Intermediate-Result TLV, followed by optional TLVs */
+} STRUCT_PACKED;
+
+struct teap_tlv_nak {
+ be16 tlv_type;
+ be16 length;
+ be32 vendor_id;
+ be16 nak_type;
+ /* followed by optional TLVs */
+} STRUCT_PACKED;
+
+struct teap_tlv_crypto_binding {
+ be16 tlv_type; /* TLV Type[14b] and M/R flags */
+ be16 length;
+ u8 reserved;
+ u8 version;
+ u8 received_version;
+ u8 subtype; /* Flags[4b] and Sub-Type[4b] */
+ u8 nonce[EAP_TEAP_NONCE_LEN];
+ u8 emsk_compound_mac[EAP_TEAP_COMPOUND_MAC_LEN];
+ u8 msk_compound_mac[EAP_TEAP_COMPOUND_MAC_LEN];
+} STRUCT_PACKED;
+
+struct teap_tlv_request_action {
+ be16 tlv_type;
+ be16 length;
+ u8 status;
+ u8 action;
+ /* followed by optional TLVs */
+} STRUCT_PACKED;
+
+enum teap_request_action {
+ TEAP_REQUEST_ACTION_PROCESS_TLV = 1,
+ TEAP_REQUEST_ACTION_NEGOTIATE_EAP = 2,
+};
+
+/* PAC TLV with PAC-Acknowledgement TLV attribute */
+struct teap_tlv_pac_ack {
+ be16 tlv_type;
+ be16 length;
+ be16 pac_type;
+ be16 pac_len;
+ be16 result;
+} STRUCT_PACKED;
+
+struct teap_attr_pac_type {
+ be16 type; /* PAC_TYPE_PAC_TYPE */
+ be16 length; /* 2 */
+ be16 pac_type;
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+#define TEAP_CRYPTO_BINDING_SUBTYPE_REQUEST 0
+#define TEAP_CRYPTO_BINDING_SUBTYPE_RESPONSE 1
+
+#define TEAP_CRYPTO_BINDING_EMSK_CMAC 1
+#define TEAP_CRYPTO_BINDING_MSK_CMAC 2
+#define TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC 3
+
+
+#define EAP_TEAP_PAC_KEY_LEN 48
+
+/* RFC 7170: 4.2.12.6 PAC-Type TLV */
+#define PAC_TYPE_TUNNEL_PAC 1
+
+
+/* RFC 7170, 4.2.1: General TLV Format */
+enum teap_tlv_types {
+ TEAP_TLV_AUTHORITY_ID = 1,
+ TEAP_TLV_IDENTITY_TYPE = 2,
+ TEAP_TLV_RESULT = 3,
+ TEAP_TLV_NAK = 4,
+ TEAP_TLV_ERROR = 5,
+ TEAP_TLV_CHANNEL_BINDING = 6,
+ TEAP_TLV_VENDOR_SPECIFIC = 7,
+ TEAP_TLV_REQUEST_ACTION = 8,
+ TEAP_TLV_EAP_PAYLOAD = 9,
+ TEAP_TLV_INTERMEDIATE_RESULT = 10,
+ TEAP_TLV_PAC = 11,
+ TEAP_TLV_CRYPTO_BINDING = 12,
+ TEAP_TLV_BASIC_PASSWORD_AUTH_REQ = 13,
+ TEAP_TLV_BASIC_PASSWORD_AUTH_RESP = 14,
+ TEAP_TLV_PKCS7 = 15,
+ TEAP_TLV_PKCS10 = 16,
+ TEAP_TLV_TRUSTED_SERVER_ROOT = 17,
+};
+
+enum teap_tlv_result_status {
+ TEAP_STATUS_SUCCESS = 1,
+ TEAP_STATUS_FAILURE = 2
+};
+
+/* Identity-Type values within Identity-Type TLV */
+enum teap_identity_types {
+ TEAP_IDENTITY_TYPE_USER = 1,
+ TEAP_IDENTITY_TYPE_MACHINE = 2,
+};
+
+#define TEAP_TLV_MANDATORY 0x8000
+#define TEAP_TLV_TYPE_MASK 0x3fff
+
+/* RFC 7170, 4.2.6: Error TLV */
+enum teap_error_codes {
+ TEAP_ERROR_INNER_METHOD = 1001,
+ TEAP_ERROR_UNSPEC_AUTH_INFRA_PROBLEM = 1002,
+ TEAP_ERROR_UNSPEC_AUTHENTICATION_FAILURE = 1003,
+ TEAP_ERROR_UNSPEC_AUTHORIZATION_FAILURE = 1004,
+ TEAP_ERROR_USER_ACCOUNT_CRED_UNAVAILABLE = 1005,
+ TEAP_ERROR_USER_ACCOUNT_EXPIRED = 1006,
+ TEAP_ERROR_USER_ACCOUNT_LOCKED_TRY_AGAIN_LATER = 1007,
+ TEAP_ERROR_USER_ACCOUNT_LOCKED_ADMIN_REQ = 1008,
+ TEAP_ERROR_TUNNEL_COMPROMISE_ERROR = 2001,
+ TEAP_ERROR_UNEXPECTED_TLVS_EXCHANGED = 2002,
+};
+
+struct wpabuf;
+struct tls_connection;
+
+struct eap_teap_tlv_parse {
+ u8 *eap_payload_tlv;
+ size_t eap_payload_tlv_len;
+ struct teap_tlv_crypto_binding *crypto_binding;
+ size_t crypto_binding_len;
+ int iresult;
+ int result;
+ u8 *nak;
+ size_t nak_len;
+ u8 request_action;
+ u8 request_action_status;
+ u8 *pac;
+ size_t pac_len;
+ u8 *basic_auth_req;
+ size_t basic_auth_req_len;
+ u8 *basic_auth_resp;
+ size_t basic_auth_resp_len;
+ u32 error_code;
+ u16 identity_type;
+};
+
+void eap_teap_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len);
+void eap_teap_put_tlv(struct wpabuf *buf, u16 type, const void *data, u16 len);
+void eap_teap_put_tlv_buf(struct wpabuf *buf, u16 type,
+ const struct wpabuf *data);
+struct wpabuf * eap_teap_tlv_eap_payload(struct wpabuf *buf);
+int eap_teap_derive_eap_msk(u16 tls_cs, const u8 *simck, u8 *msk);
+int eap_teap_derive_eap_emsk(u16 tls_cs, const u8 *simck, u8 *emsk);
+int eap_teap_derive_cmk_basic_pw_auth(u16 tls_cs, const u8 *s_imck_msk,
+ u8 *cmk);
+int eap_teap_derive_imck(u16 tls_cs,
+ const u8 *prev_s_imck_msk, const u8 *prev_s_imck_emsk,
+ const u8 *msk, size_t msk_len,
+ const u8 *emsk, size_t emsk_len,
+ u8 *s_imck_msk, u8 *cmk_msk,
+ u8 *s_imck_emsk, u8 *cmk_emsk);
+int eap_teap_compound_mac(u16 tls_cs, const struct teap_tlv_crypto_binding *cb,
+ const struct wpabuf *server_outer_tlvs,
+ const struct wpabuf *peer_outer_tlvs,
+ const u8 *cmk, u8 *compound_mac);
+int eap_teap_parse_tlv(struct eap_teap_tlv_parse *tlv,
+ int tlv_type, u8 *pos, size_t len);
+const char * eap_teap_tlv_type_str(enum teap_tlv_types type);
+struct wpabuf * eap_teap_tlv_result(int status, int intermediate);
+struct wpabuf * eap_teap_tlv_error(enum teap_error_codes error);
+struct wpabuf * eap_teap_tlv_identity_type(enum teap_identity_types id);
+enum eap_type;
+int eap_teap_allowed_anon_prov_phase2_method(int vendor, enum eap_type type);
+int eap_teap_allowed_anon_prov_cipher_suite(u16 cs);
+
+#endif /* EAP_TEAP_H */
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 974c475..74c2ad3 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -1,6 +1,6 @@
/*
* EAP peer state machines (RFC 4137)
- * 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.
@@ -32,12 +32,13 @@
#define STATE_MACHINE_DATA struct eap_sm
#define STATE_MACHINE_DEBUG_PREFIX "EAP"
-#define EAP_MAX_AUTH_ROUNDS 50
+#define EAP_MAX_AUTH_ROUNDS 100
+#define EAP_MAX_AUTH_ROUNDS_SHORT 50
#define EAP_CLIENT_TIMEOUT_DEFAULT 60
-static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
- EapType method);
+static bool eap_sm_allowMethod(struct eap_sm *sm, int vendor,
+ enum eap_type method);
static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id);
static void eap_sm_processIdentity(struct eap_sm *sm,
const struct wpabuf *req);
@@ -53,14 +54,14 @@
-static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
+static bool eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
{
return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
}
static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var,
- Boolean value)
+ bool value)
{
sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);
}
@@ -209,8 +210,8 @@
/*
* This state initializes state machine variables when the machine is
- * activated (portEnabled = TRUE). This is also used when re-starting
- * authentication (eapRestart == TRUE).
+ * activated (portEnabled = true). This is also used when re-starting
+ * authentication (eapRestart == true).
*/
SM_STATE(EAP, INITIALIZE)
{
@@ -228,17 +229,17 @@
}
sm->selectedMethod = EAP_TYPE_NONE;
sm->methodState = METHOD_NONE;
- sm->allowNotifications = TRUE;
+ sm->allowNotifications = true;
sm->decision = DECISION_FAIL;
sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
- eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
- eapol_set_bool(sm, EAPOL_eapFail, FALSE);
+ eapol_set_bool(sm, EAPOL_eapSuccess, false);
+ eapol_set_bool(sm, EAPOL_eapFail, false);
eap_sm_free_key(sm);
os_free(sm->eapSessionId);
sm->eapSessionId = NULL;
- sm->eapKeyAvailable = FALSE;
- eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
+ sm->eapKeyAvailable = false;
+ eapol_set_bool(sm, EAPOL_eapRestart, false);
sm->lastId = -1; /* new session - make sure this does not match with
* the first EAP-Packet */
/*
@@ -246,36 +247,39 @@
* seemed to be able to trigger cases where both were set and if EAPOL
* state machine uses eapNoResp first, it may end up not sending a real
* reply correctly. This occurred when the workaround in FAIL state set
- * eapNoResp = TRUE.. Maybe that workaround needs to be fixed to do
+ * eapNoResp = true.. Maybe that workaround needs to be fixed to do
* something else(?)
*/
- eapol_set_bool(sm, EAPOL_eapResp, FALSE);
- eapol_set_bool(sm, EAPOL_eapNoResp, FALSE);
+ eapol_set_bool(sm, EAPOL_eapResp, false);
+ eapol_set_bool(sm, EAPOL_eapNoResp, false);
/*
* RFC 4137 does not reset ignore here, but since it is possible for
- * some method code paths to end up not setting ignore=FALSE, clear the
+ * some method code paths to end up not setting ignore=false, clear the
* value here to avoid issues if a previous authentication attempt
- * failed with ignore=TRUE being left behind in the last
+ * failed with ignore=true being left behind in the last
* m.check(eapReqData) operation.
*/
sm->ignore = 0;
sm->num_rounds = 0;
+ sm->num_rounds_short = 0;
sm->prev_failure = 0;
sm->expected_failure = 0;
- sm->reauthInit = FALSE;
+ sm->reauthInit = false;
sm->erp_seq = (u32) -1;
+ sm->use_machine_cred = 0;
}
/*
* This state is reached whenever service from the lower layer is interrupted
- * or unavailable (portEnabled == FALSE). Immediate transition to INITIALIZE
+ * or unavailable (portEnabled == false). Immediate transition to INITIALIZE
* occurs when the port becomes enabled.
*/
SM_STATE(EAP, DISABLED)
{
SM_ENTRY(EAP, DISABLED);
sm->num_rounds = 0;
+ sm->num_rounds_short = 0;
/*
* RFC 4137 does not describe clearing of idleWhile here, but doing so
* allows the timer tick to be stopped more quickly when EAP is not in
@@ -297,7 +301,7 @@
/*
- * This state is entered when an EAP packet is received (eapReq == TRUE) to
+ * This state is entered when an EAP packet is received (eapReq == true) to
* parse the packet header.
*/
SM_STATE(EAP, RECEIVED)
@@ -309,6 +313,10 @@
/* parse rxReq, rxSuccess, rxFailure, reqId, reqMethod */
eap_sm_parseEapReq(sm, eapReqData);
sm->num_rounds++;
+ if (!eapReqData || wpabuf_len(eapReqData) < 20)
+ sm->num_rounds_short++;
+ else
+ sm->num_rounds_short = 0;
}
@@ -319,7 +327,7 @@
SM_STATE(EAP, GET_METHOD)
{
int reinit;
- EapType method;
+ enum eap_type method;
const struct eap_method *eap_method;
SM_ENTRY(EAP, GET_METHOD);
@@ -815,7 +823,8 @@
wpa_printf(MSG_DEBUG, "EAP: Valid ERP key found %s (SEQ=%u)",
erp->keyname_nai, erp->next_seq);
- msg = eap_msg_alloc(EAP_VENDOR_IETF, (EapType) EAP_ERP_TYPE_REAUTH,
+ msg = eap_msg_alloc(EAP_VENDOR_IETF,
+ (enum eap_type) EAP_ERP_TYPE_REAUTH,
1 + 2 + 2 + os_strlen(erp->keyname_nai) + 1 + 16,
EAP_CODE_INITIATE, eap_id);
if (msg == NULL)
@@ -857,7 +866,7 @@
wpa_printf(MSG_DEBUG, "EAP: Sending EAP-Initiate/Re-auth");
wpabuf_free(sm->eapRespData);
sm->eapRespData = msg;
- sm->reauthInit = TRUE;
+ sm->reauthInit = true;
return 0;
}
#endif /* CONFIG_ERP */
@@ -949,18 +958,20 @@
SM_ENTRY(EAP, SEND_RESPONSE);
wpabuf_free(sm->lastRespData);
if (sm->eapRespData) {
+ if (wpabuf_len(sm->eapRespData) >= 20)
+ sm->num_rounds_short = 0;
if (sm->workaround)
os_memcpy(sm->last_sha1, sm->req_sha1, 20);
sm->lastId = sm->reqId;
sm->lastRespData = wpabuf_dup(sm->eapRespData);
- eapol_set_bool(sm, EAPOL_eapResp, TRUE);
+ eapol_set_bool(sm, EAPOL_eapResp, true);
} else {
wpa_printf(MSG_DEBUG, "EAP: No eapRespData available");
sm->lastRespData = NULL;
}
- eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+ eapol_set_bool(sm, EAPOL_eapReq, false);
eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
- sm->reauthInit = FALSE;
+ sm->reauthInit = false;
}
@@ -971,8 +982,8 @@
SM_STATE(EAP, DISCARD)
{
SM_ENTRY(EAP, DISCARD);
- eapol_set_bool(sm, EAPOL_eapReq, FALSE);
- eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+ eapol_set_bool(sm, EAPOL_eapReq, false);
+ eapol_set_bool(sm, EAPOL_eapNoResp, true);
}
@@ -1037,15 +1048,15 @@
SM_ENTRY(EAP, SUCCESS);
if (sm->eapKeyData != NULL)
- sm->eapKeyAvailable = TRUE;
- eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
+ sm->eapKeyAvailable = true;
+ eapol_set_bool(sm, EAPOL_eapSuccess, true);
/*
* RFC 4137 does not clear eapReq here, but this seems to be required
* to avoid processing the same request twice when state machine is
* initialized.
*/
- eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+ eapol_set_bool(sm, EAPOL_eapReq, false);
/*
* RFC 4137 does not set eapNoResp here, but this seems to be required
@@ -1053,7 +1064,7 @@
* addition, either eapResp or eapNoResp is required to be set after
* processing the received EAP frame.
*/
- eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+ eapol_set_bool(sm, EAPOL_eapNoResp, true);
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
"EAP authentication completed successfully");
@@ -1072,21 +1083,21 @@
SM_STATE(EAP, FAILURE)
{
SM_ENTRY(EAP, FAILURE);
- eapol_set_bool(sm, EAPOL_eapFail, TRUE);
+ eapol_set_bool(sm, EAPOL_eapFail, true);
/*
* RFC 4137 does not clear eapReq here, but this seems to be required
* to avoid processing the same request twice when state machine is
* initialized.
*/
- eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+ eapol_set_bool(sm, EAPOL_eapReq, false);
/*
* RFC 4137 does not set eapNoResp here. However, either eapResp or
* eapNoResp is required to be set after processing the received EAP
* frame.
*/
- eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+ eapol_set_bool(sm, EAPOL_eapNoResp, true);
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
"EAP authentication failed");
@@ -1341,6 +1352,14 @@
sm->num_rounds++;
SM_ENTER_GLOBAL(EAP, FAILURE);
}
+ } else if (sm->num_rounds_short > EAP_MAX_AUTH_ROUNDS_SHORT) {
+ if (sm->num_rounds_short == EAP_MAX_AUTH_ROUNDS_SHORT + 1) {
+ wpa_msg(sm->msg_ctx, MSG_INFO,
+ "EAP: more than %d authentication rounds (short) - abort",
+ EAP_MAX_AUTH_ROUNDS_SHORT);
+ sm->num_rounds_short++;
+ SM_ENTER_GLOBAL(EAP, FAILURE);
+ }
} else {
/* Local transitions */
eap_peer_sm_step_local(sm);
@@ -1348,19 +1367,19 @@
}
-static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
- EapType method)
+static bool eap_sm_allowMethod(struct eap_sm *sm, int vendor,
+ enum eap_type method)
{
if (!eap_allowed_method(sm, vendor, method)) {
wpa_printf(MSG_DEBUG, "EAP: configuration does not allow: "
"vendor %u method %u", vendor, method);
- return FALSE;
+ return false;
}
if (eap_peer_get_eap_method(vendor, method))
- return TRUE;
+ return true;
wpa_printf(MSG_DEBUG, "EAP: not included in build: "
"vendor %u method %u", vendor, method);
- return FALSE;
+ return false;
}
@@ -1595,13 +1614,13 @@
static int eap_sm_set_scard_pin(struct eap_sm *sm,
struct eap_peer_config *conf)
{
- if (scard_set_pin(sm->scard_ctx, conf->pin)) {
+ if (scard_set_pin(sm->scard_ctx, conf->cert.pin)) {
/*
* Make sure the same PIN is not tried again in order to avoid
* blocking SIM.
*/
- os_free(conf->pin);
- conf->pin = NULL;
+ os_free(conf->cert.pin);
+ conf->cert.pin = NULL;
wpa_printf(MSG_WARNING, "PIN validation failed");
eap_sm_request_pin(sm);
@@ -1657,6 +1676,11 @@
identity_len = config->anonymous_identity_len;
wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity",
identity, identity_len);
+ } else if (sm->use_machine_cred) {
+ identity = config->machine_identity;
+ identity_len = config->machine_identity_len;
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP: using machine identity",
+ identity, identity_len);
} else {
identity = config->identity;
identity_len = config->identity_len;
@@ -1778,7 +1802,7 @@
#endif /* CONFIG_ERP */
wpa_printf(MSG_DEBUG,
"EAP: EAP-Initiate/Re-auth-Start - No suitable ERP keys available - try to start full EAP authentication");
- eapol_set_bool(sm, EAPOL_eapTriggerStart, TRUE);
+ eapol_set_bool(sm, EAPOL_eapTriggerStart, true);
}
@@ -1902,9 +1926,9 @@
if (flags & 0x80 || !auth_tag_ok) {
wpa_printf(MSG_DEBUG,
"EAP: EAP-Finish/Re-auth indicated failure");
- eapol_set_bool(sm, EAPOL_eapFail, TRUE);
- eapol_set_bool(sm, EAPOL_eapReq, FALSE);
- eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+ eapol_set_bool(sm, EAPOL_eapFail, true);
+ eapol_set_bool(sm, EAPOL_eapReq, false);
+ eapol_set_bool(sm, EAPOL_eapNoResp, true);
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
"EAP authentication failed");
sm->prev_failure = 1;
@@ -1933,10 +1957,10 @@
}
wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rMSK",
sm->eapKeyData, sm->eapKeyDataLen);
- sm->eapKeyAvailable = TRUE;
- eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
- eapol_set_bool(sm, EAPOL_eapReq, FALSE);
- eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+ sm->eapKeyAvailable = true;
+ eapol_set_bool(sm, EAPOL_eapSuccess, true);
+ eapol_set_bool(sm, EAPOL_eapReq, false);
+ eapol_set_bool(sm, EAPOL_eapNoResp, true);
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
"EAP re-authentication completed successfully");
#endif /* CONFIG_ERP */
@@ -1949,7 +1973,7 @@
size_t plen;
const u8 *pos;
- sm->rxReq = sm->rxResp = sm->rxSuccess = sm->rxFailure = FALSE;
+ sm->rxReq = sm->rxResp = sm->rxSuccess = sm->rxFailure = false;
sm->reqId = 0;
sm->reqMethod = EAP_TYPE_NONE;
sm->reqVendor = EAP_VENDOR_IETF;
@@ -1983,7 +2007,7 @@
"no Type field");
return;
}
- sm->rxReq = TRUE;
+ sm->rxReq = true;
pos = (const u8 *) (hdr + 1);
sm->reqMethod = *pos++;
if (sm->reqMethod == EAP_TYPE_EXPANDED) {
@@ -2014,7 +2038,7 @@
"EAP-Response - no Type field");
return;
}
- sm->rxResp = TRUE;
+ sm->rxResp = true;
pos = (const u8 *) (hdr + 1);
sm->reqMethod = *pos;
wpa_printf(MSG_DEBUG, "EAP: Received EAP-Response for "
@@ -2027,7 +2051,7 @@
case EAP_CODE_SUCCESS:
wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success");
eap_notify_status(sm, "completion", "success");
- sm->rxSuccess = TRUE;
+ sm->rxSuccess = true;
break;
case EAP_CODE_FAILURE:
wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure");
@@ -2041,7 +2065,7 @@
if (error_code != NO_EAP_METHOD_ERROR)
eap_report_error(sm, error_code);
}
- sm->rxFailure = TRUE;
+ sm->rxFailure = true;
break;
case EAP_CODE_INITIATE:
eap_peer_initiate(sm, hdr, plen);
@@ -2097,12 +2121,8 @@
}
}
- sm->eapol_cb->notify_cert(sm->eapol_ctx,
- data->peer_cert.depth,
- data->peer_cert.subject,
- data->peer_cert.altsubject,
- data->peer_cert.num_altsubject,
- hash_hex, data->peer_cert.cert);
+ sm->eapol_cb->notify_cert(sm->eapol_ctx, &data->peer_cert,
+ hash_hex);
break;
case TLS_ALERT:
if (data->alert.is_local)
@@ -2213,7 +2233,7 @@
{
int res = 0;
do {
- sm->changed = FALSE;
+ sm->changed = false;
SM_STEP_RUN(EAP);
if (sm->changed)
res = 1;
@@ -2242,7 +2262,7 @@
/* This is not clearly specified in the EAP statemachines draft, but
* it seems necessary to make sure that some of the EAPOL variables get
* cleared for the next authentication. */
- eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
+ eapol_set_bool(sm, EAPOL_eapSuccess, false);
}
@@ -2604,10 +2624,12 @@
static int eap_allowed_phase2_type(int vendor, int type)
{
+ if (vendor == EAP_VENDOR_HOSTAP)
+ return 1;
if (vendor != EAP_VENDOR_IETF)
return 0;
return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS &&
- type != EAP_TYPE_FAST;
+ type != EAP_TYPE_FAST && type != EAP_TYPE_TEAP;
}
@@ -2666,7 +2688,7 @@
if (eap_allowed_phase2_type(vendor, method)) {
if (vendor == EAP_VENDOR_IETF &&
method == EAP_TYPE_TLS && config &&
- config->private_key2 == NULL)
+ !config->phase2_cert.private_key)
continue;
buf[*count].vendor = vendor;
buf[*count].method = method;
@@ -2725,8 +2747,15 @@
const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
{
struct eap_peer_config *config = eap_get_config(sm);
- if (config == NULL)
+
+ if (!config)
return NULL;
+
+ if (sm->use_machine_cred) {
+ *len = config->machine_identity_len;
+ return config->machine_identity;
+ }
+
*len = config->identity_len;
return config->identity;
}
@@ -2736,14 +2765,24 @@
struct eap_peer_config *config)
{
char *name;
+ const u8 *password;
+ size_t password_len;
- if (config->password == NULL)
+ if (sm->use_machine_cred) {
+ password = config->machine_password;
+ password_len = config->machine_password_len;
+ } else {
+ password = config->password;
+ password_len = config->password_len;
+ }
+
+ if (!password)
return -1;
- name = os_zalloc(config->password_len + 1);
- if (name == NULL)
+ name = os_zalloc(password_len + 1);
+ if (!name)
return -1;
- os_memcpy(name, config->password, config->password_len);
+ os_memcpy(name, password, password_len);
ext_password_free(sm->ext_pw_buf);
sm->ext_pw_buf = ext_password_get(sm->ext_pw, name);
@@ -2762,16 +2801,25 @@
const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
{
struct eap_peer_config *config = eap_get_config(sm);
- if (config == NULL)
+
+ if (!config)
return NULL;
- if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+ if ((sm->use_machine_cred &&
+ (config->flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD)) ||
+ (!sm->use_machine_cred &&
+ (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD))) {
if (eap_get_ext_password(sm, config) < 0)
return NULL;
*len = wpabuf_len(sm->ext_pw_buf);
return wpabuf_head(sm->ext_pw_buf);
}
+ if (sm->use_machine_cred) {
+ *len = config->machine_password_len;
+ return config->machine_password;
+ }
+
*len = config->password_len;
return config->password;
}
@@ -2789,10 +2837,14 @@
const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
{
struct eap_peer_config *config = eap_get_config(sm);
- if (config == NULL)
+
+ if (!config)
return NULL;
- if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+ if ((sm->use_machine_cred &&
+ (config->flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD)) ||
+ (!sm->use_machine_cred &&
+ (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD))) {
if (eap_get_ext_password(sm, config) < 0)
return NULL;
if (hash)
@@ -2801,6 +2853,14 @@
return wpabuf_head(sm->ext_pw_buf);
}
+ if (sm->use_machine_cred) {
+ *len = config->machine_password_len;
+ if (hash)
+ *hash = !!(config->flags &
+ EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH);
+ return config->machine_password;
+ }
+
*len = config->password_len;
if (hash)
*hash = !!(config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH);
@@ -2945,8 +3005,8 @@
return;
if (sm->eapKeyData != NULL)
- sm->eapKeyAvailable = TRUE;
- eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
+ sm->eapKeyAvailable = true;
+ eapol_set_bool(sm, EAPOL_eapSuccess, true);
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
"EAP authentication completed successfully (based on lower "
"layer success)");
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index d0837e3..a40d007 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -16,6 +16,7 @@
struct eap_sm;
struct wpa_config_blob;
struct wpabuf;
+struct tls_cert_data;
struct eap_method_type {
int vendor;
@@ -43,7 +44,7 @@
/**
* EAPOL_eapRestart - Lower layer request to restart authentication
*
- * Set to TRUE in lower layer, FALSE in EAP state machine.
+ * Set to true in lower layer, false in EAP state machine.
*/
EAPOL_eapRestart,
@@ -57,21 +58,21 @@
/**
* EAPOL_eapResp - Response to send
*
- * Set to TRUE in EAP state machine, FALSE in lower layer.
+ * Set to true in EAP state machine, false in lower layer.
*/
EAPOL_eapResp,
/**
* EAPOL_eapNoResp - Request has been process; no response to send
*
- * Set to TRUE in EAP state machine, FALSE in lower layer.
+ * Set to true in EAP state machine, false in lower layer.
*/
EAPOL_eapNoResp,
/**
* EAPOL_eapReq - EAP request available from lower layer
*
- * Set to TRUE in lower layer, FALSE in EAP state machine.
+ * Set to true in lower layer, false in EAP state machine.
*/
EAPOL_eapReq,
@@ -146,7 +147,7 @@
* @variable: EAPOL boolean variable to get
* Returns: Value of the EAPOL variable
*/
- Boolean (*get_bool)(void *ctx, enum eapol_bool_var variable);
+ bool (*get_bool)(void *ctx, enum eapol_bool_var variable);
/**
* set_bool - Set a boolean EAPOL state variable
@@ -154,8 +155,7 @@
* @variable: EAPOL boolean variable to set
* @value: Value for the EAPOL variable
*/
- void (*set_bool)(void *ctx, enum eapol_bool_var variable,
- Boolean value);
+ void (*set_bool)(void *ctx, enum eapol_bool_var variable, bool value);
/**
* get_int - Get an integer EAPOL state variable
@@ -226,16 +226,11 @@
/**
* notify_cert - Notification of a peer certificate
* @ctx: eapol_ctx from eap_peer_sm_init() call
- * @depth: Depth in certificate chain (0 = server)
- * @subject: Subject of the peer certificate
- * @altsubject: Select fields from AltSubject of the peer certificate
- * @num_altsubject: Number of altsubject values
+ * @cert: Certificate information
* @cert_hash: SHA-256 hash of the certificate
- * @cert: Peer certificate
*/
- void (*notify_cert)(void *ctx, int depth, const char *subject,
- const char *altsubject[], int num_altsubject,
- const char *cert_hash, const struct wpabuf *cert);
+ void (*notify_cert)(void *ctx, struct tls_cert_data *cert,
+ const char *cert_hash);
/**
* notify_status - Notification of the current EAP state
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index ff88cf8..e57461a 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -31,6 +31,7 @@
u8 emsk[EAP_EMSK_LEN];
u8 rand[EAP_AKA_RAND_LEN], autn[EAP_AKA_AUTN_LEN];
u8 auts[EAP_AKA_AUTS_LEN];
+ u8 reauth_mac[EAP_SIM_MAC_LEN];
int num_id_req, num_notification;
u8 *pseudonym;
@@ -931,8 +932,13 @@
attr->checkcode_len)) {
wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
"message");
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore AT_CHECKCODE mismatch for fuzz testing");
+#else /* TEST_FUZZ */
return eap_aka_client_error(data, id,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+#endif /* TEST_FUZZ */
}
#ifdef EAP_AKA_PRIME
@@ -1064,8 +1070,13 @@
if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
"used invalid AT_MAC");
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore AT_MAC mismatch for fuzz testing");
+#else /* TEST_FUZZ */
return eap_aka_client_error(data, id,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+#endif /* TEST_FUZZ */
}
/* Old reauthentication identity must not be used anymore. In
@@ -1214,8 +1225,13 @@
if (attr->checkcode &&
eap_aka_verify_checkcode(data, attr->checkcode,
attr->checkcode_len)) {
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore AT_CHECKCODE mismatch for fuzz testing");
+#else /* TEST_FUZZ */
wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
"message");
+#endif /* TEST_FUZZ */
return eap_aka_client_error(data, id,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
@@ -1235,6 +1251,14 @@
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
+ /* At this stage the received MAC has been verified. Use this MAC for
+ * reauth Session-Id calculation if all other checks pass.
+ * The peer does not use the local MAC but the received MAC in deriving
+ * Session-Id. */
+ os_memcpy(data->reauth_mac, attr->mac, EAP_SIM_MAC_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-AKA: Server MAC",
+ data->reauth_mac, EAP_SIM_MAC_LEN);
+
if (attr->encr_data == NULL || attr->iv == NULL) {
wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
"message did not include encrypted data");
@@ -1341,24 +1365,24 @@
if (eap_get_config_identity(sm, &len) == NULL) {
wpa_printf(MSG_INFO, "EAP-AKA: Identity not configured");
eap_sm_request_identity(sm);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, reqData,
&len);
if (pos == NULL || len < 3) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
req = wpabuf_head(reqData);
id = req->identifier;
len = be_to_host16(req->length);
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
subtype = *pos++;
wpa_printf(MSG_DEBUG, "EAP-AKA: Subtype=%d", subtype);
@@ -1417,14 +1441,14 @@
ret->methodState = METHOD_CONT;
if (ret->methodState == METHOD_DONE) {
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
}
return res;
}
-static Boolean eap_aka_has_reauth_data(struct eap_sm *sm, void *priv)
+static bool eap_aka_has_reauth_data(struct eap_sm *sm, void *priv)
{
struct eap_aka_data *data = priv;
return data->pseudonym || data->reauth_id;
@@ -1473,7 +1497,7 @@
}
-static Boolean eap_aka_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_aka_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_aka_data *data = priv;
return data->state == SUCCESS;
@@ -1506,14 +1530,24 @@
if (data->state != SUCCESS)
return NULL;
- *len = 1 + EAP_AKA_RAND_LEN + EAP_AKA_AUTN_LEN;
+ if (!data->reauth)
+ *len = 1 + EAP_AKA_RAND_LEN + EAP_AKA_AUTN_LEN;
+ else
+ *len = 1 + EAP_SIM_NONCE_S_LEN + EAP_SIM_MAC_LEN;
id = os_malloc(*len);
if (id == NULL)
return NULL;
id[0] = data->eap_method;
- os_memcpy(id + 1, data->rand, EAP_AKA_RAND_LEN);
- os_memcpy(id + 1 + EAP_AKA_RAND_LEN, data->autn, EAP_AKA_AUTN_LEN);
+ if (!data->reauth) {
+ os_memcpy(id + 1, data->rand, EAP_AKA_RAND_LEN);
+ os_memcpy(id + 1 + EAP_AKA_RAND_LEN, data->autn,
+ EAP_AKA_AUTN_LEN);
+ } else {
+ os_memcpy(id + 1, data->nonce_s, EAP_SIM_NONCE_S_LEN);
+ os_memcpy(id + 1 + EAP_SIM_NONCE_S_LEN, data->reauth_mac,
+ EAP_SIM_MAC_LEN);
+ }
wpa_hexdump(MSG_DEBUG, "EAP-AKA: Derived Session-Id", id, *len);
return id;
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index 3a88f2a..3238f74 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -1,6 +1,6 @@
/*
* EAP peer configuration data
- * Copyright (c) 2003-2013, 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.
@@ -10,68 +10,9 @@
#define EAP_CONFIG_H
/**
- * struct eap_peer_config - EAP peer configuration/credentials
+ * struct eap_peer_cert_config - EAP peer certificate configuration/credential
*/
-struct eap_peer_config {
- /**
- * identity - EAP Identity
- *
- * This field is used to set the real user identity or NAI (for
- * EAP-PSK/PAX/SAKE/GPSK).
- */
- u8 *identity;
-
- /**
- * identity_len - EAP Identity length
- */
- size_t identity_len;
-
- /**
- * anonymous_identity - Anonymous EAP Identity
- *
- * This field is used for unencrypted use with EAP types that support
- * different tunnelled identity, e.g., EAP-TTLS, in order to reveal the
- * real identity (identity field) only to the authentication server.
- *
- * If not set, the identity field will be used for both unencrypted and
- * protected fields.
- *
- * This field can also be used with EAP-SIM/AKA/AKA' to store the
- * pseudonym identity.
- */
- u8 *anonymous_identity;
-
- /**
- * anonymous_identity_len - Length of anonymous_identity
- */
- size_t anonymous_identity_len;
-
- u8 *imsi_identity;
- size_t imsi_identity_len;
-
- /**
- * password - Password string for EAP
- *
- * This field can include either the plaintext password (default
- * option) or a NtPasswordHash (16-byte MD4 hash of the unicode
- * presentation of the password) if flags field has
- * EAP_CONFIG_FLAGS_PASSWORD_NTHASH bit set to 1. NtPasswordHash can
- * only be used with authentication mechanism that use this hash as the
- * starting point for operation: MSCHAP and MSCHAPv2 (EAP-MSCHAPv2,
- * EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
- *
- * In addition, this field is used to configure a pre-shared key for
- * EAP-PSK/PAX/SAKE/GPSK. The length of the PSK must be 16 for EAP-PSK
- * and EAP-PAX and 32 for EAP-SAKE. EAP-GPSK can use a variable length
- * PSK.
- */
- u8 *password;
-
- /**
- * password_len - Length of password field
- */
- size_t password_len;
-
+struct eap_peer_cert_config {
/**
* ca_cert - File path to CA certificate file (PEM/DER)
*
@@ -231,14 +172,6 @@
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
*
* Semicolon separated string of entries to be matched against the
@@ -299,115 +232,181 @@
char *domain_match;
/**
- * ca_cert2 - File path to CA certificate file (PEM/DER) (Phase 2)
+ * pin - PIN for USIM, GSM SIM, and smartcards
*
- * This file can have one or more trusted CA certificates. If ca_cert2
- * and ca_path2 are not included, server certificate will not be
- * verified. This is insecure and a trusted CA certificate should
- * always be configured. Full path to the file should be used since
- * working directory may change when wpa_supplicant is run in the
- * background.
+ * This field is used to configure PIN for SIM and smartcards for
+ * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a
+ * smartcard is used for private key operations.
*
- * This field is like ca_cert, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
- *
- * Alternatively, a named configuration blob can be used by setting
- * this to blob://blob_name.
+ * If left out, this will be asked through control interface.
*/
- char *ca_cert2;
+ char *pin;
/**
- * ca_path2 - Directory path for CA certificate files (PEM) (Phase 2)
+ * engine - Enable OpenSSL engine (e.g., for smartcard access)
*
- * This path may contain multiple CA certificates in OpenSSL format.
- * Common use for this is to point to system trusted CA list which is
- * often installed into directory like /etc/ssl/certs. If configured,
- * these certificates are added to the list of trusted CAs. ca_cert
- * may also be included in that case, but it is not required.
- *
- * This field is like ca_path, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * This is used if private key operations for EAP-TLS are performed
+ * using a smartcard.
*/
- char *ca_path2;
+ int engine;
/**
- * client_cert2 - File path to client certificate file
+ * engine_id - Engine ID for OpenSSL engine
*
- * This field is like client_cert, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
- * file should be used since working directory may change when
- * wpa_supplicant is run in the background.
+ * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11
+ * engine.
*
- * Alternatively, a named configuration blob can be used by setting
- * this to blob://blob_name.
+ * This is used if private key operations for EAP-TLS are performed
+ * using a smartcard.
*/
- char *client_cert2;
+ char *engine_id;
+
/**
- * private_key2 - File path to client private key file
+ * key_id - Key ID for OpenSSL engine
*
- * This field is like private_key, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
- * file should be used since working directory may change when
- * wpa_supplicant is run in the background.
- *
- * Alternatively, a named configuration blob can be used by setting
- * this to blob://blob_name.
+ * This is used if private key operations for EAP-TLS are performed
+ * using a smartcard.
*/
- char *private_key2;
+ char *key_id;
/**
- * private_key2_passwd - Password for private key file
+ * cert_id - Cert ID for OpenSSL engine
*
- * This field is like private_key_passwd, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * This is used if the certificate operations for EAP-TLS are performed
+ * using a smartcard.
*/
- char *private_key2_passwd;
+ char *cert_id;
/**
- * dh_file2 - File path to DH/DSA parameters file (in PEM format)
+ * ca_cert_id - CA Cert ID for OpenSSL engine
*
- * This field is like dh_file, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
- * file should be used since working directory may change when
- * wpa_supplicant is run in the background.
- *
- * Alternatively, a named configuration blob can be used by setting
- * this to blob://blob_name.
+ * This is used if the CA certificate for EAP-TLS is on a smartcard.
*/
- char *dh_file2;
+ char *ca_cert_id;
/**
- * subject_match2 - Constraint for server certificate subject
+ * ocsp - Whether to use/require OCSP to check server certificate
*
- * This field is like subject_match, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * 0 = do not use OCSP stapling (TLS certificate status extension)
+ * 1 = try to use OCSP stapling, but not require response
+ * 2 = require valid OCSP stapling response
*/
- char *subject_match2;
+ int ocsp;
+};
+
+/**
+ * struct eap_peer_config - EAP peer configuration/credentials
+ */
+struct eap_peer_config {
+ /**
+ * identity - EAP Identity
+ *
+ * This field is used to set the real user identity or NAI (for
+ * EAP-PSK/PAX/SAKE/GPSK).
+ */
+ u8 *identity;
/**
- * altsubject_match2 - Constraint for server certificate alt. subject
- *
- * This field is like altsubject_match, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * identity_len - EAP Identity length
*/
- char *altsubject_match2;
+ size_t identity_len;
/**
- * domain_suffix_match2 - Constraint for server domain name
+ * anonymous_identity - Anonymous EAP Identity
*
- * This field is like domain_suffix_match, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * This field is used for unencrypted use with EAP types that support
+ * different tunnelled identity, e.g., EAP-TTLS, in order to reveal the
+ * real identity (identity field) only to the authentication server.
+ *
+ * If not set, the identity field will be used for both unencrypted and
+ * protected fields.
+ *
+ * This field can also be used with EAP-SIM/AKA/AKA' to store the
+ * pseudonym identity.
*/
- char *domain_suffix_match2;
+ u8 *anonymous_identity;
/**
- * domain_match2 - Constraint for server domain name
- *
- * This field is like domain_match, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ * anonymous_identity_len - Length of anonymous_identity
*/
- char *domain_match2;
+ size_t anonymous_identity_len;
+
+ u8 *imsi_identity;
+ size_t imsi_identity_len;
+
+ /**
+ * machine_identity - EAP Identity for machine credential
+ *
+ * This field is used to set the machine identity or NAI for cases where
+ * and explicit machine credential (instead of or in addition to a user
+ * credential (from %identity) is needed.
+ */
+ u8 *machine_identity;
+
+ /**
+ * machine_identity_len - EAP Identity length for machine credential
+ */
+ size_t machine_identity_len;
+
+ /**
+ * password - Password string for EAP
+ *
+ * This field can include either the plaintext password (default
+ * option) or a NtPasswordHash (16-byte MD4 hash of the unicode
+ * presentation of the password) if flags field has
+ * EAP_CONFIG_FLAGS_PASSWORD_NTHASH bit set to 1. NtPasswordHash can
+ * only be used with authentication mechanism that use this hash as the
+ * starting point for operation: MSCHAP and MSCHAPv2 (EAP-MSCHAPv2,
+ * EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
+ *
+ * In addition, this field is used to configure a pre-shared key for
+ * EAP-PSK/PAX/SAKE/GPSK. The length of the PSK must be 16 for EAP-PSK
+ * and EAP-PAX and 32 for EAP-SAKE. EAP-GPSK can use a variable length
+ * PSK.
+ */
+ u8 *password;
+
+ /**
+ * password_len - Length of password field
+ */
+ size_t password_len;
+
+ /**
+ * machine_password - Password string for EAP machine credential
+ *
+ * This field is used when machine credential based on username/password
+ * is needed instead of a user credential (from %password). See
+ * %password for more details on the format.
+ */
+ u8 *machine_password;
+
+ /**
+ * machine_password_len - Length of machine credential password field
+ */
+ size_t machine_password_len;
+
+ /**
+ * cert - Certificate parameters for Phase 1
+ */
+ struct eap_peer_cert_config cert;
+
+ /**
+ * phase2_cert - Certificate parameters for Phase 2
+ *
+ * This is like cert, but used for Phase 2 (inside
+ * EAP-TTLS/PEAP/FAST/TEAP tunnel) authentication.
+ */
+ struct eap_peer_cert_config phase2_cert;
+
+ /**
+ * machine_cert - Certificate parameters for Phase 2 machine credential
+ *
+ * This is like cert, but used for Phase 2 (inside EAP-TEAP tunnel)
+ * authentication with machine credentials (while phase2_cert is used
+ * for user credentials).
+ */
+ struct eap_peer_cert_config machine_cert;
/**
* eap_methods - Allowed EAP methods
@@ -496,6 +495,13 @@
char *phase2;
/**
+ * machine_phase2 - Phase2 parameters for machine credentials
+ *
+ * See phase2 for more details.
+ */
+ char *machine_phase2;
+
+ /**
* pcsc - Parameters for PC/SC smartcard interface for USIM and GSM SIM
*
* This field is used to configure PC/SC smartcard interface.
@@ -507,123 +513,6 @@
char *pcsc;
/**
- * pin - PIN for USIM, GSM SIM, and smartcards
- *
- * This field is used to configure PIN for SIM and smartcards for
- * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a
- * smartcard is used for private key operations.
- *
- * If left out, this will be asked through control interface.
- */
- char *pin;
-
- /**
- * engine - Enable OpenSSL engine (e.g., for smartcard access)
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- */
- int engine;
-
- /**
- * engine_id - Engine ID for OpenSSL engine
- *
- * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11
- * engine.
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- */
- char *engine_id;
-
- /**
- * engine2 - Enable OpenSSL engine (e.g., for smartcard) (Phase 2)
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- *
- * This field is like engine, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
- */
- int engine2;
-
-
- /**
- * pin2 - PIN for USIM, GSM SIM, and smartcards (Phase 2)
- *
- * This field is used to configure PIN for SIM and smartcards for
- * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a
- * smartcard is used for private key operations.
- *
- * This field is like pin2, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
- *
- * If left out, this will be asked through control interface.
- */
- char *pin2;
-
- /**
- * engine2_id - Engine ID for OpenSSL engine (Phase 2)
- *
- * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11
- * engine.
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- *
- * This field is like engine_id, but used for phase 2 (inside
- * EAP-TTLS/PEAP/FAST tunnel) authentication.
- */
- char *engine2_id;
-
-
- /**
- * key_id - Key ID for OpenSSL engine
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- */
- char *key_id;
-
- /**
- * cert_id - Cert ID for OpenSSL engine
- *
- * This is used if the certificate operations for EAP-TLS are performed
- * using a smartcard.
- */
- char *cert_id;
-
- /**
- * ca_cert_id - CA Cert ID for OpenSSL engine
- *
- * This is used if the CA certificate for EAP-TLS is on a smartcard.
- */
- char *ca_cert_id;
-
- /**
- * key2_id - Key ID for OpenSSL engine (phase2)
- *
- * This is used if private key operations for EAP-TLS are performed
- * using a smartcard.
- */
- char *key2_id;
-
- /**
- * cert2_id - Cert ID for OpenSSL engine (phase2)
- *
- * This is used if the certificate operations for EAP-TLS are performed
- * using a smartcard.
- */
- char *cert2_id;
-
- /**
- * ca_cert2_id - CA Cert ID for OpenSSL engine (phase2)
- *
- * This is used if the CA certificate for EAP-TLS is on a smartcard.
- */
- char *ca_cert2_id;
-
- /**
* otp - One-time-password
*
* This field should not be set in configuration step. It is only used
@@ -751,6 +640,8 @@
#define EAP_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0)
#define EAP_CONFIG_FLAGS_EXT_PASSWORD BIT(1)
+#define EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH BIT(2)
+#define EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD BIT(3)
/**
* flags - Network configuration flags (bitfield)
*
@@ -760,19 +651,14 @@
* instead of plaintext password
* bit 1 = password is stored in external storage; the value in the
* password field is the name of that external entry
+ * bit 2 = machine password is represented as a 16-byte NtPasswordHash
+ * value instead of plaintext password
+ * bit 3 = machine password is stored in external storage; the value in
+ * the password field is the name of that external entry
*/
u32 flags;
/**
- * ocsp - Whether to use/require OCSP to check server certificate
- *
- * 0 = do not use OCSP stapling (TLS certificate status extension)
- * 1 = try to use OCSP stapling, but not require response
- * 2 = require valid OCSP stapling response
- */
- int ocsp;
-
- /**
* external_sim_resp - Response from external SIM processing
*
* This field should not be set in configuration step. It is only used
@@ -816,6 +702,8 @@
EXT_CERT_CHECK_GOOD,
EXT_CERT_CHECK_BAD,
} pending_ext_cert_check;
+
+ int teap_anon_dh;
};
diff --git a/src/eap_peer/eap_eke.c b/src/eap_peer/eap_eke.c
index 0de7d6c..9029442 100644
--- a/src/eap_peer/eap_eke.c
+++ b/src/eap_peer/eap_eke.c
@@ -211,7 +211,7 @@
eap_eke_state(data, FAILURE);
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
return resp;
}
@@ -414,7 +414,7 @@
*/
if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) {
wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH");
- os_memset(key, 0, sizeof(key));
+ forced_memzero(key, sizeof(key));
return eap_eke_build_fail(data, ret, id,
EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
}
@@ -422,7 +422,7 @@
if (eap_eke_shared_secret(&data->sess, key, data->dh_priv, dhcomp) < 0)
{
wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret");
- os_memset(key, 0, sizeof(key));
+ forced_memzero(key, sizeof(key));
return eap_eke_build_fail(data, ret, id,
EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
}
@@ -431,7 +431,7 @@
data->serverid, data->serverid_len,
data->peerid, data->peerid_len) < 0) {
wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
- os_memset(key, 0, sizeof(key));
+ forced_memzero(key, sizeof(key));
return eap_eke_build_fail(data, ret, id,
EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
}
@@ -442,7 +442,7 @@
data->sess.dhcomp_len + data->sess.pnonce_len,
EAP_EKE_COMMIT);
if (resp == NULL) {
- os_memset(key, 0, sizeof(key));
+ forced_memzero(key, sizeof(key));
return eap_eke_build_fail(data, ret, id,
EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
}
@@ -452,11 +452,11 @@
if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) {
wpabuf_free(resp);
wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_P");
- os_memset(key, 0, sizeof(key));
+ forced_memzero(key, sizeof(key));
return eap_eke_build_fail(data, ret, id,
EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
}
- os_memset(key, 0, sizeof(key));
+ forced_memzero(key, sizeof(key));
wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P",
rpos, data->sess.dhcomp_len);
@@ -617,7 +617,7 @@
eap_eke_state(data, SUCCESS);
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_COND_SUCC;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
return resp;
}
@@ -656,7 +656,7 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, reqData, &len);
if (pos == NULL || len < 1) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -666,10 +666,10 @@
wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: exch %d", eke_exch);
wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received Data", pos, end - pos);
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
switch (eke_exch) {
case EAP_EKE_ID:
@@ -689,18 +689,18 @@
break;
default:
wpa_printf(MSG_DEBUG, "EAP-EKE: Ignoring message with unknown EKE-Exch %d", eke_exch);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (ret->methodState == METHOD_DONE)
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
return resp;
}
-static Boolean eap_eke_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_eke_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_eke_data *data = priv;
return data->state == SUCCESS;
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 94ce57d..b12cfee 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -162,7 +162,7 @@
if (eap_peer_select_phase2_methods(config, "auth=",
&data->phase2_types,
- &data->num_phase2_types) < 0) {
+ &data->num_phase2_types, 0) < 0) {
eap_fast_deinit(sm, data);
return NULL;
}
@@ -364,22 +364,24 @@
}
-static int eap_fast_select_phase2_method(struct eap_fast_data *data, u8 type)
+static int eap_fast_select_phase2_method(struct eap_fast_data *data,
+ int vendor, enum eap_type type)
{
size_t i;
/* TODO: TNC with anonymous provisioning; need to require both
* completed MSCHAPv2 and TNC */
- if (data->anon_provisioning && type != EAP_TYPE_MSCHAPV2) {
- wpa_printf(MSG_INFO, "EAP-FAST: Only EAP-MSCHAPv2 is allowed "
- "during unauthenticated provisioning; reject phase2"
- " type %d", type);
+ if (data->anon_provisioning &&
+ (vendor != EAP_VENDOR_IETF || type != EAP_TYPE_MSCHAPV2)) {
+ wpa_printf(MSG_INFO,
+ "EAP-FAST: Only EAP-MSCHAPv2 is allowed during unauthenticated provisioning; reject phase2 type %u:%u",
+ vendor, type);
return -1;
}
#ifdef EAP_TNC
- if (type == EAP_TYPE_TNC) {
+ if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_TNC) {
data->phase2_type.vendor = EAP_VENDOR_IETF;
data->phase2_type.method = EAP_TYPE_TNC;
wpa_printf(MSG_DEBUG, "EAP-FAST: Selected Phase 2 EAP "
@@ -391,7 +393,7 @@
#endif /* EAP_TNC */
for (i = 0; i < data->num_phase2_types; i++) {
- if (data->phase2_types[i].vendor != EAP_VENDOR_IETF ||
+ if (data->phase2_types[i].vendor != vendor ||
data->phase2_types[i].method != type)
continue;
@@ -404,7 +406,9 @@
break;
}
- if (type != data->phase2_type.method || type == EAP_TYPE_NONE)
+ if (vendor != data->phase2_type.vendor ||
+ type != data->phase2_type.method ||
+ (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_NONE))
return -1;
return 0;
@@ -422,6 +426,8 @@
struct eap_method_ret iret;
struct eap_peer_config *config = eap_get_config(sm);
struct wpabuf msg;
+ int vendor = EAP_VENDOR_IETF;
+ enum eap_type method;
if (len <= sizeof(struct eap_hdr)) {
wpa_printf(MSG_INFO, "EAP-FAST: too short "
@@ -429,14 +435,27 @@
return -1;
}
pos = (u8 *) (hdr + 1);
- wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%d", *pos);
- if (*pos == EAP_TYPE_IDENTITY) {
+ method = *pos;
+ if (method == EAP_TYPE_EXPANDED) {
+ if (len < sizeof(struct eap_hdr) + 8) {
+ wpa_printf(MSG_INFO,
+ "EAP-FAST: Too short Phase 2 request (expanded header) (len=%lu)",
+ (unsigned long) len);
+ return -1;
+ }
+ vendor = WPA_GET_BE24(pos + 1);
+ method = WPA_GET_BE32(pos + 4);
+ }
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%u:%u",
+ vendor, method);
+ if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_IDENTITY) {
*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
return 0;
}
if (data->phase2_priv && data->phase2_method &&
- *pos != data->phase2_type.method) {
+ (vendor != data->phase2_type.vendor ||
+ method != data->phase2_type.method)) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 EAP sequence - "
"deinitialize previous method");
data->phase2_method->deinit(sm, data->phase2_priv);
@@ -448,7 +467,7 @@
if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
data->phase2_type.method == EAP_TYPE_NONE &&
- eap_fast_select_phase2_method(data, *pos) < 0) {
+ eap_fast_select_phase2_method(data, vendor, method) < 0) {
if (eap_peer_tls_phase2_nak(data->phase2_types,
data->num_phase2_types,
hdr, resp))
@@ -459,8 +478,9 @@
if ((data->phase2_priv == NULL &&
eap_fast_init_phase2_method(sm, data) < 0) ||
data->phase2_method == NULL) {
- wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize "
- "Phase 2 EAP method %d", *pos);
+ wpa_printf(MSG_INFO,
+ "EAP-FAST: Failed to initialize Phase 2 EAP method %u:%u",
+ vendor, method);
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
return -1;
@@ -1668,7 +1688,7 @@
#if 0 /* FIX */
-static Boolean eap_fast_has_reauth_data(struct eap_sm *sm, void *priv)
+static bool eap_fast_has_reauth_data(struct eap_sm *sm, void *priv)
{
struct eap_fast_data *data = priv;
return tls_connection_established(sm->ssl_ctx, data->ssl.conn);
@@ -1734,7 +1754,7 @@
}
-static Boolean eap_fast_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_fast_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_fast_data *data = priv;
return data->success;
diff --git a/src/eap_peer/eap_gpsk.c b/src/eap_peer/eap_gpsk.c
index f9c4d37..20d96c1 100644
--- a/src/eap_peer/eap_gpsk.c
+++ b/src/eap_peer/eap_gpsk.c
@@ -280,7 +280,7 @@
struct wpabuf *resp;
if (data->state != GPSK_1) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -588,7 +588,7 @@
const u8 *pos, *end;
if (data->state != GPSK_3) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -671,7 +671,7 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len);
if (pos == NULL || len < 1) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -680,10 +680,10 @@
len--;
wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", opcode);
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
switch (opcode) {
case EAP_GPSK_OPCODE_GPSK_1:
@@ -696,7 +696,7 @@
wpa_printf(MSG_DEBUG,
"EAP-GPSK: Ignoring message with unknown opcode %d",
opcode);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -704,7 +704,7 @@
}
-static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_gpsk_data *data = priv;
return data->state == SUCCESS;
diff --git a/src/eap_peer/eap_gtc.c b/src/eap_peer/eap_gtc.c
index a519a78..72c02cc 100644
--- a/src/eap_peer/eap_gtc.c
+++ b/src/eap_peer/eap_gtc.c
@@ -54,7 +54,7 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, reqData, &len);
if (pos == NULL) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
id = eap_get_id(reqData);
@@ -85,15 +85,15 @@
if (password == NULL) {
wpa_printf(MSG_INFO, "EAP-GTC: Password not configured");
eap_sm_request_otp(sm, (const char *) pos, len);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = data->prefix ? METHOD_MAY_CONT : METHOD_DONE;
ret->decision = DECISION_COND_SUCC;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
plen = password_len;
identity = eap_get_config_identity(sm, &identity_len);
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index 096f0f2..f43891e 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -38,7 +38,7 @@
/**
* ignore - Whether method decided to drop the current packed (OUT)
*/
- Boolean ignore;
+ bool ignore;
/**
* methodState - Method-specific state (IN/OUT)
@@ -53,7 +53,7 @@
/**
* allowNotifications - Whether method allows notifications (OUT)
*/
- Boolean allowNotifications;
+ bool allowNotifications;
};
@@ -72,7 +72,7 @@
/**
* method - EAP type number (EAP_TYPE_*)
*/
- EapType method;
+ enum eap_type method;
/**
* name - Name of the method (e.g., "TLS")
@@ -123,9 +123,9 @@
* isKeyAvailable - Find out whether EAP method has keying material
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
* @priv: Pointer to private EAP method data from eap_method::init()
- * Returns: %TRUE if key material (eapKeyData) is available
+ * Returns: %true if key material (eapKeyData) is available
*/
- Boolean (*isKeyAvailable)(struct eap_sm *sm, void *priv);
+ bool (*isKeyAvailable)(struct eap_sm *sm, void *priv);
/**
* getKey - Get EAP method specific keying material (eapKeyData)
@@ -161,13 +161,13 @@
* has_reauth_data - Whether method is ready for fast reauthentication
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
* @priv: Pointer to private EAP method data from eap_method::init()
- * Returns: %TRUE or %FALSE based on whether fast reauthentication is
+ * Returns: %true or %false based on whether fast reauthentication is
* possible
*
* This function is an optional handler that only EAP methods
* supporting fast re-authentication need to implement.
*/
- Boolean (*has_reauth_data)(struct eap_sm *sm, void *priv);
+ bool (*has_reauth_data)(struct eap_sm *sm, void *priv);
/**
* deinit_for_reauth - Release data that is not needed for fast re-auth
@@ -312,45 +312,45 @@
EAP_FAILURE
} EAP_state;
/* Long-term local variables */
- EapType selectedMethod;
+ enum eap_type selectedMethod;
EapMethodState methodState;
int lastId;
struct wpabuf *lastRespData;
EapDecision decision;
/* Short-term local variables */
- Boolean rxReq;
- Boolean rxSuccess;
- Boolean rxFailure;
+ bool rxReq;
+ bool rxSuccess;
+ bool rxFailure;
int reqId;
- EapType reqMethod;
+ enum eap_type reqMethod;
int reqVendor;
u32 reqVendorMethod;
- Boolean ignore;
+ bool ignore;
/* Constants */
int ClientTimeout;
/* Miscellaneous variables */
- Boolean allowNotifications; /* peer state machine <-> methods */
+ bool allowNotifications; /* peer state machine <-> methods */
struct wpabuf *eapRespData; /* peer to lower layer */
- Boolean eapKeyAvailable; /* peer to lower layer */
+ bool eapKeyAvailable; /* peer to lower layer */
u8 *eapKeyData; /* peer to lower layer */
size_t eapKeyDataLen; /* peer to lower layer */
u8 *eapSessionId; /* peer to lower layer */
size_t eapSessionIdLen; /* peer to lower layer */
const struct eap_method *m; /* selected EAP method */
/* not defined in RFC 4137 */
- Boolean changed;
+ bool changed;
void *eapol_ctx;
const struct eapol_callbacks *eapol_cb;
void *eap_method_priv;
int init_phase2;
int fast_reauth;
- Boolean reauthInit; /* send EAP-Identity/Re-auth */
+ bool reauthInit; /* send EAP-Identity/Re-auth */
u32 erp_seq;
- Boolean rxResp /* LEAP only */;
- Boolean leap_done;
- Boolean peap_done;
+ bool rxResp /* LEAP only */;
+ bool leap_done;
+ bool peap_done;
u8 req_sha1[20]; /* SHA1() of the current EAP packet */
u8 last_sha1[20]; /* SHA1() of the previously received EAP packet; used
* in duplicate request detection. */
@@ -366,6 +366,7 @@
u8 *peer_challenge, *auth_challenge;
int num_rounds;
+ int num_rounds_short;
int force_disabled;
struct wps_context *wps;
@@ -381,6 +382,7 @@
unsigned int expected_failure:1;
unsigned int ext_cert_check:1;
unsigned int waiting_ext_cert_check:1;
+ unsigned int use_machine_cred:1;
struct dl_list erp_keys; /* struct eap_erp_key */
};
diff --git a/src/eap_peer/eap_ikev2.c b/src/eap_peer/eap_ikev2.c
index 6ddf508..b49fe16 100644
--- a/src/eap_peer/eap_ikev2.c
+++ b/src/eap_peer/eap_ikev2.c
@@ -138,9 +138,9 @@
u8 flags;
size_t send_len, plen, icv_len = 0;
- ret->ignore = FALSE;
+ ret->ignore = false;
wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Response");
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
flags = 0;
send_len = wpabuf_len(data->out_buf) - data->out_used;
@@ -293,7 +293,7 @@
if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) {
wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in "
"a fragmented packet");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -303,14 +303,14 @@
/* Limit maximum memory allocation */
wpa_printf(MSG_DEBUG,
"EAP-IKEV2: Ignore too long message");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
data->in_buf = wpabuf_alloc(message_length);
if (data->in_buf == NULL) {
wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for "
"message");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
wpabuf_put_data(data->in_buf, buf, len);
@@ -320,7 +320,7 @@
(unsigned long) wpabuf_tailroom(data->in_buf));
}
- ret->ignore = FALSE;
+ ret->ignore = false;
return eap_ikev2_build_frag_ack(id, EAP_CODE_RESPONSE);
}
@@ -338,7 +338,7 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, reqData, &len);
if (pos == NULL) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -355,14 +355,14 @@
if (eap_ikev2_process_icv(data, reqData, flags, pos, &end,
data->state == WAIT_FRAG_ACK && len == 0) < 0)
{
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) {
if (end - pos < 4) {
wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
message_length = WPA_GET_BE32(pos);
@@ -372,7 +372,7 @@
wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message "
"Length (%d; %ld remaining in this msg)",
message_length, (long) (end - pos));
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
}
@@ -384,7 +384,7 @@
if (len != 0) {
wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload "
"in WAIT_FRAG_ACK state");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged");
@@ -393,10 +393,10 @@
}
if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
-
+
if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) {
return eap_ikev2_process_fragment(data, ret, id, flags,
message_length, pos,
@@ -435,7 +435,7 @@
}
-static Boolean eap_ikev2_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_ikev2_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_ikev2_data *data = priv;
return data->state == DONE && data->keymat_ok;
diff --git a/src/eap_peer/eap_leap.c b/src/eap_peer/eap_leap.c
index 233b9ee..02daddf 100644
--- a/src/eap_peer/eap_leap.c
+++ b/src/eap_peer/eap_leap.c
@@ -45,7 +45,7 @@
return NULL;
data->state = LEAP_WAIT_CHALLENGE;
- sm->leap_done = FALSE;
+ sm->leap_done = false;
return data;
}
@@ -77,14 +77,14 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len);
if (pos == NULL || len < 3) {
wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Request frame");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (*pos != LEAP_VERSION) {
wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
"%d", *pos);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
pos++;
@@ -96,7 +96,7 @@
wpa_printf(MSG_INFO, "EAP-LEAP: Invalid challenge "
"(challenge_len=%d reqDataLen=%lu)",
challenge_len, (unsigned long) wpabuf_len(reqData));
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
challenge = pos;
@@ -119,7 +119,7 @@
(!pwhash &&
nt_challenge_response(challenge, password, password_len, rpos))) {
wpa_printf(MSG_DEBUG, "EAP-LEAP: Failed to derive response");
- ret->ignore = TRUE;
+ ret->ignore = true;
wpabuf_free(resp);
return NULL;
}
@@ -153,7 +153,7 @@
if (data->state != LEAP_WAIT_SUCCESS) {
wpa_printf(MSG_INFO, "EAP-LEAP: EAP-Success received in "
"unexpected state (%d) - ignored", data->state);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -170,7 +170,7 @@
wpa_printf(MSG_WARNING, "EAP-LEAP: Failed to read random data "
"for challenge");
wpabuf_free(resp);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
os_memcpy(data->ap_challenge, pos, LEAP_CHALLENGE_LEN);
@@ -204,14 +204,14 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len);
if (pos == NULL || len < 3) {
wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Response frame");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (*pos != LEAP_VERSION) {
wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
"%d", *pos);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
pos++;
@@ -223,7 +223,7 @@
wpa_printf(MSG_INFO, "EAP-LEAP: Invalid response "
"(response_len=%d reqDataLen=%lu)",
response_len, (unsigned long) wpabuf_len(reqData));
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -233,23 +233,23 @@
if (pwhash) {
if (hash_nt_password_hash(password, pw_hash_hash)) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
} else {
if (nt_password_hash(password, password_len, pw_hash) ||
hash_nt_password_hash(pw_hash, pw_hash_hash)) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
}
if (challenge_response(data->ap_challenge, pw_hash_hash, expected)) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
ret->methodState = METHOD_DONE;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
if (os_memcmp_const(pos, expected, LEAP_RESPONSE_LEN) != 0) {
wpa_printf(MSG_WARNING, "EAP-LEAP: AP sent an invalid "
@@ -265,7 +265,7 @@
/* LEAP is somewhat odd method since it sends EAP-Success in the middle
* of the authentication. Use special variable to transit EAP state
* machine to SUCCESS state. */
- sm->leap_done = TRUE;
+ sm->leap_done = true;
data->state = LEAP_DONE;
/* No more authentication messages expected; AP will send EAPOL-Key
@@ -286,7 +286,7 @@
if (password == NULL) {
wpa_printf(MSG_INFO, "EAP-LEAP: Password not configured");
eap_sm_request_password(sm);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -300,16 +300,16 @@
if (wpabuf_len(reqData) < sizeof(*eap) ||
be_to_host16(eap->length) > wpabuf_len(reqData)) {
wpa_printf(MSG_INFO, "EAP-LEAP: Invalid frame");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
- ret->ignore = FALSE;
- ret->allowNotifications = TRUE;
+ ret->ignore = false;
+ ret->allowNotifications = true;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- sm->leap_done = FALSE;
+ sm->leap_done = false;
switch (eap->code) {
case EAP_CODE_REQUEST:
@@ -321,13 +321,13 @@
default:
wpa_printf(MSG_INFO, "EAP-LEAP: Unexpected EAP code (%d) - "
"ignored", eap->code);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
}
-static Boolean eap_leap_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_leap_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_leap_data *data = priv;
return data->state == LEAP_DONE;
@@ -390,8 +390,8 @@
wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN);
*len = LEAP_KEY_LEN;
- os_memset(pw_hash, 0, sizeof(pw_hash));
- os_memset(pw_hash_hash, 0, sizeof(pw_hash_hash));
+ forced_memzero(pw_hash, sizeof(pw_hash));
+ forced_memzero(pw_hash_hash, sizeof(pw_hash_hash));
return key;
}
diff --git a/src/eap_peer/eap_md5.c b/src/eap_peer/eap_md5.c
index efae8de..14ac569 100644
--- a/src/eap_peer/eap_md5.c
+++ b/src/eap_peer/eap_md5.c
@@ -39,7 +39,7 @@
if (password == NULL) {
wpa_printf(MSG_INFO, "EAP-MD5: Password not configured");
eap_sm_request_password(sm);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -47,7 +47,7 @@
if (pos == NULL || len == 0) {
wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame (pos=%p len=%lu)",
pos, (unsigned long) len);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -60,10 +60,10 @@
wpa_printf(MSG_INFO, "EAP-MD5: Invalid challenge "
"(challenge_len=%lu len=%lu)",
(unsigned long) challenge_len, (unsigned long) len);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
- ret->ignore = FALSE;
+ ret->ignore = false;
challenge = pos;
wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge",
challenge, challenge_len);
@@ -71,7 +71,7 @@
wpa_printf(MSG_DEBUG, "EAP-MD5: Generating Challenge Response");
ret->methodState = METHOD_DONE;
ret->decision = DECISION_COND_SUCC;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, 1 + CHAP_MD5_LEN,
EAP_CODE_RESPONSE, eap_get_id(reqData));
@@ -89,7 +89,7 @@
if (chap_md5(id, password, password_len, challenge, challenge_len,
rpos)) {
wpa_printf(MSG_INFO, "EAP-MD5: CHAP MD5 operation failed");
- ret->ignore = TRUE;
+ ret->ignore = true;
wpabuf_free(resp);
return NULL;
}
diff --git a/src/eap_peer/eap_methods.c b/src/eap_peer/eap_methods.c
index 9747954..f2d2947 100644
--- a/src/eap_peer/eap_methods.c
+++ b/src/eap_peer/eap_methods.c
@@ -27,7 +27,8 @@
* @method: EAP type number
* Returns: Pointer to EAP method or %NULL if not found
*/
-const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method)
+const struct eap_method * eap_peer_get_eap_method(int vendor,
+ enum eap_type method)
{
struct eap_method *m;
for (m = eap_methods; m; m = m->next) {
@@ -47,7 +48,7 @@
* This function maps EAP type names into EAP type numbers based on the list of
* EAP methods included in the build.
*/
-EapType eap_peer_get_type(const char *name, int *vendor)
+enum eap_type eap_peer_get_type(const char *name, int *vendor)
{
struct eap_method *m;
for (m = eap_methods; m; m = m->next) {
@@ -70,7 +71,7 @@
* This function maps EAP type numbers into EAP type names based on the list of
* EAP methods included in the build.
*/
-const char * eap_get_name(int vendor, EapType type)
+const char * eap_get_name(int vendor, enum eap_type type)
{
struct eap_method *m;
if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
@@ -169,7 +170,7 @@
for (m = eap_methods; m; m = m->next)
c++;
-
+
*count = c;
return eap_methods;
}
@@ -279,7 +280,8 @@
* is not needed anymore.
*/
struct eap_method * eap_peer_method_alloc(int version, int vendor,
- EapType method, const char *name)
+ enum eap_type method,
+ const char *name)
{
struct eap_method *eap;
eap = os_zalloc(sizeof(*eap));
diff --git a/src/eap_peer/eap_methods.h b/src/eap_peer/eap_methods.h
index b96b211..e94f3d7 100644
--- a/src/eap_peer/eap_methods.h
+++ b/src/eap_peer/eap_methods.h
@@ -11,31 +11,33 @@
#include "eap_common/eap_defs.h"
-const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method);
+const struct eap_method * eap_peer_get_eap_method(int vendor,
+ enum eap_type method);
const struct eap_method * eap_peer_get_methods(size_t *count);
struct eap_method * eap_peer_method_alloc(int version, int vendor,
- EapType method, const char *name);
+ enum eap_type method,
+ const char *name);
int eap_peer_method_register(struct eap_method *method);
#ifdef IEEE8021X_EAPOL
-EapType eap_peer_get_type(const char *name, int *vendor);
-const char * eap_get_name(int vendor, EapType type);
+enum eap_type eap_peer_get_type(const char *name, int *vendor);
+const char * eap_get_name(int vendor, enum eap_type type);
size_t eap_get_names(char *buf, size_t buflen);
char ** eap_get_names_as_string_array(size_t *num);
void eap_peer_unregister_methods(void);
#else /* IEEE8021X_EAPOL */
-static inline EapType eap_peer_get_type(const char *name, int *vendor)
+static inline enum eap_type eap_peer_get_type(const char *name, int *vendor)
{
*vendor = EAP_VENDOR_IETF;
return EAP_TYPE_NONE;
}
-static inline const char * eap_get_name(int vendor, EapType type)
+static inline const char * eap_get_name(int vendor, enum eap_type type)
{
return NULL;
}
@@ -97,6 +99,7 @@
int eap_peer_aka_register(void);
int eap_peer_aka_prime_register(void);
int eap_peer_fast_register(void);
+int eap_peer_teap_register(void);
int eap_peer_pax_register(void);
int eap_peer_sake_register(void);
int eap_peer_gpsk_register(void);
diff --git a/src/eap_peer/eap_mschapv2.c b/src/eap_peer/eap_mschapv2.c
index 249baec..8ad4d18 100644
--- a/src/eap_peer/eap_mschapv2.c
+++ b/src/eap_peer/eap_mschapv2.c
@@ -250,7 +250,7 @@
if (req_len < sizeof(*req) + 1) {
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge data "
"(len %lu)", (unsigned long) req_len);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
pos = (const u8 *) (req + 1);
@@ -259,7 +259,7 @@
if (challenge_len != MSCHAPV2_CHAL_LEN) {
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid challenge length "
"%lu", (unsigned long) challenge_len);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -267,7 +267,7 @@
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge"
" packet: len=%lu challenge_len=%lu",
(unsigned long) len, (unsigned long) challenge_len);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -282,10 +282,10 @@
wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Authentication Servername",
pos, len);
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
return eap_mschapv2_challenge_reply(sm, data, id, req->mschapv2_id,
challenge);
@@ -377,7 +377,7 @@
if (resp == NULL) {
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Failed to allocate "
"buffer for success response");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -385,7 +385,7 @@
ret->methodState = METHOD_DONE;
ret->decision = DECISION_UNCOND_SUCC;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
data->success = 1;
if (data->prev_error == ERROR_PASSWD_EXPIRED)
@@ -531,10 +531,10 @@
username = mschapv2_remove_domain(username, &username_len);
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_COND_SUCC;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
ms_len = sizeof(*ms) + sizeof(*cp);
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
@@ -672,10 +672,10 @@
os_free(buf);
}
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
if (data->prev_error == ERROR_PASSWD_EXPIRED &&
data->passwd_change_version == 3) {
@@ -783,7 +783,7 @@
u8 id;
if (eap_mschapv2_check_config(sm)) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -800,13 +800,13 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, reqData,
&len);
if (pos == NULL || len < sizeof(*ms) + 1) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
ms = (const struct eap_mschapv2_hdr *) pos;
if (eap_mschapv2_check_mslen(sm, len, ms)) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -826,13 +826,13 @@
default:
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Unknown op %d - ignored",
ms->op_code);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
}
-static Boolean eap_mschapv2_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_mschapv2_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_mschapv2_data *data = priv;
return data->success && data->master_key_valid;
diff --git a/src/eap_peer/eap_otp.c b/src/eap_peer/eap_otp.c
index 0ab4c79..87615c6 100644
--- a/src/eap_peer/eap_otp.c
+++ b/src/eap_peer/eap_otp.c
@@ -36,7 +36,7 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_OTP, reqData, &len);
if (pos == NULL) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-OTP: Request message",
@@ -53,15 +53,15 @@
if (password == NULL) {
wpa_printf(MSG_INFO, "EAP-OTP: Password not configured");
eap_sm_request_otp(sm, (const char *) pos, len);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_DONE;
ret->decision = DECISION_COND_SUCC;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_OTP, password_len,
EAP_CODE_RESPONSE, eap_get_id(reqData));
diff --git a/src/eap_peer/eap_pax.c b/src/eap_peer/eap_pax.c
index 3cef1c8..a641d44 100644
--- a/src/eap_peer/eap_pax.c
+++ b/src/eap_peer/eap_pax.c
@@ -127,14 +127,14 @@
if (data->state != PAX_INIT) {
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 received in "
"unexpected state (%d) - ignored", data->state);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (req->flags & EAP_PAX_FLAGS_CE) {
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with CE flag set - "
"ignored");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -143,7 +143,7 @@
if (left < 2 + EAP_PAX_RAND_LEN) {
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with too short "
"payload");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -152,7 +152,7 @@
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with incorrect A "
"length %d (expected %d)",
WPA_GET_BE16(pos), EAP_PAX_RAND_LEN);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -171,7 +171,7 @@
if (random_get_bytes(data->rand.r.y, EAP_PAX_RAND_LEN)) {
wpa_printf(MSG_ERROR, "EAP-PAX: Failed to get random data");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Y (client rand)",
@@ -180,7 +180,7 @@
if (eap_pax_initial_key_derivation(req->mac_id, data->ak, data->rand.e,
data->mk, data->ck, data->ick,
data->mid) < 0) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -243,14 +243,14 @@
if (data->state != PAX_STD_2_SENT) {
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 received in "
"unexpected state (%d) - ignored", data->state);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (req->flags & EAP_PAX_FLAGS_CE) {
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with CE flag set - "
"ignored");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -259,7 +259,7 @@
if (left < 2 + EAP_PAX_MAC_LEN) {
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with too short "
"payload");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -268,7 +268,7 @@
wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with incorrect "
"MAC_CK length %d (expected %d)",
WPA_GET_BE16(pos), EAP_PAX_MAC_LEN);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
pos += 2;
@@ -323,7 +323,7 @@
data->state = PAX_DONE;
ret->methodState = METHOD_DONE;
ret->decision = DECISION_UNCOND_SUCC;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
return resp;
}
@@ -343,7 +343,7 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, reqData, &len);
if (pos == NULL || len < sizeof(*req) + EAP_PAX_ICV_LEN) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
id = eap_get_id(reqData);
@@ -363,7 +363,7 @@
wpa_printf(MSG_INFO, "EAP-PAX: MAC ID changed during "
"authentication (was 0x%d, is 0x%d)",
data->mac_id, req->mac_id);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -371,7 +371,7 @@
wpa_printf(MSG_INFO, "EAP-PAX: DH Group ID changed during "
"authentication (was 0x%d, is 0x%d)",
data->dh_group_id, req->dh_group_id);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -380,7 +380,7 @@
wpa_printf(MSG_INFO, "EAP-PAX: Public Key ID changed during "
"authentication (was 0x%d, is 0x%d)",
data->public_key_id, req->public_key_id);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -388,21 +388,21 @@
if (req->mac_id != EAP_PAX_MAC_HMAC_SHA1_128) {
wpa_printf(MSG_INFO, "EAP-PAX: Unsupported MAC ID 0x%x",
req->mac_id);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (req->dh_group_id != EAP_PAX_DH_GROUP_NONE) {
wpa_printf(MSG_INFO, "EAP-PAX: Unsupported DH Group ID 0x%x",
req->dh_group_id);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (req->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) {
wpa_printf(MSG_INFO, "EAP-PAX: Unsupported Public Key ID 0x%x",
req->public_key_id);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -410,7 +410,7 @@
/* TODO: add support for reassembling fragments */
wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported - "
"ignored packet");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -430,14 +430,14 @@
"message");
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected ICV",
icvbuf, EAP_PAX_ICV_LEN);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
switch (req->op_code) {
case EAP_PAX_OP_STD_1:
@@ -449,19 +449,19 @@
default:
wpa_printf(MSG_DEBUG, "EAP-PAX: ignoring message with unknown "
"op_code %d", req->op_code);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (ret->methodState == METHOD_DONE) {
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
}
return resp;
}
-static Boolean eap_pax_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_pax_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_pax_data *data = priv;
return data->state == PAX_DONE;
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 8dcf7cc..7c37043 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -137,7 +137,7 @@
data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
- sm->peap_done = FALSE;
+ sm->peap_done = false;
data->peap_version = EAP_PEAP_VERSION;
data->force_peap_version = -1;
data->peap_outer_success = 2;
@@ -148,7 +148,7 @@
if (eap_peer_select_phase2_methods(config, "auth=",
&data->phase2_types,
- &data->num_phase2_types) < 0) {
+ &data->num_phase2_types, 0) < 0) {
eap_peap_deinit(sm, data);
return NULL;
}
@@ -295,7 +295,7 @@
res = peap_prfplus(data->peap_version, tk, 40,
"Inner Methods Compound Keys",
isk, sizeof(isk), imck, sizeof(imck));
- os_memset(isk, 0, sizeof(isk));
+ forced_memzero(isk, sizeof(isk));
if (res < 0)
return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
@@ -305,7 +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));
+ forced_memzero(imck, sizeof(imck));
return 0;
}
@@ -603,6 +603,8 @@
u8 *pos;
struct eap_method_ret iret;
struct eap_peer_config *config = eap_get_config(sm);
+ int vendor;
+ enum eap_type method;
if (len <= sizeof(struct eap_hdr)) {
wpa_printf(MSG_INFO, "EAP-PEAP: too short "
@@ -666,13 +668,26 @@
#endif /* EAP_TNC */
/* fall through */
default:
+ vendor = EAP_VENDOR_IETF;
+ method = *pos;
+
+ if (method == EAP_TYPE_EXPANDED) {
+ if (len < sizeof(struct eap_hdr) + 8) {
+ wpa_printf(MSG_INFO,
+ "EAP-PEAP: Too short Phase 2 request (expanded header) (len=%lu)",
+ (unsigned long) len);
+ return -1;
+ }
+ vendor = WPA_GET_BE24(pos + 1);
+ method = WPA_GET_BE32(pos + 4);
+ }
+
if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
data->phase2_type.method == EAP_TYPE_NONE) {
size_t i;
for (i = 0; i < data->num_phase2_types; i++) {
- if (data->phase2_types[i].vendor !=
- EAP_VENDOR_IETF ||
- data->phase2_types[i].method != *pos)
+ if (data->phase2_types[i].vendor != vendor ||
+ data->phase2_types[i].method != method)
continue;
data->phase2_type.vendor =
@@ -686,8 +701,9 @@
break;
}
}
- if (*pos != data->phase2_type.method ||
- *pos == EAP_TYPE_NONE) {
+ if (vendor != data->phase2_type.vendor ||
+ method != data->phase2_type.method ||
+ (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE)) {
if (eap_peer_tls_phase2_nak(data->phase2_types,
data->num_phase2_types,
hdr, resp))
@@ -904,7 +920,7 @@
/* No EAP-Success expected for Phase 1 (outer,
* unencrypted auth), so force EAP state
* machine to SUCCESS state. */
- sm->peap_done = TRUE;
+ sm->peap_done = true;
}
} else {
/* FIX: ? */
@@ -914,7 +930,7 @@
wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
ret->decision = DECISION_FAIL;
ret->methodState = METHOD_MAY_CONT;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
/* Reply with EAP-Failure within the TLS channel to complete
* failure reporting. */
resp = wpabuf_alloc(sizeof(struct eap_hdr));
@@ -998,7 +1014,7 @@
data->force_peap_version);
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
return NULL;
}
wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d",
@@ -1150,7 +1166,7 @@
}
if (ret->methodState == METHOD_DONE) {
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
}
if (res == 1) {
@@ -1163,7 +1179,7 @@
}
-static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
+static bool eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
{
struct eap_peap_data *data = priv;
return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
@@ -1204,7 +1220,7 @@
data->phase2_eap_started = 0;
data->resuming = 1;
data->reauth = 1;
- sm->peap_done = FALSE;
+ sm->peap_done = false;
return priv;
}
@@ -1229,7 +1245,7 @@
}
-static Boolean eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_peap_data *data = priv;
return data->key_data != NULL && data->phase2_success;
@@ -1267,7 +1283,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));
+ forced_memzero(csk, sizeof(csk));
} else
os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
diff --git a/src/eap_peer/eap_psk.c b/src/eap_peer/eap_psk.c
index eea9430..4997e6a 100644
--- a/src/eap_peer/eap_psk.c
+++ b/src/eap_peer/eap_psk.c
@@ -100,7 +100,7 @@
"length (%lu; expected %lu or more)",
(unsigned long) len,
(unsigned long) sizeof(*hdr1));
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr1->flags);
@@ -120,7 +120,7 @@
if (data->id_s == NULL) {
wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for "
"ID_S (len=%lu)", (unsigned long) data->id_s_len);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S",
@@ -128,7 +128,7 @@
if (random_get_bytes(data->rand_p, EAP_PSK_RAND_LEN)) {
wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -198,7 +198,7 @@
"length (%lu; expected %lu or more)",
(unsigned long) len,
(unsigned long) sizeof(*hdr3));
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
left = len - sizeof(*hdr3);
@@ -220,7 +220,7 @@
wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in "
"third message (len=%lu, expected 21)",
(unsigned long) left);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -377,14 +377,14 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len);
if (pos == NULL) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
switch (data->state) {
case PSK_INIT:
@@ -396,19 +396,19 @@
case PSK_DONE:
wpa_printf(MSG_DEBUG, "EAP-PSK: in DONE state - ignore "
"unexpected message");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (ret->methodState == METHOD_DONE) {
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
}
return resp;
}
-static Boolean eap_psk_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_psk_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_psk_data *data = priv;
return data->state == PSK_DONE;
diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
index 76fcad4..605feb2 100644
--- a/src/eap_peer/eap_pwd.c
+++ b/src/eap_peer/eap_pwd.c
@@ -30,6 +30,7 @@
u8 *password;
size_t password_len;
int password_hash;
+ struct wpa_freq_range_list allowed_groups;
u16 group_num;
u8 prep;
u8 token[4];
@@ -54,6 +55,9 @@
};
+static void eap_pwd_deinit(struct eap_sm *sm, void *priv);
+
+
#ifndef CONFIG_NO_STDOUT_DEBUG
static const char * eap_pwd_state_txt(int state)
{
@@ -92,6 +96,7 @@
size_t identity_len, password_len;
int fragment_size;
int pwhash;
+ const char *phase1;
password = eap_get_config_password2(sm, &password_len, &pwhash);
if (password == NULL) {
@@ -129,6 +134,30 @@
data->password_len = password_len;
data->password_hash = pwhash;
+ phase1 = eap_get_config_phase1(sm);
+ if (phase1) {
+ const char *pos, *end;
+ char *copy = NULL;
+ int res;
+
+ pos = os_strstr(phase1, "eap_pwd_groups=");
+ if (pos) {
+ pos += 15;
+ end = os_strchr(pos, ' ');
+ if (end) {
+ copy = os_zalloc(end - pos + 1);
+ if (!copy)
+ goto fail;
+ os_memcpy(copy, pos, end - pos);
+ pos = copy;
+ }
+ res = freq_range_list_parse(&data->allowed_groups, pos);
+ os_free(copy);
+ if (res)
+ goto fail;
+ }
+ }
+
data->out_frag_pos = data->in_frag_pos = 0;
data->inbuf = data->outbuf = NULL;
fragment_size = eap_get_config_fragment_size(sm);
@@ -140,6 +169,9 @@
data->state = PWD_ID_Req;
return data;
+fail:
+ eap_pwd_deinit(sm, data);
+ return NULL;
}
@@ -163,6 +195,7 @@
}
wpabuf_free(data->inbuf);
wpabuf_free(data->outbuf);
+ os_free(data->allowed_groups.range);
bin_clear_free(data, sizeof(*data));
}
@@ -203,6 +236,18 @@
}
+static int eap_pwd_allowed_group(struct eap_pwd_data *data, u16 group)
+{
+ if (!data->allowed_groups.range) {
+ /* By default, allow the groups using NIST curves P-256, P-384,
+ * and P-521. */
+ return group == 19 || group == 20 || group == 21;
+ }
+
+ return freq_range_list_includes(&data->allowed_groups, group);
+}
+
+
static void
eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
struct eap_method_ret *ret,
@@ -212,13 +257,13 @@
struct eap_pwd_id *id;
if (data->state != PWD_ID_Req) {
- ret->ignore = TRUE;
+ ret->ignore = true;
eap_pwd_state(data, FAILURE);
return;
}
if (payload_len < sizeof(struct eap_pwd_id)) {
- ret->ignore = TRUE;
+ ret->ignore = true;
eap_pwd_state(data, FAILURE);
return;
}
@@ -228,9 +273,11 @@
wpa_printf(MSG_DEBUG,
"EAP-PWD: Server EAP-pwd-ID proposal: group=%u random=%u prf=%u prep=%u",
data->group_num, id->random_function, id->prf, id->prep);
- if ((id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
- (id->prf != EAP_PWD_DEFAULT_PRF)) {
- ret->ignore = TRUE;
+ if (id->random_function != EAP_PWD_DEFAULT_RAND_FUNC ||
+ id->prf != EAP_PWD_DEFAULT_PRF ||
+ !eap_pwd_allowed_group(data, data->group_num)) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd: Unsupported or disabled proposal");
eap_pwd_state(data, FAILURE);
return;
}
@@ -322,14 +369,14 @@
int res;
if (data->state != PWD_Commit_Req) {
- ret->ignore = TRUE;
+ ret->ignore = true;
goto fin;
}
if (!data->grp) {
wpa_printf(MSG_DEBUG,
"EAP-PWD (client): uninitialized EAP-pwd group");
- ret->ignore = TRUE;
+ ret->ignore = true;
goto fin;
}
@@ -362,7 +409,7 @@
data->password_len, pwhash);
if (res == 0)
res = hash_nt_password_hash(pwhash, pwhashhash);
- os_memset(pwhash, 0, sizeof(pwhash));
+ forced_memzero(pwhash, sizeof(pwhash));
}
if (res) {
@@ -514,8 +561,8 @@
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));
+ forced_memzero(pwhashhash, sizeof(pwhashhash));
+ forced_memzero(salthashpwd, sizeof(salthashpwd));
if (res) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute PWE");
eap_pwd_state(data, FAILURE);
@@ -649,7 +696,7 @@
size_t prime_len = 0, order_len = 0;
if (data->state != PWD_Confirm_Req) {
- ret->ignore = TRUE;
+ ret->ignore = true;
goto fin;
}
@@ -831,14 +878,14 @@
wpa_printf(MSG_DEBUG, "EAP-pwd: Got a frame but pos is %s and "
"len is %d",
pos == NULL ? "NULL" : "not NULL", (int) len);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
lm_exch = *pos;
pos++; /* skip over the bits and the exch */
@@ -904,7 +951,7 @@
if (len < 2) {
wpa_printf(MSG_DEBUG,
"EAP-pwd: Frame too short to contain Total-Length field");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
tot_len = WPA_GET_BE16(pos);
@@ -915,7 +962,7 @@
if (data->inbuf) {
wpa_printf(MSG_DEBUG,
"EAP-pwd: Unexpected new fragment start when previous fragment is still in use");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
data->inbuf = wpabuf_alloc(tot_len);
@@ -1060,7 +1107,7 @@
}
-static Boolean eap_pwd_key_available(struct eap_sm *sm, void *priv)
+static bool eap_pwd_key_available(struct eap_sm *sm, void *priv)
{
struct eap_pwd_data *data = priv;
return data->state == SUCCESS;
diff --git a/src/eap_peer/eap_sake.c b/src/eap_peer/eap_sake.c
index 0a6ce25..39c195d 100644
--- a/src/eap_peer/eap_sake.c
+++ b/src/eap_peer/eap_sake.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-SAKE (RFC 4763)
- * Copyright (c) 2006-2008, 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.
@@ -148,7 +148,7 @@
struct wpabuf *resp;
if (data->state != IDENTITY) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -195,7 +195,7 @@
if (data->state != IDENTITY && data->state != CHALLENGE) {
wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge received "
"in unexpected state (%d)", data->state);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (data->state == IDENTITY)
@@ -235,9 +235,13 @@
data->serverid_len = attr.serverid_len;
}
- eap_sake_derive_keys(data->root_secret_a, data->root_secret_b,
- data->rand_s, data->rand_p,
- (u8 *) &data->tek, data->msk, data->emsk);
+ if (eap_sake_derive_keys(data->root_secret_a, data->root_secret_b,
+ data->rand_s, data->rand_p,
+ (u8 *) &data->tek, data->msk,
+ data->emsk) < 0) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Failed to derive keys");
+ return NULL;
+ }
wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Challenge");
@@ -292,7 +296,7 @@
u8 *rpos;
if (data->state != CONFIRM) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -316,7 +320,7 @@
eap_sake_state(data, FAILURE);
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Auth-Reject");
return eap_sake_build_msg(data, id, 0,
EAP_SAKE_SUBTYPE_AUTH_REJECT);
@@ -326,7 +330,7 @@
eap_sake_state(data, FAILURE);
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending "
"Response/Auth-Reject");
return eap_sake_build_msg(data, id, 0,
@@ -357,7 +361,7 @@
eap_sake_state(data, SUCCESS);
ret->methodState = METHOD_DONE;
ret->decision = DECISION_UNCOND_SUCC;
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
return resp;
}
@@ -376,7 +380,7 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, reqData, &len);
if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -395,16 +399,16 @@
if (data->session_id_set && data->session_id != session_id) {
wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
session_id, data->session_id);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
data->session_id = session_id;
data->session_id_set = 1;
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
switch (subtype) {
case EAP_SAKE_SUBTYPE_IDENTITY:
@@ -422,18 +426,18 @@
default:
wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring message with "
"unknown subtype %d", subtype);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (ret->methodState == METHOD_DONE)
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
return resp;
}
-static Boolean eap_sake_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_sake_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_sake_data *data = priv;
return data->state == SUCCESS;
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index b5811a8..eaa1ad7 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -32,6 +32,7 @@
u8 msk[EAP_SIM_KEYING_DATA_LEN];
u8 emsk[EAP_EMSK_LEN];
u8 rand[3][GSM_RAND_LEN];
+ u8 reauth_mac[EAP_SIM_MAC_LEN];
int num_id_req, num_notification;
u8 *pseudonym;
@@ -43,7 +44,7 @@
u8 *last_eap_identity;
size_t last_eap_identity_len;
enum {
- CONTINUE, RESULT_SUCCESS, SUCCESS, FAILURE
+ CONTINUE, START_DONE, RESULT_SUCCESS, SUCCESS, FAILURE
} state;
int result_ind, use_result_ind;
int use_pseudonym;
@@ -57,6 +58,8 @@
switch (state) {
case CONTINUE:
return "CONTINUE";
+ case START_DONE:
+ return "START_DONE";
case RESULT_SUCCESS:
return "RESULT_SUCCESS";
case SUCCESS:
@@ -485,6 +488,7 @@
const u8 *identity = NULL;
size_t identity_len = 0;
struct eap_sim_msg *msg;
+ struct wpabuf *resp;
data->reauth = 0;
if (id_req == ANY_ID && data->reauth_id) {
@@ -534,7 +538,10 @@
identity, identity_len);
}
- return eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0);
+ resp = eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0);
+ if (resp)
+ eap_sim_state(data, START_DONE);
+ return resp;
}
@@ -720,6 +727,13 @@
int res;
wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Challenge");
+ if (data->state != START_DONE) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-SIM: Unexpected Challenge in state %s",
+ eap_sim_state_txt(data->state));
+ return eap_sim_client_error(data, id,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ }
data->reauth = 0;
if (!attr->mac || !attr->rand) {
wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
@@ -803,8 +817,13 @@
EAP_SIM_NONCE_MT_LEN)) {
wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
"used invalid AT_MAC");
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore AT_MAC mismatch for fuzz testing");
+#else /* TEST_FUZZ */
return eap_sim_client_error(data, id,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+#endif /* TEST_FUZZ */
}
/* Old reauthentication identity must not be used anymore. In
@@ -963,10 +982,30 @@
{
wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
"did not have valid AT_MAC");
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore AT_MAC mismatch for fuzz testing");
+#else /* TEST_FUZZ */
return eap_sim_client_error(data, id,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+#endif /* TEST_FUZZ */
}
+ /* At this stage the received MAC has been verified. Use this MAC for
+ * reauth Session-Id calculation if all other checks pass.
+ * The peer does not use the local MAC but the received MAC in deriving
+ * Session-Id. */
+#ifdef TEST_FUZZ
+ if (attr->mac)
+ os_memcpy(data->reauth_mac, attr->mac, EAP_SIM_MAC_LEN);
+ else
+ os_memset(data->reauth_mac, 0x12, EAP_SIM_MAC_LEN);
+#else /* TEST_FUZZ */
+ os_memcpy(data->reauth_mac, attr->mac, EAP_SIM_MAC_LEN);
+#endif /* TEST_FUZZ */
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: Server MAC",
+ data->reauth_mac, EAP_SIM_MAC_LEN);
+
if (attr->encr_data == NULL || attr->iv == NULL) {
wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
"message did not include encrypted data");
@@ -1065,23 +1104,23 @@
if (eap_get_config_identity(sm, &len) == NULL) {
wpa_printf(MSG_INFO, "EAP-SIM: Identity not configured");
eap_sm_request_identity(sm);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, reqData, &len);
if (pos == NULL || len < 3) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
req = wpabuf_head(reqData);
id = req->identifier;
len = be_to_host16(req->length);
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
subtype = *pos++;
wpa_printf(MSG_DEBUG, "EAP-SIM: Subtype=%d", subtype);
@@ -1134,14 +1173,14 @@
ret->methodState = METHOD_CONT;
if (ret->methodState == METHOD_DONE) {
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
}
return res;
}
-static Boolean eap_sim_has_reauth_data(struct eap_sm *sm, void *priv)
+static bool eap_sim_has_reauth_data(struct eap_sm *sm, void *priv)
{
struct eap_sim_data *data = priv;
return data->pseudonym || data->reauth_id;
@@ -1192,7 +1231,7 @@
}
-static Boolean eap_sim_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_sim_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_sim_data *data = priv;
return data->state == SUCCESS;
@@ -1225,15 +1264,24 @@
if (data->state != SUCCESS)
return NULL;
- *len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN;
+ if (!data->reauth)
+ *len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN;
+ else
+ *len = 1 + EAP_SIM_NONCE_S_LEN + EAP_SIM_MAC_LEN;
id = os_malloc(*len);
if (id == NULL)
return NULL;
id[0] = EAP_TYPE_SIM;
- os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN);
- os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN, data->nonce_mt,
- EAP_SIM_NONCE_MT_LEN);
+ if (!data->reauth) {
+ os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN);
+ os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN,
+ data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
+ } else {
+ os_memcpy(id + 1, data->nonce_s, EAP_SIM_NONCE_S_LEN);
+ os_memcpy(id + 1 + EAP_SIM_NONCE_S_LEN, data->reauth_mac,
+ EAP_SIM_MAC_LEN);
+ }
wpa_hexdump(MSG_DEBUG, "EAP-SIM: Derived Session-Id", id, *len);
return id;
diff --git a/src/eap_peer/eap_teap.c b/src/eap_peer/eap_teap.c
new file mode 100644
index 0000000..76179a3
--- /dev/null
+++ b/src/eap_peer/eap_teap.c
@@ -0,0 +1,2137 @@
+/*
+ * EAP peer method: EAP-TEAP (RFC 7170)
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/tls.h"
+#include "eap_common/eap_teap_common.h"
+#include "eap_i.h"
+#include "eap_tls_common.h"
+#include "eap_config.h"
+#include "eap_teap_pac.h"
+
+#ifdef EAP_TEAP_DYNAMIC
+#include "eap_teap_pac.c"
+#endif /* EAP_TEAP_DYNAMIC */
+
+
+static void eap_teap_deinit(struct eap_sm *sm, void *priv);
+
+
+struct eap_teap_data {
+ struct eap_ssl_data ssl;
+
+ u8 teap_version; /* Negotiated version */
+ u8 received_version; /* Version number received during negotiation */
+ u16 tls_cs;
+
+ const struct eap_method *phase2_method;
+ void *phase2_priv;
+ int phase2_success;
+ int inner_method_done;
+ int iresult_verified;
+ int result_success_done;
+ int on_tx_completion;
+
+ struct eap_method_type phase2_type;
+ struct eap_method_type *phase2_types;
+ size_t num_phase2_types;
+ int resuming; /* starting a resumed session */
+#define EAP_TEAP_PROV_UNAUTH 1
+#define EAP_TEAP_PROV_AUTH 2
+ int provisioning_allowed; /* Allowed PAC provisioning modes */
+ int provisioning; /* doing PAC provisioning (not the normal auth) */
+ int anon_provisioning; /* doing anonymous (unauthenticated)
+ * provisioning */
+ int session_ticket_used;
+ int test_outer_tlvs;
+
+ u8 key_data[EAP_TEAP_KEY_LEN];
+ u8 *session_id;
+ size_t id_len;
+ u8 emsk[EAP_EMSK_LEN];
+ int success;
+
+ struct eap_teap_pac *pac;
+ struct eap_teap_pac *current_pac;
+ size_t max_pac_list_len;
+ int use_pac_binary_format;
+
+ u8 simck_msk[EAP_TEAP_SIMCK_LEN];
+ u8 simck_emsk[EAP_TEAP_SIMCK_LEN];
+ int simck_idx;
+ int cmk_emsk_available;
+
+ struct wpabuf *pending_phase2_req;
+ struct wpabuf *pending_resp;
+ struct wpabuf *server_outer_tlvs;
+ struct wpabuf *peer_outer_tlvs;
+};
+
+
+static int eap_teap_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
+ const u8 *client_random,
+ const u8 *server_random,
+ u8 *master_secret)
+{
+ struct eap_teap_data *data = ctx;
+
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: SessionTicket callback");
+
+ if (!master_secret) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: SessionTicket failed - fall back to full TLS handshake");
+ data->session_ticket_used = 0;
+ if (data->provisioning_allowed) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Try to provision a new PAC-Key");
+ data->provisioning = 1;
+ data->current_pac = NULL;
+ }
+ return 0;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "EAP-TEAP: SessionTicket", ticket, len);
+
+ if (!data->current_pac) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: No PAC-Key available for using SessionTicket");
+ data->session_ticket_used = 0;
+ return 0;
+ }
+
+ /* EAP-TEAP uses PAC-Key as the TLS master_secret */
+ os_memcpy(master_secret, data->current_pac->pac_key,
+ EAP_TEAP_PAC_KEY_LEN);
+
+ data->session_ticket_used = 1;
+
+ return 1;
+}
+
+
+static void eap_teap_parse_phase1(struct eap_teap_data *data,
+ const char *phase1)
+{
+ const char *pos;
+
+ pos = os_strstr(phase1, "teap_provisioning=");
+ if (pos) {
+ data->provisioning_allowed = atoi(pos + 18);
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Automatic PAC provisioning mode: %d",
+ data->provisioning_allowed);
+ }
+
+ pos = os_strstr(phase1, "teap_max_pac_list_len=");
+ if (pos) {
+ data->max_pac_list_len = atoi(pos + 22);
+ if (data->max_pac_list_len == 0)
+ data->max_pac_list_len = 1;
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Maximum PAC list length: %lu",
+ (unsigned long) data->max_pac_list_len);
+ }
+
+ if (os_strstr(phase1, "teap_pac_format=binary")) {
+ data->use_pac_binary_format = 1;
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Using binary format for PAC list");
+ }
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (os_strstr(phase1, "teap_test_outer_tlvs=1"))
+ data->test_outer_tlvs = 1;
+#endif /* CONFIG_TESTING_OPTIONS */
+}
+
+
+static void * eap_teap_init(struct eap_sm *sm)
+{
+ struct eap_teap_data *data;
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ if (!config)
+ return NULL;
+
+ data = os_zalloc(sizeof(*data));
+ if (!data)
+ return NULL;
+ data->teap_version = EAP_TEAP_VERSION;
+ data->max_pac_list_len = 10;
+
+ if (config->phase1)
+ eap_teap_parse_phase1(data, config->phase1);
+
+ if ((data->provisioning_allowed & EAP_TEAP_PROV_AUTH) &&
+ !config->cert.ca_cert && !config->cert.ca_path) {
+ /* Prevent PAC provisioning without mutual authentication
+ * (either by validating server certificate or by suitable
+ * inner EAP method). */
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Disable authenticated provisioning due to no ca_cert/ca_path");
+ data->provisioning_allowed &= ~EAP_TEAP_PROV_AUTH;
+ }
+
+ if (eap_peer_select_phase2_methods(config, "auth=",
+ &data->phase2_types,
+ &data->num_phase2_types, 0) < 0) {
+ eap_teap_deinit(sm, data);
+ return NULL;
+ }
+
+ data->phase2_type.vendor = EAP_VENDOR_IETF;
+ data->phase2_type.method = EAP_TYPE_NONE;
+
+ config->teap_anon_dh = !!(data->provisioning_allowed &
+ EAP_TEAP_PROV_UNAUTH);
+ if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TEAP)) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: Failed to initialize SSL");
+ eap_teap_deinit(sm, data);
+ return NULL;
+ }
+
+ if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn,
+ eap_teap_session_ticket_cb,
+ data) < 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Failed to set SessionTicket callback");
+ eap_teap_deinit(sm, data);
+ return NULL;
+ }
+
+ if (!config->pac_file) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: No PAC file configured");
+ eap_teap_deinit(sm, data);
+ return NULL;
+ }
+
+ if (data->use_pac_binary_format &&
+ eap_teap_load_pac_bin(sm, &data->pac, config->pac_file) < 0) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: Failed to load PAC file");
+ eap_teap_deinit(sm, data);
+ return NULL;
+ }
+
+ if (!data->use_pac_binary_format &&
+ eap_teap_load_pac(sm, &data->pac, config->pac_file) < 0) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: Failed to load PAC file");
+ eap_teap_deinit(sm, data);
+ return NULL;
+ }
+ eap_teap_pac_list_truncate(data->pac, data->max_pac_list_len);
+
+ return data;
+}
+
+
+static void eap_teap_clear(struct eap_teap_data *data)
+{
+ forced_memzero(data->key_data, EAP_TEAP_KEY_LEN);
+ forced_memzero(data->emsk, EAP_EMSK_LEN);
+ os_free(data->session_id);
+ data->session_id = NULL;
+ wpabuf_free(data->pending_phase2_req);
+ data->pending_phase2_req = NULL;
+ wpabuf_free(data->pending_resp);
+ data->pending_resp = NULL;
+ wpabuf_free(data->server_outer_tlvs);
+ data->server_outer_tlvs = NULL;
+ wpabuf_free(data->peer_outer_tlvs);
+ data->peer_outer_tlvs = NULL;
+ forced_memzero(data->simck_msk, EAP_TEAP_SIMCK_LEN);
+ forced_memzero(data->simck_emsk, EAP_TEAP_SIMCK_LEN);
+}
+
+
+static void eap_teap_deinit(struct eap_sm *sm, void *priv)
+{
+ struct eap_teap_data *data = priv;
+ struct eap_teap_pac *pac, *prev;
+
+ if (!data)
+ return;
+ if (data->phase2_priv && data->phase2_method)
+ data->phase2_method->deinit(sm, data->phase2_priv);
+ eap_teap_clear(data);
+ os_free(data->phase2_types);
+ eap_peer_tls_ssl_deinit(sm, &data->ssl);
+
+ pac = data->pac;
+ prev = NULL;
+ while (pac) {
+ prev = pac;
+ pac = pac->next;
+ eap_teap_free_pac(prev);
+ }
+
+ os_free(data);
+}
+
+
+static int eap_teap_derive_msk(struct eap_teap_data *data)
+{
+ /* FIX: RFC 7170 does not describe whether MSK or EMSK based S-IMCK[j]
+ * is used in this derivation */
+ if (eap_teap_derive_eap_msk(data->tls_cs, data->simck_msk,
+ data->key_data) < 0 ||
+ eap_teap_derive_eap_emsk(data->tls_cs, data->simck_msk,
+ data->emsk) < 0)
+ return -1;
+ data->success = 1;
+ return 0;
+}
+
+
+static int eap_teap_derive_key_auth(struct eap_sm *sm,
+ struct eap_teap_data *data)
+{
+ int res;
+
+ /* RFC 7170, Section 5.1 */
+ res = tls_connection_export_key(sm->ssl_ctx, data->ssl.conn,
+ TEAP_TLS_EXPORTER_LABEL_SKS, NULL, 0,
+ data->simck_msk, EAP_TEAP_SIMCK_LEN);
+ if (res)
+ return res;
+ wpa_hexdump_key(MSG_DEBUG,
+ "EAP-TEAP: session_key_seed (S-IMCK[0])",
+ data->simck_msk, EAP_TEAP_SIMCK_LEN);
+ os_memcpy(data->simck_emsk, data->simck_msk, EAP_TEAP_SIMCK_LEN);
+ data->simck_idx = 0;
+ return 0;
+}
+
+
+static int eap_teap_init_phase2_method(struct eap_sm *sm,
+ struct eap_teap_data *data)
+{
+ data->inner_method_done = 0;
+ data->iresult_verified = 0;
+ data->phase2_method =
+ eap_peer_get_eap_method(data->phase2_type.vendor,
+ data->phase2_type.method);
+ if (!data->phase2_method)
+ return -1;
+
+ sm->init_phase2 = 1;
+ data->phase2_priv = data->phase2_method->init(sm);
+ sm->init_phase2 = 0;
+
+ return data->phase2_priv == NULL ? -1 : 0;
+}
+
+
+static int eap_teap_select_phase2_method(struct eap_teap_data *data,
+ int vendor, enum eap_type type)
+{
+ size_t i;
+
+ /* TODO: TNC with anonymous provisioning; need to require both
+ * completed inner EAP authentication (EAP-pwd or EAP-EKE) and TNC */
+
+ if (data->anon_provisioning &&
+ !eap_teap_allowed_anon_prov_phase2_method(vendor, type)) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: EAP type %u:%u not allowed during unauthenticated provisioning",
+ vendor, type);
+ return -1;
+ }
+
+#ifdef EAP_TNC
+ if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_TNC) {
+ data->phase2_type.vendor = EAP_VENDOR_IETF;
+ data->phase2_type.method = EAP_TYPE_TNC;
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Selected Phase 2 EAP vendor %d method %d for TNC",
+ data->phase2_type.vendor,
+ data->phase2_type.method);
+ return 0;
+ }
+#endif /* EAP_TNC */
+
+ for (i = 0; i < data->num_phase2_types; i++) {
+ if (data->phase2_types[i].vendor != vendor ||
+ data->phase2_types[i].method != type)
+ continue;
+
+ data->phase2_type.vendor = data->phase2_types[i].vendor;
+ data->phase2_type.method = data->phase2_types[i].method;
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Selected Phase 2 EAP vendor %d method %d",
+ data->phase2_type.vendor,
+ data->phase2_type.method);
+ break;
+ }
+
+ if (vendor != data->phase2_type.vendor ||
+ type != data->phase2_type.method ||
+ (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_NONE))
+ return -1;
+
+ return 0;
+}
+
+
+static void eap_teap_deinit_inner_eap(struct eap_sm *sm,
+ struct eap_teap_data *data)
+{
+ if (!data->phase2_priv || !data->phase2_method)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Phase 2 EAP sequence - deinitialize previous method");
+ data->phase2_method->deinit(sm, data->phase2_priv);
+ data->phase2_method = NULL;
+ data->phase2_priv = NULL;
+ data->phase2_type.vendor = EAP_VENDOR_IETF;
+ data->phase2_type.method = EAP_TYPE_NONE;
+}
+
+
+static int eap_teap_phase2_request(struct eap_sm *sm,
+ struct eap_teap_data *data,
+ struct eap_method_ret *ret,
+ struct eap_hdr *hdr,
+ struct wpabuf **resp)
+{
+ size_t len = be_to_host16(hdr->length);
+ u8 *pos;
+ struct eap_method_ret iret;
+ struct eap_peer_config *config = eap_get_config(sm);
+ struct wpabuf msg;
+ int vendor = EAP_VENDOR_IETF;
+ enum eap_type method;
+
+ if (len <= sizeof(struct eap_hdr)) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: too short Phase 2 request (len=%lu)",
+ (unsigned long) len);
+ return -1;
+ }
+ pos = (u8 *) (hdr + 1);
+ method = *pos;
+ if (method == EAP_TYPE_EXPANDED) {
+ if (len < sizeof(struct eap_hdr) + 8) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Too short Phase 2 request (expanded header) (len=%lu)",
+ (unsigned long) len);
+ return -1;
+ }
+ vendor = WPA_GET_BE24(pos + 1);
+ method = WPA_GET_BE32(pos + 4);
+ }
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 2 Request: type=%u:%u",
+ vendor, method);
+ if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_IDENTITY) {
+ eap_teap_deinit_inner_eap(sm, data);
+ *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
+ return 0;
+ }
+
+ if (data->phase2_priv && data->phase2_method &&
+ (vendor != data->phase2_type.vendor ||
+ method != data->phase2_type.method))
+ eap_teap_deinit_inner_eap(sm, data);
+
+ if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
+ data->phase2_type.method == EAP_TYPE_NONE &&
+ eap_teap_select_phase2_method(data, vendor, method) < 0) {
+ if (eap_peer_tls_phase2_nak(data->phase2_types,
+ data->num_phase2_types,
+ hdr, resp))
+ return -1;
+ return 0;
+ }
+
+ if ((!data->phase2_priv && eap_teap_init_phase2_method(sm, data) < 0) ||
+ !data->phase2_method) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Failed to initialize Phase 2 EAP method %u:%u",
+ vendor, method);
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ return -1;
+ }
+
+ os_memset(&iret, 0, sizeof(iret));
+ wpabuf_set(&msg, hdr, len);
+ *resp = data->phase2_method->process(sm, data->phase2_priv, &iret,
+ &msg);
+ if (iret.methodState == METHOD_DONE)
+ data->inner_method_done = 1;
+ if (!(*resp) ||
+ (iret.methodState == METHOD_DONE &&
+ iret.decision == DECISION_FAIL)) {
+ /* Wait for protected indication of failure */
+ ret->methodState = METHOD_MAY_CONT;
+ ret->decision = DECISION_FAIL;
+ } else if ((iret.methodState == METHOD_DONE ||
+ iret.methodState == METHOD_MAY_CONT) &&
+ (iret.decision == DECISION_UNCOND_SUCC ||
+ iret.decision == DECISION_COND_SUCC)) {
+ data->phase2_success = 1;
+ }
+
+ if (!(*resp) && config &&
+ (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);
+ data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
+ } else if (!(*resp))
+ return -1;
+
+ return 0;
+}
+
+
+static struct wpabuf * eap_teap_tlv_nak(int vendor_id, int tlv_type)
+{
+ struct wpabuf *buf;
+ struct teap_tlv_nak *nak;
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Add NAK TLV (Vendor-Id %u NAK-Type %u)",
+ vendor_id, tlv_type);
+ buf = wpabuf_alloc(sizeof(*nak));
+ if (!buf)
+ return NULL;
+ nak = wpabuf_put(buf, sizeof(*nak));
+ nak->tlv_type = host_to_be16(TEAP_TLV_MANDATORY | TEAP_TLV_NAK);
+ nak->length = host_to_be16(6);
+ nak->vendor_id = host_to_be32(vendor_id);
+ nak->nak_type = host_to_be16(tlv_type);
+ return buf;
+}
+
+
+static struct wpabuf * eap_teap_tlv_pac_ack(void)
+{
+ struct wpabuf *buf;
+ struct teap_tlv_result *res;
+ struct teap_tlv_pac_ack *ack;
+
+ buf = wpabuf_alloc(sizeof(*res) + sizeof(*ack));
+ if (!buf)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Add PAC TLV (ack)");
+ ack = wpabuf_put(buf, sizeof(*ack));
+ ack->tlv_type = host_to_be16(TEAP_TLV_PAC | TEAP_TLV_MANDATORY);
+ ack->length = host_to_be16(sizeof(*ack) - sizeof(struct teap_tlv_hdr));
+ ack->pac_type = host_to_be16(PAC_TYPE_PAC_ACKNOWLEDGEMENT);
+ ack->pac_len = host_to_be16(2);
+ ack->result = host_to_be16(TEAP_STATUS_SUCCESS);
+
+ return buf;
+}
+
+
+static struct wpabuf * eap_teap_add_identity_type(struct eap_sm *sm,
+ struct wpabuf *msg)
+{
+ struct wpabuf *tlv;
+
+ tlv = eap_teap_tlv_identity_type(sm->use_machine_cred ?
+ TEAP_IDENTITY_TYPE_MACHINE :
+ TEAP_IDENTITY_TYPE_USER);
+ return wpabuf_concat(msg, tlv);
+}
+
+
+static struct wpabuf * eap_teap_process_eap_payload_tlv(
+ struct eap_sm *sm, struct eap_teap_data *data,
+ struct eap_method_ret *ret,
+ u8 *eap_payload_tlv, size_t eap_payload_tlv_len,
+ enum teap_identity_types req_id_type)
+{
+ struct eap_hdr *hdr;
+ struct wpabuf *resp = NULL;
+
+ if (eap_payload_tlv_len < sizeof(*hdr)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: too short EAP Payload TLV (len=%lu)",
+ (unsigned long) eap_payload_tlv_len);
+ return NULL;
+ }
+
+ hdr = (struct eap_hdr *) eap_payload_tlv;
+ if (be_to_host16(hdr->length) > eap_payload_tlv_len) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: EAP packet overflow in EAP Payload TLV");
+ return NULL;
+ }
+
+ if (hdr->code != EAP_CODE_REQUEST) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Unexpected code=%d in Phase 2 EAP header",
+ hdr->code);
+ return NULL;
+ }
+
+ if (eap_teap_phase2_request(sm, data, ret, hdr, &resp)) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Phase 2 Request processing failed");
+ return NULL;
+ }
+
+ resp = eap_teap_tlv_eap_payload(resp);
+ if (req_id_type)
+ resp = eap_teap_add_identity_type(sm, resp);
+
+ return resp;
+}
+
+
+static struct wpabuf * eap_teap_process_basic_auth_req(
+ struct eap_sm *sm, struct eap_teap_data *data,
+ u8 *basic_auth_req, size_t basic_auth_req_len,
+ enum teap_identity_types req_id_type)
+{
+ const u8 *identity, *password;
+ size_t identity_len, password_len, plen;
+ struct wpabuf *resp;
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-TEAP: Basic-Password-Auth-Req prompt",
+ basic_auth_req, basic_auth_req_len);
+ /* TODO: send over control interface */
+
+ identity = eap_get_config_identity(sm, &identity_len);
+ password = eap_get_config_password(sm, &password_len);
+ if (!identity || !password ||
+ identity_len > 255 || password_len > 255) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: No username/password suitable for Basic-Password-Auth");
+ return eap_teap_tlv_nak(0, TEAP_TLV_BASIC_PASSWORD_AUTH_REQ);
+ }
+
+ plen = 1 + identity_len + 1 + password_len;
+ resp = wpabuf_alloc(sizeof(struct teap_tlv_hdr) + plen);
+ if (!resp)
+ return NULL;
+ eap_teap_put_tlv_hdr(resp, TEAP_TLV_BASIC_PASSWORD_AUTH_RESP, plen);
+ wpabuf_put_u8(resp, identity_len);
+ wpabuf_put_data(resp, identity, identity_len);
+ wpabuf_put_u8(resp, password_len);
+ wpabuf_put_data(resp, password, password_len);
+ wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TEAP: Basic-Password-Auth-Resp",
+ resp);
+ if (req_id_type)
+ resp = eap_teap_add_identity_type(sm, resp);
+
+ /* Assume this succeeds so that Result TLV(Success) from the server can
+ * be used to terminate TEAP. */
+ data->phase2_success = 1;
+
+ return resp;
+}
+
+
+static int
+eap_teap_validate_crypto_binding(struct eap_teap_data *data,
+ const struct teap_tlv_crypto_binding *cb)
+{
+ u8 flags, subtype;
+
+ subtype = cb->subtype & 0x0f;
+ flags = cb->subtype >> 4;
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Crypto-Binding TLV: Version %u Received Version %u Flags %u Sub-Type %u",
+ cb->version, cb->received_version, flags, subtype);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Nonce",
+ cb->nonce, sizeof(cb->nonce));
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: EMSK Compound MAC",
+ cb->emsk_compound_mac, sizeof(cb->emsk_compound_mac));
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: MSK Compound MAC",
+ cb->msk_compound_mac, sizeof(cb->msk_compound_mac));
+
+ if (cb->version != EAP_TEAP_VERSION ||
+ cb->received_version != data->received_version ||
+ subtype != TEAP_CRYPTO_BINDING_SUBTYPE_REQUEST ||
+ flags < 1 || flags > 3) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Invalid Version/Flags/Sub-Type in Crypto-Binding TLV: Version %u Received Version %u Flags %u Sub-Type %u",
+ cb->version, cb->received_version, flags, subtype);
+ return -1;
+ }
+
+ if (cb->nonce[EAP_TEAP_NONCE_LEN - 1] & 0x01) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Invalid Crypto-Binding TLV Nonce in request");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int eap_teap_write_crypto_binding(
+ struct eap_teap_data *data,
+ struct teap_tlv_crypto_binding *rbind,
+ const struct teap_tlv_crypto_binding *cb,
+ const u8 *cmk_msk, const u8 *cmk_emsk)
+{
+ u8 subtype, flags;
+
+ rbind->tlv_type = host_to_be16(TEAP_TLV_MANDATORY |
+ TEAP_TLV_CRYPTO_BINDING);
+ rbind->length = host_to_be16(sizeof(*rbind) -
+ sizeof(struct teap_tlv_hdr));
+ rbind->version = EAP_TEAP_VERSION;
+ rbind->received_version = data->received_version;
+ /* FIX: RFC 7170 is not clear on which Flags value to use when
+ * Crypto-Binding TLV is used with Basic-Password-Auth */
+ flags = cmk_emsk ? TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC :
+ TEAP_CRYPTO_BINDING_MSK_CMAC;
+ subtype = TEAP_CRYPTO_BINDING_SUBTYPE_RESPONSE;
+ rbind->subtype = (flags << 4) | subtype;
+ os_memcpy(rbind->nonce, cb->nonce, sizeof(cb->nonce));
+ inc_byte_array(rbind->nonce, sizeof(rbind->nonce));
+ os_memset(rbind->emsk_compound_mac, 0, EAP_TEAP_COMPOUND_MAC_LEN);
+ os_memset(rbind->msk_compound_mac, 0, EAP_TEAP_COMPOUND_MAC_LEN);
+
+ if (eap_teap_compound_mac(data->tls_cs, rbind, data->server_outer_tlvs,
+ data->peer_outer_tlvs, cmk_msk,
+ rbind->msk_compound_mac) < 0)
+ return -1;
+ if (cmk_emsk &&
+ eap_teap_compound_mac(data->tls_cs, rbind, data->server_outer_tlvs,
+ data->peer_outer_tlvs, cmk_emsk,
+ rbind->emsk_compound_mac) < 0)
+ return -1;
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Reply Crypto-Binding TLV: Version %u Received Version %u Flags %u SubType %u",
+ rbind->version, rbind->received_version, flags, subtype);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Nonce",
+ rbind->nonce, sizeof(rbind->nonce));
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: EMSK Compound MAC",
+ rbind->emsk_compound_mac, sizeof(rbind->emsk_compound_mac));
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: MSK Compound MAC",
+ rbind->msk_compound_mac, sizeof(rbind->msk_compound_mac));
+
+ return 0;
+}
+
+
+static int eap_teap_get_cmk(struct eap_sm *sm, struct eap_teap_data *data,
+ u8 *cmk_msk, u8 *cmk_emsk)
+{
+ u8 *msk = NULL, *emsk = NULL;
+ size_t msk_len = 0, emsk_len = 0;
+ int res;
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Determining CMK[%d] for Compound MAC calculation",
+ data->simck_idx + 1);
+
+ if (!data->phase2_method)
+ return eap_teap_derive_cmk_basic_pw_auth(data->tls_cs,
+ data->simck_msk,
+ cmk_msk);
+
+ if (!data->phase2_method || !data->phase2_priv) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: Phase 2 method not available");
+ return -1;
+ }
+
+ if (data->phase2_method->isKeyAvailable &&
+ !data->phase2_method->isKeyAvailable(sm, data->phase2_priv)) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Phase 2 key material not available");
+ return -1;
+ }
+
+ if (data->phase2_method->isKeyAvailable &&
+ data->phase2_method->getKey) {
+ msk = data->phase2_method->getKey(sm, data->phase2_priv,
+ &msk_len);
+ if (!msk) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Could not fetch Phase 2 MSK");
+ return -1;
+ }
+ }
+
+ if (data->phase2_method->isKeyAvailable &&
+ data->phase2_method->get_emsk) {
+ emsk = data->phase2_method->get_emsk(sm, data->phase2_priv,
+ &emsk_len);
+ }
+
+ res = eap_teap_derive_imck(data->tls_cs,
+ data->simck_msk, data->simck_emsk,
+ msk, msk_len, emsk, emsk_len,
+ data->simck_msk, cmk_msk,
+ data->simck_emsk, cmk_emsk);
+ bin_clear_free(msk, msk_len);
+ bin_clear_free(emsk, emsk_len);
+ if (res == 0) {
+ data->simck_idx++;
+ if (emsk)
+ data->cmk_emsk_available = 1;
+ }
+ return res;
+}
+
+
+static int eap_teap_session_id(struct eap_teap_data *data)
+{
+ const size_t max_id_len = 100;
+ int res;
+
+ os_free(data->session_id);
+ data->session_id = os_malloc(max_id_len);
+ if (!data->session_id)
+ return -1;
+
+ data->session_id[0] = EAP_TYPE_TEAP;
+ res = tls_get_tls_unique(data->ssl.conn, data->session_id + 1,
+ max_id_len - 1);
+ if (res < 0) {
+ os_free(data->session_id);
+ data->session_id = NULL;
+ wpa_printf(MSG_ERROR, "EAP-TEAP: Failed to derive Session-Id");
+ return -1;
+ }
+
+ data->id_len = 1 + res;
+ wpa_hexdump(MSG_DEBUG, "EAP-TEAP: Derived Session-Id",
+ data->session_id, data->id_len);
+ return 0;
+}
+
+
+static struct wpabuf * eap_teap_process_crypto_binding(
+ struct eap_sm *sm, struct eap_teap_data *data,
+ struct eap_method_ret *ret,
+ const struct teap_tlv_crypto_binding *cb, size_t bind_len)
+{
+ struct wpabuf *resp;
+ u8 *pos;
+ u8 cmk_msk[EAP_TEAP_CMK_LEN];
+ u8 cmk_emsk[EAP_TEAP_CMK_LEN];
+ const u8 *cmk_emsk_ptr = NULL;
+ int res;
+ size_t len;
+ u8 flags;
+
+ if (eap_teap_validate_crypto_binding(data, cb) < 0 ||
+ eap_teap_get_cmk(sm, data, cmk_msk, cmk_emsk) < 0)
+ return NULL;
+
+ /* Validate received MSK/EMSK Compound MAC */
+ flags = cb->subtype >> 4;
+
+ if (flags == TEAP_CRYPTO_BINDING_MSK_CMAC ||
+ flags == TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC) {
+ u8 msk_compound_mac[EAP_TEAP_COMPOUND_MAC_LEN];
+
+ if (eap_teap_compound_mac(data->tls_cs, cb,
+ data->server_outer_tlvs,
+ data->peer_outer_tlvs, cmk_msk,
+ msk_compound_mac) < 0)
+ return NULL;
+ res = os_memcmp_const(msk_compound_mac, cb->msk_compound_mac,
+ EAP_TEAP_COMPOUND_MAC_LEN);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Received MSK Compound MAC",
+ cb->msk_compound_mac, EAP_TEAP_COMPOUND_MAC_LEN);
+ wpa_hexdump(MSG_MSGDUMP,
+ "EAP-TEAP: Calculated MSK Compound MAC",
+ msk_compound_mac, EAP_TEAP_COMPOUND_MAC_LEN);
+ if (res != 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: MSK Compound MAC did not match");
+ return NULL;
+ }
+ }
+
+ if ((flags == TEAP_CRYPTO_BINDING_EMSK_CMAC ||
+ flags == TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC) &&
+ data->cmk_emsk_available) {
+ u8 emsk_compound_mac[EAP_TEAP_COMPOUND_MAC_LEN];
+
+ if (eap_teap_compound_mac(data->tls_cs, cb,
+ data->server_outer_tlvs,
+ data->peer_outer_tlvs, cmk_emsk,
+ emsk_compound_mac) < 0)
+ return NULL;
+ res = os_memcmp_const(emsk_compound_mac, cb->emsk_compound_mac,
+ EAP_TEAP_COMPOUND_MAC_LEN);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Received EMSK Compound MAC",
+ cb->emsk_compound_mac, EAP_TEAP_COMPOUND_MAC_LEN);
+ wpa_hexdump(MSG_MSGDUMP,
+ "EAP-TEAP: Calculated EMSK Compound MAC",
+ emsk_compound_mac, EAP_TEAP_COMPOUND_MAC_LEN);
+ if (res != 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: EMSK Compound MAC did not match");
+ return NULL;
+ }
+
+ cmk_emsk_ptr = cmk_emsk;
+ }
+
+ if (flags == TEAP_CRYPTO_BINDING_EMSK_CMAC &&
+ !data->cmk_emsk_available) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Server included only EMSK Compound MAC, but no locally generated inner EAP EMSK to validate this");
+ return NULL;
+ }
+
+ /*
+ * Compound MAC was valid, so authentication succeeded. Reply with
+ * crypto binding to allow server to complete authentication.
+ */
+
+ len = sizeof(struct teap_tlv_crypto_binding);
+ resp = wpabuf_alloc(len);
+ if (!resp)
+ return NULL;
+
+ if (data->phase2_success && eap_teap_derive_msk(data) < 0) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: Failed to generate MSK");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ data->phase2_success = 0;
+ wpabuf_free(resp);
+ return NULL;
+ }
+
+ if (data->phase2_success && eap_teap_session_id(data) < 0) {
+ wpabuf_free(resp);
+ return NULL;
+ }
+
+ pos = wpabuf_put(resp, sizeof(struct teap_tlv_crypto_binding));
+ if (eap_teap_write_crypto_binding(
+ data, (struct teap_tlv_crypto_binding *) pos,
+ cb, cmk_msk, cmk_emsk_ptr) < 0) {
+ wpabuf_free(resp);
+ return NULL;
+ }
+
+ return resp;
+}
+
+
+static void eap_teap_parse_pac_tlv(struct eap_teap_pac *entry, int type,
+ u8 *pos, size_t len, int *pac_key_found)
+{
+ switch (type & 0x7fff) {
+ case PAC_TYPE_PAC_KEY:
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: PAC-Key", pos, len);
+ if (len != EAP_TEAP_PAC_KEY_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Invalid PAC-Key length %lu",
+ (unsigned long) len);
+ break;
+ }
+ *pac_key_found = 1;
+ os_memcpy(entry->pac_key, pos, len);
+ break;
+ case PAC_TYPE_PAC_OPAQUE:
+ wpa_hexdump(MSG_DEBUG, "EAP-TEAP: PAC-Opaque", pos, len);
+ entry->pac_opaque = pos;
+ entry->pac_opaque_len = len;
+ break;
+ case PAC_TYPE_PAC_INFO:
+ wpa_hexdump(MSG_DEBUG, "EAP-TEAP: PAC-Info", pos, len);
+ entry->pac_info = pos;
+ entry->pac_info_len = len;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Ignored unknown PAC type %d",
+ type);
+ break;
+ }
+}
+
+
+static int eap_teap_process_pac_tlv(struct eap_teap_pac *entry,
+ u8 *pac, size_t pac_len)
+{
+ struct pac_attr_hdr *hdr;
+ u8 *pos;
+ size_t left, len;
+ int type, pac_key_found = 0;
+
+ pos = pac;
+ left = pac_len;
+
+ while (left > sizeof(*hdr)) {
+ hdr = (struct pac_attr_hdr *) pos;
+ type = be_to_host16(hdr->type);
+ len = be_to_host16(hdr->len);
+ pos += sizeof(*hdr);
+ left -= sizeof(*hdr);
+ if (len > left) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: PAC TLV overrun (type=%d len=%lu left=%lu)",
+ type, (unsigned long) len,
+ (unsigned long) left);
+ return -1;
+ }
+
+ eap_teap_parse_pac_tlv(entry, type, pos, len, &pac_key_found);
+
+ pos += len;
+ left -= len;
+ }
+
+ if (!pac_key_found || !entry->pac_opaque || !entry->pac_info) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: PAC TLV does not include all the required fields");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int eap_teap_parse_pac_info(struct eap_teap_pac *entry, int type,
+ u8 *pos, size_t len)
+{
+ u16 pac_type;
+ u32 lifetime;
+ struct os_time now;
+
+ switch (type & 0x7fff) {
+ case PAC_TYPE_CRED_LIFETIME:
+ if (len != 4) {
+ wpa_hexdump(MSG_DEBUG,
+ "EAP-TEAP: PAC-Info - Invalid CRED_LIFETIME length - ignored",
+ pos, len);
+ return 0;
+ }
+
+ /*
+ * This is not currently saved separately in PAC files since
+ * the server can automatically initiate PAC update when
+ * needed. Anyway, the information is available from PAC-Info
+ * dump if it is needed for something in the future.
+ */
+ lifetime = WPA_GET_BE32(pos);
+ os_get_time(&now);
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: PAC-Info - CRED_LIFETIME %d (%d days)",
+ lifetime, (lifetime - (u32) now.sec) / 86400);
+ break;
+ case PAC_TYPE_A_ID:
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-TEAP: PAC-Info - A-ID",
+ pos, len);
+ entry->a_id = pos;
+ entry->a_id_len = len;
+ break;
+ case PAC_TYPE_I_ID:
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-TEAP: PAC-Info - I-ID",
+ pos, len);
+ entry->i_id = pos;
+ entry->i_id_len = len;
+ break;
+ case PAC_TYPE_A_ID_INFO:
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-TEAP: PAC-Info - A-ID-Info",
+ pos, len);
+ entry->a_id_info = pos;
+ entry->a_id_info_len = len;
+ break;
+ case PAC_TYPE_PAC_TYPE:
+ /* RFC 7170, Section 4.2.12.6 - PAC-Type TLV */
+ if (len != 2) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Invalid PAC-Type length %lu (expected 2)",
+ (unsigned long) len);
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP-TEAP: PAC-Info - PAC-Type",
+ pos, len);
+ return -1;
+ }
+ pac_type = WPA_GET_BE16(pos);
+ if (pac_type != PAC_TYPE_TUNNEL_PAC) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Unsupported PAC Type %d",
+ pac_type);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: PAC-Info - PAC-Type %d",
+ pac_type);
+ entry->pac_type = pac_type;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Ignored unknown PAC-Info type %d", type);
+ break;
+ }
+
+ return 0;
+}
+
+
+static int eap_teap_process_pac_info(struct eap_teap_pac *entry)
+{
+ struct pac_attr_hdr *hdr;
+ u8 *pos;
+ size_t left, len;
+ int type;
+
+ /* RFC 7170, Section 4.2.12.4 */
+
+ /* PAC-Type defaults to Tunnel PAC (Type 1) */
+ entry->pac_type = PAC_TYPE_TUNNEL_PAC;
+
+ pos = entry->pac_info;
+ left = entry->pac_info_len;
+ while (left > sizeof(*hdr)) {
+ hdr = (struct pac_attr_hdr *) pos;
+ type = be_to_host16(hdr->type);
+ len = be_to_host16(hdr->len);
+ pos += sizeof(*hdr);
+ left -= sizeof(*hdr);
+ if (len > left) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: PAC-Info overrun (type=%d len=%lu left=%lu)",
+ type, (unsigned long) len,
+ (unsigned long) left);
+ return -1;
+ }
+
+ if (eap_teap_parse_pac_info(entry, type, pos, len) < 0)
+ return -1;
+
+ pos += len;
+ left -= len;
+ }
+
+ if (!entry->a_id || !entry->a_id_info) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: PAC-Info does not include all the required fields");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static struct wpabuf * eap_teap_process_pac(struct eap_sm *sm,
+ struct eap_teap_data *data,
+ struct eap_method_ret *ret,
+ u8 *pac, size_t pac_len)
+{
+ struct eap_peer_config *config = eap_get_config(sm);
+ struct eap_teap_pac entry;
+
+ os_memset(&entry, 0, sizeof(entry));
+ if (eap_teap_process_pac_tlv(&entry, pac, pac_len) ||
+ eap_teap_process_pac_info(&entry))
+ return NULL;
+
+ eap_teap_add_pac(&data->pac, &data->current_pac, &entry);
+ eap_teap_pac_list_truncate(data->pac, data->max_pac_list_len);
+ if (data->use_pac_binary_format)
+ eap_teap_save_pac_bin(sm, data->pac, config->pac_file);
+ else
+ eap_teap_save_pac(sm, data->pac, config->pac_file);
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Send PAC-Acknowledgement - %s initiated provisioning completed successfully",
+ data->provisioning ? "peer" : "server");
+ return eap_teap_tlv_pac_ack();
+}
+
+
+static int eap_teap_parse_decrypted(struct wpabuf *decrypted,
+ struct eap_teap_tlv_parse *tlv,
+ struct wpabuf **resp)
+{
+ u16 tlv_type;
+ int mandatory, res;
+ size_t len;
+ u8 *pos, *end;
+
+ os_memset(tlv, 0, sizeof(*tlv));
+
+ /* Parse TLVs from the decrypted Phase 2 data */
+ pos = wpabuf_mhead(decrypted);
+ end = pos + wpabuf_len(decrypted);
+ while (end - pos >= 4) {
+ mandatory = pos[0] & 0x80;
+ tlv_type = WPA_GET_BE16(pos) & 0x3fff;
+ pos += 2;
+ len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (len > (size_t) (end - pos)) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: TLV overflow");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Received Phase 2: TLV type %u (%s) length %u%s",
+ tlv_type, eap_teap_tlv_type_str(tlv_type),
+ (unsigned int) len,
+ mandatory ? " (mandatory)" : "");
+
+ res = eap_teap_parse_tlv(tlv, tlv_type, pos, len);
+ if (res == -2)
+ break;
+ if (res < 0) {
+ if (mandatory) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: NAK unknown mandatory TLV type %u",
+ tlv_type);
+ *resp = eap_teap_tlv_nak(0, tlv_type);
+ break;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Ignore unknown optional TLV type %u",
+ tlv_type);
+ }
+
+ pos += len;
+ }
+
+ return 0;
+}
+
+
+static struct wpabuf * eap_teap_pac_request(void)
+{
+ struct wpabuf *req;
+ struct teap_tlv_request_action *act;
+ struct teap_tlv_hdr *pac;
+ struct teap_attr_pac_type *type;
+
+ req = wpabuf_alloc(sizeof(*act) + sizeof(*pac) + sizeof(*type));
+ if (!req)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Add Request Action TLV (Process TLV)");
+ act = wpabuf_put(req, sizeof(*act));
+ act->tlv_type = host_to_be16(TEAP_TLV_REQUEST_ACTION);
+ act->length = host_to_be16(2);
+ act->status = TEAP_STATUS_SUCCESS;
+ act->action = TEAP_REQUEST_ACTION_PROCESS_TLV;
+
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Add PAC TLV (PAC-Type = Tunnel)");
+ pac = wpabuf_put(req, sizeof(*pac));
+ pac->tlv_type = host_to_be16(TEAP_TLV_PAC);
+ pac->length = host_to_be16(sizeof(*type));
+
+ type = wpabuf_put(req, sizeof(*type));
+ type->type = host_to_be16(PAC_TYPE_PAC_TYPE);
+ type->length = host_to_be16(2);
+ type->pac_type = host_to_be16(PAC_TYPE_TUNNEL_PAC);
+
+ return req;
+}
+
+
+static int eap_teap_process_decrypted(struct eap_sm *sm,
+ struct eap_teap_data *data,
+ struct eap_method_ret *ret,
+ u8 identifier,
+ struct wpabuf *decrypted,
+ struct wpabuf **out_data)
+{
+ struct wpabuf *resp = NULL, *tmp;
+ struct eap_teap_tlv_parse tlv;
+ int failed = 0;
+ enum teap_error_codes error = 0;
+ int iresult_added = 0;
+
+ if (eap_teap_parse_decrypted(decrypted, &tlv, &resp) < 0) {
+ /* Parsing failed - no response available */
+ return 0;
+ }
+
+ if (resp) {
+ /* Parsing rejected the message - send out an error response */
+ goto send_resp;
+ }
+
+ if (tlv.result == TEAP_STATUS_FAILURE) {
+ /* Server indicated failure - respond similarly per
+ * RFC 7170, 3.6.3. This authentication exchange cannot succeed
+ * and will be terminated with a cleartext EAP Failure. */
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Server rejected authentication");
+ resp = eap_teap_tlv_result(TEAP_STATUS_FAILURE, 0);
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ goto send_resp;
+ }
+
+ if (tlv.iresult == TEAP_STATUS_SUCCESS && !tlv.crypto_binding) {
+ /* Intermediate-Result TLV indicating success, but no
+ * Crypto-Binding TLV */
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Intermediate-Result TLV indicating success, but no Crypto-Binding TLV");
+ failed = 1;
+ error = TEAP_ERROR_TUNNEL_COMPROMISE_ERROR;
+ goto done;
+ }
+
+ if (!data->iresult_verified && !data->result_success_done &&
+ tlv.result == TEAP_STATUS_SUCCESS && !tlv.crypto_binding) {
+ /* Result TLV indicating success, but no Crypto-Binding TLV */
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Result TLV indicating success, but no Crypto-Binding TLV");
+ failed = 1;
+ error = TEAP_ERROR_TUNNEL_COMPROMISE_ERROR;
+ goto done;
+ }
+
+ if (tlv.iresult != TEAP_STATUS_SUCCESS &&
+ tlv.iresult != TEAP_STATUS_FAILURE &&
+ data->inner_method_done) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Inner EAP method exchange completed, but no Intermediate-Result TLV included");
+ failed = 1;
+ error = TEAP_ERROR_TUNNEL_COMPROMISE_ERROR;
+ goto done;
+ }
+
+ if (tlv.identity_type == TEAP_IDENTITY_TYPE_MACHINE) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ sm->use_machine_cred = config && config->machine_identity &&
+ config->machine_identity_len;
+ } else if (tlv.identity_type) {
+ sm->use_machine_cred = 0;
+ }
+ if (tlv.identity_type) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ os_free(data->phase2_types);
+ data->phase2_types = NULL;
+ data->num_phase2_types = 0;
+ if (config &&
+ eap_peer_select_phase2_methods(config, "auth=",
+ &data->phase2_types,
+ &data->num_phase2_types,
+ sm->use_machine_cred) < 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Failed to update Phase 2 EAP types");
+ failed = 1;
+ goto done;
+ }
+ }
+
+ if (tlv.basic_auth_req) {
+ tmp = eap_teap_process_basic_auth_req(sm, data,
+ tlv.basic_auth_req,
+ tlv.basic_auth_req_len,
+ tlv.identity_type);
+ if (!tmp)
+ failed = 1;
+ resp = wpabuf_concat(resp, tmp);
+ } else if (tlv.eap_payload_tlv) {
+ tmp = eap_teap_process_eap_payload_tlv(sm, data, ret,
+ tlv.eap_payload_tlv,
+ tlv.eap_payload_tlv_len,
+ tlv.identity_type);
+ if (!tmp)
+ failed = 1;
+ resp = wpabuf_concat(resp, tmp);
+
+ if (tlv.iresult == TEAP_STATUS_SUCCESS ||
+ tlv.iresult == TEAP_STATUS_FAILURE) {
+ tmp = eap_teap_tlv_result(failed ?
+ TEAP_STATUS_FAILURE :
+ TEAP_STATUS_SUCCESS, 1);
+ resp = wpabuf_concat(resp, tmp);
+ if (tlv.iresult == TEAP_STATUS_FAILURE)
+ failed = 1;
+ iresult_added = 1;
+ }
+ }
+
+ if (tlv.crypto_binding) {
+ if (tlv.iresult != TEAP_STATUS_SUCCESS &&
+ tlv.result != TEAP_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Unexpected Crypto-Binding TLV without Result TLV or Intermediate-Result TLV indicating success");
+ failed = 1;
+ error = TEAP_ERROR_UNEXPECTED_TLVS_EXCHANGED;
+ goto done;
+ }
+
+ tmp = eap_teap_process_crypto_binding(sm, data, ret,
+ tlv.crypto_binding,
+ tlv.crypto_binding_len);
+ if (!tmp) {
+ failed = 1;
+ error = TEAP_ERROR_TUNNEL_COMPROMISE_ERROR;
+ } else {
+ resp = wpabuf_concat(resp, tmp);
+ if (tlv.result == TEAP_STATUS_SUCCESS && !failed)
+ data->result_success_done = 1;
+ if (tlv.iresult == TEAP_STATUS_SUCCESS && !failed) {
+ data->inner_method_done = 0;
+ data->iresult_verified = 1;
+ }
+ }
+ }
+
+ if (data->result_success_done && data->session_ticket_used &&
+ eap_teap_derive_msk(data) == 0) {
+ /* Assume the server might accept authentication without going
+ * through inner authentication. */
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: PAC used - server may decide to skip inner authentication");
+ ret->methodState = METHOD_MAY_CONT;
+ ret->decision = DECISION_COND_SUCC;
+ }
+
+ if (tlv.pac) {
+ if (tlv.result == TEAP_STATUS_SUCCESS) {
+ tmp = eap_teap_process_pac(sm, data, ret,
+ tlv.pac, tlv.pac_len);
+ resp = wpabuf_concat(resp, tmp);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: PAC TLV without Result TLV acknowledging success");
+ failed = 1;
+ error = TEAP_ERROR_UNEXPECTED_TLVS_EXCHANGED;
+ }
+ }
+
+ if (!data->current_pac && data->provisioning && !failed && !tlv.pac &&
+ tlv.crypto_binding &&
+ (!data->anon_provisioning ||
+ (data->phase2_success && data->phase2_method &&
+ data->phase2_method->vendor == 0 &&
+ eap_teap_allowed_anon_prov_cipher_suite(data->tls_cs) &&
+ eap_teap_allowed_anon_prov_phase2_method(
+ data->phase2_method->vendor,
+ data->phase2_method->method))) &&
+ (tlv.iresult == TEAP_STATUS_SUCCESS ||
+ tlv.result == TEAP_STATUS_SUCCESS)) {
+ /*
+ * Need to request Tunnel PAC when using authenticated
+ * provisioning.
+ */
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Request Tunnel PAC");
+ tmp = eap_teap_pac_request();
+ resp = wpabuf_concat(resp, tmp);
+ }
+
+done:
+ if (failed) {
+ tmp = eap_teap_tlv_result(TEAP_STATUS_FAILURE, 0);
+ resp = wpabuf_concat(tmp, resp);
+
+ if (error != 0) {
+ tmp = eap_teap_tlv_error(error);
+ resp = wpabuf_concat(tmp, resp);
+ }
+
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ } else if (tlv.result == TEAP_STATUS_SUCCESS) {
+ tmp = eap_teap_tlv_result(TEAP_STATUS_SUCCESS, 0);
+ resp = wpabuf_concat(tmp, resp);
+ }
+ if ((tlv.iresult == TEAP_STATUS_SUCCESS ||
+ tlv.iresult == TEAP_STATUS_FAILURE) && !iresult_added) {
+ tmp = eap_teap_tlv_result((!failed && data->phase2_success) ?
+ TEAP_STATUS_SUCCESS :
+ TEAP_STATUS_FAILURE, 1);
+ resp = wpabuf_concat(tmp, resp);
+ }
+
+ if (resp && tlv.result == TEAP_STATUS_SUCCESS && !failed &&
+ (tlv.crypto_binding || data->iresult_verified) &&
+ data->phase2_success) {
+ /* Successfully completed Phase 2 */
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Authentication completed successfully");
+ ret->methodState = METHOD_MAY_CONT;
+ data->on_tx_completion = data->provisioning ?
+ METHOD_MAY_CONT : METHOD_DONE;
+ ret->decision = DECISION_UNCOND_SUCC;
+ }
+
+ if (!resp) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: No recognized TLVs - send empty response packet");
+ resp = wpabuf_alloc(1);
+ }
+
+send_resp:
+ if (!resp)
+ return 0;
+
+ wpa_hexdump_buf(MSG_DEBUG, "EAP-TEAP: Encrypting Phase 2 data", resp);
+ if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TEAP,
+ data->teap_version, identifier,
+ resp, out_data)) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Failed to encrypt a Phase 2 frame");
+ }
+ wpabuf_free(resp);
+
+ return 0;
+}
+
+
+static int eap_teap_decrypt(struct eap_sm *sm, struct eap_teap_data *data,
+ struct eap_method_ret *ret, u8 identifier,
+ const struct wpabuf *in_data,
+ struct wpabuf **out_data)
+{
+ struct wpabuf *in_decrypted;
+ int res;
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Received %lu bytes encrypted data for Phase 2",
+ (unsigned long) wpabuf_len(in_data));
+
+ if (data->pending_phase2_req) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Pending Phase 2 request - skip decryption and use old data");
+ /* Clear TLS reassembly state. */
+ eap_peer_tls_reset_input(&data->ssl);
+
+ in_decrypted = data->pending_phase2_req;
+ data->pending_phase2_req = NULL;
+ goto continue_req;
+ }
+
+ if (wpabuf_len(in_data) == 0) {
+ /* Received TLS ACK - requesting more fragments */
+ res = eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TEAP,
+ data->teap_version,
+ identifier, NULL, out_data);
+ if (res == 0 && !data->ssl.tls_out &&
+ data->on_tx_completion) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Mark authentication completed at full TX of fragments");
+ ret->methodState = data->on_tx_completion;
+ data->on_tx_completion = 0;
+ ret->decision = DECISION_UNCOND_SUCC;
+ }
+ return res;
+ }
+
+ res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
+ if (res)
+ return res;
+
+continue_req:
+ wpa_hexdump_buf(MSG_MSGDUMP, "EAP-TEAP: Decrypted Phase 2 TLV(s)",
+ in_decrypted);
+
+ if (wpabuf_len(in_decrypted) < 4) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Too short Phase 2 TLV frame (len=%lu)",
+ (unsigned long) wpabuf_len(in_decrypted));
+ wpabuf_free(in_decrypted);
+ return -1;
+ }
+
+ res = eap_teap_process_decrypted(sm, data, ret, identifier,
+ in_decrypted, out_data);
+
+ wpabuf_free(in_decrypted);
+
+ return res;
+}
+
+
+static void eap_teap_select_pac(struct eap_teap_data *data,
+ const u8 *a_id, size_t a_id_len)
+{
+ if (!a_id)
+ return;
+ data->current_pac = eap_teap_get_pac(data->pac, a_id, a_id_len,
+ PAC_TYPE_TUNNEL_PAC);
+ if (data->current_pac) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: PAC found for this A-ID (PAC-Type %d)",
+ data->current_pac->pac_type);
+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TEAP: A-ID-Info",
+ data->current_pac->a_id_info,
+ data->current_pac->a_id_info_len);
+ }
+}
+
+
+static int eap_teap_use_pac_opaque(struct eap_sm *sm,
+ struct eap_teap_data *data,
+ struct eap_teap_pac *pac)
+{
+ u8 *tlv;
+ size_t tlv_len, olen;
+ struct teap_tlv_hdr *ehdr;
+
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Add PAC-Opaque TLS extension");
+ olen = pac->pac_opaque_len;
+ tlv_len = sizeof(*ehdr) + olen;
+ tlv = os_malloc(tlv_len);
+ if (tlv) {
+ ehdr = (struct teap_tlv_hdr *) tlv;
+ ehdr->tlv_type = host_to_be16(PAC_TYPE_PAC_OPAQUE);
+ ehdr->length = host_to_be16(olen);
+ os_memcpy(ehdr + 1, pac->pac_opaque, olen);
+ }
+ if (!tlv ||
+ tls_connection_client_hello_ext(sm->ssl_ctx, data->ssl.conn,
+ TLS_EXT_PAC_OPAQUE,
+ tlv, tlv_len) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Failed to add PAC-Opaque TLS extension");
+ os_free(tlv);
+ return -1;
+ }
+ os_free(tlv);
+
+ return 0;
+}
+
+
+static int eap_teap_clear_pac_opaque_ext(struct eap_sm *sm,
+ struct eap_teap_data *data)
+{
+ if (tls_connection_client_hello_ext(sm->ssl_ctx, data->ssl.conn,
+ TLS_EXT_PAC_OPAQUE, NULL, 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Failed to remove PAC-Opaque TLS extension");
+ return -1;
+ }
+ return 0;
+}
+
+
+static int eap_teap_process_start(struct eap_sm *sm,
+ struct eap_teap_data *data, u8 flags,
+ const u8 *pos, size_t left)
+{
+ const u8 *a_id = NULL;
+ size_t a_id_len = 0;
+
+ /* TODO: Support (mostly theoretical) case of TEAP/Start request being
+ * fragmented */
+
+ /* EAP-TEAP version negotiation (RFC 7170, Section 3.2) */
+ data->received_version = flags & EAP_TLS_VERSION_MASK;
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Start (server ver=%u, own ver=%u)",
+ data->received_version, data->teap_version);
+ if (data->received_version < 1) {
+ /* Version 1 was the first defined version, so reject 0 */
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Server used unknown TEAP version %u",
+ data->received_version);
+ return -1;
+ }
+ if (data->received_version < data->teap_version)
+ data->teap_version = data->received_version;
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Using TEAP version %d",
+ data->teap_version);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Start message payload", pos, left);
+
+ /* Parse Authority-ID TLV from Outer TLVs, if present */
+ if (flags & EAP_TEAP_FLAGS_OUTER_TLV_LEN) {
+ const u8 *outer_pos, *outer_end;
+ u32 outer_tlv_len;
+
+ if (left < 4) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Not enough room for the Outer TLV Length field");
+ return -1;
+ }
+
+ outer_tlv_len = WPA_GET_BE32(pos);
+ pos += 4;
+ left -= 4;
+
+ if (outer_tlv_len > left) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Truncated Outer TLVs field (Outer TLV Length: %u; remaining buffer: %u)",
+ outer_tlv_len, (unsigned int) left);
+ return -1;
+ }
+
+ outer_pos = pos + left - outer_tlv_len;
+ outer_end = outer_pos + outer_tlv_len;
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Start message Outer TLVs",
+ outer_pos, outer_tlv_len);
+ wpabuf_free(data->server_outer_tlvs);
+ data->server_outer_tlvs = wpabuf_alloc_copy(outer_pos,
+ outer_tlv_len);
+ if (!data->server_outer_tlvs)
+ return -1;
+ left -= outer_tlv_len;
+ if (left > 0) {
+ wpa_hexdump(MSG_INFO,
+ "EAP-TEAP: Unexpected TLS Data in Start message",
+ pos, left);
+ return -1;
+ }
+
+ while (outer_pos < outer_end) {
+ u16 tlv_type, tlv_len;
+
+ if (outer_end - outer_pos < 4) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Truncated Outer TLV header");
+ return -1;
+ }
+ tlv_type = WPA_GET_BE16(outer_pos);
+ outer_pos += 2;
+ tlv_len = WPA_GET_BE16(outer_pos);
+ outer_pos += 2;
+ /* Outer TLVs are required to be optional, so no need to
+ * check the M flag */
+ tlv_type &= TEAP_TLV_TYPE_MASK;
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Outer TLV: Type=%u Length=%u",
+ tlv_type, tlv_len);
+ if (outer_end - outer_pos < tlv_len) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Truncated Outer TLV (Type %u)",
+ tlv_type);
+ return -1;
+ }
+ if (tlv_type == TEAP_TLV_AUTHORITY_ID) {
+ wpa_hexdump(MSG_DEBUG, "EAP-TEAP: Authority-ID",
+ outer_pos, tlv_len);
+ if (a_id) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Multiple Authority-ID TLVs in TEAP/Start");
+ return -1;
+ }
+ a_id = outer_pos;
+ a_id_len = tlv_len;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Ignore unknown Outer TLV (Type %u)",
+ tlv_type);
+ }
+ outer_pos += tlv_len;
+ }
+ } else if (left > 0) {
+ wpa_hexdump(MSG_INFO,
+ "EAP-TEAP: Unexpected TLS Data in Start message",
+ pos, left);
+ return -1;
+ }
+
+ eap_teap_select_pac(data, a_id, a_id_len);
+
+ if (data->resuming && data->current_pac) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Trying to resume session - do not add PAC-Opaque to TLS ClientHello");
+ if (eap_teap_clear_pac_opaque_ext(sm, data) < 0)
+ return -1;
+ } else if (data->current_pac) {
+ /*
+ * PAC found for the A-ID and we are not resuming an old
+ * session, so add PAC-Opaque extension to ClientHello.
+ */
+ if (eap_teap_use_pac_opaque(sm, data, data->current_pac) < 0)
+ return -1;
+ } else if (data->provisioning_allowed) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: No PAC found - starting provisioning");
+ if (eap_teap_clear_pac_opaque_ext(sm, data) < 0)
+ return -1;
+ data->provisioning = 1;
+ }
+
+ return 0;
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+static struct wpabuf * eap_teap_add_dummy_outer_tlvs(struct eap_teap_data *data,
+ struct wpabuf *resp)
+{
+ struct wpabuf *resp2;
+ u16 len;
+ const u8 *pos;
+ u8 flags;
+
+ wpabuf_free(data->peer_outer_tlvs);
+ data->peer_outer_tlvs = wpabuf_alloc(4 + 4);
+ if (!data->peer_outer_tlvs) {
+ wpabuf_free(resp);
+ return NULL;
+ }
+
+ /* Outer TLVs (dummy Vendor-Specific TLV for testing) */
+ wpabuf_put_be16(data->peer_outer_tlvs, TEAP_TLV_VENDOR_SPECIFIC);
+ wpabuf_put_be16(data->peer_outer_tlvs, 4);
+ wpabuf_put_be32(data->peer_outer_tlvs, EAP_VENDOR_HOSTAP);
+ wpa_hexdump_buf(MSG_DEBUG, "EAP-TEAP: TESTING - Add dummy Outer TLVs",
+ data->peer_outer_tlvs);
+
+ wpa_hexdump_buf(MSG_DEBUG,
+ "EAP-TEAP: TEAP/Start response before modification",
+ resp);
+ resp2 = wpabuf_alloc(wpabuf_len(resp) + 4 +
+ wpabuf_len(data->peer_outer_tlvs));
+ if (!resp2) {
+ wpabuf_free(resp);
+ return NULL;
+ }
+
+ pos = wpabuf_head(resp);
+ wpabuf_put_u8(resp2, *pos++); /* Code */
+ wpabuf_put_u8(resp2, *pos++); /* Identifier */
+ len = WPA_GET_BE16(pos);
+ pos += 2;
+ wpabuf_put_be16(resp2, len + 4 + wpabuf_len(data->peer_outer_tlvs));
+ wpabuf_put_u8(resp2, *pos++); /* Type */
+ /* Flags | Ver (with Outer TLV length included flag set to 1) */
+ flags = *pos++;
+ if (flags & (EAP_TEAP_FLAGS_OUTER_TLV_LEN |
+ EAP_TLS_FLAGS_LENGTH_INCLUDED)) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Cannot add Outer TLVs for testing");
+ wpabuf_free(resp);
+ wpabuf_free(resp2);
+ return NULL;
+ }
+ flags |= EAP_TEAP_FLAGS_OUTER_TLV_LEN;
+ wpabuf_put_u8(resp2, flags);
+ /* Outer TLV Length */
+ wpabuf_put_be32(resp2, wpabuf_len(data->peer_outer_tlvs));
+ /* TLS Data */
+ wpabuf_put_data(resp2, pos, wpabuf_len(resp) - 6);
+ wpabuf_put_buf(resp2, data->peer_outer_tlvs); /* Outer TLVs */
+
+ wpabuf_free(resp);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "EAP-TEAP: TEAP/Start response after modification",
+ resp2);
+ return resp2;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+static struct wpabuf * eap_teap_process(struct eap_sm *sm, void *priv,
+ struct eap_method_ret *ret,
+ const struct wpabuf *reqData)
+{
+ const struct eap_hdr *req;
+ size_t left;
+ int res;
+ u8 flags, id;
+ struct wpabuf *resp;
+ const u8 *pos;
+ struct eap_teap_data *data = priv;
+ struct wpabuf msg;
+
+ pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TEAP, ret,
+ reqData, &left, &flags);
+ if (!pos)
+ return NULL;
+
+ req = wpabuf_head(reqData);
+ id = req->identifier;
+
+ if (flags & EAP_TLS_FLAGS_START) {
+ if (eap_teap_process_start(sm, data, flags, pos, left) < 0)
+ return NULL;
+
+ /* Outer TLVs are not used in further packet processing and
+ * there cannot be TLS Data in this TEAP/Start message, so
+ * enforce that by ignoring whatever data might remain in the
+ * buffer. */
+ left = 0;
+ } else if (flags & EAP_TEAP_FLAGS_OUTER_TLV_LEN) {
+ /* TODO: RFC 7170, Section 4.3.1 indicates that the unexpected
+ * Outer TLVs MUST be ignored instead of ignoring the full
+ * message. */
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Outer TLVs present in non-Start message -> ignore message");
+ return NULL;
+ }
+
+ wpabuf_set(&msg, pos, left);
+
+ resp = NULL;
+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
+ !data->resuming) {
+ /* Process tunneled (encrypted) phase 2 data. */
+ res = eap_teap_decrypt(sm, data, ret, id, &msg, &resp);
+ if (res < 0) {
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ /*
+ * Ack possible Alert that may have caused failure in
+ * decryption.
+ */
+ res = 1;
+ }
+ } else {
+ if (sm->waiting_ext_cert_check && data->pending_resp) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ if (config->pending_ext_cert_check ==
+ EXT_CERT_CHECK_GOOD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: External certificate check succeeded - continue handshake");
+ resp = data->pending_resp;
+ data->pending_resp = NULL;
+ sm->waiting_ext_cert_check = 0;
+ return resp;
+ }
+
+ if (config->pending_ext_cert_check ==
+ EXT_CERT_CHECK_BAD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: External certificate check failed - force authentication failure");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ sm->waiting_ext_cert_check = 0;
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Continuing to wait external server certificate validation");
+ return NULL;
+ }
+
+ /* Continue processing TLS handshake (phase 1). */
+ res = eap_peer_tls_process_helper(sm, &data->ssl,
+ EAP_TYPE_TEAP,
+ data->teap_version, id, &msg,
+ &resp);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: TLS processing failed");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ return resp;
+ }
+
+ if (sm->waiting_ext_cert_check) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Waiting external server certificate validation");
+ wpabuf_free(data->pending_resp);
+ data->pending_resp = resp;
+ return NULL;
+ }
+
+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ char cipher[80];
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: TLS done, proceed to Phase 2");
+ data->tls_cs =
+ tls_connection_get_cipher_suite(data->ssl.conn);
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: TLS cipher suite 0x%04x",
+ data->tls_cs);
+
+ if (data->provisioning &&
+ (!(data->provisioning_allowed &
+ EAP_TEAP_PROV_AUTH) ||
+ tls_get_cipher(sm->ssl_ctx, data->ssl.conn,
+ cipher, sizeof(cipher)) < 0 ||
+ os_strstr(cipher, "ADH-") ||
+ os_strstr(cipher, "anon"))) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Using anonymous (unauthenticated) provisioning");
+ data->anon_provisioning = 1;
+ } else {
+ data->anon_provisioning = 0;
+ }
+ data->resuming = 0;
+ if (eap_teap_derive_key_auth(sm, data) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Could not derive keys");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ wpabuf_free(resp);
+ return NULL;
+ }
+ }
+
+ if (res == 2) {
+ /*
+ * Application data included in the handshake message.
+ */
+ wpabuf_free(data->pending_phase2_req);
+ data->pending_phase2_req = resp;
+ resp = NULL;
+ res = eap_teap_decrypt(sm, data, ret, id, &msg, &resp);
+ }
+ }
+
+ if (res == 1) {
+ wpabuf_free(resp);
+ return eap_peer_tls_build_ack(id, EAP_TYPE_TEAP,
+ data->teap_version);
+ }
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (data->test_outer_tlvs && res == 0 && resp &&
+ (flags & EAP_TLS_FLAGS_START) && wpabuf_len(resp) >= 6)
+ resp = eap_teap_add_dummy_outer_tlvs(data, resp);
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ return resp;
+}
+
+
+#if 0 /* TODO */
+static bool eap_teap_has_reauth_data(struct eap_sm *sm, void *priv)
+{
+ struct eap_teap_data *data = priv;
+
+ return tls_connection_established(sm->ssl_ctx, data->ssl.conn);
+}
+
+
+static void eap_teap_deinit_for_reauth(struct eap_sm *sm, void *priv)
+{
+ struct eap_teap_data *data = priv;
+
+ if (data->phase2_priv && data->phase2_method &&
+ data->phase2_method->deinit_for_reauth)
+ data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
+ eap_teap_clear(data);
+}
+
+
+static void * eap_teap_init_for_reauth(struct eap_sm *sm, void *priv)
+{
+ struct eap_teap_data *data = priv;
+
+ if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
+ eap_teap_deinit(sm, data);
+ return NULL;
+ }
+ if (data->phase2_priv && data->phase2_method &&
+ data->phase2_method->init_for_reauth)
+ data->phase2_method->init_for_reauth(sm, data->phase2_priv);
+ data->phase2_success = 0;
+ data->inner_method_done = 0;
+ data->result_success_done = 0;
+ data->iresult_verified = 0;
+ data->done_on_tx_completion = 0;
+ data->resuming = 1;
+ data->provisioning = 0;
+ data->anon_provisioning = 0;
+ data->simck_idx = 0;
+ return priv;
+}
+#endif
+
+
+static int eap_teap_get_status(struct eap_sm *sm, void *priv, char *buf,
+ size_t buflen, int verbose)
+{
+ struct eap_teap_data *data = priv;
+ int len, ret;
+
+ len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
+ if (data->phase2_method) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "EAP-TEAP Phase 2 method=%s\n",
+ data->phase2_method->name);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+ return len;
+}
+
+
+static bool eap_teap_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+ struct eap_teap_data *data = priv;
+
+ return data->success;
+}
+
+
+static u8 * eap_teap_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_teap_data *data = priv;
+ u8 *key;
+
+ if (!data->success)
+ return NULL;
+
+ key = os_memdup(data->key_data, EAP_TEAP_KEY_LEN);
+ if (!key)
+ return NULL;
+
+ *len = EAP_TEAP_KEY_LEN;
+
+ return key;
+}
+
+
+static u8 * eap_teap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_teap_data *data = priv;
+ u8 *id;
+
+ if (!data->success || !data->session_id)
+ return NULL;
+
+ id = os_memdup(data->session_id, data->id_len);
+ if (!id)
+ return NULL;
+
+ *len = data->id_len;
+
+ return id;
+}
+
+
+static u8 * eap_teap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_teap_data *data = priv;
+ u8 *key;
+
+ if (!data->success)
+ return NULL;
+
+ key = os_memdup(data->emsk, EAP_EMSK_LEN);
+ if (!key)
+ return NULL;
+
+ *len = EAP_EMSK_LEN;
+
+ return key;
+}
+
+
+int eap_peer_teap_register(void)
+{
+ struct eap_method *eap;
+
+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_TEAP, "TEAP");
+ if (!eap)
+ return -1;
+
+ eap->init = eap_teap_init;
+ eap->deinit = eap_teap_deinit;
+ eap->process = eap_teap_process;
+ eap->isKeyAvailable = eap_teap_isKeyAvailable;
+ eap->getKey = eap_teap_getKey;
+ eap->getSessionId = eap_teap_get_session_id;
+ eap->get_status = eap_teap_get_status;
+#if 0 /* TODO */
+ eap->has_reauth_data = eap_teap_has_reauth_data;
+ eap->deinit_for_reauth = eap_teap_deinit_for_reauth;
+ eap->init_for_reauth = eap_teap_init_for_reauth;
+#endif
+ eap->get_emsk = eap_teap_get_emsk;
+
+ return eap_peer_method_register(eap);
+}
diff --git a/src/eap_peer/eap_teap_pac.c b/src/eap_peer/eap_teap_pac.c
new file mode 100644
index 0000000..34a2743
--- /dev/null
+++ b/src/eap_peer/eap_teap_pac.c
@@ -0,0 +1,931 @@
+/*
+ * EAP peer method: EAP-TEAP PAC file processing
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_config.h"
+#include "eap_i.h"
+#include "eap_teap_pac.h"
+
+/* TODO: encrypt PAC-Key in the PAC file */
+
+
+/* Text data format */
+static const char *pac_file_hdr =
+ "wpa_supplicant EAP-TEAP PAC file - version 1";
+
+/*
+ * Binary data format
+ * 4-octet magic value: 6A E4 92 1C
+ * 2-octet version (big endian)
+ * <version specific data>
+ *
+ * version=0:
+ * Sequence of PAC entries:
+ * 2-octet PAC-Type (big endian)
+ * 32-octet PAC-Key
+ * 2-octet PAC-Opaque length (big endian)
+ * <variable len> PAC-Opaque data (length bytes)
+ * 2-octet PAC-Info length (big endian)
+ * <variable len> PAC-Info data (length bytes)
+ */
+
+#define EAP_TEAP_PAC_BINARY_MAGIC 0x6ae4921c
+#define EAP_TEAP_PAC_BINARY_FORMAT_VERSION 0
+
+
+/**
+ * eap_teap_free_pac - Free PAC data
+ * @pac: Pointer to the PAC entry
+ *
+ * Note that the PAC entry must not be in a list since this function does not
+ * remove the list links.
+ */
+void eap_teap_free_pac(struct eap_teap_pac *pac)
+{
+ os_free(pac->pac_opaque);
+ os_free(pac->pac_info);
+ os_free(pac->a_id);
+ os_free(pac->i_id);
+ os_free(pac->a_id_info);
+ os_free(pac);
+}
+
+
+/**
+ * eap_teap_get_pac - Get a PAC entry based on A-ID
+ * @pac_root: Pointer to root of the PAC list
+ * @a_id: A-ID to search for
+ * @a_id_len: Length of A-ID
+ * @pac_type: PAC-Type to search for
+ * Returns: Pointer to the PAC entry, or %NULL if A-ID not found
+ */
+struct eap_teap_pac * eap_teap_get_pac(struct eap_teap_pac *pac_root,
+ const u8 *a_id, size_t a_id_len,
+ u16 pac_type)
+{
+ struct eap_teap_pac *pac = pac_root;
+
+ while (pac) {
+ if (pac->pac_type == pac_type && pac->a_id_len == a_id_len &&
+ os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
+ return pac;
+ }
+ pac = pac->next;
+ }
+ return NULL;
+}
+
+
+static void eap_teap_remove_pac(struct eap_teap_pac **pac_root,
+ struct eap_teap_pac **pac_current,
+ const u8 *a_id, size_t a_id_len, u16 pac_type)
+{
+ struct eap_teap_pac *pac, *prev;
+
+ pac = *pac_root;
+ prev = NULL;
+
+ while (pac) {
+ if (pac->pac_type == pac_type && pac->a_id_len == a_id_len &&
+ os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
+ if (!prev)
+ *pac_root = pac->next;
+ else
+ prev->next = pac->next;
+ if (*pac_current == pac)
+ *pac_current = NULL;
+ eap_teap_free_pac(pac);
+ break;
+ }
+ prev = pac;
+ pac = pac->next;
+ }
+}
+
+
+static int eap_teap_copy_buf(u8 **dst, size_t *dst_len,
+ const u8 *src, size_t src_len)
+{
+ if (src) {
+ *dst = os_memdup(src, src_len);
+ if (!(*dst))
+ return -1;
+ *dst_len = src_len;
+ }
+ return 0;
+}
+
+
+/**
+ * eap_teap_add_pac - Add a copy of a PAC entry to a list
+ * @pac_root: Pointer to PAC list root pointer
+ * @pac_current: Pointer to the current PAC pointer
+ * @entry: New entry to clone and add to the list
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function makes a clone of the given PAC entry and adds this copied
+ * entry to the list (pac_root). If an old entry for the same A-ID is found,
+ * it will be removed from the PAC list and in this case, pac_current entry
+ * is set to %NULL if it was the removed entry.
+ */
+int eap_teap_add_pac(struct eap_teap_pac **pac_root,
+ struct eap_teap_pac **pac_current,
+ struct eap_teap_pac *entry)
+{
+ struct eap_teap_pac *pac;
+
+ if (!entry || !entry->a_id)
+ return -1;
+
+ /* Remove a possible old entry for the matching A-ID. */
+ eap_teap_remove_pac(pac_root, pac_current,
+ entry->a_id, entry->a_id_len, entry->pac_type);
+
+ /* Allocate a new entry and add it to the list of PACs. */
+ pac = os_zalloc(sizeof(*pac));
+ if (!pac)
+ return -1;
+
+ pac->pac_type = entry->pac_type;
+ os_memcpy(pac->pac_key, entry->pac_key, EAP_TEAP_PAC_KEY_LEN);
+ if (eap_teap_copy_buf(&pac->pac_opaque, &pac->pac_opaque_len,
+ entry->pac_opaque, entry->pac_opaque_len) < 0 ||
+ eap_teap_copy_buf(&pac->pac_info, &pac->pac_info_len,
+ entry->pac_info, entry->pac_info_len) < 0 ||
+ eap_teap_copy_buf(&pac->a_id, &pac->a_id_len,
+ entry->a_id, entry->a_id_len) < 0 ||
+ eap_teap_copy_buf(&pac->i_id, &pac->i_id_len,
+ entry->i_id, entry->i_id_len) < 0 ||
+ eap_teap_copy_buf(&pac->a_id_info, &pac->a_id_info_len,
+ entry->a_id_info, entry->a_id_info_len) < 0) {
+ eap_teap_free_pac(pac);
+ return -1;
+ }
+
+ pac->next = *pac_root;
+ *pac_root = pac;
+
+ return 0;
+}
+
+
+struct eap_teap_read_ctx {
+ FILE *f;
+ const char *pos;
+ const char *end;
+ int line;
+ char *buf;
+ size_t buf_len;
+};
+
+static int eap_teap_read_line(struct eap_teap_read_ctx *rc, char **value)
+{
+ char *pos;
+
+ rc->line++;
+ if (rc->f) {
+ if (fgets(rc->buf, rc->buf_len, rc->f) == NULL)
+ return -1;
+ } else {
+ const char *l_end;
+ size_t len;
+
+ if (rc->pos >= rc->end)
+ return -1;
+ l_end = rc->pos;
+ while (l_end < rc->end && *l_end != '\n')
+ l_end++;
+ len = l_end - rc->pos;
+ if (len >= rc->buf_len)
+ len = rc->buf_len - 1;
+ os_memcpy(rc->buf, rc->pos, len);
+ rc->buf[len] = '\0';
+ rc->pos = l_end + 1;
+ }
+
+ rc->buf[rc->buf_len - 1] = '\0';
+ pos = rc->buf;
+ while (*pos != '\0') {
+ if (*pos == '\n' || *pos == '\r') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
+ }
+
+ pos = os_strchr(rc->buf, '=');
+ if (pos)
+ *pos++ = '\0';
+ *value = pos;
+
+ return 0;
+}
+
+
+static u8 * eap_teap_parse_hex(const char *value, size_t *len)
+{
+ int hlen;
+ u8 *buf;
+
+ if (!value)
+ return NULL;
+ hlen = os_strlen(value);
+ if (hlen & 1)
+ return NULL;
+ *len = hlen / 2;
+ buf = os_malloc(*len);
+ if (!buf)
+ return NULL;
+ if (hexstr2bin(value, buf, *len)) {
+ os_free(buf);
+ return NULL;
+ }
+ return buf;
+}
+
+
+static int eap_teap_init_pac_data(struct eap_sm *sm, const char *pac_file,
+ struct eap_teap_read_ctx *rc)
+{
+ os_memset(rc, 0, sizeof(*rc));
+
+ rc->buf_len = 2048;
+ rc->buf = os_malloc(rc->buf_len);
+ if (!rc->buf)
+ return -1;
+
+ if (os_strncmp(pac_file, "blob://", 7) == 0) {
+ const struct wpa_config_blob *blob;
+
+ blob = eap_get_config_blob(sm, pac_file + 7);
+ if (!blob) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: No PAC blob '%s' - assume no PAC entries have been provisioned",
+ pac_file + 7);
+ os_free(rc->buf);
+ return -1;
+ }
+ rc->pos = (char *) blob->data;
+ rc->end = (char *) blob->data + blob->len;
+ } else {
+ rc->f = fopen(pac_file, "rb");
+ if (!rc->f) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: No PAC file '%s' - assume no PAC entries have been provisioned",
+ pac_file);
+ os_free(rc->buf);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static void eap_teap_deinit_pac_data(struct eap_teap_read_ctx *rc)
+{
+ os_free(rc->buf);
+ if (rc->f)
+ fclose(rc->f);
+}
+
+
+static const char * eap_teap_parse_start(struct eap_teap_pac **pac)
+{
+ if (*pac)
+ return "START line without END";
+
+ *pac = os_zalloc(sizeof(struct eap_teap_pac));
+ if (!(*pac))
+ return "No memory for PAC entry";
+ (*pac)->pac_type = PAC_TYPE_TUNNEL_PAC;
+ return NULL;
+}
+
+
+static const char * eap_teap_parse_end(struct eap_teap_pac **pac_root,
+ struct eap_teap_pac **pac)
+{
+ if (!(*pac))
+ return "END line without START";
+ if (*pac_root) {
+ struct eap_teap_pac *end = *pac_root;
+
+ while (end->next)
+ end = end->next;
+ end->next = *pac;
+ } else
+ *pac_root = *pac;
+
+ *pac = NULL;
+ return NULL;
+}
+
+
+static const char * eap_teap_parse_pac_type(struct eap_teap_pac *pac,
+ char *pos)
+{
+ if (!pos)
+ return "Cannot parse pac type";
+ pac->pac_type = atoi(pos);
+ if (pac->pac_type != PAC_TYPE_TUNNEL_PAC)
+ return "Unrecognized PAC-Type";
+
+ return NULL;
+}
+
+
+static const char * eap_teap_parse_pac_key(struct eap_teap_pac *pac, char *pos)
+{
+ u8 *key;
+ size_t key_len;
+
+ key = eap_teap_parse_hex(pos, &key_len);
+ if (!key || key_len != EAP_TEAP_PAC_KEY_LEN) {
+ os_free(key);
+ return "Invalid PAC-Key";
+ }
+
+ os_memcpy(pac->pac_key, key, EAP_TEAP_PAC_KEY_LEN);
+ os_free(key);
+
+ return NULL;
+}
+
+
+static const char * eap_teap_parse_pac_opaque(struct eap_teap_pac *pac,
+ char *pos)
+{
+ os_free(pac->pac_opaque);
+ pac->pac_opaque = eap_teap_parse_hex(pos, &pac->pac_opaque_len);
+ if (!pac->pac_opaque)
+ return "Invalid PAC-Opaque";
+ return NULL;
+}
+
+
+static const char * eap_teap_parse_a_id(struct eap_teap_pac *pac, char *pos)
+{
+ os_free(pac->a_id);
+ pac->a_id = eap_teap_parse_hex(pos, &pac->a_id_len);
+ if (!pac->a_id)
+ return "Invalid A-ID";
+ return NULL;
+}
+
+
+static const char * eap_teap_parse_i_id(struct eap_teap_pac *pac, char *pos)
+{
+ os_free(pac->i_id);
+ pac->i_id = eap_teap_parse_hex(pos, &pac->i_id_len);
+ if (!pac->i_id)
+ return "Invalid I-ID";
+ return NULL;
+}
+
+
+static const char * eap_teap_parse_a_id_info(struct eap_teap_pac *pac,
+ char *pos)
+{
+ os_free(pac->a_id_info);
+ pac->a_id_info = eap_teap_parse_hex(pos, &pac->a_id_info_len);
+ if (!pac->a_id_info)
+ return "Invalid A-ID-Info";
+ return NULL;
+}
+
+
+/**
+ * eap_teap_load_pac - Load PAC entries (text format)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @pac_root: Pointer to root of the PAC list (to be filled)
+ * @pac_file: Name of the PAC file/blob to load
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_teap_load_pac(struct eap_sm *sm, struct eap_teap_pac **pac_root,
+ const char *pac_file)
+{
+ struct eap_teap_read_ctx rc;
+ struct eap_teap_pac *pac = NULL;
+ int count = 0;
+ char *pos;
+ const char *err = NULL;
+
+ if (!pac_file)
+ return -1;
+
+ if (eap_teap_init_pac_data(sm, pac_file, &rc) < 0)
+ return 0;
+
+ if (eap_teap_read_line(&rc, &pos) < 0) {
+ /* empty file - assume it is fine to overwrite */
+ eap_teap_deinit_pac_data(&rc);
+ return 0;
+ }
+ if (os_strcmp(pac_file_hdr, rc.buf) != 0)
+ err = "Unrecognized header line";
+
+ while (!err && eap_teap_read_line(&rc, &pos) == 0) {
+ if (os_strcmp(rc.buf, "START") == 0)
+ err = eap_teap_parse_start(&pac);
+ else if (os_strcmp(rc.buf, "END") == 0) {
+ err = eap_teap_parse_end(pac_root, &pac);
+ count++;
+ } else if (!pac)
+ err = "Unexpected line outside START/END block";
+ else if (os_strcmp(rc.buf, "PAC-Type") == 0)
+ err = eap_teap_parse_pac_type(pac, pos);
+ else if (os_strcmp(rc.buf, "PAC-Key") == 0)
+ err = eap_teap_parse_pac_key(pac, pos);
+ else if (os_strcmp(rc.buf, "PAC-Opaque") == 0)
+ err = eap_teap_parse_pac_opaque(pac, pos);
+ else if (os_strcmp(rc.buf, "A-ID") == 0)
+ err = eap_teap_parse_a_id(pac, pos);
+ else if (os_strcmp(rc.buf, "I-ID") == 0)
+ err = eap_teap_parse_i_id(pac, pos);
+ else if (os_strcmp(rc.buf, "A-ID-Info") == 0)
+ err = eap_teap_parse_a_id_info(pac, pos);
+ }
+
+ if (pac) {
+ if (!err)
+ err = "PAC block not terminated with END";
+ eap_teap_free_pac(pac);
+ }
+
+ eap_teap_deinit_pac_data(&rc);
+
+ if (err) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: %s in '%s:%d'",
+ err, pac_file, rc.line);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Read %d PAC entries from '%s'",
+ count, pac_file);
+
+ return 0;
+}
+
+
+static void eap_teap_write(char **buf, char **pos, size_t *buf_len,
+ const char *field, const u8 *data,
+ size_t len, int txt)
+{
+ size_t i, need;
+ int ret;
+ char *end;
+
+ if (!data || !buf || !(*buf) || !pos || !(*pos) || *pos < *buf)
+ return;
+
+ need = os_strlen(field) + len * 2 + 30;
+ if (txt)
+ need += os_strlen(field) + len + 20;
+
+ if (*pos - *buf + need > *buf_len) {
+ char *nbuf = os_realloc(*buf, *buf_len + need);
+
+ if (!nbuf) {
+ os_free(*buf);
+ *buf = NULL;
+ return;
+ }
+ *pos = nbuf + (*pos - *buf);
+ *buf = nbuf;
+ *buf_len += need;
+ }
+ end = *buf + *buf_len;
+
+ ret = os_snprintf(*pos, end - *pos, "%s=", field);
+ if (os_snprintf_error(end - *pos, ret))
+ return;
+ *pos += ret;
+ *pos += wpa_snprintf_hex(*pos, end - *pos, data, len);
+ ret = os_snprintf(*pos, end - *pos, "\n");
+ if (os_snprintf_error(end - *pos, ret))
+ return;
+ *pos += ret;
+
+ if (txt) {
+ ret = os_snprintf(*pos, end - *pos, "%s-txt=", field);
+ if (os_snprintf_error(end - *pos, ret))
+ return;
+ *pos += ret;
+ for (i = 0; i < len; i++) {
+ ret = os_snprintf(*pos, end - *pos, "%c", data[i]);
+ if (os_snprintf_error(end - *pos, ret))
+ return;
+ *pos += ret;
+ }
+ ret = os_snprintf(*pos, end - *pos, "\n");
+ if (os_snprintf_error(end - *pos, ret))
+ return;
+ *pos += ret;
+ }
+}
+
+
+static int eap_teap_write_pac(struct eap_sm *sm, const char *pac_file,
+ char *buf, size_t len)
+{
+ if (os_strncmp(pac_file, "blob://", 7) == 0) {
+ struct wpa_config_blob *blob;
+
+ blob = os_zalloc(sizeof(*blob));
+ if (!blob)
+ return -1;
+ blob->data = (u8 *) buf;
+ blob->len = len;
+ buf = NULL;
+ blob->name = os_strdup(pac_file + 7);
+ if (!blob->name) {
+ os_free(blob);
+ return -1;
+ }
+ eap_set_config_blob(sm, blob);
+ } else {
+ FILE *f;
+
+ f = fopen(pac_file, "wb");
+ if (!f) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Failed to open PAC file '%s' for writing",
+ pac_file);
+ return -1;
+ }
+ if (fwrite(buf, 1, len, f) != len) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Failed to write all PACs into '%s'",
+ pac_file);
+ fclose(f);
+ return -1;
+ }
+ os_free(buf);
+ fclose(f);
+ }
+
+ return 0;
+}
+
+
+static int eap_teap_add_pac_data(struct eap_teap_pac *pac, char **buf,
+ char **pos, size_t *buf_len)
+{
+ int ret;
+
+ ret = os_snprintf(*pos, *buf + *buf_len - *pos,
+ "START\nPAC-Type=%d\n", pac->pac_type);
+ if (os_snprintf_error(*buf + *buf_len - *pos, ret))
+ return -1;
+
+ *pos += ret;
+ eap_teap_write(buf, pos, buf_len, "PAC-Key",
+ pac->pac_key, EAP_TEAP_PAC_KEY_LEN, 0);
+ eap_teap_write(buf, pos, buf_len, "PAC-Opaque",
+ pac->pac_opaque, pac->pac_opaque_len, 0);
+ eap_teap_write(buf, pos, buf_len, "PAC-Info",
+ pac->pac_info, pac->pac_info_len, 0);
+ eap_teap_write(buf, pos, buf_len, "A-ID",
+ pac->a_id, pac->a_id_len, 0);
+ eap_teap_write(buf, pos, buf_len, "I-ID",
+ pac->i_id, pac->i_id_len, 1);
+ eap_teap_write(buf, pos, buf_len, "A-ID-Info",
+ pac->a_id_info, pac->a_id_info_len, 1);
+ if (!(*buf)) {
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: No memory for PAC data");
+ return -1;
+ }
+ ret = os_snprintf(*pos, *buf + *buf_len - *pos, "END\n");
+ if (os_snprintf_error(*buf + *buf_len - *pos, ret))
+ return -1;
+ *pos += ret;
+
+ return 0;
+}
+
+
+/**
+ * eap_teap_save_pac - Save PAC entries (text format)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @pac_root: Root of the PAC list
+ * @pac_file: Name of the PAC file/blob
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_teap_save_pac(struct eap_sm *sm, struct eap_teap_pac *pac_root,
+ const char *pac_file)
+{
+ struct eap_teap_pac *pac;
+ int ret, count = 0;
+ char *buf, *pos;
+ size_t buf_len;
+
+ if (!pac_file)
+ return -1;
+
+ buf_len = 1024;
+ pos = buf = os_malloc(buf_len);
+ if (!buf)
+ return -1;
+
+ ret = os_snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr);
+ if (os_snprintf_error(buf + buf_len - pos, ret)) {
+ os_free(buf);
+ return -1;
+ }
+ pos += ret;
+
+ pac = pac_root;
+ while (pac) {
+ if (eap_teap_add_pac_data(pac, &buf, &pos, &buf_len)) {
+ os_free(buf);
+ return -1;
+ }
+ count++;
+ pac = pac->next;
+ }
+
+ if (eap_teap_write_pac(sm, pac_file, buf, pos - buf)) {
+ os_free(buf);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Wrote %d PAC entries into '%s'",
+ count, pac_file);
+
+ return 0;
+}
+
+
+/**
+ * eap_teap_pac_list_truncate - Truncate a PAC list to the given length
+ * @pac_root: Root of the PAC list
+ * @max_len: Maximum length of the list (>= 1)
+ * Returns: Number of PAC entries removed
+ */
+size_t eap_teap_pac_list_truncate(struct eap_teap_pac *pac_root,
+ size_t max_len)
+{
+ struct eap_teap_pac *pac, *prev;
+ size_t count;
+
+ pac = pac_root;
+ prev = NULL;
+ count = 0;
+
+ while (pac) {
+ count++;
+ if (count > max_len)
+ break;
+ prev = pac;
+ pac = pac->next;
+ }
+
+ if (count <= max_len || !prev)
+ return 0;
+
+ count = 0;
+ prev->next = NULL;
+
+ while (pac) {
+ prev = pac;
+ pac = pac->next;
+ eap_teap_free_pac(prev);
+ count++;
+ }
+
+ return count;
+}
+
+
+static void eap_teap_pac_get_a_id(struct eap_teap_pac *pac)
+{
+ u8 *pos, *end;
+ u16 type, len;
+
+ pos = pac->pac_info;
+ end = pos + pac->pac_info_len;
+
+ while (end - pos > 4) {
+ type = WPA_GET_BE16(pos);
+ pos += 2;
+ len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (len > (unsigned int) (end - pos))
+ break;
+
+ if (type == PAC_TYPE_A_ID) {
+ os_free(pac->a_id);
+ pac->a_id = os_memdup(pos, len);
+ if (!pac->a_id)
+ break;
+ pac->a_id_len = len;
+ }
+
+ if (type == PAC_TYPE_A_ID_INFO) {
+ os_free(pac->a_id_info);
+ pac->a_id_info = os_memdup(pos, len);
+ if (!pac->a_id_info)
+ break;
+ pac->a_id_info_len = len;
+ }
+
+ pos += len;
+ }
+}
+
+
+/**
+ * eap_teap_load_pac_bin - Load PAC entries (binary format)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @pac_root: Pointer to root of the PAC list (to be filled)
+ * @pac_file: Name of the PAC file/blob to load
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_teap_load_pac_bin(struct eap_sm *sm, struct eap_teap_pac **pac_root,
+ const char *pac_file)
+{
+ const struct wpa_config_blob *blob = NULL;
+ u8 *buf, *end, *pos;
+ size_t len, count = 0;
+ struct eap_teap_pac *pac, *prev;
+
+ *pac_root = NULL;
+
+ if (!pac_file)
+ return -1;
+
+ if (os_strncmp(pac_file, "blob://", 7) == 0) {
+ blob = eap_get_config_blob(sm, pac_file + 7);
+ if (!blob) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: No PAC blob '%s' - assume no PAC entries have been provisioned",
+ pac_file + 7);
+ return 0;
+ }
+ buf = blob->data;
+ len = blob->len;
+ } else {
+ buf = (u8 *) os_readfile(pac_file, &len);
+ if (!buf) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: No PAC file '%s' - assume no PAC entries have been provisioned",
+ pac_file);
+ return 0;
+ }
+ }
+
+ if (len == 0) {
+ if (!blob)
+ os_free(buf);
+ return 0;
+ }
+
+ if (len < 6 || WPA_GET_BE32(buf) != EAP_TEAP_PAC_BINARY_MAGIC ||
+ WPA_GET_BE16(buf + 4) != EAP_TEAP_PAC_BINARY_FORMAT_VERSION) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: Invalid PAC file '%s' (bin)",
+ pac_file);
+ if (!blob)
+ os_free(buf);
+ return -1;
+ }
+
+ pac = prev = NULL;
+ pos = buf + 6;
+ end = buf + len;
+ while (pos < end) {
+ u16 val;
+
+ if (end - pos < 2 + EAP_TEAP_PAC_KEY_LEN + 2 + 2) {
+ pac = NULL;
+ goto parse_fail;
+ }
+
+ pac = os_zalloc(sizeof(*pac));
+ if (!pac)
+ goto parse_fail;
+
+ pac->pac_type = WPA_GET_BE16(pos);
+ pos += 2;
+ os_memcpy(pac->pac_key, pos, EAP_TEAP_PAC_KEY_LEN);
+ pos += EAP_TEAP_PAC_KEY_LEN;
+ val = WPA_GET_BE16(pos);
+ pos += 2;
+ if (val > end - pos)
+ goto parse_fail;
+ pac->pac_opaque_len = val;
+ pac->pac_opaque = os_memdup(pos, pac->pac_opaque_len);
+ if (!pac->pac_opaque)
+ goto parse_fail;
+ pos += pac->pac_opaque_len;
+ if (end - pos < 2)
+ goto parse_fail;
+ val = WPA_GET_BE16(pos);
+ pos += 2;
+ if (val > end - pos)
+ goto parse_fail;
+ pac->pac_info_len = val;
+ pac->pac_info = os_memdup(pos, pac->pac_info_len);
+ if (!pac->pac_info)
+ goto parse_fail;
+ pos += pac->pac_info_len;
+ eap_teap_pac_get_a_id(pac);
+
+ count++;
+ if (prev)
+ prev->next = pac;
+ else
+ *pac_root = pac;
+ prev = pac;
+ }
+
+ if (!blob)
+ os_free(buf);
+
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Read %lu PAC entries from '%s' (bin)",
+ (unsigned long) count, pac_file);
+
+ return 0;
+
+parse_fail:
+ wpa_printf(MSG_INFO, "EAP-TEAP: Failed to parse PAC file '%s' (bin)",
+ pac_file);
+ if (!blob)
+ os_free(buf);
+ if (pac)
+ eap_teap_free_pac(pac);
+ return -1;
+}
+
+
+/**
+ * eap_teap_save_pac_bin - Save PAC entries (binary format)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @pac_root: Root of the PAC list
+ * @pac_file: Name of the PAC file/blob
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_teap_save_pac_bin(struct eap_sm *sm, struct eap_teap_pac *pac_root,
+ const char *pac_file)
+{
+ size_t len, count = 0;
+ struct eap_teap_pac *pac;
+ u8 *buf, *pos;
+
+ len = 6;
+ pac = pac_root;
+ while (pac) {
+ if (pac->pac_opaque_len > 65535 ||
+ pac->pac_info_len > 65535)
+ return -1;
+ len += 2 + EAP_TEAP_PAC_KEY_LEN + 2 + pac->pac_opaque_len +
+ 2 + pac->pac_info_len;
+ pac = pac->next;
+ }
+
+ buf = os_malloc(len);
+ if (!buf)
+ return -1;
+
+ pos = buf;
+ WPA_PUT_BE32(pos, EAP_TEAP_PAC_BINARY_MAGIC);
+ pos += 4;
+ WPA_PUT_BE16(pos, EAP_TEAP_PAC_BINARY_FORMAT_VERSION);
+ pos += 2;
+
+ pac = pac_root;
+ while (pac) {
+ WPA_PUT_BE16(pos, pac->pac_type);
+ pos += 2;
+ os_memcpy(pos, pac->pac_key, EAP_TEAP_PAC_KEY_LEN);
+ pos += EAP_TEAP_PAC_KEY_LEN;
+ WPA_PUT_BE16(pos, pac->pac_opaque_len);
+ pos += 2;
+ os_memcpy(pos, pac->pac_opaque, pac->pac_opaque_len);
+ pos += pac->pac_opaque_len;
+ WPA_PUT_BE16(pos, pac->pac_info_len);
+ pos += 2;
+ os_memcpy(pos, pac->pac_info, pac->pac_info_len);
+ pos += pac->pac_info_len;
+
+ pac = pac->next;
+ count++;
+ }
+
+ if (eap_teap_write_pac(sm, pac_file, (char *) buf, len)) {
+ os_free(buf);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Wrote %lu PAC entries into '%s' (bin)",
+ (unsigned long) count, pac_file);
+
+ return 0;
+}
diff --git a/src/eap_peer/eap_teap_pac.h b/src/eap_peer/eap_teap_pac.h
new file mode 100644
index 0000000..edf4c57
--- /dev/null
+++ b/src/eap_peer/eap_teap_pac.h
@@ -0,0 +1,50 @@
+/*
+ * EAP peer method: EAP-TEAP PAC file processing
+ * 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.
+ */
+
+#ifndef EAP_TEAP_PAC_H
+#define EAP_TEAP_PAC_H
+
+#include "eap_common/eap_teap_common.h"
+
+struct eap_teap_pac {
+ struct eap_teap_pac *next;
+
+ u8 pac_key[EAP_TEAP_PAC_KEY_LEN];
+ u8 *pac_opaque;
+ size_t pac_opaque_len;
+ u8 *pac_info;
+ size_t pac_info_len;
+ u8 *a_id;
+ size_t a_id_len;
+ u8 *i_id;
+ size_t i_id_len;
+ u8 *a_id_info;
+ size_t a_id_info_len;
+ u16 pac_type;
+};
+
+
+void eap_teap_free_pac(struct eap_teap_pac *pac);
+struct eap_teap_pac * eap_teap_get_pac(struct eap_teap_pac *pac_root,
+ const u8 *a_id, size_t a_id_len,
+ u16 pac_type);
+int eap_teap_add_pac(struct eap_teap_pac **pac_root,
+ struct eap_teap_pac **pac_current,
+ struct eap_teap_pac *entry);
+int eap_teap_load_pac(struct eap_sm *sm, struct eap_teap_pac **pac_root,
+ const char *pac_file);
+int eap_teap_save_pac(struct eap_sm *sm, struct eap_teap_pac *pac_root,
+ const char *pac_file);
+size_t eap_teap_pac_list_truncate(struct eap_teap_pac *pac_root,
+ size_t max_len);
+int eap_teap_load_pac_bin(struct eap_sm *sm, struct eap_teap_pac **pac_root,
+ const char *pac_file);
+int eap_teap_save_pac_bin(struct eap_sm *sm, struct eap_teap_pac *pac_root,
+ const char *pac_file);
+
+#endif /* EAP_TEAP_PAC_H */
diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c
index ffea9d2..ad079a7 100644
--- a/src/eap_peer/eap_tls.c
+++ b/src/eap_peer/eap_tls.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-TLS (RFC 2716)
- * Copyright (c) 2004-2008, 2012-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -33,10 +33,17 @@
{
struct eap_tls_data *data;
struct eap_peer_config *config = eap_get_config(sm);
- if (config == NULL ||
- ((sm->init_phase2 ? config->private_key2 : config->private_key)
- == NULL &&
- (sm->init_phase2 ? config->engine2 : config->engine) == 0)) {
+ struct eap_peer_cert_config *cert;
+
+ if (!config)
+ return NULL;
+ if (!sm->init_phase2)
+ cert = &config->cert;
+ else if (sm->use_machine_cred)
+ cert = &config->machine_cert;
+ else
+ cert = &config->phase2_cert;
+ if (!cert->private_key && cert->engine == 0) {
wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured");
return NULL;
}
@@ -51,17 +58,16 @@
if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TLS)) {
wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
eap_tls_deinit(sm, data);
- if (config->engine) {
+ if (cert->engine) {
wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting Smartcard "
"PIN");
eap_sm_request_pin(sm);
- sm->ignore = TRUE;
- } else if (config->private_key && !config->private_key_passwd)
- {
+ sm->ignore = true;
+ } else if (cert->private_key && !cert->private_key_passwd) {
wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting private "
"key passphrase");
eap_sm_request_passphrase(sm);
- sm->ignore = TRUE;
+ sm->ignore = true;
}
return NULL;
}
@@ -174,6 +180,9 @@
struct eap_method_ret *ret)
{
const char *label;
+ const u8 eap_tls13_context[] = { EAP_TYPE_TLS };
+ const u8 *context = NULL;
+ size_t context_len = 0;
wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
@@ -184,6 +193,8 @@
if (data->ssl.tls_v13) {
label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = 1;
/* A possible NewSessionTicket may be received before
* EAP-Success, so need to allow it to be received. */
@@ -198,7 +209,7 @@
eap_tls_free_key(data);
data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, label,
- NULL, 0,
+ context, context_len,
EAP_TLS_KEY_LEN +
EAP_EMSK_LEN);
if (data->key_data) {
@@ -291,6 +302,18 @@
return NULL;
}
+ if (res == 2) {
+ /* Application data included in the handshake message (used by
+ * EAP-TLS 1.3 to indicate conclusion of the exchange). */
+ wpa_hexdump_buf(MSG_DEBUG, "EAP-TLS: Received Application Data",
+ resp);
+ wpa_hexdump_buf(MSG_DEBUG, "EAP-TLS: Remaining tls_out data",
+ data->ssl.tls_out);
+ eap_peer_tls_reset_output(&data->ssl);
+ /* Send an ACK to allow the server to complete exchange */
+ res = 1;
+ }
+
if (tls_connection_established(data->ssl_ctx, data->ssl.conn))
eap_tls_success(sm, data, ret);
@@ -303,7 +326,7 @@
}
-static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
+static bool eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
{
struct eap_tls_data *data = priv;
return tls_connection_established(data->ssl_ctx, data->ssl.conn);
@@ -341,7 +364,7 @@
}
-static Boolean eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_tls_data *data = priv;
return data->key_data != NULL;
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index cb94c45..ab10678 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -16,7 +16,7 @@
#include "eap_config.h"
-static struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+static struct wpabuf * eap_tls_msg_alloc(enum eap_type type, size_t payload_len,
u8 code, u8 identifier)
{
if (type == EAP_UNAUTH_TLS_TYPE)
@@ -105,8 +105,8 @@
}
-static void eap_tls_params_from_conf1(struct tls_connection_params *params,
- struct eap_peer_config *config)
+static void eap_tls_cert_params_from_conf(struct tls_connection_params *params,
+ struct eap_peer_cert_config *config)
{
params->ca_cert = config->ca_cert;
params->ca_path = config->ca_path;
@@ -125,6 +125,19 @@
params->key_id = config->key_id;
params->cert_id = config->cert_id;
params->ca_cert_id = config->ca_cert_id;
+ if (config->ocsp)
+ params->flags |= TLS_CONN_REQUEST_OCSP;
+ if (config->ocsp >= 2)
+ params->flags |= TLS_CONN_REQUIRE_OCSP;
+ if (config->ocsp == 3)
+ params->flags |= TLS_CONN_REQUIRE_OCSP_ALL;
+}
+
+
+static void eap_tls_params_from_conf1(struct tls_connection_params *params,
+ struct eap_peer_config *config)
+{
+ eap_tls_cert_params_from_conf(params, &config->cert);
eap_tls_params_flags(params, config->phase1);
}
@@ -132,34 +145,27 @@
static void eap_tls_params_from_conf2(struct tls_connection_params *params,
struct eap_peer_config *config)
{
- 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;
- params->engine_id = config->engine2_id;
- params->pin = config->pin2;
- params->key_id = config->key2_id;
- params->cert_id = config->cert2_id;
- params->ca_cert_id = config->ca_cert2_id;
+ eap_tls_cert_params_from_conf(params, &config->phase2_cert);
eap_tls_params_flags(params, config->phase2);
}
+static void eap_tls_params_from_conf2m(struct tls_connection_params *params,
+ struct eap_peer_config *config)
+{
+ eap_tls_cert_params_from_conf(params, &config->machine_cert);
+ eap_tls_params_flags(params, config->machine_phase2);
+}
+
+
static int eap_tls_params_from_conf(struct eap_sm *sm,
struct eap_ssl_data *data,
struct tls_connection_params *params,
struct eap_peer_config *config, int phase2)
{
os_memset(params, 0, sizeof(*params));
- if (sm->workaround && data->eap_type != EAP_TYPE_FAST) {
+ if (sm->workaround && data->eap_type != EAP_TYPE_FAST &&
+ data->eap_type != EAP_TYPE_TEAP) {
/*
* Some deployed authentication servers seem to be unable to
* handle the TLS Session Ticket extension (they are supposed
@@ -171,7 +177,15 @@
*/
params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
}
+ if (data->eap_type == EAP_TYPE_TEAP) {
+ /* RFC 7170 requires TLS v1.2 or newer to be used with TEAP */
+ params->flags |= TLS_CONN_DISABLE_TLSv1_0 |
+ TLS_CONN_DISABLE_TLSv1_1;
+ if (config->teap_anon_dh)
+ params->flags |= TLS_CONN_TEAP_ANON_DH;
+ }
if (data->eap_type == EAP_TYPE_FAST ||
+ data->eap_type == EAP_TYPE_TEAP ||
data->eap_type == EAP_TYPE_TTLS ||
data->eap_type == EAP_TYPE_PEAP) {
/* The current EAP peer implementation is not yet ready for the
@@ -190,7 +204,10 @@
*/
params->flags |= TLS_CONN_DISABLE_TLSv1_3;
}
- if (phase2) {
+ if (phase2 && sm->use_machine_cred) {
+ wpa_printf(MSG_DEBUG, "TLS: using machine config options");
+ eap_tls_params_from_conf2m(params, config);
+ } else if (phase2) {
wpa_printf(MSG_DEBUG, "TLS: using phase2 config options");
eap_tls_params_from_conf2(params, config);
} else {
@@ -233,12 +250,6 @@
{
int res;
- if (config->ocsp)
- params->flags |= TLS_CONN_REQUEST_OCSP;
- if (config->ocsp >= 2)
- params->flags |= TLS_CONN_REQUIRE_OCSP;
- if (config->ocsp == 3)
- params->flags |= TLS_CONN_REQUIRE_OCSP_ALL;
data->conn = tls_connection_init(data->ssl_ctx);
if (data->conn == NULL) {
wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
@@ -255,15 +266,15 @@
*/
wpa_printf(MSG_INFO,
"TLS: Bad PIN provided, requesting a new one");
- os_free(config->pin);
- config->pin = NULL;
+ os_free(config->cert.pin);
+ config->cert.pin = NULL;
eap_sm_request_pin(sm);
- sm->ignore = TRUE;
+ sm->ignore = true;
} else if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) {
wpa_printf(MSG_INFO, "TLS: Failed to initialize engine");
} else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) {
wpa_printf(MSG_INFO, "TLS: Failed to load private key");
- sm->ignore = TRUE;
+ sm->ignore = true;
}
if (res) {
wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection "
@@ -404,17 +415,18 @@
if (eap_type == EAP_TYPE_TLS && data->tls_v13) {
u8 *id, *method_id;
+ const u8 context[] = { EAP_TYPE_TLS };
/* Session-Id = <EAP-Type> || Method-Id
* Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id",
- * "", 64)
+ * Type-Code, 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);
+ sm, data, "EXPORTER_EAP_TLS_Method-Id", context, 1, 64);
if (!method_id) {
os_free(id);
return NULL;
@@ -609,7 +621,8 @@
* @out_data: Buffer for returning the allocated output buffer
* Returns: ret (0 or 1) on success, -1 on failure
*/
-static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type,
+static int eap_tls_process_output(struct eap_ssl_data *data,
+ enum eap_type eap_type,
int peap_version, u8 id, int ret,
struct wpabuf **out_data)
{
@@ -707,7 +720,7 @@
* the tunneled data is used.
*/
int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
- EapType eap_type, int peap_version,
+ enum eap_type eap_type, int peap_version,
u8 id, const struct wpabuf *in_data,
struct wpabuf **out_data)
{
@@ -799,7 +812,7 @@
* @peap_version: Version number for EAP-PEAP/TTLS
* Returns: Pointer to the allocated ACK frame or %NULL on failure
*/
-struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type,
+struct wpabuf * eap_peer_tls_build_ack(u8 id, enum eap_type eap_type,
int peap_version)
{
struct wpabuf *resp;
@@ -889,7 +902,7 @@
*/
const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
struct eap_ssl_data *data,
- EapType eap_type,
+ enum eap_type eap_type,
struct eap_method_ret *ret,
const struct wpabuf *reqData,
size_t *len, u8 *flags)
@@ -900,7 +913,7 @@
if (tls_get_errors(data->ssl_ctx)) {
wpa_printf(MSG_INFO, "SSL: TLS errors detected");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -916,14 +929,14 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData,
&left);
if (pos == NULL) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (left == 0) {
wpa_printf(MSG_DEBUG, "SSL: Invalid TLS message: no Flags "
"octet included");
if (!sm->workaround) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -941,7 +954,7 @@
if (left < 4) {
wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
"length");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
tls_msg_len = WPA_GET_BE32(pos);
@@ -960,15 +973,15 @@
wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d "
"bytes) smaller than this fragment (%d "
"bytes)", (int) tls_msg_len, (int) left);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
}
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
*len = left;
return pos;
@@ -1046,7 +1059,7 @@
* Returns: 0 on success, -1 on failure
*/
int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,
- EapType eap_type, int peap_version, u8 id,
+ enum eap_type eap_type, int peap_version, u8 id,
const struct wpabuf *in_data,
struct wpabuf **out_data)
{
@@ -1082,17 +1095,21 @@
int eap_peer_select_phase2_methods(struct eap_peer_config *config,
const char *prefix,
struct eap_method_type **types,
- size_t *num_types)
+ size_t *num_types, int use_machine_cred)
{
char *start, *pos, *buf;
struct eap_method_type *methods = NULL, *_methods;
u32 method;
size_t num_methods = 0, prefix_len;
+ const char *phase2;
- if (config == NULL || config->phase2 == NULL)
+ if (!config)
+ goto get_defaults;
+ phase2 = use_machine_cred ? config->machine_phase2 : config->phase2;
+ if (!phase2)
goto get_defaults;
- start = buf = os_strdup(config->phase2);
+ start = buf = os_strdup(phase2);
if (buf == NULL)
return -1;
diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h
index 5f82529..183b7de 100644
--- a/src/eap_peer/eap_tls_common.h
+++ b/src/eap_peer/eap_tls_common.h
@@ -70,7 +70,8 @@
void *ssl_ctx;
/**
- * eap_type - EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
+ * eap_type - EAP method used in Phase 1
+ * (EAP_TYPE_TLS/PEAP/TTLS/FAST/TEAP)
*/
u8 eap_type;
@@ -85,6 +86,7 @@
#define EAP_TLS_FLAGS_LENGTH_INCLUDED 0x80
#define EAP_TLS_FLAGS_MORE_FRAGMENTS 0x40
#define EAP_TLS_FLAGS_START 0x20
+#define EAP_TEAP_FLAGS_OUTER_TLV_LEN 0x10
#define EAP_TLS_VERSION_MASK 0x07
/* could be up to 128 bytes, but only the first 64 bytes are used */
@@ -105,17 +107,17 @@
struct eap_ssl_data *data, u8 eap_type,
size_t *len);
int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
- EapType eap_type, int peap_version,
+ enum eap_type eap_type, int peap_version,
u8 id, const struct wpabuf *in_data,
struct wpabuf **out_data);
-struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type,
+struct wpabuf * eap_peer_tls_build_ack(u8 id, enum eap_type eap_type,
int peap_version);
int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data);
int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data,
char *buf, size_t buflen, int verbose);
const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
struct eap_ssl_data *data,
- EapType eap_type,
+ enum eap_type eap_type,
struct eap_method_ret *ret,
const struct wpabuf *reqData,
size_t *len, u8 *flags);
@@ -125,13 +127,13 @@
const struct wpabuf *in_data,
struct wpabuf **in_decrypted);
int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,
- EapType eap_type, int peap_version, u8 id,
+ enum eap_type eap_type, int peap_version, u8 id,
const struct wpabuf *in_data,
struct wpabuf **out_data);
int eap_peer_select_phase2_methods(struct eap_peer_config *config,
const char *prefix,
struct eap_method_type **types,
- size_t *num_types);
+ size_t *num_types, int use_machine_cred);
int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types,
struct eap_hdr *hdr, struct wpabuf **resp);
diff --git a/src/eap_peer/eap_tnc.c b/src/eap_peer/eap_tnc.c
index 726221e..af17773 100644
--- a/src/eap_peer/eap_tnc.c
+++ b/src/eap_peer/eap_tnc.c
@@ -92,9 +92,9 @@
u8 flags;
size_t send_len, plen;
- ret->ignore = FALSE;
+ ret->ignore = false;
wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Response");
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
flags = EAP_TNC_VERSION;
send_len = wpabuf_len(data->out_buf) - data->out_used;
@@ -174,7 +174,7 @@
if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) {
wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a "
"fragmented packet");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -184,7 +184,7 @@
if (data->in_buf == NULL) {
wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for "
"message");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
wpabuf_put_data(data->in_buf, buf, len);
@@ -219,7 +219,7 @@
if (pos == NULL) {
wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (pos=%p len=%lu)",
pos, (unsigned long) len);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -235,14 +235,14 @@
if (len > 0 && (flags & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d",
flags & EAP_TNC_VERSION_MASK);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) {
if (end - pos < 4) {
wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
message_length = WPA_GET_BE32(pos);
@@ -253,7 +253,7 @@
wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
"Length (%d; %ld remaining in this msg)",
message_length, (long) (end - pos));
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
}
@@ -265,7 +265,7 @@
if (len > 1) {
wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload in "
"WAIT_FRAG_ACK state");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged");
@@ -274,10 +274,10 @@
}
if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
-
+
if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
return eap_tnc_process_fragment(data, ret, id, flags,
message_length, pos,
@@ -294,7 +294,7 @@
if (!(flags & EAP_TNC_FLAGS_START)) {
wpa_printf(MSG_DEBUG, "EAP-TNC: Server did not use "
"start flag in the first message");
- ret->ignore = TRUE;
+ ret->ignore = true;
goto fail;
}
@@ -307,7 +307,7 @@
if (flags & EAP_TNC_FLAGS_START) {
wpa_printf(MSG_DEBUG, "EAP-TNC: Server used start "
"flag again");
- ret->ignore = TRUE;
+ ret->ignore = true;
goto fail;
}
@@ -316,7 +316,7 @@
wpabuf_len(data->in_buf));
switch (res) {
case TNCCS_PROCESS_ERROR:
- ret->ignore = TRUE;
+ ret->ignore = true;
goto fail;
case TNCCS_PROCESS_OK_NO_RECOMMENDATION:
case TNCCS_RECOMMENDATION_ERROR:
@@ -345,10 +345,10 @@
wpabuf_free(data->in_buf);
data->in_buf = NULL;
- ret->ignore = FALSE;
+ ret->ignore = false;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_UNCOND_SUCC;
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
if (tncs_done) {
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1,
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index 1c8dbe2..642d179 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -146,8 +146,8 @@
if (data->phase2_type == EAP_TTLS_PHASE2_EAP) {
if (eap_peer_select_phase2_methods(config, "autheap=",
&data->phase2_eap_types,
- &data->num_phase2_eap_types)
- < 0) {
+ &data->num_phase2_eap_types,
+ 0) < 0) {
eap_ttls_deinit(sm, data);
return NULL;
}
@@ -311,11 +311,11 @@
static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data,
- u8 method)
+ int vendor, enum eap_type method)
{
size_t i;
for (i = 0; i < data->num_phase2_eap_types; i++) {
- if (data->phase2_eap_types[i].vendor != EAP_VENDOR_IETF ||
+ if (data->phase2_eap_types[i].vendor != vendor ||
data->phase2_eap_types[i].method != method)
continue;
@@ -362,17 +362,19 @@
struct eap_ttls_data *data,
struct eap_method_ret *ret,
struct eap_hdr *hdr, size_t len,
- u8 method, struct wpabuf **resp)
+ int vendor, enum eap_type method,
+ struct wpabuf **resp)
{
#ifdef EAP_TNC
if (data->tnc_started && data->phase2_method &&
- data->phase2_priv && method == EAP_TYPE_TNC &&
+ data->phase2_priv &&
+ vendor == EAP_VENDOR_IETF && method == EAP_TYPE_TNC &&
data->phase2_eap_type.method == EAP_TYPE_TNC)
return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len,
resp);
if (data->ready_for_tnc && !data->tnc_started &&
- method == EAP_TYPE_TNC) {
+ vendor == EAP_VENDOR_IETF && method == EAP_TYPE_TNC) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed "
"EAP method");
data->tnc_started = 1;
@@ -386,7 +388,7 @@
return -1;
}
- data->phase2_eap_type.vendor = EAP_VENDOR_IETF;
+ data->phase2_eap_type.vendor = vendor;
data->phase2_eap_type.method = method;
wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected "
"Phase 2 EAP vendor %d method %d (TNC)",
@@ -400,10 +402,11 @@
if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF &&
data->phase2_eap_type.method == EAP_TYPE_NONE)
- eap_ttls_phase2_select_eap_method(data, method);
+ eap_ttls_phase2_select_eap_method(data, vendor, method);
- if (method != data->phase2_eap_type.method || method == EAP_TYPE_NONE)
- {
+ if (vendor != data->phase2_eap_type.vendor ||
+ method != data->phase2_eap_type.method ||
+ (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE)) {
if (eap_peer_tls_phase2_nak(data->phase2_eap_types,
data->num_phase2_eap_types,
hdr, resp))
@@ -412,8 +415,7 @@
}
if (data->phase2_priv == NULL) {
- data->phase2_method = eap_peer_get_eap_method(
- EAP_VENDOR_IETF, method);
+ data->phase2_method = eap_peer_get_eap_method(vendor, method);
if (data->phase2_method) {
sm->init_phase2 = 1;
data->phase2_priv = data->phase2_method->init(sm);
@@ -421,8 +423,9 @@
}
}
if (data->phase2_priv == NULL || data->phase2_method == NULL) {
- wpa_printf(MSG_INFO, "EAP-TTLS: failed to initialize "
- "Phase 2 EAP method %d", method);
+ wpa_printf(MSG_INFO,
+ "EAP-TTLS: failed to initialize Phase 2 EAP method %u:%u",
+ vendor, method);
return -1;
}
@@ -451,9 +454,23 @@
case EAP_TYPE_IDENTITY:
*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
break;
+ case EAP_TYPE_EXPANDED:
+ if (len < sizeof(struct eap_hdr) + 8) {
+ wpa_printf(MSG_INFO,
+ "EAP-TTLS: Too short Phase 2 request (expanded header) (len=%lu)",
+ (unsigned long) len);
+ return -1;
+ }
+ if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len,
+ WPA_GET_BE24(pos + 1),
+ WPA_GET_BE32(pos + 4),
+ resp) < 0)
+ return -1;
+ break;
default:
if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len,
- *pos, resp) < 0)
+ EAP_VENDOR_IETF, *pos,
+ resp) < 0)
return -1;
break;
}
@@ -1561,7 +1578,7 @@
struct eap_method_ret *ret)
{
if (ret->methodState == METHOD_DONE) {
- ret->allowNotifications = FALSE;
+ ret->allowNotifications = false;
if (ret->decision == DECISION_UNCOND_SUCC ||
ret->decision == DECISION_COND_SUCC) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
@@ -1656,7 +1673,7 @@
}
-static Boolean eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv)
+static bool eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv)
{
struct eap_ttls_data *data = priv;
return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
@@ -1747,7 +1764,7 @@
}
-static Boolean eap_ttls_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_ttls_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_ttls_data *data = priv;
return data->key_data != NULL && data->phase2_success;
diff --git a/src/eap_peer/eap_vendor_test.c b/src/eap_peer/eap_vendor_test.c
index 16e3c39..431f44b 100644
--- a/src/eap_peer/eap_vendor_test.c
+++ b/src/eap_peer/eap_vendor_test.c
@@ -75,28 +75,28 @@
pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE, reqData, &len);
if (pos == NULL || len < 1) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (data->state == INIT && *pos != 1) {
wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
"%d in INIT state", *pos);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (data->state == CONFIRM && *pos != 3) {
wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
"%d in CONFIRM state", *pos);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (data->state == SUCCESS) {
wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
"in SUCCESS state");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -105,17 +105,17 @@
data->first_try = 0;
wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Testing "
"pending request");
- ret->ignore = TRUE;
+ ret->ignore = true;
eloop_register_timeout(1, 0, eap_vendor_ready, sm,
NULL);
return NULL;
}
}
- ret->ignore = FALSE;
+ ret->ignore = false;
wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Generating Response");
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
resp = eap_msg_alloc(EAP_VENDOR_ID, EAP_VENDOR_TYPE, 1,
EAP_CODE_RESPONSE, eap_get_id(reqData));
@@ -138,7 +138,7 @@
}
-static Boolean eap_vendor_test_isKeyAvailable(struct eap_sm *sm, void *priv)
+static bool eap_vendor_test_isKeyAvailable(struct eap_sm *sm, void *priv)
{
struct eap_vendor_test_data *data = priv;
return data->state == SUCCESS;
diff --git a/src/eap_peer/eap_wsc.c b/src/eap_peer/eap_wsc.c
index 92d5a02..a1e7bff 100644
--- a/src/eap_peer/eap_wsc.c
+++ b/src/eap_peer/eap_wsc.c
@@ -304,9 +304,9 @@
u8 flags;
size_t send_len, plen;
- ret->ignore = FALSE;
+ ret->ignore = false;
wpa_printf(MSG_DEBUG, "EAP-WSC: Generating Response");
- ret->allowNotifications = TRUE;
+ ret->allowNotifications = true;
flags = 0;
send_len = wpabuf_len(data->out_buf) - data->out_used;
@@ -400,7 +400,7 @@
if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) {
wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length field in a "
"fragmented packet");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -410,7 +410,7 @@
if (data->in_buf == NULL) {
wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for "
"message");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
data->in_op_code = op_code;
@@ -441,7 +441,7 @@
pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, reqData,
&len);
if (pos == NULL || len < 2) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -455,7 +455,7 @@
if (flags & WSC_FLAGS_LF) {
if (end - pos < 2) {
wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
message_length = WPA_GET_BE16(pos);
@@ -464,7 +464,7 @@
if (message_length < end - pos || message_length > 50000) {
wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
"Length");
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
}
@@ -477,7 +477,7 @@
if (op_code != WSC_FRAG_ACK) {
wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
"in WAIT_FRAG_ACK state", op_code);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged");
@@ -489,7 +489,7 @@
op_code != WSC_Done && op_code != WSC_Start) {
wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
op_code);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
@@ -497,7 +497,7 @@
if (op_code != WSC_Start) {
wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
"in WAIT_START state", op_code);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
wpa_printf(MSG_DEBUG, "EAP-WSC: Received start");
@@ -507,13 +507,13 @@
} else if (op_code == WSC_Start) {
wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
op_code);
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
if (data->in_buf &&
eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) {
- ret->ignore = TRUE;
+ ret->ignore = true;
return NULL;
}
diff --git a/src/eap_peer/tncc.c b/src/eap_peer/tncc.c
index a9bafe2..c460980 100644
--- a/src/eap_peer/tncc.c
+++ b/src/eap_peer/tncc.c
@@ -144,7 +144,7 @@
TNC_MessageType messageType)
{
struct tnc_if_imc *imc;
- unsigned char *b64;
+ char *b64;
size_t b64len;
wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage(imcID=%lu "
@@ -629,8 +629,7 @@
return NULL;
*pos2 = '\0';
- decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
- decoded_len);
+ decoded = base64_decode(pos, os_strlen(pos), decoded_len);
*pos2 = '<';
if (decoded == NULL) {
wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index b130368..61032cc 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -45,43 +45,43 @@
struct eap_eapol_interface {
/* Lower layer to full authenticator variables */
- Boolean eapResp; /* shared with EAPOL Backend Authentication */
+ bool eapResp; /* shared with EAPOL Backend Authentication */
struct wpabuf *eapRespData;
- Boolean portEnabled;
+ bool portEnabled;
int retransWhile;
- Boolean eapRestart; /* shared with EAPOL Authenticator PAE */
+ bool eapRestart; /* shared with EAPOL Authenticator PAE */
int eapSRTT;
int eapRTTVAR;
/* Full authenticator to lower layer variables */
- Boolean eapReq; /* shared with EAPOL Backend Authentication */
- Boolean eapNoReq; /* shared with EAPOL Backend Authentication */
- Boolean eapSuccess;
- Boolean eapFail;
- Boolean eapTimeout;
+ bool eapReq; /* shared with EAPOL Backend Authentication */
+ bool eapNoReq; /* shared with EAPOL Backend Authentication */
+ bool eapSuccess;
+ bool eapFail;
+ bool eapTimeout;
struct wpabuf *eapReqData;
u8 *eapKeyData;
size_t eapKeyDataLen;
u8 *eapSessionId;
size_t eapSessionIdLen;
- Boolean eapKeyAvailable; /* called keyAvailable in IEEE 802.1X-2004 */
+ bool eapKeyAvailable; /* called keyAvailable in IEEE 802.1X-2004 */
/* AAA interface to full authenticator variables */
- Boolean aaaEapReq;
- Boolean aaaEapNoReq;
- Boolean aaaSuccess;
- Boolean aaaFail;
+ bool aaaEapReq;
+ bool aaaEapNoReq;
+ bool aaaSuccess;
+ bool aaaFail;
struct wpabuf *aaaEapReqData;
u8 *aaaEapKeyData;
size_t aaaEapKeyDataLen;
- Boolean aaaEapKeyAvailable;
+ bool aaaEapKeyAvailable;
int aaaMethodTimeout;
/* Full authenticator to AAA interface variables */
- Boolean aaaEapResp;
+ bool aaaEapResp;
struct wpabuf *aaaEapRespData;
/* aaaIdentity -> eap_get_identity() */
- Boolean aaaTimeout;
+ bool aaaTimeout;
};
struct eap_server_erp_key {
@@ -108,35 +108,162 @@
};
struct eap_config {
+ /**
+ * ssl_ctx - TLS context
+ *
+ * This is passed to the EAP server implementation as a callback
+ * context for TLS operations.
+ */
void *ssl_ctx;
void *msg_ctx;
+
+ /**
+ * eap_sim_db_priv - EAP-SIM/AKA database context
+ *
+ * This is passed to the EAP-SIM/AKA server implementation as a
+ * callback context.
+ */
void *eap_sim_db_priv;
- Boolean backend_auth;
+ bool backend_auth;
int eap_server;
+
+ /**
+ * pwd_group - The D-H group assigned for EAP-pwd
+ *
+ * If EAP-pwd is not used it can be set to zero.
+ */
u16 pwd_group;
+
+ /**
+ * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST
+ *
+ * This parameter is used to set a key for EAP-FAST to encrypt the
+ * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If
+ * set, must point to a 16-octet key.
+ */
u8 *pac_opaque_encr_key;
+
+ /**
+ * eap_fast_a_id - EAP-FAST authority identity (A-ID)
+ *
+ * If EAP-FAST is not used, this can be set to %NULL. In theory, this
+ * is a variable length field, but due to some existing implementations
+ * requiring A-ID to be 16 octets in length, it is recommended to use
+ * that length for the field to provide interoperability with deployed
+ * peer implementations.
+ */
u8 *eap_fast_a_id;
+
+ /**
+ * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets
+ */
size_t eap_fast_a_id_len;
+ /**
+ * eap_fast_a_id_info - EAP-FAST authority identifier information
+ *
+ * This A-ID-Info contains a user-friendly name for the A-ID. For
+ * example, this could be the enterprise and server names in
+ * human-readable format. This field is encoded as UTF-8. If EAP-FAST
+ * is not used, this can be set to %NULL.
+ */
char *eap_fast_a_id_info;
- int eap_fast_prov;
+
+ /**
+ * eap_fast_prov - EAP-FAST provisioning modes
+ *
+ * 0 = provisioning disabled, 1 = only anonymous provisioning allowed,
+ * 2 = only authenticated provisioning allowed, 3 = both provisioning
+ * modes allowed.
+ */
+ enum {
+ NO_PROV, ANON_PROV, AUTH_PROV, BOTH_PROV
+ } eap_fast_prov;
+
+ /**
+ * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds
+ *
+ * This is the hard limit on how long a provisioned PAC-Key can be
+ * used.
+ */
int pac_key_lifetime;
+
+ /**
+ * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds
+ *
+ * This is a soft limit on the PAC-Key. The server will automatically
+ * generate a new PAC-Key when this number of seconds (or fewer) of the
+ * lifetime remains.
+ */
int pac_key_refresh_time;
+ int eap_teap_auth;
+ int eap_teap_pac_no_inner;
+ int eap_teap_separate_result;
+ enum eap_teap_id {
+ EAP_TEAP_ID_ALLOW_ANY = 0,
+ EAP_TEAP_ID_REQUIRE_USER = 1,
+ EAP_TEAP_ID_REQUIRE_MACHINE = 2,
+ EAP_TEAP_ID_REQUEST_USER_ACCEPT_MACHINE = 3,
+ EAP_TEAP_ID_REQUEST_MACHINE_ACCEPT_USER = 4,
+ EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE = 5,
+ } eap_teap_id;
+
+ /**
+ * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication
+ *
+ * This controls whether the protected success/failure indication
+ * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA.
+ */
int eap_sim_aka_result_ind;
+ int eap_sim_id;
+
+ /**
+ * tnc - Trusted Network Connect (TNC)
+ *
+ * This controls whether TNC is enabled and will be required before the
+ * peer is allowed to connect. Note: This is only used with EAP-TTLS
+ * and EAP-FAST. If any other EAP method is enabled, the peer will be
+ * allowed to connect without TNC.
+ */
int tnc;
+
+ /**
+ * wps - Wi-Fi Protected Setup context
+ *
+ * If WPS is used with an external RADIUS server (which is quite
+ * unlikely configuration), this is used to provide a pointer to WPS
+ * context data. Normally, this can be set to %NULL.
+ */
struct wps_context *wps;
- const struct wpabuf *assoc_wps_ie;
- const struct wpabuf *assoc_p2p_ie;
- const u8 *peer_addr;
int fragment_size;
int pbc_in_m1;
- const u8 *server_id;
+ /**
+ * server_id - Server identity
+ */
+ u8 *server_id;
size_t server_id_len;
+
+ /**
+ * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
+ *
+ * This controls whether the authentication server derives ERP key
+ * hierarchy (rRK and rIK) from full EAP authentication and allows
+ * these keys to be used to perform ERP to derive rMSK instead of full
+ * EAP authentication to derive MSK.
+ */
int erp;
unsigned int tls_session_lifetime;
unsigned int tls_flags;
+ unsigned int max_auth_rounds;
+ unsigned int max_auth_rounds_short;
+};
+
+struct eap_session_data {
+ const struct wpabuf *assoc_wps_ie;
+ const struct wpabuf *assoc_p2p_ie;
+ const u8 *peer_addr;
#ifdef CONFIG_TESTING_OPTIONS
u32 tls_test_flags;
#endif /* CONFIG_TESTING_OPTIONS */
@@ -145,7 +272,8 @@
struct eap_sm * eap_server_sm_init(void *eapol_ctx,
const struct eapol_callbacks *eapol_cb,
- struct eap_config *eap_conf);
+ const struct eap_config *conf,
+ const struct eap_session_data *sess);
void eap_server_sm_deinit(struct eap_sm *sm);
int eap_server_sm_step(struct eap_sm *sm);
void eap_sm_notify_cached(struct eap_sm *sm);
@@ -162,5 +290,6 @@
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);
+void eap_server_config_free(struct eap_config *cfg);
#endif /* EAP_H */
diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h
index 1cade10..28bb564 100644
--- a/src/eap_server/eap_i.h
+++ b/src/eap_server/eap_i.h
@@ -23,7 +23,7 @@
*/
struct eap_method {
int vendor;
- EapType method;
+ enum eap_type method;
const char *name;
void * (*init)(struct eap_sm *sm);
@@ -32,15 +32,14 @@
struct wpabuf * (*buildReq)(struct eap_sm *sm, void *priv, u8 id);
int (*getTimeout)(struct eap_sm *sm, void *priv);
- Boolean (*check)(struct eap_sm *sm, void *priv,
- struct wpabuf *respData);
+ bool (*check)(struct eap_sm *sm, void *priv, struct wpabuf *respData);
void (*process)(struct eap_sm *sm, void *priv,
struct wpabuf *respData);
- Boolean (*isDone)(struct eap_sm *sm, void *priv);
+ bool (*isDone)(struct eap_sm *sm, void *priv);
u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len);
/* isSuccess is not specified in draft-ietf-eap-statemachine-05.txt,
* but it is useful in implementing Policy.getDecision() */
- Boolean (*isSuccess)(struct eap_sm *sm, void *priv);
+ bool (*isSuccess)(struct eap_sm *sm, void *priv);
/**
* free - Free EAP method data
@@ -128,7 +127,7 @@
/* Full authenticator state machine local variables */
/* Long-term (maintained between packets) */
- EapType currentMethod;
+ enum eap_type currentMethod;
int currentId;
enum {
METHOD_PROPOSED, METHOD_CONTINUE, METHOD_END
@@ -138,13 +137,13 @@
int methodTimeout;
/* Short-term (not maintained between packets) */
- Boolean rxResp;
- Boolean rxInitiate;
+ bool rxResp;
+ bool rxInitiate;
int respId;
- EapType respMethod;
+ enum eap_type respMethod;
int respVendor;
u32 respVendorMethod;
- Boolean ignore;
+ bool ignore;
enum {
DECISION_SUCCESS, DECISION_FAILURE, DECISION_CONTINUE,
DECISION_PASSTHROUGH, DECISION_INITIATE_REAUTH_START
@@ -153,8 +152,8 @@
/* Miscellaneous variables */
const struct eap_method *m; /* selected EAP method */
/* not defined in RFC 4137 */
- Boolean changed;
- void *eapol_ctx, *msg_ctx;
+ bool changed;
+ void *eapol_ctx;
const struct eapol_callbacks *eapol_cb;
void *eap_method_priv;
u8 *identity;
@@ -167,13 +166,12 @@
struct eap_user *user;
int user_eap_method_index;
int init_phase2;
- void *ssl_ctx;
- struct eap_sim_db_data *eap_sim_db_priv;
- Boolean backend_auth;
- Boolean update_user;
- int eap_server;
+ const struct eap_config *cfg;
+ struct eap_config cfg_buf;
+ bool update_user;
- int num_rounds;
+ unsigned int num_rounds;
+ unsigned int num_rounds_short;
enum {
METHOD_PENDING_NONE, METHOD_PENDING_WAIT, METHOD_PENDING_CONT
} method_pending;
@@ -181,39 +179,15 @@
u8 *auth_challenge;
u8 *peer_challenge;
- u8 *pac_opaque_encr_key;
- u8 *eap_fast_a_id;
- size_t eap_fast_a_id_len;
- char *eap_fast_a_id_info;
- enum {
- NO_PROV, ANON_PROV, AUTH_PROV, BOTH_PROV
- } eap_fast_prov;
- int pac_key_lifetime;
- int pac_key_refresh_time;
- int eap_sim_aka_result_ind;
- int tnc;
- u16 pwd_group;
- struct wps_context *wps;
struct wpabuf *assoc_wps_ie;
struct wpabuf *assoc_p2p_ie;
- Boolean start_reauth;
+ bool start_reauth;
u8 peer_addr[ETH_ALEN];
- /* Fragmentation size for EAP method init() handler */
- int fragment_size;
-
- int pbc_in_m1;
-
- const u8 *server_id;
- size_t server_id_len;
-
- Boolean initiate_reauth_start_sent;
- Boolean try_initiate_reauth;
- int erp;
- unsigned int tls_session_lifetime;
- unsigned int tls_flags;
+ bool initiate_reauth_start_sent;
+ bool try_initiate_reauth;
#ifdef CONFIG_TESTING_OPTIONS
u32 tls_test_flags;
diff --git a/src/eap_server/eap_methods.h b/src/eap_server/eap_methods.h
index 3bf1495..ad60700 100644
--- a/src/eap_server/eap_methods.h
+++ b/src/eap_server/eap_methods.h
@@ -12,14 +12,15 @@
#include "eap_common/eap_defs.h"
const struct eap_method * eap_server_get_eap_method(int vendor,
- EapType method);
+ enum eap_type method);
struct eap_method * eap_server_method_alloc(int version, int vendor,
- EapType method, const char *name);
+ enum eap_type method,
+ const char *name);
int eap_server_method_register(struct eap_method *method);
-EapType eap_server_get_type(const char *name, int *vendor);
+enum eap_type eap_server_get_type(const char *name, int *vendor);
void eap_server_unregister_methods(void);
-const char * eap_server_get_name(int vendor, EapType type);
+const char * eap_server_get_name(int vendor, enum eap_type type);
/* EAP server method registration calls for statically linked in methods */
int eap_server_identity_register(void);
@@ -41,6 +42,7 @@
int eap_server_gpsk_register(void);
int eap_server_vendor_test_register(void);
int eap_server_fast_register(void);
+int eap_server_teap_register(void);
int eap_server_wsc_register(void);
int eap_server_ikev2_register(void);
int eap_server_tnc_register(void);
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index e8b36e1..0b7a5b9 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -9,7 +9,7 @@
* in RFC 4137. However, to support backend authentication in RADIUS
* authentication server functionality, parts of backend authenticator (also
* from RFC 4137) are mixed in. This functionality is enabled by setting
- * backend_auth configuration variable to TRUE.
+ * backend_auth configuration variable to true.
*/
#include "includes.h"
@@ -23,8 +23,6 @@
#define STATE_MACHINE_DATA struct eap_sm
#define STATE_MACHINE_DEBUG_PREFIX "EAP"
-#define EAP_MAX_AUTH_ROUNDS 50
-
/* EAP state machines are described in RFC 4137 */
static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
@@ -37,9 +35,10 @@
static int eap_sm_nextId(struct eap_sm *sm, int id);
static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list,
size_t len);
-static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor);
+static enum eap_type eap_sm_Policy_getNextMethod(struct eap_sm *sm,
+ int *vendor);
static int eap_sm_Policy_getDecision(struct eap_sm *sm);
-static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
+static bool eap_sm_Policy_doPickUp(struct eap_sm *sm, enum eap_type method);
static int eap_get_erp_send_reauth_start(struct eap_sm *sm)
@@ -94,7 +93,7 @@
}
msg = eap_msg_alloc(EAP_VENDOR_IETF,
- (EapType) EAP_ERP_TYPE_REAUTH_START, plen,
+ (enum eap_type) EAP_ERP_TYPE_REAUTH_START, plen,
EAP_CODE_INITIATE, id);
if (msg == NULL)
return NULL;
@@ -215,6 +214,7 @@
{
SM_ENTRY(EAP, DISABLED);
sm->num_rounds = 0;
+ sm->num_rounds_short = 0;
}
@@ -222,7 +222,7 @@
{
SM_ENTRY(EAP, INITIALIZE);
- if (sm->eap_if.eapRestart && !sm->eap_server && sm->identity) {
+ if (sm->eap_if.eapRestart && !sm->cfg->eap_server && sm->identity) {
/*
* Need to allow internal Identity method to be used instead
* of passthrough at the beginning of reauthentication.
@@ -230,19 +230,19 @@
eap_server_clear_identity(sm);
}
- sm->try_initiate_reauth = FALSE;
+ sm->try_initiate_reauth = false;
sm->currentId = -1;
- sm->eap_if.eapSuccess = FALSE;
- sm->eap_if.eapFail = FALSE;
- sm->eap_if.eapTimeout = FALSE;
+ sm->eap_if.eapSuccess = false;
+ sm->eap_if.eapFail = false;
+ sm->eap_if.eapTimeout = false;
bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
sm->eap_if.eapKeyData = NULL;
sm->eap_if.eapKeyDataLen = 0;
os_free(sm->eap_if.eapSessionId);
sm->eap_if.eapSessionId = NULL;
sm->eap_if.eapSessionIdLen = 0;
- sm->eap_if.eapKeyAvailable = FALSE;
- sm->eap_if.eapRestart = FALSE;
+ sm->eap_if.eapKeyAvailable = false;
+ sm->eap_if.eapRestart = false;
/*
* This is not defined in RFC 4137, but method state needs to be
@@ -256,7 +256,7 @@
sm->m = NULL;
sm->user_eap_method_index = 0;
- if (sm->backend_auth) {
+ if (sm->cfg->backend_auth) {
sm->currentMethod = EAP_TYPE_NONE;
/* parse rxResp, respId, respMethod */
eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
@@ -265,9 +265,10 @@
}
}
sm->num_rounds = 0;
+ sm->num_rounds_short = 0;
sm->method_pending = METHOD_PENDING_NONE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
MACSTR, MAC2STR(sm->peer_addr));
}
@@ -299,7 +300,7 @@
}
}
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
"method=%u", sm->currentMethod);
}
@@ -321,10 +322,10 @@
sm->retransCount++;
if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) {
if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
- sm->eap_if.eapReq = TRUE;
+ sm->eap_if.eapReq = true;
}
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT MACSTR,
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT MACSTR,
MAC2STR(sm->peer_addr));
}
@@ -336,14 +337,18 @@
/* parse rxResp, respId, respMethod */
eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
sm->num_rounds++;
+ if (!sm->eap_if.eapRespData || wpabuf_len(sm->eap_if.eapRespData) < 20)
+ sm->num_rounds_short++;
+ else
+ sm->num_rounds_short = 0;
}
SM_STATE(EAP, DISCARD)
{
SM_ENTRY(EAP, DISCARD);
- sm->eap_if.eapResp = FALSE;
- sm->eap_if.eapNoReq = TRUE;
+ sm->eap_if.eapResp = false;
+ sm->eap_if.eapNoReq = true;
}
@@ -353,19 +358,21 @@
sm->retransCount = 0;
if (sm->eap_if.eapReqData) {
+ if (wpabuf_len(sm->eap_if.eapReqData) >= 20)
+ sm->num_rounds_short = 0;
if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0)
{
- sm->eap_if.eapResp = FALSE;
- sm->eap_if.eapReq = TRUE;
+ sm->eap_if.eapResp = false;
+ sm->eap_if.eapReq = true;
} else {
- sm->eap_if.eapResp = FALSE;
- sm->eap_if.eapReq = FALSE;
+ sm->eap_if.eapResp = false;
+ sm->eap_if.eapReq = false;
}
} else {
wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData");
- sm->eap_if.eapResp = FALSE;
- sm->eap_if.eapReq = FALSE;
- sm->eap_if.eapNoReq = TRUE;
+ sm->eap_if.eapResp = false;
+ sm->eap_if.eapReq = false;
+ sm->eap_if.eapNoReq = true;
}
}
@@ -375,7 +382,7 @@
SM_ENTRY(EAP, INTEGRITY_CHECK);
if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1)) {
- sm->ignore = TRUE;
+ sm->ignore = true;
return;
}
@@ -529,7 +536,7 @@
sm->eap_if.eapSessionId,
sm->eap_if.eapSessionIdLen);
}
- if (sm->erp && sm->m->get_emsk && sm->eap_if.eapSessionId)
+ if (sm->cfg->erp && sm->m->get_emsk && sm->eap_if.eapSessionId)
eap_server_erp_init(sm);
sm->methodState = METHOD_END;
} else {
@@ -541,11 +548,11 @@
SM_STATE(EAP, PROPOSE_METHOD)
{
int vendor;
- EapType type;
+ enum eap_type type;
SM_ENTRY(EAP, PROPOSE_METHOD);
- sm->try_initiate_reauth = FALSE;
+ sm->try_initiate_reauth = false;
try_another_method:
type = eap_sm_Policy_getNextMethod(sm, &vendor);
if (vendor == EAP_VENDOR_IETF)
@@ -579,7 +586,7 @@
else
sm->methodState = METHOD_PROPOSED;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
"vendor=%u method=%u", vendor, sm->currentMethod);
eap_log_msg(sm, "Propose EAP method vendor=%u method=%u",
vendor, sm->currentMethod);
@@ -633,10 +640,10 @@
{
SM_ENTRY(EAP, TIMEOUT_FAILURE);
- sm->eap_if.eapTimeout = TRUE;
+ sm->eap_if.eapTimeout = true;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TIMEOUT_FAILURE MACSTR,
- MAC2STR(sm->peer_addr));
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO,
+ WPA_EVENT_EAP_TIMEOUT_FAILURE MACSTR, MAC2STR(sm->peer_addr));
}
@@ -648,9 +655,9 @@
sm->eap_if.eapReqData = eap_sm_buildFailure(sm, sm->currentId);
wpabuf_free(sm->lastReqData);
sm->lastReqData = NULL;
- sm->eap_if.eapFail = TRUE;
+ sm->eap_if.eapFail = true;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
MACSTR, MAC2STR(sm->peer_addr));
}
@@ -664,10 +671,10 @@
wpabuf_free(sm->lastReqData);
sm->lastReqData = NULL;
if (sm->eap_if.eapKeyData)
- sm->eap_if.eapKeyAvailable = TRUE;
- sm->eap_if.eapSuccess = TRUE;
+ sm->eap_if.eapKeyAvailable = true;
+ sm->eap_if.eapSuccess = true;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
MACSTR, MAC2STR(sm->peer_addr));
}
@@ -676,8 +683,8 @@
{
SM_ENTRY(EAP, INITIATE_REAUTH_START);
- sm->initiate_reauth_start_sent = TRUE;
- sm->try_initiate_reauth = TRUE;
+ sm->initiate_reauth_start_sent = true;
+ sm->try_initiate_reauth = true;
sm->currentId = eap_sm_nextId(sm, sm->currentId);
wpa_printf(MSG_DEBUG,
"EAP: building EAP-Initiate-Re-auth-Start: Identifier %d",
@@ -720,7 +727,8 @@
plen = 1 + 2 + 2 + os_strlen(nai);
if (hash_len)
plen += 1 + hash_len;
- msg = eap_msg_alloc(EAP_VENDOR_IETF, (EapType) EAP_ERP_TYPE_REAUTH,
+ msg = eap_msg_alloc(EAP_VENDOR_IETF,
+ (enum eap_type) EAP_ERP_TYPE_REAUTH,
plen, EAP_CODE_FINISH, id);
if (msg == NULL)
return;
@@ -752,8 +760,8 @@
sm->lastReqData = NULL;
if ((flags & 0x80) || !erp) {
- sm->eap_if.eapFail = TRUE;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
+ sm->eap_if.eapFail = true;
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
MACSTR, MAC2STR(sm->peer_addr));
return;
}
@@ -776,12 +784,12 @@
return;
}
sm->eap_if.eapKeyDataLen = erp->rRK_len;
- sm->eap_if.eapKeyAvailable = TRUE;
+ sm->eap_if.eapKeyAvailable = true;
wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rMSK",
sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
- sm->eap_if.eapSuccess = TRUE;
+ sm->eap_if.eapSuccess = true;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
MACSTR, MAC2STR(sm->peer_addr));
}
@@ -803,9 +811,10 @@
SM_ENTRY(EAP, INITIATE_RECEIVED);
- sm->rxInitiate = FALSE;
+ sm->rxInitiate = false;
- pos = eap_hdr_validate(EAP_VENDOR_IETF, (EapType) EAP_ERP_TYPE_REAUTH,
+ pos = eap_hdr_validate(EAP_VENDOR_IETF,
+ (enum eap_type) EAP_ERP_TYPE_REAUTH,
sm->eap_if.eapRespData, &len);
if (pos == NULL) {
wpa_printf(MSG_INFO, "EAP-Initiate: Invalid frame");
@@ -852,7 +861,7 @@
os_memcpy(nai, parse.keyname, parse.keyname_len);
nai[parse.keyname_len] = '\0';
- if (!sm->eap_server) {
+ if (!sm->cfg->eap_server) {
/*
* In passthrough case, EAP-Initiate/Re-auth replaces
* EAP Identity exchange. Use keyName-NAI as the user identity
@@ -979,7 +988,7 @@
return;
fail:
- sm->ignore = TRUE;
+ sm->ignore = true;
}
#endif /* CONFIG_ERP */
@@ -991,7 +1000,7 @@
wpabuf_free(sm->eap_if.aaaEapRespData);
sm->eap_if.aaaEapRespData = NULL;
- sm->try_initiate_reauth = FALSE;
+ sm->try_initiate_reauth = false;
}
@@ -1012,10 +1021,10 @@
sm->retransCount++;
if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) {
if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
- sm->eap_if.eapReq = TRUE;
+ sm->eap_if.eapReq = true;
}
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT2 MACSTR,
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_RETRANSMIT2 MACSTR,
MAC2STR(sm->peer_addr));
}
@@ -1032,8 +1041,8 @@
SM_STATE(EAP, DISCARD2)
{
SM_ENTRY(EAP, DISCARD2);
- sm->eap_if.eapResp = FALSE;
- sm->eap_if.eapNoReq = TRUE;
+ sm->eap_if.eapResp = false;
+ sm->eap_if.eapNoReq = true;
}
@@ -1045,17 +1054,17 @@
if (sm->eap_if.eapReqData) {
if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0)
{
- sm->eap_if.eapResp = FALSE;
- sm->eap_if.eapReq = TRUE;
+ sm->eap_if.eapResp = false;
+ sm->eap_if.eapReq = true;
} else {
- sm->eap_if.eapResp = FALSE;
- sm->eap_if.eapReq = FALSE;
+ sm->eap_if.eapResp = false;
+ sm->eap_if.eapReq = false;
}
} else {
wpa_printf(MSG_INFO, "EAP: SEND_REQUEST2 - no eapReqData");
- sm->eap_if.eapResp = FALSE;
- sm->eap_if.eapReq = FALSE;
- sm->eap_if.eapNoReq = TRUE;
+ sm->eap_if.eapResp = false;
+ sm->eap_if.eapReq = false;
+ sm->eap_if.eapNoReq = true;
}
}
@@ -1094,11 +1103,11 @@
{
SM_ENTRY(EAP, AAA_IDLE);
- sm->eap_if.aaaFail = FALSE;
- sm->eap_if.aaaSuccess = FALSE;
- sm->eap_if.aaaEapReq = FALSE;
- sm->eap_if.aaaEapNoReq = FALSE;
- sm->eap_if.aaaEapResp = TRUE;
+ sm->eap_if.aaaFail = false;
+ sm->eap_if.aaaSuccess = false;
+ sm->eap_if.aaaEapReq = false;
+ sm->eap_if.aaaEapNoReq = false;
+ sm->eap_if.aaaEapResp = true;
}
@@ -1106,10 +1115,10 @@
{
SM_ENTRY(EAP, TIMEOUT_FAILURE2);
- sm->eap_if.eapTimeout = TRUE;
+ sm->eap_if.eapTimeout = true;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TIMEOUT_FAILURE2 MACSTR,
- MAC2STR(sm->peer_addr));
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO,
+ WPA_EVENT_EAP_TIMEOUT_FAILURE2 MACSTR, MAC2STR(sm->peer_addr));
}
@@ -1118,9 +1127,9 @@
SM_ENTRY(EAP, FAILURE2);
eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
- sm->eap_if.eapFail = TRUE;
+ sm->eap_if.eapFail = true;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE2 MACSTR,
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE2 MACSTR,
MAC2STR(sm->peer_addr));
}
@@ -1140,16 +1149,16 @@
sm->eap_if.eapKeyDataLen = 0;
}
- sm->eap_if.eapSuccess = TRUE;
+ sm->eap_if.eapSuccess = true;
/*
* Start reauthentication with identity request even though we know the
* previously used identity. This is needed to get reauthentication
* started properly.
*/
- sm->start_reauth = TRUE;
+ sm->start_reauth = true;
- wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS2 MACSTR,
+ wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS2 MACSTR,
MAC2STR(sm->peer_addr));
}
@@ -1160,17 +1169,26 @@
SM_ENTER_GLOBAL(EAP, INITIALIZE);
else if (!sm->eap_if.portEnabled)
SM_ENTER_GLOBAL(EAP, DISABLED);
- else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
- if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
+ else if (sm->num_rounds > sm->cfg->max_auth_rounds) {
+ if (sm->num_rounds == sm->cfg->max_auth_rounds + 1) {
wpa_printf(MSG_DEBUG, "EAP: more than %d "
"authentication rounds - abort",
- EAP_MAX_AUTH_ROUNDS);
+ sm->cfg->max_auth_rounds);
sm->num_rounds++;
SM_ENTER_GLOBAL(EAP, FAILURE);
}
+ } else if (sm->num_rounds_short > sm->cfg->max_auth_rounds_short) {
+ if (sm->num_rounds_short ==
+ sm->cfg->max_auth_rounds_short + 1) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: more than %d authentication rounds (short) - abort",
+ sm->cfg->max_auth_rounds_short);
+ sm->num_rounds_short++;
+ SM_ENTER_GLOBAL(EAP, FAILURE);
+ }
} else switch (sm->EAP_state) {
case EAP_INITIALIZE:
- if (sm->backend_auth) {
+ if (sm->cfg->backend_auth) {
if (!sm->rxResp)
SM_ENTER(EAP, SELECT_ACTION);
else if (sm->rxResp &&
@@ -1199,7 +1217,7 @@
case EAP_IDLE:
if (sm->eap_if.retransWhile == 0) {
if (sm->try_initiate_reauth) {
- sm->try_initiate_reauth = FALSE;
+ sm->try_initiate_reauth = false;
SM_ENTER(EAP, SELECT_ACTION);
} else {
SM_ENTER(EAP, RETRANSMIT);
@@ -1333,7 +1351,7 @@
else if (sm->decision == DECISION_INITIATE_REAUTH_START)
SM_ENTER(EAP, INITIATE_REAUTH_START);
#ifdef CONFIG_ERP
- else if (sm->eap_server && sm->erp && sm->rxInitiate)
+ else if (sm->cfg->eap_server && sm->cfg->erp && sm->rxInitiate)
SM_ENTER(EAP, INITIATE_RECEIVED);
#endif /* CONFIG_ERP */
else
@@ -1343,7 +1361,7 @@
SM_ENTER(EAP, SEND_REQUEST);
break;
case EAP_INITIATE_RECEIVED:
- if (!sm->eap_server)
+ if (!sm->cfg->eap_server)
SM_ENTER(EAP, SELECT_ACTION);
break;
case EAP_TIMEOUT_FAILURE:
@@ -1473,8 +1491,8 @@
size_t plen;
/* parse rxResp, respId, respMethod */
- sm->rxResp = FALSE;
- sm->rxInitiate = FALSE;
+ sm->rxResp = false;
+ sm->rxInitiate = false;
sm->respId = -1;
sm->respMethod = EAP_TYPE_NONE;
sm->respVendor = EAP_VENDOR_IETF;
@@ -1500,9 +1518,9 @@
sm->respId = hdr->identifier;
if (hdr->code == EAP_CODE_RESPONSE)
- sm->rxResp = TRUE;
+ sm->rxResp = true;
else if (hdr->code == EAP_CODE_INITIATE)
- sm->rxInitiate = TRUE;
+ sm->rxInitiate = true;
if (plen > sizeof(*hdr)) {
u8 *pos = (u8 *) (hdr + 1);
@@ -1669,9 +1687,9 @@
}
-static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
+static enum eap_type eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
{
- EapType next;
+ enum eap_type next;
int idx = sm->user_eap_method_index;
/* In theory, there should be no problems with starting
@@ -1684,7 +1702,7 @@
if (sm->identity == NULL || sm->currentId == -1) {
*vendor = EAP_VENDOR_IETF;
next = EAP_TYPE_IDENTITY;
- sm->update_user = TRUE;
+ sm->update_user = true;
} else if (sm->user && idx < EAP_MAX_METHODS &&
(sm->user->methods[idx].vendor != EAP_VENDOR_IETF ||
sm->user->methods[idx].method != EAP_TYPE_NONE)) {
@@ -1703,7 +1721,7 @@
static int eap_sm_Policy_getDecision(struct eap_sm *sm)
{
- if (!sm->eap_server && sm->identity && !sm->start_reauth) {
+ if (!sm->cfg->eap_server && sm->identity && !sm->start_reauth) {
wpa_printf(MSG_DEBUG, "EAP: getDecision: -> PASSTHROUGH");
return DECISION_PASSTHROUGH;
}
@@ -1712,7 +1730,7 @@
sm->m->isSuccess(sm, sm->eap_method_priv)) {
wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> "
"SUCCESS");
- sm->update_user = TRUE;
+ sm->update_user = true;
return DECISION_SUCCESS;
}
@@ -1720,7 +1738,7 @@
!sm->m->isSuccess(sm, sm->eap_method_priv)) {
wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> "
"FAILURE");
- sm->update_user = TRUE;
+ sm->update_user = true;
return DECISION_FAILURE;
}
@@ -1747,12 +1765,12 @@
sm->user->methods[0].method == EAP_TYPE_IDENTITY) {
wpa_printf(MSG_DEBUG, "EAP: getDecision: stop "
"identity request loop -> FAILURE");
- sm->update_user = TRUE;
+ sm->update_user = true;
return DECISION_FAILURE;
}
- sm->update_user = FALSE;
+ sm->update_user = false;
}
- sm->start_reauth = FALSE;
+ sm->start_reauth = false;
if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
(sm->user->methods[sm->user_eap_method_index].vendor !=
@@ -1783,9 +1801,9 @@
}
-static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method)
+static bool eap_sm_Policy_doPickUp(struct eap_sm *sm, enum eap_type method)
{
- return method == EAP_TYPE_IDENTITY ? TRUE : FALSE;
+ return method == EAP_TYPE_IDENTITY;
}
@@ -1802,7 +1820,7 @@
{
int res = 0;
do {
- sm->changed = FALSE;
+ sm->changed = false;
SM_STEP_RUN(EAP);
if (sm->changed)
res = 1;
@@ -1834,7 +1852,8 @@
*/
struct eap_sm * eap_server_sm_init(void *eapol_ctx,
const struct eapol_callbacks *eapol_cb,
- struct eap_config *conf)
+ const struct eap_config *conf,
+ const struct eap_session_data *sess)
{
struct eap_sm *sm;
@@ -1844,51 +1863,15 @@
sm->eapol_ctx = eapol_ctx;
sm->eapol_cb = eapol_cb;
sm->MaxRetrans = 5; /* RFC 3748: max 3-5 retransmissions suggested */
- sm->ssl_ctx = conf->ssl_ctx;
- sm->msg_ctx = conf->msg_ctx;
- sm->eap_sim_db_priv = conf->eap_sim_db_priv;
- sm->backend_auth = conf->backend_auth;
- sm->eap_server = conf->eap_server;
- if (conf->pac_opaque_encr_key) {
- sm->pac_opaque_encr_key = os_malloc(16);
- if (sm->pac_opaque_encr_key) {
- os_memcpy(sm->pac_opaque_encr_key,
- conf->pac_opaque_encr_key, 16);
- }
- }
- if (conf->eap_fast_a_id) {
- sm->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
- if (sm->eap_fast_a_id) {
- os_memcpy(sm->eap_fast_a_id, conf->eap_fast_a_id,
- conf->eap_fast_a_id_len);
- sm->eap_fast_a_id_len = conf->eap_fast_a_id_len;
- }
- }
- if (conf->eap_fast_a_id_info)
- sm->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info);
- sm->eap_fast_prov = conf->eap_fast_prov;
- sm->pac_key_lifetime = conf->pac_key_lifetime;
- sm->pac_key_refresh_time = conf->pac_key_refresh_time;
- sm->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
- sm->tnc = conf->tnc;
- sm->wps = conf->wps;
- if (conf->assoc_wps_ie)
- sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie);
- if (conf->assoc_p2p_ie)
- sm->assoc_p2p_ie = wpabuf_dup(conf->assoc_p2p_ie);
- if (conf->peer_addr)
- os_memcpy(sm->peer_addr, conf->peer_addr, ETH_ALEN);
- sm->fragment_size = conf->fragment_size;
- sm->pwd_group = conf->pwd_group;
- sm->pbc_in_m1 = conf->pbc_in_m1;
- sm->server_id = conf->server_id;
- sm->server_id_len = conf->server_id_len;
- sm->erp = conf->erp;
- sm->tls_session_lifetime = conf->tls_session_lifetime;
- sm->tls_flags = conf->tls_flags;
-
+ sm->cfg = conf;
+ if (sess->assoc_wps_ie)
+ sm->assoc_wps_ie = wpabuf_dup(sess->assoc_wps_ie);
+ if (sess->assoc_p2p_ie)
+ sm->assoc_p2p_ie = wpabuf_dup(sess->assoc_p2p_ie);
+ if (sess->peer_addr)
+ os_memcpy(sm->peer_addr, sess->peer_addr, ETH_ALEN);
#ifdef CONFIG_TESTING_OPTIONS
- sm->tls_test_flags = conf->tls_test_flags;
+ sm->tls_test_flags = sess->tls_test_flags;
#endif /* CONFIG_TESTING_OPTIONS */
wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
@@ -1918,9 +1901,6 @@
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);
wpabuf_free(sm->eap_if.aaaEapReqData);
wpabuf_free(sm->eap_if.aaaEapRespData);
bin_clear_free(sm->eap_if.aaaEapKeyData, sm->eap_if.aaaEapKeyDataLen);
@@ -2110,3 +2090,15 @@
source, user, hex_challenge, hex_response);
}
#endif /* CONFIG_TESTING_OPTIONS */
+
+
+void eap_server_config_free(struct eap_config *cfg)
+{
+ if (!cfg)
+ return;
+ os_free(cfg->pac_opaque_encr_key);
+ os_free(cfg->eap_fast_a_id);
+ os_free(cfg->eap_fast_a_id_info);
+ os_free(cfg->server_id);
+ os_free(cfg);
+}
diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index 1bea706..e9bf030 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -30,6 +30,7 @@
u8 ck[EAP_AKA_CK_LEN];
u8 ik[EAP_AKA_IK_LEN];
u8 res[EAP_AKA_RES_MAX_LEN];
+ u8 reauth_mac[EAP_SIM_MAC_LEN];
size_t res_len;
enum {
IDENTITY, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
@@ -99,7 +100,7 @@
return 0;
wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth username '%s'", username);
- data->reauth = eap_sim_db_get_reauth_entry(sm->eap_sim_db_priv,
+ data->reauth = eap_sim_db_get_reauth_entry(sm->cfg->eap_sim_db_priv,
username);
if (data->reauth == NULL) {
wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown reauth identity - "
@@ -156,7 +157,7 @@
wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
username);
permanent = eap_sim_db_get_permanent(
- sm->eap_sim_db_priv, username);
+ sm->cfg->eap_sim_db_priv, username);
if (permanent == NULL) {
os_free(username);
wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
@@ -181,7 +182,7 @@
{
struct eap_aka_data *data;
- if (sm->eap_sim_db_priv == NULL) {
+ if (!sm->cfg->eap_sim_db_priv) {
wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
return NULL;
}
@@ -207,7 +208,7 @@
/* TODO: make ANID configurable; see 3GPP TS 24.302 */
char *network_name = "WLAN";
- if (sm->eap_sim_db_priv == NULL) {
+ if (sm->cfg->eap_sim_db_priv == NULL) {
wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
return NULL;
}
@@ -392,10 +393,13 @@
const u8 *nonce_s)
{
os_free(data->next_pseudonym);
- if (nonce_s == NULL) {
+ if (!(sm->cfg->eap_sim_id & 0x01)) {
+ /* Use of pseudonyms disabled in configuration */
+ data->next_pseudonym = NULL;
+ } else if (!nonce_s) {
data->next_pseudonym =
eap_sim_db_get_next_pseudonym(
- sm->eap_sim_db_priv,
+ sm->cfg->eap_sim_db_priv,
data->eap_method == EAP_TYPE_AKA_PRIME ?
EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
} else {
@@ -403,10 +407,13 @@
data->next_pseudonym = NULL;
}
os_free(data->next_reauth_id);
- if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
+ if (!(sm->cfg->eap_sim_id & 0x02)) {
+ /* Use of fast reauth disabled in configuration */
+ data->next_reauth_id = NULL;
+ } else if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
data->next_reauth_id =
eap_sim_db_get_next_reauth_id(
- sm->eap_sim_db_priv,
+ sm->cfg->eap_sim_db_priv,
data->eap_method == EAP_TYPE_AKA_PRIME ?
EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
} else {
@@ -498,7 +505,7 @@
eap_aka_add_checkcode(data, msg);
- if (sm->eap_sim_aka_result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind) {
wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
}
@@ -542,6 +549,7 @@
struct eap_aka_data *data, u8 id)
{
struct eap_sim_msg *msg;
+ struct wpabuf *buf;
wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication");
@@ -574,14 +582,23 @@
eap_aka_add_checkcode(data, msg);
- if (sm->eap_sim_aka_result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind) {
wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
}
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
- return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, NULL, 0);
+ buf = eap_sim_msg_finish(msg, data->eap_method, data->k_aut, NULL, 0);
+
+ /* Remember this MAC before sending it to the peer. This MAC is used for
+ * Session-Id calculation after receiving response from the peer and
+ * after all other checks pass. */
+ os_memcpy(data->reauth_mac,
+ wpabuf_head_u8(buf) + wpabuf_len(buf) - EAP_SIM_MAC_LEN,
+ EAP_SIM_MAC_LEN);
+
+ return buf;
}
@@ -647,8 +664,8 @@
}
-static Boolean eap_aka_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_aka_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
struct eap_aka_data *data = priv;
const u8 *pos;
@@ -658,25 +675,25 @@
&len);
if (pos == NULL || len < 3) {
wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
-static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
+static bool eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
{
if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR ||
subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT)
- return FALSE;
+ return false;
switch (data->state) {
case IDENTITY:
if (subtype != EAP_AKA_SUBTYPE_IDENTITY) {
wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
"subtype %d", subtype);
- return TRUE;
+ return true;
}
break;
case CHALLENGE:
@@ -684,30 +701,30 @@
subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
"subtype %d", subtype);
- return TRUE;
+ return true;
}
break;
case REAUTH:
if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) {
wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
"subtype %d", subtype);
- return TRUE;
+ return true;
}
break;
case NOTIFICATION:
if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) {
wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
"subtype %d", subtype);
- return TRUE;
+ return true;
}
break;
default:
wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for "
"processing a response", data->state);
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -750,7 +767,7 @@
wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
username);
permanent = eap_sim_db_get_permanent(
- sm->eap_sim_db_priv, username);
+ sm->cfg->eap_sim_db_priv, username);
os_free(username);
if (permanent == NULL) {
wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
@@ -786,7 +803,7 @@
size_t identity_len;
int res;
- res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, data->permanent,
+ res = eap_sim_db_get_aka_auth(sm->cfg->eap_sim_db_priv, data->permanent,
data->rand, data->autn, data->ik,
data->ck, data->res, &data->res_len, sm);
if (res == EAP_SIM_DB_PENDING) {
@@ -981,7 +998,7 @@
wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the "
"correct AT_MAC");
- if (sm->eap_sim_aka_result_ind && attr->result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
data->use_result_ind = 1;
data->notification = EAP_SIM_SUCCESS;
eap_aka_state(data, NOTIFICATION);
@@ -989,14 +1006,15 @@
eap_aka_state(data, SUCCESS);
if (data->next_pseudonym) {
- eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
+ eap_sim_db_add_pseudonym(sm->cfg->eap_sim_db_priv,
+ data->permanent,
data->next_pseudonym);
data->next_pseudonym = NULL;
}
if (data->next_reauth_id) {
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
#ifdef EAP_SERVER_AKA_PRIME
- eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
+ eap_sim_db_add_reauth_prime(sm->cfg->eap_sim_db_priv,
data->permanent,
data->next_reauth_id,
data->counter + 1,
@@ -1004,7 +1022,7 @@
data->k_re);
#endif /* EAP_SERVER_AKA_PRIME */
} else {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv,
+ eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv,
data->permanent,
data->next_reauth_id,
data->counter + 1,
@@ -1034,7 +1052,7 @@
* maintaining a local flag stating whether this AUTS has already been
* reported. */
if (!data->auts_reported &&
- eap_sim_db_resynchronize(sm->eap_sim_db_priv, data->permanent,
+ eap_sim_db_resynchronize(sm->cfg->eap_sim_db_priv, data->permanent,
attr->auts, data->rand)) {
wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed");
data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
@@ -1101,7 +1119,7 @@
return;
}
- if (sm->eap_sim_aka_result_ind && attr->result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
data->use_result_ind = 1;
data->notification = EAP_SIM_SUCCESS;
eap_aka_state(data, NOTIFICATION);
@@ -1111,7 +1129,7 @@
if (data->next_reauth_id) {
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
#ifdef EAP_SERVER_AKA_PRIME
- eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
+ eap_sim_db_add_reauth_prime(sm->cfg->eap_sim_db_priv,
data->permanent,
data->next_reauth_id,
data->counter + 1,
@@ -1119,7 +1137,7 @@
data->k_re);
#endif /* EAP_SERVER_AKA_PRIME */
} else {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv,
+ eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv,
data->permanent,
data->next_reauth_id,
data->counter + 1,
@@ -1127,7 +1145,8 @@
}
data->next_reauth_id = NULL;
} else {
- eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+ eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv,
+ data->reauth);
data->reauth = NULL;
}
@@ -1136,7 +1155,7 @@
fail:
data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
eap_aka_state(data, NOTIFICATION);
- eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+ eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv, data->reauth);
data->reauth = NULL;
os_free(decrypted);
}
@@ -1250,7 +1269,7 @@
}
-static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv)
+static bool eap_aka_isDone(struct eap_sm *sm, void *priv)
{
struct eap_aka_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -1289,7 +1308,7 @@
}
-static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_aka_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_aka_data *data = priv;
return data->state == SUCCESS;
@@ -1304,14 +1323,24 @@
if (data->state != SUCCESS)
return NULL;
- *len = 1 + EAP_AKA_RAND_LEN + EAP_AKA_AUTN_LEN;
+ if (!data->reauth)
+ *len = 1 + EAP_AKA_RAND_LEN + EAP_AKA_AUTN_LEN;
+ else
+ *len = 1 + EAP_SIM_NONCE_S_LEN + EAP_SIM_MAC_LEN;
id = os_malloc(*len);
if (id == NULL)
return NULL;
id[0] = data->eap_method;
- os_memcpy(id + 1, data->rand, EAP_AKA_RAND_LEN);
- os_memcpy(id + 1 + EAP_AKA_RAND_LEN, data->autn, EAP_AKA_AUTN_LEN);
+ if (!data->reauth) {
+ os_memcpy(id + 1, data->rand, EAP_AKA_RAND_LEN);
+ os_memcpy(id + 1 + EAP_AKA_RAND_LEN, data->autn,
+ EAP_AKA_AUTN_LEN);
+ } else {
+ os_memcpy(id + 1, data->nonce_s, EAP_SIM_NONCE_S_LEN);
+ os_memcpy(id + 1 + EAP_SIM_NONCE_S_LEN, data->reauth_mac,
+ EAP_SIM_MAC_LEN);
+ }
wpa_hexdump(MSG_DEBUG, "EAP-AKA: Derived Session-Id", id, *len);
return id;
diff --git a/src/eap_server/eap_server_eke.c b/src/eap_server/eap_server_eke.c
index 71580bf..eac3245 100644
--- a/src/eap_server/eap_server_eke.c
+++ b/src/eap_server/eap_server_eke.c
@@ -84,11 +84,11 @@
eap_eke_state(data, IDENTITY);
data->serverid_type = EAP_EKE_ID_OPAQUE;
- for (i = 0; i < sm->server_id_len; i++) {
- if (sm->server_id[i] == '.' &&
+ for (i = 0; i < sm->cfg->server_id_len; i++) {
+ if (sm->cfg->server_id[i] == '.' &&
data->serverid_type == EAP_EKE_ID_OPAQUE)
data->serverid_type = EAP_EKE_ID_FQDN;
- if (sm->server_id[i] == '@')
+ if (sm->cfg->server_id[i] == '@')
data->serverid_type = EAP_EKE_ID_NAI;
}
@@ -186,7 +186,7 @@
wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Identity");
- plen = 2 + 4 * 4 + 1 + sm->server_id_len;
+ plen = 2 + 4 * 4 + 1 + sm->cfg->server_id_len;
msg = eap_eke_build_msg(data, id, plen, EAP_EKE_ID);
if (msg == NULL)
return NULL;
@@ -223,7 +223,7 @@
/* Server IDType + Identity */
wpabuf_put_u8(msg, data->serverid_type);
- wpabuf_put_data(msg, sm->server_id, sm->server_id_len);
+ wpabuf_put_data(msg, sm->cfg->server_id, sm->cfg->server_id_len);
wpabuf_free(data->msgs);
data->msgs = wpabuf_dup(msg);
@@ -252,7 +252,7 @@
if (eap_eke_derive_key(&data->sess, sm->user->password,
sm->user->password_len,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len, data->key) < 0) {
wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
@@ -338,7 +338,7 @@
wpabuf_put(msg, prot_len);
if (eap_eke_derive_ka(&data->sess,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len,
data->nonce_p, data->nonce_s) < 0) {
wpabuf_free(msg);
@@ -380,8 +380,8 @@
}
-static Boolean eap_eke_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_eke_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
struct eap_eke_data *data = priv;
size_t len;
@@ -391,28 +391,28 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-EKE: Invalid frame");
- return TRUE;
+ return true;
}
eke_exch = *pos;
wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: EKE-Exch=%d", eke_exch);
if (data->state == IDENTITY && eke_exch == EAP_EKE_ID)
- return FALSE;
+ return false;
if (data->state == COMMIT && eke_exch == EAP_EKE_COMMIT)
- return FALSE;
+ return false;
if (data->state == CONFIRM && eke_exch == EAP_EKE_CONFIRM)
- return FALSE;
+ return false;
if (eke_exch == EAP_EKE_FAILURE)
- return FALSE;
+ return false;
wpa_printf(MSG_INFO, "EAP-EKE: Unexpected EKE-Exch=%d in state=%d",
eke_exch, data->state);
- return TRUE;
+ return true;
}
@@ -552,7 +552,7 @@
}
if (eap_eke_derive_ke_ki(&data->sess,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len) < 0) {
wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
@@ -641,7 +641,8 @@
return;
}
- if (eap_eke_derive_msk(&data->sess, sm->server_id, sm->server_id_len,
+ if (eap_eke_derive_msk(&data->sess, sm->cfg->server_id,
+ sm->cfg->server_id_len,
data->peerid, data->peerid_len,
data->nonce_s, data->nonce_p,
data->msk, data->emsk) < 0) {
@@ -715,7 +716,7 @@
}
-static Boolean eap_eke_isDone(struct eap_sm *sm, void *priv)
+static bool eap_eke_isDone(struct eap_sm *sm, void *priv)
{
struct eap_eke_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -756,7 +757,7 @@
}
-static Boolean eap_eke_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_eke_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_eke_data *data = priv;
return data->state == SUCCESS;
diff --git a/src/eap_server/eap_server_fast.c b/src/eap_server/eap_server_fast.c
index a63f820..55d48d9 100644
--- a/src/eap_server/eap_server_fast.c
+++ b/src/eap_server/eap_server_fast.c
@@ -108,8 +108,8 @@
}
-static EapType eap_fast_req_failure(struct eap_sm *sm,
- struct eap_fast_data *data)
+static enum eap_type eap_fast_req_failure(struct eap_sm *sm,
+ struct eap_fast_data *data)
{
/* TODO: send Result TLV(FAILURE) */
eap_fast_state(data, FAILURE);
@@ -278,7 +278,7 @@
* Extra key material after TLS key_block: session_key_seed[40]
*/
- sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
+ sks = eap_fast_derive_key(sm->cfg->ssl_ctx, data->ssl.conn,
EAP_FAST_SKS_LEN);
if (sks == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
@@ -304,7 +304,7 @@
{
os_free(data->key_block_p);
data->key_block_p = (struct eap_fast_key_block_provisioning *)
- eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
+ eap_fast_derive_key(sm->cfg->ssl_ctx, data->ssl.conn,
sizeof(*data->key_block_p));
if (data->key_block_p == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
@@ -440,7 +440,7 @@
return NULL;
}
- if (tls_connection_set_cipher_list(sm->ssl_ctx, data->ssl.conn,
+ if (tls_connection_set_cipher_list(sm->cfg->ssl_ctx, data->ssl.conn,
ciphers) < 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to set TLS cipher "
"suites");
@@ -448,7 +448,8 @@
return NULL;
}
- if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn,
+ if (tls_connection_set_session_ticket_cb(sm->cfg->ssl_ctx,
+ data->ssl.conn,
eap_fast_session_ticket_cb,
data) < 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to set SessionTicket "
@@ -457,47 +458,48 @@
return NULL;
}
- if (sm->pac_opaque_encr_key == NULL) {
+ if (sm->cfg->pac_opaque_encr_key == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: No PAC-Opaque encryption key "
"configured");
eap_fast_reset(sm, data);
return NULL;
}
- os_memcpy(data->pac_opaque_encr, sm->pac_opaque_encr_key,
+ os_memcpy(data->pac_opaque_encr, sm->cfg->pac_opaque_encr_key,
sizeof(data->pac_opaque_encr));
- if (sm->eap_fast_a_id == NULL) {
+ if (sm->cfg->eap_fast_a_id == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: No A-ID configured");
eap_fast_reset(sm, data);
return NULL;
}
- data->srv_id = os_memdup(sm->eap_fast_a_id, sm->eap_fast_a_id_len);
+ data->srv_id = os_memdup(sm->cfg->eap_fast_a_id,
+ sm->cfg->eap_fast_a_id_len);
if (data->srv_id == NULL) {
eap_fast_reset(sm, data);
return NULL;
}
- data->srv_id_len = sm->eap_fast_a_id_len;
+ data->srv_id_len = sm->cfg->eap_fast_a_id_len;
- if (sm->eap_fast_a_id_info == NULL) {
+ if (sm->cfg->eap_fast_a_id_info == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: No A-ID-Info configured");
eap_fast_reset(sm, data);
return NULL;
}
- data->srv_id_info = os_strdup(sm->eap_fast_a_id_info);
+ data->srv_id_info = os_strdup(sm->cfg->eap_fast_a_id_info);
if (data->srv_id_info == NULL) {
eap_fast_reset(sm, data);
return NULL;
}
/* PAC-Key lifetime in seconds (hard limit) */
- data->pac_key_lifetime = sm->pac_key_lifetime;
+ data->pac_key_lifetime = sm->cfg->pac_key_lifetime;
/*
* PAC-Key refresh time in seconds (soft limit on remaining hard
* limit). The server will generate a new PAC-Key when this number of
* seconds (or fewer) of the lifetime remains.
*/
- data->pac_key_refresh_time = sm->pac_key_refresh_time;
+ data->pac_key_refresh_time = sm->cfg->pac_key_refresh_time;
return data;
}
@@ -552,8 +554,8 @@
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase1 done, starting Phase2");
- if (tls_get_cipher(sm->ssl_ctx, data->ssl.conn, cipher, sizeof(cipher))
- < 0) {
+ if (tls_get_cipher(sm->cfg->ssl_ctx, data->ssl.conn,
+ cipher, sizeof(cipher)) < 0) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to get cipher "
"information");
eap_fast_state(data, FAILURE);
@@ -872,7 +874,8 @@
case START:
return eap_fast_build_start(sm, data, id);
case PHASE1:
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ if (tls_connection_established(sm->cfg->ssl_ctx,
+ data->ssl.conn)) {
if (eap_fast_phase1_done(sm, data) < 0)
return NULL;
if (data->state == PHASE2_START) {
@@ -926,8 +929,8 @@
}
-static Boolean eap_fast_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_fast_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
const u8 *pos;
size_t len;
@@ -935,23 +938,22 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_FAST, respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-FAST: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
static int eap_fast_phase2_init(struct eap_sm *sm, struct eap_fast_data *data,
- EapType eap_type)
+ int vendor, enum eap_type eap_type)
{
if (data->phase2_priv && data->phase2_method) {
data->phase2_method->reset(sm, data->phase2_priv);
data->phase2_method = NULL;
data->phase2_priv = NULL;
}
- data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
- eap_type);
+ data->phase2_method = eap_server_get_eap_method(vendor, eap_type);
if (!data->phase2_method)
return -1;
@@ -973,7 +975,8 @@
struct eap_fast_data *data,
u8 *in_data, size_t in_len)
{
- u8 next_type = EAP_TYPE_NONE;
+ int next_vendor = EAP_VENDOR_IETF;
+ enum eap_type next_type = EAP_TYPE_NONE;
struct eap_hdr *hdr;
u8 *pos;
size_t left;
@@ -999,8 +1002,9 @@
m->method == EAP_TYPE_TNC) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Peer Nak'ed required "
"TNC negotiation");
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_fast_req_failure(sm, data);
- eap_fast_phase2_init(sm, data, next_type);
+ eap_fast_phase2_init(sm, data, next_vendor, next_type);
return;
}
#endif /* EAP_SERVER_TNC */
@@ -1008,14 +1012,17 @@
if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
sm->user->methods[sm->user_eap_method_index].method !=
EAP_TYPE_NONE) {
+ next_vendor = sm->user->methods[
+ sm->user_eap_method_index].vendor;
next_type = sm->user->methods[
sm->user_eap_method_index++].method;
- wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d",
- next_type);
+ wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %u:%u",
+ next_vendor, next_type);
} else {
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_fast_req_failure(sm, data);
}
- eap_fast_phase2_init(sm, data, next_type);
+ eap_fast_phase2_init(sm, data, next_vendor, next_type);
return;
}
@@ -1035,8 +1042,9 @@
if (!m->isSuccess(sm, priv)) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method failed");
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_fast_req_failure(sm, data);
- eap_fast_phase2_init(sm, data, next_type);
+ eap_fast_phase2_init(sm, data, next_vendor, next_type);
return;
}
@@ -1047,6 +1055,7 @@
"Identity not found in the user "
"database",
sm->identity, sm->identity_len);
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_fast_req_failure(sm, data);
break;
}
@@ -1057,23 +1066,28 @@
* Only EAP-MSCHAPv2 is allowed for anonymous
* provisioning.
*/
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_MSCHAPV2;
sm->user_eap_method_index = 0;
} else {
+ next_vendor = sm->user->methods[0].vendor;
next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
}
- wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d", next_type);
+ wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %u:%u",
+ next_vendor, next_type);
break;
case PHASE2_METHOD:
case CRYPTO_BINDING:
eap_fast_update_icmk(sm, data);
eap_fast_state(data, CRYPTO_BINDING);
data->eap_seq++;
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_NONE;
#ifdef EAP_SERVER_TNC
- if (sm->tnc && !data->tnc_started) {
+ if (sm->cfg->tnc && !data->tnc_started) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Initialize TNC");
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_TNC;
data->tnc_started = 1;
}
@@ -1087,7 +1101,7 @@
break;
}
- eap_fast_phase2_init(sm, data, next_type);
+ eap_fast_phase2_init(sm, data, next_vendor, next_type);
}
@@ -1335,8 +1349,8 @@
}
if (data->anon_provisioning &&
- sm->eap_fast_prov != ANON_PROV &&
- sm->eap_fast_prov != BOTH_PROV) {
+ sm->cfg->eap_fast_prov != ANON_PROV &&
+ sm->cfg->eap_fast_prov != BOTH_PROV) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Client is trying to "
"use unauthenticated provisioning which is "
"disabled");
@@ -1344,8 +1358,8 @@
return;
}
- if (sm->eap_fast_prov != AUTH_PROV &&
- sm->eap_fast_prov != BOTH_PROV &&
+ if (sm->cfg->eap_fast_prov != AUTH_PROV &&
+ sm->cfg->eap_fast_prov != BOTH_PROV &&
tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV &&
eap_fast_pac_type(tlv.pac, tlv.pac_len,
PAC_TYPE_TUNNEL_PAC)) {
@@ -1397,7 +1411,7 @@
return;
}
- in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ in_decrypted = tls_connection_decrypt(sm->cfg->ssl_ctx, data->ssl.conn,
in_buf);
if (in_decrypted == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 "
@@ -1457,7 +1471,7 @@
return -1;
}
- if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
+ if (!tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
wpabuf_len(data->ssl.tls_out) > 0)
return 1;
@@ -1474,7 +1488,8 @@
static int eap_fast_process_phase2_start(struct eap_sm *sm,
struct eap_fast_data *data)
{
- u8 next_type;
+ int next_vendor;
+ enum eap_type next_type;
if (data->identity) {
os_free(sm->identity);
@@ -1488,10 +1503,12 @@
"Phase2 Identity not found "
"in the user database",
sm->identity, sm->identity_len);
+ next_vendor = EAP_VENDOR_IETF;
next_type = eap_fast_req_failure(sm, data);
} else {
wpa_printf(MSG_DEBUG, "EAP-FAST: Identity already "
"known - skip Phase 2 Identity Request");
+ next_vendor = sm->user->methods[0].vendor;
next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
}
@@ -1499,10 +1516,11 @@
eap_fast_state(data, PHASE2_METHOD);
} else {
eap_fast_state(data, PHASE2_ID);
+ next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_IDENTITY;
}
- return eap_fast_phase2_init(sm, data, next_type);
+ return eap_fast_phase2_init(sm, data, next_vendor, next_type);
}
@@ -1545,7 +1563,7 @@
}
-static Boolean eap_fast_isDone(struct eap_sm *sm, void *priv)
+static bool eap_fast_isDone(struct eap_sm *sm, void *priv)
{
struct eap_fast_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -1596,7 +1614,7 @@
}
-static Boolean eap_fast_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_fast_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_fast_data *data = priv;
return data->state == SUCCESS;
diff --git a/src/eap_server/eap_server_gpsk.c b/src/eap_server/eap_server_gpsk.c
index fb3d117..4081b9f 100644
--- a/src/eap_server/eap_server_gpsk.c
+++ b/src/eap_server/eap_server_gpsk.c
@@ -117,7 +117,7 @@
wpa_hexdump(MSG_MSGDUMP, "EAP-GPSK: RAND_Server",
data->rand_server, EAP_GPSK_RAND_LEN);
- len = 1 + 2 + sm->server_id_len + EAP_GPSK_RAND_LEN + 2 +
+ len = 1 + 2 + sm->cfg->server_id_len + EAP_GPSK_RAND_LEN + 2 +
data->csuite_count * sizeof(struct eap_gpsk_csuite);
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
EAP_CODE_REQUEST, id);
@@ -129,8 +129,8 @@
}
wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_1);
- wpabuf_put_be16(req, sm->server_id_len);
- wpabuf_put_data(req, sm->server_id, sm->server_id_len);
+ wpabuf_put_be16(req, sm->cfg->server_id_len);
+ wpabuf_put_data(req, sm->cfg->server_id, sm->cfg->server_id_len);
wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
wpabuf_put_be16(req,
data->csuite_count * sizeof(struct eap_gpsk_csuite));
@@ -152,7 +152,7 @@
wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-3");
miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
- len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + sm->server_id_len +
+ len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + sm->cfg->server_id_len +
sizeof(struct eap_gpsk_csuite) + 2 + miclen;
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
EAP_CODE_REQUEST, id);
@@ -168,8 +168,8 @@
wpabuf_put_data(req, data->rand_peer, EAP_GPSK_RAND_LEN);
wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
- wpabuf_put_be16(req, sm->server_id_len);
- wpabuf_put_data(req, sm->server_id, sm->server_id_len);
+ wpabuf_put_be16(req, sm->cfg->server_id_len);
+ wpabuf_put_data(req, sm->cfg->server_id, sm->cfg->server_id_len);
csuite = wpabuf_put(req, sizeof(*csuite));
WPA_PUT_BE32(csuite->vendor, data->vendor);
WPA_PUT_BE16(csuite->specifier, data->specifier);
@@ -181,7 +181,7 @@
if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
data->specifier, start, pos - start, pos) < 0)
{
- os_free(req);
+ wpabuf_free(req);
eap_gpsk_state(data, FAILURE);
return NULL;
}
@@ -208,8 +208,8 @@
}
-static Boolean eap_gpsk_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_gpsk_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
struct eap_gpsk_data *data = priv;
const u8 *pos;
@@ -218,21 +218,21 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-GPSK: Invalid frame");
- return TRUE;
+ return true;
}
wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode=%d", *pos);
if (data->state == GPSK_1 && *pos == EAP_GPSK_OPCODE_GPSK_2)
- return FALSE;
+ return false;
if (data->state == GPSK_3 && *pos == EAP_GPSK_OPCODE_GPSK_4)
- return FALSE;
+ return false;
wpa_printf(MSG_INFO, "EAP-GPSK: Unexpected opcode=%d in state=%d",
*pos, data->state);
- return TRUE;
+ return true;
}
@@ -294,8 +294,8 @@
eap_gpsk_state(data, FAILURE);
return;
}
- if (alen != sm->server_id_len ||
- os_memcmp(pos, sm->server_id, alen) != 0) {
+ if (alen != sm->cfg->server_id_len ||
+ os_memcmp(pos, sm->cfg->server_id, alen) != 0) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and "
"GPSK-2 did not match");
eap_gpsk_state(data, FAILURE);
@@ -379,7 +379,7 @@
data->specifier = WPA_GET_BE16(csuite->specifier);
wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel %d:%d",
data->vendor, data->specifier);
- pos += sizeof(*csuite);
+ pos += sizeof(*csuite);
if (end - pos < 2) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
@@ -409,7 +409,7 @@
data->vendor, data->specifier,
data->rand_peer, data->rand_server,
data->id_peer, data->id_peer_len,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->msk, data->emsk,
data->sk, &data->sk_len,
data->pk, &data->pk_len) < 0) {
@@ -423,7 +423,8 @@
data->vendor, data->specifier,
data->rand_peer, data->rand_server,
data->id_peer, data->id_peer_len,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id,
+ sm->cfg->server_id_len,
EAP_TYPE_GPSK,
data->session_id, &data->id_len) < 0) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
@@ -559,7 +560,7 @@
}
-static Boolean eap_gpsk_isDone(struct eap_sm *sm, void *priv)
+static bool eap_gpsk_isDone(struct eap_sm *sm, void *priv)
{
struct eap_gpsk_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -600,7 +601,7 @@
}
-static Boolean eap_gpsk_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_gpsk_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_gpsk_data *data = priv;
return data->state == SUCCESS;
diff --git a/src/eap_server/eap_server_gtc.c b/src/eap_server/eap_server_gtc.c
index fcccbcb..6310793 100644
--- a/src/eap_server/eap_server_gtc.c
+++ b/src/eap_server/eap_server_gtc.c
@@ -74,8 +74,8 @@
}
-static Boolean eap_gtc_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_gtc_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
const u8 *pos;
size_t len;
@@ -83,10 +83,10 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-GTC: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -184,14 +184,14 @@
}
-static Boolean eap_gtc_isDone(struct eap_sm *sm, void *priv)
+static bool eap_gtc_isDone(struct eap_sm *sm, void *priv)
{
struct eap_gtc_data *data = priv;
return data->state != CONTINUE;
}
-static Boolean eap_gtc_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_gtc_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_gtc_data *data = priv;
return data->state == SUCCESS;
diff --git a/src/eap_server/eap_server_identity.c b/src/eap_server/eap_server_identity.c
index 1b1db53..813e1d6 100644
--- a/src/eap_server/eap_server_identity.c
+++ b/src/eap_server/eap_server_identity.c
@@ -79,8 +79,8 @@
}
-static Boolean eap_identity_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_identity_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
const u8 *pos;
size_t len;
@@ -89,10 +89,10 @@
respData, &len);
if (pos == NULL) {
wpa_printf(MSG_INFO, "EAP-Identity: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -127,7 +127,7 @@
os_free(buf);
}
if (sm->identity)
- sm->update_user = TRUE;
+ sm->update_user = true;
os_free(sm->identity);
sm->identity = os_malloc(len ? len : 1);
if (sm->identity == NULL) {
@@ -140,14 +140,14 @@
}
-static Boolean eap_identity_isDone(struct eap_sm *sm, void *priv)
+static bool eap_identity_isDone(struct eap_sm *sm, void *priv)
{
struct eap_identity_data *data = priv;
return data->state != CONTINUE;
}
-static Boolean eap_identity_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_identity_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_identity_data *data = priv;
return data->state == SUCCESS;
diff --git a/src/eap_server/eap_server_ikev2.c b/src/eap_server/eap_server_ikev2.c
index 32e6872..ef3cc8c 100644
--- a/src/eap_server/eap_server_ikev2.c
+++ b/src/eap_server/eap_server_ikev2.c
@@ -87,8 +87,8 @@
if (data == NULL)
return NULL;
data->state = MSG;
- data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size :
- IKEV2_FRAGMENT_SIZE;
+ data->fragment_size = sm->cfg->fragment_size > 0 ?
+ sm->cfg->fragment_size : IKEV2_FRAGMENT_SIZE;
data->ikev2.state = SA_INIT;
data->ikev2.peer_auth = PEER_AUTH_SECRET;
data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2");
@@ -103,10 +103,10 @@
data->ikev2.proposal.encr = ENCR_AES_CBC;
data->ikev2.proposal.dh = DH_GROUP2_1024BIT_MODP;
- data->ikev2.IDi = os_memdup(sm->server_id, sm->server_id_len);
+ data->ikev2.IDi = os_memdup(sm->cfg->server_id, sm->cfg->server_id_len);
if (data->ikev2.IDi == NULL)
goto failed;
- data->ikev2.IDi_len = sm->server_id_len;
+ data->ikev2.IDi_len = sm->cfg->server_id_len;
data->ikev2.get_shared_secret = eap_ikev2_get_shared_secret;
data->ikev2.cb_ctx = sm;
@@ -236,8 +236,8 @@
}
-static Boolean eap_ikev2_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_ikev2_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
const u8 *pos;
size_t len;
@@ -246,10 +246,10 @@
&len);
if (pos == NULL) {
wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -414,7 +414,7 @@
eap_ikev2_state(data, FAIL);
return;
}
-
+
if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) {
if (eap_ikev2_process_fragment(data, flags, message_length,
pos, end - pos) < 0)
@@ -465,14 +465,14 @@
}
-static Boolean eap_ikev2_isDone(struct eap_sm *sm, void *priv)
+static bool eap_ikev2_isDone(struct eap_sm *sm, void *priv)
{
struct eap_ikev2_data *data = priv;
return data->state == DONE || data->state == FAIL;
}
-static Boolean eap_ikev2_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_ikev2_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_ikev2_data *data = priv;
return data->state == DONE && data->ikev2.state == IKEV2_DONE &&
diff --git a/src/eap_server/eap_server_md5.c b/src/eap_server/eap_server_md5.c
index cf5ceb1..c9b500c 100644
--- a/src/eap_server/eap_server_md5.c
+++ b/src/eap_server/eap_server_md5.c
@@ -73,8 +73,8 @@
}
-static Boolean eap_md5_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_md5_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
const u8 *pos;
size_t len;
@@ -82,16 +82,16 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame");
- return TRUE;
+ return true;
}
if (*pos != CHAP_MD5_LEN || 1 + CHAP_MD5_LEN > len) {
wpa_printf(MSG_INFO, "EAP-MD5: Invalid response "
"(response_len=%d payload_len=%lu",
*pos, (unsigned long) len);
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -136,14 +136,14 @@
}
-static Boolean eap_md5_isDone(struct eap_sm *sm, void *priv)
+static bool eap_md5_isDone(struct eap_sm *sm, void *priv)
{
struct eap_md5_data *data = priv;
return data->state != CONTINUE;
}
-static Boolean eap_md5_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_md5_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_md5_data *data = priv;
return data->state == SUCCESS;
diff --git a/src/eap_server/eap_server_methods.c b/src/eap_server/eap_server_methods.c
index 79ed344..f37c9c3 100644
--- a/src/eap_server/eap_server_methods.c
+++ b/src/eap_server/eap_server_methods.c
@@ -22,7 +22,8 @@
* @method: EAP type number
* Returns: Pointer to EAP method or %NULL if not found
*/
-const struct eap_method * eap_server_get_eap_method(int vendor, EapType method)
+const struct eap_method * eap_server_get_eap_method(int vendor,
+ enum eap_type method)
{
struct eap_method *m;
for (m = eap_methods; m; m = m->next) {
@@ -42,7 +43,7 @@
* This function maps EAP type names into EAP type numbers based on the list of
* EAP methods included in the build.
*/
-EapType eap_server_get_type(const char *name, int *vendor)
+enum eap_type eap_server_get_type(const char *name, int *vendor)
{
struct eap_method *m;
for (m = eap_methods; m; m = m->next) {
@@ -69,7 +70,8 @@
* is not needed anymore.
*/
struct eap_method * eap_server_method_alloc(int version, int vendor,
- EapType method, const char *name)
+ enum eap_type method,
+ const char *name)
{
struct eap_method *eap;
eap = os_zalloc(sizeof(*eap));
@@ -163,7 +165,7 @@
* This function maps EAP type numbers into EAP type names based on the list of
* EAP methods included in the build.
*/
-const char * eap_server_get_name(int vendor, EapType type)
+const char * eap_server_get_name(int vendor, enum eap_type type)
{
struct eap_method *m;
if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c
index e9e03b0..9b3eb26 100644
--- a/src/eap_server/eap_server_mschapv2.c
+++ b/src/eap_server/eap_server_mschapv2.c
@@ -109,7 +109,7 @@
return NULL;
}
- ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + sm->server_id_len;
+ ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + sm->cfg->server_id_len;
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
EAP_CODE_REQUEST, id);
if (req == NULL) {
@@ -131,7 +131,7 @@
wpabuf_put(req, CHALLENGE_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge",
data->auth_challenge, CHALLENGE_LEN);
- wpabuf_put_data(req, sm->server_id, sm->server_id_len);
+ wpabuf_put_data(req, sm->cfg->server_id, sm->cfg->server_id_len);
return req;
}
@@ -235,8 +235,8 @@
}
-static Boolean eap_mschapv2_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_mschapv2_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
struct eap_mschapv2_data *data = priv;
struct eap_mschapv2_hdr *resp;
@@ -247,7 +247,7 @@
&len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid frame");
- return TRUE;
+ return true;
}
resp = (struct eap_mschapv2_hdr *) pos;
@@ -255,7 +255,7 @@
resp->op_code != MSCHAPV2_OP_RESPONSE) {
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Response - "
"ignore op %d", resp->op_code);
- return TRUE;
+ return true;
}
if (data->state == SUCCESS_REQ &&
@@ -263,17 +263,17 @@
resp->op_code != MSCHAPV2_OP_FAILURE) {
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Success or "
"Failure - ignore op %d", resp->op_code);
- return TRUE;
+ return true;
}
if (data->state == FAILURE_REQ &&
resp->op_code != MSCHAPV2_OP_FAILURE) {
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Failure "
"- ignore op %d", resp->op_code);
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -531,7 +531,7 @@
}
-static Boolean eap_mschapv2_isDone(struct eap_sm *sm, void *priv)
+static bool eap_mschapv2_isDone(struct eap_sm *sm, void *priv)
{
struct eap_mschapv2_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -564,7 +564,7 @@
}
-static Boolean eap_mschapv2_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_mschapv2_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_mschapv2_data *data = priv;
return data->state == SUCCESS;
diff --git a/src/eap_server/eap_server_pax.c b/src/eap_server/eap_server_pax.c
index 3257789..fb089d5 100644
--- a/src/eap_server/eap_server_pax.c
+++ b/src/eap_server/eap_server_pax.c
@@ -107,9 +107,14 @@
data->rand.r.x, EAP_PAX_RAND_LEN);
pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
- eap_pax_mac(data->mac_id, (u8 *) "", 0,
- wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN,
- NULL, 0, NULL, 0, pos);
+ if (eap_pax_mac(data->mac_id, (u8 *) "", 0,
+ wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN,
+ NULL, 0, NULL, 0, pos) < 0) {
+ wpa_printf(MSG_ERROR, "EAP-PAX: Failed to calculate ICV");
+ data->state = FAILURE;
+ wpabuf_free(req);
+ return NULL;
+ }
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
return req;
@@ -144,18 +149,28 @@
wpabuf_put_be16(req, EAP_PAX_MAC_LEN);
pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
- eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
- data->rand.r.y, EAP_PAX_RAND_LEN,
- (u8 *) data->cid, data->cid_len, NULL, 0, pos);
+ if (eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
+ data->rand.r.y, EAP_PAX_RAND_LEN,
+ (u8 *) data->cid, data->cid_len, NULL, 0, pos) < 0) {
+ wpa_printf(MSG_ERROR, "EAP-PAX: Failed to calculate MAC");
+ data->state = FAILURE;
+ wpabuf_free(req);
+ return NULL;
+ }
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)",
pos, EAP_PAX_MAC_LEN);
/* Optional ADE could be added here, if needed */
pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
- eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
- wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN,
- NULL, 0, NULL, 0, pos);
+ if (eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
+ wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN,
+ NULL, 0, NULL, 0, pos) < 0) {
+ wpa_printf(MSG_ERROR, "EAP-PAX: Failed to calculate ICV");
+ data->state = FAILURE;
+ wpabuf_free(req);
+ return NULL;
+ }
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
return req;
@@ -180,8 +195,8 @@
}
-static Boolean eap_pax_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_pax_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
struct eap_pax_data *data = priv;
struct eap_pax_hdr *resp;
@@ -190,9 +205,9 @@
u8 icvbuf[EAP_PAX_ICV_LEN], *icv;
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len);
- if (pos == NULL || len < sizeof(*resp)) {
+ if (pos == NULL || len < sizeof(*resp) + EAP_PAX_ICV_LEN) {
wpa_printf(MSG_INFO, "EAP-PAX: Invalid frame");
- return TRUE;
+ return true;
}
mlen = sizeof(struct eap_hdr) + 1 + len;
@@ -210,14 +225,14 @@
resp->op_code != EAP_PAX_OP_STD_2) {
wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX_STD-2 - "
"ignore op %d", resp->op_code);
- return TRUE;
+ return true;
}
if (data->state == PAX_STD_3 &&
resp->op_code != EAP_PAX_OP_ACK) {
wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX-ACK - "
"ignore op %d", resp->op_code);
- return TRUE;
+ return true;
}
if (resp->op_code != EAP_PAX_OP_STD_2 &&
@@ -229,54 +244,59 @@
if (data->mac_id != resp->mac_id) {
wpa_printf(MSG_DEBUG, "EAP-PAX: Expected MAC ID 0x%x, "
"received 0x%x", data->mac_id, resp->mac_id);
- return TRUE;
+ return true;
}
if (resp->dh_group_id != EAP_PAX_DH_GROUP_NONE) {
wpa_printf(MSG_INFO, "EAP-PAX: Expected DH Group ID 0x%x, "
"received 0x%x", EAP_PAX_DH_GROUP_NONE,
resp->dh_group_id);
- return TRUE;
+ return true;
}
if (resp->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) {
wpa_printf(MSG_INFO, "EAP-PAX: Expected Public Key ID 0x%x, "
"received 0x%x", EAP_PAX_PUBLIC_KEY_NONE,
resp->public_key_id);
- return TRUE;
+ return true;
}
if (resp->flags & EAP_PAX_FLAGS_MF) {
/* TODO: add support for reassembling fragments */
wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported");
- return TRUE;
+ return true;
}
if (resp->flags & EAP_PAX_FLAGS_CE) {
wpa_printf(MSG_INFO, "EAP-PAX: Unexpected CE flag");
- return TRUE;
+ return true;
}
if (data->keys_set) {
if (len - sizeof(*resp) < EAP_PAX_ICV_LEN) {
wpa_printf(MSG_INFO, "EAP-PAX: No ICV in the packet");
- return TRUE;
+ return true;
}
icv = wpabuf_mhead_u8(respData) + mlen - EAP_PAX_ICV_LEN;
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", icv, EAP_PAX_ICV_LEN);
- eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
- wpabuf_mhead(respData),
- wpabuf_len(respData) - EAP_PAX_ICV_LEN,
- NULL, 0, NULL, 0, icvbuf);
+ if (eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
+ wpabuf_mhead(respData),
+ wpabuf_len(respData) - EAP_PAX_ICV_LEN,
+ NULL, 0, NULL, 0, icvbuf) < 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-PAX: Failed to calculate ICV");
+ return true;
+ }
+
if (os_memcmp_const(icvbuf, icv, EAP_PAX_ICV_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV");
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV",
icvbuf, EAP_PAX_ICV_LEN);
- return TRUE;
+ return true;
}
}
- return FALSE;
+ return false;
}
@@ -395,10 +415,15 @@
}
data->keys_set = 1;
- eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
- data->rand.r.x, EAP_PAX_RAND_LEN,
- data->rand.r.y, EAP_PAX_RAND_LEN,
- (u8 *) data->cid, data->cid_len, mac);
+ if (eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
+ data->rand.r.x, EAP_PAX_RAND_LEN,
+ data->rand.r.y, EAP_PAX_RAND_LEN,
+ (u8 *) data->cid, data->cid_len, mac) < 0) {
+ wpa_printf(MSG_INFO, "EAP-PAX: Failed to calculate MAC_CK");
+ data->state = FAILURE;
+ return;
+ }
+
if (os_memcmp_const(mac, pos, EAP_PAX_MAC_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(A, B, CID) in "
"PAX_STD-2");
@@ -417,10 +442,14 @@
return;
}
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
- eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
- wpabuf_head(respData),
- wpabuf_len(respData) - EAP_PAX_ICV_LEN, NULL, 0, NULL, 0,
- icvbuf);
+ if (eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
+ wpabuf_head(respData),
+ wpabuf_len(respData) - EAP_PAX_ICV_LEN, NULL, 0,
+ NULL, 0, icvbuf) < 0) {
+ wpa_printf(MSG_INFO, "EAP-PAX: Failed to calculate ICV");
+ return;
+ }
+
if (os_memcmp_const(icvbuf, pos, EAP_PAX_ICV_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV in PAX_STD-2");
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV",
@@ -484,7 +513,7 @@
}
-static Boolean eap_pax_isDone(struct eap_sm *sm, void *priv)
+static bool eap_pax_isDone(struct eap_sm *sm, void *priv)
{
struct eap_pax_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -534,7 +563,7 @@
}
-static Boolean eap_pax_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_pax_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_pax_data *data = priv;
return data->state == SUCCESS;
diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c
index 92c0e5e..f234f6f 100644
--- a/src/eap_server/eap_server_peap.c
+++ b/src/eap_server/eap_server_peap.c
@@ -105,8 +105,8 @@
{
struct wpabuf *buf;
- if (!sm->tls_session_lifetime ||
- tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+ if (!sm->cfg->tls_session_lifetime ||
+ tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn))
return;
buf = wpabuf_alloc(1 + 1 + sm->identity_len);
@@ -336,7 +336,7 @@
return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
- if (tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) {
+ if (tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn)) {
/* Fast-connect: IPMK|CMK = TK */
os_memcpy(data->ipmk, tk, 40);
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK",
@@ -362,7 +362,7 @@
res = peap_prfplus(data->peap_version, tk, 40,
"Inner Methods Compound Keys",
isk, sizeof(isk), imck, sizeof(imck));
- os_memset(isk, 0, sizeof(isk));
+ forced_memzero(isk, sizeof(isk));
if (res < 0) {
os_free(tk);
return -1;
@@ -376,7 +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));
+ forced_memzero(imck, sizeof(imck));
return 0;
}
@@ -521,7 +521,8 @@
return eap_peap_build_start(sm, data, id);
case PHASE1:
case PHASE1_ID2:
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ if (tls_connection_established(sm->cfg->ssl_ctx,
+ data->ssl.conn)) {
wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
"starting Phase2");
eap_peap_state(data, PHASE2_START);
@@ -568,8 +569,8 @@
}
-static Boolean eap_peap_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_peap_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
const u8 *pos;
size_t len;
@@ -577,15 +578,15 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PEAP, respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
- int vendor, EapType eap_type)
+ int vendor, enum eap_type eap_type)
{
if (data->phase2_priv && data->phase2_method) {
data->phase2_method->reset(sm, data->phase2_priv);
@@ -1020,7 +1021,7 @@
}
#ifdef EAP_SERVER_TNC
- if (data->state != PHASE2_SOH && sm->tnc &&
+ if (data->state != PHASE2_SOH && sm->cfg->tnc &&
data->peap_version == 0) {
eap_peap_state(data, PHASE2_SOH);
wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize "
@@ -1077,7 +1078,7 @@
return;
}
- in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ in_decrypted = tls_connection_decrypt(sm->cfg->ssl_ctx, data->ssl.conn,
in_buf);
if (in_decrypted == NULL) {
wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
@@ -1237,8 +1238,8 @@
}
if (data->state == SUCCESS ||
- !tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
- !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+ !tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
+ !tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn))
return;
buf = tls_connection_get_success_data(data->ssl.conn);
@@ -1288,7 +1289,7 @@
}
-static Boolean eap_peap_isDone(struct eap_sm *sm, void *priv)
+static bool eap_peap_isDone(struct eap_sm *sm, void *priv)
{
struct eap_peap_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -1326,7 +1327,7 @@
"key");
}
- os_memset(csk, 0, sizeof(csk));
+ forced_memzero(csk, sizeof(csk));
return eapKeyData;
}
@@ -1382,7 +1383,7 @@
}
-static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_peap_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_peap_data *data = priv;
return data->state == SUCCESS;
diff --git a/src/eap_server/eap_server_psk.c b/src/eap_server/eap_server_psk.c
index 0eab893..f55f70d 100644
--- a/src/eap_server/eap_server_psk.c
+++ b/src/eap_server/eap_server_psk.c
@@ -68,7 +68,7 @@
data->rand_s, EAP_PSK_RAND_LEN);
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK,
- sizeof(*psk) + sm->server_id_len,
+ sizeof(*psk) + sm->cfg->server_id_len,
EAP_CODE_REQUEST, id);
if (req == NULL) {
wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory "
@@ -80,7 +80,7 @@
psk = wpabuf_put(req, sizeof(*psk));
psk->flags = EAP_PSK_FLAGS_SET_T(0); /* T=0 */
os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
- wpabuf_put_data(req, sm->server_id, sm->server_id_len);
+ wpabuf_put_data(req, sm->cfg->server_id, sm->cfg->server_id_len);
return req;
}
@@ -110,13 +110,13 @@
os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
/* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
- buflen = sm->server_id_len + EAP_PSK_RAND_LEN;
+ buflen = sm->cfg->server_id_len + EAP_PSK_RAND_LEN;
buf = os_malloc(buflen);
if (buf == NULL)
goto fail;
- os_memcpy(buf, sm->server_id, sm->server_id_len);
- os_memcpy(buf + sm->server_id_len, data->rand_p, EAP_PSK_RAND_LEN);
+ os_memcpy(buf, sm->cfg->server_id, sm->cfg->server_id_len);
+ os_memcpy(buf + sm->cfg->server_id_len, data->rand_p, EAP_PSK_RAND_LEN);
if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) {
os_free(buf);
goto fail;
@@ -171,8 +171,8 @@
}
-static Boolean eap_psk_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_psk_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
struct eap_psk_data *data = priv;
size_t len;
@@ -182,7 +182,7 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame");
- return TRUE;
+ return true;
}
t = EAP_PSK_FLAGS_GET_T(*pos);
@@ -191,22 +191,22 @@
if (data->state == PSK_1 && t != 1) {
wpa_printf(MSG_DEBUG, "EAP-PSK: Expected PSK-2 - "
"ignore T=%d", t);
- return TRUE;
+ return true;
}
if (data->state == PSK_3 && t != 3) {
wpa_printf(MSG_DEBUG, "EAP-PSK: Expected PSK-4 - "
"ignore T=%d", t);
- return TRUE;
+ return true;
}
if ((t == 1 && len < sizeof(struct eap_psk_hdr_2)) ||
(t == 3 && len < sizeof(struct eap_psk_hdr_4))) {
wpa_printf(MSG_DEBUG, "EAP-PSK: Too short frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -293,7 +293,7 @@
os_memcpy(data->rand_p, resp->rand_p, EAP_PSK_RAND_LEN);
/* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
- buflen = data->id_p_len + sm->server_id_len + 2 * EAP_PSK_RAND_LEN;
+ buflen = data->id_p_len + sm->cfg->server_id_len + 2 * EAP_PSK_RAND_LEN;
buf = os_malloc(buflen);
if (buf == NULL) {
data->state = FAILURE;
@@ -301,8 +301,8 @@
}
os_memcpy(buf, data->id_p, data->id_p_len);
pos = buf + data->id_p_len;
- os_memcpy(pos, sm->server_id, sm->server_id_len);
- pos += sm->server_id_len;
+ os_memcpy(pos, sm->cfg->server_id, sm->cfg->server_id_len);
+ pos += sm->cfg->server_id_len;
os_memcpy(pos, data->rand_s, EAP_PSK_RAND_LEN);
pos += EAP_PSK_RAND_LEN;
os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
@@ -433,7 +433,7 @@
}
-static Boolean eap_psk_isDone(struct eap_sm *sm, void *priv)
+static bool eap_psk_isDone(struct eap_sm *sm, void *priv)
{
struct eap_psk_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -474,7 +474,7 @@
}
-static Boolean eap_psk_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_psk_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_psk_data *data = priv;
return data->state == SUCCESS;
diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
index e720a28..81cddca 100644
--- a/src/eap_server/eap_server_pwd.c
+++ b/src/eap_server/eap_server_pwd.c
@@ -97,7 +97,7 @@
if (data == NULL)
return NULL;
- data->group_num = sm->pwd_group;
+ data->group_num = sm->cfg->pwd_group;
wpa_printf(MSG_DEBUG, "EAP-pwd: Selected group number %d",
data->group_num);
data->state = PWD_ID_Req;
@@ -134,7 +134,7 @@
data->in_frag_pos = data->out_frag_pos = 0;
data->inbuf = data->outbuf = NULL;
/* use default MTU from RFC 5931 if not configured otherwise */
- data->mtu = sm->fragment_size > 0 ? sm->fragment_size : 1020;
+ data->mtu = sm->cfg->fragment_size > 0 ? sm->cfg->fragment_size : 1020;
return data;
}
@@ -530,8 +530,8 @@
}
-static Boolean eap_pwd_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_pwd_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
struct eap_pwd_data *data = priv;
const u8 *pos;
@@ -540,7 +540,7 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-pwd: Invalid frame");
- return TRUE;
+ return true;
}
wpa_printf(MSG_DEBUG, "EAP-pwd: Received frame: exch = %d, len = %d",
@@ -548,20 +548,20 @@
if (data->state == PWD_ID_Req &&
((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_ID_EXCH))
- return FALSE;
+ return false;
if (data->state == PWD_Commit_Req &&
((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_COMMIT_EXCH))
- return FALSE;
+ return false;
if (data->state == PWD_Confirm_Req &&
((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_CONFIRM_EXCH))
- return FALSE;
+ return false;
wpa_printf(MSG_INFO, "EAP-pwd: Unexpected opcode=%d in state=%d",
*pos, data->state);
- return TRUE;
+ return true;
}
@@ -632,7 +632,7 @@
data->id_server, data->id_server_len,
data->id_peer, data->id_peer_len,
(u8 *) &data->token);
- os_memset(pwhashhash, 0, sizeof(pwhashhash));
+ forced_memzero(pwhashhash, sizeof(pwhashhash));
if (res) {
wpa_printf(MSG_INFO, "EAP-PWD (server): unable to compute "
"PWE");
@@ -1003,14 +1003,14 @@
}
-static Boolean eap_pwd_is_success(struct eap_sm *sm, void *priv)
+static bool eap_pwd_is_success(struct eap_sm *sm, void *priv)
{
struct eap_pwd_data *data = priv;
return data->state == SUCCESS;
}
-static Boolean eap_pwd_is_done(struct eap_sm *sm, void *priv)
+static bool eap_pwd_is_done(struct eap_sm *sm, void *priv)
{
struct eap_pwd_data *data = priv;
return (data->state == SUCCESS) || (data->state == FAILURE);
diff --git a/src/eap_server/eap_server_sake.c b/src/eap_server/eap_server_sake.c
index 66183f5..8c39e63 100644
--- a/src/eap_server/eap_server_sake.c
+++ b/src/eap_server/eap_server_sake.c
@@ -123,7 +123,7 @@
wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity");
plen = 4;
- plen += 2 + sm->server_id_len;
+ plen += 2 + sm->cfg->server_id_len;
msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_IDENTITY);
if (msg == NULL) {
data->state = FAILURE;
@@ -135,7 +135,7 @@
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
- sm->server_id, sm->server_id_len);
+ sm->cfg->server_id, sm->cfg->server_id_len);
return msg;
}
@@ -158,7 +158,7 @@
wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
data->rand_s, EAP_SAKE_RAND_LEN);
- plen = 2 + EAP_SAKE_RAND_LEN + 2 + sm->server_id_len;
+ plen = 2 + EAP_SAKE_RAND_LEN + 2 + sm->cfg->server_id_len;
msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_CHALLENGE);
if (msg == NULL) {
data->state = FAILURE;
@@ -171,7 +171,7 @@
wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
- sm->server_id, sm->server_id_len);
+ sm->cfg->server_id, sm->cfg->server_id_len);
return msg;
}
@@ -198,13 +198,13 @@
wpabuf_put_u8(msg, 2 + EAP_SAKE_MIC_LEN);
mic = wpabuf_put(msg, EAP_SAKE_MIC_LEN);
if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
- sm->server_id, sm->server_id_len,
+ sm->cfg->server_id, sm->cfg->server_id_len,
data->peerid, data->peerid_len, 0,
wpabuf_head(msg), wpabuf_len(msg), mic, mic))
{
wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
data->state = FAILURE;
- os_free(msg);
+ wpabuf_free(msg);
return NULL;
}
@@ -232,8 +232,8 @@
}
-static Boolean eap_sake_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_sake_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
struct eap_sake_data *data = priv;
struct eap_sake_hdr *resp;
@@ -244,7 +244,7 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
wpa_printf(MSG_INFO, "EAP-SAKE: Invalid frame");
- return TRUE;
+ return true;
}
resp = (struct eap_sake_hdr *) pos;
@@ -254,33 +254,33 @@
if (version != EAP_SAKE_VERSION) {
wpa_printf(MSG_INFO, "EAP-SAKE: Unknown version %d", version);
- return TRUE;
+ return true;
}
if (session_id != data->session_id) {
wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
session_id, data->session_id);
- return TRUE;
+ return true;
}
wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype=%d", subtype);
if (data->state == IDENTITY && subtype == EAP_SAKE_SUBTYPE_IDENTITY)
- return FALSE;
+ return false;
if (data->state == CHALLENGE && subtype == EAP_SAKE_SUBTYPE_CHALLENGE)
- return FALSE;
+ return false;
if (data->state == CONFIRM && subtype == EAP_SAKE_SUBTYPE_CONFIRM)
- return FALSE;
+ return false;
if (subtype == EAP_SAKE_SUBTYPE_AUTH_REJECT)
- return FALSE;
+ return false;
wpa_printf(MSG_INFO, "EAP-SAKE: Unexpected subtype=%d in state=%d",
subtype, data->state);
- return TRUE;
+ return true;
}
@@ -340,16 +340,25 @@
data->state = FAILURE;
return;
}
- eap_sake_derive_keys(sm->user->password,
- sm->user->password + EAP_SAKE_ROOT_SECRET_LEN,
- data->rand_s, data->rand_p,
- (u8 *) &data->tek, data->msk, data->emsk);
+ if (eap_sake_derive_keys(sm->user->password,
+ sm->user->password + EAP_SAKE_ROOT_SECRET_LEN,
+ data->rand_s, data->rand_p,
+ (u8 *) &data->tek, data->msk,
+ data->emsk) < 0) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Failed to derive keys");
+ data->state = FAILURE;
+ return;
+ }
- eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
- sm->server_id, sm->server_id_len,
- data->peerid, data->peerid_len, 1,
- wpabuf_head(respData), wpabuf_len(respData),
- attr.mic_p, mic_p);
+ if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
+ sm->cfg->server_id, sm->cfg->server_id_len,
+ data->peerid, data->peerid_len, 1,
+ wpabuf_head(respData), wpabuf_len(respData),
+ attr.mic_p, mic_p) < 0) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
+ data->state = FAILURE;
+ return;
+ }
if (os_memcmp_const(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
eap_sake_state(data, FAILURE);
@@ -382,11 +391,14 @@
return;
}
- eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
- sm->server_id, sm->server_id_len,
- data->peerid, data->peerid_len, 1,
- wpabuf_head(respData), wpabuf_len(respData),
- attr.mic_p, mic_p);
+ if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
+ sm->cfg->server_id, sm->cfg->server_id_len,
+ data->peerid, data->peerid_len, 1,
+ wpabuf_head(respData), wpabuf_len(respData),
+ attr.mic_p, mic_p) < 0) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
+ return;
+ }
if (os_memcmp_const(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
eap_sake_state(data, FAILURE);
@@ -444,7 +456,7 @@
}
-static Boolean eap_sake_isDone(struct eap_sm *sm, void *priv)
+static bool eap_sake_isDone(struct eap_sm *sm, void *priv)
{
struct eap_sake_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -485,7 +497,7 @@
}
-static Boolean eap_sake_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_sake_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_sake_data *data = priv;
return data->state == SUCCESS;
diff --git a/src/eap_server/eap_server_sim.c b/src/eap_server/eap_server_sim.c
index 1287827..8a68289 100644
--- a/src/eap_server/eap_server_sim.c
+++ b/src/eap_server/eap_server_sim.c
@@ -26,6 +26,7 @@
u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
+ u8 reauth_mac[EAP_SIM_MAC_LEN];
int num_chal;
enum {
START, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
@@ -75,7 +76,7 @@
{
struct eap_sim_data *data;
- if (sm->eap_sim_db_priv == NULL) {
+ if (!sm->cfg->eap_sim_db_priv) {
wpa_printf(MSG_WARNING, "EAP-SIM: eap_sim_db not configured");
return NULL;
}
@@ -149,18 +150,24 @@
const u8 *nonce_s)
{
os_free(data->next_pseudonym);
- if (nonce_s == NULL) {
+ if (!(sm->cfg->eap_sim_id & 0x01)) {
+ /* Use of pseudonyms disabled in configuration */
+ data->next_pseudonym = NULL;
+ } else if (!nonce_s) {
data->next_pseudonym =
- eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv,
+ eap_sim_db_get_next_pseudonym(sm->cfg->eap_sim_db_priv,
EAP_SIM_DB_SIM);
} else {
/* Do not update pseudonym during re-authentication */
data->next_pseudonym = NULL;
}
os_free(data->next_reauth_id);
- if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) {
+ if (!(sm->cfg->eap_sim_id & 0x02)) {
+ /* Use of fast reauth disabled in configuration */
+ data->next_reauth_id = NULL;
+ } else if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) {
data->next_reauth_id =
- eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv,
+ eap_sim_db_get_next_reauth_id(sm->cfg->eap_sim_db_priv,
EAP_SIM_DB_SIM);
} else {
wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication "
@@ -233,7 +240,7 @@
return NULL;
}
- if (sm->eap_sim_aka_result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind) {
wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
}
@@ -249,6 +256,7 @@
struct eap_sim_data *data, u8 id)
{
struct eap_sim_msg *msg;
+ struct wpabuf *buf;
wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Re-authentication");
@@ -271,14 +279,23 @@
return NULL;
}
- if (sm->eap_sim_aka_result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind) {
wpa_printf(MSG_DEBUG, " AT_RESULT_IND");
eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
}
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
- return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, NULL, 0);
+ buf = eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, NULL, 0);
+
+ /* Remember this MAC before sending it to the peer. This MAC is used for
+ * Session-Id calculation after receiving response from the peer and
+ * after all other checks pass. */
+ os_memcpy(data->reauth_mac,
+ wpabuf_head_u8(buf) + wpabuf_len(buf) - EAP_SIM_MAC_LEN,
+ EAP_SIM_MAC_LEN);
+
+ return buf;
}
@@ -343,8 +360,8 @@
}
-static Boolean eap_sim_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_sim_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
const u8 *pos;
size_t len;
@@ -352,55 +369,55 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len);
if (pos == NULL || len < 3) {
wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
-static Boolean eap_sim_unexpected_subtype(struct eap_sim_data *data,
- u8 subtype)
+static bool eap_sim_unexpected_subtype(struct eap_sim_data *data,
+ u8 subtype)
{
if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR)
- return FALSE;
+ return false;
switch (data->state) {
case START:
if (subtype != EAP_SIM_SUBTYPE_START) {
wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
"subtype %d", subtype);
- return TRUE;
+ return true;
}
break;
case CHALLENGE:
if (subtype != EAP_SIM_SUBTYPE_CHALLENGE) {
wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
"subtype %d", subtype);
- return TRUE;
+ return true;
}
break;
case REAUTH:
if (subtype != EAP_SIM_SUBTYPE_REAUTHENTICATION) {
wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
"subtype %d", subtype);
- return TRUE;
+ return true;
}
break;
case NOTIFICATION:
if (subtype != EAP_SIM_SUBTYPE_NOTIFICATION) {
wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
"subtype %d", subtype);
- return TRUE;
+ return true;
}
break;
default:
wpa_printf(MSG_INFO, "EAP-SIM: Unexpected state (%d) for "
"processing a response", data->state);
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -458,7 +475,7 @@
wpa_printf(MSG_DEBUG, "EAP-SIM: Reauth username '%s'",
username);
data->reauth = eap_sim_db_get_reauth_entry(
- sm->eap_sim_db_priv, username);
+ sm->cfg->eap_sim_db_priv, username);
os_free(username);
if (data->reauth == NULL) {
wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown reauth "
@@ -480,7 +497,7 @@
wpa_printf(MSG_DEBUG, "EAP-SIM: Pseudonym username '%s'",
username);
permanent = eap_sim_db_get_permanent(
- sm->eap_sim_db_priv, username);
+ sm->cfg->eap_sim_db_priv, username);
os_free(username);
if (permanent == NULL) {
wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown pseudonym "
@@ -521,7 +538,7 @@
data->reauth = NULL;
data->num_chal = eap_sim_db_get_gsm_triplets(
- sm->eap_sim_db_priv, data->permanent, EAP_SIM_MAX_CHAL,
+ sm->cfg->eap_sim_db_priv, data->permanent, EAP_SIM_MAX_CHAL,
(u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm);
if (data->num_chal == EAP_SIM_DB_PENDING) {
wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets "
@@ -582,7 +599,7 @@
wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the "
"correct AT_MAC");
- if (sm->eap_sim_aka_result_ind && attr->result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
data->use_result_ind = 1;
data->notification = EAP_SIM_SUCCESS;
eap_sim_state(data, NOTIFICATION);
@@ -590,12 +607,13 @@
eap_sim_state(data, SUCCESS);
if (data->next_pseudonym) {
- eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
+ eap_sim_db_add_pseudonym(sm->cfg->eap_sim_db_priv,
+ data->permanent,
data->next_pseudonym);
data->next_pseudonym = NULL;
}
if (data->next_reauth_id) {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent,
+ eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv, data->permanent,
data->next_reauth_id, data->counter + 1,
data->mk);
data->next_reauth_id = NULL;
@@ -655,7 +673,7 @@
return;
}
- if (sm->eap_sim_aka_result_ind && attr->result_ind) {
+ if (sm->cfg->eap_sim_aka_result_ind && attr->result_ind) {
data->use_result_ind = 1;
data->notification = EAP_SIM_SUCCESS;
eap_sim_state(data, NOTIFICATION);
@@ -663,12 +681,13 @@
eap_sim_state(data, SUCCESS);
if (data->next_reauth_id) {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent,
+ eap_sim_db_add_reauth(sm->cfg->eap_sim_db_priv, data->permanent,
data->next_reauth_id,
data->counter + 1, data->mk);
data->next_reauth_id = NULL;
} else {
- eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+ eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv,
+ data->reauth);
data->reauth = NULL;
}
@@ -677,7 +696,7 @@
fail:
data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
eap_sim_state(data, NOTIFICATION);
- eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+ eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv, data->reauth);
data->reauth = NULL;
os_free(decrypted);
}
@@ -775,7 +794,7 @@
}
-static Boolean eap_sim_isDone(struct eap_sm *sm, void *priv)
+static bool eap_sim_isDone(struct eap_sm *sm, void *priv)
{
struct eap_sim_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -814,7 +833,7 @@
}
-static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_sim_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_sim_data *data = priv;
return data->state == SUCCESS;
@@ -829,15 +848,25 @@
if (data->state != SUCCESS)
return NULL;
- *len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN;
+ if (!data->reauth)
+ *len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN;
+ else
+ *len = 1 + EAP_SIM_NONCE_S_LEN + EAP_SIM_MAC_LEN;
id = os_malloc(*len);
if (id == NULL)
return NULL;
id[0] = EAP_TYPE_SIM;
- os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN);
- os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN, data->nonce_mt,
- EAP_SIM_NONCE_MT_LEN);
+ if (!data->reauth) {
+ os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN);
+ os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN,
+ data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
+ } else {
+ os_memcpy(id + 1, data->nonce_s, EAP_SIM_NONCE_S_LEN);
+ os_memcpy(id + 1 + EAP_SIM_NONCE_S_LEN, data->reauth_mac,
+ EAP_SIM_MAC_LEN);
+
+ }
wpa_hexdump(MSG_DEBUG, "EAP-SIM: Derived Session-Id", id, *len);
return id;
diff --git a/src/eap_server/eap_server_teap.c b/src/eap_server/eap_server_teap.c
new file mode 100644
index 0000000..d7b1b09
--- /dev/null
+++ b/src/eap_server/eap_server_teap.c
@@ -0,0 +1,2092 @@
+/*
+ * EAP-TEAP server (RFC 7170)
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/tls.h"
+#include "crypto/random.h"
+#include "eap_common/eap_teap_common.h"
+#include "eap_i.h"
+#include "eap_tls_common.h"
+
+
+static void eap_teap_reset(struct eap_sm *sm, void *priv);
+
+
+/* Private PAC-Opaque TLV types */
+#define PAC_OPAQUE_TYPE_PAD 0
+#define PAC_OPAQUE_TYPE_KEY 1
+#define PAC_OPAQUE_TYPE_LIFETIME 2
+#define PAC_OPAQUE_TYPE_IDENTITY 3
+
+struct eap_teap_data {
+ struct eap_ssl_data ssl;
+ enum {
+ START, PHASE1, PHASE1B, PHASE2_START, PHASE2_ID,
+ PHASE2_BASIC_AUTH, PHASE2_METHOD, CRYPTO_BINDING, REQUEST_PAC,
+ FAILURE_SEND_RESULT, SUCCESS_SEND_RESULT, SUCCESS, FAILURE
+ } state;
+
+ u8 teap_version;
+ u8 peer_version;
+ u16 tls_cs;
+
+ const struct eap_method *phase2_method;
+ void *phase2_priv;
+
+ u8 crypto_binding_nonce[32];
+ int final_result;
+
+ u8 simck_msk[EAP_TEAP_SIMCK_LEN];
+ u8 cmk_msk[EAP_TEAP_CMK_LEN];
+ u8 simck_emsk[EAP_TEAP_SIMCK_LEN];
+ u8 cmk_emsk[EAP_TEAP_CMK_LEN];
+ int simck_idx;
+ int cmk_emsk_available;
+
+ u8 pac_opaque_encr[16];
+ u8 *srv_id;
+ size_t srv_id_len;
+ char *srv_id_info;
+
+ unsigned int basic_auth_not_done:1;
+ unsigned int inner_eap_not_done:1;
+ int anon_provisioning;
+ int skipped_inner_auth;
+ int send_new_pac; /* server triggered re-keying of Tunnel PAC */
+ struct wpabuf *pending_phase2_resp;
+ struct wpabuf *server_outer_tlvs;
+ struct wpabuf *peer_outer_tlvs;
+ u8 *identity; /* from PAC-Opaque */
+ size_t identity_len;
+ int eap_seq;
+ int tnc_started;
+
+ int pac_key_lifetime;
+ int pac_key_refresh_time;
+
+ enum teap_error_codes error_code;
+ enum teap_identity_types cur_id_type;
+};
+
+
+static int eap_teap_process_phase2_start(struct eap_sm *sm,
+ struct eap_teap_data *data);
+
+
+static const char * eap_teap_state_txt(int state)
+{
+ switch (state) {
+ case START:
+ return "START";
+ case PHASE1:
+ return "PHASE1";
+ case PHASE1B:
+ return "PHASE1B";
+ case PHASE2_START:
+ return "PHASE2_START";
+ case PHASE2_ID:
+ return "PHASE2_ID";
+ case PHASE2_BASIC_AUTH:
+ return "PHASE2_BASIC_AUTH";
+ case PHASE2_METHOD:
+ return "PHASE2_METHOD";
+ case CRYPTO_BINDING:
+ return "CRYPTO_BINDING";
+ case REQUEST_PAC:
+ return "REQUEST_PAC";
+ case FAILURE_SEND_RESULT:
+ return "FAILURE_SEND_RESULT";
+ case SUCCESS_SEND_RESULT:
+ return "SUCCESS_SEND_RESULT";
+ case SUCCESS:
+ return "SUCCESS";
+ case FAILURE:
+ return "FAILURE";
+ default:
+ return "Unknown?!";
+ }
+}
+
+
+static void eap_teap_state(struct eap_teap_data *data, int state)
+{
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: %s -> %s",
+ eap_teap_state_txt(data->state),
+ eap_teap_state_txt(state));
+ data->state = state;
+}
+
+
+static enum eap_type eap_teap_req_failure(struct eap_teap_data *data,
+ enum teap_error_codes error)
+{
+ eap_teap_state(data, FAILURE_SEND_RESULT);
+ return EAP_TYPE_NONE;
+}
+
+
+static int eap_teap_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
+ const u8 *client_random,
+ const u8 *server_random,
+ u8 *master_secret)
+{
+ struct eap_teap_data *data = ctx;
+ const u8 *pac_opaque;
+ size_t pac_opaque_len;
+ u8 *buf, *pos, *end, *pac_key = NULL;
+ os_time_t lifetime = 0;
+ struct os_time now;
+ u8 *identity = NULL;
+ size_t identity_len = 0;
+
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: SessionTicket callback");
+ wpa_hexdump(MSG_DEBUG, "EAP-TEAP: SessionTicket (PAC-Opaque)",
+ ticket, len);
+
+ if (len < 4 || WPA_GET_BE16(ticket) != PAC_TYPE_PAC_OPAQUE) {
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Ignore invalid SessionTicket");
+ return 0;
+ }
+
+ pac_opaque_len = WPA_GET_BE16(ticket + 2);
+ pac_opaque = ticket + 4;
+ if (pac_opaque_len < 8 || pac_opaque_len % 8 ||
+ pac_opaque_len > len - 4) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Ignore invalid PAC-Opaque (len=%lu left=%lu)",
+ (unsigned long) pac_opaque_len,
+ (unsigned long) len);
+ return 0;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-TEAP: Received PAC-Opaque",
+ pac_opaque, pac_opaque_len);
+
+ buf = os_malloc(pac_opaque_len - 8);
+ if (!buf) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Failed to allocate memory for decrypting PAC-Opaque");
+ return 0;
+ }
+
+ if (aes_unwrap(data->pac_opaque_encr, sizeof(data->pac_opaque_encr),
+ (pac_opaque_len - 8) / 8, pac_opaque, buf) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Failed to decrypt PAC-Opaque");
+ os_free(buf);
+ /*
+ * This may have been caused by server changing the PAC-Opaque
+ * encryption key, so just ignore this PAC-Opaque instead of
+ * failing the authentication completely. Provisioning can now
+ * be used to provision a new PAC.
+ */
+ return 0;
+ }
+
+ end = buf + pac_opaque_len - 8;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Decrypted PAC-Opaque",
+ buf, end - buf);
+
+ pos = buf;
+ while (end - pos > 1) {
+ u8 id, elen;
+
+ id = *pos++;
+ elen = *pos++;
+ if (elen > end - pos)
+ break;
+
+ switch (id) {
+ case PAC_OPAQUE_TYPE_PAD:
+ goto done;
+ case PAC_OPAQUE_TYPE_KEY:
+ if (elen != EAP_TEAP_PAC_KEY_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Invalid PAC-Key length %d",
+ elen);
+ os_free(buf);
+ return -1;
+ }
+ pac_key = pos;
+ wpa_hexdump_key(MSG_DEBUG,
+ "EAP-TEAP: PAC-Key from decrypted PAC-Opaque",
+ pac_key, EAP_TEAP_PAC_KEY_LEN);
+ break;
+ case PAC_OPAQUE_TYPE_LIFETIME:
+ if (elen != 4) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Invalid PAC-Key lifetime length %d",
+ elen);
+ os_free(buf);
+ return -1;
+ }
+ lifetime = WPA_GET_BE32(pos);
+ break;
+ case PAC_OPAQUE_TYPE_IDENTITY:
+ identity = pos;
+ identity_len = elen;
+ break;
+ }
+
+ pos += elen;
+ }
+done:
+
+ if (!pac_key) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: No PAC-Key included in PAC-Opaque");
+ os_free(buf);
+ return -1;
+ }
+
+ if (identity) {
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP-TEAP: Identity from PAC-Opaque",
+ identity, identity_len);
+ os_free(data->identity);
+ data->identity = os_malloc(identity_len);
+ if (data->identity) {
+ os_memcpy(data->identity, identity, identity_len);
+ data->identity_len = identity_len;
+ }
+ }
+
+ if (os_get_time(&now) < 0 || lifetime <= 0 || now.sec > lifetime) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: PAC-Key not valid anymore (lifetime=%ld now=%ld)",
+ lifetime, now.sec);
+ data->send_new_pac = 2;
+ /*
+ * Allow PAC to be used to allow a PAC update with some level
+ * of server authentication (i.e., do not fall back to full TLS
+ * handshake since we cannot be sure that the peer would be
+ * able to validate server certificate now). However, reject
+ * the authentication since the PAC was not valid anymore. Peer
+ * can connect again with the newly provisioned PAC after this.
+ */
+ } else if (lifetime - now.sec < data->pac_key_refresh_time) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: PAC-Key soft timeout; send an update if authentication succeeds");
+ data->send_new_pac = 1;
+ }
+
+ /* EAP-TEAP uses PAC-Key as the TLS master_secret */
+ os_memcpy(master_secret, pac_key, EAP_TEAP_PAC_KEY_LEN);
+
+ os_free(buf);
+
+ return 1;
+}
+
+
+static int eap_teap_derive_key_auth(struct eap_sm *sm,
+ struct eap_teap_data *data)
+{
+ int res;
+
+ /* RFC 7170, Section 5.1 */
+ res = tls_connection_export_key(sm->cfg->ssl_ctx, data->ssl.conn,
+ TEAP_TLS_EXPORTER_LABEL_SKS, NULL, 0,
+ data->simck_msk, EAP_TEAP_SIMCK_LEN);
+ if (res)
+ return res;
+ wpa_hexdump_key(MSG_DEBUG,
+ "EAP-TEAP: session_key_seed (S-IMCK[0])",
+ data->simck_msk, EAP_TEAP_SIMCK_LEN);
+ os_memcpy(data->simck_emsk, data->simck_msk, EAP_TEAP_SIMCK_LEN);
+ data->simck_idx = 0;
+ return 0;
+}
+
+
+static int eap_teap_update_icmk(struct eap_sm *sm, struct eap_teap_data *data)
+{
+ u8 *msk = NULL, *emsk = NULL;
+ size_t msk_len = 0, emsk_len = 0;
+ int res;
+
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Deriving ICMK[%d] (S-IMCK and CMK)",
+ data->simck_idx + 1);
+
+ if (sm->cfg->eap_teap_auth == 1)
+ return eap_teap_derive_cmk_basic_pw_auth(data->tls_cs,
+ data->simck_msk,
+ data->cmk_msk);
+
+ if (!data->phase2_method || !data->phase2_priv) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: Phase 2 method not available");
+ return -1;
+ }
+
+ if (data->phase2_method->getKey) {
+ msk = data->phase2_method->getKey(sm, data->phase2_priv,
+ &msk_len);
+ if (!msk) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Could not fetch Phase 2 MSK");
+ return -1;
+ }
+ }
+
+ if (data->phase2_method->get_emsk) {
+ emsk = data->phase2_method->get_emsk(sm, data->phase2_priv,
+ &emsk_len);
+ }
+
+ res = eap_teap_derive_imck(data->tls_cs,
+ data->simck_msk, data->simck_emsk,
+ msk, msk_len, emsk, emsk_len,
+ data->simck_msk, data->cmk_msk,
+ data->simck_emsk, data->cmk_emsk);
+ bin_clear_free(msk, msk_len);
+ bin_clear_free(emsk, emsk_len);
+ if (res == 0) {
+ data->simck_idx++;
+ if (emsk)
+ data->cmk_emsk_available = 1;
+ }
+ return 0;
+}
+
+
+static void * eap_teap_init(struct eap_sm *sm)
+{
+ struct eap_teap_data *data;
+
+ data = os_zalloc(sizeof(*data));
+ if (!data)
+ return NULL;
+ data->teap_version = EAP_TEAP_VERSION;
+ data->state = START;
+
+ if (eap_server_tls_ssl_init(sm, &data->ssl, 0, EAP_TYPE_TEAP)) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: Failed to initialize SSL.");
+ eap_teap_reset(sm, data);
+ return NULL;
+ }
+
+ /* TODO: Add anon-DH TLS cipher suites (and if one is negotiated,
+ * enforce inner EAP with mutual authentication to be used) */
+
+ if (tls_connection_set_session_ticket_cb(sm->cfg->ssl_ctx,
+ data->ssl.conn,
+ eap_teap_session_ticket_cb,
+ data) < 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Failed to set SessionTicket callback");
+ eap_teap_reset(sm, data);
+ return NULL;
+ }
+
+ if (!sm->cfg->pac_opaque_encr_key) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: No PAC-Opaque encryption key configured");
+ eap_teap_reset(sm, data);
+ return NULL;
+ }
+ os_memcpy(data->pac_opaque_encr, sm->cfg->pac_opaque_encr_key,
+ sizeof(data->pac_opaque_encr));
+
+ if (!sm->cfg->eap_fast_a_id) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: No A-ID configured");
+ eap_teap_reset(sm, data);
+ return NULL;
+ }
+ data->srv_id = os_malloc(sm->cfg->eap_fast_a_id_len);
+ if (!data->srv_id) {
+ eap_teap_reset(sm, data);
+ return NULL;
+ }
+ os_memcpy(data->srv_id, sm->cfg->eap_fast_a_id,
+ sm->cfg->eap_fast_a_id_len);
+ data->srv_id_len = sm->cfg->eap_fast_a_id_len;
+
+ if (!sm->cfg->eap_fast_a_id_info) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: No A-ID-Info configured");
+ eap_teap_reset(sm, data);
+ return NULL;
+ }
+ data->srv_id_info = os_strdup(sm->cfg->eap_fast_a_id_info);
+ if (!data->srv_id_info) {
+ eap_teap_reset(sm, data);
+ return NULL;
+ }
+
+ /* PAC-Key lifetime in seconds (hard limit) */
+ data->pac_key_lifetime = sm->cfg->pac_key_lifetime;
+
+ /*
+ * PAC-Key refresh time in seconds (soft limit on remaining hard
+ * limit). The server will generate a new PAC-Key when this number of
+ * seconds (or fewer) of the lifetime remains.
+ */
+ data->pac_key_refresh_time = sm->cfg->pac_key_refresh_time;
+
+ return data;
+}
+
+
+static void eap_teap_reset(struct eap_sm *sm, void *priv)
+{
+ struct eap_teap_data *data = priv;
+
+ if (!data)
+ return;
+ if (data->phase2_priv && data->phase2_method)
+ data->phase2_method->reset(sm, data->phase2_priv);
+ eap_server_tls_ssl_deinit(sm, &data->ssl);
+ os_free(data->srv_id);
+ os_free(data->srv_id_info);
+ wpabuf_free(data->pending_phase2_resp);
+ wpabuf_free(data->server_outer_tlvs);
+ wpabuf_free(data->peer_outer_tlvs);
+ os_free(data->identity);
+ forced_memzero(data->simck_msk, EAP_TEAP_SIMCK_LEN);
+ forced_memzero(data->simck_emsk, EAP_TEAP_SIMCK_LEN);
+ forced_memzero(data->cmk_msk, EAP_TEAP_CMK_LEN);
+ forced_memzero(data->cmk_emsk, EAP_TEAP_CMK_LEN);
+ forced_memzero(data->pac_opaque_encr, sizeof(data->pac_opaque_encr));
+ bin_clear_free(data, sizeof(*data));
+}
+
+
+static struct wpabuf * eap_teap_build_start(struct eap_sm *sm,
+ struct eap_teap_data *data, u8 id)
+{
+ struct wpabuf *req;
+ size_t outer_tlv_len = sizeof(struct teap_tlv_hdr) + data->srv_id_len;
+ const u8 *start, *end;
+
+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TEAP,
+ 1 + 4 + outer_tlv_len, EAP_CODE_REQUEST, id);
+ if (!req) {
+ wpa_printf(MSG_ERROR,
+ "EAP-TEAP: Failed to allocate memory for request");
+ eap_teap_state(data, FAILURE);
+ return NULL;
+ }
+
+ wpabuf_put_u8(req, EAP_TLS_FLAGS_START | EAP_TEAP_FLAGS_OUTER_TLV_LEN |
+ data->teap_version);
+ wpabuf_put_be32(req, outer_tlv_len);
+
+ start = wpabuf_put(req, 0);
+
+ /* RFC 7170, Section 4.2.2: Authority-ID TLV */
+ eap_teap_put_tlv(req, TEAP_TLV_AUTHORITY_ID,
+ data->srv_id, data->srv_id_len);
+
+ end = wpabuf_put(req, 0);
+ wpabuf_free(data->server_outer_tlvs);
+ data->server_outer_tlvs = wpabuf_alloc_copy(start, end - start);
+ if (!data->server_outer_tlvs) {
+ eap_teap_state(data, FAILURE);
+ return NULL;
+ }
+
+ eap_teap_state(data, PHASE1);
+
+ return req;
+}
+
+
+static int eap_teap_phase1_done(struct eap_sm *sm, struct eap_teap_data *data)
+{
+ char cipher[64];
+
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 1 done, starting Phase 2");
+
+ data->tls_cs = tls_connection_get_cipher_suite(data->ssl.conn);
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: TLS cipher suite 0x%04x",
+ data->tls_cs);
+
+ if (tls_get_cipher(sm->cfg->ssl_ctx, data->ssl.conn,
+ cipher, sizeof(cipher)) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Failed to get cipher information");
+ eap_teap_state(data, FAILURE);
+ return -1;
+ }
+ data->anon_provisioning = os_strstr(cipher, "ADH") != NULL;
+
+ if (data->anon_provisioning)
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Anonymous provisioning");
+
+ if (eap_teap_derive_key_auth(sm, data) < 0) {
+ eap_teap_state(data, FAILURE);
+ return -1;
+ }
+
+ eap_teap_state(data, PHASE2_START);
+
+ return 0;
+}
+
+
+static struct wpabuf * eap_teap_build_phase2_req(struct eap_sm *sm,
+ struct eap_teap_data *data,
+ u8 id)
+{
+ struct wpabuf *req, *id_tlv = NULL;
+
+ if (sm->cfg->eap_teap_auth == 1 ||
+ (data->phase2_priv && data->phase2_method &&
+ data->phase2_method->vendor == EAP_VENDOR_IETF &&
+ data->phase2_method->method == EAP_TYPE_IDENTITY)) {
+ switch (sm->cfg->eap_teap_id) {
+ case EAP_TEAP_ID_ALLOW_ANY:
+ break;
+ case EAP_TEAP_ID_REQUIRE_USER:
+ case EAP_TEAP_ID_REQUEST_USER_ACCEPT_MACHINE:
+ data->cur_id_type = TEAP_IDENTITY_TYPE_USER;
+ id_tlv = eap_teap_tlv_identity_type(data->cur_id_type);
+ break;
+ case EAP_TEAP_ID_REQUIRE_MACHINE:
+ case EAP_TEAP_ID_REQUEST_MACHINE_ACCEPT_USER:
+ data->cur_id_type = TEAP_IDENTITY_TYPE_MACHINE;
+ id_tlv = eap_teap_tlv_identity_type(data->cur_id_type);
+ break;
+ case EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE:
+ if (data->cur_id_type == TEAP_IDENTITY_TYPE_USER)
+ data->cur_id_type = TEAP_IDENTITY_TYPE_MACHINE;
+ else
+ data->cur_id_type = TEAP_IDENTITY_TYPE_USER;
+ id_tlv = eap_teap_tlv_identity_type(data->cur_id_type);
+ break;
+ }
+ }
+
+ if (sm->cfg->eap_teap_auth == 1) {
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Initiate Basic-Password-Auth");
+ data->basic_auth_not_done = 1;
+ req = wpabuf_alloc(sizeof(struct teap_tlv_hdr));
+ if (!req) {
+ wpabuf_free(id_tlv);
+ return NULL;
+ }
+ eap_teap_put_tlv_hdr(req, TEAP_TLV_BASIC_PASSWORD_AUTH_REQ, 0);
+ return wpabuf_concat(req, id_tlv);
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Initiate inner EAP method");
+ data->inner_eap_not_done = 1;
+ if (!data->phase2_priv) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Phase 2 method not initialized");
+ wpabuf_free(id_tlv);
+ return NULL;
+ }
+
+ req = data->phase2_method->buildReq(sm, data->phase2_priv, id);
+ if (!req) {
+ wpabuf_free(id_tlv);
+ return NULL;
+ }
+
+ wpa_hexdump_buf_key(MSG_MSGDUMP, "EAP-TEAP: Phase 2 EAP-Request", req);
+
+ return wpabuf_concat(eap_teap_tlv_eap_payload(req), id_tlv);
+}
+
+
+static struct wpabuf * eap_teap_build_crypto_binding(
+ struct eap_sm *sm, struct eap_teap_data *data)
+{
+ struct wpabuf *buf;
+ struct teap_tlv_result *result;
+ struct teap_tlv_crypto_binding *cb;
+ u8 subtype, flags;
+
+ buf = wpabuf_alloc(2 * sizeof(*result) + sizeof(*cb));
+ if (!buf)
+ return NULL;
+
+ if (data->send_new_pac || data->anon_provisioning ||
+ data->basic_auth_not_done || data->inner_eap_not_done ||
+ data->phase2_method || sm->cfg->eap_teap_separate_result)
+ data->final_result = 0;
+ else
+ data->final_result = 1;
+
+ if (!data->final_result || data->eap_seq > 0 ||
+ sm->cfg->eap_teap_auth == 1) {
+ /* Intermediate-Result */
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Add Intermediate-Result TLV (status=SUCCESS)");
+ result = wpabuf_put(buf, sizeof(*result));
+ result->tlv_type = host_to_be16(TEAP_TLV_MANDATORY |
+ TEAP_TLV_INTERMEDIATE_RESULT);
+ result->length = host_to_be16(2);
+ result->status = host_to_be16(TEAP_STATUS_SUCCESS);
+ }
+
+ if (data->final_result) {
+ /* Result TLV */
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Add Result TLV (status=SUCCESS)");
+ result = wpabuf_put(buf, sizeof(*result));
+ result->tlv_type = host_to_be16(TEAP_TLV_MANDATORY |
+ TEAP_TLV_RESULT);
+ result->length = host_to_be16(2);
+ result->status = host_to_be16(TEAP_STATUS_SUCCESS);
+ }
+
+ /* Crypto-Binding TLV */
+ cb = wpabuf_put(buf, sizeof(*cb));
+ cb->tlv_type = host_to_be16(TEAP_TLV_MANDATORY |
+ TEAP_TLV_CRYPTO_BINDING);
+ cb->length = host_to_be16(sizeof(*cb) - sizeof(struct teap_tlv_hdr));
+ cb->version = EAP_TEAP_VERSION;
+ cb->received_version = data->peer_version;
+ /* FIX: RFC 7170 is not clear on which Flags value to use when
+ * Crypto-Binding TLV is used with Basic-Password-Auth */
+ flags = data->cmk_emsk_available ?
+ TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC :
+ TEAP_CRYPTO_BINDING_MSK_CMAC;
+ subtype = TEAP_CRYPTO_BINDING_SUBTYPE_REQUEST;
+ cb->subtype = (flags << 4) | subtype;
+ if (random_get_bytes(cb->nonce, sizeof(cb->nonce)) < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ /*
+ * RFC 7170, Section 4.2.13:
+ * The nonce in a request MUST have its least significant bit set to 0.
+ */
+ cb->nonce[sizeof(cb->nonce) - 1] &= ~0x01;
+
+ os_memcpy(data->crypto_binding_nonce, cb->nonce, sizeof(cb->nonce));
+
+ if (eap_teap_compound_mac(data->tls_cs, cb, data->server_outer_tlvs,
+ data->peer_outer_tlvs, data->cmk_msk,
+ cb->msk_compound_mac) < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ if (data->cmk_emsk_available &&
+ eap_teap_compound_mac(data->tls_cs, cb, data->server_outer_tlvs,
+ data->peer_outer_tlvs, data->cmk_emsk,
+ cb->emsk_compound_mac) < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Add Crypto-Binding TLV: Version %u Received Version %u Flags %u Sub-Type %u",
+ cb->version, cb->received_version, flags, subtype);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Nonce",
+ cb->nonce, sizeof(cb->nonce));
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: EMSK Compound MAC",
+ cb->emsk_compound_mac, sizeof(cb->emsk_compound_mac));
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: MSK Compound MAC",
+ cb->msk_compound_mac, sizeof(cb->msk_compound_mac));
+
+ return buf;
+}
+
+
+static struct wpabuf * eap_teap_build_pac(struct eap_sm *sm,
+ struct eap_teap_data *data)
+{
+ u8 pac_key[EAP_TEAP_PAC_KEY_LEN];
+ u8 *pac_buf, *pac_opaque;
+ struct wpabuf *buf;
+ u8 *pos;
+ size_t buf_len, srv_id_info_len, pac_len;
+ struct teap_tlv_hdr *pac_tlv;
+ struct pac_attr_hdr *pac_info;
+ struct teap_tlv_result *result;
+ struct os_time now;
+
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Build a new PAC");
+
+ if (random_get_bytes(pac_key, EAP_TEAP_PAC_KEY_LEN) < 0 ||
+ os_get_time(&now) < 0)
+ return NULL;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Generated PAC-Key",
+ pac_key, EAP_TEAP_PAC_KEY_LEN);
+
+ pac_len = (2 + EAP_TEAP_PAC_KEY_LEN) + (2 + 4) +
+ (2 + sm->identity_len) + 8;
+ pac_buf = os_malloc(pac_len);
+ if (!pac_buf)
+ return NULL;
+
+ srv_id_info_len = os_strlen(data->srv_id_info);
+
+ pos = pac_buf;
+ *pos++ = PAC_OPAQUE_TYPE_KEY;
+ *pos++ = EAP_TEAP_PAC_KEY_LEN;
+ os_memcpy(pos, pac_key, EAP_TEAP_PAC_KEY_LEN);
+ pos += EAP_TEAP_PAC_KEY_LEN;
+
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: PAC-Key lifetime: %u seconds",
+ data->pac_key_lifetime);
+ *pos++ = PAC_OPAQUE_TYPE_LIFETIME;
+ *pos++ = 4;
+ WPA_PUT_BE32(pos, now.sec + data->pac_key_lifetime);
+ pos += 4;
+
+ if (sm->identity) {
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-TEAP: PAC-Opaque Identity",
+ sm->identity, sm->identity_len);
+ *pos++ = PAC_OPAQUE_TYPE_IDENTITY;
+ *pos++ = sm->identity_len;
+ os_memcpy(pos, sm->identity, sm->identity_len);
+ pos += sm->identity_len;
+ }
+
+ pac_len = pos - pac_buf;
+ while (pac_len % 8) {
+ *pos++ = PAC_OPAQUE_TYPE_PAD;
+ pac_len++;
+ }
+
+ pac_opaque = os_malloc(pac_len + 8);
+ if (!pac_opaque) {
+ os_free(pac_buf);
+ return NULL;
+ }
+ if (aes_wrap(data->pac_opaque_encr, sizeof(data->pac_opaque_encr),
+ pac_len / 8, pac_buf, pac_opaque) < 0) {
+ os_free(pac_buf);
+ os_free(pac_opaque);
+ return NULL;
+ }
+ os_free(pac_buf);
+
+ pac_len += 8;
+ wpa_hexdump(MSG_DEBUG, "EAP-TEAP: PAC-Opaque", pac_opaque, pac_len);
+
+ buf_len = sizeof(*pac_tlv) +
+ sizeof(struct pac_attr_hdr) + EAP_TEAP_PAC_KEY_LEN +
+ sizeof(struct pac_attr_hdr) + pac_len +
+ data->srv_id_len + srv_id_info_len + 100 + sizeof(*result);
+ buf = wpabuf_alloc(buf_len);
+ if (!buf) {
+ os_free(pac_opaque);
+ return NULL;
+ }
+
+ /* Result TLV */
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Add Result TLV (status=SUCCESS)");
+ result = wpabuf_put(buf, sizeof(*result));
+ WPA_PUT_BE16((u8 *) &result->tlv_type,
+ TEAP_TLV_MANDATORY | TEAP_TLV_RESULT);
+ WPA_PUT_BE16((u8 *) &result->length, 2);
+ WPA_PUT_BE16((u8 *) &result->status, TEAP_STATUS_SUCCESS);
+
+ /* PAC TLV */
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Add PAC TLV");
+ pac_tlv = wpabuf_put(buf, sizeof(*pac_tlv));
+ pac_tlv->tlv_type = host_to_be16(TEAP_TLV_MANDATORY | TEAP_TLV_PAC);
+
+ /* PAC-Key */
+ eap_teap_put_tlv(buf, PAC_TYPE_PAC_KEY, pac_key, EAP_TEAP_PAC_KEY_LEN);
+
+ /* PAC-Opaque */
+ eap_teap_put_tlv(buf, PAC_TYPE_PAC_OPAQUE, pac_opaque, pac_len);
+ os_free(pac_opaque);
+
+ /* PAC-Info */
+ pac_info = wpabuf_put(buf, sizeof(*pac_info));
+ pac_info->type = host_to_be16(PAC_TYPE_PAC_INFO);
+
+ /* PAC-Lifetime (inside PAC-Info) */
+ eap_teap_put_tlv_hdr(buf, PAC_TYPE_CRED_LIFETIME, 4);
+ wpabuf_put_be32(buf, now.sec + data->pac_key_lifetime);
+
+ /* A-ID (inside PAC-Info) */
+ eap_teap_put_tlv(buf, PAC_TYPE_A_ID, data->srv_id, data->srv_id_len);
+
+ /* Note: headers may be misaligned after A-ID */
+
+ if (sm->identity) {
+ eap_teap_put_tlv(buf, PAC_TYPE_I_ID, sm->identity,
+ sm->identity_len);
+ }
+
+ /* A-ID-Info (inside PAC-Info) */
+ eap_teap_put_tlv(buf, PAC_TYPE_A_ID_INFO, data->srv_id_info,
+ srv_id_info_len);
+
+ /* PAC-Type (inside PAC-Info) */
+ eap_teap_put_tlv_hdr(buf, PAC_TYPE_PAC_TYPE, 2);
+ wpabuf_put_be16(buf, PAC_TYPE_TUNNEL_PAC);
+
+ /* Update PAC-Info and PAC TLV Length fields */
+ pos = wpabuf_put(buf, 0);
+ pac_info->len = host_to_be16(pos - (u8 *) (pac_info + 1));
+ pac_tlv->length = host_to_be16(pos - (u8 *) (pac_tlv + 1));
+
+ return buf;
+}
+
+
+static int eap_teap_encrypt_phase2(struct eap_sm *sm,
+ struct eap_teap_data *data,
+ struct wpabuf *plain, int piggyback)
+{
+ struct wpabuf *encr;
+
+ wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TEAP: Encrypting Phase 2 TLVs",
+ plain);
+ encr = eap_server_tls_encrypt(sm, &data->ssl, plain);
+ wpabuf_free(plain);
+
+ if (!encr)
+ return -1;
+
+ if (data->ssl.tls_out && piggyback) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Piggyback Phase 2 data (len=%d) with last Phase 1 Message (len=%d used=%d)",
+ (int) wpabuf_len(encr),
+ (int) wpabuf_len(data->ssl.tls_out),
+ (int) data->ssl.tls_out_pos);
+ if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr)) < 0) {
+ wpa_printf(MSG_WARNING,
+ "EAP-TEAP: Failed to resize output buffer");
+ wpabuf_free(encr);
+ return -1;
+ }
+ wpabuf_put_buf(data->ssl.tls_out, encr);
+ wpabuf_free(encr);
+ } else {
+ wpabuf_free(data->ssl.tls_out);
+ data->ssl.tls_out_pos = 0;
+ data->ssl.tls_out = encr;
+ }
+
+ return 0;
+}
+
+
+static struct wpabuf * eap_teap_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+ struct eap_teap_data *data = priv;
+ struct wpabuf *req = NULL;
+ int piggyback = 0;
+
+ if (data->ssl.state == FRAG_ACK) {
+ return eap_server_tls_build_ack(id, EAP_TYPE_TEAP,
+ data->teap_version);
+ }
+
+ if (data->ssl.state == WAIT_FRAG_ACK) {
+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TEAP,
+ data->teap_version, id);
+ }
+
+ switch (data->state) {
+ case START:
+ return eap_teap_build_start(sm, data, id);
+ case PHASE1B:
+ if (tls_connection_established(sm->cfg->ssl_ctx,
+ data->ssl.conn)) {
+ if (eap_teap_phase1_done(sm, data) < 0)
+ return NULL;
+ if (data->state == PHASE2_START) {
+ int res;
+
+ /*
+ * Try to generate Phase 2 data to piggyback
+ * with the end of Phase 1 to avoid extra
+ * roundtrip.
+ */
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Try to start Phase 2");
+ res = eap_teap_process_phase2_start(sm, data);
+ if (res == 1) {
+ req = eap_teap_build_crypto_binding(
+ sm, data);
+ piggyback = 1;
+ break;
+ }
+
+ if (res)
+ break;
+ req = eap_teap_build_phase2_req(sm, data, id);
+ piggyback = 1;
+ }
+ }
+ break;
+ case PHASE2_ID:
+ case PHASE2_BASIC_AUTH:
+ case PHASE2_METHOD:
+ req = eap_teap_build_phase2_req(sm, data, id);
+ break;
+ case CRYPTO_BINDING:
+ req = eap_teap_build_crypto_binding(sm, data);
+ if (data->phase2_method) {
+ /*
+ * Include the start of the next EAP method in the
+ * sequence in the same message with Crypto-Binding to
+ * save a round-trip.
+ */
+ struct wpabuf *eap;
+
+ eap = eap_teap_build_phase2_req(sm, data, id);
+ req = wpabuf_concat(req, eap);
+ eap_teap_state(data, PHASE2_METHOD);
+ }
+ break;
+ case REQUEST_PAC:
+ req = eap_teap_build_pac(sm, data);
+ break;
+ case FAILURE_SEND_RESULT:
+ req = eap_teap_tlv_result(TEAP_STATUS_FAILURE, 0);
+ if (data->error_code)
+ req = wpabuf_concat(
+ req, eap_teap_tlv_error(data->error_code));
+ break;
+ case SUCCESS_SEND_RESULT:
+ req = eap_teap_tlv_result(TEAP_STATUS_SUCCESS, 0);
+ data->final_result = 1;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: %s - unexpected state %d",
+ __func__, data->state);
+ return NULL;
+ }
+
+ if (req && eap_teap_encrypt_phase2(sm, data, req, piggyback) < 0)
+ return NULL;
+
+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TEAP,
+ data->teap_version, id);
+}
+
+
+static bool eap_teap_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
+{
+ const u8 *pos;
+ size_t len;
+
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TEAP, respData, &len);
+ if (!pos || len < 1) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: Invalid frame");
+ return true;
+ }
+
+ return false;
+}
+
+
+static int eap_teap_phase2_init(struct eap_sm *sm, struct eap_teap_data *data,
+ int vendor, enum eap_type eap_type)
+{
+ if (data->phase2_priv && data->phase2_method) {
+ data->phase2_method->reset(sm, data->phase2_priv);
+ data->phase2_method = NULL;
+ data->phase2_priv = NULL;
+ }
+ data->phase2_method = eap_server_get_eap_method(vendor, eap_type);
+ if (!data->phase2_method)
+ return -1;
+
+ sm->init_phase2 = 1;
+ data->phase2_priv = data->phase2_method->init(sm);
+ sm->init_phase2 = 0;
+
+ return data->phase2_priv ? 0 : -1;
+}
+
+
+static int eap_teap_valid_id_type(struct eap_sm *sm, struct eap_teap_data *data,
+ enum teap_identity_types id_type)
+{
+ if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_USER &&
+ id_type != TEAP_IDENTITY_TYPE_USER)
+ return 0;
+ if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_MACHINE &&
+ id_type != TEAP_IDENTITY_TYPE_MACHINE)
+ return 0;
+ if (sm->cfg->eap_teap_id == EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE &&
+ id_type != data->cur_id_type)
+ return 0;
+ if (sm->cfg->eap_teap_id != EAP_TEAP_ID_ALLOW_ANY &&
+ id_type != TEAP_IDENTITY_TYPE_USER &&
+ id_type != TEAP_IDENTITY_TYPE_MACHINE)
+ return 0;
+ return 1;
+}
+
+
+static void eap_teap_process_phase2_response(struct eap_sm *sm,
+ struct eap_teap_data *data,
+ u8 *in_data, size_t in_len,
+ enum teap_identity_types id_type)
+{
+ int next_vendor = EAP_VENDOR_IETF;
+ enum eap_type next_type = EAP_TYPE_NONE;
+ struct eap_hdr *hdr;
+ u8 *pos;
+ size_t left;
+ struct wpabuf buf;
+ const struct eap_method *m = data->phase2_method;
+ void *priv = data->phase2_priv;
+
+ if (!priv) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: %s - Phase 2 not initialized?!",
+ __func__);
+ return;
+ }
+
+ hdr = (struct eap_hdr *) in_data;
+ pos = (u8 *) (hdr + 1);
+
+ if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
+ left = in_len - sizeof(*hdr);
+ wpa_hexdump(MSG_DEBUG,
+ "EAP-TEAP: Phase 2 type Nak'ed; allowed types",
+ pos + 1, left - 1);
+#ifdef EAP_SERVER_TNC
+ if (m && m->vendor == EAP_VENDOR_IETF &&
+ m->method == EAP_TYPE_TNC) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Peer Nak'ed required TNC negotiation");
+ next_vendor = EAP_VENDOR_IETF;
+ next_type = eap_teap_req_failure(data, 0);
+ eap_teap_phase2_init(sm, data, next_vendor, next_type);
+ return;
+ }
+#endif /* EAP_SERVER_TNC */
+ eap_sm_process_nak(sm, pos + 1, left - 1);
+ if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
+ sm->user->methods[sm->user_eap_method_index].method !=
+ EAP_TYPE_NONE) {
+ next_vendor = sm->user->methods[
+ sm->user_eap_method_index].vendor;
+ next_type = sm->user->methods[
+ sm->user_eap_method_index++].method;
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: try EAP type %u:%u",
+ next_vendor, next_type);
+ } else {
+ next_vendor = EAP_VENDOR_IETF;
+ next_type = eap_teap_req_failure(data, 0);
+ }
+ eap_teap_phase2_init(sm, data, next_vendor, next_type);
+ return;
+ }
+
+ wpabuf_set(&buf, in_data, in_len);
+
+ if (m->check(sm, priv, &buf)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Phase 2 check() asked to ignore the packet");
+ eap_teap_req_failure(data, TEAP_ERROR_INNER_METHOD);
+ return;
+ }
+
+ m->process(sm, priv, &buf);
+
+ if (!m->isDone(sm, priv))
+ return;
+
+ if (!m->isSuccess(sm, priv)) {
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 2 method failed");
+ next_vendor = EAP_VENDOR_IETF;
+ next_type = eap_teap_req_failure(data, TEAP_ERROR_INNER_METHOD);
+ eap_teap_phase2_init(sm, data, next_vendor, next_type);
+ return;
+ }
+
+ switch (data->state) {
+ case PHASE2_ID:
+ if (!eap_teap_valid_id_type(sm, data, id_type)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Provided Identity-Type %u not allowed",
+ id_type);
+ eap_teap_req_failure(data, TEAP_ERROR_INNER_METHOD);
+ break;
+ }
+ if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP-TEAP: Phase 2 Identity not found in the user database",
+ sm->identity, sm->identity_len);
+ next_vendor = EAP_VENDOR_IETF;
+ next_type = eap_teap_req_failure(
+ data, TEAP_ERROR_INNER_METHOD);
+ break;
+ }
+
+ eap_teap_state(data, PHASE2_METHOD);
+ if (data->anon_provisioning) {
+ /* TODO: Allow any inner EAP method that provides
+ * mutual authentication and EMSK derivation (i.e.,
+ * EAP-pwd or EAP-EKE). */
+ next_vendor = EAP_VENDOR_IETF;
+ next_type = EAP_TYPE_PWD;
+ sm->user_eap_method_index = 0;
+ } else {
+ next_vendor = sm->user->methods[0].vendor;
+ next_type = sm->user->methods[0].method;
+ sm->user_eap_method_index = 1;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Try EAP type %u:%u",
+ next_vendor, next_type);
+ break;
+ case PHASE2_METHOD:
+ case CRYPTO_BINDING:
+ eap_teap_update_icmk(sm, data);
+ if (data->state == PHASE2_METHOD &&
+ (sm->cfg->eap_teap_id !=
+ EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE ||
+ data->cur_id_type == TEAP_IDENTITY_TYPE_MACHINE))
+ data->inner_eap_not_done = 0;
+ eap_teap_state(data, CRYPTO_BINDING);
+ data->eap_seq++;
+ next_vendor = EAP_VENDOR_IETF;
+ next_type = EAP_TYPE_NONE;
+#ifdef EAP_SERVER_TNC
+ if (sm->cfg->tnc && !data->tnc_started) {
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Initialize TNC");
+ next_vendor = EAP_VENDOR_IETF;
+ next_type = EAP_TYPE_TNC;
+ data->tnc_started = 1;
+ }
+#endif /* EAP_SERVER_TNC */
+ break;
+ case FAILURE:
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: %s - unexpected state %d",
+ __func__, data->state);
+ break;
+ }
+
+ eap_teap_phase2_init(sm, data, next_vendor, next_type);
+}
+
+
+static void eap_teap_process_phase2_eap(struct eap_sm *sm,
+ struct eap_teap_data *data,
+ u8 *in_data, size_t in_len,
+ enum teap_identity_types id_type)
+{
+ struct eap_hdr *hdr;
+ size_t len;
+
+ hdr = (struct eap_hdr *) in_data;
+ if (in_len < (int) sizeof(*hdr)) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Too short Phase 2 EAP frame (len=%lu)",
+ (unsigned long) in_len);
+ eap_teap_req_failure(data, TEAP_ERROR_INNER_METHOD);
+ return;
+ }
+ len = be_to_host16(hdr->length);
+ if (len > in_len) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Length mismatch in Phase 2 EAP frame (len=%lu hdr->length=%lu)",
+ (unsigned long) in_len, (unsigned long) len);
+ eap_teap_req_failure(data, TEAP_ERROR_INNER_METHOD);
+ return;
+ }
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Received Phase 2: code=%d identifier=%d length=%lu",
+ hdr->code, hdr->identifier,
+ (unsigned long) len);
+ switch (hdr->code) {
+ case EAP_CODE_RESPONSE:
+ eap_teap_process_phase2_response(sm, data, (u8 *) hdr, len,
+ id_type);
+ break;
+ default:
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Unexpected code=%d in Phase 2 EAP header",
+ hdr->code);
+ break;
+ }
+}
+
+
+static void eap_teap_process_basic_auth_resp(struct eap_sm *sm,
+ struct eap_teap_data *data,
+ u8 *in_data, size_t in_len,
+ enum teap_identity_types id_type)
+{
+ u8 *pos, *end, *username, *password, *new_id;
+ u8 userlen, passlen;
+
+ if (!eap_teap_valid_id_type(sm, data, id_type)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Provided Identity-Type %u not allowed",
+ id_type);
+ eap_teap_req_failure(data, 0);
+ return;
+ }
+
+ pos = in_data;
+ end = pos + in_len;
+
+ if (end - pos < 1) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: No room for Basic-Password-Auth-Resp Userlen field");
+ eap_teap_req_failure(data, 0);
+ return;
+ }
+ userlen = *pos++;
+ if (end - pos < userlen) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Truncated Basic-Password-Auth-Resp Username field");
+ eap_teap_req_failure(data, 0);
+ return;
+ }
+ username = pos;
+ pos += userlen;
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP-TEAP: Basic-Password-Auth-Resp Username",
+ username, userlen);
+
+ if (end - pos < 1) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: No room for Basic-Password-Auth-Resp Passlen field");
+ eap_teap_req_failure(data, 0);
+ return;
+ }
+ passlen = *pos++;
+ if (end - pos < passlen) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Truncated Basic-Password-Auth-Resp Password field");
+ eap_teap_req_failure(data, 0);
+ return;
+ }
+ password = pos;
+ pos += passlen;
+ wpa_hexdump_ascii_key(MSG_DEBUG,
+ "EAP-TEAP: Basic-Password-Auth-Resp Password",
+ password, passlen);
+
+ if (end > pos) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Unexpected %d extra octet(s) at the end of Basic-Password-Auth-Resp TLV",
+ (int) (end - pos));
+ eap_teap_req_failure(data, 0);
+ return;
+ }
+
+ if (eap_user_get(sm, username, userlen, 1) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Username not found in the user database");
+ eap_teap_req_failure(data, 0);
+ return;
+ }
+
+ if (!sm->user || !sm->user->password || sm->user->password_hash) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: No plaintext user password configured");
+ eap_teap_req_failure(data, 0);
+ return;
+ }
+
+ if (sm->user->password_len != passlen ||
+ os_memcmp_const(sm->user->password, password, passlen) != 0) {
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Invalid password");
+ eap_teap_req_failure(data, 0);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Correct password");
+ new_id = os_memdup(username, userlen);
+ if (new_id) {
+ os_free(sm->identity);
+ sm->identity = new_id;
+ sm->identity_len = userlen;
+ }
+ if (sm->cfg->eap_teap_id != EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE ||
+ data->cur_id_type == TEAP_IDENTITY_TYPE_MACHINE)
+ data->basic_auth_not_done = 0;
+ eap_teap_state(data, CRYPTO_BINDING);
+ eap_teap_update_icmk(sm, data);
+}
+
+
+static int eap_teap_parse_tlvs(struct wpabuf *data,
+ struct eap_teap_tlv_parse *tlv)
+{
+ u16 tlv_type;
+ int mandatory, res;
+ size_t len;
+ u8 *pos, *end;
+
+ os_memset(tlv, 0, sizeof(*tlv));
+
+ pos = wpabuf_mhead(data);
+ end = pos + wpabuf_len(data);
+ while (end - pos > 4) {
+ mandatory = pos[0] & 0x80;
+ tlv_type = WPA_GET_BE16(pos) & 0x3fff;
+ pos += 2;
+ len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (len > (size_t) (end - pos)) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: TLV overflow");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Received Phase 2: TLV type %u (%s) length %u%s",
+ tlv_type, eap_teap_tlv_type_str(tlv_type),
+ (unsigned int) len,
+ mandatory ? " (mandatory)" : "");
+
+ res = eap_teap_parse_tlv(tlv, tlv_type, pos, len);
+ if (res == -2)
+ break;
+ if (res < 0) {
+ if (mandatory) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: NAK unknown mandatory TLV type %u",
+ tlv_type);
+ /* TODO: generate NAK TLV */
+ break;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Ignore unknown optional TLV type %u",
+ tlv_type);
+ }
+
+ pos += len;
+ }
+
+ return 0;
+}
+
+
+static int eap_teap_validate_crypto_binding(
+ struct eap_teap_data *data, const struct teap_tlv_crypto_binding *cb,
+ size_t bind_len)
+{
+ u8 flags, subtype;
+
+ subtype = cb->subtype & 0x0f;
+ flags = cb->subtype >> 4;
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Reply Crypto-Binding TLV: Version %u Received Version %u Flags %u Sub-Type %u",
+ cb->version, cb->received_version, flags, subtype);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Nonce",
+ cb->nonce, sizeof(cb->nonce));
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: EMSK Compound MAC",
+ cb->emsk_compound_mac, sizeof(cb->emsk_compound_mac));
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: MSK Compound MAC",
+ cb->msk_compound_mac, sizeof(cb->msk_compound_mac));
+
+ if (cb->version != EAP_TEAP_VERSION ||
+ cb->received_version != data->peer_version) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Unexpected version in Crypto-Binding: Version %u Received Version %u",
+ cb->version, cb->received_version);
+ return -1;
+ }
+
+ if (flags < 1 || flags > 3) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Unexpected Flags in Crypto-Binding: %u",
+ flags);
+ return -1;
+ }
+
+ if (subtype != TEAP_CRYPTO_BINDING_SUBTYPE_RESPONSE) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Unexpected Sub-Type in Crypto-Binding: %u",
+ subtype);
+ return -1;
+ }
+
+ if (os_memcmp_const(data->crypto_binding_nonce, cb->nonce,
+ EAP_TEAP_NONCE_LEN - 1) != 0 ||
+ (data->crypto_binding_nonce[EAP_TEAP_NONCE_LEN - 1] | 1) !=
+ cb->nonce[EAP_TEAP_NONCE_LEN - 1]) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Invalid Nonce in Crypto-Binding");
+ return -1;
+ }
+
+ if (flags == TEAP_CRYPTO_BINDING_MSK_CMAC ||
+ flags == TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC) {
+ u8 msk_compound_mac[EAP_TEAP_COMPOUND_MAC_LEN];
+
+ if (eap_teap_compound_mac(data->tls_cs, cb,
+ data->server_outer_tlvs,
+ data->peer_outer_tlvs, data->cmk_msk,
+ msk_compound_mac) < 0)
+ return -1;
+ if (os_memcmp_const(msk_compound_mac, cb->msk_compound_mac,
+ EAP_TEAP_COMPOUND_MAC_LEN) != 0) {
+ wpa_hexdump(MSG_DEBUG,
+ "EAP-TEAP: Calculated MSK Compound MAC",
+ msk_compound_mac,
+ EAP_TEAP_COMPOUND_MAC_LEN);
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: MSK Compound MAC did not match");
+ return -1;
+ }
+ }
+
+ if ((flags == TEAP_CRYPTO_BINDING_EMSK_CMAC ||
+ flags == TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC) &&
+ data->cmk_emsk_available) {
+ u8 emsk_compound_mac[EAP_TEAP_COMPOUND_MAC_LEN];
+
+ if (eap_teap_compound_mac(data->tls_cs, cb,
+ data->server_outer_tlvs,
+ data->peer_outer_tlvs, data->cmk_emsk,
+ emsk_compound_mac) < 0)
+ return -1;
+ if (os_memcmp_const(emsk_compound_mac, cb->emsk_compound_mac,
+ EAP_TEAP_COMPOUND_MAC_LEN) != 0) {
+ wpa_hexdump(MSG_DEBUG,
+ "EAP-TEAP: Calculated EMSK Compound MAC",
+ emsk_compound_mac,
+ EAP_TEAP_COMPOUND_MAC_LEN);
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: EMSK Compound MAC did not match");
+ return -1;
+ }
+ }
+
+ if (flags == TEAP_CRYPTO_BINDING_EMSK_CMAC &&
+ !data->cmk_emsk_available) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Peer included only EMSK Compound MAC, but no locally generated inner EAP EMSK to validate this");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int eap_teap_pac_type(u8 *pac, size_t len, u16 type)
+{
+ struct teap_attr_pac_type *tlv;
+
+ if (!pac || len != sizeof(*tlv))
+ return 0;
+
+ tlv = (struct teap_attr_pac_type *) pac;
+
+ return be_to_host16(tlv->type) == PAC_TYPE_PAC_TYPE &&
+ be_to_host16(tlv->length) == 2 &&
+ be_to_host16(tlv->pac_type) == type;
+}
+
+
+static void eap_teap_process_phase2_tlvs(struct eap_sm *sm,
+ struct eap_teap_data *data,
+ struct wpabuf *in_data)
+{
+ struct eap_teap_tlv_parse tlv;
+ int check_crypto_binding = data->state == CRYPTO_BINDING;
+
+ if (eap_teap_parse_tlvs(in_data, &tlv) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Failed to parse received Phase 2 TLVs");
+ return;
+ }
+
+ if (tlv.result == TEAP_STATUS_FAILURE) {
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Result TLV indicated failure");
+ eap_teap_state(data, FAILURE);
+ return;
+ }
+
+ if (tlv.nak) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Peer NAK'ed Vendor-Id %u NAK-Type %u",
+ WPA_GET_BE32(tlv.nak), WPA_GET_BE16(tlv.nak + 4));
+ eap_teap_state(data, FAILURE_SEND_RESULT);
+ return;
+ }
+
+ if (data->state == REQUEST_PAC) {
+ u16 type, len, res;
+
+ if (!tlv.pac || tlv.pac_len < 6) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: No PAC Acknowledgement received");
+ eap_teap_state(data, FAILURE);
+ return;
+ }
+
+ type = WPA_GET_BE16(tlv.pac);
+ len = WPA_GET_BE16(tlv.pac + 2);
+ res = WPA_GET_BE16(tlv.pac + 4);
+
+ if (type != PAC_TYPE_PAC_ACKNOWLEDGEMENT || len != 2 ||
+ res != TEAP_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: PAC TLV did not contain acknowledgement");
+ eap_teap_state(data, FAILURE);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: PAC-Acknowledgement received - PAC provisioning succeeded");
+ eap_teap_state(data, SUCCESS);
+ return;
+ }
+
+ if (check_crypto_binding) {
+ if (!tlv.crypto_binding) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: No Crypto-Binding TLV received");
+ eap_teap_state(data, FAILURE);
+ return;
+ }
+
+ if (data->final_result &&
+ tlv.result != TEAP_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Crypto-Binding TLV without Success Result");
+ eap_teap_state(data, FAILURE);
+ return;
+ }
+
+ if (sm->cfg->eap_teap_auth != 1 &&
+ !data->skipped_inner_auth &&
+ tlv.iresult != TEAP_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Crypto-Binding TLV without intermediate Success Result");
+ eap_teap_state(data, FAILURE);
+ return;
+ }
+
+ if (eap_teap_validate_crypto_binding(data, tlv.crypto_binding,
+ tlv.crypto_binding_len)) {
+ eap_teap_state(data, FAILURE);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Valid Crypto-Binding TLV received");
+ if (data->final_result) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Authentication completed successfully");
+ }
+
+ if (data->anon_provisioning &&
+ sm->cfg->eap_fast_prov != ANON_PROV &&
+ sm->cfg->eap_fast_prov != BOTH_PROV) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Client is trying to use unauthenticated provisioning which is disabled");
+ eap_teap_state(data, FAILURE);
+ return;
+ }
+
+ if (sm->cfg->eap_fast_prov != AUTH_PROV &&
+ sm->cfg->eap_fast_prov != BOTH_PROV &&
+ tlv.request_action == TEAP_REQUEST_ACTION_PROCESS_TLV &&
+ eap_teap_pac_type(tlv.pac, tlv.pac_len,
+ PAC_TYPE_TUNNEL_PAC)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Client is trying to use authenticated provisioning which is disabled");
+ eap_teap_state(data, FAILURE);
+ return;
+ }
+
+ if (data->anon_provisioning ||
+ (tlv.request_action == TEAP_REQUEST_ACTION_PROCESS_TLV &&
+ eap_teap_pac_type(tlv.pac, tlv.pac_len,
+ PAC_TYPE_TUNNEL_PAC))) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Requested a new Tunnel PAC");
+ eap_teap_state(data, REQUEST_PAC);
+ } else if (data->send_new_pac) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Server triggered re-keying of Tunnel PAC");
+ eap_teap_state(data, REQUEST_PAC);
+ } else if (data->final_result) {
+ eap_teap_state(data, SUCCESS);
+ } else if (sm->cfg->eap_teap_separate_result) {
+ eap_teap_state(data, SUCCESS_SEND_RESULT);
+ }
+ }
+
+ if (tlv.basic_auth_resp) {
+ if (sm->cfg->eap_teap_auth != 1) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Unexpected Basic-Password-Auth-Resp when trying to use inner EAP");
+ eap_teap_state(data, FAILURE);
+ return;
+ }
+ eap_teap_process_basic_auth_resp(sm, data, tlv.basic_auth_resp,
+ tlv.basic_auth_resp_len,
+ tlv.identity_type);
+ }
+
+ if (tlv.eap_payload_tlv) {
+ if (sm->cfg->eap_teap_auth == 1) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Unexpected EAP Payload TLV when trying to use Basic-Password-Auth");
+ eap_teap_state(data, FAILURE);
+ return;
+ }
+ eap_teap_process_phase2_eap(sm, data, tlv.eap_payload_tlv,
+ tlv.eap_payload_tlv_len,
+ tlv.identity_type);
+ }
+
+ if (data->state == SUCCESS_SEND_RESULT &&
+ tlv.result == TEAP_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Peer agreed with final success - authentication completed");
+ eap_teap_state(data, SUCCESS);
+ } else if (check_crypto_binding && data->state == CRYPTO_BINDING &&
+ sm->cfg->eap_teap_auth == 1 && data->basic_auth_not_done) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Continue with basic password authentication for second credential");
+ eap_teap_state(data, PHASE2_BASIC_AUTH);
+ } else if (check_crypto_binding && data->state == CRYPTO_BINDING &&
+ sm->cfg->eap_teap_auth == 0 && data->inner_eap_not_done) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Continue with inner EAP authentication for second credential");
+ eap_teap_state(data, PHASE2_ID);
+ if (eap_teap_phase2_init(sm, data, EAP_VENDOR_IETF,
+ EAP_TYPE_IDENTITY) < 0)
+ eap_teap_state(data, FAILURE);
+ }
+}
+
+
+static void eap_teap_process_phase2(struct eap_sm *sm,
+ struct eap_teap_data *data,
+ struct wpabuf *in_buf)
+{
+ struct wpabuf *in_decrypted;
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Received %lu bytes encrypted data for Phase 2",
+ (unsigned long) wpabuf_len(in_buf));
+
+ if (data->pending_phase2_resp) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Pending Phase 2 response - skip decryption and use old data");
+ eap_teap_process_phase2_tlvs(sm, data,
+ data->pending_phase2_resp);
+ wpabuf_free(data->pending_phase2_resp);
+ data->pending_phase2_resp = NULL;
+ return;
+ }
+
+ in_decrypted = tls_connection_decrypt(sm->cfg->ssl_ctx, data->ssl.conn,
+ in_buf);
+ if (!in_decrypted) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Failed to decrypt Phase 2 data");
+ eap_teap_state(data, FAILURE);
+ return;
+ }
+
+ wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TEAP: Decrypted Phase 2 TLVs",
+ in_decrypted);
+
+ eap_teap_process_phase2_tlvs(sm, data, in_decrypted);
+
+ if (sm->method_pending == METHOD_PENDING_WAIT) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Phase 2 method is in pending wait state - save decrypted response");
+ wpabuf_free(data->pending_phase2_resp);
+ data->pending_phase2_resp = in_decrypted;
+ return;
+ }
+
+ wpabuf_free(in_decrypted);
+}
+
+
+static int eap_teap_process_version(struct eap_sm *sm, void *priv,
+ int peer_version)
+{
+ struct eap_teap_data *data = priv;
+
+ if (peer_version < 1) {
+ /* Version 1 was the first defined version, so reject 0 */
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Peer used unknown TEAP version %u",
+ peer_version);
+ return -1;
+ }
+
+ if (peer_version < data->teap_version) {
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: peer ver=%u, own ver=%u; "
+ "use version %u",
+ peer_version, data->teap_version, peer_version);
+ data->teap_version = peer_version;
+ }
+
+ data->peer_version = peer_version;
+
+ return 0;
+}
+
+
+static int eap_teap_process_phase1(struct eap_sm *sm,
+ struct eap_teap_data *data)
+{
+ if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
+ wpa_printf(MSG_INFO, "EAP-TEAP: TLS processing failed");
+ eap_teap_state(data, FAILURE);
+ return -1;
+ }
+
+ if (!tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
+ wpabuf_len(data->ssl.tls_out) > 0)
+ return 1;
+
+ /*
+ * Phase 1 was completed with the received message (e.g., when using
+ * abbreviated handshake), so Phase 2 can be started immediately
+ * without having to send through an empty message to the peer.
+ */
+
+ return eap_teap_phase1_done(sm, data);
+}
+
+
+static int eap_teap_process_phase2_start(struct eap_sm *sm,
+ struct eap_teap_data *data)
+{
+ int next_vendor;
+ enum eap_type next_type;
+
+ if (data->identity) {
+ /* Used PAC and identity is from PAC-Opaque */
+ os_free(sm->identity);
+ sm->identity = data->identity;
+ data->identity = NULL;
+ sm->identity_len = data->identity_len;
+ data->identity_len = 0;
+ if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP-TEAP: Phase 2 Identity not found in the user database",
+ sm->identity, sm->identity_len);
+ next_vendor = EAP_VENDOR_IETF;
+ next_type = EAP_TYPE_NONE;
+ eap_teap_state(data, PHASE2_METHOD);
+ } else if (sm->cfg->eap_teap_pac_no_inner) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Used PAC and identity already known - skip inner auth");
+ data->skipped_inner_auth = 1;
+ /* FIX: Need to derive CMK here. However, how is that
+ * supposed to be done? RFC 7170 does not tell that for
+ * the no-inner-auth case. */
+ eap_teap_derive_cmk_basic_pw_auth(data->tls_cs,
+ data->simck_msk,
+ data->cmk_msk);
+ eap_teap_state(data, CRYPTO_BINDING);
+ return 1;
+ } else if (sm->cfg->eap_teap_auth == 1) {
+ eap_teap_state(data, PHASE2_BASIC_AUTH);
+ return 1;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Identity already known - skip Phase 2 Identity Request");
+ next_vendor = sm->user->methods[0].vendor;
+ next_type = sm->user->methods[0].method;
+ sm->user_eap_method_index = 1;
+ eap_teap_state(data, PHASE2_METHOD);
+ }
+
+ } else if (sm->cfg->eap_teap_auth == 1) {
+ eap_teap_state(data, PHASE2_BASIC_AUTH);
+ return 0;
+ } else {
+ eap_teap_state(data, PHASE2_ID);
+ next_vendor = EAP_VENDOR_IETF;
+ next_type = EAP_TYPE_IDENTITY;
+ }
+
+ return eap_teap_phase2_init(sm, data, next_vendor, next_type);
+}
+
+
+static void eap_teap_process_msg(struct eap_sm *sm, void *priv,
+ const struct wpabuf *respData)
+{
+ struct eap_teap_data *data = priv;
+
+ switch (data->state) {
+ case PHASE1:
+ case PHASE1B:
+ if (eap_teap_process_phase1(sm, data))
+ break;
+
+ /* fall through */
+ case PHASE2_START:
+ eap_teap_process_phase2_start(sm, data);
+ break;
+ case PHASE2_ID:
+ case PHASE2_BASIC_AUTH:
+ case PHASE2_METHOD:
+ case CRYPTO_BINDING:
+ case REQUEST_PAC:
+ case SUCCESS_SEND_RESULT:
+ eap_teap_process_phase2(sm, data, data->ssl.tls_in);
+ break;
+ case FAILURE_SEND_RESULT:
+ /* Protected failure result indication completed. Ignore the
+ * received message (which is supposed to include Result TLV
+ * indicating failure) and terminate exchange with cleartext
+ * EAP-Failure. */
+ eap_teap_state(data, FAILURE);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Unexpected state %d in %s",
+ data->state, __func__);
+ break;
+ }
+}
+
+
+static void eap_teap_process(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
+{
+ struct eap_teap_data *data = priv;
+ const u8 *pos;
+ size_t len;
+ struct wpabuf *resp = respData;
+ u8 flags;
+
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TEAP, respData, &len);
+ if (!pos || len < 1)
+ return;
+
+ flags = *pos++;
+ len--;
+
+ if (flags & EAP_TEAP_FLAGS_OUTER_TLV_LEN) {
+ /* Extract Outer TLVs from the message before common TLS
+ * processing */
+ u32 message_len = 0, outer_tlv_len;
+ const u8 *hdr;
+
+ if (data->state != PHASE1) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Unexpected Outer TLVs in a message that is not the first message from the peer");
+ return;
+ }
+
+ if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
+ if (len < 4) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Too short message to include Message Length field");
+ return;
+ }
+
+ message_len = WPA_GET_BE32(pos);
+ pos += 4;
+ len -= 4;
+ if (message_len < 4) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Message Length field has too msall value to include Outer TLV Length field");
+ return;
+ }
+ }
+
+ if (len < 4) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Too short message to include Outer TLVs Length field");
+ return;
+ }
+
+ outer_tlv_len = WPA_GET_BE32(pos);
+ pos += 4;
+ len -= 4;
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: Message Length %u Outer TLV Length %u",
+ message_len, outer_tlv_len);
+ if (len < outer_tlv_len) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Too short message to include Outer TLVs field");
+ return;
+ }
+
+ if (message_len &&
+ (message_len < outer_tlv_len ||
+ message_len < 4 + outer_tlv_len)) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Message Length field has too small value to include Outer TLVs");
+ return;
+ }
+
+ if (wpabuf_len(respData) < 4 + outer_tlv_len ||
+ len < outer_tlv_len)
+ return;
+ resp = wpabuf_alloc(wpabuf_len(respData) - 4 - outer_tlv_len);
+ if (!resp)
+ return;
+ hdr = wpabuf_head(respData);
+ wpabuf_put_u8(resp, *hdr++); /* Code */
+ wpabuf_put_u8(resp, *hdr++); /* Identifier */
+ wpabuf_put_be16(resp, WPA_GET_BE16(hdr) - 4 - outer_tlv_len);
+ hdr += 2;
+ wpabuf_put_u8(resp, *hdr++); /* Type */
+ /* Flags | Ver */
+ wpabuf_put_u8(resp, flags & ~EAP_TEAP_FLAGS_OUTER_TLV_LEN);
+
+ if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
+ wpabuf_put_be32(resp, message_len - 4 - outer_tlv_len);
+
+ wpabuf_put_data(resp, pos, len - outer_tlv_len);
+ pos += len - outer_tlv_len;
+ wpabuf_free(data->peer_outer_tlvs);
+ data->peer_outer_tlvs = wpabuf_alloc_copy(pos, outer_tlv_len);
+ if (!data->peer_outer_tlvs)
+ return;
+ wpa_hexdump_buf(MSG_DEBUG, "EAP-TEAP: Outer TLVs",
+ data->peer_outer_tlvs);
+
+ wpa_hexdump_buf(MSG_DEBUG,
+ "EAP-TEAP: TLS Data message after Outer TLV removal",
+ resp);
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TEAP, resp,
+ &len);
+ if (!pos || len < 1) {
+ wpa_printf(MSG_INFO,
+ "EAP-TEAP: Invalid frame after Outer TLV removal");
+ return;
+ }
+ }
+
+ if (data->state == PHASE1)
+ eap_teap_state(data, PHASE1B);
+
+ if (eap_server_tls_process(sm, &data->ssl, resp, data,
+ EAP_TYPE_TEAP, eap_teap_process_version,
+ eap_teap_process_msg) < 0)
+ eap_teap_state(data, FAILURE);
+
+ if (resp != respData)
+ wpabuf_free(resp);
+}
+
+
+static bool eap_teap_isDone(struct eap_sm *sm, void *priv)
+{
+ struct eap_teap_data *data = priv;
+
+ return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_teap_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_teap_data *data = priv;
+ u8 *eapKeyData;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ eapKeyData = os_malloc(EAP_TEAP_KEY_LEN);
+ if (!eapKeyData)
+ return NULL;
+
+ /* FIX: RFC 7170 does not describe whether MSK or EMSK based S-IMCK[j]
+ * is used in this derivation */
+ if (eap_teap_derive_eap_msk(data->tls_cs, data->simck_msk,
+ eapKeyData) < 0) {
+ os_free(eapKeyData);
+ return NULL;
+ }
+ *len = EAP_TEAP_KEY_LEN;
+
+ return eapKeyData;
+}
+
+
+static u8 * eap_teap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_teap_data *data = priv;
+ u8 *eapKeyData;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ eapKeyData = os_malloc(EAP_EMSK_LEN);
+ if (!eapKeyData)
+ return NULL;
+
+ /* FIX: RFC 7170 does not describe whether MSK or EMSK based S-IMCK[j]
+ * is used in this derivation */
+ if (eap_teap_derive_eap_emsk(data->tls_cs, data->simck_msk,
+ eapKeyData) < 0) {
+ os_free(eapKeyData);
+ return NULL;
+ }
+ *len = EAP_EMSK_LEN;
+
+ return eapKeyData;
+}
+
+
+static bool eap_teap_isSuccess(struct eap_sm *sm, void *priv)
+{
+ struct eap_teap_data *data = priv;
+
+ return data->state == SUCCESS;
+}
+
+
+static u8 * eap_teap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_teap_data *data = priv;
+ const size_t max_id_len = 100;
+ int res;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ id = os_malloc(max_id_len);
+ if (!id)
+ return NULL;
+
+ id[0] = EAP_TYPE_TEAP;
+ res = tls_get_tls_unique(data->ssl.conn, id + 1, max_id_len - 1);
+ if (res < 0) {
+ os_free(id);
+ wpa_printf(MSG_ERROR, "EAP-TEAP: Failed to derive Session-Id");
+ return NULL;
+ }
+
+ *len = 1 + res;
+ wpa_hexdump(MSG_DEBUG, "EAP-TEAP: Derived Session-Id", id, *len);
+ return id;
+}
+
+
+int eap_server_teap_register(void)
+{
+ struct eap_method *eap;
+
+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_TEAP, "TEAP");
+ if (!eap)
+ return -1;
+
+ eap->init = eap_teap_init;
+ eap->reset = eap_teap_reset;
+ eap->buildReq = eap_teap_buildReq;
+ eap->check = eap_teap_check;
+ eap->process = eap_teap_process;
+ eap->isDone = eap_teap_isDone;
+ eap->getKey = eap_teap_getKey;
+ eap->get_emsk = eap_teap_get_emsk;
+ eap->isSuccess = eap_teap_isSuccess;
+ eap->getSessionId = eap_teap_get_session_id;
+
+ return eap_server_method_register(eap);
+}
diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c
index 357e72a..769fd1f 100644
--- a/src/eap_server/eap_server_tls.c
+++ b/src/eap_server/eap_server_tls.c
@@ -58,7 +58,7 @@
{
struct wpabuf *buf;
- if (!sm->tls_session_lifetime)
+ if (!sm->cfg->tls_session_lifetime)
return;
buf = wpabuf_alloc(1);
@@ -187,7 +187,8 @@
case START:
return eap_tls_build_start(sm, data, id);
case CONTINUE:
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
+ if (tls_connection_established(sm->cfg->ssl_ctx,
+ data->ssl.conn))
data->established = 1;
break;
default:
@@ -225,8 +226,8 @@
}
-static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_tls_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
struct eap_tls_data *data = priv;
const u8 *pos;
@@ -245,10 +246,10 @@
respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -261,8 +262,43 @@
"handshake message");
return;
}
- if (eap_server_tls_phase1(sm, &data->ssl) < 0)
+ if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
eap_tls_state(data, FAILURE);
+ return;
+ }
+
+ if (data->ssl.tls_v13 &&
+ tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn)) {
+ struct wpabuf *plain, *encr;
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: Send empty application data to indicate end of exchange");
+ /* FIX: This should be an empty application data based on
+ * draft-ietf-emu-eap-tls13-05, but OpenSSL does not allow zero
+ * length payload (SSL_write() documentation explicitly
+ * describes this as not allowed), so work around that for now
+ * by sending out a payload of one octet. Hopefully the draft
+ * specification will change to allow this so that no crypto
+ * library changes are needed. */
+ plain = wpabuf_alloc(1);
+ if (!plain)
+ return;
+ wpabuf_put_u8(plain, 0);
+ encr = eap_server_tls_encrypt(sm, &data->ssl, plain);
+ wpabuf_free(plain);
+ if (!encr)
+ return;
+ if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr)) < 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-TLS: Failed to resize output buffer");
+ wpabuf_free(encr);
+ return;
+ }
+ wpabuf_put_buf(data->ssl.tls_out, encr);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "EAP-TLS: Data appended to the message", encr);
+ wpabuf_free(encr);
+ }
}
@@ -280,8 +316,8 @@
return;
}
- if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
- !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+ if (!tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
+ !tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn))
return;
buf = tls_connection_get_success_data(data->ssl.conn);
@@ -310,7 +346,7 @@
}
-static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv)
+static bool eap_tls_isDone(struct eap_sm *sm, void *priv)
{
struct eap_tls_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -322,16 +358,22 @@
struct eap_tls_data *data = priv;
u8 *eapKeyData;
const char *label;
+ const u8 eap_tls13_context[] = { EAP_TYPE_TLS };
+ const u8 *context = NULL;
+ size_t context_len = 0;
if (data->state != SUCCESS)
return NULL;
- if (data->ssl.tls_v13)
+ if (data->ssl.tls_v13) {
label = "EXPORTER_EAP_TLS_Key_Material";
- else
+ context = eap_tls13_context;
+ context_len = 1;
+ } else {
label = "client EAP encryption";
+ }
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, label,
- NULL, 0,
+ context, context_len,
EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
*len = EAP_TLS_KEY_LEN;
@@ -351,16 +393,22 @@
struct eap_tls_data *data = priv;
u8 *eapKeyData, *emsk;
const char *label;
+ const u8 eap_tls13_context[] = { EAP_TYPE_TLS };
+ const u8 *context = NULL;
+ size_t context_len = 0;
if (data->state != SUCCESS)
return NULL;
- if (data->ssl.tls_v13)
+ if (data->ssl.tls_v13) {
label = "EXPORTER_EAP_TLS_Key_Material";
- else
+ context = eap_tls13_context;
+ context_len = 1;
+ } else {
label = "client EAP encryption";
+ }
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, label,
- NULL, 0,
+ context, context_len,
EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
emsk = os_malloc(EAP_EMSK_LEN);
@@ -383,7 +431,7 @@
}
-static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_tls_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_tls_data *data = priv;
return data->state == SUCCESS;
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index 0eca0ff..b38f1e0 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -18,7 +18,7 @@
static void eap_server_tls_free_in_buf(struct eap_ssl_data *data);
-struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+struct wpabuf * eap_tls_msg_alloc(enum eap_type type, size_t payload_len,
u8 code, u8 identifier)
{
if (type == EAP_UNAUTH_TLS_TYPE)
@@ -47,9 +47,9 @@
int verify_peer, int eap_type)
{
u8 session_ctx[8];
- unsigned int flags = sm->tls_flags;
+ unsigned int flags = sm->cfg->tls_flags;
- if (sm->ssl_ctx == NULL) {
+ if (!sm->cfg->ssl_ctx) {
wpa_printf(MSG_ERROR, "TLS context not initialized - cannot use TLS-based EAP method");
return -1;
}
@@ -57,7 +57,7 @@
data->eap = sm;
data->phase2 = sm->init_phase2;
- data->conn = tls_connection_init(sm->ssl_ctx);
+ data->conn = tls_connection_init(sm->cfg->ssl_ctx);
if (data->conn == NULL) {
wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
"connection");
@@ -75,17 +75,18 @@
flags |= TLS_CONN_DISABLE_SESSION_TICKET;
os_memcpy(session_ctx, "hostapd", 7);
session_ctx[7] = (u8) eap_type;
- if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer,
+ if (tls_connection_set_verify(sm->cfg->ssl_ctx, data->conn, verify_peer,
flags, session_ctx,
sizeof(session_ctx))) {
wpa_printf(MSG_INFO, "SSL: Failed to configure verification "
"of TLS peer certificate");
- tls_connection_deinit(sm->ssl_ctx, data->conn);
+ tls_connection_deinit(sm->cfg->ssl_ctx, data->conn);
data->conn = NULL;
return -1;
}
- data->tls_out_limit = sm->fragment_size > 0 ? sm->fragment_size : 1398;
+ data->tls_out_limit = sm->cfg->fragment_size > 0 ?
+ sm->cfg->fragment_size : 1398;
if (data->phase2) {
/* Limit the fragment size in the inner TLS authentication
* since the outer authentication with EAP-PEAP does not yet
@@ -99,7 +100,7 @@
void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
{
- tls_connection_deinit(sm->ssl_ctx, data->conn);
+ tls_connection_deinit(sm->cfg->ssl_ctx, data->conn);
eap_server_tls_free_in_buf(data);
wpabuf_free(data->tls_out);
data->tls_out = NULL;
@@ -116,7 +117,7 @@
if (out == NULL)
return NULL;
- if (tls_connection_export_key(sm->ssl_ctx, data->conn, label,
+ if (tls_connection_export_key(sm->cfg->ssl_ctx, data->conn, label,
context, context_len, out, len)) {
os_free(out);
return NULL;
@@ -145,20 +146,21 @@
{
struct tls_random keys;
u8 *out;
+ const u8 context[] = { EAP_TYPE_TLS };
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)
+ * Type-Code, 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);
+ sm, data, "EXPORTER_EAP_TLS_Method-Id", context, 1, 64);
if (!method_id) {
os_free(id);
return NULL;
@@ -169,7 +171,7 @@
return id;
}
- if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys))
+ if (tls_connection_get_random(sm->cfg->ssl_ctx, data->conn, &keys))
return NULL;
if (keys.client_random == NULL || keys.server_random == NULL)
@@ -339,29 +341,30 @@
WPA_ASSERT(data->tls_out == NULL);
}
- data->tls_out = tls_connection_server_handshake(sm->ssl_ctx,
+ data->tls_out = tls_connection_server_handshake(sm->cfg->ssl_ctx,
data->conn,
data->tls_in, NULL);
if (data->tls_out == NULL) {
wpa_printf(MSG_INFO, "SSL: TLS processing failed");
return -1;
}
- if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
+ if (tls_connection_get_failed(sm->cfg->ssl_ctx, data->conn)) {
/* TLS processing has failed - return error */
wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
"report error");
return -1;
}
- if (tls_get_version(sm->ssl_ctx, data->conn, buf, sizeof(buf)) == 0) {
+ if (tls_get_version(sm->cfg->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);
+ tls_connection_established(sm->cfg->ssl_ctx, data->conn))
+ sm->serial_num = tls_connection_peer_serial_num(
+ sm->cfg->ssl_ctx, data->conn);
return 0;
}
@@ -373,6 +376,8 @@
unsigned int tls_msg_len = 0;
const u8 *end = *pos + *left;
+ wpa_hexdump(MSG_MSGDUMP, "SSL: Received data", *pos, *left);
+
if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
if (*left < 4) {
wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
@@ -448,8 +453,7 @@
{
struct wpabuf *buf;
- buf = tls_connection_encrypt(sm->ssl_ctx, data->conn,
- plain);
+ buf = tls_connection_encrypt(sm->cfg->ssl_ctx, data->conn, plain);
if (buf == NULL) {
wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data");
return NULL;
@@ -503,7 +507,7 @@
if (proc_msg)
proc_msg(sm, priv, respData);
- if (tls_connection_get_write_alerts(sm->ssl_ctx, data->conn) > 1) {
+ if (tls_connection_get_write_alerts(sm->cfg->ssl_ctx, data->conn) > 1) {
wpa_printf(MSG_INFO, "SSL: Locally detected fatal error in "
"TLS processing");
res = -1;
diff --git a/src/eap_server/eap_server_tnc.c b/src/eap_server/eap_server_tnc.c
index b568558..36fb5c3 100644
--- a/src/eap_server/eap_server_tnc.c
+++ b/src/eap_server/eap_server_tnc.c
@@ -84,8 +84,8 @@
return NULL;
}
- data->fragment_size = sm->fragment_size > 100 ?
- sm->fragment_size - 98 : 1300;
+ data->fragment_size = sm->cfg->fragment_size > 100 ?
+ sm->cfg->fragment_size - 98 : 1300;
return data;
}
@@ -320,8 +320,8 @@
}
-static Boolean eap_tnc_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_tnc_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
struct eap_tnc_data *data = priv;
const u8 *pos;
@@ -331,29 +331,29 @@
&len);
if (pos == NULL) {
wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame");
- return TRUE;
+ return true;
}
if (len == 0 && data->state != WAIT_FRAG_ACK) {
wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (empty)");
- return TRUE;
+ return true;
}
if (len == 0)
- return FALSE; /* Fragment ACK does not include flags */
+ return false; /* Fragment ACK does not include flags */
if ((*pos & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d",
*pos & EAP_TNC_VERSION_MASK);
- return TRUE;
+ return true;
}
if (*pos & EAP_TNC_FLAGS_START) {
wpa_printf(MSG_DEBUG, "EAP-TNC: Peer used Start flag");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -508,7 +508,7 @@
eap_tnc_set_state(data, FAIL);
return;
}
-
+
if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
if (eap_tnc_process_fragment(data, flags, message_length,
pos, end - pos) < 0)
@@ -537,14 +537,14 @@
}
-static Boolean eap_tnc_isDone(struct eap_sm *sm, void *priv)
+static bool eap_tnc_isDone(struct eap_sm *sm, void *priv)
{
struct eap_tnc_data *data = priv;
return data->state == DONE || data->state == FAIL;
}
-static Boolean eap_tnc_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_tnc_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_tnc_data *data = priv;
return data->state == DONE;
diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c
index 52bff8a..2f0c041 100644
--- a/src/eap_server/eap_server_ttls.c
+++ b/src/eap_server/eap_server_ttls.c
@@ -81,7 +81,7 @@
{
struct wpabuf *buf;
- if (!sm->tls_session_lifetime)
+ if (!sm->cfg->tls_session_lifetime)
return;
buf = wpabuf_alloc(1 + 1 + sm->identity_len);
@@ -480,7 +480,8 @@
case START:
return eap_ttls_build_start(sm, data, id);
case PHASE1:
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ if (tls_connection_established(sm->cfg->ssl_ctx,
+ data->ssl.conn)) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase1 done, "
"starting Phase2");
eap_ttls_state(data, PHASE2_START);
@@ -508,8 +509,8 @@
}
-static Boolean eap_ttls_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_ttls_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
const u8 *pos;
size_t len;
@@ -517,10 +518,10 @@
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TTLS, respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-TTLS: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -827,15 +828,14 @@
static int eap_ttls_phase2_eap_init(struct eap_sm *sm,
struct eap_ttls_data *data,
- EapType eap_type)
+ int vendor, enum eap_type eap_type)
{
if (data->phase2_priv && data->phase2_method) {
data->phase2_method->reset(sm, data->phase2_priv);
data->phase2_method = NULL;
data->phase2_priv = NULL;
}
- data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
- eap_type);
+ data->phase2_method = eap_server_get_eap_method(vendor, eap_type);
if (!data->phase2_method)
return -1;
@@ -850,7 +850,8 @@
struct eap_ttls_data *data,
u8 *in_data, size_t in_len)
{
- u8 next_type = EAP_TYPE_NONE;
+ int next_vendor = EAP_VENDOR_IETF;
+ enum eap_type next_type = EAP_TYPE_NONE;
struct eap_hdr *hdr;
u8 *pos;
size_t left;
@@ -875,14 +876,17 @@
if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
sm->user->methods[sm->user_eap_method_index].method !=
EAP_TYPE_NONE) {
+ next_vendor = sm->user->methods[
+ sm->user_eap_method_index].vendor;
next_type = sm->user->methods[
sm->user_eap_method_index++].method;
- wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d",
- next_type);
- if (eap_ttls_phase2_eap_init(sm, data, next_type)) {
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to "
- "initialize EAP type %d",
- next_type);
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %u:%u",
+ next_vendor, next_type);
+ if (eap_ttls_phase2_eap_init(sm, data, next_vendor,
+ next_type)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: Failed to initialize EAP type %u:%u",
+ next_vendor, next_type);
eap_ttls_state(data, FAILURE);
return;
}
@@ -930,12 +934,16 @@
}
eap_ttls_state(data, PHASE2_METHOD);
+ next_vendor = sm->user->methods[0].vendor;
next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
- wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d", next_type);
- if (eap_ttls_phase2_eap_init(sm, data, next_type)) {
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize "
- "EAP type %d", next_type);
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %u:%u",
+ next_vendor, next_type);
+ if (eap_ttls_phase2_eap_init(sm, data, next_vendor,
+ next_type)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: Failed to initialize EAP type %u:%u",
+ next_vendor, next_type);
eap_ttls_state(data, FAILURE);
}
break;
@@ -962,8 +970,8 @@
if (data->state == PHASE2_START) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: initializing Phase 2");
- if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_IDENTITY) < 0)
- {
+ if (eap_ttls_phase2_eap_init(sm, data, EAP_VENDOR_IETF,
+ EAP_TYPE_IDENTITY) < 0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: failed to "
"initialize EAP-Identity");
return;
@@ -1022,7 +1030,7 @@
return;
}
- in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ in_decrypted = tls_connection_decrypt(sm->cfg->ssl_ctx, data->ssl.conn,
in_buf);
if (in_decrypted == NULL) {
wpa_printf(MSG_INFO, "EAP-TTLS: Failed to decrypt Phase 2 "
@@ -1112,11 +1120,11 @@
static void eap_ttls_start_tnc(struct eap_sm *sm, struct eap_ttls_data *data)
{
#ifdef EAP_SERVER_TNC
- if (!sm->tnc || data->state != SUCCESS || data->tnc_started)
+ if (!sm->cfg->tnc || data->state != SUCCESS || data->tnc_started)
return;
wpa_printf(MSG_DEBUG, "EAP-TTLS: Initialize TNC");
- if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_TNC)) {
+ if (eap_ttls_phase2_eap_init(sm, data, EAP_VENDOR_IETF, EAP_TYPE_TNC)) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize TNC");
eap_ttls_state(data, FAILURE);
return;
@@ -1202,8 +1210,8 @@
return;
}
- if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
- !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
+ if (!tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
+ !tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn))
return;
buf = tls_connection_get_success_data(data->ssl.conn);
@@ -1252,7 +1260,7 @@
}
-static Boolean eap_ttls_isDone(struct eap_sm *sm, void *priv)
+static bool eap_ttls_isDone(struct eap_sm *sm, void *priv)
{
struct eap_ttls_data *data = priv;
return data->state == SUCCESS || data->state == FAILURE;
@@ -1282,7 +1290,7 @@
}
-static Boolean eap_ttls_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_ttls_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_ttls_data *data = priv;
return data->state == SUCCESS;
diff --git a/src/eap_server/eap_server_vendor_test.c b/src/eap_server/eap_server_vendor_test.c
index 9639977..7786041 100644
--- a/src/eap_server/eap_server_vendor_test.c
+++ b/src/eap_server/eap_server_vendor_test.c
@@ -88,8 +88,8 @@
}
-static Boolean eap_vendor_test_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_vendor_test_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
const u8 *pos;
size_t len;
@@ -97,10 +97,10 @@
pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE, respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-VENDOR-TEST: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -130,7 +130,7 @@
}
-static Boolean eap_vendor_test_isDone(struct eap_sm *sm, void *priv)
+static bool eap_vendor_test_isDone(struct eap_sm *sm, void *priv)
{
struct eap_vendor_test_data *data = priv;
return data->state == SUCCESS;
@@ -158,7 +158,7 @@
}
-static Boolean eap_vendor_test_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_vendor_test_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_vendor_test_data *data = priv;
return data->state == SUCCESS;
diff --git a/src/eap_server/eap_server_wsc.c b/src/eap_server/eap_server_wsc.c
index 4a5cb98..fc70cf1 100644
--- a/src/eap_server/eap_server_wsc.c
+++ b/src/eap_server/eap_server_wsc.c
@@ -103,10 +103,10 @@
data->registrar = registrar;
os_memset(&cfg, 0, sizeof(cfg));
- cfg.wps = sm->wps;
+ cfg.wps = sm->cfg->wps;
cfg.registrar = registrar;
if (registrar) {
- if (sm->wps == NULL || sm->wps->registrar == NULL) {
+ if (!sm->cfg->wps || !sm->cfg->wps->registrar) {
wpa_printf(MSG_INFO, "EAP-WSC: WPS Registrar not "
"initialized");
os_free(data);
@@ -138,14 +138,14 @@
cfg.p2p_dev_addr = p2p_get_go_dev_addr(sm->assoc_p2p_ie);
}
#endif /* CONFIG_P2P */
- cfg.pbc_in_m1 = sm->pbc_in_m1;
+ cfg.pbc_in_m1 = sm->cfg->pbc_in_m1;
data->wps = wps_init(&cfg);
if (data->wps == NULL) {
os_free(data);
return NULL;
}
- data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size :
- WSC_FRAGMENT_SIZE;
+ data->fragment_size = sm->cfg->fragment_size > 0 ?
+ sm->cfg->fragment_size : WSC_FRAGMENT_SIZE;
return data;
}
@@ -270,8 +270,8 @@
}
-static Boolean eap_wsc_check(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static bool eap_wsc_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
{
const u8 *pos;
size_t len;
@@ -280,10 +280,10 @@
respData, &len);
if (pos == NULL || len < 2) {
wpa_printf(MSG_INFO, "EAP-WSC: Invalid frame");
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -462,17 +462,17 @@
}
-static Boolean eap_wsc_isDone(struct eap_sm *sm, void *priv)
+static bool eap_wsc_isDone(struct eap_sm *sm, void *priv)
{
struct eap_wsc_data *data = priv;
return data->state == FAIL;
}
-static Boolean eap_wsc_isSuccess(struct eap_sm *sm, void *priv)
+static bool eap_wsc_isSuccess(struct eap_sm *sm, void *priv)
{
/* EAP-WSC will always result in EAP-Failure */
- return FALSE;
+ return false;
}
diff --git a/src/eap_server/eap_tls_common.h b/src/eap_server/eap_tls_common.h
index 0b04983..b0b7361 100644
--- a/src/eap_server/eap_tls_common.h
+++ b/src/eap_server/eap_tls_common.h
@@ -62,6 +62,7 @@
#define EAP_TLS_FLAGS_LENGTH_INCLUDED 0x80
#define EAP_TLS_FLAGS_MORE_FRAGMENTS 0x40
#define EAP_TLS_FLAGS_START 0x20
+#define EAP_TEAP_FLAGS_OUTER_TLV_LEN 0x10
#define EAP_TLS_VERSION_MASK 0x07
/* could be up to 128 bytes, but only the first 64 bytes are used */
@@ -72,7 +73,7 @@
#define EAP_WFA_UNAUTH_TLS_TYPE 254
-struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+struct wpabuf * eap_tls_msg_alloc(enum eap_type type, size_t payload_len,
u8 code, u8 identifier);
int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
int verify_peer, int eap_type);
diff --git a/src/eap_server/tncs.c b/src/eap_server/tncs.c
index 942a195..4a30486 100644
--- a/src/eap_server/tncs.c
+++ b/src/eap_server/tncs.c
@@ -179,7 +179,7 @@
TNC_MessageType messageType)
{
struct tncs_data *tncs;
- unsigned char *b64;
+ char *b64;
size_t b64len;
wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage(imvID=%lu "
@@ -678,8 +678,7 @@
return NULL;
*pos2 = '\0';
- decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
- decoded_len);
+ decoded = base64_decode(pos, os_strlen(pos), decoded_len);
*pos2 = '<';
if (decoded == NULL) {
wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index 36074d3..e3a57e7 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -206,10 +206,10 @@
* get here on disconnection event without advancing to the
* AUTHENTICATING state to clear keyRun before the IEEE 802.11 RSN
* authenticator state machine runs and that may advance from
- * AUTHENTICATION2 to INITPMK if keyRun = TRUE has been left from the
+ * AUTHENTICATION2 to INITPMK if keyRun = true has been left from the
* last association. This can be avoided by clearing keyRun here.
*/
- sm->keyRun = FALSE;
+ sm->keyRun = false;
}
@@ -229,7 +229,7 @@
sm->authPortStatus = Unauthorized;
setPortUnauthorized();
sm->reAuthCount = 0;
- sm->eapolLogoff = FALSE;
+ sm->eapolLogoff = false;
if (!from_initialize) {
sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
sm->flags & EAPOL_SM_PREAUTH,
@@ -251,7 +251,7 @@
SM_ENTRY_MA(AUTH_PAE, RESTART, auth_pae);
- sm->eap_if->eapRestart = TRUE;
+ sm->eap_if->eapRestart = true;
}
@@ -262,7 +262,7 @@
SM_ENTRY_MA(AUTH_PAE, CONNECTING, auth_pae);
- sm->reAuthenticate = FALSE;
+ sm->reAuthenticate = false;
sm->reAuthCount++;
}
@@ -277,7 +277,7 @@
sm->authPortStatus = Unauthorized;
setPortUnauthorized();
sm->quietWhile = sm->quietPeriod;
- sm->eapolLogoff = FALSE;
+ sm->eapolLogoff = false;
eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_WARNING,
"authentication failed - EAP type: %d (%s)",
@@ -300,7 +300,7 @@
if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authSuccess)
sm->authAuthSuccessesWhileAuthenticating++;
-
+
SM_ENTRY_MA(AUTH_PAE, AUTHENTICATED, auth_pae);
sm->authPortStatus = Authorized;
@@ -324,13 +324,13 @@
{
SM_ENTRY_MA(AUTH_PAE, AUTHENTICATING, auth_pae);
- sm->eapolStart = FALSE;
- sm->authSuccess = FALSE;
- sm->authFail = FALSE;
- sm->authTimeout = FALSE;
- sm->authStart = TRUE;
- sm->keyRun = FALSE;
- sm->keyDone = FALSE;
+ sm->eapolStart = false;
+ sm->authSuccess = false;
+ sm->authFail = false;
+ sm->authTimeout = false;
+ sm->authStart = true;
+ sm->keyRun = false;
+ sm->keyDone = false;
}
@@ -347,9 +347,9 @@
SM_ENTRY_MA(AUTH_PAE, ABORTING, auth_pae);
- sm->authAbort = TRUE;
- sm->keyRun = FALSE;
- sm->keyDone = FALSE;
+ sm->authAbort = true;
+ sm->keyRun = false;
+ sm->keyDone = false;
}
@@ -360,7 +360,7 @@
sm->authPortStatus = Authorized;
setPortAuthorized();
sm->portMode = ForceAuthorized;
- sm->eapolStart = FALSE;
+ sm->eapolStart = false;
txCannedSuccess();
}
@@ -372,7 +372,7 @@
sm->authPortStatus = Unauthorized;
setPortUnauthorized();
sm->portMode = ForceUnauthorized;
- sm->eapolStart = FALSE;
+ sm->eapolStart = false;
txCannedFail();
}
@@ -457,8 +457,8 @@
SM_ENTRY_MA(BE_AUTH, INITIALIZE, be_auth);
abortAuth();
- sm->eap_if->eapNoReq = FALSE;
- sm->authAbort = FALSE;
+ sm->eap_if->eapNoReq = false;
+ sm->authAbort = false;
}
@@ -467,7 +467,7 @@
SM_ENTRY_MA(BE_AUTH, REQUEST, be_auth);
txReq();
- sm->eap_if->eapReq = FALSE;
+ sm->eap_if->eapReq = false;
sm->backendOtherRequestsToSupplicant++;
/*
@@ -481,7 +481,7 @@
* EAP-Request from the main EAP method. This can be avoided by
* clearing eapolEap here.
*/
- sm->eapolEap = FALSE;
+ sm->eapolEap = false;
}
@@ -489,11 +489,11 @@
{
SM_ENTRY_MA(BE_AUTH, RESPONSE, be_auth);
- sm->authTimeout = FALSE;
- sm->eapolEap = FALSE;
- sm->eap_if->eapNoReq = FALSE;
+ sm->authTimeout = false;
+ sm->eapolEap = false;
+ sm->eap_if->eapNoReq = false;
sm->aWhile = sm->serverTimeout;
- sm->eap_if->eapResp = TRUE;
+ sm->eap_if->eapResp = true;
/* sendRespToServer(); */
sm->backendResponses++;
}
@@ -504,8 +504,8 @@
SM_ENTRY_MA(BE_AUTH, SUCCESS, be_auth);
txReq();
- sm->authSuccess = TRUE;
- sm->keyRun = TRUE;
+ sm->authSuccess = true;
+ sm->keyRun = true;
}
@@ -514,7 +514,7 @@
SM_ENTRY_MA(BE_AUTH, FAIL, be_auth);
txReq();
- sm->authFail = TRUE;
+ sm->authFail = true;
}
@@ -522,7 +522,7 @@
{
SM_ENTRY_MA(BE_AUTH, TIMEOUT, be_auth);
- sm->authTimeout = TRUE;
+ sm->authTimeout = true;
}
@@ -530,7 +530,7 @@
{
SM_ENTRY_MA(BE_AUTH, IDLE, be_auth);
- sm->authStart = FALSE;
+ sm->authStart = false;
}
@@ -538,7 +538,7 @@
{
SM_ENTRY_MA(BE_AUTH, IGNORE, be_auth);
- sm->eap_if->eapNoReq = FALSE;
+ sm->eap_if->eapNoReq = false;
}
@@ -621,7 +621,7 @@
{
SM_ENTRY_MA(REAUTH_TIMER, REAUTHENTICATE, reauth_timer);
- sm->reAuthenticate = TRUE;
+ sm->reAuthenticate = true;
sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta,
EAPOL_AUTH_REAUTHENTICATE);
}
@@ -648,6 +648,8 @@
+#ifdef CONFIG_WEP
+
/* Authenticator Key Transmit state machine */
SM_STATE(AUTH_KEY_TX, NO_KEY_TRANSMIT)
@@ -661,8 +663,8 @@
SM_ENTRY_MA(AUTH_KEY_TX, KEY_TRANSMIT, auth_key_tx);
txKey();
- sm->eap_if->eapKeyAvailable = FALSE;
- sm->keyDone = TRUE;
+ sm->eap_if->eapKeyAvailable = false;
+ sm->keyDone = true;
}
@@ -703,7 +705,7 @@
SM_ENTRY_MA(KEY_RX, KEY_RECEIVE, key_rx);
processKey();
- sm->rxKey = FALSE;
+ sm->rxKey = false;
}
@@ -726,6 +728,8 @@
}
}
+#endif /* CONFIG_WEP */
+
/* Controlled Directions state machine */
@@ -775,7 +779,7 @@
const char *identity, const char *radius_cui)
{
struct eapol_state_machine *sm;
- struct eap_config eap_conf;
+ struct eap_session_data eap_sess;
if (eapol == NULL)
return NULL;
@@ -803,7 +807,7 @@
sm->reauth_timer_state = REAUTH_TIMER_INITIALIZE;
sm->reAuthPeriod = eapol->conf.eap_reauth_period;
- sm->reAuthEnabled = eapol->conf.eap_reauth_period > 0 ? TRUE : FALSE;
+ sm->reAuthEnabled = eapol->conf.eap_reauth_period > 0;
sm->auth_key_tx_state = AUTH_KEY_TX_NO_KEY_TRANSMIT;
@@ -813,43 +817,24 @@
sm->portControl = Auto;
+#ifdef CONFIG_WEP
if (!eapol->conf.wpa &&
(eapol->default_wep_key || eapol->conf.individual_wep_key_len > 0))
- sm->keyTxEnabled = TRUE;
+ sm->keyTxEnabled = true;
else
- sm->keyTxEnabled = FALSE;
+#endif /* CONFIG_WEP */
+ sm->keyTxEnabled = false;
if (eapol->conf.wpa)
- sm->portValid = FALSE;
+ sm->portValid = false;
else
- sm->portValid = TRUE;
+ sm->portValid = true;
- os_memset(&eap_conf, 0, sizeof(eap_conf));
- eap_conf.eap_server = eapol->conf.eap_server;
- eap_conf.ssl_ctx = eapol->conf.ssl_ctx;
- eap_conf.msg_ctx = eapol->conf.msg_ctx;
- eap_conf.eap_sim_db_priv = eapol->conf.eap_sim_db_priv;
- eap_conf.pac_opaque_encr_key = eapol->conf.pac_opaque_encr_key;
- eap_conf.eap_fast_a_id = eapol->conf.eap_fast_a_id;
- eap_conf.eap_fast_a_id_len = eapol->conf.eap_fast_a_id_len;
- eap_conf.eap_fast_a_id_info = eapol->conf.eap_fast_a_id_info;
- eap_conf.eap_fast_prov = eapol->conf.eap_fast_prov;
- eap_conf.pac_key_lifetime = eapol->conf.pac_key_lifetime;
- eap_conf.pac_key_refresh_time = eapol->conf.pac_key_refresh_time;
- eap_conf.eap_sim_aka_result_ind = eapol->conf.eap_sim_aka_result_ind;
- eap_conf.tnc = eapol->conf.tnc;
- eap_conf.wps = eapol->conf.wps;
- eap_conf.assoc_wps_ie = assoc_wps_ie;
- eap_conf.assoc_p2p_ie = assoc_p2p_ie;
- eap_conf.peer_addr = addr;
- eap_conf.fragment_size = eapol->conf.fragment_size;
- eap_conf.pwd_group = eapol->conf.pwd_group;
- eap_conf.pbc_in_m1 = eapol->conf.pbc_in_m1;
- eap_conf.server_id = eapol->conf.server_id;
- eap_conf.server_id_len = eapol->conf.server_id_len;
- eap_conf.erp = eapol->conf.erp;
- eap_conf.tls_session_lifetime = eapol->conf.tls_session_lifetime;
- eap_conf.tls_flags = eapol->conf.tls_flags;
- sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
+ os_memset(&eap_sess, 0, sizeof(eap_sess));
+ eap_sess.assoc_wps_ie = assoc_wps_ie;
+ eap_sess.assoc_p2p_ie = assoc_p2p_ie;
+ eap_sess.peer_addr = addr;
+ sm->eap = eap_server_sm_init(sm, &eapol_cb, eapol->conf.eap_cfg,
+ &eap_sess);
if (sm->eap == NULL) {
eapol_auth_free(sm);
return NULL;
@@ -931,10 +916,12 @@
SM_STEP_RUN(BE_AUTH);
if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
SM_STEP_RUN(REAUTH_TIMER);
+#ifdef CONFIG_WEP
if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
SM_STEP_RUN(AUTH_KEY_TX);
if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
SM_STEP_RUN(KEY_RX);
+#endif /* CONFIG_WEP */
if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
SM_STEP_RUN(CTRL_DIR);
@@ -962,7 +949,7 @@
/* TODO: find a better location for this */
if (sm->eap_if->aaaEapResp) {
- sm->eap_if->aaaEapResp = FALSE;
+ sm->eap_if->aaaEapResp = false;
if (sm->eap_if->aaaEapRespData == NULL) {
wpa_printf(MSG_DEBUG, "EAPOL: aaaEapResp set, "
"but no aaaEapRespData available");
@@ -1009,14 +996,14 @@
static void eapol_auth_initialize(struct eapol_state_machine *sm)
{
- sm->initializing = TRUE;
+ sm->initializing = true;
/* Initialize the state machines by asserting initialize and then
* deasserting it after one step */
- sm->initialize = TRUE;
+ sm->initialize = true;
eapol_sm_step_run(sm);
- sm->initialize = FALSE;
+ sm->initialize = false;
eapol_sm_step_run(sm);
- sm->initializing = FALSE;
+ sm->initializing = false;
/* Start one second tick for port timers state machine */
eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
@@ -1104,7 +1091,7 @@
{
wpa_printf(MSG_DEBUG, "EAPOL: External reauthentication trigger for "
MACSTR, MAC2STR(sm->addr));
- sm->reAuthenticate = TRUE;
+ sm->reAuthenticate = true;
eapol_auth_step(sm);
}
@@ -1157,9 +1144,9 @@
if (os_strcasecmp(param, "reAuthEnabled") == 0) {
if (os_strcmp(value, "TRUE") == 0)
- sm->reAuthEnabled = TRUE;
+ sm->reAuthEnabled = true;
else if (os_strcmp(value, "FALSE") == 0)
- sm->reAuthEnabled = FALSE;
+ sm->reAuthEnabled = false;
else
return -1;
eapol_auth_step(sm);
@@ -1168,9 +1155,9 @@
if (os_strcasecmp(param, "KeyTransmissionEnabled") == 0) {
if (os_strcmp(value, "TRUE") == 0)
- sm->keyTxEnabled = TRUE;
+ sm->keyTxEnabled = true;
else if (os_strcmp(value, "FALSE") == 0)
- sm->keyTxEnabled = FALSE;
+ sm->keyTxEnabled = false;
else
return -1;
eapol_auth_step(sm);
@@ -1184,19 +1171,14 @@
static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
struct eapol_auth_config *src)
{
+ dst->eap_cfg = src->eap_cfg;
dst->ctx = src->ctx;
dst->eap_reauth_period = src->eap_reauth_period;
dst->wpa = src->wpa;
+#ifdef CONFIG_WEP
dst->individual_wep_key_len = src->individual_wep_key_len;
- dst->eap_server = src->eap_server;
- dst->ssl_ctx = src->ssl_ctx;
- dst->msg_ctx = src->msg_ctx;
- dst->eap_sim_db_priv = src->eap_sim_db_priv;
+#endif /* CONFIG_WEP */
os_free(dst->eap_req_id_text);
- dst->pwd_group = src->pwd_group;
- dst->pbc_in_m1 = src->pbc_in_m1;
- dst->server_id = src->server_id;
- dst->server_id_len = src->server_id_len;
if (src->eap_req_id_text) {
dst->eap_req_id_text = os_memdup(src->eap_req_id_text,
src->eap_req_id_text_len);
@@ -1207,34 +1189,6 @@
dst->eap_req_id_text = NULL;
dst->eap_req_id_text_len = 0;
}
- if (src->pac_opaque_encr_key) {
- dst->pac_opaque_encr_key = os_memdup(src->pac_opaque_encr_key,
- 16);
- if (dst->pac_opaque_encr_key == NULL)
- goto fail;
- } else
- dst->pac_opaque_encr_key = NULL;
- if (src->eap_fast_a_id) {
- dst->eap_fast_a_id = os_memdup(src->eap_fast_a_id,
- src->eap_fast_a_id_len);
- if (dst->eap_fast_a_id == NULL)
- goto fail;
- dst->eap_fast_a_id_len = src->eap_fast_a_id_len;
- } else
- dst->eap_fast_a_id = NULL;
- if (src->eap_fast_a_id_info) {
- dst->eap_fast_a_id_info = os_strdup(src->eap_fast_a_id_info);
- if (dst->eap_fast_a_id_info == NULL)
- goto fail;
- } else
- dst->eap_fast_a_id_info = NULL;
- dst->eap_fast_prov = src->eap_fast_prov;
- dst->pac_key_lifetime = src->pac_key_lifetime;
- dst->pac_key_refresh_time = src->pac_key_refresh_time;
- dst->eap_sim_aka_result_ind = src->eap_sim_aka_result_ind;
- dst->tnc = src->tnc;
- dst->wps = src->wps;
- dst->fragment_size = src->fragment_size;
os_free(dst->erp_domain);
if (src->erp_domain) {
@@ -1245,9 +1199,6 @@
dst->erp_domain = NULL;
}
dst->erp_send_reauth_start = src->erp_send_reauth_start;
- dst->erp = src->erp;
- dst->tls_session_lifetime = src->tls_session_lifetime;
- dst->tls_flags = src->tls_flags;
return 0;
@@ -1261,12 +1212,6 @@
{
os_free(conf->eap_req_id_text);
conf->eap_req_id_text = NULL;
- os_free(conf->pac_opaque_encr_key);
- conf->pac_opaque_encr_key = NULL;
- os_free(conf->eap_fast_a_id);
- conf->eap_fast_a_id = NULL;
- os_free(conf->eap_fast_a_id_info);
- conf->eap_fast_a_id_info = NULL;
os_free(conf->erp_domain);
conf->erp_domain = NULL;
}
@@ -1286,10 +1231,12 @@
return NULL;
}
+#ifdef CONFIG_WEP
if (conf->individual_wep_key_len > 0) {
/* use key0 in individual key and key1 in broadcast key */
eapol->default_wep_key_idx = 1;
}
+#endif /* CONFIG_WEP */
eapol->cb.eapol_send = cb->eapol_send;
eapol->cb.aaa_send = cb->aaa_send;
@@ -1314,6 +1261,8 @@
return;
eapol_auth_conf_free(&eapol->conf);
+#ifdef CONFIG_WEP
os_free(eapol->default_wep_key);
+#endif /* CONFIG_WEP */
os_free(eapol);
}
diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h
index 44f3f31..5fe89c6 100644
--- a/src/eapol_auth/eapol_auth_sm.h
+++ b/src/eapol_auth/eapol_auth_sm.h
@@ -15,35 +15,14 @@
#define EAPOL_SM_FROM_PMKSA_CACHE BIT(3)
struct eapol_auth_config {
+ const struct eap_config *eap_cfg;
int eap_reauth_period;
int wpa;
int individual_wep_key_len;
- int eap_server;
- void *ssl_ctx;
- void *msg_ctx;
- void *eap_sim_db_priv;
char *eap_req_id_text; /* a copy of this will be allocated */
size_t eap_req_id_text_len;
int erp_send_reauth_start;
char *erp_domain; /* a copy of this will be allocated */
- int erp; /* Whether ERP is enabled on authentication server */
- unsigned int tls_session_lifetime;
- unsigned int tls_flags;
- u8 *pac_opaque_encr_key;
- u8 *eap_fast_a_id;
- size_t eap_fast_a_id_len;
- char *eap_fast_a_id_info;
- int eap_fast_prov;
- int pac_key_lifetime;
- int pac_key_refresh_time;
- int eap_sim_aka_result_ind;
- int tnc;
- struct wps_context *wps;
- int fragment_size;
- u16 pwd_group;
- int pbc_in_m1;
- const u8 *server_id;
- size_t server_id_len;
/* Opaque context pointer to owner data for callback functions */
void *ctx;
diff --git a/src/eapol_auth/eapol_auth_sm_i.h b/src/eapol_auth/eapol_auth_sm_i.h
index 04386b2..3c68983 100644
--- a/src/eapol_auth/eapol_auth_sm_i.h
+++ b/src/eapol_auth/eapol_auth_sm_i.h
@@ -43,23 +43,23 @@
int reAuthWhen;
/* global variables */
- Boolean authAbort;
- Boolean authFail;
+ bool authAbort;
+ bool authFail;
PortState authPortStatus;
- Boolean authStart;
- Boolean authTimeout;
- Boolean authSuccess;
- Boolean eapolEap;
- Boolean initialize;
- Boolean keyDone;
- Boolean keyRun;
- Boolean keyTxEnabled;
+ bool authStart;
+ bool authTimeout;
+ bool authSuccess;
+ bool eapolEap;
+ bool initialize;
+ bool keyDone;
+ bool keyRun;
+ bool keyTxEnabled;
PortTypes portControl;
- Boolean portValid;
- Boolean reAuthenticate;
+ bool portValid;
+ bool reAuthenticate;
/* Port Timers state machine */
- /* 'Boolean tick' implicitly handled as registered timeout */
+ /* 'bool tick' implicitly handled as registered timeout */
/* Authenticator PAE state machine */
enum { AUTH_PAE_INITIALIZE, AUTH_PAE_DISCONNECTED, AUTH_PAE_CONNECTING,
@@ -67,8 +67,8 @@
AUTH_PAE_ABORTING, AUTH_PAE_HELD, AUTH_PAE_FORCE_AUTH,
AUTH_PAE_FORCE_UNAUTH, AUTH_PAE_RESTART } auth_pae_state;
/* variables */
- Boolean eapolLogoff;
- Boolean eapolStart;
+ bool eapolLogoff;
+ bool eapolStart;
PortTypes portMode;
unsigned int reAuthCount;
/* constants */
@@ -109,7 +109,7 @@
} reauth_timer_state;
/* constants */
unsigned int reAuthPeriod; /* default 3600 s */
- Boolean reAuthEnabled;
+ bool reAuthEnabled;
/* Authenticator Key Transmit state machine */
enum { AUTH_KEY_TX_NO_KEY_TRANSMIT, AUTH_KEY_TX_KEY_TRANSMIT
@@ -118,14 +118,14 @@
/* Key Receive state machine */
enum { KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE } key_rx_state;
/* variables */
- Boolean rxKey;
+ bool rxKey;
/* Controlled Directions state machine */
enum { CTRL_DIR_FORCE_BOTH, CTRL_DIR_IN_OR_BOTH } ctrl_dir_state;
/* variables */
ControlledDirection adminControlledDirections;
ControlledDirection operControlledDirections;
- Boolean operEdge;
+ bool operEdge;
/* Authenticator Statistics Table */
Counter dot1xAuthEapolFramesRx;
@@ -161,8 +161,8 @@
struct eap_sm *eap;
- Boolean initializing; /* in process of initializing state machines */
- Boolean changed;
+ bool initializing; /* in process of initializing state machines */
+ bool changed;
struct eapol_authenticator *eapol;
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index a0f27fd..861eea2 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -38,21 +38,21 @@
int timer_tick_enabled;
/* Global variables */
- Boolean eapFail;
- Boolean eapolEap;
- Boolean eapSuccess;
- Boolean initialize;
- Boolean keyDone;
- Boolean keyRun;
+ bool eapFail;
+ bool eapolEap;
+ bool eapSuccess;
+ bool initialize;
+ bool keyDone;
+ bool keyRun;
PortControl portControl;
- Boolean portEnabled;
+ bool portEnabled;
PortStatus suppPortStatus; /* dot1xSuppControlledPortStatus */
- Boolean portValid;
- Boolean suppAbort;
- Boolean suppFail;
- Boolean suppStart;
- Boolean suppSuccess;
- Boolean suppTimeout;
+ bool portValid;
+ bool suppAbort;
+ bool suppFail;
+ bool suppStart;
+ bool suppSuccess;
+ bool suppTimeout;
/* Supplicant PAE state machine */
enum {
@@ -69,10 +69,10 @@
SUPP_PAE_S_FORCE_UNAUTH = 10
} SUPP_PAE_state; /* dot1xSuppPaeState */
/* Variables */
- Boolean userLogoff;
- Boolean logoffSent;
+ bool userLogoff;
+ bool logoffSent;
unsigned int startCount;
- Boolean eapRestart;
+ bool eapRestart;
PortControl sPortMode;
/* Constants */
unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
@@ -85,7 +85,7 @@
KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
} KEY_RX_state;
/* Variables */
- Boolean rxKey;
+ bool rxKey;
/* Supplicant Backend state machine */
enum {
@@ -100,9 +100,9 @@
SUPP_BE_SUCCESS = 8
} SUPP_BE_state; /* dot1xSuppBackendPaeState */
/* Variables */
- Boolean eapNoResp;
- Boolean eapReq;
- Boolean eapResp;
+ bool eapNoResp;
+ bool eapReq;
+ bool eapResp;
/* Constants */
unsigned int authPeriod; /* dot1xSuppAuthPeriod */
@@ -120,30 +120,30 @@
unsigned char dot1xSuppLastEapolFrameSource[6];
/* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
- Boolean changed;
+ bool changed;
struct eap_sm *eap;
struct eap_peer_config *config;
- Boolean initial_req;
+ bool initial_req;
u8 *last_rx_key;
size_t last_rx_key_len;
struct wpabuf *eapReqData; /* for EAP */
- Boolean altAccept; /* for EAP */
- Boolean altReject; /* for EAP */
- Boolean eapTriggerStart;
- Boolean replay_counter_valid;
+ bool altAccept; /* for EAP */
+ bool altReject; /* for EAP */
+ bool eapTriggerStart;
+ bool replay_counter_valid;
u8 last_replay_counter[16];
struct eapol_config conf;
struct eapol_ctx *ctx;
enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
cb_status;
- Boolean cached_pmk;
+ bool cached_pmk;
- Boolean unicast_key_received, broadcast_key_received;
+ bool unicast_key_received, broadcast_key_received;
- Boolean force_authorized_update;
+ bool force_authorized_update;
#ifdef CONFIG_EAP_PROXY
- Boolean use_eap_proxy;
+ bool use_eap_proxy;
struct eap_proxy_sm *eap_proxy;
#endif /* CONFIG_EAP_PROXY */
};
@@ -200,6 +200,15 @@
}
+static int eapol_sm_confirm_auth(struct eapol_sm *sm)
+{
+ if (!sm->ctx->confirm_auth_cb)
+ return 0;
+
+ return sm->ctx->confirm_auth_cb(sm->ctx->ctx);
+}
+
+
static void eapol_enable_timer_tick(struct eapol_sm *sm)
{
if (sm->timer_tick_enabled)
@@ -215,7 +224,7 @@
{
SM_ENTRY(SUPP_PAE, LOGOFF);
eapol_sm_txLogoff(sm);
- sm->logoffSent = TRUE;
+ sm->logoffSent = true;
eapol_sm_set_port_unauthorized(sm);
}
@@ -225,13 +234,13 @@
SM_ENTRY(SUPP_PAE, DISCONNECTED);
sm->sPortMode = Auto;
sm->startCount = 0;
- sm->eapTriggerStart = FALSE;
- sm->logoffSent = FALSE;
+ sm->eapTriggerStart = false;
+ sm->logoffSent = false;
eapol_sm_set_port_unauthorized(sm);
- sm->suppAbort = TRUE;
+ sm->suppAbort = true;
- sm->unicast_key_received = FALSE;
- sm->broadcast_key_received = FALSE;
+ sm->unicast_key_received = false;
+ sm->broadcast_key_received = false;
/*
* IEEE Std 802.1X-2004 does not clear heldWhile here, but doing so
@@ -254,7 +263,7 @@
send_start = 1;
if (sm->ctx->preauth)
send_start = 1;
- sm->eapTriggerStart = FALSE;
+ sm->eapTriggerStart = false;
if (send_start) {
sm->startWhen = sm->startPeriod;
@@ -277,7 +286,7 @@
}
}
eapol_enable_timer_tick(sm);
- sm->eapolEap = FALSE;
+ sm->eapolEap = false;
if (send_start)
eapol_sm_txStart(sm);
}
@@ -287,12 +296,12 @@
{
SM_ENTRY(SUPP_PAE, AUTHENTICATING);
sm->startCount = 0;
- sm->suppSuccess = FALSE;
- sm->suppFail = FALSE;
- sm->suppTimeout = FALSE;
- sm->keyRun = FALSE;
- sm->keyDone = FALSE;
- sm->suppStart = TRUE;
+ sm->suppSuccess = false;
+ sm->suppFail = false;
+ sm->suppTimeout = false;
+ sm->keyRun = false;
+ sm->keyDone = false;
+ sm->suppStart = true;
}
@@ -316,17 +325,22 @@
SM_STATE(SUPP_PAE, RESTART)
{
+ if (eapol_sm_confirm_auth(sm)) {
+ /* Don't process restart, we are already reconnecting */
+ return;
+ }
+
SM_ENTRY(SUPP_PAE, RESTART);
- sm->eapRestart = TRUE;
+ sm->eapRestart = true;
if (sm->altAccept) {
/*
* Prevent EAP peer state machine from failing due to prior
- * external EAP success notification (altSuccess=TRUE in the
+ * external EAP success notification (altSuccess=true in the
* IDLE state could result in a transition to the FAILURE state.
*/
wpa_printf(MSG_DEBUG, "EAPOL: Clearing prior altAccept TRUE");
- sm->eapSuccess = FALSE;
- sm->altAccept = FALSE;
+ sm->eapSuccess = false;
+ sm->altAccept = false;
}
}
@@ -398,7 +412,7 @@
wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
"plaintext connection; no EAPOL-Key frames "
"required");
- sm->portValid = TRUE;
+ sm->portValid = true;
if (sm->ctx->eapol_done_cb)
sm->ctx->eapol_done_cb(sm->ctx->ctx);
}
@@ -445,7 +459,7 @@
{
SM_ENTRY(KEY_RX, KEY_RECEIVE);
eapol_sm_processKey(sm);
- sm->rxKey = FALSE;
+ sm->rxKey = false;
}
@@ -472,7 +486,7 @@
{
SM_ENTRY(SUPP_BE, REQUEST);
sm->authWhile = 0;
- sm->eapReq = TRUE;
+ sm->eapReq = true;
eapol_sm_getSuppRsp(sm);
}
@@ -481,15 +495,15 @@
{
SM_ENTRY(SUPP_BE, RESPONSE);
eapol_sm_txSuppRsp(sm);
- sm->eapResp = FALSE;
+ sm->eapResp = false;
}
SM_STATE(SUPP_BE, SUCCESS)
{
SM_ENTRY(SUPP_BE, SUCCESS);
- sm->keyRun = TRUE;
- sm->suppSuccess = TRUE;
+ sm->keyRun = true;
+ sm->suppSuccess = true;
#ifdef CONFIG_EAP_PROXY
if (sm->use_eap_proxy) {
@@ -499,7 +513,7 @@
/* New key received - clear IEEE 802.1X EAPOL-Key replay
* counter */
- sm->replay_counter_valid = FALSE;
+ sm->replay_counter_valid = false;
session_id = eap_proxy_get_eap_session_id(
sm->eap_proxy, &session_id_len);
@@ -520,7 +534,7 @@
if (eap_key_available(sm->eap)) {
/* New key received - clear IEEE 802.1X EAPOL-Key replay
* counter */
- sm->replay_counter_valid = FALSE;
+ sm->replay_counter_valid = false;
}
}
@@ -528,22 +542,22 @@
SM_STATE(SUPP_BE, FAIL)
{
SM_ENTRY(SUPP_BE, FAIL);
- sm->suppFail = TRUE;
+ sm->suppFail = true;
}
SM_STATE(SUPP_BE, TIMEOUT)
{
SM_ENTRY(SUPP_BE, TIMEOUT);
- sm->suppTimeout = TRUE;
+ sm->suppTimeout = true;
}
SM_STATE(SUPP_BE, IDLE)
{
SM_ENTRY(SUPP_BE, IDLE);
- sm->suppStart = FALSE;
- sm->initial_req = TRUE;
+ sm->suppStart = false;
+ sm->initial_req = true;
}
@@ -551,7 +565,7 @@
{
SM_ENTRY(SUPP_BE, INITIALIZE);
eapol_sm_abortSupp(sm);
- sm->suppAbort = FALSE;
+ sm->suppAbort = false;
/*
* IEEE Std 802.1X-2004 does not clear authWhile here, but doing so
@@ -569,9 +583,9 @@
SM_ENTRY(SUPP_BE, RECEIVE);
sm->authWhile = sm->authPeriod;
eapol_enable_timer_tick(sm);
- sm->eapolEap = FALSE;
- sm->eapNoResp = FALSE;
- sm->initial_req = FALSE;
+ sm->eapolEap = false;
+ sm->eapNoResp = false;
+ sm->initial_req = false;
}
@@ -678,6 +692,7 @@
static void eapol_sm_processKey(struct eapol_sm *sm)
{
+#ifdef CONFIG_WEP
#ifndef CONFIG_FIPS
struct ieee802_1x_hdr *hdr;
struct ieee802_1x_eapol_key *key;
@@ -816,7 +831,7 @@
return;
}
- sm->replay_counter_valid = TRUE;
+ sm->replay_counter_valid = true;
os_memcpy(sm->last_replay_counter, key->replay_counter,
IEEE8021X_REPLAY_COUNTER_LEN);
@@ -828,16 +843,16 @@
if (sm->ctx->set_wep_key &&
sm->ctx->set_wep_key(sm->ctx->ctx,
- key->key_index & IEEE8021X_KEY_INDEX_FLAG,
+ !!(key->key_index & IEEE8021X_KEY_INDEX_FLAG),
key->key_index & IEEE8021X_KEY_INDEX_MASK,
datakey, key_len) < 0) {
wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
" driver.");
} else {
if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
- sm->unicast_key_received = TRUE;
+ sm->unicast_key_received = true;
else
- sm->broadcast_key_received = TRUE;
+ sm->broadcast_key_received = true;
if ((sm->unicast_key_received ||
!(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
@@ -846,12 +861,13 @@
{
wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
"frames received");
- sm->portValid = TRUE;
+ sm->portValid = true;
if (sm->ctx->eapol_done_cb)
sm->ctx->eapol_done_cb(sm->ctx->ctx);
}
}
#endif /* CONFIG_FIPS */
+#endif /* CONFIG_WEP */
}
@@ -933,7 +949,7 @@
int cb;
cb = sm->suppPortStatus != Authorized || sm->force_authorized_update;
- sm->force_authorized_update = FALSE;
+ sm->force_authorized_update = false;
sm->suppPortStatus = Authorized;
if (cb && sm->ctx->port_cb)
sm->ctx->port_cb(sm->ctx->ctx, 1);
@@ -945,7 +961,7 @@
int cb;
cb = sm->suppPortStatus != Unauthorized || sm->force_authorized_update;
- sm->force_authorized_update = FALSE;
+ sm->force_authorized_update = false;
sm->suppPortStatus = Unauthorized;
if (cb && sm->ctx->port_cb)
sm->ctx->port_cb(sm->ctx->ctx, 0);
@@ -969,7 +985,7 @@
* allow events (e.g., SIGTERM) to stop the program cleanly if the
* state machine were to generate a busy loop. */
for (i = 0; i < 100; i++) {
- sm->changed = FALSE;
+ sm->changed = false;
SM_STEP_RUN(SUPP_PAE);
SM_STEP_RUN(KEY_RX);
SM_STEP_RUN(SUPP_BE);
@@ -977,11 +993,11 @@
if (sm->use_eap_proxy) {
/* Drive the EAP proxy state machine */
if (eap_proxy_sm_step(sm->eap_proxy, sm->eap))
- sm->changed = TRUE;
+ sm->changed = true;
} else
#endif /* CONFIG_EAP_PROXY */
if (eap_peer_sm_step(sm->eap))
- sm->changed = TRUE;
+ sm->changed = true;
if (!sm->changed)
break;
}
@@ -1354,7 +1370,7 @@
if (sm->eapReqData) {
wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
"frame");
- sm->eapolEap = TRUE;
+ sm->eapolEap = true;
#ifdef CONFIG_EAP_PROXY
if (sm->use_eap_proxy) {
eap_proxy_packet_update(
@@ -1395,7 +1411,7 @@
"frame");
os_memcpy(sm->last_rx_key, buf, data_len);
sm->last_rx_key_len = data_len;
- sm->rxKey = TRUE;
+ sm->rxKey = true;
eapol_sm_step(sm);
}
break;
@@ -1438,14 +1454,14 @@
*
* Notify EAPOL state machine about new portEnabled value.
*/
-void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
+void eapol_sm_notify_portEnabled(struct eapol_sm *sm, bool enabled)
{
if (sm == NULL)
return;
wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
"portEnabled=%d", enabled);
if (sm->portEnabled != enabled)
- sm->force_authorized_update = TRUE;
+ sm->force_authorized_update = true;
sm->portEnabled = enabled;
eapol_sm_step(sm);
}
@@ -1458,7 +1474,7 @@
*
* Notify EAPOL state machine about new portValid value.
*/
-void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
+void eapol_sm_notify_portValid(struct eapol_sm *sm, bool valid)
{
if (sm == NULL)
return;
@@ -1472,15 +1488,15 @@
/**
* eapol_sm_notify_eap_success - Notification of external EAP success trigger
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @success: %TRUE = set success, %FALSE = clear success
+ * @success: %true = set success, %false = clear success
*
* Notify the EAPOL state machine that external event has forced EAP state to
- * success (success = %TRUE). This can be cleared by setting success = %FALSE.
+ * success (success = %true). This can be cleared by setting success = %false.
*
* This function is called to update EAP state when WPA-PSK key handshake has
* been completed successfully since WPA-PSK does not use EAP state machine.
*/
-void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
+void eapol_sm_notify_eap_success(struct eapol_sm *sm, bool success)
{
if (sm == NULL)
return;
@@ -1497,12 +1513,12 @@
/**
* eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @fail: %TRUE = set failure, %FALSE = clear failure
+ * @fail: %true = set failure, %false = clear failure
*
* Notify EAPOL state machine that external event has forced EAP state to
- * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
+ * failure (fail = %true). This can be cleared by setting fail = %false.
*/
-void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
+void eapol_sm_notify_eap_fail(struct eapol_sm *sm, bool fail)
{
if (sm == NULL)
return;
@@ -1643,7 +1659,7 @@
*
* Notify EAPOL state machines that user requested logon/logoff.
*/
-void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
+void eapol_sm_notify_logoff(struct eapol_sm *sm, bool logoff)
{
if (sm) {
sm->userLogoff = logoff;
@@ -1668,7 +1684,7 @@
if (sm == NULL)
return;
wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
- sm->eapSuccess = TRUE;
+ sm->eapSuccess = true;
eap_notify_success(sm->eap);
eapol_sm_step(sm);
}
@@ -1685,7 +1701,7 @@
if (sm == NULL)
return;
wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
- sm->cached_pmk = TRUE;
+ sm->cached_pmk = true;
}
@@ -1695,7 +1711,7 @@
"doing full EAP authentication");
if (sm == NULL)
return;
- sm->cached_pmk = FALSE;
+ sm->cached_pmk = false;
sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
eapol_sm_set_port_unauthorized(sm);
@@ -1774,8 +1790,8 @@
wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
"input) notification - retrying pending EAP "
"Request");
- sm->eapolEap = TRUE;
- sm->eapReq = TRUE;
+ sm->eapolEap = true;
+ sm->eapReq = true;
eapol_sm_step(sm);
}
}
@@ -1844,11 +1860,11 @@
}
-static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
+static bool eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
{
struct eapol_sm *sm = ctx;
if (sm == NULL)
- return FALSE;
+ return false;
switch (variable) {
case EAPOL_eapSuccess:
return sm->eapSuccess;
@@ -1871,12 +1887,12 @@
case EAPOL_eapTriggerStart:
return sm->eapTriggerStart;
}
- return FALSE;
+ return false;
}
static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
- Boolean value)
+ bool value)
{
struct eapol_sm *sm = ctx;
if (sm == NULL)
@@ -1978,8 +1994,8 @@
if (sm->eapReqData && !sm->eapReq) {
wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
"state machine - retrying pending EAP Request");
- sm->eapolEap = TRUE;
- sm->eapReq = TRUE;
+ sm->eapolEap = true;
+ sm->eapReq = true;
eapol_sm_step(sm);
}
}
@@ -1998,15 +2014,12 @@
#define eapol_sm_eap_param_needed NULL
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
-static void eapol_sm_notify_cert(void *ctx, int depth, const char *subject,
- const char *altsubject[],
- int num_altsubject, const char *cert_hash,
- const struct wpabuf *cert)
+static void eapol_sm_notify_cert(void *ctx, struct tls_cert_data *cert,
+ const char *cert_hash)
{
struct eapol_sm *sm = ctx;
if (sm->ctx->cert_cb)
- sm->ctx->cert_cb(sm->ctx->ctx, depth, subject, altsubject,
- num_altsubject, cert_hash, cert);
+ sm->ctx->cert_cb(sm->ctx->ctx, cert, cert_hash);
}
@@ -2128,7 +2141,7 @@
}
#ifdef CONFIG_EAP_PROXY
- sm->use_eap_proxy = FALSE;
+ sm->use_eap_proxy = false;
sm->eap_proxy = eap_proxy_init(sm, &eapol_cb, sm->ctx->msg_ctx);
if (sm->eap_proxy == NULL) {
wpa_printf(MSG_ERROR, "Unable to initialize EAP Proxy");
@@ -2136,10 +2149,10 @@
#endif /* CONFIG_EAP_PROXY */
/* Initialize EAPOL state machines */
- sm->force_authorized_update = TRUE;
- sm->initialize = TRUE;
+ sm->force_authorized_update = true;
+ sm->initialize = true;
eapol_sm_step(sm);
- sm->initialize = FALSE;
+ sm->initialize = false;
eapol_sm_step(sm);
if (eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm) == 0)
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index 74f40bb..753b947 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -11,6 +11,8 @@
#include "common/defs.h"
+struct tls_cert_data;
+
typedef enum { Unauthorized, Authorized } PortStatus;
typedef enum { Auto, ForceUnauthorized, ForceAuthorized } PortControl;
@@ -246,16 +248,11 @@
/**
* cert_cb - Notification of a peer certificate
* @ctx: Callback context (ctx)
- * @depth: Depth in certificate chain (0 = server)
- * @subject: Subject of the peer certificate
- * @altsubject: Select fields from AltSubject of the peer certificate
- * @num_altsubject: Number of altsubject values
+ * @cert: Certificate information
* @cert_hash: SHA-256 hash of the certificate
- * @cert: Peer certificate
*/
- void (*cert_cb)(void *ctx, int depth, const char *subject,
- const char *altsubject[], int num_altsubject,
- const char *cert_hash, const struct wpabuf *cert);
+ void (*cert_cb)(void *ctx, struct tls_cert_data *cert,
+ const char *cert_hash);
/**
* cert_in_cb - Include server certificates in callback
@@ -301,6 +298,15 @@
* @len: Length of anonymous identity in octets
*/
void (*set_anon_id)(void *ctx, const u8 *id, size_t len);
+
+ /**
+ * confirm_auth_cb - Callback confirming if we can install a new PTK
+ * @ctx: eapol_ctx from eap_peer_sm_init() call
+ * Returns: 0 when authentication can continue, -1 when reconnecting
+ *
+ * Automatically triggers a reconnect when not.
+ */
+ int (*confirm_auth_cb)(void *ctx);
};
@@ -319,16 +325,16 @@
int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
size_t len);
void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm);
-void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled);
-void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid);
-void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success);
-void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail);
+void eapol_sm_notify_portEnabled(struct eapol_sm *sm, bool enabled);
+void eapol_sm_notify_portValid(struct eapol_sm *sm, bool valid);
+void eapol_sm_notify_eap_success(struct eapol_sm *sm, bool success);
+void eapol_sm_notify_eap_fail(struct eapol_sm *sm, bool fail);
void eapol_sm_notify_config(struct eapol_sm *sm,
struct eap_peer_config *config,
const struct eapol_config *conf);
int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len);
const u8 * eapol_sm_get_session_id(struct eapol_sm *sm, size_t *len);
-void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff);
+void eapol_sm_notify_logoff(struct eapol_sm *sm, bool logoff);
void eapol_sm_notify_cached(struct eapol_sm *sm);
void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm);
void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx);
@@ -391,18 +397,18 @@
{
}
static inline void eapol_sm_notify_portEnabled(struct eapol_sm *sm,
- Boolean enabled)
+ bool enabled)
{
}
static inline void eapol_sm_notify_portValid(struct eapol_sm *sm,
- Boolean valid)
+ bool valid)
{
}
static inline void eapol_sm_notify_eap_success(struct eapol_sm *sm,
- Boolean success)
+ bool success)
{
}
-static inline void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
+static inline void eapol_sm_notify_eap_fail(struct eapol_sm *sm, bool fail)
{
}
static inline void eapol_sm_notify_config(struct eapol_sm *sm,
@@ -419,7 +425,7 @@
{
return NULL;
}
-static inline void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
+static inline void eapol_sm_notify_logoff(struct eapol_sm *sm, bool logoff)
{
}
static inline void eapol_sm_notify_cached(struct eapol_sm *sm)
diff --git a/src/fst/fst.c b/src/fst/fst.c
index 32cd941..21ef3d8 100644
--- a/src/fst/fst.c
+++ b/src/fst/fst.c
@@ -20,7 +20,7 @@
static void fst_ctrl_iface_notify_peer_state_change(struct fst_iface *iface,
- Boolean connected,
+ bool connected,
const u8 *peer_addr)
{
union fst_event_extra extra;
@@ -42,7 +42,7 @@
struct fst_group *g;
struct fst_group *group = NULL;
struct fst_iface *iface = NULL;
- Boolean new_group = FALSE;
+ bool new_group = false;
WPA_ASSERT(ifname != NULL);
WPA_ASSERT(iface_obj != NULL);
@@ -62,7 +62,7 @@
cfg->group_id);
return NULL;
}
- new_group = TRUE;
+ new_group = true;
}
iface = fst_iface_create(group, ifname, own_addr, iface_obj, cfg);
@@ -166,7 +166,7 @@
void fst_rx_action(struct fst_iface *iface, const struct ieee80211_mgmt *mgmt,
size_t len)
{
- if (fst_iface_is_connected(iface, mgmt->sa, FALSE))
+ if (fst_iface_is_connected(iface, mgmt->sa, false))
fst_session_on_action_rx(iface, mgmt, len);
else
wpa_printf(MSG_DEBUG,
@@ -187,7 +187,7 @@
fst_printf_iface(iface, MSG_DEBUG, MACSTR " became connected",
MAC2STR(addr));
- fst_ctrl_iface_notify_peer_state_change(iface, TRUE, addr);
+ fst_ctrl_iface_notify_peer_state_change(iface, true, addr);
}
@@ -203,17 +203,26 @@
fst_printf_iface(iface, MSG_DEBUG, MACSTR " became disconnected",
MAC2STR(addr));
- fst_ctrl_iface_notify_peer_state_change(iface, FALSE, addr);
+ fst_ctrl_iface_notify_peer_state_change(iface, false, addr);
}
-Boolean fst_are_ifaces_aggregated(struct fst_iface *iface1,
- struct fst_iface *iface2)
+bool fst_are_ifaces_aggregated(struct fst_iface *iface1,
+ struct fst_iface *iface2)
{
return fst_iface_get_group(iface1) == fst_iface_get_group(iface2);
}
+void fst_update_mac_addr(struct fst_iface *iface, const u8 *addr)
+{
+ fst_printf_iface(iface, MSG_DEBUG, "new MAC address " MACSTR,
+ MAC2STR(addr));
+ os_memcpy(iface->own_addr, addr, sizeof(iface->own_addr));
+ fst_group_update_ie(fst_iface_get_group(iface));
+}
+
+
enum mb_band_id fst_hw_mode_to_band(enum hostapd_hw_mode mode)
{
switch (mode) {
diff --git a/src/fst/fst.h b/src/fst/fst.h
index 2967491..2410a6e 100644
--- a/src/fst/fst.h
+++ b/src/fst/fst.h
@@ -113,24 +113,24 @@
* get_peer_first - Get MAC address of the 1st connected STA
* @ctx: User context %ctx
* @get_ctx: Context to be used for %get_peer_next call
- * @mb_only: %TRUE if only multi-band capable peer should be reported
+ * @mb_only: %true if only multi-band capable peer should be reported
* Returns: Address of the 1st connected STA, %NULL if no STAs connected
*/
const u8 * (*get_peer_first)(void *ctx,
struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only);
+ bool mb_only);
/**
* get_peer_next - Get MAC address of the next connected STA
* @ctx: User context %ctx
* @get_ctx: Context received from %get_peer_first or previous
* %get_peer_next call
- * @mb_only: %TRUE if only multi-band capable peer should be reported
+ * @mb_only: %true if only multi-band capable peer should be reported
* Returns: Address of the next connected STA, %NULL if no more STAs
* connected
*/
const u8 * (*get_peer_next)(void *ctx,
struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only);
+ bool mb_only);
};
/**
@@ -273,11 +273,18 @@
* @iface1: 1st FST interface object
* @iface1: 2nd FST interface object
*
- * Returns: %TRUE if the interfaces belong to the same FST group,
- * %FALSE otherwise
+ * Returns: %true if the interfaces belong to the same FST group,
+ * %false otherwise
*/
-Boolean fst_are_ifaces_aggregated(struct fst_iface *iface1,
- struct fst_iface *iface2);
+bool fst_are_ifaces_aggregated(struct fst_iface *iface1,
+ struct fst_iface *iface2);
+
+/**
+ * fst_update_mac_addr - Notify FST about MAC address change
+ * @iface: FST interface object
+ * @addr: New MAC address
+ */
+void fst_update_mac_addr(struct fst_iface *iface, const u8 *addr);
#else /* CONFIG_FST */
diff --git a/src/fst/fst_ctrl_aux.h b/src/fst/fst_ctrl_aux.h
index 0aff5d0..ab80b6f 100644
--- a/src/fst/fst_ctrl_aux.h
+++ b/src/fst/fst_ctrl_aux.h
@@ -54,12 +54,12 @@
union fst_event_extra {
struct fst_event_extra_iface_state {
- Boolean attached;
+ bool attached;
char ifname[FST_MAX_INTERFACE_SIZE];
char group_id[FST_MAX_GROUP_ID_SIZE];
} iface_state; /* for EVENT_FST_IFACE_STATE_CHANGED */
struct fst_event_extra_peer_state {
- Boolean connected;
+ bool connected;
char ifname[FST_MAX_INTERFACE_SIZE];
u8 addr[ETH_ALEN];
} peer_state; /* for EVENT_PEER_STATE_CHANGED */
diff --git a/src/fst/fst_ctrl_iface.c b/src/fst/fst_ctrl_iface.c
index 7df3362..45607b6 100644
--- a/src/fst/fst_ctrl_iface.c
+++ b/src/fst/fst_ctrl_iface.c
@@ -32,8 +32,8 @@
/* notifications */
-static Boolean format_session_state_extra(const union fst_event_extra *extra,
- char *buffer, size_t size)
+static bool format_session_state_extra(const union fst_event_extra *extra,
+ char *buffer, size_t size)
{
int len;
char reject_str[32] = FST_CTRL_PVAL_NONE;
@@ -42,7 +42,7 @@
ss = &extra->session_state;
if (ss->new_state != FST_SESSION_STATE_INITIAL)
- return TRUE;
+ return true;
switch (ss->extra.to_initial.reason) {
case REASON_REJECT:
@@ -183,10 +183,10 @@
return os_snprintf(buf, buflen, "FAIL\n");
}
- old_peer_addr = fst_session_get_peer_addr(s, TRUE);
- new_peer_addr = fst_session_get_peer_addr(s, FALSE);
- new_iface = fst_session_get_iface(s, FALSE);
- old_iface = fst_session_get_iface(s, TRUE);
+ old_peer_addr = fst_session_get_peer_addr(s, true);
+ new_peer_addr = fst_session_get_peer_addr(s, false);
+ new_iface = fst_session_get_iface(s, false);
+ old_iface = fst_session_get_iface(s, true);
return os_snprintf(buf, buflen,
FST_CSG_PNAME_OLD_PEER_ADDR "=" MACSTR "\n"
@@ -227,13 +227,13 @@
p++;
if (os_strncasecmp(p, FST_CSS_PNAME_OLD_IFNAME, q - p) == 0) {
- ret = fst_session_set_str_ifname(s, q + 1, TRUE);
+ ret = fst_session_set_str_ifname(s, q + 1, true);
} else if (os_strncasecmp(p, FST_CSS_PNAME_NEW_IFNAME, q - p) == 0) {
- ret = fst_session_set_str_ifname(s, q + 1, FALSE);
+ ret = fst_session_set_str_ifname(s, q + 1, false);
} else if (os_strncasecmp(p, FST_CSS_PNAME_OLD_PEER_ADDR, q - p) == 0) {
- ret = fst_session_set_str_peer_addr(s, q + 1, TRUE);
+ ret = fst_session_set_str_peer_addr(s, q + 1, true);
} else if (os_strncasecmp(p, FST_CSS_PNAME_NEW_PEER_ADDR, q - p) == 0) {
- ret = fst_session_set_str_peer_addr(s, q + 1, FALSE);
+ ret = fst_session_set_str_peer_addr(s, q + 1, false);
} else if (os_strncasecmp(p, FST_CSS_PNAME_LLT, q - p) == 0) {
ret = fst_session_set_str_llt(s, q + 1);
} else {
@@ -539,8 +539,8 @@
if (!found)
return os_snprintf(buf, buflen, "FAIL\n");
- addr = fst_iface_get_peer_first(f, &ctx, FALSE);
- for (; addr != NULL; addr = fst_iface_get_peer_next(f, &ctx, FALSE)) {
+ addr = fst_iface_get_peer_first(f, &ctx, false);
+ for (; addr != NULL; addr = fst_iface_get_peer_next(f, &ctx, false)) {
int res;
res = os_snprintf(buf + ret, buflen - ret, MACSTR "\n",
@@ -692,7 +692,7 @@
static void fst_ctrl_iface_on_iface_state_changed(struct fst_iface *i,
- Boolean attached)
+ bool attached)
{
union fst_event_extra extra;
@@ -710,14 +710,14 @@
static int fst_ctrl_iface_on_iface_added(struct fst_iface *i)
{
- fst_ctrl_iface_on_iface_state_changed(i, TRUE);
+ fst_ctrl_iface_on_iface_state_changed(i, true);
return 0;
}
static void fst_ctrl_iface_on_iface_removed(struct fst_iface *i)
{
- fst_ctrl_iface_on_iface_state_changed(i, FALSE);
+ fst_ctrl_iface_on_iface_state_changed(i, false);
}
@@ -749,7 +749,7 @@
foreach_fst_group(g) {
foreach_fst_group_iface(g, f) {
- if (fst_iface_is_connected(f, addr, TRUE)) {
+ if (fst_iface_is_connected(f, addr, true)) {
ret += print_band(num++, f, addr,
buf + ret, buflen - ret);
}
@@ -789,7 +789,7 @@
const struct fst_command *c;
const char *p;
const char *temp;
- Boolean non_spaces_found;
+ bool non_spaces_found;
for (c = commands; c->name; c++) {
if (os_strncasecmp(cmd, c->name, os_strlen(c->name)) != 0)
@@ -800,10 +800,10 @@
return os_snprintf(reply, reply_size, "FAIL\n");
p++;
temp = p;
- non_spaces_found = FALSE;
+ non_spaces_found = false;
while (*temp) {
if (!isspace(*temp)) {
- non_spaces_found = TRUE;
+ non_spaces_found = true;
break;
}
temp++;
@@ -818,18 +818,18 @@
}
-int fst_read_next_int_param(const char *params, Boolean *valid, char **endp)
+int fst_read_next_int_param(const char *params, bool *valid, char **endp)
{
int ret = -1;
const char *curp;
- *valid = FALSE;
+ *valid = false;
*endp = (char *) params;
curp = params;
if (*curp) {
ret = (int) strtol(curp, endp, 0);
if (!**endp || isspace(**endp))
- *valid = TRUE;
+ *valid = true;
}
return ret;
@@ -887,7 +887,7 @@
{
char *pos;
char *endp;
- Boolean is_valid;
+ bool is_valid;
int val;
if (fst_read_next_text_param(cmd, ifname, ifname_size, &endp) ||
diff --git a/src/fst/fst_ctrl_iface.h b/src/fst/fst_ctrl_iface.h
index 4d0cd9f..354b81f 100644
--- a/src/fst/fst_ctrl_iface.h
+++ b/src/fst/fst_ctrl_iface.h
@@ -30,7 +30,7 @@
#endif /* CONFIG_FST */
-int fst_read_next_int_param(const char *params, Boolean *valid, char **endp);
+int fst_read_next_int_param(const char *params, bool *valid, char **endp);
int fst_read_next_text_param(const char *params, char *buf, size_t buflen,
char **endp);
int fst_read_peer_addr(const char *mac, u8 *peer_addr);
diff --git a/src/fst/fst_group.c b/src/fst/fst_group.c
index a4ae016..d1c4014 100644
--- a/src/fst/fst_group.c
+++ b/src/fst/fst_group.c
@@ -305,7 +305,7 @@
if (other_iface == iface ||
band_id != fst_iface_get_band_id(other_iface))
continue;
- if (fst_iface_is_connected(other_iface, tmp_peer_addr, FALSE)) {
+ if (fst_iface_is_connected(other_iface, tmp_peer_addr, false)) {
os_memcpy(other_peer_addr, tmp_peer_addr, ETH_ALEN);
return other_iface;
}
@@ -347,10 +347,10 @@
band_id != fst_iface_get_band_id(other_iface))
continue;
cur_peer_addr = fst_iface_get_peer_first(other_iface, &ctx,
- TRUE);
+ true);
for (; cur_peer_addr;
cur_peer_addr = fst_iface_get_peer_next(other_iface, &ctx,
- TRUE)) {
+ true)) {
cur_mbie = fst_iface_get_peer_mb_ie(other_iface,
cur_peer_addr);
if (!cur_mbie)
@@ -493,9 +493,9 @@
}
-Boolean fst_group_delete_if_empty(struct fst_group *group)
+bool fst_group_delete_if_empty(struct fst_group *group)
{
- Boolean is_empty = !fst_group_has_ifaces(group) &&
+ bool is_empty = !fst_group_has_ifaces(group) &&
!fst_session_global_get_first_by_group(group);
if (is_empty)
diff --git a/src/fst/fst_group.h b/src/fst/fst_group.h
index 00aee9c..4a9ff3e 100644
--- a/src/fst/fst_group.h
+++ b/src/fst/fst_group.h
@@ -29,7 +29,7 @@
void fst_group_update_ie(struct fst_group *g);
-static inline Boolean fst_group_has_ifaces(struct fst_group *g)
+static inline bool fst_group_has_ifaces(struct fst_group *g)
{
return !dl_list_empty(&g->ifaces);
}
@@ -44,7 +44,7 @@
return g->group_id;
}
-Boolean fst_group_delete_if_empty(struct fst_group *group);
+bool fst_group_delete_if_empty(struct fst_group *group);
struct fst_iface * fst_group_get_iface_by_name(struct fst_group *g,
const char *ifname);
struct fst_iface *
diff --git a/src/fst/fst_iface.c b/src/fst/fst_iface.c
index 35e83cb..90c5fc0 100644
--- a/src/fst/fst_iface.c
+++ b/src/fst/fst_iface.c
@@ -49,17 +49,17 @@
}
-Boolean fst_iface_is_connected(struct fst_iface *iface, const u8 *addr,
- Boolean mb_only)
+bool fst_iface_is_connected(struct fst_iface *iface, const u8 *addr,
+ bool mb_only)
{
struct fst_get_peer_ctx *ctx;
const u8 *a = fst_iface_get_peer_first(iface, &ctx, mb_only);
for (; a != NULL; a = fst_iface_get_peer_next(iface, &ctx, mb_only))
if (os_memcmp(addr, a, ETH_ALEN) == 0)
- return TRUE;
+ return true;
- return FALSE;
+ return false;
}
diff --git a/src/fst/fst_iface.h b/src/fst/fst_iface.h
index cbaa7d8..af7156c 100644
--- a/src/fst/fst_iface.h
+++ b/src/fst/fst_iface.h
@@ -111,20 +111,20 @@
static inline const u8 * fst_iface_get_peer_first(struct fst_iface *i,
struct fst_get_peer_ctx **ctx,
- Boolean mb_only)
+ bool mb_only)
{
return i->iface_obj.get_peer_first(i->iface_obj.ctx, ctx, mb_only);
}
static inline const u8 * fst_iface_get_peer_next(struct fst_iface *i,
struct fst_get_peer_ctx **ctx,
- Boolean mb_only)
+ bool mb_only)
{
return i->iface_obj.get_peer_next(i->iface_obj.ctx, ctx, mb_only);
}
-Boolean fst_iface_is_connected(struct fst_iface *iface, const u8 *addr,
- Boolean mb_only);
+bool fst_iface_is_connected(struct fst_iface *iface, const u8 *addr,
+ bool mb_only);
void fst_iface_attach_mbie(struct fst_iface *i, struct wpabuf *mbie);
enum mb_band_id fst_iface_get_band_id(struct fst_iface *i);
diff --git a/src/fst/fst_session.c b/src/fst/fst_session.c
index a02a93e..e42a85c 100644
--- a/src/fst/fst_session.c
+++ b/src/fst/fst_session.c
@@ -71,7 +71,7 @@
* specific session object */
struct fst_group *group;
enum fst_session_state state;
- Boolean stt_armed;
+ bool stt_armed;
};
static struct dl_list global_sessions_list;
@@ -145,12 +145,12 @@
struct fst_session *s;
for (i = 0; i < (u32) -1; i++) {
- Boolean in_use = FALSE;
+ bool in_use = false;
foreach_fst_session(s) {
if (s->id == global_session_id) {
fst_session_global_inc_id();
- in_use = TRUE;
+ in_use = true;
break;
}
}
@@ -184,7 +184,7 @@
/* Action frames sometimes get delayed. Use relaxed timeout (2*) */
eloop_register_timeout(0, 2 * TU_TO_US(FST_DEFAULT_SESSION_TIMEOUT_TU),
fst_session_timeout_handler, NULL, s);
- s->stt_armed = TRUE;
+ s->stt_armed = true;
}
@@ -192,12 +192,12 @@
{
if (s->stt_armed) {
eloop_cancel_timeout(fst_session_timeout_handler, NULL, s);
- s->stt_armed = FALSE;
+ s->stt_armed = false;
}
}
-static Boolean fst_session_is_in_transition(struct fst_session *s)
+static bool fst_session_is_in_transition(struct fst_session *s)
{
/* See spec, 10.32.2.2 Transitioning between states */
return s->stt_armed;
@@ -267,7 +267,7 @@
}
-static int fst_session_send_action(struct fst_session *s, Boolean old_iface,
+static int fst_session_send_action(struct fst_session *s, bool old_iface,
const void *payload, size_t size,
const struct wpabuf *extra_buf)
{
@@ -344,11 +344,11 @@
td.action = FST_ACTION_TEAR_DOWN;
td.fsts_id = host_to_le32(s->data.fsts_id);
- res = fst_session_send_action(s, TRUE, &td, sizeof(td), NULL);
+ res = fst_session_send_action(s, true, &td, sizeof(td), NULL);
if (!res)
- fst_printf_sframe(s, TRUE, MSG_INFO, "FST TearDown sent");
+ fst_printf_sframe(s, true, MSG_INFO, "FST TearDown sent");
else
- fst_printf_sframe(s, TRUE, MSG_ERROR,
+ fst_printf_sframe(s, true, MSG_ERROR,
"failed to send FST TearDown");
return res;
@@ -481,10 +481,10 @@
return;
}
- fst_session_set_iface(s, iface, TRUE);
- fst_session_set_peer_addr(s, mgmt->sa, TRUE);
- fst_session_set_iface(s, new_iface, FALSE);
- fst_session_set_peer_addr(s, new_iface_peer_addr, FALSE);
+ fst_session_set_iface(s, iface, true);
+ fst_session_set_peer_addr(s, mgmt->sa, true);
+ fst_session_set_iface(s, new_iface, false);
+ fst_session_set_peer_addr(s, new_iface_peer_addr, false);
fst_session_set_llt(s, FST_LLT_VAL_TO_MS(le_to_host32(req->llt)));
s->data.pending_setup_req_dlgt = req->dialog_token;
s->data.fsts_id = le_to_host32(req->stie.fsts_id);
@@ -687,8 +687,8 @@
res.dialog_token = req->dialog_token;
res.fsts_id = req->fsts_id;
- if (!fst_session_send_action(s, FALSE, &res, sizeof(res), NULL)) {
- fst_printf_sframe(s, FALSE, MSG_INFO, "FST Ack Response sent");
+ if (!fst_session_send_action(s, false, &res, sizeof(res), NULL)) {
+ fst_printf_sframe(s, false, MSG_INFO, "FST Ack Response sent");
fst_session_stt_disarm(s);
fst_session_set_state(s, FST_SESSION_STATE_TRANSITION_DONE,
NULL);
@@ -785,7 +785,7 @@
void fst_session_set_iface(struct fst_session *s, struct fst_iface *iface,
- Boolean is_old)
+ bool is_old)
{
if (is_old)
s->data.old_iface = iface;
@@ -802,7 +802,7 @@
void fst_session_set_peer_addr(struct fst_session *s, const u8 *addr,
- Boolean is_old)
+ bool is_old)
{
u8 *a = is_old ? s->data.old_peer_addr : s->data.new_peer_addr;
@@ -850,14 +850,14 @@
}
if (!fst_iface_is_connected(s->data.old_iface, s->data.old_peer_addr,
- FALSE)) {
+ false)) {
fst_printf_session(s, MSG_ERROR,
"The preset old peer address is not connected");
return -EINVAL;
}
if (!fst_iface_is_connected(s->data.new_iface, s->data.new_peer_addr,
- FALSE)) {
+ false)) {
fst_printf_session(s, MSG_ERROR,
"The preset new peer address is not connected");
return -EINVAL;
@@ -905,12 +905,12 @@
req.stie.old_band_op = 1;
req.stie.old_band_setup = 0;
- res = fst_session_send_action(s, TRUE, &req, sizeof(req),
+ res = fst_session_send_action(s, true, &req, sizeof(req),
fst_iface_get_mbie(s->data.old_iface));
if (!res) {
s->data.fsts_id = fsts_id;
s->data.pending_setup_req_dlgt = dialog_token;
- fst_printf_sframe(s, TRUE, MSG_INFO, "FST Setup Request sent");
+ fst_printf_sframe(s, true, MSG_INFO, "FST Setup Request sent");
fst_session_set_state(s, FST_SESSION_STATE_SETUP_COMPLETION,
NULL);
@@ -955,7 +955,7 @@
}
if (!fst_iface_is_connected(s->data.old_iface,
- s->data.old_peer_addr, FALSE)) {
+ s->data.old_peer_addr, false)) {
fst_printf_session(s, MSG_ERROR,
"The preset peer address is not in the peer list");
return -EINVAL;
@@ -1000,15 +1000,15 @@
status_code);
}
- if (fst_session_send_action(s, TRUE, &res, sizeof(res),
+ if (fst_session_send_action(s, true, &res, sizeof(res),
fst_iface_get_mbie(s->data.old_iface))) {
- fst_printf_sframe(s, TRUE, MSG_ERROR,
+ fst_printf_sframe(s, true, MSG_ERROR,
"cannot send FST Setup Response with code %d",
status_code);
return -EINVAL;
}
- fst_printf_sframe(s, TRUE, MSG_INFO, "FST Setup Response sent");
+ fst_printf_sframe(s, true, MSG_INFO, "FST Setup Response sent");
if (status_code != WLAN_STATUS_SUCCESS) {
union fst_session_state_switch_extra evext = {
@@ -1053,14 +1053,14 @@
req.dialog_token = dialog_token;
req.fsts_id = host_to_le32(s->data.fsts_id);
- res = fst_session_send_action(s, FALSE, &req, sizeof(req), NULL);
+ res = fst_session_send_action(s, false, &req, sizeof(req), NULL);
if (!res) {
- fst_printf_sframe(s, FALSE, MSG_INFO, "FST Ack Request sent");
+ fst_printf_sframe(s, false, MSG_INFO, "FST Ack Request sent");
fst_session_set_state(s, FST_SESSION_STATE_TRANSITION_DONE,
NULL);
fst_session_stt_arm(s);
} else {
- fst_printf_sframe(s, FALSE, MSG_ERROR,
+ fst_printf_sframe(s, false, MSG_ERROR,
"Cannot send FST Ack Request");
}
@@ -1091,7 +1091,7 @@
break;
case FST_ACTION_ON_CHANNEL_TUNNEL:
default:
- fst_printf_sframe(s, FALSE, MSG_ERROR,
+ fst_printf_sframe(s, false, MSG_ERROR,
"Unsupported FST Action frame");
break;
}
@@ -1137,7 +1137,7 @@
}
-struct fst_iface * fst_session_get_iface(struct fst_session *s, Boolean is_old)
+struct fst_iface * fst_session_get_iface(struct fst_session *s, bool is_old)
{
return is_old ? s->data.old_iface : s->data.new_iface;
}
@@ -1149,7 +1149,7 @@
}
-const u8 * fst_session_get_peer_addr(struct fst_session *s, Boolean is_old)
+const u8 * fst_session_get_peer_addr(struct fst_session *s, bool is_old)
{
return is_old ? s->data.old_peer_addr : s->data.new_peer_addr;
}
@@ -1232,7 +1232,7 @@
int fst_session_set_str_ifname(struct fst_session *s, const char *ifname,
- Boolean is_old)
+ bool is_old)
{
struct fst_group *g = fst_session_get_group(s);
struct fst_iface *i;
@@ -1252,7 +1252,7 @@
int fst_session_set_str_peer_addr(struct fst_session *s, const char *mac,
- Boolean is_old)
+ bool is_old)
{
u8 peer_addr[ETH_ALEN];
int res = fst_read_peer_addr(mac, peer_addr);
@@ -1330,11 +1330,11 @@
if (!s->data.old_iface)
return -EINVAL;
- old_addr = fst_iface_get_peer_first(s->data.old_iface, &ctx, TRUE);
+ old_addr = fst_iface_get_peer_first(s->data.old_iface, &ctx, true);
if (!old_addr)
return -EINVAL;
- new_addr = fst_iface_get_peer_first(s->data.new_iface, &ctx, TRUE);
+ new_addr = fst_iface_get_peer_first(s->data.new_iface, &ctx, true);
if (!new_addr)
return -EINVAL;
@@ -1350,7 +1350,7 @@
int fst_test_req_send_fst_request(const char *params)
{
int fsts_id;
- Boolean is_valid;
+ bool is_valid;
char *endp;
struct fst_setup_req req;
struct fst_session s;
@@ -1394,7 +1394,7 @@
req.stie.new_band_id = req.stie.old_band_id;
}
- return fst_session_send_action(&s, TRUE, &req, sizeof(req),
+ return fst_session_send_action(&s, true, &req, sizeof(req),
s.data.old_iface->mb_ie);
}
@@ -1402,7 +1402,7 @@
int fst_test_req_send_fst_response(const char *params)
{
int fsts_id;
- Boolean is_valid;
+ bool is_valid;
char *endp;
struct fst_setup_res res;
struct fst_session s;
@@ -1437,7 +1437,7 @@
* If some session has just received an FST Setup Request, then
* use the correct dialog token copied from this request.
*/
- _s = fst_find_session_in_progress(fst_session_get_peer_addr(&s, TRUE),
+ _s = fst_find_session_in_progress(fst_session_get_peer_addr(&s, true),
g);
res.dialog_token = (_s && fst_session_is_ready_pending(_s)) ?
_s->data.pending_setup_req_dlgt : g->dialog_token;
@@ -1469,7 +1469,7 @@
res.stie.new_band_id = res.stie.old_band_id;
}
- return fst_session_send_action(&s, TRUE, &res, sizeof(res),
+ return fst_session_send_action(&s, true, &res, sizeof(res),
s.data.old_iface->mb_ie);
}
@@ -1477,7 +1477,7 @@
int fst_test_req_send_ack_request(const char *params)
{
int fsts_id;
- Boolean is_valid;
+ bool is_valid;
char *endp;
struct fst_ack_req req;
struct fst_session s;
@@ -1498,14 +1498,14 @@
req.dialog_token = g->dialog_token;
req.fsts_id = host_to_le32(fsts_id);
- return fst_session_send_action(&s, FALSE, &req, sizeof(req), NULL);
+ return fst_session_send_action(&s, false, &req, sizeof(req), NULL);
}
int fst_test_req_send_ack_response(const char *params)
{
int fsts_id;
- Boolean is_valid;
+ bool is_valid;
char *endp;
struct fst_ack_res res;
struct fst_session s;
@@ -1526,14 +1526,14 @@
res.dialog_token = g->dialog_token;
res.fsts_id = host_to_le32(fsts_id);
- return fst_session_send_action(&s, FALSE, &res, sizeof(res), NULL);
+ return fst_session_send_action(&s, false, &res, sizeof(res), NULL);
}
int fst_test_req_send_tear_down(const char *params)
{
int fsts_id;
- Boolean is_valid;
+ bool is_valid;
char *endp;
struct fst_tear_down td;
struct fst_session s;
@@ -1553,14 +1553,14 @@
td.action = FST_ACTION_TEAR_DOWN;
td.fsts_id = host_to_le32(fsts_id);
- return fst_session_send_action(&s, TRUE, &td, sizeof(td), NULL);
+ return fst_session_send_action(&s, true, &td, sizeof(td), NULL);
}
u32 fst_test_req_get_fsts_id(const char *params)
{
int sid;
- Boolean is_valid;
+ bool is_valid;
char *endp;
struct fst_session *s;
diff --git a/src/fst/fst_session.h b/src/fst/fst_session.h
index 1162de4..e43d0ea 100644
--- a/src/fst/fst_session.h
+++ b/src/fst/fst_session.h
@@ -24,10 +24,10 @@
struct fst_session * fst_session_create(struct fst_group *g);
void fst_session_set_iface(struct fst_session *s, struct fst_iface *iface,
- Boolean is_old);
+ bool is_old);
void fst_session_set_llt(struct fst_session *s, u32 llt);
void fst_session_set_peer_addr(struct fst_session *s, const u8 *addr,
- Boolean is_old);
+ bool is_old);
int fst_session_initiate_setup(struct fst_session *s);
int fst_session_respond(struct fst_session *s, u8 status_code);
int fst_session_initiate_switch(struct fst_session *s);
@@ -39,8 +39,8 @@
void fst_session_delete(struct fst_session *s);
struct fst_group * fst_session_get_group(struct fst_session *s);
-struct fst_iface * fst_session_get_iface(struct fst_session *s, Boolean is_old);
-const u8 * fst_session_get_peer_addr(struct fst_session *s, Boolean is_old);
+struct fst_iface * fst_session_get_iface(struct fst_session *s, bool is_old);
+const u8 * fst_session_get_peer_addr(struct fst_session *s, bool is_old);
u32 fst_session_get_id(struct fst_session *s);
u32 fst_session_get_llt(struct fst_session *s);
enum fst_session_state fst_session_get_state(struct fst_session *s);
@@ -57,9 +57,9 @@
int fst_session_set_str_ifname(struct fst_session *s, const char *ifname,
- Boolean is_old);
+ bool is_old);
int fst_session_set_str_peer_addr(struct fst_session *s, const char *mac,
- Boolean is_old);
+ bool is_old);
int fst_session_set_str_llt(struct fst_session *s, const char *llt_str);
#ifdef CONFIG_FST_TEST
diff --git a/src/l2_packet/l2_packet.h b/src/l2_packet/l2_packet.h
index 5387177..6a86280 100644
--- a/src/l2_packet/l2_packet.h
+++ b/src/l2_packet/l2_packet.h
@@ -61,6 +61,10 @@
* points to len bytes of the payload after the layer 2 header and similarly,
* TX buffers start with payload. This behavior can be changed by setting
* l2_hdr=1 to include the layer 2 header in the data buffer.
+ *
+ * IF rx_callback is NULL, receive operation is not opened at all, i.e., only
+ * the TX path and additional helper functions for fetching MAC and IP
+ * addresses can be used.
*/
struct l2_packet_data * l2_packet_init(
const char *ifname, const u8 *own_addr, unsigned short protocol,
diff --git a/src/l2_packet/l2_packet_freebsd.c b/src/l2_packet/l2_packet_freebsd.c
index aa83648..60de9fe 100644
--- a/src/l2_packet/l2_packet_freebsd.c
+++ b/src/l2_packet/l2_packet_freebsd.c
@@ -84,7 +84,7 @@
packet = pcap_next(pcap, &hdr);
- if (packet == NULL || hdr.caplen < sizeof(*ethhdr))
+ if (!l2->rx_callback || !packet || hdr.caplen < sizeof(*ethhdr))
return;
ethhdr = (struct l2_ethhdr *) packet;
diff --git a/src/l2_packet/l2_packet_linux.c b/src/l2_packet/l2_packet_linux.c
index 291c9dd..7897bc0 100644
--- a/src/l2_packet/l2_packet_linux.c
+++ b/src/l2_packet/l2_packet_linux.c
@@ -171,13 +171,16 @@
u8 hash[SHA1_MAC_LEN];
const u8 *addr[1];
size_t len[1];
+ const struct l2_ethhdr *eth = (const struct l2_ethhdr *) buf;
/*
* Close the workaround socket if the kernel version seems to be
* able to deliver packets through the packet socket before
* authorization has been completed (in dormant state).
*/
- if (l2->num_rx_br <= 1) {
+ if (l2->num_rx_br <= 1 &&
+ (os_memcmp(eth->h_dest, l2->own_addr, ETH_ALEN) == 0 ||
+ is_multicast_ether_addr(eth->h_dest))) {
wpa_printf(MSG_DEBUG,
"l2_packet_receive: Main packet socket for %s seems to have working RX - close workaround bridge socket",
l2->ifname);
@@ -309,7 +312,8 @@
ll.sll_family = PF_PACKET;
ll.sll_ifindex = ifr.ifr_ifindex;
ll.sll_protocol = htons(protocol);
- if (bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+ if (rx_callback &&
+ bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
wpa_printf(MSG_ERROR, "%s: bind[PF_PACKET]: %s",
__func__, strerror(errno));
close(l2->fd);
@@ -326,7 +330,8 @@
}
os_memcpy(l2->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
- eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
+ if (rx_callback)
+ eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
return l2;
}
diff --git a/src/l2_packet/l2_packet_ndis.c b/src/l2_packet/l2_packet_ndis.c
index 7167781..4a4b639 100644
--- a/src/l2_packet/l2_packet_ndis.c
+++ b/src/l2_packet/l2_packet_ndis.c
@@ -294,7 +294,8 @@
}
rx_src = ethhdr->h_source;
- l2->rx_callback(l2->rx_callback_ctx, rx_src, rx_buf, rx_len);
+ if (l2->rx_callback)
+ l2->rx_callback(l2->rx_callback_ctx, rx_src, rx_buf, rx_len);
#ifndef _WIN32_WCE
l2_ndisuio_start_read(l2, 1);
#endif /* _WIN32_WCE */
diff --git a/src/l2_packet/l2_packet_none.c b/src/l2_packet/l2_packet_none.c
index 307fc6d..bc7a4e8 100644
--- a/src/l2_packet/l2_packet_none.c
+++ b/src/l2_packet/l2_packet_none.c
@@ -84,7 +84,7 @@
* TODO: open connection for receiving frames
*/
l2->fd = -1;
- if (l2->fd >= 0)
+ if (rx_callback && l2->fd >= 0)
eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
return l2;
@@ -112,7 +112,7 @@
eloop_unregister_read_sock(l2->fd);
/* TODO: close connection */
}
-
+
os_free(l2);
}
diff --git a/src/l2_packet/l2_packet_pcap.c b/src/l2_packet/l2_packet_pcap.c
index 423c099..c2b17fc 100644
--- a/src/l2_packet/l2_packet_pcap.c
+++ b/src/l2_packet/l2_packet_pcap.c
@@ -127,7 +127,7 @@
packet = pcap_next(pcap, &hdr);
- if (packet == NULL || hdr.caplen < sizeof(*ethhdr))
+ if (!l2->rx_callback || !packet || hdr.caplen < sizeof(*ethhdr))
return;
ethhdr = (struct l2_ethhdr *) packet;
@@ -152,7 +152,7 @@
unsigned char *buf;
size_t len;
- if (pkt_data == NULL || hdr->caplen < sizeof(*ethhdr))
+ if (!l2->rx_callback || !pkt_data || hdr->caplen < sizeof(*ethhdr))
return;
ethhdr = (struct l2_ethhdr *) pkt_data;
diff --git a/src/l2_packet/l2_packet_privsep.c b/src/l2_packet/l2_packet_privsep.c
index ce86802..014a45f 100644
--- a/src/l2_packet/l2_packet_privsep.c
+++ b/src/l2_packet/l2_packet_privsep.c
@@ -216,7 +216,8 @@
}
os_memcpy(l2->own_addr, reply, ETH_ALEN);
- eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
+ if (rx_callback)
+ eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
return l2;
diff --git a/src/l2_packet/l2_packet_winpcap.c b/src/l2_packet/l2_packet_winpcap.c
index 74085a3..3452051 100644
--- a/src/l2_packet/l2_packet_winpcap.c
+++ b/src/l2_packet/l2_packet_winpcap.c
@@ -224,6 +224,9 @@
return NULL;
}
+ if (!rx_callback)
+ return l2;
+
l2->rx_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
l2->rx_done = CreateEvent(NULL, TRUE, FALSE, NULL);
l2->rx_notify = CreateEvent(NULL, TRUE, FALSE, NULL);
diff --git a/src/lib.rules b/src/lib.rules
index 4ec4711..a463154 100644
--- a/src/lib.rules
+++ b/src/lib.rules
@@ -11,6 +11,7 @@
CFLAGS += -DTEST_FUZZ
endif
+CFLAGS += $(FUZZ_CFLAGS)
CFLAGS += -I.. -I../utils
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 5cc636b..1dc5b92 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -1071,22 +1071,6 @@
struct p2p_device *dev;
enum p2p_after_scan op;
- if (p2p->after_scan_tx) {
- p2p->after_scan_tx_in_progress = 1;
- p2p_dbg(p2p, "Send pending Action frame at p2p_scan completion");
- p2p->cfg->send_action(p2p->cfg->cb_ctx,
- p2p->after_scan_tx->freq,
- p2p->after_scan_tx->dst,
- p2p->after_scan_tx->src,
- p2p->after_scan_tx->bssid,
- (u8 *) (p2p->after_scan_tx + 1),
- p2p->after_scan_tx->len,
- p2p->after_scan_tx->wait_time, NULL);
- os_free(p2p->after_scan_tx);
- p2p->after_scan_tx = NULL;
- return 1;
- }
-
op = p2p->start_after_scan;
p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
switch (op) {
@@ -1425,6 +1409,7 @@
const int op_classes_5ghz[] = { 124, 125, 115, 0 };
const int op_classes_ht40[] = { 126, 127, 116, 117, 0 };
const int op_classes_vht[] = { 128, 0 };
+ const int op_classes_edmg[] = { 181, 182, 183, 0 };
p2p_dbg(p2p, "Prepare channel best");
@@ -1456,6 +1441,11 @@
p2p_dbg(p2p, "Select first pref_chan entry as operating channel preference");
p2p->op_reg_class = p2p->cfg->pref_chan[0].op_class;
p2p->op_channel = p2p->cfg->pref_chan[0].chan;
+ } else if (p2p_channel_select(&p2p->cfg->channels, op_classes_edmg,
+ &p2p->op_reg_class, &p2p->op_channel) ==
+ 0) {
+ p2p_dbg(p2p, "Select possible EDMG channel (op_class %u channel %u) as operating channel preference",
+ p2p->op_reg_class, p2p->op_channel);
} else if (p2p_channel_select(&p2p->cfg->channels, op_classes_vht,
&p2p->op_reg_class, &p2p->op_channel) ==
0) {
@@ -1651,17 +1641,6 @@
if (p2p->state != P2P_IDLE)
p2p_stop_find(p2p);
- if (p2p->after_scan_tx) {
- /*
- * We need to drop the pending frame to avoid issues with the
- * new GO Negotiation, e.g., when the pending frame was from a
- * previous attempt at starting a GO Negotiation.
- */
- p2p_dbg(p2p, "Dropped previous pending Action frame TX that was waiting for p2p_scan completion");
- os_free(p2p->after_scan_tx);
- p2p->after_scan_tx = NULL;
- }
-
dev->wps_method = wps_method;
dev->oob_pw_id = oob_pw_id;
dev->status = P2P_SC_SUCCESS;
@@ -1672,7 +1651,6 @@
os_memcpy(p2p->after_scan_peer, peer_addr, ETH_ALEN);
return 0;
}
- p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
return p2p_connect_send(p2p, dev);
}
@@ -3060,8 +3038,6 @@
p2p_device_free(p2p, dev);
}
p2p_free_sd_queries(p2p);
- os_free(p2p->after_scan_tx);
- p2p->after_scan_tx = NULL;
p2p->ssid_set = 0;
p2ps_prov_free(p2p);
p2p_reset_pending_pd(p2p);
@@ -3090,13 +3066,6 @@
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
- /* Check if after_scan_tx is for this peer. If so free it */
- if (p2p->after_scan_tx &&
- os_memcmp(addr, p2p->after_scan_tx->dst, ETH_ALEN) == 0) {
- os_free(p2p->after_scan_tx);
- p2p->after_scan_tx = NULL;
- }
-
return 0;
}
@@ -3486,23 +3455,6 @@
}
-static int p2p_check_after_scan_tx_continuation(struct p2p_data *p2p)
-{
- if (p2p->after_scan_tx_in_progress) {
- p2p->after_scan_tx_in_progress = 0;
- if (p2p->start_after_scan != P2P_AFTER_SCAN_NOTHING &&
- p2p_run_after_scan(p2p))
- return 1;
- if (p2p->state == P2P_SEARCH) {
- p2p_dbg(p2p, "Continue find after after_scan_tx completion");
- p2p_continue_find(p2p);
- }
- }
-
- return 0;
-}
-
-
static void p2p_prov_disc_resp_cb(struct p2p_data *p2p, int success)
{
p2p_dbg(p2p, "Provision Discovery Response TX callback: success=%d",
@@ -3515,19 +3467,21 @@
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
- if (!success)
- goto continue_search;
+ if (!success) {
+ if (p2p->state == P2P_SEARCH)
+ p2p_continue_find(p2p);
+ return;
+ }
if (!p2p->cfg->prov_disc_resp_cb ||
- p2p->cfg->prov_disc_resp_cb(p2p->cfg->cb_ctx) < 1)
- goto continue_search;
+ p2p->cfg->prov_disc_resp_cb(p2p->cfg->cb_ctx) < 1) {
+ if (p2p->state == P2P_SEARCH)
+ p2p_continue_find(p2p);
+ return;
+ }
p2p_dbg(p2p,
"Post-Provision Discovery operations started - do not try to continue other P2P operations");
- return;
-
-continue_search:
- p2p_check_after_scan_tx_continuation(p2p);
}
@@ -3817,7 +3771,6 @@
p2p->send_action_in_progress = 0;
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
}
- p2p_check_after_scan_tx_continuation(p2p);
break;
case P2P_PENDING_GO_NEG_REQUEST:
p2p_go_neg_req_cb(p2p, success);
@@ -3845,8 +3798,6 @@
break;
case P2P_PENDING_INVITATION_RESPONSE:
p2p_invitation_resp_cb(p2p, success);
- if (p2p->inv_status != P2P_SC_SUCCESS)
- p2p_check_after_scan_tx_continuation(p2p);
break;
case P2P_PENDING_DEV_DISC_REQUEST:
p2p_dev_disc_req_cb(p2p, success);
@@ -3858,8 +3809,6 @@
p2p_go_disc_req_cb(p2p, success);
break;
}
-
- p2p->after_scan_tx_in_progress = 0;
}
@@ -4985,29 +4934,10 @@
{
int res, scheduled;
- if (p2p->p2p_scan_running) {
- p2p_dbg(p2p, "Delay Action frame TX until p2p_scan completes");
- if (p2p->after_scan_tx) {
- p2p_dbg(p2p, "Dropped previous pending Action frame TX");
- os_free(p2p->after_scan_tx);
- }
- p2p->after_scan_tx = os_malloc(sizeof(*p2p->after_scan_tx) +
- len);
- if (p2p->after_scan_tx == NULL)
- return -1;
- p2p->after_scan_tx->freq = freq;
- os_memcpy(p2p->after_scan_tx->dst, dst, ETH_ALEN);
- os_memcpy(p2p->after_scan_tx->src, src, ETH_ALEN);
- os_memcpy(p2p->after_scan_tx->bssid, bssid, ETH_ALEN);
- p2p->after_scan_tx->len = len;
- p2p->after_scan_tx->wait_time = wait_time;
- os_memcpy(p2p->after_scan_tx + 1, buf, len);
- return 0;
- }
-
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 &&
+ p2p->drv_in_listen > 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",
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 425b037..2dae6c6 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -36,7 +36,7 @@
/**
* P2P_MAX_REG_CLASS_CHANNELS - Maximum number of channels per regulatory class
*/
-#define P2P_MAX_REG_CLASS_CHANNELS 20
+#define P2P_MAX_REG_CLASS_CHANNELS 60
/**
* struct p2p_channels - List of supported channels
@@ -99,6 +99,8 @@
int vht;
+ int edmg;
+
u8 max_oper_chwidth;
unsigned int vht_center_freq2;
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 65ab4b8..1133461 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -390,6 +390,7 @@
const int op_classes_5ghz[] = { 124, 125, 115, 0 };
const int op_classes_ht40[] = { 126, 127, 116, 117, 0 };
const int op_classes_vht[] = { 128, 129, 130, 0 };
+ const int op_classes_edmg[] = { 181, 182, 183, 0 };
if (p2p->own_freq_preference > 0 &&
p2p_freq_to_channel(p2p->own_freq_preference,
@@ -454,6 +455,14 @@
}
}
+ /* Try a channel where we might be able to use EDMG */
+ if (p2p_channel_select(intersection, op_classes_edmg,
+ &p2p->op_reg_class, &p2p->op_channel) == 0) {
+ p2p_dbg(p2p, "Pick possible EDMG channel (op_class %u channel %u) from intersection",
+ p2p->op_reg_class, p2p->op_channel);
+ return;
+ }
+
/* Try a channel where we might be able to use VHT */
if (p2p_channel_select(intersection, op_classes_vht,
&p2p->op_reg_class, &p2p->op_channel) == 0) {
@@ -676,7 +685,9 @@
"Ignore local driver frequency preference %u MHz since it is not acceptable for P2P use (go=%d)",
freq_list[i], go);
if (size - i - 1 > 0)
- os_memmove(&freq_list[i], &freq_list[i + 1], size - i - 1);
+ os_memmove(&freq_list[i], &freq_list[i + 1],
+ (size - i - 1) *
+ sizeof(unsigned int));
size--;
continue;
}
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 64a9977..2b168e8 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -159,16 +159,6 @@
struct wpabuf *tlvs;
};
-struct p2p_pending_action_tx {
- unsigned int freq;
- u8 dst[ETH_ALEN];
- u8 src[ETH_ALEN];
- u8 bssid[ETH_ALEN];
- size_t len;
- unsigned int wait_time;
- /* Followed by len octets of the frame */
-};
-
/**
* struct p2p_data - P2P module data (internal to P2P module)
*/
@@ -460,8 +450,6 @@
P2P_AFTER_SCAN_CONNECT
} start_after_scan;
u8 after_scan_peer[ETH_ALEN];
- struct p2p_pending_action_tx *after_scan_tx;
- unsigned int after_scan_tx_in_progress:1;
unsigned int send_action_in_progress:1;
/* Requested device types for find/search */
diff --git a/src/pae/ieee802_1x_cp.c b/src/pae/ieee802_1x_cp.c
index 1c4dc3e..cf41d8d 100644
--- a/src/pae/ieee802_1x_cp.c
+++ b/src/pae/ieee802_1x_cp.c
@@ -31,50 +31,50 @@
CP_SECURED, CP_RECEIVE, CP_RECEIVING, CP_READY, CP_TRANSMIT,
CP_TRANSMITTING, CP_ABANDON, CP_RETIRE
} CP_state;
- Boolean changed;
+ bool changed;
/* CP -> Client */
- Boolean port_valid;
+ bool port_valid;
/* Logon -> CP */
enum connect_type connect;
/* KaY -> CP */
- Boolean chgd_server; /* clear by CP */
- Boolean elected_self;
+ bool chgd_server; /* clear by CP */
+ bool elected_self;
enum confidentiality_offset cipher_offset;
u64 cipher_suite;
- Boolean new_sak; /* clear by CP */
+ bool new_sak; /* clear by CP */
struct ieee802_1x_mka_ki distributed_ki;
u8 distributed_an;
- Boolean using_receive_sas;
- Boolean all_receiving;
- Boolean server_transmitting;
- Boolean using_transmit_sa;
+ bool using_receive_sas;
+ bool all_receiving;
+ bool server_transmitting;
+ bool using_transmit_sa;
/* CP -> KaY */
struct ieee802_1x_mka_ki *lki;
u8 lan;
- Boolean ltx;
- Boolean lrx;
+ bool ltx;
+ bool lrx;
struct ieee802_1x_mka_ki *oki;
u8 oan;
- Boolean otx;
- Boolean orx;
+ bool otx;
+ bool orx;
/* CP -> SecY */
- Boolean protect_frames;
+ bool protect_frames;
enum validate_frames validate_frames;
- Boolean replay_protect;
+ bool replay_protect;
u32 replay_window;
u64 current_cipher_suite;
enum confidentiality_offset confidentiality_offset;
- Boolean controlled_port_enabled;
+ bool controlled_port_enabled;
/* SecY -> CP */
- Boolean port_enabled; /* SecY->CP */
+ bool port_enabled; /* SecY->CP */
/* private */
u32 transmit_when;
@@ -109,23 +109,23 @@
{
SM_ENTRY(CP, INIT);
- sm->controlled_port_enabled = FALSE;
+ sm->controlled_port_enabled = false;
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
- sm->port_valid = FALSE;
+ sm->port_valid = false;
os_free(sm->lki);
sm->lki = NULL;
- sm->ltx = FALSE;
- sm->lrx = FALSE;
+ sm->ltx = false;
+ sm->lrx = false;
os_free(sm->oki);
sm->oki = NULL;
- sm->otx = FALSE;
- sm->orx = FALSE;
+ sm->otx = false;
+ sm->orx = false;
- sm->port_enabled = TRUE;
- sm->chgd_server = FALSE;
+ sm->port_enabled = true;
+ sm->chgd_server = false;
}
@@ -133,14 +133,32 @@
{
SM_ENTRY(CP, CHANGE);
- sm->port_valid = FALSE;
- sm->controlled_port_enabled = FALSE;
+ sm->port_valid = false;
+ sm->controlled_port_enabled = false;
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
if (sm->lki)
ieee802_1x_kay_delete_sas(sm->kay, sm->lki);
if (sm->oki)
ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
+ /* The standard doesn't say it but we should clear out the latest
+ * and old key values. Why would we keep advertising them if
+ * they've been deleted and the key server has been changed?
+ */
+ os_free(sm->oki);
+ sm->oki = NULL;
+ sm->otx = false;
+ sm->orx = false;
+ sm->oan = 0;
+ ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
+ sm->otx, sm->orx);
+ os_free(sm->lki);
+ sm->lki = NULL;
+ sm->lrx = false;
+ sm->ltx = false;
+ sm->lan = 0;
+ ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
+ sm->ltx, sm->lrx);
}
@@ -148,12 +166,12 @@
{
SM_ENTRY(CP, ALLOWED);
- sm->protect_frames = FALSE;
- sm->replay_protect = FALSE;
+ sm->protect_frames = false;
+ sm->replay_protect = false;
sm->validate_frames = Checked;
- sm->port_valid = FALSE;
- sm->controlled_port_enabled = TRUE;
+ sm->port_valid = false;
+ sm->controlled_port_enabled = true;
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
@@ -167,12 +185,12 @@
{
SM_ENTRY(CP, AUTHENTICATED);
- sm->protect_frames = FALSE;
- sm->replay_protect = FALSE;
+ sm->protect_frames = false;
+ sm->replay_protect = false;
sm->validate_frames = Checked;
- sm->port_valid = FALSE;
- sm->controlled_port_enabled = TRUE;
+ sm->port_valid = false;
+ sm->controlled_port_enabled = true;
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
@@ -186,7 +204,7 @@
{
SM_ENTRY(CP, SECURED);
- sm->chgd_server = FALSE;
+ sm->chgd_server = false;
sm->protect_frames = sm->kay->macsec_protect;
sm->replay_protect = sm->kay->macsec_replay_protect;
@@ -198,7 +216,7 @@
sm->confidentiality_offset = sm->cipher_offset;
- sm->port_valid = TRUE;
+ sm->port_valid = true;
secy_cp_control_confidentiality_offset(sm->kay,
sm->confidentiality_offset);
@@ -212,18 +230,6 @@
SM_STATE(CP, RECEIVE)
{
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;
- sm->orx = sm->lrx;
- ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
- sm->otx, sm->orx);
sm->lki = os_malloc(sizeof(*sm->lki));
if (!sm->lki) {
@@ -232,14 +238,14 @@
}
os_memcpy(sm->lki, &sm->distributed_ki, sizeof(*sm->lki));
sm->lan = sm->distributed_an;
- sm->ltx = FALSE;
- sm->lrx = FALSE;
+ sm->ltx = false;
+ sm->lrx = false;
ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
sm->ltx, sm->lrx);
ieee802_1x_kay_create_sas(sm->kay, sm->lki);
ieee802_1x_kay_enable_rx_sas(sm->kay, sm->lki);
- sm->new_sak = FALSE;
- sm->all_receiving = FALSE;
+ sm->new_sak = false;
+ sm->all_receiving = false;
}
@@ -247,7 +253,7 @@
{
SM_ENTRY(CP, RECEIVING);
- sm->lrx = TRUE;
+ sm->lrx = true;
ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
sm->ltx, sm->lrx);
sm->transmit_when = sm->transmit_delay;
@@ -258,8 +264,8 @@
* but the CP will transmit from RECEIVING to READY under
* the !electedSelf when KaY is not key server */
ieee802_1x_cp_sm_step(sm);
- sm->using_receive_sas = FALSE;
- sm->server_transmitting = FALSE;
+ sm->using_receive_sas = false;
+ sm->server_transmitting = false;
}
@@ -275,14 +281,14 @@
{
SM_ENTRY(CP, TRANSMIT);
- sm->controlled_port_enabled = TRUE;
+ sm->controlled_port_enabled = true;
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
- sm->ltx = TRUE;
+ sm->ltx = true;
ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
sm->ltx, sm->lrx);
ieee802_1x_kay_enable_tx_sas(sm->kay, sm->lki);
- sm->all_receiving = FALSE;
- sm->server_transmitting = FALSE;
+ sm->all_receiving = false;
+ sm->server_transmitting = false;
}
@@ -290,21 +296,21 @@
{
SM_ENTRY(CP, TRANSMITTING);
sm->retire_when = sm->orx ? sm->retire_delay : 0;
- sm->otx = FALSE;
+ sm->otx = false;
ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
sm->otx, sm->orx);
ieee802_1x_kay_enable_new_info(sm->kay);
eloop_cancel_timeout(ieee802_1x_cp_retire_when_timeout, sm, NULL);
eloop_register_timeout(sm->retire_when / 1000, 0,
ieee802_1x_cp_retire_when_timeout, sm, NULL);
- sm->using_transmit_sa = FALSE;
+ sm->using_transmit_sa = false;
}
SM_STATE(CP, ABANDON)
{
SM_ENTRY(CP, ABANDON);
- sm->lrx = FALSE;
+ sm->lrx = false;
ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
sm->ltx, sm->lrx);
ieee802_1x_kay_delete_sas(sm->kay, sm->lki);
@@ -313,24 +319,29 @@
sm->lki = NULL;
ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
sm->ltx, sm->lrx);
- sm->new_sak = FALSE;
}
SM_STATE(CP, RETIRE)
{
SM_ENTRY(CP, RETIRE);
- /* RETIRE 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 = NULL;
}
- sm->orx = FALSE;
- sm->otx = FALSE;
+ sm->oki = sm->lki;
+ sm->otx = sm->ltx;
+ sm->orx = sm->lrx;
+ sm->oan = sm->lan;
ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
sm->otx, sm->orx);
+ sm->lki = NULL;
+ sm->ltx = false;
+ sm->lrx = false;
+ sm->lan = 0;
+ ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
+ sm->ltx, sm->lrx);
}
@@ -444,23 +455,23 @@
sm->kay = kay;
- sm->port_valid = FALSE;
+ sm->port_valid = false;
- sm->chgd_server = FALSE;
+ sm->chgd_server = false;
sm->protect_frames = kay->macsec_protect;
sm->validate_frames = kay->macsec_validate;
sm->replay_protect = kay->macsec_replay_protect;
sm->replay_window = kay->macsec_replay_window;
- sm->controlled_port_enabled = FALSE;
+ sm->controlled_port_enabled = false;
sm->lki = NULL;
- sm->lrx = FALSE;
- sm->ltx = FALSE;
+ sm->lrx = false;
+ sm->ltx = false;
sm->oki = NULL;
- sm->orx = FALSE;
- sm->otx = FALSE;
+ sm->orx = false;
+ sm->otx = false;
sm->current_cipher_suite = default_cs_id;
sm->cipher_suite = default_cs_id;
@@ -469,7 +480,7 @@
sm->transmit_delay = MKA_LIFE_TIME;
sm->retire_delay = MKA_SAK_RETIRE_TIME;
sm->CP_state = CP_BEGIN;
- sm->changed = FALSE;
+ sm->changed = false;
wpa_printf(MSG_DEBUG, "CP: state machine created");
@@ -577,14 +588,14 @@
{
struct ieee802_1x_cp_sm *sm = cp_ctx;
- sm->chgd_server = TRUE;
+ sm->chgd_server = true;
}
/**
* ieee802_1x_cp_set_electedself -
*/
-void ieee802_1x_cp_set_electedself(void *cp_ctx, Boolean status)
+void ieee802_1x_cp_set_electedself(void *cp_ctx, bool status)
{
struct ieee802_1x_cp_sm *sm = cp_ctx;
sm->elected_self = status;
@@ -617,7 +628,7 @@
void ieee802_1x_cp_signal_newsak(void *cp_ctx)
{
struct ieee802_1x_cp_sm *sm = cp_ctx;
- sm->new_sak = TRUE;
+ sm->new_sak = true;
}
@@ -645,7 +656,7 @@
/**
* ieee802_1x_cp_set_usingreceivesas -
*/
-void ieee802_1x_cp_set_usingreceivesas(void *cp_ctx, Boolean status)
+void ieee802_1x_cp_set_usingreceivesas(void *cp_ctx, bool status)
{
struct ieee802_1x_cp_sm *sm = cp_ctx;
sm->using_receive_sas = status;
@@ -655,7 +666,7 @@
/**
* ieee802_1x_cp_set_allreceiving -
*/
-void ieee802_1x_cp_set_allreceiving(void *cp_ctx, Boolean status)
+void ieee802_1x_cp_set_allreceiving(void *cp_ctx, bool status)
{
struct ieee802_1x_cp_sm *sm = cp_ctx;
sm->all_receiving = status;
@@ -665,7 +676,7 @@
/**
* ieee802_1x_cp_set_servertransmitting -
*/
-void ieee802_1x_cp_set_servertransmitting(void *cp_ctx, Boolean status)
+void ieee802_1x_cp_set_servertransmitting(void *cp_ctx, bool status)
{
struct ieee802_1x_cp_sm *sm = cp_ctx;
sm->server_transmitting = status;
@@ -675,7 +686,7 @@
/**
* ieee802_1x_cp_set_usingtransmitsas -
*/
-void ieee802_1x_cp_set_usingtransmitas(void *cp_ctx, Boolean status)
+void ieee802_1x_cp_set_usingtransmitas(void *cp_ctx, bool status)
{
struct ieee802_1x_cp_sm *sm = cp_ctx;
sm->using_transmit_sa = status;
diff --git a/src/pae/ieee802_1x_cp.h b/src/pae/ieee802_1x_cp.h
index a357b27..94110c8 100644
--- a/src/pae/ieee802_1x_cp.h
+++ b/src/pae/ieee802_1x_cp.h
@@ -24,16 +24,16 @@
void ieee802_1x_cp_connect_authenticated(void *cp_ctx);
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_electedself(void *cp_ctx, bool status);
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);
void ieee802_1x_cp_set_distributedki(void *cp_ctx,
const struct ieee802_1x_mka_ki *dki);
void ieee802_1x_cp_set_distributedan(void *cp_ctx, u8 an);
-void ieee802_1x_cp_set_usingreceivesas(void *cp_ctx, Boolean status);
-void ieee802_1x_cp_set_allreceiving(void *cp_ctx, Boolean status);
-void ieee802_1x_cp_set_servertransmitting(void *cp_ctx, Boolean status);
-void ieee802_1x_cp_set_usingtransmitas(void *cp_ctx, Boolean status);
+void ieee802_1x_cp_set_usingreceivesas(void *cp_ctx, bool status);
+void ieee802_1x_cp_set_allreceiving(void *cp_ctx, bool status);
+void ieee802_1x_cp_set_servertransmitting(void *cp_ctx, bool status);
+void ieee802_1x_cp_set_usingtransmitas(void *cp_ctx, bool status);
#endif /* IEEE802_1X_CP_H */
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index b4455c8..2fe88ac 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -354,7 +354,7 @@
/**
* ieee802_1x_kay_is_in_potential_peer
*/
-static Boolean
+static bool
ieee802_1x_kay_is_in_potential_peer(
struct ieee802_1x_mka_participant *participant, const u8 *mi)
{
@@ -365,7 +365,7 @@
/**
* ieee802_1x_kay_is_in_live_peer
*/
-static Boolean
+static bool
ieee802_1x_kay_is_in_live_peer(
struct ieee802_1x_mka_participant *participant, const u8 *mi)
{
@@ -426,8 +426,8 @@
}
-static Boolean sci_equal(const struct ieee802_1x_mka_sci *a,
- const struct ieee802_1x_mka_sci *b)
+static bool sci_equal(const struct ieee802_1x_mka_sci *a,
+ const struct ieee802_1x_mka_sci *b)
{
return os_memcmp(a, b, sizeof(struct ieee802_1x_mka_sci)) == 0;
}
@@ -486,7 +486,7 @@
psa->sc = psc;
os_get_time(&psa->created_time);
- psa->in_use = FALSE;
+ psa->in_use = false;
dl_list_add(&psc->sa_list, &psa->list);
wpa_printf(MSG_DEBUG,
@@ -534,7 +534,7 @@
os_memcpy(&psc->sci, psci, sizeof(psc->sci));
os_get_time(&psc->created_time);
- psc->receiving = FALSE;
+ psc->receiving = false;
dl_list_init(&psc->sa_list);
wpa_printf(MSG_DEBUG, "KaY: Create receive SC: SCI %s",
@@ -594,7 +594,7 @@
os_memcpy(peer->mi, mi, MI_LEN);
peer->mn = mn;
peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
- peer->sak_used = FALSE;
+ peer->sak_used = false;
peer->missing_sak_use_count = 0;
return peer;
@@ -706,11 +706,11 @@
/**
* ieee802_1x_mka_basic_body_present -
*/
-static Boolean
+static bool
ieee802_1x_mka_basic_body_present(
struct ieee802_1x_mka_participant *participant)
{
- return TRUE;
+ return true;
}
@@ -774,14 +774,14 @@
}
-static Boolean
+static bool
reset_participant_mi(struct ieee802_1x_mka_participant *participant)
{
if (os_get_random(participant->mi, sizeof(participant->mi)) < 0)
- return FALSE;
+ return false;
participant->mn = 0;
- return TRUE;
+ return true;
}
@@ -888,13 +888,13 @@
peer->macsec_desired = body->macsec_desired;
peer->macsec_capability = body->macsec_capability;
- peer->is_key_server = (Boolean) body->key_server;
+ peer->is_key_server = body->key_server;
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->macsec_desired = body->macsec_desired;
peer->macsec_capability = body->macsec_capability;
- peer->is_key_server = (Boolean) body->key_server;
+ peer->is_key_server = body->key_server;
peer->key_server_priority = body->priority;
} else {
wpa_printf(MSG_WARNING,
@@ -909,7 +909,7 @@
/**
* ieee802_1x_mka_live_peer_body_present
*/
-static Boolean
+static bool
ieee802_1x_mka_live_peer_body_present(
struct ieee802_1x_mka_participant *participant)
{
@@ -969,7 +969,7 @@
/**
* ieee802_1x_mka_potential_peer_body_present
*/
-static Boolean
+static bool
ieee802_1x_mka_potential_peer_body_present(
struct ieee802_1x_mka_participant *participant)
{
@@ -1030,7 +1030,7 @@
/**
* ieee802_1x_mka_i_in_peerlist -
*/
-static Boolean
+static bool
ieee802_1x_mka_i_in_peerlist(struct ieee802_1x_mka_participant *participant,
const u8 *mka_msg, size_t msg_len)
{
@@ -1055,7 +1055,7 @@
left_len, MKA_HDR_LEN,
MKA_ALIGN_LENGTH(body_len),
DEFAULT_ICV_LEN);
- return FALSE;
+ return false;
}
if (body_type != MKA_LIVE_PEER_LIST &&
@@ -1085,13 +1085,23 @@
wpa_printf(MSG_DEBUG,
"KaY: My MI - received MN %u, most recently transmitted MN %u",
mn, participant->mn);
- if (mn == participant->mn)
- return TRUE;
+ /* IEEE Std 802.1X-2010 is not exactly clear
+ * which values of MN should be accepted here.
+ * It uses "acceptably recent MN" language
+ * without defining what would be acceptable
+ * recent. For now, allow the last two used MN
+ * values (i.e., peer having copied my MI,MN
+ * from either of the last two MKPDUs that I
+ * have sent). */
+ if (mn == participant->mn ||
+ (participant->mn > 1 &&
+ mn == participant->mn - 1))
+ return true;
}
}
}
- return FALSE;
+ return false;
}
@@ -1106,7 +1116,7 @@
struct ieee802_1x_kay_peer *peer;
size_t body_len;
size_t i;
- Boolean is_included;
+ bool is_included;
is_included = ieee802_1x_kay_is_in_live_peer(
participant, participant->current_peer_id.mi);
@@ -1199,7 +1209,7 @@
/**
* ieee802_1x_mka_sak_use_body_present
*/
-static Boolean
+static bool
ieee802_1x_mka_sak_use_body_present(
struct ieee802_1x_mka_participant *participant)
{
@@ -1277,7 +1287,7 @@
struct ieee802_1x_mka_sak_use_body *body;
struct ieee802_1x_kay *kay = participant->kay;
unsigned int length;
- u32 pn = 1;
+ u32 olpn, llpn;
length = ieee802_1x_mka_get_sak_use_length(participant);
body = wpabuf_put(buf, length);
@@ -1286,29 +1296,42 @@
set_mka_param_body_len(body, length - MKA_HDR_LEN);
if (length == MKA_HDR_LEN) {
- body->ptx = TRUE;
- body->prx = TRUE;
+ body->ptx = true;
+ body->prx = true;
body->lan = 0;
- body->lrx = FALSE;
- body->ltx = FALSE;
- body->delay_protect = FALSE;
+ body->lrx = false;
+ body->ltx = false;
+ body->delay_protect = false;
return 0;
}
/* 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");
- if (participant->is_key_server)
- participant->new_sak = TRUE;
+ /* lowest accept packet numbers */
+ olpn = ieee802_1x_mka_get_lpn(participant, &participant->oki);
+ body->olpn = host_to_be32(olpn);
+ llpn = ieee802_1x_mka_get_lpn(participant, &participant->lki);
+ body->llpn = host_to_be32(llpn);
+ if (participant->is_key_server) {
+ /* The CP will spend most of it's time in RETIRE where only
+ * the old key is populated. Therefore we should be checking
+ * the OLPN most of the time.
+ */
+ if (participant->lrx) {
+ if (llpn > kay->pn_exhaustion) {
+ wpa_printf(MSG_WARNING,
+ "KaY: My LLPN exhaustion");
+ participant->new_sak = true;
+ }
+ } else {
+ if (olpn > kay->pn_exhaustion) {
+ wpa_printf(MSG_WARNING,
+ "KaY: My OLPN exhaustion");
+ participant->new_sak = true;
+ }
+ }
}
- body->llpn = host_to_be32(pn);
- pn = ieee802_1x_mka_get_lpn(participant, &participant->oki);
- body->olpn = host_to_be32(pn);
-
/* plain tx, plain rx */
body->ptx = !kay->macsec_protect;
body->prx = kay->macsec_validate != Strict;
@@ -1324,23 +1347,23 @@
body->oan = participant->oan;
if (participant->oki.kn != participant->lki.kn &&
participant->oki.kn != 0) {
- body->otx = TRUE;
- body->orx = TRUE;
+ body->otx = true;
+ body->orx = true;
os_memcpy(body->osrv_mi, participant->oki.mi,
sizeof(body->osrv_mi));
body->okn = host_to_be32(participant->oki.kn);
} else {
- body->otx = FALSE;
- body->orx = FALSE;
+ body->otx = false;
+ body->orx = false;
}
/* set CP's variable */
if (body->ltx) {
- kay->tx_enable = TRUE;
- kay->port_enable = TRUE;
+ kay->tx_enable = true;
+ kay->port_enable = true;
}
if (body->lrx)
- kay->rx_enable = TRUE;
+ kay->rx_enable = true;
ieee802_1x_mka_dump_sak_use_body(body);
return 0;
@@ -1358,15 +1381,12 @@
struct ieee802_1x_mka_hdr *hdr;
struct ieee802_1x_mka_sak_use_body *body;
struct ieee802_1x_kay_peer *peer;
- struct receive_sc *rxsc;
- struct receive_sa *rxsa;
struct data_key *sa_key = NULL;
size_t body_len;
struct ieee802_1x_mka_ki ki;
u32 lpn;
- Boolean all_receiving;
- Boolean found;
struct ieee802_1x_kay *kay = participant->kay;
+ u32 olpn, llpn;
if (!participant->principal) {
wpa_printf(MSG_WARNING, "KaY: Participant is not principal");
@@ -1407,46 +1427,6 @@
if (body->ptx)
wpa_printf(MSG_WARNING, "KaY: peer's plain tx are TRUE");
-
- /* check latest key is valid */
- if (body->ltx || body->lrx) {
- found = FALSE;
- os_memcpy(ki.mi, body->lsrv_mi, sizeof(ki.mi));
- ki.kn = be_to_host32(body->lkn);
- dl_list_for_each(sa_key, &participant->sak_list,
- struct data_key, list) {
- if (is_ki_equal(&sa_key->key_identifier, &ki)) {
- found = TRUE;
- break;
- }
- }
- if (!found) {
- wpa_printf(MSG_INFO, "KaY: Latest key is invalid");
- return -1;
- }
- if (os_memcmp(participant->lki.mi, body->lsrv_mi,
- sizeof(participant->lki.mi)) == 0 &&
- be_to_host32(body->lkn) == participant->lki.kn &&
- body->lan == participant->lan) {
- peer->sak_used = TRUE;
- }
- if (body->ltx && peer->is_key_server) {
- ieee802_1x_cp_set_servertransmitting(kay->cp, TRUE);
- ieee802_1x_cp_sm_step(kay->cp);
- }
- }
-
- /* 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 ||
- body->oan != participant->oan) {
- wpa_printf(MSG_WARNING, "KaY: Old key is invalid");
- return -1;
- }
- }
-
/* TODO: how to set the MACsec hardware when delay_protect is true */
if (body->delay_protect &&
(!be_to_host32(body->llpn) || !be_to_host32(body->olpn))) {
@@ -1455,65 +1435,132 @@
return -1;
}
- /* check all live peer have used the sak for receiving sa */
- all_receiving = TRUE;
- dl_list_for_each(peer, &participant->live_peers,
- struct ieee802_1x_kay_peer, list) {
- if (!peer->sak_used) {
- all_receiving = FALSE;
- break;
- }
- }
- if (all_receiving) {
- participant->to_dist_sak = FALSE;
- ieee802_1x_cp_set_allreceiving(kay->cp, TRUE);
- ieee802_1x_cp_sm_step(kay->cp);
+ olpn = be_to_host32(body->olpn);
+ llpn = be_to_host32(body->llpn);
+
+ /* Our most recent distributed key should be the first in the list.
+ * If it doesn't exist then we can't really do anything.
+ * Be lenient and don't return error here as there are legitimate cases
+ * where this can happen such as when a new participant joins the CA and
+ * the first frame it receives can have a SAKuse but not distSAK.
+ */
+ sa_key = dl_list_first(&participant->sak_list, struct data_key, list);
+ if (!sa_key) {
+ wpa_printf(MSG_INFO,
+ "KaY: We don't have a latest distributed key - ignore SAK use");
+ return 0;
}
- /* 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) {
- participant->new_sak = TRUE;
- wpa_printf(MSG_WARNING, "KaY: Peer LPN exhaustion");
- }
+ /* The peer's most recent key will be the "latest key" if it is present
+ * otherwise it will be the "old key" if in the RETIRE state.
+ */
+ if (body->lrx) {
+ os_memcpy(ki.mi, body->lsrv_mi, sizeof(ki.mi));
+ ki.kn = be_to_host32(body->lkn);
+ lpn = llpn;
+ } else {
+ os_memcpy(ki.mi, body->osrv_mi, sizeof(ki.mi));
+ ki.kn = be_to_host32(body->okn);
+ lpn = olpn;
}
- if (sa_key)
- sa_key->next_pn = lpn;
- found = FALSE;
- 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;
+ /* If the most recent distributed keys don't agree then someone is out
+ * of sync. Perhaps non key server hasn't processed the most recent
+ * distSAK yet and the key server is processing an old packet after it
+ * has done distSAK. Be lenient and don't return error in this
+ * particular case; otherwise, the key server will reset its MI and
+ * cause a traffic disruption which is really undesired for a simple
+ * timing issue.
+ */
+ if (!is_ki_equal(&sa_key->key_identifier, &ki)) {
+ wpa_printf(MSG_INFO,
+ "KaY: Distributed keys don't match - ignore SAK use");
+ return 0;
+ }
+ sa_key->next_pn = lpn;
+
+ /* The key server must check that all peers are using the most recent
+ * distributed key. Non key servers must check if the key server is
+ * transmitting.
+ */
+ if (participant->is_key_server) {
+ struct ieee802_1x_kay_peer *peer_iter;
+ bool all_receiving = true;
+
+ /* Distributed keys are equal from above comparison. */
+ peer->sak_used = true;
+
+ dl_list_for_each(peer_iter, &participant->live_peers,
+ struct ieee802_1x_kay_peer, list) {
+ if (!peer_iter->sak_used) {
+ all_receiving = false;
break;
}
}
- if (found)
- break;
- }
- if (!found) {
- wpa_printf(MSG_WARNING, "KaY: Can't find rxsa");
- return -1;
+ if (all_receiving) {
+ participant->to_dist_sak = false;
+ ieee802_1x_cp_set_allreceiving(kay->cp, true);
+ ieee802_1x_cp_sm_step(kay->cp);
+ }
+ } else if (peer->is_key_server) {
+ if (body->ltx) {
+ ieee802_1x_cp_set_servertransmitting(kay->cp, true);
+ ieee802_1x_cp_sm_step(kay->cp);
+ }
}
+ /* If I'm key server, and detects peer member PN exhaustion, rekey.
+ * We only need to check the PN of the most recent distributed key. This
+ * could be the peer's "latest" or "old" key depending on its current
+ * state. If both "old" and "latest" keys are present then the "old" key
+ * has already been exhausted.
+ */
+ if (participant->is_key_server && lpn > kay->pn_exhaustion) {
+ participant->new_sak = true;
+ wpa_printf(MSG_WARNING, "KaY: Peer LPN exhaustion");
+ }
+
+ /* Get the associated RX SAs of the keys for delay protection since both
+ * can be in use. Delay protect window (communicated via MKA) is tighter
+ * than SecY's current replay protect window, so tell SecY the new (and
+ * higher) 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);
+ struct receive_sc *rxsc;
+ struct receive_sa *rxsa;
+ bool found = false;
+
+ 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;
}
- /* 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. */
+ if (found) {
+ secy_get_receive_lowest_pn(participant->kay, rxsa);
+ if (lpn > rxsa->lowest_pn) {
+ rxsa->lowest_pn = lpn;
+ secy_set_receive_lowest_pn(participant->kay,
+ rxsa);
+ wpa_printf(MSG_DEBUG,
+ "KaY: update dist LPN=0x%x", lpn);
+ }
+ }
+
+ /* FIX: Delay protection for the SA being replaced is not
+ * implemented. Note that this key will be active for at least
+ * MKA_SAK_RETIRE_TIME (3 seconds) but could be longer depending
+ * on how long it takes to get from RECEIVE to TRANSMITTING or
+ * if going via ABANDON. Delay protection does allow PNs within
+ * a 2 second window, so getting PN would be a lot of work for
+ * just 1 second's worth of protection.
+ */
}
return 0;
@@ -1523,7 +1570,7 @@
/**
* ieee802_1x_mka_dist_sak_body_present
*/
-static Boolean
+static bool
ieee802_1x_mka_dist_sak_body_present(
struct ieee802_1x_mka_participant *participant)
{
@@ -1616,8 +1663,8 @@
*/
static void ieee802_1x_kay_init_data_key(struct data_key *pkey)
{
- pkey->transmits = TRUE;
- pkey->receives = TRUE;
+ pkey->transmits = true;
+ pkey->receives = true;
os_get_time(&pkey->created_time);
pkey->next_pn = 1;
@@ -1683,21 +1730,21 @@
}
if (body_len == 0) {
- kay->authenticated = TRUE;
- kay->secured = FALSE;
- kay->failed = FALSE;
- participant->advised_desired = FALSE;
+ kay->authenticated = true;
+ kay->secured = false;
+ kay->failed = false;
+ 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");
- participant->to_use_sak = FALSE;
+ participant->to_use_sak = false;
return 0;
}
- participant->advised_desired = TRUE;
- kay->authenticated = FALSE;
- kay->secured = TRUE;
- kay->failed = FALSE;
+ participant->advised_desired = true;
+ kay->authenticated = false;
+ kay->secured = true;
+ kay->failed = false;
ieee802_1x_cp_connect_secure(kay->cp);
ieee802_1x_cp_sm_step(kay->cp);
@@ -1778,7 +1825,7 @@
ieee802_1x_cp_sm_step(kay->cp);
kay->rcvd_keys++;
- participant->to_use_sak = TRUE;
+ participant->to_use_sak = true;
return 0;
}
@@ -1787,10 +1834,10 @@
/**
* ieee802_1x_mka_icv_body_present
*/
-static Boolean
+static bool
ieee802_1x_mka_icv_body_present(struct ieee802_1x_mka_participant *participant)
{
- return TRUE;
+ return true;
}
@@ -1955,7 +2002,7 @@
int (*body_rx)(struct ieee802_1x_mka_participant *participant,
const u8 *mka_msg, size_t msg_len);
int (*body_length)(struct ieee802_1x_mka_participant *participant);
- Boolean (*body_present)(struct ieee802_1x_mka_participant *participant);
+ bool (*body_present)(struct ieee802_1x_mka_participant *participant);
};
@@ -2182,7 +2229,7 @@
dl_list_for_each(peer, &participant->live_peers,
struct ieee802_1x_kay_peer, list)
- peer->sak_used = FALSE;
+ peer->sak_used = false;
kay->dist_kn++;
kay->dist_an++;
@@ -2222,13 +2269,13 @@
struct ieee802_1x_kay_peer *peer;
struct ieee802_1x_kay_peer *key_server = NULL;
struct ieee802_1x_kay *kay = participant->kay;
- Boolean i_is_key_server;
+ bool i_is_key_server;
int priority_comparison;
if (participant->is_obliged_key_server) {
- participant->new_sak = TRUE;
- participant->to_dist_sak = FALSE;
- ieee802_1x_cp_set_electedself(kay->cp, TRUE);
+ participant->new_sak = true;
+ participant->to_dist_sak = false;
+ ieee802_1x_cp_set_electedself(kay->cp, true);
return 0;
}
@@ -2248,7 +2295,7 @@
}
/* elect the key server between me and the above elected peer */
- i_is_key_server = FALSE;
+ i_is_key_server = false;
if (key_server && participant->can_be_key_server) {
struct ieee802_1x_kay_peer tmp;
@@ -2256,29 +2303,29 @@
os_memcpy(&tmp.sci, &kay->actor_sci, sizeof(tmp.sci));
priority_comparison = compare_priorities(&tmp, key_server);
if (priority_comparison < 0) {
- i_is_key_server = TRUE;
+ 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;
+ i_is_key_server = true;
}
if (i_is_key_server) {
- ieee802_1x_cp_set_electedself(kay->cp, TRUE);
+ ieee802_1x_cp_set_electedself(kay->cp, true);
if (!sci_equal(&kay->key_server_sci, &kay->actor_sci)) {
ieee802_1x_cp_signal_chgdserver(kay->cp);
ieee802_1x_cp_sm_step(kay->cp);
}
- participant->is_key_server = TRUE;
- participant->principal = TRUE;
- participant->new_sak = TRUE;
+ participant->is_key_server = true;
+ participant->principal = true;
+ participant->new_sak = true;
wpa_printf(MSG_DEBUG, "KaY: I am elected as key server");
- participant->to_dist_sak = FALSE;
- participant->is_elected = TRUE;
+ participant->to_dist_sak = false;
+ participant->is_elected = true;
os_memcpy(&kay->key_server_sci, &kay->actor_sci,
sizeof(kay->key_server_sci));
@@ -2287,23 +2334,23 @@
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);
+ 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);
ieee802_1x_cp_sm_step(kay->cp);
}
- participant->is_key_server = FALSE;
- participant->principal = TRUE;
- participant->is_elected = TRUE;
+ participant->is_key_server = false;
+ participant->principal = true;
+ participant->is_elected = true;
os_memcpy(&kay->key_server_sci, &key_server->sci,
sizeof(kay->key_server_sci));
kay->key_server_priority = key_server->key_server_priority;
} else {
- participant->principal = FALSE;
- participant->is_key_server = FALSE;
- participant->is_elected = FALSE;
+ participant->principal = false;
+ participant->is_key_server = false;
+ participant->is_elected = false;
}
return 0;
@@ -2323,24 +2370,24 @@
struct ieee802_1x_kay *kay = participant->kay;
struct ieee802_1x_kay_peer *peer;
enum macsec_cap less_capability;
- Boolean has_peer;
+ bool has_peer;
if (!participant->is_key_server)
return -1;
/* key server self is MACsec-desired and requesting MACsec */
if (!kay->macsec_desired) {
- participant->advised_desired = FALSE;
+ participant->advised_desired = false;
return -1;
}
if (kay->macsec_capable == MACSEC_CAP_NOT_IMPLEMENTED) {
- participant->advised_desired = FALSE;
+ participant->advised_desired = false;
return -1;
}
less_capability = kay->macsec_capable;
/* at least one of peers is MACsec-desired and requesting MACsec */
- has_peer = FALSE;
+ has_peer = false;
dl_list_for_each(peer, &participant->live_peers,
struct ieee802_1x_kay_peer, list) {
if (!peer->macsec_desired)
@@ -2351,24 +2398,24 @@
less_capability = (less_capability < peer->macsec_capability) ?
less_capability : peer->macsec_capability;
- has_peer = TRUE;
+ has_peer = true;
}
if (has_peer) {
- participant->advised_desired = TRUE;
+ participant->advised_desired = true;
participant->advised_capability = less_capability;
- kay->authenticated = FALSE;
- kay->secured = TRUE;
- kay->failed = FALSE;
+ kay->authenticated = false;
+ kay->secured = true;
+ kay->failed = false;
ieee802_1x_cp_connect_secure(kay->cp);
ieee802_1x_cp_sm_step(kay->cp);
} else {
- participant->advised_desired = FALSE;
+ participant->advised_desired = false;
participant->advised_capability = MACSEC_CAP_NOT_IMPLEMENTED;
- participant->to_use_sak = FALSE;
- kay->authenticated = TRUE;
- kay->secured = FALSE;
- kay->failed = FALSE;
+ participant->to_use_sak = false;
+ kay->authenticated = true;
+ kay->secured = false;
+ kay->failed = false;
kay->ltx_kn = 0;
kay->ltx_an = 0;
kay->lrx_kn = 0;
@@ -2467,8 +2514,8 @@
l2_packet_send(kay->l2_mka, NULL, 0, wpabuf_head(buf), wpabuf_len(buf));
wpabuf_free(buf);
- kay->active = TRUE;
- participant->active = TRUE;
+ kay->active = true;
+ participant->active = true;
return 0;
}
@@ -2494,7 +2541,7 @@
struct ieee802_1x_kay *kay;
struct ieee802_1x_kay_peer *peer, *pre_peer;
time_t now = time(NULL);
- Boolean lp_changed;
+ bool lp_changed;
struct receive_sc *rxsc, *pre_rxsc;
struct transmit_sa *txsa, *pre_txsa;
@@ -2518,7 +2565,7 @@
}
}
- lp_changed = FALSE;
+ lp_changed = false;
dl_list_for_each_safe(peer, pre_peer, &participant->live_peers,
struct ieee802_1x_kay_peer, list) {
if (now > peer->expire) {
@@ -2536,25 +2583,25 @@
}
dl_list_del(&peer->list);
os_free(peer);
- lp_changed = TRUE;
+ lp_changed = true;
}
}
if (lp_changed) {
if (dl_list_empty(&participant->live_peers)) {
- participant->advised_desired = FALSE;
+ participant->advised_desired = false;
participant->advised_capability =
MACSEC_CAP_NOT_IMPLEMENTED;
- participant->to_use_sak = FALSE;
- participant->ltx = FALSE;
- participant->lrx = FALSE;
- participant->otx = FALSE;
- participant->orx = FALSE;
- participant->is_key_server = FALSE;
- participant->is_elected = FALSE;
- kay->authenticated = FALSE;
- kay->secured = FALSE;
- kay->failed = FALSE;
+ participant->to_use_sak = false;
+ participant->ltx = false;
+ participant->lrx = false;
+ participant->otx = false;
+ participant->orx = false;
+ participant->is_key_server = false;
+ participant->is_elected = false;
+ kay->authenticated = false;
+ kay->secured = false;
+ kay->failed = false;
kay->ltx_kn = 0;
kay->ltx_an = 0;
kay->lrx_kn = 0;
@@ -2591,9 +2638,9 @@
if (participant->new_sak && participant->is_key_server) {
if (!ieee802_1x_kay_generate_new_sak(participant))
- participant->to_dist_sak = TRUE;
+ participant->to_dist_sak = true;
- participant->new_sak = FALSE;
+ participant->new_sak = false;
}
if (participant->retry_count < MAX_RETRY_CNT ||
@@ -2609,9 +2656,9 @@
return;
delete_mka:
- kay->authenticated = FALSE;
- kay->secured = FALSE;
- kay->failed = TRUE;
+ kay->authenticated = false;
+ kay->secured = false;
+ kay->failed = true;
ieee802_1x_kay_delete_mka(kay, &participant->ckn);
}
@@ -2625,8 +2672,8 @@
{
struct transmit_sa *psa;
- key->tx_latest = TRUE;
- key->rx_latest = TRUE;
+ key->tx_latest = true;
+ key->rx_latest = true;
psa = os_zalloc(sizeof(*psa));
if (!psa) {
@@ -2636,9 +2683,9 @@
if (key->confidentiality_offset >= CONFIDENTIALITY_OFFSET_0 &&
key->confidentiality_offset <= CONFIDENTIALITY_OFFSET_50)
- psa->confidentiality = TRUE;
+ psa->confidentiality = true;
else
- psa->confidentiality = FALSE;
+ psa->confidentiality = false;
psa->an = an;
ieee802_1x_kay_use_data_key(key);
@@ -2647,7 +2694,7 @@
psa->sc = psc;
os_get_time(&psa->created_time);
- psa->in_use = FALSE;
+ psa->in_use = false;
dl_list_add(&psc->sa_list, &psa->list);
wpa_printf(MSG_DEBUG,
@@ -2689,9 +2736,9 @@
os_memcpy(&psc->sci, sci, sizeof(psc->sci));
os_get_time(&psc->created_time);
- psc->transmitting = FALSE;
- psc->encoding_sa = FALSE;
- psc->enciphering_sa = FALSE;
+ psc->transmitting = false;
+ psc->encoding_sa = false;
+ psc->enciphering_sa = false;
dl_list_init(&psc->sa_list);
wpa_printf(MSG_DEBUG, "KaY: Create transmit SC - SCI: %s",
@@ -2725,7 +2772,7 @@
*/
int ieee802_1x_kay_set_latest_sa_attr(struct ieee802_1x_kay *kay,
struct ieee802_1x_mka_ki *lki, u8 lan,
- Boolean ltx, Boolean lrx)
+ bool ltx, bool lrx)
{
struct ieee802_1x_mka_participant *principal;
@@ -2760,7 +2807,7 @@
*/
int ieee802_1x_kay_set_old_sa_attr(struct ieee802_1x_kay *kay,
struct ieee802_1x_mka_ki *oki,
- u8 oan, Boolean otx, Boolean orx)
+ u8 oan, bool otx, bool orx)
{
struct ieee802_1x_mka_participant *principal;
@@ -2836,13 +2883,13 @@
latest_sak = NULL;
dl_list_for_each(sa_key, &principal->sak_list, struct data_key, list) {
if (is_ki_equal(&sa_key->key_identifier, lki)) {
- sa_key->rx_latest = TRUE;
- sa_key->tx_latest = TRUE;
+ sa_key->rx_latest = true;
+ sa_key->tx_latest = true;
latest_sak = sa_key;
- principal->to_use_sak = TRUE;
+ principal->to_use_sak = true;
} else {
- sa_key->rx_latest = FALSE;
- sa_key->tx_latest = FALSE;
+ sa_key->rx_latest = false;
+ sa_key->tx_latest = false;
}
}
if (!latest_sak) {
@@ -2946,10 +2993,10 @@
dl_list_for_each(txsa, &principal->txsc->sa_list, struct transmit_sa,
list) {
if (is_ki_equal(&txsa->pkey->key_identifier, lki)) {
- txsa->in_use = TRUE;
+ txsa->in_use = true;
secy_enable_transmit_sa(kay, txsa);
ieee802_1x_cp_set_usingtransmitas(
- principal->kay->cp, TRUE);
+ principal->kay->cp, true);
ieee802_1x_cp_sm_step(principal->kay->cp);
}
}
@@ -2976,10 +3023,10 @@
dl_list_for_each(rxsa, &rxsc->sa_list, struct receive_sa, list)
{
if (is_ki_equal(&rxsa->pkey->key_identifier, lki)) {
- rxsa->in_use = TRUE;
+ rxsa->in_use = true;
secy_enable_receive_sa(kay, rxsa);
ieee802_1x_cp_set_usingreceivesas(
- principal->kay->cp, TRUE);
+ principal->kay->cp, true);
ieee802_1x_cp_sm_step(principal->kay->cp);
}
}
@@ -3161,10 +3208,10 @@
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;
+ bool handled[256];
+ bool bad_sak_use = false; /* Error detected while processing SAK Use
+ * parameter set */
+ bool i_in_peerlist, is_in_live_peer, is_in_potential_peer;
wpa_printf(MSG_DEBUG, "KaY: Decode received MKPDU (ifname=%s)",
kay->if_name);
@@ -3221,9 +3268,9 @@
* Each parameter set should be present only once.
*/
for (i = 0; i < 256; i++)
- handled[i] = FALSE;
+ handled[i] = false;
- handled[0] = TRUE;
+ handled[0] = true;
for (; left_len > MKA_HDR_LEN + DEFAULT_ICV_LEN;
pos += body_len + MKA_HDR_LEN,
left_len -= body_len + MKA_HDR_LEN) {
@@ -3249,7 +3296,7 @@
continue;
}
- handled[body_type] = TRUE;
+ handled[body_type] = true;
if (body_type < ARRAY_SIZE(mka_body_handler) &&
mka_body_handler[body_type].body_rx) {
if (mka_body_handler[body_type].body_rx
@@ -3270,7 +3317,7 @@
* 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;
+ bad_sak_use = true;
}
} else {
wpa_printf(MSG_ERROR,
@@ -3339,9 +3386,9 @@
* from 'potential_peers' to 'live_peers'. */
}
- kay->active = TRUE;
+ kay->active = true;
participant->retry_count = 0;
- participant->active = TRUE;
+ participant->active = true;
return 0;
}
@@ -3408,7 +3455,7 @@
*/
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,
+ bool macsec_replay_protect, u32 macsec_replay_window,
u16 port, u8 priority, const char *ifname, const u8 *addr)
{
struct ieee802_1x_kay *kay;
@@ -3425,12 +3472,12 @@
kay->ctx = ctx;
- kay->enable = TRUE;
- kay->active = FALSE;
+ kay->enable = true;
+ kay->active = false;
- kay->authenticated = FALSE;
- kay->secured = FALSE;
- kay->failed = FALSE;
+ kay->authenticated = false;
+ kay->secured = false;
+ kay->failed = false;
kay->policy = policy;
os_strlcpy(kay->if_name, ifname, IFNAMSIZ);
@@ -3462,23 +3509,23 @@
if (policy == DO_NOT_SECURE ||
kay->macsec_capable == MACSEC_CAP_NOT_IMPLEMENTED) {
kay->macsec_capable = MACSEC_CAP_NOT_IMPLEMENTED;
- kay->macsec_desired = FALSE;
- kay->macsec_protect = FALSE;
- kay->macsec_encrypt = FALSE;
+ kay->macsec_desired = false;
+ kay->macsec_protect = false;
+ kay->macsec_encrypt = false;
kay->macsec_validate = Disabled;
- kay->macsec_replay_protect = FALSE;
+ 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_desired = true;
+ kay->macsec_protect = true;
if (kay->macsec_capable >= MACSEC_CAP_INTEG_AND_CONF &&
policy == SHOULD_ENCRYPT) {
- kay->macsec_encrypt = TRUE;
+ kay->macsec_encrypt = true;
kay->macsec_confidentiality = CONFIDENTIALITY_OFFSET_0;
} else { /* SHOULD_SECURE */
- kay->macsec_encrypt = FALSE;
+ kay->macsec_encrypt = false;
kay->macsec_confidentiality = CONFIDENTIALITY_NONE;
}
kay->macsec_validate = Strict;
@@ -3576,7 +3623,7 @@
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)
+ enum mka_created_mode mode, bool is_authenticator)
{
struct ieee802_1x_mka_participant *participant;
unsigned int usecs;
@@ -3624,40 +3671,40 @@
switch (mode) {
case EAP_EXCHANGE:
if (is_authenticator) {
- participant->is_obliged_key_server = TRUE;
- participant->can_be_key_server = TRUE;
- participant->is_key_server = TRUE;
- participant->principal = TRUE;
+ participant->is_obliged_key_server = true;
+ participant->can_be_key_server = true;
+ participant->is_key_server = true;
+ participant->principal = true;
os_memcpy(&kay->key_server_sci, &kay->actor_sci,
sizeof(kay->key_server_sci));
kay->key_server_priority = kay->actor_priority;
- participant->is_elected = TRUE;
+ participant->is_elected = true;
} else {
- participant->is_obliged_key_server = FALSE;
- participant->can_be_key_server = FALSE;
- participant->is_key_server = FALSE;
- participant->is_elected = TRUE;
+ participant->is_obliged_key_server = false;
+ participant->can_be_key_server = false;
+ participant->is_key_server = false;
+ participant->is_elected = true;
}
break;
default:
- participant->is_obliged_key_server = FALSE;
- participant->can_be_key_server = TRUE;
- participant->is_key_server = TRUE;
- participant->is_elected = FALSE;
+ participant->is_obliged_key_server = false;
+ participant->can_be_key_server = true;
+ participant->is_key_server = true;
+ participant->is_elected = false;
break;
}
- participant->cached = FALSE;
+ participant->cached = false;
- participant->active = FALSE;
- participant->participant = FALSE;
- participant->retain = FALSE;
+ participant->active = false;
+ participant->participant = false;
+ participant->retain = false;
participant->activate = DEFAULT;
if (participant->is_key_server)
- participant->principal = TRUE;
+ participant->principal = true;
dl_list_init(&participant->live_peers);
dl_list_init(&participant->potential_peers);
@@ -3670,13 +3717,13 @@
wpa_printf(MSG_DEBUG, "KaY: Selected random MI: %s",
mi_txt(participant->mi));
- participant->lrx = FALSE;
- participant->ltx = FALSE;
- participant->orx = FALSE;
- participant->otx = FALSE;
- participant->to_dist_sak = FALSE;
- participant->to_use_sak = FALSE;
- participant->new_sak = FALSE;
+ participant->lrx = false;
+ participant->ltx = false;
+ participant->orx = false;
+ participant->otx = false;
+ participant->to_dist_sak = false;
+ participant->to_use_sak = false;
+ participant->new_sak = false;
dl_list_init(&participant->sak_list);
participant->new_key = NULL;
dl_list_init(&participant->rxsc_list);
@@ -3809,8 +3856,7 @@
* ieee802_1x_kay_mka_participate -
*/
void ieee802_1x_kay_mka_participate(struct ieee802_1x_kay *kay,
- struct mka_key_name *ckn,
- Boolean status)
+ struct mka_key_name *ckn, bool status)
{
struct ieee802_1x_mka_participant *participant;
@@ -3840,7 +3886,7 @@
if (!participant)
return -1;
- participant->new_sak = TRUE;
+ participant->new_sak = true;
wpa_printf(MSG_DEBUG, "KaY: new SAK signal");
return 0;
@@ -3869,7 +3915,7 @@
return -2;
if (cs_index == 0)
- kay->macsec_desired = FALSE;
+ kay->macsec_desired = false;
kay->macsec_csindex = cs_index;
kay->macsec_capable = cipher_suite_tbl[kay->macsec_csindex].capable;
@@ -3883,7 +3929,7 @@
participant = ieee802_1x_kay_get_principal_participant(kay);
if (participant) {
wpa_printf(MSG_INFO, "KaY: Cipher Suite changed");
- participant->new_sak = TRUE;
+ participant->new_sak = true;
}
return 0;
@@ -3997,7 +4043,7 @@
}
-static const char * true_false(Boolean val)
+static const char * true_false(bool val)
{
return val ? "true" : "false";
}
@@ -4020,7 +4066,7 @@
}
-static char * mka_mib_peer(struct dl_list *peers, Boolean live, char *buf,
+static char * mka_mib_peer(struct dl_list *peers, bool live, char *buf,
char *end)
{
char *pos = buf;
@@ -4087,8 +4133,8 @@
pos2 += res;
pos = pos2;
- pos = mka_mib_peer(&p->live_peers, TRUE, pos, end);
- pos = mka_mib_peer(&p->potential_peers, FALSE, pos, end);
+ pos = mka_mib_peer(&p->live_peers, true, pos, end);
+ pos = mka_mib_peer(&p->potential_peers, false, pos, end);
}
return pos - buf;
diff --git a/src/pae/ieee802_1x_kay.h b/src/pae/ieee802_1x_kay.h
index 3367d3a..1d3c2ac 100644
--- a/src/pae/ieee802_1x_kay.h
+++ b/src/pae/ieee802_1x_kay.h
@@ -62,14 +62,14 @@
struct ieee802_1x_mka_ki key_identifier;
enum confidentiality_offset confidentiality_offset;
u8 an;
- Boolean transmits;
- Boolean receives;
+ bool transmits;
+ bool receives;
struct os_time created_time;
u32 next_pn;
/* not defined data */
- Boolean rx_latest;
- Boolean tx_latest;
+ bool rx_latest;
+ bool tx_latest;
int user;
@@ -79,7 +79,7 @@
/* TransmitSC in IEEE Std 802.1AE-2006, Figure 10-6 */
struct transmit_sc {
struct ieee802_1x_mka_sci sci; /* const SCI sci */
- Boolean transmitting; /* bool transmitting (read only) */
+ bool transmitting; /* bool transmitting (read only) */
struct os_time created_time; /* Time createdTime */
@@ -93,14 +93,14 @@
/* TransmitSA in IEEE Std 802.1AE-2006, Figure 10-6 */
struct transmit_sa {
- Boolean in_use; /* bool inUse (read only) */
+ bool in_use; /* bool inUse (read only) */
u32 next_pn; /* PN nextPN (read only) */
struct os_time created_time; /* Time createdTime */
- Boolean enable_transmit; /* bool EnableTransmit */
+ bool enable_transmit; /* bool EnableTransmit */
u8 an;
- Boolean confidentiality;
+ bool confidentiality;
struct data_key *pkey;
struct transmit_sc *sc;
@@ -110,7 +110,7 @@
/* ReceiveSC in IEEE Std 802.1AE-2006, Figure 10-6 */
struct receive_sc {
struct ieee802_1x_mka_sci sci; /* const SCI sci */
- Boolean receiving; /* bool receiving (read only) */
+ bool receiving; /* bool receiving (read only) */
struct os_time created_time; /* Time createdTime */
@@ -120,8 +120,8 @@
/* ReceiveSA in IEEE Std 802.1AE-2006, Figure 10-6 */
struct receive_sa {
- Boolean enable_receive; /* bool enableReceive */
- Boolean in_use; /* bool inUse (read only) */
+ bool enable_receive; /* bool enableReceive */
+ bool in_use; /* bool inUse (read only) */
u32 next_pn; /* PN nextPN (read only) */
u32 lowest_pn; /* PN lowestPN (read only) */
@@ -142,11 +142,11 @@
int (*macsec_init)(void *ctx, struct macsec_init_params *params);
int (*macsec_deinit)(void *ctx);
int (*macsec_get_capability)(void *priv, enum macsec_cap *cap);
- int (*enable_protect_frames)(void *ctx, Boolean enabled);
- int (*enable_encrypt)(void *ctx, Boolean enabled);
- int (*set_replay_protect)(void *ctx, Boolean enabled, u32 window);
+ int (*enable_protect_frames)(void *ctx, bool enabled);
+ int (*enable_encrypt)(void *ctx, bool enabled);
+ int (*set_replay_protect)(void *ctx, bool enabled, u32 window);
int (*set_current_cipher_suite)(void *ctx, u64 cs);
- int (*enable_controlled_port)(void *ctx, Boolean enabled);
+ int (*enable_controlled_port)(void *ctx, bool enabled);
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);
@@ -169,12 +169,12 @@
};
struct ieee802_1x_kay {
- Boolean enable;
- Boolean active;
+ bool enable;
+ bool active;
- Boolean authenticated;
- Boolean secured;
- Boolean failed;
+ bool authenticated;
+ bool secured;
+ bool failed;
struct ieee802_1x_mka_sci actor_sci;
u8 actor_priority;
@@ -182,10 +182,10 @@
u8 key_server_priority;
enum macsec_cap macsec_capable;
- Boolean macsec_desired;
- Boolean macsec_protect;
- Boolean macsec_encrypt;
- Boolean macsec_replay_protect;
+ bool macsec_desired;
+ bool macsec_protect;
+ bool macsec_encrypt;
+ bool macsec_replay_protect;
u32 macsec_replay_window;
enum validate_frames macsec_validate;
enum confidentiality_offset macsec_confidentiality;
@@ -203,8 +203,8 @@
/* not defined in IEEE802.1X */
struct ieee802_1x_kay_ctx *ctx;
- Boolean is_key_server;
- Boolean is_obliged_key_server;
+ bool is_key_server;
+ bool is_obliged_key_server;
char if_name[IFNAMSIZ];
unsigned int macsec_csindex; /* MACsec cipher suite table index */
@@ -219,9 +219,9 @@
u8 algo_agility[4];
u32 pn_exhaustion;
- Boolean port_enable;
- Boolean rx_enable;
- Boolean tx_enable;
+ bool port_enable;
+ bool rx_enable;
+ bool tx_enable;
struct dl_list participant_list;
enum macsec_policy policy;
@@ -239,7 +239,7 @@
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,
+ bool 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);
@@ -248,22 +248,22 @@
const struct mka_key_name *ckn,
const struct mka_key *cak,
u32 life, enum mka_created_mode mode,
- Boolean is_authenticator);
+ bool is_authenticator);
void ieee802_1x_kay_delete_mka(struct ieee802_1x_kay *kay,
struct mka_key_name *ckn);
void ieee802_1x_kay_mka_participate(struct ieee802_1x_kay *kay,
struct mka_key_name *ckn,
- Boolean status);
+ bool status);
int ieee802_1x_kay_new_sak(struct ieee802_1x_kay *kay);
int ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay,
unsigned int cs_index);
int ieee802_1x_kay_set_latest_sa_attr(struct ieee802_1x_kay *kay,
struct ieee802_1x_mka_ki *lki, u8 lan,
- Boolean ltx, Boolean lrx);
+ bool ltx, bool lrx);
int ieee802_1x_kay_set_old_sa_attr(struct ieee802_1x_kay *kay,
struct ieee802_1x_mka_ki *oki,
- u8 oan, Boolean otx, Boolean orx);
+ u8 oan, bool otx, bool orx);
int ieee802_1x_kay_create_sas(struct ieee802_1x_kay *kay,
struct ieee802_1x_mka_ki *lki);
int ieee802_1x_kay_delete_sas(struct ieee802_1x_kay *kay,
diff --git a/src/pae/ieee802_1x_kay_i.h b/src/pae/ieee802_1x_kay_i.h
index f9cd3f4..7a04169 100644
--- a/src/pae/ieee802_1x_kay_i.h
+++ b/src/pae/ieee802_1x_kay_i.h
@@ -46,11 +46,11 @@
u8 mi[MI_LEN];
u32 mn;
time_t expire;
- Boolean is_key_server;
+ bool is_key_server;
u8 key_server_priority;
- Boolean macsec_desired;
+ bool macsec_desired;
enum macsec_cap macsec_capability;
- Boolean sak_used;
+ bool sak_used;
int missing_sak_use_count;
struct dl_list list;
};
@@ -87,18 +87,18 @@
/* used for active and potential participant */
struct mka_key_name ckn;
struct mka_key cak;
- Boolean cached;
+ bool cached;
/* used by management to monitor and control activation */
- Boolean active;
- Boolean participant;
- Boolean retain;
+ bool active;
+ bool participant;
+ bool retain;
enum mka_created_mode mode;
enum activate_ctrl { DEFAULT, DISABLED, ON_OPER_UP, ALWAYS } activate;
/* used for active participant */
- Boolean principal;
+ bool principal;
struct dl_list live_peers;
struct dl_list potential_peers;
@@ -110,18 +110,18 @@
struct ieee802_1x_mka_ki lki;
u8 lan;
- Boolean ltx;
- Boolean lrx;
+ bool ltx;
+ bool lrx;
struct ieee802_1x_mka_ki oki;
u8 oan;
- Boolean otx;
- Boolean orx;
+ bool otx;
+ bool orx;
- Boolean is_key_server;
- Boolean is_obliged_key_server;
- Boolean can_be_key_server;
- Boolean is_elected;
+ bool is_key_server;
+ bool is_obliged_key_server;
+ bool can_be_key_server;
+ bool is_elected;
struct dl_list sak_list;
struct dl_list rxsc_list;
@@ -137,11 +137,11 @@
time_t cak_life;
time_t mka_life;
- Boolean to_dist_sak;
- Boolean to_use_sak;
- Boolean new_sak;
+ bool to_dist_sak;
+ bool to_use_sak;
+ bool new_sak;
- Boolean advised_desired;
+ bool advised_desired;
enum macsec_cap advised_capability;
struct data_key *new_key;
diff --git a/src/pae/ieee802_1x_secy_ops.c b/src/pae/ieee802_1x_secy_ops.c
index 84ee42b..0f36e6b 100644
--- a/src/pae/ieee802_1x_secy_ops.c
+++ b/src/pae/ieee802_1x_secy_ops.c
@@ -25,7 +25,7 @@
}
-int secy_cp_control_protect_frames(struct ieee802_1x_kay *kay, Boolean enabled)
+int secy_cp_control_protect_frames(struct ieee802_1x_kay *kay, bool enabled)
{
struct ieee802_1x_kay_ctx *ops;
@@ -45,7 +45,7 @@
}
-int secy_cp_control_encrypt(struct ieee802_1x_kay *kay, Boolean enabled)
+int secy_cp_control_encrypt(struct ieee802_1x_kay *kay, bool enabled)
{
struct ieee802_1x_kay_ctx *ops;
@@ -65,7 +65,7 @@
}
-int secy_cp_control_replay(struct ieee802_1x_kay *kay, Boolean enabled, u32 win)
+int secy_cp_control_replay(struct ieee802_1x_kay *kay, bool enabled, u32 win)
{
struct ieee802_1x_kay_ctx *ops;
@@ -113,7 +113,7 @@
}
-int secy_cp_control_enable_port(struct ieee802_1x_kay *kay, Boolean enabled)
+int secy_cp_control_enable_port(struct ieee802_1x_kay *kay, bool enabled)
{
struct ieee802_1x_kay_ctx *ops;
@@ -333,7 +333,7 @@
return -1;
}
- rxsa->enable_receive = TRUE;
+ rxsa->enable_receive = true;
return ops->enable_receive_sa(ops->ctx, rxsa);
}
@@ -355,7 +355,7 @@
return -1;
}
- rxsa->enable_receive = FALSE;
+ rxsa->enable_receive = false;
return ops->disable_receive_sa(ops->ctx, rxsa);
}
@@ -462,7 +462,7 @@
return -1;
}
- txsa->enable_transmit = TRUE;
+ txsa->enable_transmit = true;
return ops->enable_transmit_sa(ops->ctx, txsa);
}
@@ -485,7 +485,7 @@
return -1;
}
- txsa->enable_transmit = FALSE;
+ txsa->enable_transmit = false;
return ops->disable_transmit_sa(ops->ctx, txsa);
}
@@ -509,9 +509,9 @@
return -1;
}
- params.use_es = FALSE;
- params.use_scb = FALSE;
- params.always_include_sci = TRUE;
+ params.use_es = false;
+ params.use_scb = false;
+ params.always_include_sci = true;
ret = ops->macsec_init(ops->ctx, ¶ms);
diff --git a/src/pae/ieee802_1x_secy_ops.h b/src/pae/ieee802_1x_secy_ops.h
index 2d112ba..18c06f6 100644
--- a/src/pae/ieee802_1x_secy_ops.h
+++ b/src/pae/ieee802_1x_secy_ops.h
@@ -20,13 +20,13 @@
/****** CP -> SecY ******/
int secy_cp_control_validate_frames(struct ieee802_1x_kay *kay,
enum validate_frames vf);
-int secy_cp_control_protect_frames(struct ieee802_1x_kay *kay, Boolean flag);
-int secy_cp_control_encrypt(struct ieee802_1x_kay *kay, Boolean enabled);
-int secy_cp_control_replay(struct ieee802_1x_kay *kay, Boolean flag, u32 win);
+int secy_cp_control_protect_frames(struct ieee802_1x_kay *kay, bool flag);
+int secy_cp_control_encrypt(struct ieee802_1x_kay *kay, bool enabled);
+int secy_cp_control_replay(struct ieee802_1x_kay *kay, bool flag, u32 win);
int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay, u64 cs);
int secy_cp_control_confidentiality_offset(struct ieee802_1x_kay *kay,
enum confidentiality_offset co);
-int secy_cp_control_enable_port(struct ieee802_1x_kay *kay, Boolean flag);
+int secy_cp_control_enable_port(struct ieee802_1x_kay *kay, bool flag);
/****** KaY -> SecY *******/
int secy_get_capability(struct ieee802_1x_kay *kay, enum macsec_cap *cap);
diff --git a/src/radius/radius.c b/src/radius/radius.c
index 07240ea..be16e27 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -609,7 +609,7 @@
{
if (msg->attr_used >= msg->attr_size) {
size_t *nattr_pos;
- int nlen = msg->attr_size * 2;
+ size_t nlen = msg->attr_size * 2;
nattr_pos = os_realloc_array(msg->attr_pos, nlen,
sizeof(*msg->attr_pos));
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index a3db404..2b7a604 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -457,7 +457,7 @@
}
/* retransmit; remove entry if too many attempts */
- if (entry->accu_attempts > RADIUS_CLIENT_MAX_FAILOVER *
+ 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");
@@ -507,7 +507,7 @@
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 ||
+ if (entry->attempts >= RADIUS_CLIENT_NUM_FAILOVER ||
(s < 0 && entry->attempts > 0)) {
if (entry->msg_type == RADIUS_ACCT ||
entry->msg_type == RADIUS_ACCT_INTERIM)
@@ -1116,7 +1116,7 @@
(!auth && entry->msg_type != RADIUS_ACCT))
continue;
entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
- entry->attempts = 1;
+ entry->attempts = 0;
entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
}
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index b621ada..971fe91 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -161,140 +161,10 @@
*/
int num_sess;
- /**
- * eap_sim_db_priv - EAP-SIM/AKA database context
- *
- * This is passed to the EAP-SIM/AKA server implementation as a
- * callback context.
- */
- void *eap_sim_db_priv;
-
- /**
- * ssl_ctx - TLS context
- *
- * This is passed to the EAP server implementation as a callback
- * context for TLS operations.
- */
- void *ssl_ctx;
-
- /**
- * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST
- *
- * This parameter is used to set a key for EAP-FAST to encrypt the
- * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If
- * set, must point to a 16-octet key.
- */
- u8 *pac_opaque_encr_key;
-
- /**
- * eap_fast_a_id - EAP-FAST authority identity (A-ID)
- *
- * If EAP-FAST is not used, this can be set to %NULL. In theory, this
- * is a variable length field, but due to some existing implementations
- * requiring A-ID to be 16 octets in length, it is recommended to use
- * that length for the field to provide interoperability with deployed
- * peer implementations.
- */
- u8 *eap_fast_a_id;
-
- /**
- * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets
- */
- size_t eap_fast_a_id_len;
-
- /**
- * eap_fast_a_id_info - EAP-FAST authority identifier information
- *
- * This A-ID-Info contains a user-friendly name for the A-ID. For
- * example, this could be the enterprise and server names in
- * human-readable format. This field is encoded as UTF-8. If EAP-FAST
- * is not used, this can be set to %NULL.
- */
- char *eap_fast_a_id_info;
-
- /**
- * eap_fast_prov - EAP-FAST provisioning modes
- *
- * 0 = provisioning disabled, 1 = only anonymous provisioning allowed,
- * 2 = only authenticated provisioning allowed, 3 = both provisioning
- * modes allowed.
- */
- int eap_fast_prov;
-
- /**
- * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds
- *
- * This is the hard limit on how long a provisioned PAC-Key can be
- * used.
- */
- int pac_key_lifetime;
-
- /**
- * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds
- *
- * This is a soft limit on the PAC-Key. The server will automatically
- * generate a new PAC-Key when this number of seconds (or fewer) of the
- * lifetime remains.
- */
- int pac_key_refresh_time;
-
- /**
- * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication
- *
- * This controls whether the protected success/failure indication
- * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA.
- */
- int eap_sim_aka_result_ind;
-
- /**
- * tnc - Trusted Network Connect (TNC)
- *
- * This controls whether TNC is enabled and will be required before the
- * peer is allowed to connect. Note: This is only used with EAP-TTLS
- * and EAP-FAST. If any other EAP method is enabled, the peer will be
- * allowed to connect without TNC.
- */
- int tnc;
-
- /**
- * pwd_group - The D-H group assigned for EAP-pwd
- *
- * If EAP-pwd is not used it can be set to zero.
- */
- u16 pwd_group;
-
- /**
- * server_id - Server identity
- */
- const char *server_id;
-
- /**
- * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
- *
- * This controls whether the authentication server derives ERP key
- * hierarchy (rRK and rIK) from full EAP authentication and allows
- * these keys to be used to perform ERP to derive rMSK instead of full
- * EAP authentication to derive MSK.
- */
- int erp;
-
const char *erp_domain;
struct dl_list erp_keys; /* struct eap_server_erp_key */
- unsigned int tls_session_lifetime;
-
- unsigned int tls_flags;
-
- /**
- * wps - Wi-Fi Protected Setup context
- *
- * If WPS is used with an external RADIUS server (which is quite
- * unlikely configuration), this is used to provide a pointer to WPS
- * context data. Normally, this can be set to %NULL.
- */
- struct wps_context *wps;
-
/**
* ipv6 - Whether to enable IPv6 support in the RADIUS server
*/
@@ -346,11 +216,6 @@
*/
size_t eap_req_id_text_len;
- /*
- * msg_ctx - Context data for wpa_msg() calls
- */
- void *msg_ctx;
-
#ifdef CONFIG_RADIUS_TEST
char *dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
@@ -364,6 +229,8 @@
#ifdef CONFIG_SQLITE
sqlite3 *db;
#endif /* CONFIG_SQLITE */
+
+ const struct eap_config *eap_cfg;
};
@@ -614,7 +481,7 @@
#ifdef CONFIG_TESTING_OPTIONS
static void radius_server_testing_options_tls(struct radius_session *sess,
const char *tls,
- struct eap_config *eap_conf)
+ struct eap_session_data *eap_conf)
{
int test = atoi(tls);
@@ -659,7 +526,7 @@
#endif /* CONFIG_TESTING_OPTIONS */
static void radius_server_testing_options(struct radius_session *sess,
- struct eap_config *eap_conf)
+ struct eap_session_data *eap_conf)
{
#ifdef CONFIG_TESTING_OPTIONS
const char *pos;
@@ -702,7 +569,7 @@
size_t user_len, id_len;
int res;
struct radius_session *sess;
- struct eap_config eap_conf;
+ struct eap_session_data eap_sess;
struct eap_user *tmp;
RADIUS_DEBUG("Creating a new session");
@@ -720,7 +587,7 @@
res = data->get_eap_user(data->conf_ctx, user, user_len, 0, tmp);
#ifdef CONFIG_ERP
- if (res != 0 && data->erp) {
+ if (res != 0 && data->eap_cfg->erp) {
char *username;
username = os_zalloc(user_len + 1);
@@ -779,31 +646,10 @@
srv_log(sess, "New session created");
- os_memset(&eap_conf, 0, sizeof(eap_conf));
- eap_conf.ssl_ctx = data->ssl_ctx;
- eap_conf.msg_ctx = data->msg_ctx;
- eap_conf.eap_sim_db_priv = data->eap_sim_db_priv;
- eap_conf.backend_auth = TRUE;
- eap_conf.eap_server = 1;
- eap_conf.pac_opaque_encr_key = data->pac_opaque_encr_key;
- eap_conf.eap_fast_a_id = data->eap_fast_a_id;
- eap_conf.eap_fast_a_id_len = data->eap_fast_a_id_len;
- eap_conf.eap_fast_a_id_info = data->eap_fast_a_id_info;
- eap_conf.eap_fast_prov = data->eap_fast_prov;
- eap_conf.pac_key_lifetime = data->pac_key_lifetime;
- eap_conf.pac_key_refresh_time = data->pac_key_refresh_time;
- eap_conf.eap_sim_aka_result_ind = data->eap_sim_aka_result_ind;
- eap_conf.tnc = data->tnc;
- eap_conf.wps = data->wps;
- eap_conf.pwd_group = data->pwd_group;
- eap_conf.server_id = (const u8 *) data->server_id;
- eap_conf.server_id_len = os_strlen(data->server_id);
- eap_conf.erp = data->erp;
- eap_conf.tls_session_lifetime = data->tls_session_lifetime;
- eap_conf.tls_flags = data->tls_flags;
- radius_server_testing_options(sess, &eap_conf);
+ os_memset(&eap_sess, 0, sizeof(eap_sess));
+ radius_server_testing_options(sess, &eap_sess);
sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
- &eap_conf);
+ data->eap_cfg, &eap_sess);
if (sess->eap == NULL) {
RADIUS_DEBUG("Failed to initialize EAP state machine for the "
"new session");
@@ -811,8 +657,8 @@
return NULL;
}
sess->eap_if = eap_get_interface(sess->eap);
- sess->eap_if->eapRestart = TRUE;
- sess->eap_if->portEnabled = TRUE;
+ sess->eap_if->eapRestart = true;
+ sess->eap_if->portEnabled = true;
RADIUS_DEBUG("New session 0x%x initialized", sess->sess_id);
@@ -1063,13 +909,13 @@
u16 reason = WLAN_REASON_IEEE_802_1X_AUTH_FAILED;
if (sess->eap_if->eapFail) {
- sess->eap_if->eapFail = FALSE;
+ sess->eap_if->eapFail = false;
code = RADIUS_CODE_ACCESS_REJECT;
} else if (sess->eap_if->eapSuccess) {
- sess->eap_if->eapSuccess = FALSE;
+ sess->eap_if->eapSuccess = false;
code = RADIUS_CODE_ACCESS_ACCEPT;
} else {
- sess->eap_if->eapReq = FALSE;
+ sess->eap_if->eapReq = false;
code = RADIUS_CODE_ACCESS_CHALLENGE;
}
@@ -1136,6 +982,13 @@
len)) {
RADIUS_DEBUG("Failed to add MPPE key attributes");
}
+
+ if (sess->eap_if->eapSessionId &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_EAP_KEY_NAME,
+ sess->eap_if->eapSessionId,
+ sess->eap_if->eapSessionIdLen)) {
+ RADIUS_DEBUG("Failed to add EAP-Key-Name attribute");
+ }
}
#ifdef CONFIG_HS20
@@ -1590,7 +1443,7 @@
wpabuf_free(sess->eap_if->eapRespData);
sess->eap_if->eapRespData = eap;
- sess->eap_if->eapResp = TRUE;
+ sess->eap_if->eapResp = true;
eap_server_sm_step(sess->eap);
if ((sess->eap_if->eapReq || sess->eap_if->eapSuccess ||
@@ -2348,71 +2201,52 @@
if (data == NULL)
return NULL;
+ data->eap_cfg = conf->eap_cfg;
+ data->auth_sock = -1;
+ data->acct_sock = -1;
dl_list_init(&data->erp_keys);
os_get_reltime(&data->start_time);
data->conf_ctx = conf->conf_ctx;
- data->eap_sim_db_priv = conf->eap_sim_db_priv;
- data->ssl_ctx = conf->ssl_ctx;
- data->msg_ctx = conf->msg_ctx;
+ conf->eap_cfg->backend_auth = true;
+ conf->eap_cfg->eap_server = 1;
data->ipv6 = conf->ipv6;
- if (conf->pac_opaque_encr_key) {
- data->pac_opaque_encr_key = os_malloc(16);
- if (data->pac_opaque_encr_key) {
- os_memcpy(data->pac_opaque_encr_key,
- conf->pac_opaque_encr_key, 16);
- }
- }
- if (conf->eap_fast_a_id) {
- data->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
- if (data->eap_fast_a_id) {
- os_memcpy(data->eap_fast_a_id, conf->eap_fast_a_id,
- conf->eap_fast_a_id_len);
- data->eap_fast_a_id_len = conf->eap_fast_a_id_len;
- }
- }
- if (conf->eap_fast_a_id_info)
- data->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info);
- data->eap_fast_prov = conf->eap_fast_prov;
- data->pac_key_lifetime = conf->pac_key_lifetime;
- data->pac_key_refresh_time = conf->pac_key_refresh_time;
data->get_eap_user = conf->get_eap_user;
- data->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
- data->tnc = conf->tnc;
- data->wps = conf->wps;
- data->pwd_group = conf->pwd_group;
- data->server_id = conf->server_id;
if (conf->eap_req_id_text) {
data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len);
- if (data->eap_req_id_text) {
- os_memcpy(data->eap_req_id_text, conf->eap_req_id_text,
- conf->eap_req_id_text_len);
- data->eap_req_id_text_len = conf->eap_req_id_text_len;
- }
+ if (!data->eap_req_id_text)
+ goto fail;
+ os_memcpy(data->eap_req_id_text, conf->eap_req_id_text,
+ conf->eap_req_id_text_len);
+ data->eap_req_id_text_len = conf->eap_req_id_text_len;
}
- data->erp = conf->erp;
data->erp_domain = conf->erp_domain;
- data->tls_session_lifetime = conf->tls_session_lifetime;
- data->tls_flags = conf->tls_flags;
if (conf->subscr_remediation_url) {
data->subscr_remediation_url =
os_strdup(conf->subscr_remediation_url);
+ if (!data->subscr_remediation_url)
+ goto fail;
}
data->subscr_remediation_method = conf->subscr_remediation_method;
- if (conf->hs20_sim_provisioning_url)
+ if (conf->hs20_sim_provisioning_url) {
data->hs20_sim_provisioning_url =
os_strdup(conf->hs20_sim_provisioning_url);
+ if (!data->hs20_sim_provisioning_url)
+ goto fail;
+ }
- if (conf->t_c_server_url)
+ if (conf->t_c_server_url) {
data->t_c_server_url = os_strdup(conf->t_c_server_url);
+ if (!data->t_c_server_url)
+ goto fail;
+ }
#ifdef CONFIG_SQLITE
if (conf->sqlite_file) {
if (sqlite3_open(conf->sqlite_file, &data->db)) {
RADIUS_ERROR("Could not open SQLite file '%s'",
conf->sqlite_file);
- radius_server_deinit(data);
- return NULL;
+ goto fail;
}
}
#endif /* CONFIG_SQLITE */
@@ -2426,8 +2260,7 @@
conf->ipv6);
if (data->clients == NULL) {
wpa_printf(MSG_ERROR, "No RADIUS clients configured");
- radius_server_deinit(data);
- return NULL;
+ goto fail;
}
#ifdef CONFIG_IPV6
@@ -2438,14 +2271,12 @@
data->auth_sock = radius_server_open_socket(conf->auth_port);
if (data->auth_sock < 0) {
wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS authentication server");
- radius_server_deinit(data);
- return NULL;
+ goto fail;
}
if (eloop_register_read_sock(data->auth_sock,
radius_server_receive_auth,
data, NULL)) {
- radius_server_deinit(data);
- return NULL;
+ goto fail;
}
if (conf->acct_port) {
@@ -2458,20 +2289,20 @@
data->acct_sock = radius_server_open_socket(conf->acct_port);
if (data->acct_sock < 0) {
wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS accounting server");
- radius_server_deinit(data);
- return NULL;
+ goto fail;
}
if (eloop_register_read_sock(data->acct_sock,
radius_server_receive_acct,
- data, NULL)) {
- radius_server_deinit(data);
- return NULL;
- }
+ data, NULL))
+ goto fail;
} else {
data->acct_sock = -1;
}
return data;
+fail:
+ radius_server_deinit(data);
+ return NULL;
}
@@ -2514,9 +2345,6 @@
radius_server_free_clients(data, data->clients);
- os_free(data->pac_opaque_encr_key);
- os_free(data->eap_fast_a_id);
- os_free(data->eap_fast_a_id_info);
os_free(data->eap_req_id_text);
#ifdef CONFIG_RADIUS_TEST
os_free(data->dump_msk_file);
diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h
index 53728f9..43192e5 100644
--- a/src/radius/radius_server.h
+++ b/src/radius/radius_server.h
@@ -51,138 +51,8 @@
*/
void *conf_ctx;
- /**
- * eap_sim_db_priv - EAP-SIM/AKA database context
- *
- * This is passed to the EAP-SIM/AKA server implementation as a
- * callback context.
- */
- void *eap_sim_db_priv;
-
- /**
- * ssl_ctx - TLS context
- *
- * This is passed to the EAP server implementation as a callback
- * context for TLS operations.
- */
- void *ssl_ctx;
-
- /**
- * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST
- *
- * This parameter is used to set a key for EAP-FAST to encrypt the
- * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If
- * set, must point to a 16-octet key.
- */
- u8 *pac_opaque_encr_key;
-
- /**
- * eap_fast_a_id - EAP-FAST authority identity (A-ID)
- *
- * If EAP-FAST is not used, this can be set to %NULL. In theory, this
- * is a variable length field, but due to some existing implementations
- * requiring A-ID to be 16 octets in length, it is recommended to use
- * that length for the field to provide interoperability with deployed
- * peer implementations.
- */
- u8 *eap_fast_a_id;
-
- /**
- * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets
- */
- size_t eap_fast_a_id_len;
-
- /**
- * eap_fast_a_id_info - EAP-FAST authority identifier information
- *
- * This A-ID-Info contains a user-friendly name for the A-ID. For
- * example, this could be the enterprise and server names in
- * human-readable format. This field is encoded as UTF-8. If EAP-FAST
- * is not used, this can be set to %NULL.
- */
- char *eap_fast_a_id_info;
-
- /**
- * eap_fast_prov - EAP-FAST provisioning modes
- *
- * 0 = provisioning disabled, 1 = only anonymous provisioning allowed,
- * 2 = only authenticated provisioning allowed, 3 = both provisioning
- * modes allowed.
- */
- int eap_fast_prov;
-
- /**
- * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds
- *
- * This is the hard limit on how long a provisioned PAC-Key can be
- * used.
- */
- int pac_key_lifetime;
-
- /**
- * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds
- *
- * This is a soft limit on the PAC-Key. The server will automatically
- * generate a new PAC-Key when this number of seconds (or fewer) of the
- * lifetime remains.
- */
- int pac_key_refresh_time;
-
- /**
- * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication
- *
- * This controls whether the protected success/failure indication
- * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA.
- */
- int eap_sim_aka_result_ind;
-
- /**
- * tnc - Trusted Network Connect (TNC)
- *
- * This controls whether TNC is enabled and will be required before the
- * peer is allowed to connect. Note: This is only used with EAP-TTLS
- * and EAP-FAST. If any other EAP method is enabled, the peer will be
- * allowed to connect without TNC.
- */
- int tnc;
-
- /**
- * pwd_group - EAP-pwd D-H group
- *
- * This is used to select which D-H group to use with EAP-pwd.
- */
- u16 pwd_group;
-
- /**
- * server_id - Server identity
- */
- const char *server_id;
-
- /**
- * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
- *
- * This controls whether the authentication server derives ERP key
- * hierarchy (rRK and rIK) from full EAP authentication and allows
- * these keys to be used to perform ERP to derive rMSK instead of full
- * EAP authentication to derive MSK.
- */
- int erp;
-
const char *erp_domain;
- unsigned int tls_session_lifetime;
-
- unsigned int tls_flags;
-
- /**
- * wps - Wi-Fi Protected Setup context
- *
- * If WPS is used with an external RADIUS server (which is quite
- * unlikely configuration), this is used to provide a pointer to WPS
- * context data. Normally, this can be set to %NULL.
- */
- struct wps_context *wps;
-
/**
* ipv6 - Whether to enable IPv6 support in the RADIUS server
*/
@@ -222,11 +92,6 @@
*/
size_t eap_req_id_text_len;
- /*
- * msg_ctx - Context data for wpa_msg() calls
- */
- void *msg_ctx;
-
#ifdef CONFIG_RADIUS_TEST
const char *dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
@@ -236,6 +101,8 @@
char *hs20_sim_provisioning_url;
char *t_c_server_url;
+
+ struct eap_config *eap_cfg;
};
diff --git a/src/rsn_supp/Makefile b/src/rsn_supp/Makefile
index c2d81f2..eea0efb 100644
--- a/src/rsn_supp/Makefile
+++ b/src/rsn_supp/Makefile
@@ -8,7 +8,6 @@
include ../lib.rules
-CFLAGS += -DCONFIG_IEEE80211W
CFLAGS += -DCONFIG_IEEE80211R
CFLAGS += -DCONFIG_TDLS
CFLAGS += -DCONFIG_WNM
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index d720f7b..e46c89a 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -14,6 +14,8 @@
#include "wpa.h"
#include "wpa_i.h"
#include "pmksa_cache.h"
+#include "wpa_supplicant_i.h"
+#include "notify.h"
#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA)
@@ -265,9 +267,12 @@
wpa_printf(MSG_DEBUG, "RSN: Added PMKSA cache entry for " MACSTR
" network_ctx=%p akmp=0x%x", MAC2STR(entry->aa),
entry->network_ctx, entry->akmp);
+ wpas_notify_pmk_cache_added((struct wpa_supplicant *)pmksa->sm->ctx->ctx, entry);
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);
+ entry->pmk, entry->pmk_len,
+ pmksa->sm->dot11RSNAConfigPMKLifetime,
+ pmksa->sm->dot11RSNAConfigPMKReauthThreshold);
return entry;
}
@@ -277,7 +282,7 @@
* pmksa_cache_flush - Flush PMKSA cache entries for a specific network
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @network_ctx: Network configuration context or %NULL to flush all entries
- * @pmk: PMK to match for or %NYLL to match all PMKs
+ * @pmk: PMK to match for or %NULL to match all PMKs
* @pmk_len: PMK length
*/
void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
@@ -371,9 +376,12 @@
{
struct rsn_pmksa_cache_entry *new_entry;
os_time_t old_expiration = old_entry->expiration;
+ const u8 *pmkid = NULL;
+ if (wpa_key_mgmt_sae(old_entry->akmp))
+ pmkid = old_entry->pmkid;
new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
- NULL, NULL, 0,
+ pmkid, NULL, 0,
aa, pmksa->sm->own_addr,
old_entry->network_ctx, old_entry->akmp,
old_entry->fils_cache_id_set ?
@@ -413,6 +421,20 @@
while (entry) {
if (entry->network_ctx == network_ctx &&
(!akmp || entry->akmp == akmp)) {
+ struct os_reltime now;
+
+ if (wpa_key_mgmt_sae(entry->akmp) &&
+ os_get_reltime(&now) == 0 &&
+ entry->reauth_time < now.sec) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Do not clone PMKSA cache entry for "
+ MACSTR
+ " since its reauth threshold has passed",
+ MAC2STR(entry->aa));
+ entry = entry->next;
+ continue;
+ }
+
entry = pmksa_cache_clone_entry(pmksa, entry, aa);
if (entry) {
wpa_printf(MSG_DEBUG, "RSN: added "
@@ -516,6 +538,20 @@
network_ctx,
fils_cache_id);
if (sm->cur_pmksa) {
+ struct os_reltime now;
+
+ if (wpa_key_mgmt_sae(sm->cur_pmksa->akmp) &&
+ os_get_reltime(&now) == 0 &&
+ sm->cur_pmksa->reauth_time < now.sec) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Do not allow PMKSA cache entry for "
+ MACSTR
+ " to be used for SAE since its reauth threshold has passed",
+ MAC2STR(sm->cur_pmksa->aa));
+ sm->cur_pmksa = NULL;
+ return -1;
+ }
+
wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID",
sm->cur_pmksa->pmkid, PMKID_LEN);
return 0;
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index d0c43f4..d4d1307 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -49,6 +49,15 @@
}
+static int rsn_preauth_key_mgmt(int akmp)
+{
+ return !!(akmp & (WPA_KEY_MGMT_IEEE8021X |
+ WPA_KEY_MGMT_IEEE8021X_SHA256 |
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B |
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
+}
+
+
static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
const u8 *buf, size_t len)
{
@@ -243,9 +252,9 @@
eapol_sm_configure(sm->preauth_eapol, -1, -1, 5, 6);
os_memcpy(sm->preauth_bssid, dst, ETH_ALEN);
- eapol_sm_notify_portValid(sm->preauth_eapol, TRUE);
+ eapol_sm_notify_portValid(sm->preauth_eapol, true);
/* 802.1X::portControl = Auto */
- eapol_sm_notify_portEnabled(sm->preauth_eapol, TRUE);
+ eapol_sm_notify_portEnabled(sm->preauth_eapol, true);
eloop_register_timeout(sm->dot11RSNAConfigSATimeout, 0,
rsn_preauth_timeout, sm, NULL);
@@ -311,10 +320,7 @@
if (sm->preauth_eapol ||
sm->proto != WPA_PROTO_RSN ||
wpa_sm_get_state(sm) != WPA_COMPLETED ||
- (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
- sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256 &&
- sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B &&
- sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)) {
+ !rsn_preauth_key_mgmt(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable "
"state for new pre-authentication");
return; /* invalid state for new pre-auth */
@@ -343,7 +349,7 @@
* PMKIDs again, so report the existing data now. */
if (p) {
wpa_sm_add_pmkid(sm, NULL, candidate->bssid, p->pmkid,
- NULL, p->pmk, p->pmk_len);
+ NULL, p->pmk, p->pmk_len, 0, 0);
}
dl_list_del(&candidate->list);
@@ -488,6 +494,9 @@
!(ie.capabilities & WPA_CAPABILITY_PREAUTH)))
return;
+ if (!rsn_preauth_key_mgmt(ie.key_mgmt))
+ return;
+
/* Give less priority to candidates found from normal scan results. */
pmksa_candidate_add(sm, bssid, PMKID_CANDIDATE_PRIO_SCAN,
ie.capabilities & WPA_CAPABILITY_PREAUTH);
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 704c95e..7b47e3a 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -178,7 +178,7 @@
static int wpa_tdls_del_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
{
if (wpa_sm_set_key(sm, WPA_ALG_NONE, peer->addr,
- 0, 0, NULL, 0, NULL, 0) < 0) {
+ 0, 0, NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE) < 0) {
wpa_printf(MSG_WARNING, "TDLS: Failed to delete TPK-TK from "
"the driver");
return -1;
@@ -227,8 +227,9 @@
wpa_printf(MSG_DEBUG, "TDLS: Configure pairwise key for peer " MACSTR,
MAC2STR(peer->addr));
- if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1,
- rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) {
+ if (wpa_sm_set_key(sm, alg, peer->addr, 0, 1, rsc, sizeof(rsc),
+ peer->tpk.tk, key_len,
+ KEY_FLAG_PAIRWISE_RX_TX) < 0) {
wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the "
"driver");
return -1;
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 66a8643..33e7f41 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -183,6 +183,14 @@
int key_info, ver;
u8 bssid[ETH_ALEN], *rbuf, *key_mic, *mic;
+ if (pairwise && sm->wpa_deny_ptk0_rekey && !sm->use_ext_key_id &&
+ wpa_sm_get_state(sm) == WPA_COMPLETED) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: PTK0 rekey not allowed, reconnecting");
+ wpa_sm_reconnect(sm);
+ return;
+ }
+
if (wpa_use_akm_defined(sm->key_mgmt))
ver = WPA_KEY_INFO_TYPE_AKM_DEFINED;
else if (wpa_key_mgmt_ft(sm->key_mgmt) ||
@@ -305,6 +313,9 @@
#endif /* CONFIG_IEEE80211R */
} else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && sm->eapol) {
int res, pmk_len;
+#ifdef CONFIG_IEEE80211R
+ u8 buf[2 * PMK_LEN];
+#endif /* CONFIG_IEEE80211R */
if (wpa_key_mgmt_sha384(sm->key_mgmt))
pmk_len = PMK_LEN_SUITE_B_192;
@@ -320,24 +331,42 @@
res = eapol_sm_get_key(sm->eapol, sm->pmk, 16);
pmk_len = 16;
}
- } else {
-#ifdef CONFIG_IEEE80211R
- u8 buf[2 * PMK_LEN];
- if (eapol_sm_get_key(sm->eapol, buf, 2 * PMK_LEN) == 0)
- {
- 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 */
}
+#ifdef CONFIG_IEEE80211R
+ if (res == 0 &&
+ eapol_sm_get_key(sm->eapol, buf, 2 * PMK_LEN) == 0) {
+ 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;
+ }
+ forced_memzero(buf, sizeof(buf));
+ if (sm->proto == WPA_PROTO_RSN &&
+ wpa_key_mgmt_ft(sm->key_mgmt)) {
+ struct rsn_pmksa_cache_entry *sa = NULL;
+ const u8 *fils_cache_id = NULL;
+
+#ifdef CONFIG_FILS
+ if (sm->fils_cache_id_set)
+ fils_cache_id = sm->fils_cache_id;
+#endif /* CONFIG_FILS */
+ wpa_hexdump_key(MSG_DEBUG,
+ "FT: Cache XXKey/MPMK",
+ sm->xxkey, sm->xxkey_len);
+ sa = pmksa_cache_add(sm->pmksa,
+ sm->xxkey, sm->xxkey_len,
+ NULL, NULL, 0,
+ src_addr, sm->own_addr,
+ sm->network_ctx,
+ sm->key_mgmt,
+ fils_cache_id);
+ if (!sm->cur_pmksa)
+ sm->cur_pmksa = sa;
+ }
+ }
+#endif /* CONFIG_IEEE80211R */
if (res == 0) {
struct rsn_pmksa_cache_entry *sa = NULL;
const u8 *fils_cache_id = NULL;
@@ -384,6 +413,11 @@
if (!sm->cur_pmksa)
sm->cur_pmksa = sa;
+#ifdef CONFIG_IEEE80211R
+ } else if (wpa_key_mgmt_ft(sm->key_mgmt) && sm->ft_protocol) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Continue 4-way handshake without PMK/PMKID for association using FT protocol");
+#endif /* CONFIG_IEEE80211R */
} else {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to get master session key from "
@@ -462,6 +496,8 @@
if (wpa_key_mgmt_ft(sm->key_mgmt)) {
int res;
+ wpa_hexdump(MSG_DEBUG, "WPA: WPA IE before FT processing",
+ wpa_ie, wpa_ie_len);
/*
* Add PMKR1Name into RSN IE (PMKID-List) and add MDIE and
* FTIE from (Re)Association Response.
@@ -477,8 +513,14 @@
os_free(rsn_ie_buf);
return -1;
}
+ wpa_hexdump(MSG_DEBUG,
+ "WPA: WPA IE after PMKID[PMKR1Name] addition into RSNE",
+ rsn_ie_buf, wpa_ie_len);
if (sm->assoc_resp_ies) {
+ wpa_hexdump(MSG_DEBUG, "WPA: Add assoc_resp_ies",
+ sm->assoc_resp_ies,
+ sm->assoc_resp_ies_len);
os_memcpy(rsn_ie_buf + wpa_ie_len, sm->assoc_resp_ies,
sm->assoc_resp_ies_len);
wpa_ie_len += sm->assoc_resp_ies_len;
@@ -536,6 +578,7 @@
{
const u8 *z = NULL;
size_t z_len = 0;
+ int akmp;
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt))
@@ -549,13 +592,67 @@
}
#endif /* CONFIG_DPP2 */
+ akmp = sm->key_mgmt;
+#ifdef CONFIG_OWE
+ if (sm->owe_ptk_workaround && akmp == WPA_KEY_MGMT_OWE &&
+ sm->pmk_len > 32) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: Force SHA256 for PTK derivation");
+ akmp |= WPA_KEY_MGMT_PSK_SHA256;
+ }
+#endif /* CONFIG_OWE */
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,
+ key->key_nonce, ptk, akmp,
sm->pairwise_cipher, z, z_len);
}
+static int wpa_handle_ext_key_id(struct wpa_sm *sm,
+ struct wpa_eapol_ie_parse *kde)
+{
+ if (sm->ext_key_id) {
+ u16 key_id;
+
+ if (!kde->key_id) {
+ wpa_msg(sm->ctx->msg_ctx,
+ sm->use_ext_key_id ? MSG_INFO : MSG_DEBUG,
+ "RSN: No Key ID in Extended Key ID handshake");
+ sm->keyidx_active = 0;
+ return sm->use_ext_key_id ? -1 : 0;
+ }
+
+ key_id = kde->key_id[0] & 0x03;
+ if (key_id > 1) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: Invalid Extended Key ID: %d", key_id);
+ return -1;
+ }
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Using Extended Key ID %d", key_id);
+ sm->keyidx_active = key_id;
+ sm->use_ext_key_id = 1;
+ } else {
+ if (kde->key_id && (kde->key_id[0] & 0x03)) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: Non-zero Extended Key ID Key ID in PTK0 handshake");
+ return -1;
+ }
+
+ if (kde->key_id) {
+ /* This is not supposed to be included here, but ignore
+ * the case of matching Key ID 0 just in case. */
+ wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Extended Key ID Key ID 0 in PTK0 handshake");
+ }
+ sm->keyidx_active = 0;
+ sm->use_ext_key_id = 0;
+ }
+
+ return 0;
+}
+
+
static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
const unsigned char *src_addr,
const struct wpa_eapol_key *key,
@@ -574,6 +671,14 @@
return;
}
+ if (sm->wpa_deny_ptk0_rekey && !sm->use_ext_key_id &&
+ wpa_sm_get_state(sm) == WPA_COMPLETED) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: PTK0 rekey not allowed, reconnecting");
+ wpa_sm_reconnect(sm);
+ return;
+ }
+
wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
wpa_dbg(sm->ctx->msg_ctx, MSG_INFO, "WPA: RX message 1 of 4-Way "
"Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
@@ -623,57 +728,57 @@
os_memcpy(buf, &ptk->tk[16], 8);
os_memcpy(&ptk->tk[16], &ptk->tk[24], 8);
os_memcpy(&ptk->tk[24], buf, 8);
- os_memset(buf, 0, sizeof(buf));
+ forced_memzero(buf, sizeof(buf));
}
sm->tptk_set = 1;
kde = sm->assoc_wpa_ie;
kde_len = sm->assoc_wpa_ie_len;
+ kde_buf = os_malloc(kde_len +
+ 2 + RSN_SELECTOR_LEN + 3 +
+ sm->assoc_rsnxe_len +
+ 2 + RSN_SELECTOR_LEN + 1);
+ if (!kde_buf)
+ goto failed;
+ os_memcpy(kde_buf, kde, kde_len);
+ kde = kde_buf;
#ifdef CONFIG_OCV
if (wpa_sm_ocv_enabled(sm)) {
struct wpa_channel_info ci;
u8 *pos;
+ pos = kde + kde_len;
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 */
+ if (sm->assoc_rsnxe && sm->assoc_rsnxe_len) {
+ os_memcpy(kde + kde_len, sm->assoc_rsnxe, sm->assoc_rsnxe_len);
+ kde_len += sm->assoc_rsnxe_len;
+ }
+
#ifdef CONFIG_P2P
if (sm->p2p) {
- kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 1);
- if (kde_buf) {
- u8 *pos;
- wpa_printf(MSG_DEBUG, "P2P: Add IP Address Request KDE "
- "into EAPOL-Key 2/4");
- os_memcpy(kde_buf, kde, kde_len);
- kde = kde_buf;
- pos = kde + kde_len;
- *pos++ = WLAN_EID_VENDOR_SPECIFIC;
- *pos++ = RSN_SELECTOR_LEN + 1;
- RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_IP_ADDR_REQ);
- pos += RSN_SELECTOR_LEN;
- *pos++ = 0x01;
- kde_len = pos - kde;
- }
+ u8 *pos;
+
+ wpa_printf(MSG_DEBUG,
+ "P2P: Add IP Address Request KDE into EAPOL-Key 2/4");
+ pos = kde + kde_len;
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = RSN_SELECTOR_LEN + 1;
+ RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_IP_ADDR_REQ);
+ pos += RSN_SELECTOR_LEN;
+ *pos++ = 0x01;
+ kde_len = pos - kde;
}
#endif /* CONFIG_P2P */
@@ -713,11 +818,11 @@
wpa_sm_mlme_setprotection(
sm, addr, MLME_SETPROTECTION_PROTECT_TYPE_RX_TX,
MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
- eapol_sm_notify_portValid(sm->eapol, TRUE);
+ eapol_sm_notify_portValid(sm->eapol, true);
if (wpa_key_mgmt_wpa_psk(sm->key_mgmt) ||
sm->key_mgmt == WPA_KEY_MGMT_DPP ||
sm->key_mgmt == WPA_KEY_MGMT_OWE)
- eapol_sm_notify_eap_success(sm->eapol, TRUE);
+ eapol_sm_notify_eap_success(sm->eapol, true);
/*
* Start preauthentication after a short wait to avoid a
* possible race condition between the data receive and key
@@ -755,7 +860,8 @@
static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
- const struct wpa_eapol_key *key)
+ const struct wpa_eapol_key *key,
+ enum key_flag key_flag)
{
int keylen, rsclen;
enum wpa_alg alg;
@@ -799,12 +905,14 @@
wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen);
}
- if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen,
- sm->ptk.tk, keylen) < 0) {
+ if (wpa_sm_set_key(sm, alg, sm->bssid, sm->keyidx_active, 1, key_rsc,
+ rsclen, sm->ptk.tk, keylen,
+ KEY_FLAG_PAIRWISE | key_flag) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "WPA: Failed to set PTK to the "
- "driver (alg=%d keylen=%d bssid=" MACSTR ")",
- alg, keylen, MAC2STR(sm->bssid));
+ "WPA: Failed to set PTK to the driver (alg=%d keylen=%d bssid="
+ MACSTR " idx=%d key_flag=0x%x)",
+ alg, keylen, MAC2STR(sm->bssid),
+ sm->keyidx_active, key_flag);
return -1;
}
@@ -818,7 +926,23 @@
eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk,
sm, NULL);
}
+ return 0;
+}
+
+static int wpa_supplicant_activate_ptk(struct wpa_sm *sm)
+{
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: Activate PTK (idx=%d bssid=" MACSTR ")",
+ sm->keyidx_active, MAC2STR(sm->bssid));
+
+ if (wpa_sm_set_key(sm, 0, sm->bssid, sm->keyidx_active, 0, NULL, 0,
+ NULL, 0, KEY_FLAG_PAIRWISE_RX_TX_MODIFY) < 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Failed to activate PTK for TX (idx=%d bssid="
+ MACSTR ")", sm->keyidx_active, MAC2STR(sm->bssid));
+ return -1;
+ }
return 0;
}
@@ -893,24 +1017,25 @@
if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
if (wpa_sm_set_key(sm, gd->alg, NULL,
gd->keyidx, 1, key_rsc, gd->key_rsc_len,
- _gtk, gd->gtk_len) < 0) {
+ _gtk, gd->gtk_len,
+ KEY_FLAG_GROUP_RX_TX_DEFAULT) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to set GTK to the driver "
"(Group only)");
- os_memset(gtk_buf, 0, sizeof(gtk_buf));
+ forced_memzero(gtk_buf, sizeof(gtk_buf));
return -1;
}
} else if (wpa_sm_set_key(sm, gd->alg, broadcast_ether_addr,
gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len,
- _gtk, gd->gtk_len) < 0) {
+ _gtk, gd->gtk_len, KEY_FLAG_GROUP_RX) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to set GTK to "
"the driver (alg=%d keylen=%d keyidx=%d)",
gd->alg, gd->gtk_len, gd->keyidx);
- os_memset(gtk_buf, 0, sizeof(gtk_buf));
+ forced_memzero(gtk_buf, sizeof(gtk_buf));
return -1;
}
- os_memset(gtk_buf, 0, sizeof(gtk_buf));
+ forced_memzero(gtk_buf, sizeof(gtk_buf));
if (wnm_sleep) {
sm->gtk_wnm_sleep.gtk_len = gd->gtk_len;
@@ -1016,16 +1141,15 @@
wpa_supplicant_install_gtk(sm, &gd, key_rsc, 0))) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"RSN: Failed to install GTK");
- os_memset(&gd, 0, sizeof(gd));
+ forced_memzero(&gd, sizeof(gd));
return -1;
}
- os_memset(&gd, 0, sizeof(gd));
+ forced_memzero(&gd, sizeof(gd));
return 0;
}
-#ifdef CONFIG_IEEE80211W
static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
const struct wpa_igtk_kde *igtk,
int wnm_sleep)
@@ -1057,7 +1181,7 @@
if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
broadcast_ether_addr,
keyidx, 0, igtk->pn, sizeof(igtk->pn),
- igtk->igtk, len) < 0) {
+ igtk->igtk, len, KEY_FLAG_GROUP_RX) < 0) {
if (keyidx == 0x0400 || keyidx == 0x0500) {
/* Assume the AP has broken PMF implementation since it
* seems to have swapped the KeyID bytes. The AP cannot
@@ -1092,18 +1216,68 @@
return 0;
}
-#endif /* CONFIG_IEEE80211W */
+
+
+static int wpa_supplicant_install_bigtk(struct wpa_sm *sm,
+ const struct wpa_bigtk_kde *bigtk,
+ int wnm_sleep)
+{
+ size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+ u16 keyidx = WPA_GET_LE16(bigtk->keyid);
+
+ /* Detect possible key reinstallation */
+ if ((sm->bigtk.bigtk_len == len &&
+ os_memcmp(sm->bigtk.bigtk, bigtk->bigtk,
+ sm->bigtk.bigtk_len) == 0) ||
+ (sm->bigtk_wnm_sleep.bigtk_len == len &&
+ os_memcmp(sm->bigtk_wnm_sleep.bigtk, bigtk->bigtk,
+ sm->bigtk_wnm_sleep.bigtk_len) == 0)) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: Not reinstalling already in-use BIGTK to the driver (keyidx=%d)",
+ keyidx);
+ return 0;
+ }
+
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: BIGTK keyid %d pn " COMPACT_MACSTR,
+ keyidx, MAC2STR(bigtk->pn));
+ wpa_hexdump_key(MSG_DEBUG, "WPA: BIGTK", bigtk->bigtk, len);
+ if (keyidx < 6 || keyidx > 7) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Invalid BIGTK KeyID %d", keyidx);
+ return -1;
+ }
+ if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+ broadcast_ether_addr,
+ keyidx, 0, bigtk->pn, sizeof(bigtk->pn),
+ bigtk->bigtk, len, KEY_FLAG_GROUP_RX) < 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Failed to configure BIGTK to the driver");
+ return -1;
+ }
+
+ if (wnm_sleep) {
+ sm->bigtk_wnm_sleep.bigtk_len = len;
+ os_memcpy(sm->bigtk_wnm_sleep.bigtk, bigtk->bigtk,
+ sm->bigtk_wnm_sleep.bigtk_len);
+ } else {
+ sm->bigtk.bigtk_len = len;
+ os_memcpy(sm->bigtk.bigtk, bigtk->bigtk, sm->bigtk.bigtk_len);
+ }
+
+ return 0;
+}
static int ieee80211w_set_keys(struct wpa_sm *sm,
struct wpa_eapol_ie_parse *ie)
{
-#ifdef CONFIG_IEEE80211W
+ size_t len;
+
if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher))
return 0;
if (ie->igtk) {
- size_t len;
const struct wpa_igtk_kde *igtk;
len = wpa_cipher_key_len(sm->mgmt_group_cipher);
@@ -1115,10 +1289,19 @@
return -1;
}
+ if (ie->bigtk && sm->beacon_prot) {
+ const struct wpa_bigtk_kde *bigtk;
+
+ len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+ if (ie->bigtk_len != WPA_BIGTK_KDE_PREFIX_LEN + len)
+ return -1;
+
+ bigtk = (const struct wpa_bigtk_kde *) ie->bigtk;
+ if (wpa_supplicant_install_bigtk(sm, bigtk, 0) < 0)
+ return -1;
+ }
+
return 0;
-#else /* CONFIG_IEEE80211W */
- return 0;
-#endif /* CONFIG_IEEE80211W */
}
@@ -1304,11 +1487,10 @@
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Could not find AP from "
"the scan results");
- } else {
- wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
- "WPA: Found the current AP from "
- "updated scan results");
+ return -1;
}
+ wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: Found the current AP from updated scan results");
}
if (ie->wpa_ie == NULL && ie->rsn_ie == NULL &&
@@ -1345,6 +1527,21 @@
return -1;
}
+ if ((sm->ap_rsnxe && !ie->rsnxe) ||
+ (!sm->ap_rsnxe && ie->rsnxe) ||
+ (sm->ap_rsnxe && ie->rsnxe &&
+ (sm->ap_rsnxe_len != ie->rsnxe_len ||
+ os_memcmp(sm->ap_rsnxe, ie->rsnxe, sm->ap_rsnxe_len) != 0))) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: RSNXE mismatch between Beacon/ProbeResp and EAPOL-Key msg 3/4");
+ wpa_hexdump(MSG_INFO, "RSNXE in Beacon/ProbeResp",
+ sm->ap_rsnxe, sm->ap_rsnxe_len);
+ wpa_hexdump(MSG_INFO, "RSNXE in EAPOL-Key msg 3/4",
+ ie->rsnxe, ie->rsnxe_len);
+ wpa_sm_deauthenticate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
+ return -1;
+ }
+
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt) &&
wpa_supplicant_validate_ie_ft(sm, src_addr, ie) < 0)
@@ -1429,7 +1626,6 @@
"WPA: GTK IE in unencrypted key data");
goto failed;
}
-#ifdef CONFIG_IEEE80211W
if (ie.igtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: IGTK KDE in unencrypted key data");
@@ -1445,11 +1641,13 @@
(unsigned long) ie.igtk_len);
goto failed;
}
-#endif /* CONFIG_IEEE80211W */
if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0)
goto failed;
+ if (wpa_handle_ext_key_id(sm, &ie))
+ goto failed;
+
if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: ANonce from message 1 of 4-Way Handshake "
@@ -1495,6 +1693,10 @@
}
#endif /* CONFIG_OCV */
+ if (sm->use_ext_key_id &&
+ wpa_supplicant_install_ptk(sm, key, KEY_FLAG_RX))
+ goto failed;
+
if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
&sm->ptk) < 0) {
goto failed;
@@ -1506,7 +1708,14 @@
sm->renew_snonce = 1;
if (key_info & WPA_KEY_INFO_INSTALL) {
- if (wpa_supplicant_install_ptk(sm, key))
+ int res;
+
+ if (sm->use_ext_key_id)
+ res = wpa_supplicant_activate_ptk(sm);
+ else
+ res = wpa_supplicant_install_ptk(sm, key,
+ KEY_FLAG_RX_TX);
+ if (res)
goto failed;
}
@@ -1514,7 +1723,7 @@
wpa_sm_mlme_setprotection(
sm, sm->bssid, MLME_SETPROTECTION_PROTECT_TYPE_RX,
MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
- eapol_sm_notify_portValid(sm->eapol, TRUE);
+ eapol_sm_notify_portValid(sm->eapol, true);
}
wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
@@ -1562,6 +1771,8 @@
sm->cur_pmksa = sa;
}
+ if (ie.transition_disable)
+ wpa_sm_transition_disable(sm, ie.transition_disable[0]);
sm->msg_3_of_4_ok = 1;
return;
@@ -1688,12 +1899,12 @@
os_memcpy(ek + 16, sm->ptk.kek, sm->ptk.kek_len);
os_memcpy(gd->gtk, key_data, key_data_len);
if (rc4_skip(ek, 32, 256, gd->gtk, key_data_len)) {
- os_memset(ek, 0, sizeof(ek));
+ forced_memzero(ek, sizeof(ek));
wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
"WPA: RC4 failed");
return -1;
}
- os_memset(ek, 0, sizeof(ek));
+ forced_memzero(ek, sizeof(ek));
#endif /* CONFIG_NO_RC4 */
} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
if (maxkeylen % 8) {
@@ -1842,7 +2053,7 @@
if (wpa_supplicant_install_gtk(sm, &gd, key_rsc, 0) ||
wpa_supplicant_send_2_of_2(sm, key, ver, key_info) < 0)
goto failed;
- os_memset(&gd, 0, sizeof(gd));
+ forced_memzero(&gd, sizeof(gd));
if (rekey) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Group rekeying "
@@ -1861,7 +2072,7 @@
return;
failed:
- os_memset(&gd, 0, sizeof(gd));
+ forced_memzero(&gd, sizeof(gd));
wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
}
@@ -1975,12 +2186,12 @@
os_memcpy(ek, key->key_iv, 16);
os_memcpy(ek + 16, sm->ptk.kek, sm->ptk.kek_len);
if (rc4_skip(ek, 32, 256, key_data, *key_data_len)) {
- os_memset(ek, 0, sizeof(ek));
+ forced_memzero(ek, sizeof(ek));
wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
"WPA: RC4 failed");
return -1;
}
- os_memset(ek, 0, sizeof(ek));
+ forced_memzero(ek, sizeof(ek));
#endif /* CONFIG_NO_RC4 */
} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
ver == WPA_KEY_INFO_TYPE_AES_128_CMAC ||
@@ -2268,9 +2479,7 @@
key_info = WPA_GET_BE16(key->key_info);
ver = key_info & WPA_KEY_INFO_TYPE_MASK;
if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
!wpa_use_akm_defined(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
@@ -2298,7 +2507,6 @@
}
} else
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
!wpa_use_akm_defined(sm->key_mgmt)) {
@@ -2307,11 +2515,9 @@
"negotiated AES-128-CMAC");
goto out;
}
- } else
-#endif /* CONFIG_IEEE80211W */
- if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
- !wpa_use_akm_defined(sm->key_mgmt) &&
- ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+ } else if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
+ !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 "
"descriptor version (%d) is not 2", ver);
@@ -2454,12 +2660,10 @@
case WPA_KEY_MGMT_FT_PSK:
return RSN_AUTH_KEY_MGMT_FT_PSK;
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
case WPA_KEY_MGMT_IEEE8021X_SHA256:
return RSN_AUTH_KEY_MGMT_802_1X_SHA256;
case WPA_KEY_MGMT_PSK_SHA256:
return RSN_AUTH_KEY_MGMT_PSK_SHA256;
-#endif /* CONFIG_IEEE80211W */
case WPA_KEY_MGMT_CCKM:
return (sm->proto == WPA_PROTO_RSN ?
RSN_AUTH_KEY_MGMT_CCKM:
@@ -2492,7 +2696,8 @@
int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
{
char pmkid_txt[PMKID_LEN * 2 + 1];
- int rsna, ret;
+ bool rsna;
+ int ret;
size_t len;
if (sm->cur_pmksa) {
@@ -2501,12 +2706,9 @@
} else
pmkid_txt[0] = '\0';
- if ((wpa_key_mgmt_wpa_psk(sm->key_mgmt) ||
- wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) &&
- sm->proto == WPA_PROTO_RSN)
- rsna = 1;
- else
- rsna = 0;
+ rsna = (wpa_key_mgmt_wpa_psk(sm->key_mgmt) ||
+ wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) &&
+ sm->proto == WPA_PROTO_RSN;
ret = os_snprintf(buf, buflen,
"dot11RSNAOptionImplemented=TRUE\n"
@@ -2651,8 +2853,10 @@
eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL);
eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
os_free(sm->assoc_wpa_ie);
+ os_free(sm->assoc_rsnxe);
os_free(sm->ap_wpa_ie);
os_free(sm->ap_rsn_ie);
+ os_free(sm->ap_rsnxe);
wpa_sm_drop_sa(sm);
os_free(sm->ctx);
#ifdef CONFIG_IEEE80211R
@@ -2707,13 +2911,16 @@
* Clear portValid to kick EAPOL state machine to re-enter
* AUTHENTICATED state to get the EAPOL port Authorized.
*/
- eapol_sm_notify_portValid(sm->eapol, FALSE);
+ eapol_sm_notify_portValid(sm->eapol, false);
wpa_supplicant_key_neg_complete(sm, sm->bssid, 1);
/* Prepare for the next transition */
wpa_ft_prepare_auth_request(sm, NULL);
clear_keys = 0;
+ sm->ft_protocol = 1;
+ } else {
+ sm->ft_protocol = 0;
}
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_FILS
@@ -2739,10 +2946,8 @@
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
os_memset(&sm->gtk, 0, sizeof(sm->gtk));
os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep));
-#ifdef CONFIG_IEEE80211W
os_memset(&sm->igtk, 0, sizeof(sm->igtk));
os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep));
-#endif /* CONFIG_IEEE80211W */
}
#ifdef CONFIG_TDLS
@@ -2752,6 +2957,8 @@
#ifdef CONFIG_P2P
os_memset(sm->p2p_ip_addr, 0, sizeof(sm->p2p_ip_addr));
#endif /* CONFIG_P2P */
+
+ sm->keyidx_active = 0;
}
@@ -2778,10 +2985,12 @@
#endif /* CONFIG_FILS */
#ifdef CONFIG_IEEE80211R
sm->ft_reassoc_completed = 0;
+ sm->ft_protocol = 0;
#endif /* CONFIG_IEEE80211R */
/* Keys are not needed in the WPA state machine anymore */
wpa_sm_drop_sa(sm);
+ sm->keyidx_active = 0;
sm->msg_3_of_4_ok = 0;
os_memset(sm->bssid, 0, ETH_ALEN);
@@ -2877,7 +3086,7 @@
/**
- * wpa_sm_set_config - Notification of current configration change
+ * wpa_sm_set_config - Notification of current configuration change
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @config: Pointer to current network configuration
*
@@ -2904,6 +3113,7 @@
sm->wpa_ptk_rekey = config->wpa_ptk_rekey;
sm->p2p = config->p2p;
sm->wpa_rsc_relaxation = config->wpa_rsc_relaxation;
+ sm->owe_ptk_workaround = config->owe_ptk_workaround;
#ifdef CONFIG_FILS
if (config->fils_cache_id) {
sm->fils_cache_id_set = 1;
@@ -2913,6 +3123,7 @@
sm->fils_cache_id_set = 0;
}
#endif /* CONFIG_FILS */
+ sm->beacon_prot = config->beacon_prot;
} else {
sm->network_ctx = NULL;
sm->allowed_pairwise_cipher = 0;
@@ -2923,6 +3134,8 @@
sm->wpa_ptk_rekey = 0;
sm->p2p = 0;
sm->wpa_rsc_relaxation = 0;
+ sm->owe_ptk_workaround = 0;
+ sm->beacon_prot = 0;
}
}
@@ -3013,11 +3226,9 @@
case WPA_PARAM_KEY_MGMT:
sm->key_mgmt = value;
break;
-#ifdef CONFIG_IEEE80211W
case WPA_PARAM_MGMT_GROUP:
sm->mgmt_group_cipher = value;
break;
-#endif /* CONFIG_IEEE80211W */
case WPA_PARAM_RSN_ENABLED:
sm->rsn_enabled = value;
break;
@@ -3027,6 +3238,23 @@
case WPA_PARAM_OCV:
sm->ocv = value;
break;
+ case WPA_PARAM_SAE_PWE:
+ sm->sae_pwe = value;
+ break;
+ case WPA_PARAM_DENY_PTK0_REKEY:
+ sm->wpa_deny_ptk0_rekey = value;
+ break;
+ case WPA_PARAM_EXT_KEY_ID:
+ sm->ext_key_id = value;
+ break;
+ case WPA_PARAM_USE_EXT_KEY_ID:
+ sm->use_ext_key_id = value;
+ break;
+#ifdef CONFIG_TESTING_OPTIONS
+ case WPA_PARAM_FT_RSNXE_USED:
+ sm->ft_rsnxe_used = value;
+ break;
+#endif /* CONFIG_TESTING_OPTIONS */
default:
break;
}
@@ -3101,6 +3329,18 @@
}
+int wpa_sm_ext_key_id(struct wpa_sm *sm)
+{
+ return sm ? sm->ext_key_id : 0;
+}
+
+
+int wpa_sm_ext_key_id_active(struct wpa_sm *sm)
+{
+ return sm ? sm->use_ext_key_id : 0;
+}
+
+
int wpa_sm_ocv_enabled(struct wpa_sm *sm)
{
struct wpa_ie_data rsn;
@@ -3205,6 +3445,83 @@
/**
+ * wpa_sm_set_assoc_rsnxe_default - Generate own RSNXE from configuration
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @rsnxe: Pointer to buffer for RSNXE
+ * @rsnxe_len: Pointer to the length of the rsne buffer
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_sm_set_assoc_rsnxe_default(struct wpa_sm *sm, u8 *rsnxe,
+ size_t *rsnxe_len)
+{
+ int res;
+
+ if (!sm)
+ return -1;
+
+ res = wpa_gen_rsnxe(sm, rsnxe, *rsnxe_len);
+ if (res < 0)
+ return -1;
+ *rsnxe_len = res;
+
+ wpa_hexdump(MSG_DEBUG, "RSN: Set own RSNXE default", rsnxe, *rsnxe_len);
+
+ if (sm->assoc_rsnxe) {
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: Leave previously set RSNXE default",
+ sm->assoc_rsnxe, sm->assoc_rsnxe_len);
+ } else if (*rsnxe_len > 0) {
+ /*
+ * Make a copy of the RSNXE so that 4-Way Handshake gets the
+ * correct version of the IE even if it gets changed.
+ */
+ sm->assoc_rsnxe = os_memdup(rsnxe, *rsnxe_len);
+ if (!sm->assoc_rsnxe)
+ return -1;
+
+ sm->assoc_rsnxe_len = *rsnxe_len;
+ }
+
+ return 0;
+}
+
+
+/**
+ * wpa_sm_set_assoc_rsnxe - Set own RSNXE from (Re)AssocReq
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ie: Pointer to IE data (starting from id)
+ * @len: IE length
+ * Returns: 0 on success, -1 on failure
+ *
+ * Inform WPA state machine about the RSNXE used in (Re)Association Request
+ * frame. The IE will be used to override the default value generated
+ * with wpa_sm_set_assoc_rsnxe_default().
+ */
+int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len)
+{
+ if (!sm)
+ return -1;
+
+ os_free(sm->assoc_rsnxe);
+ if (!ie || len == 0) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: clearing own RSNXE");
+ sm->assoc_rsnxe = NULL;
+ sm->assoc_rsnxe_len = 0;
+ } else {
+ wpa_hexdump(MSG_DEBUG, "RSN: set own RSNXE", ie, len);
+ sm->assoc_rsnxe = os_memdup(ie, len);
+ if (!sm->assoc_rsnxe)
+ return -1;
+
+ sm->assoc_rsnxe_len = len;
+ }
+
+ return 0;
+}
+
+
+/**
* wpa_sm_set_ap_wpa_ie - Set AP WPA IE from Beacon/ProbeResp
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @ie: Pointer to IE data (starting from id)
@@ -3273,6 +3590,39 @@
/**
+ * wpa_sm_set_ap_rsnxe - Set AP RSNXE from Beacon/ProbeResp
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ie: Pointer to IE data (starting from id)
+ * @len: IE length
+ * Returns: 0 on success, -1 on failure
+ *
+ * Inform WPA state machine about the RSNXE used in Beacon / Probe Response
+ * frame.
+ */
+int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len)
+{
+ if (!sm)
+ return -1;
+
+ os_free(sm->ap_rsnxe);
+ if (!ie || len == 0) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: clearing AP RSNXE");
+ sm->ap_rsnxe = NULL;
+ sm->ap_rsnxe_len = 0;
+ } else {
+ wpa_hexdump(MSG_DEBUG, "WPA: set AP RSNXE", ie, len);
+ sm->ap_rsnxe = os_memdup(ie, len);
+ if (!sm->ap_rsnxe)
+ return -1;
+
+ sm->ap_rsnxe_len = len;
+ }
+
+ return 0;
+}
+
+
+/**
* wpa_sm_parse_own_wpa_ie - Parse own WPA/RSN IE
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @data: Pointer to data area for parsing results
@@ -3345,10 +3695,8 @@
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
os_memset(&sm->gtk, 0, sizeof(sm->gtk));
os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep));
-#ifdef CONFIG_IEEE80211W
os_memset(&sm->igtk, 0, sizeof(sm->igtk));
os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep));
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
sm->xxkey_len = 0;
@@ -3368,6 +3716,14 @@
}
+int wpa_sm_has_ptk_installed(struct wpa_sm *sm)
+{
+ if (!sm)
+ return 0;
+ return sm->ptk.installed;
+}
+
+
void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
{
os_memcpy(sm->rx_replay_counter, replay_ctr, WPA_REPLAY_COUNTER_LEN);
@@ -3416,20 +3772,25 @@
wpa_hexdump_key(MSG_DEBUG, "Install GTK (WNM SLEEP)",
gd.gtk, gd.gtk_len);
if (wpa_supplicant_install_gtk(sm, &gd, key_rsc, 1)) {
- os_memset(&gd, 0, sizeof(gd));
+ forced_memzero(&gd, sizeof(gd));
wpa_printf(MSG_DEBUG, "Failed to install the GTK in "
"WNM mode");
return -1;
}
- os_memset(&gd, 0, sizeof(gd));
-#ifdef CONFIG_IEEE80211W
+ forced_memzero(&gd, sizeof(gd));
} else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
const struct wpa_igtk_kde *igtk;
igtk = (const struct wpa_igtk_kde *) (buf + 2);
if (wpa_supplicant_install_igtk(sm, igtk, 1) < 0)
return -1;
-#endif /* CONFIG_IEEE80211W */
+ } else if (subelem_id == WNM_SLEEP_SUBELEM_BIGTK) {
+ const struct wpa_bigtk_kde *bigtk;
+
+ bigtk = (const struct wpa_bigtk_kde *) (buf + 2);
+ if (sm->beacon_prot &&
+ wpa_supplicant_install_bigtk(sm, bigtk, 1) < 0)
+ return -1;
} else {
wpa_printf(MSG_DEBUG, "Unknown element id");
return -1;
@@ -3613,13 +3974,13 @@
wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
wpabuf_put_data(buf, sm->fils_session, FILS_SESSION_LEN);
- /* FILS Wrapped Data */
+ /* Wrapped Data */
sm->fils_erp_pmkid_set = 0;
if (erp_msg) {
wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */
wpabuf_put_u8(buf, 1 + wpabuf_len(erp_msg)); /* Length */
/* Element ID Extension */
- wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_WRAPPED_DATA);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
wpabuf_put_buf(buf, erp_msg);
/* Calculate pending PMKID here so that we do not need to
* maintain a copy of the EAP-Initiate/Reauth message. */
@@ -3824,16 +4185,16 @@
goto fail;
}
- /* FILS Wrapped Data */
- if (!sm->cur_pmksa && elems.fils_wrapped_data) {
+ /* Wrapped Data */
+ if (!sm->cur_pmksa && elems.wrapped_data) {
u8 rmsk[ERP_MAX_KEY_LEN];
size_t rmsk_len;
wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
- elems.fils_wrapped_data,
- elems.fils_wrapped_data_len);
- eapol_sm_process_erp_finish(sm->eapol, elems.fils_wrapped_data,
- elems.fils_wrapped_data_len);
+ elems.wrapped_data,
+ elems.wrapped_data_len);
+ eapol_sm_process_erp_finish(sm->eapol, elems.wrapped_data,
+ elems.wrapped_data_len);
if (eapol_sm_failed(sm->eapol))
goto fail;
@@ -3851,7 +4212,7 @@
dh_ss ? wpabuf_head(dh_ss) : NULL,
dh_ss ? wpabuf_len(dh_ss) : 0,
sm->pmk, &sm->pmk_len);
- os_memset(rmsk, 0, sizeof(rmsk));
+ forced_memzero(rmsk, sizeof(rmsk));
/* Don't use DHss in PTK derivation if PMKSA caching is not
* used. */
@@ -3926,7 +4287,7 @@
sm->fils_key_auth_ap,
&sm->fils_key_auth_len);
wpabuf_free(pub);
- os_memset(ick, 0, sizeof(ick));
+ forced_memzero(ick, sizeof(ick));
return res;
fail:
wpabuf_free(pub);
@@ -3989,12 +4350,14 @@
/* RSN Capabilities */
capab = 0;
-#ifdef CONFIG_IEEE80211W
- if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC)
+ if (sm->mfp)
capab |= WPA_CAPABILITY_MFPC;
-#endif /* CONFIG_IEEE80211W */
+ if (sm->mfp == 2)
+ capab |= WPA_CAPABILITY_MFPR;
if (sm->ocv)
capab |= WPA_CAPABILITY_OCVC;
+ if (sm->ext_key_id)
+ capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
wpabuf_put_le16(buf, capab);
/* PMKID Count */
@@ -4032,13 +4395,11 @@
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) {
/* Management Group Cipher Suite */
pos = wpabuf_put(buf, RSN_SELECTOR_LEN);
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
}
-#endif /* CONFIG_IEEE80211W */
rsnie->len = ((u8 *) wpabuf_put(buf, 0) - (u8 *) rsnie) - 2;
return 0;
@@ -4290,6 +4651,26 @@
sm->fils_session, FILS_SESSION_LEN);
}
+ if (!elems.rsn_ie) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: No RSNE in (Re)Association Response");
+ /* As an interop workaround, allow this for now since IEEE Std
+ * 802.11ai-2016 did not include all the needed changes to make
+ * a FILS AP include RSNE in the frame. This workaround might
+ * eventually be removed and replaced with rejection (goto fail)
+ * to follow a strict interpretation of the standard. */
+ } else if (wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt),
+ sm->ap_rsn_ie, sm->ap_rsn_ie_len,
+ elems.rsn_ie - 2, elems.rsn_ie_len + 2)) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "FILS: RSNE mismatch between Beacon/Probe Response and (Re)Association Response");
+ wpa_hexdump(MSG_DEBUG, "FILS: RSNE in Beacon/Probe Response",
+ sm->ap_rsn_ie, sm->ap_rsn_ie_len);
+ wpa_hexdump(MSG_DEBUG, "FILS: RSNE in (Re)Association Response",
+ elems.rsn_ie, elems.rsn_ie_len);
+ goto fail;
+ }
+
/* TODO: FILS Public Key */
if (!elems.fils_key_confirm) {
@@ -4404,11 +4785,12 @@
keylen, (long unsigned int) sm->ptk.tk_len);
goto fail;
}
+
rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
wpa_hexdump_key(MSG_DEBUG, "FILS: Set TK to driver",
sm->ptk.tk, keylen);
if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, null_rsc, rsclen,
- sm->ptk.tk, keylen) < 0) {
+ sm->ptk.tk, keylen, KEY_FLAG_PAIRWISE_RX_TX) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"FILS: Failed to set PTK to the driver (alg=%d keylen=%d bssid="
MACSTR ")",
@@ -4430,9 +4812,14 @@
wpa_printf(MSG_DEBUG, "FILS: Auth+Assoc completed successfully");
sm->fils_completed = 1;
+ forced_memzero(&gd, sizeof(gd));
+
+ if (kde.transition_disable)
+ wpa_sm_transition_disable(sm, kde.transition_disable[0]);
return 0;
fail:
+ forced_memzero(&gd, sizeof(gd));
return -1;
}
@@ -4644,7 +5031,7 @@
else if (group == 21)
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);
+ forced_memzero(prk, SHA512_MAC_LEN);
if (res < 0) {
sm->pmk_len = 0;
return -1;
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 8903f8e..0986c6c 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -26,11 +26,12 @@
void (*set_state)(void *ctx, enum wpa_states state);
enum wpa_states (*get_state)(void *ctx);
- void (*deauthenticate)(void * ctx, int reason_code);
+ void (*deauthenticate)(void * ctx, u16 reason_code);
+ void (*reconnect)(void *ctx);
int (*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);
+ const u8 *key, size_t key_len, enum key_flag key_flag);
void * (*get_network_ctx)(void *ctx);
int (*get_bssid)(void *ctx, u8 *bssid);
int (*ether_send)(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
@@ -41,7 +42,8 @@
size_t *msg_len, void **data_pos);
int (*add_pmkid)(void *ctx, void *network_ctx, const u8 *bssid,
const u8 *pmkid, const u8 *fils_cache_id,
- const u8 *pmk, size_t pmk_len);
+ const u8 *pmk, size_t pmk_len, u32 pmk_lifetime,
+ u8 pmk_reauth_threshold);
int (*remove_pmkid)(void *ctx, void *network_ctx, const u8 *bssid,
const u8 *pmkid, const u8 *fils_cache_id);
void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
@@ -84,6 +86,7 @@
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);
+ void (*transition_disable)(void *ctx, u8 bitmap);
};
@@ -98,7 +101,12 @@
WPA_PARAM_MGMT_GROUP,
WPA_PARAM_RSN_ENABLED,
WPA_PARAM_MFP,
- WPA_PARAM_OCV
+ WPA_PARAM_OCV,
+ WPA_PARAM_SAE_PWE,
+ WPA_PARAM_DENY_PTK0_REKEY,
+ WPA_PARAM_EXT_KEY_ID,
+ WPA_PARAM_USE_EXT_KEY_ID,
+ WPA_PARAM_FT_RSNXE_USED,
};
struct rsn_supp_config {
@@ -110,9 +118,12 @@
const u8 *ssid;
size_t ssid_len;
int wpa_ptk_rekey;
+ int wpa_deny_ptk0_rekey;
int p2p;
int wpa_rsc_relaxation;
+ int owe_ptk_workaround;
const u8 *fils_cache_id;
+ int beacon_prot;
};
#ifndef CONFIG_NO_WPA
@@ -134,8 +145,12 @@
int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
size_t *wpa_ie_len);
+int wpa_sm_set_assoc_rsnxe_default(struct wpa_sm *sm, u8 *rsnxe,
+ size_t *rsnxe_len);
+int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
+int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen);
int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
@@ -144,6 +159,8 @@
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_ext_key_id(struct wpa_sm *sm);
+int wpa_sm_ext_key_id_active(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);
@@ -167,6 +184,7 @@
const void *network_ctx);
void wpa_sm_drop_sa(struct wpa_sm *sm);
int wpa_sm_has_ptk(struct wpa_sm *sm);
+int wpa_sm_has_ptk_installed(struct wpa_sm *sm);
void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr);
@@ -260,6 +278,12 @@
return -1;
}
+static inline int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie,
+ size_t len)
+{
+ return -1;
+}
+
static inline int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
{
return 0;
@@ -283,6 +307,16 @@
return 0;
}
+static inline int wpa_sm_ext_key_id(struct wpa_sm *sm)
+{
+ return 0;
+}
+
+static inline int wpa_sm_ext_key_id_active(struct wpa_sm *sm)
+{
+ return 0;
+}
+
static inline int wpa_sm_ocv_enabled(struct wpa_sm *sm)
{
return 0;
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 7dcb104..3e51cf2 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -18,6 +18,8 @@
#include "drivers/driver.h"
#include "wpa.h"
#include "wpa_i.h"
+#include "wpa_ie.h"
+#include "pmksa_cache.h"
#ifdef CONFIG_IEEE80211R
@@ -27,15 +29,23 @@
u8 ptk_name[WPA_PMK_NAME_LEN];
const u8 *anonce = key->key_nonce;
int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
+ const u8 *mpmk;
+ size_t mpmk_len;
- if (sm->xxkey_len == 0) {
+ if (sm->xxkey_len > 0) {
+ mpmk = sm->xxkey;
+ mpmk_len = sm->xxkey_len;
+ } else if (sm->cur_pmksa) {
+ mpmk = sm->cur_pmksa->pmk;
+ mpmk_len = sm->cur_pmksa->pmk_len;
+ } else {
wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
"derivation");
return -1;
}
sm->pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
- if (wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, sm->ssid,
+ if (wpa_derive_pmk_r0(mpmk, mpmk_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)
@@ -72,23 +82,30 @@
if (sm == NULL)
return 0;
+ if (!get_ie(ies, ies_len, WLAN_EID_MOBILITY_DOMAIN)) {
+ os_free(sm->assoc_resp_ies);
+ sm->assoc_resp_ies = NULL;
+ sm->assoc_resp_ies_len = 0;
+ os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN);
+ os_memset(sm->r0kh_id, 0, FT_R0KH_ID_MAX_LEN);
+ sm->r0kh_id_len = 0;
+ os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN);
+ return 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)
+ if (ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1)
return -1;
- if (ft.mdie) {
- wpa_hexdump(MSG_DEBUG, "FT: Mobility domain",
- ft.mdie, MOBILITY_DOMAIN_ID_LEN);
- os_memcpy(sm->mobility_domain, ft.mdie,
- MOBILITY_DOMAIN_ID_LEN);
- sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN];
- wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x",
- sm->mdie_ft_capab);
- } else
- os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: Mobility domain",
+ ft.mdie, MOBILITY_DOMAIN_ID_LEN);
+ os_memcpy(sm->mobility_domain, ft.mdie, MOBILITY_DOMAIN_ID_LEN);
+ sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN];
+ wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x",
+ sm->mdie_ft_capab);
if (ft.r0kh_id) {
wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID",
@@ -115,10 +132,10 @@
sm->assoc_resp_ies = os_malloc(ft.mdie_len + 2 + ft.ftie_len + 2);
if (sm->assoc_resp_ies) {
u8 *pos = sm->assoc_resp_ies;
- if (ft.mdie) {
- os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2);
- pos += ft.mdie_len + 2;
- }
+
+ os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2);
+ pos += ft.mdie_len + 2;
+
if (ft.ftie) {
os_memcpy(pos, ft.ftie - 2, ft.ftie_len + 2);
pos += ft.ftie_len + 2;
@@ -145,6 +162,7 @@
* @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL
* @ric_ies_len: Length of ric_ies buffer in octets
* @ap_mdie: Mobility Domain IE from the target AP
+ * @omit_rsnxe: Whether RSNXE is omitted from Reassociation Request frame
* Returns: Pointer to buffer with IEs or %NULL on failure
*
* Caller is responsible for freeing the returned buffer with os_free();
@@ -154,14 +172,17 @@
const u8 *kck, size_t kck_len,
const u8 *target_ap,
const u8 *ric_ies, size_t ric_ies_len,
- const u8 *ap_mdie)
+ const u8 *ap_mdie, int omit_rsnxe)
{
size_t buf_len;
u8 *buf, *pos, *ftie_len, *ftie_pos, *fte_mic, *elem_count;
struct rsn_mdie *mdie;
struct rsn_ie_hdr *rsnie;
- u16 capab;
int mdie_len;
+ u8 rsnxe[10];
+ size_t rsnxe_len;
+ int rsnxe_used;
+ int res;
sm->ft_completed = 0;
sm->ft_reassoc_completed = 0;
@@ -236,17 +257,7 @@
pos += RSN_SELECTOR_LEN;
/* RSN Capabilities */
- capab = 0;
-#ifdef CONFIG_IEEE80211W
- 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);
+ WPA_PUT_LE16(pos, rsn_supp_capab(sm));
pos += 2;
/* PMKID Count */
@@ -257,7 +268,6 @@
os_memcpy(pos, pmk_name, WPA_PMK_NAME_LEN);
pos += WPA_PMK_NAME_LEN;
-#ifdef CONFIG_IEEE80211W
/* Management Group Cipher Suite */
switch (sm->mgmt_group_cipher) {
case WPA_CIPHER_AES_128_CMAC:
@@ -277,7 +287,6 @@
pos += RSN_SELECTOR_LEN;
break;
}
-#endif /* CONFIG_IEEE80211W */
rsnie->len = (pos - (u8 *) rsnie) - 2;
@@ -294,10 +303,20 @@
ftie_pos = pos;
*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
ftie_len = pos++;
+ rsnxe_used = wpa_key_mgmt_sae(sm->key_mgmt) && anonce &&
+ (sm->sae_pwe == 1 || sm->sae_pwe == 2);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (anonce && sm->ft_rsnxe_used) {
+ rsnxe_used = sm->ft_rsnxe_used == 1;
+ wpa_printf(MSG_DEBUG, "TESTING: FT: Force RSNXE Used %d",
+ rsnxe_used);
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_key_mgmt_sha384(sm->key_mgmt)) {
struct rsn_ftie_sha384 *ftie;
ftie = (struct rsn_ftie_sha384 *) pos;
+ ftie->mic_control[0] = !!rsnxe_used;
fte_mic = ftie->mic;
elem_count = &ftie->mic_control[1];
pos += sizeof(*ftie);
@@ -308,6 +327,7 @@
struct rsn_ftie *ftie;
ftie = (struct rsn_ftie *) pos;
+ ftie->mic_control[0] = !!rsnxe_used;
fte_mic = ftie->mic;
elem_count = &ftie->mic_control[1];
pos += sizeof(*ftie);
@@ -355,6 +375,17 @@
pos += ric_ies_len;
}
+ if (omit_rsnxe) {
+ rsnxe_len = 0;
+ } else {
+ res = wpa_gen_rsnxe(sm, rsnxe, sizeof(rsnxe));
+ if (res < 0) {
+ os_free(buf);
+ return NULL;
+ }
+ rsnxe_len = res;
+ }
+
if (kck) {
/*
* IEEE Std 802.11r-2008, 11A.8.4
@@ -366,14 +397,18 @@
* MDIE
* FTIE (with MIC field set to 0)
* RIC-Request (if present)
+ * RSNXE (if present)
*/
/* Information element count */
*elem_count = 3 + ieee802_11_ie_count(ric_ies, ric_ies_len);
+ if (rsnxe_len)
+ *elem_count += 1;
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, fte_mic) < 0) {
+ ric_ies_len, rsnxe_len ? rsnxe : NULL, rsnxe_len,
+ fte_mic) < 0) {
wpa_printf(MSG_INFO, "FT: Failed to calculate MIC");
os_free(buf);
return NULL;
@@ -403,8 +438,9 @@
alg = wpa_cipher_to_alg(sm->pairwise_cipher);
keylen = wpa_cipher_key_len(sm->pairwise_cipher);
- if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc,
- sizeof(null_rsc), (u8 *) sm->ptk.tk, keylen) < 0) {
+ if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc, sizeof(null_rsc),
+ (u8 *) sm->ptk.tk, keylen,
+ KEY_FLAG_PAIRWISE_RX_TX) < 0) {
wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
return -1;
}
@@ -431,7 +467,7 @@
}
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
- NULL, 0, sm->bssid, NULL, 0, mdie);
+ NULL, 0, sm->bssid, NULL, 0, mdie, 0);
if (ft_ies) {
wpa_sm_update_ft_ies(sm, sm->mobility_domain,
ft_ies, ft_ies_len);
@@ -589,6 +625,12 @@
return -1;
}
+ if (sm->mfp == 2 && !(parse.rsn_capab & WPA_CAPABILITY_MFPC)) {
+ wpa_printf(MSG_INFO,
+ "FT: Target AP does not support PMF, but local configuration requires that");
+ return -1;
+ }
+
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);
@@ -621,7 +663,8 @@
sm->pmk_r1_name,
kck, kck_len, bssid,
ric_ies, ric_ies_len,
- parse.mdie ? parse.mdie - 2 : NULL);
+ parse.mdie ? parse.mdie - 2 : NULL,
+ !sm->ap_rsnxe);
if (ft_ies) {
wpa_sm_update_ft_ies(sm, sm->mobility_domain,
ft_ies, ft_ies_len);
@@ -748,7 +791,8 @@
os_memcpy(gtk + 24, tmp, 8);
}
if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0,
- gtk_elem + 3, rsc_len, gtk, keylen) < 0) {
+ gtk_elem + 3, rsc_len, gtk, keylen,
+ KEY_FLAG_GROUP_RX) < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
"driver.");
return -1;
@@ -758,7 +802,6 @@
}
-#ifdef CONFIG_IEEE80211W
static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
size_t igtk_elem_len)
{
@@ -816,17 +859,85 @@
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) {
+ igtk_elem + 2, 6, igtk, igtk_len,
+ KEY_FLAG_GROUP_RX) < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the "
"driver.");
- os_memset(igtk, 0, sizeof(igtk));
+ forced_memzero(igtk, sizeof(igtk));
return -1;
}
- os_memset(igtk, 0, sizeof(igtk));
+ forced_memzero(igtk, sizeof(igtk));
return 0;
}
-#endif /* CONFIG_IEEE80211W */
+
+
+static int wpa_ft_process_bigtk_subelem(struct wpa_sm *sm, const u8 *bigtk_elem,
+ size_t bigtk_elem_len)
+{
+ u8 bigtk[WPA_BIGTK_MAX_LEN];
+ size_t bigtk_len;
+ u16 keyidx;
+ const u8 *kek;
+ size_t kek_len;
+
+ if (!sm->beacon_prot || !bigtk_elem ||
+ (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 (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;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "FT: Received BIGTK in Reassoc Resp",
+ bigtk_elem, bigtk_elem_len);
+
+ bigtk_len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+ if (bigtk_elem_len != 2 + 6 + 1 + bigtk_len + 8) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Invalid BIGTK sub-elem length %lu",
+ (unsigned long) bigtk_elem_len);
+ return -1;
+ }
+ if (bigtk_elem[8] != bigtk_len) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Invalid BIGTK sub-elem Key Length %d",
+ bigtk_elem[8]);
+ return -1;
+ }
+
+ if (aes_unwrap(kek, kek_len, bigtk_len / 8, bigtk_elem + 9, bigtk)) {
+ wpa_printf(MSG_WARNING,
+ "FT: AES unwrap failed - could not decrypt BIGTK");
+ return -1;
+ }
+
+ /* KeyID[2] | IPN[6] | Key Length[1] | Key[16+8] */
+
+ keyidx = WPA_GET_LE16(bigtk_elem);
+
+ wpa_hexdump_key(MSG_DEBUG, "FT: BIGTK from Reassoc Resp", bigtk,
+ bigtk_len);
+ if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+ broadcast_ether_addr, keyidx, 0,
+ bigtk_elem + 2, 6, bigtk, bigtk_len,
+ KEY_FLAG_GROUP_RX) < 0) {
+ wpa_printf(MSG_WARNING,
+ "WPA: Failed to set BIGTK to the driver");
+ forced_memzero(bigtk, sizeof(bigtk));
+ return -1;
+ }
+ forced_memzero(bigtk, sizeof(bigtk));
+
+ return 0;
+}
int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
@@ -841,6 +952,7 @@
int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
const u8 *anonce, *snonce, *fte_mic;
u8 fte_elem_count;
+ int own_rsnxe_used, rsnxe_used;
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
@@ -879,6 +991,7 @@
anonce = ftie->anonce;
snonce = ftie->snonce;
+ rsnxe_used = ftie->mic_control[0] & 0x01;
fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic;
} else {
@@ -892,6 +1005,7 @@
anonce = ftie->anonce;
snonce = ftie->snonce;
+ rsnxe_used = ftie->mic_control[0] & 0x01;
fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic;
}
@@ -953,6 +1067,8 @@
count = 3;
if (parse.ric)
count += ieee802_11_ie_count(parse.ric, parse.ric_len);
+ if (parse.rsnxe)
+ count++;
if (fte_elem_count != count) {
wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
"Control: received %u expected %u",
@@ -973,6 +1089,8 @@
parse.ftie - 2, parse.ftie_len + 2,
parse.rsn - 2, parse.rsn_len + 2,
parse.ric, parse.ric_len,
+ parse.rsnxe ? parse.rsnxe - 2 : NULL,
+ parse.rsnxe ? parse.rsnxe_len + 2 : 0,
mic) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
return -1;
@@ -985,6 +1103,58 @@
return -1;
}
+ if (rsnxe_used && !sm->ap_rsnxe) {
+ wpa_printf(MSG_INFO,
+ "FT: FTE indicated that AP uses RSNXE, but RSNXE was not included in Beacon/Probe Response frames");
+ return -1;
+ }
+
+ if (!sm->ap_rsn_ie) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "FT: No RSNE for this AP known - trying to get from scan results");
+ if (wpa_sm_get_beacon_ie(sm) < 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "FT: Could not find AP from the scan results");
+ return -1;
+ }
+ wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "FT: Found the current AP from updated scan results");
+ }
+
+ if (sm->ap_rsn_ie &&
+ wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt),
+ sm->ap_rsn_ie, sm->ap_rsn_ie_len,
+ parse.rsn - 2, parse.rsn_len + 2)) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "FT: RSNE mismatch between Beacon/ProbeResp and FT protocol Reassociation Response frame");
+ wpa_hexdump(MSG_INFO, "RSNE in Beacon/ProbeResp",
+ sm->ap_rsn_ie, sm->ap_rsn_ie_len);
+ wpa_hexdump(MSG_INFO,
+ "RSNE in FT protocol Reassociation Response frame",
+ parse.rsn ? parse.rsn - 2 : NULL,
+ parse.rsn ? parse.rsn_len + 2 : 0);
+ return -1;
+ }
+
+ own_rsnxe_used = wpa_key_mgmt_sae(sm->key_mgmt) &&
+ (sm->sae_pwe == 1 || sm->sae_pwe == 2);
+ if ((sm->ap_rsnxe && !parse.rsnxe && own_rsnxe_used) ||
+ (!sm->ap_rsnxe && parse.rsnxe) ||
+ (sm->ap_rsnxe && parse.rsnxe &&
+ (sm->ap_rsnxe_len != 2 + parse.rsnxe_len ||
+ os_memcmp(sm->ap_rsnxe, parse.rsnxe - 2,
+ sm->ap_rsnxe_len) != 0))) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "FT: RSNXE mismatch between Beacon/ProbeResp and FT protocol Reassociation Response frame");
+ wpa_hexdump(MSG_INFO, "RSNXE in Beacon/ProbeResp",
+ sm->ap_rsnxe, sm->ap_rsnxe_len);
+ wpa_hexdump(MSG_INFO,
+ "RSNXE in FT protocol Reassociation Response frame",
+ parse.rsnxe ? parse.rsnxe - 2 : NULL,
+ parse.rsnxe ? parse.rsnxe_len + 2 : 0);
+ return -1;
+ }
+
#ifdef CONFIG_OCV
if (wpa_sm_ocv_enabled(sm)) {
struct wpa_channel_info ci;
@@ -1006,14 +1176,11 @@
sm->ft_reassoc_completed = 1;
- if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
+ if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0 ||
+ wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0 ||
+ wpa_ft_process_bigtk_subelem(sm, parse.bigtk, parse.bigtk_len) < 0)
return -1;
-#ifdef CONFIG_IEEE80211W
- if (wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0)
- return -1;
-#endif /* CONFIG_IEEE80211W */
-
if (sm->set_ptk_after_assoc) {
wpa_printf(MSG_DEBUG, "FT: Try to set PTK again now that we "
"are associated");
@@ -1058,7 +1225,7 @@
}
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
- NULL, 0, target_ap, NULL, 0, mdie);
+ NULL, 0, target_ap, NULL, 0, mdie, 0);
if (ft_ies) {
sm->over_the_ds_in_progress = 1;
os_memcpy(sm->target_ap, target_ap, ETH_ALEN);
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 5dc9f2e..497d128 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -31,10 +31,10 @@
u8 request_counter[WPA_REPLAY_COUNTER_LEN];
struct wpa_gtk gtk;
struct wpa_gtk gtk_wnm_sleep;
-#ifdef CONFIG_IEEE80211W
struct wpa_igtk igtk;
struct wpa_igtk igtk_wnm_sleep;
-#endif /* CONFIG_IEEE80211W */
+ struct wpa_bigtk bigtk;
+ struct wpa_bigtk bigtk_wnm_sleep;
struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
@@ -63,8 +63,15 @@
u8 ssid[32];
size_t ssid_len;
int wpa_ptk_rekey;
+ int wpa_deny_ptk0_rekey:1;
int p2p;
int wpa_rsc_relaxation;
+ int owe_ptk_workaround;
+ int beacon_prot;
+ int ext_key_id; /* whether Extended Key ID is enabled */
+ int use_ext_key_id; /* whether Extended Key ID has been detected
+ * to be used */
+ int keyidx_active; /* Key ID for the active TK */
u8 own_addr[ETH_ALEN];
const char *ifname;
@@ -87,11 +94,14 @@
int rsn_enabled; /* Whether RSN is enabled in configuration */
int mfp; /* 0 = disabled, 1 = optional, 2 = mandatory */
int ocv; /* Operating Channel Validation */
+ int sae_pwe; /* SAE PWE generation options */
u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
size_t assoc_wpa_ie_len;
- u8 *ap_wpa_ie, *ap_rsn_ie;
- size_t ap_wpa_ie_len, ap_rsn_ie_len;
+ u8 *assoc_rsnxe; /* Own RSNXE from (Re)AssocReq */
+ size_t assoc_rsnxe_len;
+ u8 *ap_wpa_ie, *ap_rsn_ie, *ap_rsnxe;
+ size_t ap_wpa_ie_len, ap_rsn_ie_len, ap_rsnxe_len;
#ifdef CONFIG_TDLS
struct wpa_tdls_peer *tdls;
@@ -126,8 +136,9 @@
u8 r0kh_id[FT_R0KH_ID_MAX_LEN];
size_t r0kh_id_len;
u8 r1kh_id[FT_R1KH_ID_LEN];
- int ft_completed;
- int ft_reassoc_completed;
+ unsigned int ft_completed:1;
+ unsigned int ft_reassoc_completed:1;
+ unsigned int ft_protocol:1;
int over_the_ds_in_progress;
u8 target_ap[ETH_ALEN]; /* over-the-DS target AP */
int set_ptk_after_assoc;
@@ -142,6 +153,7 @@
#ifdef CONFIG_TESTING_OPTIONS
struct wpabuf *test_assoc_ie;
+ int ft_rsnxe_used;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_FILS
@@ -187,7 +199,7 @@
return sm->ctx->get_state(sm->ctx->ctx);
}
-static inline void wpa_sm_deauthenticate(struct wpa_sm *sm, int reason_code)
+static inline void wpa_sm_deauthenticate(struct wpa_sm *sm, u16 reason_code)
{
WPA_ASSERT(sm->ctx->deauthenticate);
sm->ctx->deauthenticate(sm->ctx->ctx, reason_code);
@@ -196,11 +208,18 @@
static inline int wpa_sm_set_key(struct wpa_sm *sm, 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)
+ const u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
WPA_ASSERT(sm->ctx->set_key);
return sm->ctx->set_key(sm->ctx->ctx, alg, addr, key_idx, set_tx,
- seq, seq_len, key, key_len);
+ seq, seq_len, key, key_len, key_flag);
+}
+
+static inline void wpa_sm_reconnect(struct wpa_sm *sm)
+{
+ WPA_ASSERT(sm->ctx->reconnect);
+ sm->ctx->reconnect(sm->ctx->ctx);
}
static inline void * wpa_sm_get_network_ctx(struct wpa_sm *sm)
@@ -246,11 +265,13 @@
static inline int wpa_sm_add_pmkid(struct wpa_sm *sm, void *network_ctx,
const u8 *bssid, const u8 *pmkid,
const u8 *cache_id, const u8 *pmk,
- size_t pmk_len)
+ size_t pmk_len, u32 pmk_lifetime,
+ u8 pmk_reauth_threshold)
{
WPA_ASSERT(sm->ctx->add_pmkid);
return sm->ctx->add_pmkid(sm->ctx->ctx, network_ctx, bssid, pmkid,
- cache_id, pmk, pmk_len);
+ cache_id, pmk, pmk_len, pmk_lifetime,
+ pmk_reauth_threshold);
}
static inline int wpa_sm_remove_pmkid(struct wpa_sm *sm, void *network_ctx,
@@ -408,6 +429,12 @@
return sm->ctx->channel_info(sm->ctx->ctx, ci);
}
+static inline void wpa_sm_transition_disable(struct wpa_sm *sm, u8 bitmap)
+{
+ if (sm->ctx->transition_disable)
+ sm->ctx->transition_disable(sm->ctx->ctx, bitmap);
+}
+
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 ae9f4ca..9068781 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -105,6 +105,23 @@
}
+u16 rsn_supp_capab(struct wpa_sm *sm)
+{
+ u16 capab = 0;
+
+ if (sm->mfp)
+ capab |= WPA_CAPABILITY_MFPC;
+ if (sm->mfp == 2)
+ capab |= WPA_CAPABILITY_MFPR;
+ if (sm->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
+ if (sm->ext_key_id)
+ capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
+
+ return capab;
+}
+
+
static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
int pairwise_cipher, int group_cipher,
int key_mgmt, int mgmt_group_cipher,
@@ -112,7 +129,6 @@
{
u8 *pos;
struct rsn_ie_hdr *hdr;
- u16 capab;
u32 suite;
if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
@@ -168,12 +184,10 @@
} else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
} else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
} else if (key_mgmt == WPA_KEY_MGMT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
@@ -216,16 +230,7 @@
pos += RSN_SELECTOR_LEN;
/* RSN Capabilities */
- capab = 0;
-#ifdef CONFIG_IEEE80211W
- if (sm->mfp)
- capab |= WPA_CAPABILITY_MFPC;
- if (sm->mfp == 2)
- capab |= WPA_CAPABILITY_MFPR;
-#endif /* CONFIG_IEEE80211W */
- if (sm->ocv)
- capab |= WPA_CAPABILITY_OCVC;
- WPA_PUT_LE16(pos, capab);
+ WPA_PUT_LE16(pos, rsn_supp_capab(sm));
pos += 2;
if (sm->cur_pmksa) {
@@ -237,7 +242,6 @@
pos += PMKID_LEN;
}
-#ifdef CONFIG_IEEE80211W
if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) {
if (!sm->cur_pmksa) {
/* PMKID Count */
@@ -250,7 +254,6 @@
mgmt_group_cipher));
pos += RSN_SELECTOR_LEN;
}
-#endif /* CONFIG_IEEE80211W */
hdr->len = (pos - rsn_ie) - 2;
@@ -348,261 +351,23 @@
}
-/**
- * wpa_parse_vendor_specific - Parse Vendor Specific IEs
- * @pos: Pointer to the IE header
- * @end: Pointer to the end of the Key Data buffer
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, 1 if end mark is found, -1 on failure
- */
-static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end,
- struct wpa_eapol_ie_parse *ie)
+int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len)
{
- unsigned int oui;
+ u8 *pos = rsnxe;
- if (pos[1] < 4) {
- wpa_printf(MSG_MSGDUMP, "Too short vendor specific IE ignored (len=%u)",
- pos[1]);
- return 1;
- }
+ if (!wpa_key_mgmt_sae(sm->key_mgmt))
+ return 0; /* SAE not in use */
+ if (sm->sae_pwe != 1 && sm->sae_pwe != 2)
+ return 0; /* no supported extended RSN capabilities */
- oui = WPA_GET_BE24(&pos[2]);
- if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) {
- if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) {
- ie->wmm = &pos[2];
- ie->wmm_len = pos[1];
- wpa_hexdump(MSG_DEBUG, "WPA: WMM IE",
- ie->wmm, ie->wmm_len);
- } else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) {
- ie->wmm = &pos[2];
- ie->wmm_len = pos[1];
- wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element",
- ie->wmm, ie->wmm_len);
- }
- }
- return 0;
-}
+ if (rsnxe_len < 3)
+ return -1;
+ *pos++ = WLAN_EID_RSNX;
+ *pos++ = 1;
+ /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
+ * used for now */
+ *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
-/**
- * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
- * @pos: Pointer to the IE header
- * @end: Pointer to the end of the Key Data buffer
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, 1 if end mark is found, -1 on failure
- */
-static int wpa_parse_generic(const u8 *pos, const u8 *end,
- struct wpa_eapol_ie_parse *ie)
-{
- if (pos[1] == 0)
- return 1;
-
- if (pos[1] >= 6 &&
- RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
- pos[2 + WPA_SELECTOR_LEN] == 1 &&
- pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
- ie->wpa_ie = pos;
- ie->wpa_ie_len = pos[1] + 2;
- wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
- ie->wpa_ie, ie->wpa_ie_len);
- return 0;
- }
-
- if (1 + RSN_SELECTOR_LEN < end - pos &&
- pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
- ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
- ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
- ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
- ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-
-#ifdef CONFIG_IEEE80211W
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
- ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-#endif /* CONFIG_IEEE80211W */
-
-#ifdef CONFIG_P2P
- if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
- ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
- ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
- return 0;
- }
-
- if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
- ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG,
- "WPA: IP Address Allocation in EAPOL-Key",
- ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
- return 0;
- }
-#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;
-}
-
-
-/**
- * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs
- * @buf: Pointer to the Key Data buffer
- * @len: Key Data Length
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, -1 on failure
- */
-int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
- struct wpa_eapol_ie_parse *ie)
-{
- const u8 *pos, *end;
- int ret = 0;
-
- os_memset(ie, 0, sizeof(*ie));
- for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) {
- if (pos[0] == 0xdd &&
- ((pos == buf + len - 1) || pos[1] == 0)) {
- /* Ignore padding */
- break;
- }
- if (2 + pos[1] > end - pos) {
- wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
- "underflow (ie=%d len=%d pos=%d)",
- pos[0], pos[1], (int) (pos - buf));
- wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
- buf, len);
- ret = -1;
- break;
- }
- if (*pos == WLAN_EID_RSN) {
- ie->rsn_ie = pos;
- ie->rsn_ie_len = pos[1] + 2;
- wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
- ie->rsn_ie, ie->rsn_ie_len);
- } else if (*pos == WLAN_EID_MOBILITY_DOMAIN &&
- pos[1] >= sizeof(struct rsn_mdie)) {
- ie->mdie = pos;
- ie->mdie_len = pos[1] + 2;
- wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
- ie->mdie, ie->mdie_len);
- } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION &&
- pos[1] >= sizeof(struct rsn_ftie)) {
- ie->ftie = pos;
- ie->ftie_len = pos[1] + 2;
- wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
- ie->ftie, ie->ftie_len);
- } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
- if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) {
- ie->reassoc_deadline = pos;
- wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
- "in EAPOL-Key",
- ie->reassoc_deadline, pos[1] + 2);
- } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
- ie->key_lifetime = pos;
- wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
- "in EAPOL-Key",
- ie->key_lifetime, pos[1] + 2);
- } else {
- wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
- "EAPOL-Key Key Data IE",
- pos, 2 + pos[1]);
- }
- } else if (*pos == WLAN_EID_LINK_ID) {
- if (pos[1] >= 18) {
- ie->lnkid = pos;
- ie->lnkid_len = pos[1] + 2;
- }
- } else if (*pos == WLAN_EID_EXT_CAPAB) {
- ie->ext_capab = pos;
- ie->ext_capab_len = pos[1] + 2;
- } else if (*pos == WLAN_EID_SUPP_RATES) {
- ie->supp_rates = pos;
- ie->supp_rates_len = pos[1] + 2;
- } else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
- ie->ext_supp_rates = pos;
- ie->ext_supp_rates_len = pos[1] + 2;
- } else if (*pos == WLAN_EID_HT_CAP &&
- pos[1] >= sizeof(struct ieee80211_ht_capabilities)) {
- ie->ht_capabilities = pos + 2;
- } else if (*pos == WLAN_EID_VHT_AID) {
- if (pos[1] >= 2)
- ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff;
- } else if (*pos == WLAN_EID_VHT_CAP &&
- pos[1] >= sizeof(struct ieee80211_vht_capabilities))
- {
- ie->vht_capabilities = pos + 2;
- } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
- ie->qosinfo = pos[2];
- } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
- ie->supp_channels = pos + 2;
- ie->supp_channels_len = pos[1];
- } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) {
- /*
- * The value of the Length field of the Supported
- * Operating Classes element is between 2 and 253.
- * Silently skip invalid elements to avoid interop
- * issues when trying to use the value.
- */
- if (pos[1] >= 2 && pos[1] <= 253) {
- ie->supp_oper_classes = pos + 2;
- ie->supp_oper_classes_len = pos[1];
- }
- } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
- ret = wpa_parse_generic(pos, end, ie);
- if (ret < 0)
- break;
- if (ret > 0) {
- ret = 0;
- break;
- }
-
- ret = wpa_parse_vendor_specific(pos, end, ie);
- if (ret < 0)
- break;
- if (ret > 0) {
- ret = 0;
- break;
- }
- } else {
- wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
- "Key Data IE", pos, 2 + pos[1]);
- }
- }
-
- return ret;
+ return pos - rsnxe;
}
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index 9d53973..83a6727 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -11,56 +11,8 @@
struct wpa_sm;
-struct wpa_eapol_ie_parse {
- const u8 *wpa_ie;
- size_t wpa_ie_len;
- const u8 *rsn_ie;
- size_t rsn_ie_len;
- const u8 *pmkid;
- const u8 *gtk;
- size_t gtk_len;
- const u8 *mac_addr;
- size_t mac_addr_len;
-#ifdef CONFIG_IEEE80211W
- const u8 *igtk;
- size_t igtk_len;
-#endif /* CONFIG_IEEE80211W */
- const u8 *mdie;
- size_t mdie_len;
- const u8 *ftie;
- size_t ftie_len;
- const u8 *reassoc_deadline;
- const u8 *key_lifetime;
- const u8 *lnkid;
- size_t lnkid_len;
- const u8 *ext_capab;
- size_t ext_capab_len;
- const u8 *supp_rates;
- size_t supp_rates_len;
- const u8 *ext_supp_rates;
- size_t ext_supp_rates_len;
- const u8 *ht_capabilities;
- const u8 *vht_capabilities;
- const u8 *supp_channels;
- size_t supp_channels_len;
- const u8 *supp_oper_classes;
- size_t supp_oper_classes_len;
- u8 qosinfo;
- u16 aid;
- const u8 *wmm;
- size_t wmm_len;
-#ifdef CONFIG_P2P
- 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,
- struct wpa_eapol_ie_parse *ie);
int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len);
+int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len);
+u16 rsn_supp_capab(struct wpa_sm *sm);
#endif /* WPA_IE_H */
diff --git a/src/tls/asn1.c b/src/tls/asn1.c
index 822f87c..2da7b4a 100644
--- a/src/tls/asn1.c
+++ b/src/tls/asn1.c
@@ -9,18 +9,129 @@
#include "includes.h"
#include "common.h"
+#include "utils/wpabuf.h"
#include "asn1.h"
-struct asn1_oid asn1_sha1_oid = {
+const struct asn1_oid asn1_sha1_oid = {
.oid = { 1, 3, 14, 3, 2, 26 },
.len = 6
};
-struct asn1_oid asn1_sha256_oid = {
+const struct asn1_oid asn1_sha256_oid = {
.oid = { 2, 16, 840, 1, 101, 3, 4, 2, 1 },
.len = 9
};
+const struct asn1_oid asn1_ec_public_key_oid = {
+ .oid = { 1, 2, 840, 10045, 2, 1 },
+ .len = 6
+};
+
+const struct asn1_oid asn1_prime256v1_oid = {
+ .oid = { 1, 2, 840, 10045, 3, 1, 7 },
+ .len = 7
+};
+
+const struct asn1_oid asn1_secp384r1_oid = {
+ .oid = { 1, 3, 132, 0, 34 },
+ .len = 5
+};
+
+const struct asn1_oid asn1_secp521r1_oid = {
+ .oid = { 1, 3, 132, 0, 35 },
+ .len = 5
+};
+
+const struct asn1_oid asn1_brainpoolP256r1_oid = {
+ .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 7 },
+ .len = 10
+};
+
+const struct asn1_oid asn1_brainpoolP384r1_oid = {
+ .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 11 },
+ .len = 10
+};
+
+const struct asn1_oid asn1_brainpoolP512r1_oid = {
+ .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 13 },
+ .len = 10
+};
+
+const struct asn1_oid asn1_aes_siv_cmac_aead_256_oid = {
+ .oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 22 },
+ .len = 9
+};
+
+const struct asn1_oid asn1_aes_siv_cmac_aead_384_oid = {
+ .oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 23 },
+ .len = 9
+};
+
+const struct asn1_oid asn1_aes_siv_cmac_aead_512_oid = {
+ .oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 24 },
+ .len = 9
+};
+
+const struct asn1_oid asn1_pbkdf2_oid = {
+ .oid = { 1, 2, 840, 113549, 1, 5, 12 },
+ .len = 7
+};
+
+const struct asn1_oid asn1_pbkdf2_hmac_sha256_oid = {
+ .oid = { 1, 2, 840, 113549, 2, 9 },
+ .len = 6
+};
+
+const struct asn1_oid asn1_pbkdf2_hmac_sha384_oid = {
+ .oid = { 1, 2, 840, 113549, 2, 10 },
+ .len = 6
+};
+
+const struct asn1_oid asn1_pbkdf2_hmac_sha512_oid = {
+ .oid = { 1, 2, 840, 113549, 2, 11 },
+ .len = 6
+};
+
+const struct asn1_oid asn1_dpp_config_params_oid = {
+ .oid = { 1, 3, 6, 1, 4, 1, 40808, 1, 2, 1 },
+ .len = 10
+};
+
+const struct asn1_oid asn1_dpp_asymmetric_key_package_oid = {
+ .oid = { 1, 3, 6, 1, 4, 1, 40808, 1, 2, 2 },
+ .len = 10
+};
+
+
+static int asn1_valid_der_boolean(struct asn1_hdr *hdr)
+{
+ /* Enforce DER requirements for a single way of encoding a BOOLEAN */
+ if (hdr->length != 1) {
+ wpa_printf(MSG_DEBUG, "ASN.1: Unexpected BOOLEAN length (%u)",
+ hdr->length);
+ return 0;
+ }
+
+ if (hdr->payload[0] != 0 && hdr->payload[0] != 0xff) {
+ wpa_printf(MSG_DEBUG,
+ "ASN.1: Invalid BOOLEAN value 0x%x (DER requires 0 or 0xff)",
+ hdr->payload[0]);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int asn1_valid_der(struct asn1_hdr *hdr)
+{
+ if (hdr->class != ASN1_CLASS_UNIVERSAL)
+ return 1;
+ if (hdr->tag == ASN1_TAG_BOOLEAN && !asn1_valid_der_boolean(hdr))
+ return 0;
+ return 1;
+}
+
int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
{
@@ -91,7 +202,8 @@
}
hdr->payload = pos;
- return 0;
+
+ return asn1_valid_der(hdr) ? 0 : -1;
}
@@ -239,3 +351,231 @@
return 1;
}
+
+
+int asn1_get_integer(const u8 *buf, size_t len, int *integer, const u8 **next)
+{
+ struct asn1_hdr hdr;
+ size_t left;
+ const u8 *pos;
+ int value;
+
+ if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0)
+ return -1;
+
+ if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
+ wpa_printf(MSG_DEBUG,
+ "ASN.1: Expected INTEGER - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ *next = hdr.payload + hdr.length;
+ pos = hdr.payload;
+ left = hdr.length;
+ if (left > sizeof(value)) {
+ wpa_printf(MSG_DEBUG, "ASN.1: Too large INTEGER (len %u)",
+ hdr.length);
+ return -1;
+ }
+ value = 0;
+ while (left) {
+ value <<= 8;
+ value |= *pos++;
+ left--;
+ }
+
+ *integer = value;
+ return 0;
+}
+
+
+int asn1_get_sequence(const u8 *buf, size_t len, struct asn1_hdr *hdr,
+ const u8 **next)
+{
+ if (asn1_get_next(buf, len, hdr) < 0 ||
+ hdr->class != ASN1_CLASS_UNIVERSAL ||
+ hdr->tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "ASN.1: Expected SEQUENCE - found class %d tag 0x%x",
+ hdr->class, hdr->tag);
+ return -1;
+ }
+
+ if (next)
+ *next = hdr->payload + hdr->length;
+ return 0;
+}
+
+
+int asn1_get_alg_id(const u8 *buf, size_t len, struct asn1_oid *oid,
+ const u8 **params, size_t *params_len, const u8 **next)
+{
+ const u8 *pos = buf, *end = buf + len;
+ struct asn1_hdr hdr;
+
+ /*
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL}
+ */
+ if (asn1_get_sequence(pos, end - pos, &hdr, next) < 0 ||
+ asn1_get_oid(hdr.payload, hdr.length, oid, &pos) < 0)
+ return -1;
+
+ if (params && params_len) {
+ *params = pos;
+ *params_len = hdr.payload + hdr.length - pos;
+ }
+
+ return 0;
+}
+
+
+void asn1_put_integer(struct wpabuf *buf, int val)
+{
+ u8 bin[4];
+ int zeros;
+
+ WPA_PUT_BE32(bin, val);
+ zeros = 0;
+ while (zeros < 3 && bin[zeros] == 0)
+ zeros++;
+ wpabuf_put_u8(buf, ASN1_TAG_INTEGER);
+ wpabuf_put_u8(buf, 4 - zeros);
+ wpabuf_put_data(buf, &bin[zeros], 4 - zeros);
+}
+
+
+static void asn1_put_len(struct wpabuf *buf, size_t len)
+{
+ if (len <= 0x7f) {
+ wpabuf_put_u8(buf, len);
+ } else if (len <= 0xff) {
+ wpabuf_put_u8(buf, 0x80 | 1);
+ wpabuf_put_u8(buf, len);
+ } else if (len <= 0xffff) {
+ wpabuf_put_u8(buf, 0x80 | 2);
+ wpabuf_put_be16(buf, len);
+ } else if (len <= 0xffffff) {
+ wpabuf_put_u8(buf, 0x80 | 3);
+ wpabuf_put_be24(buf, len);
+ } else {
+ wpabuf_put_u8(buf, 0x80 | 4);
+ wpabuf_put_be32(buf, len);
+ }
+}
+
+
+void asn1_put_octet_string(struct wpabuf *buf, const struct wpabuf *val)
+{
+ wpabuf_put_u8(buf, ASN1_TAG_OCTETSTRING);
+ asn1_put_len(buf, wpabuf_len(val));
+ wpabuf_put_buf(buf, val);
+}
+
+
+void asn1_put_oid(struct wpabuf *buf, const struct asn1_oid *oid)
+{
+ u8 *len;
+ size_t i;
+
+ if (oid->len < 2)
+ return;
+ wpabuf_put_u8(buf, ASN1_TAG_OID);
+ len = wpabuf_put(buf, 1);
+ wpabuf_put_u8(buf, 40 * oid->oid[0] + oid->oid[1]);
+ for (i = 2; i < oid->len; i++) {
+ unsigned long val = oid->oid[i];
+ u8 bytes[8];
+ int idx = 0;
+
+ while (val) {
+ bytes[idx] = (idx ? 0x80 : 0x00) | (val & 0x7f);
+ idx++;
+ val >>= 7;
+ }
+ if (idx == 0) {
+ bytes[idx] = 0;
+ idx = 1;
+ }
+ while (idx > 0) {
+ idx--;
+ wpabuf_put_u8(buf, bytes[idx]);
+ }
+ }
+ *len = (u8 *) wpabuf_put(buf, 0) - len - 1;
+}
+
+
+void asn1_put_hdr(struct wpabuf *buf, u8 class, int constructed, u8 tag,
+ size_t len)
+{
+ wpabuf_put_u8(buf, class << 6 | (constructed ? 0x20 : 0x00) | tag);
+ asn1_put_len(buf, len);
+}
+
+
+void asn1_put_sequence(struct wpabuf *buf, const struct wpabuf *payload)
+{
+ asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SEQUENCE,
+ wpabuf_len(payload));
+ wpabuf_put_buf(buf, payload);
+}
+
+
+void asn1_put_set(struct wpabuf *buf, const struct wpabuf *payload)
+{
+ asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SET,
+ wpabuf_len(payload));
+ wpabuf_put_buf(buf, payload);
+}
+
+
+void asn1_put_utf8string(struct wpabuf *buf, const char *val)
+{
+ asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 0, ASN1_TAG_UTF8STRING,
+ os_strlen(val));
+ wpabuf_put_str(buf, val);
+}
+
+
+struct wpabuf * asn1_build_alg_id(const struct asn1_oid *oid,
+ const struct wpabuf *params)
+{
+ struct wpabuf *buf;
+ size_t len;
+
+ /*
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL}
+ */
+
+ len = 100;
+ if (params)
+ len += wpabuf_len(params);
+ buf = wpabuf_alloc(len);
+ if (!buf)
+ return NULL;
+ asn1_put_oid(buf, oid);
+ if (params)
+ wpabuf_put_buf(buf, params);
+ return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+struct wpabuf * asn1_encaps(struct wpabuf *buf, u8 class, u8 tag)
+{
+ struct wpabuf *res;
+
+ if (!buf)
+ return NULL;
+ res = wpabuf_alloc(10 + wpabuf_len(buf));
+ if (res) {
+ asn1_put_hdr(res, class, 1, tag, wpabuf_len(buf));
+ wpabuf_put_buf(res, buf);
+ }
+ wpabuf_clear_free(buf);
+ return res;
+}
diff --git a/src/tls/asn1.h b/src/tls/asn1.h
index 6bd7df5..6878a4f 100644
--- a/src/tls/asn1.h
+++ b/src/tls/asn1.h
@@ -65,8 +65,43 @@
void asn1_oid_to_str(const struct asn1_oid *oid, char *buf, size_t len);
unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len);
int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b);
+int asn1_get_integer(const u8 *buf, size_t len, int *integer, const u8 **next);
+int asn1_get_sequence(const u8 *buf, size_t len, struct asn1_hdr *hdr,
+ const u8 **next);
+int asn1_get_alg_id(const u8 *buf, size_t len, struct asn1_oid *oid,
+ const u8 **params, size_t *params_len, const u8 **next);
+void asn1_put_integer(struct wpabuf *buf, int val);
+void asn1_put_octet_string(struct wpabuf *buf, const struct wpabuf *val);
+void asn1_put_oid(struct wpabuf *buf, const struct asn1_oid *oid);
+void asn1_put_hdr(struct wpabuf *buf, u8 class, int constructed, u8 tag,
+ size_t len);
+void asn1_put_sequence(struct wpabuf *buf, const struct wpabuf *payload);
+void asn1_put_set(struct wpabuf *buf, const struct wpabuf *payload);
+void asn1_put_utf8string(struct wpabuf *buf, const char *val);
+struct wpabuf * asn1_build_alg_id(const struct asn1_oid *oid,
+ const struct wpabuf *params);
+struct wpabuf * asn1_encaps(struct wpabuf *buf, u8 class, u8 tag);
-extern struct asn1_oid asn1_sha1_oid;
-extern struct asn1_oid asn1_sha256_oid;
+extern const struct asn1_oid asn1_sha1_oid;
+extern const struct asn1_oid asn1_sha256_oid;
+extern const struct asn1_oid asn1_ec_public_key_oid;
+extern const struct asn1_oid asn1_prime256v1_oid;
+extern const struct asn1_oid asn1_secp384r1_oid;
+extern const struct asn1_oid asn1_secp521r1_oid;
+extern const struct asn1_oid asn1_brainpoolP256r1_oid;
+extern const struct asn1_oid asn1_brainpoolP384r1_oid;
+extern const struct asn1_oid asn1_brainpoolP512r1_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_256_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_384_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_512_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_256_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_384_oid;
+extern const struct asn1_oid asn1_aes_siv_cmac_aead_512_oid;
+extern const struct asn1_oid asn1_pbkdf2_oid;
+extern const struct asn1_oid asn1_pbkdf2_hmac_sha256_oid;
+extern const struct asn1_oid asn1_pbkdf2_hmac_sha384_oid;
+extern const struct asn1_oid asn1_pbkdf2_hmac_sha512_oid;
+extern const struct asn1_oid asn1_dpp_config_params_oid;
+extern const struct asn1_oid asn1_dpp_asymmetric_key_package_oid;
#endif /* ASN1_H */
diff --git a/src/tls/libtommath.c b/src/tls/libtommath.c
index 4f7a148..7156744 100644
--- a/src/tls/libtommath.c
+++ b/src/tls/libtommath.c
@@ -2441,6 +2441,7 @@
/* clear the carry */
_W = 0;
+ os_memset(W, 0, sizeof(W));
for (ix = 0; ix < pa; ix++) {
int tx, ty;
int iy;
diff --git a/src/tls/pkcs1.c b/src/tls/pkcs1.c
index 141ac50..654c01b 100644
--- a/src/tls/pkcs1.c
+++ b/src/tls/pkcs1.c
@@ -157,6 +157,7 @@
plain[0] != 0x00 || plain[1] != 0x01) {
wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
"structure");
+ wpa_hexdump_key(MSG_DEBUG, "Signature EB", plain, len);
return -1;
}
@@ -165,6 +166,7 @@
if (plain[2] != 0xff) {
wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
"PS (BT=01)");
+ wpa_hexdump_key(MSG_DEBUG, "Signature EB", plain, len);
return -1;
}
while (pos < plain + len && *pos == 0xff)
@@ -174,12 +176,14 @@
/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
"padding");
+ wpa_hexdump_key(MSG_DEBUG, "Signature EB", plain, len);
return -1;
}
if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
"structure (2)");
+ wpa_hexdump_key(MSG_DEBUG, "Signature EB", plain, len);
return -1;
}
pos++;
diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c
index 80874e5..3825a73 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -312,6 +312,14 @@
x509_name_string(&cert->subject, subject, sizeof(subject));
ev.peer_cert.subject = subject;
+ if (cert->extensions_present & X509_EXT_CERTIFICATE_POLICY) {
+ if (cert->certificate_policy & X509_EXT_CERT_POLICY_TOD_STRICT)
+ ev.peer_cert.tod = 1;
+ else if (cert->certificate_policy &
+ X509_EXT_CERT_POLICY_TOD_TOFU)
+ ev.peer_cert.tod = 2;
+ }
+
conn->event_cb(conn->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
wpabuf_free(cert_buf);
}
@@ -532,7 +540,7 @@
}
} else if (conn->cred && conn->cred->cert_probe) {
wpa_printf(MSG_DEBUG,
- "TLSv1: Reject server certificate on probe-only rune");
+ "TLSv1: Reject server certificate on probe-only run");
if (conn->event_cb) {
union tls_event_data ev;
char buf[128];
diff --git a/src/tls/tlsv1_cred.c b/src/tls/tlsv1_cred.c
index 842e5dd..01b2f83 100644
--- a/src/tls/tlsv1_cred.c
+++ b/src/tls/tlsv1_cred.c
@@ -130,7 +130,7 @@
return -1;
}
- der = base64_decode(pos, end - pos, &der_len);
+ der = base64_decode((const char *) pos, end - pos, &der_len);
if (der == NULL) {
wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
"certificate");
@@ -293,7 +293,7 @@
}
}
- der = base64_decode(pos, end - pos, &der_len);
+ der = base64_decode((const char *) pos, end - pos, &der_len);
if (!der)
return NULL;
pkey = crypto_private_key_import(der, der_len, NULL);
@@ -321,7 +321,7 @@
if (!end)
return NULL;
- der = base64_decode(pos, end - pos, &der_len);
+ der = base64_decode((const char *) pos, end - pos, &der_len);
if (!der)
return NULL;
pkey = crypto_private_key_import(der, der_len, passwd);
@@ -1225,7 +1225,7 @@
return -1;
}
- der = base64_decode(pos, end - pos, &der_len);
+ der = base64_decode((const char *) pos, end - pos, &der_len);
if (der == NULL) {
wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
return -1;
diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c
index fa4d442..d2e685c 100644
--- a/src/tls/x509v3.c
+++ b/src/tls/x509v3.c
@@ -264,7 +264,8 @@
return -1;
pos = hdr.payload;
if (*pos) {
- wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits",
+ wpa_printf(MSG_DEBUG,
+ "X509: BITSTRING (subjectPublicKey) - %d unused bits",
*pos);
/*
* TODO: should this be rejected? X.509 certificates are
@@ -538,9 +539,43 @@
}
+static int parse_uint2(const char *pos, size_t len)
+{
+ char buf[3];
+ int ret;
+
+ if (len < 2)
+ return -1;
+ buf[0] = pos[0];
+ buf[1] = pos[1];
+ buf[2] = 0x00;
+ if (sscanf(buf, "%2d", &ret) != 1)
+ return -1;
+ return ret;
+}
+
+
+static int parse_uint4(const char *pos, size_t len)
+{
+ char buf[5];
+ int ret;
+
+ if (len < 4)
+ return -1;
+ buf[0] = pos[0];
+ buf[1] = pos[1];
+ buf[2] = pos[2];
+ buf[3] = pos[3];
+ buf[4] = 0x00;
+ if (sscanf(buf, "%4d", &ret) != 1)
+ return -1;
+ return ret;
+}
+
+
int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag, os_time_t *val)
{
- const char *pos;
+ const char *pos, *end;
int year, month, day, hour, min, sec;
/*
@@ -554,6 +589,7 @@
*/
pos = (const char *) buf;
+ end = pos + len;
switch (asn1_tag) {
case ASN1_TAG_UTCTIME:
@@ -562,7 +598,8 @@
"UTCTime format", buf, len);
return -1;
}
- if (sscanf(pos, "%02d", &year) != 1) {
+ year = parse_uint2(pos, end - pos);
+ if (year < 0) {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse "
"UTCTime year", buf, len);
return -1;
@@ -579,7 +616,8 @@
"GeneralizedTime format", buf, len);
return -1;
}
- if (sscanf(pos, "%04d", &year) != 1) {
+ year = parse_uint4(pos, end - pos);
+ if (year < 0) {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse "
"GeneralizedTime year", buf, len);
return -1;
@@ -592,35 +630,40 @@
return -1;
}
- if (sscanf(pos, "%02d", &month) != 1) {
+ month = parse_uint2(pos, end - pos);
+ if (month < 0) {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
"(month)", buf, len);
return -1;
}
pos += 2;
- if (sscanf(pos, "%02d", &day) != 1) {
+ day = parse_uint2(pos, end - pos);
+ if (day < 0) {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
"(day)", buf, len);
return -1;
}
pos += 2;
- if (sscanf(pos, "%02d", &hour) != 1) {
+ hour = parse_uint2(pos, end - pos);
+ if (hour < 0) {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
"(hour)", buf, len);
return -1;
}
pos += 2;
- if (sscanf(pos, "%02d", &min) != 1) {
+ min = parse_uint2(pos, end - pos);
+ if (min < 0) {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
"(min)", buf, len);
return -1;
}
pos += 2;
- if (sscanf(pos, "%02d", &sec) != 1) {
+ sec = parse_uint2(pos, end - pos);
+ if (sec < 0) {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
"(sec)", buf, len);
return -1;
@@ -773,6 +816,7 @@
struct asn1_hdr hdr;
unsigned long value;
size_t left;
+ const u8 *end_seq;
/*
* BasicConstraints ::= SEQUENCE {
@@ -794,6 +838,7 @@
if (hdr.length == 0)
return 0;
+ end_seq = hdr.payload + hdr.length;
if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL) {
wpa_printf(MSG_DEBUG, "X509: Failed to parse "
@@ -802,22 +847,16 @@
}
if (hdr.tag == ASN1_TAG_BOOLEAN) {
- if (hdr.length != 1) {
- wpa_printf(MSG_DEBUG, "X509: Unexpected "
- "Boolean length (%u) in BasicConstraints",
- hdr.length);
- return -1;
- }
cert->ca = hdr.payload[0];
- if (hdr.length == pos + len - hdr.payload) {
+ pos = hdr.payload + hdr.length;
+ if (pos >= end_seq) {
+ /* No optional pathLenConstraint */
wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d",
cert->ca);
return 0;
}
-
- if (asn1_get_next(hdr.payload + hdr.length, len - hdr.length,
- &hdr) < 0 ||
+ if (asn1_get_next(pos, end_seq - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL) {
wpa_printf(MSG_DEBUG, "X509: Failed to parse "
"BasicConstraints");
@@ -1082,6 +1121,133 @@
}
+static int x509_id_cert_policy_any_oid(struct asn1_oid *oid)
+{
+ return oid->len == 5 &&
+ oid->oid[0] == 2 /* iso/itu-t */ &&
+ oid->oid[1] == 5 /* X.500 Directory Services */ &&
+ oid->oid[2] == 29 /* id-ce */ &&
+ oid->oid[3] == 32 /* id-ce-certificate-policies */ &&
+ oid->oid[4] == 0 /* anyPolicy */;
+}
+
+
+static int x509_id_wfa_oid(struct asn1_oid *oid)
+{
+ return oid->len >= 7 &&
+ oid->oid[0] == 1 /* iso */ &&
+ oid->oid[1] == 3 /* identified-organization */ &&
+ oid->oid[2] == 6 /* dod */ &&
+ oid->oid[3] == 1 /* internet */ &&
+ oid->oid[4] == 4 /* private */ &&
+ oid->oid[5] == 1 /* enterprise */ &&
+ oid->oid[6] == 40808 /* WFA */;
+}
+
+
+static int x509_id_wfa_tod_oid(struct asn1_oid *oid)
+{
+ return oid->len >= 9 &&
+ x509_id_wfa_oid(oid) &&
+ oid->oid[7] == 1 &&
+ oid->oid[8] == 3;
+}
+
+
+static int x509_id_wfa_tod_strict_oid(struct asn1_oid *oid)
+{
+ return oid->len == 10 &&
+ x509_id_wfa_tod_oid(oid) &&
+ oid->oid[9] == 1;
+}
+
+
+static int x509_id_wfa_tod_tofu_oid(struct asn1_oid *oid)
+{
+ return oid->len == 10 &&
+ x509_id_wfa_tod_oid(oid) &&
+ oid->oid[9] == 2;
+}
+
+
+static int x509_parse_ext_certificate_policies(struct x509_certificate *cert,
+ const u8 *pos, size_t len)
+{
+ struct asn1_hdr hdr;
+ const u8 *end;
+
+ /*
+ * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
+ *
+ * PolicyInformation ::= SEQUENCE {
+ * policyIdentifier CertPolicyId,
+ * policyQualifiers SEQUENCE SIZE (1..MAX) OF
+ * PolicyQualifierInfo OPTIONAL }
+ *
+ * CertPolicyId ::= OBJECT IDENTIFIER
+ */
+
+ if (asn1_get_next(pos, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE (certificatePolicies) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ if (hdr.length > pos + len - hdr.payload)
+ return -1;
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ wpa_hexdump(MSG_MSGDUMP, "X509: certificatePolicies", pos, end - pos);
+
+ while (pos < end) {
+ const u8 *pol_end;
+ struct asn1_oid oid;
+ char buf[80];
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE (PolicyInformation) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ if (hdr.length > end - hdr.payload)
+ return -1;
+ pos = hdr.payload;
+ pol_end = pos + hdr.length;
+ wpa_hexdump(MSG_MSGDUMP, "X509: PolicyInformation",
+ pos, pol_end - pos);
+
+ if (asn1_get_oid(pos, pol_end - pos, &oid, &pos))
+ return -1;
+ if (x509_id_cert_policy_any_oid(&oid)) {
+ os_strlcpy(buf, "anyPolicy-STRICT", sizeof(buf));
+ cert->certificate_policy |=
+ X509_EXT_CERT_POLICY_ANY;
+ } else if (x509_id_wfa_tod_strict_oid(&oid)) {
+ os_strlcpy(buf, "TOD-STRICT", sizeof(buf));
+ cert->certificate_policy |=
+ X509_EXT_CERT_POLICY_TOD_STRICT;
+ } else if (x509_id_wfa_tod_tofu_oid(&oid)) {
+ os_strlcpy(buf, "TOD-TOFU", sizeof(buf));
+ cert->certificate_policy |=
+ X509_EXT_CERT_POLICY_TOD_TOFU;
+ } else {
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ }
+ wpa_printf(MSG_DEBUG, "policyIdentifier: %s", buf);
+
+ pos = pol_end;
+ }
+
+ cert->extensions_present |= X509_EXT_CERTIFICATE_POLICY;
+
+ return 0;
+}
+
+
static int x509_id_pkix_oid(struct asn1_oid *oid)
{
return oid->len >= 7 &&
@@ -1196,7 +1362,6 @@
return 1;
/* TODO: add other extensions required by RFC 3280, Ch 4.2:
- * certificate policies (section 4.2.1.5)
* name constraints (section 4.2.1.11)
* policy constraints (section 4.2.1.12)
* inhibit any-policy (section 4.2.1.15)
@@ -1210,6 +1375,8 @@
return x509_parse_ext_issuer_alt_name(cert, pos, len);
case 19: /* id-ce-basicConstraints */
return x509_parse_ext_basic_constraints(cert, pos, len);
+ case 32: /* id-ce-certificatePolicies */
+ return x509_parse_ext_certificate_policies(cert, pos, len);
case 37: /* id-ce-extKeyUsage */
return x509_parse_ext_ext_key_usage(cert, pos, len);
default:
@@ -1263,11 +1430,6 @@
}
if (hdr.tag == ASN1_TAG_BOOLEAN) {
- if (hdr.length != 1) {
- wpa_printf(MSG_DEBUG, "X509: Unexpected "
- "Boolean length (%u)", hdr.length);
- return -1;
- }
critical_ext = hdr.payload[0];
pos = hdr.payload;
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
@@ -1690,7 +1852,8 @@
}
pos = hdr.payload;
if (*pos) {
- wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits",
+ wpa_printf(MSG_DEBUG,
+ "X509: BITSTRING (signatureValue) - %d unused bits",
*pos);
/* PKCS #1 v1.5 10.2.1:
* It is an error if the length in bits of the signature S is
diff --git a/src/tls/x509v3.h b/src/tls/x509v3.h
index 7df8e2a..e3b108f 100644
--- a/src/tls/x509v3.h
+++ b/src/tls/x509v3.h
@@ -74,6 +74,7 @@
#define X509_EXT_SUBJECT_ALT_NAME (1 << 3)
#define X509_EXT_ISSUER_ALT_NAME (1 << 4)
#define X509_EXT_EXT_KEY_USAGE (1 << 5)
+#define X509_EXT_CERTIFICATE_POLICY (1 << 6)
/* BasicConstraints */
int ca; /* cA */
@@ -98,6 +99,12 @@
#define X509_EXT_KEY_USAGE_CLIENT_AUTH (1 << 2)
#define X509_EXT_KEY_USAGE_OCSP (1 << 3)
+ /* CertificatePolicy */
+ unsigned long certificate_policy;
+#define X509_EXT_CERT_POLICY_ANY (1 << 0)
+#define X509_EXT_CERT_POLICY_TOD_STRICT (1 << 1)
+#define X509_EXT_CERT_POLICY_TOD_TOFU (1 << 2)
+
/*
* The DER format certificate follows struct x509_certificate. These
* pointers point to that buffer.
diff --git a/src/utils/base64.c b/src/utils/base64.c
index 53a92f4..a17d2d3 100644
--- a/src/utils/base64.c
+++ b/src/utils/base64.c
@@ -12,18 +12,16 @@
#include "os.h"
#include "base64.h"
-static const unsigned char base64_table[65] =
+static const char base64_table[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-static const unsigned char base64_url_table[65] =
+static const char base64_url_table[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
-static unsigned char * base64_gen_encode(const unsigned char *src, size_t len,
- size_t *out_len,
- const unsigned char *table,
- int add_pad)
+static char * base64_gen_encode(const unsigned char *src, size_t len,
+ size_t *out_len, const char *table, int add_pad)
{
- unsigned char *out, *pos;
+ char *out, *pos;
const unsigned char *end, *in;
size_t olen;
int line_len;
@@ -83,9 +81,8 @@
}
-static unsigned char * base64_gen_decode(const unsigned char *src, size_t len,
- size_t *out_len,
- const unsigned char *table)
+static unsigned char * base64_gen_decode(const char *src, size_t len,
+ size_t *out_len, const char *table)
{
unsigned char dtable[256], *out, *pos, block[4], tmp;
size_t i, count, olen;
@@ -94,12 +91,12 @@
os_memset(dtable, 0x80, 256);
for (i = 0; i < sizeof(base64_table) - 1; i++)
- dtable[table[i]] = (unsigned char) i;
+ dtable[(unsigned char) table[i]] = (unsigned char) i;
dtable['='] = 0;
count = 0;
for (i = 0; i < len; i++) {
- if (dtable[src[i]] != 0x80)
+ if (dtable[(unsigned char) src[i]] != 0x80)
count++;
}
@@ -165,17 +162,15 @@
* nul terminated to make it easier to use as a C string. The nul terminator is
* not included in out_len.
*/
-unsigned char * base64_encode(const unsigned char *src, size_t len,
- size_t *out_len)
+char * base64_encode(const void *src, size_t len, size_t *out_len)
{
return base64_gen_encode(src, len, out_len, base64_table, 1);
}
-unsigned char * base64_url_encode(const unsigned char *src, size_t len,
- size_t *out_len, int add_pad)
+char * base64_url_encode(const void *src, size_t len, size_t *out_len)
{
- return base64_gen_encode(src, len, out_len, base64_url_table, add_pad);
+ return base64_gen_encode(src, len, out_len, base64_url_table, 0);
}
@@ -189,15 +184,13 @@
*
* Caller is responsible for freeing the returned buffer.
*/
-unsigned char * base64_decode(const unsigned char *src, size_t len,
- size_t *out_len)
+unsigned char * base64_decode(const char *src, size_t len, size_t *out_len)
{
return base64_gen_decode(src, len, out_len, base64_table);
}
-unsigned char * base64_url_decode(const unsigned char *src, size_t len,
- size_t *out_len)
+unsigned char * base64_url_decode(const char *src, size_t len, size_t *out_len)
{
return base64_gen_decode(src, len, out_len, base64_url_table);
}
diff --git a/src/utils/base64.h b/src/utils/base64.h
index 5a72c3e..6216f44 100644
--- a/src/utils/base64.h
+++ b/src/utils/base64.h
@@ -9,13 +9,9 @@
#ifndef BASE64_H
#define BASE64_H
-unsigned char * base64_encode(const unsigned char *src, size_t len,
- size_t *out_len);
-unsigned char * base64_decode(const unsigned char *src, size_t len,
- size_t *out_len);
-unsigned char * base64_url_encode(const unsigned char *src, size_t len,
- size_t *out_len, int add_pad);
-unsigned char * base64_url_decode(const unsigned char *src, size_t len,
- size_t *out_len);
+char * base64_encode(const void *src, size_t len, size_t *out_len);
+unsigned char * base64_decode(const char *src, size_t len, size_t *out_len);
+char * base64_url_encode(const void *src, size_t len, size_t *out_len);
+unsigned char * base64_url_decode(const char *src, size_t len, size_t *out_len);
#endif /* BASE64_H */
diff --git a/src/utils/browser-android.c b/src/utils/browser-android.c
index 71a1652..26c83d6 100644
--- a/src/utils/browser-android.c
+++ b/src/utils/browser-android.c
@@ -62,7 +62,7 @@
}
-int hs20_web_browser(const char *url)
+int hs20_web_browser(const char *url, int ignore_tls)
{
struct http_server *http;
struct in_addr addr;
diff --git a/src/utils/browser-system.c b/src/utils/browser-system.c
index aed3970..d87d97b 100644
--- a/src/utils/browser-system.c
+++ b/src/utils/browser-system.c
@@ -62,7 +62,7 @@
}
-int hs20_web_browser(const char *url)
+int hs20_web_browser(const char *url, int ignore_tls)
{
struct http_server *http;
struct in_addr addr;
diff --git a/src/utils/browser-wpadebug.c b/src/utils/browser-wpadebug.c
index dfb4b67..d32a85b 100644
--- a/src/utils/browser-wpadebug.c
+++ b/src/utils/browser-wpadebug.c
@@ -63,7 +63,7 @@
}
-int hs20_web_browser(const char *url)
+int hs20_web_browser(const char *url, int ignore_tls)
{
struct http_server *http;
struct in_addr addr;
diff --git a/src/utils/browser.c b/src/utils/browser.c
index ad0b382..c0f4380 100644
--- a/src/utils/browser.c
+++ b/src/utils/browser.c
@@ -7,7 +7,11 @@
*/
#include "includes.h"
+#ifdef USE_WEBKIT2
+#include <webkit2/webkit2.h>
+#else /* USE_WEBKIT2 */
#include <webkit/webkit.h>
+#endif /* USE_WEBKIT2 */
#include "common.h"
#include "browser.h"
@@ -15,16 +19,20 @@
struct browser_context {
GtkWidget *win;
+ WebKitWebView *view;
int success;
int progress;
char *hover_link;
char *title;
+ int gtk_main_started;
+ int quit_gtk_main;
};
static void win_cb_destroy(GtkWidget *win, struct browser_context *ctx)
{
wpa_printf(MSG_DEBUG, "BROWSER:%s", __func__);
- gtk_main_quit();
+ if (ctx->gtk_main_started)
+ gtk_main_quit();
}
@@ -50,6 +58,142 @@
}
+static void process_request_starting_uri(struct browser_context *ctx,
+ const char *uri)
+{
+ int quit = 0;
+
+ if (g_str_has_prefix(uri, "osu://")) {
+ ctx->success = atoi(uri + 6);
+ quit = 1;
+ } else if (g_str_has_prefix(uri, "http://localhost:12345")) {
+ /*
+ * This is used as a special trigger to indicate that the
+ * user exchange has been completed.
+ */
+ ctx->success = 1;
+ quit = 1;
+ }
+
+ if (quit) {
+ if (ctx->gtk_main_started) {
+ gtk_main_quit();
+ ctx->gtk_main_started = 0;
+ } else {
+ ctx->quit_gtk_main = 1;
+ }
+ }
+}
+
+
+#ifdef USE_WEBKIT2
+
+static void view_cb_notify_estimated_load_progress(WebKitWebView *view,
+ GParamSpec *pspec,
+ struct browser_context *ctx)
+{
+ ctx->progress = 100 * webkit_web_view_get_estimated_load_progress(view);
+ wpa_printf(MSG_DEBUG, "BROWSER:%s progress=%d", __func__,
+ ctx->progress);
+ browser_update_title(ctx);
+}
+
+
+static void view_cb_resource_load_starting(WebKitWebView *view,
+ WebKitWebResource *res,
+ WebKitURIRequest *req,
+ struct browser_context *ctx)
+{
+ const gchar *uri = webkit_uri_request_get_uri(req);
+
+ wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri);
+ process_request_starting_uri(ctx, uri);
+}
+
+
+static gboolean view_cb_decide_policy(WebKitWebView *view,
+ WebKitPolicyDecision *policy,
+ WebKitPolicyDecisionType type,
+ struct browser_context *ctx)
+{
+ wpa_printf(MSG_DEBUG, "BROWSER:%s type=%d", __func__, type);
+ switch (type) {
+ case WEBKIT_POLICY_DECISION_TYPE_RESPONSE: {
+ /* This function makes webkit send a download signal for all
+ * unknown mime types. */
+ WebKitResponsePolicyDecision *response;
+
+ response = WEBKIT_RESPONSE_POLICY_DECISION(policy);
+ if (!webkit_response_policy_decision_is_mime_type_supported(
+ response)) {
+ webkit_policy_decision_download(policy);
+ return TRUE;
+ }
+ break;
+ }
+ case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION: {
+ WebKitNavigationPolicyDecision *d;
+ WebKitNavigationAction *a;
+ WebKitURIRequest *req;
+ const gchar *uri;
+
+ d = WEBKIT_NAVIGATION_POLICY_DECISION(policy);
+ a = webkit_navigation_policy_decision_get_navigation_action(d);
+ req = webkit_navigation_action_get_request(a);
+ uri = webkit_uri_request_get_uri(req);
+ wpa_printf(MSG_DEBUG, "BROWSER:%s navigation action: uri=%s",
+ __func__, uri);
+ process_request_starting_uri(ctx, uri);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+
+static void view_cb_mouse_target_changed(WebKitWebView *view,
+ WebKitHitTestResult *h,
+ guint modifiers,
+ struct browser_context *ctx)
+{
+ WebKitHitTestResultContext hc = webkit_hit_test_result_get_context(h);
+ const char *uri = NULL;
+
+ if (hc & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK)
+ uri = webkit_hit_test_result_get_link_uri(h);
+ else if (hc & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE)
+ uri = webkit_hit_test_result_get_image_uri(h);
+ else if (hc & WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA)
+ uri = webkit_hit_test_result_get_media_uri(h);
+
+ wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri ? uri : "N/A");
+ os_free(ctx->hover_link);
+ if (uri)
+ ctx->hover_link = os_strdup(uri);
+ else
+ ctx->hover_link = NULL;
+
+ browser_update_title(ctx);
+}
+
+
+static void view_cb_notify_title(WebKitWebView *view, GParamSpec *ps,
+ struct browser_context *ctx)
+{
+ const char *title;
+
+ title = webkit_web_view_get_title(ctx->view);
+ wpa_printf(MSG_DEBUG, "BROWSER:%s title=%s", __func__, title);
+ os_free(ctx->title);
+ ctx->title = os_strdup(title);
+ browser_update_title(ctx);
+}
+
+#else /* USE_WEBKIT2 */
+
static void view_cb_notify_progress(WebKitWebView *view, GParamSpec *pspec,
struct browser_context *ctx)
{
@@ -66,6 +210,10 @@
int status = webkit_web_view_get_load_status(view);
wpa_printf(MSG_DEBUG, "BROWSER:%s load-status=%d uri=%s",
__func__, status, webkit_web_view_get_uri(view));
+ if (ctx->quit_gtk_main) {
+ gtk_main_quit();
+ ctx->gtk_main_started = 0;
+ }
}
@@ -77,21 +225,12 @@
struct browser_context *ctx)
{
const gchar *uri = webkit_network_request_get_uri(req);
+
wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri);
if (g_str_has_suffix(uri, "/favicon.ico"))
webkit_network_request_set_uri(req, "about:blank");
- if (g_str_has_prefix(uri, "osu://")) {
- ctx->success = atoi(uri + 6);
- gtk_main_quit();
- }
- if (g_str_has_prefix(uri, "http://localhost:12345")) {
- /*
- * This is used as a special trigger to indicate that the
- * user exchange has been completed.
- */
- ctx->success = 1;
- gtk_main_quit();
- }
+
+ process_request_starting_uri(ctx, uri);
}
@@ -147,23 +286,32 @@
browser_update_title(ctx);
}
+#endif /* USE_WEBKIT2 */
-int hs20_web_browser(const char *url)
+
+int hs20_web_browser(const char *url, int ignore_tls)
{
GtkWidget *scroll;
- SoupSession *s;
WebKitWebView *view;
+#ifdef USE_WEBKIT2
+ WebKitSettings *settings;
+#else /* USE_WEBKIT2 */
WebKitWebSettings *settings;
+ SoupSession *s;
+#endif /* USE_WEBKIT2 */
struct browser_context ctx;
memset(&ctx, 0, sizeof(ctx));
if (!gtk_init_check(NULL, NULL))
return -1;
+#ifndef USE_WEBKIT2
s = webkit_get_default_session();
g_object_set(G_OBJECT(s), "ssl-ca-file",
"/etc/ssl/certs/ca-certificates.crt", NULL);
- g_object_set(G_OBJECT(s), "ssl-strict", FALSE, NULL);
+ if (ignore_tls)
+ g_object_set(G_OBJECT(s), "ssl-strict", FALSE, NULL);
+#endif /* USE_WEBKIT2 */
ctx.win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_role(GTK_WINDOW(ctx.win), "Hotspot 2.0 client");
@@ -177,10 +325,24 @@
G_CALLBACK(win_cb_destroy), &ctx);
view = WEBKIT_WEB_VIEW(webkit_web_view_new());
- g_signal_connect(G_OBJECT(view), "notify::progress",
- G_CALLBACK(view_cb_notify_progress), &ctx);
+ ctx.view = view;
+#ifdef USE_WEBKIT2
+ g_signal_connect(G_OBJECT(view), "notify::estimated-load-progress",
+ G_CALLBACK(view_cb_notify_estimated_load_progress),
+ &ctx);
+ g_signal_connect(G_OBJECT(view), "resource-load-started",
+ G_CALLBACK(view_cb_resource_load_starting), &ctx);
+ g_signal_connect(G_OBJECT(view), "decide-policy",
+ G_CALLBACK(view_cb_decide_policy), &ctx);
+ g_signal_connect(G_OBJECT(view), "mouse-target-changed",
+ G_CALLBACK(view_cb_mouse_target_changed), &ctx);
+ g_signal_connect(G_OBJECT(view), "notify::title",
+ G_CALLBACK(view_cb_notify_title), &ctx);
+#else /* USE_WEBKIT2 */
g_signal_connect(G_OBJECT(view), "notify::load-status",
G_CALLBACK(view_cb_notify_load_status), &ctx);
+ g_signal_connect(G_OBJECT(view), "notify::progress",
+ G_CALLBACK(view_cb_notify_progress), &ctx);
g_signal_connect(G_OBJECT(view), "resource-request-starting",
G_CALLBACK(view_cb_resource_request_starting), &ctx);
g_signal_connect(G_OBJECT(view), "mime-type-policy-decision-requested",
@@ -191,6 +353,7 @@
G_CALLBACK(view_cb_hovering_over_link), &ctx);
g_signal_connect(G_OBJECT(view), "title-changed",
G_CALLBACK(view_cb_title_changed), &ctx);
+#endif /* USE_WEBKIT2 */
gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(view));
gtk_container_add(GTK_CONTAINER(ctx.win), GTK_WIDGET(scroll));
@@ -205,8 +368,19 @@
"hs20-client/1.0", NULL);
g_object_set(G_OBJECT(settings), "auto-load-images", TRUE, NULL);
+#ifdef USE_WEBKIT2
+ if (ignore_tls) {
+ WebKitWebContext *wkctx;
+
+ wkctx = webkit_web_context_get_default();
+ webkit_web_context_set_tls_errors_policy(
+ wkctx, WEBKIT_TLS_ERRORS_POLICY_IGNORE);
+ }
+#endif /* USE_WEBKIT2 */
+
webkit_web_view_load_uri(view, url);
+ ctx.gtk_main_started = 1;
gtk_main();
gtk_widget_destroy(ctx.win);
while (gtk_events_pending())
diff --git a/src/utils/browser.h b/src/utils/browser.h
index aaa0eed..3af13b9 100644
--- a/src/utils/browser.h
+++ b/src/utils/browser.h
@@ -10,12 +10,12 @@
#define BROWSER_H
#ifdef CONFIG_NO_BROWSER
-static inline int hs20_web_browser(const char *url)
+static inline int hs20_web_browser(const char *url, int ignore_tls)
{
return -1;
}
#else /* CONFIG_NO_BROWSER */
-int hs20_web_browser(const char *url);
+int hs20_web_browser(const char *url, int ignore_tls);
#endif /* CONFIG_NO_BROWSER */
#endif /* BROWSER_H */
diff --git a/src/utils/common.c b/src/utils/common.c
index b9c8bfd..2c12751 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -7,6 +7,7 @@
*/
#include "includes.h"
+#include <limits.h>
#include "common/ieee802_11_defs.h"
#include "common.h"
@@ -230,6 +231,16 @@
}
+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;
+}
+
+
void wpa_get_ntp_timestamp(u8 *buf)
{
struct os_time now;
@@ -780,6 +791,10 @@
*/
pos = value;
while (pos && pos[0]) {
+ if (count == UINT_MAX) {
+ os_free(freq);
+ return -1;
+ }
n = os_realloc_array(freq, count + 1,
sizeof(struct wpa_freq_range));
if (n == NULL) {
@@ -864,9 +879,10 @@
}
-int int_array_len(const int *a)
+size_t int_array_len(const int *a)
{
- int i;
+ size_t i;
+
for (i = 0; a && a[i]; i++)
;
return i;
@@ -875,12 +891,21 @@
void int_array_concat(int **res, const int *a)
{
- int reslen, alen, i;
+ size_t reslen, alen, i, max_size;
int *n;
reslen = int_array_len(*res);
alen = int_array_len(a);
-
+ max_size = (size_t) -1;
+ if (alen >= max_size - reslen) {
+ /* This should not really happen, but if it did, something
+ * would overflow. Do not try to merge the arrays; instead, make
+ * this behave like memory allocation failure to avoid messing
+ * up memory. */
+ os_free(*res);
+ *res = NULL;
+ return;
+ }
n = os_realloc_array(*res, reslen + alen + 1, sizeof(int));
if (n == NULL) {
os_free(*res);
@@ -908,8 +933,7 @@
void int_array_sort_unique(int *a)
{
- int alen;
- int i, j;
+ size_t alen, i, j;
if (a == NULL)
return;
@@ -934,7 +958,7 @@
void int_array_add_unique(int **res, int a)
{
- int reslen;
+ size_t reslen, max_size;
int *n;
for (reslen = 0; *res && (*res)[reslen]; reslen++) {
@@ -942,6 +966,16 @@
return; /* already in the list */
}
+ max_size = (size_t) -1;
+ if (reslen > max_size - 2) {
+ /* This should not really happen in practice, but if it did,
+ * something would overflow. Do not try to add the new value;
+ * instead, make this behave like memory allocation failure to
+ * avoid messing up memory. */
+ os_free(*res);
+ *res = NULL;
+ return;
+ }
n = os_realloc_array(*res, reslen + 2, sizeof(int));
if (n == NULL) {
os_free(*res);
@@ -960,7 +994,7 @@
{
if (str) {
size_t len = os_strlen(str);
- os_memset(str, 0, len);
+ forced_memzero(str, len);
os_free(str);
}
}
@@ -969,7 +1003,7 @@
void bin_clear_free(void *bin, size_t len)
{
if (bin) {
- os_memset(bin, 0, len);
+ forced_memzero(bin, len);
os_free(bin);
}
}
@@ -1249,3 +1283,22 @@
val[len] = '\0';
return val;
}
+
+
+/* Try to prevent most compilers from optimizing out clearing of memory that
+ * becomes unaccessible after this function is called. This is mostly the case
+ * for clearing local stack variables at the end of a function. This is not
+ * exactly perfect, i.e., someone could come up with a compiler that figures out
+ * the pointer is pointing to memset and then end up optimizing the call out, so
+ * try go a bit further by storing the first octet (now zero) to make this even
+ * a bit more difficult to optimize out. Once memset_s() is available, that
+ * could be used here instead. */
+static void * (* const volatile memset_func)(void *, int, size_t) = memset;
+static u8 forced_memzero_val;
+
+void forced_memzero(void *ptr, size_t len)
+{
+ memset_func(ptr, 0, len);
+ if (len)
+ forced_memzero_val = ((u8 *) ptr)[0];
+}
diff --git a/src/utils/common.h b/src/utils/common.h
index 792a30a..8e5cfe1 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -344,6 +344,9 @@
#ifndef ETH_P_OUI
#define ETH_P_OUI 0x88B7
#endif /* ETH_P_OUI */
+#ifndef ETH_P_8021Q
+#define ETH_P_8021Q 0x8100
+#endif /* ETH_P_8021Q */
#ifdef __GNUC__
@@ -477,6 +480,7 @@
int hex2byte(const char *hex);
int hexstr2bin(const char *hex, u8 *buf, size_t len);
void inc_byte_array(u8 *counter, size_t len);
+void buf_shift_right(u8 *buf, size_t len, size_t bits);
void wpa_get_ntp_timestamp(u8 *buf);
int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...);
int wpa_snprintf_hex_sep(char *buf, size_t buf_size, const u8 *data, size_t len,
@@ -543,7 +547,7 @@
unsigned int freq);
char * freq_range_list_str(const struct wpa_freq_range_list *list);
-int int_array_len(const int *a);
+size_t int_array_len(const int *a);
void int_array_concat(int **res, const int *a);
void int_array_sort_unique(int *a);
void int_array_add_unique(int **res, int a);
@@ -569,6 +573,8 @@
u8 rssi_to_rcpi(int rssi);
char * get_param(const char *cmd, const char *param);
+void forced_memzero(void *ptr, size_t len);
+
/*
* gcc 4.4 ends up generating strict-aliasing warnings about some very common
* networking socket uses that do not really result in a real problem and
diff --git a/src/utils/crc32.c b/src/utils/crc32.c
new file mode 100644
index 0000000..12d9e2a
--- /dev/null
+++ b/src/utils/crc32.c
@@ -0,0 +1,85 @@
+/*
+ * 32-bit CRC for FCS calculation
+ * Copyright (c) 2010, 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/crc32.h"
+
+/*
+ * IEEE 802.11 FCS CRC32
+ * G(x) = x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 +
+ * x^5 + x^4 + x^2 + x + 1
+ */
+static const u32 crc32_table[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+ 0x2d02ef8d
+};
+
+
+u32 crc32(const u8 *frame, size_t frame_len)
+{
+ size_t i;
+ u32 crc;
+
+ crc = 0xFFFFFFFF;
+ for (i = 0; i < frame_len; i++)
+ crc = crc32_table[(crc ^ frame[i]) & 0xff] ^ (crc >> 8);
+
+ return ~crc;
+}
diff --git a/src/utils/eloop.c b/src/utils/eloop.c
index bb375be..b353ab0 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -68,7 +68,7 @@
};
struct eloop_sock_table {
- int count;
+ size_t count;
struct eloop_sock *table;
eloop_event_type type;
int changed;
@@ -77,10 +77,10 @@
struct eloop_data {
int max_sock;
- int count; /* sum of all table counts */
+ size_t count; /* sum of all table counts */
#ifdef CONFIG_ELOOP_POLL
- int max_pollfd_map; /* number of pollfds_map currently allocated */
- int max_poll_fds; /* number of pollfds currently allocated */
+ size_t max_pollfd_map; /* number of pollfds_map currently allocated */
+ size_t max_poll_fds; /* number of pollfds currently allocated */
struct pollfd *pollfds;
struct pollfd **pollfds_map;
#endif /* CONFIG_ELOOP_POLL */
@@ -90,12 +90,12 @@
#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
#ifdef CONFIG_ELOOP_EPOLL
int epollfd;
- int epoll_max_event_num;
+ size_t epoll_max_event_num;
struct epoll_event *epoll_events;
#endif /* CONFIG_ELOOP_EPOLL */
#ifdef CONFIG_ELOOP_KQUEUE
int kqueuefd;
- int kqueue_nevents;
+ size_t kqueue_nevents;
struct kevent *kqueue_events;
#endif /* CONFIG_ELOOP_KQUEUE */
struct eloop_sock_table readers;
@@ -104,7 +104,7 @@
struct dl_list timeout;
- int signal_count;
+ size_t signal_count;
struct eloop_signal *signals;
int signaled;
int pending_terminate;
@@ -125,7 +125,8 @@
static void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
{
- int i;
+ size_t i;
+
if (table == NULL || table->table == NULL)
return;
for (i = 0; i < table->count; i++) {
@@ -139,7 +140,8 @@
static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
{
- int i;
+ size_t i;
+
if (table == NULL || table->table == NULL)
return;
for (i = 0; i < table->count; i++) {
@@ -266,7 +268,7 @@
#endif /* CONFIG_ELOOP_EPOLL */
#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
struct eloop_sock *temp_table;
- int next;
+ size_t next;
#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
struct eloop_sock *tmp;
int new_max_sock;
@@ -280,7 +282,7 @@
return -1;
#ifdef CONFIG_ELOOP_POLL
- if (new_max_sock >= eloop.max_pollfd_map) {
+ if ((size_t) new_max_sock >= eloop.max_pollfd_map) {
struct pollfd **nmap;
nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50,
sizeof(struct pollfd *));
@@ -293,7 +295,8 @@
if (eloop.count + 1 > eloop.max_poll_fds) {
struct pollfd *n;
- int nmax = eloop.count + 1 + 50;
+ size_t nmax = eloop.count + 1 + 50;
+
n = os_realloc_array(eloop.pollfds, nmax,
sizeof(struct pollfd));
if (n == NULL)
@@ -385,7 +388,7 @@
#ifdef CONFIG_ELOOP_KQUEUE
struct kevent ke;
#endif /* CONFIG_ELOOP_KQUEUE */
- int i;
+ size_t i;
if (table == NULL || table->table == NULL || table->count == 0)
return;
@@ -444,7 +447,7 @@
struct pollfd **pollfds_map,
int max_pollfd_map)
{
- int i;
+ size_t i;
int nxt = 0;
int fd;
struct pollfd *pfd;
@@ -519,7 +522,7 @@
int max_pollfd_map,
short int revents)
{
- int i;
+ size_t i;
struct pollfd *pfd;
if (!table || !table->table)
@@ -572,7 +575,7 @@
static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
fd_set *fds)
{
- int i;
+ size_t i;
FD_ZERO(fds);
@@ -589,7 +592,7 @@
static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
fd_set *fds)
{
- int i;
+ size_t i;
if (table == NULL || table->table == NULL)
return;
@@ -653,7 +656,8 @@
static int eloop_sock_table_requeue(struct eloop_sock_table *table)
{
- int i, r;
+ size_t i;
+ int r;
r = 0;
for (i = 0; i < table->count && table->table; i++) {
@@ -694,7 +698,8 @@
static void eloop_sock_table_destroy(struct eloop_sock_table *table)
{
if (table) {
- int i;
+ size_t i;
+
for (i = 0; i < table->count && table->table; i++) {
wpa_printf(MSG_INFO, "ELOOP: remaining socket: "
"sock=%d eloop_data=%p user_data=%p "
@@ -968,7 +973,7 @@
static void eloop_handle_signal(int sig)
{
- int i;
+ size_t i;
#ifndef CONFIG_NATIVE_WINDOWS
if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
@@ -992,7 +997,7 @@
static void eloop_process_pending_signals(void)
{
- int i;
+ size_t i;
if (eloop.signaled == 0)
return;
diff --git a/src/utils/eloop_win.c b/src/utils/eloop_win.c
index 9c8b12b..74eaa33 100644
--- a/src/utils/eloop_win.c
+++ b/src/utils/eloop_win.c
@@ -54,7 +54,7 @@
struct dl_list timeout;
- int signal_count;
+ size_t signal_count;
struct eloop_signal *signals;
int signaled;
int pending_terminate;
@@ -422,7 +422,7 @@
#if 0
static void eloop_handle_signal(int sig)
{
- int i;
+ size_t i;
eloop.signaled++;
for (i = 0; i < eloop.signal_count; i++) {
@@ -437,7 +437,7 @@
static void eloop_process_pending_signals(void)
{
- int i;
+ size_t i;
if (eloop.signaled == 0)
return;
@@ -517,7 +517,7 @@
eloop.term_signal.handler = handler;
eloop.term_signal.user_data = user_data;
-
+
return 0;
}
diff --git a/src/utils/http-utils.h b/src/utils/http-utils.h
index 8d4399a..d9fc925 100644
--- a/src/utils/http-utils.h
+++ b/src/utils/http-utils.h
@@ -28,11 +28,11 @@
struct http_cert {
char **dnsname;
- unsigned int num_dnsname;
+ size_t num_dnsname;
struct http_othername *othername;
- unsigned int num_othername;
+ size_t num_othername;
struct http_logo *logo;
- unsigned int num_logo;
+ size_t num_logo;
};
int soap_init_client(struct http_ctx *ctx, const char *address,
diff --git a/src/utils/includes.h b/src/utils/includes.h
index 75513fc..741fc9c 100644
--- a/src/utils/includes.h
+++ b/src/utils/includes.h
@@ -18,6 +18,7 @@
#include <stdlib.h>
#include <stddef.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
diff --git a/src/utils/json.c b/src/utils/json.c
index b644339..5a0edf2 100644
--- a/src/utils/json.c
+++ b/src/utils/json.c
@@ -51,7 +51,7 @@
*txt++ = data[i];
} else {
txt += os_snprintf(txt, end - txt, "\\u%04x",
- data[i]);
+ (unsigned char) data[i]);
}
break;
}
@@ -300,8 +300,10 @@
goto fail;
if (!curr_token) {
token = json_alloc_token(&tokens);
- if (!token)
+ if (!token) {
+ os_free(str);
goto fail;
+ }
token->type = JSON_STRING;
token->string = str;
token->state = JSON_COMPLETED;
@@ -514,8 +516,8 @@
token = json_get_member(json, name);
if (!token || token->type != JSON_STRING)
return NULL;
- buf = base64_url_decode((const unsigned char *) token->string,
- os_strlen(token->string), &buflen);
+ buf = base64_url_decode(token->string, os_strlen(token->string),
+ &buflen);
if (!buf)
return NULL;
ret = wpabuf_alloc_ext_data(buf, buflen);
@@ -574,3 +576,79 @@
buf[0] = '\0';
json_print_token(root, 1, buf, buflen);
}
+
+
+void json_add_int(struct wpabuf *json, const char *name, int val)
+{
+ wpabuf_printf(json, "\"%s\":%d", name, val);
+}
+
+
+void json_add_string(struct wpabuf *json, const char *name, const char *val)
+{
+ wpabuf_printf(json, "\"%s\":\"%s\"", name, val);
+}
+
+
+int json_add_string_escape(struct wpabuf *json, const char *name,
+ const void *val, size_t len)
+{
+ char *tmp;
+ size_t tmp_len = 6 * len + 1;
+
+ tmp = os_malloc(tmp_len);
+ if (!tmp)
+ return -1;
+ json_escape_string(tmp, tmp_len, val, len);
+ json_add_string(json, name, tmp);
+ bin_clear_free(tmp, tmp_len);
+ return 0;
+}
+
+
+int json_add_base64url(struct wpabuf *json, const char *name, const void *val,
+ size_t len)
+{
+ char *b64;
+
+ b64 = base64_url_encode(val, len, NULL);
+ if (!b64)
+ return -1;
+ json_add_string(json, name, b64);
+ os_free(b64);
+ return 0;
+}
+
+
+void json_start_object(struct wpabuf *json, const char *name)
+{
+ if (name)
+ wpabuf_printf(json, "\"%s\":", name);
+ wpabuf_put_u8(json, '{');
+}
+
+
+void json_end_object(struct wpabuf *json)
+{
+ wpabuf_put_u8(json, '}');
+}
+
+
+void json_start_array(struct wpabuf *json, const char *name)
+{
+ if (name)
+ wpabuf_printf(json, "\"%s\":", name);
+ wpabuf_put_u8(json, '[');
+}
+
+
+void json_end_array(struct wpabuf *json)
+{
+ wpabuf_put_u8(json, ']');
+}
+
+
+void json_value_sep(struct wpabuf *json)
+{
+ wpabuf_put_u8(json, ',');
+}
diff --git a/src/utils/json.h b/src/utils/json.h
index 8faa95d..ca4a2e4 100644
--- a/src/utils/json.h
+++ b/src/utils/json.h
@@ -38,5 +38,16 @@
struct wpabuf * json_get_member_base64url(struct json_token *json,
const char *name);
void json_print_tree(struct json_token *root, char *buf, size_t buflen);
+void json_add_int(struct wpabuf *json, const char *name, int val);
+void json_add_string(struct wpabuf *json, const char *name, const char *val);
+int json_add_string_escape(struct wpabuf *json, const char *name,
+ const void *val, size_t len);
+int json_add_base64url(struct wpabuf *json, const char *name, const void *val,
+ size_t len);
+void json_start_object(struct wpabuf *json, const char *name);
+void json_end_object(struct wpabuf *json);
+void json_start_array(struct wpabuf *json, const char *name);
+void json_end_array(struct wpabuf *json);
+void json_value_sep(struct wpabuf *json);
#endif /* JSON_H */
diff --git a/src/utils/os_internal.c b/src/utils/os_internal.c
index 474c8a3..feade6e 100644
--- a/src/utils/os_internal.c
+++ b/src/utils/os_internal.c
@@ -25,10 +25,16 @@
void os_sleep(os_time_t sec, os_time_t usec)
{
+#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
+ const struct timespec req = { sec, usec * 1000 };
+
+ nanosleep(&req, NULL);
+#else
if (sec)
sleep(sec);
if (usec)
usleep(usec);
+#endif
}
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index b56bab2..ae2f802 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -51,10 +51,16 @@
void os_sleep(os_time_t sec, os_time_t usec)
{
+#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
+ const struct timespec req = { sec, usec * 1000 };
+
+ nanosleep(&req, NULL);
+#else
if (sec)
sleep(sec);
if (usec)
usleep(usec);
+#endif
}
@@ -333,6 +339,8 @@
int os_program_init(void)
{
+ unsigned int seed;
+
#ifdef ANDROID
struct __user_cap_header_struct header;
struct __user_cap_data_struct cap;
@@ -385,6 +393,9 @@
capset(&header, &cap);
#endif /* ANDROID */
+ if (os_get_random((unsigned char *) &seed, sizeof(seed)) == 0)
+ srandom(seed);
+
return 0;
}
diff --git a/src/utils/state_machine.h b/src/utils/state_machine.h
index a514315..204c8a8 100644
--- a/src/utils/state_machine.h
+++ b/src/utils/state_machine.h
@@ -9,7 +9,7 @@
* implement a state machine. In addition to including this header file, each
* file implementing a state machine must define STATE_MACHINE_DATA to be the
* data structure including state variables (enum machine_state,
- * Boolean changed), and STATE_MACHINE_DEBUG_PREFIX to be a string that is used
+ * bool changed), and STATE_MACHINE_DEBUG_PREFIX to be a string that is used
* as a prefix for all debug messages. If SM_ENTRY_MA macro is used to define
* a group of state machines with shared data structure, STATE_MACHINE_ADDR
* needs to be defined to point to the MAC address used in debug output.
@@ -45,7 +45,7 @@
*/
#define SM_ENTRY(machine, state) \
if (!global || sm->machine ## _state != machine ## _ ## state) { \
- sm->changed = TRUE; \
+ sm->changed = true; \
wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " #machine \
" entering state " #state); \
} \
@@ -64,7 +64,7 @@
*/
#define SM_ENTRY_M(machine, _state, data) \
if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \
- sm->changed = TRUE; \
+ sm->changed = true; \
wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " \
#machine " entering state " #_state); \
} \
@@ -82,7 +82,7 @@
*/
#define SM_ENTRY_MA(machine, _state, data) \
if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \
- sm->changed = TRUE; \
+ sm->changed = true; \
wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " MACSTR " " \
#machine " entering state " #_state, \
MAC2STR(STATE_MACHINE_ADDR)); \
diff --git a/src/utils/trace.c b/src/utils/trace.c
index e0b5b0b..8f12da8 100644
--- a/src/utils/trace.c
+++ b/src/utils/trace.c
@@ -146,6 +146,17 @@
unsigned int line;
};
+/*
+ * binutils removed the bfd parameter and renamed things but
+ * those were macros so we can detect their absence.
+ * Cf. https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commitdiff;h=fd3619828e94a24a92cddec42cbc0ab33352eeb4;hp=5dfda3562a69686c43aad4fb0269cc9d5ec010d5
+ */
+#ifndef bfd_get_section_vma
+#define bfd_get_section_vma(bfd, section) bfd_section_vma(section)
+#endif
+#ifndef bfd_get_section_size
+#define bfd_get_section_size bfd_section_size
+#endif
static void find_addr_sect(bfd *abfd, asection *section, void *obj)
{
@@ -186,7 +197,7 @@
if (abfd == NULL)
return;
- data.pc = (bfd_hostptr_t) (pc - start_offset);
+ data.pc = (bfd_hostptr_t) ((u8 *) pc - start_offset);
data.found = FALSE;
bfd_map_over_sections(abfd, find_addr_sect, &data);
@@ -227,7 +238,7 @@
if (abfd == NULL)
return NULL;
- data.pc = (bfd_hostptr_t) (pc - start_offset);
+ data.pc = (bfd_hostptr_t) ((u8 *) pc - start_offset);
data.found = FALSE;
bfd_map_over_sections(abfd, find_addr_sect, &data);
@@ -299,7 +310,7 @@
for (i = 0; i < btrace_num; i++) {
struct bfd_data data;
- data.pc = (bfd_hostptr_t) (btrace_res[i] - start_offset);
+ data.pc = (bfd_hostptr_t) ((u8 *) btrace_res[i] - start_offset);
data.found = FALSE;
bfd_map_over_sections(abfd, find_addr_sect, &data);
diff --git a/src/utils/utils_module_tests.c b/src/utils/utils_module_tests.c
index 3af4fcd..365f21f 100644
--- a/src/utils/utils_module_tests.c
+++ b/src/utils/utils_module_tests.c
@@ -226,7 +226,7 @@
int test3[] = { 1, 1, 1, -1, 2, 3, 4, 1, 2, 0 };
int test3_res[] = { -1, 1, 2, 3, 4, 0 };
int errors = 0;
- int len;
+ size_t len;
wpa_printf(MSG_INFO, "int_array tests");
@@ -296,52 +296,53 @@
{
int errors = 0;
unsigned char *res;
+ char *res2;
size_t res_len;
wpa_printf(MSG_INFO, "base64 tests");
- res = base64_encode((const unsigned char *) "", ~0, &res_len);
+ res2 = base64_encode("", ~0, &res_len);
+ if (res2) {
+ errors++;
+ os_free(res2);
+ }
+
+ res2 = base64_encode("=", 1, &res_len);
+ if (!res2 || res_len != 5 || res2[0] != 'P' || res2[1] != 'Q' ||
+ res2[2] != '=' || res2[3] != '=' || res2[4] != '\n')
+ errors++;
+ os_free(res2);
+
+ res2 = base64_encode("=", 1, NULL);
+ if (!res2 || res2[0] != 'P' || res2[1] != 'Q' ||
+ res2[2] != '=' || res2[3] != '=' || res2[4] != '\n')
+ errors++;
+ os_free(res2);
+
+ res = base64_decode("", 0, &res_len);
if (res) {
errors++;
os_free(res);
}
- res = base64_encode((const unsigned char *) "=", 1, &res_len);
- if (!res || res_len != 5 || res[0] != 'P' || res[1] != 'Q' ||
- res[2] != '=' || res[3] != '=' || res[4] != '\n')
- errors++;
- os_free(res);
-
- res = base64_encode((const unsigned char *) "=", 1, NULL);
- if (!res || res[0] != 'P' || res[1] != 'Q' ||
- res[2] != '=' || res[3] != '=' || res[4] != '\n')
- errors++;
- os_free(res);
-
- res = base64_decode((const unsigned char *) "", 0, &res_len);
+ res = base64_decode("a", 1, &res_len);
if (res) {
errors++;
os_free(res);
}
- res = base64_decode((const unsigned char *) "a", 1, &res_len);
+ res = base64_decode("====", 4, &res_len);
if (res) {
errors++;
os_free(res);
}
- res = base64_decode((const unsigned char *) "====", 4, &res_len);
- if (res) {
- errors++;
- os_free(res);
- }
-
- res = base64_decode((const unsigned char *) "PQ==", 4, &res_len);
+ res = base64_decode("PQ==", 4, &res_len);
if (!res || res_len != 1 || res[0] != '=')
errors++;
os_free(res);
- res = base64_decode((const unsigned char *) "P.Q-=!=*", 8, &res_len);
+ res = base64_decode("P.Q-=!=*", 8, &res_len);
if (!res || res_len != 1 || res[0] != '=')
errors++;
os_free(res);
@@ -929,7 +930,7 @@
{ 0, 0 },
{ 1, 0 },
{ 2, 0 },
- { 1 << (sizeof(unsigned int) * 8 - 1), ~0 },
+ { 1U << (sizeof(unsigned int) * 8 - 1), ~0 },
{ ~0 - 1, ~0 },
{ ~0, ~0 }
};
@@ -940,7 +941,7 @@
{ 0, ~0 },
{ 1, 0 },
{ 2, 0 },
- { 1 << (sizeof(unsigned int) * 8 - 1), 0 },
+ { 1U << (sizeof(unsigned int) * 8 - 1), 0 },
{ ~0 - 1, 0 },
{ ~0, 0 }
};
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index c437000..a338a20 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -12,8 +12,6 @@
#ifdef CONFIG_DEBUG_SYSLOG
#include <syslog.h>
-
-int wpa_debug_syslog = 0;
#endif /* CONFIG_DEBUG_SYSLOG */
#ifdef CONFIG_DEBUG_LINUX_TRACING
@@ -32,6 +30,10 @@
int wpa_debug_level = MSG_INFO;
int wpa_debug_show_keys = 0;
int wpa_debug_timestamp = 0;
+int wpa_debug_syslog = 0;
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static FILE *out_file = NULL;
+#endif /* CONFIG_NO_STDOUT_DEBUG */
#ifdef CONFIG_ANDROID_LOG
@@ -61,8 +63,6 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
-
-static FILE *out_file = NULL;
#endif /* CONFIG_DEBUG_FILE */
@@ -76,12 +76,12 @@
os_get_time(&tv);
#ifdef CONFIG_DEBUG_FILE
- if (out_file) {
+ if (out_file)
fprintf(out_file, "%ld.%06u: ", (long) tv.sec,
(unsigned int) tv.usec);
- } else
#endif /* CONFIG_DEBUG_FILE */
- printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
+ if (!out_file && !wpa_debug_syslog)
+ printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
#endif /* CONFIG_ANDROID_LOG */
}
@@ -144,6 +144,7 @@
printf("failed to read /proc/mounts\n");
return -1;
}
+ buf[buflen] = '\0';
line = strtok_r(buf, "\n", &tmp1);
while (line) {
@@ -209,35 +210,37 @@
{
va_list ap;
- va_start(ap, fmt);
if (level >= wpa_debug_level) {
#ifdef CONFIG_ANDROID_LOG
+ va_start(ap, fmt);
__android_log_vprint(wpa_to_android_level(level),
ANDROID_LOG_NAME, fmt, ap);
+ va_end(ap);
#else /* CONFIG_ANDROID_LOG */
#ifdef CONFIG_DEBUG_SYSLOG
if (wpa_debug_syslog) {
+ va_start(ap, fmt);
vsyslog(syslog_priority(level), fmt, ap);
- } else {
+ va_end(ap);
+ }
#endif /* CONFIG_DEBUG_SYSLOG */
wpa_debug_print_timestamp();
#ifdef CONFIG_DEBUG_FILE
if (out_file) {
+ va_start(ap, fmt);
vfprintf(out_file, fmt, ap);
fprintf(out_file, "\n");
- } else {
-#endif /* CONFIG_DEBUG_FILE */
- vprintf(fmt, ap);
- printf("\n");
-#ifdef CONFIG_DEBUG_FILE
+ va_end(ap);
}
#endif /* CONFIG_DEBUG_FILE */
-#ifdef CONFIG_DEBUG_SYSLOG
+ if (!wpa_debug_syslog && !out_file) {
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ printf("\n");
+ va_end(ap);
}
-#endif /* CONFIG_DEBUG_SYSLOG */
#endif /* CONFIG_ANDROID_LOG */
}
- va_end(ap);
#ifdef CONFIG_DEBUG_LINUX_TRACING
if (wpa_debug_tracing_file != NULL) {
@@ -253,7 +256,7 @@
static void _wpa_hexdump(int level, const char *title, const u8 *buf,
- size_t len, int show)
+ size_t len, int show, int only_syslog)
{
size_t i;
@@ -344,7 +347,8 @@
syslog(syslog_priority(level), "%s - hexdump(len=%lu):%s",
title, (unsigned long) len, display);
bin_clear_free(strbuf, 1 + 3 * len);
- return;
+ if (only_syslog)
+ return;
}
#endif /* CONFIG_DEBUG_SYSLOG */
wpa_debug_print_timestamp();
@@ -361,33 +365,32 @@
fprintf(out_file, " [REMOVED]");
}
fprintf(out_file, "\n");
- } else {
-#endif /* CONFIG_DEBUG_FILE */
- printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
- if (buf == NULL) {
- printf(" [NULL]");
- } else if (show) {
- for (i = 0; i < len; i++)
- printf(" %02x", buf[i]);
- } else {
- printf(" [REMOVED]");
- }
- printf("\n");
-#ifdef CONFIG_DEBUG_FILE
}
#endif /* CONFIG_DEBUG_FILE */
+ if (!wpa_debug_syslog && !out_file) {
+ printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
+ if (buf == NULL) {
+ printf(" [NULL]");
+ } else if (show) {
+ for (i = 0; i < len; i++)
+ printf(" %02x", buf[i]);
+ } else {
+ printf(" [REMOVED]");
+ }
+ printf("\n");
+ }
#endif /* CONFIG_ANDROID_LOG */
}
void wpa_hexdump(int level, const char *title, const void *buf, size_t len)
{
- _wpa_hexdump(level, title, buf, len, 1);
+ _wpa_hexdump(level, title, buf, len, 1, 0);
}
void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len)
{
- _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys);
+ _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys, 0);
}
@@ -420,13 +423,11 @@
if (level < wpa_debug_level)
return;
#ifdef CONFIG_ANDROID_LOG
- _wpa_hexdump(level, title, buf, len, show);
+ _wpa_hexdump(level, title, buf, len, show, 0);
#else /* CONFIG_ANDROID_LOG */
#ifdef CONFIG_DEBUG_SYSLOG
- if (wpa_debug_syslog) {
- _wpa_hexdump(level, title, buf, len, show);
- return;
- }
+ if (wpa_debug_syslog)
+ _wpa_hexdump(level, title, buf, len, show, 1);
#endif /* CONFIG_DEBUG_SYSLOG */
wpa_debug_print_timestamp();
#ifdef CONFIG_DEBUG_FILE
@@ -435,13 +436,13 @@
fprintf(out_file,
"%s - hexdump_ascii(len=%lu): [REMOVED]\n",
title, (unsigned long) len);
- return;
+ goto file_done;
}
if (buf == NULL) {
fprintf(out_file,
"%s - hexdump_ascii(len=%lu): [NULL]\n",
title, (unsigned long) len);
- return;
+ goto file_done;
}
fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n",
title, (unsigned long) len);
@@ -465,42 +466,43 @@
pos += llen;
len -= llen;
}
- } else {
+ }
+file_done:
#endif /* CONFIG_DEBUG_FILE */
- if (!show) {
- printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
- title, (unsigned long) len);
- return;
- }
- if (buf == NULL) {
- printf("%s - hexdump_ascii(len=%lu): [NULL]\n",
- title, (unsigned long) len);
- return;
- }
- printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len);
- while (len) {
- llen = len > line_len ? line_len : len;
- printf(" ");
- for (i = 0; i < llen; i++)
- printf(" %02x", pos[i]);
- for (i = llen; i < line_len; i++)
- printf(" ");
- printf(" ");
- for (i = 0; i < llen; i++) {
- if (isprint(pos[i]))
- printf("%c", pos[i]);
- else
- printf("_");
+ if (!wpa_debug_syslog && !out_file) {
+ if (!show) {
+ printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
+ title, (unsigned long) len);
+ return;
}
- for (i = llen; i < line_len; i++)
- printf(" ");
- printf("\n");
- pos += llen;
- len -= llen;
+ if (buf == NULL) {
+ printf("%s - hexdump_ascii(len=%lu): [NULL]\n",
+ title, (unsigned long) len);
+ return;
+ }
+ printf("%s - hexdump_ascii(len=%lu):\n", title,
+ (unsigned long) len);
+ while (len) {
+ llen = len > line_len ? line_len : len;
+ printf(" ");
+ for (i = 0; i < llen; i++)
+ printf(" %02x", pos[i]);
+ for (i = llen; i < line_len; i++)
+ printf(" ");
+ printf(" ");
+ for (i = 0; i < llen; i++) {
+ if (isprint(pos[i]))
+ printf("%c", pos[i]);
+ else
+ printf("_");
+ }
+ for (i = llen; i < line_len; i++)
+ printf(" ");
+ printf("\n");
+ pos += llen;
+ len -= llen;
+ }
}
-#ifdef CONFIG_DEBUG_FILE
- }
-#endif /* CONFIG_DEBUG_FILE */
#endif /* CONFIG_ANDROID_LOG */
}
diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h
index 1fe0b7d..c6d5cc6 100644
--- a/src/utils/wpa_debug.h
+++ b/src/utils/wpa_debug.h
@@ -14,9 +14,7 @@
extern int wpa_debug_level;
extern int wpa_debug_show_keys;
extern int wpa_debug_timestamp;
-#ifdef CONFIG_DEBUG_SYSLOG
extern int wpa_debug_syslog;
-#endif /* CONFIG_DEBUG_SYSLOG */
/* Debugging function - conditional printf and hex dump. Driver wrappers can
* use these for debugging purposes. */
@@ -305,7 +303,6 @@
#define HOSTAPD_MODULE_RADIUS 0x00000004
#define HOSTAPD_MODULE_WPA 0x00000008
#define HOSTAPD_MODULE_DRIVER 0x00000010
-#define HOSTAPD_MODULE_IAPP 0x00000020
#define HOSTAPD_MODULE_MLME 0x00000040
enum hostapd_logger_level {
diff --git a/src/utils/xml_libxml2.c b/src/utils/xml_libxml2.c
index 7b6d276..d73654e 100644
--- a/src/utils/xml_libxml2.c
+++ b/src/utils/xml_libxml2.c
@@ -409,7 +409,7 @@
if (txt == NULL)
return NULL;
- ret = base64_decode((unsigned char *) txt, strlen(txt), &len);
+ ret = base64_decode(txt, strlen(txt), &len);
if (ret_len)
*ret_len = len;
xml_node_get_text_free(ctx, txt);
diff --git a/src/wps/upnp_xml.c b/src/wps/upnp_xml.c
index a9958ee..ca0925c 100644
--- a/src/wps/upnp_xml.c
+++ b/src/wps/upnp_xml.c
@@ -235,7 +235,7 @@
return NULL;
}
- decoded = base64_decode((unsigned char *) msg, os_strlen(msg), &len);
+ decoded = base64_decode(msg, os_strlen(msg), &len);
os_free(msg);
if (decoded == NULL) {
*ret = UPNP_OUT_OF_MEMORY;
diff --git a/src/wps/wps.h b/src/wps/wps.h
index 14ce863..93888b0 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -98,6 +98,7 @@
u16 config_methods;
struct wpabuf *vendor_ext_m1;
struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+ struct wpabuf *application_ext;
int p2p;
u8 multi_ap_ext;
@@ -344,6 +345,14 @@
const char *dev_name);
/**
+ * lookup_pskfile_cb - Callback for searching for PSK in wpa_psk_file
+ * @ctx: Higher layer context data (cb_ctx)
+ * @addr: Enrollee's MAC address
+ * @psk: Pointer to found PSK (output arg)
+ */
+ int (*lookup_pskfile_cb)(void *ctx, const u8 *mac_addr, const u8 **psk);
+
+ /**
* cb_ctx: Higher layer context data for Registrar callbacks
*/
void *cb_ctx;
@@ -386,11 +395,6 @@
int disable_auto_conf;
/**
- * static_wep_only - Whether the BSS supports only static WEP
- */
- int static_wep_only;
-
- /**
* dualband - Whether this is a concurrent dualband AP
*/
int dualband;
@@ -733,7 +737,7 @@
* uses this when acting as an Enrollee to notify Registrar of the
* current configuration.
*
- * When using WPA/WPA2-Person, this key can be either the ASCII
+ * When using WPA/WPA2-Personal, this key can be either the ASCII
* passphrase (8..63 characters) or the 32-octet PSK (64 hex
* characters). When this is set to the ASCII passphrase, the PSK can
* be provided in the psk buffer and used per-Enrollee to control which
diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c
index 4e872f3..f372256 100644
--- a/src/wps/wps_attr_build.c
+++ b/src/wps/wps_attr_build.c
@@ -175,7 +175,9 @@
len[0] = wpabuf_len(wps->last_msg);
addr[1] = wpabuf_head(msg);
len[1] = wpabuf_len(msg);
- hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
+ if (hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len,
+ hash) < 0)
+ return -1;
wpa_printf(MSG_DEBUG, "WPS: * Authenticator");
wpabuf_put_be16(msg, ATTR_AUTHENTICATOR);
@@ -308,6 +310,9 @@
auth_types &= ~WPS_AUTH_WPA;
auth_types &= ~WPS_AUTH_WPA2;
auth_types &= ~WPS_AUTH_SHARED;
+#ifdef CONFIG_NO_TKIP
+ auth_types &= ~WPS_AUTH_WPAPSK;
+#endif /* CONFIG_NO_TKIP */
#ifdef CONFIG_WPS_TESTING
if (wps_force_auth_types_in_use) {
wpa_printf(MSG_DEBUG,
@@ -329,6 +334,9 @@
{
u16 encr_types = WPS_ENCR_TYPES;
encr_types &= ~WPS_ENCR_WEP;
+#ifdef CONFIG_NO_TKIP
+ encr_types &= ~WPS_ENCR_TKIP;
+#endif /* CONFIG_NO_TKIP */
#ifdef CONFIG_WPS_TESTING
if (wps_force_encr_types_in_use) {
wpa_printf(MSG_DEBUG,
@@ -371,8 +379,9 @@
u8 hash[SHA256_MAC_LEN];
wpa_printf(MSG_DEBUG, "WPS: * Key Wrap Authenticator");
- hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg),
- wpabuf_len(msg), hash);
+ if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg),
+ wpabuf_len(msg), hash) < 0)
+ return -1;
wpabuf_put_be16(msg, ATTR_KEY_WRAP_AUTH);
wpabuf_put_be16(msg, WPS_KWA_LEN);
diff --git a/src/wps/wps_attr_process.c b/src/wps/wps_attr_process.c
index e8c4579..44436a4 100644
--- a/src/wps/wps_attr_process.c
+++ b/src/wps/wps_attr_process.c
@@ -39,9 +39,10 @@
len[0] = wpabuf_len(wps->last_msg);
addr[1] = wpabuf_head(msg);
len[1] = wpabuf_len(msg) - 4 - WPS_AUTHENTICATOR_LEN;
- hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
- if (os_memcmp_const(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) {
+ if (hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len,
+ hash) < 0 ||
+ os_memcmp_const(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator");
return -1;
}
@@ -70,8 +71,8 @@
return -1;
}
- hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash);
- if (os_memcmp_const(hash, key_wrap_auth, WPS_KWA_LEN) != 0) {
+ if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash) < 0 ||
+ os_memcmp_const(hash, key_wrap_auth, WPS_KWA_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Invalid KWA");
return -1;
}
diff --git a/src/wps/wps_dev_attr.c b/src/wps/wps_dev_attr.c
index b209fea..c2e949c 100644
--- a/src/wps/wps_dev_attr.c
+++ b/src/wps/wps_dev_attr.c
@@ -242,6 +242,21 @@
}
+int wps_build_application_ext(struct wps_device_data *dev, struct wpabuf *msg)
+{
+ if (!dev->application_ext)
+ return 0;
+
+ wpa_hexdump_buf(MSG_DEBUG, "WPS: * Application Extension",
+ dev->application_ext);
+ wpabuf_put_be16(msg, ATTR_APPLICATION_EXT);
+ wpabuf_put_be16(msg, wpabuf_len(dev->application_ext));
+ wpabuf_put_buf(msg, dev->application_ext);
+
+ return 0;
+}
+
+
static int wps_process_manufacturer(struct wps_device_data *dev, const u8 *str,
size_t str_len)
{
@@ -424,4 +439,6 @@
dev->model_number = NULL;
os_free(dev->serial_number);
dev->serial_number = NULL;
+ wpabuf_free(dev->application_ext);
+ dev->application_ext = NULL;
}
diff --git a/src/wps/wps_dev_attr.h b/src/wps/wps_dev_attr.h
index a4b4173..81fdd5f 100644
--- a/src/wps/wps_dev_attr.h
+++ b/src/wps/wps_dev_attr.h
@@ -33,6 +33,7 @@
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);
+int wps_build_application_ext(struct wps_device_data *dev, struct wpabuf *msg);
int wps_build_req_dev_type(struct wps_device_data *dev, struct wpabuf *msg,
unsigned int num_req_dev_types,
const u8 *req_dev_types);
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 80ed603..819cd43 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -880,6 +880,17 @@
cred.auth_type |= WPS_AUTH_WPA2PSK;
}
+#ifdef CONFIG_NO_TKIP
+ if (cred.encr_type & WPS_ENCR_TKIP) {
+ wpa_printf(MSG_DEBUG, "WPS: Disable encr_type TKIP");
+ cred.encr_type &= ~WPS_ENCR_TKIP;
+ }
+ if (cred.auth_type & WPS_AUTH_WPAPSK) {
+ wpa_printf(MSG_DEBUG, "WPS: Disable auth_type WPAPSK");
+ cred.auth_type &= ~WPS_AUTH_WPAPSK;
+ }
+#endif /* CONFIG_NO_TKIP */
+
if (wps->wps->cred_cb) {
cred.cred_attr = wpabuf_head(attrs);
cred.cred_attr_len = wpabuf_len(attrs);
diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c
index 06a8fda..6bded14 100644
--- a/src/wps/wps_er.c
+++ b/src/wps/wps_er.c
@@ -897,7 +897,7 @@
const struct sockaddr_in *dst,
char **len_ptr, char **body_ptr)
{
- unsigned char *encoded;
+ char *encoded;
size_t encoded_len;
struct wpabuf *buf;
@@ -939,7 +939,7 @@
wpabuf_put_str(buf, "\">\n");
if (encoded) {
wpabuf_printf(buf, "<%s>%s</%s>\n",
- arg_name, (char *) encoded, arg_name);
+ arg_name, encoded, arg_name);
os_free(encoded);
}
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 0ac5b28..9e1ee36 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -17,6 +17,7 @@
#include "crypto/sha256.h"
#include "crypto/random.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_common.h"
#include "wps_i.h"
#include "wps_dev_attr.h"
#include "wps_upnp.h"
@@ -159,6 +160,7 @@
const u8 *pri_dev_type, u16 config_methods,
u16 dev_password_id, u8 request_type,
const char *dev_name);
+ int (*lookup_pskfile_cb)(void *ctx, const u8 *mac_addr, const u8 **psk);
void *cb_ctx;
struct dl_list pins;
@@ -171,7 +173,6 @@
int sel_reg_union;
int sel_reg_dev_password_id_override;
int sel_reg_config_methods_override;
- int static_wep_only;
int dualband;
int force_per_enrollee_psk;
@@ -681,6 +682,7 @@
reg->reg_success_cb = cfg->reg_success_cb;
reg->set_sel_reg_cb = cfg->set_sel_reg_cb;
reg->enrollee_seen_cb = cfg->enrollee_seen_cb;
+ reg->lookup_pskfile_cb = cfg->lookup_pskfile_cb;
reg->cb_ctx = cfg->cb_ctx;
reg->skip_cred_build = cfg->skip_cred_build;
if (cfg->extra_cred) {
@@ -694,7 +696,6 @@
reg->disable_auto_conf = cfg->disable_auto_conf;
reg->sel_reg_dev_password_id_override = -1;
reg->sel_reg_config_methods_override = -1;
- reg->static_wep_only = cfg->static_wep_only;
reg->dualband = cfg->dualband;
reg->force_per_enrollee_psk = cfg->force_per_enrollee_psk;
@@ -1290,6 +1291,15 @@
}
+static int wps_cp_lookup_pskfile(struct wps_registrar *reg, const u8 *mac_addr,
+ const u8 **psk)
+{
+ if (!reg->lookup_pskfile_cb)
+ return 0;
+ return reg->lookup_pskfile_cb(reg->cb_ctx, mac_addr, psk);
+}
+
+
static int wps_set_ie(struct wps_registrar *reg)
{
struct wpabuf *beacon;
@@ -1331,7 +1341,8 @@
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, 0) ||
- wps_build_vendor_ext(®->wps->dev, beacon)) {
+ wps_build_vendor_ext(®->wps->dev, beacon) ||
+ wps_build_application_ext(®->wps->dev, beacon)) {
wpabuf_free(beacon);
wpabuf_free(probe);
return -1;
@@ -1361,7 +1372,8 @@
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, 0) ||
- wps_build_vendor_ext(®->wps->dev, probe)) {
+ wps_build_vendor_ext(®->wps->dev, probe) ||
+ wps_build_application_ext(®->wps->dev, probe)) {
wpabuf_free(beacon);
wpabuf_free(probe);
return -1;
@@ -1376,28 +1388,6 @@
return -1;
}
- if (reg->static_wep_only) {
- /*
- * Windows XP and Vista clients can get confused about
- * EAP-Identity/Request when they probe the network with
- * EAPOL-Start. In such a case, they may assume the network is
- * using IEEE 802.1X and prompt user for a certificate while
- * the correct (non-WPS) behavior would be to ask for the
- * static WEP key. As a workaround, use Microsoft Provisioning
- * IE to advertise that legacy 802.1X is not supported.
- */
- const u8 ms_wps[7] = {
- WLAN_EID_VENDOR_SPECIFIC, 5,
- /* Microsoft Provisioning IE (00:50:f2:5) */
- 0x00, 0x50, 0xf2, 5,
- 0x00 /* no legacy 802.1X or MS WPS */
- };
- wpa_printf(MSG_DEBUG, "WPS: Add Microsoft Provisioning IE "
- "into Beacon/Probe Response frames");
- wpabuf_put_data(beacon, ms_wps, sizeof(ms_wps));
- wpabuf_put_data(probe, ms_wps, sizeof(ms_wps));
- }
-
return wps_cb_set_ie(reg, beacon, probe);
}
@@ -1642,6 +1632,8 @@
{
struct wpabuf *cred;
struct wps_registrar *reg = wps->wps->registrar;
+ const u8 *pskfile_psk;
+ char hex[65];
if (wps->wps->registrar->skip_cred_build)
goto skip_cred_build;
@@ -1685,8 +1677,10 @@
wps->wps->auth_types, wps->auth_type);
if (wps->auth_type & WPS_AUTH_WPA2PSK)
wps->auth_type = WPS_AUTH_WPA2PSK;
+#ifndef CONFIG_NO_TKIP
else if (wps->auth_type & WPS_AUTH_WPAPSK)
wps->auth_type = WPS_AUTH_WPAPSK;
+#endif /* CONFIG_NO_TKIP */
else if (wps->auth_type & WPS_AUTH_OPEN)
wps->auth_type = WPS_AUTH_OPEN;
else {
@@ -1708,8 +1702,10 @@
wps->auth_type == WPS_AUTH_WPAPSK) {
if (wps->encr_type & WPS_ENCR_AES)
wps->encr_type = WPS_ENCR_AES;
+#ifndef CONFIG_NO_TKIP
else if (wps->encr_type & WPS_ENCR_TKIP)
wps->encr_type = WPS_ENCR_TKIP;
+#endif /* CONFIG_NO_TKIP */
else {
wpa_printf(MSG_DEBUG, "WPS: No suitable encryption "
"type for WPA/WPA2");
@@ -1745,7 +1741,8 @@
return -1;
}
os_free(wps->new_psk);
- wps->new_psk = base64_encode(r, sizeof(r), &wps->new_psk_len);
+ wps->new_psk = (u8 *) base64_encode(r, sizeof(r),
+ &wps->new_psk_len);
if (wps->new_psk == NULL)
return -1;
wps->new_psk_len--; /* remove newline */
@@ -1756,23 +1753,27 @@
wps->new_psk, wps->new_psk_len);
os_memcpy(wps->cred.key, wps->new_psk, wps->new_psk_len);
wps->cred.key_len = wps->new_psk_len;
+ } else if (wps_cp_lookup_pskfile(reg, wps->mac_addr_e, &pskfile_psk)) {
+ wpa_hexdump_key(MSG_DEBUG, "WPS: Use PSK from wpa_psk_file",
+ pskfile_psk, PMK_LEN);
+ wpa_snprintf_hex(hex, sizeof(hex), pskfile_psk, PMK_LEN);
+ os_memcpy(wps->cred.key, hex, PMK_LEN * 2);
+ wps->cred.key_len = PMK_LEN * 2;
} else if (!wps->wps->registrar->force_per_enrollee_psk &&
wps->use_psk_key && wps->wps->psk_set) {
- char hex[65];
wpa_printf(MSG_DEBUG, "WPS: Use PSK format for Network Key");
- wpa_snprintf_hex(hex, sizeof(hex), wps->wps->psk, 32);
- os_memcpy(wps->cred.key, hex, 32 * 2);
- wps->cred.key_len = 32 * 2;
+ wpa_snprintf_hex(hex, sizeof(hex), wps->wps->psk, PMK_LEN);
+ os_memcpy(wps->cred.key, hex, PMK_LEN * 2);
+ wps->cred.key_len = PMK_LEN * 2;
} else if (!wps->wps->registrar->force_per_enrollee_psk &&
wps->wps->network_key) {
os_memcpy(wps->cred.key, wps->wps->network_key,
wps->wps->network_key_len);
wps->cred.key_len = wps->wps->network_key_len;
} else if (wps->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
- char hex[65];
/* Generate a random per-device PSK */
os_free(wps->new_psk);
- wps->new_psk_len = 32;
+ wps->new_psk_len = PMK_LEN;
wps->new_psk = os_malloc(wps->new_psk_len);
if (wps->new_psk == NULL)
return -1;
@@ -3481,6 +3482,7 @@
"unselect internal Registrar");
reg->selected_registrar = 0;
reg->pbc = 0;
+ wps_registrar_expire_pins(reg);
wps_registrar_selected_registrar_changed(reg, 0);
}
diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c
index ca893a4..6e10e4b 100644
--- a/src/wps/wps_upnp.c
+++ b/src/wps/wps_upnp.c
@@ -519,8 +519,9 @@
dl_list_for_each_safe(s, tmp, &sm->subscriptions, struct subscription,
list) {
- event_add(s, buf,
- sm->wlanevent_type == UPNP_WPS_WLANEVENT_TYPE_PROBE);
+ wps_upnp_event_add(
+ s, buf,
+ sm->wlanevent_type == UPNP_WPS_WLANEVENT_TYPE_PROBE);
}
wpabuf_free(buf);
@@ -541,7 +542,7 @@
struct upnp_wps_device_interface *iface;
wpa_printf(MSG_DEBUG, "WPS UPnP: Destroy subscription %p", s);
subscr_addr_free_all(s);
- event_delete_all(s);
+ wps_upnp_event_delete_all(s);
dl_list_for_each(iface, &s->sm->interfaces,
struct upnp_wps_device_interface, list)
upnp_er_remove_notification(iface->wps->registrar, s);
@@ -647,7 +648,7 @@
"initial WLANEvent");
msg = build_fake_wsc_ack();
if (msg) {
- s->sm->wlanevent = (char *)
+ s->sm->wlanevent =
base64_encode(wpabuf_head(msg),
wpabuf_len(msg), NULL);
wpabuf_free(msg);
@@ -672,7 +673,7 @@
wpabuf_put_property(buf, "WLANEvent", wlan_event);
wpabuf_put_str(buf, tail);
- ret = event_add(s, buf, 0);
+ ret = wps_upnp_event_add(s, buf, 0);
if (ret) {
wpabuf_free(buf);
return ret;
@@ -749,7 +750,7 @@
"WPS UPnP: Subscription %p (SID %s) started with %s",
s, str, callback_urls);
/* Schedule sending this */
- event_send_all_later(sm);
+ wps_upnp_event_send_all_later(sm);
return s;
}
@@ -822,7 +823,7 @@
}
raw_len = pos;
- val = (char *) base64_encode(raw, raw_len, &val_len);
+ val = base64_encode(raw, raw_len, &val_len);
if (val == NULL)
goto fail;
@@ -987,7 +988,7 @@
advertisement_state_machine_stop(sm, 1);
- event_send_stop_all(sm);
+ wps_upnp_event_send_stop_all(sm);
os_free(sm->wlanevent);
sm->wlanevent = NULL;
os_free(sm->ip_addr_text);
diff --git a/src/wps/wps_upnp_event.c b/src/wps/wps_upnp_event.c
index 94aae75..d7e6edc 100644
--- a/src/wps/wps_upnp_event.c
+++ b/src/wps/wps_upnp_event.c
@@ -96,8 +96,8 @@
}
-/* event_delete_all -- delete entire event queue and current event */
-void event_delete_all(struct subscription *s)
+/* wps_upnp_event_delete_all -- delete entire event queue and current event */
+void wps_upnp_event_delete_all(struct subscription *s)
{
struct wps_event_ *e;
while ((e = event_dequeue(s)) != NULL)
@@ -134,11 +134,11 @@
event_delete(e);
s->last_event_failed = 1;
if (!dl_list_empty(&s->event_queue))
- event_send_all_later(s->sm);
+ wps_upnp_event_send_all_later(s->sm);
return;
}
dl_list_add(&s->event_queue, &e->list);
- event_send_all_later(sm);
+ wps_upnp_event_send_all_later(sm);
}
@@ -228,7 +228,7 @@
/* Schedule sending more if there is more to send */
if (!dl_list_empty(&s->event_queue))
- event_send_all_later(s->sm);
+ wps_upnp_event_send_all_later(s->sm);
break;
case HTTP_CLIENT_FAILED:
wpa_printf(MSG_DEBUG, "WPS UPnP: Event send failure");
@@ -328,19 +328,19 @@
if (nerrors) {
/* Try again later */
- event_send_all_later(sm);
+ wps_upnp_event_send_all_later(sm);
}
}
-/* event_send_all_later -- schedule sending events to all subscribers
+/* wps_upnp_event_send_all_later -- schedule sending events to all subscribers
* that need it.
* This avoids two problems:
* -- After getting a subscription, we should not send the first event
* until after our reply is fully queued to be sent back,
* -- Possible stack depth or infinite recursion issues.
*/
-void event_send_all_later(struct upnp_wps_device_sm *sm)
+void wps_upnp_event_send_all_later(struct upnp_wps_device_sm *sm)
{
/*
* The exact time in the future isn't too important. Waiting a bit
@@ -354,8 +354,8 @@
}
-/* event_send_stop_all -- cleanup */
-void event_send_stop_all(struct upnp_wps_device_sm *sm)
+/* wps_upnp_event_send_stop_all -- cleanup */
+void wps_upnp_event_send_stop_all(struct upnp_wps_device_sm *sm)
{
if (sm->event_send_all_queued)
eloop_cancel_timeout(event_send_all_later_handler, NULL, sm);
@@ -364,13 +364,14 @@
/**
- * event_add - Add a new event to a queue
+ * wps_upnp_event_add - Add a new event to a queue
* @s: Subscription
* @data: Event data (is copied; caller retains ownership)
* @probereq: Whether this is a Probe Request event
* Returns: 0 on success, -1 on error, 1 on max event queue limit reached
*/
-int event_add(struct subscription *s, const struct wpabuf *data, int probereq)
+int wps_upnp_event_add(struct subscription *s, const struct wpabuf *data,
+ int probereq)
{
struct wps_event_ *e;
unsigned int len;
@@ -416,6 +417,6 @@
wpa_printf(MSG_DEBUG, "WPS UPnP: Queue event %p for subscriber %p "
"(queue len %u)", e, s, len + 1);
dl_list_add_tail(&s->event_queue, &e->list);
- event_send_all_later(s->sm);
+ wps_upnp_event_send_all_later(s->sm);
return 0;
}
diff --git a/src/wps/wps_upnp_i.h b/src/wps/wps_upnp_i.h
index 6a7c627..e87a932 100644
--- a/src/wps/wps_upnp_i.h
+++ b/src/wps/wps_upnp_i.h
@@ -177,10 +177,11 @@
void web_listener_stop(struct upnp_wps_device_sm *sm);
/* wps_upnp_event.c */
-int event_add(struct subscription *s, const struct wpabuf *data, int probereq);
-void event_delete_all(struct subscription *s);
-void event_send_all_later(struct upnp_wps_device_sm *sm);
-void event_send_stop_all(struct upnp_wps_device_sm *sm);
+int wps_upnp_event_add(struct subscription *s, const struct wpabuf *data,
+ int probereq);
+void wps_upnp_event_delete_all(struct subscription *s);
+void wps_upnp_event_send_all_later(struct upnp_wps_device_sm *sm);
+void wps_upnp_event_send_stop_all(struct upnp_wps_device_sm *sm);
/* wps_upnp_ap.c */
int upnp_er_set_selected_registrar(struct wps_registrar *reg,
diff --git a/src/wps/wps_upnp_web.c b/src/wps/wps_upnp_web.c
index 7548e84..3c5a97c 100644
--- a/src/wps/wps_upnp_web.c
+++ b/src/wps/wps_upnp_web.c
@@ -765,8 +765,8 @@
if (reply) {
size_t len;
- replydata = (char *) base64_encode(wpabuf_head(reply),
- wpabuf_len(reply), &len);
+ replydata = base64_encode(wpabuf_head(reply), wpabuf_len(reply),
+ &len);
} else
replydata = NULL;
diff --git a/tests/test-eapol.c b/tests/test-eapol.c
deleted file mode 100644
index 0a0844b..0000000
--- a/tests/test-eapol.c
+++ /dev/null
@@ -1,606 +0,0 @@
-/*
- * 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
deleted file mode 100644
index c7cb460..0000000
--- a/tests/test-json.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 9941fb5..0000000
--- a/tests/test-tls.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * 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/Android.mk b/wpa_supplicant/Android.mk
index 8bcd7ef..37432d9 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -95,7 +95,6 @@
INCLUDES += $(LOCAL_PATH)/src/eapol_supp
INCLUDES += $(LOCAL_PATH)/src/eap_peer
INCLUDES += $(LOCAL_PATH)/src/eap_server
-INCLUDES += $(LOCAL_PATH)/src/hlr_auc_gw
INCLUDES += $(LOCAL_PATH)/src/l2_packet
INCLUDES += $(LOCAL_PATH)/src/radius
INCLUDES += $(LOCAL_PATH)/src/rsn_supp
@@ -124,6 +123,8 @@
OBJS += src/utils/wpa_debug.c
OBJS += src/utils/wpabuf.c
OBJS += src/utils/bitfield.c
+OBJS += src/utils/ip_addr.c
+OBJS += src/utils/crc32.c
OBJS += wmm_ac.c
OBJS += op_classes.c
OBJS += rrm.c
@@ -195,6 +196,10 @@
L_CFLAGS += -DCONFIG_VHT_OVERRIDES
endif
+ifdef CONFIG_HE_OVERRIDES
+L_CFLAGS += -DCONFIG_HE_OVERRIDES
+endif
+
ifndef CONFIG_BACKEND
CONFIG_BACKEND=file
endif
@@ -229,8 +234,6 @@
ifdef CONFIG_SUITEB
L_CFLAGS += -DCONFIG_SUITEB
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_SUITEB192
@@ -241,25 +244,15 @@
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
L_CFLAGS += -DCONFIG_IEEE80211R
OBJS += src/rsn_supp/wpa_ft.c
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_MESH
NEED_80211_COMMON=y
-NEED_SHA256=y
NEED_AES_SIV=y
CONFIG_SAE=y
CONFIG_AP=y
@@ -274,6 +267,11 @@
OBJS += src/common/sae.c
NEED_ECC=y
NEED_DH_GROUPS=y
+NEED_HMAC_SHA256_KDF=y
+NEED_DRAGONFLY=y
+ifdef CONFIG_TESTING_OPTIONS
+NEED_DH_GROUPS_ALL=y
+endif
endif
ifdef CONFIG_DPP
@@ -284,12 +282,13 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
+NEED_ECC=y
NEED_JSON=y
NEED_GAS_SERVER=y
NEED_BASE64=y
+NEED_ASN1=y
ifdef CONFIG_DPP2
L_CFLAGS += -DCONFIG_DPP2
endif
@@ -301,11 +300,14 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
endif
+ifdef CONFIG_WAPI_INTERFACE
+L_CFLAGS += -DCONFIG_WAPI_INTERFACE
+endif
+
ifdef CONFIG_FILS
L_CFLAGS += -DCONFIG_FILS
NEED_SHA384=y
@@ -328,8 +330,6 @@
ifdef CONFIG_TDLS
L_CFLAGS += -DCONFIG_TDLS
OBJS += src/rsn_supp/tdls.c
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_TDLS_TESTING
@@ -394,7 +394,6 @@
OBJS += hs20_supplicant.c
L_CFLAGS += -DCONFIG_HS20
CONFIG_INTERWORKING=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_INTERWORKING
@@ -418,6 +417,14 @@
endif
endif
+ifdef CONFIG_WEP
+L_CFLAGS += -DCONFIG_WEP
+endif
+
+ifdef CONFIG_NO_TKIP
+L_CFLAGS += -DCONFIG_NO_TKIP
+endif
+
include $(LOCAL_PATH)/src/drivers/drivers.mk
@@ -461,7 +468,6 @@
ifdef CONFIG_ERP
L_CFLAGS += -DCONFIG_ERP
-NEED_SHA256=y
NEED_HMAC_SHA256_KDF=y
endif
@@ -616,7 +622,6 @@
endif
CONFIG_IEEE8021X_EAPOL=y
NEED_AES=y
-NEED_AES_OMAC1=y
NEED_AES_ENCBLOCK=y
NEED_AES_EAX=y
endif
@@ -649,7 +654,6 @@
else
L_CFLAGS += -DEAP_AKA_PRIME
endif
-NEED_SHA256=y
endif
ifdef CONFIG_EAP_SIM_COMMON
@@ -674,6 +678,25 @@
NEED_T_PRF=y
endif
+ifdef CONFIG_EAP_TEAP
+# EAP-TEAP
+ifeq ($(CONFIG_EAP_TEAP), dyn)
+L_CFLAGS += -DEAP_YEAP_DYNAMIC
+EAPDYN += src/eap_peer/eap_teap.so
+EAPDYN += src/eap_common/eap_teap_common.c
+else
+L_CFLAGS += -DEAP_TEAP
+OBJS += src/eap_peer/eap_teap.c src/eap_peer/eap_teap_pac.c
+OBJS += src/eap_common/eap_teap_common.c
+endif
+TLS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+NEED_T_PRF=y
+NEED_SHA384=y
+NEED_TLS_PRF_SHA256=y
+NEED_TLS_PRF_SHA384=y
+endif
+
ifdef CONFIG_EAP_PAX
# EAP-PAX
ifeq ($(CONFIG_EAP_PAX), dyn)
@@ -711,16 +734,14 @@
ifdef CONFIG_EAP_GPSK_SHA256
L_CFLAGS += -DEAP_GPSK_SHA256
endif
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_EAP_PWD
L_CFLAGS += -DEAP_PWD
OBJS += src/eap_peer/eap_pwd.c src/eap_common/eap_pwd_common.c
CONFIG_IEEE8021X_EAPOL=y
-NEED_SHA256=y
NEED_ECC=y
+NEED_DRAGONFLY=y
endif
ifdef CONFIG_EAP_EKE
@@ -735,7 +756,6 @@
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
NEED_DH_GROUPS_ALL=y
-NEED_SHA256=y
NEED_AES_CBC=y
endif
@@ -755,7 +775,6 @@
OBJS += src/wps/wps_registrar.c
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
-NEED_SHA256=y
NEED_BASE64=y
NEED_AES_CBC=y
NEED_MODEXP=y
@@ -872,7 +891,6 @@
OBJS += src/ap/utils.c
OBJS += src/ap/authsrv.c
OBJS += src/ap/ap_config.c
-OBJS += src/utils/ip_addr.c
OBJS += src/ap/sta_info.c
OBJS += src/ap/tkip_countermeasures.c
OBJS += src/ap/ap_mlme.c
@@ -887,7 +905,6 @@
OBJS += src/ap/eap_user_db.c
OBJS += src/ap/neighbor_db.c
OBJS += src/ap/rrm.c
-ifdef CONFIG_IEEE80211N
OBJS += src/ap/ieee802_11_ht.c
ifdef CONFIG_IEEE80211AC
OBJS += src/ap/ieee802_11_vht.c
@@ -895,7 +912,6 @@
ifdef CONFIG_IEEE80211AX
OBJS += src/ap/ieee802_11_he.c
endif
-endif
ifdef CONFIG_WNM_AP
L_CFLAGS += -DCONFIG_WNM_AP
OBJS += src/ap/wnm_ap.c
@@ -915,15 +931,12 @@
OBJS += src/eap_server/eap_server_identity.c
OBJS += src/eap_server/eap_server_methods.c
-ifdef CONFIG_IEEE80211N
-L_CFLAGS += -DCONFIG_IEEE80211N
ifdef CONFIG_IEEE80211AC
L_CFLAGS += -DCONFIG_IEEE80211AC
endif
ifdef CONFIG_IEEE80211AX
L_CFLAGS += -DCONFIG_IEEE80211AX
endif
-endif
ifdef NEED_AP_MLME
OBJS += src/ap/wmm.c
@@ -941,8 +954,12 @@
ifdef CONFIG_DPP
OBJS += src/ap/dpp_hostapd.c
OBJS += src/ap/gas_query_ap.c
+NEED_AP_GAS_SERV=y
endif
ifdef CONFIG_INTERWORKING
+NEED_AP_GAS_SERV=y
+endif
+ifdef NEED_AP_GAS_SERV
OBJS += src/ap/gas_serv.c
endif
ifdef CONFIG_HS20
@@ -1010,6 +1027,10 @@
L_CFLAGS += -DCONFIG_SMARTCARD
endif
+ifdef NEED_DRAGONFLY
+OBJS += src/common/dragonfly.c
+endif
+
ifdef MS_FUNCS
OBJS += src/crypto/ms_funcs.c
NEED_DES=y
@@ -1042,7 +1063,6 @@
ifdef CONFIG_TLSV12
L_CFLAGS += -DCONFIG_TLSV12
-NEED_SHA256=y
endif
ifeq ($(CONFIG_TLS), openssl)
@@ -1057,7 +1077,6 @@
ifdef NEED_FIPS186_2_PRF
OBJS += src/crypto/fips_prf_openssl.c
endif
-NEED_SHA256=y
NEED_TLS_PRF_SHA256=y
LIBS += -lcrypto
LIBS_p += -lcrypto
@@ -1114,13 +1133,12 @@
OBJS += src/tls/tlsv1_client_write.c
OBJS += src/tls/tlsv1_client_read.c
OBJS += src/tls/tlsv1_client_ocsp.c
-OBJS += src/tls/asn1.c
+NEED_ASN1=y
OBJS += src/tls/rsa.c
OBJS += src/tls/x509v3.c
OBJS += src/tls/pkcs1.c
OBJS += src/tls/pkcs5.c
OBJS += src/tls/pkcs8.c
-NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -1240,12 +1258,10 @@
ifdef NEED_AES_EAX
AESOBJS += src/crypto/aes-eax.c
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_SIV
AESOBJS += src/crypto/aes-siv.c
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_CTR
AESOBJS += src/crypto/aes-ctr.c
@@ -1253,14 +1269,12 @@
ifdef NEED_AES_ENCBLOCK
AESOBJS += src/crypto/aes-encblock.c
endif
-ifdef NEED_AES_OMAC1
NEED_AES_ENC=y
ifdef CONFIG_OPENSSL_CMAC
L_CFLAGS += -DCONFIG_OPENSSL_CMAC
else
AESOBJS += src/crypto/aes-omac1.c
endif
-endif
ifdef NEED_AES_WRAP
NEED_AES_ENC=y
ifdef NEED_INTERNAL_AES_WRAP
@@ -1353,7 +1367,6 @@
endif
SHA256OBJS = # none by default
-ifdef NEED_SHA256
L_CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), gnutls)
@@ -1375,6 +1388,9 @@
ifdef NEED_TLS_PRF_SHA256
SHA256OBJS += src/crypto/sha256-tlsprf.c
endif
+ifdef NEED_TLS_PRF_SHA384
+SHA256OBJS += src/crypto/sha384-tlsprf.c
+endif
ifdef NEED_HMAC_SHA256_KDF
L_CFLAGS += -DCONFIG_HMAC_SHA256_KDF
SHA256OBJS += src/crypto/sha256-kdf.c
@@ -1388,7 +1404,6 @@
SHA256OBJS += src/crypto/sha512-kdf.c
endif
OBJS += $(SHA256OBJS)
-endif
ifdef NEED_SHA384
L_CFLAGS += -DCONFIG_SHA384
ifneq ($(CONFIG_TLS), openssl)
@@ -1408,6 +1423,10 @@
OBJS += src/crypto/sha512-prf.c
endif
+ifdef NEED_ASN1
+OBJS += src/tls/asn1.c
+endif
+
ifdef NEED_DH_GROUPS
OBJS += src/crypto/dh_groups.c
endif
@@ -1479,6 +1498,7 @@
ifdef CONFIG_CTRL_IFACE_HIDL
WPA_SUPPLICANT_USE_HIDL=y
L_CFLAGS += -DCONFIG_HIDL -DCONFIG_CTRL_IFACE_HIDL
+HIDL_INTERFACE_VERSION := 1.3
endif
ifdef CONFIG_READLINE
@@ -1640,9 +1660,6 @@
OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.c
OBJS_t += src/radius/radius_client.c
OBJS_t += src/radius/radius.c
-ifndef CONFIG_AP
-OBJS_t += src/utils/ip_addr.c
-endif
OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.c
OBJS += $(CONFIG_MAIN).c
@@ -1733,8 +1750,13 @@
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_SHARED_LIBRARIES += android.hardware.wifi.supplicant@1.3
+LOCAL_SHARED_LIBRARIES += libhidlbase libutils libbase
LOCAL_STATIC_LIBRARIES += libwpa_hidl
+LOCAL_VINTF_FRAGMENTS := hidl/$(HIDL_INTERFACE_VERSION)/manifest.xml
+ifeq ($(WIFI_HIDL_UNIFIED_SUPPLICANT_SERVICE_RC_ENTRY), true)
+LOCAL_INIT_RC=hidl/$(HIDL_INTERFACE_VERSION)/android.hardware.wifi.supplicant-service.rc
+endif
endif
include $(BUILD_EXECUTABLE)
@@ -1783,7 +1805,6 @@
LOCAL_CPPFLAGS := $(L_CPPFLAGS)
LOCAL_CFLAGS := $(L_CFLAGS)
LOCAL_C_INCLUDES := $(INCLUDES)
-HIDL_INTERFACE_VERSION = 1.2
LOCAL_SRC_FILES := \
hidl/$(HIDL_INTERFACE_VERSION)/hidl.cpp \
hidl/$(HIDL_INTERFACE_VERSION)/hidl_manager.cpp \
@@ -1797,9 +1818,9 @@
android.hardware.wifi.supplicant@1.0 \
android.hardware.wifi.supplicant@1.1 \
android.hardware.wifi.supplicant@1.2 \
+ android.hardware.wifi.supplicant@1.3 \
libbase \
libhidlbase \
- libhidltransport \
libutils \
liblog \
libssl
diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog
index bf4daaa..f82e5e0 100644
--- a/wpa_supplicant/ChangeLog
+++ b/wpa_supplicant/ChangeLog
@@ -1,5 +1,103 @@
ChangeLog for wpa_supplicant
+2019-08-07 - v2.9
+ * SAE changes
+ - disable use of groups using Brainpool curves
+ - improved protection against side channel attacks
+ [https://w1.fi/security/2019-6/]
+ * EAP-pwd changes
+ - disable use of groups using Brainpool curves
+ - allow the set of groups to be configured (eap_pwd_groups)
+ - improved protection against side channel attacks
+ [https://w1.fi/security/2019-6/]
+ * fixed FT-EAP initial mobility domain association using PMKSA caching
+ (disabled by default for backwards compatibility; can be enabled
+ with ft_eap_pmksa_caching=1)
+ * fixed a regression in OpenSSL 1.1+ engine loading
+ * added validation of RSNE in (Re)Association Response frames
+ * fixed DPP bootstrapping URI parser of channel list
+ * extended EAP-SIM/AKA fast re-authentication to allow use with FILS
+ * extended ca_cert_blob to support PEM format
+ * improved robustness of P2P Action frame scheduling
+ * added support for EAP-SIM/AKA using anonymous@realm identity
+ * fixed Hotspot 2.0 credential selection based on roaming consortium
+ to ignore credentials without a specific EAP method
+ * added experimental support for EAP-TEAP peer (RFC 7170)
+ * added experimental support for EAP-TLS peer with TLS v1.3
+ * fixed a regression in WMM parameter configuration for a TDLS peer
+ * fixed a regression in operation with drivers that offload 802.1X
+ 4-way handshake
+ * fixed an ECDH operation corner case with OpenSSL
+
+2019-04-21 - v2.8
+ * SAE changes
+ - added support for SAE Password Identifier
+ - changed default configuration to enable only groups 19, 20, 21
+ (i.e., disable groups 25 and 26) and disable all unsuitable groups
+ completely based on REVmd changes
+ - do not regenerate PWE unnecessarily when the AP uses the
+ anti-clogging token mechanisms
+ - fixed some association cases where both SAE and FT-SAE were enabled
+ on both the station and the selected AP
+ - started to prefer FT-SAE over SAE AKM if both are enabled
+ - started to prefer FT-SAE over FT-PSK if both are enabled
+ - fixed FT-SAE when SAE PMKSA caching is used
+ - reject use of unsuitable groups based on new implementation guidance
+ in REVmd (allow only FFC groups with prime >= 3072 bits and ECC
+ groups with prime >= 256)
+ - minimize timing and memory use differences in PWE derivation
+ [https://w1.fi/security/2019-1/] (CVE-2019-9494)
+ * EAP-pwd changes
+ - minimize timing and memory use differences in PWE derivation
+ [https://w1.fi/security/2019-2/] (CVE-2019-9495)
+ - verify server scalar/element
+ [https://w1.fi/security/2019-4/] (CVE-2019-9499)
+ - fix message reassembly issue with unexpected fragment
+ [https://w1.fi/security/2019-5/]
+ - enforce rand,mask generation rules more strictly
+ - fix a memory leak in PWE derivation
+ - disallow ECC groups with a prime under 256 bits (groups 25, 26, and
+ 27)
+ * fixed CONFIG_IEEE80211R=y (FT) build without CONFIG_FILS=y
+ * Hotspot 2.0 changes
+ - do not indicate release number that is higher than the one
+ AP supports
+ - added support for release number 3
+ - enable PMF automatically for network profiles created from
+ credentials
+ * fixed OWE network profile saving
+ * fixed DPP network profile saving
+ * added support for RSN operating channel validation
+ (CONFIG_OCV=y and network profile parameter ocv=1)
+ * added Multi-AP backhaul STA support
+ * fixed build with LibreSSL
+ * number of MKA/MACsec fixes and extensions
+ * extended domain_match and domain_suffix_match to allow list of values
+ * fixed dNSName matching in domain_match and domain_suffix_match when
+ using wolfSSL
+ * started to prefer FT-EAP-SHA384 over WPA-EAP-SUITE-B-192 AKM if both
+ are enabled
+ * extended nl80211 Connect and external authentication to support
+ SAE, FT-SAE, FT-EAP-SHA384
+ * fixed KEK2 derivation for FILS+FT
+ * extended client_cert file to allow loading of a chain of PEM
+ encoded certificates
+ * extended beacon reporting functionality
+ * extended D-Bus interface with number of new properties
+ * fixed a regression in FT-over-DS with mac80211-based drivers
+ * OpenSSL: allow systemwide policies to be overridden
+ * extended driver flags indication for separate 802.1X and PSK
+ 4-way handshake offload capability
+ * added support for random P2P Device/Interface Address use
+ * extended PEAP to derive EMSK to enable use with ERP/FILS
+ * extended WPS to allow SAE configuration to be added automatically
+ for PSK (wps_cred_add_sae=1)
+ * removed support for the old D-Bus interface (CONFIG_CTRL_IFACE_DBUS)
+ * extended domain_match and domain_suffix_match to allow list of values
+ * added a RSN workaround for misbehaving PMF APs that advertise
+ IGTK/BIP KeyID using incorrect byte order
+ * fixed PTK rekeying with FILS and FT
+
2018-12-02 - v2.7
* fixed WPA packet number reuse with replayed messages and key
reinstallation
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index e81238e..738b0bd 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -103,6 +103,8 @@
OBJS += ../src/utils/wpa_debug.o
OBJS += ../src/utils/wpabuf.o
OBJS += ../src/utils/bitfield.o
+OBJS += ../src/utils/ip_addr.o
+OBJS += ../src/utils/crc32.o
OBJS += op_classes.o
OBJS += rrm.o
OBJS_p = wpa_passphrase.o
@@ -196,6 +198,10 @@
CFLAGS += -DCONFIG_VHT_OVERRIDES
endif
+ifdef CONFIG_HE_OVERRIDES
+CFLAGS += -DCONFIG_HE_OVERRIDES
+endif
+
ifndef CONFIG_BACKEND
CONFIG_BACKEND=file
endif
@@ -230,8 +236,6 @@
ifdef CONFIG_SUITEB
CFLAGS += -DCONFIG_SUITEB
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_SUITEB192
@@ -242,25 +246,15 @@
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
CFLAGS += -DCONFIG_IEEE80211R
OBJS += ../src/rsn_supp/wpa_ft.o
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_MESH
NEED_80211_COMMON=y
-NEED_SHA256=y
NEED_AES_SIV=y
CONFIG_SAE=y
CONFIG_AP=y
@@ -275,6 +269,11 @@
OBJS += ../src/common/sae.o
NEED_ECC=y
NEED_DH_GROUPS=y
+NEED_HMAC_SHA256_KDF=y
+NEED_DRAGONFLY=y
+ifdef CONFIG_TESTING_OPTIONS
+NEED_DH_GROUPS_ALL=y
+endif
endif
ifdef CONFIG_DPP
@@ -285,12 +284,13 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
+NEED_ECC=y
NEED_JSON=y
NEED_GAS_SERVER=y
NEED_BASE64=y
+NEED_ASN1=y
ifdef CONFIG_DPP2
CFLAGS += -DCONFIG_DPP2
endif
@@ -302,11 +302,14 @@
NEED_HMAC_SHA256_KDF=y
NEED_HMAC_SHA384_KDF=y
NEED_HMAC_SHA512_KDF=y
-NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
endif
+ifdef CONFIG_WAPI_INTERFACE
+L_CFLAGS += -DCONFIG_WAPI_INTERFACE
+endif
+
ifdef CONFIG_FILS
CFLAGS += -DCONFIG_FILS
NEED_SHA384=y
@@ -329,8 +332,6 @@
ifdef CONFIG_TDLS
CFLAGS += -DCONFIG_TDLS
OBJS += ../src/rsn_supp/tdls.o
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_TDLS_TESTING
@@ -403,7 +404,6 @@
OBJS += hs20_supplicant.o
CFLAGS += -DCONFIG_HS20
CONFIG_INTERWORKING=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_INTERWORKING
@@ -457,7 +457,6 @@
ifdef CONFIG_ERP
CFLAGS += -DCONFIG_ERP
-NEED_SHA256=y
NEED_HMAC_SHA256_KDF=y
endif
@@ -612,7 +611,6 @@
endif
CONFIG_IEEE8021X_EAPOL=y
NEED_AES=y
-NEED_AES_OMAC1=y
NEED_AES_ENCBLOCK=y
NEED_AES_EAX=y
endif
@@ -645,7 +643,6 @@
else
CFLAGS += -DEAP_AKA_PRIME
endif
-NEED_SHA256=y
endif
ifdef CONFIG_EAP_SIM_COMMON
@@ -670,6 +667,25 @@
NEED_T_PRF=y
endif
+ifdef CONFIG_EAP_TEAP
+# EAP-TEAP
+ifeq ($(CONFIG_EAP_TEAP), dyn)
+CFLAGS += -DEAP_TEAP_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_teap.so
+EAPDYN += ../src/eap_common/eap_teap_common.o
+else
+CFLAGS += -DEAP_TEAP
+OBJS += ../src/eap_peer/eap_teap.o ../src/eap_peer/eap_teap_pac.o
+OBJS += ../src/eap_common/eap_teap_common.o
+endif
+TLS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+NEED_T_PRF=y
+NEED_SHA384=y
+NEED_TLS_PRF_SHA256=y
+NEED_TLS_PRF_SHA384=y
+endif
+
ifdef CONFIG_EAP_PAX
# EAP-PAX
ifeq ($(CONFIG_EAP_PAX), dyn)
@@ -707,8 +723,6 @@
ifdef CONFIG_EAP_GPSK_SHA256
CFLAGS += -DEAP_GPSK_SHA256
endif
-NEED_SHA256=y
-NEED_AES_OMAC1=y
endif
ifdef CONFIG_EAP_PWD
@@ -718,8 +732,8 @@
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
+NEED_DRAGONFLY=y
endif
ifdef CONFIG_EAP_EKE
@@ -734,7 +748,6 @@
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
NEED_DH_GROUPS_ALL=y
-NEED_SHA256=y
NEED_AES_CBC=y
endif
@@ -754,7 +767,6 @@
OBJS += ../src/wps/wps_registrar.o
CONFIG_IEEE8021X_EAPOL=y
NEED_DH_GROUPS=y
-NEED_SHA256=y
NEED_BASE64=y
NEED_AES_CBC=y
NEED_MODEXP=y
@@ -852,12 +864,14 @@
NEED_AES_ENCBLOCK=y
NEED_AES_UNWRAP=y
NEED_AES_WRAP=y
-NEED_AES_OMAC1=y
OBJS += wpas_kay.o
OBJS += ../src/pae/ieee802_1x_cp.o
OBJS += ../src/pae/ieee802_1x_kay.o
OBJS += ../src/pae/ieee802_1x_key.o
OBJS += ../src/pae/ieee802_1x_secy_ops.o
+ifdef CONFIG_AP
+OBJS += ../src/ap/wpa_auth_kay.o
+endif
endif
ifdef CONFIG_IEEE8021X_EAPOL
@@ -885,7 +899,6 @@
OBJS += ../src/ap/utils.o
OBJS += ../src/ap/authsrv.o
OBJS += ../src/ap/ap_config.o
-OBJS += ../src/utils/ip_addr.o
OBJS += ../src/ap/sta_info.o
OBJS += ../src/ap/tkip_countermeasures.o
OBJS += ../src/ap/ap_mlme.o
@@ -900,7 +913,6 @@
OBJS += ../src/ap/eap_user_db.o
OBJS += ../src/ap/neighbor_db.o
OBJS += ../src/ap/rrm.o
-ifdef CONFIG_IEEE80211N
OBJS += ../src/ap/ieee802_11_ht.o
ifdef CONFIG_IEEE80211AC
OBJS += ../src/ap/ieee802_11_vht.o
@@ -908,7 +920,6 @@
ifdef CONFIG_IEEE80211AX
OBJS += ../src/ap/ieee802_11_he.o
endif
-endif
ifdef CONFIG_WNM_AP
CFLAGS += -DCONFIG_WNM_AP
OBJS += ../src/ap/wnm_ap.o
@@ -928,15 +939,12 @@
OBJS += ../src/eap_server/eap_server_identity.o
OBJS += ../src/eap_server/eap_server_methods.o
-ifdef CONFIG_IEEE80211N
-CFLAGS += -DCONFIG_IEEE80211N
ifdef CONFIG_IEEE80211AC
CFLAGS += -DCONFIG_IEEE80211AC
endif
ifdef CONFIG_IEEE80211AX
CFLAGS += -DCONFIG_IEEE80211AX
endif
-endif
ifdef NEED_AP_MLME
OBJS += ../src/ap/wmm.o
@@ -954,8 +962,12 @@
ifdef CONFIG_DPP
OBJS += ../src/ap/dpp_hostapd.o
OBJS += ../src/ap/gas_query_ap.o
+NEED_AP_GAS_SERV=y
endif
ifdef CONFIG_INTERWORKING
+NEED_AP_GAS_SERV=y
+endif
+ifdef NEED_AP_GAS_SERV
OBJS += ../src/ap/gas_serv.o
endif
ifdef CONFIG_HS20
@@ -1023,6 +1035,10 @@
CFLAGS += -DCONFIG_SMARTCARD
endif
+ifdef NEED_DRAGONFLY
+OBJS += ../src/common/dragonfly.o
+endif
+
ifdef MS_FUNCS
OBJS += ../src/crypto/ms_funcs.o
NEED_DES=y
@@ -1035,7 +1051,8 @@
ifdef TLS_FUNCS
NEED_DES=y
-# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST)
+# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, EAP_FAST, and
+# EAP_TEAP)
OBJS += ../src/eap_peer/eap_tls_common.o
ifndef CONFIG_FIPS
NEED_TLS_PRF=y
@@ -1054,7 +1071,6 @@
ifdef CONFIG_TLSV12
CFLAGS += -DCONFIG_TLSV12
-NEED_SHA256=y
endif
ifeq ($(CONFIG_TLS), wolfssl)
@@ -1085,7 +1101,6 @@
ifdef NEED_FIPS186_2_PRF
OBJS += ../src/crypto/fips_prf_openssl.o
endif
-NEED_SHA256=y
NEED_TLS_PRF_SHA256=y
LIBS += -lcrypto
LIBS_p += -lcrypto
@@ -1143,13 +1158,12 @@
OBJS += ../src/tls/tlsv1_client_write.o
OBJS += ../src/tls/tlsv1_client_read.o
OBJS += ../src/tls/tlsv1_client_ocsp.o
-OBJS += ../src/tls/asn1.o
OBJS += ../src/tls/rsa.o
OBJS += ../src/tls/x509v3.o
OBJS += ../src/tls/pkcs1.o
OBJS += ../src/tls/pkcs5.o
OBJS += ../src/tls/pkcs8.o
-NEED_SHA256=y
+NEED_ASN1=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -1223,13 +1237,12 @@
OBJS += ../src/tls/tlsv1_client_write.o
OBJS += ../src/tls/tlsv1_client_read.o
OBJS += ../src/tls/tlsv1_client_ocsp.o
-OBJS += ../src/tls/asn1.o
OBJS += ../src/tls/rsa.o
OBJS += ../src/tls/x509v3.o
OBJS += ../src/tls/pkcs1.o
OBJS += ../src/tls/pkcs5.o
OBJS += ../src/tls/pkcs8.o
-NEED_SHA256=y
+NEED_ASN1=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
@@ -1315,12 +1328,10 @@
ifdef NEED_AES_EAX
AESOBJS += ../src/crypto/aes-eax.o
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_SIV
AESOBJS += ../src/crypto/aes-siv.o
NEED_AES_CTR=y
-NEED_AES_OMAC1=y
endif
ifdef NEED_AES_CTR
AESOBJS += ../src/crypto/aes-ctr.o
@@ -1328,7 +1339,6 @@
ifdef NEED_AES_ENCBLOCK
AESOBJS += ../src/crypto/aes-encblock.o
endif
-ifdef NEED_AES_OMAC1
NEED_AES_ENC=y
ifdef CONFIG_OPENSSL_CMAC
CFLAGS += -DCONFIG_OPENSSL_CMAC
@@ -1339,7 +1349,6 @@
endif
endif
endif
-endif
ifdef NEED_AES_WRAP
NEED_AES_ENC=y
ifdef NEED_INTERNAL_AES_WRAP
@@ -1448,7 +1457,6 @@
endif
SHA256OBJS = # none by default
-ifdef NEED_SHA256
CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
@@ -1474,6 +1482,9 @@
ifdef NEED_TLS_PRF_SHA256
SHA256OBJS += ../src/crypto/sha256-tlsprf.o
endif
+ifdef NEED_TLS_PRF_SHA384
+SHA256OBJS += ../src/crypto/sha384-tlsprf.o
+endif
ifdef NEED_HMAC_SHA256_KDF
CFLAGS += -DCONFIG_HMAC_SHA256_KDF
OBJS += ../src/crypto/sha256-kdf.o
@@ -1487,7 +1498,6 @@
OBJS += ../src/crypto/sha512-kdf.o
endif
OBJS += $(SHA256OBJS)
-endif
ifdef NEED_SHA384
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
@@ -1515,6 +1525,10 @@
OBJS += ../src/crypto/sha512-prf.o
endif
+ifdef NEED_ASN1
+OBJS += ../src/tls/asn1.o
+endif
+
ifdef NEED_DH_GROUPS
OBJS += ../src/crypto/dh_groups.o
endif
@@ -1781,9 +1795,6 @@
OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.o
OBJS_t += ../src/radius/radius_client.o
OBJS_t += ../src/radius/radius.o
-ifndef CONFIG_AP
-OBJS_t += ../src/utils/ip_addr.o
-endif
OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.o
OBJS_nfc := $(OBJS) $(OBJS_l2) nfc_pw_token.o
@@ -1841,6 +1852,14 @@
OBJS_nfc += $(FST_OBJS)
endif
+ifdef CONFIG_WEP
+CFLAGS += -DCONFIG_WEP
+endif
+
+ifdef CONFIG_NO_TKIP
+CFLAGS += -DCONFIG_NO_TKIP
+endif
+
ifndef LDO
LDO=$(CC)
endif
diff --git a/wpa_supplicant/README-DPP b/wpa_supplicant/README-DPP
index 6496733..d378245 100644
--- a/wpa_supplicant/README-DPP
+++ b/wpa_supplicant/README-DPP
@@ -9,42 +9,44 @@
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
+Device Provisioning Protocol (also known as Wi-Fi Easy Connect) 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 (password with in-band provisioning), 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.
+More information about Wi-Fi Easy Connect is available from this Wi-Fi
+Alliance web page:
+https://www.wi-fi.org/discover-wi-fi/wi-fi-easy-connect
+
Build config setup
------------------
-The following changes must go in the config file used to compile hostapd
-and wpa_supplicant.
+The following parameters must be included 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
+Enable DPP 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
+Enable DPP 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.
+Any STA or AP device can act as a Configurator. Enable DPP in build
+config. For an AP to act as a Configurator, Interworking needs to be
+enabled for GAS. For wpa_supplicant it is not required.
CONFIG_INTERWORKING=y
@@ -92,39 +94,46 @@
> dpp_configurator_get_key <id>
-How to configure an enrollee using Configurator
+How to configure an Enrollee using Configurator
-----------------------------------------------
-On enrollee side:
+On Enrollee side:
-Generate QR code for the device. Store the qr code id returned by the
+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)
+> dpp_bootstrap_gen type=qrcode mac=<mac-address-of-device> chan=<operating-class/channel> key=<key of the device>
+(Returns bootstrapping info id. If the key parameter is not included, a new key
+is generated automatically. The MAC address is specified without octet
+separating colons. The channel list includes the possible channels on which the
+device is waiting. This uses global operating classes; e.g., 81/1 is the 2.4
+GHz channel 1 on 2412 MHz.)
-Get QR Code of device using the bootstrap info id.
+Get URI for the 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.
+Make device listen to DPP request. The central frequency of the 2.4 GHz
+band channel 1 is 2412 MHz) in case the Enrollee is a client device. An
+AP as an Enrollee is listening on its operating channel.
> dpp_listen <frequency>
On Configurator side:
Enter the QR Code in the Configurator.
-> dpp_qr_code "<QR-Code-read-from-enrollee>"
+> dpp_qr_code "<URI-from-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>
+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> ssid=<SSID hexdump> configurator=<configurator-id>
+or for legacy (PSK/SAE) provisioning for a station Enrollee:
+> dpp_auth_init peer=<qr-code-id> conf=sta-psk ssid=<SSID hexdump> pass=<passphrase hexdump>
-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,
+The DPP values will be printed in the console. Save these 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.
@@ -156,7 +165,7 @@
> dpp_configurator_add
(returns configurator id)
-> dpp_configurator_sign conf=<ap-dpp|sta-dpp> configurator=<configurator-id>
+> dpp_configurator_sign conf=<ap-dpp|sta-dpp> configurator=<configurator-id> ssid=<SSID hexdump>
Sample AP configuration files after provisioning
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index b9b5d9d..5f8c8f6 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -270,10 +270,6 @@
# bridge interfaces (commit 'bridge: respect RFC2863 operational state')').
#CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y
-# IEEE 802.11w (management frame protection), also known as PMF
-# Driver support is also needed for IEEE 802.11w.
-CONFIG_IEEE80211W=y
-
# Support Operating Channel Validation
#CONFIG_OCV=y
@@ -439,11 +435,7 @@
# either wpa_supplicant or hostapd are run.
CONFIG_NO_RANDOM_POOL=y
-# IEEE 802.11n (High Throughput) support (mainly for AP mode)
-CONFIG_IEEE80211N=y
-
# IEEE 802.11ac (Very High Throughput) support (mainly for AP mode)
-# (depends on CONFIG_IEEE80211N)
#CONFIG_IEEE80211AC=y
# Wireless Network Management (IEEE Std 802.11v-2011)
@@ -507,10 +499,13 @@
#CONFIG_FST=y
# Support Multi Band Operation
-#CONFIG_MBO=y
+CONFIG_MBO=y
# Fast Initial Link Setup (FILS) (IEEE 802.11ai)
-#CONFIG_FILS=y
+CONFIG_FILS=y
+
+# EAP Re-authentication protocol
+CONFIG_ERP=y
# Support RSN on IBSS networks
# This is needed to be able to use mode=1 network profile with proto=RSN and
@@ -536,10 +531,9 @@
#CONFIG_BGSCAN_LEARN=y
# Opportunistic Wireless Encryption (OWE)
-# Experimental implementation of draft-harkins-owe-07.txt
CONFIG_OWE=y
-# Easy Connect (Device Provisioning Protocol - DPP)
+# Easy Connect (Device Provisioning Protocol - DPP R1)
CONFIG_DPP=y
# WPA3-Personal (SAE)
@@ -549,4 +543,17 @@
CONFIG_SUITEB=y
CONFIG_SUITEB192=y
+# WLAN Authentication and Privacy Infrastructure (WAPI): interface only.
+# Configure the building of the interface which allows WAPI configuration.
+# Note: does not configure WAPI implementation itself.
+#CONFIG_WAPI_INTERFACE=y
+
+# Wired equivalent privacy (WEP)
+# WEP is an obsolete cryptographic data confidentiality algorithm that is not
+# considered secure. It should not be used for anything anymore. The
+# functionality needed to use WEP is available in the current wpa_supplicant
+# release under this optional build parameter. This functionality is subject to
+# be completely removed in a future release.
+CONFIG_WEP=y
+
include $(wildcard $(LOCAL_PATH)/android_config_*.inc)
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 4e19169..6241682 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -44,7 +44,6 @@
#endif /* CONFIG_WPS */
-#ifdef CONFIG_IEEE80211N
static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
struct hostapd_config *conf,
@@ -67,7 +66,7 @@
if (!ssid->p2p_group) {
if (!ssid->vht_center_freq1 ||
- conf->vht_oper_chwidth == VHT_CHANWIDTH_USE_HT)
+ conf->vht_oper_chwidth == CHANWIDTH_USE_HT)
goto no_vht;
ieee80211_freq_to_chan(ssid->vht_center_freq1,
&conf->vht_oper_centr_freq_seg0_idx);
@@ -78,14 +77,14 @@
#ifdef CONFIG_P2P
switch (conf->vht_oper_chwidth) {
- case VHT_CHANWIDTH_80MHZ:
- case VHT_CHANWIDTH_80P80MHZ:
+ case CHANWIDTH_80MHZ:
+ case 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:
+ case 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",
@@ -97,14 +96,14 @@
* try oper_cwidth 160 MHz first then VHT 80 MHz, if 160 MHz is
* not supported.
*/
- conf->vht_oper_chwidth = VHT_CHANWIDTH_160MHZ;
+ conf->vht_oper_chwidth = CHANWIDTH_160MHZ;
center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel);
if (center_chan) {
wpa_printf(MSG_DEBUG,
"VHT center channel %u for auto-selected 160 MHz bandwidth",
center_chan);
} else {
- conf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
+ conf->vht_oper_chwidth = CHANWIDTH_80MHZ;
center_chan = wpas_p2p_get_vht80_center(wpa_s, mode,
channel);
wpa_printf(MSG_DEBUG,
@@ -128,9 +127,8 @@
conf->channel);
conf->vht_oper_centr_freq_seg0_idx =
conf->channel + conf->secondary_channel * 2;
- conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
+ conf->vht_oper_chwidth = CHANWIDTH_USE_HT;
}
-#endif /* CONFIG_IEEE80211N */
int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
@@ -149,7 +147,6 @@
/* TODO: enable HT40 if driver supports it;
* drop to 11b if driver does not support 11g */
-#ifdef CONFIG_IEEE80211N
/*
* Enable HT20 if the driver supports it, by setting conf->ieee80211n
* and a mask of allowed capabilities within conf->ht_capab.
@@ -239,6 +236,11 @@
conf->vht_capab |= mode->vht_capab;
wpas_conf_ap_vht(wpa_s, ssid, conf, mode);
}
+
+ if (mode->he_capab[wpas_mode_to_ieee80211_mode(
+ ssid->mode)].he_supported &&
+ ssid->he)
+ conf->ieee80211ax = 1;
}
}
@@ -264,7 +266,6 @@
conf->no_pri_sec_switch = 1;
}
}
-#endif /* CONFIG_IEEE80211N */
return 0;
}
@@ -343,7 +344,9 @@
#endif /* CONFIG_IEEE80211AX */
bss->isolate = !wpa_s->conf->p2p_intra_bss;
+ bss->extended_key_id = wpa_s->conf->extended_key_id;
bss->force_per_enrollee_psk = wpa_s->global->p2p_per_sta_psk;
+ bss->wpa_deny_ptk0_rekey = ssid->wpa_deny_ptk0_rekey;
if (ssid->p2p_group) {
os_memcpy(bss->ip_addr_go, wpa_s->p2pdev->conf->ip_addr_go, 4);
@@ -376,7 +379,9 @@
else
bss->wpa_key_mgmt = ssid->key_mgmt;
bss->wpa_pairwise = ssid->pairwise_cipher;
- if (ssid->psk_set) {
+ if (wpa_key_mgmt_sae(bss->wpa_key_mgmt) && ssid->passphrase) {
+ bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
+ } else if (ssid->psk_set) {
bin_clear_free(bss->ssid.wpa_psk, sizeof(*bss->ssid.wpa_psk));
bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
if (bss->ssid.wpa_psk == NULL)
@@ -386,6 +391,7 @@
bss->ssid.wpa_psk_set = 1;
} else if (ssid->passphrase) {
bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
+#ifdef CONFIG_WEP
} else if (ssid->wep_key_len[0] || ssid->wep_key_len[1] ||
ssid->wep_key_len[2] || ssid->wep_key_len[3]) {
struct hostapd_wep_keys *wep = &bss->ssid.wep;
@@ -401,7 +407,36 @@
}
wep->idx = ssid->wep_tx_keyidx;
wep->keys_set = 1;
+#endif /* CONFIG_WEP */
}
+#ifdef CONFIG_SAE
+ if (ssid->sae_password) {
+ struct sae_password_entry *pw;
+
+ pw = os_zalloc(sizeof(*pw));
+ if (!pw)
+ return -1;
+ os_memset(pw->peer_addr, 0xff, ETH_ALEN);
+ pw->password = os_strdup(ssid->sae_password);
+ if (!pw->password) {
+ os_free(pw);
+ return -1;
+ }
+ if (ssid->sae_password_id) {
+ pw->identifier = os_strdup(ssid->sae_password_id);
+ if (!pw->identifier) {
+ str_clear_free(pw->password);
+ os_free(pw);
+ return -1;
+ }
+ }
+
+ pw->next = bss->sae_passwords;
+ bss->sae_passwords = pw;
+ }
+
+ bss->sae_pwe = wpa_s->conf->sae_pwe;
+#endif /* CONFIG_SAE */
if (wpa_s->conf->go_interworking) {
wpa_printf(MSG_DEBUG,
@@ -454,11 +489,12 @@
bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
bss->rsn_pairwise);
- if (bss->wpa && bss->ieee802_1x)
+ if (bss->wpa && bss->ieee802_1x) {
bss->ssid.security_policy = SECURITY_WPA;
- else if (bss->wpa)
+ } else if (bss->wpa) {
bss->ssid.security_policy = SECURITY_WPA_PSK;
- else if (bss->ieee802_1x) {
+#ifdef CONFIG_WEP
+ } else if (bss->ieee802_1x) {
int cipher = WPA_CIPHER_NONE;
bss->ssid.security_policy = SECURITY_IEEE_802_1X;
bss->ssid.wep.default_len = bss->default_wep_key_len;
@@ -476,6 +512,7 @@
bss->wpa_group = cipher;
bss->wpa_pairwise = cipher;
bss->rsn_pairwise = cipher;
+#endif /* CONFIG_WEP */
} else {
bss->ssid.security_policy = SECURITY_PLAINTEXT;
bss->wpa_group = WPA_CIPHER_NONE;
@@ -495,10 +532,8 @@
bss->wpa_group_rekey = 86400;
}
-#ifdef CONFIG_IEEE80211W
if (ssid->ieee80211w != MGMT_FRAME_PROTECTION_DEFAULT)
bss->ieee80211w = ssid->ieee80211w;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
bss->ocv = ssid->ocv;
@@ -572,6 +607,8 @@
bss->ftm_responder = wpa_s->conf->ftm_responder;
bss->ftm_initiator = wpa_s->conf->ftm_initiator;
+ bss->transition_disable = ssid->transition_disable;
+
return 0;
}
@@ -742,6 +779,21 @@
ssid->frequency = 2462; /* default channel 11 */
params.freq.freq = ssid->frequency;
+ if ((ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO) &&
+ ssid->enable_edmg) {
+ u8 primary_channel;
+
+ if (ieee80211_freq_to_chan(ssid->frequency, &primary_channel) ==
+ NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_WARNING,
+ "EDMG: Failed to get the primary channel");
+ return -1;
+ }
+
+ hostapd_encode_edmg_chan(ssid->enable_edmg, ssid->edmg_channel,
+ primary_channel, ¶ms.freq.edmg);
+ }
+
params.wpa_proto = ssid->proto;
if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
@@ -791,7 +843,6 @@
return -1;
hapd_iface->owner = wpa_s;
hapd_iface->drv_flags = wpa_s->drv_flags;
- hapd_iface->smps_modes = wpa_s->drv_smps_modes;
hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads;
hapd_iface->extended_capa = wpa_s->extended_capa;
hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask;
@@ -880,6 +931,8 @@
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
wpa_s->assoc_freq = ssid->frequency;
+ wpa_s->ap_iface->conf->enable_edmg = ssid->enable_edmg;
+ wpa_s->ap_iface->conf->edmg_channel = ssid->edmg_channel;
#if defined(CONFIG_P2P) && defined(CONFIG_ACS)
if (wpa_s->p2p_go_do_acs) {
@@ -1387,7 +1440,7 @@
void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
- int offset, int width, int cf1, int cf2)
+ int offset, int width, int cf1, int cf2, int finished)
{
struct hostapd_iface *iface = wpa_s->ap_iface;
@@ -1399,7 +1452,7 @@
if (wpa_s->current_ssid)
wpa_s->current_ssid->frequency = freq;
hostapd_event_ch_switch(iface->bss[0], freq, ht,
- offset, width, cf1, cf2);
+ offset, width, cf1, cf2, finished);
}
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 447b551..6c6e94c 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -54,7 +54,7 @@
struct csa_settings *settings);
int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *txtaddr);
void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
- int offset, int width, int cf1, int cf2);
+ int offset, int width, int cf1, int cf2, int finished);
struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
int ndef);
#ifdef CONFIG_AP
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 9b19f37..127f43e 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -431,6 +431,7 @@
struct os_reltime *fetch_time)
{
struct wpa_bss *bss;
+ char extra[50];
bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
if (bss == NULL)
@@ -456,10 +457,15 @@
dl_list_add_tail(&wpa_s->bss, &bss->list);
dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
wpa_s->num_bss++;
+ if (!is_zero_ether_addr(bss->hessid))
+ os_snprintf(extra, sizeof(extra), " HESSID " MACSTR,
+ MAC2STR(bss->hessid));
+ else
+ extra[0] = '\0';
wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR
- " SSID '%s' freq %d",
+ " SSID '%s' freq %d%s",
bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len),
- bss->freq);
+ bss->freq, extra);
wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
return bss;
}
@@ -900,7 +906,7 @@
}
}
- wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u",
+ wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%zu/%zu",
wpa_s->last_scan_res_used, wpa_s->last_scan_res_size);
}
@@ -1032,23 +1038,30 @@
#ifdef CONFIG_P2P
/**
- * wpa_bss_get_p2p_dev_addr - Fetch a BSS table entry based on P2P Device Addr
+ * wpa_bss_get_p2p_dev_addr - Fetch the latest BSS table entry based on P2P Device Addr
* @wpa_s: Pointer to wpa_supplicant data
* @dev_addr: P2P Device Address of the GO
* Returns: Pointer to the BSS entry or %NULL if not found
+ *
+ * This function tries to find the entry that has the most recent update. This
+ * can help in finding the correct entry in cases where the SSID of the P2P
+ * Device may have changed recently.
*/
struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
const u8 *dev_addr)
{
- struct wpa_bss *bss;
+ struct wpa_bss *bss, *found = NULL;
dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
u8 addr[ETH_ALEN];
if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
- addr) == 0 &&
- os_memcmp(addr, dev_addr, ETH_ALEN) == 0)
- return bss;
+ addr) != 0 ||
+ os_memcmp(addr, dev_addr, ETH_ALEN) != 0)
+ continue;
+ if (!found ||
+ os_reltime_before(&found->last_update, &bss->last_update))
+ found = bss;
}
- return NULL;
+ return found;
}
#endif /* CONFIG_P2P */
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 3ce8cd3..0716761 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -18,6 +18,7 @@
#define WPA_BSS_AUTHENTICATED BIT(4)
#define WPA_BSS_ASSOCIATED BIT(5)
#define WPA_BSS_ANQP_FETCH_TRIED BIT(6)
+#define WPA_BSS_OWE_TRANSITION BIT(7)
struct wpa_bss_anqp_elem {
struct dl_list list;
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index a7ca41c..e1d9824 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-2018, 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.
@@ -12,6 +12,7 @@
#include "utils/uuid.h"
#include "utils/ip_addr.h"
#include "common/ieee802_1x_defs.h"
+#include "common/sae.h"
#include "crypto/sha1.h"
#include "rsn_supp/wpa.h"
#include "eap_peer/eap.h"
@@ -740,12 +741,10 @@
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)
val |= WPA_KEY_MGMT_PSK_SHA256;
else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
else if (os_strcmp(start, "WPS") == 0)
val |= WPA_KEY_MGMT_WPS;
@@ -910,7 +909,6 @@
#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
ret = os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
pos == buf ? "" : " ");
@@ -930,7 +928,6 @@
}
pos += ret;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
@@ -1614,7 +1611,7 @@
#ifdef CONFIG_EXT_PASSWORD
if (os_strncmp(value, "ext:", 4) == 0) {
char *name = os_strdup(value + 4);
- if (name == NULL)
+ if (!name)
return -1;
bin_clear_free(ssid->eap.password, ssid->eap.password_len);
ssid->eap.password = (u8 *) name;
@@ -1630,9 +1627,9 @@
size_t res_len;
tmp = wpa_config_parse_string(value, &res_len);
- if (tmp == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: failed to parse "
- "password.", line);
+ if (!tmp) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: failed to parse password.", line);
return -1;
}
wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
@@ -1650,13 +1647,14 @@
/* NtPasswordHash: hash:<32 hex digits> */
if (os_strlen(value + 5) != 2 * 16) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid password hash length "
- "(expected 32 hex digits)", line);
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid password hash length (expected 32 hex digits)",
+ line);
return -1;
}
hash = os_malloc(16);
- if (hash == NULL)
+ if (!hash)
return -1;
if (hexstr2bin(value + 5, hash, 16)) {
@@ -1683,19 +1681,118 @@
}
+static int wpa_config_parse_machine_password(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ u8 *hash;
+
+ if (os_strcmp(value, "NULL") == 0) {
+ if (!ssid->eap.machine_password)
+ return 1; /* Already unset */
+ wpa_printf(MSG_DEBUG,
+ "Unset configuration string 'machine_password'");
+ bin_clear_free(ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ ssid->eap.machine_password = NULL;
+ ssid->eap.machine_password_len = 0;
+ return 0;
+ }
+
+#ifdef CONFIG_EXT_PASSWORD
+ if (os_strncmp(value, "ext:", 4) == 0) {
+ char *name = os_strdup(value + 4);
+
+ if (!name)
+ return -1;
+ bin_clear_free(ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ ssid->eap.machine_password = (u8 *) name;
+ ssid->eap.machine_password_len = os_strlen(name);
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
+ ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
+ return 0;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
+ if (os_strncmp(value, "hash:", 5) != 0) {
+ char *tmp;
+ size_t res_len;
+
+ tmp = wpa_config_parse_string(value, &res_len);
+ if (!tmp) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: failed to parse machine_password.",
+ line);
+ return -1;
+ }
+ wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
+ (u8 *) tmp, res_len);
+
+ bin_clear_free(ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ ssid->eap.machine_password = (u8 *) tmp;
+ ssid->eap.machine_password_len = res_len;
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
+
+ return 0;
+ }
+
+
+ /* NtPasswordHash: hash:<32 hex digits> */
+ if (os_strlen(value + 5) != 2 * 16) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid machine_password hash length (expected 32 hex digits)",
+ line);
+ return -1;
+ }
+
+ hash = os_malloc(16);
+ if (!hash)
+ return -1;
+
+ if (hexstr2bin(value + 5, hash, 16)) {
+ os_free(hash);
+ wpa_printf(MSG_ERROR, "Line %d: Invalid machine_password hash",
+ line);
+ return -1;
+ }
+
+ wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
+
+ if (ssid->eap.machine_password &&
+ ssid->eap.machine_password_len == 16 &&
+ os_memcmp(ssid->eap.machine_password, hash, 16) == 0 &&
+ (ssid->eap.flags & EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH)) {
+ bin_clear_free(hash, 16);
+ return 1;
+ }
+ bin_clear_free(ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ ssid->eap.machine_password = hash;
+ ssid->eap.machine_password_len = 16;
+ ssid->eap.flags |= EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
+
+ return 0;
+}
+
+
#ifndef NO_CONFIG_WRITE
+
static char * wpa_config_write_password(const struct parse_data *data,
struct wpa_ssid *ssid)
{
char *buf;
- if (ssid->eap.password == NULL)
+ if (!ssid->eap.password)
return NULL;
#ifdef CONFIG_EXT_PASSWORD
if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
buf = os_zalloc(4 + ssid->eap.password_len + 1);
- if (buf == NULL)
+ if (!buf)
return NULL;
os_memcpy(buf, "ext:", 4);
os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len);
@@ -1709,7 +1806,7 @@
}
buf = os_malloc(5 + 32 + 1);
- if (buf == NULL)
+ if (!buf)
return NULL;
os_memcpy(buf, "hash:", 5);
@@ -1717,10 +1814,50 @@
return buf;
}
+
+
+static char * wpa_config_write_machine_password(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ char *buf;
+
+ if (!ssid->eap.machine_password)
+ return NULL;
+
+#ifdef CONFIG_EXT_PASSWORD
+ if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD) {
+ buf = os_zalloc(4 + ssid->eap.machine_password_len + 1);
+ if (!buf)
+ return NULL;
+ os_memcpy(buf, "ext:", 4);
+ os_memcpy(buf + 4, ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ return buf;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
+ if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH)) {
+ return wpa_config_write_string(
+ ssid->eap.machine_password,
+ ssid->eap.machine_password_len);
+ }
+
+ buf = os_malloc(5 + 32 + 1);
+ if (!buf)
+ return NULL;
+
+ os_memcpy(buf, "hash:", 5);
+ wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.machine_password, 16);
+
+ return buf;
+}
+
#endif /* NO_CONFIG_WRITE */
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_WEP
+
static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
const char *value, int idx)
{
@@ -1831,6 +1968,8 @@
}
#endif /* NO_CONFIG_WRITE */
+#endif /* CONFIG_WEP */
+
#ifdef CONFIG_P2P
@@ -2141,23 +2280,24 @@
/* STR: Define a string variable for an ASCII string; f = field name */
#ifdef NO_CONFIG_WRITE
#define _STR(f) #f, wpa_config_parse_str, OFFSET(f)
-#define _STRe(f) #f, wpa_config_parse_str, OFFSET(eap.f)
+#define _STRe(f, m) #f, wpa_config_parse_str, OFFSET(eap.m)
#else /* NO_CONFIG_WRITE */
#define _STR(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(f)
-#define _STRe(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(eap.f)
+#define _STRe(f, m) #f, wpa_config_parse_str, wpa_config_write_str, \
+ OFFSET(eap.m)
#endif /* NO_CONFIG_WRITE */
#define STR(f) _STR(f), NULL, NULL, NULL, 0
-#define STRe(f) _STRe(f), NULL, NULL, NULL, 0
+#define STRe(f, m) _STRe(f, m), NULL, NULL, NULL, 0
#define STR_KEY(f) _STR(f), NULL, NULL, NULL, 1
-#define STR_KEYe(f) _STRe(f), NULL, NULL, NULL, 1
+#define STR_KEYe(f, m) _STRe(f, m), NULL, NULL, NULL, 1
/* STR_LEN: Define a string variable with a separate variable for storing the
* data length. Unlike STR(), this can be used to store arbitrary binary data
* (i.e., even nul termination character). */
#define _STR_LEN(f) _STR(f), OFFSET(f ## _len)
-#define _STR_LENe(f) _STRe(f), OFFSET(eap.f ## _len)
+#define _STR_LENe(f, m) _STRe(f, m), OFFSET(eap.m ## _len)
#define STR_LEN(f) _STR_LEN(f), NULL, NULL, 0
-#define STR_LENe(f) _STR_LENe(f), NULL, NULL, 0
+#define STR_LENe(f, m) _STR_LENe(f, m), NULL, NULL, 0
#define STR_LEN_KEY(f) _STR_LEN(f), NULL, NULL, 1
/* STR_RANGE: Like STR_LEN(), but with minimum and maximum allowed length
@@ -2168,17 +2308,17 @@
#ifdef NO_CONFIG_WRITE
#define _INT(f) #f, wpa_config_parse_int, OFFSET(f), (void *) 0
-#define _INTe(f) #f, wpa_config_parse_int, OFFSET(eap.f), (void *) 0
+#define _INTe(f, m) #f, wpa_config_parse_int, OFFSET(eap.m), (void *) 0
#else /* NO_CONFIG_WRITE */
#define _INT(f) #f, wpa_config_parse_int, wpa_config_write_int, \
OFFSET(f), (void *) 0
-#define _INTe(f) #f, wpa_config_parse_int, wpa_config_write_int, \
- OFFSET(eap.f), (void *) 0
+#define _INTe(f, m) #f, wpa_config_parse_int, wpa_config_write_int, \
+ OFFSET(eap.m), (void *) 0
#endif /* NO_CONFIG_WRITE */
/* INT: Define an integer variable */
#define INT(f) _INT(f), NULL, NULL, 0
-#define INTe(f) _INTe(f), NULL, NULL, 0
+#define INTe(f, m) _INTe(f, m), NULL, NULL, 0
/* INT_RANGE: Define an integer variable with allowed value range */
#define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0
@@ -2240,69 +2380,95 @@
{ INT_RANGE(ht, 0, 1) },
{ INT_RANGE(vht, 0, 1) },
{ INT_RANGE(ht40, -1, 1) },
- { INT_RANGE(max_oper_chwidth, VHT_CHANWIDTH_USE_HT,
- VHT_CHANWIDTH_80P80MHZ) },
+ { INT_RANGE(max_oper_chwidth, CHANWIDTH_USE_HT,
+ CHANWIDTH_80P80MHZ) },
{ INT(vht_center_freq1) },
{ INT(vht_center_freq2) },
#ifdef IEEE8021X_EAPOL
{ FUNC(eap) },
- { STR_LENe(identity) },
- { STR_LENe(anonymous_identity) },
- { STR_LENe(imsi_identity) },
+ { STR_LENe(identity, identity) },
+ { STR_LENe(anonymous_identity, anonymous_identity) },
+ { STR_LENe(imsi_identity, imsi_identity) },
+ { STR_LENe(machine_identity, machine_identity) },
{ FUNC_KEY(password) },
- { STRe(ca_cert) },
- { STRe(ca_path) },
- { STRe(client_cert) },
- { STRe(private_key) },
- { 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) },
- { STRe(ca_cert2) },
- { STRe(ca_path2) },
- { STRe(client_cert2) },
- { STRe(private_key2) },
- { 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) },
- { STRe(phase1) },
- { STRe(phase2) },
- { STRe(pcsc) },
- { STR_KEYe(pin) },
- { STRe(engine_id) },
- { STRe(key_id) },
- { STRe(cert_id) },
- { STRe(ca_cert_id) },
- { STR_KEYe(pin2) },
- { STRe(engine2_id) },
- { STRe(key2_id) },
- { STRe(cert2_id) },
- { STRe(ca_cert2_id) },
- { INTe(engine) },
- { INTe(engine2) },
+ { FUNC_KEY(machine_password) },
+ { STRe(ca_cert, cert.ca_cert) },
+ { STRe(ca_path, cert.ca_path) },
+ { STRe(client_cert, cert.client_cert) },
+ { STRe(private_key, cert.private_key) },
+ { STR_KEYe(private_key_passwd, cert.private_key_passwd) },
+ { STRe(dh_file, cert.dh_file) },
+ { STRe(subject_match, cert.subject_match) },
+ { STRe(check_cert_subject, cert.check_cert_subject) },
+ { STRe(altsubject_match, cert.altsubject_match) },
+ { STRe(domain_suffix_match, cert.domain_suffix_match) },
+ { STRe(domain_match, cert.domain_match) },
+ { STRe(ca_cert2, phase2_cert.ca_cert) },
+ { STRe(ca_path2, phase2_cert.ca_path) },
+ { STRe(client_cert2, phase2_cert.client_cert) },
+ { STRe(private_key2, phase2_cert.private_key) },
+ { STR_KEYe(private_key2_passwd, phase2_cert.private_key_passwd) },
+ { STRe(dh_file2, phase2_cert.dh_file) },
+ { STRe(subject_match2, phase2_cert.subject_match) },
+ { STRe(check_cert_subject2, phase2_cert.check_cert_subject) },
+ { STRe(altsubject_match2, phase2_cert.altsubject_match) },
+ { STRe(domain_suffix_match2, phase2_cert.domain_suffix_match) },
+ { STRe(domain_match2, phase2_cert.domain_match) },
+ { STRe(phase1, phase1) },
+ { STRe(phase2, phase2) },
+ { STRe(machine_phase2, machine_phase2) },
+ { STRe(pcsc, pcsc) },
+ { STR_KEYe(pin, cert.pin) },
+ { STRe(engine_id, cert.engine_id) },
+ { STRe(key_id, cert.key_id) },
+ { STRe(cert_id, cert.cert_id) },
+ { STRe(ca_cert_id, cert.ca_cert_id) },
+ { STR_KEYe(pin2, phase2_cert.pin) },
+ { STRe(engine_id2, phase2_cert.engine_id) },
+ { STRe(key_id2, phase2_cert.key_id) },
+ { STRe(cert_id2, phase2_cert.cert_id) },
+ { STRe(ca_cert_id2, phase2_cert.ca_cert_id) },
+ { INTe(engine, cert.engine) },
+ { INTe(engine2, phase2_cert.engine) },
+ { STRe(machine_ca_cert, machine_cert.ca_cert) },
+ { STRe(machine_ca_path, machine_cert.ca_path) },
+ { STRe(machine_client_cert, machine_cert.client_cert) },
+ { STRe(machine_private_key, machine_cert.private_key) },
+ { STR_KEYe(machine_private_key_passwd,
+ machine_cert.private_key_passwd) },
+ { STRe(machine_dh_file, machine_cert.dh_file) },
+ { STRe(machine_subject_match, machine_cert.subject_match) },
+ { STRe(machine_check_cert_subject, machine_cert.check_cert_subject) },
+ { STRe(machine_altsubject_match, machine_cert.altsubject_match) },
+ { STRe(machine_domain_suffix_match,
+ machine_cert.domain_suffix_match) },
+ { STRe(machine_domain_match, machine_cert.domain_match) },
+ { STR_KEYe(machine_pin, machine_cert.pin) },
+ { STRe(machine_engine_id, machine_cert.engine_id) },
+ { STRe(machine_key_id, machine_cert.key_id) },
+ { STRe(machine_cert_id, machine_cert.cert_id) },
+ { STRe(machine_ca_cert_id, machine_cert.ca_cert_id) },
+ { INTe(machine_engine, machine_cert.engine) },
+ { INTe(machine_ocsp, machine_cert.ocsp) },
{ INT(eapol_flags) },
- { INTe(sim_num) },
- { STRe(openssl_ciphers) },
- { INTe(erp) },
+ { INTe(sim_num, sim_num) },
+ { STRe(openssl_ciphers, openssl_ciphers) },
+ { INTe(erp, erp) },
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_WEP
{ FUNC_KEY(wep_key0) },
{ FUNC_KEY(wep_key1) },
{ FUNC_KEY(wep_key2) },
{ FUNC_KEY(wep_key3) },
{ INT(wep_tx_keyidx) },
+#endif /* CONFIG_WEP */
{ INT(priority) },
#ifdef IEEE8021X_EAPOL
{ INT(eap_workaround) },
- { STRe(pac_file) },
- { INTe(fragment_size) },
- { INTe(ocsp) },
+ { STRe(pac_file, pac_file) },
+ { INTe(fragment_size, fragment_size) },
+ { INTe(ocsp, cert.ocsp) },
+ { INTe(ocsp2, phase2_cert.ocsp) },
#endif /* IEEE8021X_EAPOL */
#ifdef CONFIG_MESH
{ INT_RANGE(mode, 0, 5) },
@@ -2314,16 +2480,16 @@
{ INT_RANGE(proactive_key_caching, 0, 1) },
{ INT_RANGE(disabled, 0, 2) },
{ STR(id_str) },
-#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) },
+ { INT_RANGE(frequency, 0, 70200) },
{ INT_RANGE(fixed_freq, 0, 1) },
+ { INT_RANGE(enable_edmg, 0, 1) },
+ { INT_RANGE(edmg_channel, 9, 13) },
#ifdef CONFIG_ACS
{ INT_RANGE(acs, 0, 1) },
#endif /* CONFIG_ACS */
@@ -2335,6 +2501,7 @@
{ INT(dot11MeshHoldingTimeout) },
#endif /* CONFIG_MESH */
{ INT(wpa_ptk_rekey) },
+ { INT_RANGE(wpa_deny_ptk0_rekey, 0, 2) },
{ INT(group_rekey) },
{ STR(bgscan) },
{ INT_RANGE(ignore_broadcast_ssid, 0, 2) },
@@ -2377,6 +2544,9 @@
{ INT_RANGE(vht_tx_mcs_nss_7, -1, 3) },
{ INT_RANGE(vht_tx_mcs_nss_8, -1, 3) },
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ { INT_RANGE(disable_he, 0, 1)},
+#endif /* CONFIG_HE_OVERRIDES */
{ INT(ap_max_inactivity) },
{ INT(dtim_period) },
{ INT(beacon_int) },
@@ -2403,10 +2573,15 @@
{ STR_LEN(dpp_netaccesskey) },
{ INT(dpp_netaccesskey_expiry) },
{ STR_LEN(dpp_csign) },
+ { INT_RANGE(dpp_pfs, 0, 2) },
#endif /* CONFIG_DPP */
{ INT_RANGE(owe_group, 0, 65535) },
{ INT_RANGE(owe_only, 0, 1) },
+ { INT_RANGE(owe_ptk_workaround, 0, 1) },
{ INT_RANGE(multi_ap_backhaul_sta, 0, 1) },
+ { INT_RANGE(ft_eap_pmksa_caching, 0, 1) },
+ { INT_RANGE(beacon_prot, 0, 1) },
+ { INT_RANGE(transition_disable, 0, 255) },
};
#undef OFFSET
@@ -2442,7 +2617,7 @@
int wpa_config_add_prio_network(struct wpa_config *config,
struct wpa_ssid *ssid)
{
- int prio;
+ size_t prio;
struct wpa_ssid *prev, **nlist;
/*
@@ -2513,48 +2688,44 @@
#ifdef IEEE8021X_EAPOL
+
+static void eap_peer_config_free_cert(struct eap_peer_cert_config *cert)
+{
+ os_free(cert->ca_cert);
+ os_free(cert->ca_path);
+ os_free(cert->client_cert);
+ os_free(cert->private_key);
+ str_clear_free(cert->private_key_passwd);
+ os_free(cert->dh_file);
+ os_free(cert->subject_match);
+ os_free(cert->check_cert_subject);
+ os_free(cert->altsubject_match);
+ os_free(cert->domain_suffix_match);
+ os_free(cert->domain_match);
+ str_clear_free(cert->pin);
+ os_free(cert->engine_id);
+ os_free(cert->key_id);
+ os_free(cert->cert_id);
+ os_free(cert->ca_cert_id);
+}
+
+
static void eap_peer_config_free(struct eap_peer_config *eap)
{
os_free(eap->eap_methods);
bin_clear_free(eap->identity, eap->identity_len);
os_free(eap->anonymous_identity);
os_free(eap->imsi_identity);
+ os_free(eap->machine_identity);
bin_clear_free(eap->password, eap->password_len);
- os_free(eap->ca_cert);
- os_free(eap->ca_path);
- os_free(eap->client_cert);
- os_free(eap->private_key);
- 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);
- os_free(eap->ca_cert2);
- os_free(eap->ca_path2);
- os_free(eap->client_cert2);
- os_free(eap->private_key2);
- 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);
+ bin_clear_free(eap->machine_password, eap->machine_password_len);
+ eap_peer_config_free_cert(&eap->cert);
+ eap_peer_config_free_cert(&eap->phase2_cert);
+ eap_peer_config_free_cert(&eap->machine_cert);
os_free(eap->phase1);
os_free(eap->phase2);
+ os_free(eap->machine_phase2);
os_free(eap->pcsc);
- str_clear_free(eap->pin);
- os_free(eap->engine_id);
- os_free(eap->key_id);
- os_free(eap->cert_id);
- os_free(eap->ca_cert_id);
- os_free(eap->key2_id);
- os_free(eap->cert2_id);
- os_free(eap->ca_cert2_id);
- str_clear_free(eap->pin2);
- os_free(eap->engine2_id);
os_free(eap->otp);
os_free(eap->pending_req_otp);
os_free(eap->pac_file);
@@ -2562,6 +2733,7 @@
str_clear_free(eap->external_sim_resp);
os_free(eap->openssl_ciphers);
}
+
#endif /* IEEE8021X_EAPOL */
@@ -2608,6 +2780,9 @@
dl_list_del(&psk->list);
bin_clear_free(psk, sizeof(*psk));
}
+#ifdef CONFIG_SAE
+ sae_deinit_pt(ssid->pt);
+#endif /* CONFIG_SAE */
bin_clear_free(ssid, sizeof(*ssid));
}
@@ -2726,6 +2901,8 @@
#ifdef CONFIG_MBO
os_free(config->non_pref_chan);
#endif /* CONFIG_MBO */
+ os_free(config->dpp_name);
+ os_free(config->dpp_mud_url);
os_free(config);
}
@@ -2855,6 +3032,7 @@
ssid->pairwise_cipher = DEFAULT_PAIRWISE;
ssid->group_cipher = DEFAULT_GROUP;
ssid->key_mgmt = DEFAULT_KEY_MGMT;
+ ssid->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS;
ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
ssid->ht = 1;
#ifdef IEEE8021X_EAPOL
@@ -2900,9 +3078,7 @@
ssid->vht_tx_mcs_nss_8 = -1;
#endif /* CONFIG_VHT_OVERRIDES */
ssid->proactive_key_caching = -1;
-#ifdef CONFIG_IEEE80211W
ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_MACSEC
ssid->mka_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
#endif /* CONFIG_MACSEC */
@@ -2947,6 +3123,15 @@
}
ret = -1;
}
+#ifdef CONFIG_SAE
+ if (os_strcmp(var, "ssid") == 0 ||
+ os_strcmp(var, "psk") == 0 ||
+ os_strcmp(var, "sae_password") == 0 ||
+ os_strcmp(var, "sae_password_id") == 0) {
+ sae_deinit_pt(ssid->pt);
+ ssid->pt = NULL;
+ }
+#endif /* CONFIG_SAE */
break;
}
if (i == NUM_SSID_FIELDS) {
@@ -4113,6 +4298,7 @@
config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
config->cert_in_cb = DEFAULT_CERT_IN_CB;
config->wpa_rsc_relaxation = DEFAULT_WPA_RSC_RELAXATION;
+ config->extended_key_id = DEFAULT_EXTENDED_KEY_ID;
#ifdef CONFIG_MBO
config->mbo_cell_capa = DEFAULT_MBO_CELL_CAPA;
@@ -4138,7 +4324,7 @@
*/
void wpa_config_debug_dump_networks(struct wpa_config *config)
{
- int prio;
+ size_t prio;
struct wpa_ssid *ssid;
for (prio = 0; prio < config->num_prio; prio++) {
@@ -4469,7 +4655,7 @@
struct wpa_config *config, int line, const char *pos)
{
struct p2p_channel *pref = NULL, *n;
- unsigned int num = 0;
+ size_t num = 0;
const char *pos2;
u8 op_class, chan;
@@ -4780,6 +4966,7 @@
{ INT(p2p_go_ht40), 0 },
{ INT(p2p_go_vht), 0 },
{ INT(p2p_go_he), 0 },
+ { INT(p2p_go_edmg), 0 },
{ INT(p2p_disabled), 0 },
{ INT_RANGE(p2p_go_ctwindow, 0, 127), 0 },
{ INT(p2p_no_group_iface), 0 },
@@ -4826,6 +5013,8 @@
{ INT(okc), 0 },
{ INT(pmf), 0 },
{ FUNC(sae_groups), 0 },
+ { INT_RANGE(sae_pwe, 0, 3), 0 },
+ { INT_RANGE(sae_pmkid_in_assoc, 0, 1), 0 },
{ INT(dtim_period), 0 },
{ INT(beacon_int), 0 },
{ FUNC(ap_vendor_elements), 0 },
@@ -4865,9 +5054,17 @@
{ INT_RANGE(ftm_initiator, 0, 1), 0 },
{ INT(gas_rand_addr_lifetime), 0 },
{ INT_RANGE(gas_rand_mac_addr, 0, 2), 0 },
+#ifdef CONFIG_DPP
{ INT_RANGE(dpp_config_processing, 0, 2), 0 },
+ { STR(dpp_name), 0 },
+ { STR(dpp_mud_url), 0 },
+#endif /* CONFIG_DPP */
{ INT_RANGE(coloc_intf_reporting, 0, 1), 0 },
{ INT_RANGE(bss_no_flush_when_down, 0, 1), 0 },
+#ifdef CONFIG_WNM
+ { INT_RANGE(disable_btm, 0, 1), CFG_CHANGED_DISABLE_BTM },
+ { INT_RANGE(extended_key_id, 0, 1), 0 },
+#endif /* CONFIG_WNM */
};
#undef FUNC
@@ -4983,6 +5180,7 @@
"AC item", line);
return -1;
}
+ return ret;
}
#endif /* CONFIG_AP */
if (line < 0)
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 95817ff..0ca27cb 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -44,6 +44,7 @@
#define DEFAULT_MBO_CELL_CAPA MBO_CELL_CAPA_NOT_SUPPORTED
#define DEFAULT_DISASSOC_IMMINENT_RSSI_THRESHOLD -75
#define DEFAULT_OCE_SUPPORT OCE_STA
+#define DEFAULT_EXTENDED_KEY_ID 0
#include "config_ssid.h"
#include "wps/wps.h"
@@ -332,7 +333,7 @@
*/
unsigned int max_bss_load;
- unsigned int num_req_conn_capab;
+ size_t num_req_conn_capab;
u8 *req_conn_capab_proto;
int **req_conn_capab_port;
@@ -374,6 +375,7 @@
#define CFG_CHANGED_P2P_PASSPHRASE_LEN BIT(16)
#define CFG_CHANGED_SCHED_SCAN_PLANS BIT(17)
#define CFG_CHANGED_WOWLAN_TRIGGERS BIT(18)
+#define CFG_CHANGED_DISABLE_BTM BIT(19)
/**
* struct wpa_config - wpa_supplicant configuration data
@@ -402,7 +404,7 @@
* This indicates how many per-priority network lists are included in
* pssid.
*/
- int num_prio;
+ size_t num_prio;
/**
* cred - Head of the credential list
@@ -1089,6 +1091,16 @@
int p2p_go_vht;
/**
+ * p2p_go_edmg - Default mode for EDMG 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_edmg;
+
+ /**
* 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.
@@ -1164,6 +1176,19 @@
int *sae_groups;
/**
+ * sae_pwe - SAE mechanism for PWE derivation
+ * 0 = hunting-and-pecking loop only
+ * 1 = hash-to-element only
+ * 2 = both hunting-and-pecking loop and hash-to-element enabled
+ */
+ int sae_pwe;
+
+ /**
+ * sae_pmkid_in_assoc - Whether to include PMKID in SAE Assoc Req
+ */
+ int sae_pmkid_in_assoc;
+
+ /**
* dtim_period - Default DTIM period in Beacon intervals
*
* This parameter can be used to set the default value for network
@@ -1491,6 +1516,16 @@
int dpp_config_processing;
/**
+ * dpp_name - Name for Enrollee's DPP Configuration Request
+ */
+ char *dpp_name;
+
+ /**
+ * dpp_mud_url - MUD URL for Enrollee's DPP Configuration Request
+ */
+ char *dpp_mud_url;
+
+ /**
* coloc_intf_reporting - Colocated interference reporting
*
* dot11CoLocIntfReportingActivated
@@ -1535,6 +1570,26 @@
* 1 = Do not flush BSS entries when the interface becomes disabled
*/
int bss_no_flush_when_down;
+
+ /**
+ * disable_btm - Disable BSS transition management in STA
+ * - Set to 0 to enable BSS transition management
+ * - Set to 1 to disable BSS transition management
+ *
+ * By default BSS transition management is enabled
+ */
+ int disable_btm;
+
+ /**
+ * extended_key_id - Extended Key ID support
+ *
+ * IEEE Std 802.11-2016 optionally allows to use Key ID 0 and 1 for PTK
+ * keys with Extended Key ID.
+ *
+ * 0 = don't use Extended Key ID
+ * 1 = use Extended Key ID when possible
+ */
+ int extended_key_id;
};
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 2c6035c..52e1372 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Configuration backend: text file
- * Copyright (c) 2003-2012, 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.
@@ -213,8 +213,22 @@
}
}
- if (wpa_config_set(ssid, pos, pos2, *line) < 0)
+ if (wpa_config_set(ssid, pos, pos2, *line) < 0) {
+#ifndef CONFIG_WEP
+ if (os_strcmp(pos, "wep_key0") == 0 ||
+ os_strcmp(pos, "wep_key1") == 0 ||
+ os_strcmp(pos, "wep_key2") == 0 ||
+ os_strcmp(pos, "wep_key3") == 0 ||
+ os_strcmp(pos, "wep_tx_keyidx") == 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: unsupported WEP parameter",
+ *line);
+ ssid->disabled = 1;
+ continue;
+ }
+#endif /* CONFIG_WEP */
errors++;
+ }
}
if (!end) {
@@ -296,7 +310,7 @@
{
struct wpa_config_blob *blob;
char buf[256], *pos;
- unsigned char *encoded = NULL, *nencoded;
+ char *encoded = NULL, *nencoded;
int end = 0;
size_t encoded_len = 0, len;
@@ -653,6 +667,7 @@
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_WEP
static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid)
{
char field[20], *value;
@@ -667,6 +682,7 @@
os_free(value);
}
}
+#endif /* CONFIG_WEP */
#ifdef CONFIG_P2P
@@ -741,13 +757,11 @@
static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
{
- int i;
-
#define STR(t) write_str(f, #t, ssid)
#define INT(t) write_int(f, #t, ssid->t, 0)
-#define INTe(t) write_int(f, #t, ssid->eap.t, 0)
+#define INTe(t, m) write_int(f, #t, ssid->eap.m, 0)
#define INT_DEF(t, def) write_int(f, #t, ssid->t, def)
-#define INT_DEFe(t, def) write_int(f, #t, ssid->eap.t, def)
+#define INT_DEFe(t, m, def) write_int(f, #t, ssid->eap.m, def)
STR(ssid);
INT(scan_ssid);
@@ -774,7 +788,9 @@
STR(identity);
STR(anonymous_identity);
STR(imsi_identity);
+ STR(machine_identity);
STR(password);
+ STR(machine_password);
STR(ca_cert);
STR(ca_path);
STR(client_cert);
@@ -797,8 +813,20 @@
STR(altsubject_match2);
STR(domain_suffix_match2);
STR(domain_match2);
+ STR(machine_ca_cert);
+ STR(machine_ca_path);
+ STR(machine_client_cert);
+ STR(machine_private_key);
+ STR(machine_private_key_passwd);
+ STR(machine_dh_file);
+ STR(machine_subject_match);
+ STR(machine_check_cert_subject);
+ STR(machine_altsubject_match);
+ STR(machine_domain_suffix_match);
+ STR(machine_domain_match);
STR(phase1);
STR(phase2);
+ STR(machine_phase2);
STR(pcsc);
STR(pin);
STR(engine_id);
@@ -810,26 +838,37 @@
STR(engine2_id);
STR(cert2_id);
STR(ca_cert2_id);
- INTe(engine);
- INTe(engine2);
+ INTe(engine, cert.engine);
+ INTe(engine2, phase2_cert.engine);
+ INTe(machine_engine, machine_cert.engine);
INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
STR(openssl_ciphers);
- INTe(erp);
+ INTe(erp, erp);
#endif /* IEEE8021X_EAPOL */
- for (i = 0; i < 4; i++)
- write_wep_key(f, i, ssid);
- INT(wep_tx_keyidx);
+#ifdef CONFIG_WEP
+ {
+ int i;
+
+ for (i = 0; i < 4; i++)
+ write_wep_key(f, i, ssid);
+ INT(wep_tx_keyidx);
+ }
+#endif /* CONFIG_WEP */
INT(priority);
#ifdef IEEE8021X_EAPOL
INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
STR(pac_file);
- INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
- INTe(ocsp);
- INT_DEFe(sim_num, DEFAULT_USER_SELECTED_SIM);
+ INT_DEFe(fragment_size, fragment_size, DEFAULT_FRAGMENT_SIZE);
+ INTe(ocsp, cert.ocsp);
+ INTe(ocsp2, phase2_cert.ocsp);
+ INTe(machine_ocsp, machine_cert.ocsp);
+ INT_DEFe(sim_num, sim_num, DEFAULT_USER_SELECTED_SIM);
#endif /* IEEE8021X_EAPOL */
INT(mode);
INT(no_auto_peer);
INT(frequency);
+ INT(enable_edmg);
+ INT(edmg_channel);
INT(fixed_freq);
#ifdef CONFIG_ACS
INT(acs);
@@ -846,10 +885,8 @@
INT(pbss);
INT(wps_disabled);
INT(fils_dh_group);
-#ifdef CONFIG_IEEE80211W
write_int(f, "ieee80211w", ssid->ieee80211w,
MGMT_FRAME_PROTECTION_DEFAULT);
-#endif /* CONFIG_IEEE80211W */
STR(id_str);
#ifdef CONFIG_P2P
write_go_p2p_dev_addr(f, ssid);
@@ -883,6 +920,7 @@
INT_DEF(mesh_rssi_threshold, DEFAULT_MESH_RSSI_THRESHOLD);
#endif /* CONFIG_MESH */
INT(wpa_ptk_rekey);
+ INT(wpa_deny_ptk0_rekey);
INT(group_rekey);
INT(ignore_broadcast_ssid);
#ifdef CONFIG_DPP
@@ -890,10 +928,15 @@
STR(dpp_netaccesskey);
INT(dpp_netaccesskey_expiry);
STR(dpp_csign);
+ INT(dpp_pfs);
#endif /* CONFIG_DPP */
INT(owe_group);
INT(owe_only);
+ INT(owe_ptk_workaround);
INT(multi_ap_backhaul_sta);
+ INT(ft_eap_pmksa_caching);
+ INT(beacon_prot);
+ INT(transition_disable);
#ifdef CONFIG_HT_OVERRIDES
INT_DEF(disable_ht, DEFAULT_DISABLE_HT);
INT_DEF(disable_ht40, DEFAULT_DISABLE_HT40);
@@ -928,6 +971,9 @@
INT_DEF(vht_tx_mcs_nss_7, -1);
INT_DEF(vht_tx_mcs_nss_8, -1);
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ INT(disable_he);
+#endif /* CONFIG_HE_OVERRIDES */
#undef STR
#undef INT
@@ -1080,7 +1126,7 @@
#ifndef CONFIG_NO_CONFIG_BLOBS
static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob)
{
- unsigned char *encoded;
+ char *encoded;
encoded = base64_encode(blob->data, blob->len, NULL);
if (encoded == NULL)
@@ -1269,6 +1315,8 @@
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_edmg)
+ fprintf(f, "p2p_go_edmg=%d\n", config->p2p_go_edmg);
if (config->p2p_go_ctwindow != DEFAULT_P2P_GO_CTWINDOW)
fprintf(f, "p2p_go_ctwindow=%d\n", config->p2p_go_ctwindow);
if (config->p2p_disabled)
@@ -1389,6 +1437,13 @@
fprintf(f, "\n");
}
+ if (config->sae_pwe)
+ fprintf(f, "sae_pwe=%d\n", config->sae_pwe);
+
+ if (config->sae_pmkid_in_assoc)
+ fprintf(f, "sae_pmkid_in_assoc=%d\n",
+ config->sae_pmkid_in_assoc);
+
if (config->ap_vendor_elements) {
int i, len = wpabuf_len(config->ap_vendor_elements);
const u8 *p = wpabuf_head_u8(config->ap_vendor_elements);
@@ -1547,7 +1602,11 @@
if (config->bss_no_flush_when_down)
fprintf(f, "bss_no_flush_when_down=%d\n",
config->bss_no_flush_when_down);
-
+ if (config->disable_btm)
+ fprintf(f, "disable_btm=1\n");
+ if (config->extended_key_id != DEFAULT_EXTENDED_KEY_ID)
+ fprintf(f, "extended_key_id=%d\n",
+ config->extended_key_id);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
@@ -1564,9 +1623,16 @@
#endif /* CONFIG_NO_CONFIG_BLOBS */
int ret = 0;
const char *orig_name = name;
- int tmp_len = os_strlen(name) + 5; /* allow space for .tmp suffix */
- char *tmp_name = os_malloc(tmp_len);
+ int tmp_len;
+ char *tmp_name;
+ if (!name) {
+ wpa_printf(MSG_ERROR, "No configuration file for writing");
+ return -1;
+ }
+
+ tmp_len = os_strlen(name) + 5; /* allow space for .tmp suffix */
+ tmp_name = os_malloc(tmp_len);
if (tmp_name) {
os_snprintf(tmp_name, tmp_len, "%s.tmp", name);
name = tmp_name;
@@ -1594,8 +1660,11 @@
for (ssid = config->ssid; ssid; ssid = ssid->next) {
if (ssid->key_mgmt == WPA_KEY_MGMT_WPS || ssid->temporary)
continue; /* do not save temporary networks */
- if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
- !ssid->passphrase)
+ if (wpa_key_mgmt_wpa_psk_no_sae(ssid->key_mgmt) &&
+ !ssid->psk_set && !ssid->passphrase)
+ continue; /* do not save invalid network */
+ if (wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ !ssid->passphrase && !ssid->sae_password)
continue; /* do not save invalid network */
fprintf(f, "\nnetwork={\n");
wpa_config_write_network(f, ssid);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 1b2b1f1..6737223 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -13,14 +13,18 @@
#include "utils/list.h"
#include "eap_peer/eap_config.h"
-
#define DEFAULT_EAP_WORKAROUND ((unsigned int) -1)
#define DEFAULT_EAPOL_FLAGS (EAPOL_FLAG_REQUIRE_KEY_UNICAST | \
EAPOL_FLAG_REQUIRE_KEY_BROADCAST)
#define DEFAULT_PROTO (WPA_PROTO_WPA | WPA_PROTO_RSN)
#define DEFAULT_KEY_MGMT (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X)
+#ifdef CONFIG_NO_TKIP
+#define DEFAULT_PAIRWISE (WPA_CIPHER_CCMP)
+#define DEFAULT_GROUP (WPA_CIPHER_CCMP)
+#else /* CONFIG_NO_TKIP */
#define DEFAULT_PAIRWISE (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP)
#define DEFAULT_GROUP (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP)
+#endif /* CONFIG_NO_TKIP */
#define DEFAULT_FRAGMENT_SIZE 1398
#define DEFAULT_BG_SCAN_PERIOD -1
@@ -48,6 +52,15 @@
u8 p2p;
};
+enum wpas_mode {
+ WPAS_MODE_INFRA = 0,
+ WPAS_MODE_IBSS = 1,
+ WPAS_MODE_AP = 2,
+ WPAS_MODE_P2P_GO = 3,
+ WPAS_MODE_P2P_GROUP_FORMATION = 4,
+ WPAS_MODE_MESH = 5,
+};
+
/**
* struct wpa_ssid - Network configuration data
*
@@ -204,6 +217,8 @@
*/
char *sae_password_id;
+ struct sae_pt *pt;
+
/**
* ext_psk - PSK/passphrase name in external storage
*
@@ -289,6 +304,7 @@
struct eap_peer_config eap;
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_WEP
#define NUM_WEP_KEYS 4
#define MAX_WEP_KEY_LEN 16
/**
@@ -305,6 +321,7 @@
* wep_tx_keyidx - Default key index for TX frames using WEP
*/
int wep_tx_keyidx;
+#endif /* CONFIG_WEP */
/**
* proactive_key_caching - Enable proactive key caching
@@ -394,14 +411,7 @@
* CCMP, but not both), and psk must also be set (either directly or
* using ASCII passphrase).
*/
- enum wpas_mode {
- WPAS_MODE_INFRA = 0,
- WPAS_MODE_IBSS = 1,
- WPAS_MODE_AP = 2,
- WPAS_MODE_P2P_GO = 3,
- WPAS_MODE_P2P_GROUP_FORMATION = 4,
- WPAS_MODE_MESH = 5,
- } mode;
+ enum wpas_mode mode;
/**
* pbss - Whether to use PBSS. Relevant to DMG networks only.
@@ -444,7 +454,6 @@
*/
char *id_str;
-#ifdef CONFIG_IEEE80211W
/**
* ieee80211w - Whether management frame protection is enabled
*
@@ -458,7 +467,6 @@
* followed).
*/
enum mfp_options ieee80211w;
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
/**
@@ -484,6 +492,23 @@
int frequency;
/**
+ * enable_edmg - Enable EDMG feature in STA/AP mode
+ *
+ * This flag is used for enabling the EDMG capability in STA/AP mode.
+ */
+ int enable_edmg;
+
+ /**
+ * edmg_channel - EDMG channel number
+ *
+ * This value is used to configure the EDMG channel bonding feature.
+ * In AP mode it defines the EDMG channel to start the AP on.
+ * in STA mode it defines the EDMG channel to use for connection
+ * (if supported by AP).
+ */
+ u8 edmg_channel;
+
+ /**
* fixed_freq - Use fixed frequency for IBSS
*/
int fixed_freq;
@@ -534,6 +559,19 @@
*/
int wpa_ptk_rekey;
+ /** wpa_deny_ptk0_rekey - Control PTK0 rekeying
+ *
+ * Rekeying a pairwise key using only keyid 0 (PTK0 rekey) has many
+ * broken implementations and should be avoided when using or
+ * interacting with one.
+ *
+ * 0 = always rekey when configured/instructed
+ * 1 = only rekey when the local driver is explicitly indicating it can
+ * perform this operation without issues
+ * 2 = never allow PTK0 rekeys
+ */
+ enum ptk0_rekey_handling wpa_deny_ptk0_rekey;
+
/**
* group_rekey - Group rekeying time in seconds
*
@@ -745,6 +783,16 @@
vht_tx_mcs_nss_7, vht_tx_mcs_nss_8;
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ /**
+ * disable_he - Disable HE (IEEE 802.11ax) for this network
+ *
+ * By default, use it if it is available, but this can be configured
+ * to 1 to have it disabled.
+ */
+ int disable_he;
+#endif /* CONFIG_HE_OVERRIDES */
+
/**
* ap_max_inactivity - Timeout in seconds to detect STA's inactivity
*
@@ -969,6 +1017,22 @@
size_t dpp_csign_len;
/**
+ * dpp_pfs - DPP PFS
+ * 0: allow PFS to be used or not used
+ * 1: require PFS to be used (note: not compatible with DPP R1)
+ * 2: do not allow PFS to be used
+ */
+ int dpp_pfs;
+
+ /**
+ * dpp_pfs_fallback - DPP PFS fallback selection
+ *
+ * This is an internally used variable (i.e., not used in external
+ * configuration) to track state of the DPP PFS fallback mechanism.
+ */
+ int dpp_pfs_fallback;
+
+ /**
* owe_group - OWE DH Group
*
* 0 = use default (19) first and then try all supported groups one by
@@ -990,6 +1054,19 @@
int owe_only;
/**
+ * owe_ptk_workaround - OWE PTK derivation workaround
+ *
+ * Initial OWE implementation used SHA256 when deriving the PTK for all
+ * OWE groups. This was supposed to change to SHA384 for group 20 and
+ * SHA512 for group 21. This parameter can be used to enable older
+ * behavior mainly for testing purposes. There is no impact to group 19
+ * behavior, but if enabled, this will make group 20 and 21 cases use
+ * SHA256-based PTK derivation which will not work with the updated
+ * OWE implementation on the AP side.
+ */
+ int owe_ptk_workaround;
+
+ /**
* owe_transition_bss_select_count - OWE transition BSS select count
*
* This is an internally used variable (i.e., not used in external
@@ -1005,6 +1082,44 @@
* 1 = Multi-AP backhaul station
*/
int multi_ap_backhaul_sta;
+
+ /**
+ * ft_eap_pmksa_caching - Whether FT-EAP PMKSA caching is allowed
+ * 0 = do not try to use PMKSA caching with FT-EAP
+ * 1 = try to use PMKSA caching with FT-EAP
+ *
+ * This controls whether to try to use PMKSA caching with FT-EAP for the
+ * FT initial mobility domain association.
+ */
+ int ft_eap_pmksa_caching;
+
+ /**
+ * beacon_prot - Whether Beacon protection is enabled
+ *
+ * This depends on management frame protection (ieee80211w) being
+ * enabled.
+ */
+ int beacon_prot;
+
+ /**
+ * transition_disable - Transition Disable indication
+ * The AP can notify authenticated stations to disable transition mode
+ * in their network profiles when the network has completed transition
+ * steps, i.e., once sufficiently large number of APs in the ESS have
+ * been updated to support the more secure alternative. When this
+ * indication is used, the stations are expected to automatically
+ * disable transition mode and less secure security options. This
+ * includes use of WEP, TKIP (including use of TKIP as the group
+ * cipher), and connections without PMF.
+ * Bitmap bits:
+ * bit 0 (0x01): WPA3-Personal (i.e., disable WPA2-Personal = WPA-PSK
+ * and only allow SAE to be used)
+ * bit 1 (0x02): SAE-PK (disable SAE without use of SAE-PK)
+ * bit 2 (0x04): WPA3-Enterprise (move to requiring PMF)
+ * bit 3 (0x08): Enhanced Open (disable use of open network; require
+ * OWE)
+ */
+ u8 transition_disable;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 6328e91..1b7f96e 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Configuration backend: Windows registry
- * Copyright (c) 2003-2008, 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.
@@ -277,6 +277,15 @@
wpa_config_read_reg_dword(hk, TEXT("okc"), &config->okc);
wpa_config_read_reg_dword(hk, TEXT("pmf"), &val);
config->pmf = val;
+ if (wpa_config_read_reg_dword(hk, TEXT("extended_key_id"),
+ &val) == 0) {
+ if (val < 0 || val > 1) {
+ wpa_printf(MSG_ERROR,
+ "Invalid Extended Key ID setting (%d)", val);
+ errors++;
+ }
+ config->extended_key_id = val;
+ }
return errors ? -1 : 0;
}
@@ -823,6 +832,7 @@
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_WEP
static void write_wep_key(HKEY hk, int idx, struct wpa_ssid *ssid)
{
char field[20], *value;
@@ -834,11 +844,12 @@
os_free(value);
}
}
+#endif /* CONFIG_WEP */
static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id)
{
- int i, errors = 0;
+ int errors = 0;
HKEY nhk, netw;
LONG ret;
TCHAR name[5];
@@ -868,9 +879,9 @@
#define STR(t) write_str(netw, #t, ssid)
#define INT(t) write_int(netw, #t, ssid->t, 0)
-#define INTe(t) write_int(netw, #t, ssid->eap.t, 0)
+#define INTe(t, m) write_int(netw, #t, ssid->eap.m, 0)
#define INT_DEF(t, def) write_int(netw, #t, ssid->t, def)
-#define INT_DEFe(t, def) write_int(netw, #t, ssid->eap.t, def)
+#define INT_DEFe(t, m, def) write_int(netw, #t, ssid->eap.m, def)
STR(ssid);
INT(scan_ssid);
@@ -920,32 +931,37 @@
STR(engine2_id);
STR(cert2_id);
STR(ca_cert2_id);
- INTe(engine);
- INTe(engine2);
+ INTe(engine, cert.engine);
+ INTe(engine2, phase2_cert.engine);
INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
#endif /* IEEE8021X_EAPOL */
- for (i = 0; i < 4; i++)
- write_wep_key(netw, i, ssid);
- INT(wep_tx_keyidx);
+#ifdef CONFIG_WEP
+ {
+ int i;
+
+ for (i = 0; i < 4; i++)
+ write_wep_key(netw, i, ssid);
+ INT(wep_tx_keyidx);
+ }
+#endif /* CONFIG_WEP */
INT(priority);
#ifdef IEEE8021X_EAPOL
INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
STR(pac_file);
- INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
+ INT_DEFe(fragment_size, fragment_size, DEFAULT_FRAGMENT_SIZE);
#endif /* IEEE8021X_EAPOL */
INT(mode);
write_int(netw, "proactive_key_caching", ssid->proactive_key_caching,
-1);
INT(disabled);
-#ifdef CONFIG_IEEE80211W
write_int(netw, "ieee80211w", ssid->ieee80211w,
MGMT_FRAME_PROTECTION_DEFAULT);
-#endif /* CONFIG_IEEE80211W */
STR(id_str);
#ifdef CONFIG_HS20
INT(update_identifier);
#endif /* CONFIG_HS20 */
INT(group_rekey);
+ INT(ft_eap_pmksa_caching);
#undef STR
#undef INT
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 198ac56..e0547f1 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -8,7 +8,6 @@
#include "utils/includes.h"
#ifdef CONFIG_TESTING_OPTIONS
-#include <net/ethernet.h>
#include <netinet/ip.h>
#endif /* CONFIG_TESTING_OPTIONS */
@@ -58,6 +57,12 @@
#include "dpp_supplicant.h"
#include "sme.h"
+#ifdef __NetBSD__
+#include <net/if_ether.h>
+#elif !defined(__CYGWIN__) && !defined(CONFIG_NATIVE_WINDOWS)
+#include <net/ethernet.h>
+#endif
+
static int wpa_supplicant_global_iface_list(struct wpa_global *global,
char *buf, int len);
static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
@@ -414,6 +419,64 @@
}
+#ifdef CONFIG_TESTING_OPTIONS
+static int wpas_ctrl_iface_set_dso(struct wpa_supplicant *wpa_s,
+ const char *val)
+{
+ u8 bssid[ETH_ALEN];
+ const char *pos = val;
+ struct driver_signal_override *dso = NULL, *tmp, parsed;
+
+ if (hwaddr_aton(pos, bssid))
+ return -1;
+ pos = os_strchr(pos, ' ');
+
+ dl_list_for_each(tmp, &wpa_s->drv_signal_override,
+ struct driver_signal_override, list) {
+ if (os_memcmp(bssid, tmp->bssid, ETH_ALEN) == 0) {
+ dso = tmp;
+ break;
+ }
+ }
+
+ if (!pos) {
+ /* Remove existing entry */
+ if (dso) {
+ dl_list_del(&dso->list);
+ os_free(dso);
+ }
+ return 0;
+ }
+ pos++;
+
+ /* Update an existing entry or add a new one */
+ os_memset(&parsed, 0, sizeof(parsed));
+ if (sscanf(pos, "%d %d %d %d %d",
+ &parsed.si_current_signal,
+ &parsed.si_avg_signal,
+ &parsed.si_avg_beacon_signal,
+ &parsed.si_current_noise,
+ &parsed.scan_level) != 5)
+ return -1;
+
+ if (!dso) {
+ dso = os_zalloc(sizeof(*dso));
+ if (!dso)
+ return -1;
+ os_memcpy(dso->bssid, bssid, ETH_ALEN);
+ dl_list_add(&wpa_s->drv_signal_override, &dso->list);
+ }
+ dso->si_current_signal = parsed.si_current_signal;
+ dso->si_avg_signal = parsed.si_avg_signal;
+ dso->si_avg_beacon_signal = parsed.si_avg_beacon_signal;
+ dso->si_current_noise = parsed.si_current_noise;
+ dso->scan_level = parsed.scan_level;
+
+ return 0;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
char *cmd)
{
@@ -658,6 +721,52 @@
wpa_s->ignore_assoc_disallow = !!atoi(value);
wpa_drv_ignore_assoc_disallow(wpa_s,
wpa_s->ignore_assoc_disallow);
+ } else if (os_strcasecmp(cmd, "disable_sa_query") == 0) {
+ wpa_s->disable_sa_query = !!atoi(value);
+ } else if (os_strcasecmp(cmd, "ignore_sae_h2e_only") == 0) {
+ wpa_s->ignore_sae_h2e_only = !!atoi(value);
+ } else if (os_strcasecmp(cmd, "extra_sae_rejected_groups") == 0) {
+ char *pos;
+
+ os_free(wpa_s->extra_sae_rejected_groups);
+ wpa_s->extra_sae_rejected_groups = NULL;
+ pos = value;
+ while (pos && pos[0]) {
+ int group;
+
+ group = atoi(pos);
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Extra rejection of SAE group %d",
+ group);
+ if (group)
+ int_array_add_unique(
+ &wpa_s->extra_sae_rejected_groups,
+ group);
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ break;
+ pos++;
+ }
+ } else if (os_strcasecmp(cmd, "ft_rsnxe_used") == 0) {
+ wpa_s->ft_rsnxe_used = atoi(value);
+ } else if (os_strcasecmp(cmd, "rsne_override_eapol") == 0) {
+ wpabuf_free(wpa_s->rsne_override_eapol);
+ if (os_strcmp(value, "NULL") == 0)
+ wpa_s->rsne_override_eapol = NULL;
+ else
+ wpa_s->rsne_override_eapol = wpabuf_parse_bin(value);
+ } else if (os_strcasecmp(cmd, "rsnxe_override_assoc") == 0) {
+ wpabuf_free(wpa_s->rsnxe_override_assoc);
+ if (os_strcmp(value, "NULL") == 0)
+ wpa_s->rsnxe_override_assoc = NULL;
+ else
+ wpa_s->rsnxe_override_assoc = wpabuf_parse_bin(value);
+ } else if (os_strcasecmp(cmd, "rsnxe_override_eapol") == 0) {
+ wpabuf_free(wpa_s->rsnxe_override_eapol);
+ if (os_strcmp(value, "NULL") == 0)
+ wpa_s->rsnxe_override_eapol = NULL;
+ else
+ wpa_s->rsnxe_override_eapol = wpabuf_parse_bin(value);
} else if (os_strcasecmp(cmd, "reject_btm_req_reason") == 0) {
wpa_s->reject_btm_req_reason = atoi(value);
} else if (os_strcasecmp(cmd, "get_pref_freq_list_override") == 0) {
@@ -672,6 +781,8 @@
wpa_s->sae_commit_override = NULL;
else
wpa_s->sae_commit_override = wpabuf_parse_bin(value);
+ } else if (os_strcasecmp(cmd, "driver_signal_override") == 0) {
+ ret = wpas_ctrl_iface_set_dso(wpa_s, value);
#ifdef CONFIG_DPP
} else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
os_free(wpa_s->dpp_config_obj_override);
@@ -810,6 +921,8 @@
return wpa_snprintf_hex(buf, buflen,
wpa_sm_get_anonce(wpa_s->wpa),
WPA_NONCE_LEN);
+ } else if (os_strcasecmp(cmd, "last_tk_key_idx") == 0) {
+ res = os_snprintf(buf, buflen, "%d", wpa_s->last_tk_key_idx);
#endif /* CONFIG_TESTING_OPTIONS */
} else {
res = wpa_config_get_value(cmd, wpa_s->conf, buf, buflen);
@@ -2654,7 +2767,6 @@
pos += ret;
}
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
pos == start ? "" : "+");
@@ -2669,7 +2781,6 @@
return pos;
pos += ret;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SUITEB
if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
@@ -2873,6 +2984,15 @@
}
if (bss_is_dmg(bss)) {
const char *s;
+
+ if (get_ie_ext((const u8 *) (bss + 1), bss->ie_len,
+ WLAN_EID_EXT_EDMG_OPERATION)) {
+ ret = os_snprintf(pos, end - pos, "[EDMG]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+
ret = os_snprintf(pos, end - pos, "[DMG]");
if (os_snprintf_error(end - pos, ret))
return -1;
@@ -3129,6 +3249,49 @@
return wpas_mesh_peer_add(wpa_s, addr, duration);
}
+
+static int wpa_supplicant_ctrl_iface_mesh_link_probe(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ struct ether_header *eth;
+ u8 addr[ETH_ALEN];
+ u8 *buf;
+ char *pos;
+ size_t payload_len = 0, len;
+ int ret = -1;
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ pos = os_strstr(cmd, " payload=");
+ if (pos) {
+ pos = pos + 9;
+ payload_len = os_strlen(pos);
+ if (payload_len & 1)
+ return -1;
+
+ payload_len /= 2;
+ }
+
+ len = ETH_HLEN + payload_len;
+ buf = os_malloc(len);
+ if (!buf)
+ return -1;
+
+ eth = (struct ether_header *) buf;
+ os_memcpy(eth->ether_dhost, addr, ETH_ALEN);
+ os_memcpy(eth->ether_shost, wpa_s->own_addr, ETH_ALEN);
+ eth->ether_type = htons(ETH_P_802_3);
+
+ if (payload_len && hexstr2bin(pos, buf + ETH_HLEN, payload_len) < 0)
+ goto fail;
+
+ ret = wpa_drv_mesh_link_probe(wpa_s, addr, buf, len);
+fail:
+ os_free(buf);
+ return -ret;
+}
+
#endif /* CONFIG_MESH */
@@ -3796,10 +3959,14 @@
{ WPA_DRIVER_CAPA_ENC_GCMP_256, "GCMP-256", 0 },
{ WPA_DRIVER_CAPA_ENC_CCMP, "CCMP", 0 },
{ WPA_DRIVER_CAPA_ENC_GCMP, "GCMP", 0 },
+#ifndef CONFIG_NO_TKIP
{ WPA_DRIVER_CAPA_ENC_TKIP, "TKIP", 0 },
+#endif /* CONFIG_NO_TKIP */
{ WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE, "NONE", 0 },
+#ifdef CONFIG_WEP
{ WPA_DRIVER_CAPA_ENC_WEP104, "WEP104", 1 },
{ WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 }
+#endif /* CONFIG_WEP */
};
static const struct cipher_info ciphers_group_mgmt[] = {
@@ -3825,7 +3992,11 @@
if (res < 0) {
if (strict)
return 0;
+#ifdef CONFIG_NO_TKIP
+ len = os_strlcpy(buf, "CCMP NONE", buflen);
+#else /* CONFIG_NO_TKIP */
len = os_strlcpy(buf, "CCMP TKIP NONE", buflen);
+#endif /* CONFIG_NO_TKIP */
if (len >= buflen)
return -1;
return len;
@@ -3861,7 +4032,19 @@
if (res < 0) {
if (strict)
return 0;
+#ifdef CONFIG_WEP
+#ifdef CONFIG_NO_TKIP
+ len = os_strlcpy(buf, "CCMP WEP104 WEP40", buflen);
+#else /* CONFIG_NO_TKIP */
len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
+#endif /* CONFIG_NO_TKIP */
+#else /* CONFIG_WEP */
+#ifdef CONFIG_NO_TKIP
+ len = os_strlcpy(buf, "CCMP", buflen);
+#else /* CONFIG_NO_TKIP */
+ len = os_strlcpy(buf, "CCMP TKIP", buflen);
+#endif /* CONFIG_NO_TKIP */
+#endif /* CONFIG_WEP */
if (len >= buflen)
return -1;
return len;
@@ -5194,17 +5377,24 @@
{
wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
/* MLME-DELETEKEYS.request */
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
-#ifdef CONFIG_IEEE80211W
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
-#endif /* CONFIG_IEEE80211W */
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL,
+ 0, KEY_FLAG_GROUP);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL,
+ 0, KEY_FLAG_GROUP);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL,
+ 0, KEY_FLAG_GROUP);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL,
+ 0, KEY_FLAG_GROUP);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL,
+ 0, KEY_FLAG_GROUP);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL,
+ 0, KEY_FLAG_GROUP);
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
- 0);
+ 0, KEY_FLAG_PAIRWISE);
+ if (wpa_sm_ext_key_id(wpa_s->wpa))
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 1, 0,
+ NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE);
/* MLME-SETPROTECTION.request(None) */
wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
MLME_SETPROTECTION_PROTECT_TYPE_NONE,
@@ -5548,17 +5738,17 @@
if (freq2 < 0)
return -1;
if (freq2)
- return VHT_CHANWIDTH_80P80MHZ;
+ return CHANWIDTH_80P80MHZ;
switch (chwidth) {
case 0:
case 20:
case 40:
- return VHT_CHANWIDTH_USE_HT;
+ return CHANWIDTH_USE_HT;
case 80:
- return VHT_CHANWIDTH_80MHZ;
+ return CHANWIDTH_80MHZ;
case 160:
- return VHT_CHANWIDTH_160MHZ;
+ return CHANWIDTH_160MHZ;
default:
wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d",
chwidth);
@@ -5584,6 +5774,7 @@
int freq = 0;
int pd;
int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
+ int edmg;
u8 _group_ssid[SSID_MAX_LEN], *group_ssid = NULL;
size_t group_ssid_len = 0;
int he;
@@ -5599,7 +5790,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] [he] [auto] [ssid=<hexdump>] */
+ * [ht40] [vht] [he] [edmg] [auto] [ssid=<hexdump>] */
if (hwaddr_aton(cmd, addr))
return -1;
@@ -5631,6 +5822,7 @@
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;
+ edmg = (os_strstr(cmd, " edmg") != NULL) || wpa_s->conf->p2p_go_edmg;
pos2 = os_strstr(pos, " go_intent=");
if (pos2) {
@@ -5701,7 +5893,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, he,
+ pd, ht40, vht, max_oper_chwidth, he, edmg,
group_ssid, group_ssid_len);
if (new_pin == -2) {
os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
@@ -6258,6 +6450,7 @@
u8 *_peer = NULL, peer[ETH_ALEN];
int freq = 0, pref_freq = 0;
int ht40, vht, he, max_oper_chwidth, chwidth = 0, freq2 = 0;
+ int edmg;
id = atoi(cmd);
pos = os_strstr(cmd, " peer=");
@@ -6295,6 +6488,7 @@
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;
+ edmg = (os_strstr(cmd, " edmg") != NULL) || wpa_s->conf->p2p_go_edmg;
pos = os_strstr(cmd, "freq2=");
if (pos)
@@ -6309,7 +6503,7 @@
return -1;
return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
- max_oper_chwidth, pref_freq, he);
+ max_oper_chwidth, pref_freq, he, edmg);
}
@@ -6358,7 +6552,7 @@
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 he)
+ int he, int edmg)
{
struct wpa_ssid *ssid;
@@ -6372,7 +6566,8 @@
return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq,
vht_center_freq2, 0, ht40, vht,
- vht_chwidth, he, NULL, 0, 0);
+ vht_chwidth, he, edmg,
+ NULL, 0, 0);
}
@@ -6382,6 +6577,7 @@
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 edmg = wpa_s->conf->p2p_go_edmg;
int max_oper_chwidth, chwidth = 0, freq2 = 0;
char *token, *context = NULL;
#ifdef CONFIG_ACS
@@ -6406,6 +6602,8 @@
ht40 = 1;
} else if (os_strcmp(token, "he") == 0) {
he = 1;
+ } else if (os_strcmp(token, "edmg") == 0) {
+ edmg = 1;
} else if (os_strcmp(token, "persistent") == 0) {
persistent = 1;
} else {
@@ -6443,10 +6641,11 @@
if (group_id >= 0)
return p2p_ctrl_group_add_persistent(wpa_s, group_id,
freq, freq2, ht40, vht,
- max_oper_chwidth, he);
+ max_oper_chwidth, he,
+ edmg);
return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht,
- max_oper_chwidth, he);
+ max_oper_chwidth, he, edmg);
}
@@ -7032,7 +7231,7 @@
return -1;
}
- bss = wpa_bss_get_bssid(wpa_s, bssid);
+ bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
if (bss == NULL) {
wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
MAC2STR(bssid));
@@ -7761,6 +7960,34 @@
}
+static int wpas_ctrl_iface_driver_flags2(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ int ret, i;
+ char *pos, *end;
+
+ ret = os_snprintf(buf, buflen, "%016llX:\n",
+ (long long unsigned) wpa_s->drv_flags2);
+ if (os_snprintf_error(buflen, ret))
+ return -1;
+
+ pos = buf + ret;
+ end = buf + buflen;
+
+ for (i = 0; i < 64; i++) {
+ if (wpa_s->drv_flags2 & (1LLU << i)) {
+ ret = os_snprintf(pos, end - pos, "%s\n",
+ driver_flag2_to_string(1LLU << i));
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ }
+
+ return pos - buf;
+}
+
+
static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen)
{
@@ -7921,6 +8148,10 @@
wpa_s->dpp_resp_wait_time = 0;
wpa_s->dpp_resp_max_tries = 0;
wpa_s->dpp_resp_retry_time = 0;
+#ifdef CONFIG_DPP2
+ wpas_dpp_chirp_stop(wpa_s);
+ wpa_s->dpp_pfs_fallback = 0;
+#endif /* CONFIG_DPP2 */
#ifdef CONFIG_TESTING_OPTIONS
os_memset(dpp_pkex_own_mac_override, 0, ETH_ALEN);
os_memset(dpp_pkex_peer_mac_override, 0, ETH_ALEN);
@@ -7940,9 +8171,12 @@
eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
wpa_supplicant_stop_countermeasures(wpa_s, NULL);
+ wpa_s->last_michael_mic_error.sec = 0;
wpa_s->no_keep_alive = 0;
wpa_s->own_disconnect_req = 0;
+ wpa_s->own_reconnect_req = 0;
+ wpa_s->deny_ptk0_rekey = 0;
os_free(wpa_s->disallow_aps_bssid);
wpa_s->disallow_aps_bssid = NULL;
@@ -7969,7 +8203,7 @@
wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 43200);
wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 70);
wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, 60);
- eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
+ eapol_sm_notify_logoff(wpa_s->eapol, false);
radio_remove_works(wpa_s, NULL, 1);
wpa_s->ext_work_in_progress = 0;
@@ -7991,13 +8225,25 @@
wpa_s->p2p_go_csa_on_inv = 0;
wpa_s->ignore_auth_resp = 0;
wpa_s->ignore_assoc_disallow = 0;
+ wpa_s->disable_sa_query = 0;
wpa_s->testing_resend_assoc = 0;
+ wpa_s->ignore_sae_h2e_only = 0;
+ wpa_s->ft_rsnxe_used = 0;
wpa_s->reject_btm_req_reason = 0;
wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL);
os_free(wpa_s->get_pref_freq_list_override);
wpa_s->get_pref_freq_list_override = NULL;
wpabuf_free(wpa_s->sae_commit_override);
wpa_s->sae_commit_override = NULL;
+ os_free(wpa_s->extra_sae_rejected_groups);
+ wpa_s->extra_sae_rejected_groups = NULL;
+ wpabuf_free(wpa_s->rsne_override_eapol);
+ wpa_s->rsne_override_eapol = NULL;
+ wpabuf_free(wpa_s->rsnxe_override_assoc);
+ wpa_s->rsnxe_override_assoc = NULL;
+ wpabuf_free(wpa_s->rsnxe_override_eapol);
+ wpa_s->rsnxe_override_eapol = NULL;
+ wpas_clear_driver_signal_override(wpa_s);
#ifdef CONFIG_DPP
os_free(wpa_s->dpp_config_obj_override);
wpa_s->dpp_config_obj_override = NULL;
@@ -8012,6 +8258,8 @@
wpa_s->disconnected = 0;
os_free(wpa_s->next_scan_freqs);
wpa_s->next_scan_freqs = NULL;
+ os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN);
+ wpa_s->next_scan_bssid_wildcard_ssid = 0;
os_free(wpa_s->select_network_scan_freqs);
wpa_s->select_network_scan_freqs = NULL;
@@ -8030,6 +8278,7 @@
#ifdef CONFIG_SME
wpa_s->sme.last_unprot_disconnect.sec = 0;
+ wpa_s->sme.auth_alg = 0;
#endif /* CONFIG_SME */
wpabuf_free(wpa_s->ric_ies);
@@ -8346,6 +8595,9 @@
goto done;
}
os_memcpy(wpa_s->next_scan_bssid, bssid, ETH_ALEN);
+
+ wpa_s->next_scan_bssid_wildcard_ssid =
+ os_strstr(params, "wildcard_ssid=1") != NULL;
}
pos = params;
@@ -8857,7 +9109,7 @@
{
struct wpa_supplicant *wpa_s = ctx;
const struct ether_header *eth;
- struct iphdr ip;
+ struct ip ip;
const u8 *pos;
unsigned int i;
char extra[30];
@@ -8873,14 +9125,13 @@
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) {
+ if (ip.ip_hl != 5 || ip.ip_v != 4 || ntohs(ip.ip_len) > HWSIM_IP_LEN) {
wpa_printf(MSG_DEBUG,
"test data: RX - ignore unexpect IP header");
return;
}
- for (i = 0; i < ntohs(ip.tot_len) - sizeof(ip); i++) {
+ for (i = 0; i < ntohs(ip.ip_len) - sizeof(ip); i++) {
if (*pos != (u8) i) {
wpa_printf(MSG_DEBUG,
"test data: RX - ignore mismatching payload");
@@ -8889,8 +9140,8 @@
pos++;
}
extra[0] = '\0';
- if (ntohs(ip.tot_len) != HWSIM_IP_LEN)
- os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.tot_len));
+ if (ntohs(ip.ip_len) != HWSIM_IP_LEN)
+ os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.ip_len));
wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s",
MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra);
}
@@ -8942,7 +9193,7 @@
u8 tos;
u8 buf[2 + HWSIM_PACKETLEN];
struct ether_header *eth;
- struct iphdr *ip;
+ struct ip *ip;
u8 *dpos;
unsigned int i;
size_t send_len = HWSIM_IP_LEN;
@@ -8981,17 +9232,17 @@
os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
os_memcpy(eth->ether_shost, src, ETH_ALEN);
eth->ether_type = htons(ETHERTYPE_IP);
- ip = (struct iphdr *) (eth + 1);
+ ip = (struct ip *) (eth + 1);
os_memset(ip, 0, sizeof(*ip));
- ip->ihl = 5;
- ip->version = 4;
- ip->ttl = 64;
- ip->tos = tos;
- 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));
+ ip->ip_hl = 5;
+ ip->ip_v = 4;
+ ip->ip_ttl = 64;
+ ip->ip_tos = tos;
+ ip->ip_len = htons(send_len);
+ ip->ip_p = 1;
+ ip->ip_src.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
+ ip->ip_dst.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
+ ip->ip_sum = ipv4_hdr_checksum(ip, sizeof(*ip));
dpos = (u8 *) (ip + 1);
for (i = 0; i < send_len - sizeof(*ip); i++)
*dpos++ = i;
@@ -9184,13 +9435,15 @@
* in the driver. */
if (wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
wpa_s->last_tk_key_idx, 1, zero, 6,
- zero, wpa_s->last_tk_len) < 0)
+ zero, wpa_s->last_tk_len,
+ KEY_FLAG_PAIRWISE_RX_TX) < 0)
return -1;
/* Set the previously configured key to reset its TSC/RSC */
return wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
wpa_s->last_tk_key_idx, 1, zero, 6,
- wpa_s->last_tk, wpa_s->last_tk_len);
+ wpa_s->last_tk, wpa_s->last_tk_len,
+ KEY_FLAG_PAIRWISE_RX_TX);
}
@@ -9412,16 +9665,16 @@
if (pos[0] != WLAN_EID_NEIGHBOR_REPORT ||
nr_len < NR_IE_MIN_LEN) {
- wpa_printf(MSG_DEBUG,
- "CTRL: Invalid Neighbor Report element: id=%u len=%u",
- data[0], nr_len);
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "CTRL: Invalid Neighbor Report element: id=%u len=%u",
+ data[0], nr_len);
goto out;
}
if (2U + nr_len > len) {
- wpa_printf(MSG_DEBUG,
- "CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u",
- data[0], len, nr_len);
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u",
+ data[0], len, nr_len);
goto out;
}
pos += 2;
@@ -9491,8 +9744,8 @@
ssid_s = os_strstr(cmd, "ssid=");
if (ssid_s) {
if (ssid_parse(ssid_s + 5, &ssid)) {
- wpa_printf(MSG_ERROR,
- "CTRL: Send Neighbor Report: bad SSID");
+ wpa_msg(wpa_s, MSG_INFO,
+ "CTRL: Send Neighbor Report: bad SSID");
return -1;
}
@@ -9583,59 +9836,10 @@
return -1;
}
- if (!enable) {
- wpas_mac_addr_rand_scan_clear(wpa_s, type);
- if (wpa_s->pno) {
- if (type & MAC_ADDR_RAND_PNO) {
- wpas_stop_pno(wpa_s);
- wpas_start_pno(wpa_s);
- }
- } else if (wpa_s->sched_scanning &&
- (type & MAC_ADDR_RAND_SCHED_SCAN)) {
- wpas_scan_restart_sched_scan(wpa_s);
- }
- return 0;
- }
+ if (!enable)
+ return wpas_disable_mac_addr_randomization(wpa_s, type);
- if ((addr && !mask) || (!addr && mask)) {
- wpa_printf(MSG_INFO,
- "CTRL: MAC_RAND_SCAN invalid addr/mask combination");
- return -1;
- }
-
- if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
- wpa_printf(MSG_INFO,
- "CTRL: MAC_RAND_SCAN cannot allow multicast address");
- return -1;
- }
-
- if (type & MAC_ADDR_RAND_SCAN) {
- if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
- addr, mask))
- return -1;
- }
-
- if (type & MAC_ADDR_RAND_SCHED_SCAN) {
- 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) {
- 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);
- }
- }
-
- return 0;
+ return wpas_enable_mac_addr_randomization(wpa_s, type, addr, mask);
}
@@ -10013,9 +10217,9 @@
reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
reply, reply_size);
} else if (os_strcmp(buf, "LOGON") == 0) {
- eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
+ eapol_sm_notify_logoff(wpa_s->eapol, false);
} else if (os_strcmp(buf, "LOGOFF") == 0) {
- eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
+ eapol_sm_notify_logoff(wpa_s->eapol, true);
} else if (os_strcmp(buf, "REASSOCIATE") == 0) {
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
reply_len = -1;
@@ -10171,6 +10375,9 @@
} else if (os_strncmp(buf, "MESH_PEER_ADD ", 14) == 0) {
if (wpa_supplicant_ctrl_iface_mesh_peer_add(wpa_s, buf + 14))
reply_len = -1;
+ } else if (os_strncmp(buf, "MESH_LINK_PROBE ", 16) == 0) {
+ if (wpa_supplicant_ctrl_iface_mesh_link_probe(wpa_s, buf + 16))
+ reply_len = -1;
#endif /* CONFIG_MESH */
#ifdef CONFIG_P2P
} else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
@@ -10551,6 +10758,9 @@
} else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
reply_len = wpas_ctrl_iface_driver_flags(wpa_s, reply,
reply_size);
+ } else if (os_strcmp(buf, "DRIVER_FLAGS2") == 0) {
+ reply_len = wpas_ctrl_iface_driver_flags2(wpa_s, reply,
+ reply_size);
#ifdef ANDROID
} else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
@@ -10627,12 +10837,10 @@
} 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)
@@ -10673,6 +10881,39 @@
if (os_snprintf_error(reply_size, reply_len))
reply_len = -1;
}
+ } else if (os_strncmp(buf, "DPP_NFC_URI ", 12) == 0) {
+ int res;
+
+ res = wpas_dpp_nfc_uri(wpa_s, buf + 12);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_REQ ", 21) == 0) {
+ int res;
+
+ res = wpas_dpp_nfc_handover_req(wpa_s, buf + 20);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_SEL ", 21) == 0) {
+ int res;
+
+ res = wpas_dpp_nfc_handover_sel(wpa_s, buf + 20);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) {
int res;
@@ -10701,6 +10942,10 @@
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_INFO ", 19) == 0) {
reply_len = dpp_bootstrap_info(wpa_s->dpp, atoi(buf + 19),
reply, reply_size);
+ } else if (os_strncmp(buf, "DPP_BOOTSTRAP_SET ", 18) == 0) {
+ if (dpp_bootstrap_set(wpa_s->dpp, atoi(buf + 18),
+ os_strchr(buf + 18, ' ')) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
if (wpas_dpp_auth_init(wpa_s, buf + 13) < 0)
reply_len = -1;
@@ -10745,6 +10990,21 @@
} else if (os_strncmp(buf, "DPP_PKEX_REMOVE ", 16) == 0) {
if (wpas_dpp_pkex_remove(wpa_s, buf + 16) < 0)
reply_len = -1;
+#ifdef CONFIG_DPP2
+ } else if (os_strncmp(buf, "DPP_CONTROLLER_START ", 21) == 0) {
+ if (wpas_dpp_controller_start(wpa_s, buf + 20) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "DPP_CONTROLLER_START") == 0) {
+ if (wpas_dpp_controller_start(wpa_s, NULL) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "DPP_CONTROLLER_STOP") == 0) {
+ dpp_controller_stop(wpa_s->dpp);
+ } else if (os_strncmp(buf, "DPP_CHIRP ", 10) == 0) {
+ if (wpas_dpp_chirp(wpa_s, buf + 9) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) {
+ wpas_dpp_chirp_stop(wpa_s);
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index 8a6057a..1e92b97 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -516,7 +516,7 @@
return;
if (ifname)
- os_snprintf(levelstr, sizeof(levelstr), "IFACE=%s <%d>",
+ os_snprintf(levelstr, sizeof(levelstr), "IFNAME=%s <%d>",
ifname, level);
else
os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index fc2fc2e..793a881 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -750,10 +750,12 @@
if (cred->auth_type & WPS_AUTH_OPEN)
auth_type[at_num++] = "open";
+#ifndef CONFIG_NO_TKIP
if (cred->auth_type & WPS_AUTH_WPAPSK)
auth_type[at_num++] = "wpa-psk";
if (cred->auth_type & WPS_AUTH_WPA)
auth_type[at_num++] = "wpa-eap";
+#endif /* CONFIG_NO_TKIP */
if (cred->auth_type & WPS_AUTH_WPA2)
auth_type[at_num++] = "wpa2-eap";
if (cred->auth_type & WPS_AUTH_WPA2PSK)
@@ -761,8 +763,10 @@
if (cred->encr_type & WPS_ENCR_NONE)
encr_type[et_num++] = "none";
+#ifndef CONFIG_NO_TKIP
if (cred->encr_type & WPS_ENCR_TKIP)
encr_type[et_num++] = "tkip";
+#endif /* CONFIG_NO_TKIP */
if (cred->encr_type & WPS_ENCR_AES)
encr_type[et_num++] = "aes";
@@ -2855,30 +2859,6 @@
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 }
};
@@ -3786,6 +3766,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
+ },
#ifdef CONFIG_MESH
{ "MeshPeers", WPAS_DBUS_NEW_IFACE_MESH, "aay",
wpas_dbus_getter_mesh_peers,
@@ -3803,6 +3807,12 @@
NULL,
NULL
},
+ { "MACAddressRandomizationMask", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ "a{say}",
+ wpas_dbus_getter_mac_address_randomization_mask,
+ wpas_dbus_setter_mac_address_randomization_mask,
+ NULL
+ },
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -4791,8 +4801,8 @@
if (!wpa_s->dbus_groupobj_path) {
wpa_printf(MSG_DEBUG,
- "%s: Group object '%s' already unregistered",
- __func__, wpa_s->dbus_groupobj_path);
+ "%s: Group object has already unregistered",
+ __func__);
return;
}
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 6c36d91..d1f9607 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -137,8 +137,15 @@
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
+ "bssid", "scan_freq", "freq_list", "scan_ssid", "bssid_hint",
+ "bssid_blacklist", "bssid_whitelist", "group_mgmt",
+#ifdef CONFIG_MESH
+ "mesh_basic_rates",
+#endif /* CONFIG_MESH */
+#ifdef CONFIG_P2P
+ "go_p2p_dev_addr", "p2p_client_list", "psk_list",
+#endif /* CONFIG_P2P */
+ NULL
};
static dbus_bool_t should_quote_opt(const char *key)
@@ -984,21 +991,25 @@
const struct wpa_dbus_property_desc *property_desc,
DBusMessageIter *iter, DBusError *error, void *user_data)
{
- const char *capabilities[10] = { NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL };
+ const char *capabilities[12];
size_t num_items = 0;
-#ifdef CONFIG_FILS
struct wpa_global *global = user_data;
struct wpa_supplicant *wpa_s;
+#ifdef CONFIG_FILS
int fils_supported = 0, fils_sk_pfs_supported = 0;
+#endif /* CONFIG_FILS */
+ int ext_key_id_supported = 0;
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+#ifdef CONFIG_FILS
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 */
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID)
+ ext_key_id_supported = 1;
+ }
#ifdef CONFIG_AP
capabilities[num_items++] = "ap";
@@ -1012,9 +1023,7 @@
#ifdef CONFIG_INTERWORKING
capabilities[num_items++] = "interworking";
#endif /* CONFIG_INTERWORKING */
-#ifdef CONFIG_IEEE80211W
capabilities[num_items++] = "pmf";
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_MESH
capabilities[num_items++] = "mesh";
#endif /* CONFIG_MESH */
@@ -1030,6 +1039,11 @@
#ifdef CONFIG_SHA384
capabilities[num_items++] = "sha384";
#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_OWE
+ capabilities[num_items++] = "owe";
+#endif /* CONFIG_OWE */
+ if (ext_key_id_supported)
+ capabilities[num_items++] = "extended_key_id";
return wpas_dbus_simple_array_property_getter(iter,
DBUS_TYPE_STRING,
@@ -1139,7 +1153,7 @@
DBusMessage **reply)
{
u8 *ies = NULL, *nies;
- int ies_len = 0;
+ size_t ies_len = 0;
DBusMessageIter array_iter, sub_array_iter;
char *val;
int len;
@@ -1170,7 +1184,7 @@
dbus_message_iter_recurse(&array_iter, &sub_array_iter);
dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
- if (len == 0) {
+ if (len <= 0) {
dbus_message_iter_next(&array_iter);
continue;
}
@@ -1201,7 +1215,7 @@
{
DBusMessageIter array_iter, sub_array_iter;
int *freqs = NULL, *nfreqs;
- int freqs_num = 0;
+ size_t freqs_num = 0;
if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
wpa_printf(MSG_DEBUG,
@@ -2618,7 +2632,11 @@
/***** pairwise cipher */
if (res < 0) {
+#ifdef CONFIG_NO_TKIP
+ const char *args[] = {"ccmp", "none"};
+#else /* CONFIG_NO_TKIP */
const char *args[] = {"ccmp", "tkip", "none"};
+#endif /* CONFIG_NO_TKIP */
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "Pairwise", args,
@@ -2641,9 +2659,11 @@
((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "gcmp")) ||
+#ifndef CONFIG_NO_TKIP
((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "tkip")) ||
+#endif /* CONFIG_NO_TKIP */
((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "none")) ||
@@ -2657,7 +2677,13 @@
/***** group cipher */
if (res < 0) {
const char *args[] = {
- "ccmp", "tkip", "wep104", "wep40"
+ "ccmp",
+#ifndef CONFIG_NO_TKIP
+ "tkip",
+#endif /* CONFIG_NO_TKIP */
+#ifdef CONFIG_WEP
+ "wep104", "wep40"
+#endif /* CONFIG_WEP */
};
if (!wpa_dbus_dict_append_string_array(
@@ -2681,15 +2707,19 @@
((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "gcmp")) ||
+#ifndef CONFIG_NO_TKIP
((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "tkip")) ||
+#endif /* CONFIG_NO_TKIP */
+#ifdef CONFIG_WEP
((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")) ||
+#endif /* CONFIG_WEP */
!wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
@@ -2753,11 +2783,9 @@
goto nomem;
/* TODO: Ensure that driver actually supports sha256 encryption. */
-#ifdef CONFIG_IEEE80211W
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "wpa-eap-sha256"))
goto nomem;
-#endif /* CONFIG_IEEE80211W */
}
if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
@@ -2771,11 +2799,9 @@
goto nomem;
/* TODO: Ensure that driver actually supports sha256 encryption. */
-#ifdef CONFIG_IEEE80211W
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "wpa-psk-sha256"))
goto nomem;
-#endif /* CONFIG_IEEE80211W */
}
if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
@@ -2790,6 +2816,12 @@
goto nomem;
#endif /* CONFIG_WPS */
+#ifdef CONFIG_SAE
+ if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) &&
+ !wpa_dbus_dict_string_array_add_element(&iter_array, "sae"))
+ goto nomem;
+#endif /* CONFIG_SAE */
+
if (!wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
@@ -3990,6 +4022,173 @@
/**
+ * wpas_dbus_setter_mac_address_randomization_mask - Set masks used for
+ * MAC address randomization
+ * @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 for "MACAddressRandomizationMask" property.
+ */
+dbus_bool_t wpas_dbus_setter_mac_address_randomization_mask(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
+ const char *key;
+ unsigned int rand_type = 0;
+ const u8 *mask;
+ int mask_len;
+ unsigned int rand_types_to_disable = MAC_ADDR_RAND_ALL;
+
+ dbus_message_iter_recurse(iter, &variant_iter);
+ if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY) {
+ dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+ "invalid message format");
+ return FALSE;
+ }
+ dbus_message_iter_recurse(&variant_iter, &dict_iter);
+ while (dbus_message_iter_get_arg_type(&dict_iter) ==
+ DBUS_TYPE_DICT_ENTRY) {
+ dbus_message_iter_recurse(&dict_iter, &entry_iter);
+ if (dbus_message_iter_get_arg_type(&entry_iter) !=
+ DBUS_TYPE_STRING) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: key not a string", __func__);
+ return FALSE;
+ }
+ dbus_message_iter_get_basic(&entry_iter, &key);
+ dbus_message_iter_next(&entry_iter);
+ if (dbus_message_iter_get_arg_type(&entry_iter) !=
+ DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type(&entry_iter) !=
+ DBUS_TYPE_BYTE) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: mask was not a byte array",
+ __func__);
+ return FALSE;
+ }
+ dbus_message_iter_recurse(&entry_iter, &array_iter);
+ dbus_message_iter_get_fixed_array(&array_iter, &mask,
+ &mask_len);
+
+ if (os_strcmp(key, "scan") == 0) {
+ rand_type = MAC_ADDR_RAND_SCAN;
+ } else if (os_strcmp(key, "sched_scan") == 0) {
+ rand_type = MAC_ADDR_RAND_SCHED_SCAN;
+ } else if (os_strcmp(key, "pno") == 0) {
+ rand_type = MAC_ADDR_RAND_PNO;
+ } else {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: bad scan type \"%s\"",
+ __func__, key);
+ return FALSE;
+ }
+
+ if (mask_len != ETH_ALEN) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: malformed MAC mask given",
+ __func__);
+ return FALSE;
+ }
+
+ if (wpas_enable_mac_addr_randomization(
+ wpa_s, rand_type, wpa_s->perm_addr, mask)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to set up MAC address randomization for %s",
+ __func__, key);
+ return FALSE;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "%s: Enabled MAC address randomization for %s with mask: "
+ MACSTR, wpa_s->ifname, key, MAC2STR(mask));
+ rand_types_to_disable &= ~rand_type;
+ dbus_message_iter_next(&dict_iter);
+ }
+
+ if (rand_types_to_disable &&
+ wpas_disable_mac_addr_randomization(wpa_s, rand_types_to_disable)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to disable MAC address randomization",
+ __func__);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+dbus_bool_t wpas_dbus_getter_mac_address_randomization_mask(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
+ unsigned int i;
+ u8 mask_buf[ETH_ALEN];
+ /* Read docs on dbus_message_iter_append_fixed_array() for why this
+ * is necessary... */
+ u8 *mask = mask_buf;
+ static const struct {
+ const char *key;
+ unsigned int type;
+ } types[] = {
+ { "scan", MAC_ADDR_RAND_SCAN },
+ { "sched_scan", MAC_ADDR_RAND_SCHED_SCAN },
+ { "pno", MAC_ADDR_RAND_PNO }
+ };
+
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+ "a{say}", &variant_iter) ||
+ !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+ "{say}", &dict_iter)) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+ return FALSE;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(types); i++) {
+ if (wpas_mac_addr_rand_scan_get_mask(wpa_s, types[i].type,
+ mask))
+ continue;
+
+ if (!dbus_message_iter_open_container(&dict_iter,
+ DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry_iter) ||
+ !dbus_message_iter_append_basic(&entry_iter,
+ DBUS_TYPE_STRING,
+ &types[i].key) ||
+ !dbus_message_iter_open_container(&entry_iter,
+ DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING,
+ &array_iter) ||
+ !dbus_message_iter_append_fixed_array(&array_iter,
+ DBUS_TYPE_BYTE,
+ &mask,
+ ETH_ALEN) ||
+ !dbus_message_iter_close_container(&entry_iter,
+ &array_iter) ||
+ !dbus_message_iter_close_container(&dict_iter,
+ &entry_iter)) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+ "no memory");
+ return FALSE;
+ }
+ }
+
+ if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) ||
+ !dbus_message_iter_close_container(iter, &variant_iter)) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
* 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
@@ -4497,7 +4696,7 @@
DBusMessageIter iter_dict, variant_iter;
const char *group;
const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
- const char *key_mgmt[15]; /* max 15 key managements may be supported */
+ const char *key_mgmt[16]; /* max 16 key managements may be supported */
int n;
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
@@ -4550,6 +4749,10 @@
if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_SAE)
key_mgmt[n++] = "ft-sae";
#endif /* CONFIG_SAE */
+#ifdef CONFIG_OWE
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_OWE)
+ key_mgmt[n++] = "owe";
+#endif /* CONFIG_OWE */
if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
key_mgmt[n++] = "wpa-none";
@@ -4559,21 +4762,25 @@
/* Group */
switch (ie_data->group_cipher) {
+#ifdef CONFIG_WEP
case WPA_CIPHER_WEP40:
group = "wep40";
break;
+ case WPA_CIPHER_WEP104:
+ group = "wep104";
+ break;
+#endif /* CONFIG_WEP */
+#ifndef CONFIG_NO_TKIP
case WPA_CIPHER_TKIP:
group = "tkip";
break;
+#endif /* CONFIG_NO_TKIP */
case WPA_CIPHER_CCMP:
group = "ccmp";
break;
case WPA_CIPHER_GCMP:
group = "gcmp";
break;
- case WPA_CIPHER_WEP104:
- group = "wep104";
- break;
case WPA_CIPHER_CCMP_256:
group = "ccmp-256";
break;
@@ -4590,8 +4797,10 @@
/* Pairwise */
n = 0;
+#ifndef CONFIG_NO_TKIP
if (ie_data->pairwise_cipher & WPA_CIPHER_TKIP)
pairwise[n++] = "tkip";
+#endif /* CONFIG_NO_TKIP */
if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP)
pairwise[n++] = "ccmp";
if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP)
@@ -4608,11 +4817,9 @@
/* Management group (RSN only) */
if (ie_data->proto == WPA_PROTO_RSN) {
switch (ie_data->mgmt_group_cipher) {
-#ifdef CONFIG_IEEE80211W
case WPA_CIPHER_AES_128_CMAC:
group = "aes128cmac";
break;
-#endif /* CONFIG_IEEE80211W */
default:
group = "";
break;
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index d922ce1..afa26ef 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -177,6 +177,8 @@
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_mac_address_randomization_mask);
+DECLARE_ACCESSOR(wpas_dbus_setter_mac_address_randomization_mask);
DECLARE_ACCESSOR(wpas_dbus_getter_sta_address);
DECLARE_ACCESSOR(wpas_dbus_getter_sta_aid);
DECLARE_ACCESSOR(wpas_dbus_getter_sta_caps);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 8cdd885..7a65673 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -40,6 +40,14 @@
}
+static dbus_bool_t no_p2p_mgmt_interface(DBusError *error)
+{
+ dbus_set_error_const(error, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
+ "Could not find P2P mgmt interface");
+ return FALSE;
+}
+
+
/**
* Parses out the mac address from the peer object path.
* @peer_path - object path of the form
@@ -78,6 +86,22 @@
}
+/**
+ * wpas_dbus_error_no_p2p_mgmt_iface - Return a new InterfaceUnknown error
+ * message
+ * @message: Pointer to incoming dbus message this error refers to
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return an unknown interface error.
+ */
+static DBusMessage * wpas_dbus_error_no_p2p_mgmt_iface(DBusMessage *message)
+{
+ wpa_printf(MSG_DEBUG, "dbus: Could not find P2P mgmt interface");
+ return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
+ "Could not find P2P mgmt interface");
+}
+
+
DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
@@ -145,6 +169,10 @@
}
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s) {
+ reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
+ goto error_nop2p;
+ }
if (wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types,
req_dev_types, NULL, 0, 0, NULL, freq))
@@ -157,8 +185,9 @@
error_clear:
wpa_dbus_dict_entry_clear(&entry);
error:
- os_free(req_dev_types);
reply = wpas_dbus_error_invalid_args(message, entry.key);
+error_nop2p:
+ os_free(req_dev_types);
return reply;
}
@@ -166,7 +195,9 @@
DBusMessage * wpas_dbus_handler_p2p_stop_find(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
- wpas_p2p_stop_find(wpa_s->global->p2p_init_wpa_s);
+ wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (wpa_s)
+ wpas_p2p_stop_find(wpa_s);
return NULL;
}
@@ -185,6 +216,8 @@
return wpas_dbus_error_invalid_args(message, NULL);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
if (wpas_p2p_reject(wpa_s, peer_addr) < 0)
return wpas_dbus_error_unknown_error(message,
@@ -204,6 +237,8 @@
return wpas_dbus_error_no_memory(message);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
if (wpas_p2p_listen(wpa_s, (unsigned int) timeout)) {
return dbus_message_new_error(message,
@@ -245,6 +280,8 @@
}
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
if (wpas_p2p_ext_listen(wpa_s, period, interval))
return wpas_dbus_error_unknown_error(
@@ -350,6 +387,10 @@
}
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s) {
+ reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
+ goto out;
+ }
if (pg_object_path != NULL) {
char *net_id_str;
@@ -384,14 +425,14 @@
goto inv_args;
if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0, 0,
- 0, 0, 0, NULL, 0, 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, 0, 0))
goto inv_args;
out:
@@ -433,6 +474,12 @@
"P2P is not available for this interface");
return FALSE;
}
+ if (!wpa_s->global->p2p_init_wpa_s) {
+ if (out_reply)
+ *out_reply = wpas_dbus_error_no_p2p_mgmt_iface(
+ message);
+ return no_p2p_mgmt_interface(error);
+ }
return TRUE;
}
@@ -605,7 +652,7 @@
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, 0,
+ go_intent, freq, 0, -1, 0, 0, 0, 0, 0, 0,
NULL, 0);
if (new_pin >= 0) {
@@ -763,7 +810,7 @@
goto err;
if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0, 0,
- 0, 0) < 0) {
+ 0, 0, 0) < 0) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
@@ -822,6 +869,8 @@
return wpas_dbus_error_invalid_args(message, NULL);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method,
WPAS_P2P_PD_FOR_GO_NEG, NULL) < 0)
@@ -1882,6 +1931,8 @@
wpa_s = peer_args->wpa_s;
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return no_p2p_mgmt_interface(error);
wpa_s_go = wpas_get_p2p_client_iface(wpa_s, info->p2p_device_addr);
if (wpa_s_go) {
@@ -1963,6 +2014,9 @@
dbus_bool_t success = FALSE;
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return no_p2p_mgmt_interface(error);
+
if (!wpa_s->parent->dbus_new_path)
return FALSE;
@@ -2077,6 +2131,11 @@
dbus_message_iter_init(message, &iter);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s) {
+ reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
+ goto err;
+ }
+
if (wpa_s->parent->dbus_new_path)
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL) {
@@ -2159,6 +2218,10 @@
DBUS_TYPE_INVALID);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s) {
+ reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
+ goto out;
+ }
/*
* Extract the network ID and ensure the network is actually a child of
@@ -2235,6 +2298,8 @@
struct wpa_config *config;
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
config = wpa_s->conf;
ssid = config->ssid;
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.c b/wpa_supplicant/dbus/dbus_new_helpers.c
index 0115e32..d9009ba 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.c
+++ b/wpa_supplicant/dbus/dbus_new_helpers.c
@@ -98,6 +98,7 @@
dbus_error_init(&error);
if (!fill_dict_with_properties(&dict_iter, obj_dsc->properties,
interface, obj_dsc->user_data, &error)) {
+ wpa_dbus_dict_close_write(&iter, &dict_iter);
dbus_message_unref(reply);
reply = wpas_dbus_reply_new_from_error(
message, &error, DBUS_ERROR_INVALID_ARGS,
@@ -741,7 +742,7 @@
DBusConnection *con = eloop_ctx;
struct wpa_dbus_object_desc *obj_desc = timeout_ctx;
- wpa_printf(MSG_DEBUG,
+ wpa_printf(MSG_MSGDUMP,
"dbus: %s: Timeout - sending changed properties of object %s",
__func__, obj_desc->path);
wpa_dbus_flush_object_changed_properties(con, obj_desc->path);
@@ -930,6 +931,7 @@
dbus_error_is_set(&error) ? error.name : "none",
dbus_error_is_set(&error) ? error.message : "none");
dbus_error_free(&error);
+ wpa_dbus_dict_close_write(iter, &dict_iter);
return FALSE;
}
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 88cd790..c570775 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -77,7 +77,7 @@
#CONFIG_DRIVER_MACSEC_QCA=y
# Driver interface for Linux MACsec drivers
-#CONFIG_DRIVER_MACSEC_LINUX=y
+CONFIG_DRIVER_MACSEC_LINUX=y
# Driver interface for the Broadcom RoboSwitch family
#CONFIG_DRIVER_ROBOSWITCH=y
@@ -111,6 +111,16 @@
# EAP-FAST
CONFIG_EAP_FAST=y
+# EAP-TEAP
+# Note: The current EAP-TEAP implementation is experimental and should not be
+# enabled for production use. The IETF RFC 7170 that defines EAP-TEAP has number
+# of conflicting statements and missing details and the implementation has
+# vendor specific workarounds for those and as such, may not interoperate with
+# any other implementation. This should not be used for anything else than
+# experimentation and interoperability testing until those issues has been
+# resolved.
+#CONFIG_EAP_TEAP=y
+
# EAP-GTC
CONFIG_EAP_GTC=y
@@ -120,6 +130,9 @@
# EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used)
#CONFIG_EAP_SIM=y
+# Enable SIM simulator (Milenage) for EAP-SIM
+#CONFIG_SIM_SIMULATOR=y
+
# EAP-PSK (experimental; this is _not_ needed for WPA-PSK)
#CONFIG_EAP_PSK=y
@@ -170,7 +183,7 @@
#CONFIG_EAP_EKE=y
# MACsec
-#CONFIG_MACSEC=y
+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)
@@ -235,7 +248,7 @@
# 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.
+# Disable scan result processing (ap_scan=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
@@ -297,10 +310,6 @@
# bridge interfaces (commit 'bridge: respect RFC2863 operational state')').
#CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y
-# IEEE 802.11w (management frame protection), also known as PMF
-# Driver support is also needed for IEEE 802.11w.
-CONFIG_IEEE80211W=y
-
# Support Operating Channel Validation
#CONFIG_OCV=y
@@ -353,7 +362,7 @@
#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib"
# Add support for new DBus control interface
-# (fi.w1.hostap.wpa_supplicant1)
+# (fi.w1.wpa_supplicant1)
CONFIG_CTRL_IFACE_DBUS_NEW=y
# Add introspection support for new DBus control interface
@@ -462,11 +471,7 @@
# 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
-
# IEEE 802.11ac (Very High Throughput) support (mainly for AP mode)
-# (depends on CONFIG_IEEE80211N)
CONFIG_IEEE80211AC=y
# Wireless Network Management (IEEE Std 802.11v-2011)
@@ -597,6 +602,27 @@
#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
+
+# WLAN Authentication and Privacy Infrastructure (WAPI): interface only.
+# Configure the building of the interface which allows WAPI configuration.
+# Note: does not configure WAPI implementation itself.
+#CONFIG_WAPI_INTERFACE=y
+
+# Wired equivalent privacy (WEP)
+# WEP is an obsolete cryptographic data confidentiality algorithm that is not
+# considered secure. It should not be used for anything anymore. The
+# functionality needed to use WEP is available in the current wpa_supplicant
+# release under this optional build parameter. This functionality is subject to
+# be completely removed in a future release.
+#CONFIG_WEP=y
+
+# Remove all TKIP functionality
+# TKIP is an old cryptographic data confidentiality algorithm that is not
+# considered secure. It should not be used anymore for anything else than a
+# backwards compatibility option as a group cipher when connecting to APs that
+# use WPA+WPA2 mixed mode. For now, the default wpa_supplicant build includes
+# support for this by default, but that functionality is subject to be removed
+# in the future.
+#CONFIG_NO_TKIP=y
+
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index 8a9e444..6dfa2e5 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -1,7 +1,7 @@
/*
* wpa_supplicant - DPP
* Copyright (c) 2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
+#include "utils/ip_addr.h"
#include "common/dpp.h"
#include "common/gas.h"
#include "common/gas_server.h"
@@ -88,6 +89,91 @@
}
+/**
+ * wpas_dpp_nfc_uri - Parse and add DPP bootstrapping info from NFC Tag (URI)
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @cmd: DPP URI read from a NFC Tag (URI NDEF message)
+ * Returns: Identifier of the stored info or -1 on failure
+ */
+int wpas_dpp_nfc_uri(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ struct dpp_bootstrap_info *bi;
+
+ bi = dpp_add_nfc_uri(wpa_s->dpp, cmd);
+ if (!bi)
+ return -1;
+
+ return bi->id;
+}
+
+
+int wpas_dpp_nfc_handover_req(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ const char *pos;
+ struct dpp_bootstrap_info *peer_bi, *own_bi;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
+ if (!own_bi)
+ return -1;
+ own_bi->nfc_negotiated = 1;
+
+ pos = os_strstr(cmd, " uri=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ peer_bi = dpp_add_nfc_uri(wpa_s->dpp, pos);
+ if (!peer_bi) {
+ wpa_printf(MSG_INFO,
+ "DPP: Failed to parse URI from NFC Handover Request");
+ return -1;
+ }
+
+ if (dpp_nfc_update_bi(own_bi, peer_bi) < 0)
+ return -1;
+
+ return peer_bi->id;
+}
+
+
+int wpas_dpp_nfc_handover_sel(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ const char *pos;
+ struct dpp_bootstrap_info *peer_bi, *own_bi;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
+ if (!own_bi)
+ return -1;
+ own_bi->nfc_negotiated = 1;
+
+ pos = os_strstr(cmd, " uri=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ peer_bi = dpp_add_nfc_uri(wpa_s->dpp, pos);
+ if (!peer_bi) {
+ wpa_printf(MSG_INFO,
+ "DPP: Failed to parse URI from NFC Handover Select");
+ return -1;
+ }
+
+ if (peer_bi->curve != own_bi->curve) {
+ wpa_printf(MSG_INFO,
+ "DPP: Peer (NFC Handover Selector) used different curve");
+ return -1;
+ }
+
+ return peer_bi->id;
+}
+
+
static void wpas_dpp_auth_resp_retry_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
@@ -148,6 +234,8 @@
static void wpas_dpp_try_to_connect(struct wpa_supplicant *wpa_s)
{
wpa_printf(MSG_DEBUG, "DPP: Trying to connect to the new network");
+ wpa_s->suitable_network = 0;
+ wpa_s->no_suitable_network = 0;
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
wpa_s->scan_runs = 0;
@@ -157,6 +245,143 @@
}
+#ifdef CONFIG_DPP2
+
+static void wpas_dpp_conn_status_result_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ enum dpp_status_error result;
+
+ if (!auth || !auth->conn_status_requested)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Connection timeout - report Connection Status Result");
+ if (wpa_s->suitable_network)
+ result = DPP_STATUS_AUTH_FAILURE;
+ else if (wpa_s->no_suitable_network)
+ result = DPP_STATUS_NO_AP;
+ else
+ result = 255; /* What to report here for unexpected state? */
+ if (wpa_s->wpa_state == WPA_SCANNING)
+ wpas_abort_ongoing_scan(wpa_s);
+ wpas_dpp_send_conn_status_result(wpa_s, result);
+}
+
+
+static char * wpas_dpp_scan_channel_list(struct wpa_supplicant *wpa_s)
+{
+ char *str, *end, *pos;
+ size_t len;
+ unsigned int i;
+ u8 last_op_class = 0;
+ int res;
+
+ if (!wpa_s->last_scan_freqs || !wpa_s->num_last_scan_freqs)
+ return NULL;
+
+ len = wpa_s->num_last_scan_freqs * 8;
+ str = os_zalloc(len);
+ if (!str)
+ return NULL;
+ end = str + len;
+ pos = str;
+
+ for (i = 0; i < wpa_s->num_last_scan_freqs; i++) {
+ enum hostapd_hw_mode mode;
+ u8 op_class, channel;
+
+ mode = ieee80211_freq_to_channel_ext(wpa_s->last_scan_freqs[i],
+ 0, 0, &op_class, &channel);
+ if (mode == NUM_HOSTAPD_MODES)
+ continue;
+ if (op_class == last_op_class)
+ res = os_snprintf(pos, end - pos, ",%d", channel);
+ else
+ res = os_snprintf(pos, end - pos, "%s%d/%d",
+ pos == str ? "" : ",",
+ op_class, channel);
+ if (os_snprintf_error(end - pos, res)) {
+ *pos = '\0';
+ break;
+ }
+ pos += res;
+ last_op_class = op_class;
+ }
+
+ if (pos == str) {
+ os_free(str);
+ str = NULL;
+ }
+ return str;
+}
+
+
+void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s,
+ enum dpp_status_error result)
+{
+ struct wpabuf *msg;
+ const char *channel_list = NULL;
+ char *channel_list_buf = NULL;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
+
+ if (!auth || !auth->conn_status_requested)
+ return;
+ auth->conn_status_requested = 0;
+ wpa_printf(MSG_DEBUG, "DPP: Report connection status result %d",
+ result);
+
+ if (result == DPP_STATUS_NO_AP) {
+ channel_list_buf = wpas_dpp_scan_channel_list(wpa_s);
+ channel_list = channel_list_buf;
+ }
+
+ msg = dpp_build_conn_status_result(auth, result,
+ ssid ? ssid->ssid :
+ wpa_s->dpp_last_ssid,
+ ssid ? ssid->ssid_len :
+ wpa_s->dpp_last_ssid_len,
+ channel_list);
+ os_free(channel_list_buf);
+ if (!msg) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
+
+ 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_CONNECTION_STATUS_RESULT);
+ offchannel_send_action(wpa_s, auth->curr_freq,
+ auth->peer_mac_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 */
+ auth->remove_on_tx_status = 1;
+
+ return;
+}
+
+
+void wpas_dpp_connected(struct wpa_supplicant *wpa_s)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (auth && auth->conn_status_requested)
+ wpas_dpp_send_conn_status_result(wpa_s, DPP_STATUS_OK);
+}
+
+#endif /* CONFIG_DPP2 */
+
+
static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid,
@@ -182,18 +407,30 @@
#ifdef CONFIG_DPP2
if (auth->connect_on_tx_status) {
+ auth->connect_on_tx_status = 0;
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;
+ if (auth->conn_status_requested) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Start 15 second timeout for reporting connection status result");
+ eloop_cancel_timeout(
+ wpas_dpp_conn_status_result_timeout,
+ wpa_s, NULL);
+ eloop_register_timeout(
+ 15, 0, wpas_dpp_conn_status_result_timeout,
+ wpa_s, NULL);
+ } else {
+ 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");
+ "DPP: Terminate authentication exchange due to a request to do so on TX status");
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,
@@ -436,8 +673,15 @@
{
const char *pos;
struct dpp_bootstrap_info *peer_bi, *own_bi = NULL;
+ struct dpp_authentication *auth;
u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
unsigned int neg_freq = 0;
+ int tcp = 0;
+#ifdef CONFIG_DPP2
+ int tcp_port = DPP_TCP_PORT;
+ struct hostapd_ip_addr ipaddr;
+ char *addr;
+#endif /* CONFIG_DPP2 */
wpa_s->dpp_gas_client = 0;
@@ -452,6 +696,25 @@
return -1;
}
+#ifdef CONFIG_DPP2
+ pos = os_strstr(cmd, " tcp_port=");
+ if (pos) {
+ pos += 10;
+ tcp_port = atoi(pos);
+ }
+
+ addr = get_param(cmd, " tcp_addr=");
+ if (addr) {
+ int res;
+
+ res = hostapd_parse_ip_addr(addr, &ipaddr);
+ os_free(addr);
+ if (res)
+ return -1;
+ tcp = 1;
+ }
+#endif /* CONFIG_DPP2 */
+
pos = os_strstr(cmd, " own=");
if (pos) {
pos += 5;
@@ -487,39 +750,51 @@
pos = os_strstr(cmd, " netrole=");
if (pos) {
pos += 9;
- wpa_s->dpp_netrole_ap = os_strncmp(pos, "ap", 2) == 0;
+ if (os_strncmp(pos, "ap", 2) == 0)
+ wpa_s->dpp_netrole = DPP_NETROLE_AP;
+ else if (os_strncmp(pos, "configurator", 12) == 0)
+ wpa_s->dpp_netrole = DPP_NETROLE_CONFIGURATOR;
+ else
+ wpa_s->dpp_netrole = DPP_NETROLE_STA;
+ } else {
+ wpa_s->dpp_netrole = DPP_NETROLE_STA;
}
pos = os_strstr(cmd, " neg_freq=");
if (pos)
neg_freq = atoi(pos + 10);
- if (wpa_s->dpp_auth) {
+ if (!tcp && 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, 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);
- 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;
+ }
+
+ auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, own_bi, allowed_roles,
+ neg_freq, wpa_s->hw.modes, wpa_s->hw.num_modes);
+ if (!auth)
+ goto fail;
+ wpas_dpp_set_testing_options(wpa_s, auth);
+ if (dpp_set_configurator(auth, cmd) < 0) {
+ dpp_auth_deinit(auth);
goto fail;
}
- wpa_s->dpp_auth->neg_freq = neg_freq;
+ auth->neg_freq = neg_freq;
if (!is_zero_ether_addr(peer_bi->mac_addr))
- os_memcpy(wpa_s->dpp_auth->peer_mac_addr, peer_bi->mac_addr,
- ETH_ALEN);
+ os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
+#ifdef CONFIG_DPP2
+ if (tcp)
+ return dpp_tcp_init(wpa_s->dpp, auth, &ipaddr, tcp_port);
+#endif /* CONFIG_DPP2 */
+
+ wpa_s->dpp_auth = auth;
return wpas_dpp_auth_init_next(wpa_s);
fail:
return -1;
@@ -585,6 +860,7 @@
}
wpa_s->off_channel_freq = 0;
wpa_s->roc_waiting_drv_freq = lwork->freq;
+ wpa_drv_dpp_listen(wpa_s, true);
}
@@ -634,7 +910,12 @@
wpa_s->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR |
DPP_CAPAB_ENROLLEE;
wpa_s->dpp_qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
- wpa_s->dpp_netrole_ap = os_strstr(cmd, " netrole=ap") != NULL;
+ if (os_strstr(cmd, " netrole=ap"))
+ wpa_s->dpp_netrole = DPP_NETROLE_AP;
+ else if (os_strstr(cmd, " netrole=configurator"))
+ wpa_s->dpp_netrole = DPP_NETROLE_CONFIGURATOR;
+ else
+ wpa_s->dpp_netrole = DPP_NETROLE_STA;
if (wpa_s->dpp_listen_freq == (unsigned int) freq) {
wpa_printf(MSG_DEBUG, "DPP: Already listening on %u MHz",
freq);
@@ -654,6 +935,7 @@
wpa_printf(MSG_DEBUG, "DPP: Stop listen on %u MHz",
wpa_s->dpp_listen_freq);
wpa_drv_cancel_remain_on_channel(wpa_s);
+ wpa_drv_dpp_listen(wpa_s, false);
wpa_s->dpp_listen_freq = 0;
wpas_dpp_listen_work_done(wpa_s);
}
@@ -700,6 +982,10 @@
wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
MAC2STR(src));
+#ifdef CONFIG_DPP2
+ wpas_dpp_chirp_stop(wpa_s);
+#endif /* CONFIG_DPP2 */
+
r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
&r_bootstrap_len);
if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
@@ -738,7 +1024,8 @@
wpa_s->dpp_gas_client = 0;
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_auth = dpp_auth_req_rx(wpa_s->dpp, wpa_s,
+ wpa_s->dpp_allowed_roles,
wpa_s->dpp_qr_mutual,
peer_bi, own_bi, freq, hdr, buf, len);
if (!wpa_s->dpp_auth) {
@@ -746,7 +1033,7 @@
return;
}
wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth);
- if (dpp_set_configurator(wpa_s->dpp, wpa_s, wpa_s->dpp_auth,
+ if (dpp_set_configurator(wpa_s->dpp_auth,
wpa_s->dpp_configurator_params) < 0) {
dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL;
@@ -780,12 +1067,13 @@
static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth)
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
struct wpa_ssid *ssid;
#ifdef CONFIG_DPP2
- if (auth->akm == DPP_AKM_SAE) {
+ if (conf->akm == DPP_AKM_SAE) {
#ifdef CONFIG_SAE
struct wpa_driver_capa capa;
int res;
@@ -812,27 +1100,29 @@
wpa_config_set_network_defaults(ssid);
ssid->disabled = 1;
- ssid->ssid = os_malloc(auth->ssid_len);
+ ssid->ssid = os_malloc(conf->ssid_len);
if (!ssid->ssid)
goto fail;
- os_memcpy(ssid->ssid, auth->ssid, auth->ssid_len);
- ssid->ssid_len = auth->ssid_len;
+ os_memcpy(ssid->ssid, conf->ssid, conf->ssid_len);
+ ssid->ssid_len = conf->ssid_len;
- if (auth->connector) {
- ssid->key_mgmt = WPA_KEY_MGMT_DPP;
- ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
- ssid->dpp_connector = os_strdup(auth->connector);
+ if (conf->connector) {
+ if (dpp_akm_dpp(conf->akm)) {
+ ssid->key_mgmt = WPA_KEY_MGMT_DPP;
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
+ }
+ ssid->dpp_connector = os_strdup(conf->connector);
if (!ssid->dpp_connector)
goto fail;
}
- if (auth->c_sign_key) {
- ssid->dpp_csign = os_malloc(wpabuf_len(auth->c_sign_key));
+ if (conf->c_sign_key) {
+ ssid->dpp_csign = os_malloc(wpabuf_len(conf->c_sign_key));
if (!ssid->dpp_csign)
goto fail;
- os_memcpy(ssid->dpp_csign, wpabuf_head(auth->c_sign_key),
- wpabuf_len(auth->c_sign_key));
- ssid->dpp_csign_len = wpabuf_len(auth->c_sign_key);
+ os_memcpy(ssid->dpp_csign, wpabuf_head(conf->c_sign_key),
+ wpabuf_len(conf->c_sign_key));
+ ssid->dpp_csign_len = wpabuf_len(conf->c_sign_key);
}
if (auth->net_access_key) {
@@ -847,29 +1137,32 @@
ssid->dpp_netaccesskey_expiry = auth->net_access_key_expiry;
}
- if (!auth->connector || dpp_akm_psk(auth->akm) ||
- dpp_akm_sae(auth->akm)) {
- if (!auth->connector)
+ if (!conf->connector || dpp_akm_psk(conf->akm) ||
+ dpp_akm_sae(conf->akm)) {
+ if (!conf->connector || !dpp_akm_dpp(conf->akm))
ssid->key_mgmt = 0;
- if (dpp_akm_psk(auth->akm))
+ if (dpp_akm_psk(conf->akm))
ssid->key_mgmt |= WPA_KEY_MGMT_PSK |
WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_FT_PSK;
- if (dpp_akm_sae(auth->akm))
+ if (dpp_akm_sae(conf->akm))
ssid->key_mgmt |= WPA_KEY_MGMT_SAE |
WPA_KEY_MGMT_FT_SAE;
ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
- if (auth->passphrase[0]) {
+ if (conf->passphrase[0]) {
if (wpa_config_set_quoted(ssid, "psk",
- auth->passphrase) < 0)
+ conf->passphrase) < 0)
goto fail;
wpa_config_update_psk(ssid);
ssid->export_keys = 1;
} else {
- ssid->psk_set = auth->psk_set;
- os_memcpy(ssid->psk, auth->psk, PMK_LEN);
+ ssid->psk_set = conf->psk_set;
+ os_memcpy(ssid->psk, conf->psk, PMK_LEN);
}
}
+ os_memcpy(wpa_s->dpp_last_ssid, conf->ssid, conf->ssid_len);
+ wpa_s->dpp_last_ssid_len = conf->ssid_len;
+
return ssid;
fail:
wpas_notify_network_removed(wpa_s, ssid);
@@ -879,14 +1172,15 @@
static int wpas_dpp_process_config(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth)
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
struct wpa_ssid *ssid;
if (wpa_s->conf->dpp_config_processing < 1)
return 0;
- ssid = wpas_dpp_add_network(wpa_s, auth);
+ ssid = wpas_dpp_add_network(wpa_s, auth, conf);
if (!ssid)
return -1;
@@ -903,49 +1197,59 @@
wpa_printf(MSG_DEBUG, "DPP: Failed to update configuration");
#endif /* CONFIG_NO_CONFIG_WRITE */
+ return 0;
+}
+
+
+static void wpas_dpp_post_process_config(struct wpa_supplicant *wpa_s,
+ struct dpp_authentication *auth)
+{
if (wpa_s->conf->dpp_config_processing < 2)
- return 0;
+ return;
#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;
+ return;
}
#endif /* CONFIG_DPP2 */
wpas_dpp_try_to_connect(wpa_s);
- return 0;
}
static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth)
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
- if (auth->ssid_len)
+ if (conf->ssid_len)
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
- wpa_ssid_txt(auth->ssid, auth->ssid_len));
- if (auth->connector) {
+ wpa_ssid_txt(conf->ssid, conf->ssid_len));
+ if (conf->ssid_charset)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID_CHARSET "%d",
+ conf->ssid_charset);
+ if (conf->connector) {
/* TODO: Save the Connector and consider using a command
* to fetch the value instead of sending an event with
* it. The Connector could end up being larger than what
* most clients are ready to receive as an event
* message. */
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
- auth->connector);
+ conf->connector);
}
- if (auth->c_sign_key) {
+ if (conf->c_sign_key) {
char *hex;
size_t hexlen;
- hexlen = 2 * wpabuf_len(auth->c_sign_key) + 1;
+ hexlen = 2 * wpabuf_len(conf->c_sign_key) + 1;
hex = os_malloc(hexlen);
if (hex) {
wpa_snprintf_hex(hex, hexlen,
- wpabuf_head(auth->c_sign_key),
- wpabuf_len(auth->c_sign_key));
+ wpabuf_head(conf->c_sign_key),
+ wpabuf_len(conf->c_sign_key));
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_C_SIGN_KEY "%s",
hex);
os_free(hex);
@@ -973,7 +1277,33 @@
}
}
- return wpas_dpp_process_config(wpa_s, auth);
+ return wpas_dpp_process_config(wpa_s, auth, conf);
+}
+
+
+static int wpas_dpp_handle_key_pkg(struct wpa_supplicant *wpa_s,
+ struct dpp_asymmetric_key *key)
+{
+#ifdef CONFIG_DPP2
+ int res;
+
+ if (!key)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "DPP: Received Configurator backup");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
+
+ while (key) {
+ res = dpp_configurator_from_backup(wpa_s->dpp, key);
+ if (res < 0)
+ return -1;
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFIGURATOR_ID "%d",
+ res);
+ key = key->next;
+ }
+#endif /* CONFIG_DPP2 */
+
+ return 0;
}
@@ -987,6 +1317,7 @@
struct dpp_authentication *auth = wpa_s->dpp_auth;
int res;
enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
+ unsigned int i;
wpa_s->dpp_gas_dialog_token = -1;
@@ -1024,8 +1355,15 @@
goto fail;
}
- res = wpas_dpp_handle_config_obj(wpa_s, auth);
- if (res < 0)
+ for (i = 0; i < auth->num_conf_obj; i++) {
+ res = wpas_dpp_handle_config_obj(wpa_s, auth,
+ &auth->conf_obj[i]);
+ if (res < 0)
+ goto fail;
+ }
+ if (auth->num_conf_obj)
+ wpas_dpp_post_process_config(wpa_s, auth);
+ if (wpas_dpp_handle_key_pkg(wpa_s, auth->conf_key_pkg) < 0)
goto fail;
status = DPP_STATUS_OK;
@@ -1075,27 +1413,19 @@
{
struct dpp_authentication *auth = wpa_s->dpp_auth;
struct wpabuf *buf;
- char json[100];
int res;
+ int *supp_op_classes;
wpa_s->dpp_gas_client = 1;
- os_snprintf(json, sizeof(json),
- "{\"name\":\"Test\","
- "\"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);
- buf = dpp_build_conf_req(auth, json);
+ supp_op_classes = wpas_supp_op_classes(wpa_s);
+ buf = dpp_build_conf_req_helper(auth, wpa_s->conf->dpp_name,
+ wpa_s->dpp_netrole,
+ wpa_s->conf->dpp_mud_url,
+ supp_op_classes);
+ os_free(supp_op_classes);
if (!buf) {
wpa_printf(MSG_DEBUG,
"DPP: No configuration request data available");
@@ -1106,7 +1436,7 @@
MAC2STR(auth->peer_mac_addr), auth->curr_freq);
res = gas_query_req(wpa_s->gas, auth->peer_mac_addr, auth->curr_freq,
- 1, buf, wpas_dpp_gas_resp_cb, wpa_s);
+ 1, 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);
@@ -1244,6 +1574,26 @@
wpa_printf(MSG_DEBUG,
"DPP: Timeout while waiting for Configuration Result");
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ wpas_notify_dpp_configuration_failure(wpa_s);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+}
+
+
+static void wpas_dpp_conn_status_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_conn_status_result)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Timeout while waiting for Connection Status Result");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT "timeout");
+ wpas_notify_dpp_timeout(wpa_s);
+ wpas_dpp_listen_stop(wpa_s);
dpp_auth_deinit(auth);
wpa_s->dpp_auth = NULL;
}
@@ -1272,17 +1622,165 @@
status = dpp_conf_result_rx(auth, hdr, buf, len);
+ if (status == DPP_STATUS_OK && auth->send_conn_status) {
+ wpa_msg(wpa_s, MSG_INFO,
+ DPP_EVENT_CONF_SENT "wait_conn_status=1");
+ wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
+ wpas_notify_dpp_config_accepted(wpa_s);
+ eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout,
+ wpa_s, NULL);
+ auth->waiting_conn_status_result = 1;
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
+ wpa_s, NULL);
+ eloop_register_timeout(16, 0,
+ wpas_dpp_conn_status_result_wait_timeout,
+ wpa_s, NULL);
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_start(wpa_s, auth->neg_freq ? auth->neg_freq :
+ auth->curr_freq);
+ return;
+ }
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
- if (status == DPP_STATUS_OK)
+ if (status == DPP_STATUS_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_config_rejected(wpa_s);
+ }
dpp_auth_deinit(auth);
wpa_s->dpp_auth = NULL;
eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
}
+
+static void wpas_dpp_rx_conn_status_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;
+ u8 ssid[SSID_MAX_LEN];
+ size_t ssid_len = 0;
+ char *channel_list = NULL;
+
+ wpa_printf(MSG_DEBUG, "DPP: Connection Status Result");
+
+ if (!auth || !auth->waiting_conn_status_result) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for connection status result - drop");
+ return;
+ }
+
+ status = dpp_conn_status_result_rx(auth, hdr, buf, len,
+ ssid, &ssid_len, &channel_list);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT
+ "result=%d ssid=%s channel_list=%s",
+ status, wpa_ssid_txt(ssid, ssid_len),
+ channel_list ? channel_list : "N/A");
+ wpas_notify_dpp_conn_status(wpa_s, status, wpa_ssid_txt(ssid, ssid_len),
+ channel_list, auth->band_list, auth->band_list_size);
+ os_free(channel_list);
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_stop(wpa_s);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
+ wpa_s, NULL);
+}
+
+
+static int wpas_dpp_process_conf_obj(void *ctx,
+ struct dpp_authentication *auth)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ unsigned int i;
+ int res = -1;
+
+ for (i = 0; i < auth->num_conf_obj; i++) {
+ res = wpas_dpp_handle_config_obj(wpa_s, auth,
+ &auth->conf_obj[i]);
+ if (res)
+ break;
+ }
+ if (!res)
+ wpas_dpp_post_process_config(wpa_s, auth);
+
+ return res;
+}
+
+
+static void wpas_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ if (bi == wpa_s->dpp_chirp_bi)
+ wpas_dpp_chirp_stop(wpa_s);
+}
+
+
+static void
+wpas_dpp_rx_presence_announcement(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ const u8 *r_bootstrap;
+ u16 r_bootstrap_len;
+ struct dpp_bootstrap_info *peer_bi;
+ struct dpp_authentication *auth;
+
+ if (!wpa_s->dpp)
+ return;
+
+ if (wpa_s->dpp_auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore Presence Announcement during ongoing Authentication");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Presence Announcement from " MACSTR,
+ MAC2STR(src));
+
+ r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_bootstrap_len);
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_msg(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",
+ r_bootstrap, r_bootstrap_len);
+ peer_bi = dpp_bootstrap_find_chirp(wpa_s->dpp, r_bootstrap);
+ if (!peer_bi) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No matching bootstrapping information found");
+ return;
+ }
+
+ auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, NULL,
+ DPP_CAPAB_CONFIGURATOR, freq, NULL, 0);
+ if (!auth)
+ return;
+ wpas_dpp_set_testing_options(wpa_s, auth);
+ if (dpp_set_configurator(auth, wpa_s->dpp_configurator_params) < 0) {
+ dpp_auth_deinit(auth);
+ return;
+ }
+
+ auth->neg_freq = freq;
+
+ if (!is_zero_ether_addr(peer_bi->mac_addr))
+ os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
+
+ wpa_s->dpp_auth = auth;
+ if (wpas_dpp_auth_init_next(wpa_s) < 0) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ }
+}
+
#endif /* CONFIG_DPP2 */
@@ -1353,6 +1851,9 @@
status[0]);
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
" status=%u", MAC2STR(src), status[0]);
+#ifdef CONFIG_DPP2
+ wpas_dpp_send_conn_status_result(wpa_s, status[0]);
+#endif /* CONFIG_DPP2 */
goto fail;
}
@@ -1376,6 +1877,9 @@
"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));
+#ifdef CONFIG_DPP2
+ wpas_dpp_send_conn_status_result(wpa_s, res);
+#endif /* CONFIG_DPP2 */
goto fail;
}
@@ -1741,6 +2245,7 @@
if (wpas_dpp_auth_init(wpa_s, cmd) < 0) {
wpa_printf(MSG_DEBUG,
"DPP: Authentication initialization failed");
+ offchannel_send_action_done(wpa_s);
return;
}
}
@@ -1818,6 +2323,13 @@
case DPP_PA_CONFIGURATION_RESULT:
wpas_dpp_rx_conf_result(wpa_s, src, hdr, buf, len);
break;
+ case DPP_PA_CONNECTION_STATUS_RESULT:
+ wpas_dpp_rx_conn_status_result(wpa_s, src, hdr, buf, len);
+ break;
+ case DPP_PA_PRESENCE_ANNOUNCEMENT:
+ wpas_dpp_rx_presence_announcement(wpa_s, src, hdr, buf, len,
+ freq);
+ break;
#endif /* CONFIG_DPP2 */
default:
wpa_printf(MSG_DEBUG,
@@ -1853,6 +2365,18 @@
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
return NULL;
}
+
+ if (wpa_s->dpp_auth_ok_on_ack && auth->configurator) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Have not received ACK for Auth Confirm yet - assume it was received based on this GAS request");
+ /* wpas_dpp_auth_success() would normally have been called from
+ * TX status handler, but since there was no such handler call
+ * yet, simply send out the event message and proceed with
+ * exchange. */
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=1");
+ wpa_s->dpp_auth_ok_on_ack = 0;
+ }
+
wpa_hexdump(MSG_DEBUG,
"DPP: Received Configuration Request (GAS Query Request)",
query, query_len);
@@ -1894,6 +2418,7 @@
if (ok && auth->peer_version >= 2 &&
auth->conf_resp_status == DPP_STATUS_OK) {
wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
+ wpas_notify_dpp_config_sent_wait_response(wpa_s);
auth->waiting_conf_result = 1;
auth->conf_resp = NULL;
wpabuf_free(resp);
@@ -1927,15 +2452,18 @@
int ret = -1;
char *curve = NULL;
- auth = os_zalloc(sizeof(*auth));
+ auth = dpp_alloc_auth(wpa_s->dpp, wpa_s);
if (!auth)
return -1;
curve = get_param(cmd, " curve=");
wpas_dpp_set_testing_options(wpa_s, auth);
- if (dpp_set_configurator(wpa_s->dpp, wpa_s, auth, cmd) == 0 &&
+ if (dpp_set_configurator(auth, cmd) == 0 &&
dpp_configurator_own_config(auth, curve, 0) == 0)
- ret = wpas_dpp_handle_config_obj(wpa_s, auth);
+ ret = wpas_dpp_handle_config_obj(wpa_s, auth,
+ &auth->conf_obj[0]);
+ if (!ret)
+ wpas_dpp_post_process_config(wpa_s, auth);
dpp_auth_deinit(auth);
os_free(curve);
@@ -2202,6 +2730,8 @@
void wpas_dpp_stop(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->dpp_auth || wpa_s->dpp_pkex)
+ offchannel_send_action_done(wpa_s);
dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL;
dpp_pkex_free(wpa_s->dpp_pkex);
@@ -2213,6 +2743,7 @@
int wpas_dpp_init(struct wpa_supplicant *wpa_s)
{
+ struct dpp_global_config config;
u8 adv_proto_id[7];
adv_proto_id[0] = WLAN_EID_VENDOR_SPECIFIC;
@@ -2225,7 +2756,15 @@
sizeof(adv_proto_id), wpas_dpp_gas_req_handler,
wpas_dpp_gas_status_handler, wpa_s) < 0)
return -1;
- wpa_s->dpp = dpp_global_init();
+
+ os_memset(&config, 0, sizeof(config));
+ config.msg_ctx = wpa_s;
+ config.cb_ctx = wpa_s;
+#ifdef CONFIG_DPP2
+ config.process_conf_obj = wpas_dpp_process_conf_obj;
+ config.remove_bi = wpas_dpp_remove_bi;
+#endif /* CONFIG_DPP2 */
+ wpa_s->dpp = dpp_global_init(&config);
return wpa_s->dpp ? 0 : -1;
}
@@ -2250,8 +2789,12 @@
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);
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
+ wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
dpp_pfs_free(wpa_s->dpp_pfs);
wpa_s->dpp_pfs = NULL;
+ wpas_dpp_chirp_stop(wpa_s);
#endif /* CONFIG_DPP2 */
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
@@ -2261,3 +2804,290 @@
os_free(wpa_s->dpp_configurator_params);
wpa_s->dpp_configurator_params = NULL;
}
+
+
+#ifdef CONFIG_DPP2
+
+int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ struct dpp_controller_config config;
+ const char *pos;
+
+ os_memset(&config, 0, sizeof(config));
+ if (cmd) {
+ pos = os_strstr(cmd, " tcp_port=");
+ if (pos) {
+ pos += 10;
+ config.tcp_port = atoi(pos);
+ }
+ }
+ config.configurator_params = wpa_s->dpp_configurator_params;
+ return dpp_controller_start(wpa_s->dpp, &config);
+}
+
+
+static void wpas_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx);
+
+static void wpas_dpp_chirp_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "DPP: No chirp response received");
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_chirp_next(wpa_s, NULL);
+}
+
+
+static void wpas_dpp_chirp_tx_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)
+{
+ if (result == OFFCHANNEL_SEND_ACTION_FAILED) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to send chirp on %d MHz",
+ wpa_s->dpp_chirp_freq);
+ if (eloop_register_timeout(0, 0, wpas_dpp_chirp_next,
+ wpa_s, NULL) < 0)
+ wpas_dpp_chirp_stop(wpa_s);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Chirp send completed - wait for response");
+ if (eloop_register_timeout(2, 0, wpas_dpp_chirp_timeout,
+ wpa_s, NULL) < 0)
+ wpas_dpp_chirp_stop(wpa_s);
+}
+
+
+static void wpas_dpp_chirp_start(struct wpa_supplicant *wpa_s)
+{
+ wpa_printf(MSG_DEBUG, "DPP: Chirp on %d MHz", wpa_s->dpp_chirp_freq);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(broadcast), wpa_s->dpp_chirp_freq,
+ DPP_PA_PRESENCE_ANNOUNCEMENT);
+ if (offchannel_send_action(
+ wpa_s, wpa_s->dpp_chirp_freq, broadcast,
+ wpa_s->own_addr, broadcast,
+ wpabuf_head(wpa_s->dpp_presence_announcement),
+ wpabuf_len(wpa_s->dpp_presence_announcement),
+ 2000, wpas_dpp_chirp_tx_status, 0) < 0)
+ wpas_dpp_chirp_stop(wpa_s);
+}
+
+
+static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ struct dpp_bootstrap_info *bi = wpa_s->dpp_chirp_bi;
+ unsigned int i;
+ struct hostapd_hw_modes *mode;
+ int c;
+ struct wpa_bss *bss;
+
+ if (!bi)
+ return;
+
+ wpa_s->dpp_chirp_scan_done = 1;
+
+ os_free(wpa_s->dpp_chirp_freqs);
+ wpa_s->dpp_chirp_freqs = NULL;
+
+ /* Channels from own bootstrapping info */
+ for (i = 0; i < bi->num_freq; i++)
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs, bi->freq[i]);
+
+ /* Preferred chirping channels */
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs, 2437);
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ HOSTAPD_MODE_IEEE80211A, 0);
+ if (mode) {
+ int chan44 = 0, chan149 = 0;
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+
+ if (chan->flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_RADAR))
+ continue;
+ if (chan->freq == 5220)
+ chan44 = 1;
+ if (chan->freq == 5745)
+ chan149 = 1;
+ }
+ if (chan149)
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs, 5745);
+ else if (chan44)
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs, 5220);
+ }
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ HOSTAPD_MODE_IEEE80211AD, 0);
+ if (mode) {
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+
+ if ((chan->flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_RADAR)) ||
+ chan->freq != 60480)
+ continue;
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs, 60480);
+ break;
+ }
+ }
+
+ /* Add channels from scan results for APs that advertise Configurator
+ * Connectivity element */
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ if (wpa_bss_get_vendor_ie(bss, DPP_CC_IE_VENDOR_TYPE))
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs,
+ bss->freq);
+ }
+
+ if (!wpa_s->dpp_chirp_freqs ||
+ eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL) < 0)
+ wpas_dpp_chirp_stop(wpa_s);
+}
+
+
+static void wpas_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ int i;
+
+ if (wpa_s->dpp_chirp_listen)
+ wpas_dpp_listen_stop(wpa_s);
+
+ if (wpa_s->dpp_chirp_freq == 0) {
+ if (wpa_s->dpp_chirp_round % 4 == 0 &&
+ !wpa_s->dpp_chirp_scan_done) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Update channel list for chirping");
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
+ wpa_s->scan_res_handler =
+ wpas_dpp_chirp_scan_res_handler;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ return;
+ }
+ wpa_s->dpp_chirp_freq = wpa_s->dpp_chirp_freqs[0];
+ wpa_s->dpp_chirp_round++;
+ wpa_printf(MSG_DEBUG, "DPP: Start chirping round %d",
+ wpa_s->dpp_chirp_round);
+ } else {
+ for (i = 0; wpa_s->dpp_chirp_freqs[i]; i++)
+ if (wpa_s->dpp_chirp_freqs[i] == wpa_s->dpp_chirp_freq)
+ break;
+ if (!wpa_s->dpp_chirp_freqs[i]) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Previous chirp freq %d not found",
+ wpa_s->dpp_chirp_freq);
+ return;
+ }
+ i++;
+ if (wpa_s->dpp_chirp_freqs[i]) {
+ wpa_s->dpp_chirp_freq = wpa_s->dpp_chirp_freqs[i];
+ } else {
+ wpa_s->dpp_chirp_iter--;
+ if (wpa_s->dpp_chirp_iter <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Chirping iterations completed");
+ wpas_dpp_chirp_stop(wpa_s);
+ return;
+ }
+ wpa_s->dpp_chirp_freq = 0;
+ wpa_s->dpp_chirp_scan_done = 0;
+ if (eloop_register_timeout(30, 0, wpas_dpp_chirp_next,
+ wpa_s, NULL) < 0) {
+ wpas_dpp_chirp_stop(wpa_s);
+ return;
+ }
+ if (wpa_s->dpp_chirp_listen) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Listen on %d MHz during chirp 30 second wait",
+ wpa_s->dpp_chirp_listen);
+ wpas_dpp_listen_start(wpa_s,
+ wpa_s->dpp_chirp_listen);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Wait 30 seconds before starting the next chirping round");
+ }
+ return;
+ }
+ }
+
+ wpas_dpp_chirp_start(wpa_s);
+}
+
+
+int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ const char *pos;
+ int iter = 1, listen_freq = 0;
+ struct dpp_bootstrap_info *bi;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
+ if (!bi) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Identified bootstrap info not found");
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " iter=");
+ if (pos) {
+ iter = atoi(pos + 6);
+ if (iter <= 0)
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " listen=");
+ if (pos) {
+ listen_freq = atoi(pos + 8);
+ if (iter <= 0)
+ return -1;
+ }
+
+ wpas_dpp_chirp_stop(wpa_s);
+ wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
+ wpa_s->dpp_qr_mutual = 0;
+ wpa_s->dpp_chirp_bi = bi;
+ wpa_s->dpp_presence_announcement = dpp_build_presence_announcement(bi);
+ if (!wpa_s->dpp_presence_announcement)
+ return -1;
+ wpa_s->dpp_chirp_iter = iter;
+ wpa_s->dpp_chirp_round = 0;
+ wpa_s->dpp_chirp_scan_done = 0;
+ wpa_s->dpp_chirp_listen = listen_freq;
+
+ return eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL);
+}
+
+
+void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->dpp_presence_announcement) {
+ offchannel_send_action_done(wpa_s);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CHIRP_STOPPED);
+ }
+ wpa_s->dpp_chirp_bi = NULL;
+ wpabuf_free(wpa_s->dpp_presence_announcement);
+ wpa_s->dpp_presence_announcement = NULL;
+ if (wpa_s->dpp_chirp_listen)
+ wpas_dpp_listen_stop(wpa_s);
+ wpa_s->dpp_chirp_listen = 0;
+ wpa_s->dpp_chirp_freq = 0;
+ os_free(wpa_s->dpp_chirp_freqs);
+ wpa_s->dpp_chirp_freqs = NULL;
+ eloop_cancel_timeout(wpas_dpp_chirp_next, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_chirp_timeout, wpa_s, NULL);
+ if (wpa_s->scan_res_handler == wpas_dpp_chirp_scan_res_handler) {
+ wpas_abort_ongoing_scan(wpa_s);
+ wpa_s->scan_res_handler = NULL;
+ }
+}
+
+#endif /* CONFIG_DPP2 */
diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h
index ecb7a7d..2ce378d 100644
--- a/wpa_supplicant/dpp_supplicant.h
+++ b/wpa_supplicant/dpp_supplicant.h
@@ -1,6 +1,7 @@
/*
* wpa_supplicant - DPP
* Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,7 +10,12 @@
#ifndef DPP_SUPPLICANT_H
#define DPP_SUPPLICANT_H
+enum dpp_status_error;
+
int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_nfc_uri(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_nfc_handover_req(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_nfc_handover_sel(struct wpa_supplicant *wpa_s, const char *cmd);
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);
@@ -25,5 +31,11 @@
void wpas_dpp_deinit(struct wpa_supplicant *wpa_s);
int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_bss *bss);
+int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd);
+void wpas_dpp_connected(struct wpa_supplicant *wpa_s);
+void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s,
+ enum dpp_status_error result);
+int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd);
+void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s);
#endif /* DPP_SUPPLICANT_H */
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 4a9f472..54ae03b 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -87,6 +87,16 @@
return -1;
}
+static inline int wpa_drv_mesh_link_probe(struct wpa_supplicant *wpa_s,
+ const u8 *addr,
+ const u8 *eth, size_t len)
+{
+ if (wpa_s->driver->probe_mesh_link)
+ return wpa_s->driver->probe_mesh_link(wpa_s->drv_priv, addr,
+ eth, len);
+ return -1;
+}
+
static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s,
struct wpa_driver_scan_params *params)
{
@@ -114,13 +124,8 @@
return -1;
}
-static inline struct wpa_scan_results * wpa_drv_get_scan_results2(
- struct wpa_supplicant *wpa_s)
-{
- if (wpa_s->driver->get_scan_results2)
- return wpa_s->driver->get_scan_results2(wpa_s->drv_priv);
- return NULL;
-}
+struct wpa_scan_results *
+wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s);
static inline int wpa_drv_get_bssid(struct wpa_supplicant *wpa_s, u8 *bssid)
{
@@ -142,18 +147,38 @@
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)
+ const u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
+ struct wpa_driver_set_key_params params;
+
+ os_memset(¶ms, 0, sizeof(params));
+ params.ifname = wpa_s->ifname;
+ params.alg = alg;
+ params.addr = addr;
+ params.key_idx = key_idx;
+ params.set_tx = set_tx;
+ params.seq = seq;
+ params.seq_len = seq_len;
+ params.key = key;
+ params.key_len = key_len;
+ params.key_flag = key_flag;
+
if (alg != WPA_ALG_NONE) {
- if (key_idx >= 0 && key_idx <= 6)
+ /* keyidx = 1 can be either a broadcast or--with
+ * Extended Key ID--a unicast key. Use bit 15 for
+ * the pairwise keyidx 1 which is hopefully high enough
+ * to not clash with future extensions.
+ */
+ if (key_idx == 1 && (key_flag & KEY_FLAG_PAIRWISE))
+ wpa_s->keys_cleared &= ~BIT(15);
+ else if (key_idx >= 0 && key_idx <= 5)
wpa_s->keys_cleared &= ~BIT(key_idx);
else
wpa_s->keys_cleared = 0;
}
if (wpa_s->driver->set_key) {
- return wpa_s->driver->set_key(wpa_s->ifname, wpa_s->drv_priv,
- alg, addr, key_idx, set_tx,
- seq, seq_len, key, key_len);
+ return wpa_s->driver->set_key(wpa_s->drv_priv, ¶ms);
}
return -1;
}
@@ -168,7 +193,7 @@
}
static inline int wpa_drv_sta_deauth(struct wpa_supplicant *wpa_s,
- const u8 *addr, int reason_code)
+ const u8 *addr, u16 reason_code)
{
if (wpa_s->driver->sta_deauth) {
return wpa_s->driver->sta_deauth(wpa_s->drv_priv,
@@ -179,7 +204,7 @@
}
static inline int wpa_drv_deauthenticate(struct wpa_supplicant *wpa_s,
- const u8 *addr, int reason_code)
+ const u8 *addr, u16 reason_code)
{
if (wpa_s->driver->deauthenticate) {
return wpa_s->driver->deauthenticate(wpa_s->drv_priv, addr,
@@ -294,12 +319,12 @@
static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s,
const u8 *data, size_t data_len, int noack,
- unsigned int freq)
+ unsigned int freq, unsigned int wait)
{
if (wpa_s->driver->send_mlme)
return wpa_s->driver->send_mlme(wpa_s->drv_priv,
data, data_len, noack,
- freq, NULL, 0);
+ freq, NULL, 0, 0, wait);
return -1;
}
@@ -337,6 +362,17 @@
return -1;
}
+static inline int wpa_drv_tx_control_port(struct wpa_supplicant *wpa_s,
+ const u8 *dest, u16 proto,
+ const u8 *buf, size_t len,
+ int no_encrypt)
+{
+ if (!wpa_s->driver->tx_control_port)
+ return -1;
+ return wpa_s->driver->tx_control_port(wpa_s->drv_priv, dest, proto,
+ buf, len, no_encrypt);
+}
+
static inline int wpa_drv_hapd_send_eapol(struct wpa_supplicant *wpa_s,
const u8 *addr, const u8 *data,
size_t data_len, int encrypt,
@@ -484,13 +520,8 @@
return -1;
}
-static inline int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
- struct wpa_signal_info *si)
-{
- if (wpa_s->driver->signal_poll)
- return wpa_s->driver->signal_poll(wpa_s->drv_priv, si);
- return -1;
-}
+int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
+ struct wpa_signal_info *si);
static inline int wpa_drv_channel_info(struct wpa_supplicant *wpa_s,
struct wpa_channel_info *ci)
@@ -671,6 +702,13 @@
qos_map_set_len);
}
+static inline int wpa_drv_get_wowlan(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->driver->get_wowlan)
+ return 0;
+ return wpa_s->driver->get_wowlan(wpa_s->drv_priv);
+}
+
static inline int wpa_drv_wowlan(struct wpa_supplicant *wpa_s,
const struct wowlan_triggers *triggers)
{
@@ -740,7 +778,7 @@
}
static inline int wpa_drv_enable_protect_frames(struct wpa_supplicant *wpa_s,
- Boolean enabled)
+ bool enabled)
{
if (!wpa_s->driver->enable_protect_frames)
return -1;
@@ -748,7 +786,7 @@
}
static inline int wpa_drv_enable_encrypt(struct wpa_supplicant *wpa_s,
- Boolean enabled)
+ bool enabled)
{
if (!wpa_s->driver->enable_encrypt)
return -1;
@@ -756,7 +794,7 @@
}
static inline int wpa_drv_set_replay_protect(struct wpa_supplicant *wpa_s,
- Boolean enabled, u32 window)
+ bool enabled, u32 window)
{
if (!wpa_s->driver->set_replay_protect)
return -1;
@@ -773,7 +811,7 @@
}
static inline int wpa_drv_enable_controlled_port(struct wpa_supplicant *wpa_s,
- Boolean enabled)
+ bool enabled)
{
if (!wpa_s->driver->enable_controlled_port)
return -1;
@@ -1070,4 +1108,11 @@
wpa_s->bridge_ifname, val);
}
+static inline int wpa_drv_dpp_listen(struct wpa_supplicant *wpa_s, bool enable)
+{
+ if (!wpa_s->driver->dpp_listen)
+ return 0;
+ return wpa_s->driver->dpp_listen(wpa_s->drv_priv, enable);
+}
+
#endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/eap_register.c b/wpa_supplicant/eap_register.c
index ece5716..3f018c4 100644
--- a/wpa_supplicant/eap_register.c
+++ b/wpa_supplicant/eap_register.c
@@ -102,6 +102,11 @@
ret = eap_peer_fast_register();
#endif /* EAP_FAST */
+#ifdef EAP_TEAP
+ if (ret == 0)
+ ret = eap_peer_teap_register();
+#endif /* EAP_TEAP */
+
#ifdef EAP_PAX
if (ret == 0)
ret = eap_peer_pax_register();
@@ -237,6 +242,11 @@
ret = eap_server_fast_register();
#endif /* EAP_SERVER_FAST */
+#ifdef EAP_SERVER_TEAP
+ if (ret == 0)
+ ret = eap_server_teap_register();
+#endif /* EAP_SERVER_TEAP */
+
#ifdef EAP_SERVER_WSC
if (ret == 0)
ret = eap_server_wsc_register();
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index 3fd4ce6..9f69736 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -15,6 +15,7 @@
#include "common.h"
#include "utils/ext_password.h"
#include "common/version.h"
+#include "crypto/tls.h"
#include "config.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "eap_peer/eap.h"
@@ -438,7 +439,7 @@
static void eapol_test_write_cert(FILE *f, const char *subject,
const struct wpabuf *cert)
{
- unsigned char *encoded;
+ char *encoded;
encoded = base64_encode(wpabuf_head(cert), wpabuf_len(cert), NULL);
if (encoded == NULL)
@@ -497,45 +498,40 @@
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
-static void eapol_test_cert_cb(void *ctx, int depth, const char *subject,
- const char *altsubject[], int num_altsubject,
- const char *cert_hash,
- const struct wpabuf *cert)
+static void eapol_test_cert_cb(void *ctx, struct tls_cert_data *cert,
+ const char *cert_hash)
{
struct eapol_test_data *e = ctx;
+ int i;
wpa_msg(e->wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
"depth=%d subject='%s'%s%s",
- depth, subject,
+ cert->depth, cert->subject,
cert_hash ? " hash=" : "",
cert_hash ? cert_hash : "");
- if (cert) {
+ if (cert->cert) {
char *cert_hex;
- size_t len = wpabuf_len(cert) * 2 + 1;
+ size_t len = wpabuf_len(cert->cert) * 2 + 1;
cert_hex = os_malloc(len);
if (cert_hex) {
- wpa_snprintf_hex(cert_hex, len, wpabuf_head(cert),
- wpabuf_len(cert));
+ wpa_snprintf_hex(cert_hex, len, wpabuf_head(cert->cert),
+ wpabuf_len(cert->cert));
wpa_msg_ctrl(e->wpa_s, MSG_INFO,
WPA_EVENT_EAP_PEER_CERT
"depth=%d subject='%s' cert=%s",
- depth, subject, cert_hex);
+ cert->depth, cert->subject, cert_hex);
os_free(cert_hex);
}
if (e->server_cert_file)
eapol_test_write_cert(e->server_cert_file,
- subject, cert);
+ cert->subject, cert->cert);
}
- if (altsubject) {
- int i;
-
- for (i = 0; i < num_altsubject; i++)
- wpa_msg(e->wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_ALT
- "depth=%d %s", depth, altsubject[i]);
- }
+ for (i = 0; i < cert->num_altsubject; i++)
+ wpa_msg(e->wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_ALT
+ "depth=%d %s", cert->depth, cert->altsubject[i]);
}
@@ -648,9 +644,9 @@
eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
- eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+ eapol_sm_notify_portValid(wpa_s->eapol, false);
/* 802.1X::portControl = Auto */
- eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
+ eapol_sm_notify_portEnabled(wpa_s->eapol, true);
return 0;
}
@@ -1394,7 +1390,7 @@
eapol_test.ctrl_iface = 1;
break;
case 'v':
- printf("eapol_test v" VERSION_STR "\n");
+ printf("eapol_test v%s\n", VERSION_STR);
return 0;
case 'W':
wait_for_monitor++;
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 815b994..f531c39 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -188,6 +188,16 @@
drv_ssid_len) == 0)
return 0; /* current profile still in use */
+#ifdef CONFIG_OWE
+ if ((wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+ wpa_s->current_bss &&
+ (wpa_s->current_bss->flags & WPA_BSS_OWE_TRANSITION) &&
+ drv_ssid_len == wpa_s->current_bss->ssid_len &&
+ os_memcmp(drv_ssid, wpa_s->current_bss->ssid,
+ drv_ssid_len) == 0)
+ return 0; /* current profile still in use */
+#endif /* CONFIG_OWE */
+
wpa_msg(wpa_s, MSG_DEBUG,
"Driver-initiated BSS selection changed the SSID to %s",
wpa_ssid_txt(drv_ssid, drv_ssid_len));
@@ -312,12 +322,13 @@
if (bssid_changed)
wpas_notify_bssid_changed(wpa_s);
- eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
- eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+ eapol_sm_notify_portEnabled(wpa_s->eapol, false);
+ eapol_sm_notify_portValid(wpa_s->eapol, false);
if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
wpa_s->key_mgmt == WPA_KEY_MGMT_OWE ||
- wpa_s->key_mgmt == WPA_KEY_MGMT_DPP)
- eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+ wpa_s->key_mgmt == WPA_KEY_MGMT_DPP || wpa_s->drv_authorized_port)
+ eapol_sm_notify_eap_success(wpa_s->eapol, false);
+ wpa_s->drv_authorized_port = 0;
wpa_s->ap_ies_from_associnfo = 0;
wpa_s->current_ssid = NULL;
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
@@ -326,6 +337,7 @@
wpas_rrm_reset(wpa_s);
wpa_s->wnmsleep_used = 0;
wnm_clear_coloc_intf_reporting(wpa_s);
+ wpa_s->disable_mbo_oce = 0;
#ifdef CONFIG_TESTING_OPTIONS
wpa_s->last_tk_alg = WPA_ALG_NONE;
@@ -477,6 +489,7 @@
#ifndef CONFIG_NO_SCAN_PROCESSING
+#ifdef CONFIG_WEP
static int has_wep_key(struct wpa_ssid *ssid)
{
int i;
@@ -488,6 +501,7 @@
return 0;
}
+#endif /* CONFIG_WEP */
static int wpa_supplicant_match_privacy(struct wpa_bss *bss,
@@ -508,8 +522,10 @@
return 1;
#endif /* CONFIG_OWE */
+#ifdef CONFIG_WEP
if (has_wep_key(ssid))
privacy = 1;
+#endif /* CONFIG_WEP */
#ifdef IEEE8021X_EAPOL
if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
@@ -538,17 +554,21 @@
int proto_match = 0;
const u8 *rsn_ie, *wpa_ie;
int ret;
+#ifdef CONFIG_WEP
int wep_ok;
+#endif /* CONFIG_WEP */
ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss);
if (ret >= 0)
return ret;
+#ifdef CONFIG_WEP
/* Allow TSN if local configuration accepts WEP use without WPA/WPA2 */
wep_ok = !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
(((ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
ssid->wep_key_len[ssid->wep_tx_keyidx] > 0) ||
(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA));
+#endif /* CONFIG_WEP */
rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
while ((ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)) && rsn_ie) {
@@ -565,6 +585,7 @@
if (!ie.has_group)
ie.group_cipher = wpa_default_rsn_cipher(bss->freq);
+#ifdef CONFIG_WEP
if (wep_ok &&
(ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
{
@@ -573,6 +594,7 @@
" selected based on TSN in RSN IE");
return 1;
}
+#endif /* CONFIG_WEP */
if (!(ie.proto & ssid->proto) &&
!(ssid->proto & WPA_PROTO_OSEN)) {
@@ -611,7 +633,6 @@
break;
}
-#ifdef CONFIG_IEEE80211W
if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
wpas_get_ssid_pmf(wpa_s, ssid) ==
MGMT_FRAME_PROTECTION_REQUIRED) {
@@ -620,7 +641,6 @@
" skip RSN IE - no mgmt frame protection");
break;
}
-#endif /* CONFIG_IEEE80211W */
if ((ie.capabilities & WPA_CAPABILITY_MFPR) &&
wpas_get_ssid_pmf(wpa_s, ssid) ==
NO_MGMT_FRAME_PROTECTION) {
@@ -629,17 +649,6 @@
" skip RSN IE - no mgmt frame protection enabled but AP requires it");
break;
}
-#ifdef CONFIG_MBO
- if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
- wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND) &&
- wpas_get_ssid_pmf(wpa_s, ssid) !=
- NO_MGMT_FRAME_PROTECTION) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip RSN IE - no mgmt frame protection enabled on MBO AP");
- break;
- }
-#endif /* CONFIG_MBO */
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG,
@@ -647,7 +656,6 @@
return 1;
}
-#ifdef CONFIG_IEEE80211W
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)
@@ -655,7 +663,6 @@
" skip - MFP Required but network not MFP Capable");
return 0;
}
-#endif /* CONFIG_IEEE80211W */
wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
while ((ssid->proto & WPA_PROTO_WPA) && wpa_ie) {
@@ -668,6 +675,7 @@
break;
}
+#ifdef CONFIG_WEP
if (wep_ok &&
(ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
{
@@ -676,6 +684,7 @@
" selected based on TSN in WPA IE");
return 1;
}
+#endif /* CONFIG_WEP */
if (!(ie.proto & ssid->proto)) {
if (debug_print)
@@ -785,8 +794,8 @@
}
-static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
- int debug_print)
+static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_bss *bss, int debug_print)
{
const struct hostapd_hw_modes *mode = NULL, *modes;
const u8 scan_ie[2] = { WLAN_EID_SUPP_RATES, WLAN_EID_EXT_SUPP_RATES };
@@ -863,6 +872,28 @@
continue;
}
+#ifdef CONFIG_SAE
+ if (flagged && ((rate_ie[j] & 0x7f) ==
+ BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY)) {
+ if (wpa_s->conf->sae_pwe == 0 &&
+ !ssid->sae_password_id &&
+ wpa_key_mgmt_sae(ssid->key_mgmt)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " SAE H2E disabled");
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ignore_sae_h2e_only) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "TESTING: Ignore SAE H2E requirement mismatch");
+ continue;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ return 0;
+ }
+ continue;
+ }
+#endif /* CONFIG_SAE */
+
if (!flagged)
continue;
@@ -964,6 +995,24 @@
*ret_ssid = pos;
*ret_ssid_len = ssid_len;
+ if (!(bss->flags & WPA_BSS_OWE_TRANSITION)) {
+ struct wpa_ssid *ssid;
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (wpas_network_disabled(wpa_s, ssid))
+ continue;
+ if (ssid->ssid_len == ssid_len &&
+ os_memcmp(ssid->ssid, pos, ssid_len) == 0) {
+ /* OWE BSS in transition mode for a currently
+ * enabled OWE network. */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "OWE: transition mode OWE SSID for active OWE profile");
+ bss->flags |= WPA_BSS_OWE_TRANSITION;
+ break;
+ }
+ }
+ }
+
if (bss->ssid_len > 0)
return;
@@ -1004,10 +1053,33 @@
wpa_ssid_txt(pos, ssid_len));
os_memcpy(bss->ssid, pos, ssid_len);
bss->ssid_len = ssid_len;
+ bss->flags |= WPA_BSS_OWE_TRANSITION;
#endif /* CONFIG_OWE */
}
+static int disabled_freq(struct wpa_supplicant *wpa_s, int freq)
+{
+ int i, j;
+
+ if (!wpa_s->hw.modes || !wpa_s->hw.num_modes)
+ return 0;
+
+ for (j = 0; j < wpa_s->hw.num_modes; j++) {
+ struct hostapd_hw_modes *mode = &wpa_s->hw.modes[j];
+
+ for (i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *chan = &mode->channels[i];
+
+ if (chan->freq == freq)
+ return !!(chan->flag & HOSTAPD_CHAN_DISABLED);
+ }
+ }
+
+ return 1;
+}
+
+
struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
int i, struct wpa_bss *bss,
struct wpa_ssid *group,
@@ -1099,6 +1171,12 @@
return NULL;
}
+ if (disabled_freq(wpa_s, bss->freq)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - channel disabled");
+ return NULL;
+ }
+
wpa = wpa_ie_len > 0 || rsn_ie_len > 0;
for (ssid = group; ssid; ssid = only_first_ssid ? NULL : ssid->pnext) {
@@ -1199,6 +1277,7 @@
continue;
}
+#ifdef CONFIG_WEP
if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
has_wep_key(ssid)) {
if (debug_print)
@@ -1206,6 +1285,7 @@
" skip - ignore WPA/WPA2 AP for WEP network block");
continue;
}
+#endif /* CONFIG_WEP */
if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen &&
!rsn_osen) {
@@ -1222,7 +1302,7 @@
continue;
}
- if (ssid->mode != IEEE80211_MODE_MESH && !bss_is_ess(bss) &&
+ if (ssid->mode != WPAS_MODE_MESH && !bss_is_ess(bss) &&
!bss_is_pbss(bss)) {
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG,
@@ -1246,7 +1326,7 @@
}
#ifdef CONFIG_MESH
- if (ssid->mode == IEEE80211_MODE_MESH && ssid->frequency > 0 &&
+ if (ssid->mode == WPAS_MODE_MESH && ssid->frequency > 0 &&
ssid->frequency != bss->freq) {
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG,
@@ -1255,13 +1335,27 @@
}
#endif /* CONFIG_MESH */
- if (!rate_match(wpa_s, bss, debug_print)) {
+ if (!rate_match(wpa_s, ssid, bss, debug_print)) {
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG,
" skip - rate sets do not match");
continue;
}
+#ifdef CONFIG_SAE
+ if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) &&
+ wpa_s->conf->sae_pwe != 3 &&
+ wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ (!(ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX)) ||
+ ie[1] < 1 ||
+ !(ie[2] & BIT(WLAN_RSNX_CAPAB_SAE_H2E)))) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - SAE H2E required, but not supported by the AP");
+ continue;
+ }
+#endif /* CONFIG_SAE */
+
#ifndef CONFIG_IBSS_RSN
if (ssid->mode == WPAS_MODE_IBSS &&
!(ssid->key_mgmt & (WPA_KEY_MGMT_NONE |
@@ -1426,8 +1520,9 @@
wpa_s->owe_transition_select = 0;
if (!*selected_ssid)
continue;
- wpa_dbg(wpa_s, MSG_DEBUG, " selected BSS " MACSTR
+ wpa_dbg(wpa_s, MSG_DEBUG, " selected %sBSS " MACSTR
" ssid='%s'",
+ bss == wpa_s->current_bss ? "current ": "",
MAC2STR(bss->bssid),
wpa_ssid_txt(bss->ssid, bss->ssid_len));
return bss;
@@ -1441,7 +1536,7 @@
struct wpa_ssid **selected_ssid)
{
struct wpa_bss *selected = NULL;
- int prio;
+ size_t prio;
struct wpa_ssid *next_ssid = NULL;
struct wpa_ssid *ssid;
@@ -1596,7 +1691,7 @@
static struct wpa_ssid *
wpa_supplicant_pick_new_network(struct wpa_supplicant *wpa_s)
{
- int prio;
+ size_t prio;
struct wpa_ssid *ssid;
for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
@@ -1615,9 +1710,9 @@
continue;
}
#endif /* !CONFIG_IBSS_RSN */
- if (ssid->mode == IEEE80211_MODE_IBSS ||
- ssid->mode == IEEE80211_MODE_AP ||
- ssid->mode == IEEE80211_MODE_MESH)
+ if (ssid->mode == WPAS_MODE_IBSS ||
+ ssid->mode == WPAS_MODE_AP ||
+ ssid->mode == WPAS_MODE_MESH)
return ssid;
}
}
@@ -1652,6 +1747,31 @@
}
+#ifndef CONFIG_NO_ROAMING
+
+static int wpas_get_snr_signal_info(u32 frequency, int avg_signal, int noise)
+{
+ if (noise == WPA_INVALID_NOISE)
+ noise = IS_5GHZ(frequency) ? DEFAULT_NOISE_FLOOR_5GHZ :
+ DEFAULT_NOISE_FLOOR_2GHZ;
+ return avg_signal - noise;
+}
+
+
+static unsigned int
+wpas_get_est_throughput_from_bss_snr(const struct wpa_supplicant *wpa_s,
+ const struct wpa_bss *bss, int snr)
+{
+ int rate = wpa_bss_get_max_rate(bss);
+ const u8 *ies = (const void *) (bss + 1);
+ size_t ie_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
+
+ return wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr);
+}
+
+#endif /* CONFIG_NO_ROAMING */
+
+
static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
struct wpa_bss *selected,
struct wpa_ssid *ssid)
@@ -1660,7 +1780,10 @@
#ifndef CONFIG_NO_ROAMING
int min_diff, diff;
int to_5ghz;
- int cur_est, sel_est;
+ int cur_level;
+ unsigned int cur_est, sel_est;
+ struct wpa_signal_info si;
+ int cur_snr = 0;
#endif /* CONFIG_NO_ROAMING */
if (wpa_s->reassociate)
@@ -1711,7 +1834,41 @@
return 1;
}
- if (selected->est_throughput > current_bss->est_throughput + 5000) {
+ cur_level = current_bss->level;
+ cur_est = current_bss->est_throughput;
+ sel_est = selected->est_throughput;
+
+ /*
+ * Try to poll the signal from the driver since this will allow to get
+ * more accurate values. In some cases, there can be big differences
+ * between the RSSI of the Probe Response frames of the AP we are
+ * associated with and the Beacon frames we hear from the same AP after
+ * association. This can happen, e.g., when there are two antennas that
+ * hear the AP very differently. If the driver chooses to hear the
+ * Probe Response frames during the scan on the "bad" antenna because
+ * it wants to save power, but knows to choose the other antenna after
+ * association, we will hear our AP with a low RSSI as part of the
+ * scan even when we can hear it decently on the other antenna. To cope
+ * with this, ask the driver to teach us how it hears the AP. Also, the
+ * scan results may be a bit old, since we can very quickly get fresh
+ * information about our currently associated AP.
+ */
+ if (wpa_drv_signal_poll(wpa_s, &si) == 0 &&
+ (si.avg_beacon_signal || si.avg_signal)) {
+ cur_level = si.avg_beacon_signal ? si.avg_beacon_signal :
+ si.avg_signal;
+ cur_snr = wpas_get_snr_signal_info(si.frequency, cur_level,
+ si.current_noise);
+
+ cur_est = wpas_get_est_throughput_from_bss_snr(wpa_s,
+ current_bss,
+ cur_snr);
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Using signal poll values for the current BSS: level=%d snr=%d est_throughput=%u",
+ cur_level, cur_snr, cur_est);
+ }
+
+ if (sel_est > cur_est + 5000) {
wpa_dbg(wpa_s, MSG_DEBUG,
"Allow reassociation - selected BSS has better estimated throughput");
return 1;
@@ -1719,59 +1876,59 @@
to_5ghz = selected->freq > 4000 && current_bss->freq < 4000;
- if (current_bss->level < 0 &&
- current_bss->level > selected->level + to_5ghz * 2) {
+ if (cur_level < 0 && cur_level > selected->level + to_5ghz * 2 &&
+ sel_est < cur_est * 1.2) {
wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better "
"signal level");
return 0;
}
- if (current_bss->est_throughput > selected->est_throughput + 5000) {
+ if (cur_est > sel_est + 5000) {
wpa_dbg(wpa_s, MSG_DEBUG,
"Skip roam - Current BSS has better estimated throughput");
return 0;
}
- cur_est = current_bss->est_throughput;
- sel_est = selected->est_throughput;
- min_diff = 2;
- if (current_bss->level < 0) {
- if (current_bss->level < -85)
- min_diff = 1;
- else if (current_bss->level < -80)
- min_diff = 2;
- else if (current_bss->level < -75)
- min_diff = 3;
- else if (current_bss->level < -70)
- min_diff = 4;
- else
- min_diff = 5;
- if (cur_est > sel_est * 1.5)
- min_diff += 10;
- else if (cur_est > sel_est * 1.2)
- min_diff += 5;
- else if (cur_est > sel_est * 1.1)
- min_diff += 2;
- else if (cur_est > sel_est)
- min_diff++;
+ if (cur_snr > GREAT_SNR) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Skip roam - Current BSS has good SNR (%u > %u)",
+ cur_snr, GREAT_SNR);
+ return 0;
}
- if (to_5ghz) {
- int reduce = 2;
- /* Make it easier to move to 5 GHz band */
- if (sel_est > cur_est * 1.5)
- reduce = 5;
- else if (sel_est > cur_est * 1.2)
- reduce = 4;
- else if (sel_est > cur_est * 1.1)
- reduce = 3;
+ if (cur_level < -85) /* ..-86 dBm */
+ min_diff = 1;
+ else if (cur_level < -80) /* -85..-81 dBm */
+ min_diff = 2;
+ else if (cur_level < -75) /* -80..-76 dBm */
+ min_diff = 3;
+ else if (cur_level < -70) /* -75..-71 dBm */
+ min_diff = 4;
+ else if (cur_level < 0) /* -70..-1 dBm */
+ min_diff = 5;
+ else /* unspecified units (not in dBm) */
+ min_diff = 2;
- if (min_diff > reduce)
- min_diff -= reduce;
- else
- min_diff = 0;
- }
- diff = abs(current_bss->level - selected->level);
+ if (cur_est > sel_est * 1.5)
+ min_diff += 10;
+ else if (cur_est > sel_est * 1.2)
+ min_diff += 5;
+ else if (cur_est > sel_est * 1.1)
+ min_diff += 2;
+ else if (cur_est > sel_est)
+ min_diff++;
+ else if (sel_est > cur_est * 1.5)
+ min_diff -= 10;
+ else if (sel_est > cur_est * 1.2)
+ min_diff -= 5;
+ else if (sel_est > cur_est * 1.1)
+ min_diff -= 2;
+ else if (sel_est > cur_est)
+ min_diff--;
+
+ if (to_5ghz)
+ min_diff -= 2;
+ diff = selected->level - cur_level;
if (diff < min_diff) {
wpa_dbg(wpa_s, MSG_DEBUG,
"Skip roam - too small difference in signal level (%d < %d)",
@@ -1867,15 +2024,6 @@
goto scan_work_done;
}
- if (ap) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Ignore scan results in AP mode");
-#ifdef CONFIG_AP
- if (wpa_s->ap_iface->scan_cb)
- wpa_s->ap_iface->scan_cb(wpa_s->ap_iface);
-#endif /* CONFIG_AP */
- goto scan_work_done;
- }
-
wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available (own=%u ext=%u)",
wpa_s->own_scan_running,
data ? data->scan_info.external_scan : 0);
@@ -1892,6 +2040,15 @@
wpas_notify_scan_done(wpa_s, 1);
+ if (ap) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Ignore scan results in AP mode");
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface->scan_cb)
+ wpa_s->ap_iface->scan_cb(wpa_s->ap_iface);
+#endif /* CONFIG_AP */
+ goto scan_work_done;
+ }
+
if (data && data->scan_info.external_scan) {
wpa_dbg(wpa_s, MSG_DEBUG, "Do not use results from externally requested scan operation for network selection");
wpa_scan_results_free(scan_res);
@@ -1901,7 +2058,7 @@
if (wnm_scan_process(wpa_s, 1) > 0)
goto scan_work_done;
- if (sme_proc_obss_scan(wpa_s) > 0)
+ if (sme_proc_obss_scan(wpa_s, scan_res) > 0)
goto scan_work_done;
if (own_request && data &&
@@ -1937,6 +2094,21 @@
radio_work_done(work);
}
+ os_free(wpa_s->last_scan_freqs);
+ wpa_s->last_scan_freqs = NULL;
+ wpa_s->num_last_scan_freqs = 0;
+ if (own_request && data &&
+ data->scan_info.freqs && data->scan_info.num_freqs) {
+ wpa_s->last_scan_freqs = os_malloc(sizeof(int) *
+ data->scan_info.num_freqs);
+ if (wpa_s->last_scan_freqs) {
+ os_memcpy(wpa_s->last_scan_freqs,
+ data->scan_info.freqs,
+ sizeof(int) * data->scan_info.num_freqs);
+ wpa_s->num_last_scan_freqs = data->scan_info.num_freqs;
+ }
+ }
+
return wpas_select_network_from_last_scan(wpa_s, 1, own_request);
scan_work_done:
@@ -1990,6 +2162,8 @@
return 0;
}
+ wpa_s->suitable_network++;
+
if (ssid != wpa_s->current_ssid &&
wpa_s->wpa_state >= WPA_AUTHENTICATING) {
wpa_s->own_disconnect_req = 1;
@@ -2010,6 +2184,7 @@
*/
return 1;
} else {
+ wpa_s->no_suitable_network++;
wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
ssid = wpa_supplicant_pick_new_network(wpa_s);
if (ssid) {
@@ -2156,7 +2331,8 @@
return -1;
os_get_reltime(&now);
- if (os_reltime_expired(&now, &wpa_s->last_scan, 5)) {
+ if (os_reltime_expired(&now, &wpa_s->last_scan,
+ SCAN_RES_VALID_FOR_CONNECT)) {
wpa_printf(MSG_DEBUG, "Fast associate: Old scan results");
return -1;
}
@@ -2289,28 +2465,41 @@
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;
+ wpa_s->multi_ap_ie = 0;
- if (!elems.multi_ap || elems.multi_ap_len < 7) {
- wpa_printf(MSG_INFO, "AP doesn't support Multi-AP protocol");
- goto fail;
- }
+ if (!ies ||
+ ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed ||
+ !elems.multi_ap || elems.multi_ap_len < 7)
+ return;
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");
+ if (!map_sub_elem || map_sub_elem[1] < 1)
+ return;
+
+ wpa_s->multi_ap_backhaul = !!(map_sub_elem[2] & MULTI_AP_BACKHAUL_BSS);
+ wpa_s->multi_ap_fronthaul = !!(map_sub_elem[2] &
+ MULTI_AP_FRONTHAUL_BSS);
+ wpa_s->multi_ap_ie = 1;
+}
+
+
+static void multi_ap_set_4addr_mode(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->current_ssid ||
+ !wpa_s->current_ssid->multi_ap_backhaul_sta)
+ return;
+
+ if (!wpa_s->multi_ap_ie) {
+ wpa_printf(MSG_INFO,
+ "AP does not include valid Multi-AP element");
goto fail;
}
- if (!(map_sub_elem[2] & MULTI_AP_BACKHAUL_BSS)) {
- if ((map_sub_elem[2] & MULTI_AP_FRONTHAUL_BSS) &&
+ if (!wpa_s->multi_ap_backhaul) {
+ if (wpa_s->multi_ap_fronthaul &&
wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
wpa_printf(MSG_INFO,
"WPS active, accepting fronthaul-only BSS");
@@ -2380,7 +2569,7 @@
static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
- int l, len, found = 0, wpa_found, rsn_found;
+ int l, len, found = 0, found_x = 0, wpa_found, rsn_found;
const u8 *p;
#if defined(CONFIG_IEEE80211R) || defined(CONFIG_OWE)
u8 bssid[ETH_ALEN];
@@ -2434,10 +2623,40 @@
wpa_s->connection_set = 1;
wpa_s->connection_ht = req_elems.ht_capabilities &&
resp_elems.ht_capabilities;
+ /* Do not include subset of VHT on 2.4 GHz vendor
+ * extension in consideration for reporting VHT
+ * association. */
wpa_s->connection_vht = req_elems.vht_capabilities &&
- resp_elems.vht_capabilities;
+ resp_elems.vht_capabilities &&
+ (!data->assoc_info.freq ||
+ wpas_freq_to_band(data->assoc_info.freq) !=
+ BAND_2_4_GHZ);
wpa_s->connection_he = req_elems.he_capabilities &&
resp_elems.he_capabilities;
+
+ int max_nss_rx_req = get_max_nss_capability(&req_elems, 1);
+ int max_nss_rx_resp = get_max_nss_capability(&resp_elems, 1);
+ wpa_s->connection_max_nss_rx = (max_nss_rx_resp > max_nss_rx_req) ?
+ max_nss_rx_req : max_nss_rx_resp;
+ int max_nss_tx_req = get_max_nss_capability(&req_elems, 0);
+ int max_nss_tx_resp = get_max_nss_capability(&resp_elems, 0);
+ wpa_s->connection_max_nss_tx = (max_nss_tx_resp > max_nss_tx_req) ?
+ max_nss_tx_req : max_nss_tx_resp;
+
+ struct supported_chan_width sta_supported_chan_width =
+ get_supported_channel_width(&req_elems);
+ enum chan_width ap_operation_chan_width =
+ get_operation_channel_width(&resp_elems);
+ if (wpa_s->connection_vht || wpa_s->connection_he) {
+ wpa_s->connection_channel_bandwidth =
+ get_sta_operation_chan_width(ap_operation_chan_width,
+ sta_supported_chan_width);
+ } else if (wpa_s->connection_ht) {
+ wpa_s->connection_channel_bandwidth = (ap_operation_chan_width
+ == CHAN_WIDTH_40) ? CHAN_WIDTH_40 : CHAN_WIDTH_20;
+ } else {
+ wpa_s->connection_channel_bandwidth = CHAN_WIDTH_20;
+ }
}
}
@@ -2452,22 +2671,29 @@
p, l);
break;
}
- if ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
- (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
- (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 &&
- (os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) ||
- (p[0] == WLAN_EID_RSN && p[1] >= 2)) {
+ if (!found &&
+ ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
+ (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
+ (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 &&
+ (os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) ||
+ (p[0] == WLAN_EID_RSN && p[1] >= 2))) {
if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len))
break;
found = 1;
wpa_find_assoc_pmkid(wpa_s);
- break;
+ }
+ if (!found_x && p[0] == WLAN_EID_RSNX) {
+ if (wpa_sm_set_assoc_rsnxe(wpa_s->wpa, p, len))
+ break;
+ found_x = 1;
}
l -= len;
p += len;
}
if (!found && data->assoc_info.req_ies)
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ if (!found_x && data->assoc_info.req_ies)
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
#ifdef CONFIG_FILS
#ifdef CONFIG_SME
@@ -2629,14 +2855,19 @@
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len);
}
+ if (p[0] == WLAN_EID_RSNX && p[1] >= 1)
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, p, len);
+
l -= len;
p += len;
}
if (!wpa_found && data->assoc_info.beacon_ies)
wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
- if (!rsn_found && data->assoc_info.beacon_ies)
+ if (!rsn_found && data->assoc_info.beacon_ies) {
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
+ }
if (wpa_found || rsn_found)
wpa_s->ap_ies_from_associnfo = 1;
@@ -2656,7 +2887,7 @@
static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
{
- const u8 *bss_wpa = NULL, *bss_rsn = NULL;
+ const u8 *bss_wpa = NULL, *bss_rsn = NULL, *bss_rsnx = NULL;
if (!wpa_s->current_bss || !wpa_s->current_ssid)
return -1;
@@ -2667,11 +2898,14 @@
bss_wpa = wpa_bss_get_vendor_ie(wpa_s->current_bss,
WPA_IE_VENDOR_TYPE);
bss_rsn = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSN);
+ bss_rsnx = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSNX);
if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
bss_wpa ? 2 + bss_wpa[1] : 0) ||
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
- bss_rsn ? 2 + bss_rsn[1] : 0))
+ bss_rsn ? 2 + bss_rsn[1] : 0) ||
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, bss_rsnx,
+ bss_rsnx ? 2 + bss_rsnx[1] : 0))
return -1;
return 0;
@@ -2723,6 +2957,9 @@
u8 bssid[ETH_ALEN];
int ft_completed, already_authorized;
int new_bss = 0;
+#if defined(CONFIG_FILS) || defined(CONFIG_MBO)
+ struct wpa_bss *bss;
+#endif /* CONFIG_FILS || CONFIG_MBO */
#ifdef CONFIG_AP
if (wpa_s->ap_iface) {
@@ -2738,6 +2975,7 @@
#endif /* CONFIG_AP */
eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+ wpa_s->own_reconnect_req = 0;
ft_completed = wpa_ft_is_completed(wpa_s->wpa);
if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0)
@@ -2787,6 +3025,8 @@
}
}
+ multi_ap_set_4addr_mode(wpa_s);
+
if (wpa_s->conf->ap_scan == 1 &&
wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION) {
if (wpa_supplicant_assoc_update_ie(wpa_s) < 0 && new_bss)
@@ -2817,7 +3057,7 @@
already_authorized = data && data->assoc_info.authorized;
/*
- * Set portEnabled first to FALSE in order to get EAP state machine out
+ * Set portEnabled first to false in order to get EAP state machine out
* of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE
* state machine may transit to AUTHENTICATING state based on obsolete
* eapSuccess and then trigger BE_AUTH to SUCCESS and PAE to
@@ -2825,21 +3065,21 @@
* reset the state.
*/
if (!ft_completed && !already_authorized) {
- eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
- eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+ eapol_sm_notify_portEnabled(wpa_s->eapol, false);
+ eapol_sm_notify_portValid(wpa_s->eapol, false);
}
if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
wpa_s->key_mgmt == WPA_KEY_MGMT_DPP ||
wpa_s->key_mgmt == WPA_KEY_MGMT_OWE || ft_completed ||
- already_authorized)
- eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+ already_authorized || wpa_s->drv_authorized_port)
+ eapol_sm_notify_eap_success(wpa_s->eapol, false);
/* 802.1X::portControl = Auto */
- eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
+ eapol_sm_notify_portEnabled(wpa_s->eapol, true);
wpa_s->eapol_received = 0;
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE ||
(wpa_s->current_ssid &&
- wpa_s->current_ssid->mode == IEEE80211_MODE_IBSS)) {
+ wpa_s->current_ssid->mode == WPAS_MODE_IBSS)) {
if (wpa_s->current_ssid &&
wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE &&
(wpa_s->drv_flags &
@@ -2866,8 +3106,8 @@
*/
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);
+ 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)) {
/*
@@ -2876,8 +3116,8 @@
*/
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);
+ 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)) {
/*
@@ -2885,11 +3125,28 @@
* to allow EAPOL supplicant to complete its work without
* waiting for WPA supplicant.
*/
- eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+ eapol_sm_notify_portValid(wpa_s->eapol, true);
}
wpa_s->last_eapol_matches_bssid = 0;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->rsne_override_eapol) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: RSNE EAPOL-Key msg 2/4 override");
+ wpa_sm_set_assoc_wpa_ie(wpa_s->wpa,
+ wpabuf_head(wpa_s->rsne_override_eapol),
+ wpabuf_len(wpa_s->rsne_override_eapol));
+ }
+ if (wpa_s->rsnxe_override_eapol) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: RSNXE EAPOL-Key msg 2/4 override");
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa,
+ wpabuf_head(wpa_s->rsnxe_override_eapol),
+ wpabuf_len(wpa_s->rsnxe_override_eapol));
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
if (wpa_s->pending_eapol_rx) {
struct os_reltime now, age;
os_get_reltime(&now);
@@ -2909,6 +3166,7 @@
wpa_s->pending_eapol_rx = NULL;
}
+#ifdef CONFIG_WEP
if ((wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
wpa_s->current_ssid &&
@@ -2916,6 +3174,7 @@
/* Set static WEP keys again */
wpa_set_wep_keys(wpa_s, wpa_s->current_ssid);
}
+#endif /* CONFIG_WEP */
#ifdef CONFIG_IBSS_RSN
if (wpa_s->current_ssid &&
@@ -2946,15 +3205,25 @@
wmm_ac_restore_tspecs(wpa_s);
}
+#if defined(CONFIG_FILS) || defined(CONFIG_MBO)
+ bss = wpa_bss_get_bssid(wpa_s, bssid);
+#endif /* CONFIG_FILS || CONFIG_MBO */
#ifdef CONFIG_FILS
if (wpa_key_mgmt_fils(wpa_s->key_mgmt)) {
- struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, bssid);
const u8 *fils_cache_id = wpa_bss_get_fils_cache_id(bss);
if (fils_cache_id)
wpa_sm_set_fils_cache_id(wpa_s->wpa, fils_cache_id);
}
#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_MBO
+ wpas_mbo_check_pmf(wpa_s, bss, wpa_s->current_ssid);
+#endif /* CONFIG_MBO */
+
+#ifdef CONFIG_DPP2
+ wpa_s->dpp_pfs_fallback = 0;
+#endif /* CONFIG_DPP2 */
}
@@ -2999,8 +3268,10 @@
int locally_generated)
{
if (wpa_s->wpa_state != WPA_4WAY_HANDSHAKE ||
- !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt))
- return 0; /* Not in 4-way handshake with PSK */
+ !wpa_s->new_connection ||
+ !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
+ wpa_key_mgmt_sae(wpa_s->key_mgmt))
+ return 0; /* Not in initial 4-way handshake with PSK */
/*
* It looks like connection was lost while trying to go through PSK
@@ -3062,6 +3333,10 @@
if (wpas_p2p_4way_hs_failed(wpa_s) > 0)
return; /* P2P group removed */
wpas_auth_failed(wpa_s, "WRONG_KEY");
+#ifdef CONFIG_DPP2
+ wpas_dpp_send_conn_status_result(wpa_s,
+ DPP_STATUS_AUTH_FAILURE);
+#endif /* CONFIG_DPP2 */
}
if (!wpa_s->disconnected &&
(!wpa_s->auto_reconnect_disabled ||
@@ -3076,21 +3351,25 @@
if (wpa_s->wpa_state == WPA_COMPLETED &&
wpa_s->current_ssid &&
wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
- !locally_generated &&
- disconnect_reason_recoverable(reason_code)) {
+ (wpa_s->own_reconnect_req ||
+ (!locally_generated &&
+ disconnect_reason_recoverable(reason_code)))) {
/*
* It looks like the AP has dropped association with
- * us, but could allow us to get back in. Try to
- * reconnect to the same BSS without full scan to save
- * time for some common cases.
+ * us, but could allow us to get back in. This is also
+ * triggered for cases where local reconnection request
+ * is used to force reassociation with the same BSS.
+ * Try to reconnect to the same BSS without a full scan
+ * to save time for some common cases.
*/
fast_reconnect = wpa_s->current_bss;
fast_reconnect_ssid = wpa_s->current_ssid;
- } else if (wpa_s->wpa_state >= WPA_ASSOCIATING)
+ } else if (wpa_s->wpa_state >= WPA_ASSOCIATING) {
wpa_supplicant_req_scan(wpa_s, 0, 100000);
- else
+ } else {
wpa_dbg(wpa_s, MSG_DEBUG, "Do not request new "
"immediate scan");
+ }
} else {
wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect disabled: do not "
"try to re-connect");
@@ -3510,26 +3789,22 @@
static void wpa_supplicant_event_unprot_deauth(struct wpa_supplicant *wpa_s,
struct unprot_deauth *e)
{
-#ifdef CONFIG_IEEE80211W
wpa_printf(MSG_DEBUG, "Unprotected Deauthentication frame "
"dropped: " MACSTR " -> " MACSTR
" (reason code %u)",
MAC2STR(e->sa), MAC2STR(e->da), e->reason_code);
sme_event_unprot_disconnect(wpa_s, e->sa, e->da, e->reason_code);
-#endif /* CONFIG_IEEE80211W */
}
static void wpa_supplicant_event_unprot_disassoc(struct wpa_supplicant *wpa_s,
struct unprot_disassoc *e)
{
-#ifdef CONFIG_IEEE80211W
wpa_printf(MSG_DEBUG, "Unprotected Disassociation frame "
"dropped: " MACSTR " -> " MACSTR
" (reason code %u)",
MAC2STR(e->sa), MAC2STR(e->da), e->reason_code);
sme_event_unprot_disconnect(wpa_s, e->sa, e->da, e->reason_code);
-#endif /* CONFIG_IEEE80211W */
}
@@ -3596,8 +3871,9 @@
ie_len = info->ie_len;
reason_code = info->reason_code;
locally_generated = info->locally_generated;
- wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s", reason_code,
- locally_generated ? " (locally generated)" : "");
+ wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u (%s)%s", reason_code,
+ reason2str(reason_code),
+ locally_generated ? " locally_generated=1" : "");
if (addr)
wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR,
MAC2STR(addr));
@@ -3650,9 +3926,9 @@
ie_len = info->ie_len;
reason_code = info->reason_code;
locally_generated = info->locally_generated;
- wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s",
- reason_code,
- locally_generated ? " (locally generated)" : "");
+ wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u (%s)%s",
+ reason_code, reason2str(reason_code),
+ locally_generated ? " locally_generated=1" : "");
if (addr) {
wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR,
MAC2STR(addr));
@@ -3786,14 +4062,12 @@
}
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
#ifdef CONFIG_SME
if (category == WLAN_ACTION_SA_QUERY) {
sme_sa_query_rx(wpa_s, mgmt->sa, payload, plen);
return;
}
#endif /* CONFIG_SME */
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WNM
if (mgmt->u.action.category == WLAN_ACTION_WNM) {
@@ -3932,8 +4206,9 @@
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);
+ eapol_sm_notify_portValid(wpa_s->eapol, true);
+ eapol_sm_notify_eap_success(wpa_s->eapol, true);
+ wpa_s->drv_authorized_port = 1;
}
}
@@ -4058,9 +4333,18 @@
union wpa_event_data *data)
{
const u8 *bssid = data->assoc_reject.bssid;
+#ifdef CONFIG_MBO
+ struct wpa_bss *reject_bss;
+#endif /* CONFIG_MBO */
if (!bssid || is_zero_ether_addr(bssid))
bssid = wpa_s->pending_bssid;
+#ifdef CONFIG_MBO
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+ reject_bss = wpa_s->current_bss;
+ else
+ reject_bss = wpa_bss_get_bssid(wpa_s, bssid);
+#endif /* CONFIG_MBO */
if (data->assoc_reject.bssid)
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
@@ -4109,11 +4393,43 @@
}
#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP2
+ /* Try to follow AP's PFS policy. WLAN_STATUS_ASSOC_DENIED_UNSPEC is
+ * the status code defined in the DPP R2 tech spec.
+ * WLAN_STATUS_AKMP_NOT_VALID is addressed in the same manner as an
+ * interoperability workaround with older hostapd implementation. */
+ if (wpa_s->current_ssid &&
+ wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_DPP &&
+ wpa_s->current_ssid->dpp_pfs == 0 &&
+ (data->assoc_reject.status_code ==
+ WLAN_STATUS_ASSOC_DENIED_UNSPEC ||
+ data->assoc_reject.status_code == WLAN_STATUS_AKMP_NOT_VALID)) {
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct wpa_bss *bss = wpa_s->current_bss;
+
+ wpa_s->current_ssid->dpp_pfs_fallback ^= 1;
+ if (!bss)
+ bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
+ if (!bss || wpa_s->dpp_pfs_fallback) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Updated PFS policy for next try");
+ wpas_connection_failed(wpa_s, bssid);
+ wpa_supplicant_mark_disassoc(wpa_s);
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Try again with updated PFS policy");
+ wpa_s->dpp_pfs_fallback = 1;
+ wpas_connect_work_done(wpa_s);
+ wpa_supplicant_mark_disassoc(wpa_s);
+ wpa_supplicant_connect(wpa_s, bss, ssid);
+ return;
+ }
+#endif /* CONFIG_DPP2 */
+
#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) {
+ reject_bss && data->assoc_reject.resp_ies) {
const u8 *rssi_rej;
rssi_rej = mbo_get_attr_from_ies(
@@ -4124,13 +4440,12 @@
wpa_printf(MSG_DEBUG,
"OCE: RSSI-based association rejection from "
MACSTR " (Delta RSSI: %u, Retry Delay: %u)",
- MAC2STR(data->assoc_reject.bssid),
+ MAC2STR(reject_bss->bssid),
rssi_rej[2], rssi_rej[3]);
wpa_bss_tmp_disallow(wpa_s,
- data->assoc_reject.bssid,
+ reject_bss->bssid,
rssi_rej[3],
- rssi_rej[2] +
- wpa_s->current_bss->level);
+ rssi_rej[2] + reject_bss->level);
}
}
#endif /* CONFIG_MBO */
@@ -4177,11 +4492,44 @@
}
+static void wpas_event_unprot_beacon(struct wpa_supplicant *wpa_s,
+ struct unprot_beacon *data)
+{
+ struct wpabuf *buf;
+ int res;
+
+ if (!data || wpa_s->wpa_state != WPA_COMPLETED ||
+ os_memcmp(data->sa, wpa_s->bssid, ETH_ALEN) != 0)
+ return;
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_UNPROT_BEACON MACSTR,
+ MAC2STR(data->sa));
+
+ buf = wpabuf_alloc(4);
+ if (!buf)
+ return;
+
+ 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, WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE);
+
+ res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0);
+ if (res < 0)
+ wpa_printf(MSG_DEBUG,
+ "Failed to send WNM-Notification Request frame");
+
+ wpabuf_free(buf);
+}
+
+
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
struct wpa_supplicant *wpa_s = ctx;
int resched;
+ struct os_reltime age, clear_at;
#ifndef CONFIG_NO_STDOUT_DEBUG
int level = MSG_DEBUG;
#endif /* CONFIG_NO_STDOUT_DEBUG */
@@ -4462,22 +4810,42 @@
data->rx_from_unknown.wds);
break;
#endif /* CONFIG_AP */
+
+ case EVENT_CH_SWITCH_STARTED:
case EVENT_CH_SWITCH:
if (!data || !wpa_s->current_ssid)
break;
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CHANNEL_SWITCH
- "freq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d",
+ wpa_msg(wpa_s, MSG_INFO,
+ "%sfreq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d",
+ event == EVENT_CH_SWITCH ? WPA_EVENT_CHANNEL_SWITCH :
+ WPA_EVENT_CHANNEL_SWITCH_STARTED,
data->ch_switch.freq,
data->ch_switch.ht_enabled,
data->ch_switch.ch_offset,
channel_width_to_string(data->ch_switch.ch_width),
data->ch_switch.cf1,
data->ch_switch.cf2);
+ if (event == EVENT_CH_SWITCH_STARTED)
+ break;
wpa_s->assoc_freq = data->ch_switch.freq;
wpa_s->current_ssid->frequency = data->ch_switch.freq;
+#ifdef CONFIG_SME
+ switch (data->ch_switch.ch_offset) {
+ case 1:
+ wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_ABOVE;
+ break;
+ case -1:
+ wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_BELOW;
+ break;
+ default:
+ wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_UNKNOWN;
+ break;
+ }
+#endif /* CONFIG_SME */
+
#ifdef CONFIG_AP
if (wpa_s->current_ssid->mode == WPAS_MODE_AP ||
wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO ||
@@ -4489,13 +4857,12 @@
data->ch_switch.ch_offset,
data->ch_switch.ch_width,
data->ch_switch.cf1,
- data->ch_switch.cf2);
+ data->ch_switch.cf2,
+ 1);
}
#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;
@@ -4701,7 +5068,10 @@
case EVENT_INTERFACE_ENABLED:
wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled");
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+ eloop_cancel_timeout(wpas_clear_disabled_interface,
+ wpa_s, NULL);
wpa_supplicant_update_mac_addr(wpa_s);
+ wpa_supplicant_set_default_scan_ies(wpa_s);
if (wpa_s->p2p_mgmt) {
wpa_supplicant_set_state(wpa_s,
WPA_DISCONNECTED);
@@ -4768,8 +5138,20 @@
wpa_s, WLAN_REASON_DEAUTH_LEAVING, 1);
}
wpa_supplicant_mark_disassoc(wpa_s);
- if (!wpa_s->conf->bss_no_flush_when_down)
- wpa_bss_flush(wpa_s);
+ os_reltime_age(&wpa_s->last_scan, &age);
+ if (age.sec >= SCAN_RES_VALID_FOR_CONNECT) {
+ clear_at.sec = SCAN_RES_VALID_FOR_CONNECT;
+ clear_at.usec = 0;
+ } else {
+ struct os_reltime tmp;
+
+ tmp.sec = SCAN_RES_VALID_FOR_CONNECT;
+ tmp.usec = 0;
+ os_reltime_sub(&tmp, &age, &clear_at);
+ }
+ eloop_register_timeout(clear_at.sec, clear_at.usec,
+ wpas_clear_disabled_interface,
+ wpa_s, NULL);
radio_remove_works(wpa_s, NULL, 0);
wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
@@ -4946,6 +5328,9 @@
data->sta_opmode.rx_nss);
#endif /* CONFIG_AP */
break;
+ case EVENT_UNPROT_BEACON:
+ wpas_event_unprot_beacon(wpa_s, &data->unprot_beacon);
+ break;
default:
wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
break;
diff --git a/wpa_supplicant/examples/dpp-nfc.py b/wpa_supplicant/examples/dpp-nfc.py
new file mode 100755
index 0000000..f49da34
--- /dev/null
+++ b/wpa_supplicant/examples/dpp-nfc.py
@@ -0,0 +1,692 @@
+#!/usr/bin/python3
+#
+# Example nfcpy to wpa_supplicant wrapper for DPP NFC operations
+# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2019-2020, The Linux Foundation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import sys
+import time
+import threading
+import argparse
+
+import nfc
+import ndef
+
+import logging
+
+scriptsdir = os.path.dirname(os.path.realpath("dpp-nfc.py"))
+sys.path.append(os.path.join(scriptsdir, '..', '..', 'wpaspy'))
+import wpaspy
+
+wpas_ctrl = '/var/run/wpa_supplicant'
+ifname = None
+init_on_touch = False
+in_raw_mode = False
+prev_tcgetattr = 0
+no_input = False
+srv = None
+continue_loop = True
+terminate_now = False
+summary_file = None
+success_file = None
+
+def summary(txt):
+ print(txt)
+ if summary_file:
+ with open(summary_file, 'a') as f:
+ f.write(txt + "\n")
+
+def success_report(txt):
+ summary(txt)
+ if success_file:
+ with open(success_file, 'a') as f:
+ f.write(txt + "\n")
+
+def wpas_connect():
+ ifaces = []
+ if os.path.isdir(wpas_ctrl):
+ try:
+ ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
+ except OSError as error:
+ print("Could not find wpa_supplicant: ", error)
+ return None
+
+ if len(ifaces) < 1:
+ print("No wpa_supplicant control interface found")
+ return None
+
+ for ctrl in ifaces:
+ if ifname:
+ if ifname not in ctrl:
+ continue
+ try:
+ print("Trying to use control interface " + ctrl)
+ wpas = wpaspy.Ctrl(ctrl)
+ return wpas
+ except Exception as e:
+ pass
+ return None
+
+def dpp_nfc_uri_process(uri):
+ wpas = wpas_connect()
+ if wpas is None:
+ return False
+ peer_id = wpas.request("DPP_NFC_URI " + uri)
+ if "FAIL" in peer_id:
+ print("Could not parse DPP URI from NFC URI record")
+ return False
+ peer_id = int(peer_id)
+ print("peer_id=%d" % peer_id)
+ cmd = "DPP_AUTH_INIT peer=%d" % peer_id
+ res = wpas.request(cmd)
+ if "OK" not in res:
+ print("Failed to initiate DPP Authentication")
+ return False
+ print("DPP Authentication initiated")
+ return True
+
+def dpp_hs_tag_read(record):
+ wpas = wpas_connect()
+ if wpas is None:
+ return False
+ print(record)
+ if len(record.data) < 5:
+ print("Too short DPP HS")
+ return False
+ if record.data[0] != 0:
+ print("Unexpected URI Identifier Code")
+ return False
+ uribuf = record.data[1:]
+ try:
+ uri = uribuf.decode()
+ except:
+ print("Invalid URI payload")
+ return False
+ print("URI: " + uri)
+ if not uri.startswith("DPP:"):
+ print("Not a DPP URI")
+ return False
+ return dpp_nfc_uri_process(uri)
+
+def get_status(wpas, extra=None):
+ if extra:
+ extra = "-" + extra
+ else:
+ extra = ""
+ res = wpas.request("STATUS" + extra)
+ lines = res.splitlines()
+ vals = dict()
+ for l in lines:
+ try:
+ [name, value] = l.split('=', 1)
+ except ValueError:
+ logger.info("Ignore unexpected status line: " + l)
+ continue
+ vals[name] = value
+ return vals
+
+def get_status_field(wpas, field, extra=None):
+ vals = get_status(wpas, extra)
+ if field in vals:
+ return vals[field]
+ return None
+
+def own_addr(wpas):
+ return get_status_field(wpas, "address")
+
+def dpp_bootstrap_gen(wpas, type="qrcode", chan=None, mac=None, info=None,
+ curve=None, key=None):
+ cmd = "DPP_BOOTSTRAP_GEN type=" + type
+ if chan:
+ cmd += " chan=" + chan
+ if mac:
+ if mac is True:
+ mac = own_addr(wpas)
+ cmd += " mac=" + mac.replace(':', '')
+ if info:
+ cmd += " info=" + info
+ if curve:
+ cmd += " curve=" + curve
+ if key:
+ cmd += " key=" + key
+ res = wpas.request(cmd)
+ if "FAIL" in res:
+ raise Exception("Failed to generate bootstrapping info")
+ return int(res)
+
+def wpas_get_nfc_uri(start_listen=True):
+ wpas = wpas_connect()
+ if wpas is None:
+ return None
+ global own_id, chanlist
+ own_id = dpp_bootstrap_gen(wpas, type="nfc-uri", chan=chanlist, mac=True)
+ res = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
+ if "FAIL" in res:
+ return None
+ if start_listen:
+ wpas.request("DPP_LISTEN 2412 netrole=configurator")
+ return res
+
+def wpas_report_handover_req(uri):
+ wpas = wpas_connect()
+ if wpas is None:
+ return None
+ global own_id
+ cmd = "DPP_NFC_HANDOVER_REQ own=%d uri=%s" % (own_id, uri)
+ return wpas.request(cmd)
+
+def wpas_report_handover_sel(uri):
+ wpas = wpas_connect()
+ if wpas is None:
+ return None
+ global own_id
+ cmd = "DPP_NFC_HANDOVER_SEL own=%d uri=%s" % (own_id, uri)
+ return wpas.request(cmd)
+
+def dpp_handover_client(llc):
+ uri = wpas_get_nfc_uri(start_listen=False)
+ uri = ndef.UriRecord(uri)
+ print("NFC URI record for DPP: " + str(uri))
+ carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
+ hr = ndef.HandoverRequestRecord(version="1.4", crn=os.urandom(2))
+ hr.add_alternative_carrier('active', carrier.name)
+ message = [hr, carrier]
+ print("NFC Handover Request message for DPP: " + str(message))
+
+ client = nfc.handover.HandoverClient(llc)
+ try:
+ summary("Trying to initiate NFC connection handover")
+ client.connect()
+ summary("Connected for handover")
+ except nfc.llcp.ConnectRefused:
+ summary("Handover connection refused")
+ client.close()
+ return
+ except Exception as e:
+ summary("Other exception: " + str(e))
+ client.close()
+ return
+
+ summary("Sending handover request")
+
+ if not client.send_records(message):
+ summary("Failed to send handover request")
+ client.close()
+ return
+
+ summary("Receiving handover response")
+ message = client.recv_records(timeout=3.0)
+ if message is None:
+ summary("No response received")
+ client.close()
+ return
+ print("Received message: " + str(message))
+ if len(message) < 1 or \
+ not isinstance(message[0], ndef.HandoverSelectRecord):
+ summary("Response was not Hs - received: " + message.type)
+ client.close()
+ return
+
+ print("Received message")
+ print("alternative carriers: " + str(message[0].alternative_carriers))
+
+ dpp_found = False
+ for carrier in message:
+ if isinstance(carrier, ndef.HandoverSelectRecord):
+ continue
+ print("Remote carrier type: " + carrier.type)
+ if carrier.type == "application/vnd.wfa.dpp":
+ if len(carrier.data) == 0 or carrier.data[0] != 0:
+ print("URI Identifier Code 'None' not seen")
+ continue
+ print("DPP carrier type match - send to wpa_supplicant")
+ dpp_found = True
+ uri = carrier.data[1:].decode("utf-8")
+ print("DPP URI: " + uri)
+ res = wpas_report_handover_sel(uri)
+ if res is None or "FAIL" in res:
+ summary("DPP handover report rejected")
+ break
+
+ success_report("DPP handover reported successfully (initiator)")
+ print("peer_id=" + res)
+ peer_id = int(res)
+ # TODO: Single Configurator instance
+ wpas = wpas_connect()
+ if wpas is None:
+ break
+ res = wpas.request("DPP_CONFIGURATOR_ADD")
+ if "FAIL" in res:
+ print("Failed to initiate Configurator")
+ break
+ conf_id = int(res)
+ global own_id
+ print("Initiate DPP authentication")
+ cmd = "DPP_AUTH_INIT peer=%d own=%d conf=sta-dpp configurator=%d" % (peer_id, own_id, conf_id)
+ res = wpas.request(cmd)
+ if "FAIL" in res:
+ print("Failed to initiate DPP authentication")
+ break
+
+ if not dpp_found:
+ print("DPP carrier not seen in response - allow peer to initiate a new handover with different parameters")
+ client.close()
+ print("Returning from dpp_handover_client")
+ return
+
+ print("Remove peer")
+ client.close()
+ print("Done with handover")
+ global only_one
+ if only_one:
+ print("only_one -> stop loop")
+ global continue_loop
+ continue_loop = False
+
+ global no_wait
+ if no_wait:
+ print("Trying to exit..")
+ global terminate_now
+ terminate_now = True
+
+ print("Returning from dpp_handover_client")
+
+class HandoverServer(nfc.handover.HandoverServer):
+ def __init__(self, llc):
+ super(HandoverServer, self).__init__(llc)
+ self.sent_carrier = None
+ self.ho_server_processing = False
+ self.success = False
+ self.try_own = False
+
+ def process_handover_request_message(self, records):
+ self.ho_server_processing = True
+ clear_raw_mode()
+ print("\nHandoverServer - request received: " + str(records))
+
+ carrier = None
+ hs = ndef.HandoverSelectRecord('1.4')
+ sel = [hs]
+
+ found = False
+
+ for carrier in records:
+ if isinstance(carrier, ndef.HandoverRequestRecord):
+ continue
+ print("Remote carrier type: " + carrier.type)
+ if carrier.type == "application/vnd.wfa.dpp":
+ print("DPP carrier type match - add DPP carrier record")
+ if len(carrier.data) == 0 or carrier.data[0] != 0:
+ print("URI Identifier Code 'None' not seen")
+ continue
+ uri = carrier.data[1:].decode("utf-8")
+ print("Received DPP URI: " + uri)
+
+ data = wpas_get_nfc_uri(start_listen=False)
+ print("Own URI (pre-processing): %s" % data)
+
+ res = wpas_report_handover_req(uri)
+ if res is None or "FAIL" in res:
+ print("DPP handover request processing failed")
+ continue
+
+ found = True
+ self.received_carrier = carrier
+
+ wpas = wpas_connect()
+ if wpas is None:
+ continue
+ global own_id
+ data = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
+ if "FAIL" in data:
+ continue
+ print("Own URI (post-processing): %s" % data)
+ uri = ndef.UriRecord(data)
+ print("Own bootstrapping NFC URI record: " + str(uri))
+
+ info = wpas.request("DPP_BOOTSTRAP_INFO %d" % own_id)
+ freq = None
+ for line in info.splitlines():
+ if line.startswith("use_freq="):
+ freq = int(line.split('=')[1])
+ if freq is None:
+ print("No channel negotiated over NFC - use channel 1")
+ freq = 2412
+ res = wpas.request("DPP_LISTEN %d" % freq)
+ if "OK" not in res:
+ print("Failed to start DPP listen")
+ break
+
+ carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
+ print("Own DPP carrier record: " + str(carrier))
+ hs.add_alternative_carrier('active', carrier.name)
+ sel = [hs, carrier]
+ break
+
+ summary("Sending handover select: " + str(sel))
+ if found:
+ self.success = True
+ else:
+ self.try_own = True
+ return sel
+
+def clear_raw_mode():
+ import sys, tty, termios
+ global prev_tcgetattr, in_raw_mode
+ if not in_raw_mode:
+ return
+ fd = sys.stdin.fileno()
+ termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr)
+ in_raw_mode = False
+
+def getch():
+ import sys, tty, termios, select
+ global prev_tcgetattr, in_raw_mode
+ fd = sys.stdin.fileno()
+ prev_tcgetattr = termios.tcgetattr(fd)
+ ch = None
+ try:
+ tty.setraw(fd)
+ in_raw_mode = True
+ [i, o, e] = select.select([fd], [], [], 0.05)
+ if i:
+ ch = sys.stdin.read(1)
+ finally:
+ termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr)
+ in_raw_mode = False
+ return ch
+
+def dpp_tag_read(tag):
+ success = False
+ for record in tag.ndef.records:
+ print(record)
+ print("record type " + record.type)
+ if record.type == "application/vnd.wfa.dpp":
+ summary("DPP HS tag - send to wpa_supplicant")
+ success = dpp_hs_tag_read(record)
+ break
+ if isinstance(record, ndef.UriRecord):
+ print("URI record: uri=" + record.uri)
+ print("URI record: iri=" + record.iri)
+ if record.iri.startswith("DPP:"):
+ print("DPP URI")
+ if not dpp_nfc_uri_process(record.iri):
+ break
+ success = True
+ else:
+ print("Ignore unknown URI")
+ break
+
+ if success:
+ success_report("Tag read succeeded")
+
+ return success
+
+def rdwr_connected_write_tag(tag):
+ summary("Tag found - writing - " + str(tag))
+ if not tag.ndef.is_writeable:
+ print("Not a writable tag")
+ return
+ global dpp_tag_data
+ if tag.ndef.capacity < len(dpp_tag_data):
+ print("Not enough room for the message")
+ return
+ tag.ndef.records = dpp_tag_data
+ success_report("Tag write succeeded")
+ print("Done - remove tag")
+ global only_one
+ if only_one:
+ global continue_loop
+ continue_loop = False
+ global dpp_sel_wait_remove
+ return dpp_sel_wait_remove
+
+def write_nfc_uri(clf, wait_remove=True):
+ print("Write NFC URI record")
+ data = wpas_get_nfc_uri()
+ if data is None:
+ summary("Could not get NFC URI from wpa_supplicant")
+ return
+
+ global dpp_sel_wait_remove
+ dpp_sel_wait_remove = wait_remove
+ print("URI: %s" % data)
+ uri = ndef.UriRecord(data)
+ print(uri)
+
+ print("Touch an NFC tag")
+ global dpp_tag_data
+ dpp_tag_data = [uri]
+ clf.connect(rdwr={'on-connect': rdwr_connected_write_tag})
+
+def write_nfc_hs(clf, wait_remove=True):
+ print("Write NFC Handover Select record on a tag")
+ data = wpas_get_nfc_uri()
+ if data is None:
+ summary("Could not get NFC URI from wpa_supplicant")
+ return
+
+ global dpp_sel_wait_remove
+ dpp_sel_wait_remove = wait_remove
+ print("URI: %s" % data)
+ uri = ndef.UriRecord(data)
+ print(uri)
+ carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
+ hs = ndef.HandoverSelectRecord('1.4')
+ hs.add_alternative_carrier('active', carrier.name)
+ print(hs)
+ print(carrier)
+
+ print("Touch an NFC tag")
+ global dpp_tag_data
+ dpp_tag_data = [hs, carrier]
+ print(dpp_tag_data)
+ clf.connect(rdwr={'on-connect': rdwr_connected_write_tag})
+
+def rdwr_connected(tag):
+ global only_one, no_wait
+ summary("Tag connected: " + str(tag))
+
+ if tag.ndef:
+ print("NDEF tag: " + tag.type)
+ print(tag.ndef.records)
+ success = dpp_tag_read(tag)
+ if only_one and success:
+ global continue_loop
+ continue_loop = False
+ else:
+ summary("Not an NDEF tag - remove tag")
+ return True
+
+ return not no_wait
+
+def llcp_worker(llc):
+ global init_on_touch
+ if init_on_touch:
+ print("Starting handover client")
+ dpp_handover_client(llc)
+ print("Exiting llcp_worker thread (init_in_touch)")
+ return
+
+ global no_input
+ if no_input:
+ print("Wait for handover to complete")
+ else:
+ print("Wait for handover to complete - press 'i' to initiate")
+ global srv
+ global wait_connection
+ while not wait_connection and srv.sent_carrier is None:
+ if srv.try_own:
+ srv.try_own = False
+ print("Try to initiate another handover with own parameters")
+ dpp_handover_client(llc)
+ print("Exiting llcp_worker thread (retry with own parameters)")
+ return
+ if srv.ho_server_processing:
+ time.sleep(0.025)
+ elif no_input:
+ time.sleep(0.5)
+ else:
+ res = getch()
+ if res != 'i':
+ continue
+ clear_raw_mode()
+ print("Starting handover client")
+ dpp_handover_client(llc)
+ print("Exiting llcp_worker thread (manual init)")
+ return
+
+ clear_raw_mode()
+ print("\rExiting llcp_worker thread")
+
+def llcp_startup(llc):
+ print("Start LLCP server")
+ global srv
+ srv = HandoverServer(llc)
+ return llc
+
+def llcp_connected(llc):
+ print("P2P LLCP connected")
+ global wait_connection
+ wait_connection = False
+ global init_on_touch
+ if not init_on_touch:
+ global srv
+ srv.start()
+ if init_on_touch or not no_input:
+ threading.Thread(target=llcp_worker, args=(llc,)).start()
+ return True
+
+def llcp_release(llc):
+ print("LLCP release")
+ return True
+
+def terminate_loop():
+ global terminate_now
+ return terminate_now
+
+def main():
+ clf = nfc.ContactlessFrontend()
+
+ parser = argparse.ArgumentParser(description='nfcpy to wpa_supplicant integration for DPP NFC operations')
+ parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
+ action='store_const', dest='loglevel',
+ help='verbose debug output')
+ parser.add_argument('-q', const=logging.WARNING, action='store_const',
+ dest='loglevel', help='be quiet')
+ parser.add_argument('--only-one', '-1', action='store_true',
+ help='run only one operation and exit')
+ parser.add_argument('--init-on-touch', '-I', action='store_true',
+ help='initiate handover on touch')
+ parser.add_argument('--no-wait', action='store_true',
+ help='do not wait for tag to be removed before exiting')
+ parser.add_argument('--ifname', '-i',
+ help='network interface name')
+ parser.add_argument('--no-input', '-a', action='store_true',
+ help='do not use stdout input to initiate handover')
+ parser.add_argument('--tag-read-only', '-t', action='store_true',
+ help='tag read only (do not allow connection handover)')
+ parser.add_argument('--handover-only', action='store_true',
+ help='connection handover only (do not allow tag read)')
+ parser.add_argument('--summary',
+ help='summary file for writing status updates')
+ parser.add_argument('--success',
+ help='success file for writing success update')
+ parser.add_argument('--device', default='usb', help='NFC device to open')
+ parser.add_argument('--chan', default='81/1', help='channel list')
+ parser.add_argument('command', choices=['write-nfc-uri',
+ 'write-nfc-hs'],
+ nargs='?')
+ args = parser.parse_args()
+ print(args)
+
+ global only_one
+ only_one = args.only_one
+
+ global no_wait
+ no_wait = args.no_wait
+
+ global chanlist
+ chanlist = args.chan
+
+ logging.basicConfig(level=args.loglevel)
+
+ global init_on_touch
+ init_on_touch = args.init_on_touch
+
+ if args.ifname:
+ global ifname
+ ifname = args.ifname
+ print("Selected ifname " + ifname)
+
+ if args.summary:
+ global summary_file
+ summary_file = args.summary
+
+ if args.success:
+ global success_file
+ success_file = args.success
+
+ if args.no_input:
+ global no_input
+ no_input = True
+
+ clf = nfc.ContactlessFrontend()
+ global wait_connection
+
+ try:
+ if not clf.open(args.device):
+ print("Could not open connection with an NFC device")
+ raise SystemExit
+
+ if args.command == "write-nfc-uri":
+ write_nfc_uri(clf, wait_remove=not args.no_wait)
+ raise SystemExit
+
+ if args.command == "write-nfc-hs":
+ write_nfc_hs(clf, wait_remove=not args.no_wait)
+ raise SystemExit
+
+ global continue_loop
+ while continue_loop:
+ clear_raw_mode()
+ print("\rWaiting for a tag or peer to be touched")
+ wait_connection = True
+ try:
+ if args.tag_read_only:
+ if not clf.connect(rdwr={'on-connect': rdwr_connected}):
+ break
+ elif args.handover_only:
+ if not clf.connect(llcp={'on-startup': llcp_startup,
+ 'on-connect': llcp_connected,
+ 'on-release': llcp_release},
+ terminate=terminate_loop):
+ break
+ else:
+ if not clf.connect(rdwr={'on-connect': rdwr_connected},
+ llcp={'on-startup': llcp_startup,
+ 'on-connect': llcp_connected,
+ 'on-release': llcp_release},
+ terminate=terminate_loop):
+ break
+ except Exception as e:
+ print("clf.connect failed: " + str(e))
+ break
+
+ global srv
+ if only_one and srv and srv.success:
+ raise SystemExit
+
+ except KeyboardInterrupt:
+ raise SystemExit
+ finally:
+ clf.close()
+
+ raise SystemExit
+
+if __name__ == '__main__':
+ main()
diff --git a/wpa_supplicant/examples/p2p/p2p_connect.py b/wpa_supplicant/examples/p2p/p2p_connect.py
index 6e3d94e..2f62e9c 100644
--- a/wpa_supplicant/examples/p2p/p2p_connect.py
+++ b/wpa_supplicant/examples/p2p/p2p_connect.py
@@ -108,7 +108,7 @@
self.path = None
try:
self.path = self.wpas.GetInterface(ifname)
- except:
+ except dbus.DBusException as exc:
if not str(exc).startswith(
self.wpas_dbus_interface + \
".InterfaceUnknown:"):
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 8e977a3..4b3fcfc 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -43,6 +43,7 @@
unsigned int offchannel_tx_started:1;
unsigned int retry:1;
unsigned int wildcard_bssid:1;
+ unsigned int maintain_addr:1;
int freq;
u16 status_code;
struct wpabuf *req;
@@ -693,7 +694,8 @@
return;
}
- if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
+ if (!query->maintain_addr &&
+ wpas_update_random_addr_disassoc(wpa_s) < 0) {
wpa_msg(wpa_s, MSG_INFO,
"Failed to assign random MAC address for GAS");
gas_query_free(query, 1);
@@ -727,19 +729,24 @@
static int gas_query_new_dialog_token(struct gas_query *gas, const u8 *dst)
{
- static int next_start = 0;
- int dialog_token;
+ u8 dialog_token;
+ int i;
- for (dialog_token = 0; dialog_token < 256; dialog_token++) {
- if (gas_query_dialog_token_available(
- gas, dst, (next_start + dialog_token) % 256))
+ /* There should never be more than couple active GAS queries in
+ * progress, so it should be very likely to find an available dialog
+ * token by checking random values. Use a limit on the number of
+ * iterations to handle the unexpected case of large number of pending
+ * queries cleanly. */
+ for (i = 0; i < 256; i++) {
+ /* Get a random number and check if the slot is available */
+ if (os_get_random(&dialog_token, sizeof(dialog_token)) < 0)
break;
+ if (gas_query_dialog_token_available(gas, dst, dialog_token))
+ return dialog_token;
}
- if (dialog_token == 256)
- return -1; /* Too many pending queries */
- dialog_token = (next_start + dialog_token) % 256;
- next_start = (dialog_token + 1) % 256;
- return dialog_token;
+
+ /* No dialog token value available */
+ return -1;
}
@@ -749,12 +756,23 @@
struct wpa_supplicant *wpa_s = gas->wpa_s;
struct os_reltime now;
- if (!wpa_s->conf->gas_rand_mac_addr ||
+ if (query->maintain_addr ||
+ !wpa_s->conf->gas_rand_mac_addr ||
!(wpa_s->current_bss ?
(wpa_s->drv_flags &
WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED) :
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA))) {
/* Use own MAC address as the transmitter address */
+ wpa_printf(MSG_DEBUG,
+ "GAS: Use own MAC address as the transmitter address%s%s%s",
+ query->maintain_addr ? " (maintain_addr)" : "",
+ !wpa_s->conf->gas_rand_mac_addr ? " (no gas_rand_mac_adr set)" : "",
+ !(wpa_s->current_bss ?
+ (wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED) :
+ (wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA)) ?
+ " (no driver rand capa" : "");
os_memcpy(query->sa, wpa_s->own_addr, ETH_ALEN);
return 0;
}
@@ -800,6 +818,9 @@
* @gas: GAS query data from gas_query_init()
* @dst: Destination MAC address for the query
* @freq: Frequency (in MHz) for the channel on which to send the query
+ * @wildcard_bssid: Force use of wildcard BSSID value
+ * @maintain_addr: Maintain own MAC address for exchange (i.e., ignore MAC
+ * address randomization rules)
* @req: GAS query payload (to be freed by gas_query module in case of success
* return)
* @cb: Callback function for reporting GAS query result and response
@@ -807,7 +828,7 @@
* Returns: dialog token (>= 0) on success or -1 on failure
*/
int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
- int wildcard_bssid, struct wpabuf *req,
+ int wildcard_bssid, int maintain_addr, struct wpabuf *req,
void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
enum gas_query_result result,
const struct wpabuf *adv_proto,
@@ -829,6 +850,7 @@
return -1;
query->gas = gas;
+ query->maintain_addr = !!maintain_addr;
if (gas_query_set_sa(gas, query)) {
os_free(query);
return -1;
diff --git a/wpa_supplicant/gas_query.h b/wpa_supplicant/gas_query.h
index d2b4554..f9ce7b6 100644
--- a/wpa_supplicant/gas_query.h
+++ b/wpa_supplicant/gas_query.h
@@ -35,7 +35,7 @@
};
int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
- int wildcard_bssid, struct wpabuf *req,
+ int wildcard_bssid, int maintain_addr, struct wpabuf *req,
void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
enum gas_query_result result,
const struct wpabuf *adv_proto,
diff --git a/wpa_supplicant/hidl/1.2/misc_utils.h b/wpa_supplicant/hidl/1.2/misc_utils.h
deleted file mode 100644
index 1360e6b..0000000
--- a/wpa_supplicant/hidl/1.2/misc_utils.h
+++ /dev/null
@@ -1,73 +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_2 {
-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_2
-} // namespace supplicant
-} // namespace wifi
-} // namespace hardware
-} // namespace android
-#endif // MISC_UTILS_H_
diff --git a/wpa_supplicant/hidl/1.3/android.hardware.wifi.supplicant-service.rc b/wpa_supplicant/hidl/1.3/android.hardware.wifi.supplicant-service.rc
new file mode 100644
index 0000000..3cf2500
--- /dev/null
+++ b/wpa_supplicant/hidl/1.3/android.hardware.wifi.supplicant-service.rc
@@ -0,0 +1,15 @@
+service wpa_supplicant /vendor/bin/hw/wpa_supplicant \
+ -O/data/vendor/wifi/wpa/sockets -dd \
+ -g@android:wpa_wlan0
+ # we will start as root and wpa_supplicant will switch to user wifi
+ # after setting up the capabilities required for WEXT
+ # user wifi
+ # group wifi inet keystore
+ interface android.hardware.wifi.supplicant@1.0::ISupplicant default
+ interface android.hardware.wifi.supplicant@1.1::ISupplicant default
+ interface android.hardware.wifi.supplicant@1.2::ISupplicant default
+ interface android.hardware.wifi.supplicant@1.3::ISupplicant default
+ class main
+ socket wpa_wlan0 dgram 660 wifi wifi
+ disabled
+ oneshot
diff --git a/wpa_supplicant/hidl/1.2/hidl.cpp b/wpa_supplicant/hidl/1.3/hidl.cpp
similarity index 83%
rename from wpa_supplicant/hidl/1.2/hidl.cpp
rename to wpa_supplicant/hidl/1.3/hidl.cpp
index ea1fa98..4c2d434 100644
--- a/wpa_supplicant/hidl/1.2/hidl.cpp
+++ b/wpa_supplicant/hidl/1.3/hidl.cpp
@@ -19,16 +19,20 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/includes.h"
+#include "dpp.h"
}
using android::hardware::configureRpcThreadpool;
using android::hardware::handleTransportPoll;
using android::hardware::setupTransportPolling;
-using android::hardware::wifi::supplicant::V1_2::implementation::HidlManager;
-using namespace android::hardware::wifi::supplicant::V1_2;
+using android::hardware::wifi::supplicant::V1_3::DppFailureCode;
+using android::hardware::wifi::supplicant::V1_3::DppProgressCode;
+using android::hardware::wifi::supplicant::V1_3::DppSuccessCode;
+using android::hardware::wifi::supplicant::V1_3::implementation::HidlManager;
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);
+static void wpas_hidl_notify_dpp_success(struct wpa_supplicant *wpa_s, DppSuccessCode code);
void wpas_hidl_sock_handler(
int sock, void * /* eloop_ctx */, void * /* sock_ctx */)
@@ -666,84 +670,56 @@
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);
+ wpas_hidl_notify_dpp_success(wpa_s, DppSuccessCode::CONFIGURATION_SENT);
}
/* 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;
+ wpas_hidl_notify_dpp_failure(wpa_s, DppFailureCode::AUTHENTICATION);
}
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);
}
+void wpas_hidl_notify_dpp_config_sent_wait_response(struct wpa_supplicant *wpa_s)
+{
+ wpas_hidl_notify_dpp_progress(wpa_s, DppProgressCode::CONFIGURATION_SENT_WAITING_RESPONSE);
+}
+
/* DPP notification helper functions */
static void wpas_hidl_notify_dpp_failure(struct wpa_supplicant *wpa_s, DppFailureCode code)
{
@@ -776,3 +752,126 @@
hidl_manager->notifyDppProgress(wpa_s, code);
}
+
+void wpas_hidl_notify_dpp_config_accepted(struct wpa_supplicant *wpa_s)
+{
+ wpas_hidl_notify_dpp_progress(wpa_s, DppProgressCode::CONFIGURATION_ACCEPTED);
+}
+
+static void wpas_hidl_notify_dpp_config_applied(struct wpa_supplicant *wpa_s)
+{
+ wpas_hidl_notify_dpp_success(wpa_s, DppSuccessCode::CONFIGURATION_APPLIED);
+}
+
+static void wpas_hidl_notify_dpp_success(struct wpa_supplicant *wpa_s, DppSuccessCode 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->notifyDppSuccess(wpa_s, code);
+}
+
+void wpas_hidl_notify_dpp_config_rejected(struct wpa_supplicant *wpa_s)
+{
+ wpas_hidl_notify_dpp_failure(wpa_s, DppFailureCode::CONFIGURATION_REJECTED);
+}
+
+static void wpas_hidl_notify_dpp_no_ap_failure(struct wpa_supplicant *wpa_s,
+ const char *ssid, const char *channel_list, unsigned short band_list[],
+ int size)
+{
+ if (!wpa_s)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "Notifying DPP NO AP event for SSID %s\nTried channels: %s",
+ ssid ? ssid : "N/A", channel_list ? channel_list : "N/A");
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyDppFailure(wpa_s, DppFailureCode::CANNOT_FIND_NETWORK,
+ ssid, channel_list, band_list, size);
+}
+
+void wpas_hidl_notify_dpp_enrollee_auth_failure(struct wpa_supplicant *wpa_s,
+ const char *ssid, unsigned short band_list[], int size)
+{
+ if (!wpa_s)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "Notifying DPP Enrollee authentication failure, SSID %s",
+ ssid ? ssid : "N/A");
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyDppFailure(wpa_s, DppFailureCode::ENROLLEE_AUTHENTICATION,
+ ssid, NULL, band_list, size);
+}
+
+
+void wpas_hidl_notify_dpp_conn_status(struct wpa_supplicant *wpa_s, enum dpp_status_error status,
+ const char *ssid, const char *channel_list, unsigned short band_list[], int size)
+{
+ switch (status)
+ {
+ case DPP_STATUS_OK:
+ wpas_hidl_notify_dpp_config_applied(wpa_s);
+ break;
+
+ case DPP_STATUS_NO_AP:
+ wpas_hidl_notify_dpp_no_ap_failure(wpa_s, ssid, channel_list, band_list, size);
+ break;
+
+ case DPP_STATUS_AUTH_FAILURE:
+ wpas_hidl_notify_dpp_enrollee_auth_failure(wpa_s, ssid, band_list, size);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void wpas_hidl_notify_pmk_cache_added(
+ struct wpa_supplicant *wpa_s,
+ struct rsn_pmksa_cache_entry *pmksa_entry)
+{
+ if (!wpa_s || !pmksa_entry)
+ return;
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG,
+ "Notifying PMK cache added event");
+
+ hidl_manager->notifyPmkCacheAdded(wpa_s, pmksa_entry);
+}
+
+void wpas_hidl_notify_bss_tm_status(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Notifying BSS transition status");
+
+ hidl_manager->notifyBssTmStatus(wpa_s);
+}
diff --git a/wpa_supplicant/hidl/1.2/hidl.h b/wpa_supplicant/hidl/1.3/hidl.h
similarity index 90%
rename from wpa_supplicant/hidl/1.2/hidl.h
rename to wpa_supplicant/hidl/1.3/hidl.h
index a177f6e..304a4d6 100644
--- a/wpa_supplicant/hidl/1.2/hidl.h
+++ b/wpa_supplicant/hidl/1.3/hidl.h
@@ -111,6 +111,15 @@
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);
+ void wpas_hidl_notify_dpp_config_sent_wait_response(struct wpa_supplicant *wpa_s);
+ void wpas_hidl_notify_dpp_config_accepted(struct wpa_supplicant *wpa_s);
+ void wpas_hidl_notify_dpp_config_rejected(struct wpa_supplicant *wpa_s);
+ void wpas_hidl_notify_dpp_conn_status(struct wpa_supplicant *wpa_s,
+ enum dpp_status_error status, const char *ssid,
+ const char *channel_list, unsigned short band_list[], int size);
+ void wpas_hidl_notify_pmk_cache_added(
+ struct wpa_supplicant *wpas, struct rsn_pmksa_cache_entry *pmksa_entry);
+ void wpas_hidl_notify_bss_tm_status(struct wpa_supplicant *wpa_s);
#else // CONFIG_CTRL_IFACE_HIDL
static inline int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s)
{
@@ -239,6 +248,19 @@
{}
static void wpas_hidl_notify_dpp_failure(struct wpa_supplicant *wpa_s)
{}
+void wpas_hidl_notify_dpp_config_sent_wait_response(struct wpa_supplicant *wpa_s)
+{}
+void wpas_hidl_notify_dpp_config_accepted(struct wpa_supplicant *wpa_s)
+{}
+void wpas_hidl_notify_dpp_config_applied(struct wpa_supplicant *wpa_s)
+{}
+void wpas_hidl_notify_dpp_config_rejected(struct wpa_supplicant *wpa_s)
+{}
+static void wpas_hidl_notify_pmk_cache_added(struct wpa_supplicant *wpas,
+ struct rsn_pmksa_cache_entry *pmksa_entry)
+{}
+void wpas_hidl_notify_bss_tm_status(struct wpa_supplicant *wpa_s)
+{}
#endif // CONFIG_CTRL_IFACE_HIDL
#ifdef _cplusplus
diff --git a/wpa_supplicant/hidl/1.2/hidl_constants.h b/wpa_supplicant/hidl/1.3/hidl_constants.h
similarity index 100%
rename from wpa_supplicant/hidl/1.2/hidl_constants.h
rename to wpa_supplicant/hidl/1.3/hidl_constants.h
diff --git a/wpa_supplicant/hidl/1.2/hidl_i.h b/wpa_supplicant/hidl/1.3/hidl_i.h
similarity index 100%
rename from wpa_supplicant/hidl/1.2/hidl_i.h
rename to wpa_supplicant/hidl/1.3/hidl_i.h
diff --git a/wpa_supplicant/hidl/1.2/hidl_manager.cpp b/wpa_supplicant/hidl/1.3/hidl_manager.cpp
similarity index 83%
rename from wpa_supplicant/hidl/1.2/hidl_manager.cpp
rename to wpa_supplicant/hidl/1.3/hidl_manager.cpp
index b69fe04..e15e9fd 100644
--- a/wpa_supplicant/hidl/1.2/hidl_manager.cpp
+++ b/wpa_supplicant/hidl/1.3/hidl_manager.cpp
@@ -8,6 +8,7 @@
*/
#include <algorithm>
+#include <iostream>
#include <regex>
#include "hidl_manager.h"
@@ -20,7 +21,6 @@
namespace {
using android::hardware::hidl_array;
-using namespace android::hardware::wifi::supplicant::V1_2;
constexpr uint8_t kWfdDeviceInfoLen = 6;
// GSM-AUTH:<RAND1>:<RAND2>[:<RAND3>]
@@ -289,13 +289,13 @@
}
}
-template <class CallbackTypeV1_0, class CallbackTypeV1_1>
-void callWithEachIfaceCallback_1_1(
+template <class CallbackTypeBase, class CallbackTypeDerived>
+void callWithEachIfaceCallbackDerived(
const std::string &ifname,
const std::function<
- android::hardware::Return<void>(android::sp<CallbackTypeV1_1>)> &method,
+ android::hardware::Return<void>(android::sp<CallbackTypeDerived>)> &method,
const std::map<
- const std::string, std::vector<android::sp<CallbackTypeV1_0>>>
+ const std::string, std::vector<android::sp<CallbackTypeBase>>>
&callbacks_map)
{
if (ifname.empty())
@@ -306,41 +306,12 @@
return;
const auto &iface_callback_list = iface_callback_map_iter->second;
for (const auto &callback : iface_callback_list) {
- android::sp<CallbackTypeV1_1> callback_1_1 =
- CallbackTypeV1_1::castFrom(callback);
- if (callback_1_1 == nullptr)
+ android::sp<CallbackTypeDerived> callback_derived =
+ CallbackTypeDerived::castFrom(callback);
+ if (callback_derived == nullptr)
continue;
- if (!method(callback_1_1).isOk()) {
- wpa_printf(
- MSG_ERROR, "Failed to invoke HIDL iface callback");
- }
- }
-}
-
-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()) {
+ if (!method(callback_derived).isOk()) {
wpa_printf(
MSG_ERROR, "Failed to invoke HIDL iface callback");
}
@@ -429,10 +400,8 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_2 {
+namespace V1_3 {
namespace implementation {
-
-using namespace android::hardware::wifi::supplicant::V1_2;
using V1_0::ISupplicantStaIfaceCallback;
HidlManager *HidlManager::instance_ = NULL;
@@ -513,6 +482,12 @@
"Failed to enable scan mac randomization");
}
}
+
+ // Enable randomized source MAC address for GAS/ANQP
+ // Set the lifetime to 0, guarantees a unique address for each GAS
+ // session
+ wpa_s->conf->gas_rand_mac_addr = 1;
+ wpa_s->conf->gas_rand_addr_lifetime = 0;
}
// Invoke the |onInterfaceCreated| method on all registered callbacks.
@@ -731,13 +706,22 @@
} 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));
+ bool fils_hlp_sent =
+ (wpa_auth_alg_fils(wpa_s->auth_alg) &&
+ !dl_list_empty(&wpa_s->fils_hlp_req) &&
+ (wpa_s->wpa_state == WPA_COMPLETED)) ? true : false;
+
+ // Invoke the |onStateChanged_1_3| method on all registered callbacks.
+ const std::function<
+ Return<void>(android::sp<V1_3::ISupplicantStaIfaceCallback>)>
+ func = std::bind(
+ &V1_3::ISupplicantStaIfaceCallback::onStateChanged_1_3,
+ std::placeholders::_1,
+ static_cast<ISupplicantStaIfaceCallback::State>(
+ wpa_s->wpa_state),
+ bssid, hidl_network_id, hidl_ssid,
+ fils_hlp_sent);
+ callWithEachStaIfaceCallbackDerived(wpa_s->ifname, func);
return 0;
}
@@ -1269,6 +1253,16 @@
bool hidl_is_go = (client == 0 ? true : false);
bool hidl_is_persistent = (persistent == 1 ? true : false);
+ // notify the group device again to ensure the framework knowing this device.
+ struct p2p_data *p2p = wpa_s->global->p2p;
+ struct p2p_device *dev = p2p_get_device(p2p, wpa_group_s->go_dev_addr);
+ if (NULL != dev) {
+ wpa_printf(MSG_DEBUG, "P2P: Update GO device on group started.");
+ p2p->cfg->dev_found(p2p->cfg->cb_ctx, wpa_group_s->go_dev_addr,
+ &dev->info, !(dev->flags & P2P_DEV_REPORTED_ONCE));
+ dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE;
+ }
+
callWithEachP2pIfaceCallback(
wpa_s->ifname,
std::bind(
@@ -1462,27 +1456,14 @@
void HidlManager::notifyEapError(struct wpa_supplicant *wpa_s, int error_code)
{
- typedef V1_1::ISupplicantStaIfaceCallback::EapErrorCode EapErrorCode;
-
if (!wpa_s)
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;
- }
-
- callWithEachStaIfaceCallback_1_1(
+ callWithEachStaIfaceCallback_1_3(
wpa_s->ifname,
std::bind(
- &V1_1::ISupplicantStaIfaceCallback::onEapFailure_1_1,
- std::placeholders::_1, static_cast<EapErrorCode>(error_code)));
+ &V1_3::ISupplicantStaIfaceCallback::onEapFailure_1_3,
+ std::placeholders::_1, error_code));
}
/**
@@ -1507,7 +1488,9 @@
/* Unsupported AKM */
wpa_printf(MSG_ERROR, "DPP: Error: Unsupported AKM 0x%X",
config->key_mgmt);
- notifyDppFailure(wpa_s, DppFailureCode::NOT_SUPPORTED);
+ notifyDppFailure(wpa_s,
+ android::hardware::wifi::supplicant::V1_3::DppFailureCode
+ ::NOT_SUPPORTED);
return;
}
@@ -1545,13 +1528,29 @@
* @param ifname Interface name
* @param code Status code
*/
-void HidlManager::notifyDppFailure(struct wpa_supplicant *wpa_s, DppFailureCode code)
-{
+void HidlManager::notifyDppFailure(struct wpa_supplicant *wpa_s,
+ android::hardware::wifi::supplicant::V1_3::DppFailureCode code) {
std::string hidl_ifname = wpa_s->ifname;
- callWithEachStaIfaceCallback_1_2(hidl_ifname,
- std::bind(&V1_2::ISupplicantStaIfaceCallback::onDppFailure,
- std::placeholders::_1, code));
+ notifyDppFailure(wpa_s, code, NULL, NULL, NULL, 0);
+}
+
+/**
+ * Notify listener about a DPP failure event
+ *
+ * @param ifname Interface name
+ * @param code Status code
+ */
+void HidlManager::notifyDppFailure(struct wpa_supplicant *wpa_s,
+ android::hardware::wifi::supplicant::V1_3::DppFailureCode code,
+ const char *ssid, const char *channel_list, unsigned short band_list[],
+ int size) {
+ std::string hidl_ifname = wpa_s->ifname;
+ std::vector<uint16_t> band_list_vec(band_list, band_list + size);
+
+ callWithEachStaIfaceCallback_1_3(hidl_ifname,
+ std::bind(&V1_3::ISupplicantStaIfaceCallback::onDppFailure_1_3,
+ std::placeholders::_1, code, ssid, channel_list, band_list_vec));
}
/**
@@ -1560,16 +1559,209 @@
* @param ifname Interface name
* @param code Status code
*/
-void HidlManager::notifyDppProgress(struct wpa_supplicant *wpa_s, DppProgressCode code)
+void HidlManager::notifyDppProgress(struct wpa_supplicant *wpa_s,
+ android::hardware::wifi::supplicant::V1_3::DppProgressCode code) {
+ std::string hidl_ifname = wpa_s->ifname;
+
+ callWithEachStaIfaceCallback_1_3(hidl_ifname,
+ std::bind(&V1_3::ISupplicantStaIfaceCallback::onDppProgress_1_3,
+ std::placeholders::_1, code));
+}
+
+/**
+ * Notify listener about a DPP success event
+ *
+ * @param ifname Interface name
+ * @param code Status code
+ */
+void HidlManager::notifyDppSuccess(struct wpa_supplicant *wpa_s, DppSuccessCode code)
{
std::string hidl_ifname = wpa_s->ifname;
- callWithEachStaIfaceCallback_1_2(hidl_ifname,
- std::bind(&V1_2::ISupplicantStaIfaceCallback::onDppProgress,
+ callWithEachStaIfaceCallback_1_3(hidl_ifname,
+ std::bind(&V1_3::ISupplicantStaIfaceCallback::onDppSuccess,
std::placeholders::_1, code));
}
/**
+ * Notify listener about a PMK cache added event
+ *
+ * @param ifname Interface name
+ * @param entry PMK cache entry
+ */
+void HidlManager::notifyPmkCacheAdded(
+ struct wpa_supplicant *wpa_s, struct rsn_pmksa_cache_entry *pmksa_entry)
+{
+ std::string hidl_ifname = wpa_s->ifname;
+
+ // Serialize PmkCacheEntry into blob.
+ std::stringstream ss(
+ std::stringstream::in | std::stringstream::out | std::stringstream::binary);
+ misc_utils::serializePmkCacheEntry(ss, pmksa_entry);
+ std::vector<uint8_t> serializedEntry(
+ std::istreambuf_iterator<char>(ss), {});
+
+ const std::function<
+ Return<void>(android::sp<V1_3::ISupplicantStaIfaceCallback>)>
+ func = std::bind(
+ &V1_3::ISupplicantStaIfaceCallback::onPmkCacheAdded,
+ std::placeholders::_1, pmksa_entry->expiration, serializedEntry);
+ callWithEachStaIfaceCallbackDerived(hidl_ifname, func);
+}
+
+#ifdef CONFIG_WNM
+V1_3::ISupplicantStaIfaceCallback::BssTmStatusCode convertSupplicantBssTmStatusToHidl(
+ enum bss_trans_mgmt_status_code bss_tm_status)
+{
+ switch (bss_tm_status) {
+ case WNM_BSS_TM_ACCEPT:
+ return V1_3::ISupplicantStaIfaceCallback::BssTmStatusCode::ACCEPT;
+ case WNM_BSS_TM_REJECT_UNSPECIFIED:
+ return V1_3::ISupplicantStaIfaceCallback::
+ BssTmStatusCode::REJECT_UNSPECIFIED;
+ case WNM_BSS_TM_REJECT_INSUFFICIENT_BEACON:
+ return V1_3::ISupplicantStaIfaceCallback::
+ BssTmStatusCode::REJECT_INSUFFICIENT_BEACON;
+ case WNM_BSS_TM_REJECT_INSUFFICIENT_CAPABITY:
+ return V1_3::ISupplicantStaIfaceCallback::
+ BssTmStatusCode::REJECT_INSUFFICIENT_CAPABITY;
+ case WNM_BSS_TM_REJECT_UNDESIRED:
+ return V1_3::ISupplicantStaIfaceCallback::
+ BssTmStatusCode::REJECT_BSS_TERMINATION_UNDESIRED;
+ case WNM_BSS_TM_REJECT_DELAY_REQUEST:
+ return V1_3::ISupplicantStaIfaceCallback::
+ BssTmStatusCode::REJECT_BSS_TERMINATION_DELAY_REQUEST;
+ case WNM_BSS_TM_REJECT_STA_CANDIDATE_LIST_PROVIDED:
+ return V1_3::ISupplicantStaIfaceCallback::
+ BssTmStatusCode::REJECT_STA_CANDIDATE_LIST_PROVIDED;
+ case WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES:
+ return V1_3::ISupplicantStaIfaceCallback::
+ BssTmStatusCode::REJECT_NO_SUITABLE_CANDIDATES;
+ case WNM_BSS_TM_REJECT_LEAVING_ESS:
+ return V1_3::ISupplicantStaIfaceCallback::
+ BssTmStatusCode::REJECT_LEAVING_ESS;
+ default:
+ return V1_3::ISupplicantStaIfaceCallback::
+ BssTmStatusCode::REJECT_UNSPECIFIED;
+ }
+}
+
+uint32_t setBssTmDataFlagsMask(struct wpa_supplicant *wpa_s)
+{
+ uint32_t flags = 0;
+
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
+ flags |= V1_3::ISupplicantStaIfaceCallback::
+ BssTmDataFlagsMask::WNM_MODE_BSS_TERMINATION_INCLUDED;
+ }
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) {
+ flags |= V1_3::ISupplicantStaIfaceCallback::
+ BssTmDataFlagsMask::WNM_MODE_ESS_DISASSOCIATION_IMMINENT;
+ }
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
+ flags |= V1_3::ISupplicantStaIfaceCallback::
+ BssTmDataFlagsMask::WNM_MODE_DISASSOCIATION_IMMINENT;
+ }
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ABRIDGED) {
+ flags |= V1_3::ISupplicantStaIfaceCallback::
+ BssTmDataFlagsMask::WNM_MODE_ABRIDGED;
+ }
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
+ flags |= V1_3::ISupplicantStaIfaceCallback::
+ BssTmDataFlagsMask::WNM_MODE_PREFERRED_CANDIDATE_LIST_INCLUDED;
+ }
+#ifdef CONFIG_MBO
+ if (wpa_s->wnm_mbo_assoc_retry_delay_present) {
+ flags |= V1_3::ISupplicantStaIfaceCallback::
+ BssTmDataFlagsMask::MBO_ASSOC_RETRY_DELAY_INCLUDED;
+ }
+ if (wpa_s->wnm_mbo_trans_reason_present) {
+ flags |= V1_3::ISupplicantStaIfaceCallback::
+ BssTmDataFlagsMask::MBO_TRANSITION_REASON_CODE_INCLUDED;
+ }
+ if (wpa_s->wnm_mbo_cell_pref_present) {
+ flags |= V1_3::ISupplicantStaIfaceCallback::
+ BssTmDataFlagsMask::MBO_CELLULAR_DATA_CONNECTION_PREFERENCE_INCLUDED;
+ }
+#endif
+ return flags;
+}
+
+uint32_t getBssTmDataAssocRetryDelayMs(struct wpa_supplicant *wpa_s)
+{
+ uint32_t beacon_int;
+ uint32_t duration_ms = 0;
+
+ if (wpa_s->current_bss)
+ beacon_int = wpa_s->current_bss->beacon_int;
+ else
+ beacon_int = 100; /* best guess */
+
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
+ // number of tbtts to milliseconds
+ duration_ms = wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125;
+ }
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
+ //wnm_bss_termination_duration contains 12 bytes of BSS
+ //termination duration subelement. Format of IE is
+ // Sub eid | Length | BSS termination TSF | Duration
+ // 1 1 8 2
+ // Duration indicates number of minutes for which BSS is not
+ // present.
+ duration_ms = WPA_GET_LE16(wpa_s->wnm_bss_termination_duration + 10);
+ // minutes to milliseconds
+ duration_ms = duration_ms * 60 * 1000;
+ }
+#ifdef CONFIG_MBO
+ if (wpa_s->wnm_mbo_assoc_retry_delay_present) {
+ // number of seconds to milliseconds
+ duration_ms = wpa_s->wnm_mbo_assoc_retry_delay_sec * 1000;
+ }
+#endif
+
+ return duration_ms;
+}
+#endif
+
+/**
+ * Notify listener about the status of BSS transition management
+ * request frame handling.
+ *
+ * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
+ * the network is present.
+ */
+void HidlManager::notifyBssTmStatus(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_WNM
+ std::string hidl_ifname = wpa_s->ifname;
+ V1_3::ISupplicantStaIfaceCallback::BssTmData hidl_bsstm_data = {};
+
+ hidl_bsstm_data.status = convertSupplicantBssTmStatusToHidl(wpa_s->bss_tm_status);
+ hidl_bsstm_data.flags = setBssTmDataFlagsMask(wpa_s);
+ hidl_bsstm_data.assocRetryDelayMs = getBssTmDataAssocRetryDelayMs(wpa_s);
+#ifdef CONFIG_MBO
+ if (wpa_s->wnm_mbo_cell_pref_present) {
+ hidl_bsstm_data.mboCellPreference = static_cast
+ <V1_3::ISupplicantStaIfaceCallback::MboCellularDataConnectionPrefValue>
+ (wpa_s->wnm_mbo_cell_preference);
+ }
+ if (wpa_s->wnm_mbo_trans_reason_present) {
+ hidl_bsstm_data.mboTransitionReason =
+ static_cast<V1_3::ISupplicantStaIfaceCallback::MboTransitionReasonCode>
+ (wpa_s->wnm_mbo_transition_reason);
+ }
+#endif
+
+ const std::function<
+ Return<void>(android::sp<V1_3::ISupplicantStaIfaceCallback>)>
+ func = std::bind(
+ &V1_3::ISupplicantStaIfaceCallback::onBssTmHandlingDone,
+ std::placeholders::_1, hidl_bsstm_data);
+ callWithEachStaIfaceCallbackDerived(hidl_ifname, func);
+#endif
+}
+
+/**
* Retrieve the |ISupplicantP2pIface| hidl object reference using the provided
* ifname.
*
@@ -1602,7 +1794,7 @@
* @return 0 on success, 1 on failure.
*/
int HidlManager::getStaIfaceHidlObjectByIfname(
- const std::string &ifname, android::sp<ISupplicantStaIface> *iface_object)
+ const std::string &ifname, android::sp<V1_1::ISupplicantStaIface> *iface_object)
{
if (ifname.empty() || !iface_object)
return 1;
@@ -1911,7 +2103,7 @@
const std::function<
Return<void>(android::sp<V1_1::ISupplicantStaIfaceCallback>)> &method)
{
- callWithEachIfaceCallback_1_1(ifname, method, sta_iface_callbacks_map_);
+ callWithEachIfaceCallbackDerived(ifname, method, sta_iface_callbacks_map_);
}
/**
@@ -1928,7 +2120,42 @@
const std::function<
Return<void>(android::sp<V1_2::ISupplicantStaIfaceCallback>)> &method)
{
- callWithEachIfaceCallback_1_2(ifname, method, sta_iface_callbacks_map_);
+ callWithEachIfaceCallbackDerived(ifname, method, sta_iface_callbacks_map_);
+}
+
+/**
+ * Helper function to invoke the provided callback method on all the
+ * registered V1.3 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_3::ISupplicantIfaceCallback|.
+ */
+void HidlManager::callWithEachStaIfaceCallback_1_3(
+ const std::string &ifname,
+ const std::function<
+ Return<void>(android::sp<V1_3::ISupplicantStaIfaceCallback>)> &method)
+{
+ callWithEachIfaceCallbackDerived(ifname, method, sta_iface_callbacks_map_);
+}
+
+/**
+ * Helper function to invoke the provided callback method on all the
+ * registered derived interface callback hidl objects for the specified
+ * |ifname|.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param method Pointer to the required hidl method from
+ * derived |V1_x::ISupplicantIfaceCallback|.
+ */
+template <class CallbackTypeDerived>
+void HidlManager::callWithEachStaIfaceCallbackDerived(
+ const std::string &ifname,
+ const std::function<
+ Return<void>(android::sp<CallbackTypeDerived>)> &method)
+{
+ callWithEachIfaceCallbackDerived(ifname, method, sta_iface_callbacks_map_);
}
/**
@@ -1986,7 +2213,7 @@
ifname, network_id, method, sta_network_callbacks_map_);
}
} // namespace implementation
-} // namespace V1_2
+} // namespace V1_3
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.2/hidl_manager.h b/wpa_supplicant/hidl/1.3/hidl_manager.h
similarity index 92%
rename from wpa_supplicant/hidl/1.2/hidl_manager.h
rename to wpa_supplicant/hidl/1.3/hidl_manager.h
index 910e2bf..e49e28d 100644
--- a/wpa_supplicant/hidl/1.2/hidl_manager.h
+++ b/wpa_supplicant/hidl/1.3/hidl_manager.h
@@ -16,11 +16,12 @@
#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.2/ISupplicantStaIfaceCallback.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 "rsn_supp/pmksa_cache.h"
#include "sta_iface.h"
#include "sta_network.h"
#include "supplicant.h"
@@ -37,13 +38,14 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_2 {
+namespace V1_3 {
namespace implementation {
-using namespace android::hardware::wifi::supplicant::V1_2;
+using V1_0::ISupplicant;
using V1_0::ISupplicantP2pIface;
+using V1_0::ISupplicantStaIface;
using V1_0::ISupplicantStaIfaceCallback;
-using V1_1::ISupplicant;
-using V1_1::ISupplicantStaIface;
+using V1_0::P2pGroupCapabilityMask;
+using V1_0::WpsConfigMethods;
/**
* HidlManager is responsible for managing the lifetime of all
@@ -131,8 +133,18 @@
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);
+ void notifyDppSuccess(struct wpa_supplicant *wpa_s, DppSuccessCode code);
+ void notifyDppFailure(struct wpa_supplicant *wpa_s,
+ android::hardware::wifi::supplicant::V1_3::DppFailureCode code);
+ void notifyDppFailure(struct wpa_supplicant *wpa_s,
+ android::hardware::wifi::supplicant::V1_3::DppFailureCode code,
+ const char *ssid, const char *channel_list, unsigned short band_list[],
+ int size);
+ void notifyDppProgress(struct wpa_supplicant *wpa_s,
+ android::hardware::wifi::supplicant::V1_3::DppProgressCode code);
+ void notifyPmkCacheAdded(struct wpa_supplicant *wpa_s,
+ struct rsn_pmksa_cache_entry *pmksa_entry);
+ void notifyBssTmStatus(struct wpa_supplicant *wpa_s);
// Methods called from hidl objects.
void notifyExtRadioWorkStart(struct wpa_supplicant *wpa_s, uint32_t id);
@@ -206,6 +218,15 @@
const std::string &ifname,
const std::function<android::hardware::Return<void>(
android::sp<V1_2::ISupplicantStaIfaceCallback>)> &method);
+ void callWithEachStaIfaceCallback_1_3(
+ const std::string &ifname,
+ const std::function<android::hardware::Return<void>(
+ android::sp<V1_3::ISupplicantStaIfaceCallback>)> &method);
+ template <class CallbackTypeDerived>
+ void callWithEachStaIfaceCallbackDerived(
+ const std::string &ifname,
+ const std::function<
+ Return<void>(android::sp<CallbackTypeDerived>)> &method);
void callWithEachP2pNetworkCallback(
const std::string &ifname, int network_id,
const std::function<android::hardware::Return<void>(
@@ -365,6 +386,14 @@
WPA_KEY_MGMT_IEEE8021X_SHA256,
"KeyMgmt value mismatch");
static_assert(
+ static_cast<uint32_t>(V1_3::ISupplicantStaNetwork::KeyMgmtMask::WAPI_PSK) ==
+ WPA_KEY_MGMT_WAPI_PSK,
+ "KeyMgmt value mismatch");
+static_assert(
+ static_cast<uint32_t>(V1_3::ISupplicantStaNetwork::KeyMgmtMask::WAPI_CERT) ==
+ WPA_KEY_MGMT_WAPI_CERT,
+ "KeyMgmt value mismatch");
+static_assert(
static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::WPA) ==
WPA_PROTO_WPA,
"Proto value mismatch");
@@ -377,6 +406,10 @@
WPA_PROTO_OSEN,
"Proto value mismatch");
static_assert(
+ static_cast<uint32_t>(V1_3::ISupplicantStaNetwork::ProtoMask::WAPI) ==
+ WPA_PROTO_WAPI,
+ "Proto value mismatch");
+static_assert(
static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::OPEN) ==
WPA_AUTH_ALG_OPEN,
"AuthAlg value mismatch");
@@ -409,6 +442,10 @@
WPA_CIPHER_GCMP_256,
"GroupCipher value mismatch");
static_assert(
+ static_cast<uint32_t>(V1_3::ISupplicantStaNetwork::GroupCipherMask::SMS4) ==
+ WPA_CIPHER_SMS4,
+ "GroupCipher value mismatch");
+static_assert(
static_cast<uint32_t>(
ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED) ==
WPA_CIPHER_GTK_NOT_USED,
@@ -431,6 +468,11 @@
WPA_CIPHER_GCMP_256,
"PairwiseCipher value mismatch");
static_assert(
+ static_cast<uint32_t>(
+ V1_3::ISupplicantStaNetwork::PairwiseCipherMask::SMS4) ==
+ WPA_CIPHER_SMS4,
+ "PairwiseCipher value mismatch");
+static_assert(
static_cast<uint32_t>(ISupplicantStaIfaceCallback::State::DISCONNECTED) ==
WPA_DISCONNECTED,
"State value mismatch");
@@ -718,7 +760,7 @@
P2P_PROV_DISC_INFO_UNAVAILABLE,
"P2P status code value mismatch");
} // namespace implementation
-} // namespace V1_2
+} // namespace V1_3
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.2/hidl_return_util.h b/wpa_supplicant/hidl/1.3/hidl_return_util.h
similarity index 97%
rename from wpa_supplicant/hidl/1.2/hidl_return_util.h
rename to wpa_supplicant/hidl/1.3/hidl_return_util.h
index 238646a..4c1f919 100644
--- a/wpa_supplicant/hidl/1.2/hidl_return_util.h
+++ b/wpa_supplicant/hidl/1.3/hidl_return_util.h
@@ -14,9 +14,10 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_2 {
+namespace V1_3 {
namespace implementation {
namespace hidl_return_util {
+using V1_0::SupplicantStatusCode;
/**
* These utility functions are used to invoke a method on the provided
@@ -93,7 +94,7 @@
} // namespace hidl_return_util
} // namespace implementation
-} // namespace V1_2
+} // namespace V1_3
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.2/iface_config_utils.cpp b/wpa_supplicant/hidl/1.3/iface_config_utils.cpp
similarity index 99%
rename from wpa_supplicant/hidl/1.2/iface_config_utils.cpp
rename to wpa_supplicant/hidl/1.3/iface_config_utils.cpp
index 43908e3..31370a6 100644
--- a/wpa_supplicant/hidl/1.2/iface_config_utils.cpp
+++ b/wpa_supplicant/hidl/1.3/iface_config_utils.cpp
@@ -81,7 +81,7 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_2 {
+namespace V1_3 {
namespace implementation {
namespace iface_config_utils {
SupplicantStatus setWpsDeviceName(
@@ -176,7 +176,7 @@
}
} // namespace iface_config_utils
} // namespace implementation
-} // namespace V1_2
+} // namespace V1_3
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.2/iface_config_utils.h b/wpa_supplicant/hidl/1.3/iface_config_utils.h
similarity index 97%
rename from wpa_supplicant/hidl/1.2/iface_config_utils.h
rename to wpa_supplicant/hidl/1.3/iface_config_utils.h
index 9e88b3e..822d7ac 100644
--- a/wpa_supplicant/hidl/1.2/iface_config_utils.h
+++ b/wpa_supplicant/hidl/1.3/iface_config_utils.h
@@ -30,7 +30,7 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_2 {
+namespace V1_3 {
namespace implementation {
namespace iface_config_utils {
SupplicantStatus setWpsDeviceName(
@@ -51,7 +51,7 @@
struct wpa_supplicant* wpa_s, bool useExternalSim);
} // namespace iface_config_utils
} // namespace implementation
-} // namespace V1_2
+} // namespace V1_3
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.3/manifest.xml b/wpa_supplicant/hidl/1.3/manifest.xml
new file mode 100644
index 0000000..33e4fd4
--- /dev/null
+++ b/wpa_supplicant/hidl/1.3/manifest.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.wifi.supplicant</name>
+ <transport>hwbinder</transport>
+ <version>1.3</version>
+ <interface>
+ <name>ISupplicant</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/wpa_supplicant/hidl/1.3/misc_utils.h b/wpa_supplicant/hidl/1.3/misc_utils.h
new file mode 100644
index 0000000..b95b1ee
--- /dev/null
+++ b/wpa_supplicant/hidl/1.3/misc_utils.h
@@ -0,0 +1,111 @@
+/*
+ * 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_
+
+#include <iostream>
+
+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_3 {
+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;
+}
+
+inline std::stringstream& serializePmkCacheEntry(
+ std::stringstream &ss, struct rsn_pmksa_cache_entry *pmksa_entry) {
+ ss.write((char *) &pmksa_entry->pmk_len, sizeof(pmksa_entry->pmk_len));
+ ss.write((char *) pmksa_entry->pmk, pmksa_entry->pmk_len);
+ ss.write((char *) pmksa_entry->pmkid, PMKID_LEN);
+ ss.write((char *) pmksa_entry->aa, ETH_ALEN);
+ // Omit wpa_ssid field because the network is created on connecting to a access point.
+ ss.write((char *) &pmksa_entry->akmp, sizeof(pmksa_entry->akmp));
+ ss.write((char *) &pmksa_entry->reauth_time, sizeof(pmksa_entry->reauth_time));
+ ss.write((char *) &pmksa_entry->expiration, sizeof(pmksa_entry->expiration));
+ ss.write((char *) &pmksa_entry->opportunistic, sizeof(pmksa_entry->opportunistic));
+ char byte = (pmksa_entry->fils_cache_id_set) ? 1 : 0;
+ ss.write((char *) &byte, sizeof(byte));
+ ss.write((char *) pmksa_entry->fils_cache_id, FILS_CACHE_ID_LEN);
+ ss << std::flush;
+ return ss;
+}
+
+inline std::stringstream& deserializePmkCacheEntry(
+ std::stringstream &ss, struct rsn_pmksa_cache_entry *pmksa_entry) {
+ ss.seekg(0);
+ ss.read((char *) &pmksa_entry->pmk_len, sizeof(pmksa_entry->pmk_len));
+ ss.read((char *) pmksa_entry->pmk, pmksa_entry->pmk_len);
+ ss.read((char *) pmksa_entry->pmkid, PMKID_LEN);
+ ss.read((char *) pmksa_entry->aa, ETH_ALEN);
+ // Omit wpa_ssid field because the network is created on connecting to a access point.
+ ss.read((char *) &pmksa_entry->akmp, sizeof(pmksa_entry->akmp));
+ ss.read((char *) &pmksa_entry->reauth_time, sizeof(pmksa_entry->reauth_time));
+ ss.read((char *) &pmksa_entry->expiration, sizeof(pmksa_entry->expiration));
+ ss.read((char *) &pmksa_entry->opportunistic, sizeof(pmksa_entry->opportunistic));
+ char byte = 0;
+ ss.read((char *) &byte, sizeof(byte));
+ pmksa_entry->fils_cache_id_set = (byte) ? 1 : 0;
+ ss.read((char *) pmksa_entry->fils_cache_id, FILS_CACHE_ID_LEN);
+ return ss;
+}
+} // namespace misc_utils
+} // namespace implementation
+} // namespace V1_3
+} // namespace supplicant
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+#endif // MISC_UTILS_H_
diff --git a/wpa_supplicant/hidl/1.2/p2p_iface.cpp b/wpa_supplicant/hidl/1.3/p2p_iface.cpp
similarity index 98%
rename from wpa_supplicant/hidl/1.2/p2p_iface.cpp
rename to wpa_supplicant/hidl/1.3/p2p_iface.cpp
index fd9ce0d..ffa9b6a 100644
--- a/wpa_supplicant/hidl/1.2/p2p_iface.cpp
+++ b/wpa_supplicant/hidl/1.3/p2p_iface.cpp
@@ -100,7 +100,7 @@
struct hostapd_hw_modes *mode;
int count, i;
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band, 0);
if (mode == NULL) {
/* No channels supported in this band. */
return;
@@ -163,7 +163,7 @@
// set P2p network defaults
wpa_network->p2p_group = 1;
- wpa_network->mode = wpa_ssid::wpas_mode::WPAS_MODE_INFRA;
+ wpa_network->mode = wpas_mode::WPAS_MODE_INFRA;
wpa_network->auth_alg = WPA_AUTH_ALG_OPEN;
wpa_network->key_mgmt = WPA_KEY_MGMT_PSK;
@@ -209,6 +209,12 @@
struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res)
{
+ if (wpa_s->p2p_scan_work) {
+ struct wpa_radio_work *work = wpa_s->p2p_scan_work;
+ wpa_s->p2p_scan_work = NULL;
+ radio_work_done(work);
+ }
+
if (pending_scan_res_join_callback) {
pending_scan_res_join_callback();
}
@@ -310,6 +316,9 @@
ret = wpa_drv_scan(wpa_s, ¶ms);
if (!ret) {
os_get_reltime(&wpa_s->scan_trigger_time);
+ if (wpa_s->scan_res_handler) {
+ wpa_printf(MSG_DEBUG, "Replace current running scan result handler");
+ }
wpa_s->scan_res_handler = scanResJoinWrapper;
wpa_s->own_scan_requested = 1;
wpa_s->clear_driver_scan_cache = 0;
@@ -331,6 +340,7 @@
const std::string& passphrase)
{
int ret = 0;
+ int he = wpa_s->conf->p2p_go_he;
int vht = wpa_s->conf->p2p_go_vht;
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
@@ -349,7 +359,7 @@
if (wpas_p2p_group_add_persistent(
wpa_s, wpa_network, 0, 0, 0, 0, ht40, vht,
- VHT_CHANWIDTH_USE_HT, 0, NULL, 0, 1)) {
+ CHANWIDTH_USE_HT, he, 0, NULL, 0, 0)) {
ret = -1;
}
@@ -381,6 +391,13 @@
void scanResJoinIgnore(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) {
wpa_printf(MSG_DEBUG, "P2P: Ignore group join scan results.");
+
+ if (wpa_s->p2p_scan_work) {
+ struct wpa_radio_work *work = wpa_s->p2p_scan_work;
+ wpa_s->p2p_scan_work = NULL;
+ radio_work_done(work);
+ }
+
}
} // namespace
@@ -389,9 +406,10 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_2 {
+namespace V1_3 {
namespace implementation {
using hidl_return_util::validateAndCall;
+using V1_0::SupplicantStatusCode;
P2pIface::P2pIface(struct wpa_global* wpa_global, const char ifname[])
: wpa_global_(wpa_global), ifname_(ifname), is_valid_(true)
@@ -1060,6 +1078,7 @@
wps_method = WPS_PIN_KEYPAD;
break;
}
+ int he = wpa_s->conf->p2p_go_he;
int vht = wpa_s->conf->p2p_go_vht;
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
const char* pin =
@@ -1067,7 +1086,7 @@
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, 0, nullptr, 0);
+ vht, CHANWIDTH_USE_HT, he, 0, nullptr, 0);
if (new_pin < 0) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
@@ -1123,6 +1142,7 @@
bool persistent, SupplicantNetworkId persistent_network_id)
{
struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ int he = wpa_s->conf->p2p_go_he;
int vht = wpa_s->conf->p2p_go_vht;
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
struct wpa_ssid* ssid =
@@ -1130,7 +1150,7 @@
if (ssid == NULL) {
if (wpas_p2p_group_add(
wpa_s, persistent, 0, 0, ht40, vht,
- VHT_CHANWIDTH_USE_HT, 0)) {
+ CHANWIDTH_USE_HT, he, 0)) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
} else {
return {SupplicantStatusCode::SUCCESS, ""};
@@ -1138,7 +1158,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, 0, NULL, 0, 0)) {
+ CHANWIDTH_USE_HT, he, 0, NULL, 0, 0)) {
return {SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN,
""};
} else {
@@ -1193,6 +1213,7 @@
const std::array<uint8_t, 6>& peer_address)
{
struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ int he = wpa_s->conf->p2p_go_he;
int vht = wpa_s->conf->p2p_go_vht;
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
struct wpa_ssid* ssid =
@@ -1202,7 +1223,7 @@
}
if (wpas_p2p_invite(
wpa_s, peer_address.data(), ssid, NULL, 0, 0, ht40, vht,
- VHT_CHANWIDTH_USE_HT, 0, 0)) {
+ CHANWIDTH_USE_HT, 0, he, 0)) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -1631,6 +1652,7 @@
bool joinExistingGroup)
{
struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ int he = wpa_s->conf->p2p_go_he;
int vht = wpa_s->conf->p2p_go_vht;
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
@@ -1658,7 +1680,7 @@
if (wpas_p2p_group_add(
wpa_s, persistent, freq, 0, ht40, vht,
- VHT_CHANWIDTH_USE_HT, 0)) {
+ CHANWIDTH_USE_HT, he, 0)) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -1831,7 +1853,7 @@
}
} // namespace implementation
-} // namespace V1_2
+} // namespace V1_3
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.2/p2p_iface.h b/wpa_supplicant/hidl/1.3/p2p_iface.h
similarity index 98%
rename from wpa_supplicant/hidl/1.2/p2p_iface.h
rename to wpa_supplicant/hidl/1.3/p2p_iface.h
index bd43a5a..608dbd4 100644
--- a/wpa_supplicant/hidl/1.2/p2p_iface.h
+++ b/wpa_supplicant/hidl/1.3/p2p_iface.h
@@ -34,10 +34,13 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_2 {
+namespace V1_3 {
namespace implementation {
-using namespace android::hardware::wifi::supplicant::V1_0;
-using namespace android::hardware::wifi::supplicant::V1_1;
+using V1_0::SupplicantNetworkId;
+using V1_0::SupplicantStatus;
+using V1_0::IfaceType;
+using V1_0::ISupplicantP2pIfaceCallback;
+using V1_0::ISupplicantP2pNetwork;
/**
* Implementation of P2pIface hidl object. Each unique hidl
@@ -318,7 +321,7 @@
};
} // namespace implementation
-} // namespace V1_2
+} // namespace V1_3
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.2/p2p_network.cpp b/wpa_supplicant/hidl/1.3/p2p_network.cpp
similarity index 98%
rename from wpa_supplicant/hidl/1.2/p2p_network.cpp
rename to wpa_supplicant/hidl/1.3/p2p_network.cpp
index 693b2c0..c87e4c0 100644
--- a/wpa_supplicant/hidl/1.2/p2p_network.cpp
+++ b/wpa_supplicant/hidl/1.3/p2p_network.cpp
@@ -20,9 +20,10 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_2 {
+namespace V1_3 {
namespace implementation {
using hidl_return_util::validateAndCall;
+using V1_0::SupplicantStatusCode;
P2pNetwork::P2pNetwork(
struct wpa_global *wpa_global, const char ifname[], int network_id)
@@ -180,7 +181,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
return {{SupplicantStatusCode::SUCCESS, ""},
- (wpa_ssid->mode == wpa_ssid::wpas_mode::WPAS_MODE_P2P_GO)};
+ (wpa_ssid->mode == wpas_mode::WPAS_MODE_P2P_GO)};
}
SupplicantStatus P2pNetwork::setClientListInternal(
@@ -249,7 +250,7 @@
(struct wpa_global *)wpa_global_, ifname_.c_str());
}
} // namespace implementation
-} // namespace V1_2
+} // namespace V1_3
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.2/p2p_network.h b/wpa_supplicant/hidl/1.3/p2p_network.h
similarity index 95%
rename from wpa_supplicant/hidl/1.2/p2p_network.h
rename to wpa_supplicant/hidl/1.3/p2p_network.h
index e2e8ec2..8c134b0 100644
--- a/wpa_supplicant/hidl/1.2/p2p_network.h
+++ b/wpa_supplicant/hidl/1.3/p2p_network.h
@@ -26,10 +26,10 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_2 {
+namespace V1_3 {
namespace implementation {
-using namespace android::hardware::wifi::supplicant::V1_0;
-using namespace android::hardware::wifi::supplicant::V1_1;
+using V1_0::ISupplicantP2pNetwork;
+using V1_0::ISupplicantP2pNetworkCallback;
/**
* Implementation of P2pNetwork hidl object. Each unique hidl
@@ -96,7 +96,7 @@
};
} // namespace implementation
-} // namespace V1_2
+} // namespace V1_3
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.2/sta_iface.cpp b/wpa_supplicant/hidl/1.3/sta_iface.cpp
similarity index 83%
rename from wpa_supplicant/hidl/1.2/sta_iface.cpp
rename to wpa_supplicant/hidl/1.3/sta_iface.cpp
index 1ca440e..b738ff7 100644
--- a/wpa_supplicant/hidl/1.2/sta_iface.cpp
+++ b/wpa_supplicant/hidl/1.3/sta_iface.cpp
@@ -20,15 +20,25 @@
#include "interworking.h"
#include "hs20_supplicant.h"
#include "wps_supplicant.h"
-#include "dpp_supplicant.h"
#include "dpp.h"
+#include "dpp_supplicant.h"
+#include "rsn_supp/wpa.h"
+#include "rsn_supp/pmksa_cache.h"
}
namespace {
+using ISupplicantStaNetworkV1_2 =
+ android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork;
+using ISupplicantStaNetworkV1_3 =
+ android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork;
+using android::hardware::wifi::V1_0::WifiChannelWidthInMhz;
using android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
using android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
-using android::hardware::wifi::supplicant::V1_2::ISupplicantStaIface;
-using android::hardware::wifi::supplicant::V1_2::implementation::HidlManager;
+using android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
+using android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface;
+using android::hardware::wifi::supplicant::V1_3::ConnectionCapabilities;
+using android::hardware::wifi::supplicant::V1_3::WifiTechnology;
+using android::hardware::wifi::supplicant::V1_3::implementation::HidlManager;
constexpr uint32_t kMaxAnqpElems = 100;
constexpr char kGetMacAddress[] = "MACADDR";
@@ -152,18 +162,70 @@
startExtRadioWork(work);
}
+uint32_t convertWpaKeyMgmtCapabilitiesToHidl (
+ struct wpa_supplicant *wpa_s, struct wpa_driver_capa *capa) {
+
+ uint32_t mask = 0;
+ /* 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 |= ISupplicantStaNetworkV1_2::ISupplicantStaNetwork::KeyMgmtMask::SUITE_B_192;
+ }
+#endif /* CONFIG_SUITEB192 */
+#ifdef CONFIG_OWE
+ if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE) {
+ mask |= ISupplicantStaNetworkV1_2::ISupplicantStaNetwork::KeyMgmtMask::OWE;
+ }
+#endif /* CONFIG_OWE */
+#ifdef CONFIG_SAE
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) {
+ mask |= ISupplicantStaNetworkV1_2::ISupplicantStaNetwork::KeyMgmtMask::SAE;
+ }
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_DPP
+ if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_DPP) {
+ mask |= ISupplicantStaNetworkV1_2::ISupplicantStaNetwork::KeyMgmtMask::DPP;
+ }
+#endif
+#ifdef CONFIG_WAPI_INTERFACE
+ mask |= ISupplicantStaNetworkV1_3::ISupplicantStaNetwork::KeyMgmtMask::WAPI_PSK;
+ mask |= ISupplicantStaNetworkV1_3::ISupplicantStaNetwork::KeyMgmtMask::WAPI_CERT;
+#endif /* CONFIG_WAPI_INTERFACE */
+#ifdef CONFIG_FILS
+ if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256) {
+ mask |= ISupplicantStaNetworkV1_3::ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA256;
+ }
+ if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384) {
+ mask |= ISupplicantStaNetworkV1_3::ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA384;
+ }
+#endif /* CONFIG_FILS */
+ return mask;
+}
+
} // namespace
namespace android {
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_2 {
+namespace V1_3 {
namespace implementation {
using hidl_return_util::validateAndCall;
-
-using namespace android::hardware::wifi::supplicant::V1_0;
-using namespace android::hardware::wifi::supplicant::V1_1;
using V1_0::ISupplicantStaIfaceCallback;
StaIface::StaIface(struct wpa_global *wpa_global, const char ifname[])
@@ -205,6 +267,22 @@
&StaIface::removeNetworkInternal, _hidl_cb, id);
}
+Return<void> StaIface::filsHlpFlushRequest(filsHlpFlushRequest_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::filsHlpFlushRequestInternal, _hidl_cb);
+}
+
+Return<void> StaIface::filsHlpAddRequest(
+ const hidl_array<uint8_t, 6> &dst_mac, const hidl_vec<uint8_t> &pkt,
+ filsHlpAddRequest_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::filsHlpAddRequestInternal, _hidl_cb, dst_mac, pkt);
+}
+
Return<void> StaIface::getNetwork(
SupplicantNetworkId id, getNetwork_cb _hidl_cb)
{
@@ -249,6 +327,16 @@
&StaIface::registerCallbackInternal, _hidl_cb, callback_1_1);
}
+Return<void> StaIface::registerCallback_1_3(
+ const sp<V1_3::ISupplicantStaIfaceCallback> &callback,
+ registerCallback_cb _hidl_cb)
+{
+ sp<V1_3::ISupplicantStaIfaceCallback> callback_1_3 = callback;
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::registerCallbackInternal, _hidl_cb, callback_1_3);
+}
+
Return<void> StaIface::reassociate(reassociate_cb _hidl_cb)
{
return validateAndCall(
@@ -575,6 +663,30 @@
&StaIface::stopDppInitiatorInternal, _hidl_cb);
}
+Return<void> StaIface::getWpaDriverCapabilities(
+ getWpaDriverCapabilities_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_UNKNOWN,
+ &StaIface::getWpaDriverCapabilitiesInternal, _hidl_cb);
+}
+
+Return<void> StaIface::setMboCellularDataStatus(bool available,
+ setMboCellularDataStatus_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_UNKNOWN,
+ &StaIface::setMboCellularDataStatusInternal, _hidl_cb, available);
+}
+
+Return<void> StaIface::getKeyMgmtCapabilities_1_3(
+ getKeyMgmtCapabilities_1_3_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaIface::getKeyMgmtCapabilitiesInternal_1_3, _hidl_cb);
+}
+
std::pair<SupplicantStatus, std::string> StaIface::getNameInternal()
{
return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
@@ -585,6 +697,48 @@
return {{SupplicantStatusCode::SUCCESS, ""}, IfaceType::STA};
}
+SupplicantStatus StaIface::filsHlpFlushRequestInternal()
+{
+#ifdef CONFIG_FILS
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+
+ wpas_flush_fils_hlp_req(wpa_s);
+ return {SupplicantStatusCode::SUCCESS, ""};
+#else /* CONFIG_FILS */
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+#endif /* CONFIG_FILS */
+}
+
+SupplicantStatus StaIface::filsHlpAddRequestInternal(
+ const std::array<uint8_t, 6> &dst_mac, const std::vector<uint8_t> &pkt)
+{
+#ifdef CONFIG_FILS
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ struct fils_hlp_req *req;
+
+ if (!pkt.size())
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+
+
+ req = (struct fils_hlp_req *)os_zalloc(sizeof(*req));
+ if (!req)
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+
+ os_memcpy(req->dst, dst_mac.data(), ETH_ALEN);
+
+ req->pkt = wpabuf_alloc_copy(pkt.data(), pkt.size());
+ if (!req->pkt) {
+ os_free(req);
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+
+ dl_list_add_tail(&wpa_s->fils_hlp_req, &req->list);
+ return {SupplicantStatusCode::SUCCESS, ""};
+#else /* CONFIG_FILS */
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+#endif /* CONFIG_FILS */
+}
+
std::pair<SupplicantStatus, sp<ISupplicantNetwork>>
StaIface::addNetworkInternal()
{
@@ -603,6 +757,14 @@
return {{SupplicantStatusCode::SUCCESS, ""}, network};
}
+Return<void> StaIface::getConnectionCapabilities(
+ getConnectionCapabilities_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_UNKNOWN,
+ &StaIface::getConnectionCapabilitiesInternal, _hidl_cb);
+}
+
SupplicantStatus StaIface::removeNetworkInternal(SupplicantNetworkId id)
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
@@ -1083,52 +1245,7 @@
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};
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"}, 0};
}
std::pair<SupplicantStatus, uint32_t>
@@ -1253,6 +1370,11 @@
cmd += " conf=";
cmd += role;
+ if (net_role == DppNetRole::STA) {
+ /* DPP R2 connection status request */
+ cmd += " conn_status=1";
+ }
+
wpa_printf(MSG_DEBUG,
"DPP initiator command: %s", cmd.c_str());
@@ -1299,6 +1421,109 @@
#endif
}
+std::pair<SupplicantStatus, ConnectionCapabilities>
+StaIface::getConnectionCapabilitiesInternal()
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ struct ConnectionCapabilities capa;
+
+ if (wpa_s->connection_set) {
+ if (wpa_s->connection_he) {
+ capa.technology = WifiTechnology::HE;
+ } else if (wpa_s->connection_vht) {
+ capa.technology = WifiTechnology::VHT;
+ } else if (wpa_s->connection_ht) {
+ capa.technology = WifiTechnology::HT;
+ } else {
+ capa.technology = WifiTechnology::LEGACY;
+ }
+ switch (wpa_s->connection_channel_bandwidth) {
+ case CHAN_WIDTH_20:
+ capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
+ break;
+ case CHAN_WIDTH_40:
+ capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_40;
+ break;
+ case CHAN_WIDTH_80:
+ capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_80;
+ break;
+ case CHAN_WIDTH_160:
+ capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_160;
+ break;
+ case CHAN_WIDTH_80P80:
+ capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_80P80;
+ break;
+ default:
+ capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
+ break;
+ }
+ capa.maxNumberRxSpatialStreams = wpa_s->connection_max_nss_rx;
+ capa.maxNumberTxSpatialStreams = wpa_s->connection_max_nss_tx;
+ } else {
+ capa.technology = WifiTechnology::UNKNOWN;
+ capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
+ capa.maxNumberTxSpatialStreams = 1;
+ capa.maxNumberRxSpatialStreams = 1;
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, capa};
+}
+
+std::pair<SupplicantStatus, uint32_t>
+StaIface::getWpaDriverCapabilitiesInternal()
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ uint32_t mask = 0;
+
+#ifdef CONFIG_MBO
+ /* MBO has no capability flags. It's mainly legacy 802.11v BSS
+ * transition + Cellular steering. 11v is a default feature in
+ * supplicant. And cellular steering is handled in framework.
+ */
+ mask |= WpaDriverCapabilitiesMask::MBO;
+ if (wpa_s->enable_oce & OCE_STA) {
+ mask |= WpaDriverCapabilitiesMask::OCE;
+ }
+#endif
+
+ wpa_printf(MSG_DEBUG, "Driver capability mask: 0x%x", mask);
+
+ return {{SupplicantStatusCode::SUCCESS, ""}, mask};
+}
+
+SupplicantStatus StaIface::setMboCellularDataStatusInternal(bool available)
+{
+#ifdef CONFIG_MBO
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ enum mbo_cellular_capa mbo_cell_capa;
+
+ if (available) {
+ mbo_cell_capa = MBO_CELL_CAPA_AVAILABLE;
+ } else {
+ mbo_cell_capa = MBO_CELL_CAPA_NOT_AVAILABLE;
+ }
+ wpas_mbo_update_cell_capa(wpa_s, mbo_cell_capa);
+ return {SupplicantStatusCode::SUCCESS, ""};
+#else
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+#endif
+}
+
+std::pair<SupplicantStatus, uint32_t>
+StaIface::getKeyMgmtCapabilitiesInternal_1_3()
+{
+ 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};
+ }
+
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ convertWpaKeyMgmtCapabilitiesToHidl(wpa_s, &capa)};
+}
+
/**
* Retrieve the underlying |wpa_supplicant| struct
* pointer for this iface.
@@ -1310,7 +1535,7 @@
return wpa_supplicant_get_iface(wpa_global_, ifname_.c_str());
}
} // namespace implementation
-} // namespace V1_2
+} // namespace V1_3
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.2/sta_iface.h b/wpa_supplicant/hidl/1.3/sta_iface.h
similarity index 87%
rename from wpa_supplicant/hidl/1.2/sta_iface.h
rename to wpa_supplicant/hidl/1.3/sta_iface.h
index 5a04ee3..ba06e5a 100644
--- a/wpa_supplicant/hidl/1.2/sta_iface.h
+++ b/wpa_supplicant/hidl/1.3/sta_iface.h
@@ -15,9 +15,9 @@
#include <android-base/macros.h>
-#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaIface.h>
#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIfaceCallback.h>
-#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaNetwork.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
extern "C"
{
@@ -33,16 +33,18 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_2 {
+namespace V1_3 {
namespace implementation {
-using namespace android::hardware::wifi::supplicant::V1_2;
+using V1_0::ISupplicantNetwork;
+using android::hardware::wifi::supplicant::V1_2::DppAkm;
+using android::hardware::wifi::supplicant::V1_2::DppNetRole;
/**
* 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 V1_2::ISupplicantStaIface
+class StaIface : public V1_3::ISupplicantStaIface
{
public:
StaIface(struct wpa_global* wpa_global, const char ifname[]);
@@ -68,6 +70,11 @@
Return<void> addNetwork(addNetwork_cb _hidl_cb) override;
Return<void> removeNetwork(
SupplicantNetworkId id, removeNetwork_cb _hidl_cb) override;
+ Return<void> filsHlpFlushRequest(
+ filsHlpFlushRequest_cb _hidl_cb) override;
+ Return<void> filsHlpAddRequest(
+ const hidl_array<uint8_t, 6>& dst_mac, const hidl_vec<uint8_t>& pkt,
+ filsHlpAddRequest_cb _hidl_cb) override;
Return<void> getNetwork(
SupplicantNetworkId id, getNetwork_cb _hidl_cb) override;
Return<void> listNetworks(listNetworks_cb _hidl_cb) override;
@@ -80,6 +87,9 @@
Return<void> registerCallback_1_2(
const sp<V1_2::ISupplicantStaIfaceCallback>& callback,
registerCallback_cb _hidl_cb) override;
+ Return<void> registerCallback_1_3(
+ const sp<V1_3::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;
@@ -177,6 +187,14 @@
uint32_t own_bootstrap_id,
startDppConfiguratorInitiator_cb _hidl_cb) override;
Return<void> stopDppInitiator(stopDppInitiator_cb _hidl_cb) override;
+ Return<void> getConnectionCapabilities(
+ getConnectionCapabilities_cb _hidl_cb) override;
+ Return<void> getWpaDriverCapabilities(
+ getWpaDriverCapabilities_cb _hidl_cb) override;
+ Return<void> setMboCellularDataStatus(bool available,
+ setMboCellularDataStatus_cb _hidl_cb) override;
+ Return<void> getKeyMgmtCapabilities_1_3(
+ getKeyMgmtCapabilities_1_3_cb _hidl_cb) override;
private:
// Corresponding worker functions for the HIDL methods.
@@ -184,6 +202,10 @@
std::pair<SupplicantStatus, IfaceType> getTypeInternal();
std::pair<SupplicantStatus, sp<ISupplicantNetwork>>
addNetworkInternal();
+ SupplicantStatus filsHlpFlushRequestInternal();
+ SupplicantStatus filsHlpAddRequestInternal(
+ const std::array<uint8_t, 6>& dst_mac,
+ const std::vector<uint8_t>& pkt);
SupplicantStatus removeNetworkInternal(SupplicantNetworkId id);
std::pair<SupplicantStatus, sp<ISupplicantNetwork>> getNetworkInternal(
SupplicantNetworkId id);
@@ -260,7 +282,10 @@
SupplicantStatus startDppEnrolleeInitiatorInternal(uint32_t peer_bootstrap_id,
uint32_t own_bootstrap_id);
SupplicantStatus stopDppInitiatorInternal();
-
+ std::pair<SupplicantStatus, ConnectionCapabilities> getConnectionCapabilitiesInternal();
+ std::pair<SupplicantStatus, uint32_t> getWpaDriverCapabilitiesInternal();
+ SupplicantStatus setMboCellularDataStatusInternal(bool available);
+ std::pair<SupplicantStatus, uint32_t> getKeyMgmtCapabilitiesInternal_1_3();
struct wpa_supplicant* retrieveIfacePtr();
@@ -275,7 +300,7 @@
};
} // namespace implementation
-} // namespace V1_2
+} // namespace V1_3
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.2/sta_network.cpp b/wpa_supplicant/hidl/1.3/sta_network.cpp
similarity index 84%
rename from wpa_supplicant/hidl/1.2/sta_network.cpp
rename to wpa_supplicant/hidl/1.3/sta_network.cpp
index 4d694f7..d3b120d 100644
--- a/wpa_supplicant/hidl/1.2/sta_network.cpp
+++ b/wpa_supplicant/hidl/1.3/sta_network.cpp
@@ -19,8 +19,9 @@
namespace {
using android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
-using android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork;
-using namespace android::hardware::wifi::supplicant::V1_2;
+using android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
+using ISupplicantStaNetworkV1_2 = android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork;
+using ISupplicantStaNetworkV1_3 = android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork;
constexpr uint8_t kZeroBssid[6] = {0, 0, 0, 0, 0, 0};
@@ -32,19 +33,25 @@
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::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));
+ static_cast<uint32_t>(ISupplicantStaNetworkV1_2::KeyMgmtMask::SAE) |
+ static_cast<uint32_t>(ISupplicantStaNetworkV1_2::KeyMgmtMask::SUITE_B_192) |
+ static_cast<uint32_t>(ISupplicantStaNetworkV1_2::KeyMgmtMask::OWE) |
+ static_cast<uint32_t>(ISupplicantStaNetworkV1_2::KeyMgmtMask::WPA_PSK_SHA256) |
+ static_cast<uint32_t>(ISupplicantStaNetworkV1_2::KeyMgmtMask::WPA_EAP_SHA256) |
+ static_cast<uint32_t>(ISupplicantStaNetworkV1_3::KeyMgmtMask::WAPI_PSK) |
+ static_cast<uint32_t>(ISupplicantStaNetworkV1_3::KeyMgmtMask::WAPI_CERT) |
+ static_cast<uint32_t>(ISupplicantStaNetworkV1_3::KeyMgmtMask::FILS_SHA256) |
+ static_cast<uint32_t>(ISupplicantStaNetworkV1_3::KeyMgmtMask::FILS_SHA384));
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));
+ static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::OSEN) |
+ static_cast<uint32_t>(ISupplicantStaNetworkV1_3::ProtoMask::WAPI));
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));
+ static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::LEAP) |
+ static_cast<uint32_t>(ISupplicantStaNetworkV1_3::AuthAlgMask::SAE));
constexpr uint32_t kAllowedGroupCipherMask =
(static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::WEP40) |
static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::WEP104) |
@@ -52,20 +59,23 @@
static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::CCMP) |
static_cast<uint32_t>(
ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED) |
- static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::GCMP_256));
+ static_cast<uint32_t>(ISupplicantStaNetworkV1_2::GroupCipherMask::GCMP_256) |
+ static_cast<uint32_t>(ISupplicantStaNetworkV1_3::GroupCipherMask::SMS4));
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::GCMP_256));
+ ISupplicantStaNetworkV1_2::PairwiseCipherMask::GCMP_256) |
+ static_cast<uint32_t>(
+ ISupplicantStaNetworkV1_3::PairwiseCipherMask::SMS4));
constexpr uint32_t kAllowedGroupMgmtCipherMask =
(static_cast<uint32_t>(
- ISupplicantStaNetwork::GroupMgmtCipherMask::BIP_GMAC_128) |
+ ISupplicantStaNetworkV1_2::GroupMgmtCipherMask::BIP_GMAC_128) |
static_cast<uint32_t>(
- ISupplicantStaNetwork::GroupMgmtCipherMask::BIP_GMAC_256) |
+ ISupplicantStaNetworkV1_2::GroupMgmtCipherMask::BIP_GMAC_256) |
static_cast<uint32_t>(
- ISupplicantStaNetwork::GroupMgmtCipherMask::BIP_CMAC_256));
+ ISupplicantStaNetworkV1_2::GroupMgmtCipherMask::BIP_CMAC_256));
constexpr uint32_t kEapMethodMax =
static_cast<uint32_t>(ISupplicantStaNetwork::EapMethod::WFA_UNAUTH_TLS) + 1;
@@ -83,15 +93,21 @@
constexpr char kNetworkEapSimUmtsAutsResponse[] = "UMTS-AUTS";
constexpr char kNetworkEapSimGsmAuthFailure[] = "GSM-FAIL";
constexpr char kNetworkEapSimUmtsAuthFailure[] = "UMTS-FAIL";
+
+#ifdef CONFIG_WAPI_INTERFACE
+std::string dummyWapiCertSuite;
+std::vector<uint8_t> dummyWapiPsk;
+#endif /* CONFIG_WAPI_INTERFACE */
} // namespace
namespace android {
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_2 {
+namespace V1_3 {
namespace implementation {
using hidl_return_util::validateAndCall;
+using V1_0::SupplicantStatusCode;
StaNetwork::StaNetwork(
struct wpa_global *wpa_global, const char ifname[], int network_id)
@@ -386,6 +402,13 @@
&StaNetwork::setUpdateIdentifierInternal, _hidl_cb, id);
}
+Return<void> StaNetwork::setWapiCertSuite(
+ const hidl_string& suite, setWapiCertSuite_cb _hidl_cb) {
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setWapiCertSuiteInternal, _hidl_cb, suite);
+}
+
Return<void> StaNetwork::getSsid(getSsid_cb _hidl_cb)
{
return validateAndCall(
@@ -607,6 +630,13 @@
&StaNetwork::getWpsNfcConfigurationTokenInternal, _hidl_cb);
}
+Return<void> StaNetwork::getWapiCertSuite(getWapiCertSuite_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getWapiCertSuiteInternal, _hidl_cb);
+}
+
Return<void> StaNetwork::enable(bool no_connect, enable_cb _hidl_cb)
{
return validateAndCall(
@@ -791,6 +821,113 @@
&StaNetwork::setSaePasswordIdInternal, _hidl_cb, sae_password_id);
}
+Return<void> StaNetwork::setOcsp(
+ OcspType ocspType, setOcsp_cb _hidl_cb) {
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setOcspInternal, _hidl_cb, ocspType);
+}
+
+Return<void> StaNetwork::getOcsp(
+ getOcsp_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getOcspInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::setPmkCache(const hidl_vec<uint8_t> &serializedEntry,
+ setPmkCache_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setPmkCacheInternal, _hidl_cb, serializedEntry);
+}
+
+Return<void> StaNetwork::setKeyMgmt_1_3(
+ uint32_t key_mgmt_mask, setKeyMgmt_1_3_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setKeyMgmt_1_3Internal, _hidl_cb, key_mgmt_mask);
+}
+
+Return<void> StaNetwork::getKeyMgmt_1_3(getKeyMgmt_1_3_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getKeyMgmt_1_3Internal, _hidl_cb);
+}
+
+Return<void> StaNetwork::setProto_1_3(uint32_t proto_mask, setProto_1_3_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setProto_1_3Internal, _hidl_cb, proto_mask);
+}
+
+Return<void> StaNetwork::getProto_1_3(getProto_1_3_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getProto_1_3Internal, _hidl_cb);
+}
+
+Return<void> StaNetwork::setGroupCipher_1_3(
+ uint32_t group_cipher_mask, setGroupCipher_1_3_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setGroupCipher_1_3Internal, _hidl_cb, group_cipher_mask);
+}
+
+Return<void> StaNetwork::getGroupCipher_1_3(getGroupCipher_1_3_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getGroupCipher_1_3Internal, _hidl_cb);
+}
+
+Return<void> StaNetwork::setPairwiseCipher_1_3(
+ uint32_t pairwise_cipher_mask, setPairwiseCipher_1_3_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setPairwiseCipher_1_3Internal, _hidl_cb,
+ pairwise_cipher_mask);
+}
+
+Return<void> StaNetwork::getPairwiseCipher_1_3(
+ getPairwiseCipher_1_3_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getPairwiseCipher_1_3Internal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getAuthAlg_1_3(getAuthAlg_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getAuthAlgInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::setAuthAlg_1_3(
+ 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::setEapErp(bool enable, setEapErp_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setEapErpInternal, _hidl_cb, enable);
+}
+
std::pair<SupplicantStatus, uint32_t> StaNetwork::getIdInternal()
{
return {{SupplicantStatusCode::SUCCESS, ""}, network_id_};
@@ -871,27 +1008,12 @@
SupplicantStatus StaNetwork::setKeyMgmtInternal(uint32_t key_mgmt_mask)
{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- 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();
- return {SupplicantStatusCode::SUCCESS, ""};
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"};
}
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, ""};
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"};
}
SupplicantStatus StaNetwork::setAuthAlgInternal(uint32_t auth_alg_mask)
@@ -908,33 +1030,39 @@
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, ""};
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"};
}
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, ""};
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"};
}
-SupplicantStatus StaNetwork::setPskPassphraseInternal(const std::string &psk)
+SupplicantStatus StaNetwork::setPskPassphraseInternal(const std::string &rawPsk)
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ std::string psk = rawPsk;
+#ifdef CONFIG_WAPI_INTERFACE
+ if (wpa_ssid->key_mgmt & WPA_KEY_MGMT_WAPI_PSK) {
+ if (rawPsk.size() > 2 && rawPsk.front()== '"' && rawPsk.back() == '"') {
+ psk = rawPsk.substr(1, rawPsk.size() - 2);
+ } else {
+ if ((rawPsk.size() & 1)) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ size_t len = psk.size() / 2;
+ uint8_t *buf = (uint8_t *) os_malloc(len);
+ if (hexstr2bin(psk.c_str(), buf, len) < 0) {
+ os_free(buf);
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ std::vector<uint8_t> bytes(buf, buf + len);
+ os_free(buf);
+ return setWapiPskInternal(bytes);
+ }
+ }
+#endif
if (isPskPassphraseValid(psk)) {
return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
}
@@ -1174,7 +1302,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- path.c_str(), &(wpa_ssid->eap.ca_cert), "eap ca_cert")) {
+ path.c_str(), &(wpa_ssid->eap.cert.ca_cert), "eap ca_cert")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -1184,7 +1312,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- path.c_str(), &(wpa_ssid->eap.ca_path), "eap ca_path")) {
+ path.c_str(), &(wpa_ssid->eap.cert.ca_path), "eap ca_path")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -1194,7 +1322,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- path.c_str(), &(wpa_ssid->eap.client_cert),
+ path.c_str(), &(wpa_ssid->eap.cert.client_cert),
"eap client_cert")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
@@ -1205,7 +1333,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- id.c_str(), &(wpa_ssid->eap.key_id), "eap key_id")) {
+ id.c_str(), &(wpa_ssid->eap.cert.key_id), "eap key_id")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -1216,7 +1344,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- match.c_str(), &(wpa_ssid->eap.subject_match),
+ match.c_str(), &(wpa_ssid->eap.cert.subject_match),
"eap subject_match")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
@@ -1228,7 +1356,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- match.c_str(), &(wpa_ssid->eap.altsubject_match),
+ match.c_str(), &(wpa_ssid->eap.cert.altsubject_match),
"eap altsubject_match")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
@@ -1238,7 +1366,7 @@
SupplicantStatus StaNetwork::setEapEngineInternal(bool enable)
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- wpa_ssid->eap.engine = enable ? 1 : 0;
+ wpa_ssid->eap.cert.engine = enable ? 1 : 0;
return {SupplicantStatusCode::SUCCESS, ""};
}
@@ -1246,7 +1374,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- id.c_str(), &(wpa_ssid->eap.engine_id), "eap engine_id")) {
+ id.c_str(), &(wpa_ssid->eap.cert.engine_id), "eap engine_id")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -1257,7 +1385,7 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
if (setStringFieldAndResetState(
- match.c_str(), &(wpa_ssid->eap.domain_suffix_match),
+ match.c_str(), &(wpa_ssid->eap.cert.domain_suffix_match),
"eap domain_suffix_match")) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
@@ -1292,6 +1420,33 @@
return {SupplicantStatusCode::SUCCESS, ""};
}
+SupplicantStatus StaNetwork::setWapiCertSuiteInternal(const std::string &suite)
+{
+#ifdef CONFIG_WAPI_INTERFACE
+ dummyWapiCertSuite = suite;
+ return {SupplicantStatusCode::SUCCESS, "Dummy implementation"};
+#else
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, "Not implemented"};
+#endif
+}
+
+SupplicantStatus StaNetwork::setWapiPskInternal(const std::vector<uint8_t> &psk)
+{
+#ifdef CONFIG_WAPI_INTERFACE
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ str_clear_free(wpa_ssid->passphrase);
+ wpa_ssid->passphrase = nullptr;
+
+ dummyWapiPsk = psk;
+
+ wpa_ssid->psk_set = 1;
+ resetInternalStateAfterParamsUpdate();
+ return {SupplicantStatusCode::SUCCESS, "Dummy implementation"};
+#else
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, "Not implemented"};
+#endif
+}
+
std::pair<SupplicantStatus, std::vector<uint8_t>> StaNetwork::getSsidInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
@@ -1321,18 +1476,12 @@
std::pair<SupplicantStatus, uint32_t> StaNetwork::getKeyMgmtInternal()
{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- uint32_t key_mgmt_mask = wpa_ssid->key_mgmt & kAllowedKeyMgmtMask;
-
- resetFastTransitionKeyMgmt(key_mgmt_mask);
- return {{SupplicantStatusCode::SUCCESS, ""}, key_mgmt_mask};
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"}, 0};
}
std::pair<SupplicantStatus, uint32_t> StaNetwork::getProtoInternal()
{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""},
- wpa_ssid->proto & kAllowedProtoMask};
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"}, 0};
}
std::pair<SupplicantStatus, uint32_t> StaNetwork::getAuthAlgInternal()
@@ -1344,21 +1493,40 @@
std::pair<SupplicantStatus, uint32_t> StaNetwork::getGroupCipherInternal()
{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""},
- wpa_ssid->group_cipher & kAllowedGroupCipherMask};
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"}, 0};
}
std::pair<SupplicantStatus, uint32_t> StaNetwork::getPairwiseCipherInternal()
{
- struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""},
- wpa_ssid->pairwise_cipher & kAllowedPairwisewCipherMask};
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, "deprecated"}, 0};
}
std::pair<SupplicantStatus, std::string> StaNetwork::getPskPassphraseInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+#ifdef CONFIG_WAPI_INTERFACE
+ if (wpa_ssid->key_mgmt & WPA_KEY_MGMT_WAPI_PSK) {
+ if (wpa_ssid->psk_set) {
+ std::pair<SupplicantStatus, std::vector<uint8_t>> ret = getWapiPskInternal();
+ std::string psk;
+ char buf[3] = {0};
+ for (int i = 0; i < ret.second.size(); i++) {
+ snprintf(buf, sizeof(buf), "%02x", ret.second[i]);
+ psk.append(buf);
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, psk};
+ } else {
+ if (!wpa_ssid->passphrase) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ std::string passphrase;
+ passphrase.append("\"");
+ passphrase.append(wpa_ssid->passphrase);
+ passphrase.append("\"");
+ return {{SupplicantStatusCode::SUCCESS, ""}, passphrase};
+ }
+ }
+#endif
if (!wpa_ssid->passphrase) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
@@ -1438,7 +1606,7 @@
// 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));
+ static_cast<enum eap_type>(wpa_ssid->eap.eap_methods[0].method));
size_t eap_method_idx =
std::find(
std::begin(kEapMethodStrings), std::end(kEapMethodStrings),
@@ -1532,89 +1700,89 @@
std::pair<SupplicantStatus, std::string> StaNetwork::getEapCACertInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.ca_cert) {
+ if (!wpa_ssid->eap.cert.ca_cert) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
return {{SupplicantStatusCode::SUCCESS, ""},
- reinterpret_cast<char *>(wpa_ssid->eap.ca_cert)};
+ reinterpret_cast<char *>(wpa_ssid->eap.cert.ca_cert)};
}
std::pair<SupplicantStatus, std::string> StaNetwork::getEapCAPathInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.ca_path) {
+ if (!wpa_ssid->eap.cert.ca_path) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
return {{SupplicantStatusCode::SUCCESS, ""},
- reinterpret_cast<char *>(wpa_ssid->eap.ca_path)};
+ reinterpret_cast<char *>(wpa_ssid->eap.cert.ca_path)};
}
std::pair<SupplicantStatus, std::string> StaNetwork::getEapClientCertInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.client_cert) {
+ if (!wpa_ssid->eap.cert.client_cert) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
return {{SupplicantStatusCode::SUCCESS, ""},
- reinterpret_cast<char *>(wpa_ssid->eap.client_cert)};
+ reinterpret_cast<char *>(wpa_ssid->eap.cert.client_cert)};
}
std::pair<SupplicantStatus, std::string>
StaNetwork::getEapPrivateKeyIdInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.key_id) {
+ if (!wpa_ssid->eap.cert.key_id) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
- return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->eap.key_id};
+ return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->eap.cert.key_id};
}
std::pair<SupplicantStatus, std::string>
StaNetwork::getEapSubjectMatchInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.subject_match) {
+ if (!wpa_ssid->eap.cert.subject_match) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
return {{SupplicantStatusCode::SUCCESS, ""},
- reinterpret_cast<char *>(wpa_ssid->eap.subject_match)};
+ reinterpret_cast<char *>(wpa_ssid->eap.cert.subject_match)};
}
std::pair<SupplicantStatus, std::string>
StaNetwork::getEapAltSubjectMatchInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.altsubject_match) {
+ if (!wpa_ssid->eap.cert.altsubject_match) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
return {{SupplicantStatusCode::SUCCESS, ""},
- reinterpret_cast<char *>(wpa_ssid->eap.altsubject_match)};
+ reinterpret_cast<char *>(wpa_ssid->eap.cert.altsubject_match)};
}
std::pair<SupplicantStatus, bool> StaNetwork::getEapEngineInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->eap.engine == 1};
+ return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->eap.cert.engine == 1};
}
std::pair<SupplicantStatus, std::string> StaNetwork::getEapEngineIDInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.engine_id) {
+ if (!wpa_ssid->eap.cert.engine_id) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
- return {{SupplicantStatusCode::SUCCESS, ""}, {wpa_ssid->eap.engine_id}};
+ return {{SupplicantStatusCode::SUCCESS, ""}, {wpa_ssid->eap.cert.engine_id}};
}
std::pair<SupplicantStatus, std::string>
StaNetwork::getEapDomainSuffixMatchInternal()
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
- if (!wpa_ssid->eap.domain_suffix_match) {
+ if (!wpa_ssid->eap.cert.domain_suffix_match) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
return {{SupplicantStatusCode::SUCCESS, ""},
- {wpa_ssid->eap.domain_suffix_match}};
+ {wpa_ssid->eap.cert.domain_suffix_match}};
}
std::pair<SupplicantStatus, std::string> StaNetwork::getIdStrInternal()
@@ -1640,6 +1808,24 @@
misc_utils::convertWpaBufToVector(token_buf.get())};
}
+std::pair<SupplicantStatus, std::string> StaNetwork::getWapiCertSuiteInternal()
+{
+#ifdef CONFIG_WAPI_INTERFACE
+ return {{SupplicantStatusCode::SUCCESS, "Dummy implementation"}, dummyWapiCertSuite};
+#else
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, "Not implemented"}, {}};
+#endif
+}
+
+std::pair<SupplicantStatus, std::vector<uint8_t>> StaNetwork::getWapiPskInternal()
+{
+#ifdef CONFIG_WAPI_INTERFACE
+ return {{SupplicantStatusCode::SUCCESS, "Dummy implementation"}, dummyWapiPsk};
+#else
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, "Not implemented"}, {}};
+#endif
+}
+
SupplicantStatus StaNetwork::enableInternal(bool no_connect)
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
@@ -1677,9 +1863,6 @@
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
wpa_s->scan_min_time.sec = 0;
wpa_s->scan_min_time.usec = 0;
- // Make sure that the supplicant is updated to the latest
- // MAC address, which might have changed due to MAC randomization.
- wpa_supplicant_update_mac_addr(wpa_s);
wpa_supplicant_select_network(wpa_s, wpa_ssid);
return {SupplicantStatusCode::SUCCESS, ""};
}
@@ -1947,6 +2130,126 @@
wpa_ssid->group_mgmt_cipher & kAllowedGroupMgmtCipherMask};
}
+SupplicantStatus StaNetwork::setOcspInternal(OcspType ocspType) {
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (ocspType < OcspType::NONE || ocspType > OcspType::REQUIRE_ALL_CERTS_STATUS) {
+ return{ SupplicantStatusCode::FAILURE_ARGS_INVALID, "" };
+ }
+ wpa_ssid->eap.cert.ocsp = (int) ocspType;
+ wpa_printf(
+ MSG_MSGDUMP, "ocsp: %d", wpa_ssid->eap.cert.ocsp);
+ resetInternalStateAfterParamsUpdate();
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+std::pair<SupplicantStatus, OcspType> StaNetwork::getOcspInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ (OcspType) wpa_ssid->eap.cert.ocsp};
+}
+
+SupplicantStatus StaNetwork::setPmkCacheInternal(const std::vector<uint8_t>& serializedEntry) {
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ struct rsn_pmksa_cache_entry *new_entry = NULL;
+
+ new_entry = (struct rsn_pmksa_cache_entry *) os_zalloc(sizeof(*new_entry));
+ if (!new_entry) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, "Allocating memory failed"};
+ }
+
+ std::stringstream ss(
+ std::stringstream::in | std::stringstream::out | std::stringstream::binary);
+ ss.write((char *) serializedEntry.data(), std::streamsize(serializedEntry.size()));
+ misc_utils::deserializePmkCacheEntry(ss, new_entry);
+ new_entry->network_ctx = wpa_ssid;
+ wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, new_entry);
+
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setKeyMgmt_1_3Internal(uint32_t key_mgmt_mask)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ 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();
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+std::pair<SupplicantStatus, uint32_t> StaNetwork::getKeyMgmt_1_3Internal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ uint32_t key_mgmt_mask = wpa_ssid->key_mgmt & kAllowedKeyMgmtMask;
+
+ resetFastTransitionKeyMgmt(key_mgmt_mask);
+ return {{SupplicantStatusCode::SUCCESS, ""}, key_mgmt_mask};
+}
+
+SupplicantStatus StaNetwork::setProto_1_3Internal(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, ""};
+}
+
+std::pair<SupplicantStatus, uint32_t> StaNetwork::getProto_1_3Internal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ wpa_ssid->proto & kAllowedProtoMask};
+}
+
+SupplicantStatus StaNetwork::setGroupCipher_1_3Internal(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, ""};
+}
+
+std::pair<SupplicantStatus, uint32_t> StaNetwork::getGroupCipher_1_3Internal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ wpa_ssid->group_cipher & kAllowedGroupCipherMask};
+}
+
+SupplicantStatus StaNetwork::setPairwiseCipher_1_3Internal(
+ 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, ""};
+}
+
+std::pair<SupplicantStatus, uint32_t> StaNetwork::getPairwiseCipher_1_3Internal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ wpa_ssid->pairwise_cipher & kAllowedPairwisewCipherMask};
+}
+
/**
* Retrieve the underlying |wpa_ssid| struct pointer for
* this network.
@@ -2154,8 +2457,24 @@
key_mgmt_mask &= ~WPA_KEY_MGMT_FT_IEEE8021X;
}
}
+
+/**
+ * Helper function to enable erp keys generation while connecting to FILS
+ * enabled APs.
+ */
+SupplicantStatus StaNetwork::setEapErpInternal(bool enable)
+{
+#ifdef CONFIG_FILS
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ wpa_ssid->eap.erp = enable ? 1 : 0;
+ return {SupplicantStatusCode::SUCCESS, ""};
+#else /* CONFIG_FILS */
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+#endif /* CONFIG_FILS */
+}
+
} // namespace implementation
-} // namespace V1_2
+} // namespace V1_3
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.2/sta_network.h b/wpa_supplicant/hidl/1.3/sta_network.h
similarity index 86%
rename from wpa_supplicant/hidl/1.2/sta_network.h
rename to wpa_supplicant/hidl/1.3/sta_network.h
index 16d065e..0057596 100644
--- a/wpa_supplicant/hidl/1.2/sta_network.h
+++ b/wpa_supplicant/hidl/1.3/sta_network.h
@@ -15,7 +15,7 @@
#include <android-base/macros.h>
-#include <android/hardware/wifi/supplicant/1.2/ISupplicantStaNetwork.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetworkCallback.h>
extern "C"
@@ -34,17 +34,18 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_2 {
+namespace V1_3 {
namespace implementation {
-using namespace android::hardware::wifi::supplicant::V1_0;
-using namespace android::hardware::wifi::supplicant::V1_1;
+using V1_0::ISupplicantStaNetworkCallback;
+using V1_2::DppFailureCode;
+using V1_2::DppProgressCode;
/**
* 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_2::ISupplicantStaNetwork
+class StaNetwork : public V1_3::ISupplicantStaNetwork
{
public:
StaNetwork(
@@ -225,6 +226,36 @@
Return<void> setSaePasswordId(
const hidl_string& sae_password_id,
setSaePasswordId_cb _hidl_cb) override;
+ Return<void> setOcsp(
+ OcspType ocspType, setOcsp_cb _hidl_cb) override;
+ Return<void> getOcsp(
+ getOcsp_cb _hidl_cb) override;
+ Return<void> setPmkCache(const hidl_vec<uint8_t>& serializedEntry,
+ setPmkCache_cb _hidl_cb) override;
+ Return<void> setKeyMgmt_1_3(
+ uint32_t key_mgmt_mask, setKeyMgmt_1_3_cb _hidl_cb) override;
+ Return<void> getKeyMgmt_1_3(getKeyMgmt_1_3_cb _hidl_cb) override;
+ Return<void> setProto_1_3(
+ uint32_t proto_mask, setProto_cb _hidl_cb) override;
+ Return<void> getProto_1_3(getProto_cb _hidl_cb) override;
+ Return<void> setPairwiseCipher_1_3(
+ uint32_t pairwise_cipher_mask,
+ setPairwiseCipher_1_3_cb _hidl_cb) override;
+ Return<void> getPairwiseCipher_1_3(
+ getPairwiseCipher_1_3_cb _hidl_cb) override;
+ Return<void> setGroupCipher_1_3(
+ uint32_t group_cipher_mask,
+ setGroupCipher_1_3_cb _hidl_cb) override;
+ Return<void> getGroupCipher_1_3(
+ getGroupCipher_1_3_cb _hidl_cb) override;
+ Return<void> setWapiCertSuite(
+ const hidl_string& suite, setWapiCertSuite_cb _hidl_cb) override;
+ Return<void> getWapiCertSuite(getWapiCertSuite_cb _hidl_cb) override;
+ Return<void> getAuthAlg_1_3(getAuthAlg_cb _hidl_cb) override;
+ Return<void> setAuthAlg_1_3(uint32_t auth_alg_mask,
+ std::function<void(const SupplicantStatus &status)> _hidl_cb)
+ override;
+ Return<void> setEapErp(bool enable, setEapErp_cb _hidl_cb) override;
private:
// Corresponding worker functions for the HIDL methods.
@@ -341,6 +372,22 @@
const std::string& sae_password_id);
SupplicantStatus setGroupMgmtCipherInternal(uint32_t group_mgmt_cipher_mask);
std::pair<SupplicantStatus, uint32_t> getGroupMgmtCipherInternal();
+ SupplicantStatus setOcspInternal(OcspType ocspType);
+ std::pair<SupplicantStatus, OcspType> getOcspInternal();
+ SupplicantStatus setPmkCacheInternal(const std::vector<uint8_t>& serialziedEntry);
+ SupplicantStatus setWapiCertSuiteInternal(const std::string& suite);
+ std::pair<SupplicantStatus, std::string> getWapiCertSuiteInternal();
+ SupplicantStatus setKeyMgmt_1_3Internal(uint32_t key_mgmt_mask);
+ std::pair<SupplicantStatus, uint32_t> getKeyMgmt_1_3Internal();
+ SupplicantStatus setProto_1_3Internal(uint32_t proto_mask);
+ std::pair<SupplicantStatus, uint32_t> getProto_1_3Internal();
+ std::pair<SupplicantStatus, uint32_t> getGroupCipher_1_3Internal();
+ SupplicantStatus setGroupCipher_1_3Internal(uint32_t group_cipher_mask);
+ std::pair<SupplicantStatus, uint32_t> getPairwiseCipher_1_3Internal();
+ SupplicantStatus setPairwiseCipher_1_3Internal(
+ uint32_t pairwise_cipher_mask);
+ SupplicantStatus setWapiPskInternal(const std::vector<uint8_t>& psk);
+ std::pair<SupplicantStatus, std::vector<uint8_t>> getWapiPskInternal();
struct wpa_ssid* retrieveNetworkPtr();
struct wpa_supplicant* retrieveIfacePtr();
@@ -365,6 +412,7 @@
const char* hexdump_prefix);
void setFastTransitionKeyMgmt(uint32_t &key_mgmt_mask);
void resetFastTransitionKeyMgmt(uint32_t &key_mgmt_mask);
+ SupplicantStatus setEapErpInternal(bool enable);
// Reference to the global wpa_struct. This is assumed to be valid
// for the lifetime of the process.
@@ -379,7 +427,7 @@
};
} // namespace implementation
-} // namespace V1_2
+} // namespace V1_3
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.2/supplicant.cpp b/wpa_supplicant/hidl/1.3/supplicant.cpp
similarity index 98%
rename from wpa_supplicant/hidl/1.2/supplicant.cpp
rename to wpa_supplicant/hidl/1.3/supplicant.cpp
index 9342ace..50d2343 100644
--- a/wpa_supplicant/hidl/1.2/supplicant.cpp
+++ b/wpa_supplicant/hidl/1.3/supplicant.cpp
@@ -16,7 +16,6 @@
#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.
@@ -157,9 +156,10 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_2 {
+namespace V1_3 {
namespace implementation {
using hidl_return_util::validateAndCall;
+using V1_0::SupplicantStatusCode;
Supplicant::Supplicant(struct wpa_global* global) : wpa_global_(global) {}
bool Supplicant::isValid()
@@ -353,7 +353,7 @@
wpa_s->conf->persistent_reconnect = true;
return {{SupplicantStatusCode::SUCCESS, ""}, iface};
} else {
- android::sp<ISupplicantStaIface> iface;
+ android::sp<V1_1::ISupplicantStaIface> iface;
if (!hidl_manager ||
hidl_manager->getStaIfaceHidlObjectByIfname(
wpa_s->ifname, &iface)) {
@@ -417,7 +417,7 @@
return SupplicantStatus{SupplicantStatusCode::SUCCESS, ""};
}
} // namespace implementation
-} // namespace V1_2
+} // namespace V1_3
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hidl/1.2/supplicant.h b/wpa_supplicant/hidl/1.3/supplicant.h
similarity index 93%
rename from wpa_supplicant/hidl/1.2/supplicant.h
rename to wpa_supplicant/hidl/1.3/supplicant.h
index 8985854..0c0ac72 100644
--- a/wpa_supplicant/hidl/1.2/supplicant.h
+++ b/wpa_supplicant/hidl/1.3/supplicant.h
@@ -13,7 +13,7 @@
#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/hardware/wifi/supplicant/1.3/ISupplicant.h>
#include <android-base/macros.h>
#include <hidl/Status.h>
@@ -29,16 +29,17 @@
namespace hardware {
namespace wifi {
namespace supplicant {
-namespace V1_2 {
+namespace V1_3 {
namespace implementation {
-using namespace android::hardware::wifi::supplicant::V1_0;
+using V1_0::ISupplicantCallback;
+using V1_0::ISupplicantIface;
/**
* Implementation of the supplicant hidl object. This hidl
* object is used core for global control operations on
* wpa_supplicant.
*/
-class Supplicant : public V1_2::ISupplicant
+class Supplicant : public V1_3::ISupplicant
{
public:
Supplicant(struct wpa_global* global);
@@ -92,7 +93,7 @@
};
} // namespace implementation
-} // namespace V1_2
+} // namespace V1_3
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index e81fef1..ce5608e 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -289,7 +289,8 @@
if (buf == NULL)
return -1;
- res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, anqp_resp_cb, wpa_s);
+ res = gas_query_req(wpa_s->gas, dst, freq, 0, 0, buf, anqp_resp_cb,
+ wpa_s);
if (res < 0) {
wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
wpabuf_free(buf);
@@ -341,7 +342,7 @@
{
struct icon_entry *icon;
size_t out_size;
- unsigned char *b64;
+ char *b64;
size_t b64_size;
int reply_size;
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index e96ea65..02e6390 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -64,10 +64,16 @@
{
struct ibss_rsn_peer *peer = ctx;
struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s;
+ int encrypt = peer->authentication_status & IBSS_RSN_REPORTED_PTK;
- wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x "
- "len=%lu)",
- __func__, MAC2STR(dest), proto, (unsigned long) len);
+ wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR
+ " proto=0x%04x len=%lu no_encrypt=%d)",
+ __func__, MAC2STR(dest), proto, (unsigned long) len,
+ !encrypt);
+
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT)
+ return wpa_drv_tx_control_port(wpa_s, dest, proto, buf, len,
+ !encrypt);
if (wpa_s->l2)
return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
@@ -111,6 +117,7 @@
wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
/* TODO: get correct RSN IE */
+ wpa_sm_set_ap_rsnxe(peer->supp, NULL, 0);
return wpa_sm_set_ap_rsn_ie(peer->supp,
(u8 *) "\x30\x14\x01\x00"
"\x00\x0f\xac\x04"
@@ -139,7 +146,7 @@
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)
+ const u8 *key, size_t key_len, enum key_flag key_flag)
{
struct ibss_rsn_peer *peer = ctx;
@@ -166,7 +173,7 @@
if (is_broadcast_ether_addr(addr))
addr = peer->addr;
return wpa_drv_set_key(peer->ibss_rsn->wpa_s, alg, addr, key_idx,
- set_tx, seq, seq_len, key, key_len);
+ set_tx, seq, seq_len, key, key_len, key_flag);
}
@@ -193,7 +200,13 @@
}
-static void supp_deauthenticate(void * ctx, int reason_code)
+static void supp_deauthenticate(void *ctx, u16 reason_code)
+{
+ wpa_printf(MSG_DEBUG, "SUPP: %s (TODO)", __func__);
+}
+
+
+static void supp_reconnect(void *ctx)
{
wpa_printf(MSG_DEBUG, "SUPP: %s (TODO)", __func__);
}
@@ -218,6 +231,7 @@
ctx->mlme_setprotection = supp_mlme_setprotection;
ctx->cancel_auth_timeout = supp_cancel_auth_timeout;
ctx->deauthenticate = supp_deauthenticate;
+ ctx->reconnect = supp_reconnect;
peer->supp = wpa_sm_init(ctx);
if (peer->supp == NULL) {
wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
@@ -286,6 +300,10 @@
"encrypt=%d)",
__func__, MAC2STR(addr), (unsigned long) data_len, encrypt);
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT)
+ return wpa_drv_tx_control_port(wpa_s, addr, ETH_P_EAPOL,
+ data, data_len, !encrypt);
+
if (wpa_s->l2)
return l2_packet_send(wpa_s->l2, addr, ETH_P_EAPOL, data,
data_len);
@@ -295,7 +313,8 @@
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)
+ const u8 *addr, int idx, u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
struct ibss_rsn *ibss_rsn = ctx;
u8 seq[6];
@@ -334,7 +353,7 @@
}
return wpa_drv_set_key(ibss_rsn->wpa_s, alg, addr, idx,
- 1, seq, 6, key, key_len);
+ 1, seq, 6, key, key_len, key_flag);
}
@@ -464,7 +483,7 @@
"\x00\x0f\xac\x04"
"\x01\x00\x00\x0f\xac\x04"
"\x01\x00\x00\x0f\xac\x02"
- "\x00\x00", 22, NULL, 0, NULL, 0) !=
+ "\x00\x00", 22, NULL, 0, NULL, 0, NULL, 0) !=
WPA_IE_OK) {
wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
return -1;
@@ -486,9 +505,6 @@
const size_t auth_length = IEEE80211_HDRLEN + sizeof(auth.u.auth);
struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s;
- if (wpa_s->driver->send_frame == NULL)
- return -1;
-
os_memset(&auth, 0, sizeof(auth));
auth.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@@ -504,8 +520,7 @@
wpa_printf(MSG_DEBUG, "RSN: IBSS TX Auth frame (SEQ %d) to " MACSTR,
seq, MAC2STR(da));
- return wpa_s->driver->send_frame(wpa_s->drv_priv, (u8 *) &auth,
- auth_length, 0);
+ return wpa_drv_send_mlme(wpa_s, (u8 *) &auth, auth_length, 0, 0, 0);
}
@@ -851,7 +866,7 @@
wpa_printf(MSG_DEBUG, "RSN: Clear pairwise key for peer "
MACSTR, MAC2STR(addr));
wpa_drv_set_key(ibss_rsn->wpa_s, WPA_ALG_NONE, addr, 0, 0,
- NULL, 0, NULL, 0);
+ NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE);
}
if (peer &&
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index c66a09b..c16c2a9 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -176,7 +176,7 @@
continue;
if (!cred->eap_method)
return 1;
- if (cred->realm && cred->roaming_consortium_len == 0)
+ if (cred->realm)
return 1;
}
return 0;
@@ -316,7 +316,7 @@
if (buf == NULL)
return -1;
- res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, 0, buf,
+ res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, 0, 0, buf,
interworking_anqp_resp_cb, wpa_s);
if (res < 0) {
wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request");
@@ -1388,11 +1388,18 @@
cred->num_roaming_consortiums == 0)
continue;
+ if (!cred->eap_method)
+ continue;
+
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))
+ !cred_roaming_consortiums_match(ie, anqp, cred) &&
+ (cred->required_roaming_consortium_len == 0 ||
+ !roaming_consortium_match(
+ ie, anqp, cred->required_roaming_consortium,
+ cred->required_roaming_consortium_len)))
continue;
if (cred_no_required_oi_match(cred, bss))
@@ -1547,7 +1554,7 @@
cred->domain_suffix_match) < 0)
return -1;
- ssid->eap.ocsp = cred->ocsp;
+ ssid->eap.cert.ocsp = cred->ocsp;
return 0;
}
@@ -2255,7 +2262,7 @@
realm++;
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Search for match with SIM/USIM domain %s",
- realm);
+ realm ? realm : "[NULL]");
if (realm &&
domain_name_list_contains(domain_names, realm, 1))
return 1;
@@ -2669,7 +2676,8 @@
found++;
bss->flags |= WPA_BSS_ANQP_FETCH_TRIED;
wpa_msg(wpa_s, MSG_INFO, "Starting ANQP fetch for "
- MACSTR, MAC2STR(bss->bssid));
+ MACSTR " (HESSID " MACSTR ")",
+ MAC2STR(bss->bssid), MAC2STR(bss->hessid));
interworking_anqp_send_req(wpa_s, bss);
break;
}
@@ -2796,7 +2804,8 @@
if (buf == NULL)
return -1;
- res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, anqp_resp_cb, wpa_s);
+ res = gas_query_req(wpa_s->gas, dst, freq, 0, 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);
@@ -3236,7 +3245,8 @@
} else
wpabuf_put_le16(buf, 0);
- res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, gas_resp_cb, wpa_s);
+ res = gas_query_req(wpa_s->gas, dst, freq, 0, 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/mbo.c b/wpa_supplicant/mbo.c
index 43b1fa7..8ac73ef 100644
--- a/wpa_supplicant/mbo.c
+++ b/wpa_supplicant/mbo.c
@@ -15,6 +15,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/gas.h"
+#include "rsn_supp/wpa.h"
#include "config.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
@@ -82,6 +83,35 @@
}
+void wpas_mbo_check_pmf(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ struct wpa_ssid *ssid)
+{
+ const u8 *rsne, *mbo, *oce;
+ struct wpa_ie_data ie;
+
+ wpa_s->disable_mbo_oce = 0;
+ if (!bss)
+ return;
+ mbo = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND);
+ oce = wpas_mbo_get_bss_attr(bss, OCE_ATTR_ID_CAPA_IND);
+ if (!mbo && !oce)
+ return;
+ if (oce && oce[1] >= 1 && (oce[2] & OCE_IS_STA_CFON))
+ return; /* STA-CFON is not required to enable PMF */
+ rsne = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ if (!rsne || wpa_parse_wpa_ie(rsne, 2 + rsne[1], &ie) < 0)
+ return; /* AP is not using RSN */
+
+ if (!(ie.capabilities & WPA_CAPABILITY_MFPC))
+ wpa_s->disable_mbo_oce = 1; /* AP uses RSN without PMF */
+ if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION)
+ wpa_s->disable_mbo_oce = 1; /* STA uses RSN without PMF */
+ if (wpa_s->disable_mbo_oce)
+ wpa_printf(MSG_INFO,
+ "MBO: Disable MBO/OCE due to misbehaving AP not having enabled PMF");
+}
+
+
static void wpas_mbo_non_pref_chan_attr_body(struct wpa_supplicant *wpa_s,
struct wpabuf *mbo,
u8 start, u8 end)
@@ -434,9 +464,8 @@
void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie,
size_t len)
{
- const u8 *pos, *cell_pref = NULL;
+ const u8 *pos;
u8 id, elen;
- u16 disallowed_sec = 0;
if (len <= 4 || WPA_GET_BE24(mbo_ie) != OUI_WFA ||
mbo_ie[3] != MBO_OUI_TYPE)
@@ -459,11 +488,14 @@
goto fail;
if (wpa_s->conf->mbo_cell_capa ==
- MBO_CELL_CAPA_AVAILABLE)
- cell_pref = pos;
- else
+ MBO_CELL_CAPA_AVAILABLE) {
+ wpa_s->wnm_mbo_cell_pref_present = 1;
+ wpa_s->wnm_mbo_cell_preference = *pos;
+ } else {
wpa_printf(MSG_DEBUG,
- "MBO: Station does not support Cellular data connection");
+ "MBO: Station does not support "
+ "Cellular data connection");
+ }
break;
case MBO_ATTR_ID_TRANSITION_REASON:
if (elen != 1)
@@ -479,17 +511,20 @@
if (wpa_s->wnm_mode &
WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
wpa_printf(MSG_DEBUG,
- "MBO: Unexpected association retry delay, BSS is terminating");
+ "MBO: Unexpected association retry delay, "
+ "BSS is terminating");
goto fail;
} else if (wpa_s->wnm_mode &
WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
- disallowed_sec = WPA_GET_LE16(pos);
+ wpa_s->wnm_mbo_assoc_retry_delay_present = 1;
+ wpa_s->wnm_mbo_assoc_retry_delay_sec = WPA_GET_LE16(pos);
wpa_printf(MSG_DEBUG,
"MBO: Association retry delay: %u",
- disallowed_sec);
+ wpa_s->wnm_mbo_assoc_retry_delay_sec);
} else {
wpa_printf(MSG_DEBUG,
- "MBO: Association retry delay attribute not in disassoc imminent mode");
+ "MBO: Association retry delay attribute "
+ "not in disassoc imminent mode");
}
break;
@@ -512,17 +547,17 @@
len -= elen;
}
- if (cell_pref)
+ if (wpa_s->wnm_mbo_cell_pref_present)
wpa_msg(wpa_s, MSG_INFO, MBO_CELL_PREFERENCE "preference=%u",
- *cell_pref);
+ wpa_s->wnm_mbo_cell_preference);
if (wpa_s->wnm_mbo_trans_reason_present)
wpa_msg(wpa_s, MSG_INFO, MBO_TRANSITION_REASON "reason=%u",
wpa_s->wnm_mbo_transition_reason);
- if (disallowed_sec && wpa_s->current_bss)
+ if (wpa_s->wnm_mbo_assoc_retry_delay_sec && wpa_s->current_bss)
wpa_bss_tmp_disallow(wpa_s, wpa_s->current_bss->bssid,
- disallowed_sec, 0);
+ wpa_s->wnm_mbo_assoc_retry_delay_sec, 0);
return;
fail:
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 9260021..c085466 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -86,7 +86,6 @@
MESH_CONF_SEC_AMPE;
else
conf->security |= MESH_CONF_SEC_NONE;
-#ifdef CONFIG_IEEE80211W
conf->ieee80211w = ssid->ieee80211w;
if (conf->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
if (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)
@@ -94,7 +93,6 @@
else
conf->ieee80211w = NO_MGMT_FRAME_PROTECTION;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
conf->ocv = ssid->ocv;
#endif /* CONFIG_OCV */
@@ -116,8 +114,14 @@
}
conf->group_cipher = cipher;
- if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
- conf->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ if (ssid->group_mgmt_cipher == WPA_CIPHER_BIP_GMAC_128 ||
+ ssid->group_mgmt_cipher == WPA_CIPHER_BIP_GMAC_256 ||
+ ssid->group_mgmt_cipher == WPA_CIPHER_BIP_CMAC_256)
+ conf->mgmt_group_cipher = ssid->group_mgmt_cipher;
+ else
+ conf->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
+ }
/* defaults */
conf->mesh_pp_id = MESH_PATH_PROTOCOL_HWMP;
@@ -208,6 +212,7 @@
wpa_printf(MSG_ERROR,
"mesh: RSN initialization failed - deinit mesh");
wpa_supplicant_mesh_deinit(wpa_s);
+ wpa_drv_leave_mesh(wpa_s);
return -1;
}
@@ -263,6 +268,7 @@
return -ENOMEM;
ifmsh->drv_flags = wpa_s->drv_flags;
+ ifmsh->drv_flags2 = wpa_s->drv_flags2;
ifmsh->num_bss = 1;
ifmsh->bss = os_calloc(wpa_s->ifmsh->num_bss,
sizeof(struct hostapd_data *));
@@ -333,14 +339,14 @@
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:
+ case CHANWIDTH_80MHZ:
+ case CHANWIDTH_80P80MHZ:
ieee80211_freq_to_chan(
frequency,
&conf->vht_oper_centr_freq_seg0_idx);
conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
break;
- case VHT_CHANWIDTH_160MHZ:
+ case CHANWIDTH_160MHZ:
ieee80211_freq_to_chan(
frequency,
&conf->vht_oper_centr_freq_seg0_idx);
@@ -455,6 +461,7 @@
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;
+ wpa_s->mesh_he_enabled = !!params->freq.he_enabled;
if (params->freq.ht_enabled && params->freq.sec_channel_offset)
ssid->ht40 = params->freq.sec_channel_offset;
@@ -464,21 +471,23 @@
switch (params->freq.bandwidth) {
case 80:
if (params->freq.center_freq2) {
- ssid->max_oper_chwidth = VHT_CHANWIDTH_80P80MHZ;
+ ssid->max_oper_chwidth = CHANWIDTH_80P80MHZ;
ssid->vht_center_freq2 =
params->freq.center_freq2;
} else {
- ssid->max_oper_chwidth = VHT_CHANWIDTH_80MHZ;
+ ssid->max_oper_chwidth = CHANWIDTH_80MHZ;
}
break;
case 160:
- ssid->max_oper_chwidth = VHT_CHANWIDTH_160MHZ;
+ ssid->max_oper_chwidth = CHANWIDTH_160MHZ;
break;
default:
- ssid->max_oper_chwidth = VHT_CHANWIDTH_USE_HT;
+ ssid->max_oper_chwidth = CHANWIDTH_USE_HT;
break;
}
}
+ if (wpa_s->mesh_he_enabled)
+ ssid->he = 1;
if (ssid->beacon_int > 0)
params->beacon_int = ssid->beacon_int;
else if (wpa_s->conf->beacon_int > 0)
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 9d6ab8d..12aafcb 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -147,13 +147,13 @@
/* return true if elems from a neighbor match this MBSS */
-static Boolean matches_local(struct wpa_supplicant *wpa_s,
- struct ieee802_11_elems *elems)
+static bool matches_local(struct wpa_supplicant *wpa_s,
+ struct ieee802_11_elems *elems)
{
struct mesh_conf *mconf = wpa_s->ifmsh->mconf;
if (elems->mesh_config_len < 5)
- return FALSE;
+ return false;
return (mconf->meshid_len == elems->mesh_id_len &&
os_memcmp(mconf->meshid, elems->mesh_id,
@@ -167,17 +167,17 @@
/* check if local link id is already used with another peer */
-static Boolean llid_in_use(struct wpa_supplicant *wpa_s, u16 llid)
+static bool llid_in_use(struct wpa_supplicant *wpa_s, u16 llid)
{
struct sta_info *sta;
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
for (sta = hapd->sta_list; sta; sta = sta->next) {
if (sta->my_lid == llid)
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
@@ -231,20 +231,28 @@
2 + 32 + /* mesh ID */
2 + 7 + /* mesh config */
2 + 24 + /* peering management */
- 2 + 96 + /* AMPE */
+ 2 + 96 + 32 + 32 + /* AMPE (96 + max GTKlen + max IGTKlen) */
2 + 16; /* MIC */
-#ifdef CONFIG_IEEE80211N
if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) {
buf_len += 2 + 26 + /* HT capabilities */
2 + 22; /* HT operation */
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
if (type != PLINK_CLOSE && wpa_s->mesh_vht_enabled) {
buf_len += 2 + 12 + /* VHT Capabilities */
2 + 5; /* VHT Operation */
}
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ if (type != PLINK_CLOSE && wpa_s->mesh_he_enabled) {
+ buf_len += 3 +
+ HE_MAX_MAC_CAPAB_SIZE +
+ HE_MAX_PHY_CAPAB_SIZE +
+ HE_MAX_MCS_CAPAB_SIZE +
+ HE_MAX_PPET_CAPAB_SIZE;
+ buf_len += 3 + sizeof(struct ieee80211_he_operation);
+ }
+#endif /* CONFIG_IEEE80211AX */
if (type != PLINK_CLOSE)
buf_len += conf->rsn_ie_len; /* RSN IE */
#ifdef CONFIG_OCV
@@ -344,7 +352,6 @@
wpabuf_put(buf, PMKID_LEN));
}
-#ifdef CONFIG_IEEE80211N
if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) {
u8 ht_capa_oper[2 + 26 + 2 + 22];
@@ -352,7 +359,6 @@
pos = hostapd_eid_ht_operation(bss, pos);
wpabuf_put_data(buf, ht_capa_oper, pos - ht_capa_oper);
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
if (type != PLINK_CLOSE && wpa_s->mesh_vht_enabled) {
u8 vht_capa_oper[2 + 12 + 2 + 5];
@@ -362,6 +368,21 @@
wpabuf_put_data(buf, vht_capa_oper, pos - vht_capa_oper);
}
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ if (type != PLINK_CLOSE && wpa_s->mesh_he_enabled) {
+ u8 he_capa_oper[3 +
+ HE_MAX_MAC_CAPAB_SIZE +
+ HE_MAX_PHY_CAPAB_SIZE +
+ HE_MAX_MCS_CAPAB_SIZE +
+ HE_MAX_PPET_CAPAB_SIZE +
+ 3 + sizeof(struct ieee80211_he_operation)];
+
+ pos = hostapd_eid_he_capab(bss, he_capa_oper,
+ IEEE80211_MODE_MESH);
+ pos = hostapd_eid_he_operation(bss, pos);
+ wpabuf_put_data(buf, he_capa_oper, pos - he_capa_oper);
+ }
+#endif /* CONFIG_IEEE80211AX */
#ifdef CONFIG_OCV
if (type != PLINK_CLOSE && conf->ocv) {
@@ -671,9 +692,7 @@
struct mesh_conf *conf = wpa_s->ifmsh->mconf;
struct hostapd_data *data = wpa_s->ifmsh->bss[0];
struct sta_info *sta;
-#ifdef CONFIG_IEEE80211N
struct ieee80211_ht_operation *oper;
-#endif /* CONFIG_IEEE80211N */
int ret;
if (elems->mesh_config_len >= 7 &&
@@ -685,11 +704,12 @@
}
sta = ap_get_sta(data, addr);
- if (!sta) {
- sta = ap_sta_add(data, addr);
- if (!sta)
- return NULL;
- }
+ if (sta)
+ return NULL;
+
+ sta = ap_sta_add(data, addr);
+ if (!sta)
+ return NULL;
/* Set WMM by default since Mesh STAs are QoS STAs */
sta->flags |= WLAN_STA_WMM;
@@ -703,7 +723,6 @@
if (!sta->my_lid)
mesh_mpm_init_link(wpa_s, sta);
-#ifdef CONFIG_IEEE80211N
copy_sta_ht_capab(data, sta, elems->ht_capabilities);
oper = (struct ieee80211_ht_operation *) elems->ht_operation;
@@ -717,7 +736,6 @@
}
update_ht_state(data, sta);
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
copy_sta_vht_capab(data, sta, elems->vht_capabilities);
@@ -725,6 +743,11 @@
set_sta_vht_opmode(data, sta, elems->vht_opmode_notif);
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ copy_sta_he_capab(data, sta, IEEE80211_MODE_MESH,
+ elems->he_capabilities, elems->he_capabilities_len);
+#endif /* CONFIG_IEEE80211AX */
+
if (hostapd_get_aid(data, sta) < 0) {
wpa_msg(wpa_s, MSG_ERROR, "No AIDs available");
ap_free_sta(data, sta);
@@ -742,6 +765,8 @@
params.listen_interval = 100;
params.ht_capabilities = sta->ht_capabilities;
params.vht_capabilities = sta->vht_capabilities;
+ params.he_capab = sta->he_capab;
+ params.he_capab_len = sta->he_capab_len;
params.flags |= WPA_STA_WMM;
params.flags_mask |= WPA_STA_AUTHENTICATED;
if (conf->security == MESH_CONF_SEC_NONE) {
@@ -844,7 +869,8 @@
wpa_hexdump_key(MSG_DEBUG, "mesh: MTK", sta->mtk, sta->mtk_len);
wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->pairwise_cipher),
sta->addr, 0, 0, seq, sizeof(seq),
- sta->mtk, sta->mtk_len);
+ sta->mtk, sta->mtk_len,
+ KEY_FLAG_PAIRWISE_RX_TX);
wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK Key RSC",
sta->mgtk_rsc, sizeof(sta->mgtk_rsc));
@@ -853,7 +879,8 @@
wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->group_cipher),
sta->addr, sta->mgtk_key_id, 0,
sta->mgtk_rsc, sizeof(sta->mgtk_rsc),
- sta->mgtk, sta->mgtk_len);
+ sta->mgtk, sta->mgtk_len,
+ KEY_FLAG_GROUP_RX);
if (sta->igtk_len) {
wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK Key RSC",
@@ -865,7 +892,8 @@
wpa_cipher_to_alg(conf->mgmt_group_cipher),
sta->addr, sta->igtk_key_id, 0,
sta->igtk_rsc, sizeof(sta->igtk_rsc),
- sta->igtk, sta->igtk_len);
+ sta->igtk, sta->igtk_len,
+ KEY_FLAG_GROUP_RX);
}
}
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index 4b8d6c4..f19bfbf 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -100,7 +100,8 @@
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)
+ const u8 *addr, int idx, u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
struct mesh_rsn *mesh_rsn = ctx;
u8 seq[6];
@@ -118,7 +119,7 @@
wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len);
return wpa_drv_set_key(mesh_rsn->wpa_s, alg, addr, idx,
- 1, seq, 6, key, key_len);
+ 1, seq, 6, key, key_len, key_flag);
}
@@ -165,11 +166,9 @@
conf.wpa_group_rekey = -1;
conf.wpa_group_update_count = 4;
conf.wpa_pairwise_update_count = 4;
-#ifdef CONFIG_IEEE80211W
conf.ieee80211w = ieee80211w;
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 */
@@ -186,7 +185,6 @@
return -1;
rsn->mgtk_key_id = 1;
-#ifdef CONFIG_IEEE80211W
if (ieee80211w != NO_MGMT_FRAME_PROTECTION) {
rsn->igtk_len = wpa_cipher_key_len(conf.group_mgmt_cipher);
if (random_get_bytes(rsn->igtk, rsn->igtk_len) < 0)
@@ -199,16 +197,16 @@
wpa_drv_set_key(rsn->wpa_s,
wpa_cipher_to_alg(rsn->mgmt_group_cipher), NULL,
rsn->igtk_key_id, 1,
- seq, sizeof(seq), rsn->igtk, rsn->igtk_len);
+ seq, sizeof(seq), rsn->igtk, rsn->igtk_len,
+ KEY_FLAG_GROUP_TX_DEFAULT);
}
-#endif /* CONFIG_IEEE80211W */
/* group privacy / data frames */
wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX MGTK",
rsn->mgtk, rsn->mgtk_len);
wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher), NULL,
rsn->mgtk_key_id, 1, seq, sizeof(seq),
- rsn->mgtk, rsn->mgtk_len);
+ rsn->mgtk, rsn->mgtk_len, KEY_FLAG_GROUP_TX_DEFAULT);
return 0;
}
@@ -545,10 +543,8 @@
len = sizeof(*ampe);
if (cat[1] == PLINK_OPEN)
len += rsn->mgtk_len + WPA_KEY_RSC_LEN + 4;
-#ifdef CONFIG_IEEE80211W
if (cat[1] == PLINK_OPEN && rsn->igtk_len)
len += 2 + 6 + rsn->igtk_len;
-#endif /* CONFIG_IEEE80211W */
if (2 + AES_BLOCK_SIZE + 2 + len > wpabuf_tailroom(buf)) {
wpa_printf(MSG_ERROR, "protect frame: buffer too small");
@@ -591,7 +587,6 @@
WPA_PUT_LE32(pos, 0xffffffff);
pos += 4;
-#ifdef CONFIG_IEEE80211W
/*
* IGTKdata[variable]:
* Key ID[2], IPN[6], IGTK[variable]
@@ -603,7 +598,6 @@
pos += 6;
os_memcpy(pos, rsn->igtk, rsn->igtk_len);
}
-#endif /* CONFIG_IEEE80211W */
skip_keys:
wpa_hexdump_key(MSG_DEBUG, "mesh: Plaintext AMPE element",
@@ -774,7 +768,6 @@
WPA_GET_LE32(pos));
pos += 4;
-#ifdef CONFIG_IEEE80211W
/*
* IGTKdata[variable]:
* Key ID[2], IPN[6], IGTK[variable]
@@ -794,7 +787,6 @@
wpa_hexdump_key(MSG_DEBUG, "mesh: IGTKdata - IGTK",
sta->igtk, sta->igtk_len);
}
-#endif /* CONFIG_IEEE80211W */
free:
os_free(crypt);
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 41dc334..56eb62a 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -17,6 +17,7 @@
#include "dbus/dbus_new.h"
#include "rsn_supp/wpa.h"
#include "fst/fst.h"
+#include "crypto/tls.h"
#include "driver_i.h"
#include "scan.h"
#include "p2p_supplicant.h"
@@ -197,6 +198,10 @@
return;
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSS_TM_STATUS);
+
+#ifdef CONFIG_WNM
+ wpas_hidl_notify_bss_tm_status(wpa_s);
+#endif
}
@@ -857,42 +862,42 @@
}
-void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
- const char *subject, const char *altsubject[],
- int num_altsubject, const char *cert_hash,
- const struct wpabuf *cert)
+void wpas_notify_certification(struct wpa_supplicant *wpa_s,
+ struct tls_cert_data *cert,
+ const char *cert_hash)
{
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
- "depth=%d subject='%s'%s%s",
- depth, subject, cert_hash ? " hash=" : "",
- cert_hash ? cert_hash : "");
+ int i;
- if (cert) {
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
+ "depth=%d subject='%s'%s%s%s%s",
+ cert->depth, cert->subject, cert_hash ? " hash=" : "",
+ cert_hash ? cert_hash : "",
+ cert->tod == 2 ? " tod=2" : "",
+ cert->tod == 1 ? " tod=1" : "");
+
+ if (cert->cert) {
char *cert_hex;
- size_t len = wpabuf_len(cert) * 2 + 1;
+ size_t len = wpabuf_len(cert->cert) * 2 + 1;
cert_hex = os_malloc(len);
if (cert_hex) {
- wpa_snprintf_hex(cert_hex, len, wpabuf_head(cert),
- wpabuf_len(cert));
+ wpa_snprintf_hex(cert_hex, len, wpabuf_head(cert->cert),
+ wpabuf_len(cert->cert));
wpa_msg_ctrl(wpa_s, MSG_INFO,
WPA_EVENT_EAP_PEER_CERT
"depth=%d subject='%s' cert=%s",
- depth, subject, cert_hex);
+ cert->depth, cert->subject, cert_hex);
os_free(cert_hex);
}
}
- if (altsubject) {
- int i;
-
- for (i = 0; i < num_altsubject; i++)
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_ALT
- "depth=%d %s", depth, altsubject[i]);
- }
+ for (i = 0; i < cert->num_altsubject; i++)
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_ALT
+ "depth=%d %s", cert->depth, cert->altsubject[i]);
/* notify the new DBus API */
- wpas_dbus_signal_certification(wpa_s, depth, subject, altsubject,
- num_altsubject, cert_hash, cert);
+ wpas_dbus_signal_certification(wpa_s, cert->depth, cert->subject,
+ cert->altsubject, cert->num_altsubject,
+ cert_hash, cert->cert);
}
@@ -1024,7 +1029,7 @@
void wpas_notify_mesh_group_removed(struct wpa_supplicant *wpa_s,
const u8 *meshid, u8 meshid_len,
- int reason_code)
+ u16 reason_code)
{
if (wpa_s->p2p_mgmt)
return;
@@ -1045,7 +1050,7 @@
void wpas_notify_mesh_peer_disconnected(struct wpa_supplicant *wpa_s,
- const u8 *peer_addr, int reason_code)
+ const u8 *peer_addr, u16 reason_code)
{
if (wpa_s->p2p_mgmt)
return;
@@ -1163,3 +1168,42 @@
wpas_hidl_notify_dpp_fail(wpa_s);
#endif /* CONFIG_DPP */
}
+
+void wpas_notify_dpp_config_sent_wait_response(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_DPP2
+ wpas_hidl_notify_dpp_config_sent_wait_response(wpa_s);
+#endif /* CONFIG_DPP2 */
+}
+
+void wpas_notify_dpp_config_accepted(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_DPP2
+ wpas_hidl_notify_dpp_config_accepted(wpa_s);
+#endif /* CONFIG_DPP2 */
+}
+
+void wpas_notify_dpp_conn_status(struct wpa_supplicant *wpa_s,
+ enum dpp_status_error status, const char *ssid,
+ const char *channel_list, unsigned short band_list[], int size)
+{
+#ifdef CONFIG_DPP2
+ wpas_hidl_notify_dpp_conn_status(wpa_s, status, ssid, channel_list, band_list, size);
+#endif /* CONFIG_DPP2 */
+}
+
+void wpas_notify_dpp_config_rejected(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_DPP2
+ wpas_hidl_notify_dpp_config_rejected(wpa_s);
+#endif /* CONFIG_DPP2 */
+}
+
+void wpas_notify_pmk_cache_added(struct wpa_supplicant *wpa_s,
+ struct rsn_pmksa_cache_entry *entry)
+{
+ if (!wpa_s)
+ return;
+
+ wpas_hidl_notify_pmk_cache_added(wpa_s, entry);
+}
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 2f194ce..e9e39ee 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -11,10 +11,13 @@
#include "p2p/p2p.h"
#include "bss.h"
+#include "rsn_supp/pmksa_cache.h"
+#include "dpp.h"
struct wps_credential;
struct wps_event_m2d;
struct wps_event_fail;
+struct tls_cert_data;
int wpas_notify_supplicant_initialized(struct wpa_global *global);
void wpas_notify_supplicant_deinitialized(struct wpa_global *global);
@@ -134,10 +137,9 @@
void wpas_notify_p2p_wps_failed(struct wpa_supplicant *wpa_s,
struct wps_event_fail *fail);
-void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
- const char *subject, const char *altsubject[],
- int num_altsubject, const char *cert_hash,
- const struct wpabuf *cert);
+void wpas_notify_certification(struct wpa_supplicant *wpa_s,
+ struct tls_cert_data *cert,
+ const char *cert_hash);
void wpas_notify_preq(struct wpa_supplicant *wpa_s,
const u8 *addr, const u8 *dst, const u8 *bssid,
const u8 *ie, size_t ie_len, u32 ssi_signal);
@@ -155,11 +157,11 @@
struct wpa_ssid *ssid);
void wpas_notify_mesh_group_removed(struct wpa_supplicant *wpa_s,
const u8 *meshid, u8 meshid_len,
- int reason_code);
+ u16 reason_code);
void wpas_notify_mesh_peer_connected(struct wpa_supplicant *wpa_s,
const u8 *peer_addr);
void wpas_notify_mesh_peer_disconnected(struct wpa_supplicant *wpa_s,
- const u8 *peer_addr, int reason_code);
+ const u8 *peer_addr, u16 reason_code);
void wpas_notify_anqp_query_done(struct wpa_supplicant *wpa_s, const u8* bssid,
const char* result,
const struct wpa_bss_anqp *anqp);
@@ -183,5 +185,13 @@
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);
+void wpas_notify_dpp_config_sent_wait_response(struct wpa_supplicant *wpa_s);
+void wpas_notify_dpp_conn_status(struct wpa_supplicant *wpa_s,
+ enum dpp_status_error status, const char *ssid,
+ const char *channel_list, unsigned short band_list[], int size);
+void wpas_notify_dpp_config_accepted(struct wpa_supplicant *wpa_s);
+void wpas_notify_dpp_config_rejected(struct wpa_supplicant *wpa_s);
+void wpas_notify_pmk_cache_added(struct wpa_supplicant *wpa_s,
+ struct rsn_pmksa_cache_entry *entry);
#endif /* NOTIFY_H */
diff --git a/wpa_supplicant/offchannel.c b/wpa_supplicant/offchannel.c
index b74be7d..e40cf5b 100644
--- a/wpa_supplicant/offchannel.c
+++ b/wpa_supplicant/offchannel.c
@@ -226,10 +226,10 @@
}
#ifdef CONFIG_P2P
- if (wpa_s->p2p_long_listen > 0) {
+ if (wpa_s->global->p2p_long_listen > 0) {
/* Continue the listen */
wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
- wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen);
+ wpas_p2p_listen_start(wpa_s, wpa_s->global->p2p_long_listen);
}
#endif /* CONFIG_P2P */
}
@@ -246,7 +246,7 @@
* @buf: Frame to transmit starting from the Category field
* @len: Length of @buf in bytes
* @wait_time: Wait time for response in milliseconds
- * @tx_cb: Callback function for indicating TX status or %NULL for now callback
+ * @tx_cb: Callback function for indicating TX status or %NULL for no callback
* @no_cck: Whether CCK rates are to be disallowed for TX rate selection
* Returns: 0 on success or -1 on failure
*
diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c
index 947917b..983801f 100644
--- a/wpa_supplicant/op_classes.c
+++ b/wpa_supplicant/op_classes.c
@@ -14,15 +14,22 @@
#include "utils/common.h"
#include "common/ieee802_11_common.h"
#include "wpa_supplicant_i.h"
+#include "bss.h"
-static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode, u8 chan,
+static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode,
+ u8 op_class, u8 chan,
unsigned int *flags)
{
int i;
+ int is_6ghz = op_class >= 131 && op_class <= 135;
for (i = 0; i < mode->num_channels; i++) {
- if (mode->channels[i].chan == chan)
+ int chan_is_6ghz;
+
+ chan_is_6ghz = mode->channels[i].freq > 5940 &&
+ mode->channels[i].freq <= 7105;
+ if (is_6ghz == chan_is_6ghz && mode->channels[i].chan == chan)
break;
}
@@ -62,7 +69,8 @@
}
-static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 channel)
+static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode,
+ u8 op_class, u8 channel)
{
u8 center_chan;
unsigned int i;
@@ -77,7 +85,8 @@
unsigned int flags;
u8 adj_chan = center_chan - 6 + i * 4;
- if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
+ if (allow_channel(mode, op_class, adj_chan, &flags) ==
+ NOT_ALLOWED)
return NOT_ALLOWED;
if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) ||
@@ -120,7 +129,7 @@
static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
- u8 channel)
+ u8 op_class, u8 channel)
{
u8 center_chan;
unsigned int i;
@@ -135,7 +144,8 @@
unsigned int flags;
u8 adj_chan = center_chan - 14 + i * 4;
- if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
+ if (allow_channel(mode, op_class, adj_chan, &flags) ==
+ NOT_ALLOWED)
return NOT_ALLOWED;
if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) ||
@@ -159,42 +169,42 @@
}
-enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel,
- u8 bw)
+enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class,
+ u8 channel, u8 bw)
{
unsigned int flag = 0;
enum chan_allowed res, res2;
- res2 = res = allow_channel(mode, channel, &flag);
+ res2 = res = allow_channel(mode, op_class, channel, &flag);
if (bw == BW40MINUS) {
if (!(flag & HOSTAPD_CHAN_HT40MINUS))
return NOT_ALLOWED;
- res2 = allow_channel(mode, channel - 4, NULL);
+ res2 = allow_channel(mode, op_class, channel - 4, NULL);
} else if (bw == BW40PLUS) {
if (!(flag & HOSTAPD_CHAN_HT40PLUS))
return NOT_ALLOWED;
- res2 = allow_channel(mode, channel + 4, NULL);
+ res2 = allow_channel(mode, op_class, channel + 4, NULL);
} else if (bw == BW80) {
/*
* channel is a center channel and as such, not necessarily a
* valid 20 MHz channels. Override earlier allow_channel()
* result and use only the 80 MHz specific version.
*/
- res2 = res = verify_80mhz(mode, channel);
+ res2 = res = verify_80mhz(mode, op_class, channel);
} else if (bw == BW160) {
/*
* channel is a center channel and as such, not necessarily a
* valid 20 MHz channels. Override earlier allow_channel()
* result and use only the 160 MHz specific version.
*/
- res2 = res = verify_160mhz(mode, channel);
+ res2 = res = verify_160mhz(mode, op_class, channel);
} else if (bw == BW80P80) {
/*
* channel is a center channel and as such, not necessarily a
* valid 20 MHz channels. Override earlier allow_channel()
* result and use only the 80 MHz specific version.
*/
- res2 = res = verify_80mhz(mode, channel);
+ res2 = res = verify_80mhz(mode, op_class, channel);
}
if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
@@ -219,13 +229,14 @@
int freq2 = 0;
int freq5 = 0;
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode,
+ is_6ghz_op_class(op_class->op_class));
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]) {
+ if (ssid && ssid->freq_list && ssid->freq_list[0]) {
for (z = 0; ; z++) {
int f = ssid->freq_list[z];
@@ -248,7 +259,7 @@
return 0;
#ifdef CONFIG_HT_OVERRIDES
- if (ssid->disable_ht) {
+ if (ssid && ssid->disable_ht) {
switch (op_class->op_class) {
case 83:
case 84:
@@ -272,7 +283,7 @@
#endif /* CONFIG_HT_OVERRIDES */
#ifdef CONFIG_VHT_OVERRIDES
- if (ssid->disable_vht) {
+ if (ssid && ssid->disable_vht) {
if (op_class->op_class >= 128 && op_class->op_class <= 130) {
/* Disable >= 80 MHz channels if VHT is disabled */
return 0;
@@ -284,7 +295,8 @@
u8 channels[] = { 42, 58, 106, 122, 138, 155 };
for (i = 0; i < ARRAY_SIZE(channels); i++) {
- if (verify_channel(mode, channels[i], op_class->bw) !=
+ if (verify_channel(mode, op_class->op_class,
+ channels[i], op_class->bw) !=
NOT_ALLOWED)
return 1;
}
@@ -294,25 +306,35 @@
if (op_class->op_class == 129) {
/* Check if either 160 MHz channels is allowed */
- return verify_channel(mode, 50, op_class->bw) != NOT_ALLOWED ||
- verify_channel(mode, 114, op_class->bw) != NOT_ALLOWED;
+ return verify_channel(mode, op_class->op_class, 50,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 114,
+ op_class->bw) != NOT_ALLOWED;
}
if (op_class->op_class == 130) {
/* Need at least two non-contiguous 80 MHz segments */
found = 0;
- if (verify_channel(mode, 42, op_class->bw) != NOT_ALLOWED ||
- verify_channel(mode, 58, op_class->bw) != NOT_ALLOWED)
+ if (verify_channel(mode, op_class->op_class, 42,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 58,
+ op_class->bw) != NOT_ALLOWED)
found++;
- if (verify_channel(mode, 106, op_class->bw) != NOT_ALLOWED ||
- verify_channel(mode, 122, op_class->bw) != NOT_ALLOWED ||
- verify_channel(mode, 138, op_class->bw) != NOT_ALLOWED)
+ if (verify_channel(mode, op_class->op_class, 106,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 122,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 138,
+ op_class->bw) != NOT_ALLOWED)
found++;
- if (verify_channel(mode, 106, op_class->bw) != NOT_ALLOWED &&
- verify_channel(mode, 138, op_class->bw) != NOT_ALLOWED)
+ if (verify_channel(mode, op_class->op_class, 106,
+ op_class->bw) != NOT_ALLOWED &&
+ verify_channel(mode, op_class->op_class, 138,
+ op_class->bw) != NOT_ALLOWED)
found++;
- if (verify_channel(mode, 155, op_class->bw) != NOT_ALLOWED)
+ if (verify_channel(mode, op_class->op_class, 155,
+ op_class->bw) != NOT_ALLOWED)
found++;
if (found >= 2)
@@ -324,7 +346,8 @@
found = 0;
for (chan = op_class->min_chan; chan <= op_class->max_chan;
chan += op_class->inc) {
- if (verify_channel(mode, chan, op_class->bw) != NOT_ALLOWED) {
+ if (verify_channel(mode, op_class->op_class, chan,
+ op_class->bw) != NOT_ALLOWED) {
found = 1;
break;
}
@@ -334,9 +357,25 @@
}
+static int wpas_sta_secondary_channel_offset(struct wpa_bss *bss, u8 *current,
+ u8 *channel)
+{
+
+ u8 *ies, phy_type;
+ size_t ies_len;
+
+ if (!bss)
+ return -1;
+ ies = (u8 *) (bss + 1);
+ ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
+ return wpas_get_op_chan_phy(bss->freq, ies, ies_len, current,
+ channel, &phy_type);
+}
+
+
size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
- int freq, u8 *pos, size_t len)
+ struct wpa_bss *bss, u8 *pos, size_t len)
{
struct wpabuf *buf;
u8 op, current, chan;
@@ -344,11 +383,13 @@
size_t res;
/*
- * Assume 20 MHz channel for now.
- * TODO: Use the secondary channel and VHT channel width that will be
- * used after association.
+ * Determine the current operating class correct mode based on
+ * advertised BSS capabilities, if available. Fall back to a less
+ * accurate guess based on frequency if the needed IEs are not available
+ * or used.
*/
- if (ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT,
+ if (wpas_sta_secondary_channel_offset(bss, ¤t, &chan) < 0 &&
+ ieee80211_freq_to_channel_ext(bss->freq, 0, CHANWIDTH_USE_HT,
¤t, &chan) == NUM_HOSTAPD_MODES)
return 0;
@@ -385,3 +426,24 @@
wpabuf_free(buf);
return res;
}
+
+
+int * wpas_supp_op_classes(struct wpa_supplicant *wpa_s)
+{
+ int op;
+ unsigned int pos, max_num = 0;
+ int *classes;
+
+ for (op = 0; global_op_class[op].op_class; op++)
+ max_num++;
+ classes = os_zalloc((max_num + 1) * sizeof(int));
+ if (!classes)
+ return NULL;
+
+ for (op = 0, pos = 0; global_op_class[op].op_class; op++) {
+ if (wpas_op_class_supported(wpa_s, NULL, &global_op_class[op]))
+ classes[pos++] = global_op_class[op].op_class;
+ }
+
+ return classes;
+}
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 70b61d6..b0bea61 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -1556,7 +1556,7 @@
{
struct send_action_work *awork;
- if (wpa_s->p2p_send_action_work) {
+ if (radio_work_pending(wpa_s, "p2p-send-action")) {
wpa_printf(MSG_DEBUG, "P2P: Cannot schedule new p2p-send-action work since one is already pending");
return -1;
}
@@ -1573,7 +1573,7 @@
awork->wait_time = wait_time;
os_memcpy(awork->buf, buf, len);
- if (radio_add_work(wpa_s, freq, "p2p-send-action", 0,
+ if (radio_add_work(wpa_s, freq, "p2p-send-action", 1,
wpas_send_action_cb, awork) < 0) {
os_free(awork);
return -1;
@@ -1885,6 +1885,83 @@
}
+/**
+ * wpas_p2p_freq_to_edmg_channel - Convert frequency into EDMG channel
+ * @freq: Frequency (MHz) to convert
+ * @op_class: Buffer for returning operating class
+ * @op_edmg_channel: Buffer for returning channel number
+ * Returns: 0 on success, -1 on failure
+ *
+ * This can be used to find the highest channel bonding which includes the
+ * specified frequency.
+ */
+static int wpas_p2p_freq_to_edmg_channel(struct wpa_supplicant *wpa_s,
+ unsigned int freq,
+ u8 *op_class, u8 *op_edmg_channel)
+{
+ struct hostapd_hw_modes *hwmode;
+ struct ieee80211_edmg_config edmg;
+ unsigned int i;
+ enum chan_width chanwidth[] = {
+ CHAN_WIDTH_8640,
+ CHAN_WIDTH_6480,
+ CHAN_WIDTH_4320,
+ };
+
+ if (!wpa_s->hw.modes)
+ return -1;
+
+ hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ HOSTAPD_MODE_IEEE80211AD, 0);
+ if (!hwmode) {
+ wpa_printf(MSG_ERROR,
+ "Unsupported AP mode: HOSTAPD_MODE_IEEE80211AD");
+ return -1;
+ }
+
+ /* Find the highest EDMG channel bandwidth to start the P2P GO */
+ for (i = 0; i < ARRAY_SIZE(chanwidth); i++) {
+ if (ieee80211_chaninfo_to_channel(freq, chanwidth[i], 0,
+ op_class,
+ op_edmg_channel) < 0)
+ continue;
+
+ hostapd_encode_edmg_chan(1, *op_edmg_channel, 0, &edmg);
+ if (edmg.channels &&
+ ieee802_edmg_is_allowed(hwmode->edmg, edmg)) {
+ wpa_printf(MSG_DEBUG,
+ "Freq %u to EDMG channel %u at opclass %u",
+ freq, *op_edmg_channel, *op_class);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
+int wpas_p2p_try_edmg_channel(struct wpa_supplicant *wpa_s,
+ struct p2p_go_neg_results *params)
+{
+ u8 op_channel, op_class;
+ int freq;
+
+ /* Try social channel as primary channel frequency */
+ freq = (!params->freq) ? 58320 + 1 * 2160 : params->freq;
+
+ if (wpas_p2p_freq_to_edmg_channel(wpa_s, freq, &op_class,
+ &op_channel) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "Freq %d will be used to set an EDMG connection (channel=%u opclass=%u)",
+ freq, op_channel, op_class);
+ params->freq = freq;
+ return 0;
+ }
+
+ return -1;
+}
+
+
static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params,
int group_formation)
@@ -1921,6 +1998,20 @@
ssid->max_oper_chwidth = params->max_oper_chwidth;
ssid->vht_center_freq2 = params->vht_center_freq2;
ssid->he = params->he;
+ if (params->edmg) {
+ u8 op_channel, op_class;
+
+ if (!wpas_p2p_freq_to_edmg_channel(wpa_s, params->freq,
+ &op_class, &op_channel)) {
+ ssid->edmg_channel = op_channel;
+ ssid->enable_edmg = params->edmg;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Could not match EDMG channel, freq %d, for GO",
+ params->freq);
+ }
+ }
+
ssid->ssid = os_zalloc(params->ssid_len + 1);
if (ssid->ssid) {
os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
@@ -2268,6 +2359,10 @@
res->ht40 = 1;
if (wpa_s->p2p_go_vht)
res->vht = 1;
+ if (wpa_s->p2p_go_he)
+ res->he = 1;
+ if (wpa_s->p2p_go_edmg)
+ res->edmg = 1;
res->max_oper_chwidth = wpa_s->p2p_go_max_oper_chwidth;
res->vht_center_freq2 = wpa_s->p2p_go_vht_center_freq2;
@@ -2327,7 +2422,7 @@
wpas_start_wps_enrollee(group_wpa_s, res);
}
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
@@ -2606,7 +2701,7 @@
{
struct wpa_supplicant *wpa_s = ctx;
return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1,
- freq);
+ freq, 0);
}
@@ -3097,7 +3192,12 @@
MAC2STR(sa), s->id);
}
wpas_p2p_group_add_persistent(
- wpa_s, s, go, 0, op_freq, 0, 0, 0, 0, 0, NULL,
+ wpa_s, s, go, 0, op_freq, 0,
+ wpa_s->conf->p2p_go_ht40,
+ wpa_s->conf->p2p_go_vht,
+ 0,
+ wpa_s->conf->p2p_go_he,
+ wpa_s->conf->p2p_go_edmg, NULL,
go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0,
1);
} else if (bssid) {
@@ -3324,6 +3424,7 @@
wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht,
wpa_s->p2p_go_max_oper_chwidth,
wpa_s->p2p_go_he,
+ wpa_s->p2p_go_edmg,
channels,
ssid->mode == WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
@@ -3568,6 +3669,20 @@
}
+static enum chan_allowed wpas_p2p_verify_edmg(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode,
+ u8 channel)
+{
+ struct ieee80211_edmg_config edmg;
+
+ hostapd_encode_edmg_chan(1, channel, 0, &edmg);
+ if (edmg.channels && ieee802_edmg_is_allowed(mode->edmg, edmg))
+ return ALLOWED;
+
+ return NOT_ALLOWED;
+}
+
+
static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode,
u8 channel, u8 bw)
@@ -3588,6 +3703,8 @@
res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw);
} else if (bw == BW160) {
res2 = wpas_p2p_verify_160mhz(wpa_s, mode, channel, bw);
+ } else if (bw == BW4320 || bw == BW6480 || bw == BW8640) {
+ return wpas_p2p_verify_edmg(wpa_s, mode, channel);
}
if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
@@ -3622,7 +3739,8 @@
if (o->p2p == NO_P2P_SUPP)
continue;
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode,
+ is_6ghz_op_class(o->op_class));
if (mode == NULL)
continue;
if (mode->mode == HOSTAPD_MODE_IEEE80211G)
@@ -3632,23 +3750,32 @@
res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
if (res == ALLOWED) {
if (reg == NULL) {
+ if (cla == P2P_MAX_REG_CLASSES)
+ continue;
wpa_printf(MSG_DEBUG, "P2P: Add operating class %u",
o->op_class);
reg = &chan->reg_class[cla];
cla++;
reg->reg_class = o->op_class;
}
+ if (reg->channels == P2P_MAX_REG_CLASS_CHANNELS)
+ continue;
reg->channel[reg->channels] = ch;
reg->channels++;
} else if (res == NO_IR &&
wpa_s->conf->p2p_add_cli_chan) {
if (cli_reg == NULL) {
+ if (cli_cla == P2P_MAX_REG_CLASSES)
+ continue;
wpa_printf(MSG_DEBUG, "P2P: Add operating class %u (client only)",
o->op_class);
cli_reg = &cli_chan->reg_class[cli_cla];
cli_cla++;
cli_reg->reg_class = o->op_class;
}
+ if (cli_reg->channels ==
+ P2P_MAX_REG_CLASS_CHANNELS)
+ continue;
cli_reg->channel[cli_reg->channels] = ch;
cli_reg->channels++;
}
@@ -4238,14 +4365,14 @@
if (response_done && persistent_go) {
wpas_p2p_group_add_persistent(
wpa_s, persistent_go,
- 0, 0, freq, 0, 0, 0, 0, 0, NULL,
+ 0, 0, freq, 0, 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, 0);
+ 0, 0, 0, 0, 0, 0);
}
if (passwd_id == DEV_PW_P2PS_DEFAULT) {
@@ -4361,11 +4488,12 @@
if (persistent_go) {
wpas_p2p_group_add_persistent(
- wpa_s, persistent_go, 0, 0, 0, 0, 0, 0, 0, 0, NULL,
+ wpa_s, persistent_go, 0, 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, 0);
+ wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0, 0);
}
return 1;
@@ -4644,7 +4772,7 @@
eloop_cancel_timeout(wpas_p2p_psk_failure_removal, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
wpas_p2p_remove_pending_group_interface(wpa_s);
@@ -4948,6 +5076,7 @@
wpa_s->p2p_go_vht,
wpa_s->p2p_go_max_oper_chwidth,
wpa_s->p2p_go_he,
+ wpa_s->p2p_go_edmg,
NULL, 0);
return;
}
@@ -5484,7 +5613,7 @@
* @ht40: Start GO with 40 MHz channel width
* @vht: Start GO with VHT support
* @vht_chwidth: Channel width supported by GO operating with VHT support
- * (VHT_CHANWIDTH_*).
+ * (CHANWIDTH_*).
* @group_ssid: Specific Group SSID for join or %NULL if not set
* @group_ssid_len: Length of @group_ssid in octets
* Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified
@@ -5496,8 +5625,8 @@
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, int he, const u8 *group_ssid,
- size_t group_ssid_len)
+ unsigned int vht_chwidth, int he, int edmg,
+ const u8 *group_ssid, size_t group_ssid_len)
{
int force_freq = 0, pref_freq = 0;
int ret = 0, res;
@@ -5528,7 +5657,7 @@
go_intent = wpa_s->conf->p2p_go_intent;
if (!auth)
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
wpa_s->p2p_wps_method = wps_method;
wpa_s->p2p_persistent_group = !!persistent_group;
@@ -5542,6 +5671,7 @@
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;
+ wpa_s->p2p_go_edmg = !!edmg;
if (pin)
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
@@ -5697,19 +5827,20 @@
{
wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
"(p2p_long_listen=%d ms pending_action_tx=%p)",
- wpa_s->p2p_long_listen, offchannel_pending_action_tx(wpa_s));
+ wpa_s->global->p2p_long_listen,
+ offchannel_pending_action_tx(wpa_s));
wpas_p2p_listen_work_done(wpa_s);
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
- if (wpa_s->p2p_long_listen > 0)
- wpa_s->p2p_long_listen -= wpa_s->max_remain_on_chan;
+ if (wpa_s->global->p2p_long_listen > 0)
+ wpa_s->global->p2p_long_listen -= wpa_s->max_remain_on_chan;
if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
return; /* P2P module started a new operation */
if (offchannel_pending_action_tx(wpa_s))
return;
- if (wpa_s->p2p_long_listen > 0) {
+ if (wpa_s->global->p2p_long_listen > 0) {
wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
- wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen);
+ wpas_p2p_listen_start(wpa_s, wpa_s->global->p2p_long_listen);
} else {
/*
* When listen duration is over, stop listen & update p2p_state
@@ -5966,6 +6097,7 @@
struct p2p_go_neg_results *params,
int freq, int vht_center_freq2, int ht40,
int vht, int max_oper_chwidth, int he,
+ int edmg,
const struct p2p_channels *channels)
{
struct wpa_used_freq_data *freqs;
@@ -5981,6 +6113,7 @@
params->he = he;
params->max_oper_chwidth = max_oper_chwidth;
params->vht_center_freq2 = vht_center_freq2;
+ params->edmg = edmg;
freqs = os_calloc(wpa_s->num_multichan_concurrent,
sizeof(struct wpa_used_freq_data));
@@ -6011,6 +6144,13 @@
}
}
+ /* Try to use EDMG channel */
+ if (params->edmg) {
+ if (wpas_p2p_try_edmg_channel(wpa_s, params) == 0)
+ goto success;
+ params->edmg = 0;
+ }
+
/* try using the forced freq */
if (freq) {
if (wpas_p2p_disallowed_freq(wpa_s->global, freq) ||
@@ -6173,7 +6313,7 @@
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);
+ mode, is_6ghz_freq(cand));
if (!hwmode ||
wpas_p2p_verify_channel(wpa_s, hwmode, chan,
BW80) != ALLOWED)
@@ -6200,7 +6340,7 @@
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);
+ mode, is_6ghz_freq(cand));
if (!wpas_same_band(wpa_s->current_ssid->frequency,
cand) ||
!hwmode ||
@@ -6328,6 +6468,7 @@
* @ht40: Start GO with 40 MHz channel width
* @vht: Start GO with VHT support
* @vht_chwidth: channel bandwidth for GO operating with VHT support
+ * @edmg: Start GO with EDMG support
* Returns: 0 on success, -1 on failure
*
* This function creates a new P2P group with the local end as the Group Owner,
@@ -6335,7 +6476,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 he)
+ int max_oper_chwidth, int he, int edmg)
{
struct p2p_go_neg_results params;
@@ -6356,7 +6497,8 @@
}
if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, vht_center_freq2,
- ht40, vht, max_oper_chwidth, he, NULL))
+ ht40, vht, max_oper_chwidth, he, edmg,
+ NULL))
return -1;
p2p_go_params(wpa_s->global->p2p, ¶ms);
@@ -6436,6 +6578,7 @@
int force_freq, int neg_freq,
int vht_center_freq2, int ht40,
int vht, int max_oper_chwidth, int he,
+ int edmg,
const struct p2p_channels *channels,
int connection_timeout, int force_scan)
{
@@ -6511,7 +6654,8 @@
}
if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, vht_center_freq2,
- ht40, vht, max_oper_chwidth, he, channels))
+ ht40, vht, max_oper_chwidth, he, edmg,
+ channels))
return -1;
params.role_go = 1;
@@ -6831,7 +6975,7 @@
u8 seek_cnt, const char **seek_string, int freq)
{
wpas_p2p_clear_pending_action_tx(wpa_s);
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL ||
wpa_s->p2p_in_provisioning) {
@@ -6876,7 +7020,7 @@
static void wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
{
wpas_p2p_clear_pending_action_tx(wpa_s);
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
@@ -6902,7 +7046,7 @@
static void wpas_p2p_long_listen_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
}
@@ -6931,7 +7075,7 @@
timeout = 3600;
}
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
/*
* Stop previous find/listen operation to avoid trying to request a new
@@ -6943,7 +7087,7 @@
res = wpas_p2p_listen_start(wpa_s, timeout * 1000);
if (res == 0 && timeout * 1000 > wpa_s->max_remain_on_chan) {
- wpa_s->p2p_long_listen = timeout * 1000;
+ wpa_s->global->p2p_long_listen = timeout * 1000;
eloop_register_timeout(timeout, 0,
wpas_p2p_long_listen_timeout,
wpa_s, NULL);
@@ -7050,7 +7194,7 @@
int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr)
{
- wpa_s->p2p_long_listen = 0;
+ wpa_s->global->p2p_long_listen = 0;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
@@ -7063,7 +7207,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 he)
+ int pref_freq, int he, int edmg)
{
enum p2p_invite_role role;
u8 *bssid = NULL;
@@ -7084,6 +7228,7 @@
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;
+ wpa_s->p2p_go_edmg = !!edmg;
if (ssid->mode == WPAS_MODE_P2P_GO) {
role = P2P_INVITE_ROLE_GO;
if (peer_addr == NULL) {
@@ -7161,6 +7306,7 @@
wpa_s->p2p_go_vht = 0;
wpa_s->p2p_go_vht_center_freq2 = 0;
wpa_s->p2p_go_max_oper_chwidth = 0;
+ wpa_s->p2p_go_edmg = 0;
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
if (os_strcmp(wpa_s->ifname, ifname) == 0)
@@ -8106,7 +8252,9 @@
wpa_s->p2p_go_ht40,
wpa_s->p2p_go_vht,
wpa_s->p2p_go_max_oper_chwidth,
- wpa_s->p2p_go_he, NULL, 0);
+ wpa_s->p2p_go_he,
+ wpa_s->p2p_go_edmg,
+ NULL, 0);
return ret;
}
@@ -8642,7 +8790,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,
+ wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
params->go_ssid_len ? params->go_ssid : NULL,
params->go_ssid_len);
}
@@ -8722,7 +8870,8 @@
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,
- wpa_s->p2p_go_he, NULL, 0);
+ wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
+ NULL, 0);
}
@@ -8738,7 +8887,8 @@
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,
- wpa_s->p2p_go_he, NULL, 0);
+ wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
+ NULL, 0);
if (res)
return res;
@@ -9123,7 +9273,8 @@
* 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, 0, NULL)) {
+ if (wpas_p2p_init_go_params(wpa_s, ¶ms, 0, 0, 0, 0, 0, 0, 0,
+ NULL)) {
wpa_dbg(wpa_s, MSG_DEBUG,
"P2P CSA: Failed to select new frequency for GO");
return -1;
@@ -9201,11 +9352,11 @@
csa_settings.freq_params.center_freq2 = freq2;
switch (conf->vht_oper_chwidth) {
- case VHT_CHANWIDTH_80MHZ:
- case VHT_CHANWIDTH_80P80MHZ:
+ case CHANWIDTH_80MHZ:
+ case CHANWIDTH_80P80MHZ:
csa_settings.freq_params.bandwidth = 80;
break;
- case VHT_CHANWIDTH_160MHZ:
+ case CHANWIDTH_160MHZ:
csa_settings.freq_params.bandwidth = 160;
break;
}
@@ -9235,7 +9386,8 @@
wpa_supplicant_ap_deinit(wpa_s);
/* Reselect the GO frequency */
- if (wpas_p2p_init_go_params(wpa_s, ¶ms, 0, 0, 0, 0, 0, 0, NULL)) {
+ if (wpas_p2p_init_go_params(wpa_s, ¶ms, 0, 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);
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 24ec2ca..941198e 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, int he, const u8 *group_ssid,
- size_t group_ssid_len);
+ unsigned int vht_chwidth, int he, int edmg,
+ 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 he);
+ int max_oper_chwidth, int he, int edmg);
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 he,
+ int vht_center_freq2, int ht40, int vht,
+ int max_oper_chwidth, int he, int edmg,
const struct p2p_channels *channels,
int connection_timeout, int force_scan);
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
@@ -116,8 +116,8 @@
int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr);
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 he);
+ int vht_center_freq2, int ht40, int vht, int max_chwidth,
+ int pref_freq, int he, int edmg);
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,
@@ -165,6 +165,8 @@
const struct wpabuf *sel, int forced_freq);
int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled);
void wpas_p2p_pbc_overlap_cb(void *eloop_ctx, void *timeout_ctx);
+int wpas_p2p_try_edmg_channel(struct wpa_supplicant *wpa_s,
+ struct p2p_go_neg_results *params);
#ifdef CONFIG_P2P
diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c
index f2fff55..4a8f4ff 100644
--- a/wpa_supplicant/preauth_test.c
+++ b/wpa_supplicant/preauth_test.c
@@ -35,12 +35,18 @@
};
-static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
+static void _wpa_supplicant_deauthenticate(void *wpa_s, u16 reason_code)
{
wpa_supplicant_deauthenticate(wpa_s, reason_code);
}
+static void _wpa_supplicant_reconnect(void *wpa_s)
+{
+ wpa_supplicant_reconnect(wpa_s);
+}
+
+
static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type,
const void *data, u16 data_len,
size_t *msg_len, void **data_pos)
@@ -127,7 +133,8 @@
static int wpa_supplicant_set_key(void *wpa_s, 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)
+ const u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
printf("%s - not implemented\n", __func__);
return -1;
@@ -146,7 +153,8 @@
static int wpa_supplicant_add_pmkid(void *wpa_s, void *network_ctx,
const u8 *bssid, const u8 *pmkid,
const u8 *fils_cache_id,
- const u8 *pmk, size_t pmk_len)
+ const u8 *pmk, size_t pmk_len,
+ u32 pmk_lifetime, u8 pmk_reauth_threshold)
{
printf("%s - not implemented\n", __func__);
return -1;
@@ -244,6 +252,7 @@
ctx->set_config_blob = wpa_supplicant_set_config_blob;
ctx->get_config_blob = wpa_supplicant_get_config_blob;
ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection;
+ ctx->reconnect = _wpa_supplicant_reconnect;
wpa_s->wpa = wpa_sm_init(ctx);
assert(wpa_s->wpa != NULL);
diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c
index cb3c6c9..afc1172 100644
--- a/wpa_supplicant/rrm.c
+++ b/wpa_supplicant/rrm.c
@@ -79,7 +79,7 @@
NULL);
if (!wpa_s->rrm.notify_neighbor_rep) {
- wpa_printf(MSG_ERROR, "RRM: Unexpected neighbor report");
+ wpa_msg(wpa_s, MSG_INFO, "RRM: Unexpected neighbor report");
return;
}
@@ -90,8 +90,8 @@
return;
}
wpabuf_put_data(neighbor_rep, report + 1, report_len - 1);
- wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
- report[0]);
+ wpa_dbg(wpa_s, MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
+ report[0]);
wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx,
neighbor_rep);
wpa_s->rrm.notify_neighbor_rep = NULL;
@@ -101,10 +101,16 @@
#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
/* Workaround different, undefined for Windows, error codes used here */
+#ifndef ENOTCONN
#define ENOTCONN -1
+#endif
+#ifndef EOPNOTSUPP
#define EOPNOTSUPP -1
+#endif
+#ifndef ECANCELED
#define ECANCELED -1
#endif
+#endif
/* Measurement Request element + Location Subject + Maximum Age subelement */
#define MEASURE_REQUEST_LCI_LEN (3 + 1 + 4)
@@ -142,12 +148,12 @@
const u8 *rrm_ie;
if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) {
- wpa_printf(MSG_DEBUG, "RRM: No connection, no RRM.");
+ wpa_dbg(wpa_s, MSG_DEBUG, "RRM: No connection, no RRM.");
return -ENOTCONN;
}
if (!wpa_s->rrm.rrm_used) {
- wpa_printf(MSG_DEBUG, "RRM: No RRM in current connection.");
+ wpa_dbg(wpa_s, MSG_DEBUG, "RRM: No RRM in current connection.");
return -EOPNOTSUPP;
}
@@ -155,15 +161,15 @@
WLAN_EID_RRM_ENABLED_CAPABILITIES);
if (!rrm_ie || !(wpa_s->current_bss->caps & IEEE80211_CAP_RRM) ||
!(rrm_ie[2] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
- wpa_printf(MSG_DEBUG,
- "RRM: No network support for Neighbor Report.");
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RRM: No network support for Neighbor Report.");
return -EOPNOTSUPP;
}
/* Refuse if there's a live request */
if (wpa_s->rrm.notify_neighbor_rep) {
- wpa_printf(MSG_DEBUG,
- "RRM: Currently handling previous Neighbor Report.");
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RRM: Currently handling previous Neighbor Report.");
return -EBUSY;
}
@@ -172,14 +178,15 @@
(lci ? 2 + MEASURE_REQUEST_LCI_LEN : 0) +
(civic ? 2 + MEASURE_REQUEST_CIVIC_LEN : 0));
if (buf == NULL) {
- wpa_printf(MSG_DEBUG,
- "RRM: Failed to allocate Neighbor Report Request");
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RRM: Failed to allocate Neighbor Report Request");
return -ENOMEM;
}
- wpa_printf(MSG_DEBUG, "RRM: Neighbor report request (for %s), token=%d",
- (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
- wpa_s->rrm.next_neighbor_rep_token);
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RRM: Neighbor report request (for %s), token=%d",
+ (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
+ wpa_s->rrm.next_neighbor_rep_token);
wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST);
@@ -261,8 +268,8 @@
if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
wpa_s->own_addr, wpa_s->bssid,
wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
- wpa_printf(MSG_DEBUG,
- "RRM: Failed to send Neighbor Report Request");
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RRM: Failed to send Neighbor Report Request");
wpabuf_free(buf);
return -ECANCELED;
}
@@ -522,7 +529,8 @@
next_freq = freqs;
for (i = 0; i < num_chans; i++) {
u8 chan = channels ? channels[i] : op->min_chan + i * op->inc;
- enum chan_allowed res = verify_channel(mode, chan, op->bw);
+ enum chan_allowed res = verify_channel(mode, op->op_class, chan,
+ op->bw);
if (res == NOT_ALLOWED || (res == NO_IR && active))
continue;
@@ -601,7 +609,8 @@
pos++;
left--;
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode,
+ is_6ghz_op_class(op->op_class));
if (!mode)
continue;
@@ -653,7 +662,8 @@
return NULL;
}
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode,
+ is_6ghz_op_class(op->op_class));
if (!mode)
return NULL;
@@ -685,8 +695,8 @@
}
-static int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
- u8 *op_class, u8 *chan, u8 *phy_type)
+int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
+ u8 *op_class, u8 *chan, u8 *phy_type)
{
const u8 *ie;
int sec_chan = 0, vht = 0;
@@ -717,20 +727,20 @@
seg0 = vht_oper->vht_op_info_chan_center_freq_seg0_idx;
seg1 = vht_oper->vht_op_info_chan_center_freq_seg1_idx;
if (seg1 && abs(seg1 - seg0) == 8)
- vht = VHT_CHANWIDTH_160MHZ;
+ vht = CHANWIDTH_160MHZ;
else if (seg1)
- vht = VHT_CHANWIDTH_80P80MHZ;
+ vht = CHANWIDTH_80P80MHZ;
else
- vht = VHT_CHANWIDTH_80MHZ;
+ vht = CHANWIDTH_80MHZ;
break;
case 2:
- vht = VHT_CHANWIDTH_160MHZ;
+ vht = CHANWIDTH_160MHZ;
break;
case 3:
- vht = VHT_CHANWIDTH_80P80MHZ;
+ vht = CHANWIDTH_80P80MHZ;
break;
default:
- vht = VHT_CHANWIDTH_USE_HT;
+ vht = CHANWIDTH_USE_HT;
break;
}
}
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 7abb028..b475730 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -79,6 +79,33 @@
#endif /* CONFIG_WPS */
+static int wpa_setup_mac_addr_rand_params(struct wpa_driver_scan_params *params,
+ const u8 *mac_addr)
+{
+ u8 *tmp;
+
+ if (params->mac_addr) {
+ params->mac_addr_mask = NULL;
+ os_free(params->mac_addr);
+ params->mac_addr = NULL;
+ }
+
+ params->mac_addr_rand = 1;
+
+ if (!mac_addr)
+ return 0;
+
+ tmp = os_malloc(2 * ETH_ALEN);
+ if (!tmp)
+ return -1;
+
+ os_memcpy(tmp, mac_addr, 2 * ETH_ALEN);
+ params->mac_addr = tmp;
+ params->mac_addr_mask = tmp + ETH_ALEN;
+ return 0;
+}
+
+
/**
* wpa_supplicant_enabled_networks - Check whether there are enabled networks
* @wpa_s: Pointer to wpa_supplicant data
@@ -169,6 +196,10 @@
return;
}
+ if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
+ wpa_s->wpa_state <= WPA_SCANNING)
+ wpa_setup_mac_addr_rand_params(params, wpa_s->mac_addr_scan);
+
if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
wpa_msg(wpa_s, MSG_INFO,
"Failed to assign random MAC address for a scan");
@@ -637,13 +668,14 @@
static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s,
enum hostapd_hw_mode band,
- struct wpa_driver_scan_params *params)
+ struct wpa_driver_scan_params *params,
+ int is_6ghz)
{
/* 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);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band, is_6ghz);
if (mode == NULL) {
/* No channels supported in this band - use empty list */
params->freqs = os_zalloc(sizeof(int));
@@ -670,10 +702,10 @@
return; /* already using a limited channel set */
if (wpa_s->setband == WPA_SETBAND_5G)
wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A,
- params);
+ params, 0);
else if (wpa_s->setband == WPA_SETBAND_2G)
wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G,
- params);
+ params, 0);
}
@@ -1077,7 +1109,9 @@
tssid = tssid->next) {
if (wpas_network_disabled(wpa_s, tssid))
continue;
- if ((params.freqs || !freqs_set) && tssid->scan_freq) {
+ if (((params.freqs || !freqs_set) &&
+ tssid->scan_freq) &&
+ int_array_len(params.freqs) < 100) {
int_array_concat(¶ms.freqs,
tssid->scan_freq);
} else {
@@ -1211,20 +1245,16 @@
#endif /* CONFIG_P2P */
if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
- wpa_s->wpa_state <= WPA_SCANNING) {
- params.mac_addr_rand = 1;
- if (wpa_s->mac_addr_scan) {
- params.mac_addr = wpa_s->mac_addr_scan;
- params.mac_addr_mask = wpa_s->mac_addr_scan + ETH_ALEN;
- }
- }
+ wpa_s->wpa_state <= WPA_SCANNING)
+ wpa_setup_mac_addr_rand_params(¶ms, wpa_s->mac_addr_scan);
if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) {
struct wpa_bss *bss;
params.bssid = wpa_s->next_scan_bssid;
bss = wpa_bss_get_bssid_latest(wpa_s, params.bssid);
- if (bss && bss->ssid_len && params.num_ssids == 1 &&
+ if (!wpa_s->next_scan_bssid_wildcard_ssid &&
+ bss && bss->ssid_len && params.num_ssids == 1 &&
params.ssids[0].ssid_len == 0) {
params.ssids[0].ssid = bss->ssid;
params.ssids[0].ssid_len = bss->ssid_len;
@@ -1286,6 +1316,7 @@
wpabuf_free(extra_ie);
os_free(params.freqs);
os_free(params.filter_ssids);
+ os_free(params.mac_addr);
if (ret) {
wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
@@ -1300,6 +1331,7 @@
#ifdef CONFIG_INTERWORKING
wpa_s->interworking_fast_assoc_tried = 0;
#endif /* CONFIG_INTERWORKING */
+ wpa_s->next_scan_bssid_wildcard_ssid = 0;
if (params.bssid)
os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN);
}
@@ -1664,20 +1696,16 @@
wpa_setband_scan_freqs(wpa_s, scan_params);
if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) &&
- wpa_s->wpa_state <= WPA_SCANNING) {
- params.mac_addr_rand = 1;
- if (wpa_s->mac_addr_sched_scan) {
- params.mac_addr = wpa_s->mac_addr_sched_scan;
- params.mac_addr_mask = wpa_s->mac_addr_sched_scan +
- ETH_ALEN;
- }
- }
+ wpa_s->wpa_state <= WPA_SCANNING)
+ wpa_setup_mac_addr_rand_params(¶ms,
+ wpa_s->mac_addr_sched_scan);
wpa_scan_set_relative_rssi_params(wpa_s, scan_params);
ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params);
wpabuf_free(extra_ie);
os_free(params.filter_ssids);
+ os_free(params.mac_addr);
if (ret) {
wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate sched scan");
if (prev_state != wpa_s->wpa_state)
@@ -1933,20 +1961,6 @@
}
-/*
- * Channels with a great SNR can operate at full rate. What is a great SNR?
- * This doc https://supportforums.cisco.com/docs/DOC-12954 says, "the general
- * rule of thumb is that any SNR above 20 is good." This one
- * http://www.cisco.com/en/US/tech/tk722/tk809/technologies_q_and_a_item09186a00805e9a96.shtml#qa23
- * recommends 25 as a minimum SNR for 54 Mbps data rate. The estimates used in
- * scan_est_throughput() allow even smaller SNR values for the maximum rates
- * (21 for 54 Mbps, 22 for VHT80 MCS9, 24 for HT40 and HT20 MCS7). Use 25 as a
- * somewhat conservative value here.
- */
-#define GREAT_SNR 25
-
-#define IS_5GHZ(n) (n > 4000)
-
/* Compare function for sorting scan results. Return >0 if @b is considered
* better. */
static int wpa_scan_result_compar(const void *a, const void *b)
@@ -2155,14 +2169,6 @@
}
-/*
- * Noise floor values to use when we have signal strength
- * measurements, but no noise floor measurements. These values were
- * measured in an office environment with many APs.
- */
-#define DEFAULT_NOISE_FLOOR_2GHZ (-89)
-#define DEFAULT_NOISE_FLOOR_5GHZ (-92)
-
void scan_snr(struct wpa_scan_res *res)
{
if (res->flags & WPA_SCAN_NOISE_INVALID) {
@@ -2181,86 +2187,83 @@
}
-static unsigned int max_ht20_rate(int snr)
+static unsigned int interpolate_rate(int snr, int snr0, int snr1,
+ int rate0, int rate1)
{
- if (snr < 6)
- return 6500; /* HT20 MCS0 */
- if (snr < 8)
- return 13000; /* HT20 MCS1 */
- if (snr < 13)
- return 19500; /* HT20 MCS2 */
- if (snr < 17)
- return 26000; /* HT20 MCS3 */
- if (snr < 20)
- return 39000; /* HT20 MCS4 */
- if (snr < 23)
- return 52000; /* HT20 MCS5 */
- if (snr < 24)
- return 58500; /* HT20 MCS6 */
- return 65000; /* HT20 MCS7 */
+ return rate0 + (snr - snr0) * (rate1 - rate0) / (snr1 - snr0);
}
-static unsigned int max_ht40_rate(int snr)
+#define INTERPOLATE_RATE(snr0, snr1, rate0, rate1) \
+ if (snr < (snr1)) \
+ return interpolate_rate(snr, (snr0), (snr1), (rate0), (rate1))
+
+static unsigned int max_ht20_rate(int snr, int vht)
{
- if (snr < 3)
- return 13500; /* HT40 MCS0 */
- if (snr < 6)
- return 27000; /* HT40 MCS1 */
- if (snr < 10)
- return 40500; /* HT40 MCS2 */
- if (snr < 15)
- return 54000; /* HT40 MCS3 */
- if (snr < 17)
- return 81000; /* HT40 MCS4 */
- if (snr < 22)
- return 108000; /* HT40 MCS5 */
- if (snr < 24)
- return 121500; /* HT40 MCS6 */
- return 135000; /* HT40 MCS7 */
+ if (snr < 0)
+ return 0;
+ INTERPOLATE_RATE(0, 2, 0, 6500); /* HT20 MCS0 */
+ INTERPOLATE_RATE(2, 5, 6500, 13000); /* HT20 MCS1 */
+ INTERPOLATE_RATE(5, 9, 13000, 19500); /* HT20 MCS2 */
+ INTERPOLATE_RATE(9, 11, 19500, 26000); /* HT20 MCS3 */
+ INTERPOLATE_RATE(11, 15, 26000, 39000); /* HT20 MCS4 */
+ INTERPOLATE_RATE(15, 18, 39000, 52000); /* HT20 MCS5 */
+ INTERPOLATE_RATE(18, 20, 52000, 58500); /* HT20 MCS6 */
+ INTERPOLATE_RATE(20, 25, 58500, 65000); /* HT20 MCS7 */
+ if (!vht)
+ return 65000;
+ INTERPOLATE_RATE(25, 29, 65000, 78000); /* VHT20 MCS8 */
+ return 78000;
+}
+
+
+static unsigned int max_ht40_rate(int snr, int vht)
+{
+ if (snr < 0)
+ return 0;
+ INTERPOLATE_RATE(0, 5, 0, 13500); /* HT40 MCS0 */
+ INTERPOLATE_RATE(5, 8, 13500, 27000); /* HT40 MCS1 */
+ INTERPOLATE_RATE(8, 12, 27000, 40500); /* HT40 MCS2 */
+ INTERPOLATE_RATE(12, 14, 40500, 54000); /* HT40 MCS3 */
+ INTERPOLATE_RATE(14, 18, 54000, 81000); /* HT40 MCS4 */
+ INTERPOLATE_RATE(18, 21, 81000, 108000); /* HT40 MCS5 */
+ INTERPOLATE_RATE(21, 23, 108000, 121500); /* HT40 MCS6 */
+ INTERPOLATE_RATE(23, 28, 121500, 135000); /* HT40 MCS7 */
+ if (!vht)
+ return 135000;
+ INTERPOLATE_RATE(28, 32, 135000, 162000); /* VHT40 MCS8 */
+ INTERPOLATE_RATE(32, 34, 162000, 180000); /* VHT40 MCS9 */
+ return 180000;
}
static unsigned int max_vht80_rate(int snr)
{
- if (snr < 1)
+ if (snr < 0)
return 0;
- if (snr < 2)
- return 29300; /* VHT80 MCS0 */
- if (snr < 5)
- return 58500; /* VHT80 MCS1 */
- if (snr < 9)
- return 87800; /* VHT80 MCS2 */
- if (snr < 11)
- return 117000; /* VHT80 MCS3 */
- if (snr < 15)
- return 175500; /* VHT80 MCS4 */
- if (snr < 16)
- return 234000; /* VHT80 MCS5 */
- if (snr < 18)
- return 263300; /* VHT80 MCS6 */
- if (snr < 20)
- return 292500; /* VHT80 MCS7 */
- if (snr < 22)
- return 351000; /* VHT80 MCS8 */
- return 390000; /* VHT80 MCS9 */
+ INTERPOLATE_RATE(0, 8, 0, 29300); /* VHT80 MCS0 */
+ INTERPOLATE_RATE(8, 11, 29300, 58500); /* VHT80 MCS1 */
+ INTERPOLATE_RATE(11, 15, 58500, 87800); /* VHT80 MCS2 */
+ INTERPOLATE_RATE(15, 17, 87800, 117000); /* VHT80 MCS3 */
+ INTERPOLATE_RATE(17, 21, 117000, 175500); /* VHT80 MCS4 */
+ INTERPOLATE_RATE(21, 24, 175500, 234000); /* VHT80 MCS5 */
+ INTERPOLATE_RATE(24, 26, 234000, 263300); /* VHT80 MCS6 */
+ INTERPOLATE_RATE(26, 31, 263300, 292500); /* VHT80 MCS7 */
+ INTERPOLATE_RATE(31, 35, 292500, 351000); /* VHT80 MCS8 */
+ INTERPOLATE_RATE(35, 37, 351000, 390000); /* VHT80 MCS9 */
+ return 390000;
}
+#undef INTERPOLATE_RATE
-void scan_est_throughput(struct wpa_supplicant *wpa_s,
- struct wpa_scan_res *res)
+
+unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
+ const u8 *ies, size_t ies_len, int rate,
+ int snr)
{
enum local_hw_capab capab = wpa_s->hw_capab;
- int rate; /* max legacy rate in 500 kb/s units */
- const u8 *ie;
unsigned int est, tmp;
- int snr = res->snr;
-
- if (res->est_throughput)
- return;
-
- /* Get maximum legacy rate */
- rate = wpa_scan_get_max_rate(res);
+ const u8 *ie;
/* Limit based on estimated SNR */
if (rate > 1 * 2 && snr < 1)
@@ -2273,32 +2276,50 @@
rate = 9 * 2;
else if (rate > 12 * 2 && snr < 7)
rate = 12 * 2;
+ else if (rate > 12 * 2 && snr < 8)
+ rate = 14 * 2;
+ else if (rate > 12 * 2 && snr < 9)
+ rate = 16 * 2;
else if (rate > 18 * 2 && snr < 10)
rate = 18 * 2;
else if (rate > 24 * 2 && snr < 11)
rate = 24 * 2;
+ else if (rate > 24 * 2 && snr < 12)
+ rate = 27 * 2;
+ else if (rate > 24 * 2 && snr < 13)
+ rate = 30 * 2;
+ else if (rate > 24 * 2 && snr < 14)
+ rate = 33 * 2;
else if (rate > 36 * 2 && snr < 15)
rate = 36 * 2;
+ else if (rate > 36 * 2 && snr < 16)
+ rate = 39 * 2;
+ else if (rate > 36 * 2 && snr < 17)
+ rate = 42 * 2;
+ else if (rate > 36 * 2 && snr < 18)
+ rate = 45 * 2;
else if (rate > 48 * 2 && snr < 19)
rate = 48 * 2;
+ else if (rate > 48 * 2 && snr < 20)
+ rate = 51 * 2;
else if (rate > 54 * 2 && snr < 21)
rate = 54 * 2;
est = rate * 500;
if (capab == CAPAB_HT || capab == CAPAB_HT40 || capab == CAPAB_VHT) {
- ie = wpa_scan_get_ie(res, WLAN_EID_HT_CAP);
+ ie = get_ie(ies, ies_len, WLAN_EID_HT_CAP);
if (ie) {
- tmp = max_ht20_rate(snr);
+ tmp = max_ht20_rate(snr, 0);
if (tmp > est)
est = tmp;
}
}
if (capab == CAPAB_HT40 || capab == CAPAB_VHT) {
- ie = wpa_scan_get_ie(res, WLAN_EID_HT_OPERATION);
+ ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION);
if (ie && ie[1] >= 2 &&
(ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
- tmp = max_ht40_rate(snr);
+ tmp = max_ht40_rate(snr, 0);
if (tmp > est)
est = tmp;
}
@@ -2306,22 +2327,22 @@
if (capab == CAPAB_VHT) {
/* Use +1 to assume VHT is always faster than HT */
- ie = wpa_scan_get_ie(res, WLAN_EID_VHT_CAP);
+ ie = get_ie(ies, ies_len, WLAN_EID_VHT_CAP);
if (ie) {
- tmp = max_ht20_rate(snr) + 1;
+ tmp = max_ht20_rate(snr, 1) + 1;
if (tmp > est)
est = tmp;
- ie = wpa_scan_get_ie(res, WLAN_EID_HT_OPERATION);
+ ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION);
if (ie && ie[1] >= 2 &&
(ie[3] &
HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
- tmp = max_ht40_rate(snr) + 1;
+ tmp = max_ht40_rate(snr, 1) + 1;
if (tmp > est)
est = tmp;
}
- ie = wpa_scan_get_ie(res, WLAN_EID_VHT_OPERATION);
+ ie = get_ie(ies, ies_len, WLAN_EID_VHT_OPERATION);
if (ie && ie[1] >= 1 &&
(ie[2] & VHT_OPMODE_CHANNEL_WIDTH_MASK)) {
tmp = max_vht80_rate(snr) + 1;
@@ -2331,9 +2352,30 @@
}
}
- /* TODO: channel utilization and AP load (e.g., from AP Beacon) */
+ return est;
+}
- res->est_throughput = est;
+
+void scan_est_throughput(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_res *res)
+{
+ int rate; /* max legacy rate in 500 kb/s units */
+ int snr = res->snr;
+ const u8 *ies = (const void *) (res + 1);
+ size_t ie_len = res->ie_len;
+
+ if (res->est_throughput)
+ return;
+
+ /* Get maximum legacy rate */
+ rate = wpa_scan_get_max_rate(res);
+
+ if (!ie_len)
+ ie_len = res->beacon_ie_len;
+ res->est_throughput =
+ wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr);
+
+ /* TODO: channel utilization and AP load (e.g., from AP Beacon) */
}
@@ -2535,23 +2577,9 @@
params->sched_scan_plans_num = src->sched_scan_plans_num;
}
- if (src->mac_addr_rand) {
- params->mac_addr_rand = src->mac_addr_rand;
-
- if (src->mac_addr && src->mac_addr_mask) {
- u8 *mac_addr;
-
- mac_addr = os_malloc(2 * ETH_ALEN);
- if (!mac_addr)
- goto failed;
-
- os_memcpy(mac_addr, src->mac_addr, ETH_ALEN);
- os_memcpy(mac_addr + ETH_ALEN, src->mac_addr_mask,
- ETH_ALEN);
- params->mac_addr = mac_addr;
- params->mac_addr_mask = mac_addr + ETH_ALEN;
- }
- }
+ if (src->mac_addr_rand &&
+ wpa_setup_mac_addr_rand_params(params, src->mac_addr))
+ goto failed;
if (src->bssid) {
u8 *bssid;
@@ -2602,8 +2630,8 @@
int wpas_start_pno(struct wpa_supplicant *wpa_s)
{
- int ret, prio;
- size_t i, num_ssid, num_match_ssid;
+ int ret;
+ size_t prio, i, num_ssid, num_match_ssid;
struct wpa_ssid *ssid;
struct wpa_driver_scan_params params;
struct sched_scan_plan scan_plan;
@@ -2738,18 +2766,14 @@
}
if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) &&
- wpa_s->wpa_state <= WPA_SCANNING) {
- params.mac_addr_rand = 1;
- if (wpa_s->mac_addr_pno) {
- params.mac_addr = wpa_s->mac_addr_pno;
- params.mac_addr_mask = wpa_s->mac_addr_pno + ETH_ALEN;
- }
- }
+ wpa_s->wpa_state <= WPA_SCANNING)
+ wpa_setup_mac_addr_rand_params(¶ms, wpa_s->mac_addr_pno);
wpa_scan_set_relative_rssi_params(wpa_s, ¶ms);
ret = wpa_supplicant_start_sched_scan(wpa_s, ¶ms);
os_free(params.filter_ssids);
+ os_free(params.mac_addr);
if (ret == 0)
wpa_s->pno = 1;
else
@@ -2843,6 +2867,32 @@
}
+int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant *wpa_s,
+ unsigned int type, u8 *mask)
+{
+ const u8 *to_copy;
+
+ if ((wpa_s->mac_addr_rand_enable & type) != type)
+ return -1;
+
+ if (type == MAC_ADDR_RAND_SCAN) {
+ to_copy = wpa_s->mac_addr_scan;
+ } else if (type == MAC_ADDR_RAND_SCHED_SCAN) {
+ to_copy = wpa_s->mac_addr_sched_scan;
+ } else if (type == MAC_ADDR_RAND_PNO) {
+ to_copy = wpa_s->mac_addr_pno;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "scan: Invalid MAC randomization type=0x%x",
+ type);
+ return -1;
+ }
+
+ os_memcpy(mask, to_copy + ETH_ALEN, ETH_ALEN);
+ return 0;
+}
+
+
int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s)
{
struct wpa_radio_work *work;
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 2aa0a8b..c9ce2ce 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -9,6 +9,28 @@
#ifndef SCAN_H
#define SCAN_H
+/*
+ * Noise floor values to use when we have signal strength
+ * measurements, but no noise floor measurements. These values were
+ * measured in an office environment with many APs.
+ */
+#define DEFAULT_NOISE_FLOOR_2GHZ (-89)
+#define DEFAULT_NOISE_FLOOR_5GHZ (-92)
+
+/*
+ * Channels with a great SNR can operate at full rate. What is a great SNR?
+ * This doc https://supportforums.cisco.com/docs/DOC-12954 says, "the general
+ * rule of thumb is that any SNR above 20 is good." This one
+ * http://www.cisco.com/en/US/tech/tk722/tk809/technologies_q_and_a_item09186a00805e9a96.shtml#qa23
+ * recommends 25 as a minimum SNR for 54 Mbps data rate. The estimates used in
+ * scan_est_throughput() allow even smaller SNR values for the maximum rates
+ * (21 for 54 Mbps, 22 for VHT80 MCS9, 24 for HT40 and HT20 MCS7). Use 25 as a
+ * somewhat conservative value here.
+ */
+#define GREAT_SNR 25
+
+#define IS_5GHZ(n) (n > 4000)
+
int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s);
void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec);
int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
@@ -52,12 +74,17 @@
int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
unsigned int type, const u8 *addr,
const u8 *mask);
+int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant *wpa_s,
+ unsigned int type, u8 *mask);
int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s);
void filter_scan_res(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *res);
void scan_snr(struct wpa_scan_res *res);
void scan_est_throughput(struct wpa_supplicant *wpa_s,
struct wpa_scan_res *res);
+unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
+ const u8 *ies, size_t ies_len, int rate,
+ int snr);
void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s);
#endif /* SCAN_H */
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index e2cc439..4eaece0 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -13,6 +13,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/ocv.h"
+#include "common/hw_features_common.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "common/wpa_common.h"
#include "common/sae.h"
@@ -37,9 +38,7 @@
static void sme_auth_timer(void *eloop_ctx, void *timeout_ctx);
static void sme_assoc_timer(void *eloop_ctx, void *timeout_ctx);
static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx);
-#ifdef CONFIG_IEEE80211W
static void sme_stop_sa_query(struct wpa_supplicant *wpa_s);
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
@@ -86,11 +85,16 @@
static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
const u8 *bssid, int external,
- int reuse)
+ int reuse, int *ret_use_pt)
{
struct wpabuf *buf;
size_t len;
const char *password;
+ struct wpa_bss *bss;
+ int use_pt = 0;
+
+ if (ret_use_pt)
+ *ret_use_pt = 0;
#ifdef CONFIG_TESTING_OPTIONS
if (wpa_s->sae_commit_override) {
@@ -119,6 +123,7 @@
os_memcmp(bssid, wpa_s->sme.sae.tmp->bssid, ETH_ALEN) == 0) {
wpa_printf(MSG_DEBUG,
"SAE: Reuse previously generated PWE on a retry with the same AP");
+ use_pt = wpa_s->sme.sae.tmp->h2e;
goto reuse_data;
}
if (sme_set_sae_group(wpa_s) < 0) {
@@ -126,7 +131,36 @@
return NULL;
}
- if (sae_prepare_commit(wpa_s->own_addr, bssid,
+ if (ssid->sae_password_id && wpa_s->conf->sae_pwe != 3)
+ use_pt = 1;
+
+ if (use_pt || wpa_s->conf->sae_pwe == 1 || wpa_s->conf->sae_pwe == 2) {
+ bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
+ if (bss) {
+ const u8 *rsnxe;
+
+ rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ if (rsnxe && rsnxe[1] >= 1)
+ use_pt = !!(rsnxe[2] &
+ BIT(WLAN_RSNX_CAPAB_SAE_H2E));
+ }
+
+ if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) &&
+ wpa_s->conf->sae_pwe != 3 &&
+ !use_pt) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Cannot use H2E with the selected AP");
+ return NULL;
+ }
+ }
+
+ if (use_pt &&
+ sae_prepare_commit_pt(&wpa_s->sme.sae, ssid->pt,
+ wpa_s->own_addr, bssid,
+ wpa_s->sme.sae_rejected_groups) < 0)
+ return NULL;
+ if (!use_pt &&
+ sae_prepare_commit(wpa_s->own_addr, bssid,
(u8 *) password, os_strlen(password),
ssid->sae_password_id,
&wpa_s->sme.sae) < 0) {
@@ -137,7 +171,7 @@
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;
+ len = wpa_s->sme.sae_token ? 3 + 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);
@@ -145,10 +179,16 @@
return NULL;
if (!external) {
wpabuf_put_le16(buf, 1); /* Transaction seq# */
- wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ wpabuf_put_le16(buf, use_pt ? WLAN_STATUS_SAE_HASH_TO_ELEMENT :
+ WLAN_STATUS_SUCCESS);
}
- sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token,
- ssid->sae_password_id);
+ if (sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token,
+ ssid->sae_password_id) < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+ if (ret_use_pt)
+ *ret_use_pt = use_pt;
return buf;
}
@@ -249,7 +289,7 @@
#if defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS)
const u8 *md = NULL;
#endif /* CONFIG_IEEE80211R || CONFIG_FILS */
- int i, bssid_changed;
+ int bssid_changed;
struct wpabuf *resp = NULL;
u8 ext_capab[18];
int ext_capab_len;
@@ -259,6 +299,7 @@
#ifdef CONFIG_MBO
const u8 *mbo_ie;
#endif /* CONFIG_MBO */
+ int omit_rsnxe = 0;
if (bss == NULL) {
wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
@@ -333,18 +374,18 @@
}
#endif /* CONFIG_SAE */
- for (i = 0; i < NUM_WEP_KEYS; i++) {
- if (ssid->wep_key_len[i])
- params.wep_key[i] = ssid->wep_key[i];
- params.wep_key_len[i] = ssid->wep_key_len[i];
- }
- params.wep_tx_keyidx = ssid->wep_tx_keyidx;
+#ifdef CONFIG_WEP
+ {
+ int i;
- bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
- os_memset(wpa_s->bssid, 0, ETH_ALEN);
- os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
- if (bssid_changed)
- wpas_notify_bssid_changed(wpa_s);
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if (ssid->wep_key_len[i])
+ params.wep_key[i] = ssid->wep_key[i];
+ params.wep_key_len[i] = ssid->wep_key_len[i];
+ }
+ params.wep_tx_keyidx = ssid->wep_tx_keyidx;
+ }
+#endif /* CONFIG_WEP */
if ((wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
@@ -466,6 +507,7 @@
wpa_dbg(wpa_s, MSG_DEBUG, "SME: FT mobility domain %02x%02x",
md[0], md[1]);
+ omit_rsnxe = !wpa_bss_get_ie(bss, WLAN_EID_RSNX);
if (wpa_s->sme.assoc_req_ie_len + 5 <
sizeof(wpa_s->sme.assoc_req_ie)) {
struct rsn_mdie *mdie;
@@ -492,7 +534,6 @@
}
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
wpa_s->sme.mfp = wpas_get_ssid_pmf(wpa_s, ssid);
if (wpa_s->sme.mfp != NO_MGMT_FRAME_PROTECTION) {
const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
@@ -505,7 +546,6 @@
wpa_s->sme.mfp = MGMT_FRAME_PROTECTION_REQUIRED;
}
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_P2P
if (wpa_s->global->p2p) {
@@ -540,7 +580,7 @@
sme_auth_handle_rrm(wpa_s, bss);
wpa_s->sme.assoc_req_ie_len += wpas_supp_op_class_ie(
- wpa_s, ssid, bss->freq,
+ wpa_s, ssid, bss,
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);
@@ -562,6 +602,27 @@
os_memcpy(pos, ext_capab, ext_capab_len);
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->rsnxe_override_assoc &&
+ wpabuf_len(wpa_s->rsnxe_override_assoc) <=
+ sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len) {
+ wpa_printf(MSG_DEBUG, "TESTING: RSNXE AssocReq override");
+ os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+ wpabuf_head(wpa_s->rsnxe_override_assoc),
+ wpabuf_len(wpa_s->rsnxe_override_assoc));
+ wpa_s->sme.assoc_req_ie_len +=
+ wpabuf_len(wpa_s->rsnxe_override_assoc);
+ } else
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (wpa_s->rsnxe_len > 0 &&
+ wpa_s->rsnxe_len <=
+ sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len &&
+ !omit_rsnxe) {
+ os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+ wpa_s->rsnxe, wpa_s->rsnxe_len);
+ wpa_s->sme.assoc_req_ie_len += wpa_s->rsnxe_len;
+ }
+
#ifdef CONFIG_HS20
if (is_hs20_network(wpa_s, ssid, bss)) {
struct wpabuf *hs20;
@@ -623,7 +684,7 @@
#ifdef CONFIG_MBO
mbo_ie = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
- if (mbo_ie) {
+ if (!wpa_s->disable_mbo_oce && mbo_ie) {
int len;
len = wpas_mbo_ie(wpa_s, wpa_s->sme.assoc_req_ie +
@@ -655,7 +716,7 @@
if (start)
resp = sme_auth_build_sae_commit(wpa_s, ssid,
bss->bssid, 0,
- start == 2);
+ start == 2, NULL);
else
resp = sme_auth_build_sae_confirm(wpa_s, 0);
if (resp == NULL) {
@@ -668,6 +729,12 @@
}
#endif /* CONFIG_SAE */
+ bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
+ os_memset(wpa_s->bssid, 0, ETH_ALEN);
+ os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
+ if (bssid_changed)
+ wpas_notify_bssid_changed(wpa_s);
+
old_ssid = wpa_s->current_ssid;
wpa_s->current_ssid = ssid;
wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
@@ -761,7 +828,7 @@
" (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid),
wpa_ssid_txt(params.ssid, params.ssid_len), params.freq);
- eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+ eapol_sm_notify_portValid(wpa_s->eapol, false);
wpa_clear_keys(wpa_s, bss->bssid);
wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
if (old_ssid != wpa_s->current_ssid)
@@ -855,6 +922,8 @@
/* Starting new connection, so clear the possibly used WPA IE from the
* previous association. */
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_s->rsnxe_len = 0;
sme_send_authentication(wpa_s, cwork->bss, cwork->ssid, 1);
}
@@ -909,7 +978,8 @@
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)
+ u16 auth_transaction, u16 seq_num,
+ u16 status_code)
{
struct ieee80211_mgmt *resp;
@@ -924,7 +994,7 @@
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);
+ resp->u.auth.status_code = host_to_le16(status_code);
if (params)
wpabuf_put_buf(buf, params);
@@ -932,29 +1002,36 @@
}
-static void sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s,
- const u8 *bssid,
- struct wpa_ssid *ssid)
+static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s,
+ const u8 *bssid,
+ struct wpa_ssid *ssid)
{
struct wpabuf *resp, *buf;
+ int use_pt;
- resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0);
- if (!resp)
- return;
+ resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0, &use_pt);
+ if (!resp) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to build SAE commit");
+ return -1;
+ }
wpa_s->sme.sae.state = SAE_COMMITTED;
buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + wpabuf_len(resp));
if (!buf) {
wpabuf_free(resp);
- return;
+ return -1;
}
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);
+ bssid, 1, wpa_s->sme.seq_num,
+ use_pt ? WLAN_STATUS_SAE_HASH_TO_ELEMENT :
+ WLAN_STATUS_SUCCESS);
+ wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0);
wpabuf_free(resp);
wpabuf_free(buf);
+
+ return 0;
}
@@ -968,12 +1045,14 @@
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;
+ if (wpa_s->conf->sae_pmkid_in_assoc && status == WLAN_STATUS_SUCCESS)
+ params.pmkid = wpa_s->sme.sae.pmkid;
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)
+static int 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;
@@ -987,13 +1066,12 @@
(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);
+ if (!ssid ||
+ sme_external_auth_send_sae_commit(wpa_s, data->external_auth.bssid,
+ ssid) < 0)
+ return -1;
+
+ return 0;
}
@@ -1017,8 +1095,9 @@
}
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);
+ da, 2, wpa_s->sme.seq_num,
+ WLAN_STATUS_SUCCESS);
+ wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0);
wpabuf_free(resp);
wpabuf_free(buf);
}
@@ -1043,7 +1122,9 @@
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);
+ if (sme_handle_external_auth_start(wpa_s, data) < 0)
+ sme_send_external_auth_status(wpa_s,
+ WLAN_STATUS_UNSPECIFIED_FAILURE);
} else if (data->external_auth.action == EXT_AUTH_ABORT) {
/* Report failure to driver for the wrong trigger */
sme_send_external_auth_status(wpa_s,
@@ -1052,6 +1133,52 @@
}
+static int sme_sae_is_group_enabled(struct wpa_supplicant *wpa_s, int group)
+{
+ int *groups = wpa_s->conf->sae_groups;
+ int default_groups[] = { 19, 20, 21, 0 };
+ int i;
+
+ if (!groups)
+ groups = default_groups;
+
+ for (i = 0; groups[i] > 0; i++) {
+ if (groups[i] == group)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int sme_check_sae_rejected_groups(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *groups)
+{
+ size_t i, count;
+ const u8 *pos;
+
+ if (!groups)
+ return 0;
+
+ pos = wpabuf_head(groups);
+ count = wpabuf_len(groups) / 2;
+ for (i = 0; i < count; i++) {
+ int enabled;
+ u16 group;
+
+ group = WPA_GET_LE16(pos);
+ pos += 2;
+ enabled = sme_sae_is_group_enabled(wpa_s, group);
+ wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
+ group, enabled ? "enabled" : "disabled");
+ if (enabled)
+ return 1;
+ }
+
+ return 0;
+}
+
+
static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
u16 status_code, const u8 *data, size_t len,
int external, const u8 *sa)
@@ -1067,11 +1194,16 @@
(external || wpa_s->current_bss) && wpa_s->current_ssid) {
int default_groups[] = { 19, 20, 21, 0 };
u16 group;
+ const u8 *token_pos;
+ size_t token_len;
+ int h2e = 0;
groups = wpa_s->conf->sae_groups;
if (!groups || groups[0] <= 0)
groups = default_groups;
+ wpa_hexdump(MSG_DEBUG, "SME: SAE anti-clogging token request",
+ data, len);
if (len < sizeof(le16)) {
wpa_dbg(wpa_s, MSG_DEBUG,
"SME: Too short SAE anti-clogging token request");
@@ -1089,8 +1221,30 @@
return -1;
}
wpabuf_free(wpa_s->sme.sae_token);
- wpa_s->sme.sae_token = wpabuf_alloc_copy(data + sizeof(le16),
- len - sizeof(le16));
+ token_pos = data + sizeof(le16);
+ token_len = len - sizeof(le16);
+ if (wpa_s->sme.sae.tmp)
+ h2e = wpa_s->sme.sae.tmp->h2e;
+ if (h2e) {
+ if (token_len < 3) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SME: Too short SAE anti-clogging token container");
+ return -1;
+ }
+ if (token_pos[0] != WLAN_EID_EXTENSION ||
+ token_pos[1] == 0 ||
+ token_pos[1] > token_len - 2 ||
+ token_pos[2] != WLAN_EID_EXT_ANTI_CLOGGING_TOKEN) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SME: Invalid SAE anti-clogging token container header");
+ return -1;
+ }
+ token_len = token_pos[1] - 1;
+ token_pos += 3;
+ }
+ wpa_s->sme.sae_token = wpabuf_alloc_copy(token_pos, token_len);
+ wpa_hexdump_buf(MSG_DEBUG, "SME: Requested anti-clogging token",
+ wpa_s->sme.sae_token);
if (!external)
sme_send_authentication(wpa_s, wpa_s->current_bss,
wpa_s->current_ssid, 2);
@@ -1106,6 +1260,8 @@
wpa_s->sme.sae.state == SAE_COMMITTED &&
(external || wpa_s->current_bss) && wpa_s->current_ssid) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE group not supported");
+ int_array_add_unique(&wpa_s->sme.sae_rejected_groups,
+ wpa_s->sme.sae.group);
wpa_s->sme.sae_group_index++;
if (sme_set_sae_group(wpa_s) < 0)
return -1; /* no other groups enabled */
@@ -1130,7 +1286,8 @@
return -1;
}
- if (status_code != WLAN_STATUS_SUCCESS)
+ if (status_code != WLAN_STATUS_SUCCESS &&
+ status_code != WLAN_STATUS_SAE_HASH_TO_ELEMENT)
return -1;
if (auth_transaction == 1) {
@@ -1142,12 +1299,29 @@
if ((!external && wpa_s->current_bss == NULL) ||
wpa_s->current_ssid == NULL)
return -1;
- if (wpa_s->sme.sae.state != SAE_COMMITTED)
+ if (wpa_s->sme.sae.state != SAE_COMMITTED) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Ignore commit message while waiting for confirm");
+ return 0;
+ }
+ if (wpa_s->sme.sae.tmp && wpa_s->sme.sae.tmp->h2e &&
+ status_code == WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Unexpected use of status code 0 in SAE commit when H2E was expected");
return -1;
+ }
+ if (wpa_s->sme.sae.tmp && !wpa_s->sme.sae.tmp->h2e &&
+ status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Unexpected use of status code for H2E in SAE commit when H2E was not expected");
+ return -1;
+ }
+
if (groups && groups[0] <= 0)
groups = NULL;
res = sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL,
- groups);
+ groups, status_code ==
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT);
if (res == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message due to reflection attack");
@@ -1156,6 +1330,12 @@
if (res != WLAN_STATUS_SUCCESS)
return -1;
+ if (wpa_s->sme.sae.tmp &&
+ sme_check_sae_rejected_groups(
+ wpa_s,
+ wpa_s->sme.sae.tmp->peer_rejected_groups))
+ return -1;
+
if (sae_process_commit(&wpa_s->sme.sae) < 0) {
wpa_printf(MSG_DEBUG, "SAE: Failed to process peer "
"commit");
@@ -1171,6 +1351,8 @@
sme_external_auth_send_sae_confirm(wpa_s, sa);
return 0;
} else if (auth_transaction == 2) {
+ if (status_code != WLAN_STATUS_SUCCESS)
+ return -1;
wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm");
if (wpa_s->sme.sae.state != SAE_CONFIRMED)
return -1;
@@ -1192,6 +1374,37 @@
}
+static int sme_sae_set_pmk(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ 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, bssid);
+ if (wpa_s->conf->sae_pmkid_in_assoc) {
+ /* Update the own RSNE contents now that we have set the PMK
+ * and added a PMKSA cache entry based on the successfully
+ * completed SAE exchange. In practice, this will add the PMKID
+ * into RSNE. */
+ if (wpa_s->sme.assoc_req_ie_len + 2 + PMKID_LEN >
+ sizeof(wpa_s->sme.assoc_req_ie)) {
+ wpa_msg(wpa_s, MSG_WARNING,
+ "RSN: Not enough room for inserting own PMKID into RSNE");
+ return -1;
+ }
+ if (wpa_insert_pmkid(wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len,
+ wpa_s->sme.sae.pmkid) < 0)
+ return -1;
+ wpa_hexdump(MSG_DEBUG,
+ "SME: Updated Association Request IEs",
+ wpa_s->sme.assoc_req_ie,
+ wpa_s->sme.assoc_req_ie_len);
+ }
+
+ return 0;
+}
+
+
void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s,
const u8 *auth_frame, size_t len)
{
@@ -1225,10 +1438,8 @@
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);
+ if (sme_sae_set_pmk(wpa_s, wpa_s->sme.ext_auth_bssid) < 0)
+ return;
}
}
@@ -1281,10 +1492,8 @@
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);
+ if (sme_sae_set_pmk(wpa_s, wpa_s->pending_bssid) < 0)
+ return;
}
#endif /* CONFIG_SAE */
@@ -1584,7 +1793,9 @@
#ifdef CONFIG_DPP2
if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && wpa_s->current_ssid &&
- wpa_s->current_ssid->dpp_netaccesskey) {
+ wpa_s->current_ssid->dpp_netaccesskey &&
+ wpa_s->current_ssid->dpp_pfs != 2 &&
+ !wpa_s->current_ssid->dpp_pfs_fallback) {
struct wpa_ssid *ssid = wpa_s->current_ssid;
dpp_pfs_free(wpa_s->dpp_pfs);
@@ -1658,6 +1869,9 @@
params.vhtcaps_mask = &vhtcaps_mask;
wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, ¶ms);
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ wpa_supplicant_apply_he_overrides(wpa_s, wpa_s->current_ssid, ¶ms);
+#endif /* CONFIG_HE_OVERRIDES */
#ifdef CONFIG_IEEE80211R
if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies &&
get_ie(wpa_s->sme.ft_ies, wpa_s->sme.ft_ies_len,
@@ -1773,6 +1987,11 @@
elems.osen_len + 2);
} else
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ if (elems.rsnxe)
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, elems.rsnxe - 2,
+ elems.rsnxe_len + 2);
+ else
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
if (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group)
params.p2p = 1;
@@ -1990,15 +2209,17 @@
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)
{
sme_clear_on_disassoc(wpa_s);
+#ifdef CONFIG_SAE
+ os_free(wpa_s->sme.sae_rejected_groups);
+ wpa_s->sme.sae_rejected_groups = NULL;
+#endif /* CONFIG_SAE */
eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
@@ -2056,13 +2277,14 @@
}
-int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
+int sme_proc_obss_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
{
- struct wpa_bss *bss;
const u8 *ie;
- u16 ht_cap;
u8 chan_list[P2P_MAX_CHANNELS], channel;
u8 num_channels = 0, num_intol = 0, i;
+ size_t j;
+ int pri_freq, sec_freq;
if (!wpa_s->sme.sched_obss_scan)
return 0;
@@ -2090,22 +2312,36 @@
os_memset(chan_list, 0, sizeof(chan_list));
- dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
- /* Skip other band bss */
+ pri_freq = wpa_s->assoc_freq;
+
+ switch (wpa_s->sme.ht_sec_chan) {
+ case HT_SEC_CHAN_ABOVE:
+ sec_freq = pri_freq + 20;
+ break;
+ case HT_SEC_CHAN_BELOW:
+ sec_freq = pri_freq - 20;
+ break;
+ case HT_SEC_CHAN_UNKNOWN:
+ default:
+ wpa_msg(wpa_s, MSG_WARNING,
+ "Undefined secondary channel: drop OBSS scan results");
+ return 1;
+ }
+
+ for (j = 0; j < scan_res->num; j++) {
+ struct wpa_scan_res *bss = scan_res->res[j];
enum hostapd_hw_mode mode;
+ int res;
+
+ /* Skip other band bss */
mode = ieee80211_freq_to_chan(bss->freq, &channel);
if (mode != HOSTAPD_MODE_IEEE80211G &&
mode != HOSTAPD_MODE_IEEE80211B)
continue;
- ie = wpa_bss_get_ie(bss, WLAN_EID_HT_CAP);
- ht_cap = (ie && (ie[1] == 26)) ? WPA_GET_LE16(ie + 2) : 0;
- wpa_printf(MSG_DEBUG, "SME OBSS scan BSS " MACSTR
- " freq=%u chan=%u ht_cap=0x%x",
- MAC2STR(bss->bssid), bss->freq, channel, ht_cap);
-
- if (!ht_cap || (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)) {
- if (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)
+ res = check_bss_coex_40mhz(bss, pri_freq, sec_freq);
+ if (res) {
+ if (res == 2)
num_intol++;
/* Check whether the channel is already considered */
@@ -2134,7 +2370,7 @@
int start, end;
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
- HOSTAPD_MODE_IEEE80211G);
+ HOSTAPD_MODE_IEEE80211G, 0);
if (mode == NULL) {
/* No channels supported in this band - use empty list */
params->freqs = os_zalloc(sizeof(int));
@@ -2241,7 +2477,7 @@
*/
if (!((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) ||
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_OBSS_SCAN)) ||
- ssid == NULL || ssid->mode != IEEE80211_MODE_INFRA)
+ ssid == NULL || ssid->mode != WPAS_MODE_INFRA)
return;
if (!wpa_s->hw.modes)
@@ -2287,8 +2523,6 @@
}
-#ifdef CONFIG_IEEE80211W
-
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 */
@@ -2429,6 +2663,10 @@
return;
if (wpa_s->sme.sa_query_count > 0)
return;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->disable_sa_query)
+ return;
+#endif /* CONFIG_TESTING_OPTIONS */
os_get_reltime(&now);
if (wpa_s->sme.last_unprot_disconnect.sec &&
@@ -2577,5 +2815,3 @@
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 1a7f9e8..42d5a83 100644
--- a/wpa_supplicant/sme.h
+++ b/wpa_supplicant/sme.h
@@ -37,7 +37,8 @@
void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s);
void sme_deinit(struct wpa_supplicant *wpa_s);
-int sme_proc_obss_scan(struct wpa_supplicant *wpa_s);
+int sme_proc_obss_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res);
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);
@@ -112,7 +113,8 @@
{
}
-static inline int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
+static inline int sme_proc_obss_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
{
return 0;
}
diff --git a/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
index 03ac507..da69a87 100644
--- a/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
+++ b/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
@@ -12,4 +12,4 @@
ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-nl80211-%I.conf -Dnl80211 -i%I
[Install]
-Alias=multi-user.target.wants/wpa_supplicant-nl80211@%i.service
+WantedBy=multi-user.target
diff --git a/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
index c8a744d..ca3054b 100644
--- a/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
+++ b/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
@@ -12,4 +12,4 @@
ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-wired-%I.conf -Dwired -i%I
[Install]
-Alias=multi-user.target.wants/wpa_supplicant-wired@%i.service
+WantedBy=multi-user.target
diff --git a/wpa_supplicant/systemd/wpa_supplicant.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
index 7788b38..55d2b9c 100644
--- a/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
+++ b/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
@@ -12,4 +12,4 @@
ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I
[Install]
-Alias=multi-user.target.wants/wpa_supplicant@%i.service
+WantedBy=multi-user.target
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 39cd163..2e09102 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -271,7 +271,6 @@
WNM_SLEEP_SUBELEM_GTK,
ptr);
ptr += 13 + gtk_len;
-#ifdef CONFIG_IEEE80211W
} else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) {
if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) {
wpa_printf(MSG_DEBUG, "WNM: Too short IGTK "
@@ -281,7 +280,15 @@
wpa_wnmsleep_install_key(wpa_s->wpa,
WNM_SLEEP_SUBELEM_IGTK, ptr);
ptr += 10 + WPA_IGTK_LEN;
-#endif /* CONFIG_IEEE80211W */
+ } else if (*ptr == WNM_SLEEP_SUBELEM_BIGTK) {
+ if (ptr[1] < 2 + 6 + WPA_BIGTK_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Too short BIGTK subelem");
+ break;
+ }
+ wpa_wnmsleep_install_key(wpa_s->wpa,
+ WNM_SLEEP_SUBELEM_BIGTK, ptr);
+ ptr += 10 + WPA_BIGTK_LEN;
} else
break; /* skip the loop */
}
@@ -452,7 +459,8 @@
break;
case WNM_NEIGHBOR_BSS_TERMINATION_DURATION:
if (elen < 10) {
- wpa_printf(MSG_DEBUG, "WNM: Too short bss_term_tsf");
+ wpa_printf(MSG_DEBUG,
+ "WNM: Too short BSS termination duration");
break;
}
rep->bss_term_tsf = WPA_GET_LE64(pos);
@@ -924,9 +932,9 @@
if (ie && ie[1] >= 1) {
vht_oper = (struct ieee80211_vht_operation *) (ie + 2);
- if (vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80MHZ ||
- vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_160MHZ ||
- vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80P80MHZ)
+ if (vht_oper->vht_op_info_chwidth == CHANWIDTH_80MHZ ||
+ vht_oper->vht_op_info_chwidth == CHANWIDTH_160MHZ ||
+ vht_oper->vht_op_info_chwidth == CHANWIDTH_80P80MHZ)
vht = vht_oper->vht_op_info_chwidth;
}
@@ -1370,12 +1378,19 @@
const u8 *vendor;
#endif /* CONFIG_MBO */
+ if (wpa_s->disable_mbo_oce || wpa_s->conf->disable_btm)
+ return;
+
if (end - pos < 5)
return;
#ifdef CONFIG_MBO
wpa_s->wnm_mbo_trans_reason_present = 0;
wpa_s->wnm_mbo_transition_reason = 0;
+ wpa_s->wnm_mbo_cell_pref_present = 0;
+ wpa_s->wnm_mbo_cell_preference = 0;
+ wpa_s->wnm_mbo_assoc_retry_delay_present = 0;
+ wpa_s->wnm_mbo_assoc_retry_delay_sec = 0;
#endif /* CONFIG_MBO */
if (wpa_s->current_bss)
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 695fcbe..07d5f31 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -52,6 +52,7 @@
static const char *global = NULL;
static const char *pid_file = NULL;
static const char *action_file = NULL;
+static int reconnect = 0;
static int ping_interval = 5;
static int interactive = 0;
static char *ifname_prefix = NULL;
@@ -80,7 +81,7 @@
static void usage(void)
{
- printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] "
+ printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvBr] "
"[-a<action file>] \\\n"
" [-P<pid file>] [-g<global ctrl>] [-G<ping interval>] "
"\\\n"
@@ -91,6 +92,8 @@
" -a = run in daemon mode executing the action file based on "
"events from\n"
" wpa_supplicant\n"
+ " -r = try to reconnect when client socket is disconnected.\n"
+ " This is useful only when used with -a.\n"
" -B = run a daemon in the background\n"
" default path: " CONFIG_CTRL_IFACE_DIR "\n"
" default interface: first interface found in socket path\n");
@@ -474,7 +477,7 @@
"p2p_optimize_listen_chan", "p2p_go_ht40", "p2p_go_vht",
"p2p_disabled", "p2p_go_ctwindow", "p2p_no_group_iface",
"p2p_ignore_shared_freq", "ip_addr_go", "ip_addr_mask",
- "ip_addr_start", "ip_addr_end",
+ "ip_addr_start", "ip_addr_end", "p2p_go_edmg",
#endif /* CONFIG_P2P */
"country", "bss_max_count", "bss_expiration_age",
"bss_expiration_scan_count", "filter_ssids", "filter_rssi",
@@ -499,6 +502,7 @@
"ignore_auth_resp",
#endif /* CONFIG_TESTING_OPTIONS */
"relative_rssi", "relative_band_adjust",
+ "extended_key_id",
};
int i, num_fields = ARRAY_SIZE(fields);
@@ -590,7 +594,7 @@
"tdls_external_control", "osu_dir", "wowlan_triggers",
"p2p_search_delay", "mac_addr", "rand_addr_lifetime",
"preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
- "reassoc_same_bss_optim"
+ "reassoc_same_bss_optim", "extended_key_id"
};
int i, num_fields = ARRAY_SIZE(fields);
@@ -1299,7 +1303,7 @@
static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- return wpa_ctrl_command(ctrl, "LIST_NETWORKS");
+ return wpa_cli_cmd(ctrl, "LIST_NETWORKS", 0, argc, argv);
}
@@ -1406,7 +1410,7 @@
"bssid_whitelist", "psk", "proto", "key_mgmt",
"bg_scan_period", "pairwise", "group", "auth_alg", "scan_freq",
"freq_list", "max_oper_chwidth", "ht40", "vht", "vht_center_freq1",
- "vht_center_freq2", "ht",
+ "vht_center_freq2", "ht", "edmg",
#ifdef IEEE8021X_EAPOL
"eap", "identity", "anonymous_identity", "password", "ca_cert",
"ca_path", "client_cert", "private_key", "private_key_passwd",
@@ -1427,22 +1431,19 @@
#ifdef IEEE8021X_EAPOL
"eap_workaround", "pac_file", "fragment_size", "ocsp",
#endif /* IEEE8021X_EAPOL */
-#ifdef CONFIG_MESH
- "mode", "no_auto_peer", "mesh_rssi_threshold",
-#else /* CONFIG_MESH */
"mode",
-#endif /* CONFIG_MESH */
"proactive_key_caching", "disabled", "id_str",
-#ifdef CONFIG_IEEE80211W
"ieee80211w",
-#endif /* CONFIG_IEEE80211W */
"mixed_cell", "frequency", "fixed_freq",
#ifdef CONFIG_MESH
+ "no_auto_peer", "mesh_rssi_threshold",
"mesh_basic_rates", "dot11MeshMaxRetries",
"dot11MeshRetryTimeout", "dot11MeshConfirmTimeout",
"dot11MeshHoldingTimeout",
#endif /* CONFIG_MESH */
"wpa_ptk_rekey", "bgscan", "ignore_broadcast_ssid",
+ "wpa_deny_ptk0_rekey",
+ "enable_edmg", "edmg_channel",
#ifdef CONFIG_P2P
"go_p2p_dev_addr", "p2p_client_list", "psk_list",
#endif /* CONFIG_P2P */
@@ -1459,6 +1460,9 @@
"vht_tx_mcs_nss_3", "vht_tx_mcs_nss_4", "vht_tx_mcs_nss_5",
"vht_tx_mcs_nss_6", "vht_tx_mcs_nss_7", "vht_tx_mcs_nss_8",
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ "disable_he",
+#endif /* CONFIG_HE_OVERRIDES */
"ap_max_inactivity", "dtim_period", "beacon_int",
#ifdef CONFIG_MACSEC
"macsec_policy",
@@ -1783,7 +1787,7 @@
}
if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
- printf("Connected to interface '%s.\n", ctrl_ifname);
+ printf("Connected to interface '%s'.\n", ctrl_ifname);
} else {
printf("Could not connect to interface '%s' - re-trying\n",
ctrl_ifname);
@@ -2064,6 +2068,13 @@
return wpa_cli_cmd(ctrl, "MESH_PEER_ADD", 1, argc, argv);
}
+
+static int wpa_cli_cmd_mesh_link_probe(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MESH_LINK_PROBE", 1, argc, argv);
+}
+
#endif /* CONFIG_MESH */
@@ -3384,6 +3395,9 @@
{ "mesh_peer_add", wpa_cli_cmd_mesh_peer_add, NULL,
cli_cmd_flag_none,
"<addr> [duration=<seconds>] = Add a mesh peer" },
+ { "mesh_link_probe", wpa_cli_cmd_mesh_link_probe, NULL,
+ cli_cmd_flag_none,
+ "<addr> [payload=<hex dump of payload>] = Probe a mesh link for a given peer by injecting a frame." },
#endif /* CONFIG_MESH */
#ifdef CONFIG_P2P
{ "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find,
@@ -3967,6 +3981,8 @@
wpa_cli_connected = 0;
wpa_cli_exec(action_file, ifname, "DISCONNECTED");
}
+ } else if (str_starts(pos, WPA_EVENT_CHANNEL_SWITCH_STARTED)) {
+ wpa_cli_exec(action_file, ctrl_ifname, pos);
} else if (str_starts(pos, AP_EVENT_ENABLED)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
} else if (str_starts(pos, AP_EVENT_DISABLED)) {
@@ -3993,6 +4009,10 @@
wpa_cli_exec(action_file, ifname, pos);
} else if (str_starts(pos, WPS_EVENT_ACTIVE)) {
wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, WPS_EVENT_PIN_ACTIVE)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, WPS_EVENT_CANCEL)) {
+ wpa_cli_exec(action_file, ifname, pos);
} else if (str_starts(pos, WPS_EVENT_TIMEOUT)) {
wpa_cli_exec(action_file, ifname, pos);
} else if (str_starts(pos, WPS_EVENT_FAIL)) {
@@ -4009,9 +4029,26 @@
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, DPP_EVENT_CONF_RECEIVED)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_CONFOBJ_AKM)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_CONFOBJ_SSID)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_CONNECTOR)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_CONFOBJ_PASS)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_CONFOBJ_PSK)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_C_SIGN_KEY)) {
+ wpa_cli_exec(action_file, ifname, pos);
+ } else if (str_starts(pos, DPP_EVENT_NET_ACCESS_KEY)) {
+ 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;
+ if (!reconnect)
+ wpa_cli_quit = 1;
}
}
@@ -4203,6 +4240,10 @@
if (wpa_ctrl_pending(ctrl) < 0) {
printf("Connection to wpa_supplicant lost - trying to "
"reconnect\n");
+ if (reconnect) {
+ eloop_terminate();
+ return;
+ }
wpa_cli_reconnect();
}
}
@@ -4550,6 +4591,8 @@
static void wpa_cli_terminate(int sig, void *ctx)
{
eloop_terminate();
+ if (reconnect)
+ wpa_cli_quit = 1;
}
@@ -4580,8 +4623,11 @@
if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
continue;
#endif /* _DIRENT_HAVE_D_TYPE */
+ /* Skip current/previous directory and special P2P Device
+ * interfaces. */
if (os_strcmp(dent->d_name, ".") == 0 ||
- os_strcmp(dent->d_name, "..") == 0)
+ os_strcmp(dent->d_name, "..") == 0 ||
+ os_strncmp(dent->d_name, "p2p-dev-", 8) == 0)
continue;
printf("Selected interface '%s'\n", dent->d_name);
ifname = os_strdup(dent->d_name);
@@ -4627,7 +4673,7 @@
return -1;
for (;;) {
- c = getopt(argc, argv, "a:Bg:G:hi:p:P:s:v");
+ c = getopt(argc, argv, "a:Bg:G:hi:p:P:rs:v");
if (c < 0)
break;
switch (c) {
@@ -4659,6 +4705,9 @@
case 'P':
pid_file = optarg;
break;
+ case 'r':
+ reconnect = 1;
+ break;
case 's':
client_socket_dir = optarg;
break;
@@ -4684,7 +4733,22 @@
if (ctrl_ifname == NULL)
ctrl_ifname = wpa_cli_get_default_ifname();
- if (interactive) {
+ if (reconnect && action_file && ctrl_ifname) {
+ while (!wpa_cli_quit) {
+ if (ctrl_conn)
+ wpa_cli_action(ctrl_conn);
+ else
+ os_sleep(1, 0);
+ wpa_cli_close_connection();
+ wpa_cli_open_connection(ctrl_ifname, 0);
+ if (ctrl_conn) {
+ if (wpa_ctrl_attach(ctrl_conn) != 0)
+ wpa_cli_close_connection();
+ else
+ wpa_cli_attached = 1;
+ }
+ }
+ } else if (interactive) {
wpa_cli_interactive();
} else {
if (!global &&
diff --git a/wpa_supplicant/wpa_gui-qt4/peers.cpp b/wpa_supplicant/wpa_gui-qt4/peers.cpp
index 3bcf2f5..0a0b3ff 100644
--- a/wpa_supplicant/wpa_gui-qt4/peers.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/peers.cpp
@@ -476,7 +476,9 @@
add_station(info);
reply_len = sizeof(reply) - 1;
- snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply);
+ res = snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply);
+ if (res < 0 || (size_t) res >= sizeof(cmd))
+ break;
res = wpagui->ctrlRequest(cmd, reply, &reply_len);
} while (res >= 0);
}
diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
index a0aa05e..9404ab4 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
@@ -12,6 +12,8 @@
#include <cstdio>
#include <unistd.h>
+#include <chrono>
+#include <thread>
#include <QMessageBox>
#include <QCloseEvent>
#include <QImageReader>
@@ -713,9 +715,22 @@
strstr(flags, "[DISABLED]") == NULL)
first_active = networkSelect->count() - 1;
- if (last)
- break;
start = end + 1;
+ if (*start && strchr(start, '\n'))
+ continue;
+
+ /* avoid race conditions */
+ std::this_thread::sleep_for(std::chrono::milliseconds(200));
+ QString cmd("LIST_NETWORKS LAST_ID=");
+ cmd.append(id);
+ if (ctrlRequest(cmd.toLocal8Bit().constData(), buf, &len) < 0)
+ break;
+
+ buf[len] = '\0';
+ start = strchr(buf, '\n');
+ if (!start)
+ break;
+ start++;
}
if (networkSelect->count() > 1)
diff --git a/wpa_supplicant/wpa_passphrase.c b/wpa_supplicant/wpa_passphrase.c
index adca1cc..538997e 100644
--- a/wpa_supplicant/wpa_passphrase.c
+++ b/wpa_supplicant/wpa_passphrase.c
@@ -31,9 +31,9 @@
if (argc > 2) {
passphrase = argv[2];
} else {
- printf("# reading passphrase from stdin\n");
+ fprintf(stderr, "# reading passphrase from stdin\n");
if (fgets(buf, sizeof(buf), stdin) == NULL) {
- printf("Failed to read passphrase\n");
+ fprintf(stderr, "Failed to read passphrase\n");
return 1;
}
buf[sizeof(buf) - 1] = '\0';
@@ -50,11 +50,11 @@
len = os_strlen(passphrase);
if (len < 8 || len > 63) {
- printf("Passphrase must be 8..63 characters\n");
+ fprintf(stderr, "Passphrase must be 8..63 characters\n");
return 1;
}
if (has_ctrl_char((u8 *) passphrase, len)) {
- printf("Invalid passphrase character\n");
+ fprintf(stderr, "Invalid passphrase character\n");
return 1;
}
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index b3ad45e..c5d7168 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -391,6 +391,7 @@
{
struct privsep_cmd_set_key *params;
int res;
+ struct wpa_driver_set_key_params p;
if (iface->drv_priv == NULL || iface->driver->set_key == NULL)
return;
@@ -402,14 +403,19 @@
params = buf;
- res = iface->driver->set_key(iface->ifname, iface->drv_priv,
- params->alg,
- params->addr, params->key_idx,
- params->set_tx,
- params->seq_len ? params->seq : NULL,
- params->seq_len,
- params->key_len ? params->key : NULL,
- params->key_len);
+ os_memset(&p, 0, sizeof(p));
+ p.ifname = iface->ifname;
+ p.alg = params->alg;
+ p.addr = params->addr;
+ p.key_idx = params->key_idx;
+ p.set_tx = params->set_tx;
+ p.seq = params->seq_len ? params->seq : NULL;
+ p.seq_len = params->seq_len;
+ p.key = params->key_len ? params->key : NULL;
+ p.key_len = params->key_len;
+ p.key_flag = params->key_flag;
+
+ res = iface->driver->set_key(iface->drv_priv, &p);
wpa_printf(MSG_DEBUG, "drv->set_key: res=%d", res);
}
@@ -598,7 +604,7 @@
}
dst_addr = buf;
- os_memcpy(&proto, buf + ETH_ALEN, 2);
+ os_memcpy(&proto, (char *) buf + ETH_ALEN, 2);
if (!wpa_priv_allowed_l2_proto(proto)) {
wpa_printf(MSG_DEBUG, "Refused l2_packet send for ethertype "
@@ -607,7 +613,8 @@
}
res = l2_packet_send(iface->l2[idx], dst_addr, proto,
- buf + ETH_ALEN + 2, len - ETH_ALEN - 2);
+ (unsigned char *) buf + ETH_ALEN + 2,
+ len - ETH_ALEN - 2);
wpa_printf(MSG_DEBUG, "L2 send[idx=%d]: res=%d", idx, res);
}
@@ -1183,14 +1190,15 @@
static void usage(void)
{
- printf("wpa_priv v" VERSION_STR "\n"
+ printf("wpa_priv v%s\n"
"Copyright (c) 2007-2017, Jouni Malinen <j@w1.fi> and "
"contributors\n"
"\n"
"usage:\n"
" wpa_priv [-Bdd] [-c<ctrl dir>] [-P<pid file>] "
"<driver:ifname> \\\n"
- " [driver:ifname ...]\n");
+ " [driver:ifname ...]\n",
+ VERSION_STR);
}
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 5d4adf4..ea62e59 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -36,6 +36,7 @@
#include "rsn_supp/preauth.h"
#include "rsn_supp/pmksa_cache.h"
#include "common/wpa_ctrl.h"
+#include "common/ieee802_11_common.h"
#include "common/ieee802_11_defs.h"
#include "common/hw_features_common.h"
#include "common/gas_server.h"
@@ -124,8 +125,12 @@
#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s);
#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+#ifdef CONFIG_OWE
+static void wpas_update_owe_connect_params(struct wpa_supplicant *wpa_s);
+#endif /* CONFIG_OWE */
+#ifdef CONFIG_WEP
/* Configure default/group WEP keys for static WEP */
int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
@@ -138,11 +143,15 @@
set = 1;
wpa_drv_set_key(wpa_s, WPA_ALG_WEP, NULL,
i, i == ssid->wep_tx_keyidx, NULL, 0,
- ssid->wep_key[i], ssid->wep_key_len[i]);
+ ssid->wep_key[i], ssid->wep_key_len[i],
+ i == ssid->wep_tx_keyidx ?
+ KEY_FLAG_GROUP_RX_TX_DEFAULT :
+ KEY_FLAG_GROUP_RX_TX);
}
return set;
}
+#endif /* CONFIG_WEP */
int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
@@ -196,7 +205,8 @@
/* TODO: should actually remember the previously used seq#, both for TX
* and RX from each STA.. */
- ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
+ ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen,
+ KEY_FLAG_GROUP_RX_TX_DEFAULT);
os_memset(key, 0, sizeof(key));
return ret;
}
@@ -310,14 +320,14 @@
* per-BSSID EAPOL authentication.
*/
eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
- eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
- eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
+ eapol_sm_notify_eap_success(wpa_s->eapol, true);
+ eapol_sm_notify_eap_fail(wpa_s->eapol, false);
return;
}
#endif /* CONFIG_IBSS_RSN */
- eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
- eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
+ eapol_sm_notify_eap_success(wpa_s->eapol, false);
+ eapol_sm_notify_eap_fail(wpa_s->eapol, false);
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
@@ -389,7 +399,9 @@
void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
+#ifdef CONFIG_WEP
int i;
+#endif /* CONFIG_WEP */
if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
wpa_s->key_mgmt = WPA_KEY_MGMT_WPS;
@@ -399,11 +411,15 @@
wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_s->rsnxe_len = 0;
wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
wpa_s->group_cipher = WPA_CIPHER_NONE;
wpa_s->mgmt_group_cipher = 0;
+#ifdef CONFIG_WEP
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (ssid->wep_key_len[i] > 5) {
wpa_s->pairwise_cipher = WPA_CIPHER_WEP104;
@@ -415,16 +431,15 @@
break;
}
}
+#endif /* CONFIG_WEP */
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED, 0);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
wpa_s->pairwise_cipher);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
-#ifdef CONFIG_IEEE80211W
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
wpa_s->mgmt_group_cipher);
-#endif /* CONFIG_IEEE80211W */
pmksa_cache_clear_current(wpa_s->wpa);
}
@@ -472,6 +487,31 @@
}
+void wpas_clear_disabled_interface(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
+ return;
+ wpa_dbg(wpa_s, MSG_DEBUG, "Clear cached state on disabled interface");
+ wpa_bss_flush(wpa_s);
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+void wpas_clear_driver_signal_override(struct wpa_supplicant *wpa_s)
+{
+ struct driver_signal_override *dso;
+
+ while ((dso = dl_list_first(&wpa_s->drv_signal_override,
+ struct driver_signal_override, list))) {
+ dl_list_del(&dso->list);
+ os_free(dso);
+ }
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
{
int i;
@@ -495,6 +535,15 @@
wpa_s->get_pref_freq_list_override = NULL;
wpabuf_free(wpa_s->last_assoc_req_wpa_ie);
wpa_s->last_assoc_req_wpa_ie = NULL;
+ os_free(wpa_s->extra_sae_rejected_groups);
+ wpa_s->extra_sae_rejected_groups = NULL;
+ wpabuf_free(wpa_s->rsne_override_eapol);
+ wpa_s->rsne_override_eapol = NULL;
+ wpabuf_free(wpa_s->rsnxe_override_assoc);
+ wpa_s->rsnxe_override_assoc = NULL;
+ wpabuf_free(wpa_s->rsnxe_override_eapol);
+ wpa_s->rsnxe_override_eapol = NULL;
+ wpas_clear_driver_signal_override(wpa_s);
#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_s->conf != NULL) {
@@ -541,6 +590,7 @@
#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_clear_disabled_interface, wpa_s, NULL);
wpas_wps_deinit(wpa_s);
@@ -690,25 +740,24 @@
*/
void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
{
- int i, max;
-
-#ifdef CONFIG_IEEE80211W
- max = 6;
-#else /* CONFIG_IEEE80211W */
- max = 4;
-#endif /* CONFIG_IEEE80211W */
+ int i, max = 6;
/* MLME-DELETEKEYS.request */
for (i = 0; i < max; i++) {
if (wpa_s->keys_cleared & BIT(i))
continue;
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, i, 0, NULL, 0,
- NULL, 0);
+ NULL, 0, KEY_FLAG_GROUP);
}
- if (!(wpa_s->keys_cleared & BIT(0)) && addr &&
+ /* Pairwise Key ID 1 for Extended Key ID is tracked in bit 15 */
+ if (~wpa_s->keys_cleared & (BIT(0) | BIT(15)) && addr &&
!is_zero_ether_addr(addr)) {
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
- 0);
+ if (!(wpa_s->keys_cleared & BIT(0)))
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_PAIRWISE);
+ if (!(wpa_s->keys_cleared & BIT(15)))
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 1, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_PAIRWISE);
/* MLME-SETPROTECTION.request(None) */
wpa_drv_mlme_setprotection(
wpa_s, addr,
@@ -845,6 +894,9 @@
enum wpa_states state)
{
enum wpa_states old_state = wpa_s->wpa_state;
+#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
+ bool update_fils_connect_params = false;
+#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
wpa_dbg(wpa_s, MSG_DEBUG, "State: %s -> %s",
wpa_supplicant_state_txt(wpa_s->wpa_state),
@@ -942,8 +994,12 @@
#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
if (!fils_hlp_sent && ssid && ssid->eap.erp)
- wpas_update_fils_connect_params(wpa_s);
+ update_fils_connect_params = true;
#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+#ifdef CONFIG_OWE
+ if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_OWE))
+ wpas_update_owe_connect_params(wpa_s);
+#endif /* CONFIG_OWE */
} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
state == WPA_ASSOCIATED) {
wpa_s->new_connection = 1;
@@ -983,7 +1039,15 @@
if (wpa_s->wpa_state == WPA_COMPLETED ||
old_state == WPA_COMPLETED)
wpas_notify_auth_changed(wpa_s);
+#ifdef CONFIG_DPP2
+ if (wpa_s->wpa_state == WPA_COMPLETED)
+ wpas_dpp_connected(wpa_s);
+#endif /* CONFIG_DPP2 */
}
+#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
+ if (update_fils_connect_params)
+ wpas_update_fils_connect_params(wpa_s);
+#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
}
@@ -1097,7 +1161,7 @@
* Clear forced success to clear EAP state for next
* authentication.
*/
- eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+ eapol_sm_notify_eap_success(wpa_s->eapol, false);
}
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
wpa_sm_set_config(wpa_s->wpa, NULL);
@@ -1179,7 +1243,6 @@
return -1;
}
-#ifdef CONFIG_IEEE80211W
if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
@@ -1187,7 +1250,6 @@
"reject");
return -1;
}
-#endif /* CONFIG_IEEE80211W */
return 0;
}
@@ -1224,15 +1286,17 @@
u8 *wpa_ie, size_t *wpa_ie_len)
{
struct wpa_ie_data ie;
- int sel, proto;
- const u8 *bss_wpa, *bss_rsn, *bss_osen;
+ int sel, proto, sae_pwe;
+ const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen;
if (bss) {
bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ bss_rsnx = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
bss_osen = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
- } else
- bss_wpa = bss_rsn = bss_osen = NULL;
+ } else {
+ bss_wpa = bss_rsn = bss_rsnx = bss_osen = NULL;
+ }
if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
@@ -1312,7 +1376,6 @@
ie.group_cipher = ssid->group_cipher;
ie.pairwise_cipher = ssid->pairwise_cipher;
ie.key_mgmt = ssid->key_mgmt;
-#ifdef CONFIG_IEEE80211W
ie.mgmt_group_cipher = 0;
if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
if (ssid->group_mgmt_cipher &
@@ -1331,7 +1394,6 @@
ie.mgmt_group_cipher =
WPA_CIPHER_AES_128_CMAC;
}
-#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OWE
if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
!ssid->owe_only &&
@@ -1351,12 +1413,10 @@
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected cipher suites: group %d "
"pairwise %d key_mgmt %d proto %d",
ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto);
-#ifdef CONFIG_IEEE80211W
if (ssid->ieee80211w) {
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected mgmt group cipher %d",
ie.mgmt_group_cipher);
}
-#endif /* CONFIG_IEEE80211W */
wpa_s->wpa_proto = proto;
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
@@ -1367,7 +1427,9 @@
if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
bss_wpa ? 2 + bss_wpa[1] : 0) ||
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
- bss_rsn ? 2 + bss_rsn[1] : 0))
+ bss_rsn ? 2 + bss_rsn[1] : 0) ||
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, bss_rsnx,
+ bss_rsnx ? 2 + bss_rsnx[1] : 0))
return -1;
}
@@ -1403,23 +1465,30 @@
#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 */
+#ifdef CONFIG_IEEE80211R
+ if (!(wpa_s->drv_flags & (WPA_DRIVER_FLAGS_SME |
+ WPA_DRIVER_FLAGS_UPDATE_FT_IES)))
+ sel &= ~WPA_KEY_MGMT_FT;
+#endif /* CONFIG_IEEE80211R */
+ 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);
if (0) {
#ifdef CONFIG_IEEE80211R
#ifdef CONFIG_SHA384
- } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+ } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) &&
+ os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
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. */
+ if (!ssid->ft_eap_pmksa_caching &&
+ pmksa_cache_get_current(wpa_s->wpa)) {
+ /* PMKSA caching with FT may have interoperability
+ * issues, so disable that case by default for now. */
wpa_dbg(wpa_s, MSG_DEBUG,
"WPA: Disable PMKSA caching for FT/802.1X connection");
pmksa_cache_clear_current(wpa_s->wpa);
@@ -1455,12 +1524,14 @@
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA256");
#endif /* CONFIG_FILS */
#ifdef CONFIG_IEEE80211R
- } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
+ } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X) &&
+ os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
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. */
+ if (!ssid->ft_eap_pmksa_caching &&
+ pmksa_cache_get_current(wpa_s->wpa)) {
+ /* PMKSA caching with FT may have interoperability
+ * issues, so disable that case by default for now. */
wpa_dbg(wpa_s, MSG_DEBUG,
"WPA: Disable PMKSA caching for FT/802.1X connection");
pmksa_cache_clear_current(wpa_s->wpa);
@@ -1484,7 +1555,6 @@
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_IEEE80211W
} else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
wpa_dbg(wpa_s, MSG_DEBUG,
@@ -1493,7 +1563,6 @@
wpa_s->key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
wpa_dbg(wpa_s, MSG_DEBUG,
"WPA: using KEY_MGMT PSK with SHA256");
-#endif /* CONFIG_IEEE80211W */
} else if (sel & WPA_KEY_MGMT_IEEE8021X) {
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
@@ -1524,7 +1593,13 @@
wpa_s->pairwise_cipher);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
-#ifdef CONFIG_IEEE80211W
+ if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
+ wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "RSN: Management frame protection required but the selected AP does not enable it");
+ return -1;
+ }
+
sel = ie.mgmt_group_cipher;
if (ssid->group_mgmt_cipher)
sel &= ssid->group_mgmt_cipher;
@@ -1558,16 +1633,54 @@
wpa_s->mgmt_group_cipher);
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 */
+ sae_pwe = wpa_s->conf->sae_pwe;
+ if (ssid->sae_password_id && sae_pwe != 3)
+ sae_pwe = 1;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, sae_pwe);
+#ifdef CONFIG_TESTING_OPTIONS
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_FT_RSNXE_USED,
+ wpa_s->ft_rsnxe_used);
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Extended Key ID is only supported in infrastructure BSS so far */
+ if (ssid->mode == WPAS_MODE_INFRA && wpa_s->conf->extended_key_id &&
+ (ssid->proto & WPA_PROTO_RSN) &&
+ ssid->pairwise_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_CCMP_256 |
+ WPA_CIPHER_GCMP | WPA_CIPHER_GCMP_256) &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID)) {
+ int use_ext_key_id = 0;
+
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "WPA: Enable Extended Key ID support");
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXT_KEY_ID,
+ wpa_s->conf->extended_key_id);
+ if (bss_rsn &&
+ wpa_s->conf->extended_key_id &&
+ wpa_s->pairwise_cipher != WPA_CIPHER_TKIP &&
+ (ie.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST))
+ use_ext_key_id = 1;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID,
+ use_ext_key_id);
+ } else {
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXT_KEY_ID, 0);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID, 0);
+ }
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;
}
+ wpa_s->rsnxe_len = sizeof(wpa_s->rsnxe);
+ if (wpa_sm_set_assoc_rsnxe_default(wpa_s->wpa, wpa_s->rsnxe,
+ &wpa_s->rsnxe_len)) {
+ wpa_msg(wpa_s, MSG_WARNING, "RSN: Failed to generate RSNXE");
+ return -1;
+ }
+
if (0) {
#ifdef CONFIG_DPP
} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
@@ -1689,6 +1802,20 @@
} else
wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
+ if (ssid->mode != WPAS_MODE_IBSS &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED) &&
+ (ssid->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_NEVER ||
+ (ssid->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_LOCAL_OK &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS)))) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Disable PTK0 rekey support - replaced with reconnect");
+ wpa_s->deny_ptk0_rekey = 1;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 1);
+ } else {
+ wpa_s->deny_ptk0_rekey = 0;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 0);
+ }
+
return 0;
}
@@ -1709,7 +1836,8 @@
case 2: /* Bits 16-23 */
#ifdef CONFIG_WNM
*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
- *pos |= 0x08; /* Bit 19 - BSS Transition */
+ if (!wpa_s->disable_mbo_oce && !wpa_s->conf->disable_btm)
+ *pos |= 0x08; /* Bit 19 - BSS Transition */
#endif /* CONFIG_WNM */
break;
case 3: /* Bits 24-31 */
@@ -1915,6 +2043,59 @@
}
+static void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_SAE
+ int *groups = conf->sae_groups;
+ int default_groups[] = { 19, 20, 21, 0 };
+ const char *password;
+
+ if (!groups || groups[0] <= 0)
+ groups = default_groups;
+
+ password = ssid->sae_password;
+ if (!password)
+ password = ssid->passphrase;
+
+ if ((conf->sae_pwe == 0 && !ssid->sae_password_id) || !password ||
+ conf->sae_pwe == 3) {
+ /* PT derivation not needed */
+ sae_deinit_pt(ssid->pt);
+ ssid->pt = NULL;
+ return;
+ }
+
+ if (ssid->pt)
+ return; /* PT already derived */
+ ssid->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len,
+ (const u8 *) password, os_strlen(password),
+ ssid->sae_password_id);
+#endif /* CONFIG_SAE */
+}
+
+
+static void wpa_s_clear_sae_rejected(struct wpa_supplicant *wpa_s)
+{
+#if defined(CONFIG_SAE) && defined(CONFIG_SME)
+ os_free(wpa_s->sme.sae_rejected_groups);
+ wpa_s->sme.sae_rejected_groups = NULL;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->extra_sae_rejected_groups) {
+ int i, *groups = wpa_s->extra_sae_rejected_groups;
+
+ for (i = 0; groups[i]; i++) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Indicate rejection of an extra SAE group %d",
+ groups[i]);
+ int_array_add_unique(&wpa_s->sme.sae_rejected_groups,
+ groups[i]);
+ }
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_SAE && CONFIG_SME */
+}
+
+
static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
/**
@@ -1932,6 +2113,7 @@
int rand_style;
wpa_s->own_disconnect_req = 0;
+ wpa_s->own_reconnect_req = 0;
/*
* If we are starting a new connection, any previously pending EAPOL
@@ -1945,6 +2127,7 @@
else
rand_style = ssid->mac_addr;
+ wpa_s->multi_ap_ie = 0;
wmm_ac_clear_saved_tspecs(wpa_s);
wpa_s->reassoc_same_bss = 0;
wpa_s->reassoc_same_ess = 0;
@@ -1961,6 +2144,11 @@
} else if (wpa_s->current_bss && wpa_s->current_bss != bss) {
os_get_reltime(&wpa_s->roam_start);
}
+ } else {
+#ifdef CONFIG_SAE
+ wpa_s_clear_sae_rejected(wpa_s);
+ wpa_s_setup_sae_pt(wpa_s->conf, ssid);
+#endif /* CONFIG_SAE */
}
if (rand_style > 0 && !wpa_s->reassoc_same_ess) {
@@ -2062,8 +2250,12 @@
bss->ie_len);
#endif /* CONFIG_TDLS */
+#ifdef CONFIG_MBO
+ wpas_mbo_check_pmf(wpa_s, bss, ssid);
+#endif /* CONFIG_MBO */
+
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
- ssid->mode == IEEE80211_MODE_INFRA) {
+ ssid->mode == WPAS_MODE_INFRA) {
sme_authenticate(wpa_s, bss, ssid);
return;
}
@@ -2137,6 +2329,7 @@
const struct wpa_ssid *ssid,
struct hostapd_freq_params *freq)
{
+ int ieee80211_mode = wpas_mode_to_ieee80211_mode(ssid->mode);
enum hostapd_hw_mode hw_mode;
struct hostapd_hw_modes *mode = NULL;
int ht40plus[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
@@ -2149,6 +2342,7 @@
struct hostapd_freq_params vht_freq;
int chwidth, seg0, seg1;
u32 vht_caps = 0;
+ int is_24ghz;
freq->freq = ssid->frequency;
@@ -2200,6 +2394,9 @@
if (!mode)
return;
+ is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
+ hw_mode == HOSTAPD_MODE_IEEE80211B;
+
#ifdef CONFIG_HT_OVERRIDES
if (ssid->disable_ht) {
freq->ht_enabled = 0;
@@ -2211,6 +2408,14 @@
if (!freq->ht_enabled)
return;
+ /* Allow HE on 2.4 GHz without VHT: see nl80211_put_freq_params() */
+ if (is_24ghz)
+ freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+#ifdef CONFIG_HE_OVERRIDES
+ if (is_24ghz && ssid->disable_he)
+ freq->he_enabled = 0;
+#endif /* CONFIG_HE_OVERRIDES */
+
/* Setup higher BW only for 5 GHz */
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
return;
@@ -2232,8 +2437,10 @@
#ifdef CONFIG_HT_OVERRIDES
if (ssid->disable_ht40) {
+#ifdef CONFIG_VHT_OVERRIDES
if (ssid->disable_vht)
return;
+#endif /* CONFIG_VHT_OVERRIDES */
goto skip_ht40;
}
#endif /* CONFIG_HT_OVERRIDES */
@@ -2279,8 +2486,7 @@
return;
}
- res = check_40mhz_5g(mode, scan_res, pri_chan->chan,
- sec_chan->chan);
+ res = check_40mhz_5g(scan_res, pri_chan, sec_chan);
switch (res) {
case 0:
/* Back to HT20 */
@@ -2331,6 +2537,9 @@
if (!vht_freq.vht_enabled)
return;
+ /* Enable HE with VHT for 5 GHz */
+ freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
+
/* setup center_freq1, bandwidth */
for (j = 0; j < ARRAY_SIZE(vht80); j++) {
if (freq->channel >= vht80[j] &&
@@ -2353,11 +2562,11 @@
return;
}
- chwidth = VHT_CHANWIDTH_80MHZ;
+ chwidth = CHANWIDTH_80MHZ;
seg0 = vht80[j] + 6;
seg1 = 0;
- if (ssid->max_oper_chwidth == VHT_CHANWIDTH_80P80MHZ) {
+ if (ssid->max_oper_chwidth == CHANWIDTH_80P80MHZ) {
/* setup center_freq2, bandwidth */
for (k = 0; k < ARRAY_SIZE(vht80); k++) {
/* Only accept 80 MHz segments separated by a gap */
@@ -2376,27 +2585,27 @@
continue;
/* Found a suitable second segment for 80+80 */
- chwidth = VHT_CHANWIDTH_80P80MHZ;
+ chwidth = CHANWIDTH_80P80MHZ;
vht_caps |=
VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
seg1 = vht80[k] + 6;
}
- if (chwidth == VHT_CHANWIDTH_80P80MHZ)
+ if (chwidth == CHANWIDTH_80P80MHZ)
break;
}
- } else if (ssid->max_oper_chwidth == VHT_CHANWIDTH_160MHZ) {
+ } else if (ssid->max_oper_chwidth == CHANWIDTH_160MHZ) {
if (freq->freq == 5180) {
- chwidth = VHT_CHANWIDTH_160MHZ;
+ chwidth = CHANWIDTH_160MHZ;
vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
seg0 = 50;
} else if (freq->freq == 5520) {
- chwidth = VHT_CHANWIDTH_160MHZ;
+ chwidth = CHANWIDTH_160MHZ;
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;
+ } else if (ssid->max_oper_chwidth == CHANWIDTH_USE_HT) {
+ chwidth = CHANWIDTH_USE_HT;
seg0 = vht80[j] + 2;
#ifdef CONFIG_HT_OVERRIDES
if (ssid->disable_ht40)
@@ -2404,11 +2613,19 @@
#endif /* CONFIG_HT_OVERRIDES */
}
+#ifdef CONFIG_HE_OVERRIDES
+ if (ssid->disable_he) {
+ vht_freq.he_enabled = 0;
+ freq->he_enabled = 0;
+ }
+#endif /* CONFIG_HE_OVERRIDES */
if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
- freq->channel, freq->ht_enabled,
- vht_freq.vht_enabled,
+ freq->channel, ssid->enable_edmg,
+ ssid->edmg_channel, freq->ht_enabled,
+ vht_freq.vht_enabled, freq->he_enabled,
freq->sec_channel_offset,
- chwidth, seg0, seg1, vht_caps) != 0)
+ chwidth, seg0, seg1, vht_caps,
+ &mode->he_capab[ieee80211_mode]) != 0)
return;
*freq = vht_freq;
@@ -2720,7 +2937,7 @@
#endif /* CONFIG_P2P */
if (bss) {
- wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss->freq,
+ wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss,
wpa_ie + wpa_ie_len,
max_wpa_ie_len -
wpa_ie_len);
@@ -2807,7 +3024,7 @@
#ifdef CONFIG_MBO
mbo_ie = bss ? wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE) : NULL;
- if (mbo_ie) {
+ if (!wpa_s->disable_mbo_oce && mbo_ie) {
int len;
len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
@@ -2869,7 +3086,8 @@
#ifdef CONFIG_DPP2
if (wpa_sm_get_key_mgmt(wpa_s->wpa) == WPA_KEY_MGMT_DPP &&
- ssid->dpp_netaccesskey) {
+ ssid->dpp_netaccesskey &&
+ ssid->dpp_pfs != 2 && !ssid->dpp_pfs_fallback) {
dpp_pfs_free(wpa_s->dpp_pfs);
wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey,
ssid->dpp_netaccesskey_len);
@@ -2922,6 +3140,23 @@
}
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->rsnxe_override_assoc &&
+ wpabuf_len(wpa_s->rsnxe_override_assoc) <=
+ max_wpa_ie_len - wpa_ie_len) {
+ wpa_printf(MSG_DEBUG, "TESTING: RSNXE AssocReq override");
+ os_memcpy(wpa_ie + wpa_ie_len,
+ wpabuf_head(wpa_s->rsnxe_override_assoc),
+ wpabuf_len(wpa_s->rsnxe_override_assoc));
+ wpa_ie_len += wpabuf_len(wpa_s->rsnxe_override_assoc);
+ } else
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (wpa_s->rsnxe_len > 0 &&
+ wpa_s->rsnxe_len <= max_wpa_ie_len - wpa_ie_len) {
+ os_memcpy(wpa_ie + wpa_ie_len, wpa_s->rsnxe, wpa_s->rsnxe_len);
+ wpa_ie_len += wpa_s->rsnxe_len;
+ }
+
if (ssid->multi_ap_backhaul_sta) {
size_t multi_ap_ie_len;
@@ -2947,6 +3182,24 @@
}
+#ifdef CONFIG_OWE
+static void wpas_update_owe_connect_params(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_driver_associate_params params;
+ u8 *wpa_ie;
+
+ 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_OWE */
+
+
#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s)
{
@@ -2975,6 +3228,117 @@
#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+static u8 wpa_ie_get_edmg_oper_chans(const u8 *edmg_ie)
+{
+ if (!edmg_ie || edmg_ie[1] < 6)
+ return 0;
+ return edmg_ie[EDMG_BSS_OPERATING_CHANNELS_OFFSET];
+}
+
+
+static u8 wpa_ie_get_edmg_oper_chan_width(const u8 *edmg_ie)
+{
+ if (!edmg_ie || edmg_ie[1] < 6)
+ return 0;
+ return edmg_ie[EDMG_OPERATING_CHANNEL_WIDTH_OFFSET];
+}
+
+
+/* Returns the intersection of two EDMG configurations.
+ * Note: The current implementation is limited to CB2 only (CB1 included),
+ * i.e., the implementation supports up to 2 contiguous channels.
+ * For supporting non-contiguous (aggregated) channels and for supporting
+ * CB3 and above, this function will need to be extended.
+ */
+static struct ieee80211_edmg_config
+get_edmg_intersection(struct ieee80211_edmg_config a,
+ struct ieee80211_edmg_config b,
+ u8 primary_channel)
+{
+ struct ieee80211_edmg_config result;
+ int i, contiguous = 0;
+ int max_contiguous = 0;
+
+ result.channels = b.channels & a.channels;
+ if (!result.channels) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG not possible: cannot intersect channels 0x%x and 0x%x",
+ a.channels, b.channels);
+ goto fail;
+ }
+
+ if (!(result.channels & BIT(primary_channel - 1))) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG not possible: the primary channel %d is not one of the intersected channels 0x%x",
+ primary_channel, result.channels);
+ goto fail;
+ }
+
+ /* Find max contiguous channels */
+ for (i = 0; i < 6; i++) {
+ if (result.channels & BIT(i))
+ contiguous++;
+ else
+ contiguous = 0;
+
+ if (contiguous > max_contiguous)
+ max_contiguous = contiguous;
+ }
+
+ /* Assuming AP and STA supports ONLY contiguous channels,
+ * bw configuration can have value between 4-7.
+ */
+ if ((b.bw_config < a.bw_config))
+ result.bw_config = b.bw_config;
+ else
+ result.bw_config = a.bw_config;
+
+ if ((max_contiguous >= 2 && result.bw_config < EDMG_BW_CONFIG_5) ||
+ (max_contiguous >= 1 && result.bw_config < EDMG_BW_CONFIG_4)) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG not possible: not enough contiguous channels %d for supporting CB1 or CB2",
+ max_contiguous);
+ goto fail;
+ }
+
+ return result;
+
+fail:
+ result.channels = 0;
+ result.bw_config = 0;
+ return result;
+}
+
+
+static struct ieee80211_edmg_config
+get_supported_edmg(struct wpa_supplicant *wpa_s,
+ struct hostapd_freq_params *freq,
+ struct ieee80211_edmg_config request_edmg)
+{
+ enum hostapd_hw_mode hw_mode;
+ struct hostapd_hw_modes *mode = NULL;
+ u8 primary_channel;
+
+ if (!wpa_s->hw.modes)
+ goto fail;
+
+ hw_mode = ieee80211_freq_to_chan(freq->freq, &primary_channel);
+ if (hw_mode == NUM_HOSTAPD_MODES)
+ goto fail;
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, hw_mode, 0);
+ if (!mode)
+ goto fail;
+
+ return get_edmg_intersection(mode->edmg, request_edmg, primary_channel);
+
+fail:
+ request_edmg.channels = 0;
+ request_edmg.bw_config = 0;
+ return request_edmg;
+}
+
+
#ifdef CONFIG_MBO
void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s)
{
@@ -3010,10 +3374,13 @@
struct wpa_ssid *ssid = cwork->ssid;
struct wpa_supplicant *wpa_s = work->wpa_s;
u8 *wpa_ie;
- int use_crypt, ret, i, bssid_changed;
+ const u8 *edmg_ie_oper;
+ int use_crypt, ret, bssid_changed;
unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt;
struct wpa_driver_associate_params params;
+#if defined(CONFIG_WEP) || defined(IEEE8021X_EAPOL)
int wep_keys_set = 0;
+#endif /* CONFIG_WEP || IEEE8021X_EAPOL */
int assoc_failed = 0;
struct wpa_ssid *old_ssid;
u8 prev_bssid[ETH_ALEN];
@@ -3102,6 +3469,8 @@
/* Starting new association, so clear the possibly used WPA IE from the
* previous association. */
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_s->rsnxe_len = 0;
wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, ¶ms, NULL);
if (!wpa_ie) {
@@ -3118,10 +3487,12 @@
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE)
use_crypt = 0;
+#ifdef CONFIG_WEP
if (wpa_set_wep_keys(wpa_s, ssid)) {
use_crypt = 1;
wep_keys_set = 1;
}
+#endif /* CONFIG_WEP */
}
if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS)
use_crypt = 0;
@@ -3193,6 +3564,71 @@
params.beacon_int = wpa_s->conf->beacon_int;
}
+ if (bss && ssid->enable_edmg)
+ edmg_ie_oper = get_ie_ext((const u8 *) (bss + 1), bss->ie_len,
+ WLAN_EID_EXT_EDMG_OPERATION);
+ else
+ edmg_ie_oper = NULL;
+
+ if (edmg_ie_oper) {
+ params.freq.edmg.channels =
+ wpa_ie_get_edmg_oper_chans(edmg_ie_oper);
+ params.freq.edmg.bw_config =
+ wpa_ie_get_edmg_oper_chan_width(edmg_ie_oper);
+ wpa_printf(MSG_DEBUG,
+ "AP supports EDMG channels 0x%x, bw_config %d",
+ params.freq.edmg.channels,
+ params.freq.edmg.bw_config);
+
+ /* User may ask for specific EDMG channel for EDMG connection
+ * (must be supported by AP)
+ */
+ if (ssid->edmg_channel) {
+ struct ieee80211_edmg_config configured_edmg;
+ enum hostapd_hw_mode hw_mode;
+ u8 primary_channel;
+
+ hw_mode = ieee80211_freq_to_chan(bss->freq,
+ &primary_channel);
+ if (hw_mode == NUM_HOSTAPD_MODES)
+ goto edmg_fail;
+
+ hostapd_encode_edmg_chan(ssid->enable_edmg,
+ ssid->edmg_channel,
+ primary_channel,
+ &configured_edmg);
+
+ if (ieee802_edmg_is_allowed(params.freq.edmg,
+ configured_edmg)) {
+ params.freq.edmg = configured_edmg;
+ wpa_printf(MSG_DEBUG,
+ "Use EDMG channel %d for connection",
+ ssid->edmg_channel);
+ } else {
+ edmg_fail:
+ params.freq.edmg.channels = 0;
+ params.freq.edmg.bw_config = 0;
+ wpa_printf(MSG_WARNING,
+ "EDMG channel %d not supported by AP, fallback to DMG",
+ ssid->edmg_channel);
+ }
+ }
+
+ if (params.freq.edmg.channels) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG before: channels 0x%x, bw_config %d",
+ params.freq.edmg.channels,
+ params.freq.edmg.bw_config);
+ params.freq.edmg = get_supported_edmg(wpa_s,
+ ¶ms.freq,
+ params.freq.edmg);
+ wpa_printf(MSG_DEBUG,
+ "EDMG after: channels 0x%x, bw_config %d",
+ params.freq.edmg.channels,
+ params.freq.edmg.bw_config);
+ }
+ }
+
params.pairwise_suite = cipher_pairwise;
params.group_suite = cipher_group;
params.mgmt_group_suite = cipher_group_mgmt;
@@ -3201,12 +3637,18 @@
wpa_s->auth_alg = params.auth_alg;
params.mode = ssid->mode;
params.bg_scan_period = ssid->bg_scan_period;
- for (i = 0; i < NUM_WEP_KEYS; i++) {
- if (ssid->wep_key_len[i])
- params.wep_key[i] = ssid->wep_key[i];
- params.wep_key_len[i] = ssid->wep_key_len[i];
+#ifdef CONFIG_WEP
+ {
+ int i;
+
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if (ssid->wep_key_len[i])
+ params.wep_key[i] = ssid->wep_key[i];
+ params.wep_key_len[i] = ssid->wep_key_len[i];
+ }
+ params.wep_tx_keyidx = ssid->wep_tx_keyidx;
}
- params.wep_tx_keyidx = ssid->wep_tx_keyidx;
+#endif /* CONFIG_WEP */
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
(params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
@@ -3221,7 +3663,7 @@
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;
+ params.req_handshake_offload = 1;
if (wpa_s->conf->key_mgmt_offload) {
if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
@@ -3243,7 +3685,6 @@
params.drop_unencrypted = use_crypt;
-#ifdef CONFIG_IEEE80211W
params.mgmt_frame_protection = wpas_get_ssid_pmf(wpa_s, ssid);
if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
@@ -3262,7 +3703,6 @@
#endif /* CONFIG_OWE */
}
}
-#endif /* CONFIG_IEEE80211W */
params.p2p = ssid->p2p_group;
@@ -3285,6 +3725,9 @@
params.vhtcaps_mask = &vhtcaps_mask;
wpa_supplicant_apply_vht_overrides(wpa_s, ssid, ¶ms);
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+ wpa_supplicant_apply_he_overrides(wpa_s, ssid, ¶ms);
+#endif /* CONFIG_HE_OVERRIDES */
#ifdef CONFIG_P2P
/*
@@ -3366,11 +3809,13 @@
wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
}
+#ifdef CONFIG_WEP
if (wep_keys_set &&
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC)) {
/* Set static WEP keys again */
wpa_set_wep_keys(wpa_s, ssid);
}
+#endif /* CONFIG_WEP */
if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) {
/*
@@ -3422,16 +3867,17 @@
* current AP.
*/
void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
- int reason_code)
+ u16 reason_code)
{
u8 *addr = NULL;
union wpa_event_data event;
int zero_addr = 0;
wpa_dbg(wpa_s, MSG_DEBUG, "Request to deauthenticate - bssid=" MACSTR
- " pending_bssid=" MACSTR " reason=%d state=%s",
+ " pending_bssid=" MACSTR " reason=%d (%s) state=%s",
MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
- reason_code, wpa_supplicant_state_txt(wpa_s->wpa_state));
+ reason_code, reason2str(reason_code),
+ wpa_supplicant_state_txt(wpa_s->wpa_state));
if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
(wpa_s->wpa_state == WPA_AUTHENTICATING ||
@@ -3473,7 +3919,7 @@
if (addr) {
wpa_drv_deauthenticate(wpa_s, addr, reason_code);
os_memset(&event, 0, sizeof(event));
- event.deauth_info.reason_code = (u16) reason_code;
+ event.deauth_info.reason_code = reason_code;
event.deauth_info.locally_generated = 1;
wpa_supplicant_event(wpa_s, EVENT_DEAUTH, &event);
if (zero_addr)
@@ -3483,6 +3929,15 @@
wpa_supplicant_clear_connection(wpa_s, addr);
}
+
+void wpa_supplicant_reconnect(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->own_reconnect_req = 1;
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED);
+
+}
+
+
static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
@@ -3754,9 +4209,12 @@
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
+ wpa_s_clear_sae_rejected(wpa_s);
wpa_s->last_owe_group = 0;
- if (ssid)
+ if (ssid) {
ssid->owe_transition_bss_select_count = 0;
+ wpa_s_setup_sae_pt(wpa_s->conf, ssid);
+ }
if (wpa_s->connect_without_scan ||
wpa_supplicant_fast_associate(wpa_s) != 1) {
@@ -4228,7 +4686,7 @@
!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
wpa_s->wpa_state != WPA_COMPLETED) &&
(wpa_s->current_ssid == NULL ||
- wpa_s->current_ssid->mode != IEEE80211_MODE_IBSS)) {
+ wpa_s->current_ssid->mode != WPAS_MODE_IBSS)) {
/* Timeout for completing IEEE 802.1X and WPA authentication */
int timeout = 10;
@@ -4294,16 +4752,23 @@
wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
/*
- * Set portValid = TRUE here since we are going to skip 4-way
+ * Set portValid = true here since we are going to skip 4-way
* handshake processing which would normally set portValid. We
* need this to allow the EAPOL state machines to be completed
* without going through EAPOL-Key handshake.
*/
- eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+ eapol_sm_notify_portValid(wpa_s->eapol, true);
}
}
+static int wpas_eapol_needs_l2_packet(struct wpa_supplicant *wpa_s)
+{
+ return !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT) ||
+ !(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX);
+}
+
+
int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
{
if ((!wpa_s->p2p_mgmt ||
@@ -4313,7 +4778,9 @@
wpa_s->l2 = l2_packet_init(wpa_s->ifname,
wpa_drv_get_mac_addr(wpa_s),
ETH_P_EAPOL,
- wpa_supplicant_rx_eapol, wpa_s, 0);
+ wpas_eapol_needs_l2_packet(wpa_s) ?
+ wpa_supplicant_rx_eapol : NULL,
+ wpa_s, 0);
if (wpa_s->l2 == NULL)
return -1;
@@ -4321,20 +4788,26 @@
L2_PACKET_FILTER_PKTTYPE))
wpa_dbg(wpa_s, MSG_DEBUG,
"Failed to attach pkt_type filter");
+
+ if (l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Failed to get own L2 address");
+ return -1;
+ }
} else {
const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
if (addr)
os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
}
- if (wpa_s->l2 && l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
- wpa_msg(wpa_s, MSG_ERROR, "Failed to get own L2 address");
- return -1;
- }
-
wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
wpas_wps_update_mac_addr(wpa_s);
+#ifdef CONFIG_FST
+ if (wpa_s->fst)
+ fst_update_mac_addr(wpa_s->fst, wpa_s->own_addr);
+#endif /* CONFIG_FST */
+
return 0;
}
@@ -4385,7 +4858,7 @@
os_memcpy(wpa_s->perm_addr, wpa_s->own_addr, ETH_ALEN);
wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
- if (wpa_s->bridge_ifname[0]) {
+ if (wpa_s->bridge_ifname[0] && wpas_eapol_needs_l2_packet(wpa_s)) {
wpa_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge "
"interface '%s'", wpa_s->bridge_ifname);
wpa_s->l2_br = l2_packet_init_bridge(
@@ -4462,6 +4935,9 @@
dl_list_init(&wpa_s->bss_tmp_disallowed);
dl_list_init(&wpa_s->fils_hlp_req);
+#ifdef CONFIG_TESTING_OPTIONS
+ dl_list_init(&wpa_s->drv_signal_override);
+#endif /* CONFIG_TESTING_OPTIONS */
return wpa_s;
}
@@ -4824,6 +5300,19 @@
#endif /* CONFIG_VHT_OVERRIDES */
+#ifdef CONFIG_HE_OVERRIDES
+void wpa_supplicant_apply_he_overrides(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params)
+{
+ if (!ssid)
+ return;
+
+ params->disable_he = ssid->disable_he;
+}
+#endif /* CONFIG_HE_OVERRIDES */
+
+
static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
{
#ifdef PCSC_FUNCS
@@ -4987,7 +5476,7 @@
static const u8 * wpas_fst_get_peer_first(void *ctx,
struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+ bool mb_only)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -5001,7 +5490,7 @@
static const u8 * wpas_fst_get_peer_next(void *ctx,
struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+ bool mb_only)
{
return NULL;
}
@@ -5697,8 +6186,8 @@
}
/* RSNA Supplicant Key Management - INITIALIZE */
- eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
- eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+ eapol_sm_notify_portEnabled(wpa_s->eapol, false);
+ eapol_sm_notify_portValid(wpa_s->eapol, false);
/* Initialize driver interface and register driver event handler before
* L2 receive handler so that association events are processed before
@@ -5765,8 +6254,8 @@
if (capa_res == 0) {
wpa_s->drv_capa_known = 1;
wpa_s->drv_flags = capa.flags;
+ wpa_s->drv_flags2 = capa.flags2;
wpa_s->drv_enc = capa.enc;
- wpa_s->drv_smps_modes = capa.smps_modes;
wpa_s->drv_rrm_flags = capa.rrm_flags;
wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
wpa_s->max_scan_ssids = capa.max_scan_ssids;
@@ -5943,7 +6432,7 @@
hs20_init(wpa_s);
#endif /* CONFIG_HS20 */
#ifdef CONFIG_MBO
- if (wpa_s->conf->oce) {
+ if (!wpa_s->disable_mbo_oce && wpa_s->conf->oce) {
if ((wpa_s->conf->oce & OCE_STA) &&
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA))
wpa_s->enable_oce = OCE_STA;
@@ -5990,11 +6479,17 @@
wpa_s->disconnected = 1;
if (wpa_s->drv_priv) {
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
+ /* Don't deauthenticate if WoWLAN is enabled */
+ if (!wpa_drv_get_wowlan(wpa_s)) {
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
- wpa_drv_set_countermeasures(wpa_s, 0);
- wpa_clear_keys(wpa_s, NULL);
+ wpa_drv_set_countermeasures(wpa_s, 0);
+ wpa_clear_keys(wpa_s, NULL);
+ } else {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Do not deauthenticate as part of interface deinit since WoWLAN is enabled");
+ }
}
wpa_supplicant_cleanup(wpa_s);
@@ -6041,6 +6536,7 @@
}
os_free(wpa_s->ssids_from_scan_req);
+ os_free(wpa_s->last_scan_freqs);
os_free(wpa_s);
}
@@ -6374,7 +6870,7 @@
if (params->wpa_debug_file_path)
wpa_debug_open_file(params->wpa_debug_file_path);
- else
+ if (!params->wpa_debug_file_path && !params->wpa_debug_syslog)
wpa_debug_setup_stdout();
if (params->wpa_debug_syslog)
wpa_debug_open_syslog();
@@ -6442,7 +6938,7 @@
wpa_debug_timestamp = global->params.wpa_debug_timestamp =
params->wpa_debug_timestamp;
- wpa_printf(MSG_DEBUG, "wpa_supplicant v" VERSION_STR);
+ wpa_printf(MSG_DEBUG, "wpa_supplicant v%s", VERSION_STR);
if (eloop_init()) {
wpa_printf(MSG_ERROR, "Failed to initialize event loop");
@@ -6630,6 +7126,9 @@
wpa_s->conf->wowlan_triggers);
}
+ if (wpa_s->conf->changed_parameters & CFG_CHANGED_DISABLE_BTM)
+ wpa_supplicant_set_default_scan_ies(wpa_s);
+
#ifdef CONFIG_WPS
wpas_wps_update_config(wpa_s);
#endif /* CONFIG_WPS */
@@ -6703,7 +7202,7 @@
* There is no point in blacklisting the AP if this event is
* generated based on local request to disconnect.
*/
- if (wpa_s->own_disconnect_req) {
+ if (wpa_s->own_disconnect_req || wpa_s->own_reconnect_req) {
wpa_s->own_disconnect_req = 0;
wpa_dbg(wpa_s, MSG_DEBUG,
"Ignore connection failure due to local request to disconnect");
@@ -6907,8 +7406,8 @@
wpa_s->reassociate = 1;
break;
case WPA_CTRL_REQ_EAP_PIN:
- str_clear_free(eap->pin);
- eap->pin = os_strdup(value);
+ str_clear_free(eap->cert.pin);
+ eap->cert.pin = os_strdup(value);
eap->pending_req_pin = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
@@ -6922,8 +7421,8 @@
eap->pending_req_otp_len = 0;
break;
case WPA_CTRL_REQ_EAP_PASSPHRASE:
- str_clear_free(eap->private_key_passwd);
- eap->private_key_passwd = os_strdup(value);
+ str_clear_free(eap->cert.private_key_passwd);
+ eap->cert.private_key_passwd = os_strdup(value);
eap->pending_req_passphrase = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
@@ -6968,8 +7467,10 @@
int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
+#ifdef CONFIG_WEP
int i;
unsigned int drv_enc;
+#endif /* CONFIG_WEP */
if (wpa_s->p2p_mgmt)
return 1; /* no normal network profiles on p2p_mgmt interface */
@@ -6980,6 +7481,7 @@
if (ssid->disabled)
return 1;
+#ifdef CONFIG_WEP
if (wpa_s->drv_capa_known)
drv_enc = wpa_s->drv_enc;
else
@@ -6997,6 +7499,7 @@
continue;
return 1; /* invalid WEP key */
}
+#endif /* CONFIG_WEP */
if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
(!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk &&
@@ -7010,7 +7513,6 @@
int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
-#ifdef CONFIG_IEEE80211W
if (ssid == NULL || ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
if (wpa_s->conf->pmf == MGMT_FRAME_PROTECTION_OPTIONAL &&
!(wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)) {
@@ -7039,9 +7541,6 @@
}
return ssid->ieee80211w;
-#else /* CONFIG_IEEE80211W */
- return NO_MGMT_FRAME_PROTECTION;
-#endif /* CONFIG_IEEE80211W */
}
@@ -7398,12 +7897,17 @@
struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
- u16 num_modes, enum hostapd_hw_mode mode)
+ u16 num_modes, enum hostapd_hw_mode mode,
+ int is_6ghz)
{
u16 i;
for (i = 0; i < num_modes; i++) {
- if (modes[i].mode == mode)
+ if (modes[i].mode != mode ||
+ !modes[i].num_channels || !modes[i].channels)
+ continue;
+ if ((!is_6ghz && !is_6ghz_freq(modes[i].channels[0].freq)) ||
+ (is_6ghz && is_6ghz_freq(modes[i].channels[0].freq)))
return &modes[i];
}
@@ -7517,3 +8021,150 @@
return 1;
}
+
+
+int wpas_enable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
+ unsigned int type, const u8 *addr,
+ const u8 *mask)
+{
+ if ((addr && !mask) || (!addr && mask)) {
+ wpa_printf(MSG_INFO,
+ "MAC_ADDR_RAND_SCAN invalid addr/mask combination");
+ return -1;
+ }
+
+ if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
+ wpa_printf(MSG_INFO,
+ "MAC_ADDR_RAND_SCAN cannot allow multicast address");
+ return -1;
+ }
+
+ if (type & MAC_ADDR_RAND_SCAN) {
+ if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
+ addr, mask))
+ return -1;
+ }
+
+ if (type & MAC_ADDR_RAND_SCHED_SCAN) {
+ 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) {
+ 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);
+ }
+ }
+
+ return 0;
+}
+
+
+int wpas_disable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
+ unsigned int type)
+{
+ wpas_mac_addr_rand_scan_clear(wpa_s, type);
+ if (wpa_s->pno) {
+ if (type & MAC_ADDR_RAND_PNO) {
+ wpas_stop_pno(wpa_s);
+ wpas_start_pno(wpa_s);
+ }
+ } else if (wpa_s->sched_scanning && (type & MAC_ADDR_RAND_SCHED_SCAN)) {
+ wpas_scan_restart_sched_scan(wpa_s);
+ }
+
+ return 0;
+}
+
+
+int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
+ struct wpa_signal_info *si)
+{
+ int res;
+
+ if (!wpa_s->driver->signal_poll)
+ return -1;
+
+ res = wpa_s->driver->signal_poll(wpa_s->drv_priv, si);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (res == 0) {
+ struct driver_signal_override *dso;
+
+ dl_list_for_each(dso, &wpa_s->drv_signal_override,
+ struct driver_signal_override, list) {
+ if (os_memcmp(wpa_s->bssid, dso->bssid,
+ ETH_ALEN) != 0)
+ continue;
+ wpa_printf(MSG_DEBUG,
+ "Override driver signal_poll information: current_signal: %d->%d avg_signal: %d->%d avg_beacon_signal: %d->%d current_noise: %d->%d",
+ si->current_signal,
+ dso->si_current_signal,
+ si->avg_signal,
+ dso->si_avg_signal,
+ si->avg_beacon_signal,
+ dso->si_avg_beacon_signal,
+ si->current_noise,
+ dso->si_current_noise);
+ si->current_signal = dso->si_current_signal;
+ si->avg_signal = dso->si_avg_signal;
+ si->avg_beacon_signal = dso->si_avg_beacon_signal;
+ si->current_noise = dso->si_current_noise;
+ break;
+ }
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ return res;
+}
+
+
+struct wpa_scan_results *
+wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_scan_results *scan_res;
+#ifdef CONFIG_TESTING_OPTIONS
+ size_t idx;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (!wpa_s->driver->get_scan_results2)
+ return NULL;
+
+ scan_res = wpa_s->driver->get_scan_results2(wpa_s->drv_priv);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ for (idx = 0; scan_res && idx < scan_res->num; idx++) {
+ struct driver_signal_override *dso;
+ struct wpa_scan_res *res = scan_res->res[idx];
+
+ dl_list_for_each(dso, &wpa_s->drv_signal_override,
+ struct driver_signal_override, list) {
+ if (os_memcmp(res->bssid, dso->bssid, ETH_ALEN) != 0)
+ continue;
+ wpa_printf(MSG_DEBUG,
+ "Override driver scan signal level %d->%d for "
+ MACSTR,
+ res->level, dso->scan_level,
+ MAC2STR(res->bssid));
+ res->flags |= WPA_SCAN_QUAL_INVALID;
+ if (dso->scan_level < 0)
+ res->flags |= WPA_SCAN_LEVEL_DBM;
+ else
+ res->flags &= ~WPA_SCAN_LEVEL_DBM;
+ res->level = dso->scan_level;
+ break;
+ }
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ return scan_res;
+}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index a9205f0..3b90567 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -94,11 +94,8 @@
# 1: wpa_supplicant initiates scanning and AP selection; if no APs matching to
# the currently enabled networks are found, a new network (IBSS or AP mode
# operation) may be initialized (if configured) (default)
-# 0: driver takes care of scanning, AP selection, and IEEE 802.11 association
-# parameters (e.g., WPA IE generation); this mode can also be used with
-# non-WPA drivers when using IEEE 802.1X mode; do not try to associate with
-# APs (i.e., external program needs to control association). This mode must
-# also be used when using wired Ethernet drivers (including MACsec).
+# 0: This mode must only be used when using wired Ethernet drivers
+# (including MACsec).
# 2: like 0, but associate with APs using security policy and SSID (but not
# BSSID); this can be used, e.g., with ndiswrapper and NDIS drivers to
# enable operation with hidden SSIDs and optimized roaming; in this mode,
@@ -106,8 +103,8 @@
# the driver reports successful association; each network block should have
# explicit security policy (i.e., only one option in the lists) for
# key_mgmt, pairwise, group, proto variables
-# Note: ap_scan=2 should not be used with the nl80211 driver interface (the
-# current Linux interface). ap_scan=1 is optimized work working with nl80211.
+# Note: ap_scan=0/2 should not be used with the nl80211 driver interface (the
+# current Linux interface). ap_scan=1 is the only option working with nl80211.
# For finding networks using hidden SSID, scan_ssid=1 in the network block can
# be used with nl80211.
# When using IBSS or AP mode, ap_scan=2 mode can force the new network to be
@@ -311,6 +308,26 @@
# by executing the WPS protocol.
#wps_priority=0
+# Device Provisioning Protocol (DPP) parameters
+#
+# How to process DPP configuration
+# 0 = report received configuration to an external program for
+# processing; do not generate any network profile internally (default)
+# 1 = report received configuration to an external program and generate
+# a network profile internally, but do not automatically connect
+# to the created (disabled) profile; the network profile id is
+# reported to external programs
+# 2 = report received configuration to an external program, generate
+# a network profile internally, try to connect to the created
+# profile automatically
+#dpp_config_processing=0
+#
+# Name for Enrollee's DPP Configuration Request
+#dpp_name=Test
+#
+# MUD URL for Enrollee's DPP Configuration Request (optional)
+#dpp_mud_url=https://example.com/mud
+
# Maximum number of BSS entries to keep in memory
# Default: 200
# This can be used to limit memory use on the BSS entries (cached scan
@@ -405,6 +422,16 @@
# since all implementations are required to support group 19.
#sae_groups=19 20 21
+# SAE mechanism for PWE derivation
+# 0 = hunting-and-pecking loop only (default without password identifier)
+# 1 = hash-to-element only (default with password identifier)
+# 2 = both hunting-and-pecking loop and hash-to-element enabled
+# Note: The default value is likely to change from 0 to 2 once the new
+# hash-to-element mechanism has received more interoperability testing.
+# When using SAE password identifier, the hash-to-element mechanism is used
+# regardless of the sae_pwe parameter value.
+#sae_pwe=0
+
# Default value for DTIM period (if not overridden in network block)
#dtim_period=2
@@ -454,6 +481,11 @@
# 0 = use permanent MAC address
# 1 = use random MAC address
# 2 = like 1, but maintain OUI (with local admin bit set)
+# Note that this setting is ignored when a specific MAC address is needed for
+# a full protocol exchange that includes GAS, e.g., when going through a DPP
+# exchange that exposes the configured interface address as part of the DP
+# Public Action frame exchanges before using GAS. That same address is then used
+# during the GAS exchange as well to avoid breaking the protocol expectations.
#gas_rand_mac_addr=0
# Lifetime of GAS random MAC address in seconds (default: 60)
@@ -775,6 +807,11 @@
# Set BIT(1) to Enable OCE in STA-CFON mode
#oce=1
+# Extended Key ID support for Individually Addressed frames
+# 0 = force off: Do not use Extended Key ID (default)
+# 1 = auto: Activate Extended Key ID support if the driver supports it
+#extended_key_id=0
+
# network block
#
# Each network (usually AP's sharing the same SSID) is configured as a separate
@@ -927,7 +964,8 @@
# management frames) certification program are:
# PMF enabled: ieee80211w=1 and key_mgmt=WPA-EAP WPA-EAP-SHA256
# PMF required: ieee80211w=2 and key_mgmt=WPA-EAP-SHA256
-# (and similarly for WPA-PSK and WPA-WPSK-SHA256 if WPA2-Personal is used)
+# (and similarly for WPA-PSK and WPA-PSK-SHA256 if WPA2-Personal is used)
+# WPA3-Personal-only mode: ieee80211w=2 and key_mgmt=SAE
#
# ocv: whether operating channel validation is enabled
# This is a countermeasure against multi-channel man-in-the-middle attacks.
@@ -1058,6 +1096,14 @@
# 0 = disabled (default unless changed with the global okc parameter)
# 1 = enabled
#
+# ft_eap_pmksa_caching:
+# Whether FT-EAP PMKSA caching is allowed
+# 0 = do not try to use PMKSA caching with FT-EAP (default)
+# 1 = try to use PMKSA caching with FT-EAP
+# This controls whether to try to use PMKSA caching with FT-EAP for the
+# FT initial mobility domain association.
+#ft_eap_pmksa_caching=0
+#
# wep_key0..3: Static WEP key (ASCII in double quotation, e.g. "abcde" or
# hex without quotation, e.g., 0102030405)
# wep_tx_keyidx: Default WEP key index (TX) (0..3)
@@ -1065,6 +1111,18 @@
# wpa_ptk_rekey: Maximum lifetime for PTK in seconds. This can be used to
# enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies.
#
+# wpa_deny_ptk0_rekey: Workaround for PTK rekey issues
+# PTK0 rekeys (using only one Key ID value for pairwise keys) can degrade the
+# security and stability with some cards.
+# To avoid the issues wpa_supplicant can replace those PTK rekeys (including
+# EAP reauthentications) with fast reconnects.
+#
+# Available options:
+# 0 = always rekey when configured/instructed (default)
+# 1 = only rekey when the local driver is explicitly indicating it can perform
+# this operation without issues
+# 2 = never allow problematic PTK0 rekeys
+#
# group_rekey: Group rekeying time in seconds. This value, if non-zero, is used
# as the dot11RSNAConfigGroupRekeyTime parameter when operating in
# Authenticator role in IBSS, or in AP and mesh modes.
@@ -1315,6 +1373,12 @@
# certificate. See altsubject_match documentation for more details.
# domain_suffix_match2: Constraint for server domain name. See
# domain_suffix_match for more details.
+# ocsp2: See ocsp for more details.
+#
+# Separate machine credentials can be configured for EAP-TEAP Phase 2 with
+# "machine_" prefix (e.g., "machine_identity") in the configuration parameters.
+# See the parameters without that prefix for more details on the meaning and
+# format of each such parameter.
#
# fragment_size: Maximum EAP fragment size in bytes (default 1398).
# This value limits the fragment size for EAP methods that support
@@ -1402,6 +1466,12 @@
# 1-65535 = DH Group to use for FILS PFS
#fils_dh_group=0
+# DPP PFS
+# 0: allow PFS to be used or not used (default)
+# 1: require PFS to be used (note: not compatible with DPP R1)
+# 2: do not allow PFS to be used
+#dpp_pfs=0
+
# MAC address policy
# 0 = use permanent MAC address
# 1 = use random MAC address for each ESS connection
@@ -1508,6 +1578,22 @@
# Transitioning between states).
#fst_llt=100
+# BSS Transition Management
+# disable_btm - Disable BSS transition management in STA
+# Set to 0 to enable BSS transition management (default behavior)
+# Set to 1 to disable BSS transition management
+#disable_btm=0
+
+# Enable EDMG capability in STA/AP mode, default value is false
+#enable_edmg=1
+
+# This value is used to configure the channel bonding feature.
+# Default value is 0.
+# Relevant only if enable_edmg is true
+# In AP mode it defines the EDMG channel to use for AP operation.
+# In STA mode it defines the EDMG channel for connection (if supported by AP).
+#edmg_channel=9
+
# Example blocks:
# Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 7eef32c..2f95eeb 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -47,6 +47,9 @@
struct wpas_dbus_priv;
struct wpas_hidl_priv;
+/* How many seconds to consider old scan results valid for association. */
+#define SCAN_RES_VALID_FOR_CONNECT 5
+
/**
* struct wpa_interface - Parameters for wpa_supplicant_add_iface()
*/
@@ -280,6 +283,7 @@
struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */
int p2p_disabled;
int cross_connection;
+ int p2p_long_listen; /* remaining time in long Listen state in ms */
struct wpa_freq_range_list p2p_disallow_freq;
struct wpa_freq_range_list p2p_go_avoid_freq;
enum wpa_conc_pref {
@@ -477,6 +481,16 @@
struct wpabuf *pkt;
};
+struct driver_signal_override {
+ struct dl_list list;
+ u8 bssid[ETH_ALEN];
+ int si_current_signal;
+ int si_avg_signal;
+ int si_avg_beacon_signal;
+ int si_current_noise;
+ int scan_level;
+};
+
/**
* struct wpa_supplicant - Internal data for wpa_supplicant interface
*
@@ -540,6 +554,7 @@
/* Selected configuration (based on Beacon/ProbeResp WPA IE) */
int pairwise_cipher;
+ int deny_ptk0_rekey;
int group_cipher;
int key_mgmt;
int wpa_proto;
@@ -592,8 +607,8 @@
* results.
*/
struct wpa_bss **last_scan_res;
- unsigned int last_scan_res_used;
- unsigned int last_scan_res_size;
+ size_t last_scan_res_used;
+ size_t last_scan_res_size;
struct os_reltime last_scan;
const struct wpa_driver_ops *driver;
@@ -614,6 +629,9 @@
int eapol_received; /* number of EAPOL packets received after the
* previous association event */
+ u8 rsnxe[20];
+ size_t rsnxe_len;
+
struct scard_data *scard;
char imsi[20];
int mnc_len;
@@ -697,13 +715,18 @@
int scan_id[MAX_SCAN_ID];
unsigned int scan_id_count;
u8 next_scan_bssid[ETH_ALEN];
+ unsigned int next_scan_bssid_wildcard_ssid:1;
struct wpa_ssid_value *ssids_from_scan_req;
unsigned int num_ssids_from_scan_req;
+ int *last_scan_freqs;
+ unsigned int num_last_scan_freqs;
+ unsigned int suitable_network;
+ unsigned int no_suitable_network;
u64 drv_flags;
+ u64 drv_flags2;
unsigned int drv_enc;
- unsigned int drv_smps_modes;
unsigned int drv_rrm_flags;
/*
@@ -752,6 +775,10 @@
unsigned int connection_ht:1;
unsigned int connection_vht:1;
unsigned int connection_he:1;
+ unsigned int connection_max_nss_rx:4;
+ unsigned int connection_max_nss_tx:4;
+ unsigned int connection_channel_bandwidth:5;
+ unsigned int disable_mbo_oce:1;
struct os_reltime last_mac_addr_change;
int last_mac_addr_style;
@@ -805,6 +832,7 @@
u8 ext_auth_bssid[ETH_ALEN];
u8 ext_auth_ssid[SSID_MAX_LEN];
size_t ext_auth_ssid_len;
+ int *sae_rejected_groups;
#endif /* CONFIG_SAE */
} sme;
#endif /* CONFIG_SME */
@@ -823,6 +851,7 @@
unsigned int mesh_if_created:1;
unsigned int mesh_ht_enabled:1;
unsigned int mesh_vht_enabled:1;
+ unsigned int mesh_he_enabled:1;
struct wpa_driver_mesh_join_params *mesh_params;
#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
/* struct external_pmksa_cache::list */
@@ -867,7 +896,6 @@
P2P_GROUP_INTERFACE_CLIENT
} p2p_group_interface;
struct p2p_group *p2p_group;
- int p2p_long_listen; /* remaining time in long Listen state in ms */
char p2p_pin[10];
int p2p_wps_method;
u8 p2p_auth_invite[ETH_ALEN];
@@ -921,6 +949,7 @@
unsigned int p2p_pd_before_go_neg:1;
unsigned int p2p_go_ht40:1;
unsigned int p2p_go_vht:1;
+ unsigned int p2p_go_edmg:1;
unsigned int p2p_go_he:1;
unsigned int user_initiated_pd:1;
unsigned int p2p_go_group_formation_completed:1;
@@ -1050,6 +1079,7 @@
unsigned int wmm_ac_supported:1;
unsigned int ext_work_in_progress:1;
unsigned int own_disconnect_req:1;
+ unsigned int own_reconnect_req:1;
unsigned int ignore_post_flush_scan_res:1;
#define MAC_ADDR_RAND_SCAN BIT(0)
@@ -1083,7 +1113,11 @@
u8 coloc_intf_timeout;
#ifdef CONFIG_MBO
unsigned int wnm_mbo_trans_reason_present:1;
+ unsigned int wnm_mbo_cell_pref_present:1;
+ unsigned int wnm_mbo_assoc_retry_delay_present:1;
u8 wnm_mbo_transition_reason;
+ u8 wnm_mbo_cell_preference;
+ u16 wnm_mbo_assoc_retry_delay_sec;
#endif /* CONFIG_MBO */
#endif /* CONFIG_WNM */
@@ -1108,7 +1142,10 @@
unsigned int p2p_go_csa_on_inv:1;
unsigned int ignore_auth_resp:1;
unsigned int ignore_assoc_disallow:1;
+ unsigned int disable_sa_query:1;
unsigned int testing_resend_assoc:1;
+ unsigned int ignore_sae_h2e_only:1;
+ int ft_rsnxe_used;
struct wpabuf *sae_commit_override;
enum wpa_alg last_tk_alg;
u8 last_tk_addr[ETH_ALEN];
@@ -1116,6 +1153,11 @@
u8 last_tk[WPA_TK_MAX_LEN];
size_t last_tk_len;
struct wpabuf *last_assoc_req_wpa_ie;
+ int *extra_sae_rejected_groups;
+ struct wpabuf *rsne_override_eapol;
+ struct wpabuf *rsnxe_override_assoc;
+ struct wpabuf *rsnxe_override_eapol;
+ struct dl_list drv_signal_override;
#endif /* CONFIG_TESTING_OPTIONS */
struct wmm_ac_assoc_data *wmm_ac_assoc_info;
@@ -1218,7 +1260,7 @@
unsigned int dpp_listen_freq;
u8 dpp_allowed_roles;
int dpp_qr_mutual;
- int dpp_netrole_ap;
+ int dpp_netrole;
int dpp_auth_ok_on_ack;
int dpp_in_response_listen;
int dpp_gas_client;
@@ -1238,8 +1280,19 @@
unsigned int dpp_resp_wait_time;
unsigned int dpp_resp_max_tries;
unsigned int dpp_resp_retry_time;
+ u8 dpp_last_ssid[SSID_MAX_LEN];
+ size_t dpp_last_ssid_len;
#ifdef CONFIG_DPP2
struct dpp_pfs *dpp_pfs;
+ int dpp_pfs_fallback;
+ struct wpabuf *dpp_presence_announcement;
+ struct dpp_bootstrap_info *dpp_chirp_bi;
+ int dpp_chirp_freq;
+ int *dpp_chirp_freqs;
+ int dpp_chirp_iter;
+ int dpp_chirp_round;
+ int dpp_chirp_scan_done;
+ int dpp_chirp_listen;
#endif /* CONFIG_DPP2 */
#ifdef CONFIG_TESTING_OPTIONS
char *dpp_config_obj_override;
@@ -1255,6 +1308,10 @@
unsigned int ieee80211ac:1;
unsigned int enabled_4addr_mode:1;
unsigned int multi_bss_support:1;
+ unsigned int drv_authorized_port:1;
+ unsigned int multi_ap_ie:1;
+ unsigned int multi_ap_backhaul:1;
+ unsigned int multi_ap_fronthaul:1;
};
@@ -1265,6 +1322,9 @@
void wpa_supplicant_apply_vht_overrides(
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_driver_associate_params *params);
+void wpa_supplicant_apply_he_overrides(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params);
int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
@@ -1295,7 +1355,8 @@
const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s);
void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s);
void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
- int reason_code);
+ u16 reason_code);
+void wpa_supplicant_reconnect(struct wpa_supplicant *wpa_s);
struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s);
int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id);
@@ -1361,6 +1422,8 @@
int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s);
void add_freq(int *freqs, int *num_freqs, int freq);
+int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
+ u8 *op_class, u8 *chan, u8 *phy_type);
void wpas_rrm_reset(struct wpa_supplicant *wpa_s);
void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
const u8 *report, size_t report_len);
@@ -1383,6 +1446,7 @@
struct scan_info *info);
void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s);
void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s);
+void wpas_clear_disabled_interface(void *eloop_ctx, void *timeout_ctx);
/* MBO functions */
@@ -1390,6 +1454,8 @@
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);
+void wpas_mbo_check_pmf(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ struct wpa_ssid *ssid);
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,
@@ -1413,11 +1479,18 @@
NOT_ALLOWED, NO_IR, ALLOWED
};
-enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel,
- u8 bw);
+enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class,
+ u8 channel, u8 bw);
size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
- int freq, u8 *pos, size_t len);
+ struct wpa_bss *bss, u8 *pos, size_t len);
+int * wpas_supp_op_classes(struct wpa_supplicant *wpa_s);
+
+int wpas_enable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
+ unsigned int type, const u8 *addr,
+ const u8 *mask);
+int wpas_disable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
+ unsigned int type);
/**
* wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
@@ -1480,6 +1553,24 @@
return ssid->disabled == 2 && ssid->p2p_persistent_group;
}
+static inline int wpas_mode_to_ieee80211_mode(enum wpas_mode mode)
+{
+ switch (mode) {
+ default:
+ case WPAS_MODE_INFRA:
+ return IEEE80211_MODE_INFRA;
+ case WPAS_MODE_IBSS:
+ return IEEE80211_MODE_IBSS;
+ case WPAS_MODE_AP:
+ case WPAS_MODE_P2P_GO:
+ case WPAS_MODE_P2P_GROUP_FORMATION:
+ return IEEE80211_MODE_AP;
+ case WPAS_MODE_MESH:
+ return IEEE80211_MODE_MESH;
+ }
+}
+
+
int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
@@ -1515,7 +1606,8 @@
int wpas_sched_scan_plans_set(struct wpa_supplicant *wpa_s, const char *cmd);
struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
- u16 num_modes, enum hostapd_hw_mode mode);
+ u16 num_modes, enum hostapd_hw_mode mode,
+ int is_6ghz);
void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
unsigned int sec, int rssi_threshold);
@@ -1536,4 +1628,6 @@
int wpa_is_fils_supported(struct wpa_supplicant *wpa_s);
int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s);
+void wpas_clear_driver_signal_override(struct wpa_supplicant *wpa_s);
+
#endif /* WPA_SUPPLICANT_I_H */
diff --git a/wpa_supplicant/wpa_supplicant_template.conf b/wpa_supplicant/wpa_supplicant_template.conf
index f55227f..fce7e5e 100644
--- a/wpa_supplicant/wpa_supplicant_template.conf
+++ b/wpa_supplicant/wpa_supplicant_template.conf
@@ -5,3 +5,4 @@
fast_reauth=1
pmf=1
p2p_add_cli_chan=1
+oce=1
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 449e04a..6bd271e 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -112,6 +112,14 @@
}
#endif /* CONFIG_TESTING_OPTIONS */
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT) {
+ int encrypt = wpa_s->wpa &&
+ wpa_sm_has_ptk_installed(wpa_s->wpa);
+
+ return wpa_drv_tx_control_port(wpa_s, dest, proto, buf, len,
+ !encrypt);
+ }
+
if (wpa_s->l2) {
return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
}
@@ -219,6 +227,7 @@
}
+#ifdef CONFIG_WEP
/**
* wpa_eapol_set_wep_key - set WEP key for the driver
* @ctx: Pointer to wpa_supplicant data (wpa_s)
@@ -242,8 +251,11 @@
}
return wpa_drv_set_key(wpa_s, WPA_ALG_WEP,
unicast ? wpa_s->bssid : NULL,
- keyidx, unicast, NULL, 0, key, keylen);
+ keyidx, unicast, NULL, 0, key, keylen,
+ unicast ? KEY_FLAG_PAIRWISE_RX_TX :
+ KEY_FLAG_GROUP_RX_TX_DEFAULT);
}
+#endif /* CONFIG_WEP */
static void wpa_supplicant_aborted_cached(void *ctx)
@@ -340,8 +352,8 @@
wpa_hexdump_key(MSG_DEBUG, "RSN: Configure PMK for driver-based 4-way "
"handshake", pmk, pmk_len);
- if (wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, NULL, 0, pmk,
- pmk_len)) {
+ if (wpa_drv_set_key(wpa_s, 0, NULL, 0, 0, NULL, 0, pmk,
+ pmk_len, KEY_FLAG_PMK)) {
wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver");
}
@@ -386,6 +398,13 @@
curr = bss;
break;
}
+#ifdef CONFIG_OWE
+ if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+ (bss->flags & WPA_BSS_OWE_TRANSITION)) {
+ curr = bss;
+ break;
+ }
+#endif /* CONFIG_OWE */
}
if (curr) {
@@ -396,6 +415,10 @@
ie = wpa_bss_get_ie(curr, WLAN_EID_RSN);
if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
ret = -1;
+
+ ie = wpa_bss_get_ie(curr, WLAN_EID_RSNX);
+ if (wpa_sm_set_ap_rsnxe(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
+ ret = -1;
} else {
ret = -1;
}
@@ -464,7 +487,7 @@
}
-static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
+static void _wpa_supplicant_deauthenticate(void *wpa_s, u16 reason_code)
{
wpa_supplicant_deauthenticate(wpa_s, reason_code);
/* Schedule a scan to make sure we continue looking for networks */
@@ -472,6 +495,12 @@
}
+static void _wpa_supplicant_reconnect(void *wpa_s)
+{
+ wpa_supplicant_reconnect(wpa_s);
+}
+
+
static void * wpa_supplicant_get_network_ctx(void *wpa_s)
{
return wpa_supplicant_get_ssid(wpa_s);
@@ -488,7 +517,8 @@
static int wpa_supplicant_set_key(void *_wpa_s, 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)
+ const u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
struct wpa_supplicant *wpa_s = _wpa_s;
if (alg == WPA_ALG_TKIP && key_idx == 0 && key_len == 32) {
@@ -503,7 +533,8 @@
}
#endif /* CONFIG_TESTING_GET_GTK */
#ifdef CONFIG_TESTING_OPTIONS
- if (addr && !is_broadcast_ether_addr(addr)) {
+ if (addr && !is_broadcast_ether_addr(addr) &&
+ !(key_flag & KEY_FLAG_MODIFY)) {
wpa_s->last_tk_alg = alg;
os_memcpy(wpa_s->last_tk_addr, addr, ETH_ALEN);
wpa_s->last_tk_key_idx = key_idx;
@@ -513,7 +544,7 @@
}
#endif /* CONFIG_TESTING_OPTIONS */
return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
- key, key_len);
+ key, key_len, key_flag);
}
@@ -543,7 +574,8 @@
static int wpa_supplicant_add_pmkid(void *_wpa_s, void *network_ctx,
const u8 *bssid, const u8 *pmkid,
const u8 *fils_cache_id,
- const u8 *pmk, size_t pmk_len)
+ const u8 *pmk, size_t pmk_len,
+ u32 pmk_lifetime, u8 pmk_reauth_threshold)
{
struct wpa_supplicant *wpa_s = _wpa_s;
struct wpa_ssid *ssid;
@@ -565,6 +597,8 @@
params.pmkid = pmkid;
params.pmk = pmk;
params.pmk_len = pmk_len;
+ params.pmk_lifetime = pmk_lifetime;
+ params.pmk_reauth_threshold = pmk_reauth_threshold;
return wpa_drv_add_pmkid(wpa_s, ¶ms);
}
@@ -1017,15 +1051,12 @@
}
-static void wpa_supplicant_cert_cb(void *ctx, int depth, const char *subject,
- const char *altsubject[], int num_altsubject,
- const char *cert_hash,
- const struct wpabuf *cert)
+static void wpa_supplicant_cert_cb(void *ctx, struct tls_cert_data *cert,
+ const char *cert_hash)
{
struct wpa_supplicant *wpa_s = ctx;
- wpas_notify_certification(wpa_s, depth, subject, altsubject,
- num_altsubject, cert_hash, cert);
+ wpas_notify_certification(wpa_s, cert, cert_hash);
}
@@ -1046,6 +1077,21 @@
}
+static int wpa_supplicant_eap_auth_start_cb(void *ctx)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ if (!wpa_s->new_connection && wpa_s->deny_ptk0_rekey &&
+ !wpa_sm_ext_key_id_active(wpa_s->wpa)) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "WPA: PTK0 rekey not allowed, reconnecting");
+ wpa_supplicant_reconnect(wpa_s);
+ return -1;
+ }
+ return 0;
+}
+
+
static void wpa_supplicant_set_anon_id(void *ctx, const u8 *id, size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -1101,7 +1147,9 @@
ctx->preauth = 0;
ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done;
ctx->eapol_send = wpa_supplicant_eapol_send;
+#ifdef CONFIG_WEP
ctx->set_wep_key = wpa_eapol_set_wep_key;
+#endif /* CONFIG_WEP */
#ifndef CONFIG_NO_CONFIG_BLOBS
ctx->set_config_blob = wpa_supplicant_set_config_blob;
ctx->get_config_blob = wpa_supplicant_get_config_blob;
@@ -1124,6 +1172,7 @@
ctx->cert_in_cb = wpa_s->conf->cert_in_cb;
ctx->status_cb = wpa_supplicant_status_cb;
ctx->eap_error_cb = wpa_supplicant_eap_error_cb;
+ ctx->confirm_auth_cb = wpa_supplicant_eap_auth_start_cb;
ctx->set_anon_id = wpa_supplicant_set_anon_id;
ctx->cb_ctx = wpa_s;
wpa_s->eapol = eapol_sm_init(ctx);
@@ -1159,8 +1208,8 @@
if (wpa_s->conf->key_mgmt_offload &&
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD))
- return wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0,
- NULL, 0, pmk, pmk_len);
+ return wpa_drv_set_key(wpa_s, 0, NULL, 0, 0,
+ NULL, 0, pmk, pmk_len, KEY_FLAG_PMK);
else
return 0;
}
@@ -1192,6 +1241,73 @@
return wpa_drv_channel_info(wpa_s, ci);
}
+
+static void disable_wpa_wpa2(struct wpa_ssid *ssid)
+{
+ ssid->proto &= ~WPA_PROTO_WPA;
+ ssid->proto |= WPA_PROTO_RSN;
+ ssid->key_mgmt &= ~(WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK |
+ WPA_KEY_MGMT_PSK_SHA256);
+ ssid->group_cipher &= ~WPA_CIPHER_TKIP;
+ if (!(ssid->group_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
+ WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256)))
+ ssid->group_cipher |= WPA_CIPHER_CCMP;
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
+}
+
+
+static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap)
+{
+ struct wpa_supplicant *wpa_s = _wpa_s;
+ struct wpa_ssid *ssid;
+ int changed = 0;
+
+ wpa_msg(wpa_s, MSG_INFO, TRANSITION_DISABLE "%02x", bitmap);
+
+ ssid = wpa_s->current_ssid;
+ if (!ssid)
+ return;
+
+ if ((bitmap & TRANSITION_DISABLE_WPA3_PERSONAL) &&
+ wpa_key_mgmt_sae(wpa_s->key_mgmt) &&
+ (ssid->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE)) &&
+ (ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED ||
+ (ssid->group_cipher & WPA_CIPHER_TKIP))) {
+ wpa_printf(MSG_DEBUG,
+ "WPA3-Personal transition mode disabled based on AP notification");
+ disable_wpa_wpa2(ssid);
+ changed = 1;
+ }
+
+ if ((bitmap & TRANSITION_DISABLE_WPA3_ENTERPRISE) &&
+ wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
+ (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X |
+ WPA_KEY_MGMT_FT_IEEE8021X |
+ WPA_KEY_MGMT_IEEE8021X_SHA256)) &&
+ (ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED ||
+ (ssid->group_cipher & WPA_CIPHER_TKIP))) {
+ disable_wpa_wpa2(ssid);
+ changed = 1;
+ }
+
+ if ((bitmap & TRANSITION_DISABLE_ENHANCED_OPEN) &&
+ wpa_s->key_mgmt == WPA_KEY_MGMT_OWE &&
+ (ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+ !ssid->owe_only) {
+ ssid->owe_only = 1;
+ changed = 1;
+ }
+
+ if (!changed)
+ return;
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+ if (wpa_s->conf->update_config &&
+ wpa_config_write(wpa_s->confname, wpa_s->conf))
+ wpa_printf(MSG_DEBUG, "Failed to update configuration");
+#endif /* CONFIG_NO_CONFIG_WRITE */
+}
+
#endif /* CONFIG_NO_WPA */
@@ -1210,6 +1326,7 @@
ctx->set_state = _wpa_supplicant_set_state;
ctx->get_state = _wpa_supplicant_get_state;
ctx->deauthenticate = _wpa_supplicant_deauthenticate;
+ ctx->reconnect = _wpa_supplicant_reconnect;
ctx->set_key = wpa_supplicant_set_key;
ctx->get_network_ctx = wpa_supplicant_get_network_ctx;
ctx->get_bssid = wpa_supplicant_get_bssid;
@@ -1243,6 +1360,7 @@
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;
+ ctx->transition_disable = wpa_supplicant_transition_disable;
wpa_s->wpa = wpa_sm_init(ctx);
if (wpa_s->wpa == NULL) {
@@ -1274,6 +1392,8 @@
conf.ssid = ssid->ssid;
conf.ssid_len = ssid->ssid_len;
conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey;
+ conf.wpa_deny_ptk0_rekey = ssid->wpa_deny_ptk0_rekey;
+ conf.owe_ptk_workaround = ssid->owe_ptk_workaround;
#ifdef CONFIG_P2P
if (ssid->p2p_group && wpa_s->current_bss &&
!wpa_s->p2p_disable_ip_addr_req) {
@@ -1296,6 +1416,7 @@
conf.fils_cache_id =
wpa_bss_get_fils_cache_id(wpa_s->current_bss);
#endif /* CONFIG_FILS */
+ conf.beacon_prot = ssid->beacon_prot;
}
wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
}
diff --git a/wpa_supplicant/wpas_kay.c b/wpa_supplicant/wpas_kay.c
index 41477d5..defd0f2 100644
--- a/wpa_supplicant/wpas_kay.c
+++ b/wpa_supplicant/wpas_kay.c
@@ -44,19 +44,19 @@
}
-static int wpas_enable_protect_frames(void *wpa_s, Boolean enabled)
+static int wpas_enable_protect_frames(void *wpa_s, bool enabled)
{
return wpa_drv_enable_protect_frames(wpa_s, enabled);
}
-static int wpas_enable_encrypt(void *wpa_s, Boolean enabled)
+static int wpas_enable_encrypt(void *wpa_s, bool enabled)
{
return wpa_drv_enable_encrypt(wpa_s, enabled);
}
-static int wpas_set_replay_protect(void *wpa_s, Boolean enabled, u32 window)
+static int wpas_set_replay_protect(void *wpa_s, bool enabled, u32 window)
{
return wpa_drv_set_replay_protect(wpa_s, enabled, window);
}
@@ -68,7 +68,7 @@
}
-static int wpas_enable_controlled_port(void *wpa_s, Boolean enabled)
+static int wpas_enable_controlled_port(void *wpa_s, bool enabled)
{
return wpa_drv_enable_controlled_port(wpa_s, enabled);
}
@@ -376,7 +376,7 @@
wpa_hexdump(MSG_DEBUG, "Derived CKN", ckn->name, ckn->len);
res = ieee802_1x_kay_create_mka(wpa_s->kay, ckn, cak, 0,
- EAP_EXCHANGE, FALSE);
+ EAP_EXCHANGE, false);
fail:
if (msk) {
@@ -424,7 +424,7 @@
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);
+ res = ieee802_1x_kay_create_mka(wpa_s->kay, ckn, cak, 0, PSK, false);
if (res)
goto free_cak;
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 5da8154..130c278 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -484,7 +484,7 @@
case WPS_ENCR_NONE:
break;
case WPS_ENCR_TKIP:
- ssid->pairwise_cipher = WPA_CIPHER_TKIP;
+ ssid->pairwise_cipher = WPA_CIPHER_TKIP | WPA_CIPHER_CCMP;
break;
case WPS_ENCR_AES:
ssid->pairwise_cipher = WPA_CIPHER_CCMP;
@@ -525,17 +525,16 @@
case WPS_AUTH_WPAPSK:
ssid->auth_alg = WPA_AUTH_ALG_OPEN;
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
- ssid->proto = WPA_PROTO_WPA;
+ ssid->proto = WPA_PROTO_WPA | WPA_PROTO_RSN;
break;
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->auth_alg = 0;
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;
@@ -1180,6 +1179,11 @@
/* P2P in 60 GHz uses PBSS */
ssid->pbss = 1;
}
+ if (wpa_s->go_params->edmg &&
+ wpas_p2p_try_edmg_channel(wpa_s,
+ wpa_s->go_params) == 0)
+ ssid->enable_edmg = 1;
+
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
"SSID", ssid->ssid, ssid->ssid_len);
}
@@ -1263,6 +1267,11 @@
/* P2P in 60 GHz uses PBSS */
ssid->pbss = 1;
}
+ if (wpa_s->go_params->edmg &&
+ wpas_p2p_try_edmg_channel(wpa_s,
+ wpa_s->go_params) == 0)
+ ssid->enable_edmg = 1;
+
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
"SSID", ssid->ssid, ssid->ssid_len);
}
@@ -1286,6 +1295,10 @@
wpa_printf(MSG_DEBUG, "WPS: Failed to set phase1 '%s'", val);
return -1;
}
+
+ if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER)
+ wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_PIN_ACTIVE);
+
if (wpa_s->wps_fragment_size)
ssid->eap.fragment_size = wpa_s->wps_fragment_size;
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
@@ -1351,6 +1364,7 @@
wpas_clear_wps(wpa_s);
}
+ wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CANCEL);
wpa_s->after_wps = 0;
return 0;
@@ -1604,8 +1618,13 @@
os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN);
wpas_wps_set_uuid(wpa_s, wps);
+#ifdef CONFIG_NO_TKIP
+ wps->auth_types = WPS_AUTH_WPA2PSK;
+ wps->encr_types = WPS_ENCR_AES;
+#else /* CONFIG_NO_TKIP */
wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
+#endif /* CONFIG_NO_TKIP */
os_memset(&rcfg, 0, sizeof(rcfg));
rcfg.new_psk_cb = wpas_wps_new_psk_cb;
@@ -1816,6 +1835,10 @@
wpa_printf(MSG_DEBUG, "WPS: Check whether PBC session overlap is "
"present in scan results; selected BSSID " MACSTR,
MAC2STR(selected->bssid));
+ if (!is_zero_ether_addr(ssid->bssid))
+ wpa_printf(MSG_DEBUG,
+ "WPS: Network profile limited to accept only a single BSSID " MACSTR,
+ MAC2STR(ssid->bssid));
/* Make sure that only one AP is in active PBC mode */
wps_ie = wpa_bss_get_vendor_ie_multi(selected, WPS_IE_VENDOR_TYPE);
@@ -1836,6 +1859,14 @@
os_memcmp(selected->bssid, ap->bssid, ETH_ALEN) == 0)
continue;
+ if (!is_zero_ether_addr(ssid->bssid) &&
+ os_memcmp(ap->bssid, ssid->bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "WPS: Ignore another BSS " MACSTR
+ " in active PBC mode due to local BSSID limitation",
+ MAC2STR(ap->bssid));
+ continue;
+ }
+
wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: "
MACSTR, MAC2STR(ap->bssid));
wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS",
@@ -2691,7 +2722,7 @@
(attr.rf_bands == NULL ||
*attr.rf_bands & WPS_RF_50GHZ))
freq = 5000 + 5 * chan;
- else if (chan >= 1 && chan <= 4 &&
+ else if (chan >= 1 && chan <= 6 &&
(attr.rf_bands == NULL ||
*attr.rf_bands & WPS_RF_60GHZ))
freq = 56160 + 2160 * chan;